Перейти к содержанию
    

STM32, работа с UART и DMA

Доброго дня.

 

Нужен совет по архитектуре типичнейшей задачи, как правильно соорудить передачу по UART.

 

Мы используем кучу уартов, работая через прерывания. Далее - копипаста по нескольким uart'ам, различающаяся только указателями на uart, и на буфер: обработчик прерывания, который перекладывает байты из софт-буфера (ну и наоборот, в буфер); API - функции "получить 1 байт", "передать 1 байт", "передать N байт".

Типичное использование на передачу - функция формирует пакет и налету скидывает его порциями в буфер.

 

Так вот, все примеры общения с DMA, что я видел - сформировать большой буфер, настроить DMA на его передачу, курить бамбук, пока всё не отработает.

С нашим API как-то не очень совместимо - постоянно останавливать-запускать DMA при добавлении в очередь ещё одного байта совсем плохо.

 

Я что-то пропустил, или передача по DMA на мою задачу никак не ложится?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

На Вашу задачу STM32 - никак не ложится, ибо очень неудобно в нём использовать UART, а тем более если нужна куча их. Нужно было выбирать что-то другое, где есть нормальное FIFO в UART.

А так - на каждый UART Вам придётся выделить в худшем случае по два DMA-канала. Может и не хватить их.

 

А использовать DMA совместно с кольцевым буфером никакой проблемы нет.

Зачем там что-то останавливать и перезапускать? Почитайте описание работы DMA.

Накопилось у Вас в Вашем кольцевом буфере сколько-то данных - программируете DMA-канал на передачу этого блока.

Закончилась DMA-передача блока - программируете на след. блок (если уже накопился).

Что тут сложного?

 

С приёмом сложнее. Так как размер входящих данных заранее не известен, то нужно будет программировать на какой-то размер блока,

а потом возможно - контролировать кол-во поступивших на данный момент данных и останавливать DMA-приём.

Я на STM32 связку UART.RX+DMA не использовал, так что сказать точно про приём не могу.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

а потом возможно - контролировать кол-во поступивших на данный момент данных и останавливать DMA-приём.
У UART есть хорошее прерывание IDLE.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

DMA при работе с UART позволит вам снизить нагрузку на процессор при передаче больших объёмов данных. Если ресурсов процессора хватает или объём данных небольшой, то вам без DMA вполне можно обойтись. Отправляйте байт, в цикле дожидайтесь пустого передатчика, повторяйте.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

DMA при работе с UART позволит вам снизить нагрузку на процессор при передаче больших объёмов данных.

...либо снизить потребление электричества.

 

Отправляйте байт, в цикле дожидайтесь пустого передатчика, повторяйте.

ЖЕСТЬ :twak:

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Всё с точностью до наоборот. Я давно и успешно использую DMA для STM32.

На приём с помощью DMA никаких проблем нет. По сути получается аппаратный приёмный кольцевой буфер, который необходимо с достаточной интенсивностью выгребать.

И знать кол-во принимаемых данных совсем не нужно.

А вот с передачей действительно немного не тривиально.

Как вариант, можно организовать очередь из блоков памяти для отправки по ДМА. Но это не выгодно для байтовой передачи.

Но и здесь можно вывернуться накапливая байты в блоке и отправлять их например по таймеру и или таймауту и по заполнению блока.

На мой взгляд это всё не слишком красиво. А вашу идею с кольцевым буфером я не до конца понял.

Как передать участок кольцевого буфера перехлёстывающегося через его конец?

ПС: При использовании динамической памяти задача для передачи блоков данных по UART через DMA решается самым элегантным образом, но это не мой метод...

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Всё с точностью до наоборот. Я давно и успешно использую DMA для STM32.

На приём с помощью DMA никаких проблем нет.

Проблема не с DMA, проблема с их количеством. ТС написал про "кучу UART-ов", а кол-во DMA-каналов у нас сильно ограниченно.

И если для передачи ещё можно как-то попытаться расшарить один DMA-канал на неск. UART-ов, то вот для приёма ой....

А ведь в девайсе возможно DMA и для других нужд могут быть нужны.

 

Как передать участок кольцевого буфера перехлёстывающегося через его конец?

ПС: При использовании динамической памяти задача для передачи блоков данных по UART через DMA решается самым элегантным образом, но это не мой метод...

С передачей как раз всё просто.

При перехлёсте очевидно же - передавать в два приёма: до конца и с начала.

В обработчике завершения DMA проверять "имеются-ли ещё символы в TX-буфере?" и стартовать новый блок если да.

Если нет - стоп, сброс флага активности TX.DMA (с опциональным освобождением DMA-канала в пул).

 

Стартовать сам процесс передачи можно либо в каком-то периодическом процессе (периодически проверяя есть-ли байты в TX-FIFO),

либо в функции, пишущей в TX-FIFO при достижении некоей water mark.

Либо и так и так.

Но это при условии, что флаг активности TX.DMA сброшен.

 

Недавно когда я переносил некоторый шаблонный проект с LPC на STM32 (там имелся символьный вывод потока в UART), в LPC DMA для этого не использовался (так как там хватало FIFO).

На STM32 пришлось сделать через DMA именно так как и описал.

Заняло это около дня.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Хорошо.

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

а это весьма долго, т.к. мы привязаны к скорости UART. Это как-бы не совсем то что хочется, или вы как-то обходите эту ситуацию?

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

А откуда вы знаете долго или нет? вы же не знаете какими блоками будет писать ТС, и вообще - блоками-ли он будет писать? Он писал как раз про байтовый ввод/вывод.

Размер FIFO можно выбрать соответствующим (побольше) и стартовать DMA-транзакцию, как я уже писал, можно раньше, до полного заполнения буфера.

У меня был простой символьный вывод, DMA-транзакция стартовала по некоему таймауту (с величиной задержки некритичной для потока)

или по заполнению трети буфера.

Как оптимально - будет зависеть от протокола обмена, который идёт через этот канал.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

DMA-транзакция стартовала по некоему таймауту (с величиной задержки некритичной для потока) или по заполнению трети буфера.

Или по "пинку" из программы. Особенно в протокольных вещах часто бывает известно, когда пакет уже готов польностью.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Или по "пинку" из программы. Особенно в протокольных вещах часто бывает известно, когда пакет уже готов польностью.

+1 uart_flush

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...