Осциллограф на стм32 – STM32F103C8T6 — делаем осциллограф. Часть 3 / Habr

STM32F103C8T6 — делаем осциллограф. Часть 3 / Habr

Третья часть (первая и вторая) про то как я делаю осциллограф из отладочной платы ценой менее $3. Демонстрационное видео работы:


А описание некоторых ключевых особенностей под катом.

Аналоговая часть


Почти всё как было описано во второй части, кроме источника двухполярного питания. ОУ потребляют значительный ток (порядка 10 мА) и как не пытался схемами умножителей напряжения на диодах и конденсаторах получить приемлемых результатов — не удалось. Поэтому для положительного напряжения поставил вот такой модуль на основе МТ3608:

настроенный на 10 В выходного напряжения. А отрицательное напряжение получаю путём инвертирования положительного с помощью LT1054.

Про размер кода


В первой части я писал, что памяти потребляется очень много. Теперь я дошёл до того, что программа не влазит в память и изучил этот вопрос подробней.

CooCox CoIDE выводит информацию о размер программы в таком виде:

      text	   data	    bss	    dec	    hex	filename
     60224	   2500	  10540	  73264	  11e30	projectName.elf

где
  • text — размер сегмента с кодом, векторами прерываний и константами только на чтение;
  • data — размер сегмента с инициализированными не нулём переменными;
  • bss — размер сегмента с неинициализированными и инициализированными нулём переменными.

Вся программа занимает:

  • флеш — text + data + 10..50 байт
  • ОЗУ — data + bss + 10..50 байт

Теперь посмотрим на что тратится память. Делаем новый проект и компилируем:

      text	   data	    bss	    dec	    hex	filename
       364	   1080	     32	   1476	    5c4	test-size.elf

Чтобы использовать макросы типа GPIO_BSRR_BS9 надо подключить файл stm32f10x.h.
Чтобы подключить файл stm32f10x.h надо в репозитоях добавить компонент STM32F10x_MD_STDLIB, который подтягивает за собой cmsis_core. В итоге для программы, записывающей одно значение в регистр получаем:
text data bss dec hex filename 1316 1104 32 2452 994 test-size.elf

Далее меня интересуют функции типа sprintf и sscanf. Чтобы их использовать надо определить некоторые функции типа _sbrk и возможно некоторых других. Я взял готовый файл (есть в архиве с проектом). Добавляем 1 вызов sscanf и получаем:
Попробуйте угадать сколько, прежде чем смотреть!
      text	   data	    bss	    dec	    hex	filename
     39312	   2264	     96	  41672	   a2c8	test-size.elf

41 кБ флеша! Больше половины, того, что есть в контроллере!
В рабочей же прошивке при использовании printf добавление sscanf увеличивает потребление флеша на 13.2 кБ. В итоге от sscanf отказался, а команды от ПК стал парсить менее ресурсоёмким методом.
Отказ же от printf позволяет сэкономить ещё 8.3 кБ.

Режимы работы


Реализовал 3 режима по принципу действия: непрерывный, пакетный и логический и 3 по количеству каналов: 1, 2 и 4-х канальный.
МК имеет 9 аналоговых входов, но я не представляю когда мне может понадобиться больше 4-х каналов.

Непрерывный


Тут всё просто: в главном цикле МК считываем данные АЦП и передаём их на ПК, где можем строить непрерывный график. Недостаток — ограничение скорости со стороны канала МК -> ПК. Чтобы его обойти реализовал ещё 2 режима.

Пакетный


В этом режиме МК вначале набирает данные, потом пачкой передаёт на ПК. Опционально его можно разгонять. Про разгон подробно писал в предыдущих частях.

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

В отличие от проекта baghear у меня триггер программный. Преимущества такого решения:

  • Меньше деталей, а значит меньше цена и проще монтаж;
  • Возможность в будущем реализовать более сложные триггеры, а не просто «сигнал в A канале стал больше Х».

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

Логический анализатор


Самый быстрый режим. Примерно 20 MSPS на каждом канале. Самый быстрый код для этого режима выглядит так:
u32 i = 0;
dataBuffer.u8[i] = GPIOA->IDR;
dataBuffer.u8[++i] = GPIOA->IDR;
dataBuffer.u8[++i] = GPIOA->IDR;
dataBuffer.u8[++i] = GPIOA->IDR;
dataBuffer.u8[++i] = GPIOA->IDR;
dataBuffer.u8[++i] = GPIOA->IDR;

и так далее на весь буфер.
Значение переменной i в этом случае вычисляются на этапе компиляции и в итоге из dataBuffer.u8[++i] = GPIOA->IDR; получается всего 2 операции — загрузить данные в регистр из порта и сохранить данные в память по заранее посчитанному адресу. Никакими циклами такой производительности достичь не получилось.

Программа для ПК


Главные, на мой взгляд, измение — переход на OpenGL. С ним графики рисовать стало проще (для меня это оказалось неожиданно, но там всё действительно просто и кратко!), рисуются они быстрее и получаются гораздо красивей, чем были раньше.

Итог


Проект не завершён, есть глюки, допиливать ещё много чего, но каких-то прорывов уже не предвидится. Для более быстрых систем нужно другое железо, например, отдельный АЦП + ПЛИС + память — а это уже будет гораздо дороже и сложнее монтировать.

Почитав комментарии к статье «История одного осциллографа на stm32» сразу отвечу на некоторые вопросы:

  • Дисплей прикручивать не собираюсь т.к.:
    • Он стоит денег, а комп есть.
    • По качеству будет хуже, чем на большом экране ПК.
    • Создавать и изменять пользовательский интерфейс на C# проще, чем паять и перепаивать.

  • Я не планирую его доводить коммерческого продукта и продавать.
  • Делал для 2-х целей: освоить МК и сделать себе цифровой осциллограф.

Архив с проектом
Если у кого появятся вопросы, а тут не зарегистрированы, пишите в почту: adefikux на gmail точка com.

habr.com

История одного осциллографа на stm32 / Habr

Чуть больше года назад, мне в голову пришла мысль о том, что хорошо бы было сделать осциллограф. Тогда мне хотелось, чтобы это было независимое устройство с собственным TFT дисплеем, да и вообще, идея разобраться с TFT дисплеями, мне казалась очень перспективной. Спустя некоторое время на али был заказан TFT размером 3.2 дюйма с драйвером

SSD1289.

На тот момент у меня уже был опыт программирования микроконтроллеров AVR, поэтому решил запустить дисплей на моём любимом Atmega16. Дойдёт ли дело до создания осциллографа тогда ещё не знал, но то что буду в своих проектах использовать TFT знал точно, поэтому не стал искать сторонние библиотеки, а решил написать свою, которой пользуюсь и по сей день.
 
После того, как получилось инициализировать дисплей, стало понятно, что на Atmega16 сделать осциллограф не получится. Уж очень медленный он для дисплея такого размера. И что-то внутри подсказывало мне, что пора переходить на STM32, но оно же и останавливало меня. В общем, процесс обдумывания был недолгим и на али была заказана плата с STM32F103VET6 на борту. Но кроме причины описанной выше, была ещё одна причина перейти на STM32 – встроенный 12 битный АЦП на 1Msps, который можно использовать для оцифровки сигнала.

 
К моему удивлению, после нескольких недель работы с STM32 стало понятно, что в них нет ничего сложного и я перестал понимать, почему не перешёл на них раньше. Перенести код, написанный для AVR, на STM32, не составило труда, но не давала покоя мысль о том, что мне необходимо, чтобы дисплей работал на максимальной скорости, а для этого надо было разобраться с FSMC. На самом деле и тут оказалось всё просто — это заняло у меня одни выходные. На этом подготовительные мероприятия с дисплеем были закончены и можно было переходить непосредственно к реализации осциллографа.
 
Первоочередной задачей было научиться выводить сигнал на дисплей, для этого накапливал необходимое количество выборок АЦП, затем выводил их на экран, заливал экран чёрным цветом и так по кругу. Кстати, уже тогда для сохранения данных в буфер использовал DMA.
 
Первый шаг был сделан и меня переполняла радость и гордость за проделанную работу. Далее, хотелось, чтобы синусоида не бежала, а стояла, для этого надо было научиться запускать преобразование АЦП по триггеру.
Сделать это можно с помощью обычного компаратора, как показано на схеме ниже.


Компаратор на ОУ.

На инвертирующий вход подаётся опорное напряжение, которое формируется с помощью ШИМ и RC цепочки. А на прямой вход подаётся сигнал, тот же что подаётся на вход АЦП.

Когда напряжение на прямом входе становится выше или ниже напряжения на инверсном входе изменяется полярность на выходе ОУ. Это изменение фиксирует вывод МК настроенный на внешнее прерывание. Изменяя активный фронт, для внешнего прерывания можно производить захват как по возрастающему, так и по спадающему фронту.

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

 
Спустя некоторое время мне на глаза попался обзор DSO 138 и из того же обзора я узнал, что его схема доступна в интернете и решил позаимствовать оттуда кусочек.


Фрагмент схемы DSO 138.

Что делает этот кусочек схемы?
Диапазон напряжений, с которыми может работать АЦП определяют уровни опорных напряжений(+VREF и -VREF), они не должны выходить за диапазон питания микроконтроллера. Нижнюю границу диапазона ограничивает 0 вольт, верхнюю — 3.3 вольта. Отсюда становится понятно что измерять отрицательные напряжения АЦП не может, а это необходимо.

Для того чтобы АЦП чувствовало отрицательные напряжения необходимо, чтобы в отсутствие сигнала на его вход подавалась половина опорного напряжения в нашем случае 1.6 вольта. В таком случаем при измерении отрицательного напряжения, например, минус 0,3 вольта, напряжение на входе АЦП уменьшится на 0,3 вольта и станет равно 1,6 — 0,3 = 1,3 вольта. Такое напряжение АЦП с лёгкостью оцифрует. Этот пример приблизителен потому, что не учитывает коэффициент усиления схемы(в данном случае мы приняли его за 1), зато нагляден.

 
Также хотелось обратить внимание, что питание ОУ двухполярное, это надо для того чтобы ОУ мог работать с отрицательным напряжением. В случае если питание ОУ однополярное(на один вывод питания подаётся 0, на второй 5 вольт)и на вход ему подать отрицательное напряжение, ОУ просто его не почувствует и сделать с ним ничего не сможет, вот так вот.

Для реализации двухполярного питания использовал две зарядки от телефона, соединив плюс одной с минусом другой, и принял потенциал этого соединения за точку отсчёта, то есть землю.
 
Схема была собрана на макетке и теперь осциллограф мог осуществлять захват по триггеру и измерять отрицательные напряжения, что делать дальше в плане железа у меня идей не было, поэтому перешёл к софту.
 
На тот момент времени у меня уже было чёткое понимание, что буфер должен быть кольцевой, а размер позаимствовал у DSO 138, то есть 4096 точек.

Для чего столько точек?
Такое количество точек, с помощью прореживания позволяет реализовать некоторые развёртки, которые нельзя реализовать аппаратно. У STM32 длительность преобразования составляет 12.5 цикла, для того чтобы найти период выборок надо к длительности преобразования прибавить значение, которое определяется битовым полем SMPx[2:0]. На данный момент у DSO 138 уменьшили размер буфера до 1024 точек, у меня же осталось 4096.
 
Так а для чего всё-таки кольцевой буфер?
Кольцевой буфер необходим для изменения соотношения количества пред и пост выборок, на быстрых развёртках. Предвыборки — выборки до срабатывания триггера, поствыборки — выборки после срабатывания триггера. Алгоритм работы следующий, после отрисовки осциллограммы:

  1. накапливаем нужное количество предвыборок;
  2. разрешаем внешние прерывания;
  3. МК начинает выполнение каких-то сторонних задач, до тех пор, пока не придёт сигнал внешнего прерывания.
 
По этому сигналу буфер дополняется поствыборками и вся осциллограмма выводится на дисплей.
Количество пред поствыборок пользователь может задавать только на быстрых развёртках, на медленных сразу после захвата точки отрисовываются на экране, минуя буфер. На самом деле конечно, буфер есть, потому что со времён стало понятно, что закрашивать после каждой отрисовки рабочую область неразумно, можно просто отрисовывать ту же осциллограмму только чёрным цветом и восстанавливать разметку, таким образом уменьшается время отрисовки одной осциллограммы и пропадает, такой неприятный эффект как мерцание.

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

Что мог прототип осциллографа на тот момент?(а что он что-то мог?)
Можно было изменять время развёртки, выбрать тип триггера, выбрать активный фронт, изменять количество пред и пост выборок, изменять уровень триггера, также изменять базовый уровень.
Что касается типа триггера, в режиме авто, всё происходит также как в режиме норм за исключением того, что если в течение 100 миллисекунд не приходит сигнал, вызывающий внешнее прерывание, то происходит прерывание по таймеру и в нём заполняется буфер.
 
Для того чтобы реализовать остальные функции пришлось снова вернуться к железу. И думаю у многих возник вопрос, почему не заюзать всю схему от DSO138?
Всё просто, хотелось чтобы положение аттенюатора переключалось электроникой, а не переключателями и, главное, чтобы при смене открытого входа на закрытый и наоборот щёлкало реле))
В общем, передо мной стояла задача, найти аналоговую часть, которая бы соответствовала моим требованиям. На самом деле это задача непростая, если бы не одно но…
В один прекрасный момент я вспомнил, что у меня есть осциллограф, а его разработчик около года назад отвечал мне на вопросы по его использованию в skype, в общем, решил ему написать.
После того как рассказал ему о своих планах сделать осциллограф он предложил мне несколько вариантов аналоговой части, я выбрал наиболее мне понятную схему, задал ему имеющиеся у меня вопросы и принялся за реализацию. Через несколько месяцев осциллограф был готов.

В итоге получилось сделать осциллограф обладающий следующими характеристиками:
Напряжение питания: 9 В
Потребляемый ток: 110 мА
Частота сэмплирования: 1 Мвыб/с
Аналоговая полоса пропускания: 0 — 200 КГц
Разрешение по вертикали: 12 бит
Максимальное входное напряжение: 50 В
Чувствительность по вертикали: 10 мВ/дел — 10 В/дел
Время горизонтальной развертки: 10 мкс/дел до 200 мс/дел
Входной импеданс: 1 МОм/20пФ
Режимы входа: DC, AC, земля
Режимы запуска — развертки: авто, нормальный, однократный

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

habr.com

USB осциллограф своими руками

Вариант недорогого, а вернее очень дешевого двухканального осциллографа на процессоре STM32F103C8T6, будет рассмотрен в этой статье. Сразу оговорюсь что это приставка к компьютеру которая подключается к USB порту ПК. Вот некоторые характеристики осциллографа на STM32:

  • Частота дискретизации (семплирование) — 461 kSps
  • Входное напряжение — 6,6 В.
  • Входное сопротивление — 20 кОм.

Как видим, осциллограф имеет нестандартное входное сопротивление, поэтому стандартные осциллографические щупы к нему не подойдут и для измерения напряжений свыше 6,6 В придется делать делитель с согласованием именно на 20 кОм. Еще небольшое пояснение по поводу частоты дискретизации. Многие ошибочно полагают что это и есть полоса пропускания. В действительности это вовсе не так. 461 kSps означает что осциллограф за одну секунду делает 461 тысячу замеров. Если подать на его вход сигнал, к примеру 1 кГц (период T=1/F; T=1 миллисекунда). За период в 1 миллисекунду осциллограф сделает 461000*0,001=461 измерение. Будем говорить что на период приходится 461 точка. Этого количества точек более чем достаточно чтобы четко отрисовать сигнал. Но если мы подадим на вход сигнал 200 кГц, период которого составляет 5 микросекунд, то уже на этот период мы получим 2,3 точку.  Из 2 точек невозможно построить сигнал и оценить его параметры. Минимально необходимое число точек на период должно быть не менее 20. Поэтому максимальная частота при которой этим осциллографом можно будет рассмотреть сигнал будет 461/20= 23,5 кГц. Для звукового диапазона вполне подойдет. И не стоит забывать что это устройство не имеет гальванической развязки!!! Будьте внимательны если будете ремонтировать импульсные блоки питания!

Схема осциллографа представлена ниже. Оригинал схемы, печатной платы и прошивку вы можете скачать в конце статьи.

Как видно, схема состоит из одного процессора и его обвязки. Здесь особо нечего пояснять. Скажу только что на плате разведен только UART интерфейс для прошивки процессора. Я все же рекомендую развести SWD интерфейс и прошивать через него с помощью программатора STLINK. Это проще и быстрее. Но можно и так как на плате с помощью UART. Я вкратце опишу и тот и другой вариант. Для прошивки через UART нам потребуется любой переходник с USB в UART, из полно в продаже и стоят они не дорого. Подключаем переходник к плате по 3-х проводной шине RX, TX, GND. Затем скачиваем и устанавливаем программу STM Flash Loader Demo. Переводим плату в режим Boot. Для этого нажимаем и удерживаем кнопку Boot при нажатии кнопки Reset. Затем заходим в программу и выполняем пошаговые действия: выбираем номер COM порта, ожидаем соединения с платой, выбираем файл прошивки, ждем окончания процесса прошивки, закрываем прогу отключаем UART, и снимаем питание с платы. Теперь вариант с SWD. Подключаем программатор по 4 проводам: POWER, SWCLK, SWDIO, GND. (При этом питание на плату поступает с программатора). Качаем и ставим программу STM32 ST-Link Utility. При запуске программы она сама определит контроллер, вам останется лишь выбрать файл прошивки и запустить процесс прошивки.

И еще одно немаловажное замечание. Перед сборкой устройства, установите программную оболочку осциллографа на STM32 на свой ПК. Убедитесь что программа в принципе запускается. Были случаи когда программа просто не хотела запускаться на некоторых ПК и ноутбуках. С чем это связано — непонятно.

СКАЧАТЬ ПРОГРАММУ MINISCOPE V4

СКАЧАТЬ ДРАЙВЕР ДЛЯ MINISCOPE

СКАЧАТЬ ПРОШИВКУ ДЛЯ MINISCOPE

СКАЧАТЬ СХЕМУ И ПЛАТУ

elschemo.ru

0 comments on “Осциллограф на стм32 – STM32F103C8T6 — делаем осциллограф. Часть 3 / Habr

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *