Я хотел всё написать про протокол DMX на STM32. Я всё же сделал это>< Протокол сей используется большей частью в освещении (в театрах и типа того) и подобных некритических к потерям пактов областям. Один пакет DMX содержит информацию о уровнях 512 каналов (0-255), посылается он 44 раза в секунду, если без перерывов.
В качестве физической линии используется стандарт RS-485 (дифференциальная линия), программно же это последовательный асинхронный протокол (UART) со скоростью передачи данных 250 кбит/сек с двумя стоповыми битами и без контроля чётности.
читать дальшеПакет состоить из трёх частей: сброс линии (BREAK), стартовый код (байт 0x00) и данные (512 байт с уровнями каналов). То есть достаточно просто. Тайминги установлены тоже не жёстко, только на минимум: ширина BREAK не менее 92 мкс (лучше ~120 мкс), перерыв между BREAK и стартовым кодом - не менее 12 мкс. В остальном полная свобода.
Приём пакета заключается в ожидании сброса линии (определяется как Frame Error, FE) и последовательном приёме 513 байт в буфер (но их может быть и меньше). Если нулевой байт равен нулю, то это пакет DMX и его можно передать дальше в устройство. Если нет, пакет отбрасывается (так как это пакет какого-то другого формата).
Отправка тоже незамысловата: передаём BREAK нужной длины, передаём Mark After Break (время между BREAK и стартовыйм кодом) нужной длины, передаём ноль и 512 байт данных. После чего всё начинается с начала.
Самая хитрость заключается в создании BREAK и MAB. Некоторые контроллеры, в частности и STM32, хвастаются, что умеют делать BREAK аппаратно. В общем-то, это хорошо, но BREAK отличается от нулевого байта только отсутствием стопового бита (вместо 1 там 0), длина же байта остаётся той же. Для DMX такое положение дел не годится — байт при заявленной скорости занимает 44 мкс, что в два раза меньше минимально необходимой. потому его надо генерировать как-то иначе.
Раньше я использовал для таких целей таймер, но это нерационально - целый таймер на уарт, жуть. А если надо 4 DMX генерировать? Не вариант.
Если вспомнить, что в уарте есть встроенный таймер (протокол-то асинхронный), то можно воспользоваться и им. Алгоритм таков:
1. Передача BREAK.
Переводим линию в низкий уровень, знаменующий собой стартовый бит, используя режим GPIO.
Выбираем такую скорость UART, чтобы передача одного байта занимала требуемое нам время в 120 мкс. Передаём какой-нибудь байт (так как он никуда не улетит всё равно).
Окончание передачи в линию ознаменует и конец заданного интервала времени.
2. Передача Mark After Break.
Всё то же самое, только уровень на линии дефолтный: высокий.
Переводим линию в высокий уровень, знаменуя возврат линии в неактивное состояние, используя режим GPIO.
Выбираем такую скорость UART, чтобы передача одного байта занимала требуемое нам время в 24 мкс (да, с запасом). Передаём какой-нибудь байт.
Окончание передачи завершит данный этап.
3. Передача стартового кода.
Линия переводится в режим UART, желательно таким образом, чтоб промежуточных состояний не было (никаких отклонений от высокого уровня на линии быть не должно). В частности, в СТМ обратите внимание на переключение в альтернативную функцию: сначала выбираем номер, потом переводим режим! Если номер выбирать после, то кто знает, какая периферия подключится на это время и что будет на выводе.
Выбирается скорость передачи данных 250 кбит/сек.
Передаётся нулевой байт 0x00.
4. Передача данных.
По очереди передаются данные, все 512 байт.
Всё. В итоге получается, что передача DMX осуществляется только на прерываниях/флагах статуса самого приёмопередатчика, без привлечения посторонней периферии. К сожалению, в некоторых контроллерах (типа LPC23xx) нет прерываний о завершении передачи в линию, потому там данный алгоритм применим с некоторыми ограничениями и костылями. Но это уже древний хлам, так что не будем о нём.
Расчёт времени передачи байта по UART выполняется примерно так: 1 бит передаётся за (1000000 / скорость) микросекунд. В байте с двумя стоповыми битами всего 11 бит: один стартовый, восемь бит данных и два стоповых. То есть в 11 раз больше времени передачи одного бита. Обратив эту формулу, получим формулу для расчёта скорости по заданной длине.
Собственно, пример приёма и передачи DMX. проект сейчас настроен на передачу сигнала (который ещё надо драйвером RS485 сконвертировать в дифференциальный вид).
Если dmx_Transmit закомментировать, а dmx_Receive наоборот, то плата начнёт принимать DMX.
В данный момент используется USART3 с выводами PB10, PB11:
Линия управления направлением драйвера RS485 (~RE/DE) выведена на PA2:
UART в STM32 достаточно прост (несмотря на широкие возможности) и имеет всего несколько управляющих регистров:
USART_SR — регистр статуса, текущее состояние приёмопередатчика;
USART_DR —- регистр данных;
USART_BRR — регистр настройки скорости, делитель, 4 бита дробной части и 12 целой, но по сути, туда надо просто записать результат деления (частота шины/нужная скорость);
USART_CR1 — включение/выключение модуля, разрешение генерации прерываний;
USART_CR2 — для настройки генерации синхросигнала, количества стоповых бит и LIN;
USART_CR3 — для DMA и всяких хитрых режимов работы (IrDA, линии CTS, RTS);
USART_GTPR — какие-то тайминги для работы со смарт-картами.
Чтоб UART заработал, достаточно подать на него тактирование, включить (USART_CR1: UE, RE, TE), настроить скорость (USART_BRR) и передавать/принимать данные (USART_DR). Ну и, если надо, настроить режимы чётности и всякие там стоповые биты.
Вот.
Интересные файлы:
uart.c
uart.h
dmx.c
dmx.h
Проект.
STM32F4. DMX v2
Я хотел всё написать про протокол DMX на STM32. Я всё же сделал это>< Протокол сей используется большей частью в освещении (в театрах и типа того) и подобных некритических к потерям пактов областям. Один пакет DMX содержит информацию о уровнях 512 каналов (0-255), посылается он 44 раза в секунду, если без перерывов.
В качестве физической линии используется стандарт RS-485 (дифференциальная линия), программно же это последовательный асинхронный протокол (UART) со скоростью передачи данных 250 кбит/сек с двумя стоповыми битами и без контроля чётности.
читать дальше
В качестве физической линии используется стандарт RS-485 (дифференциальная линия), программно же это последовательный асинхронный протокол (UART) со скоростью передачи данных 250 кбит/сек с двумя стоповыми битами и без контроля чётности.
читать дальше