Comma.ai Panda Board

Use TI TCAN3404-Q1 for each of the three CAN channels.
Why it fits:
  • CAN FD: supports data rates up to 8 Mbps
  • Automotive qualified: AEC-Q100
  • 3.3 V MCU interface: compatible with the STM32H725
  • Wide bus fault protection: ±58 V
  • Low-power standby mode
  • Small VSON package: suitable for the 85 × 50 mm board
Recommended orderable part:
  • TCAN3404DRBRQ1
  • Package: 8-pin VSON/DRB, 3 × 3 mm
  • Quantity: 3
Use one TCAN3404-Q1 per channel, followed by the channel’s common-mode choke and PESD2CAN protection. Verify that the footprint includes the exposed thermal pad and connect it to ground with nearby vias.
Recommand NXP product
I recommend the NXP TJA1044GT/3 for each CAN channel.
  • Automotive AEC-Q100
  • CAN FD up to 5 Mbit/s
  • Designed for direct use with 3.3 V microcontrollers, including STM32H725
  • Standby and wake-up support
  • SO8 package, easier to assemble than VSON
  • Bus fault protection and excellent automotive EMC performance
Use three TJA1044GT/3 transceivers, one per CAN-FD channel. For improved signal integrity on long or highly branched automotive networks, consider the newer NXP TJA1443 CAN SIC transceiver, but it is larger and requires more support/configuration.
Replace and review
Replace transceivers
Compare NXP options
Check footprint fit
Update BOM cost

Refine this doc
Ask about this doc
Firmware Starter
Scope and compatibility target
This starter is grounded in the live STM32H725ZGT6 (U1) schematic. The official commaai/panda firmware remains the primary compatibility target; this file is a CubeMX/STM32CubeH7 HAL bring-up scaffold, not a replacement protocol implementation. Preserve panda CAN safety policy, USB descriptors/protocol, boot flow, and message semantics when integrating.
Live pin map

Table


FunctionMCU pinHAL/CubeMX selectionLive net / deviceElectrical behavior
FDCAN1 RX/TXPD0 / PD1AF9, FDCAN1FDCAN1_RX/TX → U2 TCAN3404-Q1Channel 1
FDCAN2 RX/TXPB5 / PB6AF9, FDCAN2FDCAN2_RX/TX → IC1Channel 2
FDCAN3 RX/TXPD12 / PD13AF5, FDCAN3FDCAN3_RX/TX → IC2Channel 3
CAN1 standbyPG11GPIO outputCAN1_STB → U2 STBlow = normal; high = standby
CAN2 standbyPB3GPIO outputCAN2_STB → IC1 STBlow = normal; high = standby; conflicts with SWO, so do not enable SWO
CAN3 standbyPD7GPIO outputCAN3_STB → IC2 STBlow = normal; high = standby
USB D− / D+PA11 / PA12USB_OTG_HS internal FS PHYUSB_DM/DP → D1 → J1USB 2.0 FS device; these pins use the dedicated USB function, not the FDCAN1 AF option
USB VBUS monitorPA0ADC1_INP16 (or analog input per CubeMX)100 kΩ/100 kΩ divider, USB_VBUS_SENSEabout 2.5 V at 5 V VBUS
Red LEDPE4GPIO outputLED_RED, R11, LED1active-low sink
Green LEDPE3GPIO outputLED_GREEN, R12, LED2active-low sink
Blue LEDPE2GPIO outputLED_BLUE, R13, LED3active-low sink
SWDIO / SWCLKPA13 / PA14SYS Serial WireJ3 pins 2 / 4preserve after reset
NRSTNRSThardware resetJ3 pin 10, R15 10 kΩ pull-up, C28do not remap
BOOT0BOOT0boot strap inputR14 10 kΩ pull-downnormal flash boot when low
All three TCAN3404-Q1 SHDN pins are hard-wired to GND. Firmware controls only STB.
Toolchain
  • STM32CubeMX / STM32CubeIDE with STM32CubeH7 HAL and USB Device middleware.
  • Target: STM32H725ZGT6, LQFP144.
  • GCC example: arm-none-eabi-gcc; use CubeIDE generated linker/startup files for STM32H725ZG.
  • Start from a CubeMX-generated project so startup, linker script, CMSIS, HAL, IRQ vectors, and USB middleware are generated consistently.
CubeMX configuration
  1. Enable SYS → Serial Wire. Do not enable trace/SWO because PB3 is CAN2 standby.
  2. Configure FDCAN1 PD0/PD1 AF9, FDCAN2 PB5/PB6 AF9, FDCAN3 PD12/PD13 AF5.
  3. Configure PG11, PB3, PD7 as push-pull outputs, initially high (transceivers safely in standby), no pull, low speed.
  4. Configure PE2/PE3/PE4 as push-pull outputs, initially high (LEDs off), no pull, low speed.
  5. Enable USB_OTG_HS in Device_Only, internal FS PHY, Full Speed. PA11/PA12 are the live USB pair. Because the dedicated OTG VBUS-sense pin is not connected in the schematic, disable peripheral VBUS sensing and, if required by the application, monitor PA0 through ADC1.
  6. Enable USB Device middleware (CDC is suitable for smoke testing; panda integration must use panda-compatible descriptors/classes).
  7. Use HSI as the initial system source and HSI48 for USB unless a populated external clock is later proven; PH0/PH1 and PC14/PC15 are unconnected in the live schematic. Select a legal FDCAN kernel clock in CubeMX and verify the generated nominal/data timing against the intended bus. The three FDCAN instances share 10 KiB message RAM, so let one CubeMX project allocate all instances and review offsets for overlap.
  8. Enable FDCAN RX FIFO0 and error/status interrupts for all three instances.
Compilable board I/O module
Add these files to a CubeMX HAL project. They depend only on generated STM32H7 HAL headers.

C


/* board_io.h */
#pragma once
#include "stm32h7xx_hal.h"

typedef enum { BOARD_CAN1 = 0, BOARD_CAN2 = 1, BOARD_CAN3 = 2 } board_can_t;
typedef enum { BOARD_LED_RED = 0, BOARD_LED_GREEN = 1, BOARD_LED_BLUE = 2 } board_led_t;

void BoardIO_Init(void);
void Board_CAN_Standby(board_can_t can, GPIO_PinState standby);
void Board_LED_Write(board_led_t led, GPIO_PinState on);
void Board_LED_Toggle(board_led_t led);

C


/* board_io.c */
#include "board_io.h"

static GPIO_TypeDef *const stb_port[3] = {GPIOG, GPIOB, GPIOD};
static const uint16_t stb_pin[3] = {GPIO_PIN_11, GPIO_PIN_3, GPIO_PIN_7};
static GPIO_TypeDef *const led_port[3] = {GPIOE, GPIOE, GPIOE};
static const uint16_t led_pin[3] = {GPIO_PIN_4, GPIO_PIN_3, GPIO_PIN_2};

void BoardIO_Init(void) {
  GPIO_InitTypeDef g = {0};
  __HAL_RCC_GPIOB_CLK_ENABLE();
  __HAL_RCC_GPIOD_CLK_ENABLE();
  __HAL_RCC_GPIOE_CLK_ENABLE();
  __HAL_RCC_GPIOG_CLK_ENABLE();

  /* Safe states before changing pin mode: CAN standby asserted, LEDs off. */
  HAL_GPIO_WritePin(GPIOG, GPIO_PIN_11, GPIO_PIN_SET);
  HAL_GPIO_WritePin(GPIOB, GPIO_PIN_3, GPIO_PIN_SET);
  HAL_GPIO_WritePin(GPIOD, GPIO_PIN_7, GPIO_PIN_SET);
  HAL_GPIO_WritePin(GPIOE, GPIO_PIN_2|GPIO_PIN_3|GPIO_PIN_4, GPIO_PIN_SET);

  g.Mode = GPIO_MODE_OUTPUT_PP; g.Pull = GPIO_NOPULL; g.Speed = GPIO_SPEED_FREQ_LOW;
  g.Pin = GPIO_PIN_11; HAL_GPIO_Init(GPIOG, &g);
  g.Pin = GPIO_PIN_3;  HAL_GPIO_Init(GPIOB, &g);
  g.Pin = GPIO_PIN_7;  HAL_GPIO_Init(GPIOD, &g);
  g.Pin = GPIO_PIN_2|GPIO_PIN_3|GPIO_PIN_4; HAL_GPIO_Init(GPIOE, &g);
}

void Board_CAN_Standby(board_can_t can, GPIO_PinState standby) {
  if ((unsigned)can < 3U) HAL_GPIO_WritePin(stb_port[can], stb_pin[can], standby);
}

void Board_LED_Write(board_led_t led, GPIO_PinState on) {
  if ((unsigned)led < 3U)
    HAL_GPIO_WritePin(led_port[led], led_pin[led], on == GPIO_PIN_SET ? GPIO_PIN_RESET : GPIO_PIN_SET);
}

void Board_LED_Toggle(board_led_t led) {
  if ((unsigned)led < 3U) HAL_GPIO_TogglePin(led_port[led], led_pin[led]);
}
HAL FDCAN startup and test transmit
CubeMX must generate hfdcan1, hfdcan2, hfdcan3 and their MX_FDCANx_Init() functions. The following code compiles against the STM32CubeH7 HAL and keeps transceivers in standby until every controller starts.

C


#include "main.h"
#include "fdcan.h"
#include "usb_device.h"
#include "board_io.h"

static FDCAN_HandleTypeDef *const canh[3] = {&hfdcan1, &hfdcan2, &hfdcan3};

static void CAN_Fatal(void) { Error_Handler(); }

static void CAN_StartAll(void) {
  FDCAN_FilterTypeDef f = {0};
  f.IdType = FDCAN_STANDARD_ID;
  f.FilterIndex = 0;
  f.FilterType = FDCAN_FILTER_MASK;
  f.FilterConfig = FDCAN_FILTER_TO_RXFIFO0;
  f.FilterID1 = 0;
  f.FilterID2 = 0;

  for (unsigned i = 0; i < 3; ++i) {
    if (HAL_FDCAN_ConfigFilter(canh[i], &f) != HAL_OK) CAN_Fatal();
    if (HAL_FDCAN_ConfigGlobalFilter(canh[i], FDCAN_ACCEPT_IN_RX_FIFO0,
        FDCAN_ACCEPT_IN_RX_FIFO0, FDCAN_REJECT_REMOTE, FDCAN_REJECT_REMOTE) != HAL_OK) CAN_Fatal();
    if (HAL_FDCAN_ActivateNotification(canh[i],
        FDCAN_IT_RX_FIFO0_NEW_MESSAGE | FDCAN_IT_BUS_OFF, 0) != HAL_OK) CAN_Fatal();
    if (HAL_FDCAN_Start(canh[i]) != HAL_OK) CAN_Fatal();
  }
  Board_CAN_Standby(BOARD_CAN1, GPIO_PIN_RESET);
  Board_CAN_Standby(BOARD_CAN2, GPIO_PIN_RESET);
  Board_CAN_Standby(BOARD_CAN3, GPIO_PIN_RESET);
}

static HAL_StatusTypeDef CAN_Send(unsigned channel, uint32_t id,
                                  const uint8_t *data, uint32_t bytes) {
  static const uint32_t dlc[9] = {FDCAN_DLC_BYTES_0,FDCAN_DLC_BYTES_1,FDCAN_DLC_BYTES_2,
    FDCAN_DLC_BYTES_3,FDCAN_DLC_BYTES_4,FDCAN_DLC_BYTES_5,FDCAN_DLC_BYTES_6,
    FDCAN_DLC_BYTES_7,FDCAN_DLC_BYTES_8};
  if (channel >= 3U || bytes > 8U) return HAL_ERROR;
  FDCAN_TxHeaderTypeDef h = {0};
  h.Identifier=id; h.IdType=FDCAN_STANDARD_ID; h.TxFrameType=FDCAN_DATA_FRAME;
  h.DataLength=dlc[bytes]; h.ErrorStateIndicator=FDCAN_ESI_ACTIVE;
  h.BitRateSwitch=FDCAN_BRS_OFF; h.FDFormat=FDCAN_CLASSIC_CAN;
  h.TxEventFifoControl=FDCAN_NO_TX_EVENTS; h.MessageMarker=0;
  return HAL_FDCAN_AddMessageToTxFifoQ(canh[channel], &h, (uint8_t *)data);
}
Call order in generated main.c:

C


HAL_Init();
SystemClock_Config();
BoardIO_Init();                 /* safe standby and LED states first */
MX_FDCAN1_Init();
MX_FDCAN2_Init();
MX_FDCAN3_Init();
MX_USB_DEVICE_Init();
CAN_StartAll();
For CAN-FD/BRS, update CubeMX nominal/data timing from measured kernel clock and network requirements, set FrameFormat = FDCAN_FRAME_FD_BRS, use legal FD DLC values, and set FDFormat=FDCAN_FD_CAN, BitRateSwitch=FDCAN_BRS_ON. Do not copy example timing constants without calculation.
Reset, boot, and recovery
  • Normal boot: BOOT0 is held low by R14; program flash through J3 SWD.
  • Recovery: assert J3 NRST while connecting ST-LINK; use “connect under reset.” BOOT0 has no user connector in the live schematic, so any forced ROM boot requires controlled access to the BOOT0 net/test point and must not be improvised on a vehicle.
  • Keep PA13/PA14 in SWD mode in early builds. PB3 cannot be SWO because it controls CAN2 standby.
  • On watchdog, hard fault, or initialization failure: command all STB pins high before entering a safe loop when GPIO state is still controllable.
Validation before panda integration
  1. Confirm all LEDs off at reset, then active-low color walk.
  2. Confirm each STB pin starts high and falls only after its FDCAN instance starts.
  3. Use internal controller loopback first, then external two-node CAN-FD tests on channels 1–3.
  4. Enumerate USB FS with temporary CDC, then replace with official panda-compatible USB descriptors/protocol.
  5. Record exact CubeMX version, HAL package version, clock tree, FDCAN timings, and message-RAM allocation in source control.
  • Scope and compatibility target

  • Live pin map

  • Toolchain

  • CubeMX configuration

  • Compilable board I/O module

  • HAL FDCAN startup and test transmit

  • Reset, boot, and recovery

  • Validation before panda integration

Assets

Assets are files uploaded to this project which can be used in various ways.

Red Panda Compatible CAN-FD Interface thumbnail
Automotive USB-C interface based on STM32H725 with three CAN-FD channels, Red Panda-compatible firmware behavior, harness connector, power protection, and connector placement.

Properties

Pricing & Availability

Distributor

Qty 1

Arrow

$15.46–$19.69

Digi-Key

$2.72–$2.92

HQonline

$2.56–$2.73

LCSC

$18.44–$19.00

Mouser

$28.64

TME

$18.00

Verical

$11.09–$22.32

Controls