Начинаем изучать Cortex-M на примере STM32, часть 2
Данная статья является продолжением цикла по программированию микроконтроллеров на базе ядра Cortex-M. Первую статью можно прочитать здесь:
Начинаем изучать Cortex-M на примере STM32
Задачей статей является подробное описание особенностей, возникающих при программировании МК. Материал не предназначен для желающих за 10 минут запустить пример мигания светодиодом. Я постараюсь подробно описать то, что часто скрывают от новичков, чтобы их не напугать.
Мне очень хочется, чтобы программисты использующие стандартные библиотеки, шаблоны, примеры и т.д. понимали как все это работает. А при отсутствии этих самых библиотек и примеров могли самостоятельно решить свою задачу.
Основное акцент сделан на изучение документации на ядро Cortex-M и документации на конкретный контроллер. На этот раз речь пойдет про прерывания, а так же будут затронуты некоторые вопросы архитектуры памяти и структуры прошивки МК.
Несколько сорв про документацию ARM
По не совсем ясным для меня причинам, нельзя зайти на сайт ARM и скачать полную документацию на ядро Cortex-M4. Да и на Cortex-M3 тоже нельзя. Придется почитать несколько документов.
1. Изучение придется начать с Cortex ™-M3 TechnicalReference Manual Revision: r1p1 — самой первой ревизии технической спецификации на ядро Cortex-M3
2. Во всех дальнейших ревизиях и описании Cortex ™-M4 TechnicalReference Manual описаны лишь общие данные и изменения относительно предыдущего документа.
Так что прошу не удивляться ссылкам на спецификации другого ядра.
Interrupt and Events
Прежде всего необходимо разобраться с тем, что такое прерывания.
В МК Cortex-M есть два понятия, которые часто путают Interrupt и Event.
Event — это событие (аппаратное или программное), на которое могут реагировать ядро или периферийные блоки. Одним из вариантов реакции может быть — прерывание.
Interrupt — это прерывание работы программы и переход управления в специализированный участок обработчик прерывания.
Взаимосвязь между Event и Interrupt заключается в следующем:
Каждый Interrupt вызывается Event, но не каждый Event вызывает Interrupt.
Помимо прерываний, события могут активировать и другие возможности МК.
NVIC
Управление и обработка прерываниями производится контроллером приоритетных векторных прерываний NVIC (Nested Vectored Interrupt Controller). Контроллер прерываний часть ядра Cortex-M. Документацию на этот контроллер необходимо начинать изучать с
При возникновении, некоторого события контроллер прерываний автоматически прерывает выполнение основной программы, и вызывает соответствующую функцию обработки прерываний. После выхода из функции обработчика прерываний программа продолжает выполнение с того места, где произошло прерывание. Все происходит автоматически (при правильной настройке NVIC, но об этом ниже).
Из самого названия видно, что контроллер NVIC поддерживает вложенность прерываний и приоритеты. Каждому прерыванию при настройке NVIC присваивается свой приоритет. Если во время обработки низкоприоритетного прерывания возникает высокоприоритетное, то оно, в свою очередь, прервет обработчик низкоприоритетного прерывания.
Как это работает?
Данный пост не претендует на абсолютную полноту, я советую изучить раздел прерываний в Cortex™-M3 Technical Reference Manual. Поскольку эта часть ядра не претерпела изменений, ее описание дано в первой ревизии r1p1 на ядро Cortex-M3.
Вход в прерывание и выход из него
При инициации прерывания NVIC переключает ядро в режим обработки прерывания. После перехода в режим обработки прерывания регистры ядра помещаются в стек. Непосредственно во время записи значения регистров в стек осуществляется выборка начального адреса функции обработки прерывания.
В стек перемещается регистр регистр статуса программы ( Program Status Register (PSR)), счетчик программы (Program Counter (PC)) и регистр связи (Link Register (LR) ). Описание регистров ядра приведено в Cortex-M4 Generic User Guide. Благодаря этому, запоминается состояние, в котором находилось ядро перед переходом в режим обработки прерываний.
Также сохраняются регистры R0 — R3 и R12. Эти регистры используются в инструкциях для передачи параметров, поэтому, помещение в стек делает возможным их использование в функции обработки прерывания, а R12 часто выступает в роли рабочего регистра программы.
По завершении обработки прерывания все действия выполнятся в обратном порядке: извлекается содержимое стека и, параллельно с этим, осуществляется выборка адреса возврата.
С момента инициации прерывания до выполнения первой команды обработчика прерывний проходит 12 тактов, такое же время необходимо для возобновления основной программы после завершения обработки прерывания.
Вложенность прерываний
Как было сказано выше NVIC поддерживает прерывания с различными приоритетами, которые могут прерывать друг друга. При этом, могут возникнуть различные ситуации, обработка которых по разному оптимизирована.
1. Приостановка низкоприоритетного прерывания В этой ситуации, обработка низкоприоритетного прерывания прекращается. Следующие 12 циклов выполняется сохранение в стек нового набора данных и запускается обработка высокоприоритетного прерывания. После его обработки, содержимое стека автоматически извлекается и возобновляется обработка низкоприоритетного прерывания.
Больших отличий от прерывания основной программы не наблюдается.
2. Непрерывная обработка прерываний Эта ситуация может возникнуть в двух случаях: если два прерывания имеют одинаковый приоритет и возникают одновременно, если низкоприоритетное прерывание возникает во время обработки высокоприоритетного.
В этом случае, промежуточные операции над стеком не производятся. Происходит только загрузка адреса обработчика низкоприоритетного прерывания и переход к его выполнению. Отказ от операций над стеком экономит 6 тактов. Переход к следующему прерыванию происходит не за 12 тактов, а всего за 6.
3. Запаздывание высокприоритетного прерывания
Ситуация возникает, если высокоприоритетное прерывание происходит во перехода к обработке низкоприоритетного (за те самые 12 тактов).
В этом случае переход к высокоприоритетному прерыванию будет происходить не менее 6 тактов с момента его возникновения (время необходимое для загрузки адреса обработчика прерывания и перехода к нему).
Возврат в низкоприоритетное уже описан выше.
Приоритеты прерываний
Помимо простой установки приоритета прерываний, NVIC реализует возможность группировки приоритетов.
Прерывания в группе с более высоким приоритетом могут прерывать обработчики прерываний группы с более низким приоритетом.
прерывания из одной группы, но с разным приоритетом внутри группы не могут прерывать друг друга. Приоритет внутри группы определяет только порядок вызова обработчика, когда были активизированы оба события.
Значение приоритета прерывания задается в регистрах Interrupt Priority Registers (см. Cortex-M4 Generic User Guide).
При этом, часть бит отвечает за приоритет группы, в которой находится прерывание, а часть — за приоритет внутри группы.
Настройка распределение бит на приоритет группы или приоритет внутри группы осуществляется с помощью регистра Application Interrupt and Reset Control Register (ВНИМАТЕЛЬНО!!! см. Cortex-M4 Generic User Guide).
Как вы, наверно, заметили, в Cortex-M4 Generic User Guide сказано, что настройка приоритетов и группировки приоритетов зависят от конкретной реализации implementation defined.
А вот дальше не очень приятная вещь. В Reference manual к МК STM32F407 про NVIC почти нет информации. Но есть ссылка на отдельный документ.
Для того, чтобы разобраться с реализацией NVIC в STM32 придется прочитать еще один документ — STM32F3xxx and STM32F4xxx Cortex-M4 programming manual. Вообще говоря, я советую внимательно изучить данный документ и по всем другим вопросам, в нем работа ядра расписана более подробно, чем в документации от ARM.
В нем, уже можно найти:
Из возможных 8 бит приоритета используются только 4. Но этого вполне достаточно для большинства задач.
Маскирование прерываний
Предположим, что у нас стоит задача запуска ракеты-носителя при нажатии на красную кнопку, но только при условии, что повернут ключ. Нет совершенно ни какого смысла генерировать прерывание на поворот ключа. А вот прерывание на нажатие красной копки нам понадобится. Для того, чтобы включать/выключать различные вектора прерываний, существует маскирование прерываний.
Маскирование прерывания осуществляется с помощью регистров Interrupt Set-enable Registers.
Если прерывание замаскировано, это не означает, что периферия не генерирует события! Просто NVIC не вызывает обработчик этого события.
Таблица векторов прерываний
Все возможные прерывания, поддерживаемые NVIC, записываются в таблицу векторов прерываний. По сути своей, таблица векторов прерываний есть ни что иное, как список адресов функций обработчиков прерываний. Номер в списке соответствует номеру прерывания.
Как написано в Cortex-M4 Generic User Guide, NVIC поддерживает до 240 различных векторов прерываний. Но реализация уже зависит от конкретного производителя.
В описании ядра стандартизованы только прерывания исключений ядра (см. раздел 2.3.2 Exception types в Cortex-M4 Generic User Guide):
- Reset
- NMI
- HardFault
- MemManage
- BusFault
- UsageFault
- SVCall
- PendSV
- SysTick
С описанием этих исключений я предлагаю вам ознакомиться самостоятельно. Некоторые из них будут затронуты в следующих статьях.
Остальные прерывания уникальны для МК. Описание таблицы векторов вашего МК вы можете найти в соответствующем Reference manual (см. Vector table for STM32F405xx/07xx and STM32F415xx/17xx).
Контроллеры STM32F4xx поддерживают 81 вектор прерываний. Можно заметить, что в этой таблице перечислены все периферийные блоки (а некоторые не единожды).
Практически все периферийные блоки генерируют прерывания, чтобы ядро отвлекалось на работку с ним только по наступлению какого-либо значимого события (например, получении данных по UART).
Расположение векторов прерываний и загрузка МК
Разобравшись с принципами работы прерываний в Cortex-M осталось понять только где хранится таблица прерываний. Для этого стоит рассмотреть процесс загрузки и структуру прошивки контроллера. На этот раз мы будем рассматривать только загрузку из встроенной флеш памяти.
В таблице векторов, находящейся в начале адресного пространства флеш памяти должны находиться по крайней мере (см. Cortex-M3 Technical Reference Manual:
Из начала флеш памяти ядро считывает значение SP (stack top addres) и PC (reset routine location). Таким образом, автоматически начинает выполняться функция, с адресом считанным в регистр PC. Это может быть, например main.
После обязательных четырех компонентов, может находиться дальнейшая таблица векторов прерываний. Главное сохранить порядок.
При желании, можно разместить таблицу векторов прерываний в другой области памяти, но тогда, необходимо сообщить NVIC, куда мы передвинули таблицу. За это смещение таблицы векторов отвечает регистр Vector Table Offset Register (см.
Cortex-M4 Technical Reference Manual. Это может понадобиться для написание встроенного загрузчика нового ПО (bootloader), но об этом как-нибудь в другой раз.
От теории к практике
Тз второго проекта
Пример создается для отладочной платы STM32F4Discovery. При нажатии на кнопку должен загореться светодиод LED3. При замыкании контактов PC6 и GND загорается светодиод LED5.
В процессе программирования поиграемся с приоритетами прерываний и посмотрим к чему это приведет.
Железная часть
Найдем в документации к плате кнопку и светодиод:
При ненажатой кнопке на пине PA0 будет логический ноль, при нажатии на кнопку на кнопке появится логическая 1 (3.3В). Светодиод LED3 подключен к пину PD13. Светодиод LED5 подключен к пину PD14.
Интересней всего с контактом PC6 — он напрямую выведен на штыревой разъем. Нам будет необходимо обеспечить регистрацию логической 1, когда он не закорочен с контактом GND. О том, как это сделать пойдет речь ниже.
Настройка GPIO
Для нашей задачи необходимо настроить пины PD13 и PD14 как выходные. О том, как это делать можно прочитать в предыдущей статье. С настройкой пина PA0 тоже все достаточно просто — его нужно настроить на вход.
Не смотря на то, что после ресчета МК почти все пины настроены на вход, крайне желательно явно прописать эту инициализацию. С пином PC7 все несколько интереснее. Поскольку он «висит в воздухе», его состояние не определено. Нам же необходимо, чтобы при этом его состояние всегда было «1».
Для этого, в блоке GPIO активировать подтяжку. В нашем случае, необходима подтяжка к питанию — PULL UP.
Активация подтяжки осуществляется с помощью регистра GPIO port pull-up/pull-down register.
Прерывания EXTI
Для выполнения нашего «ТЗ» с использованием прерываний, нам необходимо настроить прерывания, которые будут срабатывать при переходе контакта PA0 из состояния «0» в состояние «1», и прерывание при переходе контакта PC6 из состояния «1» в состояние «0».
В МК STM32F4xx для этой цели служит контроллер внешних прерываний/событий — EXTI (External interrupt/event controller). Я настоятельно рекомендую ознакомиться с его функционалом в Reference manual. Нам необходимо поступить в соответствии с описанным:
Нам понадобятся 0 и 6 линии EXTI. Для размаскирования соответствующих линий прерываний необходимо записать в регистр EXTI_IMR значение 0x9.
Для линии PA0, необходима генерация события прерывания по переходу из состояния «0» в состояние «1» — по возрастающему фронту. То есть, необходимо записать 1 в нулевой бит регистра EXTI_RTSR.
Для линии PC6, наоборот, необходима генерация события прерывания по переходу из состояния «1» в состояние «0» — по падающему фронту. То есть, необходимо записать 1 в шестой бит регистра EXTI_FTSR.
На этом настройка блока EXTI закончена. Последний пункт будет реализован при настойке NVIC.
По мимо этого, необходимо определиться, пин с какого порта подключается к определенной линии EXTI. Делается это с помощью регистров SYSCFG external interrupt configuration register (Reference manual). Эти регистры находятся в System configuration controller, что мне кажется не очень логичным (почему было не включить эту насторойку в EXTI?), но оставим сей факт на совести ST.
Настройка NVIC
Активация обработки определенного вектора прерывания осуществляется с помощью регистров Interrupt set-enable registers (NVIC_ISERx). Описание регистров приведено в Cortex-M4 Generic User Guide.
Сама таблицу векторов прерываний для нашего МК приведена в Reference manual (см. Table 61).
Из таблицы можно увидеть, что для 0 линии есть отдельное прерывание, а вот линии с 5 по 9 генерируют одно прерывание на всех.
Кроме того, из таблицы мы узнали номера векторов, необходимых нам прерываний. Теперь нужно записать «1» в 6 бит (активация прерываний линии 0 EXTI) регистра NVIC_ISER0 (адрес 0xE000E100) и в 23 бит того же регистра (активация прерываний линий 5-9).
Настройка приоритетов
Для того, чтобы можно было побаловаться с приоритетами прерываний настроим группы приоритетов так, чтобы 2 бита отвечали за приоритет внутри группы, и 2 бита — за приоритет самой группы. Для этого необходимо записать значение 0х05FA0500 в регистр Application interrupt and reset control register (STM32F3xxx and STM32F4xxx Cortex-M4 programming manual).
Настройка приоритетов осуществляется с помощью регистров Interrupt Priority Registers (STM32F3xxx and STM32F4xxx Cortex-M4 programming manual). Нас будут интересовать регистры Interrupt Priority Register 2 (0xE000E4008) и регистр Interrupt Priority Register 5(0xE000E401C).
Пока не будем изменять приоритеты. Пусть будут одинаковы для обоих прерываний.
Обработка прерываний
Функции обработчики прерываний — ни что иное, как просто функции языка C, который ни чего не получают и не возвращают (и правильно — не от кого и не кому).
Главное правило — обработка прерываний должна осуществляться как можно быстрее!!! Иначе низкоприоритетные прерывания могут слишком долго ждать.
После окончания обработки прерывания необходимо сбросить активность события, вызвавшего прерывание — «очистить прерывание». Очистка прерывания EXTI производится с помощью регистра EXTI_PR . Обратите внимание: запись «1» очищает прерывание, запись «0» не имеет ни какого воздействия.
Если с обработкой прерывания линии 0 EXTI все достаточно просто, то с группой линий 5-9 возникает вопрос — как определить какая линия вызвала прерывание. Узнать это можно проверкой бит регистра Pending register (EXTI_PR) — Reference manual.
Создаем таблицу векторов и располагаем ее в правильном месте
Для тог, чтобы таблица векторов с правильными адресами функций обработчиков прерываний располагались в начале флеш памяти МК, создадим и подключим к проекту файл startup.c.
Содержимое файла
Источник: http://savepearlharbor.com/?p=218825
Записки программиста
Ранее мы познакомились с несколькими отладочными платами на базе микроконтроллеров STM32 — это Blue Pill, платами серии Nucleo, и даже такой экзотикой, как Кракен.
Все это здорово, но что, если нам захочется использовать микроконтроллер не в прототипе, а в полноценном готовом устройстве? Не вкорячивать же в него плату Nucleo! Поэтому сегодня мы разберемся, как работать с STM32 напрямую, то есть, прямо на макетной плате, на примере микроконтроллера STM32F103C8T6.
Казалось бы, тема эта несложная, однако есть пара подводных граблей, про которые стоит знать.<\p>
Fun fact! Аналогичную инструкцию для микроконтроллеров AVR вы найдете в посте Как собрать Arduino прямо на макетной плате.
Примечание: Пользуясь случаем, я хотел бы поблагодарить пользователей форума easyelectronics.ru за то, что помогли мне разобраться с парой проблем, возникших при изучении сего вопроса. Особой благодарности заслуживают пользователи dosikus_2 и BusMaster, так как они раньше других предложили верные решения.
Итак, первая сложность заключается в том, что микроконтроллеры STM32 не бывают в DIP-корпусах, а значит понадобится переходник. STM32F103C8T6 имеет корпус LQFP-48, для которого готового переходника у меня не было.
Такой переходник можно вытравить самому, можно поискать на eBay. Я прикинул, что в будущем мне понадобится больше одного переходника. А еще я могу захотеть подарить парочку из них, так как многие мои коллеги занимаются электроникой в качестве хобби.
Плюс мне не хотелось долго ждать доставки. Поэтому я спроектировал собственный переходник в KiCad и заказал десяток плат на Резоните. Также для вашего удобства я залил плату на OSH Park.
Следует однако учесть, что в пересчете на одну плату цены у OSH Park существенно выше, чем у Резонита, и доставка обычно занимает несколько недель против трех дней.
Допустим, переходник у нас уже есть. Далее открываем даташит [PDF] и смотрим распиновку микроконтроллера (стр 16):
Наиболее интересные нам сейчас пины я выделил цветом. Подключаем их таким образом:
- Пины VSS* (8, 23, 35 и 47) идут к земле;
- Пины VDD* (9, 24, 36 и 48) — к 3.3 В;
- NRST (7) оставляем висеть неподключенным, но готовим перемычку для подключения его к земле в случае необходимости. Если места на макетке хватает, вместо перемычки можно использовать кнопку с конденсатором для защиты от дребезга. При этом подтягивающий резистор к плюсу не требуется, так как такой резистор уже есть в самом микроконтроллере;
- BOOT0 (44) определяет, откуда микроконтроллер будет загружать прошивку. Нам нужно, чтобы он делал это из flash-памяти, поэтому подключаем к земле. При этом напряжение на пине BOOT1 (20) не имеет значения, и этот пин может использоваться для обычного GPIO;
- SWIO и SWCLK (34 и 37) — к соответствующим пинам программатора;
- Наконец, пин PC13 (2) у нас будет мигать светодиодом;
Важно! Между каждой парой соседних пинов VSS и VDD втыкаем по конденсатору на 100 нФ, и желательно — как можно ближе к пинам микроконтроллера. Без этого микроконтроллер в лучшем случае не будет прошиваться (я проверял). Некоторые же источники утверждают, что без конденсаторов его можно даже сжечь в момент подачи питания.
В итоге должно получиться примерно следующее:
Теперь можно приступать и к генерации проекта в STM32CubeMX. Только обязательно проверьте, чтобы SWD был включен:
Если забыть включить SWD и прошить микроконтроллер, прошить его во второй раз будет затруднительно. У меня по умолчанию SWD был выключен. В интернете пишут, что это считается багом в STM32CubeMX, который что-то никак не починят. При этом проявляется баг только для микроконтроллеров определенных серий.
Спрашивается, а что делать, если мы случайно прошили микроконтроллер прошивкой, которая отключает SWD? В этой ситуации выполняем следующие шаги. (1) Пин NRST подключаем к земле, или, если вместо перемычки вы использовали кнопку, нажимаем и держим кнопку. (2) Говорим st-info –probe. Должны увидеть что-то вроде:
Found 1 stlink programmers serial: 543f73066775545512251267 openocd: “x54x3fx73x06x67x75x54x55x12x25x12x67” flash: 0 (pagesize: 1024) sram: 20480 chipid: 0x0410
descr: F1 Medium-density device
Заметьте, что программатор видит 0 байт flash-памяти. На этом шаге это нормально. (3) Выдергиваем перемычку между NRST и землей, или отпускаем кнопку. Несмотря на то, что ранее в микроконтроллер была залита какая-то прошивка, сейчас она не будет запущена. Если же повторить команду st-info –probe, окажется, что программатор видит всю flash-память:
flash: 65536 (pagesize: 1024)
После этого можно спокойно говорить make erase или make flash, а значит и включить SWD, как это было описано выше.
Фактически, мы получили собственную минимальную отладочную плату, собранную на макетке. За исключением описанных выше моментов, работа с ней ничем не отличается от работы с той же Blue Pill. Правим код, компилируем, прошиваем, при необходимости повторяем — все работает, как часы. Цель достигнута!
Эта заметка, разумеется, не претендует на то, чтобы полностью заменить собой даташит. В частности, за кадром осталось подключение внешних кварцевых резонаторов (LSE и HSE) и другие вопросы. Но в них, думаю, вы без труда разберетесь и самостоятельно.
Исходники к этому посту я выложил на GitHub. В репозитории вы найдете как простенькую прошивку для микроконтроллера, так и KiCad-проект адаптера для LQFP-48 вместе с готовыми Gerber-файлами.
Как обычно, если у вас есть вопросы, дополнения, возражения, и так далее — не стесняйтесь оставлять комментарии!
Дополнение: Как и зачем я делал очередную отладочную плату
Источник: https://eax.me/stm32-on-breadboard/
Знакомство с ARM Cortex-M3 и с STM32, в частности
Пожалуй, большинство эмбеддерщиков и просто интересующихся встроенными системами уже слышали про процессоры . Их устанавливают в промышленное оборудование, в смартфоны и аудио-плееры, в видеотехнику, да много ещё куда.
Популярность ARM во многом обеспечена их хорошей производительностью при низком энергопотреблении, что делает их идеальными для применения в различных мобильных устройствах. ARM расшифровывается как Advanced RISC Machines. — это архитектура процессоров с “сокращённым” набором команд, ныне одна из наиболее распространённых.
Между прочим, микроконтроллеры AVR, используемые в Arduino, имеют архитектуру RISC.
Существует современное семейство ARM под названием Cortex, которое делится на три подсемейства:
- Cortex-AЭто полноценные процессоры общего назначения для самых различных задач. Самое известное устройство на базе их — это iPhone.
- Cortex-RПредназначены для систем реального времени, где существует необходимость в быстрой и точной реакции на внешние события с гарантированным временем отклика — для применений в промышленности, медицине, автомобилестроении и пр.
- Cortex-MМикроконтроллеры, уже известная нам по AVR область. Как обычно, это не очень быстрый процессор, но со встроенной памятью для программ (flash), оперативной памятью (SRAM) и различной периферией — такой, как GPIO (порты ввода-вывода), UART, SPI, I2C и т.д.
Эта статья, как и последующие в цикле (да, это будет цикл статей), сконцентрируется на самом популярном виде Cortex-M в наши дни — Cortex-M3. Микроконтроллеры этого семейства выпускают несколько компаний — например, ST Microelectronics, NXP, Atmel, Texas Instruments. Надо сказать, что с ARM вообще и Cortex-M3, в частности, ситуация с производством отличается от привычной: компания ARM Limited занимается только разработкой архитектуры и средств разработки (компиляторов и IDE), но сама процессоры не производит, а продаёт лицензии другим компаниям — вышеперечисленным, например. При этом гарантируется совместимость кода на уровне инструкций процессора — это значит, что можно разрабатывать ПО под процессоры различных производителей, пользуясь одним и тем же компилятором.
Чем же Cortex-M3 круче других микроконтроллеров? Много чем:
- Полностью 32-битная архитектура: все регистры 32-битные, арифметические операции работают с 32-битными данными; умножение 32 x 32 -> 32 выполняется за 1 такт, деление — за 2-12 тактов. Благодаря этому CM3 за то же время успевает сделать больше, чем 8-ми и 16-битные МК.
- Большое количество (от 16) регистров общего назначения, характерное для архитектуры RISC. Так как регистры работают на частоте процессора, а RAM — на меньшей, всегда предпочтительнее работать с данными в регистрах, а чем их больше, тем дольше можно обходиться без использования RAM. Тут соперничать c CM3 могут разве что AVR.
- Отличная поддержка режимов энергосбережения. Можно отправить в спячку как весь МК, так и отдельные его подсистемы.
- 24-битный таймер SysTickЭтот таймер без ШИМ (PWM), зато 24-битный: можно задавать интервал срабатывания в широких пределах, не особо парясь. Самое то для организации конечных автоматов и планировщика RTOS.
- Полноценная отладка по JTAG или SWD даже на младших кристаллах. Полноценная — значит, можно ставить точки останова (breakpoints), просматривать содержимое переменных и регистров, выполнять программу пошагово и т.п.
- NVIC — Nested Vectored Interrupt ControllerКонтроллер прерываний, который поддерживает до 240 прерываний на все случаи жизни, до 256 их приоритетов, и обеспечивает быструю реакцию на прерывания.
- Контроллера DMA — Direct Memory AccessОчень полезная вещь — позволяет периферии (UART, SPI, I2C и пр.) читать/писать дынные в RAM без участия МК. То есть, можно дать задание контроллеру DMA считать в указанный буфер 100 байт по SPI, и эта задача будет выполняться в фоне, не загружая МК.
- Высокая плотность кода. Для большинство более-менее сложных проектов размер кода будет меньше, чем для многих других МК. Это достигается за счёт специально разработанного для этих целей набора инструкций . Меньше размер кода — больше кода влезет в МК.
- Общая ориентированность набора инструкций на компиляторы C — например, наличие команд для табличных переходов (для swicth/case), битовых манипуляций (PORTA |= (1 память, память->периферия, периферия>память и периферия>периферия.
- Несколько 16-битных таймеров с произвольными делителями (не только степени двойки, как в AVR), которые умеют генерировать прерывания по переполнению, по сравнению, генерировать ШИМ, измерять длину и число входящих импульсов, запускать ЦАП, и даже автоматически считать импульсы с энкодеров и датчиков Холла!
- NVIC, помимо всего прочего, поддерживает до 20 прерываний от внешних источников.
- Модуль RTC (Real-Time Clock) — часы реального времени с счётчиком и будильником.
- Несколько Watchdog-таймеров для пущей надёжности.
- FSMC — Flexible Static Memory ControllerОбеспечивает прозрачный доступ к нескольким видам памяти — SRAM, ROM, NOR Flash, NAND Flash, PSRAM и 16-битным PC Card-совместимым устройствам.
- SDIO — Secure Digital I/O interfaceДелает львиную долю работы по чтению/записи на карты памяти MMC и SD, что даёт возможность легко и просто прикрутить поддержку FAT и полноценно работать с файлами на карточках.
- USBПолная поддержка стантарта USB 2.0 Full-speed, до 8 эндпоинтов.
- USB OTG (On-The-Go)Эта технология позволяет связывать USB-устройства с её пооддержкой без участия хоста — например, цифровую камеру с принтером.
- Ethernet, MAC-уровеньАга, можно связываться с компом по локальной сети. С внешней PHY-микросхемой может выжимать 10/100 Мбит/с.
- Шина I2S — шина цифровой связи аудио-устройств.
- Ну, и стантдартный набор: UART, SPI, I2C, CAN.
Во-вторых, у STM32 очень хорошая структурированная документация:
- Один Reference manual с описанием всей периферии на всю линейку STM32F10x
- Подробная документация по каждой отдельной серии МК — распиновка, корпуса, наименование и т.п.
- Приличное количество аппноутов (Application Notes) — рекомендаций по применению: правильный подбор источника тактирования, питания, примеры работы с LCD, SD-картами, RTC и многое другое.
В-третьих, совместимость — и по расположению ног на кристалле, и по коду. То есть, если не хватает производительности, Flash, RAM или периферии, то можно без модификации кода и без переделки платы просто поставить на плату МК пожирнее с тем же количеством ног.
В-четвёртых, цена. Самый младший камень из серии — STM32F100C4T6B — можно купить за 1-2 $, при этом он имеет 48 ног, 16 КБ Flash, 4 КБ SRAM и может работать на частоте 24 МГц, ну и UARTы и прочие интерфейсы в наличии.
То есть, он круче, чем стандартный для Arduino контроллер ATmega168. Конечно, 48 ног — это не DIP-корпус, а TQFP: в макетку или в панельку его не воткнёшь, нужно плату разводить.
Но технология изготовления печатных плат в домашних условиях уже расписана вдоль и поперёк, так что не такая уж это и проблема.
Ну, и наконец, платы вроде Arduino для быстрого освоения у ST тоже имеются, и начнём мы изучать STM32 с одной из них — :
Так что, если кто не силён в пайке, расслабьтесь. В этой плате есть встроенный отладчик ST-Link, так что вы сможете вкусить всю прелесть полноценной отладки, для которой к AVR пришлось бы докупать AVRDragon за 70$.
В общем, STM32 — это выбор редакции, однозначно. Теперь о цикле статей. Если коротко, то цель цикла — описать STM32F10x вдоль и поперёк. А, если длинно, мы с вами:
- Изучим всю периферию линейки со всеми режимами работы.
- Познаем всю прелесть и сложность работы с прерываниями.
- Научимся разным полезным программерским трюкам и приёмам.
- Подтянем свои знания языка C.
- Научимся комбинировать полученные знания и к концу курса сделаем хотя бы одно относительно сложное устройство (уровня MP3-плеера).
Кто хочет прокачаться в программировании МК, у кого есть стальные яйца воля к победе, кто не боится трудностей — ждите продолжение, оно скоро будет. Заряжайте свои мечи, падаваны (:
Источник: http://robocraft.ru/blog/ARM/644.html
Микроконтроллеры Cortex-M0/M3/M4
Микроконтроллеры Cortex-M стали сегодня одними из самых популярных процессоров, применяемых при разработке и изготовлении электронной техники. Высокая вычислительная мощность, широкий набор периферии и низкая стоимость делают эти устройства привлекательными для самого широкого круга разработчиков.
При этом каждый желающий может выбрать наиболее подходящий вариант для решения конкретной задачи. Производители предлагают огромное количество разнообразных микросхем, общим для которых остается только процессорное ядро. На сегодняшний день распространение получили 3 варианта ядер: Cortex-M0, Cortex-M3, Cortex-M4.
Отличия этих моделей не всегда явно прослеживаются, поэтому данная статья делает попытку разобраться в особенностях этих вариантов.
Микроконтроллеры Cortex-M представляют собой одно из направлений развития микропроцессорных ядер, предлагаемых фирмой ARM. Фактически, под общей торговой маркой Cortex можно увидеть три типа процессоров (профилей), обозначаемых буквами A, R, M. Задачей профиля A стало достижение большой вычислительной мощности.
Изделия с этой маркировкой – Cortex-A, представляют собой классические микропроцессоры, являющиеся дальнейшей эволюцией разработок ARM. Профиль R нацелен на использование во встраиваемых системах, поэтому эти процессоры модернизированы для исполнения задач в реальном времени.
Основной задачей профиля M заявлена простота и низкая стоимость. Технически Cortex-M представляют сильно упрощенные варианты старших моделей. Тем не менее, даже такие «урезанные» контроллеры обладают вычислительной мощностью, значительно превышающей многие аналоги.
Также отличием от «больших» ARM стала поддержка битовых операций, необходимая в микроконтроллерах для работы с периферией.
Cortex-M0
Микроконтроллеры, использующие ядро Cortex-M0, позиционируются производителями в качестве замены 8-ми разрядных моделей. Их отличительной особенностью стала предельно низкая стоимость и малое энергопотребление, при сохранении многих возможностей архитектуры ARM.
По своей структуре ядро Cortex-M0 – это конфигурируемый мультистадийный 32-разрядный RISC процессор. В его основе лежит архитектура ARMv6-M. Основное отличие от классической «большой» ARMv6 заключается в использовании только набора 16-разрядных инструкций, под общим названием Thumb.
Дополнительно поддерживаются некоторые команды более нового набора Thumb2. Такое решение, при незначительном падении вычислительной мощности, максимально упростило процессор относительно старших моделей и позволило использовать дешевую 16-ти разрядную память.
Благодаря использованию современных технологий проектирования, количество транзисторов, из которых построено данное ядро, составляет примерно 12 тысяч. Такое количество обеспечило низкое энергопотребление и невысокую стоимость. Для сравнения процессор i8086 имел 32 тысячи транзисторов при намного меньших возможностях.
Энергопотребление процессора M0, в зависимости от исполнения и решаемых задач, колеблется от 73 до 4мкВт/МГц.
Быстродействие ядра Cortex-M0 составляет 0.84 DMIPS / МГц. Это значит, что на максимальной частоте работы ядра в 50Мгц, достигается производительность 45 DMIPS. Данное значение превышает возможности 8-ми разрядных систем в несколько десятков раз, и на порядок выше, чем у 16-разрядных моделей.
Разработчики, в архитектуре Cortex, попытались получить законченное процессорное ядро. Поэтому в его состав включены: контроллер прерываний на 32 вектора, интерфейс для периферийных устройств в виде 32-разрядной шиной ASB-Lite, отладчик. При необходимости процессор может оснащаться контроллером «спящего» режима.
Процессорное ядро Cortex-M3
Процессорное ядро Cortex-M3 стало наиболее популярным вариантом архитектуры ARM у производителей и разработчиков микроконтроллеров. Структурно, это также мультистадийный RISC процессор. Но в отличие от M0, данное ядро основано на архитектуре ARMv7-M и полностью реализует наборы команд Thumb и Thumb2.
Из особенностей следует упомянуть аппаратное умножение 32-разрядных чисел за 1 цикл, а также деление чисел подобной разрядности (от 2 до 12 циклов). Производительность процессора составляет 1.25DMIPS/МГц. Энергопотребление примерно в два раза выше, чем у варианта M0. Количество физических прерываний увеличено до 240.
В ядре предусмотрен механизм защиты памяти.
Cortex-M3, в отличие от классической ARMv7, выполнен по Гарвардской архитектуре и поддерживает несколько периферийных шин. Следует отметить, что ARMv7 является основой только процессоров под обозначением Cortex и имеет мало общего с некогда сверхпопулярной ARM7 и ее вариантами. Хотя именно с ARM7 часто сравнивают возможности Cortex-M3.
Cortex-M4
Вариант микроконтроллерного ядра Cortex-M4, по сравнению с Cortex-M3, не характеризуется ростом общих показателей. Фактически M4 тот же самый M3, но дополнительно оснащенный DSP-инструкциями. Наличие последних существенно ускоряет обработку потоковых данных, что в свою очередь делает M4 весьма привлекательным для использования в системах управления и обработки информации.
Возможности DSP, входящего в состав M4, позволяют параллельно выполнять четыре операции сложения/вычитания для 8-ми разрядных чисел или две операции сложения/вычитания с16-ти разрядными операндами. Также реализовано умножение за один цикл, при этом для 16-ти разрядных чисел возможно параллельное исполнение двух операций.
В серии M4 есть еще один вариант, под обозначением Cortex-M4F. В нем, дополнительно к DSP, установлен блок операций для чисел с плавающей точкой – FPU.
Кроме вышеназванных, существуют и другие варианты процессоров. Большинство из них представляют модернизированные варианты основных ядер.
Несколько особняком стоит малоизвестный Cortex-M1, предназначенный для использования в программируемых логических матрицах.
Основные характеристики этого процессора практически совпадают с вариантом M0, но при этом он реализован только в виде программной модели.
В отличие от профиля А, Cortex-M развивается не столь бурно. Когда и какими будут будущие микроконтроллеры неизвестно. Можно только предположить, что развитие пойдет по пути «больших» систем и в скором времени привычными станут двух-, трех или четырехядерные контроллеры.
You have no rights to post comments
Источник: https://mcucpu.ru/index.php/ucontrollers/mcu/113-mikrokontrollery-
STM32-VLDiscovery: мой вариант быстрого старта
Внимание, статья обновлена. См. примечание в конце. ***
Предисловие.
Некоторое время назад, я, как и многие другие, принял участие в акции EBV, заказав себе упомянутую в названии платку. Моя первая попытка поковырять ее не увенчалась успехом, да и буквально одновременно с ней мне в руки попал LaunchPad… Одним словом, лежал STM32-Discovery буквально до сегодняшнего дня и пылился.
Но в конце концов я взялся за него с твердым намерением наконец-то помигать светодиодом во что бы то ни стало. Естесственно, прежде всего я стал читать уже написанное на русском и английском.
Однако, несмотря на большое количество статей, все они показались мне слишком разрозненными, а некоторые из более цельных — излишне объемными для начала. Возможно, я плохо искал, но так нигде и не нашел текста, прямо и без тучи лишней информации повествующего о том, как с нуля помигать светодиодом на STM32-Discovery.
Полезные части встречались в разных местах, и вот я решил объединить их в по возможности лаконичное и законченное повествование.
Создание и настройка проекта.
Итак, что мы имеем: микроконтроллер STM32F100RB, установленный на плате с отладчиком; два светодиода, подключенных к PC8 (синий) и PC9 (зеленый). В качестве инструмента для написания кода я выбрал IAR.
Задача: помигать ими, попутно разобравшись, как настроить проект в IAR, что такое CMSIS и как в этих условиях организуется доступ к периферии. Итак, наченем. Быстро и в картинках.
Запускаем IAR:Создаем новый проект:Просим IAR самостоятельно написать шаблон для main() и сохраняем:
И теперь начинается самое интересное – надо настроить опции проекта, чтобы у оного был шанс заработать.
Если для AVR настройки проекта трогать почти не приходилось, для MSP430 дело ограничивалось небольшим вмешательством, то здесь все будет более глобально.Первое, что нужно сделать – указать тип используемого контроллера. Как уже говорилось, в STM32-Discovery стоит STM32F100RB.
Далее надо поправить настройки линковщика. В них надо указать начало таблицы векторов прерываний, а также начало и конец областей памяти программы (ROM) и оперативной памяти (RAM). Рассчитываются они следующим образом: в STM32F100RB 128Kb памяти кода и 8Kb оперативной памяти.
Начало у этих областей фиксировано на всей линейке – 0x08000000 (INTVEC) 0x08000000 (ROM) и 0x20000000 (RAM). Нам надо посчитать конечные адреса областей. Очевидно, что они получаются по следующей формуле:
[начало области] + ([размер области в килобайтах] * 1024) — 1.
Для STM32F100RB соответственно:
ROM: 0x08000000 + (0x80 * 0x400) — 1 = 0x0801FFFF
RAM: 0x20000000 + (0x8 * 0x400) — 1 = 0x20001FFF
Стек и кучу пока трогать не будем. Действуем: ставим галку Override default, жмем Edit…Вводим значения:
Жмем Save, сохраняем конфиг:С линковщиком все. Теперь надо настроить отладчик, чтобы при попытке запуска программы IAR подключался к ST-LINK на плате Discovery.
Выбираем отладчиком ST-LINK:Для корректной работы на следующей вкладке ставим галку Use flash loader:И далее указываем режим SWD:Все. Проект настроен, жмем OK. Теперь надо подключить CMSIS.
Что такое CMSIS, и вообще для чего она нужна? Каждый, кто уже писал под какой-нибудь МК, знает, что, прежде чем писать код, очень полезно подключить специальный заголовочный файл, в котором описаны имена регистров, модулей, констант и прочие обозначения, используемые в документации – без всего этого написание кода отдает мазохизмом. Естесственно, тут надо сделать то же самое. Только вместо одного файла надо добавить в проект шесть. Вот эти шесть файлов и есть CMSIS. Почему так много? Дело в том, что многие вещи, которые для, например, MSP430 компилятор генерирует сам – стартовый код, таблица прерываний, и т.п. здесь нужно писать руками. А этого делать, разумеется, неохота. Вот все это и входит в CMSIS.
Где добыть CMSIS? Для этого качаем STM32VLDISCOVERY firmware package – там все есть. Распаковываем, находим в stm32vldiscovery_packageLibraries папку CMSIS – это оно. Еще там есть папка STM32F10x_StdPeriph_Driver – этого добра нам не надо. В этой папке лежит т.н. стандартный драйвер периферии, представляющий собой набор функций для тех, кому лень читать даташит. Нас же, повторюсь, интересует исключительно CMSIS. Итак, нам нужны следующие файлы:
stm32vldiscovery_packageLibrariesCMSISCM3CoreSupportcore_cm3.c stm32vldiscovery_packageLibrariesCMSISCM3CoreSupportcore_cm3.h tm32vldiscovery_packageLibrariesCMSISCM3DeviceSupportSTSTM32F10xsystem_stm32f10x.c
tm32vldiscovery_packageLibrariesCMSISCM3DeviceSupportSTSTM32F10xsystem_stm32f10x.h
— собственно, сама CMSIS
tm32vldiscovery_packageLibrariesCMSISCM3DeviceSupportSTSTM32F10xstm32f10x.h
— заголовочный файл с определениями констант, битовых масок и т.п.
stm32vldiscovery_packageLibrariesCMSISCM3DeviceSupportSTSTM32F10xstartupiarstartup_stm32f10x_md_vl.s
— код начальной инициализации микроконтроллера. На будущее отмечу, что файл system_stm32f10x.c содержит функцию SystemInit(), которая вызывается до main() и проводит первичную настройку. Изначально там содержится код настройки системы тактирования. Пока необходимости что-либо менять там нет. Все перечисленные файлы кидаем в директорию проекта и добавляем в него:
Эстеты могут разложить их все по красивым папочкам, это дела не меняет.
Теперь последний шаг – небольшое допиливание CMSIS напильником. В начале файла stm32f10x.h надо раскомментировать дефайн, соответствующий используемому контроллеру. Для нас это #define STM32F10X_MD_VL, ибо STM32F100RB отностися к Medium density Value Line devices. Но не только раскомментировать нужный дефайн, но и закомментировать ненужный — #define STM32F10X_XL !
Все! Теперь действительно можно писать код!
Первая программа.
Для начала я предлагаю написать простую программу, которая будет перемигиваться синим и зеленым светодиодами. Для этого из конфигурационных действий нам надо выполнить только одно – настроить порт. Блоки периферии в STM32 имеют количество конфигурационных регистров, поражающее воображение человека, пришедшего с не настолько продвинутых платформ. Порты также не являют собой исключения, но в данный момент нам понадобятся только следующие регистры: GPIOC_CRH, (настройка на ввод-вывод, настройка скорости работы), GPIOC_ODR (собственно, сам выходной регистр порта) и RCC_APB2ENR. Вообще говоря, RCC_APB2ENR не относится к регистрам порта – это регистр системы тактирования. Но у периферии STM32 есть одна особенность – она не заработает (!), пока для нее не будет явно включено тактирование. В упомянутом же регистре расположен бит, отвечающий за порт C. Несколько слов о доступе к регистрам, он организован несколько необычно. Блоки периферии здесь представлены в виде структур, полями которых как раз и являются регистры. Как по мне, решение чрезвычайно необычное, но, по крайней мере, не вызывающее особого дискомфорта, и, в каком-то смысле, даже логичное. Итак, собственно программа (подробности относительно записываемых значений можно найти в даташите):#include “stm32f10x.h” void main(void) { unsigned long d; //Enabling clock for GPIOC RCC->APB2ENR|=RCC_APB2ENR_IOPCEN; //Configuring GPIO8 and GPIO9 as push-pull output //refer to datasheet for details GPIOC->CRH&=~(GPIO_CRH_CNF8_0 | GPIO_CRH_CNF9_0); GPIOC->CRH|=(GPIO_CRH_MODE8_1 | GPIO_CRH_MODE9_1); while (1) { //switching the LEDs if (GPIOC->ODR & GPIO_ODR_ODR8) { GPIOC->ODR&=~GPIO_ODR_ODR8; GPIOC->ODR|=GPIO_ODR_ODR9; } else { GPIOC->ODR|=GPIO_ODR_ODR8; GPIOC->ODR&=~GPIO_ODR_ODR9; } //simple delay for (d=0; d
Источник: http://we.easyelectronics.ru/blog/STM32/469.html