The table below lists valid combinations of Prescaler and Time Segments to achieve the target baud rate. The rows are sorted by Sample Point proximity to 87.5% (industry standard).
Prescaler
Total Tq
Time Seg 1 (BS1)
Time Seg 2 (BS2)
Sample Point
SJW (Max)
Register Values (BS1/BS2)
Understanding STM32 CAN Timing and Baud Rate Calculation
Configuring the Controller Area Network (CAN) peripheral on STM32 microcontrollers requires a precise understanding of the APB1 clock bus and the bit timing logic. Unlike simple UART, CAN bus timing involves splitting a single bit time into discrete "Time Quanta" ($t_q$) to ensure synchronization and error checking across the network.
Core Formulas
The baud rate is derived from the peripheral clock input ($f_{APB1}$) and the Bit Timing Register (CAN_BTR) settings. The fundamental formula is:
Baud Rate = $f_{APB1}$ / (Prescaler × Total Time Quanta)
Where:
Prescaler: A divider (1 to 1024) that scales the APB1 clock to generate the Time Quantum clock.
Total Time Quanta: The number of $t_q$ units that make up one bit duration. This is calculated as:
Total Tq = 1 (Sync_Seg) + BS1 + BS2
Bit Segments (BS1 and BS2)
The STM32 CAN hardware divides the bit time into three distinct sections:
Bit Segment 1 (BS1): Combines the propagation segment and phase segment 1. Configurable from 1 to 16 $t_q$.
Bit Segment 2 (BS2): Phase segment 2. Configurable from 1 to 8 $t_q$.
The Importance of the Sample Point
The Sample Point is the specific moment within the bit time when the bus level is read and interpreted as logical 0 or 1. It is crucial for network stability, especially with long cable lengths.
For most protocols (like CANopen or DeviceNet), a sample point between 75% and 87.5% is recommended. The calculator above prioritizes configurations that yield a sample point closest to 87.5%.
Register Configuration (HAL & LL)
When programming the STM32 (e.g., using STM32CubeIDE), note that the register values are often 0-indexed:
function calculateCAN() {
var apbInput = document.getElementById('apbClock');
var baudInput = document.getElementById('targetBaud');
var resultsArea = document.getElementById('results-area');
var resultsBody = document.getElementById('resultsBody');
// Parse inputs
var apbClockMHz = parseFloat(apbInput.value);
var targetBaudKbps = parseFloat(baudInput.value);
// Validation
if (isNaN(apbClockMHz) || apbClockMHz <= 0 || isNaN(targetBaudKbps) || targetBaudKbps = 8 for stability.
// Max Tq = 1 (Sync) + 16 (BS1_Max) + 8 (BS2_Max) = 25.
for (var totalTq = 4; totalTq Prescaler = PCLK / (Baud * TotalTq)
var prescalerCalc = pclk / (baud * totalTq);
// Check if Prescaler is an integer and within valid range (1 to 1024)
// We use a small epsilon for float comparison just in case, though usually exact division is needed.
if (Math.abs(prescalerCalc – Math.round(prescalerCalc)) = 1 && prescaler <= 1024) {
// Valid Prescaler found. Now calculate BS1 and BS2.
// Constraint: TotalTq = 1 + BS1 + BS2
// Constraint: 1 <= BS1 <= 16
// Constraint: 1 <= BS2 <= 8
var tqRemaining = totalTq – 1; // Subtract Sync Seg
// Iterate possible BS2 values to find optimal Sample Point
for (var bs2 = 1; bs2 = 1 && bs1 <= 16) {
// Valid combination found
var samplePoint = (1 + bs1) / totalTq;
// SJW is typically min(4, BS1, BS2) but usually set to 1 or higher based on clock tolerance.
// We will calculate max possible SJW based on standard limits (up to 4)
var maxSJW = Math.min(4, bs2);
solutions.push({
prescaler: prescaler,
totalTq: totalTq,
bs1: bs1,
bs2: bs2,
samplePoint: samplePoint * 100,
maxSJW: maxSJW
});
}
}
}
}
}
// Sort solutions: Closest to 87.5% sample point is best
solutions.sort(function(a, b) {
var diffA = Math.abs(a.samplePoint – 87.5);
var diffB = Math.abs(b.samplePoint – 87.5);
return diffA – diffB;
});
// Display Results
resultsBody.innerHTML = "";
if (solutions.length === 0) {
resultsBody.innerHTML = "
No exact integer configuration found. Try adjusting the APB1 clock slightly.
";
} else {
// Show top 5 solutions or all if fewer
var count = Math.min(solutions.length, 10);
for (var i = 0; i < count; i++) {
var sol = solutions[i];
var rowClass = (i === 0) ? "best-match" : "";
var row = "