class CAN – протокол Controller Area Network

CAN – это двухпроводной последовательный протокол, используемый для надёжной доставки сообщений в реальном времени между одним или несколькими узлами, подключёнными к общей шине. CAN 2.0 был стандартизирован в ISO-11898 и теперь также известен как CAN Classic.

Существует также более новый, обратно совместимый протокол под названием CAN FD (CAN with Flexible Data-Rate). Драйвер machine.CAN в настоящее время не поддерживает функции CAN FD; используйте pyb.CAN на STM32, если вам нужен CAN FD.

Поддержка CAN требует наличия контроллера (часто это внутреннее периферийное устройство микроконтроллера) и внешнего приёмопередатчика для согласования уровней сигналов на шине CAN.

Доступно на камерах OpenMV на базе STM32 (M4 / M7 / H7 / H7 Plus / Pure Thermal / N6, а также вариантах под маркой Arduino, в которых разведён приёмопередатчик). Пока не поддерживается на OpenMV Cam RT1062 (порт mimxrt) и OpenMV Cam AE3 (порт alif).

Интерфейс machine.CAN – это низкоуровневый базовый интерфейс обмена сообщениями CAN, который представляет контроллер CAN в виде исходящей приоритетной очереди для отправки сообщений, входящей очереди для приёма сообщений и механизмов сообщения об ошибках.

Примечание

Планируемые модули micropython-lib can и aiocan станут рекомендуемым способом использования CAN в MicroPython.

Конструктор

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

Создаёт объект контроллера CAN с заданным id:

  • id идентифицирует конкретный объект контроллера CAN; он зависит от платы и порта.

  • Все остальные аргументы передаются в CAN.init(). Должен быть указан как минимум один аргумент (bitrate).

Будущие версии этого класса могут также принимать здесь специфичные для порта именованные аргументы, которые настраивают оборудование. В настоящее время такие именованные аргументы не реализованы.

Пример

Создать и инициализировать контроллер CAN 1 со скоростью передачи 500 кбит/с:

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

Методы

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

Инициализирует шину CAN с заданными параметрами:

  • bitrate – желаемая скорость передачи данных по шине в битах в секунду.

  • mode – одно из значений, показанных в разделе Режимы, указывающее желаемый режим работы. По умолчанию используется «нормальный» режим работы на шине.

Следующие параметры являются необязательными и относятся к временным характеристикам битов CAN. В большинстве случаев вы можете оставить эти параметры со значениями по умолчанию:

  • sample_point – целочисленный процент от времени бита данных. Он задаёт положение точки выборки бита относительно всего номинального времени бита. Драйвер CAN рассчитает параметры соответствующим образом. Этот параметр игнорируется, если заданы tseg1 и tseg2.

  • sjw – ширина скачка ресинхронизации в единицах квантов времени для номинальных битов; для классического CAN это значение может быть от 1 до 4 включительно.

  • tseg1 задаёт положение точки выборки в единицах квантов времени для номинальных битов; для классического CAN это значение может быть от 1 до 16 включительно. Это сумма фаз Prop_Seg и Phase_Seg1, определённых в стандарте ISO-11898. Если это значение задано, то должно быть задано и tseg2, а sample_point игнорируется.

  • tseg2 задаёт положение точки передачи в единицах квантов времени для номинальных битов; для классического CAN это значение может быть от 1 до 8 включительно. Оно соответствует Phase_Seg2 в стандарте ISO-11898. Если это значение задано, то должно быть задано и tseg1.

Если эти аргументы указаны, то контроллер CAN корректно настраивается для желаемой bitrate и заданного общего числа квантов времени на бит. Значения tseg1 и tseg2 переопределяют аргумент sample_point, если предоставлены все они.

Примечание

Конкретное аппаратное обеспечение контроллера может иметь дополнительные ограничения на допустимые значения этих параметров и вызовет ValueError, если заданное значение не поддерживается.

Примечание

Конкретное аппаратное обеспечение контроллера может принимать дополнительные необязательные именованные параметры для аппаратно-зависимых функций, таких как избыточная дискретизация.

set_filters(filters: list | tuple | None) None

Устанавливает фильтры приёма в контроллере CAN. filters может быть:

  • None – чтобы принимать все входящие сообщения, или

  • [] либо () – чтобы отключить приём всех сообщений, или

  • Итерируемый объект из одного или нескольких элементов, определяющих критерии фильтрации. Каждый элемент должен быть кортежем или списком из трёх элементов:

    • identifier – идентификатор CAN (int).

    • bit_mask – битовая маска для битов в поле идентификатора CAN (int).

    • flags – целое число с нулём или более установленными битами, определёнными в Флаги сообщений. Оно задаёт свойства, которым должно соответствовать входящее сообщение. Не все контроллеры поддерживают фильтрацию по всем флагам; если запрошен неподдерживаемый флаг, вызывается ValueError.

Входящие сообщения принимаются, если биты, замаскированные в bit_mask, совпадают между идентификатором сообщения и значением фильтра identifier, а флаги, установленные в фильтре, соответствуют входящему сообщению.

Если в флагах установлен бит CAN.FLAG_EXT_ID, фильтр соответствует только расширенным CAN ID. Если бит CAN.FLAG_EXT_ID не установлен, фильтр соответствует только стандартным CAN ID.

Все фильтры в контроллере объединяются по ИЛИ. Передача пустого списка или кортежа в качестве аргумента filters означает, что ни одно сообщение не будет приниматься.

Некоторые контроллеры CAN требуют, чтобы каждый фильтр был связан только с одним приёмным FIFO. В таких случаях элементы фильтров в аргументе распределяются по доступным FIFO по круговому принципу. Этот драйвер не различает FIFO в IRQ приёма.

Примечание

Если вызывающая сторона передаёт итерируемый объект с числом элементов, превышающим CAN.FILTERS_MAX, будет вызвано ValueError.

Примечание

Если либо identifier, либо bit_mask выходит за допустимый диапазон для указанного типа ID, будет вызвано ValueError с причиной «invalid id».

Примеры

Принимать все входящие сообщения:

can.set_filters(None)

Принимать только сообщения со стандартными значениями ID 0x301 и 0x700:

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

Принимать только сообщения со стандартными значениями ID в диапазоне 0x300-0x3FF и расширенным значением ID 0x50700:

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

Константа, считывающая максимальное число поддерживаемых фильтров приёма для данного аппаратного контроллера.

Обратите внимание, что некоторые контроллеры могут иметь более сложные аппаратные ограничения на число используемых фильтров (например, независимый подсчёт фильтров стандартных и расширенных ID). В таких случаях CAN.set_filters может вызвать ValueError даже когда предел FILTERS_MAX не превышен.

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

Копирует новое сообщение CAN в аппаратную очередь передачи контроллера для отправки на шину. Очередь передачи – это приоритетная очередь, отсортированная по приоритету идентификатора CAN (меньшие числовые идентификаторы имеют более высокий приоритет).

  • id – целочисленное значение идентификатора CAN.

  • data – объект bytes (или подобный), содержащий данные сообщения CAN или описывающий Remote Transmission Request (см. ниже).

  • flags – целое число с нулём или более установленными битами, определёнными в Флаги сообщений, задающее свойства исходящего сообщения CAN (расширенный ID, Remote Transmission Request и т. д.)

Если сообщение успешно поставлено в очередь на передачу по шине, функция возвращает целое число в диапазоне от 0 до CAN.TX_QUEUE_LEN (не включая). Это значение – индекс буфера передачи, в который поставлено сообщение, и его можно использовать в функции CAN.cancel_send и в событиях CAN.IRQ_TX.

Если очередь заполнена, отправка завершится неудачей и будет возвращено None.

Отправка также может завершиться неудачей и вернуть None, если предоставленное значение id имеет приоритет, равный приоритету существующего сообщения в очереди передачи, и аппаратное обеспечение контроллера CAN не может гарантировать, что сообщения с одинаковым ID будут отправлены на шину в том же порядке, в котором они были добавлены в очередь. Чтобы всё равно поставить сообщение в очередь, передайте флаг CAN.FLAG_UNORDERED в аргументе flags. Этот флаг указывает, что допустимо отправлять сообщения с одинаковым CAN ID на шину в любом порядке.

Если контроллер находится в состоянии ошибки «Bus Off» или отключён, то вызов этой функции вызовет OSError.

Примечание

Эта намеренно низкоуровневая реализация спроектирована так, чтобы вызывающая сторона могла организовать программную очередь исходящих сообщений.

Важно

«Очередь передачи» CAN – это не FIFO-очередь, она упорядочена по приоритету, и хотя она может содержать до CAN.TX_QUEUE_LEN элементов, могут существовать и другие аппаратные ограничения на сообщения, которые можно поставить в очередь одновременно.

Remote Transmission Requests

Если в аргументе flags установлен бит CAN.FLAG_RTR, то контроллер отправит Remote Transmission Request вместо сообщения. В этом случае содержимое аргумента data игнорируется. Контроллер отправит запрос, в котором поле длины DLC равно длине аргумента data.

Примеры

Попытка отправить сообщение с трёхбайтовой полезной нагрузкой 0a0b0c и стандартным ID 0x200:

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

Попытка отправить сообщение с пустой полезной нагрузкой и расширенным ID 0x180008. Указать, что контроллер может отправлять сообщения с этим ID в любом порядке, на случай, если другие сообщения с тем же ID уже стоят в очереди на отправку:

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

Попытка отправить Remote Transmission Request длиной 8 байт со стандартным ID 0x555:

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

Возвращает сообщение CAN, принятое контроллером, в соответствии с фильтрами, установленными CAN.set_filters().

Эта функция принимает один необязательный аргумент; если он предоставлен, то это должен быть список как минимум из 4 элементов, где второй элемент – это объект memoryview, ссылающийся на bytearray или подобный объект, имеющий достаточную ёмкость для хранения любого принятого сообщения CAN (8 байт для CAN Classic, 64 байта для CAN FD). Предоставленный список будет возвращён как успешный результат, что позволяет избежать выделения памяти внутри функции.

Если контроллером CAN не было принято ни одного сообщения, эта функция возвращает None.

Примечание

Перед тем как контроллер сможет принимать какие-либо сообщения, должна быть вызвана CAN.set_filters. Чтобы принимать все сообщения, вызовите set_filters(None).

Если сообщение было принято контроллером CAN, эта функция возвращает список из 4 элементов:

  • Индекс 0 – это CAN ID принятого сообщения в виде целого числа.

  • Индекс 1 – это memoryview, обеспечивающий доступ к данным принятого сообщения.

    • Если arg не предоставлен, то это memoryview, содержащий принятые байты. Этот memoryview опирается на вновь выделенный bytearray, достаточно большой для хранения любого принятого сообщения CAN. Это позволяет безопасно повторно использовать результат в качестве будущего arg, чтобы сэкономить на выделениях памяти.

    • Если arg предоставлен, то предоставленный memoryview будет изменён по размеру так, чтобы вместить ровно принятые байты. Вызывающая сторона отвечает за то, чтобы базовый объект для memoryview мог вместить сообщение CAN любой длины.

  • Индекс 2 – это целое число с нулём или более установленными битами, определёнными в Флаги сообщений. Оно указывает метаданные о принятом сообщении.

  • Индекс 3 – это целое число с нулём или более установленными битами, определёнными в Флаги ошибок приёма. Любое ненулевое значение указывает на потенциальные проблемы при приёме сообщений CAN. Эти флаги сбрасываются внутри контроллера каждый раз, когда эта функция возвращает результат.

Remote Transmission Requests

Если принят Remote Transmission Request, то в индексе 2 будет установлен бит CAN.FLAG_RTR, а memoryview в индексе 1 будет содержать одни нули с длиной, равной полю DLC принятого запроса.

Пример
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

Устанавливает функцию-обработчик прерывания handler, вызываемую, когда произошло одно или несколько событий, отмеченных в trigger.

  • handler – функция, вызываемая при срабатывании события прерывания. Обработчик должен принимать ровно один аргумент – экземпляр CAN.

  • trigger настраивает событие(я), которые могут генерировать прерывание. Возможные значения – это маска одного или нескольких из следующих:

    • Событие CAN.IRQ_RX возникает после того, как контроллер CAN принял хотя бы одно сообщение в свой RX FIFO (что означает, что CAN.recv() завершится успешно).

    • Событие CAN.IRQ_TX возникает после того, как контроллер CAN либо успешно отправил сообщение на шину CAN, либо не смог его отправить. У этого триггера есть дополнительные требования к обработчику, подробности см. в Флаги IRQ.

    • Событие CAN.IRQ_STATE возникает, когда контроллер CAN перешёл в более серьёзное состояние ошибки. Вызовите CAN.state(), чтобы получить обновлённое состояние.

  • hard – если True, используется аппаратное прерывание. Это уменьшает задержку между событием контроллера CAN и вызовом обработчика. Аппаратные обработчики прерываний не могут выделять память; см. Написание обработчиков прерываний.

Возвращает объект irq. При вызове без аргументов возвращается ранее настроенный объект irq.

Пример см. в Флаги IRQ.

cancel_send(index: int) bool

Запрашивает у контроллера CAN отмену отправки сообщения на шину.

Аргумент index идентифицирует один буфер передачи. Это должно быть целое число в диапазоне от 0 до CAN.TX_QUEUE_LEN (не включая). Обычно это значение, ранее возвращённое CAN.send().

Результат равен True, если сообщение ожидало передачи в этом буфере и передача была отменена.

В противном случае результат равен False (либо сообщение не ожидало передачи в этом буфере, либо передача уже завершилась успешно).

Для определения того, было ли сообщение действительно отправлено, следует использовать событие IRQ CAN.IRQ_TX, но учтите, что возможны состояния гонки, если передача отменяется, а затем тот же буфер используется для отправки другого сообщения (особенно если IRQ контроллера CAN не является «hard»).

state() int

Возвращает целочисленное значение, указывающее текущее состояние контроллера. Значение будет одним из значений, определённых в Состояния.

Состояния ошибок меньшей серьёзности могут автоматически сбрасываться при восстановлении шины, но из состояния CAN.STATE_BUS_OFF можно выйти только вызовом CAN.restart().

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

Возвращает значения счётчиков ошибок контроллера. Результат – список из восьми значений. Если указан необязательный параметр list, то предоставленный объект списка обновляется и возвращается в качестве результата, чтобы избежать выделения памяти.

Элементы списка:

  • Значение TEC (Transmit Error Counter)

  • Значение REC (Receive Error Counter)

  • Число раз, когда контроллер переходил из активного состояния в состояние предупреждения.

  • Число раз, когда контроллер переходил из состояния предупреждения в состояние Error Passive.

  • Число раз, когда контроллер переходил из состояния Error Passive в состояние Bus Off.

  • Общее число ожидающих TX-сообщений в аппаратной очереди.

  • Общее число ожидающих RX-сообщений в аппаратной очереди.

  • Число раз, когда происходило переполнение приёма (RX overrun).

Примечание

В зависимости от контроллера эти значения после определённого значения могут переполняться обратно в 0.

Примечание

Если контроллер не поддерживает определённый счётчик, для этого элемента списка он вернёт None.

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

Возвращает список элементов, указывающих текущие временные характеристики, настроенные в контроллере CAN. Это можно использовать для проверки временных характеристик в целях отладки. Результат – список из шести значений. Если указан необязательный параметр list, то предоставленный объект списка обновляется и возвращается в качестве результата, чтобы избежать выделения памяти.

Элементы списка:

  • Точная скорость передачи, используемая контроллером. Может отличаться от аргумента bitrate, переданного в CAN.init(), из-за квантования для соблюдения аппаратных ограничений.

  • Ширина скачка ресинхронизации (SJW) в единицах квантов времени для номинальных битов. Имеет тот же смысл, что и параметр sjw функции CAN.init().

  • Положение точки выборки в единицах квантов времени для номинальных битов. Имеет тот же смысл, что и параметр tseg1 функции CAN.init().

  • Положение точки передачи в единицах квантов времени для номинальных битов. Имеет тот же смысл, что и параметр tseg2 функции CAN.init().

  • Информация о временных характеристиках CAN FD. None для контроллеров, не поддерживающих CAN FD, или если CAN FD не инициализирован. В противном случае – вложенный список из четырёх элементов, соответствующих перечисленным выше элементам, но применимых к функции CAN FD BRS.

  • Необязательная специфичная для контроллера информация о временных характеристиках. В зависимости от контроллера это будет либо None, если контроллер ничего не сообщает, либо список постоянной длины, элементы которого специфичны для конкретного аппаратного контроллера.

Примечание

Если CAN.init() не была вызвана, эта функция всё равно возвращает результат, но результат зависит от внутреннего устройства контроллера и может быть неточным.

restart() None

Заставляет контроллер выйти из STATE_BUS_OFF без сброса какого-либо другого внутреннего состояния. Также сбрасывает некоторые счётчики ошибок (всегда число раз входа в каждое состояние ошибки, возможно, TEC и REC в зависимости от контроллера).

Вызов этой функции также отменяет все сообщения, ожидающие отправки. Для этих сообщений прерывания IRQ_TX не доставляются.

Обратите внимание, что эта функция может вывести или не вывести контроллер из состояния «Error Passive», в зависимости от того, обнуляет ли аппаратное обеспечение контроллера TEC и REC.

deinit() None

Деинициализирует ранее активный экземпляр CAN. Все ожидающие сообщения (передачи и приёма) отбрасываются, и контроллер прекращает взаимодействие на шине. Чтобы снова использовать этот экземпляр, вызовите CAN.init().

В ответ на вызов этой функции не вызываются прерывания IRQ_TX или IRQ_RX.

См. также CAN.restart().

Константы

TX_QUEUE_LEN: int

Максимальное число сообщений CAN, которые можно поставить в исходящую аппаратную очередь сообщений контроллера. «Индексы буферов передачи», используемые CAN.send(), CAN.cancel_send() и Флаги IRQ, будут находиться в этом диапазоне.

Режимы

Эти значения представляют режимы работы контроллера, передаваемые в CAN.init(). Не все контроллеры могут поддерживать все режимы.

Изменение режима работающего контроллера требует вызова CAN.deinit() и последующего повторного вызова CAN.init() с новым режимом.

MODE_NORMAL: int

Контроллер активен как стандартный узел сети CAN (будет подтверждать корректные сообщения и может передавать ошибки в зависимости от своего текущего состояния).

MODE_SLEEP: int

Контроллер CAN находится в спящем режиме энергосбережения. В зависимости от контроллера это может поддерживать пробуждение контроллера и переход в CAN.MODE_NORMAL при получении трафика CAN.

MODE_LOOPBACK: int

Тестовый режим. Контроллер CAN по-прежнему подключён к внешней шине, но также будет принимать свои собственные передаваемые сообщения и игнорировать любые ошибки ACK.

MODE_SILENT: int

Контроллер CAN принимает сообщения, но не взаимодействует с шиной CAN (включая отправку ACK, ошибок и т. д.)

MODE_SILENT_LOOPBACK: int

Тестовый режим, который вообще не требует подключения приёмопередатчика CAN. Контроллер CAN принимает свои собственные передаваемые сообщения, вообще не взаимодействуя с шиной CAN. Выводы TX и RX CAN остаются в режиме ожидания.

Состояния

Эти значения возвращаются CAN.state() и отражают состояние ошибки контроллера CAN:

STATE_STOPPED: int

Контроллер не был инициализирован.

STATE_ACTIVE: int

Контроллер активен, и счётчики ошибок TEC и REC оба ниже порога предупреждения 96. См. CAN.get_counters().

STATE_WARNING: int

Контроллер активен, но хотя бы один из счётчиков ошибок TEC и REC находится в диапазоне от 96 до 127. См. CAN.get_counters().

STATE_PASSIVE: int

Контроллер находится в состоянии «Error Passive», что означает, что он больше не передаёт активные ошибки на шину, но в остальном функционирует. В это состояние происходит вход, когда хотя бы один из счётчиков ошибок TEC и REC равен 128 или больше, но TEC меньше 255. См. CAN.get_counters().

STATE_BUS_OFF: int

Контроллер находится в состоянии Bus-Off, что означает, что счётчик ошибок TEC больше 255. В этом состоянии контроллер CAN не взаимодействует с шиной, и его необходимо перезапустить через CAN.restart() для продолжения работы.

Флаги сообщений

Эти значения представляют метаданные о сообщении CAN. Функции CAN.send(), CAN.recv() и CAN.set_filters() либо принимают, либо возвращают целочисленное значение, составленное из нуля или более этих флагов, объединённых побитовым ИЛИ.

FLAG_RTR: int

Указывает, что сообщение является remote transmission request.

FLAG_EXT_ID: int

Если установлен, указывает, что идентификатор сообщения является расширенным (29-битным). Если не установлен, указывает, что идентификатор сообщения является стандартным (11-битным).

FLAG_UNORDERED: int

Если установлен в аргументе flags функции CAN.send(), указывает, что допустимо отправлять сообщения с одинаковым CAN ID на шину в любом порядке.

В противном случае попытка поставить в очередь несколько сообщений с одинаковым ID может привести к сбою CAN.send(), если аппаратное обеспечение контроллера не может обеспечить упорядочивание.

Этот флаг никогда не устанавливается на принятых сообщениях и игнорируется CAN.set_filters().

Флаги ошибок приёма

Результат CAN.recv() включает целочисленное значение, составленное из нуля или более этих флагов, объединённых побитовым ИЛИ. Если установлены, эти флаги указывают на потенциальные общие проблемы с приёмом сообщений CAN.

RECV_ERR_FULL: int

Аппаратное FIFO, в котором было принято это сообщение, заполнено, и дополнительные входящие сообщения могут быть потеряны.

RECV_ERR_OVERRUN: int

Аппаратное FIFO, в котором было принято это сообщение, заполнено, и одно или несколько входящих сообщений были потеряны.

Значения IRQ

IRQ_RX: int

Передайте в аргумент trigger метода irq(), чтобы запускать обработчик каждый раз, когда контроллер CAN принял полное сообщение в RX FIFO. Внутри обработчика считывайте сообщение с помощью recv().

IRQ_TX: int

Передайте в аргумент trigger метода irq(), чтобы запускать обработчик каждый раз, когда контроллер CAN завершает попытку передачи (успешную или неудачную). Внутри обработчика используйте дополнительные биты ниже, чтобы определить, какой почтовый ящик завершился и не произошёл ли сбой – см. Флаги IRQ.

IRQ_STATE: int

Передайте в аргумент trigger метода irq(), чтобы запускать обработчик каждый раз, когда контроллер переходит между значениями STATE_* (active / warning / passive / bus-off). Используйте state() внутри обработчика, чтобы прочитать новое состояние.

IRQ_TX_FAILED: int

Флаг состояния, который может быть установлен в irq().flags() при срабатывании события IRQ_TX. Указывает, что попытка передачи завершилась неудачей (обычно потому, что был вызван cancel_send() или контроллер перешёл в состояние ошибки).

IRQ_TX_IDX_SHIFT: int

Битовая позиция поля индекса почтового ящика передачи внутри значения irq().flags() во время события IRQ_TX. Индекс почтового ящика извлекается как (flags >> IRQ_TX_IDX_SHIFT) & IRQ_TX_IDX_MASK.

IRQ_TX_IDX_MASK: int

Битовая маска поля индекса почтового ящика передачи внутри значения irq().flags() во время события IRQ_TX. Извлечённый индекс совпадает с целым числом, возвращённым соответствующим вызовом send() (int в диапазоне от 0 до TX_QUEUE_LEN).

Флаги IRQ

Вызов CAN.irq() регистрирует обработчик прерывания с одним или несколькими триггерами CAN.IRQ_RX, CAN.IRQ_TX и CAN.IRQ_STATE.

Функция возвращает объект IRQ, и вызов функции flags() на этом объекте возвращает целое число, указывающее, какое событие(я) триггера вызвало прерывание. Обработчик IRQ CAN должен вызывать функцию flags() многократно, пока она не вернёт 0.

Когда функция flags() возвращает результат с установленным битом CAN.IRQ_TX, обработчик может также проверить следующие биты флагов в результате для получения дополнительной информации о событии TX:

  • Бит CAN.IRQ_TX_FAILED установлен, если передача завершилась неудачей. Обычно это происходит только при вызове CAN.cancel_send(), хотя это может также произойти, если контроллер переходит в состояние ошибки.

  • CAN.IRQ_TX_IDX_MASK << CAN.IRQ_TX_IDX_SHIFT – это битмаскированная область значения флагов, содержащая индекс буфера передачи, который сгенерировал событие. Это будет целое число в диапазоне от 0 до CAN.TX_QUEUE_LEN (не включая) и будет совпадать с результатом предыдущего вызова CAN.send().

Пример 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)

Важно

Если установлен триггер CAN.IRQ_TX, то обработчик должен вызывать flags() многократно, пока она не вернёт 0, как показано в этом примере. В противном случае прерывания CAN могут быть некорректно повторно включены.