DShot receiver on STM32


14.08.2025

Приймання сигналу DShot 150/300/600 з використання DMA. Приклад для STM32.

Якщо в мікроконтролері є DMA, який можна використати, його обов'язково треба використати, навіть, коли здається, що в конкретному випадку можна обійтися без DMA. Використання DMA звільнює ядро мікроконтролера від рутинних операцій.

Що таке DShot?

DShot - це простий протокол передачі цифрової інформації по одному дроту. Використовується для керування ESC. Передача інформації пакетна. Тобто передається певна кількість біт, після чого витримується пауза, яка розділяє пакети. Детекція бітів, нуль або один, відбувається за шириною імпульсів. Якщо імпульс коротший за певне значення - це "0", якщо довший за певне значення - то це "1".

Приблизний вигляд протоколу DShot:

Як видно передаються 16 біт.

Протоколи DShot150, DShot300, DShot600 мають однакову структуру і відрізняються лише швидкістю. DShot150 - передає 150 пакетів за секунду, DShot300 - триста, DShot600 - відповідно 600 пакетів за секунду.

Приймання DShot

Нам треба прийняти 16 біт, які передаються по одному входу, а потім обробити їх. Якщо конкретизувати задачу - нам потрібно вимірювати довжину кожного з 16 імпульсів і вирішувати це 0 чи 1. По завершенню приймання 16 біт, обробити весь пакет - перевірити контрольну суму, витягти дані тощо.

1. Рішення #1. Таймер + переривання

Найпростіше, але не найкраще рішення - використовувати для вимірювання ширини імпульсів звичайний таймер, а показання його знімати по перериванню від входу GPIO. Коли переривання спрацьовує при наростанні сигналу запам'ятовувати показник лічильника таймера, коли переривання спрацьовує на спад сигналу запам'ятовувати показник лічильника таймера, вираховувати різницю між запам'ятованими показниками таймера і якщо різниця менша за порогове - це був 0, якщо більша, тоді це 1.

Та у цьому підході є одна вада - це переривання. На справді переривання не виконуються негайно. Спочатку виставляється прапорець переривання, який означає, що трапилась певна подія, яку треба обробити. І коли мікроконтролер перевірить цей прапорець, тоді він почне підготовку до обробки переривання. Коли мікроконтролер обробляє більш пріоритетне переривання, він не буде перериватися на обробку вашого переривання, а завершить поточне, а потім перейде до наступного. Сам перехід до обробки переривання теж потребує "підготовки". Мікроконтролер запам'ятає те місце, на якому його перервали, збереже всю необхідну інформацію, яка потрібна буде при поверненні до виконання поточної задачі. Весь цей час таймер продовжує працювати, тому похибка вимірювань неминуча. Коли сигнал достатньо розтягнутий у часі - це не критично. В нашому випадку довжина імпульсів така мала, що може статися так, що наступне переривання відбудеться ще до того, як контролер встигне обробити поточне переривання. З таким підходом реально обробити хіба що DShot150. При роботі зі швидшими протоколами будуть виникати проблеми.

2. Рішення #2. Захоплення сигналу таймером + переривання

Трохи ліпше ситуація при використанні таймера у режимі захоплення сигналу. Коли таймер сам вимірює довжину сигналу. Нам залишається лише скопіювати значення у буфер кожного разу коли завершився імпульс. Це теж доводиться робити по перериванню таймера, пов'язаному з захопленням сигналу. Це краще ніж перший варіант, але не достатньо швидко через занадто коротку тривалість імпульсів DShot, яка вимірюється десятками імпульсів тактування мікроконтролера. Мікроконтролер так само не встигає обробляти переривання і трапляються пропуски бітів, які ведуть до втрати цілого пакета.

3. Рішення #3. Захоплення сигналу таймером + DMA

Найефективнішим рішенням є використання режиму захоплення таймером + відправляти результати у масив за допомогою DMA. А переривання від DMA обробляти, коли буде прийнято всі 16 біт. Часу між пакетами достатньо, щоб обробити прийняті дані.

Таким чином всі 16 біт будуть залітати у масив і при цьому мікроконтролер не буде відволікатися на ці операції. А після приймання всіх 16 біт виникне переривання від DMA і можна спокійно обробляти прийняті дані.

В прикладі реалізовано захоплення DShot150, DShot300, DShot600. Можливе автоматичне визначення швидкості протоколу DShot. Також в прикладі реалізовано захоплення PWM сигналу.

Завантажити приклад для STM32F030 можна тут: https://git.avislab.com/andre/STM32G030_Dshot

STM32
Коментарі:
Василь говорить:
15.08.2025 12:11
використання  HAL - це дань моді? Якось StdPeriph звичніше....

andre говорить:
15.08.2025 13:28
З HAL дещо простіше перетаскувати проєкти на інші серії мікроконтролерів. Це, мабуть, єдина причина, чому я зі скрипом перейшов на HAL.

Додати коментар
Code
* - обов'язкові поля

Архіви