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.
Состояния¶
Эти значения возвращаются
CAN.state()и отражают состояние ошибки контроллера CAN:- 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_EXT_ID: int¶
Если установлен, указывает, что идентификатор сообщения является расширенным (29-битным). Если не установлен, указывает, что идентификатор сообщения является стандартным (11-битным).
- FLAG_UNORDERED: int¶
Если установлен в аргументе
flagsфункцииCAN.send(), указывает, что допустимо отправлять сообщения с одинаковым CAN ID на шину в любом порядке.В противном случае попытка поставить в очередь несколько сообщений с одинаковым ID может привести к сбою
CAN.send(), если аппаратное обеспечение контроллера не может обеспечить упорядочивание.Этот флаг никогда не устанавливается на принятых сообщениях и игнорируется
CAN.set_filters().
Флаги ошибок приёма¶
Результат
CAN.recv()включает целочисленное значение, составленное из нуля или более этих флагов, объединённых побитовым ИЛИ. Если установлены, эти флаги указывают на потенциальные общие проблемы с приёмом сообщений CAN.Значения 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 могут быть некорректно повторно включены.