STM32F103C8T6 — первые шаги. Начинаем делать осциллограф

О радостях и трудностях первого знакомства с STM32 после AVR. Как я реализовывал простейшую задачу — передачу данных на ПК.
5f1bdb09e04b4acb8f0b8a06df379738.JPG
Имея некий опыт работы с AVR, хочется сравнить приехавшие контроллеры (которые по отдельности стоят 1.7$/шт) с близкими к ним по цене ATMEGA328 (1.4 $/шт).

ATMEGA328 STM32F103C8T6 Выигрыш, раз
Flash, кБ 32 64 2
ОЗУ, кБ 2 20 10
Максимальная частота, МГц 20 72 3.6
Скорость АЦП, kSPS 15 2*1000 (можно разогнать) 133


На фоне роста показателей производительности в 10-100 раз, Flash увеличилась всего в 2 раза. Причём, эти 64 кБ расходуются чуть ли не быстрей, чем 32 на AVR. Логично применять такие контроллеры там, где нужна высокая производительность, но нет кодоёмких алгоритмов… например, осциллограф.

Чем программировать


Сред программирования STM32 великое множество — IAR, Keil, Coocox… поначалу кажется, что это хорошо и точно найдёшь что-то подходящее. Потом приходит понимание как такой зоопарк образовался. Просто кто-то сделал не очень хорошую IDE. Остальные на это посмотрели и решили, что они могут сделать лучше. И сделали. В чём-то получилось лучше, в чём-то хуже. Почитав обзоры и попробовав IAR, остановился на Coocox.

Есть ещё одна программа — STM32CubeMX. Дело в том, что периферии в STM32 гораздо больше, чем в AVR. Инициализировать её гораздо сложнее. STM32CubeMX позволяет выбрать контроллер, потыкать мышкой и сгенерировать код инициализации. Даже если мы не хотим использовать этот сгенерированный код, в STM32CubeMX удобно посмотреть распиновку и схему тактирования, подобрать делители, множители и вручную их прописать в своём коде! Очень рекомендую всем начинающим!

STMStudio — программа позволяющая в реальном времени наблюдать значения переменных в МК.

В качестве программатора решил использовать дешёвый ST-Link V2 за 2.6$.
Подключается всё очень просто. Берём распиновку JTAG,
a5f9089dc1804f7ba79a8dd0fb17a8c4.jpg

смотрим рисунок на ST-Link,
70f1e91f547944d89b761d15eb977082.JPG

и соединяем одноимённые выводы. Запускаем CoIDE, пишем

Blink
#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 варианта:

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


Оба эти варианта реализовать не удалось.
Первый потому, что я не смог запустить USB. Вернее смог только сгенерировав проект в STM32CubeMX. Но после экспорта его в CoIDE потребовалось перемычками менять загрузчик для программирования/работы, что не удобно. Поэтому от этого варианта отказался. Ну и вдобавок скорость USB всего 12 МБит/с. Данные на высокой скорости в реальном времени всё равно не влезут. Чтобы хоть как-то передавать данные на комп, подключил преобразователь USB UART
69978e86b4084852813ab740c01b73a5.JPG
купленный в своё время для программирования Arduino Pro Mini.

Второй вариант накрылся т.к. обработчик прерывания работает дольше, чем АЦП. Скорость ограничилась всего 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 строк:
 void setup() {
  pinMode(2, OUTPUT);  
  long d = 10;
  for(;;){
    PORTD = 255;
    delayMicroseconds(d);
    PORTD = 0;  
    delayMicroseconds(d);
  }
}

void loop() {
  
}



Подключить USB + 1 проводок (чтобы 3.3 вольтный STM32 не умер от 5 вольтного сигнала, сигнал подан через резистор в 2 кОм) и готово!

Получилось следующее (под каждым изображением фотография этого же сигнала на экране аналогового осциллографа):
20aa2637bd004af795612b816daff450.png
5c765030d3f84f47bf296b1d5884fb16.JPG
Период сигнала 0.9 мкс. 1 замер = 10 пикселей. На осциллографе 1 деление = 0.5мкс.

cf1142f854b7475c86103aee9e2080f1.png
ebd9326e95f94941a67fdb61ec94353b.JPG
Период сигнала 10 мкс. 1 замер = 5 пикселей. На осциллографе 1 деление = 2мкс. Верхушки обрублены из-за превышения сигналом опорного напряжения АЦП.

Что дальше


В планах:

  1. Победить USB, чтобы отказаться от преобразователя USB <-> USART;
  2. Доделать аналоговую часть, чтобы диапазон входных напряжений был не 0 — 3.3 В, а более приличным;
  3. Сделать многоканальный режим;
  4. Реализовать управление с ПК;
  5. Сделать законченное устройство в корпусе.

В заключение обращаю внимание на два вскрывшихся недостатка STM32 по сравнению с AVR:

  1. Повышенный расход Flash памяти;
  2. Сложная инициализация периферии, которая усугубляется нехваткой материалов.


На случай, если кому понадобится: проект CoIDE и рисовалка графика на C#. Код везде сырой. Не знаю как, но на такую простую задачу, ушло 31 кБ Flash.

© Geektimes