Самые обсуждаемые темы (topbloger) wrote,
Самые обсуждаемые темы
topbloger

Categories:

Code profiling Чтобы отвлечься от грустных мыслей по поводу САР натяжения



Чтобы отвлечься от грустных мыслей по поводу САР натяжения магнитной ленты, решил переключиться на что-то другое. Давно ждал своего часа измеритель уровня, про который я тут уже писал. Решил продолжить над ним работу. А там применен STM32, что делает программирование намного более сложным, чем в случае применения AVR. Приходится читать тонны документации. С АЦП STM32 я уже когда-то разбирался, например, в проекте лабораторного источника питания PSL-3604. Но из-за крайней запутанности вопроса ничего в памяти не осталось. По документации понять получается не всё, приходится искать в Интернете похожие примеры. За неделю удалось как-то настроить АЦП, который с частотой 96 кГц складывает отсчеты в два массива – для левого и правого каналов. Хотя пока не совсем уверен, что все работает правильно. Придумывание методик проверки часто оказывается более сложным, чем основная задача.



Пока процессорную плату измерителя уровня не собирал, потому что не знаю, какой процессор туда ставить. STM32F100 с тактовой частотой 24 МГц может не справиться, тогда придется ставить STM32F103 с тактовой 72 МГц. Но ясно это станет только после появления хотя бы чернового варианта прошивки. Временно использую STM32F100 на плате Discovery.

Соответственно, аналоговой части пока тоже нет, временно подключил к входам АЦП подстроечные резисторы, которыми задал половину питания. Одновременно через разделительную емкость подсуммировал сигнал звукового генератора.



Пока решил работать с частотой дискретизации 96 кГц, чтобы обойтись вообще без anti-alias фильтра. Его роль будет выполнять сам тракт магнитофона. Если буду не успевать с обработкой, можно будет частоту дискретизации снизить. Ничего страшного не произойдет, если появятся алиасы. В теории они будут искажать пиковые значения, но их уровень не такой большой, чтобы искажения стали существенными.

Индикатор предназначен для стереофонического аппарата, значит он должен содержать два одинаковых канала. Входной сигнал надо оцифровать и поместить в отдельный массив для каждого входа. Периферия STM32 способна это сделать без участия процессора благодаря наличию DMA. Но запрограммировать все это дело крайне сложно.

АЦП STM32 имеет множество режимов работы, по названиям которых ничего невозможно сказать о логике. Например, есть «регулярные» и «инжектированные» каналы. Для тех, кто работал с обычными АЦП, эти слова не несут никакой информации. Это специфика именно STM32. Смысл в том, что тут можно формировать группы каналов, когда логический автомат будет по очереди делать преобразования в нескольких каналах и сохранять результат. Отличие «регулярных» и «инжектированных» каналов состоит в том, что в первом случае результаты валятся в одну кучу, в один регистр, а во втором случае – в отдельные регистры. Зато их количество ограничено, их всего 4. Мне надо 2, поэтому данное ограничение несущественно. Используем «инжектированные» каналы.

Настроить группу инжектированных каналов – тот еще квест. Есть регистр JSQR, где двумя битами кодируется количество каналов в группе (у меня два), а еще 4 группы по 5 битов кодируют номера входов АЦП, задействованных в группе. Причем если у меня задействованы 2 канала, то надо их указывать не в группах JSQ1и JSQ2, а в группах JSQ3 и JSQ4. Как будто работают каналы 3 и 4 группы. Но, тем не менее, данные надо брать с регистров JDR1 и JDR2, а не JDR3 и JDR4. Точно так же для смещения кода АЦП надо использовать регистры JOFR1 и JOFR2, а не JOFR3 и JOFR4. Это можно узнать только путем перебора вариантов в программе, по документации ничего не понятно.

Запуск преобразования мне надо делать строго с частотой дискретизации, тут придется использовать таймер. Использую TIM2 и его событие TRGO. Само событие тоже надо настроить, когда оно будет возникать. Я настроил TRGO по событию Update. Точно такой же эффект будет и при использования события сравнения, если в регистр сравнения загрузить ноль. Зачем вся эта карусель – не знаю. Вероятно, разработчики STM32 просто издеваются над людьми, которые чуть ниже их по умственному развитию.

Чтобы преобразования велись циклически, включил SCAN mode. Заглянул в свой старый код источника питания, там в подобной ситуации устанавливал еще бит JAUTO. Но в документации читаю: «auto injected group In this mode, external trigger on injected channels must be disabled». Попробовал на практике – что устанавливал JAUTO, что нет – никакой разницы. Зачем я его тогда устанавливал? Должна ведь была быть причина, может это еще аукнется.

Частота дискретизации выбрана 96 кГц, т.е. период равен 10.4 мкс. За это время АЦП должен успеть сделать 2 преобразования. Чем медленней работает АЦП, тем будет точнее. Тут надо оговориться, что замедление допустимо только в разумных пределах. В современных АЦП вместо резистивных матриц и метода баланса токов используется массив конденсаторов и баланс зарядов. Поэтому при слишком маленькой тактовой частоте АЦП разрядка конденсаторов из-за утечки за время цикла преобразования может стать заметной, что ухудшит точность. Но в данном случае требуется довольно быстрая работа, нам это не грозит.

Время, затрачиваемое АЦП, состоит из двух этапов: выборки сигнала и процесса преобразования. Процесс преобразования менее критичен, тут можно лишь немножко «отступить» от максимальной тактовой частоты, обычно это вызывает снижение шума. Процесс преобразования длится 12.5 тактов. В данном случае вместо максимальной частоты APB2 / 2 = 12 МГц выбираю APB2 / 4 = 6 МГц, так как время позволяет: преобразование займет чуть больше 2 мкс. Остальное время можно потратить на выборку.

Значение времени выборки является довольно критичным, оно накладывает ограничения на допустимое выходное сопротивление источника сигнала для АЦП и что неожиданно, на значение допустимой емкости на входе АЦП. Это долгий разговор, у меня на эту тему есть отдельная статья. Оставшееся время желательно потратить на выборку, благо в STM32 есть возможность менять ее длительность. Оказалось возможным использовать длительность выборки 13.5 тактов. В итоге полное преобразование будет длиться 13.5 + 12.5 = 26 тактов.

В документации сказано: «When using triggered injection, one must ensure that the interval between trigger events is longer than the injection sequence». Хорошенькое дельце, интервал запусков должен быть больше длины последовательности, но насколько – не сказано. Хорошо, что ниже приведен пример для двух каналов последовательности, где время указано больше на один такт АЦП. Что будет с другим количеством каналов – неизвестно. Но у меня их два, поэтому минимальный интервал запусков будет (26 + 26 + 1) * 1/6 [МГц] = 8.83 мкс. В наш период дискретизации 10.4 мкс вписываемся, причем особо без лишнего простоя АЦП.

По концу преобразования АЦП может запускаться цикл DMA, который будет перекладывать данные из регистра в память. С АЦП связан всего один канал DMA, поэтому данные можно забирать с одного регистра и складывать в один массив. Если работает несколько каналов, в этом массиве данные будут перемешаны, что для меня крайне неудобно.

Чтобы брать данные с двух регистров «инжектированных» каналов и сохранять их в разных массивах, потребуются два канала DMA. Но они не могут запускаться событием конца преобразования АЦП, что логично – невозможно понять, в каком именно канале закончилось преобразование. Но раз у нас запуск преобразования производится таймером, то по этому же таймеру, вероятно, можно запускать и DMA. Ведь АЦП – это логический автомат, время преобразования для него известно и постоянно. Осталось назначить два канала DMA и определить для них моменты времени, когда данные АЦП точно будут готовы.

Как именно идет преобразование в «инжектированной» группе каналов АЦП – неизвестно. Временной диаграммы работы АЦП в документации нет. Я просмотрел не только RM0041 Reference Manual, но и дополнительные документы, посвященные АЦП STM32, но никакой конкретики по этому вопросу там тоже нет. Учитывая чехарду с номерами инжектированных каналов, лучше убедиться на практике, как происходит преобразование группы. Заодно проверить, вписывается ли последовательность в период дискретизации. Тут вспомнил одну занятную статейку про профилирование кода с помощью ЦАП. Решил так и сделать. В коротком цикле делаю поллинг таймера, в ЦАП вывожу импульс синхронизации для осциллографа в момент запуска преобразования группы. Потом в цикле вывожу в ЦАП выходной код АЦП. На вход АЦП подан синусоидальный сигнал. Меняя этот сигнал, сразу видно изменения сигнала ЦАП, можно четко определить, для какого именно канала видим данные. Можно было посмотреть сигнал конца преобразования, но к какому каналу он относиться – понять невозможно. В результате на осциллографе увидел момент обновления выходного регистра АЦП для первого и второго канала.





К сожалению, скорость ЦАП слишком низкая, чтобы наблюдать столь быстрые процессы. Сигнал затянут, но все понять можно. Зато какая красивая аналоговая картинка! Период дискретизации 10.4 мкс, это чуть больше 10 клеток на экране. Видно, что первый канал заканчивает преобразование чуть раньше середины экрана, а второй – чуть раньше конца экрана. Т.е. канал DMA для первого канала можно запускать в середине периода дискретизации, для второго – в конце.

DMA использую в циклическом режиме, каждый канал работает со своим массивом в памяти. В результате в каждом из массивов обновляются данные для своего канала. Остается вовремя их оттуда забирать для дальнейшей обработки. Пока планирую делать это без прерываний. По флагу заполнения половины буфера буду обрабатывать первую часть данных, по флагу заполнения всего буфера – вторую.

В документации рекомендуют после каждого включения питания делать калибровку АЦП. Тут тоже есть туманные моменты, на которые уже просто не хватило сил. Скопировал со старого проекта, ведь когда-то в этом уже разбирался. Зачем-то там сначала идет сброс калибровки, а затем – сама калибровка.

Вывел код переменного напряжения с АЦП в ЦАП – вроде, работает, сигнал передается от входа на выход. Постоянное напряжение тоже оцифровывает, на первый взгляд, верно. Можно считать, что АЦП работает. Хотя какая-то тревога осталась, в этом чертовом STM32 все приходится делать методом подбора, не уверен, что сделал правильно. Надеюсь, время покажет.

Следующий этап – обработка полученного с АЦП сигнала. Первым делом надо реализовать DC remover. Сейчас у нас температура +30°, надеюсь, это ускорит химические реакции, коими является и мыслительный процесс. Потом пойдут другие цифровые фильтры. Что-то слышал про DSP-библиотеки для STM32, но пока не удалось скачать никаких исходников на эту тему.



источник - leoniv 
[1 ссылок 56 комментариев 2000 посещений]
читать полный текст со всеми комментариями
Tags: leoniv
Subscribe
promo topbloger novembre 1, 2020 19:44 233
Buy for 50 tokens
Привет! В моем блоге автоматически топботом собираются все самые интересные темы блогосферы. Более полно посмотреть все интересные посты блогосферы вы можете на сайте t30p.ru. Узнать какие из ваших постов попадали в ТОП 30 можно на сайте topbloger.ru. Подписаться на чтение самых…
  • Post a new comment

    Error

    Anonymous comments are disabled in this journal

    default userpic

    Your reply will be screened

    Your IP address will be recorded 

  • 0 comments