Философия Do It Yourself или DIY звучит как «Развития навыков и уверенности в себе, получение удовольствия от процесса созидания.» В современных реалиях на столе изобретателя сходятся автоматизированные системы управления, недорогие микроконтроллеры и облачные AI-сервисы. Энтузиасты строят умные устройства, домашние SCADA-приложения и даже цифровые двойники, интегрируя машинное обучение для анализа данных в реальном времени.
В этом проекте постараемся реализовать управление маломощным электроприводом по CAN-шине. А в следующем проекте добавим коммуникацию с другим PLC-устройством, интегрируем систему с IoT. А затем посмотрим можно ли переложить задачу анализа работы системы на AI-агента не прилагая значительных усилий.
Содержимое статьи излагается следующим образом. Вначале краткое описание CAN-шины и методов проектирования для пользовательских проектов. Затем модификация проекта управления приводом PMSM комплекта разработки STM32-IHM03 и тестирование полученного результата.
Цели проекта
Текущая статья
-
Исследование возможности реализации пользовательской логики в исходном коде проекта P-IHM.
-
Создание базы данных CAN-сообщений
-
Реализация CAN-интерфейса согласно требованиям, описанным ниже.
-
Тестирование обмена данными по CAN-шине
Следующая статья
-
Проектирование простого альтернативного HMI-интерфейса.
-
Интеграция IHM03 с другими MCU и протоколами обмена данными.
-
Прототип системы анализа режима работы привода за короткий промежуток времени с помощью AI-агента.
CAN-шина краткий экскурс
Этот раздел представляет собой некоторую сводную теоретическую памятку по CANBUS-протоколу на основе представленных источников. Далее опишем, что и как из этого применяется на практике. Читатель может смело продолжать со следующих разделов, если уже хорошо знаком с протоколом.
По основам CANBUS можно почитать статьи:
Стандарт CANBUS был разработан Bosh в 1986 и стал де-факто применяться в автомобильной промышленности для обмена данными между электронными блоками. Вместо того чтобы тянуть сотни отдельных проводов от каждого датчика к блоку управления, используется одна общая шина (пара проводов). На практике топология сети современного транспорта гораздо сложнее, но идея остается прежней.
Причины выбора CANBUS для проекта.
-
Необходимость коммуникации с другими устройствами, оснащенными CANBUS. В нашем примере комплект разработки STM32-IHM03 уже оснащен виртуальным ком-портом (USB) для связи с PC о чем я расскажу ниже. И это может быть вполне достаточно. Однако пользовательское решение передачи данных позволяет следующее:
-
передавать только необходимые значения
-
произвольно выбирать структуру и формат данных
-
устанавливать необходимую периодичность обмена данных
-
использовать удобный физический интерфейс
-
-
Надежная и устойчивая к электромагнитным помехам система. Для демо-проекта может не столь важно, но если речь идет о транспорте или других системах связанных с безопасностью движения, выбор CANBUS будет оправдан.
-
Относительно простая и дешевая в реализации коммуникация между электронными модулями. Для связи между устройствами в самом простом случае достаточно витой пары из двух проводов. Много недорогих MCU (микроконтроллеров) уже содержит CAN-контроллер, а производитель предоставляет SDK и документацию по программированию. В их числе известный модуль Blue pill STM32F106CT8, платы ESP32, выше упомянутый модуль STM32-IHM03 с чипом STM32G431RB. Для MCU без CAN-контроллера, как Arduino UNO, Raspberry pi и т.п. возможно подключить внешний CAN-модуль, например MCP2515. Для коммуникации MCU с CAN-контроллерами по CANBUS необходимо только CAN-трансивер и витая пара.
OSI уровни CAN-протокола
Физический уровень шины CAN определяет типы кабелей, уровни электрических сигналов, требования к узлам, импеданс кабеля и т. д. Например, физический уровень определяет следующее:
-
Скорость передачи данных: Узлы должны быть соединены двухпроводной шиной со скоростью передачи данных до 1 Мбит/с (классическая CAN) или 8 Мбит/с (CAN FD).
-
Длина кабеля: Максимальная длина кабеля CAN должна составлять от 500 метров (125 кбит/с) до 40 метров (1 Мбит/с).
-
Терминирующее сопротивление: Шина CAN должна быть терминирована с помощью резистора 120 Ом на каждом конце шины.
Канальный уровень определяет форматы кадров CAN, обработку ошибок, передачу данных и помогает обеспечить целостность данных. Например, канальный уровень определяет:
-
Форматы кадров: четыре типа (кадры данных, удаленные кадры, кадры ошибок, кадры перегрузки) и 11-битные/29-битные идентификаторы
-
Обработка ошибок: методы обнаружения/обработки ошибок CAN, включая CRC, слоты подтверждения, счетчики ошибок и многое другое
-
Арбитраж: неразрушающий побитовый арбитраж помогает управлять доступом к шине CAN и избегать коллизий с помощью приоритета на основе идентификаторов

Физическое устройство и типы сетей
В современных автомобилях используется несколько стандартов в зависимости от задач
-
High-Speed CAN (ISO 11898-2): Самый популярный вариант. Скорость от 40 кбит/с до 1 Мбит/с. Используется для критичных систем (двигатель, тормоза).
-
Low-Speed / Fault Tolerant CAN (ISO 11898-3): Скорость до 125 кбит/с. Особенность — работа продолжается даже при обрыве одного из проводов. Применяется в комфорт-системах (двери, зеркала).
-
LIN-bus: Дешёвое дополнение к CAN для простых задач (стеклоподъемники, кондиционер).
-
CAN FD (Flexible Data-rate): Новое поколение со скоростью до 8 Мбит/с и объемом данных до 64 байт (вместо 8 байт в классическом CAN).
High-Speed CAN (ISO 11898-2)
Это самый распространенный стандарт, используемый для управления критическими системами (двигатель, АКПП, ABS).
Топология
-
Линейная шина. Двухпроводная линейная топологии. Ответвления (stubs) от основной магистрали должны быть минимальными по длине.
-
Терминаторы. На обоих концах линии обязательно устанавливаются резисторы по 120 Ом. Они предотвращают отражение сигнала от концов кабеля.
-
Среда. Витая пара с волновым сопротивлением 120 Ом.

Форма сигнала и уровни напряжения
В High-Speed CAN используется дифференциальный сигнал между линиями CAN High (CAN_H) и CAN Low (CAN_L).
-
Рецессивное состояние (Логическая 1): Оба провода имеют напряжение около 2.5 В. Дифференциальное напряжение (V_{diff} = CAN\_H — CAN\_L) равно 0 В.
-
Доминантное состояние (Логический 0): CAN_H поднимается до 3.5 В, а CAN_L опускается до 1.5 В. Дифференциальное напряжение составляет 2.0 В.
Low-Speed / Fault Tolerant CAN (ISO 11898-3)
Этот стандарт разработан для систем комфорта, где важнее надежность соединения, чем скорость.
Топология
-
Гибкость. Допускает не только линейную топологию, но и звезду или смешанные варианты.
-
Распределенное терминирование. В отличие от High-Speed, здесь каждый узел имеет свою часть терминирующих резисторов (обычно около 2.2 кОм или 4.7 кОм на землю/питание). Общее сопротивление сети должно быть около 100 Ом, но оно распределено по всем устройствам.

Форма сигнала и уровни напряжения
Сигналы здесь имеют гораздо больший размах напряжений, что делает их устойчивыми к помехам.
-
Рецессивное состояние (Логическая «1»): CAN_H подтянут к 0 В, а CAN_L — к 5 В.
-
Доминантное состояние (Логический «0»): CAN_H поднимается до 3.6 В, а CAN_L опускается до 1.4 В.
Главная особенность ISO 11898-3 — способность трансиверов переходить в режим работы по одному проводу. Если один из проводов (CAN_H или CAN_L) обрывается, замыкается на массу или на питание, трансивер переключается на использование оставшегося целого провода относительно земли. Можно подробнее ознакомится в даташите трансивера TJA1055. В High-Speed CAN такое невозможно: там разница напряжений слишком мала, и без второго провода выделить чистый сигнал из шума практически невозможно.
Сравнительная таблица характеристик
|
Характеристика |
High-Speed (11898-2) |
Low-Speed (11898-3) |
|---|---|---|
|
Макс. скорость |
1 Мбит/с |
125 кбит/с |
|
Напряжение CAN_H (Dom) |
3.5 В |
3.6 В |
|
Напряжение CAN_L (Dom) |
1.5 В |
1.4 В |
|
Терминирование |
2 x 120 Ом (на концах) |
Распределенное (в каждом узле) |
|
Отказоустойчивость |
При обрыве одного провода связь теряется |
Работает при обрыве или КЗ одного из проводов |
|
Применение |
Powertrain, ADAS, Диагностика |
Кузовная электроника, Салон |

Структура Standard Data Frame (CAN 2.0A)
-
SOF (Start of Frame): 1 доминантный бит. Он сигнализирует всем узлам о начале передачи и используется для жесткой синхронизации генераторов.
-
Arbitration Field (Поле арбитража):
-
Identifier (ID): 11 бит. Определяет приоритет сообщения и его содержимое.
-
RTR (Remote Transmission Request): 1 бит. В Data Frame он всегда доминантный (0). Если он рецессивный (1), значит, это удаленный кадр запроса данных (Remote Frame).
-
-
Control Field (Поле управления):
-
IDE (Identifier Extension): Доминантный (0) для стандартного кадра.
-
r0: Резервный бит (будущее использование).
-
DLC (Data Length Code): 4 бита. Указывают количество байт данных (от 0 до 8).
-
-
Data Field (Поле данных): От 0 до 64 бит (0–8 байт). Сама полезная нагрузка.
-
CRC Field:
-
CRC Sequence: 15-битная контрольная сумма.
-
CRC Delimiter: 1 рецессивный бит (разделитель).
-
-
ACK Field (Подтверждение):
-
ACK Slot: Передатчик отправляет рецессивный бит, а все приемники, получившие кадр без ошибок, «перебивают» его доминантным.
-
ACK Delimiter: 1 рецессивный бит.
-
-
EOF (End of Frame): 7 рецессивных бит. Обозначают конец кадра.

Пример отсылки CAN-сообщения в PulseView. В качестве анализатора использовался Raspberry pico (rp2040). Подробнее о проекте можно узнать в sigrok-pico репозитории. Сигнал измерялся на выводе RxD трансивера MCP2551.
CAN ID = 0x123
DATA = 0x11 0x22

Осциллограмма на выводах CANH и CANL трансивера MCP2551 при зацикленной передаче одного и того же сообщения

Extended Data Frame (CAN 2.0B)
Расширенный формат используется там, где 2048 комбинаций идентификаторов (11 бит) недостаточно (например, в протоколе J1939 для грузовой техники).
Ключевые отличия:
-
Идентификатор: Имеет 29 бит. Состоит из базовой части (11 бит) и расширения (18 бит).
-
SRR (Substitute Remote Request): Заменяет RTR в расширенном кадре, всегда рецессивный.
-
IDE: В расширенном кадре этот бит рецессивный (1), что дает контроллеру понять: дальше пойдут еще 18 бит идентификатора.
Битовый стаффинг (Bit Stuffing)
Чтобы приемники не теряли синхронизацию при длинных последовательностях одинаковых бит, в поля от SOF до CRC включительно применяется стаффинг: если контроллер видит 5 одинаковых бит подряд, он автоматически вставляет 6-й бит противоположной полярности. Приемник его автоматически удаляет. Примечание: Поля ACK и EOF имеют фиксированную форму, и стаффинг в них не применяется.
Сравнение с CAN FD
В стандарте CAN FD структура кадра меняется:
-
DLC: Позволяет адресовать до 64 байт данных.
-
BRS (Bit Rate Switch): Позволяет переключаться на более высокую скорость (например, 5 Мбит/с) внутри поля данных, возвращаясь к базовой скорости в конце кадра.
-
CRC: Используются более длинные контрольные суммы (17 или 21 бит) для обеспечения надежности при больших объемах данных.
Подробнее про CAN FD можно почитать здесь или в Wiki. Также можно ознакомится со статьей CAN Bus Explained — A Simple Intro
Арбитраж и обработка ошибок
Арбитраж в CAN-bus — это механизм, который позволяет нескольким узлам одновременно претендовать на доступ к шине без потери данных и без необходимости в диспетчере. Этот процесс основан на принципе CSMA/CD + AMP (Carrier Sense Multiple Access with Collision Detection and Arbitration on Message Priority). В основе арбитража лежат два физических правила:
-
Доминантный бит (0) всегда подавляет рецессивный бит (1).
-
Каждый узел во время передачи слушает шину, чтобы убедиться, что состояние сети совпадает с тем, что он отправил.
Все узлы одновременно отправляют SOF (Start of Frame) — один доминантный бит (0). На шине устанавливается «0». Все синхронизированы.
Узлы начинают передавать свой Идентификатор (ID), начиная со старшего бита.
-
Шаг 1. Все три узла отправляют первый бит своего ID. Если у всех это «0», на шине остается «0». Все продолжают передачу.
-
Шаг 2. Если Узел А отправляет «1» (рецессивный), а Узлы Б и В отправляют «0» (доминантный), то на шине установится «0».
-
Проигрыш Узла А. Узел А видит, что он отправил «1», но на шине «0». Он понимает, что есть кто-то с более высоким приоритетом, мгновенно прекращает передачу и переходит в режим приема.
Про арбитраж можно подробнее прочитать в этой статье или в википедии

На этой картинке узел A прекращает передачу напряжения, начиная с области, обозначенной оранжевым цветом. Узел B также не передает напряжение, начиная с бита идентификатора 0. Таким образов выигрывает узел C.
Обработка ошибок
CAN-контроллер использует пять независимых проверок для каждого кадра. Три из них работают на уровне сообщения, а две — на уровне битов. Подробнее можно почитать в CAN Bus Errors Explained.
На уровне сообщения:
-
CRC Check (Проверка контрольной суммы). Передатчик вычисляет 15-битную контрольную сумму кадра. Приемник пересчитывает её. Если значения не совпадают — фиксируется ошибка.
-
Frame Check (Проверка формата). Контроллер проверяет структуру кадра. Определенные поля (например, ACK-делитель, EOF) должны всегда состоять из рецессивных битов. Если там обнаруживается доминантный бит — это ошибка.
-
ACK Check (Проверка подтверждения). После передачи данных передатчик ожидает «доминантный» бит в ACK-слоте от любого другого узла. Если шина осталась рецессивной (никто не подтвердил прием), фиксируется ошибка.
На уровне битов:
-
Bit Monitoring (Мониторинг бита). Каждый узел во время передачи слушает шину. Если он отправил рецессивный бит, а увидел доминантный (кроме фазы арбитража или ACK), он понимает, что произошел конфликт или сбой.
-
Bit Stuffing (Битовый стаффинг). По правилам CAN, после 5 одинаковых битов подряд контроллер автоматически вставляет один бит противоположной полярности. Если приемник видит 6 одинаковых битов подряд — это ошибка стаффинга.
Как только любой узел (передатчик или приемник) обнаруживает ошибку, он немедленно прерывает текущую передачу, отправляя в сеть Error Flag (флаг ошибки).
-
Active Error Flag: Это 6 доминантных битов подряд. Они намеренно нарушают правило «битового стаффинга», заставляя все остальные узлы тоже обнаружить ошибку и отбросить текущий кадр.
-
Passive Error Flag: Это 6 рецессивных битов. Его отправляют только узлы, которые уже имеют много ошибок (Error Passive статус).
Чтобы один неисправный узел не заспамил всю сеть флагами ошибок, в CAN реализована логика изоляции неисправностей. В каждом контроллере есть два счетчика:
-
TEC (Transmit Error Counter) — счетчик ошибок передачи.
-
REC (Receive Error Counter) — счетчик ошибок приема.
-
Если передача прошла успешно: TEC — 1, REC — 1.
-
Если узел обнаружил ошибку при приеме: REC + 1.
-
Если ошибка произошла при передаче: TEC + 8 (передатчик наказывается строже)
-
Если узел «взбесился» и шлет флаги ошибок: значения стремительно растут.
Состояния узла
В зависимости от значений TEC и REC узел переходит в разные состояния:
-
Error Active (TEC < 128 и REC < 128):
-
Нормальное состояние.
-
Узел может передавать данные и отправлять Active Error Flags (доминантные), останавливая всю шину при сбое.
-
-
Error Passive (TEC > 127 или REC > 127):
-
Узел подозревается в неисправности.
-
Он всё еще может передавать данные, но при ошибке шлет только Passive Error Flags (рецессивные), которые не мешают другим.
-
После передачи кадра такой узел обязан выждать паузу (Suspend Transmission Time) перед следующим сообщением.
-
-
Bus Off (TEC > 255):
-
Критическое состояние. Узел физически отключается от шины.
-
Он больше не может ничего передавать или подтверждать.
-
Вернуться в сеть он может только после программного сброса или специальной процедуры ожидания (128 последовательностей по 11 рецессивных битов).
-
Bit Timing
Bit Timing (Битовая синхронизация) — это важный аспект физического уровня CAN-bus. Поскольку в CAN нет отдельной линии тактового сигнала (как в SPI или I2C), каждый узел должен самостоятельно определять, когда именно нужно считывать значение бита с шины.
Чтобы все узлы понимали друг друга, один номинальный бит в CAN делится на четыре неперекрывающихся временных сегмента. Подробнее можно почитать в статье CAN (bxCAN) bit time configuration on STM32 MCUs

Структура бита (Segments)
Номинальное время передачи одного бита (Nominal Bit Time) состоит из квантов времени (Time Quanta, t_q). Общая длительность бита — это сумма четырех сегментов:
-
Sync_Seg (Synchronization Segment):
-
Всегда равен 1 \times t_q.
-
Используется для синхронизации узлов. Ожидается, что фронт сигнала (переход из рецессивного в доминантное состояние) попадет именно в этот сегмент.
-
-
Prop_Seg (Propagation Segment):
-
Компенсирует задержки распространения сигнала по проводам и задержки в приемопередатчиках (трансиверах).
-
-
Phase_Seg1 и Phase_Seg2 (Phase Buffer Segments):
-
Используются для компенсации фазовых сдвигов, вызванных разницей в частотах кварцевых резонаторов разных узлов.
-
Между ними находится Sample Point (точка сэмплирования) — момент, когда контроллер фактически считывает логический уровень шины.
-
Sample Point (Точка сэмплирования)
Это важнейший параметр настройки CAN-контроллера. Она выражается в процентах от общей длительности бита.
-
Если Sample Point настроена слишком рано, контроллер может считать бит до того, как сигнал успеет стабилизироваться.
-
Если слишком поздно, контроллер может промахнуться из-за накопленного дрейфа частоты.
-
Стандарт для автомобильной отрасли (CiA): Обычно рекомендуется устанавливать Sample Point на уровне 87.5%.
Механизмы синхронизации
Чтобы узлы не разбегались во время передачи длинных кадров, CAN использует два вида синхронизации:
Hard Synchronization (Жесткая синхронизация)
Происходит только при переходе из рецессивного в доминантное состояние в начале кадра (SOF). Внутренний таймер узла сбрасывается в ноль, принудительно начиная отсчет сегмента Sync_Seg.
Resynchronization (Ресинхронизация)
Происходит во время передачи кадра при каждом перепаде сигнала (благодаря bit stuffing, перепады происходят регулярно). Если фронт сигнала пришел не в Sync_Seg, контроллер корректирует длительность фазовых сегментов:
-
Если фронт пришел позже,
Phase_Seg1удлиняется. -
Если фронт пришел раньше,
Phase_Seg2укорачивается.
Параметр SJW (Synchronization Jump Width) определяет максимальное количество квантов времени (t_q), на которое можно изменить длительность фазовых сегментов за один цикл ресинхронизации.
При объединении различных устройств в одну сеть CAN (например, контроллера двигателя и датчика на Arduino/STM32) может быть недостаточно просто указать скорость (например, 500 кбит/с). Если у узлов будут разные настройки сегментов (даже при одинаковой скорости), они могут иметь разные Sample Points. В результате один узел будет считать бит «0», а другой в тот же момент времени — уже «1» из-за дрейфа. Это приведет к ошибкам формата (Form Error) или битовым ошибкам, и шина ляжет в статус Error Passive или Bus Off.
Стандарт CAN FD и IoT
С развитием беспилотных технологий и облачных сервисов классического CAN становится недостаточно.
-
Переход на CAN FD: Позволяет передавать в 8 раз больше данных и быстрее, что критично для систем помощи водителю (ADAS).
-
V2X и безопасность: Подключение машин к интернету требует защиты данных. Новые протоколы включают функции аутентификации, чтобы злоумышленники не могли перехватить управление тормозами или рулем.
STM32 motor-control комплект
Если ввести в поисковик, каким образом запустить бесколлекторный двигатель (PMSM), и сделать это быстро, вы наверняка столкнетесь с STM32 MCSDK. На Aliexpress был приобретен комплект разработки P-NUCLEO-IHM03.

Комплект представляет собой связку из двух плат:
-
NUCLEO-G431RB: «Мозги» на базе STM32G4 (Cortex-M4, 170 МГц), заточенного под задачи управления приводами.
-
X-NUCLEO-IHM16M1: Драйвер на базе монолитного чипа STSPIN830, способный выдавать до 1.5 А RMS при напряжении до 45 В.
В комплекте также идет небольшой двигатель Gimbal GBM2804H-100T и блок питания на 12В 2А.
Getting started with STM32 Motor Control
На Youtube канале STMicroelectronics есть ролик 5 мин Getting started with STM32 Motor control SDK6.0. Выполнив пошагово руководство в результате получим проект с исходным кодом для NUCLEO-G431RB. Тезисно приведем шаги по созданию проекта согласно источника.
Подготовка оборудования
Перед запуском программного обеспечения необходимо правильно собрать аппаратную часть:
-
Сборка: Установите силовую плату X-NUCLEO-IHM16M1 поверх платы управления NUCLEO-G431RB через разъемы ST morpho (CN7 и CN10). Убедитесь, что кнопки B1 (синяя) и B2 (черная) на плате Nucleo не закрыты.
-
Подключение двигателя: Подключите три фазных провода мотора (U, V, W) к клеммнику CN1 на силовой плате.
-
Перемычки (Jumpers): Для работы алгоритма FOC (векторного управления) по умолчанию на плате IHM16M1 должны быть установлены перемычки J5 и J6 в положение ON. На плате Nucleo перемычка JP5 должна быть в положении для питания от USB.
-
Питание: Подключите входящий в комплект блок питания постоянного тока (12 В, 2 А) к разъему J4.
Создание проекта в ST Motor Control Workbench

Процесс создания проекта «из коробки» минимизирует риск ошибок в параметрах:
-
Запуск: Откройте программу ST Motor Control Workbench.
-
Новый проект: Нажмите кнопку «New Project» на главном экране.
-
Выбор оборудования (General Info): В разделе «Hardware» выберите вариант «Pack». Это позволит выбрать готовый набор, где параметры контроллера, силовой части и мотора уже синхронизированы.
-
Выбор комплекта: В появившемся списке выберите P-NUCLEO-IHM03. После выбора нажмите «OK», чтобы создать проект со всеми предустановленными значениями.
-
Просмотр: Откроется «Project View», отображающий схему системы с заданными параметрами (частота ШИМ, топология измерения тока и т.д.).
Генерация кода и прошивка

-
Генерация: Нажмите кнопку «Generate the project» (иконка подарка) в верхней панели управления.
-
Настройка генерации: В появившемся окне выберите целевую среду разработки (Target Toolchain) — STM32CubeIDE. Также укажите версию STM32CubeMX и нажмите «Generate».
-
STM32CubeIDE: Откройте сгенерированную папку проекта в STM32CubeIDE. Выполните сборку проекта (Build) и загрузите прошивку в микроконтроллер через встроенный программатор ST-LINK.
Первый запуск и проверка
После загрузки программы система готова к работе без дополнительной настройки кода:
-
Нажмите черную кнопку Reset (B2) на плате Nucleo для инициализации.
-
Нажмите синюю пользовательскую кнопку User (B1) — это команда на старт двигателя.
-
Для регулировки скорости вращайте синий потенциометр на плате X-NUCLEO-IHM16M1.
-
Светодиоды D8, D9 и D10 на силовой плате должны загореться, индицируя работу фаз.
-
Повторное нажатие синей кнопки B1 остановит двигатель
Замечания по запуску привода
Привод работает в целом нормально в тестовом режиме с настройки по умолчанию и нагрузкой менее 1 Нм. Но в зависимости от конкретных условий и режимов работы потребуется изменение дефолтных значений. В дальнейшем все параметры и коэффициенты можно изменить в исходном коде или с помощью пользовательского интерфейса Motor Pilot.
Одна из проблем, с которой я столкнулся — это рывок двигателя при старте. Изменение PID-коэффициентов не дало результата. Как выяснилось, причиной оказался параметр Target speed, который по умолчанию равен 524 RPM.

В исходном коде это параметр OBS_MINIMUM_SPEED_RPM находится в файле drive_parameters.h или в CUBEMX конфигурации MotorControl.M1_OBS_MINIMUM_SPEED_RPM P-IHM03-Potentiometer.ioc, где можно изменить это значение из 524 на 10.
#define OBS_MINIMUM_SPEED_RPM 10
Motor Control SDK документация
Motor ControlWorkbench приложение устанавливается с достаточно объемным комплектом документации в HTML-формате. Порой быстро найти необходимую информацию не просто.

Можно сконвертировать все справочные файлы в один PDF-файл. А затем загрузить этот мануал в Notebook LM.
Стенд для двигателя GBM2804H-100T
Если изначально не подразумевается установка двигателя на готовое устройство, то стенд для него позволяет удобно проводить эксперименты с комплектом. Иначе двигатель нужно либо держать в руках во время запуска, или каким-либо другим образом закреплять. Подразумеваю, что владелец IHM-блока придумает свою оригинальную конструкцию. У меня в коробке пылился разобранный привод от старого магнитофона. Я скрепил каркас с помощью алюминиевого уголка и круга из фанеры диаметром 10 см. Для двигателя подобрал пластиковый шкив и с помощью резинового пассика соединил со шкивом кассетника.

Хочется отметить, что толщина отверстий с резьбой на нижней стороне статора меньше длины крепежных болтов, что идут в комплекте с двигателем. Поэтому можно легко повредить обмотку двигателя если плотно закрутить болт без какй-либо дополнительной основы.
База данных CAN-сообщений
При проектировании систем управления и передачи данных по CAN-шине создание файла DBC (Data Base CAN) является этапом разработки протокола взаимодействия. Это документ, который определяет, как именно байты в цифровой шине превращаются в реальные физические параметры: амперы, вольты и обороты в минуту.
Проектирование базы данных CAN — это процесс формализации всех данных, циркулирующих в сети. Вместо того чтобы каждый раз вручную разбирать пакеты в коде, вы создаете единый файл-словарь, который описывает:
-
Структуру кадра: Какие биты за какой параметр отвечают.
-
Масштабирование: Коэффициенты пересчета (Factor/Offset) для передачи дробных чисел (например, точность 0.0001 для тока
I_Qв вашем проекте). -
Логику узлов: Кто в сети является «издателем» данных (например,
PMSM_NODE), а кто — «подписчиком». -
Диагностику: Текстовую расшифровку состояний (например,
22=OTF_BRAKE), что критично при отладке электропривода.
Это позволяет автоматизировать разработку: один и тот же DBC-файл используется и в прошивке микроконтроллера, и в софте для мониторинга на ПК.
Формат DBC
Формат DBC (Data Base CAN) — это текстовый стандарт описания обмена данными в CAN-сети, который служит переводчиком между бинарными кадрами шины и понятными параметрами (ток, скорость, температура). Подробнее можно почитать статью CAN DBC File Explained.
Основные секции формата:
-
Nodes (
BU_): Список узлов (блоков управления), участвующих в обмене данными. В нашем примере — это основной узелPMSM_NODE. -
Messages (
BO_): Описание кадров (сообщений). Каждое сообщение имеет уникальный ID (например,0х100или0х200), имя, длину в байтах (DLC) и имя отправителя. -
Signals (
SG_): Определение конкретных параметров внутри сообщения. Для каждого сигнала задается:-
Bit Layout: Начальный бит и длина (например,
32|32дляPower). -
Byte Order:
@1указывает на Intel (Little Endian), а+или-на признак знака (Unsigned/Signed). -
Scaling: Коэффициент (Factor) и смещение (Offset) для перевода в физические величины. Например, фактор
0.0001используется для высокой точности токаI_Q. -
Limits: Минимальное и максимальное значения в квадратных скобках.
-
-
Value Tables (
VAL_): Таблицы перечислений, которые связывают числовые коды с текстовыми названиями состояний. Это позволяет видетьRUNилиFAULTвместо абстрактных чисел6или10. -
Comments (
CM_): Описательные строки для сигналов или сообщений, помогающие понять назначение данных (например,"I_Q current"). -
Attributes (
BA_): Метаданные всей сети, такие как скорость шины (BusType) или настройки мультиплексирования.

Пример описания CAN-сообщения
Этот формат позволяет любому софту (от анализаторов до генераторов кода) мгновенно понять, как интерпретировать 8 байт данных из сообщения Speed_feedback_MSG как конкретные обороты RPM.
Инструментарий для работы с DBC
Для реализации этого проектирования существуют разные инструменты — от тяжелых индустриальных стандартов до легких бесплатных утилит.
1. Vector CANdb++
CANdb++ — это наиболее распространенный в автомобильной и промышленной индустрии редактор. На Youtube можно найти материалы по CANdb++ или по пакету Vector CANoe, в составе которого находится редактор базы.
-
Плюсы: Строгая проверка на ошибки, поддержка сложных атрибутов сети и работа с мультиплексированием.
-
Особенность: Является частью экосистемы Vector, поэтому идеально подходит, если в разработке используются анализаторы CANalyzer или CANoe.
2. Kvaser Database Editor
Популярная альтернатива от шведской компании Kvaser.
-
Для кого: Отличный выбор для тех, кто использует интерфейсы Kvaser.
-
Особенность: Обладает более современным и интуитивно понятным интерфейсом по сравнению со «строгим» CANdb++. Позволяет быстро набрасывать структуру сообщений и сигналов, поддерживая все стандартные функции формата DBC.
3. Open-source и альтернативные редакторы
-
SavvyCAN: Мощный бесплатный инструмент с открытым кодом. В нем есть встроенный редактор DBC, который позволяет сразу же видеть результат декодирования трафика с шины.
-
Cantools (Python): Не графический редактор, а библиотека. Позволяет описывать базу данных прямо в коде или конвертировать DBC в другие форматы (например, в JSON или C-структуры).
-
DBC-редакторы VS Code: Существуют плагины, позволяющие редактировать текстовую структуру DBC с подсветкой синтаксиса, что удобно для быстрой правки комментариев или ID.
Реализация базы данных
Проектировать базу данных DBC лучше всего начинать со спецификации как правило в Excel-таблице. Где указывается:
-
имя сообщения,
-
периодичность обмена данными,
-
сигналы и их функции,
-
размер сигналов в байтах
-
пределы значений сигналов

Для простоты и ясности опишем CAN-сообщения и сигналы в виде списка. Для демо-проекта определим минимальный набор данных и команд, необходимый для управления и контроля работы двигателя. За основу возьмем интерфейс пользователя Motor Pilot, с которым будем сравнивать текущие значения величин. Забегая наперед скажу, что исходный проект IHM позволяет передавать данные с частотой 1кГц. Но для удобства обмен данными был настроен на частоту 0.5 Гц, т.е. все CAN-сообщения обновляются каждые пол-секунды. Управляющие команды отправляются без задержек.

DBC-файл будем создавать в CANdb++. Коротко приведу описание порядка создания CAN-сообщений из источника. В Vector CANdb++ этот процесс сводится к созданию иерархии: Network → Node → Message → Signal. Можно и в другом порядке, если так удобнее.
1. Создание сигналов (Signals)
Сигналы — это переменные (физические значения).
-
Перейти в раздел Signals и создать новый (например,
Speed_RPM). -
Data Type: выбрать
Signedдля значений с минусом (как в примере для оборотов [-1750|1750] ) илиUnsignedдля токов и напряжений. -
Factor/Offset: если нужно передать дробное число, используй коэффициент. В нашем примере для тока
I_Qстоит фактор 0.0001, что позволяет передавать точность до десятых долей миллиампера в обычном целом числе.
2. Создание сообщений (Messages)
Сообщение — это контейнер (фрейм), который объединяет сигналы.
-
Создать сообщение в разделе Messages (например,
Speed_feedback_MSG). -
ID: Указать идентификатор в Hex или Decimal.
-
DLC: Указать длину в байтах (от 1 до 8).
-
Layout: Перетащить созданные сигналы в сообщение и распределить их по битовой сетке. Следить, чтобы сигналы не перекрывали друг друга.
3. Определение узлов (Network Nodes)
Узлы — это участники сети (контроллеры).
-
В разделе Nodes создать узел
PMSM_NODE. -
Привязать сообщения к узлу: указать, какие сообщения он отправляет (Transmitted), а какие принимает (Received). Это важно для фильтрации и логики работы ПО.
В редакторе привязка сообщений к ноде реализована не вполне интуитивно понятно. Вкладки разделены на сообщения, которые отправляются и группы сигналов, что отправляются и принимаются. Поэтому лучше всего добавлять сигналы отдельно или группой на соотв. вкладках.
К слову сказать, что для демо-проекта определение ноды и привязка сообщений носит в основном справочных характер, и на исходный код влияние не оказывает.
4. Таблицы значений (Value Tables)
В проекте удобно использовать текстовые названия для состояний работы двигателя, которые передаются в числовом виде. Данные чисел и названий взяты из исходного кода.
Чтобы не гадать, что значит Motor_State = 6, лучше использовать перечисления.
-
Создать таблицу в Value Tables (например,
MotorStates). -
Прописать пары число-текст:
0—IDLE,6—RUN,10—FAULT. -
Привязать эту таблицу к конкретному сигналу во вкладке Value Descriptions.
В проекте создано две таблицы:
-
состояние работы двигателя
-
управляющие команды
Перечень CAN-сообщений и сигналов в проекте
Curr_Amp_feedback_MSG — текущие значения токов d и q осей
-
CAN-ID 0x210
-
Размер — 8 байтов
-
Сигналы
-
I_D — ток d-оси
-
I_Q — ток q-оси
-
Параметры сигналов выбраны одинаково для двух токов:
-
размер — 4 байта (32 бита) знаковые
-
порядок байтов — Intel
-
коэффициент пропорциональности 0.0001 выбран для одинакового значения с Motor Pilot
-
пределы 0 … 5 (в нашем случае это больше для справки)
-
распределение сигналов в Layout — автоматически
-
-
PID_feedback_MSG — значения коэффициентов PID-регулятора скорости и момента
-
CAN-ID 0x230
-
Размер — 8 байтов
-
Сигналы:
-
PID_SPEED_KI
-
PID_SPEED_KP
-
PID_TORQUE_KI
-
PID_TORQUE_KP
-
Параметры сигналов:
-
Размер два байта (16 бит) беззнаковые
-
порядок байтов — Intel
-
распределение сигналов в Layout — автоматически
-
-
Speed_control_MSG — задание команд: запуска, останова, сброса ошибок и значение скорости для двигателя
-
CAN-ID 0x100
-
Размер — 6 байтов
-
Сигналы:
-
Control_CMD
-
Размер 1 байт (8 бит) беззнаковый
-
-
Speed_RPM
-
размер — 4 байта (32 бита) знаковые
-
порядок байтов — Intel
-
диапазон: минус 1750 … 1750
-
-
Speed_feedback_MSG — текущие значения скорости и состояния двигателя
-
CAN-ID 0x200
-
Размер — 6 байтов
-
Сигналы:
-
Motor_State
-
Размер 1 байт (8 бит) беззнаковый
-
-
Speed_RPM
-
размер — 4 байта (32 бита) знаковые
-
порядок байтов — Intel
-
диапазон: минус 1750 … 1750
-
-
Torque_Power_feedback_MSG — текущие значения и момента
По правде говоря текущее значение момента можно получить из величины тока I_Q, но для наглядности решил оставить.
-
CAN-ID 0x240
-
Размер — 8 байтов
-
Сигналы:
-
Torque
-
размер — 4 байта (32 бита) знаковые
-
порядок байтов — Intel
-
диапазон: минус 2 … 2
-
-
Power
-
размер — 4 байта (32 бита) беззнаковые
-
порядок байтов — Intel
-
диапазон: 0 … 24
-
-
Voltage_Temper_feedback_MSG — текущие значения напряжения питания двигателя и температуры
-
CAN-ID 0x220
-
Размер — 8 байтов
-
Сигналы:
-
Bus_Voltage
-
Размер два байта (16 бит) беззнаковые
-
порядок байтов — Intel
-
диапазон: 0 … 45
-
-
Temperature
-
Размер два байта (16 бит) беззнаковые
-
порядок байтов — Intel
-
диапазон: 0 … 200
-
-
Сохраняем проект как PMSM-demo.dbc
Использование библиотеки cantools
cantools — это набор утилит командной строки для Python 3, которая умеет парсить, декодировать, редактировать и визуализировать трафик CAN-шины. Но её ценность для разработчика — возможность генерации статического кода для упаковки и распаковки CAN-сообщений.
Библиотека устанавливается стандартным пакетным менеджером Python:
python3 -m pip install cantools
Генерация C-кода из DBC
Команда generate_c_source берет ваш файл описания (например, PMSM-demo.dbc ) и создает пару файлов (.h и .c), которые содержат:
-
Структуры данных для каждого сообщения.
-
Функции упаковки (pack) и распаковки (unpack).
-
Функции масштабирования сигналов (применение Factor и Offset).
Пример команды:
cantools generate_c_source --use-float --database-name can_driver PMSM-demo.dbc
Разбор параметров:
-
--use-float: Принуждает генератор использовать типfloatдля сигналов, имеющих дробный коэффициент. Таким образом, числа с плавающей запятой в сгенерированном коде имеют одинарную точность (float), а не двойную (double). -
--database-name can_driver: Задает префикс для имен функций и структур (например,can_driver_pmsm_node_unpack). Это помогает избежать конфликтов имен в больших проектах. -
PMSM-demo.dbc: Исходный файл вашей базы данных.
Результат работы
После выполнения команды вы получите файлы can_driver.h и can_driver.c. Теперь в основном коде прошивки (например, для STM32 или ESP32) вам достаточно вызвать одну функцию, чтобы получить готовые значения скорости или тока:
struct can_driver_speed_feedback_msg_t speed_msg;can_driver_speed_feedback_msg_unpack(&speed_msg, can_rx_data, 6);printf("Current speed: %f RPM\n", speed_msg.speed_rpm);
Реализация CAN-интерфейса в проекте P-IHM03
Аппаратная часть и конфигурация
Микроконтроллер STM32G431RBT оснащен CAN-контроллером, поддерживающем протокол FDCAN совместимый с классическим CANBUS. В статье Getting Started with FDCAN Normal Mode on STM32 показан пример, как настроить и использовать FDCAN в STM32. Выполним настройку подобным образом но с форматом фрейма Classic Mode для совместимости с чипом MCP2515.
Для подключения к CAN-шине платы NUCLEO-G431RB выбран модуль CAN-трансивера SN65HVD230
Для подключение CAN-шины к USB на PC были приобретены CAN-конверторы, совместимые с TSMaster:
CANable V1.0 Nano

-
Форм-фактор: Nano (v 1.0)
-
Чип: STM32F072 + TJA1050
-
LED индикация статусов состояния и работы устройства.
-
Кнопка BOOT (DFU режим).
-
Терминальный переключатель сопротивления.
-
Разъем: Type-C USB
-
Питание: 5В (USB)
-
Подключение: CAN-H, CAN-L.
-
Разъемы (4 шт): CANH, CANL, 5v (output), GND.
-
Поддержка CAN 2.0A, CAN 2.0B.
-
Скорость передачи данных: до 1M.
-
Прошивка: Pcan (Canable)
-
Совместимое ПО: Cangaroo, PCAN-View.
CAN CANable v1.0 Pro

-
Форм-фактор: CANable Pro (v 1.0)
-
Чип: STM32F072 + ADM3053 (ADM3053BRWZ)
-
LED индикация статусов состояния и работы устройства.
-
Кнопка BOOT (DFU режим).
-
Терминальная перемычка сопротивления.
-
Разъем: Type-C USB
-
Питание: 5В (USB)
-
Подключение: CAN-H, CAN-L.
-
Разъемы: CANH, CANL, 5v (output), GND.
-
Поддержка CAN 2.0A, CAN 2.0B.
-
Сокрость передачи данных: до 1M.
-
Прошивка: Canable
-
Совместимое ПО: Cangaroo
Согласно CUBEMX FDCAN GPIO Settings:
-
PA12 — FDCAN1_TX
-
PB8 — FDCAN1_RX

На скриншоте схематически показаны выводы RX, TX, +3.3V, GND на плате

Для простоты подключение трансивера к плате NUCLEO-G431RB выполнено на макетной плате

Далее показана CUBEMX-конфигурация STM32G431RBT микроконтроллера проекта P-HMI, но уже с настройками FDCAN. Первым делом необходимо установить чекбокс Activated. А затем настроить Basic Parameters.
-
Frame FormatвыбираемClassic mode -
ModeвыбираемNormal modeAuto retransmission,Transmit pause,Protocol Exceptionоставляем по умолчанию.Tx Fifo Queue ModeвыбираемFIFO mode. Примем скорость передачи данных для нашего проекта 500 kbit/sec — как в большинстве автомобилей. В Basic Parameters мы не можем напрямую установить значение скорости передачи данных. Для этого нам необходимо задать значения предделителя, сегмента синхронизации и сегментов буфера (см Bit Timing). Для этого воспользуемся онлайн калькулятором Bit Timing Calculator for CAN FD.
Первым делом нам нужно знать частоту шины Clock Frequency на FDCAN. Идем в CUBEMX Clock Configuration. После активации значение частоты равно 170 MHz. Вопрос тактирования STM32 — это отдельная большая тема. Оставим значение тактирования FDCAN как есть, чтобы не переконфигурировать настройки всего проекта.

Потом необходимо определить точность кварцевого резонатора — Clock Tolerance. На плате NUCLEO-G431RB расположен резонатор NX2016SA. В даташите указано Frequency Tolerance (25 ±3 °C) = ±10 × 10^{-6} или 1 ppm.
Далее из даташита определяем величину задержки распространения Propagation Delay трансивера. В модуле SN65HVD230 между выводом RS трансивера и GND подключен резистор 10к, поэтому нужно смотреть параметр Propagation delay RS with 10 kΩ to ground, выбираем максимальное значение 125ns.

Выбор точки выборки Sample point — это всегда компромисс между устойчивостью к задержкам в кабеле и устойчивостью к нестабильности генераторов.
-
Для Nominal Bit (арбитраж): Рекомендуемым и наиболее часто используемым значением является 87.5%. Это значение является стандартным для протоколов CANopen и DeviceNet. Для скорости 1 Мбит/с диапазон может варьироваться от 75% до 90%.
-
Для Data Bit (фаза данных): Из-за очень коротких битовых интервалов и эффектов физического уровня (асимметрия сигнала) в фазе данных точку выборки часто устанавливают раньше, чем в номинальной. Типичные значения для высоких скоростей (2-5 Мбит/с) находятся в диапазоне 60–80%.

Для демо-проекта с короткими проводниками CAN-шины устойчивость к задержкам будет играть намного меньшую роль, чем в реальном оборудовании. Методом подбора в Kvaser-калькуляторе выбраны Sample point 85% для получения целого значения Nominal baud rate и приемлемых коэффициентов для CUBEMX. Но возможны и другие сочетания, зависит от топологии сети. Выставив параметры:
-
Nominal Prescaler= 17 -
Nominal Time Seg 1= 16 -
Nominal time Seg 2= 3 ПолучимNominal Baud Rate= 500000 bit/s, что нам и требуется. При других сочетаниях предделителя и сегментов может получится значение скорости 499999 bit/s, это связано с погрешностью вычислений, и в большинстве случаев можно оставить значение таким.


Std Filters Nbr — это количество стандартных (ID) фильтров, которые мы используем, в данном случае 1 фильтр для сообщения с ID 0x100.
Параметр Ext Filters Nbr установлен на 0, поскольку мы не используем расширенные идентификаторы.
Для приема сообщения мы будем использовать RX FIFO 0. Всего можно использовать до 64 элементов FIFO, и каждый элемент может хранить до 64 байт данных.
Подробнее про настройки FDCAN в CUBEMX можно ознакомится в статье Настройка FDCAN в CubeMx. Но следует учитывать, что набор параметр FDCAN отличается для разных серий чипов.

Обработку входящих CAN-сообщений мы собираемся выполнять в callback-процедуре, поэтому установим флаг Enabled во вкладке NVIC settings

Настройки пинов RX, TX оставим по умолчанию о чем уже говорилось выше, т.к. другие конфигурации уже заняты.

В процессе тестирования обнаружилась проблема конфликта обработки прерывания FDCAN с одним из каналов системного таймера TIM1. Т.е. во время прибытия нового CAN-сообщения система могла зависнуть или упасть в ошибку. Проблема решилась установкой приоритета обработки прерываний FDCAN1 ниже, чем у таймера. Это значение можно установить равным 5.

Программная реализация
Прошивка ihm03 реализует векторное управление (FOC) для двигателя BLDC/PMSM. Подробнее теорию можно почитать в руководстве STM32 Motor Control SDK или в статье Моделирование управления AC двигателя — Field oriented control.
Скорость может задаваться как встроенным потенциометром, так и удалённо — через пользовательский интерфейс. Согласно документации в исходном проекте ihm03, созданном через MCSDK, передача данных (включая измеренную скорость) в приложение ST Motor Pilot организована через протокол MCP (Motor Control Protocol) и транспортный уровень ASPEP (Advanced Serial Protocol for Embedded Performer).

Передача измеренной скорости и других параметров в Motor Pilot не происходит в одном конкретном месте в виде простой отправки строки. Она распределена по нескольким уровням:
-
Уровень протокола (MCP): Основная логика обработки команд и подготовки данных находится в файле
mcp.c. Скорость считывается из регистра MC_REG_SPEED_MEAS. -
Асинхронная передача (Datalogging): ST Motor Pilot использует механизм даталоггера для построения графиков скорости в реальном времени. Это реализовано через функции
MCPA_dataLog()mc_tasks.c. -
Транспортный уровень (ASPEP): Файлы
aspep.cиusart_aspep_driver.cотвечают за непосредственную работу с USART2 и передачу сформированных пакетов. -
Диспетчеризация задач: Все функции связи вызываются внутри задачи пользовательского интерфейса (User Interface Task), которая является частью функции
MC_RunMotorControlTasks(). Эта функция обычно вызывается периодически из обработчика системного таймера (SysTick) или основного циклаmain.c.
Для реализации периодической обработки пользовательских функций следует использовать специально предусмотренные хуки (callback-функции). Вместо модификации системных файлов протокола MCP рекомендуется интегрировать дополнительную логику в модуле mc_app_hooks.c, функция MC_APP_PostMediumFrequencyHook_M1().
Реализация отправки CAN-сообщений
Cогласно логики работы все основные процессы управления в MCSDK вызываются последовательно внутри планировщика MC_RunMotorControlTasks(), и хук выполняется первым в этой очереди. В SDK предусмотрен специальный код ошибки MC_DURATION. Эта ошибка генерируется, когда вычисления или выполнение функций занимают слишком много времени и не успевают завершиться до начала следующего цикла PWM. Блокировка процессора в цикле while — кратчайший путь к остановке мотора по этой ошибке. Передача большого количества CAN-сообщений может стать проблемой. В данном проекте мы собираемся передавать пять CAN-сообщений.
void CAN_Send_Feedback(FDCAN_HandleTypeDef *hfdcan){ static uint32_t s_Counter = 0U; if (++s_Counter < CAN_TELEMETRY_DECIMATION_COUNT) { return; } s_Counter = 0U; CAN_Send_CurrAmpFeedback(hfdcan); CAN_Send_VoltageTempFeedback(hfdcan); CAN_Send_PidFeedback(hfdcan); CAN_Send_TorquePowerFeedback(hfdcan); CAN_Send_SpeedFeedback(hfdcan);}
Если в CUBEMX CANFD параметр TX Fifo Queue Mode установить в Queue mode (в MX_FDCAN1_Init hfdcan1.Init.TxFifoQueueMode = FDCAN_TX_QUEUE_OPERATION;), то в буфер будут отправляться только первые три сообщения, остальные игнорироваться.

Есть несколько компромиссных решений.
-
Распределенная отправка — Вместо того чтобы раз в 500 мс пытаться «протолкнуть» сразу 5 сообщений в буфер из 3 ячеек, мы будем отправлять по одному сообщению каждые 100 мс. В итоге каждое из 5 сообщений будет уходить со своей частотой 2 Гц, но они никогда не встретятся в очереди одновременно.
-
CUBEMX CANFD параметр
TX Fifo Queue Modeустановить вFIFO mode(в MX_FDCAN1_Inithfdcan1.Init.TxFifoQueueMode = FDCAN_TX_FIFO_OPERATION;). А перед отправкой нового сообщения проверять очередьHAL_FDCAN_GetTxFifoFreeLevel(hfdcan) == 0Uи инкрементировать счетчик до установленного практическим способом значения. -
Изменение архитектуры проекта (FreeRTOS или CMSIS-OS), использование других чипов
Возможно кто-либо знает более интересные варианты решения подобных задач, буду рад почитать в комментариях.
Я остановился на втором варианте — FIFO mode со счетчиком до 2000. Для данной конфигурации решение получилось оптимальным. Если вместо счетчика считать миллисекунды, то задержка будет значительной. И программа не будет работать, если к CAN-шине не будет подключено другое устройства, способное активно принимать сообщения.
#define CAN_TELEMETRY_DELAY_COUNT 2000Ustatic HAL_StatusTypeDef CAN_Transmit(FDCAN_HandleTypeDef *hfdcan, uint32_t id, uint32_t dlc, const uint8_t *data){ static uint32_t s_SkippedMsgCount = 0U; uint32_t tickstart = HAL_GetTick(); while (HAL_FDCAN_GetTxFifoFreeLevel(hfdcan) == 0U) {s_SkippedMsgCount++; if (s_SkippedMsgCount > CAN_TELEMETRY_DELAY_COUNT || (HAL_GetTick() - tickstart) > 2U) { s_SkippedMsgCount = 0; return HAL_TIMEOUT; /* FIFO still full – abort this frame */ } } FDCAN_TxHeaderTypeDef h; h.Identifier = id; h.IdType = FDCAN_STANDARD_ID; h.TxFrameType = FDCAN_DATA_FRAME; h.DataLength = dlc; h.ErrorStateIndicator = FDCAN_ESI_ACTIVE; h.BitRateSwitch = FDCAN_BRS_OFF; h.FDFormat = FDCAN_CLASSIC_CAN; h.TxEventFifoControl = FDCAN_NO_TX_EVENTS; h.MessageMarker = 0U; return HAL_FDCAN_AddMessageToTxFifoQ(hfdcan, &h, data);}
Модуль CAN Bus — иерархия файлов и назначение
После настройки конфигурации FDCAN в CUBEMX и генерации проекта (подробнее можно посмотреть на Youtube) получим функцию инициализации периферии FDCAN в main.c
static void MX_FDCAN1_Init(void){ hfdcan1.Instance = FDCAN1; hfdcan1.Init.ClockDivider = FDCAN_CLOCK_DIV1; hfdcan1.Init.FrameFormat = FDCAN_FRAME_CLASSIC; hfdcan1.Init.Mode = FDCAN_MODE_NORMAL; hfdcan1.Init.AutoRetransmission = ENABLE; hfdcan1.Init.TransmitPause = DISABLE; hfdcan1.Init.ProtocolException = DISABLE; hfdcan1.Init.NominalPrescaler = 17; hfdcan1.Init.NominalSyncJumpWidth = 3; hfdcan1.Init.NominalTimeSeg1 = 16; hfdcan1.Init.NominalTimeSeg2 = 3; hfdcan1.Init.DataPrescaler = 17; hfdcan1.Init.DataSyncJumpWidth = 6; hfdcan1.Init.DataTimeSeg1 = 16; hfdcan1.Init.DataTimeSeg2 = 3; hfdcan1.Init.StdFiltersNbr = 1; hfdcan1.Init.ExtFiltersNbr = 0; hfdcan1.Init.TxFifoQueueMode = FDCAN_TX_FIFO_OPERATION; if (HAL_FDCAN_Init(&hfdcan1) != HAL_OK) { Error_Handler(); } /* USER CODE BEGIN FDCAN1_Init 2 */ CAN_Filter_Config(&hfdcan1); /* USER CODE END FDCAN1_Init 2 */}
где CAN_Filter_Config — пользовательская функция настройки фильтра приема CAN-сообщения, подробнее про фильтры можно почитать в статье Getting Started with FDCAN или на Youtube.
#define CAN_DRIVER_SPEED_CONTROL_MSG_FRAME_ID (0x100u)void CAN_Filter_Config(FDCAN_HandleTypeDef *hfdcan){ FDCAN_FilterTypeDef filterConfig; filterConfig.IdType = FDCAN_STANDARD_ID; filterConfig.FilterIndex = 0U; filterConfig.FilterType = FDCAN_FILTER_MASK; /* ID & Mask match */ filterConfig.FilterConfig = FDCAN_FILTER_TO_RXFIFO0; /* Store match in FIFO 0 */ filterConfig.FilterID1 = CAN_DRIVER_SPEED_CONTROL_MSG_FRAME_ID; filterConfig.FilterID2 = 0x7FFU; /* Mask: all 11 bits must match */ if (HAL_FDCAN_ConfigFilter(hfdcan, &filterConfig) != HAL_OK) { Error_Handler(); } /* * Reject all frames that do not match any configured filter. * Non-matching standard frames → reject FIFO (not forwarded to Rx FIFOs). */ if (HAL_FDCAN_ConfigGlobalFilter(hfdcan, FDCAN_REJECT, FDCAN_REJECT, FDCAN_FILTER_REMOTE, FDCAN_FILTER_REMOTE) != HAL_OK) { Error_Handler(); }}
Добавление кастомных файлов в проекте предусматривается по пути ..\STM32CubeIDE\Application\User\
Application/User/├── can_driver.h ← Cгенерированный cantools кодек сообщений (заголовок)├── can_driver.c ← Cгенерированный cantools кодек сообщений (реализация)└── can_interface.c ← Cвязующий слой приложения (реализация) [can_interface.h] ← Cвязующий слой приложения (заголовок)
can_driver.h / can_driver.c — Слой кодека сообщений, автоматически сгенерированы утилитой cantools из файла базы данных .dbc.
|
# |
Функционал |
|---|---|
|
1 |
Определить идентификаторы фреймов как константы |
|
2 |
Определить константы DLC (Data Length Code) для каждого фрейма |
|
3 |
Определить структуры C, которые отображаются 1-к-1 на набор сигналов каждого CAN-сообщения |
|
4 |
Предоставить функции pack() / unpack() для сериализации/десериализации структур в/из массивов байт |
|
5 |
Предоставить вспомогательные функции encode() / decode() для применения масштабирования и смещения к физическим значениям |
|
6 |
Предоставить валидаторы isin_range() для каждого сигнала |
|
7 |
Перечислить варианты значений сигналов (перечисления состояний двигателя, коды команд) |
Ключевые структуры
/* Входящие */struct can_driver_speed_control_msg_t { uint8_t control_cmd; int32_t speed_rpm; };/* Исходящие */struct can_driver_speed_feedback_msg_t { uint8_t motor_state; int32_t speed_rpm; };struct can_driver_curr_amp_feedback_msg_t { int32_t i_d; int32_t i_q; };struct can_driver_voltage_temper_feedback_msg_t { uint16_t bus_voltage; uint16_t temperature; };struct can_driver_pid_feedback_msg_t { uint16_t pid_speed_kp; uint16_t pid_speed_ki; uint16_t pid_torque_kp; uint16_t pid_torque_ki; };struct can_driver_torque_power_feedback_msg_t { int32_t torque; uint32_t power; };
can_interface.h / can_interface.c — Слой интеграции с приложением. Связующий код, соединяющий слой кодека с API управления двигателем MCSDK и драйвером STM32 HAL FDCAN.
|
# |
Функционал |
|---|---|
|
1 |
Настройка фильтра — |
|
2 |
RX-коллбэк — |
|
3 |
TX-помощники — по одной приватной |
|
4 |
Планировщик телеметрии — |
|
5 |
Защита FIFO — |
Публичный API
/* Вызвать один раз после MX_FDCAN1_Init() и до HAL_FDCAN_Start() */void CAN_Filter_Config(FDCAN_HandleTypeDef *hfdcan);/* Вызывать на каждом тике средней частоты (1 кГц) — внутри понижается до 2 Гц */void CAN_Send_Feedback(FDCAN_HandleTypeDef *hfdcan);/* Переопределение слабого символа HAL — вызывается автоматически из обработчика FDCAN IRQ */void HAL_FDCAN_RxFifo0Callback(FDCAN_HandleTypeDef *hfdcan, uint32_t RxFifo0ITs);
Функция CAN_Filter_Config используется для настройки фильтра FDCAN для приема сообщений с ID 0x100.
Функция CAN_Send_Feedback служит для циклической передачи всех CAN-сообщений. Вызывается в mc_app_hooks.c, функция MC_APP_PostMediumFrequencyHook_M1() с частотой 1 кГц.
/* USER CODE BEGIN 0 */#include "can_interface.h"extern FDCAN_HandleTypeDef hfdcan1;/* USER CODE END 0 */.....__weak void MC_APP_PostMediumFrequencyHook_M1(void){ uint16_t rawValue = RCM_GetRegularConv(&PotRegConv_M1); (void)SPDPOT_Run(&SpeedPotentiometer_M1, rawValue);/* USER SECTION BEGIN PostMediumFrequencyHookM1 */ CAN_Send_Feedback(&hfdcan1);/* USER SECTION END PostMediumFrequencyHookM1 */}
Для демо-проекта прием данных с частотой 1 кГц избыточен, поэтому внутри функции CAN_Send_Feedback выполнен счетчик, при достижении значения CAN_TELEMETRY_DECIMATION_COUNT = 500, т.е. пол-секунды выполняется отсылка всех CAN-сообщений.
API MCSDK, используемые внутри can_interface.c согласно документации и исходных файлов проекта.
|
Функция |
Назначение |
|---|---|
|
|
Запуск конечного автомата FOC |
|
|
Остановка двигателя |
|
|
Сброс зафиксированной неисправности |
|
|
Задать целевую скорость и время разгона |
|
|
Прочитать текущее состояние конечного автомата |
|
|
Прочитать среднюю механическую скорость (об/мин) |
|
|
Прочитать токи D/Q |
|
|
Прочитать среднюю электрическую мощность (Вт) |
|
|
Прочитать напряжение шины постоянного тока |
|
|
Прочитать температуру радиатора |
|
|
Прочитать актуальные коэффициенты ПИД-регулятора |
В обработчике прерывания HAL_FDCAN_RxFifo0Callback мы вызываем функции высокоуровневого API:
-
Запуск/Останов:
MC_StartMotor1()иMC_StopMotor1(). -
Задание скорости:
MC_ProgramSpeedRampMotor1(target_speed, duration). -
Сброс ошибок:
MC_AcknowledgeFaultMotor1().
Общая диаграмма потока данных
CAN Bus ──────────────────────────────────────────────────────────────── Мастер STM32G431 (периферия FDCAN1) ────── ────────────────────────────────────────────── ┌─ Аппаратный фильтр (только 0x100) ───────────-┐ 0x100 ──────────►│ HAL_FDCAN_RxFifo0Callback() │ Speed_control │ └─ can_driver_speed_control_msg_unpack() │ │ └─ MC_StartMotor1() / MC_StopMotor1() / │ │ MC_ProgramSpeedRampMotor1_F() / │ │ MC_AcknowledgeFaultMotor1() │ └───────────────────────────────────────────────┘ ┌─ MC_APP_PostMediumFrequencyHook_M1 (1 кГц) ───┐ │ CAN_Send_Feedback() ← делитель /500 │ │ ├─ CAN_Send_SpeedFeedback() → 0x200 │──► 0x200 │ ├─ CAN_Send_CurrAmpFeedback() → 0x210 │──► 0x210 │ ├─ CAN_Send_VoltageTempFeedback()→ 0x220 │──► 0x220 │ ├─ CAN_Send_PidFeedback() → 0x230 │──► 0x230 │ └─ CAN_Send_TorquePowerFeedback()→ 0x240 │──► 0x240 └───────────────────────────────────────────────┘
Исходный код всего проекта можно посмотреть в P-IHM03 репозитории.
Тестирование CAN-шины
TSMaster — это мощная программная платформа от компании TOSUN, предназначенная для разработки, моделирования и тестирования встраиваемых систем по протоколам CAN, CAN FD, LIN, FlexRay и Ethernet. Скачать можно из репозитория. Документация устанавливается вместе с софтом. Уроки можно посмотреть на канале Software Motion
Лицензия для некоммерческого использования
TSMaster придерживается политики «Hardware-Free, Software-Free». Это означает:
-
Бесплатная база: Базовый функционал программы полностью бесплатен и не требует покупки специального ключа.
-
Совместимость: Программа поддерживает оборудование сторонних производителей, что позволяет использовать её без покупки оригинальных интерфейсов TOSUN.
-
Ограничения: Платными являются только специализированные плагины (например, для диагностики по протоколу UDS, калибровки по XCP или специфических аэрокосмических стандартов).
Настройка подключения конверторов интуитивно понятная, выполняется на панели Hardvare. Могут быть баги и вылеты, если выбрано некорректное устройство или не подключено ранее выбранное. Вначале желательно выбрать тип устройства с помощью Vendor Selection
А затем настроить канал в диалоговом окне Channel Selection. Как правило, устройство автоматически обнаружится в строке CAN1.
Настройка скорости CAN-шины расположена в диалогом окне Hardware Configuration, в которое можно перейти с помощью иконки Network Hardware.
Загрузка базы данных (.dbc)
На панели Analysis кликните иконку Database и выберете Show CAN database.
В диалоговом окне CAN Database кликните иконку Load CAN database file и выберете ранее созданный .dbc файл.
После этого диалоговые окна CAN FD Transmit и CAN FD Trace будут содержать конвертированные сигналы для CAN-сообщений. В окне CAN FD Transmit будет возможность задавать физические величины сигналов, которые затем автоматически конвертируются в последовательность байтов.
Короткое видео с результатом тестирования устройства
## Что удалось реализовать
В ходе работы над проектом были спроектированы и проверены следующие компоненты системы:
-
CAN-протокол взаимодействия — разработана база данных DBC с набором сообщений для телеметрии и управления двигателем, охватывающая скорость, токи d/q-осей, напряжение шины, температуру, мощность, момент и коэффициенты ПИД-регулятора.
-
Автоматическая генерация кода — утилита
cantoolsпозволила избежать ручного написания функций упаковки/распаковки байтов и снизила вероятность ошибок при масштабировании сигналов. -
Интеграция FDCAN в прошивку IHM03 — модуль
can_interface.cвстраивается в хукMC_APP_PostMediumFrequencyHook_M1()без модификации системных файлов MCSDK, что важно для сопровождения проекта при обновлении SDK. -
Управление двигателем по CAN — реализован прием команд запуска, останова, сброса ошибок и задания скорости с аппаратной фильтрацией на уровне FDCAN-контроллера.
-
Тестовый стенд и инструментарий — подобраны доступные CAN-конверторы (CANable) и бесплатное ПО (TSMaster) для мониторинга трафика и декодирования сигналов через DBC-файл.
Ограничения и возможные улучшения
-
Реальное время — архитектура на базе FreeRTOS или CMSIS-OS позволила бы разделить задачи управления и коммуникации по отдельным приоритетам без применения счётчика-делителя частоты и задержек.
-
Необходимость в дополнительных CAN-устройств. Для обеспечения коммуникации между узлами CAN-шины необходимо, чтобы каждый узел был оснащен CAN-контроллером и CAN-трансивером. Следует также учитывать топологию сети и согласующие сопротивления. Для локальных устройств, подключенных point-to-point CAN-шина это может быть избыточно.
-
HMI и аналитика — следующим логичным шагом является интеграция с IoT для визуализации данных в реальном времени и автоматический анализа режимов работы привода.
ссылка на оригинал статьи https://habr.com/ru/articles/1023492/