ARM. STM32 быстрый старт. Прошивка ST Link, установка драйверов

Данная статья является первой в планируемом цикле статей по изучению программирования микроконтроллеров. Изучая различные материалы я отметил, что практически все они начинаются с того, что новичку предлагается скачать (или использовать идущую со средой разработки) библиотеку для работы с периферийными устройствами и использовать ее для написания своей первой программы (обычно мигание светодиодом).

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

В этой статье, путь от фразы «Да, я хочу попробовать!» до радостного подмигивания светодиода, будет значительно длиннее чем у других авторов. Я постараюсь раскрыть аспекты программирования микроконтроллеров, которые прячутся за использованием библиотечных функций и готовых примеров.
Если вы намерены серьезно изучать программирование микроконтроллеров данная статья для вас. Возможно, она может заинтересовать и тех, кто вдоволь наигрался с Arduino и хочет получить в свои руки все аппаратные возможности железа.

Выбор микроконтроллера

Многие могут сказать, что начинать изучение микроконтроллеров лучше с AVR, PIC, 8051 или чего-то еще. Вопрос многогранный и спорный. Я знаю достаточно примеров, когда люди изучив Cortex-M, программировали AVR, ARM7 и т.д. Сам же я начинал с Cortex-M3. Если перед вами стоит определенная задача, в интернете достаточно много информации со сравнением различных типов микроконтроллеров и решаемых с их помощью задач. На хабре этот вопрос тоже поднимался, например .

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

Я остановил свой выбор на STM32 (хотя и считаю, что лучше начинать изучение с МК от TexasInstruments - очень грамотно составлена документация), потому что они широко распространены среди российских разработчиков электроники. При возникновении проблем и вопросов вы сможете без труда найти решения на форумах. Еще одним плюсом является богатый выбор демонстрационных плат как от производителя, так и от сторонних организаций.

Что необходимо для изучения?

К сожалению, для начала программирования МК не достаточно одного лишь ПК. Придется где-то раздобыть демонстрационную плату и программатор. Хотя это и уменьшает конкуренцию на рынке труда.

Сам я использую демонстрационную плату STM3220G-EVAL и программатор J-Link PRO . Но для начала, будет вполне достаточно STM32F4DISCOVERY , которую можно купить без особых проблем за небольшую сумму.

Все примеры будут именно для отладочной платы STM32F4DISCOVERY . На данном этапе нам будет совершенно не важно, что этой плате стоит МК на базе ядра Cortex-M4. В ближайшее время мы не будем использовать его особенности и преимущества над Cortex-M3. А как там будет дальше - посмотрим.

Если у вас есть в наличии любая другая плата на базе STM32F2xx/STM32F4xx, вы сможете работать с ней. В изложении материала я постараюсь максимально подробно описывать почему мы делаем именно так, а не иначе. Надеюсь ни у кого не возникнет проблем с переносом примеров на другое железо.

Среда разработки

Как уже неоднократно упоминалось, для ARM микроконтроллеров существует достаточное количество сред разработки, как платных так и не очень. И снова хочется опустить полемику по этому поводу. Я использую IAR Embedded Workbench for ARM 6.60 . Все примеры будут именно в этой среде. Если вам по душе (или в вашей организации используется) что-то другое (Keil, Eclipse, CCS, CooCoc и т.д.) то это вам тоже не очень помешает. На особенности, связанные именно со средой разработки, я буду обращать отдельное внимание.

Почему платная среда разработки?

Возможно, кто-то будет не совсем доволен тем, что я предлагаю использовать платную среду разработки, но в IAR есть возможность получить временную лицензию без ограничения функционала, либо безлимитную лицензию с ограничением по размеру кода (32КБ для МК это очень много).
Помимо этого, сразу замечу, что для некоторых МК не существует бесплатных сред разработки. И к сожалению эти МК в некоторых областях незаменимы.


Процесс установки я описывать не буду.

С чего начать?

Создание проекта
Для начала создадим пустой проект. IAR позволяет создать проекты на ASM, C и C++. Мы будем использовать C.

Перед нами появится пустой проект с main файлом.

Теперь необходимо настроить проект для начала работы с «нашим» МК и отладчиком. На плате STM32F4DISCOVERY установлен MK STM32F407VG . Его необходимо выбрать в свойствах проекта (General Options->Target->Device):

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

После этого необходимо настроить отладчик. Отладка программы происходит непосредственно «в железе». Производится это с помощью JTAG отладчика. Более подробнее ознакомиться с тем, как это происходит можно на Википедии . На плату STM32F4DISCOVERY интегрирован отладчик ST-LINK/V2. Для работы с отладчиком необходимо выбрать его драйвер в меню Debugger->Setup->Driver . Так же необходимо указать, что отладка должна производиться непосредственно в железе. Для этого необходимо поставить флаг Debugger->Download->Use flash loader(s)


Для тех, кто увидел слово Simulator

Теоретически, IAR позволяет отлаживать программы с использованием симулятора. Но я ни разу на практике не встречал его использования.

Теперь проект готов для работы (программирования, заливки и отладки).

«ТЗ» для первого проекта
Подведем промежуточный итог: МК и отладочная плата выбраны, проект подготовлен. Пора определиться с задачей.

Не будем отходить от классики. Первым проектом будет мигающий светодиод. Благо на плате их предостаточно.Что же это означает с точки зрения программирования? Первым делом необходимо изучить принципиальную схему демонстрационной платы и понять как «заводится» светодиод.
доступен на сайте производителя. В данном описании даже есть отдельный раздел про светодиоды на плате -4.4 LEDs . Для примера, будем использовать User LD3 . Найдем его на схеме:

Простейший анализ схемы говорит о том, что для того, что бы «зажечь» светодиод необходимо на пин МК подать «1» (которая для данного МК соответствует 3.3В). Выключение производится подачей на этот пин «0». На схеме этот пин обозначается PD13 (это, наверное, самая важная информация из этого документа).

В итоге, мы можем написать «ТЗ» для нашей первой программы:
Программа для МК должна переводить состояние пина МК PD13 из состояния «0» в состояние «1» и обратно с некоторой периодичностью, различимой для человеческого глаза (важное замечание, если моргать светодиодом слишком часто глаз может этого не различить).

Прежде чем приступать к программированию, или немного теории
Прежде чем приступить к реализации нашего ТЗ, необходимо понять как производится управление МК.

Начнем с того, что любой МК включает ядро, память и периферийные блоки. Думаю, что с памятью пока все понятно. Упомяну лишь, в STM32 есть флеш память в которой хранится программа МК (в общем случае это не верное утверждение, программа может храниться во внешней энергонезависимой памяти, но пока это опустим) и другие данные, в том числе и пользовательские. Так же есть SRAM - оперативная память.

Ядро - часть микроконтроллера, осуществляющая выполнение одного потока команд. В нашем МК тип ядра - Cortex-M4. Ядро МК можно сравнить с процессором в ПК. Оно умеет только выполнять команды и передавать данные другим блокам (в этом сравнении не учитываются процессоры с интегрированными графическими ускорителями).
При этом производитель МК не разрабатывает ядро. Ядро покупается у компании ARM Limited . Главное отличие между различными МК - в периферии.

Периферийные блоки - блоки осуществляющие взаимодействие с «внешним миром» или выполняющие специфические функции, недоступные ядру МК. Современные МК (в том числе и STM32) содержат огромный спектр периферийных блоков. Периферийные блоки предназначены для решения различных задач, от считывания значения напряжения с аналогового входа МК до передачи данных внешним устройствам по шине SPI.
В отличии от ядра МК периферийные блоки не выполняют инструкции. Они лишь выполняют команды ядра. При этом участие ядра при выполнении команды не требуется.

Пример

В качестве примера можно привести блок UART, который предназначен для приема и передачи данных от МК внешним устройствам. От ядра необходимо лишь сконфигурировать блок и отдать ему данные для передачи. После этого ядро может дальше выполнять инструкции. На плечи же периферийного блока ложится управление соответствующим выводом МК для передачи данных в соответствии с протоколом. Периферийный блок сам переводит выход МК в необходимое состояние «0» или «1» в нужный момент времени, осуществляя передачу.

Взаимодействие ядра с периферийным блоком
Взаимодействие ядра МК с периферийным блоком осуществляется с помощью спецрегистров (есть еще взаимодействие через механизм прерываний и DMA, но об этом в следующих постах). С точки зрения ядра это просто участок памяти с определенным адресом, вот только на самом деле это не так . Запись данных в спецрегистр эквивалентна передаче команды или данных периферийному блоку. Считывание - получение данных от блока или считывание его состояния. Описание периферийных блоков и их спецрегистров занимает львиную долю описания МК.

ВАЖНО: После записи данных в спецрегистр и последующем чтении вы можете получить совершенно иные данные. Например, передача данных блоку UART для отправки, и считывание данных, полученных блоком от внешнего устройства, осуществляется с помощью одного и того же регистра.

Спецрегистры обычно разделены на битовые поля. Один (или несколько) бит управляют определенным параметром периферийного блока, обычно независимо. Например, разные биты одного регистра управляют состоянием разных выходов МК.

Вспоминаем С
Если вы гуру в языке C, то можете смело пропускать данный раздел. Он предназначен в первую очередь для тех, кого учили (или ктоучился сам) программировать для ПК. Опыт показывает, что люди часто не помнят важных команд. Здесь я вкратце напомню про побитовые операции и работу напрямую с памятью по ее адресу.

Запись данных по адресу в памяти

Предположим, что читая описание периферийного блока, мы поняли, что для его корректной работы необходимо записать в него число 0x3B. Адрес спецрегистра 0x60004012. Регистр 32-битный.
Если вы сразу не знаете как это сделать, попробую описать цепочку рассуждений для получения правильной команды.

Значение 0x60004012 есть не что иное, как значение указателя на ячейку памяти. Нужно именно это и указать в нашей программе, тоесть сделать преобразование типов согласно синтаксису языка C:

(unsigned long*)(0x60004012)

Таким образом, у нас есть указатель на элемент. Теперь нужно в этот элемент записать необходимое значение. Делается это разыменовыванием указателя. Таким образом получаем правильную команду:

*(unsigned long*)(0x60004012) = 0x3B;

Установка произвольных бит в 1

Предположим, что необходимо установить «1» в 7 и 1 биты по адресу 0x60004012, при этом не изменив значение всех остальных бит в регистре. Для этого необходимо использовать бинарную операцию |. Сразу приведу правильный ответ:

*(unsigned long*)(0x60004012) |= 0x82;

Обратите внимание на 2 факта. Биты считаются с нулевого, а не с первого. Данная операция на самом деле занимает неменее 3 тактов - считывание значения, модификация, запись. Иногда это не допустимо, поскольку между считыванием и записью значение одного из бит, которые нам запрещено изменять, могло быть изменено периферийным блоком. Незабывайте про эту особенность, иначе могут полезть баги, которые крайне сложно отловить.

Установка произвольных бит в 0

Предположим, что необходимо установить «0» в 7 и 1 биты по адресу 0x60004012, при этом не изменив значение всех остальных бит в регистре. Для этого необходимо использовать бинарную операцию &. Сразу приведу правильный ответ:

*(unsigned long*)(0x60004012) &= 0xFFFFFF7D;

Или его более простою запись (не переживайте за лишнюю операцию, компилятор все заранее посчитает даже при минимальной оптимизации):

*(unsigned long*)(0x60004012) &= (~0x82);

Некоторые особенности программ для МК
Здесь я постараюсь описать некоторые особенности программ для МК, которые важно помнить. Вещи достаточно очевидные, но все же.
У программы нет конца
В отличии от большинства программ для ПК, программа для МК не должна заканчиваться, НИКОГДА! А что собственно должен будет делать МК после завершения вашей программы? Вопрос, практически, риторический. Поэтому не забываем убедиться в том, что вы не забыли вечный цикл. При желании, можно перевести МК в режим сна.
Пользуйтесь целочисленными переменными
Не смотря на то, что мы используем МК с ядром Cortex-M4, который аппаратно выполняет операции над числами с плавающей точкой, советую вам отказаться от их использования. В МК без поддержки таких операций время вычислений будет просто огромным.
Откажитесь от динамического выделения памяти
Это только совет. Причина проста - памяти мало. Я не раз встречался с библиотеками, в которых были «медленные утечки» памяти. Было очень неприятно, когда после нескольких недель стабильной работы МК зависал с ошибкой. Лучше заранее продумать архитектуру своей программы так, чтобы не пришлось использовать динамическое выделение памяти.
Если же все-таки хочется использовать - внимательно изучите работу менеджера памяти или пишите свой.

Приступаем к работе!

Работа над программой для МК всегда начинается с чтения документации. Для нашего МК доступен на сайте производителя. Страниц много, но все читать пока не нужно. Как уже было сказано, большую часть документации составляет описание периферийных блоков и их регистров. Так же хочу обратить внимание на то, что этот Reference Manual написан не для одного МК, а для нескольких линеек. Это говорит о том, что код будет переносим при переходе на другие МК в этих линейках (если конечно не пытаться использовать периферийные блоки которых нет в используемом МК).

В первую очередь необходимо определиться с какими блоками предстоит работать. Для это достаточно изучит разделы Introduction и Main features .

Непосредственное управление состоянием пинов МК осуществляется с помощью блока GPIO. Как указано в документации в МК STM32 может быть до 11 независимых блоков GPIO. Различные периферийные блоки GPIO принято называть портами. Порты обозначаются буквам от A до K. Каждый порт может содержать до 16 пинов. Как мы отметили ранее, светодиод подключается к пину PD13. Это означает, что управление этим пином осуществляется периферийным блоком GPIO порт D. Номер пина 13.

Ни каких других периферийных блоков на это раз нам не понадобится.

Управление тактированием периферийных блоков
Для снижения электропотребления МК практически все периферийные блоки после включения МК отключены. Включение/выключение блока производится подачей/прекращением подачи тактового сигнала на его вход. Для корректной работы, необходимо сконфигурировать контроллер тактового сигнала МК, чтобы необходимому периферийному блоку поступал тактовый сигнал.
Важно: Периферийный блок не может начать работу сразу после включения тактового сигнала. Необходимо подождать несколько тактов пока он «запустится». Люди, использующие библиотеки для периферийных устройств, зачастую даже не знают об этой особенности.

За включение тактирования периферийных блоков отвечают регистры RCC XXX peripheral clock enable register .На месте XXX могут стоять шины AHB1, AHB2, AHB3, APB1 и APB2. После внимательного изучения описания соответствующих регистров, можно сделать вывод о том, тактирование периферийного блока GPIOD включается установкой «1» в третий бит регистра RCC AHB1 peripheral clock enable register (RCC_AHB1ENR) :

Теперь необходимо разобраться с тем, как узнать адрес самого регистра RCC_AHB1ENR .

Замечание: Описание системы тактирования МК STM32 достойно отдельной статьи. Если у читателей возникнет желание, я подробнее освещу этот раздел в одной из следующих статей.

Определение адресов спецрегистров
Определение адресов спецрегистров необходимо начинать с чтения раздела Memory map в Reference manual. Можно заметить, что каждому блоку выделен свой участок адресного пространства. Например, для блока RCC это участок 0x4002 3800 - 0x4002 3BFF:

Для получения адреса регистра, необходимо к начальному значению адресного пространства блока RCC прибавить Addr. offset нужного регистра. Addres offset указывается и в описании регистра (см. скриншот выше).

В итоге, мы определили адрес регистра RCC_AHB1ENR - 0x4002 3830.

Блок GPIO
Для общего ознакомления с блоком GPIO я настоятельно рекомендую полностью прочитать соответствующий раздел Reference Manual. Пока можно не особо обращать внимание на Alternate mode . Это оставим на потом.

Сейчас же наша задача научиться управлять состоянием пинов МК. Перейдем сразу к описанию регистров GPIO.

Режим работы
В первую очередь необходимо установить режим работы 13 пина порта D как General purpose output mode , что означает что блок GPIO будет управлять состоянием пина МК. Управление режимом работы пинов МК производитсяс помощью регистра GPIO port mode register (GPIOx_MODER) (x = A..I/J/K) :

Как видно из описания для совершения требуемой нам настройки необходимо записать значение 01b в 26-27 биты регистра GPIOx_MODER . Адрес регистра можно определить тем же методом, что описан выше.

Настройка параметров работы выходных пинов порта GPIO
Блок GPIO позволяет применить дополнительные настройки для выходных пинов порта. Данные настройки производятся в регистрах:
  • GPIO port output type register (GPIOx_OTYPER) - задается тип выхода push-pull или open-drain
  • GPIO port output speed register (GPIOx_OSPEEDR) - задается скорость работы выхода
Мы не будем менять данных параметров, поскольку нас вполне устраивают значения по умолчанию.
Установка значения на пине МК
Наконец-то мы подошли к моменту управления состоянием выхода МК. Для утановки выходного значения на определенном пине МК есть два метода.

Используем регистр GPIO port bit set/reset register (GPIOx_BSRR)

Запись «0» или «1» в биты 0-16 приводят к соответствующему изменению состояния пинов порта. Для того, чтобы установить определенное значение на выходе одного или нескольких пинов МК и не изменить состояния остальных, необходимо будет пользоваться операцией модификации отдельных бит. Такая операция выполняется не менее чем за 3 такта. Если же необходимо в часть битов записать 1, а в другие 0, то понадобится не менее 4 тактов. Данный метод предпочтительнее всего использовать для изменения состояния выхода на противоположное, если его изначальное состояние не известно.

GPIO port bit set/reset register (GPIOx_BSRR)

В отличии от предыдущего метода, запись 0 в любой из битов данного регистра не приведет ни к чему (да и вообще, все биты write-only!). Запись 1 в биты 0-15 приведет к установке «1» на соответствующем выходе МК. Запись 1 в биты 16-31 приведет к установке «0» на соответствующем выходе МК. Этот метод предпочтительнее предыдущего, если необходимо установить определенное значение на пине «МК», а не изменить его.

Зажигаем светодиод!
Найдя адреса всех необходимых регистров, можно написать программу, которая включает светодиод:
void main() { //Enable port D clocking *(unsigned long*)(0x40023830) |= 0x8; //little delay for GPIOD get ready volatile unsigned long i=0; i++; i++; i++; i=0; //Set PD13 as General purpose output *(unsigned long*)(0x40020C00) = (*(unsigned long*)(0x40020C00)& (~0x0C000000)) | (0x04000000); //Turn LED ON! *(unsigned long*)(0x40020C14) |= 0x2000; while(1); }
Можно компилировать (Project->Compile ) и заливать (Project->Download->Download active application ). Или запустить отладку (Project->Dpwnload and Debug ) и начать выполнение (F5).
Светодиод загорелся!
Мигаем светодиодом
Мигание светодиода есть ни что иное, как попеременное включение и выключение с задержкой между этими действиями. Самый простой способ - поместить включение и выключение в вечный цикл, а между ними вставить задержку.
void main() { //Enable port D clocking *(unsigned long*)(0x40023830) |= 0x8; //little delay for GPIOD get ready volatile unsigned long i=0; i++; i++; i++; i=0; //Set PD13 as General purpose output *(unsigned long*)(0x40020C00) = (*(unsigned long*)(0x40020C00)& (~0x0C000000)) | (0x04000000); while(1) { //Turn LED ON *(unsigned long*)(0x40020C14) |= 0x2000; //Delay for(i=0; i<1000000 ;++i); //Turn LED OFF *(unsigned long*)(0x40020C14) &= ~0x2000; //Delay for(i=0; i<1000000 ;++i); } }
Значение 1000000 в задержке подобрано экспериментально так, чтобы период мигания светодиода был различим глазом, но и не был слишком велик.
Оптимизируем алгоритм
Минусом выбранного подхода миганием светодиодом является то, что ядро МК большую часть времени проводит в пустых циклах, хотя мог бы заниматься чем-нибудь полезным (в нашем примере других задач нет, но в будущем они появятся).

Для того, чтобы этого избежать, обычно используется счетчик циклов, а переключение состояние пина МК происходит при прохождении программы определенного числа циклов.
void main() { //Enable port D clocking *(unsigned long*)(0x40023830) |= 0x8; //little delay for GPIOD get ready volatile unsigned long i=0; i++; i++; i++; i=0; //Set PD13 as General purpose output *(unsigned long*)(0x40020C00) = (*(unsigned long*)(0x40020C00)& (~0x0C000000)) | (0x04000000); while(1) { i++; if(!(i%2000000)) { //Turn LED ON *(unsigned long*)(0x40020С14) |= 0x2020; } else if(!(i%1000000)) { //Turn LED OFF *(unsigned long*)(0x40020С14) &= ~0x2000; } } }
Но и тут не обойдется без проблем, с изменением количества команд выполняемых внутри цикла, будет меняться период мигания светодиодом (или период выполнения других команд в цикле). Но на данном этапе мы не можем с этим бороться.

Немного об отладке
IAR позволяет осуществлять отладку приложения непосредственно в железе. Все выглядит практически так же, как и отладка приложения для ПК. Есть режим пошагового выполнения, входа в функцию, просмотр значения переменных (В режиме отладки View->Watch->Watch1/4 ).

Но помимо этого, присутствует возможность просмотра значений регистров ядра, спецрегистров периферийных блоков (View->Register) и т.п.
Я настоятельно рекомендую ознакомиться с возможностями дебаггера во время изучения программирования МК.

Несколько слов в заключение

Возможно, многие скажут, что ручное прописывание адресов в программе это не правильно, поскольку производитель предоставляет файлы с определениями регистров и битовых полей, библиотеки для работы с периферией и другие инструменты, облегчающие жизнь разработчику. Я с этим полностью согласен, но все равно считаю, что первые шаги в программировании МК необходимо делать перекапывая документацию к вручную, самостоятельно определяя необходимые регистры и битовые поля. В дальнейшем этим можно не пользоваться, но уметь нужно обязательно.
Приведу лишь несколько причин для этого утверждения:
  • В библиотеках от производителя иногда встречаются ошибки! Я один раз чуть не сорвал срок проекта из-за этого. Несколько раз перепаивал чип, думая, сто повредил кристалл при пайке (до этого такое случалось). А проблема заключалась в том, что в библиотеке был неверно прописан адрес спецрегистра. Обычно такое случается с МК или линейками МК только вышедшими на рынок.
  • Библиотеки для работы спериферией некоторых производителей не реализуют всех возможностей периферийных блоков. Особенно этим грешилb Luminary Micro , которых в последствии выкупили TI. Приходилось писать инициализацию периферии вручную.
  • Многие привыкают начинать программирование МК с изучения примеров. Я считаю, что сперва необходимо определиться с тем, что позволяет реализовать МК. Это можнопонять только прочитав документацию. Если чего-то нет в примерах, это не значит, что железоэто не поддерживает. Последний пример - аппаратная поддерка PTP STM32. В сети, конечно, можно кое-что найти, но это не входит в стандартный набор от производителя.
  • Драйверы периферийных блоков некоторых производителей настолько не оптимизированы, что на переключение состояния пина средствами библиотеки тратится до 20 тактов. Это непозволительная роскошь для некоторых задач.

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

В последние годы 32 разрядные микроконтроллеры (МК) на основе процессоров ARM стремительно завоёвывают мир электроники. Этот прорыв обусловлен их высокой производи тельностью, совершенной архитектурой, малым потреблением энергии, низкой стоимостью и развитыми средствами программирования.

КРАТКАЯ ИСТОРИЯ
Название ARM является аббревиатурой Advanced RISC Machines, где RISC (Reduced Instruction Set Computer) обозначает архитектуру процессоров с сокращённым набором команд. Подавляющее число популярных МК, а пример семейства PIC и AVR, также имеют архитектуру RISC, которая позволила увеличить быстродействие за счёт упрощения декодирования инструкций и ускорения их выполнения. Появление совершенных и производительных 32 разрядных ARMмикроконтроллеров позволяет перейти к решению более сложных задач, с которыми уже не справляются 8 и 16 разрядные МК. Микропроцессорная архитектура ARM с 32 разрядным ядром и набором команд RISC была разработана британской компанией ARM Ltd, которая занимается исключительно разработкой ядер, компиляторов и средств отладки. Компания не производит МК, а продаёт лицензии на их производство. МК ARM – один из быстро развивающихся сегментов рынка МК. Эти приборы используют технологии энергосбережения, поэтому находят широкое применение во встраиваемых системах и доминируют на рынке мобильных устройств, для которых важно низкое энергопотребление. Кроме того, ARM микроконтроллеры активно применяются в средствах связи, портативных и встраиваемых устройствах, где требуется высокая производительность. Особенностью архитектуры ARM является вычислительное ядро процессора, не оснащённое какими либо дополнительными элементами. Каждый разработчик процессоров должен самостоятельно до оснастить это ядро необходимыми блоками под свои конкретные задачи. Такой подход хорошо себя зарекомендовал для крупных производителей микросхем, хотя изначально был ориентирован на классические процессорные решения. Процессоры ARM уже прошли несколько этапов развития и хорошо известны семействами ARM7, ARM9, ARM11 и Cortex. Последнее делится на подсемейства классических процессоров CortexA, процессоров для систем реального времени CortexR и микропроцессорные ядра CortexM. Именно ядра CortexM стали основой для разработки большого класса 32 разрядных МК. От других вариантов архитектуры Cortex они отличаются, прежде всего, использованием 16разрядного набора инструкций Thumb2. Этот набор совмещал в себе производительность и компактность «классических» инструкций ARM и Thumb и разрабатывался специально для работы с языками С и С++, что существенно повышает качество кода. Большим достоинством МК, построенных на ядре CortexM, является их программная совместимость, что теоретически позволяет использовать программный код на языке высокого уровня в моделях разных производителей. Кроме обозначения области применения ядра, разработчики МК указывают производительность ядра CortexM по десятибалльной шкале. На сегодняшний день самыми популярными вариантами являются CortexM3 и CortexM4. МК с архитектурой ARM производят такие компании, как Analog Devices, Atmel, Xilinx, Altera, Cirrus Logic, Intel, Marvell, NXP, STMicroelectronics, Samsung, LG, MediaTek, MStar, Qualcomm, SonyEricsson, Texas Instruments, nVidia, Freescale, Миландр, HiSilicon и другие.
Благодаря оптимизированной архитектуре стоимость МК на основе ядра CortexM в некоторых случаях даже ни же, чем у многих 8разрядных приборов. «Младшие» модели в настоящее время можно приобрести по 30 руб. за корпус, что создаёт конкуренцию предыдущим поколениям МК. МИКРОКОНТРОЛЛЕРЫ STM32 Рассмотрим наиболее доступный и широко распространённый МК семейства STM32F100 от компании STMicroelectronics , которая является одним из ведущих мировых производителей МК. Недавно компания объявила о начале производства 32битного МК, использующего преимущества индустриального
ядра STM32 в недорогих приложениях. МК семейства STM32F100 Value line предназначены для устройств, где не хватает производительности 16разрядных МК, а богатый функционал «обычных» 32разрядных приборов является избыточным. Линейка МК STM32F100 базируется на современном ядре ARM CortexM3 с периферией, оптимизированной для применения в типичных приложениях, где использовались 16разрядные МК. Производительность МК STM32F100 на тактовой частоте 24 МГц превосходит большинство 16разрядных МК. Данная линейка включает приборы с различными параметрами:
● от 16 до 128 кбайт флэшпамяти программ;
● от 4 до 8 кбайт оперативной памяти;
● до 80 портов ввода вывода GPIO;
● до девяти 16разрядных таймеров с расширенными функциями;
● два сторожевых таймера;
● 16канальный высокоскоростной 12разрядный АЦП;
● два 12разрядных ЦАП со встроенными генераторами сигналов;
● до трёх интерфейсов UART с поддержкой режимов IrDA, LIN и ISO7816;
● до двух интерфейсов SPI;
● до двух интерфейсов I2С с поддержкой режимов SMBus и PMBus;
● 7канальный блок прямого доступа к памяти (DMA);
● интерфейс CEC (Consumer Electronics Control), включённый в стандарт HDMI;
● часы реального времени (RTC);
● контроллер вложенных прерываний NVIC.

Функциональная схема STM32F100 представлена на рисунке 1.

Рис. 1. Архитектура МК линейки STM32F100

Дополнительным удобством является совместимость приборов по выводам, что позволяет, при необходимости, использовать любой МК семейства с большей функциональностью и памятью без переработки печатной платы. Линейка контроллеров STM32F100 производится в трёх типах корпусов LQFP48, LQFP64 и LQFP100, имеющих, соответственно, 48, 64 и 100 выводов. Назначение выводов представлено на рисунках 2, 3 и 4. Такие корпуса можно устанавливать на печатные платы без применения специального оборудования, что является весомым фактором при мелкосерийном производстве.


Рис. 2. МК STM32 в корпусе LQFP48 Рис. 3. МК STM32 в корпусе LQFP64


Рис. 4. МК STM32 в корпусе LQFP100

STM32F100 – доступный и оптимизированный прибор, базирующийся на ядре CortexM3, поддерживается развитой средой разработки МК семейства STM32, которая содержит
бесплатные библиотеки для всей пе риферии, включая управление двига телями и сенсорными клавиатурами.

СХЕМА ВКЛЮЧЕНИЯ STM32F100C4
Рассмотрим практическое использование МК на примере самого простого прибора STM32F100C4, который, тем не менее, содержит все основные блоки линейки STM32F100. Принципиальная электрическая схема включения STM32F100C4 представлена на рисунке 5.


Рис. 5. Схема включения МК STM32F100C4

Конденсатор С1 обеспечивает сброс МК при включении питания, а конденсаторы С2-С6 фильтруют напряжение питания. Резисторы R1 и R2 ограничивают сигнальный ток выводов МК. В качестве источника тактовой частоты используется внутренний генератор, поэтому нет необходимости применять внешний кварцевый резонатор.


Входы BOOT0 и BOOT1 позволяют выбрать способ загрузки МК при включении питания в соответствии с таб лицей. Вход BOOT0 подключён к шине нулевого потенциала через резистор R2, который предохраняет вывод BOOT0 от короткого замыкания при его использовании в качестве выход ного порта PB2. С помощью соединителя J1 и одной перемычки можно из менять потенциал на входе BOOT0, определяя тем самым способ загрузки МК – из флэшпамяти или от встроенного загрузчика. При необходимости загрузки МК из оперативной памяти аналогичный соединитель с перемычкой можно подключить и к входу BOOT1.
Программирование МК осуществляется через последовательный порт UART1 или через специальные программаторы – отладчики JTAG или STLink. Последний входит в состав популярного отладочного устройства STM32VLDISCOVERY , изображённого на рисунке 6. На плате STM32VLDIS COVERY 4контактный разъём программатора – отладчика STLink – имеет обозначение SWD. Автор статьи предлагает программировать МК через последовательный порт UART1, поскольку это значительно проще, не требует специального оборудования и не уступает в скорости JTAG или ST Link. В качестве управляющего устройства, способного формировать команды и отображать результаты работы про граммы МК, а также в качестве программатора можно использовать любой персональный компьютер (ПК), имеющий последовательный COM порт или порт USB с преобразователем USBRS232.

Для сопряжения COMпорта ПК с МК подойдет любой преобразователь сиг налов RS232 в уровни логических сигналов от 0 до 3,3 В, например, микросхема ADM3232. Линия передачи TXD последовательного порта компьютера, после преобразователя уровней, должна подключаться к входу PA10 микроконтроллера, а линия приёмника RXD, через аналогичный преобразователь, – к выходу PA9.

При необходимости использования энергонезависимых часов МК, к нему следует подключить элемент питания типа CR2032 с напряжением 3 В и кварцевый резонатор на частоту 32768 Гц. Для этого МК оснащён выводами Vbat/GND и OSC32_IN/OSC32_OUT. Предварительно вывод Vbat необходимо отключить от шины питания 3,3 В.

Оставшиеся свободными выводы МК можно использовать по необходимости. Для этого их следует подключить к разъёмам, которые расположены по периметру печатной платы для МК, по аналогии с популярными устройствами Arduino и отладочной платой STM32VLDISCOVERY .


Рис. 6. Отладочное устройство STM32VLDISCOVERY


Схема электрическая принципиальная STM32VLDISCOVERY.

Таким образом, в зависимости от назначения и способа применения МК, к нему можно подключать необходимые элементы, чтобы задействовать другие функциональные блоки и пор ты, например, ADC, DAC, SPI, I2C и т.п. В дальнейшем эти устройства будут рас смотрены подробнее.

ПРОГРАММИРОВАНИЕ
Сегодня многие компании предлагают средства для создания и отладки программ микроконтроллеров STM32. К их числу относятся Keil от ARM Ltd, IAR Embedded Workbench for ARM, Atol lic TrueStudio, CooCox IDE, GCC и Eclipse IDE. Разработчик может выбрать про граммные средства по своему пред почтению. Ниже будет описан инструментарий Keil uVision 4 от компании Keil , который поддерживает огромное число типов МК, имеет развитую систему отладочных средств и может быть использован бесплатно с ограничениями размера генерируемого кода 32 кбайт (что, фактически, максимально для рассматриваемых МК).

Простой и быстрый старт с CooCox CoIDE.

Итак приступим. Идем на официальный сайт CooCox и качаем последнюю версию CooCox CoIDE . Для скачивания необходимо зарегистрироваться, регистрация простая и бесплатная. Затем инсталлируем скачанный файл и запускаем.

CooCox CoIDE — среда разработки, на базе Eclipse, которая помимо STM32 поддерживает кучу других семейств микроконтроллеров: Freescale, Holtek, NXP, Nuvoton, TI, Atmel SAM, Energy Micro и др. С каждой новой версией CoIDE список МК постоянно пополняется. После успешной установки CoIDE запускаем:

Появится стартовое окно Step 1, в котором необходимо выбрать производителя нашего микроконтроллера. Нажимаем ST и переходим к Step 2 (выбор микроконтроллера), в котором необходимо выбрать конкретную модель. У нас STM32F100RBT6B, поэтому нажимаем на соответствующую модель:

Справа, в окне Help отображаются краткие характеристики каждого чипа. После выбора нужного нам микроконтроллера переходим к третьему шагу Step 3 — к выбору необходимых библиотек для работы:

Давайте создадим простейший проект для мигания светодиодом, как это принято для изучения микроконтроллеров.

Для этого нам понадобится библиотека GPIO, при включении которой, CoIDE попросит создать новый проект. На это предложение нажимаем Yes, указываем папку где будет храниться наш проект и его название. При этом, CoIDE подключит к проекту 3 другие, необходимые для работы библиотеки, а также создаст всю необходимую структуру проекта:

Чем еще хорош CoIDE, это тем, что в нем есть возможность загружать примеры прямо в среду разработки. В вкладке Components вы можете видеть, что почти к каждой библиотеке есть примеры, нажимаем на GPIO (with 4 examples) и видим их:

Туда можно добавлять и свои примеры. Как видно на скриншоте выше, в примерах уже присутствует код для мигания светодиодом GPIO_Blink. Можно нажать кнопку add и он добавиться в проект, но как подключаемый файл, поэтому мы сделаем по другому просто скопируем весь код примера в файл main.c. Единственное, строку void GPIO_Blink(void) замените на int main(void). Итак, нажимаем F7 (или в меню выбираем Project->Build), чтобы скомпилировать проект и… не тут то было!

Среде нужен компилятор GCC, а у нас его нет. Поэтому идем на страничку GNU Tools for ARM Embedded Processors , справа выбираем тип вашей ОС и качаем последнюю версию тулчайна. Затем запускаем файл и инсталируем gcc toolchain. Далее, в настройках CoIDE укажем правильный путь к тулчайну:

Опять нажимаем F7 (Project->Build) и видим, что компиляция прошла успешно:

Осталось прошить микроконтроллер. Для этого при помощи USB подключаем нашу плату к компьютеру. Затем, в настройках дебаггера необходимо поставить ST-Link, для этого в меню выбираем Project->Configuration и открываем вкладку Debugger. В выпадающем списке выбираем ST-Link и закрываем окно:

Попробуем прошить МК. В меню выбираем Flash->Program Download (или на панели инструментов щелкаем по соответствующей иконке) и видим, что МК успешно прошит:

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

Также, в CoIDE работают различные режимы отладки, для этого нажимаем CTRL+F5 (или в меню Debug->Debug):

На этом все. Как видите, настройка среды CoIDE и работа с ней очень проста. Надеюсь данная статья подтолкнет вас в изучении очень перспективных и недорогих микроконтроллеров STM32.

ST-LINK/V2 - крайне экономичное решение для внутрисхемного программирования и отладки микроконтроллеров STM8 и STM32. Изделие имеет минимальные габариты. На плате для защиты от короткого замыкания установлен самовосстанавливающийся предохранитель на 500 мА. Выходные уровни напряжения ST-LINK/V2 составляют 3.3 В и 5 В. К компьютеру плата подключается через стандартный USB порт. Для работы с целевой платой используются SWIM и SWD интерфейсы, которые характеризуются быстрым откликом при отладке и высокой скоростью программирования. Отладчик работает в полноскоростном (FS) режиме. Доступны стандартные функции отладки: пошаговое выполнение программы, точки останова, просмотр переменных и регистров и т. д. ST-LINK/V2 имеет обновляемое firmware для расширения списка совместимых МК. Режим обновления ПО - автоматический. Изделие поддерживается широким спектром программных средств, среди которых интегрированные среды разработки IAR, Keil, ATOLLIC, а также утилиты STM.

ST-LINK/V2 поддерживает все STM8 (SWIM интерфейс) и все STM32 (SWD интерфейс).

Для работы с изделием требуется установить USB драйвер.

Таблица 1. Сравнительные характеристики различных моделей программаторов/отладчиков

Параметр

ST-LINK/V2 (mini)

ST-LINK/V2

Примечание

Диапазон напряжений SWD

ST-LINK/V2 иST-LINK/V2 (mini) низковольтные МК STM32

Диапазон напряжений SWIM

Поддержка SWV

Отладочные интерфейсы

ST-LINK/V2 и ST-LINK/V2 (mini) поддерживает STM8/STM32 с использованием отдельных интерфейсов

LED индикатор

Двухцветный LED

Двухцветный LED

Красный LED

Двухцветный светодиод увеличивает возможности индикации состояний

Предохранитель

Предохранитель поможет избежать повреждений при КЗ

Таблица 2. ST-LINK/V2 (mini) должен быть подключен к приложению на STM8 через SWIM интерфейс

Таблица 3. ST-LINK/V2 (mini) должен быть подключен к приложению на STM32 через SWD интерфейс

Примечание. Чтобы избежать повреждения ST-LINK/V2 (mini), VCC и GND должны быть подключены корректно.

Рис. 1. Программатор/отладчик ST-LINK/V2 . Общий вид

Рис. 2. Программатор/отладчик ST-LINK/V2 . Вид сверху

Рис. 3. Программатор/отладчик ST-LINK/V2 . Вид снизу

Отличительные особенности:

  • На плате установлен самовосстанавливающийся предохранитель 500 мА, чтобы избежать повреждения от КЗ;
  • Уровни выходного напряжения (3.3 V/5 V), простота отладки и программирования;
  • Стандартный USB интерфейс для простого подключения к PC;
  • Возможности отладки/программирования:
    • отладка: работа в полноскоростном режиме, пошаговое выполнение, точки останова, просмотр переменных и регистров и т. д.,
    • программирование: поддержка FLASHROM, EEPROM и т. д.,
    • USB2.0 и SWIM/ SWD интерфейсы: быстрый отклик в режиме отладки и высокая скорость программирования;
  • Обновляемое firmware:
  • Поддерживаемое ПО:
    • ST-LINK Utility v2.0 (или выше),
    • STVD Version 4.2.1 (или выше),
    • STVP Version 3.2.3 (или выше),
    • IAR EWARM Revision v6.20 (или выше),
    • IAR EWSTM8 Revision v1.30 (или выше),
    • KEIL RVMDK Revision v4.21 (или выше),
    • ATOLLIC,
    • TASKING;
  • Поддерживаемые микроконтроллеры:
    • все STM8 (SWIM интерфейс),
    • все STM32 (SWD интерфейс).

Дополнительную информацию и программное обеспечение можно найти на сайте производителя .

Анонс составил и подготовил
Шрага Александр,
a.

Микроконтроллеры для котят

Всем Мяу, котаны:)

Как-то раз от меня ушла кошка:(Ну и чем валерьянку лопать, я решил заняться делом, так сказать «на благо Родине». Давно уж хотел цифровыми устройствами заняться, да времени не было (сами понимаете, то спать, то с кошкой по крышам гулять), а тут как раз время-то и появилось. Ну-с начнём..)

Всё как обычно начинается с выбора. Ну вроде выбор-то небольшой PIC, да AVR. Последние мне как-то больше приглянулись. Нужен был ещё и USB программатор за неимением других портов на компьютере, от цены которого у меня чуть хвост не отвалился. Ещё Arduino есть - зверёк такой. Его и программировать по USB можно. Ну, думаю, "то что доктор прописал". В селе нашем его только через интернет-магазин достать можно. Нашёл, где по-выгодней, чуть не купил и... ОПА! Смотрю - STM32VL-Discovery. Что за зверь такой? Хм, STM32.. Что-то слышал краем уха.. А от характеристик усы дыбом, честно!

А лап-то у неё сколько!

Итак, попорядку:

  • У Arduino 14 цифровых портов ввода/вывода и 6 аналоговых входов. У STM32VL-Discovery 45 цифровых входа/выхода 10 из которых по желанию превращаются в аналоговые входы.
  • У Arduino 32 Кб для хранения программы и 2 Кб ОЗУ. У STM32VL-Discovery 64 Кб для хранения программ и 8 Кб ОЗУ.
  • У Arduino тактовая частота 16 МГц у STM32VL-Discovery же 24 МГц.
  • Любой микроконтроллер STM32 можно заменить другим STM32, но с лучшими характеристиками, без изменения схемы
  • STM32 можно программировать без программатора по COM порту (об этом чуть позже)
  • Цена Arduino на момент написания статьи ~1300 рублей, STM32VL-Discovery ~600 рублей. Это ж дешевле более чем в 2 раза!

А что дальше? В STM32VL-Discovery есть встроенный программатор/отладчик, который лёгким движением лапы (снятием перемычек) может программировать и отлаживать (отладка очень уж вещь полезная, но об этом чуть позже) микроконтроллеры STM32 за пределами платы. С Arduino такое не прокатит. То есть используя STM32VL-Discovery мы и деньги экономим и получаем большую производительность и свободу творчества:)

Да и сами микроконтроллеры STM32 выглядят привлекательней остальных:

STM32F100C4T6B ATtiny24A-SSU PIC16F688-I/SL STM32F103RET6 ATmega1284P-PU PIC18F4550-I/PT
Средняя цена, руб 60 65 60 240 330 220
Тактовая частота, МГц 24 20 20 72 20 48
Flash память, Кбайт 16 2 4 512 128 16
RAM, Байт 4096 128 256 65536 16384 2048
USART, шт 2 0 0 5 2 0
SPI, шт 1 1 0 3 1 1
АЦП, шт 16x12Bit 8x10Bit 8x10Bit 16х12Bit 8x10Bit 13x10Bit
ЦАП, шт 1x12Bit 0 0 2х12Bit 0 0
Количество линий ввода/вывода, шт 37 12 12 51 32 35

А ещё STM32 32-х разрядные, а это означает возможность работы с 32-х битными данными за один такт. AVR и PIC этим не похвастаются.

Ну что, котаны, убедил? Тогда начнём курс молодого бойца цифровика!)

Как оно работает? Из чего состоит? Что умеет?

Как известно, все коты очень любознательные, а радиокоты особенно!

Микроконтроллер - это микросхема сочетающая в себе функции процессора, периферии, имеющая ОЗУ, flash память. Как компьютер, только меньше!

Проведём аналогию: компьютером управляет операционная система, а микроконтроллером «прошивка», которую пишете Вы; операционная система компьютера хранится на жёстком диске, «прошивка» микроконтроллера в его flash памяти; функции ОЗУ схожи - хранение изменяющихся данных во время выполнения программы. А ещё у МК есть различные периферийные устройства, такие как АЦП и ЦАП например.

МК общается с внешним миром при помощи лап на его корпусе (не таких как у котов, конечно, а металлических). Но не все из них управляются программой, есть выводы питания, вывод сброса, выводы питания периферии, вывод резервного питания. А те, которые управляются программой делятся на группы называемые «порты». Все эти управляемые выводы называются 2-мя буквами и цифрой. Например PA1: P - порт, А - порт «А», 1 - номер вывода этого порта.

В программе порты конфигурируются либо на вход, либо на выход, по вашему желанию.

Выводы порта настроенного на вход могут быть в разных режимах, для каждого вывода он может быть своим:

  • Цифровой вход - вход, значение которого (логическая 1 или 0) можно считывать программой. Если напяжение на входе 0, то значение равно 0, если на входе напяжение равное напрядению питания, то значение входа 1. Третьего не дано. Можно сделать с подтягивающим резистором либо к питанию, либо к массе
  • Аналоговый вход - вход значение которого можно считывать программой, но значений может быть много - целых 4096. А точнее от 0 если на входе напяжение 0 относительно минуса питания микроконтроллера до 4095, если на входе напряжение равное напряжению питания. Все эти преобразования делает АЦП - аналогово-цифровой преобразователь, при помощи его можно например измерять напряжение на терморезисторе и узнавать температуру или измерять напяжение на фоторезисторе и узнавать яркость попадающего на него света... Ну много чего можно придумать, если фантазия есть:) Если питать микроконтроллер от 3В, то 0В = 0, а 3В = 4096, значит 3/4096=0.000732421, т.е. при изменении напяжения на входе на 0.000732421В значение входа в программе меняется на 1. Не так-то всё и сложно, да? Идём дальше
  • Цифровой вход в режиме альтернативной функции - вход для работы с периферией. Например вход для таймера или вход для какого-нибудь интерфейса. Из программы значение этого входа считать нельзя. В программе можно например считать данные полученные по этому выводу каким-нибудь интерфейсом.

А у порта настроенного на выход выводы могут быть в таких режимах:

  • Выход. Просто выход. Обычный цифровой выход. На выводе либо напрядение питания (логическая 1) либо на выводе нет напряжения (логическая 0). Всё просто.
  • Выход в режиме альтернативной функции - выход управляемый периферией. Этим выходом нельзя управлять из программы, но программой можно заставить управлять этим выводом например интерфейс.

Но не все выводы можно назначать «как захочется». Для того, что бы узнать, что можно, а что нельзя нужно посмотреть документацию (таблица 4) или воспользоваться программой MicroXplorer.

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

Ещё есть выводы BOOT 0 и BOOT 1 . Эти выводы не относятся к портам, они служат для управления загрузкой микроконтроллера. Если во время подачи питания на выводе BOOT 0 логический ноль (вывод соединен с общей точкой), то микроконтроллер выполняет программу загруженную во flash память, т.е. Вашу прошивку. Если во время подачи питания на выводе BOOT 0 логическая еденица (вывод соединен с питанием микроконтроллера), а на выводе BOOT 1 логический ноль, то микроконтроллер выполняет не Вашу прошивку, а записанный на заводе загрузчик. Запомните это! Вы будете часто пользоваться этим в процессе работы с микроконтроллерами STM32! Иногда загрузка записанного с завода загрузчика - единственный способ записать/изменить прошивку микроконтроллера. Это бывает например при конфигурировании в прошивке выводов, к которым подключается программатор или при прошивке микроконтроллера без использования программатора. Так что настоятельно рекомендую при проектировании печатной платы эти выводы (или хотя бы BOOT 0) распологать в удобном месте.

Вот разобрались:) Теперь знаем что такое микроконтроллер, из чего он состоит. Сейчас узнаем ещё о некоторых премудростях и перейдём к самому интересному - практике!

Программа в микроконтроллере выполняется пошагово. Один такт процессора - один шаг программы.

Например пусть перемигивается красная и зелёная лампочки, пока НЕ нажата кнопка. Длительность каждой лампы - 5 секунд. Вот алгоритм:

  1. Проверяем, на входе с кнопкой есть напряжение? (кнопка замыкает вывод микроконтроллера на + питания)
  2. Если нет напряжения, то загорается красная лампочка на 5 секунд, зелёная тухнет, если есть напряжение, то начинаем всё сначала
  3. Снова проверяем
  4. Если нет напряжение, то загорается зелёная лампочка на 5 секунд, красная тухнет, если есть напряжение, то начинаем всё сначала
  5. Начинаем сначала

СТОП! А если я нажму кнопку, пока горит лампочка? То ничего не произойдёт! Потому что программа выполняется пошагово, а шаг с проверкой нажатия кнопки находится в момент переключения лампочек.
Вот именно для таких случаев есть такая вещь, как прерывания

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

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

Встаём на лапы!

Ну, котята, пора вставать на лапы! Надеюсь у Вас уже есть отладочная плата? Или хотя бы микроконтроллер? Надеюсь есть:) А если нет, то бежим в магазин! (и желательно не за колбасой. хотя...) Какое же это учение без практики?

Отлично на первых порах иметь отладочную плату, например STM32VL-Discovery, но если жаба душит или всё-таки нехватает на колбасу, то можно обойтись и одним микроконтроллером и преобразователем интерфейсов RS-232 ->UART (напр. MAX3232) или USB ->UART (напр. FT232RL). В этом случае в 100 рублей можно вполне уложиться, но придётся делать печатную плату и паять минимум 48 выводов шириной 0,3 мм с зазором 0,2 мм. Я предупреждал.

Сначала нужно естественно прикошачить отладочную плату или контроллер к компьютеру.

Если у Вас отладочная плата:

С отладочной платой, конечно проще. Берём шнурок Mini-USB и соединяем плату с компьютером, все драйверы должны поставиться автоматически. Увидеть STMicroelectronics STLink dongle в диспетчере устройств - хороший знак! Ну а если что-то пошло не так и ничего не вышло - не надо царапать диван, нужно просто зайти сюда и установить STM32 ST-LINK utility .

Ну а если Вы счастливый обладатель компьютера под управлением Windows 8, то перед проведением вышеописанных действий нужно сделать так: Параметры -> Изменение параметров компьютера -> Общие -> Особые варианты загрузки и выбрать параметр Отключение проверки подписи драйверов .

Если у Вас микроконтроллер:

Если у Вас один микроконтроллер, то у Вас должны быть прямые лапы. Но я в Вас не сомневаюсь!

Перед подключением микроконтроллера к компьютеру его нужно припаять к печатной плате. Для этого кроме микроконтроллера и прямых лап нужна как минимум печатная плата. А тут уж Ваше творчество.

Рабочий минимум на схеме ниже:

Но это неинтересный минимум.

Добавьте светодиодов и кнопок (не забудьте про выводы BOOT), например так

А вот с пайкой этой блохи могут возникнуть проблемы. Но я надеюсь, не возникнут. Я накошачился паять её своим любимым советским 25 Вт паяльником с шириной жала в 3/4 ширины контроллера. У меня больше проблем с изготовлением печатной платы... ну тут уж у каждого своя технология.

И переходник нужно сделать на UART по документации к той микросхеме, которую купили.

Соединяем выводы TxD и RxD на печатной плате с выводами RxD и TxD соответственно переходника. Не забываем про общую точку и питание всего этого.

Выбор и установка ПО

Пользоваться мы будем средой разработки CooCox IDE , но это не просто так, а по нескольким причинам:

  • Во-первых это свободно распространяемое ПО. А это значит, что Ваша карма будет чиста
  • На мой взгляд (да и не только на мой) эта среда разработки удобнее остаальных
  • Позволяет использовать отладку
  • Много примеров, которые можно загружать в среду разработки (полезно для котят и не только)

Среда разработки - это программа для написания кода, компилятор, отладчик в одном. Удобненько:) Но если какому-то суровому Челябинскому коту удобнее писать код (в блокноте например), компилировать и прошивать разными программами - я не против, тогда Вам пригодится STM32 ST-LINK utilit для загрузки прошивки в микроконтроллер. Хозяин барин, как говорится.

Эта среда разработки основана на многим известном Eclipse.

  1. Идём сюда
  2. Тыкаем Download through CoCenter (Recommend)
  3. Вводим адрес эл.почты (можно от балды, он там «для галочки»)
  4. После загрузки устанавливаем этот самый CoCenter
  5. В первой строчке, где написано CooCox CoIDE тыкаем Download
  6. После того, как загрузка закончится, то вместо Download будет Install . Сюда и жмём
  7. Идём сюда
  8. Справа в колонке Download скачиваем файл который .exe. Устанавливаем его.
  9. Открываем сам CooCox CoIDE , вкладка Project , Select Toolchain Path .
  10. Указываем путь к файлу arm-none-eabi-gcc.exe (это мы установили в п.8, путь приблизительно такой: D:Program Files (x86)GNU Tools ARM Embedded4.7 2013q1bin)
  11. Снова открываем CoIDE , нажимаем View -> Configuration , открываем вкладку Debugger и делаем так [фото]
  12. Радуемся, потому что теперь мы можем написать программу и прошить её в микроконтроллер! Чем мы и займёмся.

Если у Вас вариант без отладочной платы/программатора, то для загрузки программы в МК понадобится программка Flash Loader Demonstrator которая находится

Находим общий язык

Перед тем, как писать свою первую программу нужно найти с МК общий язык. Вряд ли он будет учить наш язык, по этому придется выучить (а может просто вспомнить) язык на котором мы будем общаться с МК, это Си. Понадобятся нам только основы (состав программы, функции, операторы). Если язык этот знаете, то можете сразу перейти к пункту «Первая программа», ну а незнающих я введу в курс дела.

Проект состоит из файлов с расширениями .c и .h . В первых находятся функции во вторых названия используемых функций и константы например. Так уж заведено. Самый главный файл, в котором находится код программы main.c . Для использования различных функций нужно подключать библиотеки с этими функциями. Подключаются они записью #include "название_библиотеки" ну библиотеки естественно должны быть в проекте. Подключают их в самом начале файла.

Функции - это своеобразная часть программы. Вообще программа состоит из одной или нескольких функций. Функция имеет вид:

тип_возвращаемой_переменной имя_функции (тип_переменной)
{
Тело функции
}

В функцию можно отправить какую-нибудь переменную, фунция её обработает и вернёт какое-нибудь значение. Очень удобно использовать функцию для повторяющихся действий, чем писать постоянно один и тот же кусок кода, можно просто отправлять переменную в функцию и получать обратно обработанное значение.

Перед тем, как использовать функцию, её нужно объявить в самом начале файла. Делают это в таком виде:

тип_возвращаемой_переменной имя_функции (тип_переменной);

Ах, да, забыл самое главное! В конце каждой строки должна быть точка с запятой!

Если функция ничего не возвращает (например временная задержка, она просто тянет кота за хвост время), то тип указывают void .

При запуске, первой всегда выполняется функция main() .

Ну с функциями вроде разобрались, понимание придёт только с практикой.

Выше я упоминал тип переменной . Все переменные могут быть разных типов, вот основные:

  • INT - переменная этого типа может быть только целым числом от -2147483648 до 2147483647
  • FLOAT - переменная этого типа число с точностью до 7 разрядов от ±1,5*10-45 до ±3,4*1033
  • DOUBLE - число с точностью до 16 разрядов от ±5*10-324 до ±1,7*10306
  • ULONG - тоже целое число, но от 0 до 18446744073709551615
  • LONG - целое от -9223372036854775808 до 9223372036854775807
  • CHAR - один символ
  • BOOL - логическая переменная. Она может иметь только 2 значения: истина (true) или ложь (false)

Строку (слово, предложение) можно представить как массив из символов типа char. Например:

char stroka = "Слово";

Здесь квадратных скобках - количество символов в строке, «stroka» - название массива.

Перед использованием переменной её нужно обязательно объявить. (просто указать тип переменной и имя)

  • + - сложение.
  • - - вычитание.
  • * - умножение.
  • / - деление.
  • = - присвоение переменной значения.

Например выражение a=b+c значит присвоить переменной a значение суммы значений переменных b и c .

  • ++ - инкремент. Увеличение значения переменной на 1
  • -- - декремент. Уменьшение значения переменной на 1

Например выражение a++ значит увеличить значение переменной a на 1 (то же самое, что и a=a+1 )

  • == - сравнение, знак «равно». (НЕ ПУТАТЬ С ПРИСВОЕНИЕМ)
  • != - сравнение, знак «не равно».
  • < - сравнение, знак «меньше».
  • <= - сравнение, знак «меньше или равно».
  • > - сравнение, знак «больше».
  • >= - сравнение, знак «больше или равно».

Например выражение a становится истинным, если значение переменной a меньше значения переменной b и ложным, если значения равны или a больше b . Выражение a==b истинно если a равно b и ложно, если a не равно b , НО выражение a=b истинно всегда , потому что это не сравнение, это присвоение переменной a значения переменной b .

  • % - остаток от деления

Например если a=5 , b=3 , то значение выражения a%b будет равно 2 (т.к. 5/3=1 (ост.2))

  • << - побитовый сдвиг влево. Не вдаваясь в подробности значение выражения a< на языке Си будет равно выражению a*2 b
  • >> - побитовый сдвиг вправо. Выражение a>>b в программе равносильно выражению a/2 b
  • & - логическое И .
  • | - логическое ИЛИ .
  • ~ - инвертирование.

Чуть не забыл рассказать про циклы. Основные:

while(условие) {

тело цикла

Тело цикла (всё что в фигурных скобках) выполняется, когда условие истинно (пока условие не станет ложным).

for (начальное_значение; цикл_выполняется_до, шаг) {

тело цикла

Начальное_значение - начальное значение счётчика

Цикл_выполняется_до - до достижения какого значения выполняется цикл

Шаг - с каким шагом счетчик считает

Например

for (i=0; i<10, i++) {

тело цикла

Здесь начальное значение переменной i равно 0, цикл выполняется, пока значение переменной i меньше 10, при каждом выполнении цикла к переменной i прибавляется 1. Так же можно изменять значение переменной прямо в цикле.

if (условие){

тело 1

} else {

тело 2

В усовном переходе «тело 1» выполняется, если условие истинно и выполняется «тело 2», если условие ложно. Ещё есть такой вариант:

if (условие 1){

} else if (условие 2) {

В этом случае «тело 1» выполняется, если истинно «условие 1», «тело 2» выполняется, если истинно «условие 2». Таких условий может быть сколько угодно, так же может быть одно else.

Условия могут быть простыми и составными: простые - одно логическое выражение, а составное - несколько логических выражений соединённых знаком & (условия истинно, когда все условия соединённые этим знаком истинны) или | (условие истинно, если хотябы одно условие соединённое этим знаком истинно).

Ещё полезная вещь - комментарии. Помогут разобраться в забытом проекте:) или просто что бы что-то не забыть. Комментировать можно или после знаков // и до конца строки или начинаются знаками /* и заканчиваются */ , в таком случае комментарий может быть любое количество строк. На размер программы комментарии не влияют.

Ну вот, из основного вроде всё. На первое время хватит (до написания следующей части статьи)

Первая программа

Не будем отступать от традиций (а то мало ли) и начнём с Hello World. А по пути будем продолжать знакомиться с микроконтроллером и так сказать получать опыт.

Открываем среду разработки:

Нажимаем Browse in Repository

Выбираем ST

Потом мы увидим список подключаемых библиотек.

Для нашей простенькой программы нам понадобится: CMSIS core , CMSIS Boot , RCC , GPIO .

Библиотеки CMSIS core и CMSIS Boot - системные, их нужно подключать обязательно

Библиотека RCC для работы с системой тактирования

Библиотека GPIO для работы с портами ввода-вывода

Теперь слева в окне Project открываем файл main.c .

Сначала нужно подключить наши библиотеки (CMSIS подключать не нужно).

Идём в самое начало программы и добавляем строчки:

#include "stm32f10x_gpio.h"
#include "stm32f10x_rcc.h"

void Delay(int i) {
for (; i != 0; i--);
}

Так. Тут по порядку, функция ничего не возвращает, по этому void , название функции Delay , сразу объявляем переменную i типа int . В фигурных скобках тело функции - цикл for . Это его строчная запись. Начальное значение i мы не изменяем, цикл выполняется, пока i не равна нулю (как i становится равна нулю, цикл прекращается, функция «выключаеся»). С каждым выполнением тела цикла (тактом) переменная i уменьшается на 1. Т.е. суть цикла - просто повториться количество раз равное i . Пока выполняется цикл время идёт, происходит задержка.

Какой порт ответственный за какой вывод можно посмотреть в документации к МК:

Для тактирования порта С добавляем строчку:

RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC , ENABLE);

Добавляем в прогармму строчку:

GPIO_InitTypeDef GPIO_Init1;

Этой строчкой мы объявили структуру GPIO_InitTypeDef - дали ей название GPIO_Init для использования в нашей программе далее.

Какие в этой структуре можно настроить параметры и какой вид они имеют, смотрим всё в том же stm32f10x_gpio.h :

Теперь чтобы настроить параметры выводов при помощи структуры нужно написать её название, поставить точку и появится окошечко в котором эти параметры указаны

Дважды щёлкаем по одному из них, и он появляется в строке, далее ставим = (присвоить) и прописываем значение из stm32f10x_gpio.h

Так же поступаем со всеми параметрами. Не забываем точку с запятой в конце каждой строки!

GPIO_Init(GPIOC , &GPIO_Init);

Теперь будем мигать! Мигать мы будем циклично, сделаем зацикливание в цикле while. Условие цикла будет 1. Еденица - всегда истина, нуль - всегда ложь.. такова се ля ви..

Чтобы подать ток на вывод нужно установить бит, чтобы выключить вывод нужно сбросить бит. Как это делать - всё в том же stm32f10x_gpio.h :

Делаем так:

while (1){

GPIO_SetBits(GPIOC, GPIO_Pin_9);

Delay (200000);

GPIO_ResetBits(GPIOC, GPIO_Pin_9);

Delay (200000);

1 всегда истина, значит цикл будет зацикливание.

GPIO_SetBits - функция установки бита

GPIO_ResetBits - функция сброса бита

Delay (200000) - на этой строчке выполнение программы переходит в функцию Delay , в ту самую, в которой цикл for . Число 200000 в скобках - передаётся в эту функцию, как переменная i . (помним строчку void Delay(int i) ?) и выполняется тот самый цикл в этой функции, все 200000 раз. Это быстро:) после окончания работы цикла for функция D elay заканчивает свою работу, т.к. она void , то она ничего не возвращает и программа продолжает выполняется дальше.

Т.к. while зациклен, то включение светодиода, задержка, выключение светодиода, задержка будут выполняться бесконечно циклично. Пока не выключится питание или не произойдёт прерывание (об этом в следующей статье).

Ну вот, первая программа готова. Теперь нажимаем F7, программа компилируется.

Теперь если у Вас отладочная плата, то подключаем её при помощи USB шнурка и нажимаем Download Code To Flash . Радуемся выполненной работе и полученным знаниям:)

А если у Вас не отладочная плата, то подключите к своей плате переходник сделаный ранее, а переходник к COM-порту компьютера. Далее соедините вывод BOOT 0 c плюсом питания микроконтроллера и включите питание микроконтроллера. Тем самым микроконтроллер войдет в режим прошивки. Вообще процедура прошивки не сложная. Нужно просто следовать указаниям приложения Flash Loader Demonstrator . Сначала указываем номер COM-порта, через который у Вас подключен микроконтроллер и скорость. Для воизбежании сбоев, скорость лучше выбрать поменьше

Если программа увидела Ваш микроконтроллер, то появится окно, в котором будет написано, сколько у него памяти

После нажатия «Next», Вы увидите страницу с адресацией памяти. Она нам не понадобится.

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

Для прошивки выбираем Download to device и в поле Download from file выбираем компилированный.hex файл, который находится в папке CooCox -> CooIDE -> workspace -> имя_проекта -> имя_проекта -> Debug -> Bin . После снова нажимаем «Next».

После того, как увидим такое окно:

Отключаем питание микроконтроллера, закрываем Flash Loader Demonstrator , отключаем переходник, и включаем микроконтроллер в обычном режиме (когда при включении вывод BOOT 0 соединен с минусом питания микроконтроллера). Радуемся!

Итак, теперь мы знаем, чем микроконтроллеры STM лучше других, знаем как работает микроконтроллер, умеем прошивать микроконтроллер в отладочной плате и в своей плате, знаем основы языка Си, которые нужны для программирования STM32, получили опыт работы с микроконтроллером (надеюсь положительный) и самое главное, теперь Вы можете воплотить свои идеи цифровых устройств в жизнь (и поведать о них, на нашем любимом РадиоКоте)! Пусть пока ещё простенькие, но всё навёрстывается с опытом. А я постараюсь в следующих статьях рассказать об АЦП, ЦАП, прерываниях, использовании отладки и других полезностях.

Как вам эта статья?

Данная статья, которая является еще одним "быстрым стартом" в освоении ARM-контроллеров, возможно поможет сделать первые шаги в освоении 32-битных контроллеров ARM на базе ядра Cortex-M3 - STM32F1xxx серии. Возможно данная статья (которых на эту тему появляется как грибов после дождя) станет для кого-то полезной.

Введение

Почему ARM?
1. Есть из чего выбрать (разными производителями сегодня выпускается более 240 ARM-контроллеров)
2. Низкая цена (например за 1$ можно получить 37хI / O, 16K Flash, 4K RAM, 2xUART, 10x12bitADC, 6x16bitPWM).

А начнем нашу работу с контроллеров фирмы ST Microelectronics. Контроллеры на основе ядра ARM Cortex-M3 характеризуются широким набором периферии, высоким уровнем рабочих характеристик, низкой цене
P.S. В самом начале создается впечатление, что ARM"ы это какие-то страшные (в пайке, разводке, программировании) существа. Но это только на первый взгляд:) и вы в этом сами убедитесь.

Итак, изучать ARMы будем на примере контроллеров STM32F1. Одновременно эта серия имеет несколько линеек:

  • Value line STM32F100 - 24 МГц CPU, motor control, CEC.
  • Access line STM32F101 - 36 МГц CPU, до 1 Mб Flash
  • USB access line STM32F102 - 48 МГц CPU with USB FS
  • Performance line STM32F103 - 72 МГц, до 1 Mб Flash, motor control, USB, CAN
  • Connectivity line STM32F105/107 - 72 МГц CPU, Ethernet MAC, CAN, USB 2.0 OTG

Также существует следующая классификация:

Контроллеры STM32 можно заставить загружаться с 3-х областей памяти (в зависимости от состояния ножек BOOT0 и BOOT1 при старте контроллера или после его сброса). Записать программу в память контроллера можно следующими способами:

1 способ:
Используя загрузчик (он уже записан в системную память) и USART1 (USART2 remaped): использует внутренний тактовый сигнал 8 МГц. Чтобы запустить встроенный загрузчик, зашитый в контроллер производителем, достаточно просто бросить на лапки контроллера TX1, RX1 сигнал с преобразователя RS232-3.3В (например на базе FT232RL) и выставить перед этим BOOT0 = 1 и BOOT1 = 0 жмем RESET и можем шить программу в контроллер. А зашивается она в программе Flash Loader Demonstartor от STM (для Windows).

PS. Если вы сидите под LINUX и не имеете отладочной платы типа дискавери, можно заливать прошивку в контроллер через всеми любимый rs-232 (собственно - через преобразователь rs-232-3,3В). Для этого нужно использовать python-скрипт (Ivan A-R) (для LINUX или MACOSX).
Для начала у вас должен быть установлен Python 2.6 версии и библиотека для работы с последовательным портом - PySerial library.
Теперь, чтобы запустить скрипт stmloader.py (из терминала, разумеется) нужно его немного подправить под свой компьютер: откроем его в текстовом редакторе.
Набираем в командной строке
~$ dmesg | grep tty
чтобы увидеть все последовательные порты ПК.
и после набора...
~$ setserial -g /dev/ttyS
мы узнаем путь к нашему 232-му порту. Если система ругается на setserial, установим его
~$ sudo apt-get install setserial
мы узнаем путь к нашему физическому порту (например, у меня - /dev/ttyS0). Теперь нужно записать этот путь в файл скрипта stm32loader.py вместо дефолтного «/dev/tty.usbserial-...». Набираем в терминале
~$ python stm32loader.py -h
...для вызова справки и заливаем прошивку в наш контроллер.

2 способ:
Через USB OTG, используя DFU-режим, требует внешнего кварца на 8 МГц, 14.7456 МГц или 25 МГц (этот загрузчик есть не у всех контроллерах с USB OTG надо внимательно смотреть на маркировку вашего контроллера)

3 способ:
JTAG/SWD. Ну и для тех, кто имеет демоплату типа Discovery или самопальный JTAG/SWD программатор, можно заливать код и уже отлаживать свой микроконтроллер этим способом. Для JTAG в микроконтроллере отведено 6 лапок (TRST, TDI, TMS, TCK, TDO, RST) + 2 на питание. SWD использует 4 сигнала (SWDIO, SWCLK SWO, RESET) и 2 на питание.

PS. В среде EAGLE я набросал несколько схем-заготовок для 48-ми, 64-х и 100-ногих контроллеров (папка eagle), а stm32loader содержит скрипт stm32loader.py



Понравилась статья? Поделиться с друзьями: