Skip to content

CAN Message Handling

This page covers the board logic that sits on top of the CAN driver. It decides what the gateway publishes, which incoming frames should be acted on, and how those commands reach the rest of the firmware.

The core implementation is found in repos/CAN-Gateway/Core/Src/App/Communication/can_comm.c with header definitions in repos/CAN-Gateway/Core/Inc/App/Communication/can_comm.h.


FDCAN Messaging Protocol

The FDCAN interface operates on the vehicle bus using 500 KBps CAN 2.0. Messages use specific base identifiers depending on the board's compiled identity:

  • Front Gateway Base ID: 0xA0
  • Rear Gateway Base ID: 0xB0

Transmit Frames (TX)

Periodic frame serialization is defined in the set_can_frames function. The frame payload layouts differ depending on DEVICE_TYPE:

CAN IDOffsetCompiled VariantContent / Signal LayoutCode Reference
Base + 00Front & RearBytes 0-1: Wheel Speed 1 (RPM)
Bytes 2-3: Wheel Speed 2 (RPM)
Bytes 4-5: Suspension Travel 1 displacement (scaled by 1000)
Bytes 6-7: Suspension Travel 2 displacement (scaled by 1000)
repos/CAN-Gateway/Core/Src/App/Communication/can_comm.c
Base + 11Front GatewayByte 0: APPS 1 displacement
Byte 1: APPS 2 displacement
Bytes 2-3: Steering Angle (scaled by 100)
Byte 4: Ready-To-Drive (R2D) Button state (0/1)
repos/CAN-Gateway/Core/Src/App/Communication/can_comm.c
Base + 11Rear GatewayBytes 0-1: Brake Pressure (scaled by 100)
Bytes 2-3: Junction Box Current 50A
Bytes 4-5: Junction Box Current 200A
Byte 6: Shutdown Circuit (SDC) state (0/1)
repos/CAN-Gateway/Core/Src/App/Communication/can_comm.c
Base + 22Rear GatewayBytes 0-1: Flow Rate (mL/s)
Bytes 2-3: Temperature Sensor 1
Bytes 4-5: Temperature Sensor 2
repos/CAN-Gateway/Core/Src/App/Communication/can_comm.c
Base + 33Front & RearCalibration Frame: Transmitted via send_calibration_values_frame containing current min/max values: APPS1 min/max (Bytes 0-3), APPS2 min/max (Bytes 4-7)repos/CAN-Gateway/Core/Src/App/Communication/can_comm.c

Receive Frames (RX Commands)

The receive pathway consumes frames from the driver's ring buffer in the process_can_frames function:

  • ID 0x0A2: (Front Gateway only) Sets the R2D LED delay byte in can_input_data.front_nmos.R2D_LED_Delay.
  • ID 0x0B3: (Rear Gateway only) Controls the R2D buzzer state in can_input_data.rear_nmos.R2D_Buzzer_On_Off.
  • ID 0x0D0: Calibration command flags for APPS Recalibration (Bit 0), Steering Recalibration (Bit 1), and Suspension Recalibration (Bit 2).
  • ID 0x4F0: Bootloader Command. If byte 0 matches 0x02 (Front) or 0x03 (Rear), the FSM transitions to BOARD_FSM_MODE_BOOTLOADER.

RX Command Extraction

Below is the implementation detail showing how incoming CAN frames are parsed to update the shared can_input_data fields:

c
switch (current_frame.msg_id)
{
    case 0x0A2:
        can_input_data.front_nmos.R2D_LED_Delay = current_frame.payload[0];
        break;

    case 0x0B3:
        can_input_data.rear_nmos.R2D_Buzzer_On_Off = current_frame.payload[0];
        break;

    case 0x4F0:
        if (current_frame.payload[0] == (DEVICE_TYPE == DEVICE_FRONT_GATEWAY ? 0x002 : 0x003))
        {
            FSM_request_bootloader(&board_fsm_driver);
        }
        break;

    case 0x0D0:
        can_input_data.dash_buttons.APPS_Recal = GET_INTEL_BIT(current_frame.payload, 0);
        can_input_data.dash_buttons.Steering_Recal = GET_INTEL_BIT(current_frame.payload, 1);
        can_input_data.dash_buttons.Suspension_Recal = GET_INTEL_BIT(current_frame.payload, 2);
        break;

    default:
        break;
}

TIP

If a frame ID does not match any cases in this switch, the code discards it immediately. This bounds the RX processing cost and secures the board against unwanted bus interference.

Source Layout & Integration

Every iteration of the main loop calls process_can_helper(), which delegates tasks in this order:

c
static void process_can_helper(void){
    process_can_frames(&can_driver);
    CAN_send_frames(&can_driver, HAL_GetTick());
    if (can_driver.tx_queue_drain_requested) {
      CAN_process_tx_queue(&can_driver, 0);
    }
}

Released under the MIT License.