Введение: почему К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 складывает эти данные в буфер, не отнимая процессорное время на рутинную работу
При заполнении буфера процессор
Теперь, что имеем мы:
Что имеем у К1946ВК035:
Есть подходящий для этой задачи модуль ECAP (что-то вроде Input Сapture Mode у таймеров STM32)
Среди списков начинки есть модуль DMA
Эти два блока(ECAP и 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.