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

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

Cover Image

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

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

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

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

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

Скачиваем FreeRTOS.

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

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

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

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

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

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

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

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

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

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

  • один из файлов кучи, в моем случае heap_4.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

#include <stdint.h>
#include "MDR32Fx.h"

extern uint32_t SystemCoreClock;

#define configCPU_CLOCK_HZ                    (SystemCoreClock)
#define configTICK_RATE_HZ                    ((TickType_t)1000)
#define configTOTAL_HEAP_SIZE                 ((size_t)(10 * 1024))
#define configMINIMAL_STACK_SIZE              ((unsigned short)130)
#define configCHECK_FOR_STACK_OVERFLOW        0
#define configMAX_PRIORITIES                  (5)
#define configUSE_PREEMPTION                  1
#define configIDLE_SHOULD_YIELD               1
#define configMAX_TASK_NAME_LEN               (10)

#define configUSE_TIMERS                      0
#define configTIMER_TASK_PRIORITY             (2)
#define configTIMER_QUEUE_LENGTH              5
#define configTIMER_TASK_STACK_DEPTH          (configMINIMAL_STACK_SIZE * 2)

#define configUSE_MUTEXES                     1
#define configUSE_RECURSIVE_MUTEXES           1
#define configUSE_COUNTING_SEMAPHORES         1
#define configUSE_QUEUE_SETS                  1
#define configUSE_IDLE_HOOK                   0
#define configUSE_TICK_HOOK                   0
#define configUSE_MALLOC_FAILED_HOOK          0
#define configUSE_16_BIT_TICKS                0

#define INCLUDE_vTaskPrioritySet              1
#define INCLUDE_uxTaskPriorityGet             1
#define INCLUDE_vTaskDelete                   1
#define INCLUDE_vTaskSuspend                  1
#define INCLUDE_vTaskDelayUntil               1
#define INCLUDE_vTaskDelay                    1
#define INCLUDE_eTaskGetState                 1

#ifdef __NVIC_PRIO_BITS
  #define configPRIO_BITS                     __NVIC_PRIO_BITS
#else
  #define configPRIO_BITS                     4
#endif

#define configLIBRARY_LOWEST_INTERRUPT_PRIORITY   15
#define configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY   5
#define configKERNEL_INTERRUPT_PRIORITY   ( configLIBRARY_LOWEST_INTERRUPT_PRIORITY << (8 - configPRIO_BITS) )
#define configMAX_SYSCALL_INTERRUPT_PRIORITY   (configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY << (8 - configPRIO_BITS))

#define configASSERT( x ) if( ( x ) == 0 ) { taskDISABLE_INTERRUPTS(); for( ;; ); } 

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

#include "freertos_evr.h"

#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 довольно проста и понятна. Однако в некоторых моментах возникают трудности и если нет сил и возможности их преодолеть самостоятельно, лучше спросить у знающих, а не рвать на себе волосы.

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