class CAN – bus di comunicazione controller area network

CAN implementa il supporto sia per il CAN classico (bxCAN, usato sulle OpenMV Cam M4 e M7) sia per il CAN FD (FDCAN, usato sulle OpenMV Cam H7, H7 Plus e Pure Thermal). A livello fisico il bus CAN è costituito da due linee, RX e TX. Per collegare una OpenMV Cam a un bus CAN è necessario usare un transceiver CAN per convertire i segnali logici CAN dell’MCU ai corretti livelli di tensione sul bus.

CAN classico in modalità loopback (senza transceiver):

from pyb import CAN

can = CAN(1, CAN.LOOPBACK)

# Accept messages with id 123, 124, 125 or 126.
can.setfilter(0, CAN.LIST16, 0, (123, 124, 125, 126))

can.send("message!", 123)   # send a message with id 123
can.recv(0)                 # receive a message on FIFO 0

CAN FD con tutte le funzionalità opzionali abilitate (frame FD, commutazione del bit-rate, ID di frame estesi; fase di arbitraggio a 500 kbit/s, fase dati a 1 Mbit/s):

from pyb import CAN

can = CAN(
    1,
    CAN.NORMAL,
    baudrate=500_000,
    brs_baudrate=1_000_000,
    sample_point=80,
)

# Accept any id in the range 0xFFF0 .. 0xFFFF.
can.setfilter(0, CAN.RANGE, 0, (0xFFF0, 0xFFFF))

can.send(b"a" * 64, 0xFFFF, fdf=True, brs=True, extframe=True)
can.recv(0)

Le seguenti funzioni del modulo CAN e i relativi argomenti sono disponibili sia per i controller CAN classici sia per quelli FD, salvo diversa indicazione.

Costruttori

class pyb.CAN(bus: int | str, *args, **kwargs)

Costruisce un oggetto CAN sul bus indicato (un indice intero della periferica, ad es. 1 per CAN1, 2 per CAN2). Senza parametri aggiuntivi l’oggetto viene creato ma non inizializzato (mantiene le precedenti impostazioni del bus, se presenti); se vengono forniti argomenti aggiuntivi il bus viene inizializzato. Vedere CAN.init() per i parametri disponibili.

CAN(2) è collegato agli stessi pin del header su ogni OpenMV Cam che espone pyb.CAN (M4 / M7 / H7 / H7 Plus / Pure Thermal):

Segnale

Pin del header

Note

RX

P3

TX

P2

La periferica CAN fornisce solo segnali a livello logico; è necessario un transceiver CAN esterno per pilotare un bus CAN reale.

pyb.CAN non è disponibile sulla OpenMV Cam N6.

Metodi

init(mode: int, prescaler: int = 100, *, sjw: int = 1, bs1: int = 6, bs2: int = 8, auto_restart: bool = False, baudrate: int = 0, sample_point: int = 75, num_filter_banks: int = 14, brs_sjw: int = 1, brs_bs1: int = 8, brs_bs2: int = 3, brs_baudrate: int = 0, brs_sample_point: int = 75) None

Inizializza il bus CAN con i parametri indicati:

  • mode è uno tra: NORMAL, LOOPBACK, SILENT, SILENT_LOOPBACK

  • prescaler è il valore per cui viene divisa la frequenza di clock di ingresso del CAN per generare i quanti di tempo del bit nominale. Il prescaler può assumere un valore compreso tra 1 e 1024 inclusi per il CAN classico, e tra 1 e 512 inclusi per il CAN FD.

  • sjw è la larghezza del salto di risincronizzazione in unità di quanti di tempo per i bit nominali; può assumere un valore compreso tra 1 e 4 inclusi per il CAN classico, e tra 1 e 128 inclusi per il CAN FD.

  • bs1 definisce la posizione del punto di campionamento in unità di quanti di tempo per i bit nominali; può assumere un valore compreso tra 1 e 16 inclusi per il CAN classico, e tra 2 e 256 inclusi per il CAN FD.

  • bs2 definisce la posizione del punto di trasmissione in unità di quanti di tempo per i bit nominali; può assumere un valore compreso tra 1 e 8 inclusi per il CAN classico, e tra 2 e 128 inclusi per il CAN FD.

  • auto_restart imposta se il controller tenterà automaticamente di riavviare le comunicazioni dopo essere entrato nello stato bus-off; se questo è disabilitato, allora restart() può essere usato per uscire dallo stato bus-off

  • baudrate se viene fornito un baudrate diverso da 0, questa funzione tenterà di calcolare automaticamente il tempo di bit nominale del CAN (sovrascrivendo prescaler, bs1 e bs2) che soddisfi sia il baudrate (entro lo .1%) sia il sample_point desiderato (al più vicino 1%). Per un controllo più preciso della temporizzazione CAN, impostare direttamente i parametri prescaler, bs1 e bs2.

  • sample_point specifica la posizione del campionamento del bit rispetto all’intero tempo di bit nominale, espressa come percentuale intera del tempo di bit nominale. Il valore predefinito di sample_point è 75%. Questo parametro viene ignorato a meno che baudrate non sia impostato.

  • num_filter_banks per il CAN classico, è il numero di banchi che verranno assegnati a CAN(1), i rimanenti dei 28 vengono assegnati a CAN(2).

I parametri rimanenti sono presenti solo sulle schede con supporto CAN FD, e configurano la funzionalità opzionale CAN FD Bit Rate Switch (BRS):

  • brs_prescaler è il valore per cui viene divisa la frequenza di clock di ingresso del CAN FD per generare i quanti di tempo del bit dati. Il prescaler può assumere un valore compreso tra 1 e 32 inclusi.

  • brs_sjw è la larghezza del salto di risincronizzazione in unità di quanti di tempo per i bit dati; può assumere un valore compreso tra 1 e 16 inclusi

  • brs_bs1 definisce la posizione del punto di campionamento in unità di quanti di tempo per i bit dati; può assumere un valore compreso tra 1 e 32 inclusi

  • brs_bs2 definisce la posizione del punto di trasmissione in unità di quanti di tempo per i bit dati; può assumere un valore compreso tra 1 e 16 inclusi

  • brs_baudrate se viene fornito un baudrate diverso da 0, questa funzione tenterà di calcolare automaticamente il tempo di bit dati del CAN (sovrascrivendo brs_prescaler, brs_bs1 e brs_bs2) che soddisfi sia il brs_baudrate (entro lo .1%) sia il brs_sample_point desiderato (al più vicino 1%). Per un controllo più preciso della temporizzazione BRS, impostare direttamente i parametri brs_prescaler, brs_bs1 e brs_bs2.

  • brs_sample_point specifica la posizione del campionamento del bit rispetto all’intero tempo di bit nominale, espressa come percentuale intera del tempo di bit nominale. Il valore predefinito di brs_sample_point è 75%. Questo parametro viene ignorato a meno che brs_baudrate non sia impostato.

Il quanto di tempo tq è l’unità di tempo di base per il bus CAN. tq è il valore del prescaler CAN diviso per PCLK1 (la frequenza del bus periferico interno 1); vedere pyb.freq() per determinare PCLK1.

Un singolo bit è composto dal segmento di sincronizzazione, che è sempre 1 tq. Seguono poi il segmento di bit 1, quindi il segmento di bit 2. Il punto di campionamento è dopo la fine del segmento di bit 1. Il punto di trasmissione è dopo la fine del segmento di bit 2. Il baud rate sarà 1/bittime, dove il bittime è 1 + BS1 + BS2 moltiplicato per il quanto di tempo tq.

Ad esempio, sulla OpenMV Cam H7 (PCLK1 = 100 MHz), il CAN a 250 kbps con un punto di campionamento al 75% può essere configurato come prescaler=25, sjw=1, bs1=11, bs2=4: tq = 25 / 100 MHz = 250 ns, bittime = (1 + 11 + 4) × 250 ns = 4 µs, punto di campionamento = (1 + 11) / 16 = 75%, e il baudrate è 1 / 4 µs = 250 kHz.

Vedere la sezione bxCAN / FDCAN del manuale di riferimento STM32 per l’MCU della OpenMV Cam per maggiori dettagli.

deinit() None

Spegne il bus CAN.

restart() None

Forza un riavvio software del controller CAN senza azzerarne la configurazione.

Se il controller entra nello stato bus-off non parteciperà più all’attività del bus. Se il controller non è configurato per riavviarsi automaticamente (vedere init()) allora questo metodo può essere usato per attivare un riavvio, e il controller seguirà il protocollo CAN per uscire dallo stato bus-off ed entrare nello stato di errore attivo.

state() int

Restituisce lo stato del controller. Il valore restituito può essere uno tra:

  • CAN.STOPPED – il controller è completamente spento e azzerato;

  • CAN.ERROR_ACTIVE – il controller è acceso e nello stato Error Active (sia TEC che REC sono inferiori a 96);

  • CAN.ERROR_WARNING – il controller è acceso e nello stato Error Warning (almeno uno tra TEC o REC è pari o superiore a 96);

  • CAN.ERROR_PASSIVE – il controller è acceso e nello stato Error Passive (almeno uno tra TEC o REC è pari o superiore a 128);

  • CAN.BUS_OFF – il controller è acceso ma non partecipa all’attività del bus (TEC è andato in overflow oltre 255).

info(list: list | None = None) list

Ottiene informazioni sugli stati di errore del controller e sui buffer TX e RX. Se viene fornito list allora dovrebbe essere un oggetto list con almeno 8 voci, che verranno riempite con le informazioni. Altrimenti verrà creata e riempita una nuova lista. In entrambi i casi il valore restituito dal metodo è la lista popolata.

I valori nella lista sono:

  • valore TEC

  • valore REC

  • numero di volte che il controller è entrato nello stato Error Warning (riparte da 0 dopo 65535)

  • numero di volte che il controller è entrato nello stato Error Passive (riparte da 0 dopo 65535)

  • numero di volte che il controller è entrato nello stato Bus Off (riparte da 0 dopo 65535)

  • numero di messaggi TX in attesa

  • numero di messaggi RX in attesa sulla fifo 0

  • numero di messaggi RX in attesa sulla fifo 1

setfilter(bank: int, mode: int, fifo: int, params: Tuple[int, ...], *, rtr: Tuple[bool, ...] | None = None, extframe: bool = False) None

Configura un banco di filtri:

  • bank è il banco di filtri del controller CAN classico, o l’indice di filtro CAN FD, da configurare.

  • mode è la modalità in cui deve operare il filtro, vedere le tabelle sottostanti.

  • fifo è la fifo (0 o 1) in cui un messaggio deve essere memorizzato, se viene accettato da questo filtro.

  • params è un array di valori che definisce il filtro. Il contenuto dell’array dipende dall’argomento mode.

Contenuto dell’array params per i controller CAN classico (OpenMV Cam M4 / M7):

mode

Contenuto di params

CAN.LIST16

Quattro ID a 16 bit che verranno accettati.

CAN.LIST32

Due ID a 32 bit che verranno accettati.

CAN.MASK16

Due coppie id/maschera a 16 bit, ad es. (1, 3, 4, 4). La prima coppia (1, 3) accetta tutti gli ID con bit 0 = 1 e bit 1 = 0; la seconda coppia (4, 4) accetta tutti gli ID con bit 2 = 1.

CAN.MASK32

Una coppia id/maschera a 32 bit (per il resto uguale a CAN.MASK16).

Contenuto dell’array params per i controller CAN FD (OpenMV Cam H7 / H7 Plus / Pure Thermal):

mode

Contenuto di params

CAN.RANGE

Due ID che formano un intervallo di ID accettati.

CAN.DUAL

Due ID che verranno accettati (ad es. (1, 2)).

CAN.MASK

Una coppia (id, mask) (ad es. (0x111, 0x7FF)).

  • rtr Per i controller CAN classici, è un array di valori booleani che indica se un filtro deve accettare un messaggio di richiesta di trasmissione remota. Se questo argomento non viene fornito, il valore predefinito è False per tutte le voci. La lunghezza dipende da mode:

    mode

    len(rtr)

    Note

    CAN.LIST16

    4

    CAN.LIST32

    2

    CAN.MASK16

    2

    CAN.MASK32

    1

    Per il CAN FD questo argomento viene ignorato.

  • extframe Se True il frame avrà un identificatore esteso (29 bit), altrimenti viene usato un identificatore standard (11 bit).

clearfilter(bank: int, extframe: bool = False) None

Cancella e disabilita un banco di filtri:

  • bank è il banco di filtri del controller CAN classico, o l’indice di filtro CAN FD, da cancellare.

  • extframe Per i controller CAN FD, se True, cancella un filtro esteso (configurato con extframe=True), altrimenti cancella un identificatore standard (configurato con extframe=False).

any(fifo: int) bool

Restituisce True se c’è un messaggio in attesa sulla FIFO, altrimenti False.

recv(fifo: int, list: list | None = None, *, timeout: int = 5000) list

Riceve dati sul bus:

  • fifo è un intero, ovvero la FIFO su cui ricevere

  • list è un oggetto list opzionale da usare come valore di ritorno

  • timeout è il timeout in millisecondi per attendere la ricezione.

Valore di ritorno: una lista contenente cinque valori.

  • L’id del messaggio.

  • Un booleano che indica se l’ID del messaggio è standard o esteso.

  • Un booleano che indica se il messaggio è un messaggio RTR.

  • Il valore FMI (Filter Match Index).

  • Un array contenente i dati.

Se list è None allora verrà allocata una nuova lista, oltre a un nuovo oggetto bytes per contenere i dati (come quinto elemento della lista).

Se list non è None allora dovrebbe essere un oggetto list con almeno cinque elementi. Il quinto elemento dovrebbe essere un oggetto memoryview creato da un bytearray o da un array di tipo “B” o “b”, e questo array deve avere spazio sufficiente per almeno 8 byte. L’oggetto list verrà quindi popolato con i primi quattro valori di ritorno sopra indicati, e l’oggetto memoryview verrà ridimensionato in place alla dimensione dei dati e riempito con tali dati. Gli stessi oggetti list e memoryview possono essere riutilizzati nelle chiamate successive a questo metodo, fornendo un modo per ricevere dati senza usare l’heap. Ad esempio:

buf = bytearray(8)
lst = [0, 0, 0, 0, memoryview(buf)]
# No heap memory is allocated in the following call
can.recv(0, lst)
send(data: int | bytes | bytearray, id: int, *, timeout: int = 0, rtr: bool = False, extframe: bool = False, fdf: bool = False, brs: bool = False) None

Invia un messaggio sul bus:

  • data sono i dati da inviare (un intero da inviare, o un oggetto buffer).

  • id è l’id del messaggio da inviare.

  • timeout è il timeout in millisecondi per attendere l’invio.

  • rtr è un booleano che specifica se il messaggio deve essere inviato come richiesta di trasmissione remota. Se rtr è True allora solo la lunghezza di data viene usata per riempire lo slot DLC del frame; i byte effettivi in data non vengono usati.

  • extframe se True il frame avrà un identificatore esteso (29 bit), altrimenti viene usato un identificatore standard (11 bit).

  • fdf per i controller CAN FD, se impostato a True, il frame avrà un formato frame FD, che supporta payload di dati fino a 64 byte.

  • brs per i controller CAN FD, se impostato a True, viene abilitata la modalità di commutazione del bitrate, in cui la fase dati viene trasmessa a un bitrate diverso. Vedere CAN.init() per i parametri di configurazione della temporizzazione del bit dati.

Se timeout è 0 il messaggio viene posto in un buffer in uno dei tre buffer hardware e il metodo ritorna immediatamente. Se tutti e tre i buffer sono in uso viene sollevata un’eccezione. Se timeout non è 0, il metodo attende finché il messaggio non viene trasmesso. Se il messaggio non può essere trasmesso entro il tempo specificato viene sollevata un’eccezione.

Valore di ritorno: None.

rxcallback(fifo: int, fun: Callable[[CAN, int], None] | None) None

Registra una funzione da chiamare quando un messaggio viene accettato in una FIFO vuota:

  • fifo è la FIFO ricevente.

  • fun è la funzione da chiamare quando la FIFO diventa non vuota.

La funzione di callback accetta due argomenti: il primo è l’oggetto CAN stesso; il secondo è un intero che indica il motivo del callback:

Motivo

Significato

0

Un messaggio è stato accettato in una FIFO vuota.

1

La FIFO è piena.

2

Un messaggio è andato perso a causa di una FIFO piena.

Esempio di utilizzo di rxcallback:

def cb0(bus, reason):
  print('cb0')
  if reason == 0:
      print('pending')
  if reason == 1:
      print('full')
  if reason == 2:
      print('overflow')

can = CAN(1, CAN.LOOPBACK)
can.rxcallback(0, cb0)

Costanti

Costanti della modalità bus (argomento mode di init()):

NORMAL: int

Il controller partecipa normalmente sul bus – trasmette i propri frame e conferma i frame ricevuti validi.

LOOPBACK: int

Modalità di loopback interno: il controller è scollegato dai pin e instrada i frame trasmessi direttamente verso il percorso di ricezione. Utile per gli autotest senza un transceiver.

SILENT: int

Modalità solo ascolto: il controller riceve i frame ma non pilota mai il bus (nessun ACK, nessuna trasmissione). Utile per lo sniffing del bus.

SILENT_LOOPBACK: int

Combina SILENT e LOOPBACK: nessuna attività sui pin e nessuna conferma, con loopback interno della TX verso la RX.

Costanti dello stato del controller (restituite da state()):

STOPPED: int

Il controller è completamente spento e azzerato.

ERROR_ACTIVE: int

Il controller è acceso e nello stato Error Active (sia TEC che REC sono inferiori a 96).

ERROR_WARNING: int

Il controller è acceso e nello stato Error Warning (almeno uno tra TEC o REC è pari o superiore a 96).

ERROR_PASSIVE: int

Il controller è acceso e nello stato Error Passive (almeno uno tra TEC o REC è pari o superiore a 128).

BUS_OFF: int

Il controller è acceso ma non partecipa all’attività del bus (TEC è andato in overflow oltre 255).

Modalità di filtro CAN classico (argomento mode di setfilter() sulla OpenMV Cam M4 / M7):

LIST16: int

L’array params del filtro contiene quattro ID a 16 bit che verranno accettati.

LIST32: int

L’array params del filtro contiene due ID a 32 bit che verranno accettati.

MASK16: int

L’array params del filtro contiene due coppie (id, mask) a 16 bit.

MASK32: int

L’array params del filtro contiene una coppia (id, mask) a 32 bit.

Modalità di filtro CAN FD (argomento mode di setfilter() sulla OpenMV Cam H7 / H7 Plus / Pure Thermal):

RANGE: int

L’array params del filtro contiene due ID che formano un intervallo di ID accettati.

DUAL: int

L’array params del filtro contiene due ID specifici da accettare.

MASK: int

L’array params del filtro contiene una coppia (id, mask).