移植freertos到stm32 f103 的基本流程和总结

2019/04/10 10:10
阅读数 119

为什么要在stm32 f103上面移植freertos

  stm32 f103 以他的全面的文档,亲民的价格,强大的功能。成为无数微设备的方案首选。在市场上有极大的使用量。市场占有率也是非常的高。freertos作为一个开源的微型操作系统,凭借着它的资源占用小,功能强大,文档齐全,成为各大芯片公司都支持的操作系统,也是程序员操作系统学习的不二首选。所以,把这两者结合起来,除了能给我们的产品提供强大的支撑之外,还积累的很多基础技术。笔者花了不少心思才把这个移植好,在这里做个记录。希望能给你一些启发。

基本介绍

  我这里使用的是freertos的版本是9.0。移动植入之前,先看一下freertos的文件目录:

├── croutine.c
├── event_groups.c
├── include
│   ├── FreeRTOS.h
│   ├── StackMacros.h
│   ├── croutine.h
│   ├── deprecated_definitions.h
│   ├── event_groups.h
│   ├── list.h
│   ├── mpu_prototypes.h
│   ├── mpu_wrappers.h
│   ├── portable.h
│   ├── projdefs.h
│   ├── queue.h
│   ├── semphr.h
│   ├── stdint.readme
│   ├── task.h
│   └── timers.h
├── list.c
├── portable
│   ├── GCC
│   │   └── ARM_CM3
│   │       ├── port.c
│   │       └── portmacro.h
│   ├── MemMang
│   │   ├── heap_1.c
│   │   ├── heap_2.c
│   │   ├── heap_2.lst
│   │   ├── heap_2.o
│   │   ├── heap_3.c
│   │   ├── heap_4.c
│   │   └── heap_5.c
│   └── readme.txt
├── queue.c
├── readme.txt
├── tasks.c
└── timers.c

大致一看,这个操作系统是非常简洁的。从文件名字就可以看出: queue.c 这个文件是队列,负责线程之间的通信和数据传输的。 task.c 就是线程及任务模块,线程相关的都在这个文件里面。 list.c 就是一个链表,用来实现可变数据的存放和操作。 根目录下的和具体的芯片没关系,和芯片的接口及相关的元素主要在两个函数里面。 一个是portable文件下的port.c 这个里面要注意下,在stm32 f103中,这里最重要的就是这里的中断处理函数的匹配了。在无操作系统的stm32 f103中,systick, SVC 和 PendSV 这三个中断的处理函数 这三个函数一般在start.s文件或中断向量表中vector.c 中。基本额写法如下所示:

void SVC_Handler (void) attribute((weak));

void PendSV_Handler (void) attribute((weak));

void SysTick_Handler (void) attribute((weak));

在freertos中,需要替换成port.c 里面的另外三个中断处理函数:

voidxPortPendSVHandler( void ) attribute (( naked ));

voidxPortSysTickHandler( void );

voidvPortSVCHandler( void ) attribute (( naked ));

另外一个就是heap,heap主要是系统的内存管理单元。heap_1.c, heap_2.c and heap_3.c属于三个基本的样例子,用户也可以根据自己的实际情况做修改。这里的的heap虽然很多,但是每个系统只会使用一个,具体使用哪一个要看你的芯片平台的属性,stm32 f103 使用的是heap_2.c

移植流程

  第一步就是把代码拷贝到目标文件中,编译通过。这里属于一些基本功夫,详细的步骤我就不多说了,谨记中断处理函数的处理,这里非常容易出问题。再者就是FreeRTOSconfig.h文件中的heap_size大小,不能太大,太大了这个芯片的资源不够的。建议一般不要10k左右就行了吧。

  第二步就是FreeRTOSConfig.h文件的配置选择,这里面的是非常关键的,最容易出错。下面是我的这个文件的配置:

#define configUSE_PREEMPTION            1
#define configUSE_IDLE_HOOK         0
#define configUSE_TICK_HOOK         0
#define configCPU_CLOCK_HZ          ( ( unsigned long ) 72000000 )
#define configSYSTICK_CLOCK_HZ ( configCPU_CLOCK_HZ / 8 )  /* fix for vTaskDelay() */
#define configTICK_RATE_HZ          ( ( TickType_t ) 1000 )
#define configMAX_PRIORITIES            ( 5 )
#define configMINIMAL_STACK_SIZE        ( ( unsigned short ) 128 )
#define configTOTAL_HEAP_SIZE           ( ( size_t ) ( 17 * 1024 ) )
#define configMAX_TASK_NAME_LEN         ( 16 )
#define configUSE_TRACE_FACILITY        0
#define configUSE_16_BIT_TICKS          0
#define configIDLE_SHOULD_YIELD         1
#define configUSE_MUTEXES           1

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

/* Set the following definitions to 1 to include the API function, or zero
to exclude the API function. */

#define INCLUDE_vTaskPrioritySet        1
#define INCLUDE_uxTaskPriorityGet       1
#define INCLUDE_vTaskDelete         1
#define INCLUDE_vTaskCleanUpResources       0
#define INCLUDE_vTaskSuspend            0
#define INCLUDE_vTaskDelayUntil         1
#define INCLUDE_vTaskDelay          1

这里要注意几点: configCPU_CLOCK_HZ 就是CPU的的时钟,系统的时钟和CPU的时钟是不同的,这里做一个8分频:#define configSYSTICK_CLOCK_HZ ( configCPU_CLOCK_HZ / 8 ) 还有就是后面的heap大小和stack大小,要根据实际的产品情况进行调整的。这个调整好了,可以让你的小芯片发挥出极大的威力。

  第三点,应用部分: 这里手先看一下主函数:

int main()
{
    RCC_Configuration();
    GPIO_Configuration();
    usart1_init();

     printf("start main sdf \n\r");
     usart1_puts(" 512k flash, 64k ram ..........\n\r");

     xTaskCreate(tadventure,"game",configMINIMAL_STACK_SIZE,NULL,configMAX_PRIORITIES-1,NULL);
     xTaskCreate(flasher,"flash",configMINIMAL_STACK_SIZE,NULL,configMAX_PRIORITIES-1,NULL);
     xTaskCreate(vT_usart, (const char*) "USART Task", configMINIMAL_STACK_SIZE, NULL, 1, NULL);

    vTaskStartScheduler();

    while (1);

    return 0;
}

三个task的处理函数:

static void flasher(void *arg __attribute__((unused))) {

    for (;;) {
        GPIO_ResetBits(GPIOA, GPIO_Pin_1);
        vTaskDelay(pdMS_TO_TICKS(400));
        GPIO_SetBits(GPIOA, GPIO_Pin_1);
        vTaskDelay(pdMS_TO_TICKS(400));
    }
}

static void tadventure(void *arg __attribute__((unused))) {
{
    for (;;) {
        GPIO_ResetBits(GPIOA, GPIO_Pin_0);
        vTaskDelay(pdMS_TO_TICKS(1000));
        GPIO_SetBits(GPIOA, GPIO_Pin_0);
        vTaskDelay(pdMS_TO_TICKS(1000));
    }
}

static void vT_usart(void *p)
{
    // Block for 500ms.
    const portTickType xDelay = 500 / portTICK_RATE_MS;

    for(;;) {
        usart1_puts("FreeRTOS V9.0.0 demo on STM32F103c8t6\r\n");
        usart1_puts(" 64k flash, 20k ram ..........\r\n");
        vTaskDelay(xDelay);
    }
}

这里的结果如下所示:

串口日志

问题备忘

  最大的问题就是一个是FreertosConfig.h文件设置错误导致的系统timer不对。 另外就是中断的服务处理函数了,一定要换成自己的。

原文出处:https://www.cnblogs.com/dylancao/p/12331927.html

展开阅读全文
打赏
0
0 收藏
分享
加载中
更多评论
打赏
0 评论
0 收藏
0
分享
返回顶部
顶部