А описание некоторых ключевых особенностей под катом.
Аналоговая часть
Почти всё как было описано во второй части, кроме источника двухполярного питания. ОУ потребляют значительный ток (порядка 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.
Комментарии (18)
uterr
12.07.2016 15:56Привет! Расскажите, сколько отсчетов в секунду удается получить на таком МК? Есть ли разница, если использовать 1 канал или 4? Можете ли рассказать, какая разница по сравнению с другими МК, если сравнивали?
xedas
12.07.2016 16:50+1В первой части про скорость писал. Вкратце: без разгона получается 2 MSPS, с разгоном 9 MSPS.
Имеющиеся выборки делятся на все каналы. Это в режиме осциллографа.
В режиме логического анализатора ничего не делится — там читается порт целиком и скорость выборок каждого канала не зависит от количества каналов.
Если сравнивать с AVR (ATmega, ATtiny), то этот выигрывает на 2 порядка у них.
У доступного на ebay STM8S103F3P6 АЦП тоже быстрый, сколько не помню.
Если смотреть на STM, то у STM32F303, насколько я понял, можно 20 MSPS без разгона получить, вот только он сильно дороже, а отладочные платы с ним порядка $25 стоят.
GarryC
12.07.2016 17:13По поводу размера маленькая подсказка — не знаю, как у Вашего компилятора, но в IAR есть специальное поле настройки, где можно указать вид форматера print и scanf, если поставить там и там tiny, Вы будете приятно удивлены результатами. Ведь маловероятно, чтобы Вам требовались форматы с плавающей точкой двойной точности. Наверняка у Вашего компиляторы должны быть аналогичные опции.
jaiprakash
13.07.2016 14:36Автору — респект, однако, появилось несколько вопросов.
1) Не нашёл полной схемы, но по косвенным признакам понял что для ОУ выбрано питание +-10 В, а не +-5 В (как в USBee AX, например). Это так? И почему?
2) Где вы покупаете LT1054 по $0.8? Это в розницу и без учёта доставки?
Просто обычно в «народных» проектах — MC34063, доступный и недорогой.
xedas
13.07.2016 15:591. Питание ОУ +10 и -8.4 В получается. Динамические характеристики ОУ при таком питании лучше, чем при +-5В. Сейчас легко менять напряжение питание ОУ крутя винт переменного резистора.
2. Искал так. Сейчас цены от $1.05. Для MC34063 сложнее обвязка, а у LT1054 3 конденсатора — и инвертор готов.jaiprakash
13.07.2016 16:15Спасибо.
2) Ну для 5 штук — да)
Ещё вопрос — как вы фильтруете напряжение после импульсных преобразователей? (схемы всё-таки не хватает в статье)
Непонятно — эти шумы связаны с плохим питанием или с разогнанным АЦП.xedas
13.07.2016 17:08Про шумы от импульсных преобразователей не подумал, понадеялся на конденсатор 10 мкФ на питании.
Шумы действительно проходят. Вот с включённым преобразователем:
вот тоже самое с выключенным:
В обоих случаях АЦП не разогнан, период сигнал 1 мс.
Надо будет в дальнейшем подумать над фильтрами + чтобы наводок поменьше было.
Про схему: эти скриншоты делал без аналоговой части, сигналы подавал прям на ноги МК, но даже в этом случае работающие рядом преобразователи добавляют шум.jaiprakash
13.07.2016 17:14Обычно в таких схемах помимо конденсаторов ставят индуктивности, пропуская питание через них.
asakasinsky
14.07.2016 07:02xedas, здравствуйте! Можете для завершения всей картины выложить схему?
xedas
14.07.2016 08:05Рисовать там особо нечего, напишу лучше инструкцию по сборке.
- Смотрим схему отладочной платы, видим резистор R10, ищем его на плате и выпаиваем/выламываем. Вместо него подпаиваем резистор на 1.5k (по стандарту USB) к ноге B9 (случайно выбрал и прописал её в коде). Получается резистор между A12 и B9.
- ST-Link подключаем к верхней гребёнке из 4-х штырьков согласно надписям на ST-Link и гребёнке.
- Вход осциллографа и анализатора будет на ногах A0, A1, A2, A3.
- Прошиваем МК.
- Подключаем отладочную плату через её micro-usb разъём к компу. Если не появился виртуальный com-порт, отключаем, устанавливаем драйверы, и снова подключаем. Должен появиться порт. Откуда брал драйверы, не помню. Возможно по ссылке из этой статьи, но эти ссылки сейчас не работают
- Открываем проект для Visual Studio из архива, прописываем свой номер порта, запускаем и должно заработать!
В итоге получаем рабочую систему, но с ограничениями на входной сигнал 0..3.3 В. Если нужен диапазон шире, то во второй части есть пример аналоговой части. Чтобы управлять ей с ПК, открываем файл com.c и в функцию comIn дописываем обработчики своих команд. Ну и в программе для ПК добавляем элементы управления и прописываем к ним отправку этих команд, можно по образцу тех «делитель z», «усилитель x», что справа.
Flaksirus
Архив с проектом? Серьезно? Почему не гит репозиторий? Так же гораздо удобнее для всех!
xedas
По старинке. Всё никак не заставлю себя научиться пользоваться Git.
Flaksirus
Не надо пытаться, пользуйтесь — это намного проще и практичнее чем масса архивов.
Для личных проектов можно битбакет пользовать, для публичных — гитхаб.
Все в облаке, никуда не денется, еще и историю всегда можно глянуть.
Foolleren
если в очередной раз роском-что-то-там, о себе не напомнит, или какой другой «сщит хепенс».
Flaksirus
во первых, всегда можно это дело обойти и клонировать репозиторий куда либо еще
во вторых, можете завести свой собственный гит, например гитлаб, но это уже посложнее чем гитхаб и битбакет