classe CAN – protocolo Controller Area Network

CAN é um protocolo série de dois fios utilizado para entrega fiável de mensagens em tempo real entre um ou mais nós ligados a um barramento comum. O CAN 2.0 foi normalizado na ISO-11898 e é também conhecido como CAN Classic.

Existe também um protocolo mais recente e retrocompatível denominado CAN FD (CAN com Taxa de Dados Flexível). O controlador machine.CAN não suporta atualmente as funcionalidades CAN FD; utilize pyb.CAN em STM32 se necessitar de CAN FD.

O suporte a CAN requer um controlador (frequentemente um periférico interno do microcontrolador) e um transcetor externo para adaptar os sinais ao nível do barramento CAN.

Disponível nas câmaras OpenMV STM32 (M4 / M7 / H7 / H7 Plus / Pure Thermal / N6, incluindo as variantes de marca Arduino que ligam um transcetor). Ainda não suportado na OpenMV Cam RT1062 (porta mimxrt) nem 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 envio de mensagens, uma fila de entrada para receção de mensagens e mecanismos para reportar erros.

Nota

Os módulos can e aiocan da micropython-lib, previstos para o futuro, serão a forma recomendada de utilizar CAN com MicroPython.

Construtor

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

Constrói um objeto controlador CAN com o id fornecido:

  • id identifica um objeto controlador CAN específico; é específico da placa e da porta.

  • Todos os outros argumentos são passados para CAN.init(). Deve ser fornecido pelo menos um argumento (bitrate).

Versões futuras desta classe poderão também aceitar aqui argumentos de palavra-chave específicos da porta que configuram o hardware. Atualmente não estão implementados quaisquer argumentos de palavra-chave dessa natureza.

Exemplo

Constrói e inicializa o controlador CAN 1 com uma taxa de bits 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 pretendida para o barramento, em bits por segundo.

  • mode é um dos valores indicados em Modos, que especifica o modo de operação pretendido. O valor predefinido é a operação «normal» no barramento.

Os próximos parâmetros são opcionais e dizem respeito aos timings de bits CAN. Na maioria dos casos pode deixar estes parâmetros com os valores predefinidos:

  • sample_point é uma percentagem inteira do tempo de bit de dados. Especifica a posição da amostragem do bit em relação ao tempo nominal total de bit. O controlador CAN calculará os parâmetros em conformidade. Este parâmetro é ignorado se tseg1 e tseg2 estiverem definidos.

  • sjw é a largura do salto de ressincronização em unidades de quanta de tempo para bits nominais; pode ter um valor entre 1 e 4 inclusive para CAN Classic.

  • tseg1 define a localização do ponto de amostragem em unidades de quanta de tempo para bits nominais; pode ter um valor entre 1 e 16 inclusive para CAN Classic. É a soma das fases Prop_Seg e Phase_Seg1 conforme definido 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 ter um valor entre 1 e 8 inclusive para CAN Classic. Corresponde a Phase_Seg2 na norma ISO-11898. Se este valor for definido, então tseg1 também deve ser definido.

Se estes argumentos forem especificados, o controlador CAN é configurado corretamente para o bitrate pretendido e o número total especificado de quanta de tempo por bit. Os valores 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 estes parâmetros e irá lançar um ValueError se um determinado valor não for suportado.

Nota

Hardware de controlador específico pode aceitar parâmetros de palavra-chave opcionais adicionais para funcionalidades específicas do hardware, como a sobreamostragem.

set_filters(filters: list | tuple | None) None

Define filtros de receção no controlador CAN. filters pode ser:

  • None para aceitar todas as mensagens recebidas, ou

  • [] ou () para desativar toda a receção de mensagens, ou

  • Um iterável com um ou mais elementos que definem os critérios de filtragem. Cada elemento deve ser um tuplo ou lista com três elementos:

    • identifier é um identificador CAN (int).

    • bit_mask é uma máscara de bits para os bits no campo de identificador CAN (int).

    • flags é um inteiro com zero ou mais dos bits definidos em Flags de Mensagem ativados. Especifica as propriedades que a mensagem recebida precisa de corresponder. Nem todos os controladores suportam filtragem em todos os flags; é lançado um ValueError se for solicitado um flag não suportado.

As mensagens recebidas são aceites se os bits mascarados em bit_mask corresponderem entre o identificador da mensagem e o valor identifier do filtro, e se os flags definidos no filtro corresponderem à mensagem recebida.

Se o bit CAN.FLAG_EXT_ID estiver definido nos flags, o filtro corresponde apenas a IDs CAN Estendidos. Se o bit CAN.FLAG_EXT_ID não estiver definido, o filtro corresponde apenas a IDs CAN Standard.

Todos os filtros são ORed conjuntamente no controlador. Passar uma lista ou tuplo vazio para o argumento filters significa que não serão recebidas mensagens.

Alguns controladores CAN requerem que cada filtro esteja associado a apenas um FIFO de receção. Nestes casos, os elementos do filtro no argumento são alocados em round-robin aos FIFOs disponíveis. Este controlador não distingue entre FIFOs no IRQ de receção.

Nota

Se o chamador passar um iterável com mais elementos do que CAN.FILTERS_MAX, será lançado um ValueError.

Nota

Se o identifier ou a bit_mask estiver fora do intervalo para o tipo de ID especificado, será lançado um ValueError com a razão «invalid id».

Exemplos

Receber todas as mensagens recebidas:

can.set_filters(None)

Receber apenas mensagens com valores de ID Standard 0x301 e 0x700:

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

Receber apenas mensagens com valores de ID Standard 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 indica o número máximo de filtros de receção suportados por este controlador de hardware.

Note 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 Standard e Estendido de forma independente). Nestes casos, CAN.set_filters pode lançar um ValueError mesmo quando o limite FILTERS_MAX nã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 no barramento. A fila de transmissão é uma fila de prioridade ordenada pela prioridade do identificador CAN (identificadores numéricos menores têm maior prioridade).

  • id é um valor inteiro de identificador CAN.

  • data é um objeto de bytes (ou similar) que contém os dados da mensagem CAN, ou que descreve um Remote Transmission Request (ver 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, Remote Transmission Request, etc.)

Se a mensagem for colocada com sucesso na fila para transmissão no barramento, a função devolve um inteiro no intervalo 0 a CAN.TX_QUEUE_LEN (exclusivo). Este valor é o índice do buffer de transmissão onde a mensagem está na fila para envio e pode ser utilizado pela função CAN.cancel_send e em eventos CAN.IRQ_TX.

Se a fila estiver cheia, o envio falha e é devolvido None.

O envio também pode falhar e devolver None se o valor id fornecido tiver a mesma prioridade que uma mensagem existente na fila de transmissão e o hardware do controlador CAN não conseguir garantir que as mensagens com o mesmo ID sejam enviadas no barramento pela mesma ordem em que foram adicionadas à fila. Para colocar a mensagem na fila de qualquer forma, passe o flag CAN.FLAG_UNORDERED no argumento flags. Este flag indica que é aceitável enviar mensagens com o mesmo ID CAN no barramento em qualquer ordem.

Se o controlador estiver no estado de erro «Bus Off» ou desativado, chamar esta função irá lançar um OSError.

Nota

Esta implementação intencionalmente de baixo nível foi concebida 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, é ordenada por prioridade e, embora possa conter até CAN.TX_QUEUE_LEN elementos, podem existir outras restrições de hardware sobre as mensagens que podem ser colocadas em fila ao mesmo tempo.

Remote Transmission Requests

Se o bit CAN.FLAG_RTR estiver definido no argumento flags, o controlador enviará um Remote Transmission Request em vez de uma mensagem. Neste caso, o conteúdo do argumento data é ignorado. O controlador enviará um pedido em que o campo de comprimento DLC é igual ao comprimento do argumento data.

Exemplos

Tentativa de enviar uma mensagem com payload de três bytes 0a0b0c e ID Standard 0x200:

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

Tentativa de 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 na fila para envio com o mesmo ID:

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

Tentativa de enviar um Remote Transmission Request com comprimento de 8 bytes e ID Standard 0x555:

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

Devolve uma mensagem CAN que foi recebida pelo controlador, de acordo com os filtros definidos por CAN.set_filters().

Esta função aceita um único argumento opcional; se fornecido, deve ser uma lista com pelo menos 4 elementos onde o segundo elemento é um objeto memoryview que se refere a um bytearray ou 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á devolvida como resultado bem-sucedido, evitando alocação de memória dentro da função.

Se não tiverem sido recebidas mensagens pelo controlador CAN, esta função devolve None.

Nota

CAN.set_filters deve ser chamada antes de quaisquer mensagens poderem ser recebidas pelo controlador. Para receber todas as mensagens, chame set_filters(None).

Se uma mensagem tiver sido recebida pelo controlador CAN, esta função devolve uma lista com 4 elementos:

  • O índice 0 é o ID CAN da mensagem recebida, como inteiro.

  • O índice 1 é um memoryview que fornece acesso aos dados da mensagem recebida.

    • Se arg não for fornecido, trata-se de um memoryview com os bytes que foram recebidos. Este memoryview é suportado por um bytearray recentemente alocado com tamanho suficiente para conter qualquer mensagem CAN recebida. Isto permite reutilizar o resultado com segurança como um futuro arg, para poupar alocações de memória.

    • Se arg for fornecido, o memoryview fornecido será redimensionado para conter exatamente os bytes que foram recebidos. O chamador é responsável por garantir que o objeto de suporte para o memoryview pode conter uma mensagem CAN de qualquer comprimento.

  • O índice 2 é um inteiro com zero ou mais dos bits definidos em Flags de Mensagem ativados. Indica metadados sobre a mensagem recebida.

  • O índice 3 é um inteiro com zero ou mais dos bits definidos em Flags de Erro de Receção ativados. Qualquer valor diferente de zero indica potenciais problemas ao receber mensagens CAN. Estes flags são reiniciados dentro do controlador cada vez que esta função é chamada.

Remote Transmission Requests

Se um Remote Transmission Request for recebido, o bit CAN.FLAG_RTR será definido no índice 2 e o memoryview no índice 1 conterá todos os zeros, com um comprimento igual ao campo DLC do pedido recebido.

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 tiverem ocorrido.

  • handler é uma função a ser chamada quando o evento de interrupção é disparado. O handler deve aceitar exatamente um argumento que é a instância 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_RX ocorre após o controlador CAN ter recebido pelo menos uma mensagem no seu FIFO RX (o que significa que CAN.recv() retornará com sucesso).

    • O evento CAN.IRQ_TX ocorre após o controlador CAN ter enviado com sucesso uma mensagem no barramento CAN ou falhado no envio. Este gatilho tem requisitos adicionais para o handler; consulte Flags de IRQ para mais detalhes.

    • O evento CAN.IRQ_STATE ocorre quando o controlador CAN transita para um estado de erro mais grave. Chame CAN.state() para obter o estado atualizado.

  • hard se for True, é utilizada uma interrupção hard. Isto reduz o atraso entre o evento do controlador CAN e a chamada do handler. Os handlers de interrupção hard não podem alocar memória; consulte Escrita de tratadores de interrupções.

Devolve um objeto irq. Se chamado sem argumentos, devolve um objeto irq configurado anteriormente.

Consulte Flags de IRQ para um exemplo.

cancel_send(index: int) bool

Solicita ao controlador CAN que cancele o envio de uma mensagem no barramento.

O argumento index identifica um único buffer de transmissão. Deve ser um inteiro no intervalo 0 a CAN.TX_QUEUE_LEN (exclusivo). Geralmente será um valor previamente devolvido por CAN.send().

O resultado é True se uma mensagem estava pendente de transmissão neste buffer e a transmissão foi cancelada.

O resultado é False caso contrário (ou não havia mensagem pendente de transmissão neste buffer, ou a transmissão já foi concluída com sucesso).

O evento IRQ CAN.IRQ_TX deve ser utilizado para determinar se uma mensagem foi definitivamente enviada ou não, mas note que existem potenciais condições de corrida se uma transmissão for cancelada e o mesmo buffer for utilizado para enviar outra mensagem (especialmente se o IRQ do controlador CAN não for «hard»).

state() int

Devolve um valor inteiro que indica o estado atual do controlador. O valor será um dos valores definidos em Estados.

Estados de erro de menor gravidade podem ser limpos automaticamente se o barramento se recuperar, mas o estado CAN.STATE_BUS_OFF só pode ser recuperado chamando CAN.restart().

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

Devolve os valores dos contadores de erros do controlador. O resultado é uma lista de oito valores. Se o parâmetro opcional list for especificado, o objeto lista fornecido é atualizado e devolvido como resultado, para evitar uma alocação.

Os elementos da lista são:

  • Valor de TEC (Transmit Error Counter)

  • Valor de REC (Receive Error Counter)

  • Número de vezes que o controlador entrou no estado Warning a partir do estado Active.

  • Número de vezes que o controlador entrou no estado Error Passive a partir do estado Warning.

  • Número de vezes que o controlador entrou no estado Bus Off a partir do estado Error Passive.

  • Número total de mensagens TX pendentes na fila de hardware.

  • Número total de mensagens RX pendentes na fila de hardware.

  • Número de vezes que ocorreu um overrun de RX.

Nota

Dependendo do controlador, estes valores podem transbordar de volta para 0 após um determinado valor.

Nota

Se um controlador não suportar um determinado contador, devolverá None para esse elemento da lista.

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

Devolve uma lista de elementos que indica os timings atuais configurados no controlador CAN. Pode ser utilizado para verificar os timings para fins de depuração. O resultado é uma lista de seis valores. Se o parâmetro opcional list for especificado, o objeto lista fornecido é atualizado e devolvido como resultado, para evitar uma alocação.

Os elementos da lista são:

  • Taxa de bits exata utilizada pelo controlador. Pode diferir do argumento bitrate passado para CAN.init() devido à quantização para satisfazer as 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 do ponto de amostragem 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ção de timing CAN FD. None para controladores que não suportam CAN FD, ou se CAN FD não estiver inicializado. Caso contrário, uma lista aninhada de quatro elementos correspondentes aos elementos acima, mas aplicáveis à funcionalidade CAN FD BRS.

  • Informação de timing opcional específica do controlador. Dependendo do controlador, será None se o controlador não reportar 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, esta função devolve mesmo assim um resultado, mas o resultado depende dos internos do controlador e pode não ser preciso.

restart() None

Faz com que o controlador saia do estado STATE_BUS_OFF sem limpar qualquer outro estado interno. Também limpa alguns contadores de erros (sempre o número de vezes que cada estado de erro foi ativado, possivelmente TEC e REC dependendo do controlador.)

Chamar esta função também cancela quaisquer mensagens a aguardar envio. Não são entregues interrupções IRQ_TX para estas mensagens.

Note que esta função pode ou não fazer o controlador sair do estado «Error Passive», dependendo se o hardware do controlador zera ou não TEC e REC.

deinit() None

Desinicializa uma instância CAN previamente ativa. Todas as mensagens pendentes (de transmissão e receção) são descartadas e o controlador deixa de interagir no barramento. Para usar esta instância novamente, chame CAN.init().

Não são chamadas interrupções IRQ_TX ou IRQ_RX em resposta à chamada desta função.

Consulte também CAN.restart().

Constantes

TX_QUEUE_LEN: int

Número máximo de mensagens CAN que podem ser colocadas em fila na fila de mensagens de hardware de saída do controlador. Os «índices de buffer de transmissão» utilizados por CAN.send(), CAN.cancel_send() e Flags de IRQ estarão neste intervalo.

Modos

Estes valores representam modos de operação do controlador, conforme passados para CAN.init(). Nem todos os controladores podem suportar todos os modos.

Alterar o modo de um controlador em funcionamento requer chamar CAN.deinit() e depois chamar CAN.init() novamente com o novo modo.

MODE_NORMAL: int

O controlador está ativo como um nó de rede CAN padrão (irá reconhecer mensagens válidas e pode transmitir erros dependendo do seu Estado atual).

MODE_SLEEP: int

O controlador CAN está em modo de baixo consumo. Dependendo do controlador, pode suportar o despertar do controlador e a transição para CAN.MODE_NORMAL se for recebido tráfego CAN.

MODE_LOOPBACK: int

Um modo de teste. O controlador CAN ainda está ligado ao barramento externo, mas também receberá as suas próprias mensagens transmitidas e ignorará quaisquer erros ACK.

MODE_SILENT: int

O controlador CAN recebe mensagens mas não interage com o barramento CAN (incluindo envio de ACKs, erros, etc.)

MODE_SILENT_LOOPBACK: int

Um modo de teste que não requer qualquer transcetor CAN ligado. O controlador CAN recebe as suas próprias mensagens transmitidas sem interagir com o barramento CAN. Os pinos CAN TX e RX permanecem inativos.

Estados

Estes valores são devolvidos por CAN.state() e refletem o estado de erro do controlador CAN:

STATE_STOPPED: int

O controlador não foi inicializado.

STATE_ACTIVE: int

O controlador está ativo e os contadores de erros TEC e REC estão ambos abaixo do limiar de aviso de 96. Consulte CAN.get_counters().

STATE_WARNING: int

O controlador está ativo mas pelo menos um dos contadores de erros TEC e REC está entre 96 e 127. Consulte CAN.get_counters().

STATE_PASSIVE: int

O controlador está no estado «Error Passive», o que significa que já não transmite erros ativos para o barramento, mas é de outra forma funcional. Este estado é ativado quando pelo menos um dos contadores de erros TEC e REC é 128 ou superior, mas TEC é inferior a 255. Consulte CAN.get_counters().

STATE_BUS_OFF: int

O controlador está no estado Bus-Off, o que significa que o contador de erros TEC é superior a 255. O controlador CAN não irá interagir com o barramento neste estado e precisa de ser reiniciado via CAN.restart() para continuar.

Flags de Mensagem

Estes valores representam metadados sobre uma mensagem CAN. As funções CAN.send(), CAN.recv() e CAN.set_filters() aceitam ou devolvem um valor inteiro composto por zero ou mais destes flags combinados por OR bit a bit.

FLAG_RTR: int

Indica que uma mensagem é um remote transmission request.

FLAG_EXT_ID: int

Se definido, indica que um identificador de mensagem é Estendido (29 bits). Se não definido, indica que um identificador de mensagem é Standard (11 bits).

FLAG_UNORDERED: int

Se definido no argumento flags de CAN.send(), indica que é aceitável enviar mensagens com o mesmo ID CAN em qualquer ordem no barramento.

Caso contrário, tentar colocar em fila várias mensagens com o mesmo ID pode resultar em CAN.send() a falhar se o hardware do controlador não conseguir impor a ordenação.

Este flag nunca é definido em mensagens recebidas e é ignorado por CAN.set_filters().

Flags de Erro de Receção

O resultado de CAN.recv() inclui um valor inteiro composto por zero ou mais destes flags combinados por OR bit a bit. Se definidos, estes flags indicam potenciais problemas gerais na receção de mensagens CAN.

RECV_ERR_FULL: int

O FIFO de hardware onde esta mensagem foi recebida está cheio e mensagens recebidas adicionais podem ser perdidas.

RECV_ERR_OVERRUN: int

O FIFO de hardware onde esta mensagem foi recebida está cheio e uma ou mais mensagens recebidas foram perdidas.

Valores de IRQ

IRQ_RX: int

Passe ao argumento trigger de irq() para disparar o handler cada vez que o controlador CAN recebe uma mensagem completa no FIFO RX. Dentro do handler, leia a mensagem com recv().

IRQ_TX: int

Passe ao argumento trigger de irq() para disparar o handler cada vez que o controlador CAN termina uma tentativa de transmissão (com sucesso ou falha). Dentro do handler, utilize os bits adicionais abaixo para recuperar qual mailbox foi concluído e se falhou – consulte Flags de IRQ.

IRQ_STATE: int

Passe ao argumento trigger de irq() para disparar o handler cada vez que o controlador transita entre os valores STATE_* (ativo / aviso / passivo / bus-off). Utilize state() dentro do handler para ler o novo estado.

IRQ_TX_FAILED: int

Flag de estado que pode ser definido em irq().flags() quando um evento IRQ_TX é disparado. Indica que a tentativa de transmissão falhou (normalmente porque cancel_send() foi chamado, ou o controlador entrou num estado de erro).

IRQ_TX_IDX_SHIFT: int

Posição de bit do campo de índice do mailbox de transmissão dentro do valor irq().flags() durante um evento IRQ_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 do mailbox de transmissão dentro do valor irq().flags() durante um evento IRQ_TX. O índice extraído corresponde ao inteiro devolvido pela chamada correspondente de send() (um int no intervalo 0 a TX_QUEUE_LEN).

Flags de IRQ

Chamar CAN.irq() regista um handler de interrupção com um ou mais dos gatilhos CAN.IRQ_RX, CAN.IRQ_TX e CAN.IRQ_STATE.

A função devolve um objeto IRQ, e chamar a função flags() neste objeto devolve um inteiro que indica qual(ais) o(s) evento(s) de gatilho que dispararam a interrupção. Um handler de IRQ CAN deve chamar a função flags() repetidamente até devolver 0.

Quando a função flags() devolve com o bit CAN.IRQ_TX definido, o handler pode também verificar os seguintes bits de flag no resultado para obter informações adicionais sobre o evento TX:

  • O bit CAN.IRQ_TX_FAILED está definido se a transmissão falhou. Normalmente isto só acontecerá se CAN.cancel_send() foi chamado, embora também possa acontecer se o controlador entrar num 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. Será um inteiro no intervalo 0 a CAN.TX_QUEUE_LEN (exclusivo), e corresponderá ao resultado de uma chamada anterior a CAN.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 gatilho CAN.IRQ_TX estiver definido, o handler deve chamar flags() repetidamente até devolver 0, conforme mostrado neste exemplo. Caso contrário, as interrupções CAN podem não ser corretamente reativadas.