FreeRTOS — операционная система реального времени. Скорее всего если вам нужна операционка на вашем микроконтроллере, то вы воспользуетесь ей 😉 ИМХО
Дотстоинства: бесплатно, быстро, порты под многие архитектуры (не придётся осваивать чтото заново)
Недостатки(ок): документация распространяется платно.. Но не беда! Есть куча сайтов на эту тематику, в том числе и на русском языке.
О том что будет в этой статье: рассказ о том как скомпилировать и запустить FreeRTOS на камне STM32. Запустим 2 задачи, поморгаем светодиодами.
Сперва конечно же качаем FreeRTOS. Это можно сделать с официального сайта ОС freertos.org
В полученном архиве вы найдёте исходники в папке Source и примеры в папке Demo
Идём в папку Source.
Сразу оговорюсь, что я работаю в Eclipse на Ubuntu linux, что говорит о том, что у меня gcc компилятор 😉
В папке с исходниками видим папку Include с заголовочными файлами системы, и папку portable, в которой храняться порты для разных архитектур. Из этой папки скопируем нужные файлы, остально удалим.
Заходим в FreeRTOSV7.1.1/Source/portable/GCC/ARM_CM4F
и копируем оттуда два файла port.c и portmacro.h. Соответственно исходник перемещаем в папку Source, а заголовочный файл в папку Source/Include
Теперь из папки MemMang копируем файл heap_2.c в каталог с исходниками.
После проделанного можно удалить папку portable.
Готово. Дистрибутив приготовили. Теперь настроечный файл FreeRTOSConfig.h. Я не буду толком на нём останавливаться, собственно тут и происходит настройка. Но это дело отдельной статьи. Оговорюсь только о параметре:
configCPU_CLOCK_HZ - частота камня в герцах.
Также нужно переименовать или переназначить прерывания, чтобы ОС их понимала:
#define vPortSVCHandler SVC_Handler #define xPortPendSVHandler PendSV_Handler #define vPortSVCHandler SVC_Handler #define xPortSysTickHandler SysTick_Handler
Файл целиком:
#ifndef FREERTOS_CONFIG_H #define FREERTOS_CONFIG_H #define vPortSVCHandler SVC_Handler #define xPortPendSVHandler PendSV_Handler< #define vPortSVCHandler SVC_Handler #define xPortSysTickHandler SysTick_Handler #define configUSE_PREEMPTION 1 #define configUSE_IDLE_HOOK 0 #define configUSE_TICK_HOOK 0 #define configCPU_CLOCK_HZ ( ( unsigned long ) 168000000 ) #define configTICK_RATE_HZ ( ( portTickType ) 1000 ) #define configMAX_PRIORITIES ( ( unsigned portBASE_TYPE ) 5 ) #define configMINIMAL_STACK_SIZE ( ( unsigned short ) 120 ) #define configTOTAL_HEAP_SIZE ( ( size_t ) ( 18 * 1024 ) ) #define configMAX_TASK_NAME_LEN ( 16 ) #define configUSE_TRACE_FACILITY 0 #define configUSE_16_BIT_TICKS 0 #define configIDLE_SHOULD_YIELD 1 /* Co-routine definitions. */ #define configUSE_CO_ROUTINES 0 #define configMAX_CO_ROUTINE_PRIORITIES ( 2 ) #define configUSE_MUTEXES 0 #define configUSE_COUNTING_SEMAPHORES 0 #define configUSE_ALTERNATIVE_API 0 #define configCHECK_FOR_STACK_OVERFLOW 0 #define configUSE_RECURSIVE_MUTEXES 0 #define configQUEUE_REGISTRY_SIZE 0 #define configGENERATE_RUN_TIME_STATS 0 /* Set the following definitions to 1 to include the API function, or zero to exclude the API function. */ #define INCLUDE_vTaskPrioritySet 0 #define INCLUDE_uxTaskPriorityGet 0 #define INCLUDE_vTaskDelete 0 #define INCLUDE_vTaskCleanUpResources 0 #define INCLUDE_vTaskSuspend 0 #define INCLUDE_vTaskDelayUntil 0 #define INCLUDE_vTaskDelay 1 #define INCLUDE_uxTaskGetStackHighWaterMark 0 /* This is the raw value as per the Cortex-M3 NVIC. Values can be 255 (lowest) to 0 (1?) (highest). */ #define configKERNEL_INTERRUPT_PRIORITY 255 #define configMAX_SYSCALL_INTERRUPT_PRIORITY 191 /* equivalent to 0xb0, or priority 11. */ /* This is the value being used as per the ST library which permits 16 priority values, 0 to 15. This must correspond to the configKERNEL_INTERRUPT_PRIORITY setting. Here 15 corresponds to the lowest NVIC value of 255. */ #define configLIBRARY_KERNEL_INTERRUPT_PRIORITY 15 /*----------------------------------------------------------- * UART configuration. *-----------------------------------------------------------*/ #define configCOM0_RX_BUFFER_LENGTH 128 #define configCOM0_TX_BUFFER_LENGTH 128 #define configCOM1_RX_BUFFER_LENGTH 128 #define configCOM1_TX_BUFFER_LENGTH 128 #endif /* FREERTOS_CONFIG_H */
В файле main.c нашей программы запустим ОС и зададим две равноправные задачи — мигать диодами.
Инклуды:
#include <stm32f4xx.h> #include <stm32f4xx_gpio.h> #include <stm32f4xx_rcc.h> #include <misc.h> #include "FreeRTOS.h" #include "task.h"
Теперь две задачи:
void vTaskLED1(void *pvParameters) { for (;;) { GPIO_SetBits(GPIOD, GPIO_Pin_12); vTaskDelay(500); GPIO_ResetBits(GPIOD, GPIO_Pin_12); vTaskDelay(500); } }
void vTaskLED2(void *pvParameters) { for (;;) { GPIO_SetBits(GPIOD, GPIO_Pin_14); vTaskDelay(321); GPIO_ResetBits(GPIOD, GPIO_Pin_14); vTaskDelay(321); } }
В FreeRTOS принято пользоваться венгерской нотацией, так что можете не удивляться суфиксам и префиксам у функция.. Хотя я считаю это полным идеотизмом.
Обратите внимание, что каждая задача FreeRTOS должна принимать указатель на структуру void, таким способом могут быть переданы параметры.
В функции main инициализируем периферию:
GPIO_InitTypeDef GPIO_InitStructure; RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD, ENABLE); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12 GPIO_Pin_14; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT; GPIO_Init(GPIOD, &GPIO_InitStructure);
Создаём две задачи:
xTaskCreate( vTaskLED1, ( signed char * ) "LED1", configMINIMAL_STACK_SIZE, NULL, 2, ( xTaskHandle * ) NULL); xTaskCreate( vTaskLED2, ( signed char * ) "LED2", configMINIMAL_STACK_SIZE, NULL, 2, ( xTaskHandle * ) NULL);
Делается это как видите при помощи функции xTaskCreate. Первый параметр — указатель на функцию (её имя), второй — имя процесса (можно сказать, что используется для красоты), затем — минимальный размер стека для функции. потом — параметры (мы ничего не передаём — NULL), предпоследним есть приоритете (2) и последним указатель на xTaskHandl при помощи которого можно в дальнейшем управлять процессами.
Запускаем планировшик задач:
vTaskStartScheduler();
Собственно и всё. Прерываний у нас нет, поэтому я удалил файлы с прерываниями..
У меня получилось вот так:
arm-none-eabi-size --format=berkeley stm32_rtos.elf text data bss dec hex filename 3304 12 18924 22240 56e0 stm32_rtos.elf Finished building: stm32_rtos.siz
ps не забываем указать линкеру папки в которых искать хедеры.
Скачать проект.