Слева направо:
Arduino UNO (ATmega328P);
Наша плата, которую будем мучить (STM32F103C8T6):
Ещё одна отладочная плата на STM32F103C8T6;
Arduino Nano (ATmega328P).
Чем программировать
Сред программирования STM32 великое множество — IAR, Keil, Coocox… поначалу кажется, что это хорошо и точно найдёшь что-то подходящее. Потом приходит понимание как такой зоопарк образовался. Просто кто-то сделал не очень хорошую IDE. Остальные на это посмотрели и решили, что они могут сделать лучше. И сделали. В чём-то получилось лучше, в чём-то хуже. Почитав обзоры и попробовав IAR, остановился на Coocox.
Есть ещё одна программа — STM32CubeMX. Дело в том, что периферии в STM32 гораздо больше, чем в AVR. Инициализировать её гораздо сложнее. STM32CubeMX позволяет выбрать контроллер, потыкать мышкой и сгенерировать код инициализации. Даже если мы не хотим использовать этот сгенерированный код, в STM32CubeMX удобно посмотреть распиновку и схему тактирования, подобрать делители, множители и вручную их прописать в своём коде! Очень рекомендую всем начинающим!
STMStudio — программа позволяющая в реальном времени наблюдать значения переменных в МК.
В качестве программатора будем использовать дешёвый ST-Link V2.

Подключается всё очень просто. Берём распиновку JTAG,

смотрим рисунок на ST-Link,
и соединяем выводы (ST-LINK -> JTAG):
GND -> Pin 20;
3.3V -> Pin 1;
RST -> Pin 15;
SWCLC -> Pin 9;
SWDIO -> Pin 7.
Запускаем CoIDE, пишем:
- Код: выделить все
#include "stm32f10x.h"
int main(void)
{
RCC->APB2ENR |= RCC_APB2Periph_GPIOC; // включаем тактирование порта
GPIOC->CRH |= (0x3 << 20); // ставим частоту 50 МГц
GPIOC->CRH &= (~(0xC << 20)); // переводим ногу в режим выхода тяни-толкай
volatile long i = 0;
while(1)
{
GPIOC->BSRR = GPIO_BSRR_BR13;
for(i = 0; i < 1000*1000*5; i++){;};
GPIOC->BSRR = GPIO_BSRR_BS13;
for(i = 0; i < 1000*1000*5; i++){;};
}
}
Не сильно сложней, чем в AVR, однако, занимает программа 2264 байта во Flash… Это при том, что на AVR весь код металлоискателя занимал меньше.
Ради интереса удалил весь код и скомпилировал пустую программу — 2176 байт.
Отключил STDLIB — 1476 байт.
компилируем, прошиваем… и всё сразу заработало! Безо всяких танцев с бубном! Даже внутрисхемный отладчик заработал! Запускаем STMStudio — и она работает. Строит графики переменных во время работы МК! На плате есть перемычки, но ничего переключать, чтобы запрограммировать/запустить МК не надо! Прям как с Arduino! Ну не может же быть всё так хорошо… да не может.
Начинаем делать осциллограф
В моих мечтах осциллограф должен был работать следующим образом:
Оба АЦП одновременно обрабатывают сигнал со скоростью 1-2 MSPS. Далее 2 варианта:
Всё это в реальном времени передаётся на ПК по USB и там принимается решение о том, что с этим делать (запомнить, построить график, как-то обработать, ...);
После каждого преобразования происходит прерывание. В обработчике прерываний мы принимаем решение: ждать ещё или начать запоминать данные (например, хотим чтобы сигнал на экране начинался с некого уровня, как в аналоговом осциллографе, или чуть раньше этого уровня). В этом же обработчике складируем данные в буфер и по его заполнению отправляем на ПК.
Оба эти варианта реализовать не удалось.
Первый потому, что я не смог запустить USB. Вернее смог только сгенерировав проект в STM32CubeMX. Но после экспорта его в CoIDE потребовалось перемычками менять загрузчик для программирования/работы, что не удобно. Поэтому от этого варианта отказался. Ну и вдобавок скорость USB всего 12 МБит/с. Данные на высокой скорости в реальном времени всё равно не влезут. Чтобы хоть как-то передавать данные на комп, подключим преобразователь USB <-> UART
Второй вариант накрылся т.к. обработчик прерывания работает дольше, чем АЦП. Скорость ограничилась всего 340-500 kSPS, что в разы меньше ожидаемой.
Единственным рабочим высокоскоростным вариантом оказался такой: АЦП непрерывно работают, когда нам нужен замер, включаем DMA, ждём наполнения буфера, отключаем DMA и потихоньку передаём данные на ПК через USART. Этот вариант превзошёл все ожидания. МК можно разогнать так, что получается 9 MSPS с двух АЦП! Т.е. в 4.5 раза больше, чем по документации! При этом достаточно комфортно наблюдать сигнал частотой до 1 МГц. По сравнению с тем, что удалось достичь раньше на Arduino (10 kSPS) результат очень хороший — скорость увеличил в 900 раз!
Однако, с разгоном не всё так радостно. В дальнейшем, чтобы мог работать USB, частоту придётся снизить в 16/9 = 1.8 раз и тогда получится всего 5 MSPS.
Пока пытался разобраться с USB и прочей периферией осознал существенный недостаток этих контроллеров — очень мало информации в интернете. Если на AVR есть куча всего, то тут найти пример одновременной работы двух АЦП в режиме Fast interleaved оказалось не так просто.
В качестве генератора сигналов для теста осциллографа был выбран… Arduino UNO! Не потому что он хороший или ещё что… просто это очень быстро.
Написать 8 строк:
Подключить USB + 1 проводок (чтобы 3.3 вольтный STM32 не умер от 5 вольтного сигнала, сигнал подан через резистор в 2 кОм) и готово!
Получилось следующее (под каждым изображением фотография этого же сигнала на экране аналогового осциллографа):

Период сигнала 0.9 мкс. 1 замер = 10 пикселей. На осциллографе 1 деление = 0.5мкс.
Что дальше
В планах:
Победить USB, чтобы отказаться от преобразователя USB <-> USART;
Доделать аналоговую часть, чтобы диапазон входных напряжений был не 0 — 3.3 В, а более приличным;
Сделать многоканальный режим;
Реализовать управление с ПК;
Сделать законченное устройство в корпусе.
В заключение обращаю внимание на два вскрывшихся недостатка STM32 по сравнению с AVR:
Повышенный расход Flash памяти;
Сложная инициализация периферии, которая усугубляется нехваткой материалов.
Не знаю как, но на такую простую задачу, ушло 31 кБ Flash.