Введение: почему К1946ВК035?
С ростом интереса к импортозамещению в embedded-сфере отечественный микроконтроллер К1946ВК035 (разработка НИИЭТ) выглядит привлекательной альтернативой STM32 и его аналогам. Но насколько он подходит для сложных real-time задач, таких как управление бесколлекторными двигателями (ESC)?
Для всех тех, кому интереснее сразу посмотреть результат — прошу:
Ну а для всех остальных — прошу под кат, где мы подробно разберём все нюансы.
Для нашего эксперимента мы выбрали прошивку AM32 – популярное open-source решение для управления бесколлекторными двигателями (ESC), изначально разработанное под STM32. Этот проект интересен тем, что:
✅ Активно развивается и уже поддерживает ряд современных функций, востребованных в ESC:
-
30 ms Telemetry и классическая телеметрия
-
Поддержка двустороннего DShot с передачей расширенных пакетов
-
DroneCan для сетевого взаимодействия
-
Гибкая конфигурация параметров регулятора: motor kv, motor poles, sine start, tune volume и др.
✅ Имеет модульную структуру, что упрощает портирование.
✅ Написана на С с использованием HAL/LL библиотек STM32, что делает её хорошим кандидатом для проверки совместимости с К1946ВК035.
Проверяем пригодность К1946ВК035 для реализации регулятора оборотов
Первым делом отправляемся на официальный сайт производителя и изучаем документацию. Уже в описании микроконтроллера находим важный пункт: одна из ключевых областей применения — электроприводы, что сразу вселяет оптимизм. Анализируя перечень периферии, видим всё необходимое для базового регулятора: три независимых блока ШИМ, 12-битный АЦП, гибко настраиваемые таймеры и достаточное количество GPIO для управления ключами и обработки сигналов обратной связи.
Давайте трезво оценим наш К1946ВК035 на фоне микроконтроллеров, традиционно используемых в прошивке AM32. Здесь нас ждёт приятный сюрприз — в то время как стандартные сборки AM32 рассчитаны на:
-
STM32F0 (Cortex-M0) — базовый вариант:
-
Скромные 48 МГц
-
Отсутствие FPU
-
Ограниченный набор команд Thumb
-
-
Китайские аналоги STM32F4 (Cortex-M4) — продвинутый вариант
1946ВК035 предлагает Cortex-M4F с тактовой частотой до 100 МГц и аппаратной поддержкой вычислений с плавающей точкой. Такого уровня вычислительной мощности хватит с головой.
Для понимания масштаба: существуют рабочие реализации ESC даже на:
-
8-битных AVR (например, ATmega)
-
Простейших Cortex-M0
С таким железом вопрос «потянет ли?» даже не стоит. Это всё равно что спрашивать, хватит ли грузовика КамАЗ, чтобы съездить за хлебом в соседний магазин.
Сравнение периферии:
Переходя от радужных перспектив ядра к суровой реальности аппаратных модулей, картина становится не столь однозначной. Даже самые бюджетные STM32 обладают продуманной под двигательные задачи периферией:
1.Таймеры — сердце ESC:
-
В STM32 — это единый продвинутый таймер (TIM1/8) с:
-
Встроенным dead-time генератором
-
Break-функциями для аварийного отключения
-
Гибкой системой событий (TRGO, slave mode)
-
Прямой связью разных модулей с ADC для синхронных замеров
-
Поделить частоту таймера можно на любое число от 1 до 65536
-
-
В К1946ВК035 реализация иная:
-
3 раздельных ШИМ-блока, вместо одного цельного таймера
-
Dead-time присутствует, но настраивается менее интуитивно
-
Система событий есть, но имеет больше ограничений
-
Связь ШИМ-блока с ADC реализована довольно удобно, можно выставлять задержку перед измерением после получения триггера события
-
Делитель частоты ШИМ в К1946ВК035 имеет фиксированные значения, например — Div1, Div2, Div4, Div8 и т.д. Для управления мотором этого вполне хватает, но если захочется поиграть мелодии через мотор (да, так тоже можно), тут уже начинаются сложности.
-
2.Работа с АЦП:
Теперь перейдём к рассмотрению АЦП. Четыре канала это самый минимум для нашей задачи. Наш регулятор работает в sensorless-режиме, то есть информацию о скорости и положении ротора мы получаем путём измерения обратной ЭДС свободной фазы (подробнее об этом методе можно почитать в приложенных материалах [1]).
Для базовой работы нам необходимо измерять:
-
Напряжения на всех трёх фазах мотора (U, V, W)
-
Напряжение общей точки (нейтрали)
Итого все 4 канала АЦП уже заняты. Но на этом требования не заканчиваются:
Напряжение батареи — критически важно контролировать, чтобы:
-
Не допустить глубокого разряда (что может привести к возгоранию LiPo-аккумуляторов)
-
Передавать данные на полётный контроллер
Ток потребления — необходим для:
-
Реализации продвинутых алгоритмов управления
-
Защиты от перегрузки
Температура — так как встроенного датчика нет, используем внешний NTC-термистор
В итоге ресурсов встроенного аналого-цифрового преобразователя оказалось недостаточно, поэтому придётся искать обходные решения.
Да, можно было бы пойти традиционным путём и использовать мультиплексоры, но это не решает все проблемы полностью:
Проблемы быстродействия:
-
Измерение обратной ЭДС требует точного временнóго соответствия
-
Мультиплексирование вносит задержки
-
Любая ошибка синхронизации ведёт к ошибкам коммутации
Проблемы с RC-цепями:
-
Каждый аналоговый вход, измеряющий напряжение через делитель, будет требовать фильтрующего конденсатора. Без него напряжение на входе АЦП выглядит так:
Это называется «Voltage divider loading effect»[2]. Напряжение просаживается в момент измерения, полученные данные будут далеки от реальных. Изображение взято из интернета. Это называется «Voltage divider loading effect» [2]. Напряжение просаживается в момент измерения, полученные данные будут далеки от реальных.
Бороться с этим эффектом можно разными способами, например, ОУ в режиме повторителя или низкоомные делители. Оба эти варианта мне не нравятся.
Изображение взято из интернета. -
Делители напряжения с фильтрующими конденсаторами на входах измерения напряжения свободной фазы создают дополнительные RC-цепи
-
Всё это приводит к неприемлемым задержкам сигнала, что приведёт к несвоевременным коммутациям, что приведёт к перегреву мотора и перегреву силовой части регулятора
Будем использовать компараторы:
-
Нам не нужно измерять абсолютное значение напряжения — только сравнение
(то для чего они и созданы) фаз между собой -
Компараторы работают практически мгновенно (задержки в наносекундах)
-
Они идеально подходят для определения момента перехода через ноль
-
Входы компараторов могут оперировать с высоким напряжением, что позволит избиваться от делителей напряжения между фазой и аналоговым входом
-
Они дешёвые, надёжные, простые и не занимают много места на ПП
Реализация:
-
Подключаем фазы к компараторам по схеме, выход компаратора подключается к GPIO
Упрощённая схема, компараторов должно быть 3, по одному на каждую фазу. -
В программе обрабатываем фронты сигналов как триггеры коммутации
3.Обработка управляющих сигналов:
Разобравшись с управлением мотором, перейдём к системе управления регулятором. Современные протоколы ставят перед нами интересные и неинтересные задачи:
-
PWM — старый добрый аналоговый протокол:
-
Простая широтно-импульсная модуляция
-
Заполнение = значение тяги
-
Уже устарел, но до сих пор используется
-
-
DSHOT — цифровой протокол, самый распространённый [3]:
-
Имеет несколько скоростей (150, 300, 600, 1200)
Протокол DSHOT поддерживает несколько скоростей передачи сигналов — 150, 300, 600, 1200. Чем выше число, тем быстрее передаётся управляющий сигнал от полётного контроллера к регуляторам оборотов (ESC).
Высокие скорости, например DSHOT600 или DSHOT1200, особенно полезны для RPM-фильтрации — функции в прошивках полётных контроллеров (Betaflight, INAV и др.), которая измеряет реальную частоту вращения моторов с помощью телеметрии от ESC. Зная точные обороты каждого мотора, контроллер может автоматически настраивать фильтры для подавления шума именно на этих частотах и их гармониках. Это улучшает стабилизацию, снижает вибрации и делает полёт более плавным и отзывчивым. -
Работает по принципу, схожему с WS2812 (адресные светодиоды)
-
Использует импульсы разной длительности для передачи 0 и 1
Обычная реализация обработки этих сигналов на STM32 включает:
-
Таймер в режиме захвата сигнала позволяет точно фиксировать моменты времени при изменении сигнала с 0 на 1 или с 1 на 0 на входном пине.
-
DMA складывает эти данные в буфер, не отнимая процессорное время на рутинную работу
-
При заполнении буфера процессор
Теперь, что имеем мы: -
Есть подходящий для этой задачи модуль ECAP (что-то вроде Input Сapture Mode у таймеров STM32)
Что имеем у К1946ВК035:
-
Среди списков начинки есть модуль DMA
-
Эти два блока физически не соединены между собой
-
ECAP не умеет инициировать DMA-передачи
Чем это плохо:
-
Главная проблема в том, что теперь нам придётся обрабатывать каждый из 16 бит DSHOT-пакета через интеррапты.
-
Чтобы не потерять данные, прерывания от модуля ECAP по завершению захвата сигнала должны иметь наивысший приоритет, а значит они могут вмешиваться в любые другие задачи забирая на себя всё внимание.
-
Процессору придётся постоянно отвлекаться на сохранение новых данных в буфер. И в самый неподходящий момент может произойти непоправимое — мы несвоевременно обработаем сигнал с компараторов и выпадем из синхронизации.
Наше решение:
-
Настраиваем ECAP на захват фронтов
-
Пишем обработчик прерываний, который будет вызываться по готовности новых данных
-
Новые данные переносим в буфер
-
Как можно оптимизировать?
Для эффективного копирования значений заполнения (duty) и периода (period) из регистров ECAP в буфер можно применить следующий подход. Регистры CAP0–CAP3 расположены в памяти последовательно (со смещением 0x08 от базового адреса ECAP), поэтому их можно скопировать в буфер одной операцией memcpy, избегая лишних обращений к памяти.
Вместо: dma_buffer[counter++] = IC_TIMER_REGISTER->CAP0; dma_buffer[counter++] = IC_TIMER_REGISTER->CAP1; dma_buffer[counter++] = IC_TIMER_REGISTER->CAP2; dma_buffer[counter++] = IC_TIMER_REGISTER->CAP3; Делаем так: memcpy(&dma_buffer[counter], &IC_TIMER_REGISTER->CAP0, 4 * sizeof(uint32_t)); counter += 4;
Для достижения максимального быстродействия критически важных обработчиков прерываний рекомендуется размещать их в оперативной памяти (RAM).
Прирост скорости выполнения:
-
Flash: 3–5 тактов на доступ
-
RAM: 1 такт на доступ
Разница становится особенно ощутимой при работе с высокочастотными прерываниями (более 100 кГц).
Получаем в итоге
-
DSHOT150 — работал стабильно без оптимизаций
-
DSHOT300 — работал стабильно без оптимизаций
-
DSHOT600 — заработал только после всех оптимизаций
-
DSHOT1200 — пока не тестировался
4. Хранение настроек:
Любой нормальный регулятор оборотов требует тонкой настройки под конкретный мотор и задачи. Эти параметры надо где-то хранить, причём так, чтобы они не пропадали при отключении питания. Разберём работу с Flash-памятью на К1946ВК035:
-
Чтение/запись группами по 8 байт
-
Запись необходимо производить в предварительно очищенную ячейку памяти [4].
Ячейку можно очистить, стерев всю страницу размером 1КБ. -
Основная Flash-память дополнена блоками кэш-памяти по 1 Кбайт на каждую из шин I-code и D-code [4].
Кэширование Flash-памяти — это механизм ускорения доступа к данным и инструкциям за счёт их временного хранения в высокоскоростной буферной памяти (кэше).
Доступ к данным в кэше: 1 такт (vs 3-5 тактов для Flash).
Практические советы по применению:
-
Хранение
-
Разместите ваши данные в начале отдельной страницы (1 КБ).
-
-
Запись
-
Перед записью новых значений стирайте всю страницу.
-
Пишите минимум по 8 байт за раз.
-
-
Чтение
-
Читайте также кратно 8 байтам.
-
Теперь давайте поговорим о том, что оказалось удобнее при работе с этим микроконтроллером по сравнению с STM32:
Работа с UART:
Модуль UART/USART в регуляторах оборотов служит для передачи телеметрии на полётный контроллер. В состав данных входят напряжение и ток, температура, а также обороты двигателя, вычисленные по времени переключения между фазами.
UART в К1946ВК035 прост в настройке, оснащён встроенным FIFO объёмом 32 байта, не требует использования DMA в рамках нашей задачи и позволяет передавать данные по байтам, самостоятельно формируя последовательный поток.
FPU:
Оказалось, что аппаратный модуль для работы с числами с плавающей точкой (FPU) в Cortex-M4F очень даже пригодился. Особенно для точного расчёта температуры по NTC.
SDK :
Есть базовый plib aka HAL. Есть примеры.
По большей части код писался на регистрах. Особенно порадовала реализация доступа к отдельным битам регистров через union — это избавляет от необходимости использовать битовые маски и ручные операции (|, &, ~).
регистр_bit.ИМЯ_БИТА = 1; // Новый стиль регистр |= (1 << N); // Старый стиль Например: IC_TIMER_REGISTER->ECCLR_bit.CEVT3 = 1; Вместо: IC_TIMER_REGISTER->ECCLR |= ECAP_ECCLR_CEVT3_Msk;
Заключение
Портирование AM32 на К1946ВК035 оказалось задачей не из простых — не столько из-за недостатка вычислительной мощности, сколько из-за особенностей периферии. Микроконтроллер уверенно тянет любые алгоритмы управления BLDC-моторами, но разработчику придётся вложиться в адаптацию к архитектуре:
-
Таймеры и ШИМ — функционал есть, но он разбит на отдельные блоки, что требует иной логики конфигурации.
-
АЦП — минимально достаточное число каналов заставляет искать обходные пути, такие как компараторы, вместо привычных схем на мультиплексорах.
-
Обработка DSHOT — отсутствие прямой связки ECAP с DMA превращает обработку пакетов в задачу с балансировкой прерываний.
-
Flash — работать можно, но стоит учитывать групповые операции записи и необходимость стирать страницу целиком.
В то же время, у К1946ВК035 есть и сильные стороны, которые приятно удивили:
-
Производительность Cortex-M4F с FPU обеспечивает запас по мощности.
-
Удобный UART с FIFO делает телеметрию проще в реализации.
-
Прозрачная работа с регистрами и примеры в SDK ускоряют отладку.
Если ваша задача — сделать рабочий, надёжный ESC под отечественную элементную базу, К1946ВК035 — вполне жизнеспособный вариант. Но он требует от разработчика готовности копаться в низкоуровневых нюансах и изобретать свои «велосипеды» там, где на STM32 всё уже решено.
В сухом остатке: возможно — да, просто — а, мы не любим, когда просто.
-
Baciu V. Sensorless-BLDC-controller [Электронный ресурс] // GitHub. — URL: https://github.com/vladBaciu/Sensorless-BLDC-controller.
-
How does the resistance of the load affect a voltage divider? [Электронный ресурс] // Electronics Stack Exchange. — URL: https://electronics.stackexchange.com/questions/153637/how-does-the-resistance-of-the-load-affects-a-voltage-divider.
-
Dshot API [Электронный ресурс] // Betaflight Documentation. — URL: https://betaflight.com/docs/development/API/Dshot.
-
К1946ВК035. Руководство по применению [Электронный ресурс] / АО «НИИЭТ». — 2025. — URL: https://niiet.ru/wp-content/uploads/2025/02/РП-К1946ВК035.pdf.
ссылка на оригинал статьи https://habr.com/ru/articles/938128/
Добавить комментарий