Некоторое время назад автор этих строк взялся разрабатывать компактный регистратор одно-полярного аналогового сигнала в пределах 3 вольт с максимально возможной скоростью считывания и минимально возможными затратами и размерами. В список минимально возможных затрат я вписал также и свою головную боль и выбрал хорошо знакомый мне STM32F303. Это, напомню, Cortex-M4 на 72 мегагерца от известной компании, со встроенными 12 разрядными, довольно шустрыми, аналого-цифровыми преобразователями (АЦП или ADC, кому как нравится) и с CAN интерфейсом на борту.


Таких небольших регистраторов требовалось несколько десятков. А наличие у микроконтроллера корпуса о 48-ми ногах вселяло надежду на то, что получится назвать этот считыватель компактным. Интерфейс CAN, с которым у меня уже тогда были хорошие отношения, давал мне возможность объединить весь этот джаз в достаточно удобной манере.


Скорость, с которой, в конце концов, все это заработало, оказалась вполне подходящей, чтобы заявить о работоспособности выбранного подхода. Удалось добиться пол микросекундного шага дискретизации. Головной боли и ассемблера избежать не удалось, но кто об этом сейчас вспоминает?


Однако, некоторый осадок остался. Осталась мысль, что, в отношении быстродействия, выжато было не все.


И вот, совсем недавно появляется серия STM32G4 с тактовой частотой до 170 мегагерц с вариантом в маленьком корпусе, и с почти такими же шустрыми АЦП на борту в количестве пяти штук. Надо было что-то делать.


Над душой теперь никто не стоял и можно было не беспокоиться о сроках и планах.


Действительно, если об этом не думать, то можно получить удовольствие даже от работы. Но, честно говоря, о времени думать пришлось. Думать долго о времени малом (а что, поэтично).


Напрашивалась мысль, что надо начать немного с другого конца. То есть, надо исходить из минимально возможного времени выборки АЦП, которое, если исходить из описания, занимает 2.5 такта и составляет на 40 МГц (160 МГц / 4) 62.5 наносекунды. Тогда сам собой напрашивается шаг дискретизации в 100 наносекунд. Число круглое и, главное, довольно маленькое и красивое, почему бы и не попробовать?


К тому же, появилась в продаже и была куплена подходящая для экспериментов плата NUCLEO-G474RE, к которой разумно было добавить дополнительную макетную плату с двумя двухрядными разъемами, чтобы припаивать всякие провода и детали к макетной плате и не портить основную. Вот как это выглядит в готовом виде.



Там, снизу, есть несколько проводков и резистор с конденсатором, уж поверьте мне на слово.


Теперь надо подать подходящий электрический сигнал сразу на все четыре АЦП, затем запускать их друг за другом с постоянным шагом (сначала, при отладке, не очень коротким). Почему четыре? В соответствии с описанием, на одно преобразование каждый АЦП тратит 15 тактов или 0.025*15=375 наносекунд (почти 400). Поэтому при шаге 100 потребуется конвейер из четырех АЦП.


В качестве входного сигнала использовалась RC цепь, на которую подавалось напряжение просто от ножки контроллера. Этой ножкой я назначил управлять таймер TIM5 в режиме одиночных импульсов.


Минимальная схема соединений выглядела как показано на рисунке ниже.



Были задействованы ADC1-ADC4. Разрядность можно было снизить для некоторого повышения быстродействия, но 12 разрядов перевесили, поскольку не хотелось терять в точности измерений. Для запуска каждого АЦП в нужном порядке и с требуемым шагом используются три таймера (TIM2, TIM3, TIM4) и еще один таймер (TIM1) служит для синхронизации вышеуказанных трех. На рисунке 2 ниже показаны сигналы, вокруг которых все строится.



Зеленые стрелки показывают фронты импульсов, по которым происходит запуск соответствующих преобразователей ADC1-ADC4.


Чтобы получить задуманные 100 наносекунд пришлось снизить тактовую частоту до 160 мегагерц, чтобы все там делилось нацело как следует. Сначала шаг был установлен значительно медленнее, 4 микросекунды, чтобы спокойно проверить работу таймеров, используя прерывания, выходные порты и осциллограф. Затем по прерываниям был отлажен и заработал прямой доступ к памяти. В конечном счете только одно прерывание обрабатывается — это прерывание окончания работы от четвертого (последнего) канала прямого доступа к памяти. На рисунке ниже показаны соединения участвующих в процессе аппаратных блоков, а также четыре выходных буфера памяти.



Из четырех буферов памяти (на рисунке — справа) отсчеты собираются программно в один буфер результата.


В этом контроллере, в отличие от STM32F303, есть блок коммутации запросов (DMAMUX), который позволяет перенаправлять огромное количество запросов от периферийных устройств всего на 16 каналов DMA1 и на 16 каналов DMA2. В справочном руководстве (Reference manual) выходные запросы DMAMUX отсчитываются от 0, а входы каналов DMA блоков отсчитываются от 1. Не стал менять, оставил как в первоисточнике.


В качестве генератора одиночного импульса используется таймер TIM5. В нем предусмотрен удобный режим одиночного импульса. Удобство заключается в возможности установки времени до начала импульса и установки длительности самого импульса. Этот импульс получился таким как показано ниже на картинке, любезно предоставленной осциллографом, взятым напрокат.



Из осциллограммы видно, что подъем импульса длится 10 микросекунд, значит он должен вместить порядка 100 отсчетов.


Проект делался в IAR 8.4 вручную (то есть, без Куба и Шара), но, надеюсь, будет понятен самым разным конфессиям. Его можно посмотреть здесь.


Вот картинка содержимого отдельного буфера ADC1 и собранного из четырех источников буфера результата в районе начала входного импульса.



А вот содержимое этих буферов в районе пика импульса (там, где значение доходит до 2508).



Как видим, на участок от начала импульса до его вершины потрачен 196-95=101 отсчет.


Значит частота дискретизации составляет 10 мегагерц. Заработало на такой скорости не сразу.


Для того, чтобы добиться этого пришлось останавливать процессор пред началом работы прямого доступа к памяти (DMA1). Хорошо, что у Cortex-M4 есть специальная ассемблерная инструкция WFI (Ждать прерывания). Если этого не сделать то процессор будет мешаться под ногами у DMA и занимать шину обращениями в память, которые вполне могут подождать.


Если увеличить шаг отсчетов до 200 наносекунд, то они перестанут толкаться и заживут мирно и счастливо.


Если вовлечь в работу компаратор COMP4 и соединить его положительный вход (порт PB0) с входным сигналом, а затем использовать ЦАП (DAC1) и соединить его выход (CH1) с отрицательным входом компаратора (внутри контроллера), то получим пороговое устройство с регулируемым порогом. Прерывания от срабатывания компаратора позволят запускать общий тактовый таймер TIM1 и получить ждущий режим, как в осциллографе.

Комментарии (20)


  1. GarryC
    23.09.2019 17:30

    160МГц/10Мгц=16команд/отсчет. За 16 тактов вполне можно прочитать данные «руками», или я чего то не понял?


    1. kerosinimus Автор
      23.09.2019 18:03

      То, что Вы имеете ввиду выглядит, видимо, так:
      1.Записать «Старт» в регистр АЦП.
      2.Считать готовность (окончание оцифровки).
      3.Если нет готовности, вернуться к шагу 2.
      4.Положить результат в буфер.
      5.Нарастить индекс буфера.
      6.Проверить границу.
      7.Если не конец, вернуться к шагу 1.
      8.Сигнализировать завершение.

      Между стартом (шаг 1) и готовностью (шаг 4) — 400 нс.


      1. GarryC
        23.09.2019 18:16

        Приблизительно так, но возможны варианты:
        1. АЦП в непрерывном режиме, поэтому 1 вне цикла

        5. Уменьшить индекс буфера.
        6. Если не ноль, идти к шагу 2.
        Тогда основной цикл 5 команд вместо 7 в Вашем варианте, но и Ваш должен успевать за 16 тактов.


        1. kerosinimus Автор
          23.09.2019 18:34

          Но, 400 наносекунд никуда не денутся.
          Поэтому понадобился конвейер. А там шаг 100 нс.


  1. Norsat
    23.09.2019 18:02

    А для чего в итоге вы эту систему делали?


    1. kerosinimus Автор
      23.09.2019 18:04

      Эту систему я делал для проверки своих расчетов и предположений.
      И для освоения серии STM32G4xx.


  1. oam2oam
    23.09.2019 19:02

    Очень хорошо! Я также примерно осваивал stm32h750, (в моих последних статьях можно почитать) но там штатно АЦП 16-битный, хоть и два. Что интересно, я пошел не в сторону скорости (это я еще опишу в следующих своих статьях, надеюсь ;) а в сторону точности — и был очень удивлен результатом.

    У stm32h750 есть, как у многих сейчас, режим Oversampler, что позволяет улушить аппаратно точность до 26 бит.

    Но нас ничто не остановит, и я уже программно попробовал довести до 32 бит… Ну что сказать — удалось. Теперь этой прошивкой меряю падение на дорожках — легко берет уровни порядка 1-2 мкВ!

    Единственная неприятность — читать-то данные можно на скорости до 1.6 Gbps — а вот куда такой поток отдавать или как успевать его обрабатывать?


    1. VT100
      24.09.2019 09:50

      "позволяет улушить аппаратно точность до 26 бит."
      Разрешающую способность. Точность — надо перепроверять?


      1. oam2oam
        24.09.2019 09:58

        да, вы правы — это разрешающая способность. В точности приходится полагаться на встроенный источник напряжения (конечно, я меряю при каждом измерении) — а он, вроде бы 1.024 В +- 0.001. Так что точность в области до милливольта будет 1-2 мкВ, а вот выше — увы…


        1. Alexeyslav
          24.09.2019 10:39

          Учтите что точность указана для фиксированной температуры. У ИОН есть свой ТКН и точность ухудшается с отклонением температуры от той на которой он откалиброван. Причем в широком диапазоне температур отклонения получаются ужасными и получается что в условиях отличных от комнатных это будет показометр.


          1. oam2oam
            24.09.2019 10:43

            ну я указал — до 1 мВ это вполне себе измеритель… И, конечно, для дифференциального измерения нужна как раз разрешающая способность — никто же не запрещает взять прецизионный источник напряжения и уравнять разность потенциалов — вот тут-то 32 бита и скажутся…


          1. pvvv
            24.09.2019 15:41

            Там и без температуры есть нелинейность +- 6LSB, которая от увеличения разрядности через oversampling, никуда не уйдёт.
            Ну и сам по себе АЦП имеет SNR 80дБ, эффективных разрядов в лучшем случае 13. И это один АЦП, а несколько АЦП с интерливингом для большей частоты, это не улучшит, а совсем даже наоборот.
            А так да, АЦП 16ти разрядный.


  1. ancc
    23.09.2019 19:51

    А отчего бы не попробовать H7 с 400МГц и 16-ти битными АЦП?


    1. kerosinimus Автор
      23.09.2019 19:58

      Попробовать можно, коль время появится.
      Там 3 16-и битных ADC по 3.6 МГц. Шаг 100 нс может получиться из 3 ADC.
      Но это будет несколько дороговато.


  1. sim2q
    23.09.2019 21:52
    -1

    С интересом читаю, т.к. была недавно задачка где AI конечный автомат должен был ходить по меню из… телика:) Думал даже на F0 обойтись начиная сканировать строку с разных мест и накапливая результат. Хорошо, что вроде бы пока удалось с др стороны к проблеме подойти:)


  1. siargy
    24.09.2019 08:07

    осталась нераскрытой тема куда это записать и как отобразить на экране.


    1. kerosinimus Автор
      24.09.2019 09:00

      На этой плате есть встроенный ST-Link V3,
      который имеет еще и виртуальный COM порт.
      Можно по нему передать результат на PC.


  1. clawham
    24.09.2019 11:25
    +1

    10 MSPS? серьёзно? Это Вы называете осциллографом? Я не спорю — для встроенного ацп без внешних микрух это нормально но это как из пушки по воробью — из за 10-20 MSPS пришлось взять очень жирный и мощный проц а делает он то что любая параллельная АЦП внешняя сделает за копейки на намного более слабом проце. как я понял — даже внешней памяти под буфер не использовалось — то есть 500-1000 отсчетов не более — ну вообще никаких проблем.


    1. kerosinimus Автор
      24.09.2019 15:26
      +1

      Речь изначально шла о регистраторе на шине CAN с возможностью записи
      измерений длиной 200 микросекунд и размером платы 40x40 мм.
      Он показался мне чем-то похожим на осциллограф. Как-то так.


      1. Alexeyslav
        25.09.2019 10:01

        Оу, анализ импульсов системы зажигания?