Skip to content

Track Operations

Quick reference for bringing the board up, checking it's healthy, and recognizing known failure signatures without re-deriving them from first principles every time. Written from real debugging sessions on this exact board.

Display DIP switch (IM0/IM1/IM2)

The ILI9488's interface mode is set by three onboard switches (SW200A/B/C = IM0/IM1/IM2), each pulled up to 3V3 with a switch to GND.

IM2IM1IM0Interface
000MCU18
001MCU9
010MCU16
011MCU8, the correct setting for this firmware
1013-line SPI
1114-line SPI

The firmware is built for 8-bit parallel (MCU8). If the DIP is on any other setting, the panel will render something (each wrong mode reinterprets the same byte stream differently: clean-looking but wrong colors on some settings, corrupted-looking on others), which can be misleading during bring-up. Always confirm the DIP first before chasing a software bug.

Bring-up checklist, in order

Confirm each stage before moving to the next. This order reflects the actual dependency chain, and skipping ahead wastes time debugging a symptom whose real cause is one stage back.

  1. DIP on MCU8. See table above.
  2. TE is toggling. Scope PF13, should show a clean ~60 Hz signal once the panel is in the correct interface mode and scanning normally. If TE looks dead or static, the DIP is probably still wrong, not the TE circuit.
  3. DMA is completing. Breakpoint DMA_TxCpltCallback in TouchGFXHAL.cpp, it should hit repeatedly during rendering. If TE is confirmed good but DMA never completes, check GPDMA channel config against Core/Src/gpdma.c and the FMC bring-up page.
  4. Full-screen coverage, correct colors. If TE and DMA both check out but the image is still wrong, see the failure-signature table below before assuming it's a driver bug. The two real display faults found on this board were both physical, not firmware.

Failure signatures (display)

SymptomLikely causeWhat to check
Only a fixed fraction of the screen renders (for example 15-70%), rest stays blank. Same physical region regardless of what pattern is sent, and regardless of DMA vs. CPU-loop writesMarginal physical connection (bad solder joint or FPC seating) on a control line (CS/WR/DCX). Not a firmware/timing bugReseat and reflow the display FPC connector (J200), focusing on CS (PD7), WR (PD5), DCX (PE4): these are single points of failure for the whole rest of a transfer if they glitch. Confirmed root cause on this board; slowing FMC timing 10x and lowering GPIO drive strength both had zero effect, which is what pointed away from a timing/software explanation
Full coverage but wrong or inverted colorsPossible R/B swap, not yet confirmed on this board. Do not "fix" it with a per-pixel CPU swap (blocks DMA)Do a clean solid-red-then-solid-blue full-screen test and judge by eye, not through a phone camera which color-casts. If genuinely swapped, fix it at the panel's MADCTL BGR bit or in TouchGFX asset generation, not in the blit path
Coverage is a position-encoded pattern (for example vertical color bars) that still only shows in a limited stripSame connector/solder issue as above. Use a position-encoded test pattern instead of solid color specifically because it lets you see where the cutoff is, not just that one existsSee FMC Hardware Bring-Up for the diagnostic pattern technique

Failure signatures (CAN / RTOS)

SymptomLikely causeWhat to check
RX ISR fires (confirmed via breakpoint) but the corresponding task never runs, task handle reads NULL in the debugger, and this is permanent, not intermittentconfigTOTAL_HEAP_SIZE in FreeRTOSConfig.h too small: osThreadNew() fails silently and returns NULL, no crash, no logCheck the FreeRTOS heap budget against the sum of every osThreadNew/osTimerNew/osSemaphoreNew stack/object size actually created, with margin. See CAN
Button touch doesn't produce a CAN frame, and received values never update the UI, at the same timeSame root cause as above (heap exhaustion killed both canRxTask and canTxTask)Same fix. This is a single bug with two symptoms, don't chase them separately
A CAN signal shows a wrong-looking but not obviously garbage value (off by a scale factor, wrong sign, or reading a neighboring signal's data)Byte-offset or endianness bug in the manual decode in can_comm.cCross-check the exact start_bit/@0 (big-endian/Motorola) vs @1 (little-endian/Intel) against MAIN_DBC.dbc. Most signals here are @0, but not all (GPS_Speed is @1). Found three real instances of this: Pack_Inst_Voltage/Pack_Current reading the wrong byte offset entirely, landing on a different, valid neighboring signal (Pack_Open_Voltage/Average_Current, which is why it looked plausible instead of obviously broken), and GPS_Speed decoded with the wrong endianness

Regenerating from CubeMX / TouchGFX Designer: what's safe

  • CubeMX "Generate Code": safe, as long as the .ioc itself (not just hand-edited source) reflects the setting you want. Anything outside USER CODE BEGIN/END markers gets fully replaced from the .ioc, including GPIO pin lists and peripheral Init struct fields like MemoryDataWidth or StdFiltersNbr. Change the setting in the CubeMX GUI first, then generate. Don't hand-patch generated files and expect them to survive a regen.
  • TouchGFX Designer "Generate Code": touches TouchGFX/generated/** only. Confirmed safe on this board when the .touchgfx project itself hasn't changed, but always diff after, since this is the one regen path that could touch the hand-tuned partial-framebuffer/TE-pacing driver work if the project file ever changes.
  • Always git diff after either regen and review it before flashing.

Released under the MIT License.