STM32F407(STM32F4-DISCOVERY) - Нестандартний підхід - Стандартна бібліотека ч.1. Конфігурування STM32F10x SPL за допомогою макровизначень

До цього моменту ми використовували стандартну бібліотеку ядра – CMSIS. Для налаштування будь-якого порту на потрібний режим роботи нам доводилося звертатися до , щоб знайти регістр, що відповідає за певну функцію, а також шукати за великим документом іншу пов'язану з цим процесом інформацію. Справа прийме ще більші болючі та рутинні обороти, коли ми приступимо до роботи з таймером або АЦП. Кількість регістрів там значно більша, ніж у портів введення-виводу. Ручне налаштуваннязабирає чимало часу і підвищує шанс припуститися помилки. Тому багато хто воліє працювати зі стандартною бібліотекою периферії - StdPeriph. Що вона дає? Все просто - підвищується рівень абстракції, вам не потрібно лізти в документацію і думати про регістри здебільшого. У цій бібліотеці всі режими роботи та параметри периферії МК описані у вигляді структур. Тепер для налаштування периферійного пристрою необхідно лише викликати функцію ініціалізації пристрою із заповненою структурою.

Нижче наведено зображення зі схематичним зображенням рівнів абстракції.

Ми працювали з CMSIS (яка знаходиться «ближче» до ядра), щоб показати, як влаштований мікроконтролер. Наступним кроком є ​​стандартна бібліотека, користуватися якою ми навчимося зараз. Далі йдуть драйвери пристроїв. Під ними розуміються *.c\*.h-файли, які забезпечують зручний програмний інтерфейс для керування будь-яким пристроєм. Так, наприклад, у цьому курсі ми надамо вам драйвери для мікросхеми max7219 та WiFi-модуля esp8266.

Стандартний проект буде включати такі файли:


По-перше, звичайно, це файли CMSIS, які дозволяють стандартній бібліотеці працювати з ядром, про них ми вже говорили. По-друге, файли стандартної бібліотеки. І по-третє, файли користувача.

Файли бібліотеки можна знайти на сторінці, присвяченій цільовому МК (для нас це stm32f10x4), у розділі Design Resources(у середовищі CooCox IDE ці файли завантажуються з репозиторію середовища розробки). Кожній периферії відповідають два файли - заголовний (*.h) та вихідного коду(*.c). Детальний описможна знайти у файлі підтримки, що лежить в архіві з бібліотекою на сайті.

  • stm32f10x_conf.h – файл конфігурації бібліотеки. Користувач може підключити або вимкнути модулі.
  • stm32f10x_ppp.h - заголовний файл периферії. Замість ppp може бути gpio чи adc.
  • stm32f10x_ppp.c – драйвер периферійного пристрою, написаний мовою Сі.
  • stm32f10x_it.h - заголовний файл, що включає всі можливі обробники переривань (їх прототипи).
  • stm32f10x_it.c - шаблонний файл вихідного коду, що містить сервісні рутинні переривання (англ. interrupt service routine, ISR) для виняткових ситуацій у Cortex M3. Користувач може додати свої ISR для використовуваної периферії.

У стандартній бібліотеці периферії є угода у найменуванні функцій та позначень.

  • PPP – акронім для периферії, наприклад, ADC.
  • Системні, заголовні файли та файли вихідного коду - починаються з stm32f10x_.
  • Константи, що використовуються в одному файлі, визначені у цьому файлі. Константи, що використовуються у більш ніж одному файлі, визначені в заголовних файлах. Всі константи в бібліотеці периферії найчастіше написані у верхньому регістрі.
  • Регістри розглядаються як константи і називаються також ВЕЛИКИМИ літерами.
  • Імена функцій, що належать до периферії, містять акронім, наприклад USART_SendData() .
  • Для налаштування кожного периферійного пристрою використовується структура PPP_InitTypeDef, яка передається у функцію PPP_Init().
  • Для деініціалізації (налаштування за замовчуванням) можна використовувати функцію PPP_DeInit() .
  • Функція, що дозволяє включити або вимкнути периферію, називається PPP_Cmd().
  • Функція увімкнення/вимкнення переривання називається PPP_ITConfig .

З повним спискомви знову ж таки можете ознайомитися у файлі підтримки бібліотеки. А тепер давайте перепишемо блимання світлодіода з використанням стандартної бібліотеки периферії!

Перед початком роботи заглянемо у файл stm32f10x.h і знайдемо рядок:

#define USE_STDPERIPH_DRIVER

Якщо ви налаштовуватимете проект з нуля, використовуючи файли бібліотеки зі скачаного архіву, то вам буде необхідно розкоментувати цей рядок. Вона дозволить використати стандартну бібліотеку. Дане визначення (макрос) скомандує препроцесору підключити файл stm32f10x_conf.h:

#ifdef USE_STDPERIPH_DRIVER #include "stm32f10x_conf.h" #endif

У цьому файлі підключаються модулі. Якщо вам потрібні лише конкретні – відключіть решту, це заощадить час при компіляції. Нам, як ви вже могли здогадатися, потрібні модулі RTC і GPIO (проте в майбутньому будуть потрібні також _bkp.h , _flash , _pwr.h , _rtc.h , _spi.h , _tim.h , _usart.h):

#include "stm32f10x_flash.h" // for init_pll() #include "stm32f10x_gpio.h" #include "stm32f10x_rcc.h"

Як і минулого разу, спочатку потрібно включити тактування порту B. Робиться це функцією, оголошеною в stm32f10x_rcc.h:

Void RCC_APB2PeriphClockCmd(uint32_t RCC_APB2Periph, FunctionalState NewState);

Перелік FunctionalState визначено в stm32f10x.h:

Typedef enum (DISABLE = 0, ENABLE = !DISABLE) FunctionalState;

Оголосимо структуру для налаштування нашої ніжки (знайти її можна у файлі stm32f10x_gpio.h):

GPIO_InitTypeDef LED;

Тепер нам належить її заповнити. Давайте подивимося зміст цієї структури:

Typedef struct ( uint16_t GPIO_Pin; GPIOSpeed_TypeDef GPIO_Speed; GPIOMode_TypeDef GPIO_Mode; ) GPIO_InitTypeDef;

Усі необхідні переліки та константи можна знайти у цьому ж файлі. Тоді переписана функція init_leds() набуде наступного вигляду:

Void led_init() ( // Включаємо тактування RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); // Оголошуємо структуру і заповнюємо її GPIO_InitTypeDef LED; LED.GPIO_Pin = GPIO_Pin_0; LED.GP_ _Mode_Out_PP; // Ініціалізуємо порт GPIO_Init( GPIOB, &LED);

Перепишемо функцію main() :

Int main(void) ( led_init(); while (1) ( GPIO_SetBits(GPIOB, GPIO_Pin_0); delay(10000000); GPIO_ResetBits(GPIOB, GPIO_Pin_0); delay(10000000));

Головне – відчути порядок ініціалізації: включаємо тактування периферії, оголошуємо структуру, заповнюємо структуру, викликаємо метод ініціалізації. Інші периферичні пристрої зазвичай налаштовуються за подібною схемою.

У цій публікації я спробую акцентувати увагу на основних моментах швидкого початку роботи з мікроконтролерами STM32F10x на основі бібліотеки стандартної периферії від компанії-виробника STMicroelectronics.

Як середовище розробки у статті використовуватиметься Eclipse CDT. Оскільки основна увага буде зосереджена навколо програмного коду, ви можете спокійно виконати всі маніпуляції в Code::Blocks.

Загальна структура проекту для ARM мікроконтролерів описана у моїй статті.

Тут я коротко нагадаю, що для складання проекту для ARM-мікроконтролерів (STM32F10x зокрема) знадобиться скрипт компонувальника та C-Startup файл.

Скрипт компонувальника є файлом з інструкціями з розміщення коду програми та даних у пам'яті мікроконтролера. Він може скомандувати завантажити код вашої програми у Flash-пам'ять програм або SRAM-пам'ять даних.

Для мікроконтролерів з різним обсягом пам'яті програм та даних необхідні різні скрипти компонування. Їх можна дістати у виробника мікроконтролерів – компанії STMicroelectronics.
Розпакуйте з архіву ARM_Toolchain/Lib/stm32f10x_stdperiph_lib.zip бібліотеку STM32F10x standard peripheral library.
У ній є приклади проектів різних середовищ розробки (IAR EWB, Keil uVision, Atollic True Studio тощо.). Найбільш близьким для нас є Atollic True Studio, оскільки є модифікацією Eclipse.
Зайдіть в каталог Project/StdPeriph_Template/TrueSTUDIO, там є кілька підкаталогів, назви яких відповідають назв налагоджувальних плат STM3210x-EVAL.

Дізнайтеся, в якій із цих плат використовується мікроконтролер тієї ж лінійки, що й ваш. Скопіюйте файл stm32_flash.ld із відповідного каталогу у свій проект.

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

Стартовий код (C-Startup) для мікроконтролерів STM32 може бути написаний С або Assembler.
Хоча бібліотеку STM32F10x Standard Peripheral Library (далі по тексту використовується скорочення STM32F10x SPL) часто критикують за наявність помилок, все ж таки для початку програмування під STM32 використання цієї бібліотеки надає найпростіший спосіб швидко приступити до роботи.
Але завжди хочеться, щоби була якась альтернатива. Насправді їх безліч, наприклад, програмувати мовою асемблера 🙂 .

Це найважчий і безглуздий шлях. Другий спосіб - використовувати бібліотеку CMSIS, яка надає синтаксис звернення до структур мови для доступу до різної периферії мікроконтролера. Найпростішим та логічним способом (на мій погляд) є використання бібліотек.

Якщо ви категорично налаштовані проти STM32F10x SPL, то спеціально для вас є ще одна альтернатива – бібліотека libopencm3. У ній основна кількість прикладів зосереджена навколо основної серії мікроконтролерів STM32F10x, але поява прикладів для інших серій (STM32F2xx/4xx) є лише питанням часу. Ви завжди можете приєднатися до проекту libopencm3 та прискорити цей процес.

Стандарт CMSIS також не є обов'язковим для застосування у ваших програмах.
Можна обійтися і без нього, витративши деякі зусилля та час для реалізації HAL (Hardware Abstraction Layer) рівня мовою програмування.

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

Або вам необхідно реалізувати програмне забезпечення мовою С для мікроконтролерів з ядром ARM9, для якого виробники орієнтуються на використання готових операційних систем(Linux, QNX, Windows CE), тому бібліотек для програмування мовою С у чистому вигляді або у поєднанні з більш легковагою RTOS виробники можуть не надавати.

На щастя, виробники мікроконтролерів на основі ядра Cortex-M3 надають у розпорядження розробників велику кількість бібліотек коду. Це стосується мікроконтролерів STM32.
Продовжимо розгляд бібліотеки STM32F10x SPL. Розглядатимемо її на прикладі.
Ви можете відкрити цей приклад або створити свій проект «з нуля», щоб краще усвідомити весь процес того, що відбувається.

Для другого випадку я перелічу список необхідних кроків:

  • Створити у Eclipse новий порожній проект
  • Скопіювати в проект скрипт компонування та стартовий файл
  • Створити новий або скопіювати шаблонний Makefile
  • При використанні як шаблон Makefile з мого прикладу необхідно створити всередині проекту каталоги src, inc, bin, obj, всередині каталогів bin і obj створити підкаталоги Debug і Release.
  • Копіювати необхідні вихідні та заголовні файли з бібліотек CMSIS та STM32F10x SPL.
  • Внести необхідні зміни до розділу налаштувань користувача шаблонного Makefile, якщо він використовується.
  • Створити у вікні Eclipse “make target” нові цілі “Debug”, “cleanDebug”, “Release”, “cleanRelease”, “Program”.
  • Запустити на виконання ціль «Debug» та простежити за її виконанням у вікні «Console».

Для кращого розуміння матеріалу я розбив статтю на кілька незалежних параграфів, у кожному з яких описується лише один аспект роботи з бібліотекою STM32F10x SPL.

Конфігурування STM32F10x SPL за допомогою макровизначень

Для конфігурування бібліотеки використовуються наперед визначені значення макросів, які ми зараз і розглянемо.
Їх можна задати всередині файлів заголовків за допомогою директиви препроцесора #defineабо ж передати значення макровизначень через ключ -Dкомпілятор GCC.
У своєму прикладі я використовую другий спосіб.
У Makefile змінна DEFINEмістить макроси, необхідні компіляції бібліотеки STM32F10x SPL.
Макровизначення STM32F10X_MDзадає належність мікроконтролера, що використовується, до лінійки Medium-density.
Сюди входять мікроконтролери об'ємом Flash-пам'яті від 64 до 128кБ.
У наступній таблиці наведено назви макросів для різних серій мікроконтролерів:

Найменування серії Макрос Опис
Low density Value line STM32F10X_LD_VL з об'ємом Flash-пам'яті 16 - 32кБ
Low density STM32F10X_LD
з об'ємом Flash-пам'яті 16 - 32кБ
Medium density Value line STM32F10X_MD_VL Flash - пам'яті
64 - 128кБ
Medium-density STM32F10X_MD мікроконтролери серії STM32F101xx, STM32F102xx, STM32F103xx з об'ємом Flash-пам'яті 64 - 128кБ
High density Value line STM32F10X_HD_VL мікроконтролери серії STM32F100xx з об'ємом
Flash - пам'яті 256 - 512кБ
High density STM32F10X_HD з обсягом
Flash-пам'яті 256 - 512кБ
XL-density STM32F10X_XL
Flash-пам'яті 512 - 1024кБ
Connectivity line STM32F10X_CL

Для завдання тактової частоти мікроконтролера необхідно розкоментувати у файлі system_stm32f10x.c макрос із необхідним значенням тактової частоти.

#if defined (STM32F10X_LD_VL) || (Defined STM32F10X_MD_VL) || (defined STM32F10X_HD_VL) #define SYSCLK_FREQ_24MHz 24000000 #else /* #define SYSCLK_FREQ_HSE HSE_VALUE */ /* #define SYSCLK_FREQ_24MHz 24000000 000 */ /* #define SYSCLK_FREQ_48MHz 48000000 */ /* #define SYSCLK_FREQ_56MHz 56000000 */ #define SYSCLK_FREQ_72MHz 72000000 #endif

#if defined (STM32F10X_LD_VL) || (Defined STM32F10X_MD_VL) || (defined STM32F10X_HD_VL)

/* #define SYSCLK_FREQ_HSE HSE_VALUE */

#define SYSCLK_FREQ_24MHz 24000000

#else

/* #define SYSCLK_FREQ_HSE HSE_VALUE */

/* #define SYSCLK_FREQ_24MHz 24000000 */

/* #define SYSCLK_FREQ_36MHz 36000000 */

/* #define SYSCLK_FREQ_48MHz 48000000 */

/* #define SYSCLK_FREQ_56MHz 56000000 */

#define SYSCLK_FREQ_72MHz 72000000

#endif

Передбачається використання кварцового резонатораіз частотою 8МГц для всіх основних
серій мікроконтролерів крім Connectivity line, для якої необхідно встановити кварцовий резонатор на 25МГц.
Якщо ви використовуєте кварцові резонатори з іншими значеннями частоти, необхідно змінити значення макросу HSE_VALUE в заголовному файлі stm32f10x.h і адаптувати відповідним чином всі залежні функції.
Призначення макросу USE_STDPERIPH_DRIVER неважко здогадатися – використовувати бібліотеку STM32F10x standard peripheral library.
USE_FULL_ASSERT – використовувати макрос ASSERT для налагодження програми.

Використання макросу assert_param у бібліотеці

Усі функції бібліотеки STM32F10x SPL використовують для перевірки своїх аргументів макрос assert_param.
Цей макрос виконує перевірку висловлювання з участю аргументу функції на рівність нулю. Якщо значення виразу дорівнює нулю, то викликається функція-обробник помилки аргументу assert_failed, інакше (вираз не дорівнює нулю) перевірка аргументу проходить успішно.
У програмі вам необхідно реалізувати функцію assert_failed.
У ній виводиться повідомлення про помилку, назву файлу та номер рядка коду, що спричинив помилку.
Макрос debug_printf може виводити через USART за допомогою стандартної бібліотеки new_lib або, наприклад, бібліотеки від містера Чена .

#define debug_printf xprintf /* printf */ #ifdef USE_FULL_ASSERT void assert_failed(uint8_t* file, uint32_t line) ( debug_printf("Wrong parameters value: file %s on line %d\r\n", file, ; while (1) ( ) )/* assert_failed */ #endif/*USE_FULL_ASSERT*/

#define debug_printf xprintf /* printf */

#ifdef USE_FULL_ASSERT

void assert_failed (uint8_t * file, uint32_t line)

debug_printf ( "Wrong parameters value: file %s on line %d\r\n", file, (int) line);

while (1 )

) /* assert_failed */

#endif/*USE_FULL_ASSERT*/

Реалізована у вашому коді функція assert_failed використовується лише коли оголошено макрос USE_FULL_ASSERT. В іншому випадку весь код налагодження виключається з вихідного коду. Цей функціонал реалізований у заголовному файлі налаштувань бібліотеки драйверів stm32f10x_conf.h.

#ifdef USE_FULL_ASSERT #define assert_param(expr) ((expr) ? (void)0: assert_failed((uint8_t *)__FILE__, __LINE__)) void assert_failed(uint8_t* file, uint32_t line); #else #define assert_param(expr) ((void)0) #endif /* USE_FULL_ASSERT */

#ifdef USE_FULL_ASSERT

#define assert_param(expr) ((expr) ? (void)0: assert_failed((uint8_t *)__FILE__, __LINE__))

void assert_failed (uint8_t * file, uint32_t line);

#else

#define assert_param(expr) ((void)0)

#endif /* USE_FULL_ASSERT */

Тут пояснювати нема чого. Найкраще розглянемо приклад використання assert_param.

void set_param(uint8_t * param, uint8_t value) ( ​​assert_param(param != NULL); *param = value; )/*set_param*/

void set_param (uint8_t * param, uint8_t value)

assert_param (param! = NULL);

* param = value;

) /*set_param*/

Функція встановлює значення параметра через покажчик, що передається як аргумент. Якщо макрос USE_FULL_ASSERT не оголошено, можна вважати, що рядки
assert_param(param != NULL) у коді просто немає, інакше у цьому визначенні відбувається перевірка параметра.
Якщо покажчик не визначено, то значення param != NULL буде хибно і буде запущена функція assert_failed , яка виведе через USART назву файлу та номер рядка з помилкою, після чого зациклиться, тим самим запобігши присвоєнню значення за невизначеною адресою пам'яті.
Ви не повинні використовувати макрос assert_param у своєму коді, але в коді бібліотеки
STM32F10x SPL він використовується скрізь.
Функцію set_param можна реалізувати з перевіркою помилок аргументу без застосування assert_param.

#define ERROR (-1) #define OK (0) int set_param(uint8_t * param, uint8_t value) ( ​​int r = ERROR; if (param == NULL) return r; *param = value; r = OK; return r ; )/*set_param*/

#define ERROR (-1)

#define OK (0)

int set_param (uint8_t * param, uint8_t value)

int r = ERROR;

if (param == NULL )

return r;

* param = value;

r = OK;

return r;

) /*set_param*/

C-Startup файл у бібліотеці STM32F10x SPL

У стартовому коді виконується первинна ініціалізація мікроконтролера, настроюється стек, виконується обнулення секції BSS, відбувається виклик основної функції main().
Прямого відношення до бібліотеки STM32F10x SPL стартовий код не має. Однак у цьому завантажувальному коді перед викликом основної функції програми main() викликається функція ініціалізації мікроконтролера SystemInit(), що входить до складу CMSIS.
Його можна легко знайти в бібліотеці CMSIS.
Зайдіть до каталогу Libraries/CMSIS/CM3/DeviceSupport/ST/STM32F10x/startup/TrueSTUDIO та скопіюйте потрібний файл. Залишилося лише з'ясувати до якої лінійки належить мікроконтролер, що використовується у вашому проекті.
Для цього перегляньте наступну таблицю:

Найменування серії Назва файлу Опис
Low density Value line startup_stm32f10x_ld_vl.s мікроконтролери серії STM32F100xx з об'ємом
Flash-пам'яті 16 - 32кБ
Low density startup_stm32f10x_ld.s мікроконтролери серії STM32F101xx, STM32F102xx, STM32F103xx
з об'ємом Flash-пам'яті 16 - 32кБ
Medium density Value line startup_stm32f10x_md_vl.s мікроконтролери серії STM32F100xx
Medium-density startup_stm32f10x_md.s мікроконтролери серії STM32F101xx, STM32F102xx, STM32F103xx
з об'ємом Flash-пам'яті 64 - 128кБ
High density Value line startup_stm32f10x_hd_vl.s мікроконтролери серії STM32F100xx
High density startup_stm32f10x_hd.s мікроконтролери серії STM32F101xx, STM32F103xx
з об'ємом Flash-пам'яті 256 - 512кБ
XL-density startup_stm32f10x_xl.s мікроконтролери серії STM32F101xx, STM32F103xx
з об'ємом Flash-пам'яті 512 - 1024кБ
Connectivity line startup_stm32f10x_cl.s мікроконтролери серії STM32F105xx та STM32F107xx

У стартап-файлі прописані назви обробників векторів переривань і винятків, проте реалізований лише обробник вектора скидання, всередині якого і вся початкова ініціалізація перед викликом функції main().
Реалізація решти обробників винятків покладено програміста докладання. Якщо у вашій програмі не використовується жоден обробник, то немає потреби їх прописувати. У разі виключення буде використаний обробник за замовчуванням - зациклювання коду програми.

Склад бібліотеки CMSIS

Як було вже написано раніше в цій публікації, бібліотека CMSIS надає доступ до периферійних модулів мікроконтролера за допомогою елементів структур мови C.
Реалізація цієї бібліотеки поділяється на дві частини. Перша частина забезпечує доступ до периферії ядра Cortex-M3, а друга - до периферії конкретної моделімікроконтролера.
Оскільки стандарт CMSIS єдиний для всіх мікроконтролерів з ядром Cortex-M3, то реалізація першої частини буде однакова у всіх виробників, а друга частина у кожного виробника буде своєю.
До складу CMSIS входять кілька заголовних та вихідних файлів. До першої частини відносяться файли:

  • core_cm3.h
  • core_cm3.c

Друга частина CMSIS включає С-Startup файл, а також файли:

  • stm32f10x.h
  • system_stm32f10x.h
  • system_stm32f10x.c

Заголовковий файл stm32f10x.h містить макровизначення для доступу до периферійних модулів мікроконтролерів stm32f10x.
У файлах system_stm32f10x.h та system_stm32f10x.c реалізовано початкову ініціалізацію мікроконтролера.

Склад та конфігурація бібліотеки STM32F10x SPL

Бібліотека складається з однойменних з периферійними модулями вихідних та заголовних файлів з префіксом stm32f10x_.
Наприклад, реалізація взаємодії з модулем USART міститься у файлах stm32f10x_usart.h та stm32f10x_usart.c.
Існують угоди про імена елементів бібліотеки та певні правила кодування, які описані у документації.
Бібліотека містить реалізацію драйверів периферійних модулів мікроконтролера.
У назвах елементів бібліотеки використовуються такі акроніми для модулів периферії:

Акронім Периферійний модуль
ADC аналогово-цифровий перетворювач
BKP регістри резервного копіювання
CAN інтерфейс CAN
CEC контролер споживання
CRC модуль розрахунку контрольної суми
DAC цифро-аналоговий перетворювач
DBGMCU налагодження мікроконтролера
DMA контролер прямого доступу до пам'яті
EXTI контролер зовнішніх переривань
FSMC контролер зовнішньої пам'яті
FLASH Flash-пам'ять програм
GPIO порти введення/виведення загального призначення
I2C інтерфейс I2C
I2S інтерфейс I2S (Sound)
IWDG незалежний сторожовий таймер
NVIC контролер вкладених переривань
PWR контролер живлення
RCC контролер скидання та тактування
RTC контролер реального часу (годинник)
SDIO інтерфейс SDIO
SPI інтерфейс SPI
SysTick системний таймер
TIM базовий таймер або таймер із розширеними можливостями
USART універсальний послідовний синхронно-асинхронний
приймач-передавач
WWDG віконний сторожовий таймер

На основі цих акронімів формуються назви програмних модулів бібліотеки. Вам не обов'язково використовувати усі модулі бібліотеки.
Щоб використати у проекті лише необхідні модулі, бібліотеку потрібно налаштувати.
Для цього в кожному проекті, який використовує бібліотеку STM32F10x SPL, повинен бути заголовний файл stm32f10x_conf.h.

#include "stm32f10x_gpio.h" //#include "stm32f10x_i2c.h" //#include "stm32f10x_iwdg.h" //#include "stm32f10x_pwr.h" #include "stm32f10x_rcch"

#include "stm32f10x_gpio.h"

//#include "stm32f10x_i2c.h"

//#include "stm32f10x_iwdg.h"

//#include "stm32f10x_pwr.h"

#include "stm32f10x_rcc.h"

Для увімкнення потрібного модуля необхідно розкоментувати директиву #includeз відповідним заголовним файлам.
Заголовковий файл stm32f10x_conf.h включений до stm32f10x.h, тому для використання функцій бібліотеки STM32F10x SPL достатньо підключити у своєму вихіднику лише один заголовковий файл stm32f10x.h

// у файлі stm32f10x.h #ifdef USE_STDPERIPH_DRIVER #include "stm32f10x_conf.h" #endif

Повторюся, що в проекті також повинні бути визначені макроси USE_STDPERIPH_DRIVER, USE_FULL_ASSERT і макрос, що задає серію мікроконтролера, що використовується (наприклад STM32F10X_MD для лінійки Medium density).
Якщо ви використовуєте стандартне значення частоти кварцового резонатора і контролер працюватиме на максимальній тактовій частоті 72МГц, нічого більше змінювати не доведеться.
У Makefile необхідно додати список файлів бібліотеки, що компілюються.
Наприклад:

SRC += stm32f10x_rcc.c SRC += stm32f10x_gpio.c

SRC += stm32f10x_rcc. c

SRC += stm32f10x_gpio. c

Використання бібліотеки STM32F10x SPL. Механізми роботи

Для початку програмування з використанням бібліотеки периферії найпростіше дивитися в приклади, що постачаються в комплекті з бібліотекою. Але все ж таки для розуміння коду цих прикладів необхідно мати базові знання з синтаксису та використання бібліотеки.
Всі перелічені раніше периферійні модулі мікроконтролера спочатку є дезактивованими, тактовий сигнал на них не подається і вони не споживають електроенергії.
Для використання периферійного модуля насамперед необхідно подати нею тактовий сигнал. Подання тактового сигналу забезпечує модуль тактування та скидання RCC.
Для цих цілей у бібліотеці існують такі функції:

RCC_AHBPeriphClockCmd(RCC_AHBPeriph_PPPx, ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_PPPx, ENABLE); RCC_APB1PeriphClockCmd(RCC_APB1Periph_PPPx, ENABLE);

RCC_AHBPeriphClockCmd (RCC_AHBPeriph_PPPx, ENABLE);

RCC_APB2PeriphClockCmd (RCC_APB2Periph_PPPx, ENABLE);

RCC_APB1PeriphClockCmd (RCC_APB1Periph_PPPx, ENABLE);

Тут PPP означає назву актоніма модуля (наприклад ADC або USART) , а x – номер периферійного модуля.
Перш за все необхідно дізнатися до якої шини підключений модуль, що використовується вами.
Всього у мікроконтролерів з архітектурою ядра Cortex-M3 є три шини:
шина інструкцій, шина даних та системна шина. Шина інструкцій поєднує ядро ​​з Flash - пам'яттю програм. Шини даних та системна об'єднані в матрицю шин AHB (ARM Hi-Speed ​​Bus), яка працює на частоті ядра. Однак частота шини AHB може бути знижена шляхом встановлення дільників. Через шину AHB з'єднуються високошвидкісні пристрої, наприклад, ядро ​​і модуль ПДП.
Пристрої введення/виводу приєднуються до шини AHB через проміжні шини APB1 та APB2 (ARM Peripheral Bus).
Максимальна частота роботи шини APB2 становить 72МГц, частота шини APB1
обмежена значенням 36МГц.
До якої з шин підключено задіяний вами периферійний модуль можна дізнатися з документації або подивитися в заголовному файлі stm32f10x_rcc.h.
Відкрийте цей файл і послідовно виконайте пошук значень RCC_AHBPeriph, RCC_APB1Periph і RCC_APB2Periph.

#define RCC_AHBPeriph_DMA1 ((uint32_t)0x00000001) #define RCC_AHBPeriph_DMA2 ((uint32_t)0x00000002) #define RCC_AHBPeriph_SRAM ((uint32_t00) ((uint32_t)0x00000010) #define RCC_AHBPeriph_CRC ((uint32_t)0x00000040)

#define RCC_AHBPeriph_DMA1 ((uint32_t)0x00000001)

#define RCC_AHBPeriph_DMA2 ((uint32_t)0x00000002)

#define RCC_AHBPeriph_SRAM ((uint32_t)0x00000004)

#define RCC_AHBPeriph_FLITF ((uint32_t)0x00000010)

#define RCC_AHBPeriph_CRC ((uint32_t)0x00000040)

За назвами макросів визначаємо, які модулі до яких шин підключені. Також визначення приналежності до однієї з трьох шин можна скористатися здоровим глуздом. Наприклад, модуль USART є пристроєм вводу/виводу, отже, підключений до однієї з шин APB. USART є досить низькошвидкісним інтерфейсом, тому напевно він підключений до шини APB1.

#define RCC_APB1Periph_USART2 ((uint32_t)0x00020000) #define RCC_APB1Periph_USART3 ((uint32_t)0x00040000) #define RCC_APB1Periph_UART4 ((uint32 ph_UART5 ((uint32_t)0x00100000)

Після подачі тактового сигналу на периферійний модуль можна налаштувати параметри шляхом виклику функції ініціалізації:

PPP_Init(PPP, &PPP_InitStructure);

PPP_Init (PPP, & amp; PPP_InitStructure);

Оскільки для ініціалізації периферійного модуля в функцію ініціалізації необхідно передати безліч параметрів, то аргументом використовується покажчик на структуру. Сама ж структура з параметрами ініціалізації має бути створена у пам'яті до виклику функції ініціалізації, елементам структури мають бути присвоєні необхідні значення:

PPP_InitTypeDef PPP_InitStructure = ( val1, val2, …, valN);/* ініціалізація структури при оголошенні*/

Можна спочатку створити структуру, а потім привласнити її елементам необхідні значення:

PPP_InitTypeDef PPP_InitStructure; PPP_InitStructure.member1 = val1; PPP_InitStructure.member2 = val2; PPP_InitStructure.memberN=valN;

PPP_InitTypeDef PPP_InitStructure ;

PPP_InitStructure . member1 = val1;

PPP_InitStructure . member2 = val2;

PPP_InitStructure . memberN = valN;

Розглянемо приклад із проекту stm32f10xQuickstart:

GPIO_InitTypeDef GPIO_InitStructure; #ifdef USE_STM32H_103 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12; GPIO_InitStructure.GPIO_Speed ​​= GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_Init(GPIOC, &GPIO_InitStructure);

GPIO_InitTypeDef GPIO_InitStructure ;

#ifdef USE_STM32H_103

RCC_APB2PeriphClockCmd (RCC_APB2Periph_GPIOC, ENABLE);

GPIO_InitStructure . GPIO_Pin = GPIO_Pin_12;

GPIO_InitStructure . GPIO_Speed ​​= GPIO_Speed_50MHz;

GPIO_InitStructure . GPIO_Mode = GPIO_Mode_Out_PP;

GPIO_Init (GPIOC, & amp; GPIO_InitStructure);

Елементам структури GPIO_InitStructure надається значення номера виводу, режим та швидкість роботи порту.
Викликом функції GPIO_Init здійснюється ініціалізація лінії 12 порту GPIOC.
Перший аргумент функції GPIO_Init є покажчиком на область пам'яті периферійного пристрою GPIOC, перетворений на покажчик на структуру GPIO_TypeDef.

// stm32f10x.h #define GPIOC ((GPIO_TypeDef *) GPIOC_BASE) #define GPIOC_BASE (APB2PERIPH_BASE + 0x1000) #define APB2PERIPH_BASE (PERIPH_BASE + 0x10000) 00) typedef struct (__IO uint32_t CRL; __IO uint32_t CRH __IO uint32_t IDR; __IO uint32_t BRR;

// stm32f10x.h

#define GPIOC ((GPIO_TypeDef *) GPIOC_BASE)

#define GPIOC_BASE (APB2PERIPH_BASE + 0x1000)

#define APB2PERIPH_BASE (PERIPH_BASE + 0x10000)

#define PERIPH_BASE ((uint32_t)0x40000000)

typedef struct

IO uint32_t CRL;

IO uint32_t CRH;

IO uint32_t IDR;

IO uint32_t ODR;

IO uint32_t BSRR;

IO uint32_t BRR;

IO uint32_t LCKR;

) GPIO_TypeDef;

Структура GPIO_InitStructure має тип GPIO_InitTypeDef, описана в заголовку
stm32f10x_gpio.h:

//stm32f10x_gpio.h typedef struct ( uint16_t GPIO_Pin; GPIOSpeed_TypeDef GPIO_Speed; GPIOMode_TypeDef GPIO_Mode; )GPIO_InitTypeDef; typedef enum ( GPIO_Speed_10MHz = 1, GPIO_Speed_2MHz, GPIO_Speed_50MHz )GPIOSpeed_TypeDef; typedef enum ( GPIO_Mode_AIN = 0x0, GPIO_Mode_IN_FLOATING = 0x04, GPIO_Mode_IPD = 0x28, GPIO_Mode_IPU = 0x48, GPIO_Mode_Out_OD = 0x14, GPIO_Mode_Out_PP = 0 Mode_AF_PP = 0x18) GPIOMode_TypeDef;

//stm32f10x_gpio.h

typedef struct

uint16_t GPIO_Pin;

GPIOSpeed_TypeDef GPIO_Speed ​​;

GPIOMode_TypeDef GPIO_Mode ;

) GPIO_InitTypeDef ;

typedef enum

GPIO_Speed_10MHz = 1 ,

GPIO_Speed_2MHz ,

GPIO_Speed ​​_ 50MHz

) GPIOSpeed_TypeDef ;

typedef enum

( GPIO_Mode_AIN = 0x0 ,

GPIO_Mode_IN_FLOATING = 0x04 ,

GPIO_Mode_IPD = 0x28

GPIO_Mode_IPU = 0x48

GPIO_Mode_Out_OD = 0x14 ,

GPIO_Mode_Out_PP = 0x10 ,

GPIO_Mode_AF_OD = 0x1C ,

GPIO_Mode_AF_PP = 0x18

) GPIOMode_TypeDef;

Як бачите, як типи даних структури, що ініціалізується, можуть використовуватися як користувальницькі типи, на кшталт GPIOSpeed_TypeDef, і типи даних з певними значеннями для зручності ініціалізації регістрів периферії, на зразок GPIOMode_TypeDef.
Для конфігурування кожного виводу GPIO виділено 4 біти.
На наступній картинці відображається формат для нульового біта GPIO:

Mode – режим виведення (вхід/вихід). Точніше цих значень дещо більше, налаштовані як вихідні, порти мають обмеження максимальної частоти сигналу, що виводиться.

Режим Mode Опис
00 Вхід
01 вихід із частотою до 10МГц
10 вихід із частотою до 2МГц
11 вихід із частотою до 50МГц

CNF – біти зміни висновку. Залежать від режиму роботи:

Погодьтеся, що за такої структури регістру конфігурації висновків встановлювати самостійно всі біти конфігурації буде вкрай незручно. Набагато простіше це зробити за допомогою бібліотечної функції GPIO_Init.
Після того, як ви ініціалізуєте модуль периферії, його необхідно активувати за допомогою функції PPP_Cmd:

PPP_Cmd(PPP, ENABLE);

PPP_Cmd (PPP, ENABLE);

Для модулів GPIO цієї функції немає, після ініціалізації ви можете відразу користуватися висновками GPIO. Необхідно пам'ятати, що бібліотека надає лише інтерфейс апаратури мікроконтролера. Якщо апаратний модуль не має прапора активації/деактивації, то й виклик функції PPP_Cmd(PPP, ENABLE)неможливий.
Для керування станом виведення GPIOx у режимі виходу та зчитування значення у режимі входу або виходу в бібліотеці передбачені такі функції:

void GPIO_SetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin); void GPIO_ResetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin); uint8_t GPIO_ReadOutputDataBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin); uint16_t GPIO_ReadOutputData(GPIO_TypeDef* GPIOx); uint8_t GPIO_ReadInputDataBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin); uint16_t GPIO_ReadInputData(GPIO_TypeDef* GPIOx);

void GPIO_SetBits (GPIO_TypeDef * GPIOx, uint16_t GPIO_Pin);

void GPIO_ResetBits (GPIO_TypeDef * GPIOx, uint16_t GPIO_Pin);

uint8_tGPIO_ReadOutputDataBit(GPIO_TypeDef* GPIOx, uint16_tGPIO_Pin) ;

uint16_tGPIO_ReadOutputData(GPIO_TypeDef* GPIOx) ;

uint8_tGPIO_ReadInputDataBit(GPIO_TypeDef* GPIOx, uint16_tGPIO_Pin) ;

uint16_tGPIO_ReadInputData(GPIO_TypeDef* GPIOx) ;

Аналогічним чином проводиться налаштування та робота з іншими периферійними модулями. Однак існують деякі відмінності у зв'язку зі специфікою апаратного модуля, тому я настійно рекомендую спочатку переглянути приклади використання обраного модуля для бібліотеки STM32F10x SPL.

Обробка переривань та винятків

У складі ядра Cortex-M3 є контролер вкладених векторизованих переривань. Контролер підтримує до 240 джерел, які можуть спричинити переривання процесорного ядра. Скільки векторів з 240 можливих реалізовано у конкретній моделі мікроконтролера залежить від виробника. У мікроконтролерів цих векторів stm32f10x може бути до 43. Ці лінії переривань називаються маскованими. Крім того існує 15 векторів переривань ядра Cortex-M3 і одне зовнішнє переривання EXTI, що не маскується.
Контролер підтримує вкладені переривання, коли всередині одного оброблювача може виникнути інше переривання. У зв'язку з цим кожне джерело переривання має пріоритет. Підтримується 16 рівнів пріоритетів переривань.
Найвищі значення пріоритетів мають вектори переривань ядра Cortex-M3.
Три найвищі рівні переривань закріплені за векторами жорстко і не можуть бути змінені:

Номер Обробник Пріоритет Опис
1 Reset_Handler -3(Найвищий) Вектор скидання
2 NMI_Handler -2 Немасковане переривання
3 HardFault_Handler -1 Аварійні стани

Всім іншим векторам переривань можуть бути рівні пріоритету від 0 до 15.
Найвищому рівню пріоритету відповідає менше його значення. Рівень пріоритету можна призначити як окремому вектору, а й цілій групі векторів. Така можливість полегшує роботу з великою кількістю векторів переривань.
Для встановлення групи пріоритетів використовується функція із бібліотеки STM32F10x SPL.

Давно, навіть дуже давно, не було нових статей на нашій статті, так що настав час надолужувати 😉 Сьогодні ми започаткуємо вивчення STM32F4. І, мабуть, почнемо зі створення нового проекту для цих контролерів, хоча я не хотів, чесно кажучи, про це писати статтю, оскільки новий проектТут створюється, в принципі, так само як і для STM32F103(). Але все-таки буває, що саме з STM32F4 виникають деякі труднощі, так що все-таки розглянемо цей процес у подробицях)

Отже, запускаємо Keil, створюємо новий проект – Project -> New uVision Project.Зберігаємо новий проект у якійсь папці, і потім нам запропонують вибрати мікроконтролер, що використовується. Що ж, вибираємо, нехай це буде STM32F407VG:

Готово, в діалоговому вікні тикаємо «Так» і до нас в проект додасться перший файл – startup_stm32f4xx.s. Також як і раніше, ми будемо використовувати бібліотеки CMSISі Standard Peripheral LibraryАле, звичайно, вже для контролерів STM32F4xx. Так що треба їх обов'язково завантажити і додати потрібні файли до нашого поки що порожнього проекту. До речі, не раз чув від різних людей, що трапляються якісь «не такі» бібліотеки для F4, і проект навіть найпростіший не збирається. Сам я з таким не стикався, проте ось перевірені бібліотеки, які я сам використовую:

Отже, завантажили, все готово, тепер додаємо файли до проекту. На малюнку видно, які знадобляться:

Ну ось і закінчена підготовка, тепер створимо новий файл, в якому і буде наш код. Ідемо в File->New, в Keil'і відкривається порожній файл, тиснемо File->Save asта зберігаємо його під ім'ям test.c, наприклад. Не забуваймо при збереженні вказати розширення файлу (.c). Файл створили, відмінно, але треба його ще й у наш проект додати. Ну, власне, в цьому нічого складного немає 😉 У цей файл запишемо порожню тестову програму:

#include "stm32f4xx.h" #include "stm32f4xx_rcc.h" #include "stm32f4xx_gpio.h" /*******************************************************************/ int main() ( while (1 ) ( __NOP() ; ) ) /*******************************************************************/

Майже все вже готове, залишилося зазирнути у налаштування проекту – Project->Options for target…Відкривається віконце з безліччю вкладок, нас цікавлять лише кілька. Відкриваємо вкладку C/C++і в полі Define прописуємо:

Ну і внизу у полі треба додати шляхи до всіх файлів, включених у проект. Після цього кроку можна тиснути на F7 (Build), і проект збереться без помилок і попереджень. Як бачите, нічого складного)

Але взагалі я особисто роблю трохи інакше. Дивіться у чому мінус такого підходу. Ось ми завантажили собі кудись бібліотеки CMSIS та SPL, додали файли з цих папок, прописали шляхи до файлів, все круто. АЛЕ! Проект не збереться на іншому комп'ютері, оскільки всі шляхи абсолютні, тобто вказують на конкретні папки на вашому комп'ютері. І на іншій машині доведеться фактично наново виконувати дії щодо створення нового проекту. Це величезний мінус. Тому я зазвичай створюю окрему папку для нового проекту, в ній створюю підпапки для CMSIS, SPL та інших бібліотек, що використовуються, і в ці папки запихаю всі файли, які мені знадобляться в кожному конкретному проекті. Ось, наприклад, створимо папку STM32F4_Test для нового проекту і в ній наступні папки:

У папки CMSIS та SPL я засунув усі необхідні файли, які ми додавали, створюючи проект на початку статті. Тепер запускаємо Keil, створюємо новий проект і зберігаємо його в нашу підпапку Project, щоб усі файли проекту лежали в одному місці і не влаштовували хаос)

Проект створений, тепер, як і раніше, просто додаємо в нього всі файли з папок STM32F4_CMSIS і STM32F4_SPL. У папку Source запихаємо наш тестовий файл з функцією main() і його теж додаємо в проект. Залишилося налаштувати налаштування =) Все те саме – у полі define прописуємо:

USE_STDPERIPH_DRIVER,STM32F4XX



Збираємо проект - помилок немає, політ нормальний! У принципі в результаті отримали те саме, але тепер проект без проблем відразу збиратиметься на будь-якому іншому комп'ютері, а це дуже зручно і корисно) Абсолютно всі файли проекту тепер лежать поруч, в одній папці, а шляхи стали відносними і їх не доведеться міняти .
На цьому те, що все, найближчим часом щось поробимо для програмування STM32F4, обов'язково, так що до швидкого!;)

Повний проект із прикладу статті –

Я вказував, що до системи підключається стандартна бібліотека. Насправді, підключається CMSIS – система узагальненого структурного представлення МК, а також SPL – стандартна бібліотека периферії. Розглянемо кожну з них:

CMSIS
Являє собою набір заголовних файлів та невеликого набору коду для уніфікації та структурування роботи з ядром та периферією МК. По суті, без цих файлів неможливо нормально працювати із МК. Отримати бібліотеку можна на сторінці документації, що супроводжує, до МК.
Ця бібліотека якщо вірити опису створювалася для уніфікації інтерфейсів при роботі з будь-яким МК сімейства Cortex. Проте, насправді виходить, що це справедливо лише одного виробника, тобто. перейшовши на МК іншої фірми, ви змушені вивчати його периферію майже з нуля.
Хоча ті файли, що стосуються процесорного ядра МК, у всіх виробників ідентичні (хоча б тому, що модель процесорного ядра у них одна - надана у вигляді ip-блоків компанією ARM).
Тому робота з такими частинами ядра як регістри, інструкції, переривання та співпроцесорні блоки є стандартною для всіх.
Що стосується периферії то у STM32 і STM8 (раптово) вона майже схожа, також це частково справедливо і для інших МК випущених компанією ST. У практичній частині, я покажу наскільки просто використовувати CMSIS. Однак труднощі у його використанні пов'язані з небажанням людей читати документацію та розумітися на пристрої МК.

SPL
Standard Peripheral Library – стандартна бібліотека периферії. Як випливає з назви, призначення бібліотеки - створення абстракції для периферії МК. Бібліотека складається з заголовних файлів, де оголошено людино-зрозумілі константи для конфігурування та роботи з периферією МК, а також файли вихідного коду, що збираються власне в саму бібліотеку для операцій з периферією.
SPL є абстракцією над CMSIS представляючи користувачеві загальний інтерфейс для всіх МК не тільки одного виробника, а й взагалі всіх МК із процесорним ядром Cortex-Mxx.
Вважається, що вона зручніша новачкам, т.к. дозволяє не думати як працює периферія, проте якість коду, універсальність підходу та скутість інтерфейсів накладають на розробника певні обмеження.
Також функціонал бібліотеки не завжди дозволяє точно реалізувати налаштування деяких компонентів таких як USART (універсальний синхронно-асинхронний послідовний порт) у певних умовах. У практичній частині я також опишу роботу з цією частиною бібліотеки.

Всім привіт. Як Ви пам'ятаєте у минулій статті, ми налаштували програмний комплексдля роботи з мікроконтролерами STM32 та скомпілювали першу програму. У цьому записі познайомимося з архітектурою цієї плати, мікроконтролера та наявні бібліотеки для роботи.

Нижче наведено малюнок плати STM32F3 Discovery де: 1 - MEMS датчик. 3-осьовий цифровий гіроскоп L3GD20. 2 - МЕМС система-в-корпусі, що містить 3-осьовий цифровий лінійний акселерометр і 3-осьовий цифровий геомагнітний сенсор LSM303DLHC. 4 – LD1 (PWR) – живлення 3.3V. 5 – LD2 – червоний/зелений світлодіод. За промовчанням червоний. Зелений означає зв'язок між ST-LINK/v2 (or V2-B) та ПК. У мене ST-LINK/v2-B, а також індикації користувача порту USB. 6. -LD3/10 (red), LD4/9 (blue), LD5/8 (orange) та LD6/7 (green). Минулого запису ми з Вами блимали світлодіодом LD4. 7. – Дві кнопки: користувальницька USER та скидання RESET. 8. - USB USER with Mini-B connector.

9 — USB відладчик/програматор ST-LINK/V2. 1 0. - Мікроконтролер STM32F303VCT6. 11. - Зовнішній високочастотний генератор 8 МГц. 12. – Тут має бути низькочастотний генератор, на жаль не запаяний. 13. - SWD - інтерфейс. 14. – Джемпери для вибору програмування зовнішніх контролерів або внутрішнього, у першому випадку мають бути видалені. 15 - Джемпер JP3 - перемичка, призначена для підключення амперметра, щоб виміряти споживання контролера. Якщо вона видалена, то наш камінчик не запуститься. 16. - STM32F103C8T6 на ньому знаходиться налагоджувальна плата. 17. - LD3985M33R Регулятор з низьким падінням напруги та рівнем шуму, 150мА, 3.3В.

Тепер познайомимося з архітектурою мікроконтролера STM32F303VCT6. Його технічна характеристика: корпус LQFP-100, ядро ​​ARM Cortex-M4, максимальна частота ядра 72МГц, обсяг пам'яті програм 256 Кбайт, тип пам'яті програм FLASH, Об `єм оперативної пам'яті SRAM 40 кбайт, RAM 8 кбайт, кількість входів/виходів 87, інтерфейси (CAN, I²C, IrDA, LIN, SPI, UART/USART, USB), периферія (DMA, I2S, POR, PWM, WDT), АЦП/ЦАП 4 *12 bit/2*12bit, напруга живлення 2 …3.6 У, робоча температура –40 …...+85 З. На малюнку нижче розпинування, де бачимо 87 портів ввода/вывода, 45 їх Normal I/Os (TC, TTa), 42 5-volt tolerant I/Os (FT, FTf) - сумісні з 5 В. (На платі праворуч 5В висновки, зліва 3,3В). Кожна цифрова лінія введення-виведення може виконувати функцію лінії введення-виводу загального
призначення чи альтернативну функцію. По ходу просування проектів ми з Вами будемо послідовно знайомитись з периферією.

Розглянемо блок діаграму нижче. Серцем є 32-бітове ядро ​​ARM Cortex-M4, що працює до 72 МГц. Має вбудований блок з плаваючою комою FPU та блок захисту пам'яті MPU, вбудовані макро-осередки трасування - Embedded Trace Macrocell (ETM), які можуть бути використані для спостереження за процесом виконання основної програми всередині мікроконтролера. Вони здатні безперервно виводити дані цих спостережень через контакти ETM доти, доки пристрій працює. NVIC (Nested vectored interrupt controller) – модуль контролю переривань. TPIU (Trace Port Interface Unit). Містить пам'ять FLASH -256 Кбайт, SRAM 40 КБ, RAM 8 КБ. Між ядром та пам'яттю розташована Bus matrix (Шинна матриця), яка дозволяє з'єднати пристрої безпосередньо. Також тут бачимо два типи шинної матриці AHB та APB, де перша більш продуктивна та використовується для зв'язку високошвидкісних внутрішніх компонентів, а остання для периферії (пристроїв введення/виведення). Контролер має 4-рі 12-розрядних ADC (АЦП) (5Мбіт/с) і датчик температури, 7 компараторів (GP Comparator1 …7), 4-ри програмованих операційних підсилювача (OpAmp1…4) (PGA (Programmable Gain Array)), 2 12 розрядних каналу DAC (ЦАП), RTC (годинник реального часу), два сторожові таймери — незалежний та віконний (WinWatchdog and Ind. WDG32K), 17 таймерів загального призначення та багатофункціональні.

Загалом ми розглянули архітектуру контролера. Тепер розглянь доступні програмні бібліотеки. Зробивши огляд можна виділити такі: CMSIS, SPL та HAL. Розглянемо кожну застосувавши в простому прикладі блимаючи світлодіодом.

1). CMSIS(Cortex Microcontroller Software Interface Standard) – стандартна бібліотека для Cortex®-M. Забезпечує підтримку пристроїв та спрощує програмні інтерфейси. CMSIS надає послідовні та прості інтерфейсидля ядра, його периферії та операційних систем реального часу. Її використання професійним способом написання програм, т.к. передбачає прямий запис у регістри і відповідно необхідне постійне читання та вивчення даташитів. Незалежно від виробника апаратного рівня.
CMSIS включає наступні компоненти:
- CMSIS-CORE: Consistent system startup and peripheral access (Постійний запуск системи та периферійний доступ);
— CMSIS-RTOS: Deterministic Real-Time Software Execution (Детерміноване виконання програмного забезпеченняреального часу);
- CMSIS-DSP: Fast implementation of digital signal processing (Швидка реалізація цифрової обробкисигналів);
- CMSIS-Driver: Generic peripheral interfaces for middleware and application code (Загальні периферійні інтерфейси для проміжного програмного забезпечення та програмного коду);
— CMSIS-Pack : Easy access to reusable software components (Легкий доступ до багаторазового використання) програмним компонентам);
— CMSIS-SVD: Consistent view to device and peripherals (Узгоджене подання пристрою та периферійних пристроїв);
— CMSIS-DAP: Connectivity to low-cost evaluation hardware (Можливість підключення до недорогого обладнання для оцінки). ПЗ для налагодження.

Наприклад напишемо програму – блимаємо світлодіодом. Для цього нам знадобиться документація, що описує регістри. В моєму випадку RM0316 Reference manual STM32F303xB/C/D/E, STM32F303x6/8, STM32F328x8, STM32F358xC, STM32F398xE advanced ARM ® -based MCUs , а також опис конткретної ніжки DS9118: ARM®-based Cortex®-M4 32b MCU+FPU, до 256KB Flash+ 48KB SRAM, 4 ADCs, 2 DAC ch., 7 comp, 4 PGA, timers, 2.0-3.6 V.Спочатку в програмі затактуємо порт, т.к. за замовчуванням все відключено, чим досягається зменшене ергоспоживання. Відкриваємо Reference manual і дивимося розділ Reset and clock control далі RCC register map і дивимося, що за включення IOPEEN відповідає регістр

Перейдемо до опису тактування перефірії даного регістру AHB peripheral clock enable register (RCC_AHBENR), де бачимо, що даний порт знаходиться під 21-м бітом. Включаємо його RCC-> AHBENR | = (1<<21) . Далее сконфигурируем регистры GPIO. Нас интересует три: GPIOE_MODER и GPIOx_ODR . C помощью них повторим программу с предыдущей статьи, затактируем PE8. Первый отвечает за конфигурацию входа выхода, выбираем 01: General purpose output mode. GPIOE->MODER | = 0 × 10000 . Другий за включення низького/високого рівня на ніжці. Нижче програма:

#include "stm32f3xx.h // Заголовний файл мікроконтролера
unsigned int i;
void delay () (
for (i=0;i<500000;i++);
}
int main (void) (
RCC-> AHBENR | = (1<<21);
GPIOE->MODER|=0×10000;
while (1)(
delay();
GPIOE-> ODR | = 0 × 100;
delay();
GPIOE->ODR&=~(0×100);
} }

2). SPL(Standard Peripherals Library)- Ця бібліотека призначена для об'єднання всіх процесорів фірми ST Electronics. Розроблена для зрощення терпимості коду і в першу чергу розрахована на початківця розробника. ST працювала над заміною SPL під назвою "low layer", яка сумісна з HAL. Драйвери Low Layer (LL) розроблені для забезпечення майже легкого експертно-орієнтованого рівня, який є ближчим до обладнання, ніж HAL. На додаток до HAL також доступні LL API. Приклад тієї ж програми на SPL.

#include
#include
#include
#define LED GPIO_Pin_8
int main() (
long i;
GPIO_InitTypeDef gpio;
// Blue LED connected to port E, pin 8 (AHB bus)
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOE, ENABLE);
// Configure port E (LED)
GPIO_StructInit(&gpio); //оголошуємо та ініціалізуємо змінну структури даних
gpio.GPIO_Mode = GPIO_Mode_OUT;
gpio.GPIO_Pin = LED;
GPIO_Init(GPIOE, &gpio);
// Blinking LEDS
while (1) (
// On
GPIO_SetBits(GPIOE, LED);
for (i = 0; i< 500000; i++);
// All off
GPIO_ResetBits(GPIOE, LED);
for (i = 0; i< 500000; i++);
} }

Кожна функція описується у технічній документації UM1581 User manual Description of STM32F30xx/31xx Standard Peripheral Library. Тут підключаємо три заголовні файли які містять необхідні дані, структури, функції управління скиданням і синхронізацією, а також для конфігурації портів вводу/виводу.

3). HAL- (Hardware Acess Level, Hardware Abstraction Layer)– Ще одна спільна бібліотека для розробки. З якої вийшла й програма CubeMX для конфігурації, яку ми з Вами використовували у попередній статті. Там ми написали програму миготіння світлодіодом використовуючи цю бібліотеку. Як бачимо на малюнку нижче, куб генерує драйвера HAL and CMSIS. Що ж опишемо основні файли, що використовуються:
- system_stm32f3x.c і system_stm32f3x.h- надають мінімальні набори функцій зміни системи тактирования;
- core_cm4.h - надає доступ до регістрів ядра та його периферії;
- stm32f3x.h - заголовний файл мікроконтролера;
- startup_system32f3x.s - стартовий код, містить таблиця векторів переривань та ін.

#include «main.h»
#include «stm32f3xx_hal.h»
void SystemClock_Config (void); /*Оголошуємо функції конфігурації тактування*/
static void MX_GPIO_Init (void); /*Ініціалізація введення/виводу*/
int main (void) (
/*Reset of all peripherals, Initializes the Flash interface and the Systick.*/
HAL_Init();
/* Configure the system clock */
SystemClock_Config();
/* Initialize all configured peripherals */
MX_GPIO_Init();
while (1) (
HAL_GPIO_TogglePin (GPIOE, GPIO_PIN_8); //Переключаємо стан ніжки
HAL_Delay (100); )
}
void SystemClock_Config (void){
RCC_OscInitTypeDef RCC_OscInitStruct;
RCC_ClkInitTypeDef RCC_ClkInitStruct;

RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
RCC_OscInitStruct.HSIState = RCC_HSI_ON;
RCC_OscInitStruct.HSICalibrationValue = 16;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE;
if (HAL_RCC_OscConfig (&RCC_OscInitStruct) != HAL_OK){

}
/**Initializes the CPU, AHB і APB busses clocks */
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_HSI;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
if (HAL_RCC_ClockConfig (&RCC_ClkInitStruct, FLASH_LATENCY_0) != HAL_OK){
_Error_Handler (__FILE__, __LINE__);
}
/**Configure the Systick interrupt time*/
HAL_SYSTICK_Config (HAL_RCC_GetHCLKFreq()/1000);
/**Configure the Systick */
HAL_SYSTICK_CLKSourceConfig (SYSTICK_CLKSOURCE_HCLK);
/* SysTick_IRQn interrupt configuration */
HAL_NVIC_SetPriority (SysTick_IRQn, 0, 0);
}
/** Configure pins as Analog Input Output EVENT_OUT EXTI */
static void MX_GPIO_Init (void){
GPIO_InitTypeDef GPIO_InitStruct;
/* GPIO Ports Clock Enable */
__HAL_RCC_GPIOE_CLK_ENABLE();
/*Configure GPIO pin Output Level */
HAL_GPIO_WritePin (GPIOE, GPIO_PIN_8|GPIO_PIN_9|GPIO_PIN_10|GPIO_PIN_11
|GPIO_PIN_12|GPIO_PIN_13|GPIO_PIN_14|GPIO_PIN_15, GPIO_PIN_RESET);
/*Configure GPIO pins: PE8 PE9 PE10 PE11 PE12 PE13 PE14 PE15 */
GPIO_InitStruct.Pin = GPIO_PIN_8|GPIO_PIN_9|GPIO_PIN_10|GPIO_PIN_11
|GPIO_PIN_12|GPIO_PIN_13|GPIO_PIN_14|GPIO_PIN_15;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed ​​= GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init (GPIOE, &GPIO_InitStruct);
}
void _Error_Handler (char * file, int line){
while (1) (
} }
#ifdef USE_FULL_ASSERT

Void assert_failed (uint8_t* file, uint32_t line){
}
#endif
Тут також як і в попередньому прикладі можемо переглянути опис кожної функції документації, наприклад UM1786 User Manual Description of STM32F3 HAL and low-layer drivers.

Можемо підсумувати, що перший варіант, використовуючи CMSIS, є менш громіздким. Для кожної бібліотеки є документація. У наступних проектах ми будемо використовувати HAL і CMSIS, використовуючи програму для конфігурації STCube і по можливості використовувати регістри безпосередньо без програмних обгорток. На цьому й зупинимося. У наступній статті ми з Вами розглянемо основні засади побудови розумного будинку. Бувайте усі.




Top