freertos 订阅
在嵌入式领域中,嵌入式实时操作系统正得到越来越广泛的应用。采用嵌入式实时操作系统(RTOS)可以更合理、更有效地利用CPU的资源,简化应用软件的设计,缩短系统开发时间,更好地保证系统的实时性和可靠性。 展开全文
在嵌入式领域中,嵌入式实时操作系统正得到越来越广泛的应用。采用嵌入式实时操作系统(RTOS)可以更合理、更有效地利用CPU的资源,简化应用软件的设计,缩短系统开发时间,更好地保证系统的实时性和可靠性。
信息
本    质
小型实时操作系统内核
特    点
源码公开、可移植、可裁减
外文名
FreeRTOS
功能包括
任务管理、时间管理、内存管理
FreeRTOS简介
FreeRTOS是一个迷你的实时操作系统内核。作为一个轻量级的操作系统,功能包括:任务管理、时间管理、信号量、消息队列、内存管理、记录功能、软件定时器、协程等,可基本满足较小系统的需要。由于RTOS需占用一定的系统资源(尤其是RAM资源),只有μC/OS-II、embOS、salvo、FreeRTOS等少数实时操作系统能在小RAM单片机上运行。相对μC/OS-II、embOS等商业操作系统,FreeRTOS操作系统是完全免费的操作系统,具有源码公开、可移植、可裁减、调度策略灵活的特点,可以方便地移植到各种单片机上运行,其最新版本为10.3.1版。
收起全文
精华内容
下载资源
问答
  • FreeRTOS

    2020-09-09 17:59:55
    FreeRTOS中断优先级配置

    延时


    使用DWT来实现系统延时
    STM32 DWT


    配置及中断优先级


    FreeRTOS中断优先级配置
    stm32cubemx 配置freertos中断优先级
    FreeRTOS优先级详解
    在ARM Cortex-M内核上运行RTOS
    STM32中断,及FreeRTOS中断优先级配置
    c – FreeRTOS:osDelay vs HAL_delay
    cubemx在使用freertos的时候为何推荐使用除systick以外的timebase
    FreeRtos 任务优先级和中断优先级


    功能使用


    FreeRTOS学习笔记——任务间使用队列同步数据


    注意事项


    在启动FreeRTOS之前,开启了独立看门狗IWDG,3秒报警,但是在FreeRTOS任务中没有喂狗,导致运行3秒后,程序进入HardFault
    //MX_IWDG_Init();
    FREERTOS_Init();
    FREERTOS_Start();

    1、HAL_NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_4);
    2、FreeRTOS强制使用SysTick作为时基,并且将其中断优先级设置为最低。STM32 的HAL库的时基须选择其他定时器
    3、建议HAL库的时基使用TIM,便于移植操作系统,也便于从IAP跳转到APP控制(如果使用SysTick,在跳转到APP前,需要关闭SysTick中断 SysTick->CTRL &= ~SysTick_CTRL_TICKINT_Msk;//关闭SysTick中断)

    void vTaskStartScheduler( void )-->BaseType_t xPortStartScheduler( void )
    /* Make PendSV and SysTick the lowest priority interrupts. */
    	portNVIC_SYSPRI2_REG |= portNVIC_PENDSV_PRI;
    	portNVIC_SYSPRI2_REG |= portNVIC_SYSTICK_PRI;
    
    /* Cortex-M specific definitions. */
    #ifdef __NVIC_PRIO_BITS
     /* __BVIC_PRIO_BITS will be specified when CMSIS is being used. */
     #define configPRIO_BITS         __NVIC_PRIO_BITS
    #else
     #define configPRIO_BITS         4
    #endif
    
    /* The lowest interrupt priority that can be used in a call to a "set priority"
    function. */
    #define configLIBRARY_LOWEST_INTERRUPT_PRIORITY   15
    
    /* The highest interrupt priority that can be used by any interrupt service
    routine that makes calls to interrupt safe FreeRTOS API functions.  DO NOT CALL
    INTERRUPT SAFE FREERTOS API FUNCTIONS FROM ANY INTERRUPT THAT HAS A HIGHER
    PRIORITY THAN THIS! (higher priorities are lower numeric values. */
    #define configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY 5
    
    /* Interrupt priorities used by the kernel port layer itself.  These are generic
    to all Cortex-M ports, and do not rely on any particular library functions. */
    #define configKERNEL_INTERRUPT_PRIORITY 		( configLIBRARY_LOWEST_INTERRUPT_PRIORITY << (8 - configPRIO_BITS) )
    /* !!!! 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) )
    /* Definitions that map the FreeRTOS port interrupt handlers to their CMSIS
    standard names. */
    //在系统中的其他文件中不能在定义 SVC_Handler PendSV_Handler SysTick_Handler
    #define vPortSVCHandler    SVC_Handler
    #define xPortPendSVHandler PendSV_Handler
    
    /* IMPORTANT: This define is commented when used with STM32Cube firmware, when timebase is systick,
                  to prevent overwriting SysTick_Handler defined within STM32Cube HAL */
    #define xPortSysTickHandler SysTick_Handler
    
    

    FreeRTOS下载地址:

    https://download.csdn.net/download/lyrain2009/12847593


    void vListInsert( List_t * const pxList, ListItem_t * const pxNewListItem )

    /* *** NOTE ***********************************************************
    		If you find your application is crashing here then likely causes are
    		listed below.  In addition see https://www.freertos.org/FAQHelp.html for
    		more tips, and ensure configASSERT() is defined!
    		https://www.freertos.org/a00110.html#configASSERT
    
    			1) Stack overflow -
    			   see https://www.freertos.org/Stacks-and-stack-overflow-checking.html
    			2) Incorrect interrupt priority assignment, especially on Cortex-M
    			   parts where numerically high priority values denote low actual
    			   interrupt priorities, which can seem counter intuitive.  See
    			   https://www.freertos.org/RTOS-Cortex-M3-M4.html and the definition
    			   of configMAX_SYSCALL_INTERRUPT_PRIORITY on
    			   https://www.freertos.org/a00110.html
    			3) Calling an API function from within a critical section or when
    			   the scheduler is suspended, or calling an API function that does
    			   not end in "FromISR" from an interrupt.
    			4) Using a queue or semaphore before it has been initialised or
    			   before the scheduler has been started (are interrupts firing
    			   before vTaskStartScheduler() has been called?).
    

    RTOS编程思想

    1. 任务优先级分配
      1.1. 实时性要求高的,采用中断或者最高优先级,其对应的数据处理任务通过一直等待获取信号量完成信息处理
      1.2. 按键和显示任务采用较低优先级,采用任务延时循环运行
    2. 任务之间的交互
      2.1. 对于同一资源或外设的使用,可通过两种方式处理
      一种是创建一个专用任务用于处理,其他任务要使用资源或者外设,通过发送信号量或者消息邮箱
      一种是对资源或外设采用互斥信号量,保证同一时刻只有一个任务占用

    Freertos printf可重入的问题

    https://www.eemaker.com/freertos-printf.html

    展开全文
  • FreeRTOS系列第1篇---为什么选择FreeRTOS

    万次阅读 多人点赞 2015-11-13 15:55:38
    对比了许多RTOS,最终选择FreeRTOS,原因是多方面的: SafeRTOS便是基于FreeRTOS而来,前者是经过安全认证的RTOS,因此对于FreeRTOS的安全性也有了信心。 大量开发者使用,并保持高速增长趋势。2011、2012、2013、...

    1.为什么学习RTOS?

             作为基于ARM7、Cortex-M3硬件开发的嵌入式工程师,我一直反对使用RTOS。不仅因为不恰当的使用RTOS会给项目带来额外的稳定性风险,更重要的是我认为绝大多数基于ARM7、Cortex-M3硬件的项目,还没复杂到使用RTOS的地步,使用状态机就足够了。

             对于现代的微处理器,特别是资源相对丰富ARM7、Cortex-M3硬件来说,RTOS占用的硬件资源已经越来越可以忽略。所以在当今环境下,我们无需担心RTOS会拖累性能。相反,RTOS提供的事件驱动型设计方式,使得RTOS只是在处理实际任务时才会运行,这能够更合理的利用CPU。在实际项目中,如果程序等待一个超时事件,传统的无RTOS情况下,要么在原地一直等待而不能执行其它任务,要么使用复杂(相对RTOS提供的任务机制而言)的状态机机制。如果使用RTOS,则可以很方便的将当前任务阻塞在该事件下,然后自动去执行别的任务,这显然更方便,并且可以高效的利用CPU。处理这类事件,是我使用RTOS的最大动力,但考虑到系统的稳定性,我不得不再三权衡RTOS可能带来的一些弊端:

     

    1. 大多数RTOS代码都具有一定规模,任何代码都可能带来BUG,何况是代码具有一定规模的RTOS,因此引入RTOS的同时也可能会引入该RTOS的BUG,这些RTOS本身的BUG一旦被触发,影响可能是是灾难性的。
    2. 熟练的使用RTOS是一项技能,需要专业的知识储备和长期的经验积累。不将RTOS分析透彻,很容易为项目埋下错误。典型的,像中断优先级、任务堆栈分配、可重入等,都是更容易出错的地方。
    3. RTOS的优先级嵌套使得任务执行顺序、执行时序更难分析,甚至变成不可能。任务嵌套对所需的最大堆栈RAM大小估计也变得困难。这对于很多对安全有严格要求的场合是不可想象的。
    4. RTOS应该用于任务复杂的场合,以至于对任务调度的需求可以抵消RTOS所带来的稳定性影响,但大部分的应用并非复杂到需要RTOS。

     

             以上原因是我拒绝在实际项目中使用RTOS的理由,但是否使用RTOS跟是否学习RTOS完全是两码事。我认为任何嵌入式软件设计人员都应该至少学习一种RTOS,不仅是需要掌握RTOS背后的操作系统原理、学习RTOS的编程方式,更是为将来做准备。

             即便我认为现在的物联网有点言过其实,但我依然看好物联网的发展前景。随着物联网的发展,未来的嵌入式产品必然更为复杂、连接性更强以及需要更丰富的用户界面。当处理这些任务时,一个好的RTOS就变得不可缺少了。

             书到用时方恨少,我希望自己永远不会有这种感觉。所以从现在起,我要开始深入一个RTOS,探索它背后的原理,掌握其编程方法,避免其缺陷和陷阱,并将它安全的用在将来的项目中。

    2.为什么选用FreeRTOS?

             对比了许多RTOS,最终选择FreeRTOS,原因是多方面的:

     

    1. SafeRTOS便是基于FreeRTOS而来,前者是经过安全认证的RTOS,因此对于FreeRTOS的安全性也有了信心。
    2.  大量开发者使用,并保持高速增长趋势。2011、2012、2013、2014、2015、2017年(暂时没有2016年的数据)、2019年(暂时没有2018年的数据)的EEtimes杂志嵌入式系统市场报告显示,FreeRTOS在RTOS内核使用榜和RTOS内核计划使用榜上都名列前茅。更多的人使用可以促进发现BUG,增强稳定性。
    3. 简单。内核只有3个.c文件,全部围绕着任务调度,没有任何其它干扰,便于理解学习。而且,我根本不需要其它繁多的功能,只要任务调度就够了。
    4. 文档齐全。在FreeRTOS官方网站上,可以找到所有你需要的资料。
    5. 免费、开放源码。完全可以免费用于商业产品,开放源码更便于学习操作系统原理、从全局掌握FreeRTOS运行机理、以及对操作系统进行深度裁剪以适应自己的硬件。
    6. 2017年底,FreeRTOS作者加入亚马逊,担任首席工程师,FreeRTOS也由亚马逊管理。同时修改了用户许可证,FreeRTOS变得更加开放和自由。背靠亚马逊,相信未来FreeRTOS会更加稳定可靠。此外,以前价格不菲的《实时内核指南》和《参考手册》也免费开放下载,这使得学习更加容易。

     

             学习的资料来源主要是FreeRTOS的官方网站(www.freertos.org)和源代码。FreeRTOS的创始人RichardBarry编写了大量的移植代码和配套文档,我只不过是沿着Richard Barry铺好的路前进,所以,这没什么困难的。

             最后,感谢RichardBarry的付出,感谢Richard Barry的无私开源精神!

     

    附录1: EEtimes杂志嵌入式市场调查报告有关RTOS使用榜截图

    附录1.1  2010和2011年RTOS使用榜

     

    附录1.2  2012和2013年RTOS使用榜


    附录1.3   2013年和2014年RTOS使用榜

     

    附录1.4   2014年和2015年RTOS使用榜

    附录1.5   2017年RTOS使用榜

    附录1.6   2019年RTOS使用榜

     

     

    展开全文
  • FreeRTOS系列第6篇---FreeRTOS内核配置说明

    万次阅读 多人点赞 2015-12-01 21:14:21
    FreeRTOS内核是高度可定制的,使用配置文件FreeRTOSConfig.h进行定制。每个FreeRTOS应用都必须包含这个头文件,用户根据实际应用来裁剪定制FreeRTOS内核。这个配置文件是针对用户程序的,而非内核,因此配置文件一般...

           FreeRTOS内核是高度可定制的,使用配置文件FreeRTOSConfig.h进行定制。每个FreeRTOS应用都必须包含这个头文件,用户根据实际应用来裁剪定制FreeRTOS内核。这个配置文件是针对用户程序的,而非内核,因此配置文件一般放在应用程序目录下,不要放在RTOS内核源码目录下。

           在下载的FreeRTOS文件包中,每个演示例程都有一个FreeRTOSConfig.h文件。有些例程的配置文件是比较旧的版本,可能不会包含所有有效选项。如果没有在配置文件中指定某个选项,那么RTOS内核会使用默认值。典型的FreeRTOSConfig.h配置文件定义如下所示,随后会说明里面的每一个参数。

     

    #ifndef FREERTOS_CONFIG_H
    #define FREERTOS_CONFIG_H
     
    /*Here is a good place to include header files that are required across
    yourapplication. */
    #include "something.h"
     
    #define configUSE_PREEMPTION                    1
    #define configUSE_PORT_OPTIMISED_TASK_SELECTION 0
    #define configUSE_TICKLESS_IDLE                 0
    #define configCPU_CLOCK_HZ                      60000000
    #define configTICK_RATE_HZ                      250
    #define configMAX_PRIORITIES                    5
    #define configMINIMAL_STACK_SIZE                128
    #define configTOTAL_HEAP_SIZE                   10240
    #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                       0
    #define configUSE_RECURSIVE_MUTEXES             0
    #define configUSE_COUNTING_SEMAPHORES           0
    #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
     
    /*Hook function related definitions. */
    #define configUSE_IDLE_HOOK                     0
    #define configUSE_TICK_HOOK                     0
    #define configCHECK_FOR_STACK_OVERFLOW          0
    #define configUSE_MALLOC_FAILED_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         1
     
    /*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        [dependent of processor]
    #define configMAX_SYSCALL_INTERRUPT_PRIORITY   [dependent on processor and application]
    #define configMAX_API_CALL_INTERRUPT_PRIORITY  [dependent on processor and application]
     
    /*Define to trap errors during development. */
    #define configASSERT( ( x ) )     if( ( x ) == 0) vAssertCalled( __FILE__, __LINE__ )
     
    /*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_xTimerGetTimerDaemonTaskHandle  0
    #define INCLUDE_pcTaskGetTaskName               0
    #define INCLUDE_eTaskGetState                   0
    #define INCLUDE_xEventGroupSetBitFromISR        1
    #define INCLUDE_xTimerPendFunctionCall          0
     
    /* Aheader file that defines trace macro can be included here. */
     
    #end if/* FREERTOS_CONFIG_H*/

     

    1.configUSE_PREEMPTION

           为1时RTOS使用抢占式调度器,为0时RTOS使用协作式调度器(时间片)。

          注:在多任务管理机制上,操作系统可以分为抢占式和协作式两种。协作式操作系统是任务主动释放CPU后,切换到下一个任务。任务切换的时机完全取决于正在运行的任务。

    2.configUSE_PORT_OPTIMISED_TASK_SELECTION

           某些运行FreeRTOS的硬件有两种方法选择下一个要执行的任务:通用方法和特定于硬件的方法(以下简称“特殊方法”)。

           通用方法:

     

    • configUSE_PORT_OPTIMISED_TASK_SELECTION设置为0或者硬件不支持这种特殊方法。
    • 可以用于所有FreeRTOS支持的硬件。
    • 完全用C实现,效率略低于特殊方法。
    • 不强制要求限制最大可用优先级数目

     

           特殊方法:

     

    • 并非所有硬件都支持。
    • 必须将configUSE_PORT_OPTIMISED_TASK_SELECTION设置为1。
    • 依赖一个或多个特定架构的汇编指令(一般是类似计算前导零[CLZ]指令)。
    • 比通用方法更高效。
    • 一般强制限定最大可用优先级数目为32。

     

    3.configUSE_TICKLESS_IDLE

           设置configUSE_TICKLESS_IDLE为1使能低功耗tickless模式,为0保持系统节拍(tick)中断一直运行。

           通常情况下,FreeRTOS回调空闲任务钩子函数(需要设计者自己实现),在空闲任务钩子函数中设置微处理器进入低功耗模式来达到省电的目的。因为系统要响应系统节拍中断事件,因此使用这种方法会周期性的退出、再进入低功耗状态。如果系统节拍中断频率过快,则大部分电能和CPU时间会消耗在进入和退出低功耗状态上。

           FreeRTOS的tickless空闲模式会在空闲周期时停止周期性系统节拍中断。停止周期性系统节拍中断可以使微控制器长时间处于低功耗模式。移植层需要配置外部唤醒中断,当唤醒事件到来时,将微控制器从低功耗模式唤醒。微控制器唤醒后,会重新使能系统节拍中断。由于微控制器在进入低功耗后,系统节拍计数器是停止的,但我们又需要知道这段时间能折算成多少次系统节拍中断周期,这就需要有一个不受低功耗影响的外部时钟源,即微处理器处于低功耗模式时它也在计时的,这样在重启系统节拍中断时就可以根据这个外部计时器计算出一个调整值并写入RTOS 系统节拍计数器变量中。

    4.configUSE_IDLE_HOOK

           设置为1使用空闲钩子(Idle Hook类似于回调函数),0忽略空闲钩子。

           当RTOS调度器开始工作后,为了保证至少有一个任务在运行,空闲任务被自动创建,占用最低优先级(0优先级)。对于已经删除的RTOS任务,空闲任务可以释放分配给它们的堆栈内存。因此,在应用中应该注意,使用vTaskDelete()函数时要确保空闲任务获得一定的处理器时间。除此之外,空闲任务没有其它特殊功能,因此可以任意的剥夺空闲任务的处理器时间。

           应用程序也可能和空闲任务共享同个优先级。

           空闲任务钩子是一个函数,这个函数由用户来实现,RTOS规定了函数的名字和参数,这个函数在每个空闲任务周期都会被调用。

           要创建一个空闲钩子:

     

    1.  设置FreeRTOSConfig.h 文件中的configUSE_IDLE_HOOK 为1;
    2.  定义一个函数,函数名和参数如下所示:
    void vApplicationIdleHook(void );

     

           这个钩子函数不可以调用会引起空闲任务阻塞的API函数(例如:vTaskDelay()、带有阻塞时间的队列和信号量函数),在钩子函数内部使用协程是被允许的。

           使用空闲钩子函数设置CPU进入省电模式是很常见的。

    5.configUSE_MALLOC_FAILED_HOOK

           每当一个任务、队列、信号量被创建时,内核使用一个名为pvPortMalloc()的函数来从堆中分配内存。官方的下载包中包含5个简单内存分配策略,分别保存在源文件heap_1.c、heap_2.c、heap_3.c、heap_4.c、heap_5.c中。        仅当使用这五个简单策略之一时,宏configUSE_MALLOC_FAILED_HOOK才有意义。

           如果定义并正确配置malloc()失败钩子函数,则这个函数会在pvPortMalloc()函数返回NULL时被调用。只有FreeRTOS在响应内存分配请求时发现堆内存不足才会返回NULL。

           如果宏configUSE_MALLOC_FAILED_HOOK设置为1,那么必须定义一个malloc()失败钩子函数,如果宏configUSE_MALLOC_FAILED_HOOK设置为0,malloc()失败钩子函数不会被调用,即便已经定义了这个函数。malloc()失败钩子函数的函数名和原型必须如下所示:

    void vApplicationMallocFailedHook( void);

    6.configUSE_TICK_HOOK

           设置为1使用时间片钩子(Tick Hook),0忽略时间片钩子。

           注:时间片钩子函数(Tick Hook Function)

           时间片中断可以周期性的调用一个被称为钩子函数(回调函数)的应用程序。时间片钩子函数可以很方便的实现一个定时器功能。

           只有在FreeRTOSConfig.h中的configUSE_TICK_HOOK设置成1时才可以使用时间片钩子。一旦此值设置成1,就要定义钩子函数,函数名和参数如下所示:

    void vApplicationTickHook( void );

     

           vApplicationTickHook()函数在中断服务程序中执行,因此这个函数必须非常短小,不能大量使用堆栈,只能调用以”FromISR" 或 "FROM_ISR”结尾的API函数。

           在FreeRTOSVx.x.x\FreeRTOS\Demo\Common\Minimal文件夹下的crhook.c文件中有使用时间片钩子函数的例程。

    7.configCPU_CLOCK_HZ

           写入实际的CPU内核时钟频率,也就是CPU指令执行频率,通常称为Fcclk。配置此值是为了正确的配置系统节拍中断周期。

    8.configTICK_RATE_HZ

           RTOS 系统节拍中断的频率。即一秒中断的次数,每次中断RTOS都会进行任务调度。

    系统节拍中断用来测量时间,因此,越高的测量频率意味着可测到越高的分辨率时间。但是,高的系统节拍中断频率也意味着RTOS内核占用更多的CPU时间,因此会降低效率。RTOS演示例程都是使用系统节拍中断频率为1000HZ,这是为了测试RTOS内核,比实际使用的要高。(实际使用时不用这么高的系统节拍中断频率)

           多个任务可以共享一个优先级,RTOS调度器为相同优先级的任务分享CPU时间,在每一个RTOS 系统节拍中断到来时进行任务切换。高的系统节拍中断频率会降低分配给每一个任务的“时间片”持续时间。

    9.configMAX_PRIORITIES

           配置应用程序有效的优先级数目。任何数量的任务都可以共享一个优先级,使用协程可以单独的给与它们优先权。见configMAX_CO_ROUTINE_PRIORITIES。

           在RTOS内核中,每个有效优先级都会消耗一定量的RAM,因此这个值不要超过你的应用实际需要的优先级数目。

    注:任务优先级

           每一个任务都会被分配一个优先级,优先级值从0~ (configMAX_PRIORITIES - 1)之间。低优先级数表示低优先级任务。空闲任务的优先级为0(tskIDLE_PRIORITY),因此它是最低优先级任务。

           FreeRTOS调度器将确保处于就绪状态(Ready)或运行状态(Running)的高优先级任务比同样处于就绪状态的低优先级任务优先获取处理器时间。换句话说,处于运行状态的任务永远是高优先级任务。

           处于就绪状态的相同优先级任务使用时间片调度机制共享处理器时间。

    10.configMINIMAL_STACK_SIZE

           定义空闲任务使用的堆栈大小。通常此值不应小于对应处理器演示例程文件FreeRTOSConfig.h中定义的数值。

           就像xTaskCreate()函数的堆栈大小参数一样,堆栈大小不是以字节为单位而是以字为单位的,比如在32位架构下,栈大小为100表示栈内存占用400字节的空间。

    11.configTOTAL_HEAP_SIZE

           RTOS内核总计可用的有效的RAM大小。仅在你使用官方下载包中附带的内存分配策略时,才有可能用到此值。每当创建任务、队列、互斥量、软件定时器或信号量时,RTOS内核会为此分配RAM,这里的RAM都属于configTOTAL_HEAP_SIZE指定的内存区。后续的内存配置会详细讲到官方给出的内存分配策略。

    12.configMAX_TASK_NAME_LEN

           调用任务函数时,需要设置描述任务信息的字符串,这个宏用来定义该字符串的最大长度。这里定义的长度包括字符串结束符’\0’。

    13.configUSE_TRACE_FACILITY

           设置成1表示启动可视化跟踪调试,会激活一些附加的结构体成员和函数。

    14.configUSE_STATS_FORMATTING_FUNCTIONS (V7.5.0新增)

           设置宏configUSE_TRACE_FACILITY和configUSE_STATS_FORMATTING_FUNCTIONS为1会编译vTaskList()和vTaskGetRunTimeStats()函数。如果将这两个宏任意一个设置为0,上述两个函数不会被编译。

    15.configUSE_16_BIT_TICKS

           定义系统节拍计数器的变量类型,即定义portTickType是表示16位变量还是32位变量。

           定义configUSE_16_BIT_TICKS为1意味着portTickType代表16位无符号整形,定义configUSE_16_BIT_TICKS为0意味着portTickType代表32位无符号整形。

           使用16位类型可以大大提高8位和16位架构微处理器的性能,但这也限制了最大时钟计数为65535个’Tick’。因此,如果Tick频率为250HZ(4MS中断一次),对于任务最大延时或阻塞时间,16位计数器是262秒,而32位是17179869秒。

    16.configIDLE_SHOULD_YIELD

           这个参数控制任务在空闲优先级中的行为。仅在满足下列条件后,才会起作用。

     

    1. 使用抢占式内核调度
    2. 用户任务使用空闲优先级。

     

             通过时间片共享同一个优先级的多个任务,如果共享的优先级大于空闲优先级,并假设没有更高优先级任务,这些任务应该获得相同的处理器时间。

             但如果共享空闲优先级时,情况会稍微有些不同。当configIDLE_SHOULD_YIELD为1时,其它共享空闲优先级的用户任务就绪时,空闲任务立刻让出CPU,用户任务运行,这样确保了能最快响应用户任务。处于这种模式下也会有不良效果(取决于你的程序需要),描述如下:

     

           图中描述了四个处于空闲优先级的任务,任务A、B和C是用户任务,任务I是空闲任务。上下文切换周期性的发生在T0、T1…T6时刻。当用户任务运行时,空闲任务立刻让出CPU,但是,空闲任务已经消耗了当前时间片中的一定时间。这样的结果就是空闲任务I和用户任务A共享一个时间片。用户任务B和用户任务C因此获得了比用户任务A更多的处理器时间。

     

           可以通过下面方法避免:

     

    • 如果合适的话,将处于空闲优先级的各单独的任务放置到空闲钩子函数中;
    • 创建的用户任务优先级大于空闲优先级;
    • 设置IDLE_SHOULD_YIELD为0;

     

           设置configIDLE_SHOULD_YIELD为0将阻止空闲任务为用户任务让出CPU,直到空闲任务的时间片结束。这确保所有处在空闲优先级的任务分配到相同多的处理器时间,但是,这是以分配给空闲任务更高比例的处理器时间为代价的。

    17.configUSE_TASK_NOTIFICATIONS(V8.2.0新增)

           设置宏configUSE_TASK_NOTIFICATIONS为1(或不定义宏configUSE_TASK_NOTIFICATIONS)将会开启任务通知功能,有关的API函数也会被编译。设置宏configUSE_TASK_NOTIFICATIONS为0则关闭任务通知功能,相关API函数也不会被编译。默认这个功能是开启的。开启后,每个任务多增加8字节RAM。

           这是个很有用的特性,一大亮点。

           每个RTOS任务具有一个32位的通知值,RTOS任务通知相当于直接向任务发送一个事件,接收到通知的任务可以解除任务的阻塞状态(因等待任务通知而进入阻塞状态)。相对于以前必须分别创建队列、二进制信号量、计数信号量或事件组的情况,使用任务通知显然更灵活。更好的是,相比于使用信号量解除任务阻塞,使用任务通知可以快45%(使用GCC编译器,-o2优化级别)。

    18.configUSE_MUTEXES

           设置为1表示使用互斥量,设置成0表示忽略互斥量。读者应该了解在FreeRTOS中互斥量和二进制信号量的区别。

           关于互斥量和二进制信号量简单说:

     

    • 互斥型信号量必须是同一个任务申请,同一个任务释放,其他任务释放无效。
    • 二进制信号量,一个任务申请成功后,可以由另一个任务释放。
    • 互斥型信号量是二进制信号量的子集

     

    19.configUSE_RECURSIVE_MUTEXES

           设置成1表示使用递归互斥量,设置成0表示不使用。

    20.configUSE_COUNTING_SEMAPHORES

           设置成1表示使用计数信号量,设置成0表示不使用。

    21.configUSE_ALTERNATIVE_API

           设置成1表示使用“替代”队列函数('alternative' queue functions),设置成0不使用。替代API在queue.h头文件中有详细描述。

            注:“替代”队列函数已经被弃用,在新的设计中不要使用它!

    22.configCHECK_FOR_STACK_OVERFLOW

           每个任务维护自己的栈空间,任务创建时会自动分配任务需要的占内存,分配内存大小由创建任务函数(xTaskCreate())的一个参数指定。堆栈溢出是设备运行不稳定的最常见原因,因此FreeeRTOS提供了两个可选机制用来辅助检测和改正堆栈溢出。配置宏configCHECK_FOR_STACK_OVERFLOW为不同的常量来使用不同堆栈溢出检测机制。

           注意,这个选项仅适用于内存映射未分段的微处理器架构。并且,在RTOS检测到堆栈溢出发生之前,一些处理器可能先产生故障(fault)或异常(exception)来反映堆栈使用的恶化。如果宏configCHECK_FOR_STACK_OVERFLOW没有设置成0,用户必须提供一个栈溢出钩子函数,这个钩子函数的函数名和参数必须如下所示:

     

    void vApplicationStackOverflowHook(TaskHandle_t xTask, signed char *pcTaskName );

     

           参数xTask和pcTaskName为堆栈溢出任务的句柄和名字。请注意,如果溢出非常严重,这两个参数信息也可能是错误的!在这种情况下,可以直接检查pxCurrentTCb变量。

           推荐仅在开发或测试阶段使用栈溢出检查,因为堆栈溢出检测会增大上下文切换开销。

           任务切换出去后,该任务的上下文环境被保存到自己的堆栈空间,这时很可能堆栈的使用量达到了最大(最深)值。在这个时候,RTOS内核会检测堆栈指针是否还指向有效的堆栈空间。如果堆栈指针指向了有效堆栈空间之外的地方,堆栈溢出钩子函数会被调用。

           这个方法速度很快,但是不能检测到所有堆栈溢出情况(比如,堆栈溢出没有发生在上下文切换时)。设置configCHECK_FOR_STACK_OVERFLOW为1会使用这种方法。

           当堆栈首次创建时,在它的堆栈区中填充一些已知值(标记)。当任务切换时,RTOS内核会检测堆栈最后的16个字节,确保标记数据没有被覆盖。如果这16个字节有任何一个被改变,则调用堆栈溢出钩子函数。

           这个方法比第一种方法要慢,但也相当快了。它能有效捕捉堆栈溢出事件(即使堆栈溢出没有发生在上下文切换时),但是理论上它也不能百分百的捕捉到所有堆栈溢出(比如堆栈溢出的值和标记值相同,当然,这种情况发生的概率极小)。

           使用这个方法需要设置configCHECK_FOR_STACK_OVERFLOW为2.

    23.configQUEUE_REGISTRY_SIZE

           队列记录有两个目的,都涉及到RTOS内核的调试:

     

    1. 它允许在调试GUI中使用一个队列的文本名称来简单识别队列;
    2. 包含调试器需要的每一个记录队列和信号量定位信息;

     

           除了进行内核调试外,队列记录没有其它任何目的。

           configQUEUE_REGISTRY_SIZE定义可以记录的队列和信号量的最大数目。如果你想使用RTOS内核调试器查看队列和信号量信息,则必须先将这些队列和信号量进行注册,只有注册后的队列和信号量才可以使用RTOS内核调试器查看。查看API参考手册中的vQueueAddToRegistry() 和vQueueUnregisterQueue()函数获取更多信息。

    24.configUSE_QUEUE_SETS

           设置成1使能队列集功能(可以阻塞、挂起到多个队列和信号量),设置成0取消队列集功能。

    25.configUSE_TIME_SLICING(V7.5.0新增)

           默认情况下(宏configUSE_TIME_SLICING未定义或者宏configUSE_TIME_SLICING设置为1),FreeRTOS使用基于时间片的优先级抢占式调度器。这意味着RTOS调度器总是运行处于最高优先级的就绪任务,在每个RTOS 系统节拍中断时在相同优先级的多个任务间进行任务切换。如果宏configUSE_TIME_SLICING设置为0,RTOS调度器仍然总是运行处于最高优先级的就绪任务,但是当RTOS 系统节拍中断发生时,相同优先级的多个任务之间不再进行任务切换。

    26.configUSE_NEWLIB_REENTRANT(V7.5.0新增)

           如果宏configUSE_NEWLIB_REENTRANT设置为1,每一个创建的任务会分配一个newlib(一个嵌入式C库)reent结构。

    27.configENABLE_BACKWARD_COMPATIBILITY

           头文件FreeRTOS.h包含一系列#define宏定义,用来映射版本V8.0.0和V8.0.0之前版本的数据类型名字。这些宏可以确保RTOS内核升级到V8.0.0或以上版本时,之前的应用代码不用做任何修改。在FreeRTOSConfig.h文件中设置宏configENABLE_BACKWARD_COMPATIBILITY为0会去掉这些宏定义,并且需要用户确认升级之前的应用没有用到这些名字。

    28.configNUM_THREAD_LOCAL_STORAGE_POINTERS

           设置每个任务的线程本地存储指针数组大小。

           线程本地存储允许应用程序在任务的控制块中存储一些值,每个任务都有自己独立的储存空间,宏configNUM_THREAD_LOCAL_STORAGE_POINTERS指定每个任务线程本地存储指针数组的大小。API函数vTaskSetThreadLocalStoragePointer()用于向指针数组中写入值,API函数pvTaskGetThreadLocalStoragePointer()用于从指针数组中读取值。

           比如,许多库函数都包含一个叫做errno的全局变量。某些库函数使用errno返回库函数错误信息,应用程序检查这个全局变量来确定发生了那些错误。在单线程程序中,将errno定义成全局变量是可以的,但是在多线程应用中,每个线程(任务)必须具有自己独有的errno值,否则,一个任务可能会读取到另一个任务的errno值。

           FreeRTOS提供了一个灵活的机制,使得应用程序可以使用线程本地存储指针来读写线程本地存储。具体参见后续文章《FreeRTOS系列第12篇---FreeRTOS任务应用函数》。

    29.configGENERATE_RUN_TIME_STATS

           设置宏configGENERATE_RUN_TIME_STATS为1使能运行时间统计功能。一旦设置为1,则下面两个宏必须被定义:

     

    1. portCONFIGURE_TIMER_FOR_RUN_TIME_STATS():用户程序需要提供一个基准时钟函数,函数完成初始化基准时钟功能,这个函数要被define到宏portCONFIGURE_TIMER_FOR_RUN_TIME_STATS()上。这是因为运行时间统计需要一个比系统节拍中断频率还要高分辨率的基准定时器,否则,统计可能不精确。基准定时器中断频率要比统节拍中断快10~100倍。基准定时器中断频率越快,统计越精准,但能统计的运行时间也越短(比如,基准定时器10ms中断一次,8位无符号整形变量可以计到2.55秒,但如果是1秒中断一次,8位无符号整形变量可以统计到255秒)。
    2. portGET_RUN_TIME_COUNTER_VALUE():用户程序需要提供一个返回基准时钟当前“时间”的函数,这个函数要被define到宏portGET_RUN_TIME_COUNTER_VALUE()上。

     

           举一个例子,假如我们配置了一个定时器,每500us中断一次。在定时器中断服务例程中简单的使长整形变量ulHighFrequencyTimerTicks自增。那么上面提到两个宏定义如下(可以在FreeRTOSConfig.h中添加):

     

        extern volatile unsigned longulHighFrequencyTimerTicks;
        #define portCONFIGURE_TIMER_FOR_RUN_TIME_STATS() ( ulHighFrequencyTimerTicks = 0UL )
        #define portGET_RUN_TIME_COUNTER_VALUE() ulHighFrequencyTimerTicks

     

    30.configUSE_CO_ROUTINES

           设置成1表示使用协程,0表示不使用协程。如果使用协程,必须在工程中包含croutine.c文件。

           注:协程(Co-routines)主要用于资源发非常受限的嵌入式系统(RAM非常少),通常不会用于32位微处理器。

           在当前嵌入式硬件环境下,不建议使用协程,FreeRTOS的开发者早已经停止开发协程。

    31.configMAX_CO_ROUTINE_PRIORITIES

           应用程序协程(Co-routines)的有效优先级数目,任何数目的协程都可以共享一个优先级。使用协程可以单独的分配给任务优先级。见configMAX_PRIORITIES。

    32.configUSE_TIMERS

           设置成1使用软件定时器,为0不使用软件定时器功能。详细描述见FreeRTOS software timers 。

    33.configTIMER_TASK_PRIORITY

           设置软件定时器服务/守护进程的优先级。详细描述见FreeRTOS software timers 。

    34.configTIMER_QUEUE_LENGTH

           设置软件定时器命令队列的长度。详细描述见FreeRTOS software timers。

    35.configTIMER_TASK_STACK_DEPTH

           设置软件定时器服务/守护进程任务的堆栈深度,详细描述见FreeRTOS software timers 。

    36.configKERNEL_INTERRUPT_PRIORITY、configMAX_SYSCALL_INTERRUPT_PRIORITY和configMAX_API_CALL_INTERRUPT_PRIORITY

           这是移植和应用FreeRTOS出错最多的地方,所以需要打起精神仔细读懂。

           Cortex-M3、PIC24、dsPIC、PIC32、SuperH和RX600硬件设备需要设置宏configKERNEL_INTERRUPT_PRIORITY;PIC32、RX600和Cortex-M硬件设备需要设置宏configMAX_SYSCALL_INTERRUPT_PRIORITY。

           configMAX_SYSCALL_INTERRUPT_PRIORITY和configMAX_API_CALL_INTERRUPT_PRIORITY,这两个宏是等价的,后者是前者的新名字,用于更新的移植层代码。

           注意下面的描述中,在中断服务例程中仅可以调用以“FromISR”结尾的API函数。

     

    • 仅需要设置configKERNEL_INTERRUPT_PRIORITY的硬件设备(也就是宏configMAX_SYSCALL_INTERRUPT_PRIORITY不会用到):configKERNEL_INTERRUPT_PRIORITY用来设置RTOS内核自己的中断优先级。调用API函数的中断必须运行在这个优先级;不调用API函数的中断,可以运行在更高的优先级,所以这些中断不会被因RTOS内核活动而延时。 
    • configKERNEL_INTERRUPT_PRIORITY和configMAX_SYSCALL_INTERRUPT_PRIORITY都需要设置的硬件设备:configKERNEL_INTERRUPT_PRIORITY用来设置RTOS内核自己的中断优先级。因为RTOS内核中断不允许抢占用户使用的中断,因此这个宏一般定义为硬件最低优先级。configMAX_SYSCALL_INTERRUPT_PRIORITY用来设置可以在中断服务程序中安全调用FreeRTOS API函数的最高中断优先级。优先级小于等于这个宏所代表的优先级时,程序可以在中断服务程序中安全的调用FreeRTOS API函数;如果优先级大于这个宏所代表的优先级,表示FreeRTOS无法禁止这个中断,在这个中断服务程序中绝不可以调用任何API函数。

     

           通过设置configMAX_SYSCALL_INTERRUPT_PRIORITY的优先级级别高于configKERNEL_INTERRUPT_PRIORITY可以实现完整的中断嵌套模式。这意味着FreeRTOS内核不能完全禁止中断,即使在临界区。此外,这对于分段内核架构的微处理器是有利的。请注意,当一个新中断发生后,某些微处理器架构会(在硬件上)禁止中断,这意味着从硬件响应中断到FreeRTOS重新使能中断之间的这段短时间内,中断是不可避免的被禁止的。

           不调用API的中断可以运行在比configMAX_SYSCALL_INTERRUPT_PRIORITY高的优先级,这些级别的中断不会被FreeRTOS禁止,因此不会因为执行RTOS内核而被延时。

           例如:假如一个微控制器有8个中断优先级别:0表示最低优先级,7表示最高优先级(Cortex-M3和Cortex-M4内核优先数和优先级别正好与之相反,后续文章会专门介绍它们)。当两个配置选项分别为4和0时,下图描述了每一个优先级别可以和不可做的事件:

     

    • configMAX_SYSCALL_INTERRUPT_PRIORITY=4
    • configKERNEL_INTERRUPT_PRIORITY=0

     

     

     

           这些配置参数允许非常灵活的中断处理:

           在系统中可以像其它任务一样为中断处理任务分配优先级。这些任务通过一个相应中断唤醒。中断服务例程(ISR)内容应尽可能的精简---仅用于更新数据然后唤醒高优先级任务。ISR退出后,直接运行被唤醒的任务,因此中断处理(根据中断获取的数据来进行的相应处理)在时间上是连续的,就像ISR在完成这些工作。这样做的好处是当中断处理任务执行时,所有中断都可以处在使能状态。

           中断、中断服务例程(ISR)和中断处理任务是三码事:当中断来临时会进入中断服务例程,中断服务例程做必要的数据收集(更新),之后唤醒高优先级任务。这个高优先级任务在中断服务例程结束后立即执行,它可能是其它任务也可能是中断处理任务,如果是中断处理任务,那么就可以根据中断服务例程中收集的数据做相应处理。

           configMAX_SYSCALL_INTERRUPT_PRIORITY接口有着更深一层的意义:在优先级介于RTOS内核中断优先级(等于configKERNEL_INTERRUPT_PRIORITY)和configMAX_SYSCALL_INTERRUPT_PRIORITY之间的中断允许全嵌套中断模式并允许调用API函数。大于configMAX_SYSCALL_INTERRUPT_PRIORITY的中断优先级绝不会因为执行RTOS内核而延时。

           运行在大于configMAX_SYSCALL_INTERRUPT_PRIORITY的优先级中断是不会被RTOS内核所屏蔽的,因此也不受RTOS内核功能影响。这主要用于非常高的实时需求中。比如执行电机转向。但是,这类中断的中断服务例程中绝不可以调用FreeRTOS的API函数。

          为了使用这个方案,应用程序要必须符合以下规则:调用FreeRTOS API函数的任何中断,都必须和RTOS内核处于同一优先级(由宏configKERNEL_INTERRUPT_PRIORITY设置),或者小于等于宏configMAX_SYSCALL_INTERRUPT_PRIORITY定义的优先级。

    37.configASSERT

           断言,调试时可以检查传入的参数是否合法。FreeRTOS内核代码的关键点都会调用configASSERT( x )函数,如果参数x为0,则会抛出一个错误。这个错误很可能是传递给FreeRTOS API函数的无效参数引起的。定义configASSERT()有助于调试时发现错误,但是,定义configASSERT()也会增大应用程序代码量,增大运行时间。推荐在开发阶段使用这个断言宏。

           举一个例子,我们想把非法参数所在的文件名和代码行数打印出来,可以先定义一个函数vAssertCalled,该函数有两个参数,分别接收触发configASSERT宏的文件名和该宏所在行,然后通过显示屏或者串口输出。代码如下:

     

        #define configASSERT( ( x ) )     if( ( x ) == 0 )vAssertCalled( __FILE__, __LINE__ )

     

           这里__FILE__和__LINE__是大多数编译器预定义的宏,分别表示代码所在的文件名(字符串格式)和行数(整形)。

           这个例子虽然看起来很简单,但由于要把整形__LINE__转换成字符串再显示,在效率和实现上,都不能让人满意。我们可以使用C标准库assert的实现方法,这样函数vAssertCalled只需要接收一个字符串形式的参数(推荐仔细研读下面的代码并理解其中的技巧):

     

         #define STR(x)  VAL(x)
         #define VAL(x)  #x
         #define configASSERT(x) ((x)?(void) 0 :xAssertCalld(__FILE__ ":" STR(__LINE__) " " #x"\n"))

     

           这里稍微讲解一下,由于内置宏__LINE__是整数型的而不是字符串型,把它转化成字符串需要一个额外的处理层。宏STR和和宏VAL正是用来辅助完成这个转化。宏STR用来把整形行号替换掉__LINE__,宏VAL用来把这个整形行号字符串化。忽略宏STR和VAL中的任何一个,只能得到字符串”__LINE__”,这不是我们想要的。

           这里使用三目运算符’?:’来代替参数判断if语句,这样可以接受任何参数或表达式,代码也更紧凑,更重要的是代码优化度更高,因为如果参数恒为真,在编译阶段就可以去掉不必要的输出语句。

    38.INCLUDE Parameters

           以“INCLUDE”起始的宏允许用户不编译那些应用程序不需要的实时内核组件(函数),这可以确保在你的嵌入式系统中RTOS占用最少的ROM和RAM。

    每个宏以这样的形式出现:

           INCLUDE_FunctionName

          在这里FunctionName表示一个你可以控制是否编译的API函数。如果你想使用该函数,就将这个宏设置成1,如果不想使用,就将这个宏设置成0。比如,对于API函数vTaskDelete():

     

    #define INCLUDE_vTaskDelete    1

     

           表示希望使用vTaskDelete(),允许编译器编译该函数

     

    #define INCLUDE_vTaskDelete    0

     

           表示禁止编译器编译该函数。

    展开全文
  • FreeRTOS_freertos_源码

    2021-09-29 03:50:44
    STM32的FreeRTOS的文档说明和开发,希望对大家有帮助
  • 实现STM32F4 基于FreeRtos的多机485串口通讯
  • 野火开发板,FreeRTOS实现任务管理源代码。
  • 单片机 freertos 操作系统 的简要使用说明,快速上手操作。
  • FreeRTOS系列第5篇---FreeRTOS在Cortex-M3上的移植

    万次阅读 多人点赞 2015-11-27 16:38:46
    1. FreeRTOS下载包的文件结构 在FreeRTOS官方网站可以下载到最新版的FreeRTOS包,我这里使用的是V8.2.3版本。 下载包内的总文件数量多的令人生畏,但文件结构却很简洁。《FreeRTOS入门指南》一文的第3节详细描述了...

    1. FreeRTOS下载包的文件结构

          在FreeRTOS官方网站可以下载到最新版的FreeRTOS包,我这里使用的是V8.2.3版本。

          下载包内的总文件数量多的令人生畏,但文件结构却很简洁。《FreeRTOS入门指南》一文的第3节详细描述了下载包文件结构,我们这里只是简单提一下。

          下载包根目录下包含两个子目录:FreeRTOS和FreeRTOS-Plus。其中,FreeRTOS-Plus文件夹中包含一些FreeRTOS+组件和演示例程(组件大都收费),我们不对这个文件夹下的内容多做了解,重点说一下FreeRTOS文件夹。

          FreeRTOS文件夹下包含两个子目录:Demo和Source。其中,Demo包含演示例程的工程文件,Source包含实时操作系统源代码文件。

          FreeRTOS实时操作系统内核仅包含三个必要文件,此外还有三个可选文件。RTOS核心代码位于三个源文件中,分别是tasks.c、queue.c和list.c。这三个文件位于FreeRTOS/Source目录下,在同一目录下还有3个可选的文件,叫做timers.c、event_groups.c和croutine.c,分别用于软件定时器、事件组和协程。

          对于支持的处理器架构,RTOS需要一些与处理器架构相关的代码。可以称之为RTOS硬件接口层,它们位于FreeRTOS/Source/Portable/[相应编译器]/[相应处理器架构]文件夹下。我们这次要移植到Cortex-M3微控制,使用Keil MDK编译器,所以需要的RTOS硬件接口代码位于:FreeRTOS\Source\portable\RVDS\ARM_CM3文件夹下。

          堆栈分配也是属于硬件接口层(移植层),在FreeRTOS/Source/portable/MemMang文件夹下具有各种类型的堆栈分配方案。这里我们使用heap_1.c提供的堆栈分配方案。关于FreeRTOS的内存管理,后续《FreeRTOS内存管理》一文中会详细介绍FreeRTOS内存管理的特性和用法,《FreeRTOS内存管理分析》一文会从源码级别分析FreeRTOS内存管理的具体实现,这里不用多纠结,你也可以快速的浏览一下这两篇文章,里面或许有许多不懂的,但不要着急,先放过它们。

          FreeRTOS文件夹下的Demo文件夹中还包括各种演示例程,涉及多种架构的处理器以及多种编译器。FreeRTOS/Demo/Common/Minimal文件夹下的演示例程代码中,绝大部分对所有移植硬件接口都是适用的。FreeRTOS/Demo/Common/Full文件夹下的代码属于历史遗留代码,仅用于PC移植层。

    2. 移植前的一些准备

     

    • 一块具有Cortex-M3微处理器的硬件板子,并且保证板子可以正常运转。
    • 下载FreeRTOS程序包(《FreeRTOS历史版本更新记录》一文中有下载地址,这是我在CSDN下载频道做的镜像文件。如果你能忍受下载网速慢,也可以去官方网站下载。)
    • 下载CMSIS-M3,其实主要是需要里面的core_cm3.h文件(可以去ARM官方下载,如果你安装了keil 5或比较新的Keil 4 MDK编译器,在目录:Keil\ARM\CMSIS文件夹下也可以找到)

     

    3.移植过程

    3.1 添加RTOS核心代码

             将tasks.c、queue.c和list.c这三个内核代码加入工程,将port.c和heap_1.c这两个与处理器相关代码加入工程。port.c位于FreeRTOS\Source\portable\RVDS\ARM_CM3文件夹下,heap_1.c位于FreeRTOS/Source/portable/MemMang文件夹下。

    3.2 添加头文件路径

     

    1.  ...\FreeRTOS\Source\portable\RVDS\ARM_CM3
    2.  …\FreeRTOS\Source\include

     

    3.3 编写FreeRTOSConfig.h文件

          对于刚接触FreeRTOS的用户来说,最简单方法是找一个类似的Demo工程,复制该工程下的FreeRTOSConfig.h文件,在这个基础上进行修改。详细的配置说明将在后续《FreeRTOS内核配置说明》一文中给出,这里依然不必纠结。

    3.4 编写一些钩子函数

          如果你在FreeRTOSConfig.h中设置了configUSE_TICK_HOOK=1,则必须编写voidvApplicationTickHook( void )函数。该函数利用时间片中断,可以很方便的实现一个定时器功能。详见后续文章《FreeRTOS内核配置说明》有关宏configUSE_TICK_HOOK一节。

          如果你在FreeRTOSConfig.h中设置了configCHECK_FOR_STACK_OVERFLOW=1或=2,则必须编写voidvApplicationStackOverflowHook( xTaskHandle pxTask, signed char *pcTaskName )函数,该函数用于检测堆栈溢出,详见后续文章《FreeRTOS内核配置说明》有关宏configCHECK_FOR_STACK_OVERFLOW一节。

    3.5 检查硬件

          为了验证你的硬件板子是否可靠的工作,首先编写一个小程序片,比如闪烁一个LED灯或者发送一个字符等等,我们这里使用UART发送一个字符。代码如下所示(假设你已经配置好了启动代码,并正确配置了UART):

     

           #include"task.h"
           #include"queue.h"
           #include"list.h"
           #include"portable.h"   
           #include"debug.h"
         
           int main(void)
           {
               init_rtos_debug();           //初始化调试串口
               MAP_UARTCharPut('A');        //发送一个字符
               while(1);
           }

     

          如果硬件可以正常发送字符,说明硬件以及启动代码OK,可以进行下一步。

    3.6 挂接中断

          在Cortex-M3硬件下,FreeRTOS使用SysTick作为系统节拍时钟,使用SVC和PendSVC进行上下文切换。异常中断服务代码位于port.c文件中,FreeRTOS的作者已经为各种架构的CPU写好了这些代码,可以直接拿来用,需要用户做的,仅仅是将这些异常中断入口地址挂接到启动代码中。

          在startup.s中,使用IMPORT关键字声明要挂接的异常中断服务函数名,然后将:

     

             DCD     SVC_Handler            换成:   DCD     vPortSVCHandler
             DCD     PendSV_Handler         换成:   DCD     xPortPendSVHandler
             DCD     SysTick_Handler        换成:   DCD     xPortSysTickHandler

    3.7 建立第一个任务Task

          在步骤3.5中,我们为了测试硬件是是否能够工作,编写了一个发送字符的小函数,这里我们将把这个小函数作为我们第一个任务要执行的主要代码:每隔1秒钟,发送一个字符。代码如下所示:

     

       void vTask(void *pvParameters)
       {
            while(1)
            {
                MAP_UARTCharPut(0x31);
                vTaskDelay(1000/portTICK_RATE_MS);
            }
       }

     

          FreeRTOS的任务以及编写格式将在后续文章《FreeRTOS任务概述》一文中详述,这里只是一个很简单的任务,先有有大体印象。这里面有一个API函数vTaskDelay(),这个函数用于延时,具体用法将在后续文章《FreeRTOS任务控制》一文中详细介绍,延时函数代码级分析将在《FreeRTOS高级篇10---系统节拍时钟分析》。这里不必在意太多的未知情况,因为后面会一点点将这些未知空间探索一遍的。

    3.8 设置节拍时钟

          这里我们使用SysTick定时器作为系统的节拍时钟,设定每隔10ms产生一次节拍中断。由于FreeRTOS对移植做了非常多的工作,以至于我们只需要在FreeRTOSConfig.h中配置好以下两个宏定义即可:

     

    1. configCPU_CLOCK_HZ     (/*你的硬件平台CPU系统时钟,Fcclk*/)
    2. configTICK_RATE_HZ       ((portTickType)100)         

     

          第一个宏定义CPU系统时钟,也就是CPU执行时的频率。第二个宏定义FreeRTOS的时间片频率,这里定义为100,表明RTOS一秒钟可以切换100次任务,也就是每个时间片为10ms。

          在prot.c中,函数vPortSetupTimerInterrupt()设置节拍时钟。该函数根据上面的两个宏定义的参数,计算SysTick定时器的重装载数值寄存器,然后设置SysTick定时器的控制及状态寄存器,设置如下:使用内核时钟源、使能中断、使能SysTick定时器。另外,函数vPortSetupTimerInterrupt()由函数vTaskStartScheduler()调用,这个函数用于启动调度器。

    3.9设置中断优先级相关宏

          这里特别重要,因为涉及到中断优先级和中断嵌套。这里先给出基于Cortex-M3硬件(lpc177x_8x系列微控制器)的一个配置例子,在FreeRTOSConfig.h中:

     

    #ifdef __NVIC_PRIO_BITS
             #define configPRIO_BITS   __NVIC_PRIO_BITS
    #else
             #define configPRIO_BITS   5  /*lpc177x_8x微处理器使用优先级寄存器的5位*/
    #endif
     
    /*设置内核使用的中断优先级*/
    #define configKERNEL_INTERRUPT_PRIORITY      ( 31 << (8 - configPRIO_BITS) )
    /*定义RTOS可以屏蔽的最大中断优先级,大于这个优先级的中断,不受RTOS控制*/
    #define configMAX_SYSCALL_INTERRUPT_PRIORITY   ( 5<< (8 - configPRIO_BITS) )

     

          后续文章《FreeRTOS内核配置说明》会详细介绍这些宏的含义,对于Cortex-M内核,后续文章《Cortex-M内核使用FreeRTOS特别注意事项》一文,会讲述这些宏与硬件的联系,那个时候你一定会清楚这些宏所定义的数字会对你的硬件产生什么影响的。现在,我们只需要知道他们很重要就足够了,没人能一口吃成胖子。

    3.10 设置其它宏

          还需要在FreeRTOSConfig.h设置一些必要的宏,这些宏如下所示:

     

    #define configUSE_PREEMPTION 1            //配置为1使用抢占式内核,配置为0使用时间片
    #define configUSE_IDLE_HOOK  0            //设置为1使用空闲钩子;设置为0不使用空闲钩子
    #define configMAX_PRIORITIES      ( 5 )   //应用程序任务中可用优先级数目
    #define configUSE_TICK_HOOK       0       //就设置为1使用时间片钩子,设置为0不使用
    #define configMINIMAL_STACK_SIZE      ( ( unsigned short ) 80 )     //最小空闲堆栈
    #define configTOTAL_HEAP_SIZE         ( ( size_t ) ( 5 * 1024 ) )   //内核总共可用RAM

     

    3.11 创建任务

          调用FreeRTOS提供的API函数来创建任务,代码如下所示:

     

         xTaskCreate(vTask,"Task1",50,NULL,1,NULL);

     

          关于详细的创建任务API函数,会在后续文章《FreeRTOS任务创建和删除》一文中介绍。

    3.12 开启调度器

          调用FreeRTOS提供的API函数来启动调度器,代码如下所示:

     

         vTaskStartScheduler();

     

          关于详细的开启调度器API函数,会在后续文章《FreeRTOS内核控制》一文中介绍。

          此时的main函数代码如下所示:

     

         int main(void)
         {
             init_rtos_debug();                             //初始化调试串口
      
              xTaskCreate(vTask,"Task1",50,NULL,1,NULL);
              vTaskStartScheduler();
              while(1);   
           }

     

    4. 小结

          到这里,一个最基本的FreeRTOS应用程序就已经运行起来,将硬件板子接到PC的RS232串口,可以观察到每隔一秒钟,板子都会向PC发送一个指定的字符。

          回头看一下移植过程,FreeRTOS移植到Cortex-M3硬件是多么的简单,这一方面归功于FreeRTOS的设计师已经为移植做了大量工作,同时,新一代的Cortex-M3硬件也为操作系统增加了一些列便利特性,比如SysTick定时器和全新的中断及异常。

          但是移植成功也只是万里长征的第一步,因为这只是最简单的应用。我们还不清楚FreeRTOS背后的机理、调度算法的面貌、甚至连信号量也都没有涉及。就本文的移植过程来看,我们也刻意忽略了很多细节,比如FreeRTOSConfig.h文件中的宏都有什么意义?改动后对RTOS有何影响?比如FreeRTOS任务API的细节、调度API的细节,再比如FreeRTOS的内存如何分配?如何进行堆栈溢出检查等等。

          所以,先不要沾沾自喜,曲折的道路还远没到来呢。

          接下来的很多篇文章会围绕这个最简单的移植例程做详细的讲解,要把本篇文章中刻意隐藏的细节一一拿出来。这要一直持续到我们介绍队列、信号量、互斥量等通讯机制为止。

    展开全文
  • STM32F429 FreeRTOS开发手册V1_stm32f429freertos_freertos入门_freertos.zip
  • STM32F429 FreeRTOS开发手册V1_stm32f429freertos_freertos入门_freertos_源码.zip
  • Freertos实验

    2017-02-14 09:37:39
    Freertos实验
  • FreeRTOS移植实验
  • FreeRTOS学习

    2019-01-18 11:36:16
    最好用的嵌入式操作系统FreeRTOS学习资料,系统调用讲解,源码分析。
  • FreeRTOS教程

    2016-12-05 21:03:37
    FreeRTOS经典入门教程
  • freeRTOS指南

    2017-09-22 21:07:29
    是否要在系统中使用FreeRTOS,虽然我想要的也仅仅是一个实时内核,当然更重要的 是免费。之所以翻译这篇文章倒不是因为FreeRTOS有多么优秀,完全是因为这篇文章 还不算太长。而且FreeRTOS.net仿佛致力于这个内核在...
  • FreeRTOS中文版

    2020-09-30 10:56:07
    FREERTOS 实时内核实用指南,FreeRTOS中文手册,可供下载 FREERTOS 实时内核实用指南,FreeRTOS中文手册,可供下载
  • FreeRTOS API

    2016-04-14 02:00:26
    FreeRTOS的API
  • FreeRTOS.zip

    2019-12-15 21:20:13
    FreeRTOS实时内核使用指南,FreeRTOS实时内核使用指南FreeRTOS实时内核使用指南FreeRTOS实时内核使用指南
  • freeRTOS开发

    2018-08-22 14:13:55
    freeRTOS系统开发介绍,在STM32上最适合的介绍文档。适合大中小学习者
  • freertos插件 在使用FreeRTOS超过8年之后,我决定开始添加我希望一开始就可以使用的功能和实现。 当前功能 C ++包装器 封装了FreeRTOS功能的C ++包装器的集合,允许您在仍使用FreeRTOS的情况下用C ++编写RTOS应用...
  • FreeRTOS源码

    2018-09-01 17:52:26
    FreeRTOS源代码,方便学习嵌入式实时操作系统,从源代码中可以更好的理解操作系统的运行机制
  • FreeRTOS 版本

    2017-11-30 11:35:33
    freertos 版本9.0.0 还有从官方下载的组件,包括udp等
  • FreeRTOS移植

    2018-05-06 22:29:27
    FreeRTOS移植到stm32f429(编辑器是MDK5)。。。。。。。
  • trace FreeRTOS

    2018-06-22 18:51:46
    博客:https://blog.csdn.net/weixin_37058227/article/details/80776249 配置好的Trace+FreeRTOS+stm32 文件

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 21,630
精华内容 8,652
关键字:

freertos