реклама на сайте
подробности

 
 
4 страниц V   1 2 3 > »   
Reply to this topicStart new topic
> STM32F UART + DMA на чтение, Как реализовать чтение через DMA для потока данных?
krdmitry
сообщение Jul 14 2012, 10:45
Сообщение #1


Частый гость
**

Группа: Участник
Сообщений: 160
Регистрация: 24-11-05
Из: СПб
Пользователь №: 11 354



Всем привет.

Можно ли на STM32F сделать чтение данных из UART в программный буфер FIFO через DMA? Размер принимаемых данных - произвольный, от 1 байта, поток от модема. Киньте примером пожалуйста, если есть опыт подобной реализации.
Go to the top of the page
 
+Quote Post
KnightIgor
сообщение Jul 14 2012, 11:56
Сообщение #2


Знающий
****

Группа: Участник
Сообщений: 643
Регистрация: 29-05-09
Из: Германия
Пользователь №: 49 725



Цитата(krdmitry @ Jul 14 2012, 12:45) *
Можно ли на STM32F сделать чтение данных из UART в программный буфер FIFO через DMA? Размер принимаемых данных - произвольный, от 1 байта, поток от модема. Киньте примером пожалуйста, если есть опыт подобной реализации.

Можно: см. Circular Mode в мануале. Однако какой-то внешний процесс должен следить за количеством уже принятых байтов, чтобы выбирать их, и вести для этого собственный указатель выборки на область FIFO. Канал DMA содержит (циклический) счетчик записи. По соотношению указателя выборки и счетчика записи можно судить о мере заполнения FIFO. Для проталкивания процесса можно воспользоваться прерыванием от половинного заполнения буфера. На случай, если такое прерывание не сработает, т.к. пришло недостаточно данных, выборку можно еще иницировать неким периодическим процессом.
Go to the top of the page
 
+Quote Post
krdmitry
сообщение Jul 14 2012, 12:11
Сообщение #3


Частый гость
**

Группа: Участник
Сообщений: 160
Регистрация: 24-11-05
Из: СПб
Пользователь №: 11 354



Цитата(KnightIgor @ Jul 14 2012, 15:56) *
Можно: см. Circular Mode в мануале. Однако какой-то внешний процесс должен следить за количеством уже принятых байтов, чтобы выбирать их, и вести для этого собственный указатель выборки на область FIFO. Канал DMA содержит (циклический) счетчик записи. По соотношению указателя выборки и счетчика записи можно судить о мере заполнения FIFO. Для проталкивания процесса можно воспользоваться прерыванием от половинного заполнения буфера. На случай, если такое прерывание не сработает, т.к. пришло недостаточно данных, выборку можно еще иницировать неким периодическим процессом.


Игорь, в теории так оно и есть. На практике несколько сложнее. Есть RTOS, собственно от ее наличия "ноги и растут". Изначально и планировал сделать, как вы описали, а проверять пришедшие одинокие байты можно в тике от внешнего/системного таймера - если заполнение меньше половины. Хотелось бы увидеть практическую реализацию, т.к. возможно есть подводные камни.

Кстати, по поводу circular mode тоже есть вопрос.
1. Предположим, у нас есть FIFO на 16 байт. При инициализации мы установили размер передаваемых данных = 16 и старт приема на 0-й элемент буфера.
2. Внешний девайс вывалил 9 байт. DMA их принял и выставил прерывание.
3. Основная задача вычитала 4 байта и "задумалась". В это время внешний девайс присылает еще 10 байт. Как быть в этом случае? Куда они запишутся?
Go to the top of the page
 
+Quote Post
e-serg
сообщение Jul 14 2012, 14:45
Сообщение #4


Частый гость
**

Группа: Участник
Сообщений: 97
Регистрация: 24-07-08
Из: Иркутск
Пользователь №: 39 180



Цитата(krdmitry @ Jul 14 2012, 21:11) *
3. Основная задача вычитала 4 байта и "задумалась". В это время внешний девайс присылает еще 10 байт. Как быть в этом случае? Куда они запишутся?


DMA ничего не знает про программное FIFO, это автомат, раскладывает байты как приказали, вызывает прерывания, если настроили.
По USART обратить на флаг IDLE

На практике, у STM32F10x DMA работают вполне адекватно, описание в даташите "несколько странное".
в одном из устройств интенсивно использую 5 каналов DMA, причем транзакции по некоторым запускаются синхронно, все нормально.
Go to the top of the page
 
+Quote Post
KnightIgor
сообщение Jul 14 2012, 19:20
Сообщение #5


Знающий
****

Группа: Участник
Сообщений: 643
Регистрация: 29-05-09
Из: Германия
Пользователь №: 49 725



Цитата(krdmitry @ Jul 14 2012, 14:11) *
Игорь, в теории так оно и есть. На практике несколько сложнее. Есть RTOS, собственно от ее наличия "ноги и растут". Изначально и планировал сделать, как вы описали, а проверять пришедшие одинокие байты можно в тике от внешнего/системного таймера - если заполнение меньше половины. Хотелось бы увидеть практическую реализацию, т.к. возможно есть подводные камни.

Про RTOS - снизошло откровение! Ну, практической готовой реализации у меня нет, т.к. не приходилось что-то решать именно в таком виде. У меня есть прием от UART по принципу FIFO, но в нем всё работает исключительно по прерыванию. Я, честно говоря, не вижу острой необходимости "заморачивать" DMA на буфер длиной 16 байт. Вообще, DMA был бы интересен, если прием велся бы быстрыми большими порциями (хорошее слово bursts), между которыми лежала бы определенная пауза. В этом случае действительно DMA разгрузил бы процессор.
Цитата
Кстати, по поводу circular mode тоже есть вопрос.
1. Предположим, у нас есть FIFO на 16 байт. При инициализации мы установили размер передаваемых данных = 16 и старт приема на 0-й элемент буфера.
2. Внешний девайс вывалил 9 байт. DMA их принял и выставил прерывание.
3. Основная задача вычитала 4 байта и "задумалась". В это время внешний девайс присылает еще 10 байт. Как быть в этом случае? Куда они запишутся?

DMA пишет в буфер FIFO по кольцу.
В примере DMA принял в общей сложности 19 байт. 4 байта успели "выбраться" целыми и невредимыми, а на бывших их местах с индексами [0], [1] и [2] будут сидеть байты с 17-го по 19-й, при этом байты с 5-го по 16-й будут по индексам с [4] по [15], а FIFO будет иметь место еще для одного байта по индексу [3], и т.д. По-моему, так! (с) Винни Пух.

Сообщение отредактировал KnightIgor - Jul 15 2012, 09:23
Go to the top of the page
 
+Quote Post
kan35
сообщение Jul 15 2012, 15:35
Сообщение #6


Знающий
****

Группа: Участник
Сообщений: 537
Регистрация: 22-02-06
Пользователь №: 14 594



Здесь прерывания на заполнение половины буфера и буфера целиком очень пригодянтся. Таким образом, по таймеру надо вынимать данные из буферов и скалдывать в очередь, при этом блокировать прерывания от ДМА. А при прерываниях по половинкам буферов невычитанные остатки в экстренном порядке выкидывать в очередь.
При этом для таких задач как пассивная обработка NMEA GPS вычитка по таймеру чаще всего вообще не будет нужна.
Я, например обрабатываю GPS приемник по прерыванию и там в секунду около 500 байт вываливается, проц работает на 24МГц и соответственно только на вход и выход из прерывания тратится 500мкс + отправка в очередь - как минимум несколько (может быть десятков даже) мсек в сек тратится на эту хрень...
Что то я вдохновился на написание такого драйвера для своих задач.
Go to the top of the page
 
+Quote Post
krdmitry
сообщение Jul 16 2012, 07:18
Сообщение #7


Частый гость
**

Группа: Участник
Сообщений: 160
Регистрация: 24-11-05
Из: СПб
Пользователь №: 11 354



Цитата(KnightIgor @ Jul 14 2012, 23:20) *
Про RTOS - снизошло откровение! Ну, практической готовой реализации у меня нет, т.к. не приходилось что-то решать именно в таком виде. У меня есть прием от UART по принципу FIFO, но в нем всё работает исключительно по прерыванию. Я, честно говоря, не вижу острой необходимости "заморачивать" DMA на буфер длиной 16 байт. Вообще, DMA был бы интересен, если прием велся бы быстрыми большими порциями (хорошее слово bursts), между которыми лежала бы определенная пауза. В этом случае действительно DMA разгрузил бы процессор.

DMA пишет в буфер FIFO по кольцу.
В примере DMA принял в общей сложности 19 байт. 4 байта успели "выбраться" целыми и невредимыми, а на бывших их местах с индексами [0], [1] и [2] будут сидеть байты с 17-го по 19-й, при этом байты с 5-го по 16-й будут по индексам с [4] по [15], а FIFO будет иметь место еще для одного байта по индексу [3], и т.д. По-моему, так! (с) Винни Пух.


Да, сейчас сделано так же: UART через прерывание. Работают одновременно 3 UART-а.
Столкнулся с хитростью в ОС:
1. Изначально при чтении из FIFO каждого уарта запрещалось прерывание именно для него. Проблема могла возникнуть в случае, если в момент блокировки FIFO (соответственно и запрета прерывания от UART) возникало переключение контекста, и данные терялись.
2. Сделал вход в критическую секцию при чтении FIFO - проблема до конца не решилась, т.к. запрет переключения контекста в моей ОС сделан как запрет всех прерываний. В результате иногда поток данных с одного UARTа может привести к потере пары байт с другого.

Вопрос: как обычно реализуется работа с UART через прерывания в ОС?

Кстати, у STM нашлась аппнота по теме: http://www.st.com/internet/com/TECHNICAL_R.../CD00256689.pdf



Цитата(kan35 @ Jul 15 2012, 19:35) *
Здесь прерывания на заполнение половины буфера и буфера целиком очень пригодянтся. Таким образом, по таймеру надо вынимать данные из буферов и скалдывать в очередь, при этом блокировать прерывания от ДМА. А при прерываниях по половинкам буферов невычитанные остатки в экстренном порядке выкидывать в очередь.
При этом для таких задач как пассивная обработка NMEA GPS вычитка по таймеру чаще всего вообще не будет нужна.
Я, например обрабатываю GPS приемник по прерыванию и там в секунду около 500 байт вываливается, проц работает на 24МГц и соответственно только на вход и выход из прерывания тратится 500мкс + отправка в очередь - как минимум несколько (может быть десятков даже) мсек в сек тратится на эту хрень...
Что то я вдохновился на написание такого драйвера для своих задач.


Отличная идея sm.gif
Поделитесь реализацией драйвера с обществом?
Go to the top of the page
 
+Quote Post
diwil
сообщение Jul 16 2012, 07:30
Сообщение #8


Местный
***

Группа: Свой
Сообщений: 366
Регистрация: 5-09-06
Из: Санкт-Петербург
Пользователь №: 20 107



Цитата(krdmitry @ Jul 14 2012, 14:45) *
Всем привет.

Можно ли на STM32F сделать чтение данных из UART в программный буфер FIFO через DMA? Размер принимаемых данных - произвольный, от 1 байта, поток от модема. Киньте примером пожалуйста, если есть опыт подобной реализации.


Есть. Я здесь кидал рабочий пример. (или во freertos ветке).
Смысл простой:
1. ДМА настраивается в режиме кольца
2. Прерывания ДМА - заоплнение буфера и половина буфера.
3. Прерывание УАРТА одно - line IDLE.

Собствено любое прерывание из этих должно разблокировать операцию чтения данных. Данные читаются до тех пор, пока не прочитаны все.

Есть недостаточек - если какие-то данные не прочитались, то они могут быть перезаписаны новыми.
Go to the top of the page
 
+Quote Post
krdmitry
сообщение Jul 16 2012, 07:53
Сообщение #9


Частый гость
**

Группа: Участник
Сообщений: 160
Регистрация: 24-11-05
Из: СПб
Пользователь №: 11 354



Цитата(diwil @ Jul 16 2012, 11:30) *
Есть. Я здесь кидал рабочий пример. (или во freertos ветке).
Смысл простой:
1. ДМА настраивается в режиме кольца
2. Прерывания ДМА - заоплнение буфера и половина буфера.
3. Прерывание УАРТА одно - line IDLE.

Собствено любое прерывание из этих должно разблокировать операцию чтения данных. Данные читаются до тех пор, пока не прочитаны все.

Есть недостаточек - если какие-то данные не прочитались, то они могут быть перезаписаны новыми.


Спасибо.
Go to the top of the page
 
+Quote Post
KnightIgor
сообщение Jul 16 2012, 08:02
Сообщение #10


Знающий
****

Группа: Участник
Сообщений: 643
Регистрация: 29-05-09
Из: Германия
Пользователь №: 49 725



Цитата(krdmitry @ Jul 16 2012, 09:18) *
Да, сейчас сделано так же: UART через прерывание. Работают одновременно 3 UART-а.
...
Вопрос: как обычно реализуется работа с UART через прерывания в ОС?

Поделюсь одним "болтом" на хитрую "гайку" организации FIFO и работы по прерыванию применительно к приему: во время выборки из FIFO запрещать прерывания... не надо!
Предлагаю (проверенный) алгоритм:

1. Заводится бинарный флаг критической секции.
2. В обработчике прерывания по приему проверяется:
2.1. есть ли место в FIFO положить туда принятый байт. Важно - байт еще НЕ считан с регистра DR!
2.2. не взведен ли флаг критической секции.

Только если эти оба условия выполняются - место есть, флаг не взведен, происходит считывание DR, запись его в FIFO и коррекция счетчика и указателя записи.
Если хотя бы ОДНО из условий выполнилось - нет места или флаг-таки взведён, происходит ЗАПРЕТ своего прерывания и выход из него.

3. Основной процесс выборки с определенной периодичностью проверяет, нет ли в FIFO чем поживиться.
Если да, то:
3.1. установить флаг критической секции.
3.2. выбрать FIFO (или часть его), скорректировать счетчик и указатель выборки.
3.3. сбросить флаг критической секции.
3.4. (Пере)разрешить прерывание от источника (всегда).

Что получается:
- если прерывание возникло вне критической секции, то счетчик и указатель будут модифицированы монопольно в прерывании (если место в FIFO было).
- если прерывание возникло уже внутри критической секции, то прерывание лишь запретит себя само и вернет управление, а процесс выборки будет изменять счетчик и указатель монопольно; как только критическая секция будет пройдена, прерывание будет (пере)разрешено (я пишу "пере-", имея ввиду, что установка уже установленного разрешения прерывания ничего не меняет), и если DR еще не был считан, то тут же возникнет прерывание - см. 2).

Можно спросить, а что будет, если пока прерывание было запрещено, пришел еще один байт? Будет ж...па предыдущему байту. Но весь расклад будет говорить лишь о том, что система не достаточно производительна, либо неудачно распределены приоритеты прерываний.

Для случая RTOS также нужно обрамить выборку критической секцией средствами RTOS, то есть:
- начать RTOS-секцию
- установить флаг
- сделать дело
- сбросить флаг
- закрыть RTOS-секцию

Сообщение отредактировал KnightIgor - Jul 16 2012, 08:16
Go to the top of the page
 
+Quote Post
kan35
сообщение Jul 16 2012, 08:45
Сообщение #11


Знающий
****

Группа: Участник
Сообщений: 537
Регистрация: 22-02-06
Пользователь №: 14 594



krdmitry, поясните, а то из референс мануала не вполне ясно:
IDLE прерывание это когда контроллер фиксирует паузы между байтами?
Go to the top of the page
 
+Quote Post
diwil
сообщение Jul 16 2012, 09:07
Сообщение #12


Местный
***

Группа: Свой
Сообщений: 366
Регистрация: 5-09-06
Из: Санкт-Петербург
Пользователь №: 20 107



- IDLE прерывание это когда контроллер фиксирует паузы между байтами?

да, более, кажется, 1.5 байта
Go to the top of the page
 
+Quote Post
krdmitry
сообщение Jul 16 2012, 09:08
Сообщение #13


Частый гость
**

Группа: Участник
Сообщений: 160
Регистрация: 24-11-05
Из: СПб
Пользователь №: 11 354



Цитата(kan35 @ Jul 16 2012, 12:45) *
krdmitry, поясните, а то из референс мануала не вполне ясно:
IDLE прерывание это когда контроллер фиксирует паузы между байтами?


Похоже, что так. Вопрос, видимо, адресован diwill? В референс-мануале не нашел конкретного ответа, сколько битовых интервалов нужно для генерации прерывания IDLE. Видимо, это что-то из области LIN или smartcard протоколов, но подойдет и под нашу задачу.
Go to the top of the page
 
+Quote Post
kan35
сообщение Jul 16 2012, 09:57
Сообщение #14


Знающий
****

Группа: Участник
Сообщений: 537
Регистрация: 22-02-06
Пользователь №: 14 594



ой, да, diwill
krdmitry, спасибо за ответ
Я вот тоже в референсе по-быстрому не нашел ответа.
Go to the top of the page
 
+Quote Post
SSerge
сообщение Jul 16 2012, 20:20
Сообщение #15


Профессионал
*****

Группа: Свой
Сообщений: 1 719
Регистрация: 13-09-05
Из: Novosibirsk
Пользователь №: 8 528



Цитата(KnightIgor @ Jul 16 2012, 15:02) *
Поделюсь одним "болтом" на хитрую "гайку" организации FIFO и работы по прерыванию применительно к приему: во время выборки из FIFO запрещать прерывания... не надо!

Как-то сложновато...
Если отказаться от счётчика (а зачем он нужен?) и оперировать только указателями на "голову" и "хвост" буфера, то и флаг не понадобиться, и прерывания можно не трогать, один раз только разрешить при инициализации и всё.


--------------------
Russia est omnis divisa in partes octo.
Go to the top of the page
 
+Quote Post

4 страниц V   1 2 3 > » 
Reply to this topicStart new topic
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 18th July 2025 - 03:07
Рейтинг@Mail.ru


Страница сгенерированна за 0.02605 секунд с 7
ELECTRONIX ©2004-2016