Доброго дня! Прошло много времени с тех пор как я последний раз программировал под AVR и вот, решил восстановить в памяти такую, без сомнения интересную и увлекательную область разработки — разработку под микроконтроллеры. В качестве платформы был выбран ARM STM32, и, чтобы не мелочиться, сразу Cortex-M4. Отладочная плата STM32F4DISCOVERY с STM32F407 на борту. Мегабайт флеша и 128 кб памяти дает возможность не сильно заморачиваться экономией ресурсов и писать на C++.
Итак, задача: научиться с нуля моргать светодиодами под STM32 во FreeRTOS, но делать это модно — на C++, а не на чистом C.
Подразумевается, что вы уже работаете с Eclipse, знаете, как ставить в него дополнения и знаете в общих чертах, как работает Linux.
Перечитав кучу мануалов, хаутушек и прочей инфы в интернете я все поставил и… ничего не получилось, не работало, не компилировалось, а если компилировалось — то не заводилось на железке. В итоге, все-таки, все получилось, и, так как я не любитель граблей — решил написать этот пост.
Тулчейн
Установка и настройка среды разработки заняла у меня два дня. Поэтому я приведу набор, который у меня реально заработал и детально опишу проблемы, с которыми столкнулся:
— Eclipse Kepler (для C/C++)
— GCC
— texane / stlink
Заморочка была с GCC для arm-none-eabi. Вариантов тулчейна существует очень много, я пробовал два и реально заработали оба. Однако небольшая разница между ними все же есть:
— GNU Arm toochain можно взять тут
— Mentor Graphics CodeSourcery EABI можно взять тут, попросят ввести свои данные, пришлют ссылку для скачивания на почту..
Кстати, сначала я поставил arm-linux-gnueabi их своего дистра Linux. Не стоит, для наших целей не подойдет, а вот если на вашем ARM стоит Linux — то да, самое оно.
Итак, компилятор ставим, куда вздумается, но обязательно пропишем путь к нему в PATH пользователя. Как это сделать — зависит от операционки, с которой вы работаете. Я закинул в /opt эту пару тулчейнов и сделал симлинк /opt/arm-toolchain — как-бы по-умолчанию.
Программатор
Далее клонируем stlink с Github'a любым удобым способом. Собирается как обычно:
Не забудем про libusb-dev, у меня в Debian Wheezy он не был установлен. Если еще каких-то либ не хватает, ставим их как это делается в вашей системе.
Среда разработки
Далее, самое интересное для меня — настройка клипсы под разработку. Настроить проект так, чтобы все компилировалось и работало на чистом Eclipse у меня не получилось. Поэтому можно поставить полезные плагины. Однако после того, как будет достигнута определенная степень ясности настроек — можно поковыряться и сделать настройку проекта под себя без плагинов.
Есть достаточно разных плагинов для разработки под ARM, вот парочка:
— GNU Arm Eclipse можно взять тут
— Zylin CDT — здесь
Для обоих есть апдейт-сайты, ставятся плагины стандартным для клипсы способом из менюшки. Ставим оба.
Далее, создаем C++ проект в Eclipse, выбираем, что он будет под ARM (тулчейн ARM Cross GCC), далее выбираем тип тулчейна в зависимости от того, какой компилятор вы выбрали: CodeSourcery или ARM GCC. Вообще плагины поддерживают всякие разные наборы компиляторов — можно поиграться и с ними.


Вот тут есть одна проблема — в CodeSourcery я не нашел libnosys.a. Пришлось взять его из GNU Arm GCC. В общем полет нормальный.

Выводы
Теперь, небольшое лирическое отступление о том, какие проблемы решает плагин. С этим придется столкнуться, если вы будете настраивать проект под себя и вы — новичок. Для меня все это было открытием, т.к. прошивок я никогда не писал до этого.
— на контроллере нет libc. Firmware компонуется статически.
— и нет операционной системы (она будет встроена в проект), нет загрузчика — программа начнет выполняться сразу после включения.
Плагин решает кучку задач — он предоставляет сразу нужные нам либы CMSIS и Standard Perepherials в проекте, который мы только что создали. Эти библиотеки нужны, чтобы работать с переферией контроллера.
Можно, конечно, прикрутить libopencm3 вместо библиотек предоставленных производителем, но это тема отдельной статьи.
Также ппагин предоставляет набор linker scripts. Честно говоря, я с ними столкнулся впервые. В linker script'е описывается структура бинарного файла, секции, точка входа и много чего еще. Собирать все это по кусочкам вручную муторно и безынтересно, пока проект еще даже не завелся на железке, зато потом — какой простор для изучения.
Настраивается плагин из свойств проекта, собственно, в проекте они и хранит свои настройки.
Настраиваем отладчик
Вообще, этот кусок можно сделать в самом конце, но то, что отладка заработала — уже является признаком того, что все настроено. Поэтому мы сделаем это заранее.
В качестве отладчика, естественно, используется GDB. Настроим приложение сервера GDB, в качестве которого будет выступать утилита от texane/stlink.
Идем в External Tools и добавляем инструментарий. Его надо будет запускать каждый раз, если нам нужна будет отладка, при подключенной плате. Утилита будет заливать отладочный образ и служить сервером. Ключик -m как раз говорит ей не отваливаться каждый раз, когда соединение с отладчиком будет прервано, что очень удобно на мой взгляд.

Далее создадим таргет отладки. Тут все просто, берем отладчик из тулчейна, указываем порт 4242 — это порт GDB сервера по-умолчанию.

Запускаем сервер отладки, подключаемся к таргету — он соберет проект, зальет бинарник в железку и запустит. Можно отлаживаться.
FreeRTOS
Так как все, что надо для того, чтобы проект вообще мог быть собран нам дал плагин (который, кстати, создал даже темплейт моргалки светодиодом), можно взять собрать его и залить на железку. Если светодиод моргает и все работает, начинаем интегрировать операционку.
Структура проекта, созданного плагином будет иметь каталог libs, где уже лежат CMSIS, StdPeriph и прочее. Вот туда мы и закинем FreeRTOS. Далее, чтобы операционка работала надо ее сконфигруровать. Мануалов (в том числе официальных) по настройке FreeRTOS в интернете валом, поэтому описывать я его тут не буду. Если вкратце, надо сделать следующее:
1) создать FreeRTOSConfig.h и положить его к хидерам от RTOS
2) взять из portable порт для нашей железки и положить файлы порта вместе с остальными исходниками RTOS.
3) найти с исходниках RTOS memory manager, например heap_2.c и положить туда же.
Кстати, в конфиге от RTOS надо указать реальную тактовую процессора, такую же какая была указана при создании проекта. У меня это 168000000.
А также добавить вот это:
И включить vTaskDelay так как он у нас будет исползоваться для ожидания между морганиями светодиода:
Не забудем в клипсе прописать в настройках проекта пути к нашей FreeRTOS:

Вообще в проекте много всяких настроек, из которых формируются параметры компилятора, ассемблера и компоновщика. Можно поиграться, посмотреть что будет ;)
Минимум настроен, теперь можно пытаться собирать. Если что-то забыли — просто не соберется или не будет работать.
А теперьтанцы приложение!
Приложение мы будем писать на C++, причем перейдем от чистого C к C++. Я на этих языках давно не писал, так что не судите строго.
Проект на гитхабе.
С тасками есть один ньюанс, с которым я, при переходе на С++ немного промучался:
Первый параметр — указатель на метод, в котором реализована задача. Четвертый параметр в xTaskCreate — указатель на экземпляр класса Task. Передать указатель на экземпляр необходимо, иначе в методе реализации не будет доступа к переменным класса Task — в данном случае, пину светодиодика и задержке.
Ну а в остальном там все просто. Удачного дня и успешных сборок. Вопросы welcome!
P.S. А какой средой под Linux для этих целей пользуетесь вы? ;)
P.P.S. Надо понимать, что данный пост написан не системным программистом и призван помочь «высокоуровневым» товарищам, желающим войти в мир разработки firmware. Поэтому гуру ассемблера прошу не серчать ^-^
Итак, задача: научиться с нуля моргать светодиодами под STM32 во FreeRTOS, но делать это модно — на C++, а не на чистом C.
Подразумевается, что вы уже работаете с Eclipse, знаете, как ставить в него дополнения и знаете в общих чертах, как работает Linux.
Перечитав кучу мануалов, хаутушек и прочей инфы в интернете я все поставил и… ничего не получилось, не работало, не компилировалось, а если компилировалось — то не заводилось на железке. В итоге, все-таки, все получилось, и, так как я не любитель граблей — решил написать этот пост.
Тулчейн
Установка и настройка среды разработки заняла у меня два дня. Поэтому я приведу набор, который у меня реально заработал и детально опишу проблемы, с которыми столкнулся:
— Eclipse Kepler (для C/C++)
— GCC
— texane / stlink
Заморочка была с GCC для arm-none-eabi. Вариантов тулчейна существует очень много, я пробовал два и реально заработали оба. Однако небольшая разница между ними все же есть:
— GNU Arm toochain можно взять тут
— Mentor Graphics CodeSourcery EABI можно взять тут, попросят ввести свои данные, пришлют ссылку для скачивания на почту..
Кстати, сначала я поставил arm-linux-gnueabi их своего дистра Linux. Не стоит, для наших целей не подойдет, а вот если на вашем ARM стоит Linux — то да, самое оно.
Итак, компилятор ставим, куда вздумается, но обязательно пропишем путь к нему в PATH пользователя. Как это сделать — зависит от операционки, с которой вы работаете. Я закинул в /opt эту пару тулчейнов и сделал симлинк /opt/arm-toolchain — как-бы по-умолчанию.
Программатор
Далее клонируем stlink с Github'a любым удобым способом. Собирается как обычно:
# git clone github.com/texane/stlink
# cd stlink
# ./automake
# ./configure --prefix=/usr/bin
Не забудем про libusb-dev, у меня в Debian Wheezy он не был установлен. Если еще каких-то либ не хватает, ставим их как это делается в вашей системе.
Среда разработки
Далее, самое интересное для меня — настройка клипсы под разработку. Настроить проект так, чтобы все компилировалось и работало на чистом Eclipse у меня не получилось. Поэтому можно поставить полезные плагины. Однако после того, как будет достигнута определенная степень ясности настроек — можно поковыряться и сделать настройку проекта под себя без плагинов.
Есть достаточно разных плагинов для разработки под ARM, вот парочка:
— GNU Arm Eclipse можно взять тут
— Zylin CDT — здесь
Для обоих есть апдейт-сайты, ставятся плагины стандартным для клипсы способом из менюшки. Ставим оба.
Далее, создаем C++ проект в Eclipse, выбираем, что он будет под ARM (тулчейн ARM Cross GCC), далее выбираем тип тулчейна в зависимости от того, какой компилятор вы выбрали: CodeSourcery или ARM GCC. Вообще плагины поддерживают всякие разные наборы компиляторов — можно поиграться и с ними.


Вот тут есть одна проблема — в CodeSourcery я не нашел libnosys.a. Пришлось взять его из GNU Arm GCC. В общем полет нормальный.

Выводы
Теперь, небольшое лирическое отступление о том, какие проблемы решает плагин. С этим придется столкнуться, если вы будете настраивать проект под себя и вы — новичок. Для меня все это было открытием, т.к. прошивок я никогда не писал до этого.
— на контроллере нет libc. Firmware компонуется статически.
— и нет операционной системы (она будет встроена в проект), нет загрузчика — программа начнет выполняться сразу после включения.
Плагин решает кучку задач — он предоставляет сразу нужные нам либы CMSIS и Standard Perepherials в проекте, который мы только что создали. Эти библиотеки нужны, чтобы работать с переферией контроллера.
Можно, конечно, прикрутить libopencm3 вместо библиотек предоставленных производителем, но это тема отдельной статьи.
Также ппагин предоставляет набор linker scripts. Честно говоря, я с ними столкнулся впервые. В linker script'е описывается структура бинарного файла, секции, точка входа и много чего еще. Собирать все это по кусочкам вручную муторно и безынтересно, пока проект еще даже не завелся на железке, зато потом — какой простор для изучения.
Настраивается плагин из свойств проекта, собственно, в проекте они и хранит свои настройки.
Настраиваем отладчик
Вообще, этот кусок можно сделать в самом конце, но то, что отладка заработала — уже является признаком того, что все настроено. Поэтому мы сделаем это заранее.
В качестве отладчика, естественно, используется GDB. Настроим приложение сервера GDB, в качестве которого будет выступать утилита от texane/stlink.
Идем в External Tools и добавляем инструментарий. Его надо будет запускать каждый раз, если нам нужна будет отладка, при подключенной плате. Утилита будет заливать отладочный образ и служить сервером. Ключик -m как раз говорит ей не отваливаться каждый раз, когда соединение с отладчиком будет прервано, что очень удобно на мой взгляд.

Далее создадим таргет отладки. Тут все просто, берем отладчик из тулчейна, указываем порт 4242 — это порт GDB сервера по-умолчанию.

Запускаем сервер отладки, подключаемся к таргету — он соберет проект, зальет бинарник в железку и запустит. Можно отлаживаться.
FreeRTOS
Так как все, что надо для того, чтобы проект вообще мог быть собран нам дал плагин (который, кстати, создал даже темплейт моргалки светодиодом), можно взять собрать его и залить на железку. Если светодиод моргает и все работает, начинаем интегрировать операционку.
Структура проекта, созданного плагином будет иметь каталог libs, где уже лежат CMSIS, StdPeriph и прочее. Вот туда мы и закинем FreeRTOS. Далее, чтобы операционка работала надо ее сконфигруровать. Мануалов (в том числе официальных) по настройке FreeRTOS в интернете валом, поэтому описывать я его тут не буду. Если вкратце, надо сделать следующее:
1) создать FreeRTOSConfig.h и положить его к хидерам от RTOS
2) взять из portable порт для нашей железки и положить файлы порта вместе с остальными исходниками RTOS.
3) найти с исходниках RTOS memory manager, например heap_2.c и положить туда же.
Кстати, в конфиге от RTOS надо указать реальную тактовую процессора, такую же какая была указана при создании проекта. У меня это 168000000.
#define configCPU_CLOCK_HZ ( ( unsigned long ) 168000000 )
#define configTICK_RATE_HZ ( ( portTickType ) 1000 )
А также добавить вот это:
#define vPortSVCHandler SVC_Handler
#define xPortPendSVHandler PendSV_Handler
#define vPortSVCHandler SVC_Handler
#define xPortSysTickHandler SysTick_Handler
И включить vTaskDelay так как он у нас будет исползоваться для ожидания между морганиями светодиода:
#define INCLUDE_vTaskDelay 1
Не забудем в клипсе прописать в настройках проекта пути к нашей FreeRTOS:

Вообще в проекте много всяких настроек, из которых формируются параметры компилятора, ассемблера и компоновщика. Можно поиграться, посмотреть что будет ;)
Минимум настроен, теперь можно пытаться собирать. Если что-то забыли — просто не соберется или не будет работать.
А теперь
Приложение мы будем писать на C++, причем перейдем от чистого C к C++. Я на этих языках давно не писал, так что не судите строго.
Проект на гитхабе.
С тасками есть один ньюанс, с которым я, при переходе на С++ немного промучался:
void Application::attach(Task *task) {
FNMETHOD impl = &Task::impl;
pdTASK_CODE proc = ((pdTASK_CODE)(task->*impl));
xTaskCreate(
proc,
(signed char *) "test",
configMINIMAL_STACK_SIZE,
task,
2,
(xTaskHandle *) 0);
}
Первый параметр — указатель на метод, в котором реализована задача. Четвертый параметр в xTaskCreate — указатель на экземпляр класса Task. Передать указатель на экземпляр необходимо, иначе в методе реализации не будет доступа к переменным класса Task — в данном случае, пину светодиодика и задержке.
Ну а в остальном там все просто. Удачного дня и успешных сборок. Вопросы welcome!
P.S. А какой средой под Linux для этих целей пользуетесь вы? ;)
P.P.S. Надо понимать, что данный пост написан не системным программистом и призван помочь «высокоуровневым» товарищам, желающим войти в мир разработки firmware. Поэтому гуру ассемблера прошу не серчать ^-^