- PVSM.RU - https://www.pvsm.ru -
Добрый день, уважаемыее. В своих прошлых статьях (STM32F1xx — лечимся от ардуинозависимости вместе [1], STM32F1хх — продолжаем лечение от ардуинозависимости при помощи LCD [2]) я постарался осветить вопросы перехода с 8-битных микроконтроллеров на новые 32-битные STM32F1xx.
В процессе работы с ними, я, разумеется выбирал инструменты себе «по руке» — то есть, старался найти наиболее удобные для меня отладочные платы, программаторы, IDE. В этой статье я хочу поделиться с вами несколькими соображениями на этот счет, а также описать процесс сборки в выбранной IDE операционной системы реального времени FreeRTOS.
Традиционно начнем с железа.
В прошлых статьях ядром системы была плата STM32VLDISCOVERY [3].
Плата, безусловно, хороша, и подкупает тем, что ее цена всего 300 рублей. В принципе, хороший инструмент для того, чтобы начать знакомиться с этим семейством микроконтроллеров. Но.
Дело в том, что при выборе отладочной платы, всегда хочется соблюсти баланс количества и качества, то есть с одной стороны, иметь все необходимое для работы, с другой – не хочется чтобы плата превращалась в огромного и дорогого монстра. У STM32VLDISCOVERY баланс смещен в сторону дешевизны и минимализма.
Полазив по e-bay, я нашел для себя более удобную, на мой взгляд, плату, которую и представляю вашему вниманию. Вот она:
Mini-STM32 [4]
За 46 долларов нам предлагают:
#define LCDRegister (*((volatile u16*) 0x60000000)) #define LCDMemory (*((volatile u16*) 0x60020000)) //… void LCDWriteRegister(unsigned short reg, unsigned short data) { LCDRegister=reg; LCDMemory=data; } void LCDBeginRAMWrite() { LCDRegister=CTR_WRITE_DATA; } int main(void) { //… RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE); DMA_InitTypeDef DMA_InitStructure; DMA_DeInit(DMA1_Channel1); //Адрес буфера-источника графики DMA_InitStructure.DMA_PeripheralBaseAddr = (u32) PlasmaBuffer1; //Адрес «точки мапирования» дисплейной памяти DMA_InitStructure.DMA_MemoryBaseAddr = (u32)(&LCDMemory); DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC; DMA_InitStructure.DMA_BufferSize = PLASMA_WIDTH*PLASMA_HEIGHT; DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Enable; DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Disable; DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord; DMA_InitStructure.DMA_Mode = DMA_Mode_Normal; DMA_InitStructure.DMA_Priority = DMA_Priority_High; DMA_InitStructure.DMA_M2M = DMA_M2M_Enable; DMA_Init(DMA1_Channel1, &DMA_InitStructure); //… //Собственно, вывод LCDBeginRAMWrite(); DMA_SetCurrDataCounter(DMA1_Channel1, PLASMA_WIDTH*PLASMA_HEIGHT); DMA_Cmd(DMA1_Channel1, ENABLE); }
После выполнения последней строчки, управление возвращается программе, так что можно сразу же начинать просчет следующего кадра, пока первый выводится через DMA.
Кроме того, по отдельной просьбе, за 28 долларов, продавец приложит к плате J-Link-совместимый программатор (а попросту, настоящий клон Segger J-Link, беззастенчиво под него маскирующийся), со шлейфом, полностью совместимым с разъемом на плате.
Подводя итог вышесказанному, я считаю данную плату вещью первой необходимости для человека, который решил начать изучение STM32F1xx микроконтроллеров.
Теперь то, что касается IDE. Изначально я выбрал Keil uVision, так как когда-то уже работал с ней.
Ну, что я могу сказать – я проработал в кейле достаточно, и в принципе с ним можно примириться. Но, положа руку на сердце – ИДЕ там ужасна. Также ужасна как и ИДЕ IAR’a, на мой взгляд.
IAR и Keil – признанные лидеры в разработке компиллеров, этого у них не отнять, но я до сих пор не могу понять, почему, имея такие компиллеры, они продолжают тянуть свои IDE, застрявшие по удобству на уровне 2002 года. Как пример могу привести Texas Instruments – у них раньше тоже была своя IDE, в довесок к компиллеру. Потом им это надоело, они взяли Eclipse, допилили его, прикрутили к своим компиллеру и профайлеру, и получили отличный продукт. Почему так не поступят Keil и IAR для меня остается загадкой, но на мой взгляд их IDE не такие удобные, как могли бы быть. Раздражает не очень удобная подсветка синтаксиса, полное отсутствие code-completion’а, не самая удобная навигация по коду. Плюс, uVision частенько у меня падала, но это можно списать на драйвер программатора.
Как бы то ни было, я стал искать альтернативу и нашел ее в виде CooCox IDE [5].
Это бесплатная среда разработки на базе эклипса, которая призвана работать, разумеется, с GCC.
Из плюсов отмечу все достоинства эклипса – удобная навигация, есть автозавершение кода и т.п.
Кроме того прикручен удобный просмотрщик периферии процессора, мне понравился больше чем Кейловский. Очень удобно наличие репозитория компонентов – говоря по-простому, при старте проекта мы как в визарде выбираем нужный нам процессор из списка, после чего отмечаем галочками те из модулей Standard Peripheral Library, которые хотели бы использовать, и они автоматически подключаются к проекту (Об этом чуть подробнее в следующем разделе статьи). Также сразу же можно просмотреть примеры, идущие в комплекте с этим модулем SPL и справку по его функциям.
Минусы CooCox IDE вобрала также из Eclipse, к коим относится тяжеловесность – у меня она потребляет около 180 метров оперативной памяти, занимая на диске 800 мегабайт.
Еще одним минусом является ее работа с этим самым J-Link-ком. Отладка происходит через приложение от создателей J-Link’a, предоставляющее стандартный gdb-шный интерфейс, но почему-то среда при каждом дебаге это приложение перезапускает, в отличие от того же кейла (который вообще работает через свои дллки).
Поэтому старт отладки в Кейле начинается через секунду, в CooCox же – через секунд 20. Возможно, это можно как-нибудь исправить настройками, но я пока таких настроек не видел, поэтому буду благодарен, если кто подскажет.
Тем не менее, я все таки остановился на CooCox — если вас тоже не устраивает IDE от Keil или IAR, или вы не хотите пользоваться ломанным ПО и предпочитаете опенсорс – качайте не задумываясь.
Об операционной системе FreeRTOS было сказано много, в частности, на хабре (вот, например, одна из статей: FreeRTOS: введение [6])
Я решил тоже приобщиться к этой технологии и расширить свой арсенал инструментов, тем более, что FreeRTOS не навязывает никакого HAL (Hardware Abstraction Layer, слой абстракции от оборудования, драйверы то бишь), и предоставляет только средства работы с задачами, синхронизацию и меж-процессное взаимодействие, поэтому во многих случаях будет очень удобна.
Рассмотрим поподробнее, что же нам необходимо, чтобы использовать FreeRTOS вместе с CooCox IDE на нашей плате Mini-STM32.
На самом деле, все очень просто. Архитектурное портирование (портирование кода, требуемого шедулером под архитектуру Cortex M3) уже давно выполнено, и нам нужно, по сути, просто правильно составить проект для CooCox.
Начинаем с того, что скачиваем исходники FreeRTOS с их официального сайта.
Вот прямая ссылка: http://sourceforge.net/projects/freertos/files/ [7].
Тем временем создаем новый проект в CooCox, я назвал его FreeRTOS-Mini.
Выбираем в визарде производителя ST, в списке чипов – чип, на котором построена отладочная плата, STM32F103VE.
После этого перед нами открывается уже упомянутое окошечко репозитория компонентов, представляющих собой части SPL.
Выбираем там CMSIS Core и CMSIS Boot – это собственно ядро CMSIS и стартовый код, который производит настройку и дергает main()
Кстати, обратите внимание – в CooCox стартовый код написан целиком на C, ни одной асмовой строчки. Лежит в файле cmsis_bootstartupstartup_stm32f10x_hd.c – запомните этот путь, нам нужно будет там кое-что подправить. Заодно добавляем в проект модуль GPIO, чтобы было что поделать в тестовом таске FreeRTOS. Этот модуль автоматом потянет за собой зависимый RCC, отвечающий за настройку клоков.
Теперь возвращаемся к скаченным исходникам FreeRTOS. Для начала скопируем всю папку в папку с нашим проектом. После, начнем удалять лишнее. Итак, лично у меня под нож сразу пошло содержимое папки Demo – там лежат демо-приложения для разных контроллеров, вся папка вам не нужна в любом случае, но при желании можно оставить то, что относится к STM32F103. Единственное, что нам оттуда обязательно понадобится – файл настроек ядра FreeRTOS, который можно взять из любого подходящего проекта, допустим отсюда: DemoCORTEX_STM32F103_Primer_GCCFreeRTOSConfig.h
Его можно скопировать в любую папку инклудов, я лично положил в самый корень проекта, рядом с main.c
Далее, в папке sourceportable есть множество под-папок, где лежит код, рассчитанный на разные компиллеры и среды. Заходим в папку sourceportableGCCARM_CM3, копируем ее двумя уровнями выше, в sourceportable. Обращаем внимание на папку sourceportableMemMang – она нам тоже понадобится. Поэтому удаляем все, кроме sourceportableMemMang и свежескопированной sourceportableARM_CM3
После этого кликаем правой кнопкой в прожект эксплорере CooCox, нажимаем Add Linked Folder и добавляем нашу папку с подготовленными исходниками FreeRTOS. В итоге должно получиться вот такое дерево проекта:
Теперь начинаем править файлы проекта. Начнем с настроек ядра. Оттуда нам нужно будет убрать только пару строчек, связанных со старым проектом – левый, ненужный нам инклуд.
/* Library includes. */ #include "stm32f10x_lib.h"
Все остальное можно оставить без изменений, а можно прочитать статью о настройке ядра FreeRTOS и поменять опции по необходимости, этим мы сейчас заниматься не будем.
Теперь идем в стартап код (cmsis_bootstartupstartup_stm32f10x_hd.c) и делаем следующее: находим строки:
/*----------Function prototypes-----------------------------------------------*/ extern int main(void); /*!< The entry point for the application. */ extern void SystemInit(void); /*!< Setup the microcontroller system(CMSIS) */ void Default_Reset_Handler(void); /*!< Default reset handler */ static void Default_Handler(void); /*!< Default exception handler */
У меня это строки 114-122, и добавляем после них такой код:
extern void xPortPendSVHandler( void ) __attribute__ (( naked )); extern void xPortSysTickHandler( void ); extern void vPortSVCHandler( void ) __attribute__ (( naked ));
Это обработчики прерываний из ядра ОС, которые объявлены в файле port.c. Теперь нам нужно запихнуть их в вектор прерываний, который идет ниже (строки 129-209):
__attribute__ ((section(".isr_vector"))) void (* const g_pfnVectors[])(void) = { /*----------Core Exceptions-------------------------------------------------*/ (void *)&pulStack[STACK_SIZE-1], /*!< The initial stack pointer */ Reset_Handler, /*!< Reset Handler */ NMI_Handler, /*!< NMI Handler */ HardFault_Handler, /*!< Hard Fault Handler */ MemManage_Handler, /*!< MPU Fault Handler */ BusFault_Handler, /*!< Bus Fault Handler */ UsageFault_Handler, /*!< Usage Fault Handler */ 0,0,0,0, /*!< Reserved */ vPortSVCHandler, /*!< SVCall Handler */ DebugMon_Handler, /*!< Debug Monitor Handler */ 0, /*!< Reserved */ xPortPendSVHandler, /*!< PendSV Handler */ xPortSysTickHandler, /*!< SysTick Handler */
Соответственно, меняем вектор так, как написано в вышеизложенном коде, заменив строки, отмеченные SVCall Handler, PendSV Handler, SysTick Handler на vPortSVCHandler, xPortPendSVHandler и xPortSysTickHandler соответственно.
После открываем в дереве проекта папку SourceMemMang, и выбираем ту реализацию мемори менеджмента, которая нам подходит. Подробнее об этом написано тут: FreeRTOS Memory Management [8].
Если коротко – файл номер 1 это упрощенная реализация с выделением памяти, но без освобождения, файл номер 2 – более продвинутая реализация, позволяющая освобождение памяти, и номер 3 – реализация, которая потребует от вас библиотеки с реализованными malloc и free. Я выбрал вторую реализацию, оставшиеся два файла исключаем из компиляции, кликнув правой кнопкой на имя файла в дереве проекта и выбрав пункт Exclude from build.
Осталось совсем чуть-чуть – открываем файл main.c, добавляем туда нужные нам инклуды от SPL:
#include "stm32f10x.h" #include "stm32f10x_gpio.h" #include "stm32f10x_rcc.h"
Инклуды от FreeRTOS:
#include "FreeRTOS.h" #include "task.h" #include "queue.h"
После объявляем функцию, которая будет вызвана до старта шедулера, в соответствии с рекомендациями в таком виде:
static void prvSetupHardware( void );
И функцию, которая будет исполнять роль нашего тестового таска, вот так:
static void prvLedBlink( void *pvParameters );
Реализация функций выглядит так:
void prvSetupHardware() { GPIO_InitTypeDef GPIO_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOB, &GPIO_InitStructure); } void prvLedBlink( void *pvParameters ) { GPIO_SetBits(GPIOB,GPIO_Pin_5); while(1); }
В тестовых целях ничего полезного не написал, задача просто зажигает светодиод на плате.
Осталась сама функция main(), которая стартанет задачу и шедулер:
int main(void) { prvSetupHardware(); xTaskCreate(prvLedBlink,(signed char*)"LED",configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY + 1, NULL); /* Start the scheduler. */ vTaskStartScheduler(); while(1); }
Вот в принципе и все. Осталось настроить дебаг – для этого жмем «Debug configuration», во вкладке Debugger выбираем наш программатор (J-Link) и порт JTAG.
Ставим галочку Run To Main, чтобы не барахтаться в стартап-коде, в строке GDBServer cmdline tool указываем путь к экзешнику, идущему с программатором (скачать можно с сайта Segger [9]), у меня это C:SEGGERJLinkARM_V440bJLinkGDBServerCL.exe
После жмем Apply и Close.
Теперь компиллим наш проект и жмем на дебаг – если все получилось, после аплода и выполнения, должен загореться светодиод.
Правильный выбор инструментов разработчика, безусловно, обеспечит наиболее быстрое и комфортное освоение новых технологий. Я надеюсь, что, осветив в данной статье отладочную плату Mini-STM32 и CooCox IDE, я помог разработчикам приглядеться к новому инструменту. Что касается операционной системы FreeRTOS – это бесспорно очень мощное средство, и, на мой взгляд, хорошая ступень, для перехода от программирования прошивок «в лоб» к использованию эмбеддед операционных систем.
Страничка eBay где можно купить отладочную плату [10]
Официальный сайт CooCox [11]
Официальный сайт FreeRTOS [12]
Русский мануал по FreeRTOS [13]
Автор: Ariman
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/stm32/3195
Ссылки в тексте:
[1] STM32F1xx — лечимся от ардуинозависимости вместе: http://habrahabr.ru/blogs/controllers/123791/
[2] STM32F1хх — продолжаем лечение от ардуинозависимости при помощи LCD: http://habrahabr.ru/blogs/controllers/139384/
[3] STM32VLDISCOVERY: http://www.terraelectronica.ru/catalog_info.php?ID=1001&CODE=573571&Name=STM32VLDISCOVERY&Razdel=%CE%F2%EB%E0%E4%EE%F7%ED%FB%E5%20%E8%20%EE%F6%E5%ED%EE%F7%ED%FB%E5%20%EF%EB%E0%F2%FB%20%E8%20%ED%E0%E1%EE%F0%FB%20%E4%EB%FF%20%F1%E5%EC%E5%E9%F1%F2%E2%E0%20STM32%20(Cortex-M3)&TableName=class_19_2_40_4_6
[4] Mini-STM32: http://www.ebay.com/itm/280580644330?ssPageName=STRK:MEWNX:IT&_trksid=p3984.m1439.l2649
[5] CooCox IDE: http://www.coocox.org/CooCox_CoIDE.htm
[6] FreeRTOS: введение: http://habrahabr.ru/blogs/controllers/129105/
[7] http://sourceforge.net/projects/freertos/files/: http://sourceforge.net/projects/freertos/files/
[8] FreeRTOS Memory Management: http://www.freertos.org/a00111.html
[9] Segger: http://www.segger.com/jlink.html
[10] Страничка eBay где можно купить отладочную плату: http://www.ebay.com/itm/280580644330#ht_2532wt_952
[11] Официальный сайт CooCox: http://www.coocox.org/
[12] Официальный сайт FreeRTOS: http://www.freertos.org/
[13] Русский мануал по FreeRTOS: http://microsin.net/programming/ARM/freertos-part1.html
Нажмите здесь для печати.