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

 
 
> ADC3 в режиме сканирования и DMA2, Необъяснимые "лишние" данные и рассинхронизация
KnightIgor
сообщение Jul 21 2014, 12:04
Сообщение #1


Знающий
****

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



Здравствуйте, коллеги.

Не побеждается ADC3.

Имеем:
- STM32F103VC на 24MHz (не 72 для уменьшения потребления, т.к. есть back up на аккумуляторе),
- ADC3 в режиме сканирования трех каналов (11, 12 и 13), ADC тактируется 12MHz.
- естественно DMA2, канал 5, который складывает оцифрованное в буфер U16 длиной 32 триплета - всего 96 слов; таких буферов, конечно, два: один заполняем, из другого читаем.
- таймер 8, который с частотой 100Hz (замеряно) пихает ADC3 своим событием обновления (TRGO).
- прерывание от завершения передач DMA (по флагу TC), которое устанавливает флаг готовности буфера, переключает буферы и перегружает DMA канал.

В принципе, вся кухня работает. Но.
После рестарта может случиться, что данные оказываются смещенными в буфере: например, на месте канала 11 будут данные из канала 12, на месте 12 - из 13, ну а на месте 13 - из 11. Может случиться и сдвиг более дальнего порядка - в 11 - из 13, ну и так далее, по кругу. Причем этот сдвиг случается один раз при старте системы, а в процессе работы все остается фиксированно, без перескоков.

Я тщательно проанализировал последовательность инициализации и попытался в прерывании DMA сбрасывать бит STRT в ADC3->SR и "прочищать" ADC3->DR (чтением) перед тем как перегрузить DMA. Тем не менее в прерывании я мог всегда(!) поймать ситуацию при самом _первом_ вхождении, когда после перегрузки DMA его счетчик тут же уменьшался на единицу, словно ADC3 припрятал запрос к DMA несмотря на "прочистку".
Последнее, что я сделал, - поднял приоритет DMA до "kill 'em all", а в прерывании - выключал бит DMA в ADC3->CR2, делал прочистку ADC и перегрузку DMA и включал ADC3->CR2 снова. На моей плате это вроде привело к успеху (счетчик DMA не уменьшался сразу), а вот у коллеги - нет.

Идеи?
Заранее благодарен.

Сообщение отредактировал KnightIgor - Jul 21 2014, 12:44
Go to the top of the page
 
+Quote Post
 
Start new topic
Ответов
Сергей Борщ
сообщение Jul 21 2014, 18:47
Сообщение #2


Гуру
******

Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095



Ой, сложно как все...

Буферов два? Расположите их подряд. Пусть ПДП таскает в них данные в циклическом режиме. Без взяких перенастроек. "Пустил-забыл". ПДП дает два прерывания - "половину буфера заполнил" и "весь буфер запомнил". По первому флагу обрабатываем первый буфер, по второму - второй. В обработчике проверяем флаги ПДП, сбрасываем сработавший, запускаем обработку соответствующей половины "склеенного" буфера. Все. Больше ничего не трогаем.

Ваш ADC_ClearRegular() делает совсем не то, что вы хотели. Он может вычитать результат максимум только одного преобразования. А может и вообще ни одного не вычитать. Потому что DR хранит результат одного (последнего) преобразования, никакого буфера типа FIFO на несколько результатов там нет. Если бы мне понадобилась подобная функция, я бы в ней выбросил параметр cnt, проверял STRT и если он выставлен (преобразование началось) - дожидался EOC, после чего сбрасывал бы EOC чтением DR, а STRT - записью в него 0.



--------------------
На любой вопрос даю любой ответ
"Write code that is guaranteed to work, not code that doesn’t seem to break" (C++ FAQ)
Go to the top of the page
 
+Quote Post
KnightIgor
сообщение Jul 21 2014, 20:29
Сообщение #3


Знающий
****

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



Цитата(Сергей Борщ @ Jul 21 2014, 20:47) *
Ой, сложно как все...

Буферов два? Расположите их подряд. Пусть ПДП таскает в них данные в циклическом режиме. Без взяких перенастроек. "Пустил-забыл". ПДП дает два прерывания - "половину буфера заполнил" и "весь буфер запомнил". По первому флагу обрабатываем первый буфер, по второму - второй. В обработчике проверяем флаги ПДП, сбрасываем сработавший, запускаем обработку соответствующей половины "склеенного" буфера. Все. Больше ничего не трогаем.

Ваш ADC_ClearRegular() делает совсем не то, что вы хотели. Он может вычитать результат максимум только одного преобразования. А может и вообще ни одного не вычитать. Потому что DR хранит результат одного (последнего) преобразования, никакого буфера типа FIFO на несколько результатов там нет. Если бы мне понадобилась подобная функция, я бы в ней выбросил параметр cnt, проверял STRT и если он выставлен (преобразование началось) - дожидался EOC, после чего сбрасывал бы EOC чтением DR, а STRT - записью в него 0.

Хорошие идеи. Спасибо. И все же интересно, почему происходит сдвиг данных.

P.S.
Итак, я реализовал Вашу идею, все замечательно. Еще раз спасибо. И кажется, я обнаружил-таки, в чем была причина "лишних" неполных данных.
В доке написано, что повторное разрешение ADC (то есть, запись "1" на уже "1" в CR2.ADON) приводит к запуску преобразования:

Conversion starts when this bit holds a value of 1 and a 1 is written to it.

Тут же далее курсивом упомянуто, что если в этом регистре одновременно меняются и другие биты (например CR2.DMA), то запуск преобразования не происходит:

If any other bit in this register apart from ADON is changed at the same time, then
conversion is not triggered. This is to prevent triggering an erroneous conversion.

Так вот, враки это все! Этот "предохранитель" не работает, и преобразование запускается. Четко в отладчике видно. Тема для errata. Вот и получалось, что команда ADC_DMACmd(ADCx, DISABLE) запрещала передачу запросов в DMA, но запускала каждый раз преобразование. Оттуда и "лишние" данные и сдвиги.

Сообщение отредактировал KnightIgor - Jul 22 2014, 08:35
Go to the top of the page
 
+Quote Post



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

 


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


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