首页 > 其他分享 >FreeRTOS移植

FreeRTOS移植

时间:2023-08-25 13:33:05浏览次数:45  
标签:TASK 优先级 FreeRTOS 任务 task 移植 define

一、知识总结

运行FreeRTOS的系统与裸机系统主要区别在于执行业务逻辑的方式发生了改变。裸机系统一般会采用主循环轮询+定时器中断轮询+其他中断抢占的方式来处理复杂的多任务。
而FreeRTOS则采用根据功能的不同创建不同优先级的任务,然后借助任务调度器、任务通知等一系列的机制自动分配任务执行的顺序与时间。
1.好的资源
STM32F103/F407的FreeRTOS移植 https://www.codenong.com/cs110642632/
FreeRTOS源码结构分析与移植(基于STM32F407) https://bbs.huaweicloud.com/blogs/296103
移植讲的好视频https://www.bilibili.com/video/BV1GN4y157fy?spm_id_from=333.337.search-card.all.click&vd_source=2f31a001ad4383960409e00f558f4d7d
2.任务优先级
2.1 任务优先级数字越大,任务优先级越高。
2.2 当某个任务需要延时,调用vTaskDelay(),则该任务进入阻塞态,此时调度器会从就绪列表中找到优先级最高的就绪任务开始执行。

二、移植

keil STM32F407ZGT6
1.在项目新建文件夹FreeRTOS,把FreeRTOSv202112.00\FreeRTOS\Source 所有文件拷贝到项目下新建的文件夹FreeRTOS。

2.STM32F40x_FreeRTOS_Test\FreeRTOS\portable ,protable中保留如下三个文件,其它删除掉

3.添加头文件路径
STM32F40x_FreeRTOS_Test\FreeRTOS\include
STM32F40x_FreeRTOS_Test\FreeRTOS\portable\RVDS\ARM_CM4F

4.FreeRTOSConfig.h
FreeRTOSv202112.00\FreeRTOS\Demo\CORTEX_M4F_STM32F407ZG-SK\FreeRTOSConfig.h 拷贝到 STM32F40x_FreeRTOS_Test\FreeRTOS\include

5.编译,出错“..\FreeRTOS\portable\RVDS\ARM_CM4F\port.c(734): error: #20: identifier "SystemCoreClock" is undefined”
因为在"FreeRTOSConfig.h" : 中使用了SysyemCoreClock来标记MCU的频率。
在FreeRTOSConfig.h 第45行,#ifdef ICCARM 修改成 #if defined(ICCARM) || defined(__CC_ARM) || defined(GNU)

6.编译,出以下错误信息
.\Objects\STM32F40x_FreeRTOS_Test.axf: Error: L6200E: Symbol SVC_Handler multiply defined (by stm32f4xx_it.o and port.o).
.\Objects\STM32F40x_FreeRTOS_Test.axf: Error: L6200E: Symbol PendSV_Handler multiply defined (by stm32f4xx_it.o and port.o).
.\Objects\STM32F40x_FreeRTOS_Test.axf: Error: L6200E: Symbol SysTick_Handler multiply defined (by stm32f4xx_it.o and port.o).

因为在FreeRTOSConfig.h 中已定义,和stm32f4xx_it.c中冲突

在stm32f4xx_it.c注释掉SVC_Handler,PendSV_Handler,SysTick_Handler 三个函数。

7.编译,出以下错误信息

这是因为在"FreeRTOSConfig.h"中定义了这些钩子函数,但未找到函数定义,我们先注释掉这些定义,

就是将以下宏定义定义为0即可
configUSE_IDLE_HOOK
configUSE_TICK_HOOK
configCHECK_FOR_STACK_OVERFLOW
configUSE_MALLOC_FAILED_HOOK

8.编译,无错误信息,成功。

9.配置MCU的中断优先级。移植了FreeRTOS的MCU一般采用第四中断优先级分组,即全部的四位都用来配置抢占优先级(共16个抢占式中断优先级)。

NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);

10.修改延时函数

延时函数在STM32单片机开发的项目中有广泛的应用,微秒级延时在一些时间要求严格的场景下(例如软件模拟I2C通讯)是必不可少的。由于FreeRTOS默认采用了system tick作为时间片分配的时基定时器,可能与利用system tick设计的延时函数出现冲突。再加上FreeRTOS提供的延时函数void vTaskDelay( const TickType_t xTicksToDelay )最小的延时时间等于FreeRTOS的tick时间(一般设置为1ms),因此需要重新设计一套不基于system tick的微秒级延时函数。利用CM3/4内核中的数据观察点与跟踪(DWT)寄存器,可以在不占用硬件外设定时器的情况下实现微秒级的精准延时。

具体见另一篇文章:https://www.cnblogs.com/ike_li/p/17447986.html

11.FreeRTOSConfig.h 文件配置注释
来源:https://www.codenong.com/cs110642632/

/*
 * FreeRTOS 支持的调度方式FreeRTOS 操作系统支持三种调度方式:
 * 抢占式调度,时间片调度和合作式调度。
 * 实际应用主要是抢占式调度和时间片调度,合作式调度用到的很少。
 *
 * 抢占式调度:
 * 每个任务都有不同的优先级,任务会一直运行直到被高优先级任务抢占或者遇到阻塞式的 API 函数,比如 vTaskDelay。
 *
 * 时间片调度:
 * 每个任务都有相同的优先级,任务会运行固定的时间片个数或者遇到阻塞式的 API 函数,比如vTaskDelay,才会执行同优先级任务之间的任务切换。
 * 在 FreeRTOS 操作系统中只有同优先级任务才会使用时间片调度
 */

/**
 * 配置为 1, 使能抢占式调度器
 * 配置为 0, 使能合作式调度器
 */
#define configUSE_PREEMPTION                     1

/**
 * 只能使用编译器提供的RAM创建RTOS对象
 */
#define configSUPPORT_STATIC_ALLOCATION          0

/**
 * 使用从FreeRTOS堆自动分配的RAM创建RTOS对象
 */
#define configSUPPORT_DYNAMIC_ALLOCATION         1

/**
 * 钩子函数的主要功能是用于函数的扩展,用户可以根据自己的需要往里面添加相关的测试函数。
 */
//使能空闲任务的钩子函数
#define configUSE_IDLE_HOOK                      0
//使能滴答定时器中断里面执行的钩子函数
#define configUSE_TICK_HOOK                      0

/**
 * 此参数用于定义 CPU 的主频,单位 Hz
 */
#define configCPU_CLOCK_HZ                       ( SystemCoreClock )

/**
 * 此参数用于定义系统时钟节拍数,单位 Hz,一般取 1000Hz 即可
 */
#define configTICK_RATE_HZ                       ((TickType_t)1000)

/**
 * 此参数用于定义可供用户使用的最大优先级数,
 * 如果这个定义的是 5,那么用户可以使用的优先级号是 0,1,2,3,4,不包含 5
 */

#define configMAX_PRIORITIES                     ( 32 )

/**
 * 此参数用于定义空闲任务的栈空间大小,单位字,即 4 字节
 */
#define configMINIMAL_STACK_SIZE                 ((uint16_t)128)

/**
 * 定义堆大小,FreeRTOS 内核,用户动态内存申请,任务栈,任务创建,信号量创建,消息队列创建等都需要用这个空间
 */
#define configTOTAL_HEAP_SIZE                    ((size_t)10*1024)

/**
 * 定义任务名最大的字符数,末尾的结束符 '\0'也要计算在内
 */
#define configMAX_TASK_NAME_LEN                  ( 16 )

/**
 * 系统时钟节拍计数使用 TickType_t 数据类型定义的,
 * 如果用户使能了宏定义 configUSE_16_BIT_TICKS,那么 TickType_t 定义的就是 16 位无符号数,
 * 如果没有使能,那么 TickType_t 定义的就是 32 位无符号数。
 * 对于 32 位架构的处理器,一定要禁止此宏定义,即设置此宏定义数值为 0 即可。
 * 而 16 位无符号数类型主要用于 8 位和 16 位架构的处理器。
 */
#define configUSE_16_BIT_TICKS                   0

/**
 * 使能互斥信号量
 */
#define configUSE_MUTEXES                        1

/**
 * 通过此定义来设置可以注册的信号量和消息队列个数。
 */
#define configQUEUE_REGISTRY_SIZE                8

/* 某些运行FreeRTOS的硬件有两种方法选择下一个要执行的任务:
 * 通用方法和特定于硬件的方法(以下简称“特殊方法”)。
 *
 * 通用方法:
 *      1.configUSE_PORT_OPTIMISED_TASK_SELECTION 为 0 或者硬件不支持这种特殊方法。
 *      2.可以用于所有FreeRTOS支持的硬件
 *      3.完全用C实现,效率略低于特殊方法。
 *      4.不强制要求限制最大可用优先级数目
 * 特殊方法:
 *      1.必须将configUSE_PORT_OPTIMISED_TASK_SELECTION设置为1
 *      2.依赖一个或多个特定架构的汇编指令(一般是类似计算前导零[CLZ]指令)
 *      3.比通用方法更高效
 *      4.一般强制限定最大可用优先级数目为32
 * 一般是硬件计算前导零指令,如果所使用的,MCU没有这些硬件指令的话此宏应该设置为0
 */

/**
 * 此配置用于优化优先级列表中要执行的最高优先级任务的算法。对 CM 内核的移植文件,默认已经在文件 portmacro.h 文件中使能。
 */
#define configUSE_PORT_OPTIMISED_TASK_SELECTION  1

/* Co-routine definitions. */
/**
 * 使能合作式调度相关函数
 */
#define configUSE_CO_ROUTINES       0

/**
 * 此参数用于定义可供用户使用的最大的合作式任务优先级数
 */
#define configMAX_CO_ROUTINE_PRIORITIES ( 2 )

/* Software timer definitions. */
//禁能软件定时器
#define configUSE_TIMERS                0
//配置软件定时器任务的优先级
#define configTIMER_TASK_PRIORITY       ( 3 )
//配置软件定时器命令队列的长度
#define configTIMER_QUEUE_LENGTH        5
//配置软件定时器任务的栈空间大小
#define configTIMER_TASK_STACK_DEPTH    (configMINIMAL_STACK_SIZE)

/* 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   1
#define INCLUDE_vTaskSuspend            1
#define INCLUDE_vTaskDelayUntil         1
#define INCLUDE_vTaskDelay              1

/*
 * Cortex-M内核使用8bit来配置优先级,但是STM32只使用了高4bit,数值越小,优先级越高。
 * 在往寄存器里面写数值配置的时候,是按照8bit来写的,所以真正写的时候需要经过转换,公式为:
 * ((priority << (8 - __NVIC_PRIO_BITS)) & 0xff),其中的priority就是我们配置的真正的优先级
 */
//Use the system definition, if there is one
#ifdef __NVIC_PRIO_BITS
    #define configPRIO_BITS       __NVIC_PRIO_BITS
#else
    #define configPRIO_BITS       4        /* 15 priority levels */
#endif

#define configLIBRARY_LOWEST_INTERRUPT_PRIORITY         15

/**
 * SysTick和PendSV 都是配置为了最低优先级,即0xf 。这样可以提高系统的实时响应能力,即其他的外部中断可以及时的得到响应。
 *
 */
/* The lowest priority. */
#define configKERNEL_INTERRUPT_PRIORITY     ( configLIBRARY_LOWEST_INTERRUPT_PRIORITY << (8 - configPRIO_BITS) )

/*
 * 用于配置STM32的特殊寄存器basepri寄存器的值,用于屏蔽中断,当大于basepri值的优先级的中断将被全部屏蔽。basepri只有4bit有效,
 * 默认只为0,即全部中断都没有被屏蔽。configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY配置为:5,意思就是中断优先级大于5的中断都被屏蔽。
 * 当把配置好的优先级写到寄存器的时候,是按照8bit来写的,所以真正写的时候需要经过转换,公式为:
 * ((priority << (8 - __NVIC_PRIO_BITS)) & 0xff),其中的priority就是我们配置的真正的优先级。经过这个公式之后得到的是下面的这个宏:
 * configMAX_SYSCALL_INTERRUPT_PRIORITY
 *
 * 在FreeRTOS中,关中断是通过配置basepri寄存器来实现的,关掉的中断由配置的basepri的值决定,
 * 小于basepri值的中断FreeRTOS是关不掉的,这样做的好处是可以系统设计者可以人为的控制那些非常重要的中断不能被关闭,在紧要的关头必须被响应。
 * 而在UCOS中,关中断是通过控制PRIMASK来实现的,PRIMASK是一个单1的二进制位,写1则除能除了NMI和硬 fault的所有中断。
 * 当UCOS关闭中断之后,即使是你在系统中设计的非常紧急的中断来了都不能马上响应,这加大了中断延迟的时间,如果是性命攸关的场合,那后果估计挺严重。
 * 相比UCOS的关中断的设计,FreeRTOS的设计则显得人性化很多。
 */
#define configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY    5

/* Priority 5, or 95 as only the top four bits are implemented. */
/* !!!! configMAX_SYSCALL_INTERRUPT_PRIORITY must not be set to zero !!!!
See http://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html. */
#define configMAX_SYSCALL_INTERRUPT_PRIORITY    ( configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY << (8 - configPRIO_BITS) )

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

/**
 * 在 FreeRTOS 的移植文件 port.c 中有用到 SVC 中断的 0 号系统服务,即 SVC 0。此中断在 FreeRTOS中仅执行一次, 用于启动第一个要执行的任务。
 * 另外, 由于 FreeRTOS 没有配置 SVC 的中断优先级,默认没有配置的情况下, SVC 中断的优先级就是最高的 0。
 */
#define vPortSVCHandler SVC_Handler

/**
 * SysTick和PendSV 都是配置为了最低优先级
 */
#define xPortPendSVHandler PendSV_Handler
#define xPortSysTickHandler SysTick_Handler

#endif /* FREERTOS_CONFIG_H */

三、测试代码

/*

STM32F407ZGT6
168MHz
Flash size 1024Kbytes
RAM size 192KB

*/
#include "main.h"
#include <string.h>

#include "delay.h"
#include "led.h"
#include "key.h"
#include "timer2.h"
#include "timer3.h"

#include "usart1.h"
#include "usart2_timer.h"
#include "usart3.h"

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

//数字越大任务优先级越高
#define START_TASK_PRIO 1   //任务优先级
#define START_TASK_SIZE 128 //任务堆栈大小
TaskHandle_t START_TASK_HANDLER;//任务句柄

#define TASK1_TASK_PRIO 2   //任务优先级
#define TASK1_TASK_SIZE 100 //任务堆栈大小
TaskHandle_t TASK1_TASK_HANDLER;//任务句柄

#define TASK2_TASK_PRIO 3   //任务优先级
#define TASK2_TASK_SIZE 100 //任务堆栈大小
TaskHandle_t TASK2_TASK_HANDLER;//任务句柄

void start_task(void *pvParameters);
void task1_task(void *pvParameters);
void task2_task(void *pvParameters);


uint16_t TASK1_RUN_COUNT = 0;
uint16_t TASK2_RUN_COUNT = 0;

int main(void)
{
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);
    
    timer2_init();    
    usart1_init(115200);    
    
    //创建开始任务
    xTaskCreate((TaskFunction_t )start_task,           
                (const char*    )"start_task",          
                (uint16_t       )START_TASK_SIZE,        
                (void*          )NULL,                  
                (UBaseType_t    )START_TASK_PRIO,      
                (TaskHandle_t*  )&START_TASK_HANDLER); 
                
    //开启任务调度                
    vTaskStartScheduler();          


}
void start_task(void *pvParameters)
{
    taskENTER_CRITICAL(); //进入临界区  
 
    xTaskCreate((TaskFunction_t )task1_task,         
                (const char*    )"task1_task",       
                (uint16_t       )TASK1_TASK_SIZE, 
                (void*          )NULL,                
                (UBaseType_t    )TASK1_TASK_PRIO,    
                (TaskHandle_t*  )&TASK1_TASK_HANDLER);   
 
    xTaskCreate((TaskFunction_t )task2_task,     
                (const char*    )"task2_task",   
                (uint16_t       )TASK2_TASK_SIZE, 
                (void*          )NULL,
                (UBaseType_t    )TASK2_TASK_PRIO,
                (TaskHandle_t*  )&TASK2_TASK_HANDLER);  
                
    vTaskDelete(START_TASK_HANDLER);//删除开始任务
                
    taskEXIT_CRITICAL();//退出临界区
                
}

void task1_task(void *pvParameters)
{
    while(1)
    {
        TASK1_RUN_COUNT++;
        
        if(TASK1_RUN_COUNT == 10 && TASK2_TASK_HANDLER != NULL)
        {
            vTaskDelete(TASK2_TASK_HANDLER);//删除任务2            
            printf("task1 delete task2_task\r\n");
        }       
        vTaskDelay(3000);        
        printf("task1_task,%d \r\n",TASK1_RUN_COUNT);
    }
    
}   


void task2_task(void *pvParameters)
{
    
    while(1)
    {
        TASK2_RUN_COUNT++;        
        vTaskDelay(1000);        
        printf("task2_task,%d \r\n",TASK2_RUN_COUNT);
    }
    
}

测试结果
因为任务2的优先级比任务1高,所以先执行任务2,再执行任务1.
任务1执行耽误的时间长,在等待任务1的时候,任务2继续执行.

[16:13:30.043]收←◆task1_task,1 
task2_task,3 

[16:13:31.044]收←◆task2_task,4 

[16:13:32.045]收←◆task2_task,5 

[16:13:33.042]收←◆task1_task,2 
task2_task,6 

[16:13:34.046]收←◆task2_task,7 

[16:13:35.048]收←◆task2_task,8 

[16:13:36.043]收←◆task1_task,3 
task2_task,9 

[16:13:37.049]收←◆task2_task,10 

[16:13:38.051]收←◆task2_task,11 

[16:13:39.044]收←◆task1_task,4 
task2_task,12 

标签:TASK,优先级,FreeRTOS,任务,task,移植,define
From: https://www.cnblogs.com/ike_li/p/17656696.html

相关文章

  • lvgl-字库移植
    移植一下中文字库,不然后面有点麻烦1.先下载字库工具;链接我忘记了,百度应该有2.设置字体等选项设置这些选项然后就可以开始转换了,字体我记得下的时候自带一个的3.复制到程序内部:4.挂载字体(局部声明)这个是每个文件都需要声明一次的,而且部件要使用的话也要设置5.给部件添......
  • 在f1c100s芯片上移植spi网卡enc28j60的linux驱动
    前言我个人与全志的芯片颇有故事。在我还是一个不懂事的高中生时,我看到荔枝派的官方文档,顿时被这小小的板子给吸引住。点开文档的初见:荔枝派Nano(下面简称Nano)是一款精致迷你的Arm9核心板/开发板,可用于初学者学习linux或者商用于产品开发。Nano在与SD卡相当的尺寸上(25.4*3......
  • 【Freertos基础入门】深入浅出freertos互斥量
    @TOC前言FreeRTOS是一款开源的实时操作系统,提供了许多基本的内核对象,其中包括互斥锁(Mutex)。互斥锁是一种常用的同步机制,用于确保在同一时间内只有一个任务可以访问共享资源,防止竞态条件等并发问题。本文将介绍FreeRTOS中的互斥锁的使用方法和注意事项。一、互斥量是什么?当多个任务......
  • 【Freertos基础入门】队列(queue)的使用
    提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档@TOC前言本系列基于stm32系列单片机来使用freerotsFreeRTOS是一个广泛使用的开源实时操作系统(RTOS),它提供了丰富的功能和特性,使嵌入式系统的开发更加简单和高效。队列是FreeRTOS中常用的一种通信机制,它用于在任务之间传......
  • QT移植ARM开发板步骤
    原文:https://www.cnblogs.com/linux-learn/p/17058779.html一、新建编译平台更改../qt-everywhere-src-5.12.9/qtbase/mkspecs/linux-arm-gnueabi-g++/qmake.conf 目录下的文件1、添加:QT_QPA_DEFAULT_PLATFORM=linuxfbQMAKE_CFLAGS_RELEASE+=-O2-march=armv7-aQMAKE_C......
  • 将OLLVM从LLVM4移植到LLVM16
    title:将OLLVM从LLVM4移植到LLVM16date:2023-08-1714:00:00updated:2023-08-1714:00:00lang:zh-CNcategories:-[LLVM]-[OLLVM]tags:-LLVM-OLLVM-编译toc:true文章首发于https://wwh1004.com/porting-ollvm-from-llvm-4-to-llvm-16/本文介绍了将OLLVM从......
  • Qt for ARM_Linux环境搭建-Qt5.7+iTop4412嵌入式平台移植
    原文:https://blog.csdn.net/hechao3225/article/details/52981148经过为期3天的编译、移植,终于将Qt5.7成功移植到iTop4412开发板,板载exynos4412处理器,基于ARMCortex-A9内核。因此,本篇教程以iTop4412示例,适用于Qt5.7在ARM_Linux平台上的移植。---------------------------------......
  • 【Freertos基础入门】深入浅出freertos互斥量
    @TOC前言FreeRTOS是一款开源的实时操作系统,提供了许多基本的内核对象,其中包括互斥锁(Mutex)。互斥锁是一种常用的同步机制,用于确保在同一时间内只有一个任务可以访问共享资源,防止竞态条件等并发问题。本文将介绍FreeRTOS中的互斥锁的使用方法和注意事项。一、互斥量是什么?当多个任务......
  • 国产MCU-CW32F030开发学习- 移植rtthread-nano
    国产MCU-CW32F030开发学习--移植rtthread-nano硬件平台CW32_48F大学计划板CW32_IOT_EVA物联网开发评估套件RT-ThreadNanoRT-ThreadNano是一个极简版的硬实时内核,它是由C语言开发,采用面向对象的编程思维,具有良好的代码风格,是一款可裁剪的、抢占式实时多任务的RTOS。其内存资源......
  • RT-Thead学习-GD32移植(基于RT-Thread Nano源码)
    1前言当前关于RT的移植教程有很多,纯复制大佬们的很迷糊,参考官方手册和一些经验贴,完成了基于Nano源码的移植,最简单的移植教程就是基于keil的和这一种。参考资料1.野火资料(https://doc.embedfire.com/rtos/rtthread/zh/latest/application/porting_to_stm32.html)2.微信公众号(物联网......