Cube ide как прошить

Обновлено: 06.07.2024

В последнее время все чаще сталкиваюсь с холиварами на тему Cube MX и HAL, применительно к контроллерам STM32.

С одной стороны — стоят защитники, которым нравится удобство конфигурирования и читаемость кода.

С другой — приверженцы писать все руками, которым важна скорость работы и бережное использование ресурсов.

Для того, чтобы расставить все точки над i — попробуем написать «Hello world» тремя наиболее часто используемыми путями CMSIS, LL, HAL. Оценим затраты (ресурсы контроллера, объем исполняемого файла, и конечно же время работы разработчика).

Статья будет состоять из нескольких частей:

STM32 fast start. Часть 1 ПО, материалы, Cube MX.
STM32 fast start. Часть 2 Hello World на HAL, настройка отладки в Atollic TrueSTUDIO
STM32 fast start. Часть 3 Hello World на LL
STM32 fast start. Часть 4 Hello World на CMSIS
STM32 fast start. Часть 5 Подведение итогов, сравнение HAL, LL, CMSIS.

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

Идеальным вариантом будет бюджетная плата на STM32F103C8T6 микроконтроллере.

image

Данную плату можно найти на всем известном сайте по цене от 100 российских рублей.

Искать по ключевым словам: STM32F103C8T6 ARM STM32 Minimum

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

Купить можно на том же сайте по цене от 120 российских рублей.

image

Искать по ключевым словам ST LINK Stlink ST 252dLink V2 Mini STM8 STM32:

Для разработки ПО под STM32 можно использовать различные IDE.

Самые популярные — IAR, Keil, Coocox (Eclipse).

Мы же пойдем по пути, который с недавних пор абсолютно бесплатно и в полном объеме предоставляет сама ST.

Будем использовать Atollic TrueSTUDIO for STM32 или в простонародии «Толик».

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

Минусы: нет авто дополнения кода.

Доступны версии под windows и linux.

После установки можно не запускать, так как помимо самой IDE нужно еще кое что.

Если все таки запустили — просто закрываем.

Так как TrueSTUDIO — это средство разработки и отладки, хотелось бы не собирать проект руками (подключая требуемые библиотеки и прописывая пути), а получить некий преднастроенный файл, в котором можно без лишних заморочек сразу же писать код.

Для этого применяется программа генератор кода Cube MX или в простонародии «Калокуб».
Данное ПО является первым камнем преткновения в холиварах на чем же писать под STM: на регистрах и CMSIS или на HAL.

Защитники первой идеологии приводят такие аргументы: Cube MX генерирует огромный, ненужный объем кода, который к тому же замедляет работу МК.

Защитники второй — заявляют, что автоматически сгенерированный код сокращает время разработки, позволяя разработчику быстрее переключится к сутевой части устройства (к основной логике), отдав рутинную настройку периферии на откуп специализированному ПО (Cube MX).

Как ни странно — обе эти идеологии правдивы и применимы на практике, но только каждая в своих условиях.

Давайте рассмотрим пару примеров:

Пример №1: Требуется разработать устройство, максимально дешевое, так как планируется производство партиями по 100500 шт ежегодно. Естественно, каждый лишний рубль цены устройства — выльется в сотни тысяч рублей затрат на финальном устройстве. При этом в планируемой разработке есть пара тяжелых расчетов и работа с периферией (ADC, SPI, UART) на максимальных скоростях.

Устройство является полностью автономным продуктом, в дальнейшем планируется минимальные изменения за весь срок производства данного оборудования. Срок разработки до получения готового образца — 1-2 года.

Пример №2: Требуется прототип устройства, который возможно заинтересует заказчика и он закажет 100 шт аналогичных устройств для переоборудования своего объекта. Первая планируемая партия должна быть отгружена заказчику через 2 месяца. Размер первой тестовой партии 10 шт.

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

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

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

В таком случае выбирается контроллер, который можно быстро поставить в производство в текущем регионе, на нем делается инициализация с помощью Cube MX, пишется прикладная логика на HAL и прототип передается заказчику для тестирования. Такой проект может вести любой средний разработчик, который постиг навыки работы с целевым языком программирования. Вникание в тонкости работы периферии — практически не требуются.

Как бы это не печально звучало — в реалиях современной разработки устройств в России — пример №1 встречается все реже, передавая эстафету примеру №2.

К обсуждению примеров №1 и №2 вернемся в самом конце цикла статей, а сейчас продолжим с подготовкой рабочего пространства.

После того, как у нас появился доступ к сайту — скачиваем STM32 Cube MX.

В самом низу страницы есть кнопка выбора версии, нам нужна версия 5.0.0

image

Драйвер ST-LINK V2

image

image

Установка драйвера, прошивальщика и самого Cub’a не вызывают затруднений, просто соглашаемся со всем и жмем далее.

После полной установки необходимого ПО — можем приступать к созданию проекта.
Для этого запустим Cube MX.

В появившемся окне нажмем на кнопку «ACCESS TO MCU SELECTOR».

image

На нашей целевой плате установлен микроконтроллер STM32F103C8T6.

Введем его название в строке поиска и двойным щелчком выберем единственный найденный вариант.

В этой же таблице видно основную начинку нашего МК (64 килобайт флеша, 20 килобайт оперативы и пр).

image

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

На данном этапе необходимо обязательно выбрать способ подключения отладчика.

Для этого на вкладке Pinout & Configuration в левом меню выбираем пункт SYS а в нем в выпадающем списке под названием «Debug» устанавливаем значение Serial Wire.

При этом краем глаза замечаем, что программа зарезервировала для отладочных целей два пина на мнемосхеме контроллера.

image

Еще раз вспоминаем, что мы хотим помигать светодиодом на нашей плате.

Для этого необходимо сначала узнать, к какой именно ножке он подключен.

В этом нам поможет схема электрическая принципиальная:

image

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

image

Искомый светодиод находится на ножке PC13.

Соответственно, необходимо настроить данный вывод для работы в режиме выхода.

  1. Находим вывод на мнемосхеме
  2. Нажимаем на него правой кнопкой мыши, из выпадающего меню выбираем пункт «GPIO_Output»
  3. Переходим в меню GPIO,
  4. В списке выбираем PC13
  5. Заполняем таблицу PC13-TAMPER-RTC Configuration в соответствии со скриншотом, особенно нас интересуют параметры GPIO mode и User Label

Продолжаем настройку проекта, переходим к вкладке Clock Configuration.

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

image

Переходим к вкладке Project Manager, под вкладка Project.

Обязательно заполняем следующие параметры:

  1. Имя проекта (лучше использовать только латинские буквы)
  2. Директорию, в которой будет создан проект (так же лучше использовать только латиницу)
  3. IDE, в которой планируется работа над проектом (мы планируем использовать TrueSTUDIO)

Спускаемся ниже, под вкладка Code Generator.

Здесь обязательно отмечаем опцию Generate peripheral initialization as pair…

Таким образом получим более структурированный проект, в котором для каждого типа периферии имеется своя пара C и H файлов.

image

Остался последний шаг. Подвкладка Advanced Settings.

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

Даем свое согласие на скачивание файлов:

image

Идем греть чайник или готовить кофе:

image

После окончания работы кодо-генератора — сразу же открываем его:

image

Выбираем любую папку, где Atollic будет хранить рабочее пространство:

image

При успешном открытии — перед нами предстанет главное окно Atollic TrueSTUDIO for STM.

Общая информация нас мало интересует, поэтому сразу перейдем к дереву файлов.

STM32 и Cube IDE изучаем с нуля до мастера за rand() дней ч.1 «Первые шаги»

Плата Blue Pill STM32F103C8T6 ARM®32-bit Cortex®-M3 CPU Core Плата Blue Pill STM32F103C8T6 ARM®32-bit Cortex®-M3 CPU Core

По факту получается, что базовая плата Blue Pill с чипом STM32F103C8T6 может быть приобретена менее чем за 2$ у друзей из поднебесной . К этому комплекту еще необходим программатор ST-Link V2, и как и для всего остального на него существует максимально дешевая китайская копия . Программатор понадобиться в первую очередь для записи программ и внутрисхемной отладки по интерфейсу JTAG с поддержкой, разработанного ARM протокола SWD (Serial Wire Debug).

Кроме использования ST-Link существует возможность записывать программы через выводы A9, A10 платы (ножки 30, 31 USART1 микроконтроллера), для этого понадобиться преобразователь USB-UART типа FTDI FT232RL или подобный.

Но, так как этот способ не полнофункциональный с точки зрения внутрисхемной отладки, в дальнейшем речь пойдет о прошивке именно через программатор ST-Link. Это развяжет нам руки в использовании всего функционала среды разработки. Подключение показано ниже, тут все просто — надо соединить соответствующие выводы: GND→GND; CLK→SWCLK; DIO→SWDIO; 3.3→3.3V

Подсоединение платы Blue Pill к программатору ST-Link Подсоединение платы Blue Pill к программатору ST-Link

Прежде чем начать предметно разбирать Cube IDE я приведу составленную мной таблицу сравнения характеристик микроконтроллеров от различных базовых плат Arduino c STM32F103C8.

Таблица сравнения некоторых базовых МК AVR с STM32F103 Таблица сравнения некоторых базовых МК AVR с STM32F103

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

Итак, для успешного начала работы нам необходимо скачать установочный файл с официальной страницы CubeIDE на сайте ST. Для скачивания доступно несколько вариантов под Linux, macOS и Windows. Конкретно я загружал и устанавливал под форточку, но полагаю интерфейсы программы аналогичны для всех операционных систем.

На момент написания статьи доступна версия программы 1.3.0, что может нам говорить о том, что некоторые детские болезни ПО уже удалось преодолеть. Это к тому, что CubeIDE сравнительно новая программа, анонсированная в 2019 г., и поэтому у сообщества STM-щиков, естественно, есть настороженность по поводу наличия в ней багов и недоработок.

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

Итак, для создания нового проекта нам потребуется пройти по основному меню: File→New→STM32 Project

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

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

Далее IDE может спросить нас об открытии кодогенератора STM32CubeMX, возражать не имеет смысла, он в последствии будет нашим лучшим помощником.

И после этого будет создан наш первый проект, окно будет выглядеть примерно так, и главную площадь будет занимать собственно наш программируемый чип. Графическое представление именно то, что мне особенно понравилось в программировании STM-ок через эту среду.

Первым делом, нам нужно объяснить МК откуда им будет получено тактирование во время работы. На платах Blue Pill установлен кварцевый резонатор с частотой 8 MHz, он уже подключен к выводам PD0, PD1. Чтобы обозначить это для IDE, в разделе System Core заходим в RCC (Reset and clock conrol) выбираем высокоскоростное тактирование (HSE) и далее кварцевый резонатор. После этого соответствующие ноги МК будут подсвечены зеленым с указанием их назначения.

Настройка регистра RCC на внешний кварцевый резонатор. Настройка регистра RCC на внешний кварцевый резонатор.

В микроконтроллере STM32F103 есть блок фазовой автоподстройки частоты (PLL) он служит для создания основной частоты работы микропроцессора путем умножения частоты внешнего или внутреннего источника тактирования на программно определяемый множитель.

Для завершения настройки нам необходимо проверить во вкладке Clock Configuration, что частота HSE установлена в 8 MHz, а частота работы МК составляет 72 MHz.

Для первого нашего проекта мы по классике помигаем установленным на плате светодиодом. Он подключен к выводу PC13. Для его настройки правой кнопкой по выводу выберем GPIO_Output (вывод общего назначения_выход). В разделе настройки GPIO присвоим пользовательское название вывода (User Label) как LED13. В таблице конфигурации GPIO проверяем внесенные изменения.

Теперь дадим команду кодогенератору сформировать файлы проекта на основании тех настроек, что мы сделали.

После этого мы уже можем писать свою программу в файле main.c. Там будут вставлены функции для настройки выводов и тактирования:

Теперь в файле main.c находим функцию main(void) и бесконечный цикл в ней while (1). Это и есть место для нашей первой программы.

STM32 и CubeIDE изучаем с нуля до мастера за rand() дней ч.2 «Работа с АЦП — независимый режим»

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

Перед прочтением рекомендуется ознакомиться с первой частью этой серии статей. Она находиться тут .

Итак, насколько мне известно во всех микроконтроллерах STM32 присутствует по крайней мере один аналого-цифровой преобразователь. В большинстве случаев это 12-битный АЦП последовательного приближения, хотя в некоторых специализированных моделях МК ( STM32F373 ) уже стали ставить 16-битные ΔΣ АЦП. Так или иначе в данной статье речь пойдет именно о АЦП последовательного приближения ( англ. SAR ) на примере МК STM32F103C8T6 и платы Blue Pill , китайскую версию такой платы я покупал тут .

Применяемая схема АЦП от ST называется схемой последовательного приближения на переключаемых конденсаторах.

Внутренняя схема АЦП последовательного приближения (пример для 10-битного АЦП) Внутренняя схема АЦП последовательного приближения (пример для 10-битного АЦП)

Если вкратце, то процесс разбивается на два основных этапа работы - это процесс работы УВХ (англ. SHA) и процесс преобразования ( англ. ADC Conversion ).

Устройство выборки и хранения сокр. УВХ ( англ. Sample and Hold сокр. SHA ) — схема, запоминающая напряжение на входе в определённый момент времени.

На этапе выборки-хранения конденсаторы заряжаются до входного напряжения (VIN), затем это напряжение отключается от входа АЦП.

Эквивалентная схема процесса преобразования, первые два шага (для примера) Эквивалентная схема процесса преобразования, первые два шага (для примера)

На следующем этапе путем коммутации конденсаторов и сравнения их напряжения с долями от опорного напряжения (VREF) определяется значение напряжения, поступившего на вход.

Для STM32F103C8 напряжение VREF равно напряжению питания 3,3В, но для МК с большим количеством выводов может также иметься отдельный вход VREF+ для подачи внешнего опорного напряжения.

Пример работы алгоритма последовательного приближения для 4-битного АЦП Пример работы алгоритма последовательного приближения для 4-битного АЦП

В зависимости от того какое состояние получил выход компаратора логика алгоритма последовательного приближения выберет соответствующую ветку цифрового кода и следующее состояние для коммутирующих ключей.
Так произойдет столько раз сколько разрядов имеет конкретный АЦП, в нашем случае это будет 12 шагов.

Подробнее про работу SAR АЦП в STM32 см. AN2834.

Время полной работы АЦП до получения результата складывается из времени выборки ( англ. Sampling time ) и времени преобразования ( англ. ADC Conversion time ).

Tconv = Sampling time + ADC Conversion time

Время преобразования для 12 битных АЦП ST это всегда 12.5 циклов тактовой частоты АЦП.

Стоит сразу отметить, что тактовая частота АЦП устанавливается путем деления частоты тактирования ядра на делитель ADC Prescaler, который выбирается из /2/4/6/8 так, чтобы получившаяся частота АЦП не превышала 14 МГц. Например, для частоты ядра 72МГц наименьший возможный делитель, удовлетворяющий условию, будет 6 и соответственно получиться ADC CLK = 12МГц.

Установка тактирования АЦП на вкладке Clock Configuration Cube IDE Установка тактирования АЦП на вкладке Clock Configuration Cube IDE

Получение максимальной частоты тактирования АЦП возможно при частоте ядра 56МГц, тогда, при выборе делителя на 4, частота ADC CLK = 14МГц.

На практике я обычно предпочитаю поступиться максимальной частотой АЦП в пользу максимальной частоты ядра.

Типовая схема подключения АЦП (STM32F103x Datasheet Figure 38. Typical connection diagram using the ADC) Типовая схема подключения АЦП (STM32F103x Datasheet Figure 38. Typical connection diagram using the ADC)

Следующей составляющей полного времени работы АЦП является время выборки, которое определяет время заряда конденсатора С adc (см. типовую схему подключения). Эта емкость составляет всего 8пФ (max) , но при достаточно высоком сопротивлении источника Rain и/или при использовании RC фильтра перед входом АЦП, понадобиться время, чтобы зарядить эту емкость до уровня Vain . Рекомендации по выбору этого времени исходя из сопротивления источника сигнала сведены в таблицу.

Зависимость рекомендуемого времени выборки (ts) от сопротивления источника (Rain) Зависимость рекомендуемого времени выборки (ts) от сопротивления источника (Rain)

Это время выставляется при конфигурировании АЦП в разделе Sampling Time.

Выбор времени работы УВХ в циклах тактовой частоты АЦП Выбор времени работы УВХ в циклах тактовой частоты АЦП

Таким образом, при установке минимального времени Sampling time = 1,5 цикла, суммарное время АЦП будет составлять 14 циклов тактовой, что соответствует 1,17μS для частоты АЦП 12МГц и 1,00μS для частоты 14МГц.

В практических применениях, если необходимо уменьшить время аналого-цифрового преобразования, то внутреннее сопротивление источника сигнала можно свести практически к нулю поставив перед входом АЦП буферный усилитель на ОУ .

У микроконтроллеров STM32F103C8T на борту имеется 2 аналого-цифровых преобразователя, они могут работать как в независимом режиме ( англ. Independent mode ), так и в совместном режиме ( англ. Dual mode ), при этом, совместный режим предполагает внутри себя еще целый ряд вариантов. Например, режимы с чередованием запуска АЦП на 7 тактов, что дает нам возможность, используя одновременно два АЦП на один входной канал, получить частоту выборок до 2МГц.

Еще у этих МК целых 12 мультиплицированных каналов аналого-цифрового преобразования, 10 из них с возможностью вывода на ножки микроконтроллера (PA0-PA7 и PB0, PB1) и 2 внутренних канала, которые в общем-то ничем не отличаются от остальных кроме того, что они уже подключены к внутреннему датчику температуры и к напряжению опорного источника.

Запуск АЦП может производиться по следующим триггерам:

— Программный триггер ( англ. Software Trigger), когда аналого-цифровое преобразование начинается командой из кода программы.
— Аппаратный внутренний триггер ( англ. Hardware Trigger), когда аналого-цифровое преобразование начинается по некоторому аппаратному событию, например от таймера.
Эти варианты выбираются в меню External Trigger Conversion Source:

— Аппаратный внешний триггер ( англ. External Trigger — EXTI), когда аналого-цифровое преобразование начинается по внешнему событию такому как изменение уровня на ножках РB11 (ADC_EXTI11) и РС15 (ADC_EXTI15), для активации нужно выбрать группу каналов в выпадающем меню EXTI Conversion Trigger:

STM32 + CMSIS + STM32CubeIDE

Здесь я расскажу как создать минимальный проект на CMSIS с использованием «родной» IDE для микроконтроллеров STM – STM32CubeIDE.

Возможно STM32CubeIDE и обладает рядом недостатков, но у нее, на мой взгляд, есть несколько преимуществ – таких как проприетарность и бесплатность, ради которых, как минимум, стоит обратить внимание на эту среду разработки, если вы не сделали этого раньше.



Объектом прошивки выбран не очень распространенный микроконтроллер STM32F072 с ядром ARM Cortex-M0, для более привычных STM32F103 на ARM Cortex-M3, с поправкой на ядро, процесс идентичен.

    , я использую Windows версию, но также доступны версии под Mac и Linux





Создание нового проекта — File/New/STM32Project. После некоторого раздумия появляется окно выбора микроконтроллера, в моем случае это STM32F072RB в корпусе LQFP64, выбираю нужную строку, жму далее. Далее предлагается выбрать имя проекта, расположение, язык программирования C/C++, исполняемый файл/статическая библиотека и будет-ли проект сгенерирован с помощью CubeMX или сами с усами. Генерация кубом, в данном случае не нужна, поэтому тип проекта Empty — финиш.




Слева, в окне Project Explorer, появилось дерево проекта, правда он не совсем Empty, как заказывали. Впринципе, если устраивает сгенерированная структура папок, можно добавить туда файлы из библиотеки CMSIS и работать дальше, но здесь я покажу как можно привести структуру проекта в гармонию со своим чувством прекрасного, поэтому удаляется всё, кроме скрипта линкера т.е. файла c расширением .ld — он еще пригодится.



Все манипуляции с папками и файлами можно проводить как в проводнике так и внутри IDE, нажав правой кнопкой на название проекта, к примеру: правая кнопка –> new –> Folder. Если структура проекта изменялась вне IDE, то нужно просто обновить проект: правая кнопка –> Refresh.

Мой вариант структуры проекта выглядит так:

  • Startup – здесь будет храниться скрипт линкера, тот самый, оставшийся от сгенерированного проекта, а также startup файл взятый из CMSIS
  • CMSIS\src и CMSIS\inc – здесь будут лежать исходники, файлы с расширением .c в папке scr и заголовочные файлы с расширением .h в папке inc соответственно, относящиеся к библиотеке CMSIS
  • Core\src и Core\inc – здесь будет расположен собственно сам проект, для начала стоит положить туда main.c и main.h


Теперь нужно перенести файлы библиотеки CMSIS в проект. Библиотека состоит из файлов ядра и файлов периферии. Файлы ядра начинаются с core_ или cmsis_ они общие для всех микроконтроллеров, использующих данное ядро. Файлы периферии содержат в названии наименование микроконтроллера stm32 и специфичны для конкретного производителя, в данном случае, компании STM.

В распакованном виде архив содержит папку STM32Cube_FW_F0_V1.11.0, все пути указаны относительно этой папки. Итого, нужно скопировать:

  • Drivers\CMSIS\Include\cmsis_compiler.h
  • Drivers\CMSIS\Include\cmsis_gcc.h
  • Drivers\CMSIS\Include\cmsis_version.h
  • Drivers\CMSIS\Include\core_cm0.h
  • Drivers\CMSIS\Device\ST\STM32F0xx\Include\stmf0xx.h
  • Drivers\CMSIS\Device\ST\STM32F0xx\Include\stm32f072xb.h
  • Drivers\CMSIS\Device\ST\STM32F0xx\Include\system_stm32f0xx.h
  • Drivers\CMSIS\Device\ST\STM32F0xx\Source\Templates\system_stm32f0xx.c
  • Drivers\CMSIS\Device\ST\STM32F0xx\Source\Templates\gcc\startup_stm32f072xb.s


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

Правая кнопка по названию проекта -> Properties -> C/C++ Build -> Settings -> Tool Settings -> MCU GCC Linker -> General – здесь нужно указать новое расположение скрипта линкера с помощью кнопки Browse…


Также нужно указать пути к файлам проекта

Properties -> C/C++ General -> Includes
Properties -> C/C++General -> Source Location

В Includes пути к папкам inc, а в Source Location логично было-бы к папкам src, но если так сделать, то в дереве проекта будут отдельно добавлены эти папки. Чтобы не загромождать визуально дерево, в Source Location можно указать корневые папки Core, CMSIS и Startup.



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




Собственно всё. Безошибочная компиляция и сразу же куда-то подевалось целых полтора килобайта памяти ОЗУ она же RAM, и сразу же вспоминается стек и куча, в процессе создания проекта они нигде не упоминались. Величина стека и кучи указана в файле скрипта линкера, тот что с расширением .ld, их можно и нужно изменять в соответствии с требованиями проекта. Эти значения находятся в начале файла в виде меток _Min_Heap_Size/_Min_Stack_Size с указанием размера в шестнадцатеричном виде.


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

Светодиод будет мигать на отладочной плате STM32F072B-DISCO, тактирование осуществляться от внутреннего генератора HSI48 частотой 48 МГц, а в качестве источника задержки использоваться таймер SysTick, генерирующий прерывания с периодом в 1 мс, при помощи которых отсчитывается точное время задержки. Светодиод подключен к выводу 6 порта С, настроенного на выход push-pull.

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

Режимы работы АЦП:

Независимый режим работы (Independent mode)

— Одноканальное однократное преобразование ( англ. single-channel, single conversion ) — АЦП запускается по программному или аппаратному триггеру, делает одно преобразование, сохраняет результат в регистр данных и останавливается до следующего запуска.

Конфигурация АЦП для одноканального однократного преобразования (CubeIDE) Конфигурация АЦП для одноканального однократного преобразования (CubeIDE)

Пример HAL кода однократного одноканального преобразования:

/* USER CODE BEGIN PV */
uint16_t adc; // Переменная для хранения данных с АЦП
/* USER CODE END PV */
.
HAL_ADCEx_Calibration_Start(&hadc1); // Калибровка АЦП
while (1)
HAL_ADC_Start(&hadc1); // Запуск преобразования
HAL_ADC_PollForConversion(&hadc1, HAL_MAX_DELAY); // Ожидаем окончания преобразования
adc = HAL_ADC_GetValue(&hadc1); // Сохраняем значение АЦП в переменную adc
>

Это важно: любой код, который пишется в main.c или других сгенерированных файлах проекта, должен располагаться между комментариями USER CODE BEGIN и USER CODE END, иначе, когда вы захотите изменить что-нибудь в файле конфигурации .ioc и пересобрать проект, ваш код с высокой вероятностью будет утерян.

Небольшая ремарка: особенностью АЦП STM32 является система объединения каналов в группы. Существует 2 типа групп: регулярная ( англ. Regular Group ) и инжектированная группа (Injected Group).
В регулярной группе может быть до 16 каналов, опрашиваемых в любом порядке и с возможностью повторения одного и того же канала для нескольких индексов группы. Эти индексы обозначаются как «Rank».
Важно: данные с любого канала регулярной группы перезаписывают один и тот же регистр данных АЦП , поэтому их нужно своевременно оттуда забирать.

Установка порядка преобразования каналов АЦП с помощью индексов Rank Установка порядка преобразования каналов АЦП с помощью индексов Rank

Инжектированная группа может включать до 4-х каналов АЦП.
Ее особенность в том, что она прерывает преобразование регулярной группы и сразу начинает преобразование для своих каналов. По завершению инжектированной группы, регулярное преобразование продолжается с того канала, на котором произошла инжекция. Для каждого из четырех индексов инжектированной группы есть свой отдельный регистр хранения результата. Это значит, что для этих 4-х каналов можно читать данные из своих индивидуальных регистров данных АЦП. Если создана только инжектированная группа, то ее работа не будет отличаться от регулярной за исключением описанного выше.

Блок-схема АЦП STM32F1 (подробнее см. RM0008 Figure 22) Блок-схема АЦП STM32F1 (подробнее см. RM0008 Figure 22)

Подробнее про инжектированную группу будет в разделе « преобразование инжектированных каналов» .

Еще один важный момент, что любая группа может состоять всего из одного канала, и при конфигурации это дает возможность выбирать событие, по которому будет происходить старт преобразования для группы ( англ. External Trigger Conversion Source ) и время работы УВХ ( англ. Sampling Time ) для каждого члена группы.
Например, конфигурация, показанная ниже, будет работать точно так же как и предыдущая для одноканального однократного преобразования, но включает в себя группу из одного канала.

Конфигурация АЦП для одноканального однократного преобразования c созданием группы из 1-го канала (CubeIDE) Конфигурация АЦП для одноканального однократного преобразования c созданием группы из 1-го канала (CubeIDE)

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

А в разделе параметров кодогенератора появится команда создать соответствующий обработчик прерывания:

В файле main.c код будет выглядеть так:

/* USER CODE BEGIN PV */
uint16_t adc; // Переменная для хранения данных с АЦП
/* USER CODE END PV */
.
/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc) // CallBack функция из прерывания
if(hadc->Instance == ADC1) // Проверяем что прерывание пришло от АЦП1
adc = HAL_ADC_GetValue(&hadc1); // Читаем данное из регистра в нашу переменную
>
>
/* USER CODE END 0 */
.
int main(void)
.
/* USER CODE BEGIN 2 */
HAL_ADCEx_Calibration_Start(&hadc1); // Калибровка АЦП1
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
HAL_ADC_Start_IT(&hadc1); // Запускаем АЦП в режиме генерации прерываний
HAL_Delay(500); //Задержка что бы прерывания не создавались слишком часто
>

В файле stm32f1xx_it.c редактируем обработчик прерываний:

/**
* @brief This function handles ADC1 and ADC2 global interrupts.
*/
void ADC1_2_IRQHandler(void)
/* USER CODE BEGIN ADC1_2_IRQn 0 */
HAL_ADC_ConvCpltCallback(&hadc1); // Вызов CallBack функции из main.c
return; // Возврат из прерывания
/* USER CODE END ADC1_2_IRQn 0 */
HAL_ADC_IRQHandler(&hadc1);
/* USER CODE BEGIN ADC1_2_IRQn 1 */
/* USER CODE END ADC1_2_IRQn 1 */
>

— Многоканальное (сканирующее) однократное преобразовани е ( англ. multi-channel/scan mode, single conversion ) — АЦП делает одно последовательное преобразование (Scan Conversion) до 16 каналов в любом заранее определенном порядке, при этом, для каждого канала можно выбрать свое время работы устройства выборки и хранения. Очередность опроса каналов устанавливается путем их связи с индексами ( Rank ) от 1 до 16, при этом время работы УВХ устанавливается в Sampling Time для каждого Rank отдельно.

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

Конфигурация АЦП для 3-х канального однократного преобразования (CubeIDE) Конфигурация АЦП для 3-х канального однократного преобразования (CubeIDE)

Сделать это можно двумя способами, создав прерывание по готовности данных АЦП или воспользовавшись прямым доступом к памяти DMA (Direct Memory Access). Приведу пример с использованием DMA, это когда по событию готовности очередного данного происходит его чтение и дальнейшая перезапись в объявленную заранее пользовательскую переменную, в конкретном случае в массив из 3-х переменных для опроса 3-х каналов. Главным преимуществом данного способа является то, что процессор в данном случае вообще не выполняет действий по переносу, всю работу за него делает блок DMA.

Пример HAL кода многоканального однократного преобразования 3-х каналов с сохранением данных по DMA:

/* USER CODE BEGIN PV */
uint16_t adc[3]; // Массив переменных для хранения значений 3-х каналов АЦП
/* USER CODE END PV */
.
HAL_ADCEx_Calibration_Start(&hadc1); // Калибровка АЦП
while (1)
HAL_ADC_Start_DMA(&hadc1, (uint32_t*)&adc, 3); // Запуск преобразования с передачей по DMA
HAL_ADC_PollForConversion(&hadc1, HAL_MAX_DELAY); // Ожидаем окончания преобразования
>

Важная ремарка: для микроконтроллеров STM32F1 использование прерываний для сохранения результата при многоканальном преобразовании можно корректно реализовать только для инжектированной группы каналов. Это связано с тем, что глобальное прерывание происходит по окончанию аналого-цифрового преобразования всей группы, а у регулярной группы только один регистр для хранения результата. Из-за этого результаты каналов просто перепишут регистр ADC_DR и останется только последняя оцифровка.

Для более продвинутых МК (F3, F4 и т.д.) существуют функции определения события конца преобразования ( англ. End Of Conversion Selection ) и с помощью нее можно настроить корректный режим установки флага конца преобразования и соответственно генерацию прерываний для каждого канала в группе.

Еще для многоканальных режимов можно применить функцию прерывистого преобразование каналов ( англ. Discontinuous Conversion ) это дает возможность разбить выбранную группу на части. То есть, по одной команде на запуск, АЦП будет оцифровывать только часть каналов из группы.
Например, разбитие регулярной группы, состоящей из 5-ти каналов на 3 части будет конфигурироваться следующим образом:

Читайте также: