Наилегчайший старт в STM через «одно место» +30





Уже, наверное, прошло время религиозных войн AVR против STM, но нет-нет да наблюдаются вспышки столкновений двух лагерей. Практически у любой публикации на тему поделок на AVR обязательно будет каммент вроде «Да сколько уже можно лохматить бабушку, давно пора перейти на STM», дальше вариации на тему цены, количества ног и таймеров. Если STMщик более продвинут, обязательно будет указание, что DMA в AVR нет и не будет, по этому AVR должна умереть. Зачем простому блинку-вольтметру-градуснику DMA, гора 16 разрядных таймеров, 100 ног и 12 битный АЦП никто как правило не объясняет. Зачем нужен такой комбайн в устройстве, которое легко вывозит Tiny13, которая при этом не загружена даже на треть своих ресурсов никто не будет разбираться. Просто надо переходить на STM32, и баста. Ибо вот.

И надо сказать, есть у людей тяга к новизне. А действительно, может попробовать? А вдруг понравится? Вот только Референс Мануал на популярный STM32F103C8T6, на котором основана самая массовая Голубая таблетка в 1126 страниц что-то как-то не очень располагает к «быстрому старту». Даже отдельную утилиту, так ненавидимый аксакалами «калокуб», и ту надо изучать, что там к чему. Да и вникнув в Cube, стартовать за 5 минут вряд ли получится, генерируемая им портянка не самое доступное чтиво на ночь, просто «в лоб» врубиться, о чём там речь получится не у каждого.

Отдельной беседы заслуживают многочисленные статьи, похожие на эту, про быстрый и лёгкий старт в STM. У всех подобных статей меня первое время очень смущало одно обстоятельство. Нигде не присутствует подробное объяснение, а что мы тут собственно пишем. Куча скриншотов как создать проект, потом сразу стена кода-делай вот так! А что там, для чего там, почему именно так, откуда взять все эти вроде и понятные слова, никто не вникает, ибо силы кончились при написании мануала по установке Кейла и Куба, и по запуску проекта. Только спустя какое-то время, индивидуальное для каждого, приходит понимание, что происходит и зачем. В свою очередь, я предлагаю способ стартовать не с начала, как все, а с конца. Сейчас мы будем делать всё наоборот, не настраивать контроллер, писать код и дебажить его, а сразу перейдём к дебагу, и запротоколируем наши действия в виде кода.

Итак, устанавливаем Keil, как бесплатную (до 32КБ кода) среду. Описывать сие действо не будем, этого есть в интернетах, да и степ-бай-степ установщика должен осилить человек, который идёт в STM. Запускаем проект: Project-New uVision Project, создаём папку и файл проекта. Открывается окно выбора контроллера, в поиск вводим модель 103C8 и соглашаемся на единственную отобранную модель.

Далее попадаем в окно выбора библиотек:



Здесь ставим три галки: CMSIS-CORE, Device-Startup и Device-GPIO. Этого набора вполне хватит, чтобы подрыгать ножкой, зажигая светодиодик. Дальше придётся-таки понастраивать, никуда от этого не денешься. Alt+F7 запускают окно настроек, расположенное Project-Options for Target, где на вкладке «Output» надо поставить галку «Create HEX-File», чтобы создался файл прошивки, которую мы будем загружать в контроллер. Далее, во вкладке «Debug» мы выберем ST-Link, которым, собственно, и будем загружать прошивку и дебажить:



По кнопке «Setting» рядом с окошком выбора программатора попадаем в окно «Cortex-M Target Driver Setup», где во вкладке «Flash Download» ставим галку «Reset and Run».

В дереве проекта ткнём правой кнопкой в папку «Source Group 1», в открывшемся визарде создадим файл main.c, в который скоро будем писать код. В открывшемся main.c по правой кнопке вставляем самый первый и самый важный инклюд:



Дописываем код, состоящий из main и бесконечного while:

#include "stm32f10x.h"                  // Device header
int main(){
	while(1){
	}
}

Как ни странно, это всё на сей момент, это уже готовая и понятная программа, которая корректно компилируется и загружается в контроллер. Нажимаем F7 и видим, что прошивка удачно собрана, ошибок и варнингов нет.



С этого момента нам полностью доступен контроллер, мы можем войти в него под линии дебага и крутить-вертеть его во все стороны, а он будет откликаться.

Клавиши Ctrl+F5 ведут нас в дебаг, а кнопка «System Viewer Windows» позволяет запустить окошки контроля регистров тактирования и управления ногами GPIO.



Далее предлагаю всё-таки воспользоваться Reference Manual, тем более, что его даже скачивать не надо, он доступен по клику во вкладке «Books» меню «View»:



Теперь предлагаю воспользоваться следующим рассуждением. Из распиновки на Голубую Таблетку видно, что светодиод висит на ноге 13 порта С. Многочисленные инет-ресурсы и обсуждения всегда упоминают, что прежде, чем что-то сделать в STM, это что-то надо включить, иначе-подать тактирование. Не мудрствуя лукаво, пишем в окно поиска pdf-читалки то, что нам надо, а именно-включить порт C: «PORT C CLOCK ENABLE». Получаем во такую картину:



Отсюда можно сделать вывод, что включение тактирования порта С осуществляется в регистре IOPCEN. С этим знанием идём во вкладку RCC в режиме дебага, и вписываем это название в строку поиска:



Помечаем требуемый чекбокс галочкой, и с этого момента считаем порт С включенным.

Теперь, вспомная многострадальный AVR, будем искать настройку собственно пина. Для того, чтобы он заработал, надо объяснить, что именно мы от него хотим. А хотим мы подрыгать ногой номер 13 порта С, для этого надо задать режим её работы. В строке поиска в Referense Manual вбиваем «Port bit configuration», чем выразим своё желание прочитать, где же спрятаны настройки ножки. Поиск приводит нас к таблице, из которой следует, что для того, чтобы назначить ногу выходом, требуется сконфигурировать регистры MODE и CNF:



Из таблицы №20 видно, что для назначения ножки выходом Push-Pull надо сбросить регистры CNF0 и CNF1, а состояние пары MODE0 и MODE1 описано в таблице №21, я выберу верхний вариант, до 10MHz, MODE0=1, MODE1=0. Это я и проделаю в окне GPIOC для регистров CNF13 и MODE13



Теперь у нас настроено тактирование и режим работы порта. Самое время узнать, как именно дрыгнуть ножкой. По английски установить бит порта пишется как «Port bit set», эту фразу и будем искать в мануале:



Поиск приводит нас на страницу с таблицей, из которой явно видно, что за установку состояния ножки порта отвечает регистр BSRR, состоящий из пар BS и BR, Bit set и Bit reset соответственно. Находим эти регистры в окне GPIOC в режиме дебага и наслаждаемся управлением ногой №13 напрямую, тыкая мышкой галки в соответствующие чекбоксы:



Светодиод на плате голубой пилюли висит между ногой и VCC, по этому управление им обратно названию регистров. Bit Set (регистр BS13) тушит его, а Bit Reset (регистр BR13) зажигает. Это регистры атомарных операций, они сбрасываются после установки чекбокса. Есть возможность управлять ногой через регистр ODR, (пункт 9.2.4 Port output data register (GPIOx_ODR) в референс мануале), там наглядно видно, к чему приводит установка и сброс галки.



Горящий и тухнущий зелёный светодиод показывает, что всё работает верно. Остаётся только записать всё это в виде кода в файл main.c. Вот тут и появляется самый изюм, который отличает этот способ постижения контроллера STM через дебаг от остальных, которыми завален весь интернет. Я предлагаю просто переписать то, что видим в окне дебага в код. Пример:



Задали режим работы порта и включили тактирование;



Включили ножку порта, подождали, выключили и так далее:

#include "stm32f10x.h"                  // Device header

int main(){
	RCC->APB2ENR=0x00000010;			// включили тактирование
	GPIOC->CRH=0x44144444;			// задали режим Push-Pull до 10MHz
	int i;								// переменная для задания задержки вкл/выкл светодиода
	while(1){
		GPIOC->ODR=0x00002000;		// выключаем LED, по ламерски дёргая весь порт целиком
		i=2000000;					// взводим переменную для паузы
		while (i) i--;					// ждём
		GPIOC->ODR=0x00000000;		// включаем LED
		i=2000000;					// снова ждём
		while (i) i--;					
	}
}


Само собой, данный способ далеко не лучший и не правильный, но по моему мнению наиболее понятный и простой. К тому же, он приобщает к работе с даташитом (референс мануалом) и не отпугивает, как чтение манов и написание многостраничных портянок кода для Блинка. Да, здесь нет наслоений абстракций, упущено многое, но за элементарность старта я думаю можно это простить. Чтение мана и правильная работа с регистрами это потом, сейчас у нас моргает светодиод и нам в принципе понятно, как и что мы сделали, а самое главное, откуда взялись все эти аббревиатуры. Если бы мне показали такой способ изучения STM раньше, возможно я бы не собирал over 9000 разных программаторов для AVR в которых так и не было дебага, а взялся бы сразу за Кортексы. Ведь в AVR так и нет внятного и доступного дебага, но всё равно, забывать Tiny13 пока рано. Свои задачи она вывозит.

Вы можете помочь и перевести немного средств на развитие сайта

Теги:



Комментарии (61):

  1. ks0
    /#21276662 / -2

    Контроллеры мощнее, а подходы к программированию все те же. Какие-то битики, какие-то регистры. Нафига это все? Следующих шаг от 8-битных МК должен быть переход к более высокому уровню абстракции, когда пофиг сколько там таймеров и есть или нет ДМА. Т.е. к ОС. Без ОС между AVR и ARM нет никакой принципиальной разницы.

    • kotbaun
      /#21276812 / +1

      FreeRTOS, mbedOS и иже с ними. Это есть. AVR редко используется(во всяком случае мной), зачастую 32 битный STM.
      И абстракция есть, HAL называется…

      • Polaris99
        /#21276862 / +1

        С такой абстракцией никакие враги не нужны. И человек немного путает ОС и ОСРВ, никакая ОСРВ в обозримом будущем не будет заниматься организацией работы с DMA в независимом от разработчика режиме.

    • madcatdev
      /#21279402

      Предлагаете для моргания светодиодом использовать Raspberry Pi с каким-нибудь модным фреймворком? :)

  2. ancc
    /#21276872

    В кокосе в свое время можно было выбрать контроллер и создать проект прям в несколько кликов. Если не путаю.
    А сейчас все что может само генерировать проект выдает чудовищные простыни с HAL через которые новичку пробраться к железу гораздо сложнее. Хотя сейчас есть LL но с ним по-умолчанию тоже проект не сгенерируешь, опять hal прицепом.

    • Radish
      /#21276898 / +1

      Об этом я и пишу, эта стена кода ради блинка не просто пугает, она сама крестик в правом верхнем углу нажимет и Кейл с Кубом с компа сносит. Вроде хотел всего ничего, Хелловорд написать, а тебе 6 экранов кода выкинуло и дерево проекта на 30+ файлов. Тут любой по старому доброму AVR затоскует, тем более, что реальных задач для STM у домашнего мамкиного программиста как бы и нет. А реально нужного в этой портянке всего 5 строк.

    • Gryphon88
      /#21276970

      Кстати, можете мне на пальцах объяснить, почему куб выдаёт стену кода? Возможностей и шаблонов, и даже макросов вполне хватает на то, чтобы пользовательский код был достаточно краток.

      • Radish
        /#21277546

        наверное это плата за «универсальность» заготовки кода. Прописано всё на все случаи, нужное-оставить, ненужное-удалить. Как быть с пластами абстракций, если ты нуб? Скорее всего, никак, только терпеть и лопатить.

        • Gryphon88
          /#21277622

          STL очень туго обвязана шаблонами, получается, что разработчики куба просто поленились?

          • max_dark
            /#21277770

            Куб генерирует код на Си, а в Си нет шаблонов.

            • Gryphon88
              /#21277784

              Тогда понятно, на макросах тоже можно писать, но лучше так не делать.

      • SergeyMax
        /#21279298

        Кстати, можете мне на пальцах объяснить, почему куб выдаёт стену кода?
        Да никакой особой стены кода куб не выдаёт. Просто по сути каждый конфигурационный бит процессора в нём записывается как человеко-читаемая строка, например
        htim3.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
        и чтобы понять, что тут происходит, нет необходимости каждую минуту лезть в даташит, выискивая вырвиглазные названия битов в таких же вырвиглазных названиях регистров.

      • Xop
        /#21279442

        Меня похожий вопрос интересовал, когда я решил попробовать ангуляр — ng init генерит не меньше кода, чем куб

  3. melodictsk
    /#21277000

    Для быстрого перехода на стм32 идеально подходит stm32duino. По мере погружения код будет постепенно превращаться в нативный

    • semen-pro
      /#21277414

      stm32duino — это который из двух? Они несовместимы.

  4. marsdenden
    /#21277010

    Ну тинька и таблетка все же разных весовых категорий, а если сравнивать 328 и стм407 — вообще несравнимы. На тиньке что-то нормальное втиснуть — желателен ассемблер, а не ардуиноиде, на стмках же есть вполне нормальный STMCubeIDE, который содержит в себе все, что надо для разработки. Таки да, достаточно прост, чтобы разобраться, неплохой дебаггер и кейл не нужен при этом. Единственное, что плохо — он на эклипсе, посему любит задумываться даже на неслабых машинках и очень не любит стлинки на клонах китайских, aka cks или как там их.
    В общем холивар atmel vs stm — изначально глуп, как хищник против человека-паука. Ну вы меня поняли...))

    • Radish
      /#21277228

      Кубоид пробовал, что-то вообще как-то не зашло. Ну и Эклипс для моей слабенькой машинки неподъёмен, да и тоже не впечатляет

      • marsdenden
        /#21277350

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

    • Jef239
      /#21279016

      А вы с STMH7 сравните. Мег ОЗУ, два мега ПЗУ, в отдельных вариантах полтора процессора… Ну как бы зверь совсем иного класса.

  5. x893
    /#21277032

    Мне кажется так удобнее периферию смотреть
    image

    • Amomum
      /#21279420

      К сожалению, такие красивые окошки Кейл умеет рисовать для очень ограниченного количества процов; вероятно, их люди делали "вручную". А регистры рисуются по sfr-файлу, который производитель МК поставляет.

  6. Koyanisqatsi
    /#21277294

    А что делать, если нет 10к$ на Keil? =)

    • Radish
      /#21277334

      ужаться в 32КБ кода и никому не платить

    • crustal
      /#21277464

      А что делать, если нет 10к$ на Keil? =)

      Тогда можно включить собственные мозговые ресурсы, а не полагаться на статьи хабра. К примеру, зайти на сайт производителя STM32, перейти на «MCU & MPU Eval Tools», выбрать «STM32 Nucleo Boards»
      www.st.com/content/st_com/en/products/evaluation-tools/product-evaluation-tools/mcu-mpu-eval-tools/stm32-mcu-mpu-eval-tools/stm32-nucleo-boards.html
      затем прочесть такой текст: «All STM32 Nucleo users have free access to the mbed online resources (compiler, C/C++ SDK, and developer community) at www.mbed.org allowing to build a complete application in only a few minutes.»
      Другими словами купите за 10 баксов какую-нибудь STM32 Nucleo board и программируйте эту board прямо из браузера на mbed.org, там тонны примеров кода. Это и будет «наилегчайший старт в STM32». Нет особого смысла верить всему, что появляется на хабре, особенно в песочнице.

      • Radish
        /#21277576

        это будет «наилегчайший старт в STM за $10+». Да и хотелось бы ссылочку на нуклео за 10 баксов. Не стоит верить всему, что появляется на Хабре, особенно в камментах.

      • Tsvetik
        /#21277876

        Фигня жто mbed. Редактор на сайте годится только для запуска примеров. Да и то не всех. Навигации нет, отладки нет, даже нормальных сообщений об ошибках нет. Десктопный редактор еще более убог.

        • tea1975
          /#21277904

          PlatformIO спасает бедный ембед habr.com/ru/post/358682

          • Tsvetik
            /#21278102

            Спасибо

            • tea1975
              /#21279664

              Всегда пожалуйста, есть ещё вариант с Visual Studio и VisualGDB
              Правда отладчик платный, но говорят он того стоит. А также можно глянуть на Segger Embedded Studio, есть мнение, что там дебаггер просто божественен

          • isden
            /#21282778

            Ага, все ждал в комментах, когда про него вспомнят :)
            Недавно попробовал, вообще огонь.

    • ProLimit
      /#21278108

      Eclipse как IDE на голову выше и бесплатный. Компилятор — gcc для ARM, не сравнивал с Keil по качеству но на больших проектах вполне успешно справляется.

      • monah_tuk
        /#21280790

        Я в QtC вкорячил. Удобно, включая загрузку и отладку с помощью OpenOCD/GDB.

    • Jef239
      /#21279022

      Мы на gcc собираем. OpenOCD для загрузки, GDB для отладки.

    • marsdenden
      /#21279796

      Почему бы не попробовать STMCubeIDE? Все в одном — среда разработки, компилятор, программатор, отладчик. В комплекте CubeMX, интегрирован в IDE, не нужно устанавливать/запускать отдельно. Единственный глюк, который я заметил — после обновления (а они случаются) есть вероятность, что при апгрейде файла *.ioc (это основа проекта, файл CubeMX) весь код, который вы написали в соответствующих блоках будет уничтожен. Но своевременные бэкапы проекта спасают в этом случае. Причем потери не обязательны, это происходит при определенных условиях, сейчас не вспомню, каких, уже больше полугода не подходил к МК. Ну и обновления происходят не просто так, STM в каждой обновке решает некоторые проблемы, к примеру, большинство мануалов в инете для запуска USB в качестве serial port предлагают добавлять некий код в обработчики приема-передачи, начиная с некоторой верии IDE они таки включили этот код в шаблоны. Саму IDE можно взять на st.com
      Ну и на ту же таблетку можно писать, используя HAL, можно CMSIS, если очень хочется, то можно и SPL подключить. И да не будет холивар, что хал — дерьмо, настоящие пацаны пишут на регистрах )))

      • AVDerov
        /#21281032

        Я с вами согласен в целом, но все же на следующий Новый год я попрошу Деда мороза повесить каждому менеджеру ST волшебный ошейник. Что бы когда очередной noname_user будет плакать над примерами ST или документацией по волшебном ошейник пробегало вольт 300...


        P. S. Самое обидное, что-бы вычистить код примеров нужны копейки, а человеко/лет user тратится порядочно.

  7. da-nie
    /#21278348

    int i;


    volatile int i;

    • bugdesigner
      /#21278552

      Volatile нужен для глобальных переменных, изменяемых в обработчиках прерываний.

      • da-nie
        /#21278568

        Не только. :)
        Ничто не помешает компилятору выкинуть пустой цикл, как бесполезный при включении оптимизации.

        Локальные переменные

        Часто для создания небольших задержек пользуются такими функциями:

        void Delay (char D)
        {
        char i;
        for (i = 0; i < D; i++) continue;
        }

        Однако, некоторые компиляторы видят в этих функциях бесполезный код и вообще не включают его в результирующий объектный код. Если эта задержка применялась для снижения скорости программного i2c (или SPI) под компилятором, например, HT-PICC, то при переносе на ядро AVR с компилятором WinAVR программа перестанет работать, вернее, она будет работать так быстро, что управляемая микросхема не будет успевать обрабатывать сигналы из-за того, что все вызовы функции Delay будут упразднены.

        Чтобы этого не происходило, нужно использовать квалификатор volatile:

        void Delay (char D)
        {
        volatile char i;
        for (i = 0; i < D; i++) continue;
        }

        • Radish
          /#21278746

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

          • da-nie
            /#21278774 / -2

            Положим, это фрагмент статьи, на которую указывает ссылка.

            Боюсь представить, что с вами будет, если я подключу std::for_each. :)

          • devprodest
            /#21279784 / +1

            Так, а что вам не нравиться в цикле for? Любой ваш оператор цикла это по сути if и goto обернутые в красивое название (синтаксический сахар).

            • Radish
              /#21279798

              Лично я ничего не имею против, равно как и за. Это сродни предыдущему заявлению, что я был обязан указать volatile, человек считает, что я обязан, и его ничего не волнует.

              • devprodest
                /#21279834

                Мне кажется вы слишком резко восприняли критику, volatile, мне кажется, в данном случае нужен, так как эта статья позиционируется как учебный материал и было бы полезно сразу знать о граблях. Я не увидел в словах того заявления принуждения к этому, только совет с объяснением почему.
                Я использую в кейле 6.13 компилятор с настройкой оптимизации balance и подобные циклы порой исчезают.

              • da-nie
                /#21280550

                Это сродни предыдущему заявлению, что я был обязан указать volatile, человек считает, что я обязан, и его ничего не волнует.


                Меня волнует, что ряды «Не включайте оптимизацию! В компиляторе ошибка — цикл теряется.» пополнятся очередным адептом. И виноваты в этом будете вы со своей статьёй. А вот это уже скверно.

      • bugdesigner
        /#21278582

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

    • Radish
      /#21278628

      мы рады, что вам известно назначение volatile, но именно эта минимальная программа здесь и сейчас в нём не нуждается.

      • da-nie
        /#21278650 / -2

        Блажен, кто верует. ;)

        • Radish
          /#21278658 / -1

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

          • da-nie
            /#21278714 / -1

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

            • Radish
              /#21278730 / -1

              либо вы пишете всю программу по правилам хорошего тона, здравого смысла и правил программирования и конкретно этого языка, либо отбрасываете вообще всё, что может отвлекать и в конкретных учебных целях оставляете самый минимум. Здесь есть много того, за что можно развести критику до небес, но вы разглядели только volatile. К тому же, эта программа работает в дебаге, этопошаговый режим и эти задержки здесь не нужны вообще. Цель включить вручную тактирование, настроить порт и подрыгать ножкой, ставя галку мышкой.

              • da-nie
                /#21278740

                Здесь есть много того, за что можно развести критику до небес, но вы разглядели только volatile


                Потому что именно volatile приводит к тому, что люди жалуются, что их код не работает при включении оптимизации и переносе на другой компилятор. И ругают «тупой» компилятор. Я это видел не раз и не два. И потому будет лучше, чтобы те, кто прочитает вашу статью не делали таких весьма необычных ошибок.
                Но к вам вопрос: я что-то сказал неверно про использование в этом фрагменте volatile?

                • Gryphon88
                  /#21279392 / +1

                  При компиляции gcc с ключом -Os (стандарт для МК) volatile не нужен, при -O2 и выше цикл должно выкинуть. Как ведёт себя keil или пиковский компилятор не знаю, документацию на них за ненадобностью не читал.

    • ultrasonique
      /#21278660 / -1

      Разницы никакой

      • da-nie
        /#21278716

        Оптимизм — это хорошо. Повышу вам за него карму. :)

  8. alex-open-plc
    /#21280666 / +1

    «Голубая таблетка» это не STM32F103C6T8, это STM32F103C8T6. Исправьте.

  9. Affdey
    /#21281984

    Прикольно! Правильно описан ужас вначале разработки на STM, часто нигде не упоминается, откуда берутся операторы и какие они могут быть ещё. А тут по действиям понятно. Я также, когда начинал постигать VBA, включал запись макроса, делал действия, смотрел код.

    По поводу дебага на AVR — зачем? ну есть JTAG-отладчики, но кому это надо? в голове или симуляторе не дебажится? Сколько всего делал на AVR, поэтому недоумеваю.

    • Radish
      /#21282692

      Бывает что сам затупишь, бывает что с синтаксисом накосячишь. Вроде и код валидный, а работает неправильно. Дебаг в такие моменты реально вывозит, а в голове дебажить можно сутками