classe CAN – protocollo Controller Area Network

CAN è un protocollo seriale a due fili utilizzato per la consegna affidabile di messaggi in tempo reale tra uno o più nodi connessi a un bus comune. CAN 2.0 è stato standardizzato nella ISO-11898 ed è ora noto anche come CAN Classic.

Esiste anche un protocollo più recente e retrocompatibile chiamato CAN FD (CAN with Flexible Data-Rate). Il driver machine.CAN attualmente non supporta le funzionalità CAN FD; usa pyb.CAN su STM32 se hai bisogno di CAN FD.

Il supporto CAN richiede un controller (spesso una periferica interna del microcontrollore) e un transceiver esterno per adattare il livello dei segnali sul bus CAN.

Disponibile sulle OpenMV Cam STM32 (M4 / M7 / H7 / H7 Plus / Pure Thermal / N6, oltre alle varianti a marchio Arduino che integrano un transceiver). Non ancora supportato sulla OpenMV Cam RT1062 (porta mimxrt) o sulla OpenMV Cam AE3 (porta alif).

L’interfaccia machine.CAN è un’interfaccia di messaggistica CAN di base e a basso livello che astrae un controller CAN come una coda di priorità in uscita per l’invio dei messaggi, una coda in ingresso per la ricezione dei messaggi e meccanismi per la segnalazione degli errori.

Nota

I moduli micropython-lib pianificati can e aiocan saranno il modo consigliato per usare il CAN con MicroPython.

Costruttore

class machine.CAN(id: int, *args, **kwargs)

Costruisce un oggetto controller CAN con l’id indicato:

  • id identifica un particolare oggetto controller CAN; è specifico della scheda e della porta.

  • Tutti gli altri argomenti vengono passati a CAN.init(). Deve essere fornito almeno un argomento (bitrate).

Le versioni future di questa classe potrebbero anche accettare qui argomenti keyword specifici della porta che configurano l’hardware. Attualmente non è implementato alcun argomento keyword di questo tipo.

Esempio

Costruisce e inizializza il controller CAN 1 con bitrate 500kbps:

from machine import CAN
can = CAN(1, 500_000)

Metodi

init(bitrate: int, mode: int = CAN.MODE_NORMAL, sample_point: int = 75, sjw: int = 1, tseg1: int | None = None, tseg2: int | None = None) None

Inizializza il bus CAN con i parametri indicati:

  • bitrate è la velocità in bit del bus desiderata, espressa in bit al secondo.

  • mode è uno dei valori mostrati in Modalità e indica la modalità di funzionamento desiderata. Il valore predefinito è il funzionamento «normal» sul bus.

I parametri successivi sono opzionali e riguardano le temporizzazioni dei bit CAN. Nella maggior parte dei casi puoi lasciare questi parametri impostati sui valori predefiniti:

  • sample_point è una percentuale intera del tempo del bit di dati. Specifica la posizione del campionamento del bit rispetto all’intero tempo nominale del bit. Il driver CAN calcolerà i parametri di conseguenza. Questo parametro viene ignorato se tseg1 e tseg2 sono impostati.

  • sjw è l’ampiezza 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.

  • tseg1 definisce la posizione del 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. È la somma delle fasi Prop_Seg e Phase_Seg1 come definite nello standard ISO-11898. Se questo valore è impostato, allora deve essere impostato anche tseg2 e sample_point viene ignorato.

  • tseg2 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. Corrisponde a Phase_Seg2 nello standard ISO-11898. Se questo valore è impostato, allora deve essere impostato anche tseg1.

Se questi argomenti vengono specificati, il controller CAN viene configurato correttamente per il bitrate desiderato e per il numero totale di quanti di tempo per bit specificato. I valori tseg1 e tseg2 prevalgono sull’argomento sample_point se vengono forniti tutti questi valori.

Nota

I singoli hardware dei controller possono avere ulteriori restrizioni sui valori validi per questi parametri e solleveranno un ValueError se un determinato valore non è supportato.

Nota

Hardware specifici di controller possono accettare ulteriori parametri keyword opzionali per funzionalità specifiche dell’hardware, come l’oversampling.

set_filters(filters: list | tuple | None) None

Imposta i filtri di ricezione nel controller CAN. filters può essere:

  • None per accettare tutti i messaggi in ingresso, oppure

  • [] o () per disabilitare la ricezione di tutti i messaggi, oppure

  • Un iterabile di uno o più elementi che definiscono i criteri di filtro. Ogni elemento deve essere una tupla o una lista con tre elementi:

    • identifier è un identificatore CAN (int).

    • bit_mask è una maschera di bit per i bit nel campo dell’identificatore CAN (int).

    • flags è un intero con zero o più dei bit definiti in Flag dei messaggi impostati. Specifica le proprietà che il messaggio in ingresso deve soddisfare. Non tutti i controller supportano il filtraggio su tutti i flag; viene sollevato un ValueError se viene richiesto un flag non supportato.

I messaggi in ingresso vengono accettati se i bit mascherati in bit_mask corrispondono tra l’identificatore del messaggio e il valore identifier del filtro, e se i flag impostati nel filtro corrispondono al messaggio in ingresso.

Se il bit CAN.FLAG_EXT_ID è impostato nei flag, il filtro corrisponde solo agli ID CAN estesi. Se il bit CAN.FLAG_EXT_ID non è impostato, il filtro corrisponde solo agli ID CAN standard.

Tutti i filtri vengono combinati in OR nel controller. Passare una lista o una tupla vuota come argomento dei filtri significa che non verrà ricevuto alcun messaggio.

Alcuni controller CAN richiedono che ogni filtro sia associato a una sola FIFO di ricezione. In questi casi, gli elementi del filtro nell’argomento vengono assegnati in modo round-robin alle FIFO disponibili. Questo driver non distingue tra le FIFO nell’IRQ di ricezione.

Nota

Se il chiamante passa un iterabile con più elementi di CAN.FILTERS_MAX, verrà sollevato un ValueError.

Nota

Se identifier o bit_mask è fuori intervallo per il tipo di ID specificato, verrà sollevato un ValueError con motivo «invalid id».

Esempi

Ricevere tutti i messaggi in ingresso:

can.set_filters(None)

Ricevere solo i messaggi con valori Standard ID 0x301 e 0x700:

can.set_filters(((0x301, 0x7FF, 0),
                 (0x700, 0x7FF, 0)))

Ricevere solo i messaggi con valori Standard ID nell’intervallo 0x300-0x3FF e con valore Extended ID 0x50700:

can.set_filters(((0x300, 0x700, 0),
                 (0x50700, 0x1FFF_FFFF, CAN.FLAG_EXT_ID)))
FILTERS_MAX: int

Valore costante che legge il numero massimo di filtri di ricezione supportati da questo controller hardware.

Nota che alcuni controller possono avere restrizioni hardware più complesse sul numero di filtri in uso (ad esempio, contando in modo indipendente i filtri per ID standard ed esteso). In questi casi CAN.set_filters può sollevare un ValueError anche quando il limite FILTERS_MAX non è superato.

send(id: int, data: bytes, flags: int = 0) int | None

Copia un nuovo messaggio CAN nella coda di trasmissione hardware del controller per essere inviato sul bus. La coda di trasmissione è una coda di priorità ordinata in base alla priorità dell’identificatore CAN (gli identificatori numericamente inferiori hanno priorità più alta).

  • id è un valore intero di identificatore CAN.

  • data è un oggetto bytes (o simile) contenente i dati del messaggio CAN, oppure che descrive una Remote Transmission Request (vedi sotto).

  • flags è un intero con zero o più dei bit definiti in Flag dei messaggi impostati, che specifica le proprietà del messaggio CAN in uscita (ID esteso, Remote Transmission Request, ecc.)

Se il messaggio viene accodato con successo per la trasmissione sul bus, la funzione restituisce un intero nell’intervallo da 0 a CAN.TX_QUEUE_LEN (escluso). Questo valore è l’indice del buffer di trasmissione in cui il messaggio è accodato per l’invio e può essere utilizzato dalla funzione CAN.cancel_send e negli eventi CAN.IRQ_TX.

Se la coda è piena, l’invio fallirà e verrà restituito None.

L’invio può anche fallire e restituire None se il valore id fornito ha la stessa priorità di un messaggio esistente nella coda di trasmissione e l’hardware del controller CAN non può garantire che i messaggi con lo stesso ID vengano inviati sul bus nello stesso ordine in cui sono stati aggiunti alla coda. Per accodare comunque il messaggio, passa il flag CAN.FLAG_UNORDERED nell’argomento flags. Questo flag indica che è accettabile inviare sul bus i messaggi con lo stesso ID CAN in qualsiasi ordine.

Se il controller si trova nello stato di errore «Bus Off» o è disabilitato, allora la chiamata a questa funzione solleverà un OSError.

Nota

Questa implementazione volutamente a basso livello è progettata in modo che il chiamante possa stabilire una coda software di messaggi in uscita.

Importante

La «coda di trasmissione» CAN non è una coda FIFO, è ordinata per priorità e, sebbene possa contenere fino a CAN.TX_QUEUE_LEN elementi, possono esistere altre restrizioni hardware sui messaggi che possono essere accodati contemporaneamente.

Remote Transmission Request

Se il bit CAN.FLAG_RTR è impostato nell’argomento flags, allora il controller invierà una Remote Transmission Request invece di un messaggio. In questo caso il contenuto dell’argomento data viene ignorato. Il controller invierà una richiesta in cui il campo di lunghezza DLC è uguale alla lunghezza dell’argomento data.

Esempi

Tentare di inviare un messaggio con un payload di tre byte 0a0b0c e Standard ID 0x200:

can.send(0x200, b"\x0a\x0b\x0c", 0)

Tentare di inviare un messaggio con un payload vuoto ed Extended ID 0x180008. Indicare che il controller può inviare messaggi con questo ID in qualsiasi ordine, nel caso in cui altri messaggi con lo stesso ID siano già in coda per l’invio:

can.send(0x180008, b"", can.FLAG_EXT_ID | can.FLAG_UNORDERED)

Tentare di inviare una Remote Transmission Request con lunghezza 8 byte e Standard ID 0x555:

can.send(0x555, b" " * 8, can.FLAG_RTR)
recv(arg: list | None = None) list | None

Restituisce un messaggio CAN ricevuto dal controller, in base ai filtri impostati con CAN.set_filters().

Questa funzione accetta un singolo argomento opzionale; se fornito, deve essere una lista di almeno 4 elementi in cui il secondo elemento è un oggetto memoryview che fa riferimento a un oggetto bytearray o simile con capacità sufficiente a contenere qualsiasi messaggio CAN ricevuto (8 byte per CAN Classic, 64 byte per CAN FD). La lista fornita verrà restituita come risultato in caso di successo, evitando l’allocazione di memoria all’interno della funzione.

Se il controller CAN non ha ricevuto alcun messaggio, questa funzione restituisce None.

Nota

CAN.set_filters deve essere chiamata prima che il controller possa ricevere qualsiasi messaggio. Per ricevere tutti i messaggi, chiama set_filters(None).

Se un messaggio è stato ricevuto dal controller CAN, questa funzione restituisce una lista con 4 elementi:

  • L’indice 0 è l’ID CAN del messaggio ricevuto, come intero.

  • L’indice 1 è una memoryview che fornisce l’accesso ai dati del messaggio ricevuto.

    • Se arg non viene fornito, allora questa è una memoryview che contiene i byte ricevuti. Questa memoryview è supportata da un bytearray appena allocato, abbastanza grande da contenere qualsiasi messaggio CAN ricevuto. Questo consente di riutilizzare in sicurezza il risultato come futuro arg, per risparmiare allocazioni di memoria.

    • Se arg viene fornito, allora la memoryview fornita verrà ridimensionata per contenere esattamente i byte ricevuti. Il chiamante è responsabile di assicurarsi che l’oggetto di supporto della memoryview possa contenere un messaggio CAN di qualsiasi lunghezza.

  • L’indice 2 è un intero con zero o più dei bit definiti in Flag dei messaggi impostati. Indica i metadati relativi al messaggio ricevuto.

  • L’indice 3 è un intero con zero o più dei bit definiti in Flag di errore di ricezione impostati. Qualsiasi valore diverso da zero indica potenziali problemi durante la ricezione dei messaggi CAN. Questi flag vengono azzerati all’interno del controller ogni volta che questa funzione restituisce un valore.

Remote Transmission Request

Se viene ricevuta una Remote Transmission Request, allora il bit CAN.FLAG_RTR sarà impostato nell’Indice 2 e la memoryview all’Indice 1 conterrà tutti zeri, con una lunghezza pari al campo DLC della richiesta ricevuta.

Esempio
can.set_filters(None)   # receive all
while True:
    res = can.recv()
    if res:
        can_id, data, flags, errs = res
        print("Received", hex(can_id), data.hex(), hex(flags), hex(errs))
    else:
        time.sleep_ms(1)  # not a good pattern, use the irq instead!
irq(handler: Callable[[CAN], None] | None = None, trigger: int = 0, hard: bool = False) None

Imposta una funzione handler di interrupt da chiamare quando si è verificato uno o più degli eventi segnalati in trigger.

  • handler è una funzione da chiamare quando l’evento di interrupt viene attivato. L’handler deve accettare esattamente un argomento, che è l’istanza CAN.

  • trigger configura gli eventi che possono generare un interrupt. I valori possibili sono una maschera di uno o più dei seguenti:

    • L’evento CAN.IRQ_RX si verifica dopo che il controller CAN ha ricevuto almeno un messaggio nella sua FIFO RX (il che significa che CAN.recv() restituirà un valore con successo).

    • L’evento CAN.IRQ_TX si verifica dopo che il controller CAN ha inviato con successo un messaggio sul bus CAN oppure non è riuscito a inviare un messaggio. Questo trigger ha requisiti aggiuntivi per l’handler, vedi Flag IRQ per i dettagli.

    • L’evento CAN.IRQ_STATE si verifica quando il controller CAN è passato a uno stato di errore più grave. Chiama CAN.state() per ottenere lo stato aggiornato.

  • hard se True, viene utilizzato un hard interrupt. Questo riduce il ritardo tra l’evento del controller CAN e la chiamata dell’handler. Gli handler di hard interrupt non possono allocare memoria; vedi Scrittura dei gestori di interrupt.

Restituisce un oggetto irq. Se chiamata senza argomenti, viene restituito un oggetto irq configurato in precedenza.

Vedi Flag IRQ per un esempio.

cancel_send(index: int) bool

Richiede al controller CAN di annullare l’invio di un messaggio sul bus.

L’argomento index identifica un singolo buffer di trasmissione. Deve essere un intero nell’intervallo da 0 a CAN.TX_QUEUE_LEN (escluso). Generalmente sarà un valore restituito in precedenza da CAN.send().

Il risultato è True se un messaggio era in attesa di trasmissione in questo buffer e la trasmissione è stata annullata.

Il risultato è False in caso contrario (o nessun messaggio era in attesa di trasmissione in questo buffer, oppure la trasmissione è già riuscita).

L’evento IRQ CAN.IRQ_TX dovrebbe essere utilizzato per determinare se un messaggio è stato sicuramente inviato o meno, ma nota che esistono potenziali race condition se una trasmissione viene annullata e poi lo stesso buffer viene utilizzato per inviare un altro messaggio (specialmente se l’IRQ del controller CAN non è di tipo «hard»).

state() int

Restituisce un valore intero che indica lo stato attuale del controller. Il valore sarà uno dei valori definiti in Stati.

Gli stati di errore di minore gravità possono azzerarsi automaticamente se il bus si ripristina, ma lo stato CAN.STATE_BUS_OFF può essere ripristinato solo chiamando CAN.restart().

get_counters(list: list | None = None, /) list

Restituisce i valori dei contatori di errore del controller. Il risultato è una lista di otto valori. Se viene specificato il parametro opzionale list, allora l’oggetto lista fornito viene aggiornato e restituito come risultato, per evitare un’allocazione.

Gli elementi della lista sono:

  • Valore TEC (Transmit Error Counter)

  • Valore REC (Receive Error Counter)

  • Numero di volte in cui il controller è entrato nello stato Warning dallo stato Active.

  • Numero di volte in cui il controller è entrato nello stato Error Passive dallo stato Warning.

  • Numero di volte in cui il controller è entrato nello stato Bus Off dallo stato Error Passive.

  • Numero totale di messaggi TX in sospeso nella coda hardware.

  • Numero totale di messaggi RX in sospeso nella coda hardware.

  • Numero di volte in cui si è verificato un overrun RX.

Nota

A seconda del controller, questi valori possono andare in overflow tornando a 0 dopo un certo valore.

Nota

Se un controller non supporta un particolare contatore, restituirà None per quell’elemento della lista.

get_timings(list: list | None = None, /) list

Restituisce una lista di elementi che indicano le temporizzazioni attualmente configurate nel controller CAN. Può essere utilizzata per verificare le temporizzazioni a scopo di debug. Il risultato è una lista di sei valori. Se viene specificato il parametro opzionale list, allora l’oggetto lista fornito viene aggiornato e restituito come risultato, per evitare un’allocazione.

Gli elementi della lista sono:

  • Bitrate esatto utilizzato dal controller. Può differire dall’argomento bitrate passato a CAN.init() a causa della quantizzazione necessaria per soddisfare i vincoli hardware.

  • Ampiezza del salto di risincronizzazione (SJW) in unità di quanti di tempo per i bit nominali. Ha lo stesso significato del parametro sjw di CAN.init().

  • Posizione del campionamento in unità di quanti di tempo per i bit nominali. Ha lo stesso significato del parametro tseg1 di CAN.init().

  • Posizione del punto di trasmissione in unità di quanti di tempo per i bit nominali. Ha lo stesso significato del parametro tseg2 di CAN.init().

  • Informazioni di temporizzazione CAN FD. None per i controller che non supportano CAN FD, oppure se il CAN FD non è inizializzato. Altrimenti, una lista annidata di quattro elementi corrispondenti alle voci precedenti ma applicabili alla funzionalità BRS del CAN FD.

  • Informazioni di temporizzazione opzionali specifiche del controller. A seconda del controller, sarà None se il controller non ne fornisce alcuna, oppure sarà una lista di lunghezza costante i cui elementi sono specifici di un particolare controller hardware.

Nota

Se CAN.init() non è stata chiamata, questa funzione restituisce comunque un risultato, ma il risultato dipende dagli aspetti interni del controller e potrebbe non essere accurato.

restart() None

Fa uscire il controller dallo stato STATE_BUS_OFF senza azzerare alcun altro stato interno. Azzera inoltre alcuni dei contatori di errore (sempre il numero di volte in cui è stato raggiunto ciascuno stato di errore, eventualmente TEC e REC a seconda del controller).

La chiamata a questa funzione annulla anche tutti i messaggi in attesa di essere inviati. Per questi messaggi non vengono generati interrupt IRQ_TX.

Nota che questa funzione può o meno far uscire il controller dallo stato «Error Passive», a seconda che l’hardware del controller azzeri o meno TEC e REC.

deinit() None

De-inizializza un’istanza CAN precedentemente attiva. Tutti i messaggi in sospeso (in trasmissione e in ricezione) vengono scartati e il controller smette di interagire sul bus. Per utilizzare nuovamente questa istanza, chiama CAN.init().

In risposta alla chiamata di questa funzione non viene chiamato alcun interrupt IRQ_TX o IRQ_RX.

Vedi anche CAN.restart().

Costanti

TX_QUEUE_LEN: int

Numero massimo di messaggi CAN che possono essere accodati nella coda hardware dei messaggi in uscita del controller. Gli «indici del buffer di trasmissione» utilizzati da CAN.send(), CAN.cancel_send() e Flag IRQ saranno in questo intervallo.

Modalità

Questi valori rappresentano le modalità di funzionamento del controller, come passate a CAN.init(). Non tutti i controller possono supportare tutte le modalità.

La modifica della modalità di un controller in funzione richiede di chiamare CAN.deinit() e poi di chiamare nuovamente CAN.init() con la nuova modalità.

MODE_NORMAL: int

Il controller è attivo come nodo di rete CAN standard (riconoscerà i messaggi validi e potrà trasmettere errori a seconda del suo Stato attuale).

MODE_SLEEP: int

Il controller CAN è in stato di riposo in una modalità a basso consumo. A seconda del controller, ciò può supportare il risveglio del controller e la transizione a CAN.MODE_NORMAL se viene ricevuto traffico CAN.

MODE_LOOPBACK: int

Una modalità di test. Il controller CAN è ancora connesso al bus esterno, ma riceverà anche i propri messaggi trasmessi e ignorerà eventuali errori di ACK.

MODE_SILENT: int

Il controller CAN riceve i messaggi ma non interagisce con il bus CAN (inclusi l’invio di ACK, errori, ecc.)

MODE_SILENT_LOOPBACK: int

Una modalità di test che non richiede affatto la connessione di un transceiver CAN. Il controller CAN riceve i propri messaggi trasmessi senza interagire in alcun modo con il bus CAN. I pin TX e RX del CAN rimangono inattivi.

Stati

Questi valori vengono restituiti da CAN.state() e riflettono lo stato di errore del controller CAN:

STATE_STOPPED: int

Il controller non è stato inizializzato.

STATE_ACTIVE: int

Il controller è attivo e i contatori di errore TEC e REC sono entrambi al di sotto della soglia di warning di 96. Vedi CAN.get_counters().

STATE_WARNING: int

Il controller è attivo ma almeno uno dei contatori di errore TEC e REC è compreso tra 96 e 127. Vedi CAN.get_counters().

STATE_PASSIVE: int

Il controller è nello stato «Error Passive», il che significa che non trasmette più errori attivi sul bus, ma per il resto è funzionante. Si entra in questo stato quando almeno uno dei contatori di errore TEC e REC è pari o superiore a 128, ma TEC è inferiore a 255. Vedi CAN.get_counters().

STATE_BUS_OFF: int

Il controller è nello stato Bus-Off, il che significa che il contatore di errore TEC è maggiore di 255. In questo stato il controller CAN non interagirà con il bus e deve essere riavviato tramite CAN.restart() per continuare.

Flag dei messaggi

Questi valori rappresentano i metadati relativi a un messaggio CAN. Le funzioni CAN.send(), CAN.recv() e CAN.set_filters() accettano o restituiscono un valore intero composto da zero o più di questi flag combinati tra loro in OR bit a bit.

FLAG_RTR: int

Indica che un messaggio è una remote transmission request.

FLAG_EXT_ID: int

Se impostato, indica che un identificatore di messaggio è Esteso (29 bit). Se non impostato, indica che un identificatore di messaggio è Standard (11 bit).

FLAG_UNORDERED: int

Se impostato nell’argomento flags di CAN.send(), indica che è accettabile che i messaggi con lo stesso ID CAN vengano inviati sul bus in qualsiasi ordine.

In caso contrario, tentare di accodare più messaggi con lo stesso ID può causare il fallimento di CAN.send() se l’hardware del controller non è in grado di garantire l’ordinamento.

Questo flag non viene mai impostato sui messaggi ricevuti e viene ignorato da CAN.set_filters().

Flag di errore di ricezione

Il risultato di CAN.recv() include un valore intero composto da zero o più di questi flag combinati tra loro in OR bit a bit. Se impostati, questi flag indicano potenziali problemi generali nella ricezione dei messaggi CAN.

RECV_ERR_FULL: int

La FIFO hardware in cui è stato ricevuto questo messaggio è piena e ulteriori messaggi in ingresso potrebbero andare persi.

RECV_ERR_OVERRUN: int

La FIFO hardware in cui è stato ricevuto questo messaggio è piena e uno o più messaggi in ingresso sono andati persi.

Valori IRQ

IRQ_RX: int

Passa all’argomento trigger di irq() per attivare l’handler ogni volta che il controller CAN ha ricevuto un messaggio completo nella FIFO RX. All’interno dell’handler, leggi il messaggio con recv().

IRQ_TX: int

Passa all’argomento trigger di irq() per attivare l’handler ogni volta che il controller CAN termina un tentativo di trasmissione (con successo o con fallimento). All’interno dell’handler, usa i bit aggiuntivi qui sotto per recuperare quale mailbox è stata completata e se è fallita – vedi Flag IRQ.

IRQ_STATE: int

Passa all’argomento trigger di irq() per attivare l’handler ogni volta che il controller passa tra i valori STATE_* (active / warning / passive / bus-off). Usa state() all’interno dell’handler per leggere il nuovo stato.

IRQ_TX_FAILED: int

Flag di stato che può essere impostato in irq().flags() quando si verifica un evento IRQ_TX. Indica che il tentativo di trasmissione è fallito (tipicamente perché è stato chiamato cancel_send(), oppure perché il controller è entrato in uno stato di errore).

IRQ_TX_IDX_SHIFT: int

Posizione del bit del campo indice-mailbox-di-trasmissione all’interno del valore irq().flags() durante un evento IRQ_TX. L’indice della mailbox viene estratto come (flags >> IRQ_TX_IDX_SHIFT) & IRQ_TX_IDX_MASK.

IRQ_TX_IDX_MASK: int

Maschera di bit del campo indice-mailbox-di-trasmissione all’interno del valore irq().flags() durante un evento IRQ_TX. L’indice estratto corrisponde all’intero restituito dalla corrispondente chiamata send() (un int nell’intervallo da 0 a TX_QUEUE_LEN).

Flag IRQ

La chiamata a CAN.irq() registra un handler di interrupt con uno o più dei trigger CAN.IRQ_RX, CAN.IRQ_TX e CAN.IRQ_STATE.

La funzione restituisce un oggetto IRQ e la chiamata alla funzione flags() su questo oggetto restituisce un intero che indica quale evento o eventi di trigger hanno attivato l’interrupt. Un handler di IRQ CAN dovrebbe chiamare la funzione flags() ripetutamente finché non restituisce 0.

Quando la funzione flags() restituisce un valore con il bit CAN.IRQ_TX impostato, l’handler può anche controllare i seguenti bit di flag nel risultato per ottenere informazioni aggiuntive sull’evento TX:

  • Il bit CAN.IRQ_TX_FAILED è impostato se la trasmissione è fallita. Di solito ciò accade solo se è stata chiamata CAN.cancel_send(), sebbene possa accadere anche se il controller entra in uno stato di errore.

  • CAN.IRQ_TX_IDX_MASK << CAN.IRQ_TX_IDX_SHIFT è una regione mascherata in bit del valore dei flag che contiene l’indice del buffer di trasmissione che ha generato l’evento. Sarà un intero nell’intervallo da 0 a CAN.TX_QUEUE_LEN (escluso) e corrisponderà al risultato di una precedente chiamata a CAN.send().

Esempio di IRQ_TX

from machine import CAN

def irq_send(can):
    while flags := can.irq().flags():
        if flags & can.IRQ_TX:
            idx = (flags >> can.IRQ_TX_IDX_SHIFT) & can.IRQ_TX_IDX_MASK
            success = not (flags & can.IRQ_TX_FAILED)
            print("irq_send", idx, success)

can = CAN(1, 500_000)
can.irq(irq_send, trigger=can.IRQ_TX, hard=True)

Importante

Se il trigger CAN.IRQ_TX è impostato, allora l’handler deve chiamare flags() ripetutamente finché non restituisce 0, come mostrato in questo esempio. Altrimenti, gli interrupt CAN potrebbero non essere riabilitati correttamente.