【FreeRTOS】FreeRTOS 源码学习笔记(1) 文件结构 + stm32f103c8t6移植步骤

0. 引言

之前freeRTOS用过几次,但是项目赶工的急,一直没有认真的去里面看过,最近正好有空,准备到里面看下源码实现,毕竟核心文件就这么几个,认真看一下流程,对操作系统的雏形也就有一个认识了。而且一些常用的功能,队列,内存管理,信号量之类的,都有,基本上彻底弄懂一个,对以后理解别的也有帮助。

1. FreeRTOS介绍

FreeRTOS其实不用再多介绍了,现在太火了,主要是免费,感觉很多厂家的出场demo都会带。
而且FreeRTOS是一个十分小巧的系统,占用资源也不多,甚至可以在stm32f103c8t6(64k flash ,20k ram)上跑起来。具体能裁剪到多小倒是没有看到有介绍,但是基本够用。(这里移到c8t6上也只是为了学习一下流程,如果真的使用可以用个大点的MCU。)
先放上官网,FreeRTOS官网。在这里可以轻松下载到最新的freeRTOS源码、组件、demo、新功能,而且现在的官网比以前好看多了。

现在的:
在这里插入图片描述
以前的(网摘):
在这里插入图片描述
现在清爽多了。

2. FreeRTOS 文件结构

现在(2020.4.11)最新的是v10.3.1,下载之后,打开文件夹,文件列表如下:

FreeRTOSv10.3.1
    |
    | -- FreeRTOS
            | -- Demo 
            | -- License 
            | -- Source 
                    | -- include 
                    | -- portable
                    | -- croutine.c
                    | -- event_groups.c
                    | -- list.c
                    | -- queue.c
                    | -- stream_buffer.c
                    | -- tasks.c
                    | -- timers.c
    |
    | -- FreeRTOS-Plus
            | -- Demo
            | -- Source
                    | -- FreeRTOS-Plus-CLI 

基本功能:

  1. FreeRTOS文件夹
  • Demo 放的是一些主流芯片主流IDE的示例代码,刚开始建立工程的时候可以参考里面的 FreeRTOSConfig.h
  • License 放的是许可证
  • Source文件夹下就是源代码了。
    在这里插入图片描述
  • source/include是API的头文件
  • source/portable 目录下的文件提供一些会被 FreeRTOS 核心代码调用的函数,这些函数的实现与运行环境有关系,或者是存在多种实现方式

另外的几个.c,看他们放在这么明显的位置上,就知道是FreeRTOS的关键了。

  • source/croutine.c 协程相关 ,以前片子资源不够的时候用,现在用的人很少了,
  • source/event_groups.c 事件组
  • source/stream_buffer.c 流缓冲区
  • source/timers.c 软定时器
  • source/list.c (核心)列表结构描述,在内核整体控制上都使用了列表格式数据处理,一切数据结构的基础
  • source/queue.c (核心)消息队列用于task间通信和同步
  • source/tasks.c (核心)任务相关的函数
  1. FreeRTOS-Plus里主要是一些内核以外的附加的组件
  • FreeRTOS-Plus-IO:提供不同硬件设备I/O引脚的通信接口
  • FreeRTOS-Plus-TCP:TCP/IP协议组件,
  • FreeRTOS-Plus-UDP:UDP组件
  • FreeRTOS-Plus-CLI : 指令交互
  • FreeRTOS-Plus-Trace:可视化跟踪
  • Reliance-Edge
  • WolfSSL

3. stm32f103c8t6移植FreeRTOS

3.1 文件需要

这里只是为了把系统跑起来,所以只移植了核心组件。
我们需要移植的,最少的文件只需要:

  • FreeRTOSv10.3.1\FreeRTOS\Source\tasks.c, queue.c and list.c 3个文件(kernel核心)
  • FreeRTOSv10.3.1\FreeRTOS\Source\portable\RVDS\ARM_CM3\port.c + portmacro.h(3个中断都是在这里做的,pendSV,SVC,tick)
  • FreeRTOSv10.3.1\FreeRTOS\Source\portable\MemMang \ heap_4.c(内存管理,5中选1)
  • FreeRTOSv10.3.1\FreeRTOS\Source\include 所有(API接口)
  • FreeRTOSv10.3.1\FreeRTOS\Demo\CORTEX_STM32F103_Keil\FreeRTOSConfig.h(freeRTOS系统裁剪配置文件)
    在这里插入图片描述

3.2 移植步骤

3.2.1 工程添加文件

将文件全部添加到工程中,把头文件路径添加到工程中
在这里插入图片描述
在这里插入图片描述

3.2.2 修改main

之前main是按这个格式写的:

//全局变量
int main()
{
	//局部变量
	bsp初始化
	while(1)
	{
		//任务
	}
}

需要修改为task的,这边随手写了一个测试的。

#include <stdio.h>
#include "hdl_sys.h"							//Öжϡ¢GPIO¡¢Êý¾ÝÀàÐÍ
#include "hdl_systickdelay.h"					//sysÑÓʱ
#include "hdl_led.h"							//Êä³öIO¿Ú
#include "hdl_key.h"							//ÊäÈëIO¿Ú
#include "hdl_usart1.h"							//´®¿Ú1
#include "hdl_usart2.h"							//´®¿Ú2
#include "hdl_usart3.h"							//´®¿Ú2
#include "hdl_timer.h"							//¶¨Ê±Æ÷
#include "hdl_iwdg.h"

#include "FreeRTOS.h"
#include "task.h"

//°æ±¾ºÅ
static Uint8 Version[4] = {20,4,9,1};

TaskHandle_t StartTask_Handler;

void uart1_task(void *pvParameters)
{
	while(1)
	{
        printf("Uart1  PA9 send  PA10 rec @ %lld ms\r\n",GetSysMs());
        vTaskDelay(2000);
	}
}

void uart2_task(void *pvParameters)
{
	while(1)
	{
        UART2_Put_String("´®¿Ú¶þPA2£¬PA3·¢ËÍÕý³£\r\n");
        vTaskDelay(1000);
	}
}



void start_task(void *pvParameters)
{
    taskENTER_CRITICAL();           

    xTaskCreate((TaskFunction_t )uart1_task,             
            (const char*    )"uart1_task",           
            (uint16_t       )128,        
            (void*          )NULL,                  
            (UBaseType_t    )2,        
            (TaskHandle_t*  )NULL);  
            
    xTaskCreate((TaskFunction_t )uart2_task,             
        (const char*    )"uart2_task",           
        (uint16_t       )128,        
        (void*          )NULL,                  
        (UBaseType_t    )3,        
        (TaskHandle_t*  )NULL);  

	vTaskDelete(StartTask_Handler); 
    taskEXIT_CRITICAL();            

}

int main(void)
{	
	DelayInit(72);                      //ϵͳʱÖÓÉèÖÃ
    NvicConfiguration();				//ÖжÏÔ´·Ö×é
	Uart1Init(115200L);				    //´®¿Ú1³õʼ»¯
	Uart2Init(115200L);				//´®¿Ú2³õʼ»¯
	//Uart3Init(115200L);				//´®¿Ú3³õʼ»¯
	//Timer2Init(9,7199);				    //719±íÃ÷72M/(7199+1)=10KhzµÄ¼ÆÊýƵÂÊ£¬¼ÆÊýµ½10£¨9+1£©Îª1ms, ΪϵͳÌṩʱÖÓ 
	//IWDG_Init(4,625*5);                 //Óë·ÖƵÊýΪ64,ÖØÔØֵΪ625,Òç³öʱ¼äΪ3s	 


	printf("\r\n\r\n***************************************\r\n");	
	printf("**         STM32 taotao Demo         **\r\n");
	printf("** Complie Time:%s %s **\r\n", __TIME__,__DATE__);
    printf("**         Version:%d.%d.%d.%d        **\r\n", Version[0],Version[1],Version[2],Version[3]);
	printf("***************************************\r\n");	


    xTaskCreate((TaskFunction_t )start_task,            
                (const char*    )"start_task",         
                (uint16_t       )128,        
                (void*          )NULL,                 
                (UBaseType_t    )1,       
                (TaskHandle_t*  )&StartTask_Handler);              
    vTaskStartScheduler();        



    while(1)
    {
    }
	
}

3.3.3 修改堆栈大小

因为使用的是stm32f103c8t6,ram只有20k,所以选择吧heap设置小一些,毕竟只是个测试程序,能用就行。
在这里插入图片描述

3.3.3 修改中断函数名

这么修改之后,运行依然跑不起来,一旦全速运行就会出现HardFault_Handler。
之前一直不理解,跟着堆栈跑觉得挺正常的,怎么一进中断就HardFault_Handler了,后来搜了一下,发现是因为名字不一样。
修改中断函数名

  1. 把stm32f10x_it.c里面把 SVC_Handler PendSV_Handler SysTick_Handler 这3个函数注释掉,
    在这里插入图片描述
  2. 然后在freertosconfig.h里面定义这几个
    #define vPortSVCHandler SVC_Handler
    #define xPortPendSVHandler PendSV_Handler
    /#define xPortSysTickHandler SysTick_Handler
    在这里插入图片描述
    这个很好理解,因为在启动文件中,向量表定义的这三个中断的名称就是
  • SVC_Handler
  • PendSV_Handler
  • SysTick_Handler
    在这里插入图片描述
    和FreeRTOS默认的名字不同,需要转一下,到
  • vPortSVCHandler
  • xPortPendSVHandler
  • xPortSysTickHandler 。

4. 参考链接

发布了25 篇原创文章 · 获赞 7 · 访问量 5102

猜你喜欢

转载自blog.csdn.net/tao475824827/article/details/105447763