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:

  • id identifica 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_Seg e Phase_Seg1 conforme 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_Seg2 na 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 ValueError se 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:

  • None para aceitar todas as mensagens recebidas, ou

  • [] ou () para desabilitar todo o recebimento de mensagens, ou

  • Um 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; um ValueError é levantado se uma flag não suportada for solicitada.

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

Se o bit CAN.FLAG_EXT_ID estiver definido em 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 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, um ValueError será levantado.

Nota

Se identifier ou bit_mask estiver fora do intervalo para o tipo de ID especificado, um ValueError com 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_filters pode levantar 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 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 0 a CAN.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ção CAN.cancel_send e em eventos CAN.IRQ_TX.

Se a fila estiver cheia, o envio falhará e None será retornado.

O envio também pode falhar e retornar None se 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 flag CAN.FLAG_UNORDERED no 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_LEN itens, 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_RTR estiver 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 comprimento DLC é igual ao comprimento do argumento data.

Exemplos

Tenta enviar uma mensagem com payload de três bytes 0a0b0c e 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 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á 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_filters deve ser chamada antes que qualquer mensagem possa ser recebida pelo controlador. Para receber todas as mensagens, chame set_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 memoryview contendo os bytes que foram recebidos. Esse memoryview é respaldado por um bytearray recé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 memoryview fornecido será redimensionado para conter exatamente os bytes que foram recebidos. O chamador é responsável por garantir que o objeto de respaldo do memoryview possa 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_RTR será definido no Índice 2 e o memoryview no Índice 1 conterá apenas zeros, com um comprimento igual ao campo DLC da 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_RX ocorre após o controlador CAN ter recebido pelo menos uma mensagem em sua FIFO de 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 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_STATE ocorre quando o controlador CAN faz a transição para um estado de erro mais grave. Chame CAN.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 0 a CAN.TX_QUEUE_LEN (exclusivo). Geralmente, este será um valor previamente retornado 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 nenhuma mensagem estava pendente de transmissão neste buffer, ou a transmissão já teve sucesso).

O evento IRQ CAN.IRQ_TX deve 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_OFF só pode ser recuperado chamando CAN.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á None para 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. None para 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á None se 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_OFF sem 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_TX ou IRQ_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 chamar CAN.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_NORMAL se 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.

MODE_SILENT: int

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

MODE_SILENT_LOOPBACK: int

Um modo de teste que não requer que um transceptor CAN esteja conectado de forma alguma. O controlador CAN recebe suas próprias mensagens transmitidas sem interagir com o barramento CAN de modo algum. Os pinos TX e RX do CAN permanecem ociosos.

Estados

Esses valores são retornados 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 erro TEC e REC estão ambos abaixo do limiar de aviso de 96. Veja CAN.get_counters().

STATE_WARNING: int

O controlador está ativo, mas pelo menos um dos contadores de erro TEC e REC está entre 96 e 127. Veja CAN.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 TEC e REC é 128 ou maior, mas o TEC é menor que 255. Veja CAN.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 via CAN.restart() para continuar.

Flags de Mensagem

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

FLAG_RTR: int

Indica que uma mensagem é uma solicitação de transmissão remota.

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 flags de CAN.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.

RECV_ERR_FULL: int

A FIFO de hardware onde esta mensagem foi recebida está cheia, e mensagens recebidas adicionais podem ser perdidas.

RECV_ERR_OVERRUN: int

A FIFO de hardware onde esta mensagem foi recebida está cheia, e uma ou mais mensagens recebidas foram perdidas.

Valores de IRQ

IRQ_RX: int

Passe para o argumento trigger de irq() 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 com recv().

IRQ_TX: int

Passe para o argumento trigger de irq() 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 trigger de irq() para disparar o handler toda vez que o controlador fizer a transição entre os valores STATE_* (ativo / aviso / passive / bus-off). Use state() dentro do handler para ler o novo estado.

IRQ_TX_FAILED: int

Flag de status que pode ser definida em irq().flags() quando um evento IRQ_TX é disparado. Indica que a tentativa de transmissão falhou (normalmente porque cancel_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 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 de mailbox de transmissão dentro do valor irq().flags() durante um evento IRQ_TX. O índice extraído corresponde ao inteiro retornado pela chamada send() correspondente (um int no intervalo de 0 a TX_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á se CAN.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 de 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 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.