Подключаем FreeRTOS к Миландр.

Миландр и FreeRTOS. Как установить и настроить FreeRTOS на микроконтроллере Миландр. Описание процесса настройки и использования.

Администратор
Cover Image

О полезности операционных систем реального времени можно говорить часами, ровно как и о их вреде. Но раз уж читаете эту запись, значит RTOS вам действительно нужна.

Здесь не будет описания как пользоваться FreeRTOS. Всё что будет затронуто - это запуск на микроконтроллере 1986ВЕ92У (К1986ВЕ92QI) фирмы Миландр. В принципе данный гайд аналогичен для 91, 93 и 94 чипа.

Если разобраться, и разложить всё по пунктам, то можно привести всю задачу к нескольким простым шагам:

  • скачиваем FreeRTOS и распаковываем;
  • создаем проект в Keil (я использую версию 5);
  • подключаем операционную систему;
  • настраиваем и пользуемся.

Тем у кого нет желания или времени читать предлагаю перейти сразу в конец статьи и скачать проект для 1986ВЕ92У с подключенной операционной системой. В тестовой программе мигают четыре светодиода с разной частотой. Думаю этого вполне достаточно для переработки проекта под свои нужды.

Скачиваем FreeRTOS.

Наверно самый простой пункт нашего плана. Для этого нужно перейти на сайт www.freertos.org далее в раздел "⇓ Download Source ⇓" и скачать последнюю версию, на данный момент это версия 9.0. Или можно нажать на эту ссылку и загрузить сразу.

Теперь остается распаковать архив и приступить к изучению внутренностей, но это чуть позже.

Создаем проект в Keil.

 Здесь должно быть всё понятно, открывает keil и создаём новый проект для микроконтроллера 1986ВЕ92У.

Подключаем операционную систему.

Вот теперь самое интересное. Пришло время взглянуть на внутренности папки FreeRTOS, именно её, папку с именем FreeRTOS-Plus оставим на потом (в данном примере она нам не нужна).

У нас есть две папки:

  • Demo - здесь хранятся примеры под разные платформы.
  • Source - здесь исходники операционной системы, именно эта папка нам и нужна.

Начинаем процесс подключения.

В папке с нашим проектом создаем папку rtos (для большего порядка, хотя этого можно и не делать) и в неё копируем все содержимое папки Source за исключением папки portable, из которой нам нужны только несколько файлов. А именно:

  • один из файлов кучи, в моем случае heap_2.c из portable\MemMang\. Подробнее об этих файлах можно почитать на официальном сайте www.freertos.org.
  • port.c - из папки \portable\RVDS\ARM_CM3\
  • portmacro.h - из той же папки

Файлы *.c копируем в папку rtos, а файлы *.h в поддиректорию \rtos\include\

Настраиваем ...

Теперь необходимо подготовить файл конфигурации операционной системы FreeRTOSConfig.h, его можно взять в папке \Demo\CORTEX_STM32F103_Keil\, настроив его под свои нужды или воспользоваться моим файлом (подробности как и с файлами heap_*.c можно почитать на сайте операционки).

#ifndef FREERTOS_CONFIG_H
#define FREERTOS_CONFIG_H

/* Here is a good place to include header files that are required across
your application. */

#define configUSE_PREEMPTION                    1
#define configUSE_PORT_OPTIMISED_TASK_SELECTION 0
#define configUSE_TICKLESS_IDLE                 0
#define configCPU_CLOCK_HZ                      ( ( unsigned long ) 8000000 )
#define configTICK_RATE_HZ                      1000
#define configMAX_PRIORITIES                    5
#define configMINIMAL_STACK_SIZE                128
#define configMAX_TASK_NAME_LEN                 16
#define configUSE_16_BIT_TICKS                  0
#define configIDLE_SHOULD_YIELD                 1
#define configUSE_TASK_NOTIFICATIONS            1
#define configUSE_MUTEXES                       1
#define configUSE_RECURSIVE_MUTEXES             1
#define configUSE_COUNTING_SEMAPHORES           1
#define configUSE_ALTERNATIVE_API               0 /* Deprecated! */
#define configQUEUE_REGISTRY_SIZE               10
#define configUSE_QUEUE_SETS                    0
#define configUSE_TIME_SLICING                  0
#define configUSE_NEWLIB_REENTRANT              0
#define configENABLE_BACKWARD_COMPATIBILITY     0
#define configNUM_THREAD_LOCAL_STORAGE_POINTERS 5
/* Memory allocation related definitions. */
#define configTOTAL_HEAP_SIZE                   ( ( size_t ) ( 20 * 1024 ) )
#define configAPPLICATION_ALLOCATED_HEAP        0

/* Hook function related definitions. */
#define configUSE_IDLE_HOOK                     1
#define configUSE_TICK_HOOK                     0
#define configCHECK_FOR_STACK_OVERFLOW          0
#define configUSE_MALLOC_FAILED_HOOK            0
#define configUSE_DAEMON_TASK_STARTUP_HOOK      0

/* Run time and task stats gathering related definitions. */
#define configGENERATE_RUN_TIME_STATS           0
#define configUSE_TRACE_FACILITY                0
#define configUSE_STATS_FORMATTING_FUNCTIONS    0

/* Co-routine related definitions. */
#define configUSE_CO_ROUTINES                   0
#define configMAX_CO_ROUTINE_PRIORITIES         2

/* Software timer related definitions. */
#define configUSE_TIMERS                        1
#define configTIMER_TASK_PRIORITY               3
#define configTIMER_QUEUE_LENGTH                10
#define configTIMER_TASK_STACK_DEPTH            configMINIMAL_STACK_SIZE

/* Interrupt nesting behaviour configuration. */
#define configKERNEL_INTERRUPT_PRIORITY         255
#define configMAX_SYSCALL_INTERRUPT_PRIORITY    191
#define configMAX_API_CALL_INTERRUPT_PRIORITY   15

/* FreeRTOS MPU specific definitions. */
#define configINCLUDE_APPLICATION_DEFINED_PRIVILEGED_FUNCTIONS 0

/* Optional functions - most linkers will remove unused functions anyway. */
#define INCLUDE_vTaskPrioritySet                1
#define INCLUDE_uxTaskPriorityGet               1
#define INCLUDE_vTaskDelete                     1
#define INCLUDE_vTaskSuspend                    1
#define INCLUDE_xResumeFromISR                  1
#define INCLUDE_vTaskDelayUntil                 1
#define INCLUDE_vTaskDelay                      1
#define INCLUDE_xTaskGetSchedulerState          1
#define INCLUDE_xTaskGetCurrentTaskHandle       1
#define INCLUDE_uxTaskGetStackHighWaterMark     0
#define INCLUDE_xTaskGetIdleTaskHandle          0
#define INCLUDE_eTaskGetState                   0
#define INCLUDE_xEventGroupSetBitFromISR        1
#define INCLUDE_xTimerPendFunctionCall          0
#define INCLUDE_xTaskAbortDelay                 0
#define INCLUDE_xTaskGetHandle                  0
#define INCLUDE_xTaskResumeFromISR              1

#define xPortSysTickHandler                     SysTick_Handler
#define xPortPendSVHandler                      PendSV_Handler
#define vPortSVCHandler                         SVC_Handler

/* A header file that defines trace macro can be included here. */

#endif /* FREERTOS_CONFIG_H */

Теперь пробуем собрать прошивку. Но ничего не получается, появляются несколько ошибок:

.\obj\cantest.axf: Error: L6200E: Symbol PendSV_Handler multiply defined (by port.o and mdr32f9qx_it.o).
.\obj\cantest.axf: Error: L6200E: Symbol SVC_Handler multiply defined (by port.o and mdr32f9qx_it.o).
.\obj\cantest.axf: Error: L6200E: Symbol SysTick_Handler multiply defined (by port.o and mdr32f9qx_it.o).

Что в принципе и понятно в файле mdr32f9qx_it.с описаны функции PendSV_Handler()SVC_Handler() и SysTick_Handler(), которые использует операционная система. Нужно просто удалить из файла, что мы и сделаем.

Теперь можно видеть желанную строку с информацией об удачной сборке

FromELF: creating hex file...
".\obj\cantest.axf" - 0 Error(s), 0 Warning(s).
Build Time Elapsed:  00:00:03

... и пользуемся.

Как принято, тестовой программой будет мигание светодиода, благо на отладочной палате (LDM-K1986BE92QI) с микроконтроллером их четыре штуки. Если нет отладочной платы думаю вы разберетесь что делать дальше.

void vLed1(void *argument)
{
    while(1)
    {
        PORT_SetBits(MDR_PORTB, PORT_Pin_0);
        vTaskDelay(1000);
        PORT_ResetBits(MDR_PORTB, PORT_Pin_0);
        vTaskDelay(1000);
    }
}

void vApplicationIdleHook (void)
{

}

int main(void)
{
    init ();
    xTaskCreate(vLed1, "1", configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY + 1, NULL);

    // Запускаем диспетчер и понеслась.     
    vTaskStartScheduler();
}

Собираем, заливаем и видим мигание примерно раз в секунду. 

Надеюсь вы не забыли инициализировать вывод микроконтроллера ответственный за вывод сигнала на светодиод? Кстати эти выводы находятся в порте B, на котором висит JTAGA, так что внимательнее.

void PORT_init ( void )
{
    PORT_InitTypeDef PORT_InitStructure;
    // Запуск тактирования порта контроллера
    RST_CLK_PCLKcmd( RST_CLK_PCLK_PORTB, ENABLE);

    PORT_InitStructure.PORT_Pin   = PORT_Pin_0 | PORT_Pin_1 | PORT_Pin_2 | PORT_Pin_3;
    PORT_InitStructure.PORT_OE    = PORT_OE_OUT;
    PORT_InitStructure.PORT_FUNC  = PORT_FUNC_PORT;
    PORT_InitStructure.PORT_MODE  = PORT_MODE_DIGITAL;
    PORT_InitStructure.PORT_SPEED = PORT_SPEED_FAST;
    PORT_Init(MDR_PORTB, &PORT_InitStructure);
}

Как видим, установка FreeRTOS довольно проста и понятна. Однако в некоторых моментах возникают трудности и если нет сил и возможности их преодолеть самостоятельно, лучше спросить у знающих, а не рвать на себе волосы.

Исходники проекта можно взять здесь.