CAN Bus Bit Timing Calculator

Calculate CAN and CAN-FD BTR/NBTP register values, sample point %, and sync jump width for STM32, ESP32 TWAI, and custom CAN controllers.

Configuration

Target bit rate
bps
Target sample point87.5%
50%87.5% std95%

Result

Actual bit rate

500 kbps

Bit rate error

< 0.01%

Sample point

85.7%

Time quanta / bit

14 TQ

Timing detail

TQ duration142.9 ns
Bit time2.000 µs
BRP (prescaler)6
SJW2 TQ

STM32 BTR register fields

BRP (reg)5 (prescaler = 6)
TS1 (reg)10 (BS1 = 11 TQ)
TS2 (reg)1 (BS2 = 2 TQ)
SJW (reg)1 (SJW = 2 TQ)

BTR register value

0x011A0005

C register snippet

/* STM32 Classic CAN BTR register */
CAN1->BTR = 0x011A0005;
/* BRP=5, TS1=10, TS2=1, SJW=1 */

Bit time structure

SYNCBS111 TQBS22 TQSP 85.7%

1 TQ = 142.9 ns  |  bit time = 14 TQ = 2.000 µs

Standard bit rates — STM32F4 (42 MHz)

Bit rateBRPBS1BS2N_TQSample ptErrorBTR[15:0]
125 kbps4261887.5%0x00050029
250 kbps2161887.5%0x00050014
500 kbps61121485.7%0x011A0005
1 Mbps31121485.7%0x011A0002

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):

BitsFieldValue written
[9:0]BRPprescaler − 1 (0 = ÷1)
[19:16]TS1BS1 − 1 (0 = 1 TQ)
[22:20]TS2BS2 − 1 (0 = 1 TQ)
[25:24]SJWSJW − 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):

BitsFieldDescription
[24:16]NSJWNominal SJW − 1 (up to 128 TQ)
[15:8]NTSEG1Nominal BS1 − 1 (up to 256 TQ)
[6:0]NTSEG2Nominal BS2 − 1 (up to 128 TQ)
[31:25]NBRPNominal 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.

Frequently asked questions

What is the CAN sample point and why is 87.5% the standard? +

The sample point is where in the bit period the receiver reads the bus level, expressed as a percentage of the total bit time. 87.5% (7/8 of the way through the bit) is the CiA 601 default because it gives maximum tolerance for propagation delay while still leaving enough time in BS2 for resynchronisation. Networks with long cable runs or many nodes may need to reduce to 75–80% to accommodate the increased propagation delay. Never go below 75% or above 87.5% on a real network.

Why is CAN bit timing more complex than UART baud rate calculation? +

UART just divides a clock to produce a bit period. CAN bit timing must also place a precise sample point within that period and configure the sync jump width for resynchronisation across nodes. Every node on the bus must agree on the same bit rate AND have compatible sample points — typically within ±1 sample point location of each other. Tighter tolerances are needed because CAN uses a multi-master bus with arbitration: a node reading its own transmission must see exactly what it transmitted, and resynchronisation must happen within the SJW window.

What does SJW (sync jump width) do? +

SJW allows a CAN node to lengthen or shorten the current bit period by up to SJW time quanta to resynchronise with the bus when it detects an edge. Without SJW, clock drift between nodes would accumulate over a message frame and cause bit errors. Larger SJW gives more tolerance for clock deviation but reduces the maximum achievable bit rate for a given oscillator accuracy. A safe starting point is SJW = min(BS2, 4) TQ. ISO 11898-1 requires SJW ≤ min(BS1, BS2).

Why is my STM32 CAN not working despite correct BTR values? PCLK1 pitfall. +

The most common issue is that PCLK1 is not what you assume. On STM32F4 at 168 MHz system clock with the default CubeMX clock tree, PCLK1 is typically 42 MHz (168/4), not 168 MHz. If you calculate BTR for 168 MHz but the hardware uses 42 MHz, you will get a bit rate 4× too slow. Always verify with HAL_RCC_GetPCLK1Freq() at runtime. A second common mistake: you must set INRQ=1 in CAN_MCR before writing to BTR, then clear INRQ and wait for INAK=0 before enabling the bus. Writing BTR while the peripheral is not in initialisation mode has no effect.

Newsletter

The embedded engineer's weekly cheat sheet

Register tricks, timing gotchas, and tool updates. One email per week. No fluff.

No spam. Unsubscribe anytime.