class CAN – шина связи controller area network

CAN реализует поддержку как классического CAN (bxCAN, используется на OpenMV Cam M4 и M7), так и CAN FD (FDCAN, используется на OpenMV Cam H7, H7 Plus и Pure Thermal) контроллеров. На физическом уровне шина CAN состоит из двух линий, RX и TX. Чтобы подключить OpenMV Cam к шине CAN, необходимо использовать приёмопередатчик CAN для преобразования логических сигналов CAN от MCU в корректные уровни напряжения на шине.

Классический CAN в режиме петлевого замыкания (без приёмопередатчика):

from pyb import CAN

can = CAN(1, CAN.LOOPBACK)

# Accept messages with id 123, 124, 125 or 126.
can.setfilter(0, CAN.LIST16, 0, (123, 124, 125, 126))

can.send("message!", 123)   # send a message with id 123
can.recv(0)                 # receive a message on FIFO 0

CAN FD со всеми включёнными дополнительными функциями (FD-кадр, переключение скорости передачи, расширенные идентификаторы кадров; фаза арбитража 500 кбит/с, фаза данных 1 Мбит/с):

from pyb import CAN

can = CAN(
    1,
    CAN.NORMAL,
    baudrate=500_000,
    brs_baudrate=1_000_000,
    sample_point=80,
)

# Accept any id in the range 0xFFF0 .. 0xFFFF.
can.setfilter(0, CAN.RANGE, 0, (0xFFF0, 0xFFFF))

can.send(b"a" * 64, 0xFFFF, fdf=True, brs=True, extframe=True)
can.recv(0)

Следующие функции модуля CAN и их аргументы доступны как для классических, так и для FD-контроллеров CAN, если не указано иное.

Конструкторы

class pyb.CAN(bus: int | str, *args, **kwargs)

Создаёт объект CAN на заданной шине bus (целочисленный индекс периферийного устройства, например, 1 для CAN1, 2 для CAN2). Без дополнительных параметров объект создаётся, но не инициализируется (он сохраняет предыдущие настройки шины, если они есть); если переданы дополнительные аргументы, шина инициализируется. См. CAN.init() для доступных параметров.

CAN(2) подключён к одним и тем же выводам разъёма на каждой OpenMV Cam, которая предоставляет pyb.CAN (M4 / M7 / H7 / H7 Plus / Pure Thermal):

Сигнал

Вывод разъёма

Примечания

RX

P3

TX

P2

Периферийное устройство CAN предоставляет только сигналы логического уровня; для управления реальной шиной CAN требуется внешний приёмопередатчик CAN.

pyb.CAN недоступен на OpenMV Cam N6.

Методы

init(mode: int, prescaler: int = 100, *, sjw: int = 1, bs1: int = 6, bs2: int = 8, auto_restart: bool = False, baudrate: int = 0, sample_point: int = 75, num_filter_banks: int = 14, brs_sjw: int = 1, brs_bs1: int = 8, brs_bs2: int = 3, brs_baudrate: int = 0, brs_sample_point: int = 75) None

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

  • mode — один из: NORMAL, LOOPBACK, SILENT, SILENT_LOOPBACK

  • prescaler — это значение, на которое делится входная тактовая частота CAN для генерации квантов времени номинального бита. Предделитель может принимать значение от 1 до 1024 включительно для классического CAN и от 1 до 512 включительно для CAN FD.

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

  • bs1 определяет расположение точки выборки в единицах квантов времени для номинальных битов; оно может принимать значение от 1 до 16 включительно для классического CAN и от 2 до 256 включительно для CAN FD.

  • bs2 определяет расположение точки передачи в единицах квантов времени для номинальных битов; оно может принимать значение от 1 до 8 включительно для классического CAN и от 2 до 128 включительно для CAN FD.

  • auto_restart задаёт, будет ли контроллер автоматически пытаться перезапустить связь после перехода в состояние bus-off; если эта функция отключена, то для выхода из состояния bus-off можно использовать restart()

  • baudrate если указана скорость передачи, отличная от 0, эта функция попытается автоматически вычислить номинальное битовое время CAN (переопределяя prescaler, bs1 и bs2), которое удовлетворяет как baudrate (с точностью до .1%), так и желаемой sample_point (с точностью до ближайшего 1%). Для более точного контроля над таймингом CAN задайте параметры prescaler, bs1 и bs2 напрямую.

  • sample_point задаёт позицию выборки бита относительно всего номинального битового времени, выраженную как целочисленный процент от номинального битового времени. По умолчанию sample_point равна 75%. Этот параметр игнорируется, если не задан baudrate.

  • num_filter_banks для классического CAN — это количество банков, которые будут назначены CAN(1), остальные из 28 назначаются CAN(2).

Остальные параметры присутствуют только на платах с поддержкой CAN FD и настраивают дополнительную функцию CAN FD Bit Rate Switch (BRS):

  • brs_prescaler — это значение, на которое делится входная тактовая частота CAN FD для генерации квантов времени бита данных. Предделитель может принимать значение от 1 до 32 включительно.

  • brs_sjw — это ширина скачка ресинхронизации в единицах квантов времени для битов данных; она может принимать значение от 1 до 16 включительно

  • brs_bs1 определяет расположение точки выборки в единицах квантов времени для битов данных; оно может принимать значение от 1 до 32 включительно

  • brs_bs2 определяет расположение точки передачи в единицах квантов времени для битов данных; оно может принимать значение от 1 до 16 включительно

  • brs_baudrate если указана скорость передачи, отличная от 0, эта функция попытается автоматически вычислить битовое время данных CAN (переопределяя brs_prescaler, brs_bs1 и brs_bs2), которое удовлетворяет как brs_baudrate (с точностью до .1%), так и желаемой brs_sample_point (с точностью до ближайшего 1%). Для более точного контроля над таймингом BRS задайте параметры brs_prescaler, brs_bs1 и brs_bs2 напрямую.

  • brs_sample_point задаёт позицию выборки бита относительно всего номинального битового времени, выраженную как целочисленный процент от номинального битового времени. По умолчанию brs_sample_point равна 75%. Этот параметр игнорируется, если не задан brs_baudrate.

Квант времени tq — это базовая единица времени для шины CAN. tq равно значению предделителя CAN, делённому на PCLK1 (частота внутренней периферийной шины 1); см. pyb.freq() для определения PCLK1.

Один бит состоит из сегмента синхронизации, который всегда равен 1 tq. Затем следует битовый сегмент 1, затем битовый сегмент 2. Точка выборки находится после окончания битового сегмента 1. Точка передачи находится после окончания битового сегмента 2. Скорость передачи будет равна 1/bittime, где bittime равно 1 + BS1 + BS2, умноженному на квант времени tq.

Например, на OpenMV Cam H7 (PCLK1 = 100 МГц) CAN со скоростью 250 кбит/с и точкой выборки 75% можно настроить как prescaler=25, sjw=1, bs1=11, bs2=4: tq = 25 / 100 MHz = 250 ns, bittime = (1 + 11 + 4) × 250 ns = 4 µs, точка выборки = (1 + 11) / 16 = 75%, а скорость передачи равна 1 / 4 µs = 250 kHz.

См. раздел bxCAN / FDCAN справочного руководства STM32 для MCU OpenMV Cam для получения более подробной информации.

deinit() None

Выключает шину CAN.

restart() None

Принудительно выполняет программный перезапуск контроллера CAN без сброса его конфигурации.

Если контроллер переходит в состояние bus-off, то он больше не участвует в активности на шине. Если контроллер не настроен на автоматический перезапуск (см. init()), то этот метод можно использовать для запуска перезапуска, и контроллер будет следовать протоколу CAN, чтобы выйти из состояния bus-off и перейти в активное состояние ошибки.

state() int

Возвращает состояние контроллера. Возвращаемое значение может быть одним из:

  • CAN.STOPPED — контроллер полностью выключен и сброшен;

  • CAN.ERROR_ACTIVE — контроллер включён и находится в активном состоянии ошибки (Error Active) (как TEC, так и REC меньше 96);

  • CAN.ERROR_WARNING — контроллер включён и находится в состоянии предупреждения об ошибке (Error Warning) (хотя бы одно из TEC или REC равно 96 или больше);

  • CAN.ERROR_PASSIVE — контроллер включён и находится в пассивном состоянии ошибки (Error Passive) (хотя бы одно из TEC или REC равно 128 или больше);

  • CAN.BUS_OFF — контроллер включён, но не участвует в активности на шине (TEC переполнился сверх 255).

info(list: list | None = None) list

Получает информацию о состояниях ошибок контроллера и буферах TX и RX. Если предоставлен list, то это должен быть объект списка как минимум с 8 элементами, которые будут заполнены этой информацией. В противном случае будет создан и заполнен новый список. В обоих случаях возвращаемым значением метода является заполненный список.

Значения в списке таковы:

  • значение TEC

  • значение REC

  • количество раз, когда контроллер переходил в состояние предупреждения об ошибке (Error Warning) (сбрасывается в 0 после 65535)

  • количество раз, когда контроллер переходил в пассивное состояние ошибки (Error Passive) (сбрасывается в 0 после 65535)

  • количество раз, когда контроллер переходил в состояние Bus Off (сбрасывается в 0 после 65535)

  • количество ожидающих сообщений TX

  • количество ожидающих сообщений RX в fifo 0

  • количество ожидающих сообщений RX в fifo 1

setfilter(bank: int, mode: int, fifo: int, params: Tuple[int, ...], *, rtr: Tuple[bool, ...] | None = None, extframe: bool = False) None

Настраивает банк фильтра:

  • bank — это банк фильтра классического контроллера CAN или индекс фильтра CAN FD, который нужно настроить.

  • mode — это режим, в котором должен работать фильтр, см. таблицы ниже.

  • fifo — это то, в каком fifo (0 или 1) должно храниться сообщение, если оно принято этим фильтром.

  • params — это массив значений, которые определяют фильтр. Содержимое массива зависит от аргумента mode.

Содержимое массива params для классических контроллеров CAN (OpenMV Cam M4 / M7):

mode

Содержимое params

CAN.LIST16

Четыре 16-битных ID, которые будут приняты.

CAN.LIST32

Два 32-битных ID, которые будут приняты.

CAN.MASK16

Две пары id/маска по 16 бит, например, (1, 3, 4, 4). Первая пара (1, 3) принимает все ID с битом 0 = 1 и битом 1 = 0; вторая пара (4, 4) принимает все ID с битом 2 = 1.

CAN.MASK32

Одна пара id/маска по 32 бита (в остальном то же самое, что CAN.MASK16).

Содержимое массива params для CAN FD контроллеров (OpenMV Cam H7 / H7 Plus / Pure Thermal):

mode

Содержимое params

CAN.RANGE

Два ID, образующих диапазон принимаемых ID.

CAN.DUAL

Два ID, которые будут приняты (например, (1, 2)).

CAN.MASK

Одна пара (id, mask) (например, (0x111, 0x7FF)).

  • rtr Для классических контроллеров CAN это массив булевых значений, который определяет, должен ли фильтр принимать сообщение запроса удалённой передачи (remote transmission request). Если этот аргумент не задан, по умолчанию для всех элементов используется False. Длина зависит от mode:

    mode

    len(rtr)

    Примечания

    CAN.LIST16

    4

    CAN.LIST32

    2

    CAN.MASK16

    2

    CAN.MASK32

    1

    Для CAN FD этот аргумент игнорируется.

  • extframe Если True, кадр будет иметь расширенный идентификатор (29 бит), в противном случае используется стандартный идентификатор (11 бит).

clearfilter(bank: int, extframe: bool = False) None

Очищает и отключает банк фильтра:

  • bank — это банк фильтра классического контроллера CAN или индекс фильтра CAN FD, который нужно очистить.

  • extframe Для контроллеров CAN FD, если True, очищает расширенный фильтр (настроенный с extframe=True), в противном случае очищает стандартный идентификатор (настроенный с extframe=False).

any(fifo: int) bool

Возвращает True, если на FIFO ожидает какое-либо сообщение, иначе False.

recv(fifo: int, list: list | None = None, *, timeout: int = 5000) list

Принимает данные на шине:

  • fifo — это целое число, обозначающее FIFO, на котором осуществляется приём

  • list — это необязательный объект списка, используемый в качестве возвращаемого значения

  • timeout — это тайм-аут в миллисекундах для ожидания приёма.

Возвращаемое значение: список, содержащий пять значений.

  • ID сообщения.

  • Булево значение, указывающее, является ли ID сообщения стандартным или расширенным.

  • Булево значение, указывающее, является ли сообщение RTR-сообщением.

  • Значение FMI (Filter Match Index).

  • Массив, содержащий данные.

Если list равен None, то будет выделен новый список, а также новый объект bytes для хранения данных (в качестве пятого элемента списка).

Если list не равен None, то это должен быть объект списка как минимум с пятью элементами. Пятый элемент должен быть объектом memoryview, созданным из bytearray или массива типа „B“ или „b“, и этот массив должен иметь достаточно места как минимум для 8 байт. Объект списка затем будет заполнен первыми четырьмя возвращаемыми значениями выше, а объект memoryview будет изменён по размеру на месте до размера данных и заполнен этими данными. Одни и те же объекты списка и memoryview можно повторно использовать в последующих вызовах этого метода, что обеспечивает способ приёма данных без использования кучи. Например:

buf = bytearray(8)
lst = [0, 0, 0, 0, memoryview(buf)]
# No heap memory is allocated in the following call
can.recv(0, lst)
send(data: int | bytes | bytearray, id: int, *, timeout: int = 0, rtr: bool = False, extframe: bool = False, fdf: bool = False, brs: bool = False) None

Отправляет сообщение на шине:

  • data — это данные для отправки (целое число для отправки или объект буфера).

  • id — это ID отправляемого сообщения.

  • timeout — это тайм-аут в миллисекундах для ожидания отправки.

  • rtr — это булево значение, которое определяет, должно ли сообщение быть отправлено как запрос удалённой передачи (remote transmission request). Если rtr равно True, то для заполнения слота DLC кадра используется только длина data; фактические байты в data не используются.

  • extframe если True, кадр будет иметь расширенный идентификатор (29 бит), в противном случае используется стандартный идентификатор (11 бит).

  • fdf для контроллеров CAN FD, если установлено в True, кадр будет иметь формат FD-кадра, который поддерживает полезную нагрузку данных до 64 байт.

  • brs для контроллеров CAN FD, если установлено в True, включается режим переключения скорости передачи, при котором фаза данных передаётся с другой скоростью. См. CAN.init() для параметров конфигурации тайминга бита данных.

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

Возвращаемое значение: None.

rxcallback(fifo: int, fun: Callable[[CAN, int], None] | None) None

Регистрирует функцию, которая будет вызвана, когда сообщение принимается в пустой FIFO:

  • fifo — это принимающий FIFO.

  • fun — это функция, которая будет вызвана, когда FIFO станет непустым.

Функция обратного вызова принимает два аргумента: первый — это сам объект CAN; второй — это целое число, указывающее причину вызова:

Причина

Значение

0

Сообщение принято в пустой FIFO.

1

FIFO заполнен.

2

Сообщение потеряно из-за заполненного FIFO.

Пример использования rxcallback:

def cb0(bus, reason):
  print('cb0')
  if reason == 0:
      print('pending')
  if reason == 1:
      print('full')
  if reason == 2:
      print('overflow')

can = CAN(1, CAN.LOOPBACK)
can.rxcallback(0, cb0)

Константы

Константы режима шины (аргумент mode метода init()):

NORMAL: int

Контроллер участвует в работе шины обычным образом — передаёт собственные кадры и подтверждает корректно принятые кадры.

LOOPBACK: int

Внутренний режим петлевого замыкания: контроллер отключён от выводов и направляет переданные кадры прямо обратно на путь приёма. Полезно для самотестирования без приёмопередатчика.

SILENT: int

Режим только прослушивания: контроллер принимает кадры, но никогда не управляет шиной (нет ACK, нет передач). Полезно для прослушивания шины.

SILENT_LOOPBACK: int

Сочетает SILENT и LOOPBACK: нет активности на выводах и нет подтверждений, с внутренним петлевым замыканием TX на RX.

Константы состояния контроллера (возвращаются методом state()):

STOPPED: int

Контроллер полностью выключен и сброшен.

ERROR_ACTIVE: int

Контроллер включён и находится в активном состоянии ошибки (Error Active) (как TEC, так и REC меньше 96).

ERROR_WARNING: int

Контроллер включён и находится в состоянии предупреждения об ошибке (Error Warning) (хотя бы одно из TEC или REC равно 96 или больше).

ERROR_PASSIVE: int

Контроллер включён и находится в пассивном состоянии ошибки (Error Passive) (хотя бы одно из TEC или REC равно 128 или больше).

BUS_OFF: int

Контроллер включён, но не участвует в активности на шине (TEC переполнился сверх 255).

Режимы фильтра классического CAN (аргумент mode метода setfilter() на OpenMV Cam M4 / M7):

LIST16: int

Массив фильтра params содержит четыре 16-битных ID, которые будут приняты.

LIST32: int

Массив фильтра params содержит два 32-битных ID, которые будут приняты.

MASK16: int

Массив фильтра params содержит две пары (id, mask) по 16 бит.

MASK32: int

Массив фильтра params содержит одну пару (id, mask) по 32 бита.

Режимы фильтра CAN FD (аргумент mode метода setfilter() на OpenMV Cam H7 / H7 Plus / Pure Thermal):

RANGE: int

Массив фильтра params содержит два ID, образующих диапазон принимаемых ID.

DUAL: int

Массив фильтра params содержит два конкретных ID для приёма.

MASK: int

Массив фильтра params содержит одну пару (id, mask).