SDK for TESAIoT Dev Kit
API reference & tutorials (ModusToolbox)
Loading...
Searching...
No Matches
Appendix W — The signal atlas

Learning goal

Recognize — not trigger — every failure signature the board can show. Given a photo of the LEDs, a description of the screen, or a console capture, you name the state and the file that produces it. Where a safe way exists to reproduce a signature harmlessly it is given; where none exists, none is invented.

The real firmware sequence

There is no single sequence; this chapter is a lookup table built from three sources, each cited: the printf-suppression ground truth on CM33_NS, the LED tables in proj_cm55/main.c, and the display step codes in the CM55 display controller (TESAIoT_KIT_PSE84_AI-Micropython-BentoClaw/proj_cm55/modules/lvgl_display/controller/tesaiot_display.c — compiled into libbento_cm55.a; the template ships the archive, not the file).

Ground truth: what can print at all

CM33_NS owns the UART (proj_cm55/main.c:9-10). On it, three suppression layers exist and exactly one is active:

  1. debug_log_disable.h:26 — inert; never -included.
  2. #ifdef BOOT_VERBOSE — BOOT_VERBOSE is defined nowhere, so every such print is compiled out.
  3. Per-file #define printf(...) ((void)0) — active in seven files: sensor_auto_task.c:36, modules/tesaiot_config/tesaiot_config_store.c:26, modules/tesaiot_config/ipc_tesaiot_handler.c:26, tesaiot_mqtt.c:17, publisher_task.c:28, subscriber_task.c:46, modbentoclaw.c:79.

The rule is exact string + call form, never prefix. A function-like #define printf(...) mutes plain printf(...) in that file but not parenthesised (printf)(...) — the muted files use (printf) deliberately where a line must survive.

Verdict Signal Where
LIVE [HB] t=lus tasks=u proj_cm33_ns/main.c:110-112 (mtb-only)
LIVE [MPY] GC heap u KB @ p in s mpy_main.c:552-554 (mtb-mpy)
LIVE [BOOT] optiga_psa_register failed: d / [BOOT] psa_crypto_init failed: d main.c:238, :242 — failure only; success is silent
LIVE storage: SMIF setup failed 0x%08lx / storage: mount failed (d); volume left untouched bento_storage.c:108, :131 (mtb-only)
LIVE ERROR: storage unavailable — config and WiFi credentials will use defaults / ERROR: tesaiot_config_init failed main.c:306-308, :310-312 (mtb-only)
LIVE FATAL: Stack overflow in task 's' main.c stack-overflow hook
LIVE [MQTT] Connected to broker and the other [MQTT] lines mqtt_task.c:328-356; the mute at :39 is commented out
LIVE [MQTT-Config], [mTLS], [CSR], [DirectPub], [PU-Ingest], [WiFi] (modwifi), [wifi-glue] (compile-time live; reached only by a BLE-driven connect under ENABLE_PAGE_BENTO_BUDDY=1), [boot] (needs ENABLE_PAGE_BENTO_BUDDY=1) see Groups C, D, I
LIVE (printf)-form [Subscriber] lines subscriber_task.c:169,:186,:203-205,:211,:217,:223,:229
LIVE (printf)("[PUB-TASK] stack_free…") publisher_task.c:76
DEAD [WiFi-Boot], [WiFiIPC] plain printf under sensor_auto_task.c:36
DEAD [TESAIOT_CFG], [TESAIOT_IPC] plain printf under the two tesaiot_config/ mutes
DEAD [Subscriber] Subscribing to: / Subscribed (QoS…) plain printf, subscriber_task.c:98, :104
DEAD [Publisher] Published to … plain printf, publisher_task.c:100
DEAD CM33_NS: Booting CM55..., CM33_NS: CM55 boot initiated, [BOOT] HSM OPTIGA handler OK, the PSoC Edge AI MicroPython + WiFi banner all BOOT_VERBOSE
PINNED [PSA-Sign] Using Key OID 0x%04X for TLS CertificateVerify (slot=lu) optiga_psa_se.c:364-365, bare printf, no mute; marks sign attempted, success additionally needs no ERROR: trustm_ecdsa_sign status= after it

If a document — including an older revision of this one — tells you to wait for a DEAD line, the document is wrong, not the board. If you need a DEAD line for your own debugging, comment out the mute in that file (e.g. sensor_auto_task.c:36) and rebuild; that is a per-file, deliberate change, not a flag.

CM55 LED codes

CM55 has no console. proj_cm55/main.c and the display controller use the two user LEDs. LED1 and LED2 are CYBSP_USER_LED1/CYBSP_USER_LED2.

Signature Meaning Source
LED1 toggling every 50 ms (≈10 Hz, reads as ~20 Hz flicker) cybsp_init() failed on CM55 proj_cm55/main.c:180-188
LED2 toggling every 50 ms tesaiot_display_init() did not return pdPASS — the GFX task could not be created proj_cm55/main.c:193-199
LED2 toggling every 100 ms radar task creation failed (BSP_HAS_RADAR boards) proj_cm55/main.c:206-212
LED1 and LED2 toggling every 100 ms app_task creation failed proj_cm55/main.c:217-224
LED1 and LED2 toggling every 500 ms scheduler returned — should never happen proj_cm55/main.c:232-237
LED2 one blink, then solid ON display step 1 (Cy_GFXSS_Init) in progress tesaiot_display.c:262-263
LED2 N quick blinks, repeating every 2 s display bring-up failed at step N (see table below); IPC is still up (ipc_only loop) tesaiot_display.c:135-139, :581-582
LED2 4 blinks backlight/panel-MCU write NAKed during bring-up tesaiot_display.c:432
LED2 OFF display init fully succeeded tesaiot_display.c:459-468
LED1 blinking in groups of 1 Stack overflow hook fired on CM55 proj_cm55/main.c:246-254
LED2 blinking in groups of 2 Malloc failed hook fired on CM55 same
LED1+LED2 blinking in groups of 3 HardFault on CM55 same

Display step numbering (tesaiot_display.c:139, repeated at :248):

Steps: 1=GFXSS  2=DC_IRQ  3=GPU_IRQ  4=I2C  5=Panel  6=VGLite

LED contract (tesaiot_display.c:135-138):

OFF              = display init succeeded
ON solid         = display init failed
N quick blinks   = failed at step N (visible during ipc_only loop)

CM55 fault markers in SRAM

proj_cm55/main.c:246-254 writes a breadcrumb word at 0x28000000 that survives until power-cycle:

Word Fault
0xDEAD0001 stack overflow
0xDEAD0002 malloc failed
0xDEAD0003 HardFault

Read it with a debugger memory read only on a halted or crashed board (mem32 0x28000000 1 in the source comment). On mtb-only, attaching to a running board is itself a fault (Appendix X #16) — read the marker after the crash, never as a health check.

Screen states

What you see Meaning Source
Dark screen, immediately after make program, no power-cycle yet Debugger reset; backlight never got its cold 0→1 edge. Not a failed flash shipped READMEs (in-zip :47-49; dist mtb-mpy:51-52, mtb-only:54)
Dark screen after one power-cycle, [HB] beating (mtb-only) Cold-boot backlight; unplug-replug once more dist mtb-only:55
Solid dark-blue fill (0x003366), no cards CM55 reached UI creation but the Home page has not loaded tesaiot_display.c:435-443
Home card grid, v…-mtb_mpy / v…-mtb_only badge Success; the badge tells you which variant is actually running page_home.c:485-489
Home grid present but a page you added has no card page_home.c s_card_defs[] entry missing (registered, no card) Group F
Tap on a card does nothing card exists, page not registered — pm_navigate guards NULL and ignores it (older docs said "crashes"; stale) page_manager.c:92; Group F
Topbar WiFi glyph hidden / clock absent not connected / no NTP yet — not a fault Chapter B3

Step-by-step

Step 1 — Classify a console capture

Take any console capture from A1. For every line with a bracketed prefix, find it in the table in Ground truth: what can print at all. If it is not in the LIVE rows, you are not looking at this firmware's output.

What you should observe
On mtb-only, a healthy capture is a [HB] t=lus tasks=u line every 10 s and nothing else. On mtb-mpy, a single [MPY] GC heap u KB @ p in s and then the REPL prompt. Any [BOOT] … failed, storage: or ERROR: line is a real failure and is always printed.

Step 2 — Classify an LED pattern

Count the blinks and time the cadence. Match against CM55 LED codes.

What you should observe
LED2 OFF with the Home grid showing is success. LED2 repeating N blinks with a dark screen is a display step failure with IPC still alive — the CM33 console keeps working, and on mtb-mpy ui._diag() still answers because the IPC pipe was set up before the display (Chapter B2).

Step 3 — Reproduce the one harmless signature

The only failure signature with a safe recipe is the dark-screen-after-flash: run make program and do not power-cycle.

What you should observe
The programmer reports verified … bytes; the panel stays dark; on mtb-only [HB] begins beating anyway (the core is running — it is the backlight that is off). Power-cycle, and the screen appears. You have now seen, harmlessly, the exact state that looks like a failed flash.

No recipe is given for the LED fault codes, the SRAM markers, or the debugger-attach loop. They are recognised, not triggered.

Traps

  • Appendix X #21 — the dark-screen-after-flash is the reset, not the image.
  • Appendix X #22 — mtb-only cold-boot backlight may need a second unplug.
  • Appendix X #16 — do not attach a debugger to a running mtb-only board to read the fault marker; read it after the fault.
  • Appendix X #1 — CM55 printf is a silent no-op once libbento_edge_ai.a is linked (ai_engine.c:276-288): adding a printf to your CM55 page to "see what happens" produces nothing and is not a sign of a crash.
  • Prefix matching. [Subscriber] is both LIVE and DEAD depending on the call form at the specific line. Match the exact string.

Variant applicability

Variant
mtb-mpy and mtb-only. The LED, marker and screen tables are identical (CM55 is variant-agnostic). The console rows are labelled per variant where they differ; ui._diag() in Step 2 is mtb-mpy only.