FreeRTOS быстрый старт на STM32 F4 DISCOVERY

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 не забываем указать линкеру папки в которых искать хедеры.

Скачать проект.

 

Похожий код:

Фото аватара
Алексей Петров

Программист, разработчик с 5 летним опытом работы. Учусь на разработчика игр на Unity и разработчика VR&AR реальности (виртуальной реальности). Основные языки программирования: C#, C++.

Оцените автора
Бла, бла код
Добавить комментарий