esaulenka 7 8 июля, 2014 Опубликовано 8 июля, 2014 · Жалоба Доброго дня. Нужен совет по архитектуре типичнейшей задачи, как правильно соорудить передачу по UART. Мы используем кучу уартов, работая через прерывания. Далее - копипаста по нескольким uart'ам, различающаяся только указателями на uart, и на буфер: обработчик прерывания, который перекладывает байты из софт-буфера (ну и наоборот, в буфер); API - функции "получить 1 байт", "передать 1 байт", "передать N байт". Типичное использование на передачу - функция формирует пакет и налету скидывает его порциями в буфер. Так вот, все примеры общения с DMA, что я видел - сформировать большой буфер, настроить DMA на его передачу, курить бамбук, пока всё не отработает. С нашим API как-то не очень совместимо - постоянно останавливать-запускать DMA при добавлении в очередь ещё одного байта совсем плохо. Я что-то пропустил, или передача по DMA на мою задачу никак не ложится? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
jcxz 241 9 июля, 2014 Опубликовано 9 июля, 2014 · Жалоба На Вашу задачу STM32 - никак не ложится, ибо очень неудобно в нём использовать UART, а тем более если нужна куча их. Нужно было выбирать что-то другое, где есть нормальное FIFO в UART. А так - на каждый UART Вам придётся выделить в худшем случае по два DMA-канала. Может и не хватить их. А использовать DMA совместно с кольцевым буфером никакой проблемы нет. Зачем там что-то останавливать и перезапускать? Почитайте описание работы DMA. Накопилось у Вас в Вашем кольцевом буфере сколько-то данных - программируете DMA-канал на передачу этого блока. Закончилась DMA-передача блока - программируете на след. блок (если уже накопился). Что тут сложного? С приёмом сложнее. Так как размер входящих данных заранее не известен, то нужно будет программировать на какой-то размер блока, а потом возможно - контролировать кол-во поступивших на данный момент данных и останавливать DMA-приём. Я на STM32 связку UART.RX+DMA не использовал, так что сказать точно про приём не могу. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Сергей Борщ 141 9 июля, 2014 Опубликовано 9 июля, 2014 · Жалоба а потом возможно - контролировать кол-во поступивших на данный момент данных и останавливать DMA-приём.У UART есть хорошее прерывание IDLE. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
andrewlekar 0 9 июля, 2014 Опубликовано 9 июля, 2014 · Жалоба DMA при работе с UART позволит вам снизить нагрузку на процессор при передаче больших объёмов данных. Если ресурсов процессора хватает или объём данных небольшой, то вам без DMA вполне можно обойтись. Отправляйте байт, в цикле дожидайтесь пустого передатчика, повторяйте. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
jcxz 241 9 июля, 2014 Опубликовано 9 июля, 2014 · Жалоба DMA при работе с UART позволит вам снизить нагрузку на процессор при передаче больших объёмов данных. ...либо снизить потребление электричества. Отправляйте байт, в цикле дожидайтесь пустого передатчика, повторяйте. ЖЕСТЬ :twak: Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
andrewlekar 0 9 июля, 2014 Опубликовано 9 июля, 2014 · Жалоба В чём проблема то? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
demiurg_spb 0 9 июля, 2014 Опубликовано 9 июля, 2014 · Жалоба Всё с точностью до наоборот. Я давно и успешно использую DMA для STM32. На приём с помощью DMA никаких проблем нет. По сути получается аппаратный приёмный кольцевой буфер, который необходимо с достаточной интенсивностью выгребать. И знать кол-во принимаемых данных совсем не нужно. А вот с передачей действительно немного не тривиально. Как вариант, можно организовать очередь из блоков памяти для отправки по ДМА. Но это не выгодно для байтовой передачи. Но и здесь можно вывернуться накапливая байты в блоке и отправлять их например по таймеру и или таймауту и по заполнению блока. На мой взгляд это всё не слишком красиво. А вашу идею с кольцевым буфером я не до конца понял. Как передать участок кольцевого буфера перехлёстывающегося через его конец? ПС: При использовании динамической памяти задача для передачи блоков данных по UART через DMA решается самым элегантным образом, но это не мой метод... Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
jcxz 241 9 июля, 2014 Опубликовано 9 июля, 2014 · Жалоба Всё с точностью до наоборот. Я давно и успешно использую 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 именно так как и описал. Заняло это около дня. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
demiurg_spb 0 9 июля, 2014 Опубликовано 9 июля, 2014 · Жалоба Хорошо. Но тогда при записи блока в фифо равного его размеру мы не сможем больше записать в фифо ни одного байта до окончания DMA транзакции, а это весьма долго, т.к. мы привязаны к скорости UART. Это как-бы не совсем то что хочется, или вы как-то обходите эту ситуацию? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
jcxz 241 9 июля, 2014 Опубликовано 9 июля, 2014 · Жалоба А откуда вы знаете долго или нет? вы же не знаете какими блоками будет писать ТС, и вообще - блоками-ли он будет писать? Он писал как раз про байтовый ввод/вывод. Размер FIFO можно выбрать соответствующим (побольше) и стартовать DMA-транзакцию, как я уже писал, можно раньше, до полного заполнения буфера. У меня был простой символьный вывод, DMA-транзакция стартовала по некоему таймауту (с величиной задержки некритичной для потока) или по заполнению трети буфера. Как оптимально - будет зависеть от протокола обмена, который идёт через этот канал. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
demiurg_spb 0 9 июля, 2014 Опубликовано 9 июля, 2014 · Жалоба Ваша точка зрения понятна. Спасибо. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
adnega 11 9 июля, 2014 Опубликовано 9 июля, 2014 · Жалоба DMA-транзакция стартовала по некоему таймауту (с величиной задержки некритичной для потока) или по заполнению трети буфера. Или по "пинку" из программы. Особенно в протокольных вещах часто бывает известно, когда пакет уже готов польностью. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
demiurg_spb 0 9 июля, 2014 Опубликовано 9 июля, 2014 · Жалоба Или по "пинку" из программы. Особенно в протокольных вещах часто бывает известно, когда пакет уже готов польностью. +1 uart_flush Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться