# CAN bit timing calculator
# Input: MCU CAN clock, target baud rate, desired sample point %
def calculate_bit_timing(can_clock_hz, target_baud, sample_point_pct=80):
results = []
for prescaler in range(1, 65):
tq_ns = (1 / can_clock_hz) * prescaler * 1e9
total_tq = round(1e9 / (target_baud * tq_ns))
if not (8 <= total_tq <= 25): # practical range
continue
ph2 = round(total_tq * (1 - sample_point_pct / 100))
ph2 = max(1, min(8, ph2))
remaining = total_tq - 1 - ph2 # subtract Sync_Seg
prop = max(1, remaining // 2)
ph1 = remaining - prop
if 1 <= ph1 <= 8 and 1 <= prop <= 8:
actual_baud = 1e9 / (tq_ns * total_tq)
actual_sp = (1 + prop + ph1) / total_tq * 100
error_ppm = abs(actual_baud - target_baud) / target_baud * 1e6
results.append((prescaler, prop, ph1, ph2, actual_baud, actual_sp, error_ppm))
return sorted(results, key=lambda r: r[6]) # sort by baud error
# Example: STM32 at 42 MHz → 500 kbps
for r in calculate_bit_timing(42_000_000, 500_000)[:3]:
pre, prop, ph1, ph2, baud, sp, err = r
print(f"Prescaler={pre} Prop={prop} Ph1={ph1} Ph2={ph2} "
f"→ {baud/1000:.1f} kbps SP={sp:.1f}% error={err:.1f} ppm")
| MCU Clock | Prescaler | Prop+Ph1+Ph2 (tq) | Baud Rate | Sample Point |
|---|
| 48 MHz | 6 | 1+5+2 (8 tq per bit) | 1 Mbps | 75% |
| 48 MHz | 6 | 3+8+3 (14 tq per bit) | 571 kbps | — |
| 40 MHz | 4 | 4+7+2 (13 tq per bit + 1 sync = 10 tq total) | 1 Mbps | 80% |
| 80 MHz | 8 | 4+7+3 (14 tq per bit + 1 = 15 total) | 666 kbps | — |