classe CAN – protocolo Controller Area Network¶
CAN é um protocolo serial de dois fios usado para a entrega confiável de mensagens em tempo real entre um ou mais nós conectados a um barramento comum. O CAN 2.0 foi padronizado na ISO-11898 e agora também é conhecido como CAN Classic.
Há também um protocolo mais recente e compatível com versões anteriores chamado CAN FD (CAN com Taxa de Dados Flexível). O driver machine.CAN atualmente não oferece suporte aos recursos do CAN FD; use pyb.CAN no STM32 se você precisar do CAN FD.
O suporte a CAN requer um controlador (frequentemente um periférico interno do microcontrolador) e um transceptor externo para fazer a conversão de nível dos sinais no barramento CAN.
Disponível nas câmeras OpenMV STM32 (M4 / M7 / H7 / H7 Plus / Pure Thermal / N6, além das variantes da marca Arduino que possuem um transceptor cabeado). Ainda não há suporte na OpenMV Cam RT1062 (porta mimxrt) ou na OpenMV Cam AE3 (porta alif).
A interface machine.CAN é uma interface de mensagens CAN básica de baixo nível que abstrai um controlador CAN como uma fila de prioridade de saída para o envio de mensagens, uma fila de entrada para o recebimento de mensagens e mecanismos para relatar erros.
Nota
Os módulos micropython-lib planejados can e aiocan serão a maneira recomendada de usar CAN com MicroPython.
Construtor¶
- class machine.CAN(id: int, *args, **kwargs)¶
Constrói um objeto controlador CAN com o id fornecido:
ididentifica um objeto controlador CAN específico; ele é específico da placa e da porta.Todos os outros argumentos são passados para
CAN.init(). Pelo menos um argumento (bitrate) deve ser fornecido.
Versões futuras desta classe também poderão aceitar aqui argumentos nomeados específicos da porta que configuram o hardware. Atualmente, nenhum desses argumentos nomeados está implementado.
Exemplo¶
Constrói e inicializa o controlador CAN 1 com bitrate de 500 kbps:
from machine import CAN can = CAN(1, 500_000)
Métodos¶
- init(bitrate: int, mode: int = CAN.MODE_NORMAL, sample_point: int = 75, sjw: int = 1, tseg1: int | None = None, tseg2: int | None = None) None¶
Inicializa o barramento CAN com os parâmetros fornecidos:
bitrate é a taxa de bits do barramento desejada, em bits por segundo.
mode é um dos valores mostrados em Modos, indicando o modo de operação desejado. O padrão é a operação “normal” no barramento.
Os próximos parâmetros são opcionais e dizem respeito às temporizações de bits do CAN. Na maioria dos casos, você pode deixar esses parâmetros com os valores padrão:
sample_point é uma porcentagem inteira do tempo do bit de dados. Ele especifica a posição da amostra do bit em relação ao tempo nominal total do bit. O driver CAN calculará os parâmetros de acordo. Este parâmetro é ignorado se tseg1 e tseg2 forem definidos.
sjw é a largura do salto de ressincronização em unidades de quanta de tempo para bits nominais; pode ser um valor entre 1 e 4 inclusive para CAN classic.
tseg1 define a localização da amostra do bit em unidades de quanta de tempo para bits nominais; pode ser um valor entre 1 e 16 inclusive para CAN classic. Esta é a soma das fases
Prop_SegePhase_Seg1conforme definidas na norma ISO-11898. Se este valor for definido, então tseg2 também deve ser definido e sample_point é ignorado.tseg2 define a localização do ponto de transmissão em unidades de quanta de tempo para bits nominais; pode ser um valor entre 1 e 8 inclusive para CAN classic. Isso corresponde a
Phase_Seg2na norma ISO-11898. Se este valor for definido, então tseg1 também deve ser definido.
Se esses argumentos forem especificados, então o controlador CAN será configurado corretamente para o bitrate desejado e o número total especificado de quanta de tempo por bit. Os valores de tseg1 e tseg2 substituem o argumento sample_point se todos eles forem fornecidos.
Nota
O hardware de cada controlador pode ter restrições adicionais sobre os valores válidos para esses parâmetros e levantará um
ValueErrorse um determinado valor não for suportado.Nota
Hardware de controlador específico pode aceitar parâmetros nomeados opcionais adicionais para recursos específicos do hardware, como sobreamostragem.
- set_filters(filters: list | tuple | None) None¶
Define os filtros de recepção no controlador CAN. filters pode ser:
Nonepara aceitar todas as mensagens recebidas, ou[]ou()para desabilitar todo o recebimento de mensagens, ouUm iterável de um ou mais itens definindo os critérios do filtro. Cada item deve ser uma tupla ou lista com três elementos:
identifieré um identificador CAN (int).bit_maské uma máscara de bits para os bits no campo identificador CAN (int).flagsé um inteiro com zero ou mais dos bits definidos em Flags de Mensagem ativados. Isso especifica as propriedades que a mensagem recebida precisa corresponder. Nem todos os controladores oferecem suporte à filtragem em todas as flags; umValueErroré levantado se uma flag não suportada for solicitada.
As mensagens recebidas são aceitas se os bits mascarados em
bit_maskcorresponderem entre o identificador da mensagem e o valoridentifierdo filtro, e se as flags definidas no filtro corresponderem à mensagem recebida.Se o bit
CAN.FLAG_EXT_IDestiver definido em flags, o filtro corresponde apenas a IDs CAN Estendidos. Se o bitCAN.FLAG_EXT_IDnão estiver definido, o filtro corresponde apenas a IDs CAN Padrão.Todos os filtros são combinados por OR no controlador. Passar uma lista ou tupla vazia para o argumento filters significa que nenhuma mensagem será recebida.
Alguns controladores CAN exigem que cada filtro seja associado a apenas uma FIFO de recepção. Nesses casos, os itens de filtro no argumento são alocados em rodízio (round-robin) às FIFOs disponíveis. Este driver não distingue entre FIFOs na IRQ de recepção.
Nota
Se o chamador passar um iterável com mais itens do que
CAN.FILTERS_MAX, umValueErrorserá levantado.Nota
Se
identifieroubit_maskestiver fora do intervalo para o tipo de ID especificado, umValueErrorcom o motivo “invalid id” será levantado.Exemplos¶
Recebe todas as mensagens recebidas:
can.set_filters(None)Recebe apenas mensagens com os valores de ID Padrão 0x301 e 0x700:
can.set_filters(((0x301, 0x7FF, 0), (0x700, 0x7FF, 0)))
Recebe apenas mensagens com valores de ID Padrão no intervalo 0x300-0x3FF e o valor de ID Estendido 0x50700:
can.set_filters(((0x300, 0x700, 0), (0x50700, 0x1FFF_FFFF, CAN.FLAG_EXT_ID)))
- FILTERS_MAX: int¶
Valor constante que lê o número máximo de filtros de recepção suportados por este controlador de hardware.
Observe que alguns controladores podem ter restrições de hardware mais complexas sobre o número de filtros em uso (por exemplo, contando filtros de ID Padrão e Estendido de forma independente). Nesses casos,
CAN.set_filterspode levantar umValueErrormesmo quando o limiteFILTERS_MAXnão é excedido.
- send(id: int, data: bytes, flags: int = 0) int | None¶
Copia uma nova mensagem CAN para a fila de transmissão de hardware do controlador para ser enviada ao barramento. A fila de transmissão é uma fila de prioridade ordenada pela prioridade do identificador CAN (identificadores numericamente menores têm prioridade mais alta).
id é um valor inteiro de identificador CAN.
data é um objeto bytes (ou similar) contendo os dados da mensagem CAN, ou descrevendo uma Solicitação de Transmissão Remota (Remote Transmission Request, veja abaixo).
flags é um inteiro com zero ou mais dos bits definidos em Flags de Mensagem ativados, especificando propriedades da mensagem CAN de saída (ID Estendido, Solicitação de Transmissão Remota etc.)
Se a mensagem for enfileirada com sucesso para transmissão ao barramento, a função retorna um inteiro no intervalo de
0aCAN.TX_QUEUE_LEN(exclusivo). Esse valor é o índice do buffer de transmissão onde a mensagem está enfileirada para envio, e pode ser usado pela funçãoCAN.cancel_sende em eventosCAN.IRQ_TX.Se a fila estiver cheia, o envio falhará e
Noneserá retornado.O envio também pode falhar e retornar
Nonese o valor de id fornecido tiver prioridade igual à de uma mensagem existente na fila de transmissão e o hardware do controlador CAN não puder garantir que mensagens com o mesmo ID serão enviadas ao barramento na mesma ordem em que foram adicionadas à fila. Para enfileirar a mensagem mesmo assim, passe a flagCAN.FLAG_UNORDEREDno argumento flags. Essa flag indica que está tudo bem em enviar mensagens com o mesmo ID CAN ao barramento em qualquer ordem.Se o controlador estiver no estado de erro “Bus Off” ou estiver desabilitado, então chamar esta função levantará um
OSError.Nota
Esta implementação intencionalmente de baixo nível foi projetada para que o chamador possa estabelecer uma fila de software de mensagens de saída.
Importante
A “fila de transmissão” CAN não é uma fila FIFO, ela é ordenada por prioridade, e embora possa conter até
CAN.TX_QUEUE_LENitens, pode haver outras restrições de hardware sobre quais mensagens podem ser enfileiradas ao mesmo tempo.Solicitações de Transmissão Remota¶
Se o bit
CAN.FLAG_RTRestiver definido no argumento flags, então o controlador enviará uma Solicitação de Transmissão Remota em vez de uma mensagem. Nesse caso, o conteúdo do argumento data é ignorado. O controlador enviará uma solicitação na qual o campo de comprimentoDLCé igual ao comprimento do argumento data.Exemplos¶
Tenta enviar uma mensagem com payload de três bytes
0a0b0ce ID Padrão 0x200:can.send(0x200, b"\x0a\x0b\x0c", 0)Tenta enviar uma mensagem com payload vazio e ID Estendido 0x180008. Indica que o controlador pode enviar mensagens com este ID em qualquer ordem, caso outras mensagens já estejam enfileiradas para envio com o mesmo ID:
can.send(0x180008, b"", can.FLAG_EXT_ID | can.FLAG_UNORDERED)Tenta enviar uma Solicitação de Transmissão Remota com comprimento de 8 bytes e ID Padrão 0x555:
can.send(0x555, b" " * 8, can.FLAG_RTR)
- recv(arg: list | None = None) list | None¶
Retorna uma mensagem CAN que foi recebida pelo controlador, de acordo com os filtros definidos por
CAN.set_filters().Esta função recebe um único argumento opcional; se fornecido, ele deve ser uma lista com pelo menos 4 elementos, onde o segundo elemento é um objeto
memoryviewque se refere a umbytearrayou objeto similar com capacidade suficiente para conter qualquer mensagem CAN recebida (8 bytes para CAN Classic, 64 bytes para CAN FD). A lista fornecida será retornada como um resultado bem-sucedido e evita a alocação de memória dentro da função.Se nenhuma mensagem tiver sido recebida pelo controlador CAN, esta função retorna
None.Nota
CAN.set_filtersdeve ser chamada antes que qualquer mensagem possa ser recebida pelo controlador. Para receber todas as mensagens, chameset_filters(None).Se uma mensagem tiver sido recebida pelo controlador CAN, esta função retorna uma lista com 4 elementos:
O índice 0 é o ID CAN da mensagem recebida, como um inteiro.
O índice 1 é um memoryview que fornece acesso aos dados da mensagem recebida.
Se arg não for fornecido, então este é um
memoryviewcontendo os bytes que foram recebidos. Essememoryviewé respaldado por umbytearrayrecém-alocado grande o suficiente para conter qualquer mensagem CAN recebida. Isso permite que o resultado seja reutilizado com segurança como um futuro arg, economizando alocações de memória.Se arg for fornecido, então o
memoryviewfornecido será redimensionado para conter exatamente os bytes que foram recebidos. O chamador é responsável por garantir que o objeto de respaldo domemoryviewpossa conter uma mensagem CAN de qualquer comprimento.
O índice 2 é um inteiro com zero ou mais dos bits definidos em Flags de Mensagem ativados. Ele indica metadados sobre a mensagem recebida.
O índice 3 é um inteiro com zero ou mais dos bits definidos em Flags de Erro de Recepção ativados. Qualquer valor diferente de zero indica possíveis problemas ao receber mensagens CAN. Essas flags são redefinidas dentro do controlador toda vez que esta função retorna.
Solicitações de Transmissão Remota¶
Se uma Solicitação de Transmissão Remota for recebida, então o bit
CAN.FLAG_RTRserá definido no Índice 2 e o memoryview no Índice 1 conterá apenas zeros, com um comprimento igual ao campoDLCda solicitação recebida.Exemplo¶
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¶
Define uma função handler de interrupção a ser chamada quando um ou mais dos eventos sinalizados em trigger tiver ocorrido.
handler é uma função a ser chamada quando o evento de interrupção é disparado. O handler deve receber exatamente um argumento, que é a instância de
CAN.trigger configura o(s) evento(s) que podem gerar uma interrupção. Os valores possíveis são uma máscara de um ou mais dos seguintes:
O evento
CAN.IRQ_RXocorre após o controlador CAN ter recebido pelo menos uma mensagem em sua FIFO de RX (o que significa queCAN.recv()retornará com sucesso).O evento
CAN.IRQ_TXocorre após o controlador CAN ter enviado com sucesso uma mensagem ao barramento CAN ou ter falhado ao enviar uma mensagem. Este trigger tem requisitos adicionais para o handler; veja Flags de IRQ para detalhes.O evento
CAN.IRQ_STATEocorre quando o controlador CAN faz a transição para um estado de erro mais grave. ChameCAN.state()para obter o estado atualizado.
hard se True, uma interrupção de hardware (hard) é usada. Isso reduz o atraso entre o evento do controlador CAN e a chamada do handler. Handlers de interrupção hard não podem alocar memória; veja Escrevendo manipuladores de interrupção.
Retorna um objeto irq. Se chamada sem argumentos, então um objeto irq previamente configurado é retornado.
Veja Flags de IRQ para um exemplo.
- cancel_send(index: int) bool¶
Solicita ao controlador CAN que cancele o envio de uma mensagem ao barramento.
O argumento index identifica um único buffer de transmissão. Ele deve ser um inteiro no intervalo de
0aCAN.TX_QUEUE_LEN(exclusivo). Geralmente, este será um valor previamente retornado porCAN.send().O resultado é
Truese uma mensagem estava pendente de transmissão neste buffer e a transmissão foi cancelada.O resultado é
Falsecaso contrário (ou nenhuma mensagem estava pendente de transmissão neste buffer, ou a transmissão já teve sucesso).O evento IRQ
CAN.IRQ_TXdeve ser usado para determinar se uma mensagem foi definitivamente enviada ou não, mas observe que há possíveis condições de corrida se uma transmissão for cancelada e, em seguida, o mesmo buffer for usado para enviar outra mensagem (especialmente se a IRQ do controlador CAN não for “hard”).
- state() int¶
Retorna um valor inteiro indicando o estado atual do controlador. O valor será um dos valores definidos em Estados.
Estados de erro de menor gravidade podem se limpar automaticamente se o barramento se recuperar, mas o estado
CAN.STATE_BUS_OFFsó pode ser recuperado chamandoCAN.restart().
- get_counters(list: list | None = None, /) list¶
Retorna os valores dos contadores de erro do controlador. O resultado é uma lista de oito valores. Se o parâmetro opcional list for especificado, então o objeto de lista fornecido é atualizado e retornado como resultado, para evitar uma alocação.
Os itens da lista são:
Valor do TEC (Contador de Erros de Transmissão)
Valor do REC (Contador de Erros de Recepção)
Número de vezes que o controlador entrou no estado de Aviso a partir do estado Ativo.
Número de vezes que o controlador entrou no estado Error Passive a partir do estado de Aviso.
Número de vezes que o controlador entrou no estado Bus Off a partir do estado Error Passive.
Número total de mensagens de TX pendentes na fila de hardware.
Número total de mensagens de RX pendentes na fila de hardware.
Número de vezes que ocorreu um overrun de RX.
Nota
Dependendo do controlador, esses valores podem transbordar de volta para 0 após um certo valor.
Nota
Se um controlador não oferecer suporte a um contador específico, ele retornará
Nonepara esse elemento da lista.
- get_timings(list: list | None = None, /) list¶
Retorna uma lista de elementos indicando as temporizações atuais configuradas no controlador CAN. Isso pode ser usado para verificar as temporizações para fins de depuração. O resultado é uma lista de seis valores. Se o parâmetro opcional list for especificado, então o objeto de lista fornecido é atualizado e retornado como resultado, para evitar uma alocação.
Os itens da lista são:
Bitrate exato usado pelo controlador. Pode variar em relação ao argumento bitrate passado para
CAN.init()devido à quantização para atender às restrições de hardware.Largura do salto de ressincronização (SJW) em unidades de quanta de tempo para bits nominais. Tem o mesmo significado que o parâmetro sjw de
CAN.init().Localização da amostra do bit em unidades de quanta de tempo para bits nominais. Tem o mesmo significado que o parâmetro tseg1 de
CAN.init().Localização do ponto de transmissão em unidades de quanta de tempo para bits nominais. Tem o mesmo significado que o parâmetro tseg2 de
CAN.init().Informações de temporização do CAN FD.
Nonepara controladores que não oferecem suporte a CAN FD, ou se o CAN FD não estiver inicializado. Caso contrário, uma lista aninhada de quatro elementos correspondentes aos itens acima, mas aplicáveis ao recurso BRS do CAN FD.Informações de temporização opcionais específicas do controlador. Dependendo do controlador, isto será
Nonese o controlador não relatar nenhuma, ou será uma lista de comprimento constante cujos elementos são específicos de um determinado controlador de hardware.
Nota
Se
CAN.init()não tiver sido chamada, então esta função ainda retorna um resultado, mas o resultado depende dos detalhes internos do controlador e pode não ser preciso.
- restart() None¶
Faz com que o controlador saia de
STATE_BUS_OFFsem limpar nenhum outro estado interno. Também limpa alguns dos contadores de erro (sempre o número de vezes que cada estado de erro foi alcançado, possivelmente o TEC e o REC dependendo do controlador).Chamar esta função também cancela quaisquer mensagens aguardando para serem enviadas. Nenhuma interrupção
IRQ_TXé entregue para essas mensagens.Observe que esta função pode ou não fazer com que o controlador saia do estado “Error Passive”, dependendo de o hardware do controlador zerar o TEC e o REC ou não.
- deinit() None¶
Desinicializa uma instância CAN previamente ativa. Todas as mensagens pendentes (de transmissão e recepção) são descartadas e o controlador para de interagir no barramento. Para usar esta instância novamente, chame
CAN.init().Nenhuma interrupção
IRQ_TXouIRQ_RXé chamada em resposta à chamada desta função.Veja também
CAN.restart().
Constantes¶
- TX_QUEUE_LEN: int¶
Número máximo de mensagens CAN que podem ser enfileiradas na fila de mensagens de saída de hardware do controlador. Os “índices de buffer de transmissão” usados por
CAN.send(),CAN.cancel_send()e Flags de IRQ estarão neste intervalo.
Modos¶
Esses valores representam os modos de operação do controlador, conforme passados para
CAN.init(). Nem todos os controladores oferecem suporte a todos os modos.Alterar o modo de um controlador em execução requer chamar
CAN.deinit()e depois chamarCAN.init()novamente com o novo modo.- MODE_NORMAL: int¶
O controlador está ativo como um nó padrão da rede CAN (reconhecerá mensagens válidas e poderá transmitir erros dependendo de seu Estado atual).
- MODE_SLEEP: int¶
O controlador CAN está adormecido em um modo de baixo consumo de energia. Dependendo do controlador, isso pode permitir o despertar do controlador e a transição para
CAN.MODE_NORMALse tráfego CAN for recebido.
- MODE_LOOPBACK: int¶
Um modo de teste. O controlador CAN ainda está conectado ao barramento externo, mas também receberá suas próprias mensagens transmitidas e ignorará quaisquer erros de ACK.
Estados¶
Esses valores são retornados por
CAN.state()e refletem o estado de erro do controlador CAN:- STATE_ACTIVE: int¶
O controlador está ativo e os contadores de erro
TECeRECestão ambos abaixo do limiar de aviso de 96. VejaCAN.get_counters().
- STATE_WARNING: int¶
O controlador está ativo, mas pelo menos um dos contadores de erro
TECeRECestá entre 96 e 127. VejaCAN.get_counters().
- STATE_PASSIVE: int¶
O controlador está no estado “Error Passive”, o que significa que ele não transmite mais erros ativos ao barramento, mas, fora isso, está funcional. Este estado é alcançado quando pelo menos um dos contadores de erro
TECeRECé 128 ou maior, mas oTECé menor que 255. VejaCAN.get_counters().
- STATE_BUS_OFF: int¶
O controlador está no estado Bus-Off, o que significa que o contador de erros
TECé maior que 255. O controlador CAN não interagirá com o barramento neste estado e precisa ser reiniciado viaCAN.restart()para continuar.
Flags de Mensagem¶
Esses valores representam metadados sobre uma mensagem CAN. As funções
CAN.send(),CAN.recv()eCAN.set_filters()aceitam ou retornam um valor inteiro composto por zero ou mais dessas flags combinadas por OR bit a bit.- FLAG_EXT_ID: int¶
Se definido, indica que o identificador de uma Mensagem é Estendido (29 bits). Se não definido, indica que o identificador de uma mensagem é Padrão (11 bits).
- FLAG_UNORDERED: int¶
Se definido no argumento
flagsdeCAN.send(), indica que está tudo bem se mensagens com o mesmo ID CAN forem enviadas ao barramento em qualquer ordem.Caso contrário, tentar enfileirar várias mensagens com o mesmo ID pode resultar em falha de
CAN.send()se o hardware do controlador não puder garantir a ordenação.Esta flag nunca é definida em mensagens recebidas e é ignorada por
CAN.set_filters().
Flags de Erro de Recepção¶
O resultado de
CAN.recv()inclui um valor inteiro composto por zero ou mais dessas flags combinadas por OR bit a bit. Se definidas, essas flags indicam possíveis problemas gerais ao receber mensagens CAN.Valores de IRQ¶
- IRQ_RX: int¶
Passe para o argumento
triggerdeirq()para disparar o handler toda vez que o controlador CAN tiver recebido uma mensagem completa na FIFO de RX. Dentro do handler, leia a mensagem comrecv().
- IRQ_TX: int¶
Passe para o argumento
triggerdeirq()para disparar o handler toda vez que o controlador CAN finalizar uma tentativa de transmissão (sucesso ou falha). Dentro do handler, use os bits adicionais abaixo para recuperar qual mailbox foi concluído e se ele falhou – veja Flags de IRQ.
- IRQ_STATE: int¶
Passe para o argumento
triggerdeirq()para disparar o handler toda vez que o controlador fizer a transição entre os valoresSTATE_*(ativo / aviso / passive / bus-off). Usestate()dentro do handler para ler o novo estado.
- IRQ_TX_FAILED: int¶
Flag de status que pode ser definida em
irq().flags()quando um eventoIRQ_TXé disparado. Indica que a tentativa de transmissão falhou (normalmente porquecancel_send()foi chamada, ou o controlador entrou em um estado de erro).
- IRQ_TX_IDX_SHIFT: int¶
Posição do bit do campo de índice de mailbox de transmissão dentro do valor
irq().flags()durante um eventoIRQ_TX. O índice do mailbox é extraído como(flags >> IRQ_TX_IDX_SHIFT) & IRQ_TX_IDX_MASK.
- IRQ_TX_IDX_MASK: int¶
Máscara de bits do campo de índice de mailbox de transmissão dentro do valor
irq().flags()durante um eventoIRQ_TX. O índice extraído corresponde ao inteiro retornado pela chamadasend()correspondente (um int no intervalo de0aTX_QUEUE_LEN).
Flags de IRQ¶
Chamar CAN.irq() registra um handler de interrupção com um ou mais dos triggers CAN.IRQ_RX, CAN.IRQ_TX e CAN.IRQ_STATE.
A função retorna um objeto IRQ, e chamar a função flags() neste objeto retorna um inteiro indicando qual(is) evento(s) de trigger dispararam a interrupção. Um handler de IRQ do CAN deve chamar a função flags() repetidamente até que ela retorne 0.
Quando a função flags() retorna com o bit CAN.IRQ_TX definido, o handler também pode verificar os seguintes bits de flag no resultado para obter informações adicionais sobre o evento de TX:
O bit
CAN.IRQ_TX_FAILEDé definido se a transmissão falhou. Normalmente, isso só acontecerá seCAN.cancel_send()foi chamada, embora também possa acontecer se o controlador entrar em um estado de erro.CAN.IRQ_TX_IDX_MASK << CAN.IRQ_TX_IDX_SHIFTé uma região mascarada por bits do valor de flags que contém o índice do buffer de transmissão que gerou o evento. Este será um inteiro no intervalo de0aCAN.TX_QUEUE_LEN(exclusivo) e corresponderá ao resultado de uma chamada anterior aCAN.send().
Exemplo de 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 o trigger CAN.IRQ_TX estiver definido, então o handler deve chamar flags() repetidamente até que ela retorne 0, como mostrado neste exemplo. Caso contrário, as interrupções CAN podem não ser reabilitadas corretamente.