Skip to content

Module Index

The dashboard runs FreeRTOS (via the CMSIS-RTOS2 wrapper), no superloop. TouchGFX gets its own task, CAN RX/TX get their own tasks, and they all talk through two shared structs: can_input_data (read-only outside the CAN RX path) and ui_data (driver-intent and UI state, written by screens and read by the CAN TX path). This page is the map of every task and where it's documented.

Tasks

Application tasks are created in MX_FREERTOS_Init() (app_freertos.c) and init_can_tasks() (can_tasks.c), both called before osKernelStart(). Lower osPriority_t value means lower priority.

TaskPriorityRate / triggerJobDocs
GUI_TaskNormalTouchGFX internal (~60 Hz target)Runs the TouchGFX task entry, renders dirty screen regions, drives the display DMA/TE pipelineTouchGFX Integration
canRxTaskAboveNormalon RX ISR flagDrains the RX ring buffer, decodes recognized CAN IDs into can_input_dataCAN
canTxTaskNormalon button-change flag, or every 1 msPacks ui_data into TX frames, runs the periodic TX scheduler, drains the TX ring buffer into the FDCAN FIFOCAN
defaultTaskNormalfree-runningIdle placeholder (LED blink stub, currently a no-op osDelay(1) loop)(none)
Startup frame timer(software timer, not a task)one-shot, 3000 ms after bootFires the first DASH_Buttons CAN frame after boot, deliberately delayedCAN

Interrupts vs. tasks

Peripherals (FDCAN, the display's GPDMA channel, the TE line) do the minimum in their ISRs: copy a frame into a ring buffer, advance a DMA block, or signal a semaphore/flag. The heavier work of decoding CAN payloads and transmitting the next framebuffer block happens in the corresponding task once it wakes.

Shared state, not message passing

Unlike a strict message-passing design, most cross-task communication here goes through two long-lived structs plus a flag:

  • can_input_data: written only by canRxTask inside process_can_frames(), read by Model::tick() on the TouchGFX side. Model::tick() runs memcmp against the previous snapshot and only pushes an update to the active screen's presenter when something actually changed.
  • ui_data: written by screen Views (via Model setters) when the driver touches something, and read by canTxTask when packing TX frames. A buttons_updated_flag plus a thread-flag wake (CAN_TX_WAKE_FLAG) tells canTxTask there's something new to send without it having to poll.

This keeps both directions simple: the CAN side never blocks on the UI, and the UI never blocks on the CAN side.

Modules by group

Bringing up a board or chasing a hardware fault? Skip the theory and go straight to Track Operations: DIP switch settings, the bring-up checklist, and a failure-signature reference built from real debugging sessions on this board.

Released under the MIT License.