Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: STM32, работа с UART и DMA
Форум разработчиков электроники ELECTRONIX.ru > Сайт и форум > В помощь начинающему > ARM, 32bit
esaulenka
Доброго дня.

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

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

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

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

А использовать DMA совместно с кольцевым буфером никакой проблемы нет.
Зачем там что-то останавливать и перезапускать? Почитайте описание работы DMA.
Накопилось у Вас в Вашем кольцевом буфере сколько-то данных - программируете DMA-канал на передачу этого блока.
Закончилась DMA-передача блока - программируете на след. блок (если уже накопился).
Что тут сложного?

С приёмом сложнее. Так как размер входящих данных заранее не известен, то нужно будет программировать на какой-то размер блока,
а потом возможно - контролировать кол-во поступивших на данный момент данных и останавливать DMA-приём.
Я на STM32 связку UART.RX+DMA не использовал, так что сказать точно про приём не могу.
Сергей Борщ
Цитата(jcxz @ Jul 9 2014, 04:48) *
а потом возможно - контролировать кол-во поступивших на данный момент данных и останавливать DMA-приём.
У UART есть хорошее прерывание IDLE.
andrewlekar
DMA при работе с UART позволит вам снизить нагрузку на процессор при передаче больших объёмов данных. Если ресурсов процессора хватает или объём данных небольшой, то вам без DMA вполне можно обойтись. Отправляйте байт, в цикле дожидайтесь пустого передатчика, повторяйте.
jcxz
Цитата(andrewlekar @ Jul 9 2014, 11:51) *
DMA при работе с UART позволит вам снизить нагрузку на процессор при передаче больших объёмов данных.

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

Цитата(andrewlekar @ Jul 9 2014, 11:51) *
Отправляйте байт, в цикле дожидайтесь пустого передатчика, повторяйте.

ЖЕСТЬ twak.gif
andrewlekar
В чём проблема то?
demiurg_spb
Цитата(jcxz @ Jul 9 2014, 05:48) *
Всё с точностью до наоборот. Я давно и успешно использую DMA для STM32.
На приём с помощью DMA никаких проблем нет. По сути получается аппаратный приёмный кольцевой буфер, который необходимо с достаточной интенсивностью выгребать.
И знать кол-во принимаемых данных совсем не нужно.
А вот с передачей действительно немного не тривиально.
Как вариант, можно организовать очередь из блоков памяти для отправки по ДМА. Но это не выгодно для байтовой передачи.
Но и здесь можно вывернуться накапливая байты в блоке и отправлять их например по таймеру и или таймауту и по заполнению блока.
На мой взгляд это всё не слишком красиво. А вашу идею с кольцевым буфером я не до конца понял.
Как передать участок кольцевого буфера перехлёстывающегося через его конец?
ПС: При использовании динамической памяти задача для передачи блоков данных по UART через DMA решается самым элегантным образом, но это не мой метод...
jcxz
Цитата(demiurg_spb @ Jul 9 2014, 14:13) *
Всё с точностью до наоборот. Я давно и успешно использую DMA для STM32.
На приём с помощью DMA никаких проблем нет.

Проблема не с DMA, проблема с их количеством. ТС написал про "кучу UART-ов", а кол-во DMA-каналов у нас сильно ограниченно.
И если для передачи ещё можно как-то попытаться расшарить один DMA-канал на неск. UART-ов, то вот для приёма ой....
А ведь в девайсе возможно DMA и для других нужд могут быть нужны.

Цитата(demiurg_spb @ Jul 9 2014, 14:13) *
Как передать участок кольцевого буфера перехлёстывающегося через его конец?
ПС: При использовании динамической памяти задача для передачи блоков данных по UART через DMA решается самым элегантным образом, но это не мой метод...

С передачей как раз всё просто.
При перехлёсте очевидно же - передавать в два приёма: до конца и с начала.
В обработчике завершения DMA проверять "имеются-ли ещё символы в TX-буфере?" и стартовать новый блок если да.
Если нет - стоп, сброс флага активности TX.DMA (с опциональным освобождением DMA-канала в пул).

Стартовать сам процесс передачи можно либо в каком-то периодическом процессе (периодически проверяя есть-ли байты в TX-FIFO),
либо в функции, пишущей в TX-FIFO при достижении некоей water mark.
Либо и так и так.
Но это при условии, что флаг активности TX.DMA сброшен.

Недавно когда я переносил некоторый шаблонный проект с LPC на STM32 (там имелся символьный вывод потока в UART), в LPC DMA для этого не использовался (так как там хватало FIFO).
На STM32 пришлось сделать через DMA именно так как и описал.
Заняло это около дня.
demiurg_spb
Цитата(jcxz @ Jul 9 2014, 13:27) *
Хорошо.
Но тогда при записи блока в фифо равного его размеру мы не сможем больше записать в фифо ни одного байта до окончания DMA транзакции,
а это весьма долго, т.к. мы привязаны к скорости UART. Это как-бы не совсем то что хочется, или вы как-то обходите эту ситуацию?
jcxz
А откуда вы знаете долго или нет? вы же не знаете какими блоками будет писать ТС, и вообще - блоками-ли он будет писать? Он писал как раз про байтовый ввод/вывод.
Размер FIFO можно выбрать соответствующим (побольше) и стартовать DMA-транзакцию, как я уже писал, можно раньше, до полного заполнения буфера.
У меня был простой символьный вывод, DMA-транзакция стартовала по некоему таймауту (с величиной задержки некритичной для потока)
или по заполнению трети буфера.
Как оптимально - будет зависеть от протокола обмена, который идёт через этот канал.
demiurg_spb
Цитата(jcxz @ Jul 9 2014, 14:51) *
Ваша точка зрения понятна. Спасибо.
adnega
Цитата(jcxz @ Jul 9 2014, 14:51) *
DMA-транзакция стартовала по некоему таймауту (с величиной задержки некритичной для потока) или по заполнению трети буфера.

Или по "пинку" из программы. Особенно в протокольных вещах часто бывает известно, когда пакет уже готов польностью.
demiurg_spb
Цитата(adnega @ Jul 9 2014, 17:33) *
Или по "пинку" из программы. Особенно в протокольных вещах часто бывает известно, когда пакет уже готов польностью.

+1 uart_flush
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.