CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-python-can

Controller Area Network interface module for Python providing common abstractions for CAN hardware devices and message handling utilities

Pending
Overview
Eval results
Files

bit-timing.mddocs/

Bit Timing Configuration

CAN bit timing calculation and configuration utilities for both CAN 2.0 and CAN FD, supporting various calculation methods including sample point-based timing, register-based configuration, and bitrate-based parameter calculation.

Capabilities

CAN 2.0 Bit Timing

Configure bit timing parameters for standard CAN 2.0 communication.

class BitTiming:
    def __init__(self, f_clock: int, brp: int, tseg1: int, tseg2: int, sjw: int, 
                 nof_samples: int = 1, strict: bool = False):
        """
        Create CAN 2.0 bit timing configuration.
        
        Parameters:
        - f_clock: CAN system clock frequency in Hz
        - brp: Bit rate prescaler (1-1024)
        - tseg1: Time segment 1 (number of quanta from sync to sampling point)
        - tseg2: Time segment 2 (number of quanta from sampling point to end)
        - sjw: Synchronization jump width (1 to min(4, tseg1, tseg2))
        - nof_samples: Number of samples (1 or 3)
        - strict: If True, raise exceptions for invalid parameters
        """
    
    @classmethod
    def from_bitrate_and_segments(cls, f_clock: int, bitrate: int, tseg1: int, 
                                 tseg2: int, sjw: int, nof_samples: int = 1):
        """
        Create bit timing from bitrate and time segments.
        
        Parameters:
        - f_clock: CAN system clock frequency in Hz
        - bitrate: Desired bit rate in bits per second
        - tseg1: Time segment 1 in quanta
        - tseg2: Time segment 2 in quanta  
        - sjw: Synchronization jump width in quanta
        - nof_samples: Number of samples per bit
        
        Returns:
        BitTiming instance with calculated prescaler
        """
    
    @classmethod
    def from_registers(cls, f_clock: int, btr0: int, btr1: int):
        """
        Create bit timing from BTR register values.
        
        Parameters:
        - f_clock: CAN system clock frequency in Hz
        - btr0: Bus Timing Register 0 value
        - btr1: Bus Timing Register 1 value
        
        Returns:
        BitTiming instance decoded from register values
        """
    
    @classmethod
    def from_sample_point(cls, f_clock: int, bitrate: int, sample_point: float):
        """
        Calculate bit timing for desired sample point percentage.
        
        Parameters:
        - f_clock: CAN system clock frequency in Hz
        - bitrate: Desired bit rate in bits per second
        - sample_point: Desired sample point as percentage (e.g., 75.0 for 75%)
        
        Returns:
        BitTiming instance with calculated parameters
        """

CAN FD Bit Timing

Configure bit timing for CAN FD with separate arbitration and data phase parameters.

class BitTimingFd:
    def __init__(self, f_clock: int, nom_brp: int, nom_tseg1: int, nom_tseg2: int,
                 nom_sjw: int, data_brp: int, data_tseg1: int, data_tseg2: int,
                 data_sjw: int, nom_sam: bool = False):
        """
        Create CAN FD bit timing configuration.
        
        Parameters:
        - f_clock: CAN system clock frequency in Hz
        - nom_brp: Nominal (arbitration) bit rate prescaler
        - nom_tseg1: Nominal time segment 1
        - nom_tseg2: Nominal time segment 2
        - nom_sjw: Nominal synchronization jump width
        - data_brp: Data phase bit rate prescaler
        - data_tseg1: Data phase time segment 1
        - data_tseg2: Data phase time segment 2
        - data_sjw: Data phase synchronization jump width
        - nom_sam: Nominal phase sampling (False=1 sample, True=3 samples)
        """
    
    @classmethod
    def from_bitrates_and_sample_points(cls, f_clock: int, nom_bitrate: int, 
                                       data_bitrate: int, nom_sample_point: float,
                                       data_sample_point: float):
        """
        Calculate CAN FD timing from bitrates and sample points.
        
        Parameters:
        - f_clock: System clock frequency in Hz
        - nom_bitrate: Nominal (arbitration) phase bitrate
        - data_bitrate: Data phase bitrate
        - nom_sample_point: Nominal phase sample point percentage
        - data_sample_point: Data phase sample point percentage
        
        Returns:
        BitTimingFd instance with calculated parameters
        """

Bit Timing Properties

Access calculated timing properties and register values.

# BitTiming properties
@property
def bitrate(self) -> int:
    """Calculated bitrate in bits per second."""

@property
def sample_point(self) -> float:
    """Sample point as percentage of bit time."""

@property
def btr0(self) -> int:
    """Bus Timing Register 0 value."""

@property  
def btr1(self) -> int:
    """Bus Timing Register 1 value."""

@property
def tseg(self) -> int:
    """Total time segments (tseg1 + tseg2)."""

# Dictionary-like access
def __getitem__(self, key: str):
    """Access timing parameters as dictionary keys."""

def keys(self):
    """Get available parameter keys."""

def values(self):
    """Get parameter values."""

def items(self):
    """Get parameter key-value pairs."""

Usage Examples

Basic Bit Timing Configuration

import can

# Create bit timing for 500 kbps with 8 MHz clock
timing = can.BitTiming(
    f_clock=8_000_000,    # 8 MHz clock
    brp=1,                # Prescaler = 1
    tseg1=13,             # Time segment 1 = 13 quanta
    tseg2=2,              # Time segment 2 = 2 quanta  
    sjw=1                 # SJW = 1 quantum
)

print(f"Configured bitrate: {timing.bitrate} bps")
print(f"Sample point: {timing.sample_point:.1f}%")
print(f"BTR registers: BTR0=0x{timing.btr0:02X}, BTR1=0x{timing.btr1:02X}")

Calculate from Bitrate and Sample Point

import can

# Calculate timing for 1 Mbps with 87.5% sample point
timing = can.BitTiming.from_sample_point(
    f_clock=16_000_000,   # 16 MHz clock
    bitrate=1_000_000,    # 1 Mbps
    sample_point=87.5     # 87.5% sample point
)

print(f"Calculated parameters:")
print(f"  BRP: {timing['brp']}")
print(f"  TSEG1: {timing['tseg1']}")  
print(f"  TSEG2: {timing['tseg2']}")
print(f"  SJW: {timing['sjw']}")
print(f"Actual bitrate: {timing.bitrate} bps")
print(f"Actual sample point: {timing.sample_point:.1f}%")

CAN FD Bit Timing

import can

# CAN FD with 500 kbps arbitration, 2 Mbps data phase
fd_timing = can.BitTimingFd(
    f_clock=40_000_000,   # 40 MHz clock
    # Nominal (arbitration) phase - 500 kbps
    nom_brp=5,
    nom_tseg1=13,
    nom_tseg2=2,
    nom_sjw=1,
    # Data phase - 2 Mbps
    data_brp=1,
    data_tseg1=15,
    data_tseg2=4,
    data_sjw=1
)

print(f"Arbitration phase: {fd_timing.nom_bitrate} bps")
print(f"Data phase: {fd_timing.data_bitrate} bps")
print(f"Speed improvement: {fd_timing.data_bitrate / fd_timing.nom_bitrate:.1f}x")

Multiple Standard Bitrates

import can

# Common CAN bitrates with 8 MHz clock
standard_configs = {
    '125k': can.BitTiming(f_clock=8_000_000, brp=4, tseg1=13, tseg2=2, sjw=1),
    '250k': can.BitTiming(f_clock=8_000_000, brp=2, tseg1=13, tseg2=2, sjw=1),
    '500k': can.BitTiming(f_clock=8_000_000, brp=1, tseg1=13, tseg2=2, sjw=1),
    '1M':   can.BitTiming(f_clock=8_000_000, brp=1, tseg1=5, tseg2=2, sjw=1)
}

print("Standard CAN bitrate configurations:")
for name, timing in standard_configs.items():
    print(f"{name:>4}: {timing.bitrate:>7} bps, "
          f"SP={timing.sample_point:4.1f}%, "
          f"BTR0=0x{timing.btr0:02X}, BTR1=0x{timing.btr1:02X}")

Bit Timing Validation

import can

def validate_timing(timing, target_bitrate, tolerance=0.01):
    """Validate bit timing against target bitrate."""
    actual_rate = timing.bitrate
    error = abs(actual_rate - target_bitrate) / target_bitrate
    
    print(f"Target: {target_bitrate} bps")
    print(f"Actual: {actual_rate} bps")
    print(f"Error: {error * 100:.3f}%")
    
    if error <= tolerance:
        print("✓ Timing within tolerance")
        return True
    else:
        print("✗ Timing exceeds tolerance")
        return False

# Test different configurations
configs_to_test = [
    (8_000_000, 500_000, {'brp': 1, 'tseg1': 13, 'tseg2': 2, 'sjw': 1}),
    (10_000_000, 250_000, {'brp': 5, 'tseg1': 6, 'tseg2': 1, 'sjw': 1}),
    (16_000_000, 1_000_000, {'brp': 1, 'tseg1': 13, 'tseg2': 2, 'sjw': 1})
]

for f_clock, target_rate, params in configs_to_test:
    print(f"\nTesting {f_clock/1e6:.0f} MHz clock, {target_rate/1000:.0f} kbps:")
    timing = can.BitTiming(f_clock=f_clock, **params)
    validate_timing(timing, target_rate)

Using Bit Timing with Bus

import can

# Calculate optimal timing for hardware
timing = can.BitTiming.from_sample_point(
    f_clock=16_000_000,
    bitrate=500_000,
    sample_point=80.0
)

# Use timing parameters with bus (example for socketcan)
bus = can.Bus(
    channel='can0',
    interface='socketcan',
    # Note: Most interfaces handle timing automatically
    # This is conceptual - actual parameter names vary by interface
    bitrate=timing.bitrate
)

print(f"Bus configured for {timing.bitrate} bps")
bus.shutdown()

Register-Based Configuration

import can

# Create timing from existing BTR register values
# (e.g., read from hardware or configuration file)
timing_from_regs = can.BitTiming.from_registers(
    f_clock=8_000_000,
    btr0=0x00,  # BRP-1 in lower 6 bits, SJW-1 in upper 2 bits
    btr1=0xDE   # TSEG1-1 in lower 4 bits, TSEG2-1 in upper 3 bits, SAM in bit 7
)

print(f"Decoded from registers:")
print(f"  Bitrate: {timing_from_regs.bitrate} bps")
print(f"  BRP: {timing_from_regs['brp']}")
print(f"  TSEG1: {timing_from_regs['tseg1']}")
print(f"  TSEG2: {timing_from_regs['tseg2']}")

Types

from typing import Union, Dict, Any
from collections.abc import Mapping

class BitTiming(Mapping[str, int]):
    """CAN 2.0 bit timing configuration with dictionary-like access."""
    
    def __init__(self, f_clock: int, brp: int, tseg1: int, tseg2: int, 
                 sjw: int, nof_samples: int = 1, strict: bool = False): ...
    
    # Properties
    f_clock: int
    brp: int
    tseg1: int
    tseg2: int  
    sjw: int
    nof_samples: int
    
    @property
    def bitrate(self) -> int: ...
    @property
    def sample_point(self) -> float: ...
    @property
    def btr0(self) -> int: ...
    @property
    def btr1(self) -> int: ...

class BitTimingFd:
    """CAN FD bit timing configuration with dual-phase parameters."""
    
    def __init__(self, f_clock: int, nom_brp: int, nom_tseg1: int, 
                 nom_tseg2: int, nom_sjw: int, data_brp: int, 
                 data_tseg1: int, data_tseg2: int, data_sjw: int,
                 nom_sam: bool = False): ...
    
    # Properties for both phases
    @property
    def nom_bitrate(self) -> int: ...
    @property
    def data_bitrate(self) -> int: ...
    @property
    def nom_sample_point(self) -> float: ...
    @property
    def data_sample_point(self) -> float: ...

Install with Tessl CLI

npx tessl i tessl/pypi-python-can

docs

bit-timing.md

bus-operations.md

cli-tools.md

event-system.md

file-io.md

hardware-interfaces.md

index.md

message-handling.md

periodic-transmission.md

tile.json