The CAN bit structure
Every CAN bit is divided into time quanta (TQ). The total bit period contains three segments:
|←————————— 1 / bitrate ————————→|
| SYNC_SEG | BS1 | BS2 |
| 1 TQ | 1..16 TQ | 1..8 |
↑
Sample point
- SYNC_SEG — always 1 TQ. Bus edges are expected here.
- BS1 (Bit Segment 1, also called TSEG1) — 1 to 16 TQ. Extended during resync if the bus edge is late.
- BS2 (Bit Segment 2, also called TSEG2) — 1 to 8 TQ. Shortened during resync if the edge is early.
The relationships:
TQ duration = BRP / fCAN_CLK
N_TQ = 1 + BS1 + BS2
Bit rate = fCAN_CLK / (BRP × N_TQ)
Sample point = (1 + BS1) / N_TQ × 100%
BRP is the bit rate prescaler. On STM32, the register value is BRP_reg = BRP - 1.
Typical configuration for 500 kbps on a 42 MHz clock:
BRP = 6, BS1 = 11, BS2 = 2
N_TQ = 1 + 11 + 2 = 14
Bit rate = 42,000,000 / (6 × 14) = 500,000 bps ✓
Sample point = 12 / 14 × 100 = 85.7%
Sample point selection
87.5% is the CiA 601 default. It places the sample 7 TQ into an 8-TQ bit period — or equivalently, 7/8 of the way through. This leaves BS2 = 1 TQ minimum, which is tight but workable on short, low-node-count networks.
On a 1 Mbit/s network with 40-metre cable and 30 nodes, propagation delay alone can eat 400–600 ns of the 1,000 ns bit period. At that point, an 87.5% sample point leaves insufficient margin. Drop to 75–80%.
J1939 (the dominant industrial CAN standard) mandates 87.5% at all bit rates. Stick with it unless you have a specific reason to deviate — mixing sample points across nodes degrades timing margin for every node on the network.
Practical guidance:
- Short bus (< 5 m), few nodes: 87.5% is fine up to 1 Mbps.
- Long bus or high node count: Use the propagation delay formula from ISO 11898-1 to verify.
- CAN FD data phase: Sample point 70–80% is common at 2–5 Mbps.
- Never below 50%: Below 50%, you’re sampling closer to the previous bit than the current one.
STM32 Classic CAN: BTR register
STM32F1/F2/F4 use the CAN_BTR register (offset 0x1C from the CAN base):
| Bits | Field | Value written |
|---|---|---|
| [9:0] | BRP | prescaler − 1 (0 = ÷1) |
| [19:16] | TS1 | BS1 − 1 (0 = 1 TQ) |
| [22:20] | TS2 | BS2 − 1 (0 = 1 TQ) |
| [25:24] | SJW | SJW − 1 (0 = 1 TQ) |
Direct register write (bare metal, no HAL):
/* Enter initialisation mode */
CAN1->MCR |= CAN_MCR_INRQ;
while (!(CAN1->MSR & CAN_MSR_INAK)); /* wait for INAK=1 */
/* 500 kbps, 85.7% SP, 42 MHz PCLK1: BRP=6, TS1=10, TS2=1, SJW=0 */
CAN1->BTR = (0U << CAN_BTR_SJW_Pos) /* SJW = 1 TQ */
| (1U << CAN_BTR_TS2_Pos) /* BS2 = 2 TQ */
| (10U << CAN_BTR_TS1_Pos) /* BS1 = 11 TQ */
| (5U << CAN_BTR_BRP_Pos); /* BRP = 6 */
/* Leave initialisation mode */
CAN1->MCR &= ~CAN_MCR_INRQ;
while (CAN1->MSR & CAN_MSR_INAK); /* wait for INAK=0 */
If you write BTR while INRQ is not set, the register write is silently ignored. This is the most common CAN initialisation bug.
With STM32 HAL, set the fields in hcan.Init before calling HAL_CAN_Init():
hcan1.Init.Prescaler = 6;
hcan1.Init.TimeSeg1 = CAN_BS1_11TQ;
hcan1.Init.TimeSeg2 = CAN_BS2_2TQ;
hcan1.Init.SyncJumpWidth = CAN_SJW_1TQ;
STM32 FDCAN: NBTP register
STM32G0/G4/H7 peripherals use FDCAN, which replaces the BTR register with FDCAN_NBTP (nominal bit timing and prescaler):
| Bits | Field | Description |
|---|---|---|
| [24:16] | NSJW | Nominal SJW − 1 (up to 128 TQ) |
| [15:8] | NTSEG1 | Nominal BS1 − 1 (up to 256 TQ) |
| [6:0] | NTSEG2 | Nominal BS2 − 1 (up to 128 TQ) |
| [31:25] | NBRP | Nominal BRP − 1 (up to 512) |
FDCAN extends the register fields significantly — BS1 up to 256 TQ and BRP up to 512 — which allows very low bit rates from high-frequency clocks. The configuration procedure requires writing to FDCAN registers while CCCR.INIT = 1 and CCCR.CCE = 1:
/* Enter configuration mode */
FDCAN1->CCCR |= FDCAN_CCCR_INIT;
while (!(FDCAN1->CCCR & FDCAN_CCCR_INIT));
FDCAN1->CCCR |= FDCAN_CCCR_CCE;
/* 500 kbps, 64 MHz FDCAN clock: NBRP=4, NTSEG1=13, NTSEG2=2, NSJW=1 */
FDCAN1->NBTP = (0U << FDCAN_NBTP_NSJW_Pos) /* SJW = 1 TQ */
| (13U << FDCAN_NBTP_NTSEG1_Pos) /* BS1 = 14 TQ */
| (2U << FDCAN_NBTP_NTSEG2_Pos) /* BS2 = 3 TQ */
| (3U << FDCAN_NBTP_NBRP_Pos); /* BRP = 4 */
/* Leave configuration mode */
FDCAN1->CCCR &= ~FDCAN_CCCR_CCE;
FDCAN1->CCCR &= ~FDCAN_CCCR_INIT;
For CAN FD data phase timing, configure FDCAN_DBTP in the same initialisation window.
CAN clock source pitfalls on STM32
PCLK1 is not always what you think. The CAN peripheral on STM32F4 is clocked from PCLK1. At 168 MHz system clock with the default CubeMX configuration, PCLK1 = 42 MHz (168/4). If you calculate BTR for 168 MHz but the hardware runs at 42 MHz, the actual bit rate will be 4× too slow.
Verify at runtime:
uint32_t pclk1 = HAL_RCC_GetPCLK1Freq();
/* Should match your calculator input */
FDCAN clock source on STM32G0/G4/H7 is configurable independently from PCLK1. In CubeMX, check the FDCAN kernel clock mux — it can be sourced from PCLK1, PLL1Q, or HSE directly. The HAL_RCCEx_GetPeriphCLKConfig() API returns the actual source. Getting this wrong is the most frequent root cause of FDCAN not working after migration from a Classic CAN project.
STM32H7 dual-core clock tree: On H7, FDCAN1/2 are on the D2 domain. If you configure clocks for the D1 domain but forget to set up D2 clocks, FDCAN gets a default (often very slow) clock.
Common mistakes
Wrong PCLK1. Enter the wrong clock frequency and every calculated BTR value is wrong. Verify with HAL_RCC_GetPCLK1Freq() early in your main() and assert it matches what you expect.
Not entering initialisation mode before writing BTR. You must set INRQ in CAN_MCR and wait for INAK in CAN_MSR to go high. Writes to BTR while INAK = 0 are silently discarded.
Sample point outside 75–90%. Too low and you’re sampling partially into the previous bit. Too high and there is insufficient time in BS2 for resynchronisation, which causes bit errors under any bus clock drift.
SJW too small. Setting SJW = 1 TQ works on a bench with a single node but fails in production when clock oscillators are at their tolerance extremes (±0.5% on cheap ceramics). Use SJW = min(BS2, 4) TQ as a baseline.
Mismatched sample points across nodes. All nodes on a CAN network do not need identical BTR values — they just need the same bit rate and compatible sample points. A node with an 80% sample point and another at 87.5% can coexist if the 7.5% difference falls within the propagation delay budget. But mixing 65% and 90% on the same network guarantees sporadic errors under any realistic cable length.
Not accounting for oscillator accuracy. The total CAN error budget from ISO 11898-1 is ±1.58% of the bit period. A 20 ppm crystal contributes essentially nothing; a ±1% ceramic resonator (cheap STM32 board without a crystal) is already at 63% of the budget before any other source of error. Use a crystal for CAN networks.