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

    千次阅读 多人点赞 2013-11-20 11:50:37
    FreeRTOS(读作"free-arr-toss")是一个嵌入式系统使用的开源实时操作系统。FreeRTOS被设计为“小巧,简单,和易用”,能支持许多不同硬件架构以及交叉编译器。 FreeRTOS自2002年Richard Barry开始开发以来,一直都...

    本文转自点击打开链接,技术改变世界,阅读塑造人生。

    FreeRTOS(读作"free-arr-toss")是一个嵌入式系统使用的开源实时操作系统。FreeRTOS被设计为“小巧,简单,和易用”,能支持许多不同硬件架构以及交叉编译器。

    FreeRTOS自2002年Richard Barry开始开发以来,一直都在积极开发中。至于我,我不是FreeRTOS的开发人员或贡献者,我只不过是一个最终用户和爱好者。因此,这章将着重与FreeRTOS架构之“是什么”和“怎么做”,而相对本书其他章节来说,较少去讲“为什么”。

    就像所有操作系统一样,FreeRTOS的主要工作是执行任务。大部分FreeRTOS的代码都涉及优先权、调度以及执行用户自定义任务。但又与所有其他操作系统不同,FreeRTOS是一款运行在嵌入式系统上的实时操作系统。

    到本章结束,我希望你可以了解FreeRTOS的基本架构。大部分FreeRTOS致力于执行任务,所以你可以很好地看到它究竟是如何做到的。

    如果这是你首次去深入了解一个操作系统,我还是希望你可以学习到最基本的操作系统是如何工作的。FreeRTOS是相对简单的,特别是相比Windows,linux,或者OS X而言,不过所有操作系统都有着相同的概念和目标,所以不论学习哪个操作系统都是有启发和有趣的。

    3.1 什么是“嵌入式”和“实时”?

    “嵌入式”和“实时”对于不同的人来说代表不同的理解,所以让我们像FreeRTOS用户那样来定义它们。

    嵌入式系统就是一个专门设计用来做一些简单事情的计算机系统,就像是电视遥控器,车载GPS,电子手表,或者起搏器这类。嵌入式系统比通用计算机系统显著的区别在于更小和更慢,通常也更便宜。一个典型的低端嵌入式系统可能有一个运行速度为25MHz的8位CPU,几KB的内存,和也许32KB的闪存。一个高端的嵌入式系统可能有一个运行速度为750MHz的32位CPU,一个GB左右的内存,和几个GB的闪存。

    实时系统是设计去完成一定时间内的事,它们保证这些事是在应该做的时候去做。

    心脏起搏器是实时嵌入式系统的一个极好例子。起搏器必须在正确的时间收缩心肌,以挽救你的生命;它不能够太忙而没有及时响应。心脏起搏器以及其他的实时嵌入式系统都必须精心设计,以便在任何时刻都能及时执行它们的任务。

    3.2架构概述

    FreeRTOS是一个相对较小的应用程序。最小化的FreeRTOS内核仅包括3个(.c)文件和少数头文件,总共不到9000行代码,还包括了注释和空行。一个典型的编译后(二进制)代码映像小于10KB。

    FreeRTOS的代码可以分解为三个主要区块:任务,通讯,和硬件接口。

    ●任务:大约有一半的FreeRTOS的核心代码用来处理多数操作系统首要关注的问题:任务。任务是给定优先级的用户定义的C函数。task.c和task.h完成了所有有关创建,调度,和维护任务的繁重工作。

    ●通讯:任务很重要,不过任务间可以互相通讯则更为重要!它给我们带来FreeRTOS的第二项任务:通讯。大约40%的FreeRTOS核心代码是用来处理通讯的。queue.cqueue.h是负责处理FreeRTOS的通讯的。任务和中断使用队列互相发送数据,并且使用信号灯和互斥来发送临界资源的使用情况。

    ●硬件接口:接近9000行的代码拼凑起基本的FreeRTOS,是硬件无关的;相同的代码都能够运行,不论FreeRTOS是运行在不起眼的8051,还是最新、最炫的ARM内核上。大约有6%的FreeRTOS的核心代码,在硬件无关的FreeRTOS内核与硬件相关的代码间扮演着垫片的角色。我们将在下个部分讨论硬件相关的代码。

    硬件注意事项

    硬件无关的FreeRTOS层在硬件相关层之上。硬件相关层声明了你选择什么样的芯片架构。图3.1显示了FreeRTOS的各层。

    enter image description here

    图3.1:FreeRTOS的软件层

    FreeRTOS包含所有你需要用来启动很运行系统的硬件无关以及硬件相关的代码。它支持许多编译器(CodeWarrior,GCC,IAR等)也支持许多处理器架构(ARM7,ARM Cortex-M3,PICs各系列,Silicon Labs 8051, x86等)。请参阅FreeRTOS网站,可以看到处理器和编译器支持列表。

    FreeRTOS是高可配置设计。FreeRTOS可以被编译成为适合单CPU,极简RTOS,只之支持少数任务的操作系统,也可以被编译成为适合多核功能强大的结合了TCP/IP,文件系统,和USB的怪兽。

    配置选项可以通过设置不同的#defines,在FreeRTOSConfig.h文件里选择。时钟速度,堆大小,互斥,和API子集,连同其他许多选项,都可以在这个文件中配置。这里是几个例子,设置了任务优先级的最大数量,CPU的频率,系统节拍器的频率,最小的堆栈大小和总的堆大小:

    #define configMAX_PRIORITIES      ( ( unsigned portBASE_TYPE ) 5 )
    #define configCPU_CLOCK_HZ        ( 12000000UL )
    #define configTICK_RATE_HZ        ( ( portTickType ) 1000 )
    #define configMINIMAL_STACK_SIZE  ( ( unsigned short ) 100 )
    #define configTOTAL_HEAP_SIZE     ( ( size_t ) ( 4 * 1024 ) )

    对于不同的交叉编译器和CPU架构,硬件相关代码分布在多个文件中。举例来说,如果你使用ARM Cortex-M3芯片,IAR编译器工作,那么硬件相关的代码就存在FreeRTOS/Source/portable/IAR/ARM_CM3/目录下。portmacro.h文件声明了所有硬件特定功能,port.cportasm.s 包含了所有实际硬件相关的代码。硬件无关的头文件portable.h在编译的时候用#include's引入正确的portmacro.h文件。FreeRTOS使用#define'd调用在portmacro.h中声明的硬件特定功能。

    让我们来看一个例子,FreeRTOS是如何调用一个硬件相关功能的。硬件无关的文件tasks.c常常需要插入一个代码的临界区,以防止抢占。在不同架构上,插入一个临界区的表现也不同,并且硬件无关的task.c不需要了解硬件相关的细节。所以task.c调用全局宏指令portENTER_CRITICAL(), 乐得忽略它实际上是如何做到的。假设我们使用IAR编译器在ARM Crotex-M3芯片上编译生成FreeRTOS,使用那个定义了portENTER_CRITICAL()的文件/Source/portable/IAR/ARM_CM3/portmacro.h,如下所示:

    #define portENTER_CRITICAL()   vPortEnterCritical()

    vPortEnterCritical()实际上是在FreeRTOS/Source/portable/IAR/ARM_CM3/port.c中定义的。这个port.c文件是一个硬件相关的文件,同时包含了对IAR编译器和Cortex-M3芯片认识的代码文件。vPortEnterCritical()函数利用这些硬件特定的知识进入临界区,又返回到与硬件无关的task.c中。

    protmacro.h文件也定义了一个数据类型的基本架构。这个数据类型中包括了基本整型变量,指针,以及系统时钟节拍器的数据类型,在ARM Cortex-M3 chips上使用IAR编译器时,就采用如下定义:

    #define portBASE_TYPE  long              // Basic integer variable type
    #define portSTACK_TYPE unsigned long     // Pointers to memory locations
    typedef unsigned portLONG portTickType;  // The system timer tick type

    这样使用数据类型的方法,和函数透过小层的#defines,看上去略微有点复杂,不过它允许了FreeRTOS能够被重新编译在一个完全不同的系统架构上,仅仅只需要通过修改这些硬件相关的文件。同时,如果你想要让FreeRTOS运行在一个当前尚未被支持的架构上,你只仅仅需要去实现硬件相关的功能,这要比在FreeRTOS上去实现硬件无关的部分,要少得多。

    就如同我们已经见到的,FreeRTOS用C的预处理宏#define来实现硬件相关的功能。FreeRTOS也同样用#define来应对大量的硬件无关的代码。对于非嵌入式应用程序这样频繁使用#define是一个严重的错误,不过在许多小型嵌入式系统中这点开销比起“实时”所提供的功能来说就微不足道了。

    3.3. 调度任务:快速概述

    任务优先级和就绪列表

    所有任务都有一个用户指定优先级,从0(最低优先级)到 configMAX_PRIORITIES-1的编译时间值(最高优先级)。例如,如果configMAX_PRIORITIES设置为5,当FreeRTOS使用5个优先等级时:0(最低优先级),1,2,3,和4(最高优先级)。

    FreeRTOS使用一个“就绪列表”来跟踪所有已经准备好运行的任务。它像一个任务列表数组来实现就绪列表,如下所示:

    static xList pxReadyTasksLists[ configMAX_PRIORITIES ];  /* Prioritised ready tasks.  */

    pxReadyTasksLists[0]是所有准备好的优先级为0的任务列表,pxReadyTasksLists[1]是所有准备好的优先级为1的任务列表,以此类推,直到pxReadyTasksLists[configMAX_PRIORITIES-1]

    系统节拍器(时钟)

    FreeRTOS系统的心跳就是被称为系统节拍器(时钟)。FreeRTOS配置这个系统生成一个定期的节拍(时钟)中断。用户可以配置的节拍中断频率,通常是在毫秒范围。vTaskSwitchContext()函数在每次的节拍中断释放的时候被调用。vTaskSwitchContext()选择优先级最高的就绪任务并将它赋予pxCurrentTCB变量,如下所示:

    /* Find the highest-priority queue that contains ready tasks. */
    while( listLIST_IS_EMPTY( &( pxReadyTasksLists[ uxTopReadyPriority ] ) ) )
    {
        configASSERT( uxTopReadyPriority );
        --uxTopReadyPriority;
    }
    
    /* listGET_OWNER_OF_NEXT_ENTRY walks through the list, so the tasks of the same 
    priority get an equal share of the processor time. */
    listGET_OWNER_OF_NEXT_ENTRY( pxCurrentTCB, &( pxReadyTasksLists[ uxTopReadyPriority ] ) );

    在当型循环(while loop)开始之前,uxTopReadyPriority就被确保大于或等于优先级最高的就绪任务。while()循环从优先级uxTopReadyPriority开始,循环走下去从pxReadyTasksLists[]数组里找到就绪任务优先级最高的那个。接着listGET_OWNER_OF_NEXT_ENTRY()就抢占那个就绪列表中优先级最高的下一个就绪任务。

    现在pxCurrentTCB指向了优先级最高的任务,并且当vTaskSwitchContext()返回硬件相关代码时开始运行那个任务。

    那九行代码是FreeRTOS的绝对核心。其余FreeRTOS的8900+行代码都是用来确保那九行代码,全都是用来保持优先级最高任务的运行的。

    图3.2是一个大致的就绪列表看起来像什么的图。这个例子有三个优先级,有一个优先级为0的任务,没有优先级为1的任务,和三个优先级为2的任务。这张图是准确的,但不完整的;它的少掉一些细节,我们稍后将补充。

    enter image description here

    图3.2:FreeRTOS的就绪列表的基本视图

    现在我们有了大致概述的方式,让我们去深究它的细节。我们将着眼于三个主要FreeRTOS的数据结构:任务,列表和队列。

    3.4. 任务

    所有操作系统的主要工作是运行和协调用户任务。像多数操作系统一样,FreeRTOS中的基本工作单元是任务。FreeRTOS的使用任务控制块(TCB)来表示每个任务。

    任务控制块(TCB)

    TCB的在tasks.c定义是这样的:

    typedef struct tskTaskControlBlock
    {
      volatile portSTACK_TYPE *pxTopOfStack;                  /* Points to the location of
                                                                 the last item placed on 
                                                                 the tasks stack.  THIS 
                                                                 MUST BE THE FIRST MEMBER 
                                                                 OF THE STRUCT. */
    
      xListItem    xGenericListItem;                          /* List item used to place 
                                                                 the TCB in ready and 
                                                                 blocked queues. */
      xListItem    xEventListItem;                            /* List item used to place 
                                                                 the TCB in event lists.*/
      unsigned portBASE_TYPE uxPriority;                      /* The priority of the task
                                                                 where 0 is the lowest 
                                                                 priority. */
      portSTACK_TYPE *pxStack;                                /* Points to the start of 
                                                                 the stack. */
      signed char    pcTaskName[ configMAX_TASK_NAME_LEN ];   /* Descriptive name given 
                                                                 to the task when created.
                                                                 Facilitates debugging 
                                                                 only. */
    
      #if ( portSTACK_GROWTH > 0 )
        portSTACK_TYPE *pxEndOfStack;                         /* Used for stack overflow 
                                                                 checking on architectures
                                                                 where the stack grows up
                                                                 from low memory. */
      #endif
    
      #if ( configUSE_MUTEXES == 1 )
        unsigned portBASE_TYPE uxBasePriority;                /* The priority last 
                                                                 assigned to the task - 
                                                                 used by the priority 
                                                                 inheritance mechanism. */
      #endif
    
    } tskTCB;

    TCB在pxStack里存储堆栈的起始地址,以及在pxTopOfStack里存储当前堆栈的顶部。如果堆栈“向上”增长到更高的地址,它还在pxEndOfStack存储堆栈的结束的指针来检查堆栈溢出。如果堆栈“向下”增长到更低的地址,那么通过比较当前堆栈的顶部与pxStack中的堆内存起始位置来检查溢出。

    TCB在uxPriorityuxBasePriority中存储任务的初始优先级。一个任务在它创建的时候被赋予优先级,同时任务的优先级是可以被改变的。如果FreeRTOS实现了优先级继承,那么当任务临时提升到“继承的”优先级时,它使用uxBasePriority去记住原来的优先级。(优先级继承,请参见下面关于互斥的讨论。)

    每个任务有两个清单项目给FreeRTOS操作系统的各种调度列表使用。当一个任务被插入到FreeRTOS的一个列表中,不会直接向TCB插入一个指针。取而代之的是,它向TCB的xGenericListItemxEventListItem插入一个指针。这些xListItem变量,比起若是仅仅获得一个指向TCB的指针来说,让FreeRTOS的列表变得更加灵活。

    任务可以在以下四种状态之一:运行,准备运行,挂起或阻塞。你可能希望每个任务都有一个变量来告诉FreeRTOS它正处于什么状态,但事实上并非如此。相反,FreeRTOS通过把任务放入相应的列表:就绪列表,挂起列表等,隐式地跟踪任务状态。随着任务的变化,从一个状态到另一个,FreeRTOS的只是简单的将它从一个列表移动到另一个。

    任务设置

    我们已经触及如何利用pxReadyTasksLists数组来选择和调度一个任务的;现在让我们来看一看一个任务最初是如何被创建的。当xTaskCreate()函数被调用的时候,一个任务被创建。FreeRTOS为一个任务新分配一个TCB对象,来记录它的名称,优先级,和其他细节,接着分配用户请求的总的堆栈(假设有足够使用的内存)和在TCB的pxStack成员中记录堆内存的开始。

    堆栈被初始化看起来就像一个已经在运行的新任务被上下文切换所中断。这就是任务调度处理最新创建的任务的方法,同样也是处理运行了一段时间的任务的方法;任务调度在不需要任何特殊(case)代码的情况下去处理新的任务。

    任务的堆栈建立看起来像是它通过上下文切换来被中断,这个方法是取决于FreeRTOS正在运行的架构,但这个ARM Cortex-M3处理器的实现是一个很好的例子:

    unsigned int *pxPortInitialiseStack( unsigned int *pxTopOfStack, 
                                         pdTASK_CODE pxCode,
                                         void *pvParameters )
    {
      /* Simulate the stack frame as it would be created by a context switch interrupt. */
      pxTopOfStack--; /* Offset added to account for the way the MCU uses the stack on 
                         entry/exit of interrupts. */
      *pxTopOfStack = portINITIAL_XPSR;  /* xPSR */
      pxTopOfStack--;
      *pxTopOfStack = ( portSTACK_TYPE ) pxCode;  /* PC */
      pxTopOfStack--;
      *pxTopOfStack = 0;  /* LR */
      pxTopOfStack -= 5;  /* R12, R3, R2 and R1. */
      *pxTopOfStack = ( portSTACK_TYPE ) pvParameters;  /* R0 */
      pxTopOfStack -= 8;  /* R11, R10, R9, R8, R7, R6, R5 and R4. */
    
      return pxTopOfStack;
    }

    当一个任务被中断的时候,ARM Cortex-M3处理器就压寄存器入堆栈。pxPortInitialiseStack()修改堆栈使之看来像是即便任务实际上还未开始运行,寄存器就已经被压入了。已知的值被存储到堆栈,赋给ARM寄存器xPSRPCLR,和R0。剩余的寄存器R1-R12获得由栈顶指针递减分配给它们的寄存器空间,但没有具体的数据存储在这些寄存器堆栈内。ARM架构告诉我们那些寄存器在复位的时候未被定义,所以一个(非弱智的)程序将不依赖于已知的值。

    堆栈准备好后,任务几乎是同时准备运行。首先,FreeRTOS禁用中断:我们将开始使用就绪列表和其他任务调度的数据结构,同时我们不希望它们被其他人背着我们私底下修改。

    如果这是被创建的第一个任务,FreeRTOS将初始化调度的任务列表。FreeRTOS操作系统的调度有一个就绪列表的数组,pxReadyTasksLists [],为每一个可能的优先级提供一个就绪列表。FreeRTOS也有一些其他的列表用来跟踪任务的挂起,终止和延时。现在这些也都是初始化的。

    任何第一次初始化完成后,新的任务以它指定的优先级被加入就绪列表。中断被重新启用,同时新任务的创建完成。

    3.5. 列表

    任务之后,最常用的FreeRTOS数据结构是列表。FreeRTOS使用列表结构来跟踪调度任务,并执行队列。

    enter image description here

    图3.3:就绪列表全貌

    这个FreeRTOS的列表是一个有着几个有趣的补充的标准循环双链表。下面就是列表元素:

    struct xLIST_ITEM
    {
      portTickType xItemValue;                   /* The value being listed.  In most cases
                                                    this is used to sort the list in 
                                                    descending order. */
      volatile struct xLIST_ITEM * pxNext;       /* Pointer to the next xListItem in the 
                                                    list.  */
      volatile struct xLIST_ITEM * pxPrevious;   /* Pointer to the previous xListItem in 
                                                    the list. */
      void * pvOwner;                            /* Pointer to the object (normally a TCB)
                                                    that contains the list item.  There is
                                                    therefore a two-way link between the 
                                                    object containing the list item and 
                                                    the list item itself. */
      void * pvContainer;                        /* Pointer to the list in which this list
                                                    item is placed (if any). */
    };

    每个元素持有一个数字,xItemValue,这通常是一个被跟踪的任务优先级或者是一个调度事件的计时器值。列表保存从高到低的优先级指令,这意味着最高的优先级xItemValue(最大数)在列表的最前端,而最低的优先级xItemValue(最小数)在列表的末尾。

    pxNextpxPrevious指针是标准链表指针。pvOwner 列表元素所有者的指针。这通常是任务的TCB对象的指针。pvOwner被用来在vTaskSwitchContext()中加快任务切换:当最高优先级任务元素在pxReadyTasksLists[]中被发现,这个列表元素的pvOwner指针直接连接到需要任务调度的TCB。

    pvContainer指向自己所在的这个列表。若列表项处于一个特定列表它被用作快速终止。任意列表元素可以被置于一个列表,如下所定义:

    typedef struct xLIST
    {
      volatile unsigned portBASE_TYPE uxNumberOfItems;
      volatile xListItem * pxIndex;           /* Used to walk through the list.  Points to
                                                 the last item returned by a call to 
                                                 pvListGetOwnerOfNextEntry (). */
      volatile xMiniListItem xListEnd;        /* List item that contains the maximum 
                                                 possible item value, meaning it is always
                                                 at the end of the list and is therefore 
                                                 used as a marker. */
    } xList;

    列表的大小任何时候都是被存储在uxNumberOfItems中,用于快速列表大小操作。所有的列表都被初始化为容纳一个元素:xListEnd元素。xListEnd.xItemValue是一个定点值,当portTickType是16位数时,它等于xItemValue变量的最大值:0xffffportTickType是32位数时为0xffffffff。其他的列表元素也可以使用相同的值;插入算法保证了xListEnd总是列表项中最后一个值。

    自列表从高到低排序后,xListEnd被用作列表开始的记号。并且,自循环开始,xListEnd也被用作列表结束的记号。

    你也许可以用一个单独的for()循环或者是函数调用来访问大多数“传统的”列表,去做所有的工作,就像这样:

    for (listPtr = listStart; listPtr != NULL; listPtr = listPtr->next) {
      // Do something with listPtr here...
    }

    FreeRTOS经常需要通过多个for()和while()循环,也包括函数调用来访问列表,因此它使用操纵pxIndex指针的列表函数来遍历这个列表。这个列表函数listGET_OWNER_OF_NEXT_ENTRY()执行pxIndex = pxIndex->pxNext;并且返回pxIndex。(当然它也会正确检测列尾环绕。)这种,当执行遍历的时候使用pxIndex,由列表自己负责跟踪“在哪里”的方法,使FreeRTOS可以休息而不用关心这方面的事。

    enter image description here

    图3.4:系统节拍计时器下的FreeRTOS就绪列表全貌

    pxReadyTasksLists[]列出了在vTaskSwitchContext()中已经操纵完成的内容,是如何使用pxIndex的一个很好的例子。让我们假设我们仅有一个优先级,优先级0,并且有三个任务在此优先级上。这与我们之前看到的基本就绪列表图相似,但这一次我们将包括所有的数据结构和字段。

    就如你在图3.3中所见,pxCurrentTCB显示我们当前正在运行任务B。下一个时刻,vTaskSwitchContext()运行,它调用listGET_OWNER_OF_NEXT_ENTRY()载入下一个任务来运行。如图3.4所示,这个函数使用pxIndex->pxNext找出下一个任务是任务C,并且pxIndex指向任务C的列表元素,同时pxCurrentTCB指向任务C的TCB。

    请注意,每个struct xlistitem对象实际上都是来自相关TCB的xGenericListItem对象。

    3.6. 队列

    FreeRTOS允许任务使用队列来互相间通信和同步。中断服务程序(ISRs)同样使用队列来通信和同步。

    基本队列数据结构如下:

    typedef struct QueueDefinition
    {
      signed char *pcHead;                      /* Points to the beginning of the queue 
                                                   storage area. */
      signed char *pcTail;                      /* Points to the byte at the end of the 
                                                   queue storage area. One more byte is 
                                                   allocated than necessary to store the 
                                                 queue items; this is used as a marker. */
      signed char *pcWriteTo;                   /* Points to the free next place in the 
                                                   storage area. */
      signed char *pcReadFrom;                  /* Points to the last place that a queued 
                                                   item was read from. */
    
      xList xTasksWaitingToSend;                /* List of tasks that are blocked waiting 
                                                   to post onto this queue.  Stored in 
                                                   priority order. */
      xList xTasksWaitingToReceive;             /* List of tasks that are blocked waiting 
                                                   to read from this queue. Stored in 
                                                   priority order. */
    
      volatile unsigned portBASE_TYPE uxMessagesWaiting;  /* The number of items currently
                                                             in the queue. */
      unsigned portBASE_TYPE uxLength;                    /* The length of the queue 
                                                             defined as the number of 
                                                             items it will hold, not the 
                                                             number of bytes. */
      unsigned portBASE_TYPE uxItemSize;                  /* The size of each items that 
                                                             the queue will hold. */
    
    } xQUEUE;

    这是一个颇为标准的队列,不但包括了头部和尾部指针,而且指针指向我们刚刚读过或者写过的位置。

    当刚刚创建一个队列,用户指定了队列的长度和需要队列跟踪的项目大小。pcHeadpcTail被用来跟踪队列的内部存储器。加入一个项目到队列就对队列内部存储器进行一次深拷贝。

    FreeRTOS用深拷贝替代在项目中存放一个指针是因为有可能项目插入的生命周期要比队列的生命周期短。例如,试想一个简单的整数队列使用局部变量,跨几个函数调用的插入和删除。如果这个队列在局部变量里存储这些整数的指针,当整数的局部变量离开作用域时指针将会失效,同时局部变量的存储空间将被新的数值使用。

    什么需要用户选择使用队列。若内容很少,用户可以把复制的内容进行排列,就像上图中简单整数的例子,或者,若内容很多,用户可以排列内容的指针。请注意,在这两种情况下FreeRTOS都是在做深拷贝:如果用户选择排列复制的内容,那么这个队列存储了每项内容的一份深拷贝;如果用户选择了排列指针,队列存储了指针的一份深拷贝。当然,用户在队列里存储了指针,那么用户有责任管理与内存相关的指针。队列并不关心你存储了什么样的数据,它只需要知道数据的大小。

    FreeRTOS支持阻塞和非阻塞队列的插入和移除。非阻塞队列操作会立即返回"队列的插入是否完成?"或者 "队列的移除是否完成?"的状态。阻塞操作则根据特定的超时。一个任务可以无限期地阻塞或者在有限时间里阻塞。

    一个阻塞任务——叫它任务A——将保持阻塞只要它的插入/移除操作没有完成,并且它的超时(如果存在)没有过期。如果一个中断或者另一个任务编辑了这个队列以便任务A的操作能够完成,任务A将被解除阻塞。如果此时任务A的队列操作仍然是允许的,那么它实际上会执行操作,于是任务A会完成它的队列操作,并且返回“成功”的状态。不过,任务A正在执行的那个时间,有可能同时有一个高优先级任务或者中断也在同一个队列上执行另一个操作,这会阻止任务A正在执行的操作。在这种情况下任务A将检查它的超时,同时,如果它未超时就恢复阻塞,否则就返回队列操作“失败”的状态。

    特别需要注意的是,当任务被阻塞在一个队列时,系统保持运行所带来的风险;以及当任务被阻塞在一个队列时,有其他任务或中断在继续运行。这种阻塞任务的方法能不浪费CPU周期,使其他任务和中断可以有效地使用CPU周期。

    FreeRTOS使用xTasksWaitingToSend列表来保持对正阻塞在插入队列里的任务的跟踪。每当有一个元素被移出队列,xTasksWaitingToSend列表就会被检查。如果有个任务在那个列表中等待,那个是未阻塞任务。同样的,xTasksWaitingToReceive保持对那些正阻塞在移除队列里的任务的跟踪。每当有一个新元素被插入到队列,xTasksWaitingToReceive列表就会被检查。如果有个任务在那个列表中等待,那个是未阻塞任务。

    信号灯和互斥

    FreeRTOS使用它的队列与任务通信,也在任务间通信。FreeRTOS也使用它的队列来实现信号灯与互斥。

    有什么区别?

    信号灯与互斥听上去像一回事,但它们不是。FreeRTOS同样地实现了它们,但本来它们以不同的方式被使用。它们是如何不同地被使用?嵌入式系统宗师Michael Barr说这是在他文章中写得最好的,“信号灯与互斥揭秘”:

    The correct use of a semaphore is for signaling from one task to another. A mutex is meant to be taken and released, always in that order, by each task that uses the shared resource it protects. By contrast, tasks that use semaphores either signal ["send" in FreeRTOS terms] or wait ["receive" in FreeRTOS terms] - not both.

    正确使用的一个信号是从一个任务向另一个发信号。从每个使用被保护共享资源的任务来看,总是认为,一个互斥意味着获得和释放。相比之下,使用信号灯的任务不是发信号[在FreeRTOS里“发送”]就是在等信号[在FreeRTOS里“接收”]——不能同时。

    互斥被用来保护共享资源。一个使用共享资源的任务获得互斥,接着释放互斥。当有另一个任务占据互斥时,没有一个任务可以获得这个互斥。这就是保证,在同一时刻仅有一个任务可以使用共享资源。

    一个任务向另一个任务发信号时使用信号灯。以下引用Barr的文章:

    For example, Task 1 may contain code to post (i.e., signal or increment) a particular semaphore when the "power" button is pressed and Task 2, which wakes the display, pends on that same semaphore. In this scenario, one task is the producer of the event signal; the other the consumer.

    举例来说,任务一可能包含当“电源”按钮被按下时,发布(即,发信号或增加信号量)一个特定的信号灯的代码,并且唤醒显示屏的任务二,取决于同一个信号灯。在这种情况下,一个任务是发信号事件的制造者;另一个是消费者。

    如果你是在信号灯和互斥有任何疑问,请查阅Michael的文章。

    实现

    FreeRTOS像队列一样来实现一个N元素的信号灯,这样就可以控制N个项。它没有去存储队列每项的任何实际数据;信号灯只关心有多少在队列的uxMessagesWaiting字段中被跟踪的队列记录,目前正被占用。当FreeRTOS的头文件semphr.h调用它的时候,它正在做“纯同步”。因此这个队列有一个零字节的项 (uxItemSize == 0)。每个信号灯uxMessagesWaiting字段递增或递减;没有项或数据的复制是需要的。

    同信号灯一样,互斥也被实现为一个队列,不过有几个xQUEUE结构字段被用#defines重载:

    /* Effectively make a union out of the xQUEUE structure. */
    #define uxQueueType           pcHead
    #define pxMutexHolder         pcTail

    当互斥没有在队列中存储任何数据时,它不需要任何内部存储器,同样pcHeadpcTail字段也不需要。FreeRTOS设置uxQueueType字段(实际上的pcHead字段)为0来表明,这个队列正在被一个互斥使用。FreeRTOS使用重载的pcTail字段来实现互斥的优先级继承。

    万一你不熟悉优先级继承,我将再次引用Michael Barr的话来定义它,这次是来自他的文章,“优先级倒置”:

    [Priority inheritance] mandates that a lower-priority task inherit the priority of any higher-priority task pending on a resource they share. This priority change should take place as soon as the high-priority task begins to pend; it should end when the resource is released.

    [优先级继承]要求低优先级任务继承任何高优先级任务的优先级,取决于它们共享的资源。这个优先级的改变应当在高优先级任务一开始挂起时就发生;资源被释放时就结束。

    FreeRTOS使用pxMutexHolder字段(实际上是#define重载的pcTail字段)来实现优先级继承。FreeRTOS记录在pxMutexHolder字段里包含一个互斥的任务。当一个高优先级任务正在等待一个由低优先级任务取得的互斥,FreeRTOS“更新”低优先级任务到高优先级任务的优先级,直至这个互斥再次可用。

    3.7. 结论

    我们完成了对FreeRTOS架构的一览。希望你现在对于FreeRTOS的任务是如何执行以及通信有一个好的感觉。如果之前你从未了解过操作系统的内在,我希望现在你对于它们是如何工作的有一个基本的思路。

    显然,本章没有覆盖FreeRTOS架构的全部。值得注意的是,我没有提到的内存分配,中断服务,调试,或MPU支持。本章也没有讨论如何设置或使用FreeRTOS。Richard Barry已经写了一本极好的书,使用FreeRTOS实时内核:实用指南,这本书就是讲这些内容的;如果你要使用FreeRTOS的话,我强烈推荐它。

    3.8. 致谢

    我想感谢Richard Barry创造和维护了FreeRTOS,并选择将它开源。在写这一章的时候Richard给予了极大的帮助,提供了关于FreeRTOS的历史以及非常有价值的技术回顾。

    也感谢Amy Brown和Greg Wilson共同拉动这整个AOSA的事情。

    最后也是最(最多),感谢我的妻子Sarah共同承担了我对本章的研究和写作。幸运的是,她在嫁给我的时候就知道我是一名极客。

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

    万次阅读 多人点赞 2015-11-13 15:55:38
    1.为什么学习RTOS? 作为基于ARM7、Cortex-M3硬件开发的嵌入式工程师,我一直反对使用RTOS。不仅因为不恰当的使用RTOS会给项目带来额外的稳定性风险,更重要的是我认为绝大多数基于ARM7、Cortex-M3硬件的项目,还...

    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笔记(十五)FreeRTOS总结

    千次阅读 2019-02-09 17:37:00
    文章目录01 - 裸机和FreeRTOS区别1.1 - 裸机1.2 - FreeRTOS1.3 - 区别02 - 对FreeRTOS的感受03 - 推荐 上一文链接:FreeRTOS笔记(十四)[简] 软件定时器、事件组、任务通知 01 - 裸机和FreeRTOS区别   学完...

    上一文链接:FreeRTOS笔记(十四)[简] 软件定时器、事件组、任务通知


    01 - 裸机和FreeRTOS区别

      学完FreeRTOS,应该要自己总结一下FreeRTOS和裸机的区别,宏观上说,FreeRTOS是一个运行在裸机上的微内核,它和裸机的最终目标是一致的,都是需要运行用户程序,接受一些输入,然后输出
      而微观上,FreeRTOS和裸机是有很大区别的,怎样的区别,在乎站在哪个角度上考虑,如果站在用户角度上,那么FreeRTOS和裸机可能没有区别,所以在这一切站在开发者的角度上考虑
    Alt

    1.1 - 裸机

      前台和后台,前台是中断,用于处理异步事件,后台是大循环,循环里面调用API完成相关操作,任务顺序执行
      裸机要使得任务并发性是可以的,使用中断实现一些固定的跳转方式,比如使用软件中断呼叫某些固定号数的任务程序,;整个程序逻辑简单的时候是没有问题的,但是当整个程序逻辑复杂的时候,比如手机,你完全不知道用户的下一个步骤到底是什么,所以必须考虑全部的可执行性,整个程序就会非常复杂,如果继续用裸机,可能可以,但是绝对难以维护和阅读,所以此时裸机显得无能为力

    1.2 - FreeRTOS

      基于任务开发,核心是可剥夺的内核,实现多任务并发执行,任务是可以剥夺其他任务的CPU使用权,哪一个任务可以执行,哪一个任务需要等待,完全由内核决定和管理,开发者可以设计任务的优先级逻辑让任务之间按照开发者的意愿进行

    1.3 - 区别

      总的来说,裸机用于处理逻辑简单、功能简单的需求,例如平衡小车、蓝牙玩具、闹钟等等,而FreeRTOS则用于处理逻辑复杂,功能复杂的需求,例如实现蓝牙协议和串口传输、实现并发C/S模式、高速环境采集器等等,具体细节如下表

    …… 裸机 FreeRTOS
    逻辑复杂度
    开发方式 基于前后台 基于任务
    模块执行模式 顺序 并发
    堆栈操作 不需要操作 需要操作
    内存管理 没有
    模块通信 没有任何保护机制的全局变量 基于队列的各种含原子操作和保护的介质
    模块独立性
    应用例子 平衡小车、蓝牙玩具、闹钟…… 蓝牙协议和串口传输、实现并发C/S模式、高速环境采集器
    ------ ------ ------

    02 - 对FreeRTOS的感受

      对于裸机开发而言,FreeRTOS更像是提供了一个便捷的平台,不需要从轮子造起,任务之间的并发安全不需要考虑,这对于功能复杂、逻辑复杂的需求而言是个福音,但是任务的并发调度不一定要用FreeRTOS,自定义中断也能进行,只是FreeRTOS是经过千锤百炼得出的微内核,修改了各种BUG,对任务的并发调度有非常大的帮助,使用别人优秀的代码也是自己优秀的体现

    03 - 推荐

      最后,推荐一下大牛的FreeRTOS笔记/教程,个人觉得比较全面
      FreeRTOS基础篇
      FreeRTOS高级篇

    展开全文
  • FreeRTOS系统配置

    千次阅读 2017-08-23 01:43:04
    FreeRTOS

    本文是《ALIENTEK STM32F429 FreeRTOS 开发教程》第三章学习笔记
    第一章笔记–FreeRTOS简介与源码下载
    第二章笔记–FreeRTOS在STM32F4上移植

    FreeRTOSConfig.h

    FreeRTOS的配置基本是通过在FreeRTOSConfig.h中定义宏定义实现。

    INCLUDE_ 开头的宏

    这里写图片描述
    用来配置FreeRTOS中可选API函数,设置为1表示使能包含的API函数,设置为0表示不使用包含的API函数
    这里写图片描述
    从文件tasks.c中可以看到,当满足

    INCLUDE_vTaskPrioritySet == 1

    函数vTaskPrioritySet()才会被编译。使用条件编译的方法,根据实际需求来减少系统占用ROM和RAM的大小。

    从FreeRTOS.h中可以看到
    这里写图片描述
    如果未宏定义”INCLUDE_vTaskPrioritySet”则默认为0,即不使能

    INCLUDE_开头宏列表

    对应函数(宏定义为1时使能)
    INCLUDE_xSemaphoreGetMutexHolder xQueueGetMutexHolder()
    INCLUDE_xTaskAbortDelay xTaskAbortDelay()
    INCLUDE_vTaskDelay vTaskDelay()
    INCLUDE_vTaskDelayUntil vTaskDelayUntil()
    INCLUDE_vTaskDelete vTaskDelete()
    INCLUDE_xTaskGetCurrentTaskHandle xTaskGetCurrentTaskHandle()
    INCLUDE_xTaskGetHandle xTaskGetHandle()
    INCLUDE_xTaskGetIdleTaskHandle xTaskGetIdleTaskHandle()
    INCLUDE_xTaskGetSchedulerState xTaskGetSchedulerState()
    INCLUDE_uxTaskGetStackHighWaterMark uxTaskGetStackHighWaterMark()
    INCLUDE_uxTaskPriorityGet uxTaskPriorityGet()
    INCLUDE_vTaskPrioritySet vTaskPrioritySet()
    INCLUDE_xTaskResumeFromISR xTaskResumeFromISR()
    INCLUDE_eTaskGetState eTaskGetState()
    INCLUDE_vTaskSuspend vTaskSuspend()、vTaskResume()、prvTaskIsTaskSuspended()、xTaskResumeFromISR()(使用函数xTaskResumeFromISR()时宏INCLUDE_xTaskResumeFromISR和INCLUDE_vTaskSuspend都必须为i)
    INCLUDE_xTimerPendFunctionCall xTimerPendFunctionCall()、xTimerPendFunctionCallFromISR()(使用这两函数宏INCLUDE_xTimerPendFunctionCall和configUSE_TIMERS都必须为1)

    config 开头的宏

    config 开头的宏 用来完成 FreeRTOS的配置
    这里写图片描述

    1. configUSE_PREEMPTION

    1:使用抢占式内核;0:使用协程

    使用抢占式调度器内核会在每个时钟节拍中断中进行任务切换;

    使用协程会在以下地方进行任务切换

    一个任务调用了函数taskTIELD()
    一个任务调用了可以使任务进入阻塞态的API函数
    应用程序明确定义了在中断中执行上下文切换

    2. configUSE_IDLE_HOOK

    1:使能空闲任务钩子函数; 0: 禁用

    用户需要自行实现空闲任务钩子函数 函数原型:

    void vApplicationIdleHook(void)

    这里写图片描述

    3. configUSE_TICK_HOOK

    1:使能时间片钩子函数; 0: 禁用

    用户需要自行实现时间片钩子函数 函数原型:

    void vApplicationTickHook(void)

    4. configCPU_CLOCK_HZ

    设置CPU的频率 此时是16MHz

    5. configTICK_RATE_HZ

    FreeRTOS的系统时钟节拍频率(滴答定时器的中断频率),为了兼容HAL库,设置频率为1000HZ(滴答定时器的中断时间为1ms)

    6. configMAX_PRIORITIES

    设置任务优先级数量,任务可以使用从0到configMAX_PRIORITIES-1的优先级

    0是最低优先级,configMAX_PRIORITIES-1是最高优先级

    7. configMINIMAL_STACK_SIZE

    设置空闲任务的最小任务堆栈大小,单位是字(不是字节)

    stm32上设置为130,真正堆栈大小为 130*4=520字节

    8. configTOTAL_HEAP_SIZE

    设置堆大小,如果试用了动态内存管理,FreeRTOS在创建任务、信号量、队列等的时候使用heap_x.c(x为1-5)中内存申请函数申请内存。内存从堆ucHeap[configTOTAL_HEAP_SIZE]

    9. configMAX_TASK_NAME_LEN

    设置任务名最大长度

    10 . configUSE_TRACE_FACILITY

    1:启用可视化跟踪调试

    与宏configUSE_STATS_FORMATTING_FUNCTIONS同时为1时会编译下面3个函数

    prvWriteNameToBuffer()
    vTaskList()
    vTaskGetRunTimeStats()

    11. configUSE_16_BIT_TICKS

    设置系统节拍计数器变量数据类型

    1:为16位无符号整形;0:为32位无符号整形

    12. configIDLE_SHOULD_YIELD

    1:空闲任务会为处于同等优先级的用户任务让出CPU使用权;
    0:空闲任务不会为其他处于同优先级的任务让出CPU使用权

    建议关闭此功能,因为此功能的开启可能会导致空闲任务和用户任务使用同一个时间片,使得此用户任务比其他用户任务运行时间少

    13.configUSE_MUTEXES

    1:使用互斥信号量,相关API函数会被编译
    0:不使用互斥信号量

    14. configQUEUE_REGISTRY_SIZE

    设置可以注册的队列和信号量的最大数量

    15. configCHECK_FOR_STACK_OVERFLOW

    设置堆栈溢出检测

    若使用函数xTaskCreate()创建一个任务,任务的堆栈是自动从FreeRTOS的堆(ucHeap)中分配的,堆栈的大小是由函数xTaskCreate()的参数usStackDepth决定的; 若使用函数xTaskCreateStatic()创建任务任务堆栈由用户设置,参数pxStackBuffer为任务堆栈

    如果使能了堆栈检测功能,用户必须自行定义一个钩子函数,函数原型:

    void vApplicationStackOverflowHook( TaskHandle_t xTask, char *pcTaskName )

    参数xTask是任务句柄,pcTaskName是任务名字

    0: 不使用堆栈溢出检测

    1: 使用堆栈溢出检测方法1

    上下文切换的时候需要保存现场,现场保存在堆栈中,这个时候任务堆栈使用率可能达到最大值,此时不断检测任务堆栈指针是否指向有效空间,如果指向了无效空间,回掉使用钩子函数。 方法1优点快,缺点是不能检测所有的堆栈溢出

    2: 使用堆栈溢出检测方法2

    向任务堆栈填充一个已知的标记值,方法2会一直检测堆栈后面的几个bytes(标记值)是否被改写,如果改写调用堆栈溢出钩子函数。相对方法1要慢一点,几乎能检测到所有的堆栈溢出(溢出值和标记值相同时检测不到)

    16. configUSE_RECURSIVE_MUTEXES

    1: 使用递归护持信号量,相关API函数被编译

    17. configUSE_MALLOC_FAILED_HOOK

    1: 使能内存分配失败钩子函数, 用户需要自行实现内存分配失败钩子函数,函数原型:

    void vApplicationMallocFailedHook( void )

    18. configUSE_APPLICATION_TASK_TAG

    1: 设置为1时 以下函数会被编译

    void vTaskSetApplicationTaskTag( TaskHandle_t xTask, TaskHookFunction_t pxHookFunction );
    TaskHookFunction_t xTaskGetApplicationTaskTag( TaskHandle_t xTask );
    BaseType_t xTaskCallApplicationTaskHook( TaskHandle_t xTask, void *pvParameter )

    19. configUSE_COUNTING_SEMAPHORES

    1: 使能计数型信号量 相关API函数被编译

    20. configGENERATE_RUN_TIME_STATS

    1: 开启时间统计功能,响应API函数被编译
    还需定义表中的宏:

    描述
    portCONFIGURE_TIMER_FOR_RUN_TIME_STATS 此宏用来初始化一个外设来作为时间统计的基准时钟
    portGET_RUN_TIME_COUNTER_VALUE()或portALT_GET_RUN_TIME_COUNTER_VALUE 此宏用来返回当前基准时钟的时钟值

    0:关闭时间统计功能

    21. configUSE_CO_ROUTINES

    1:启用协程 启用协程以后必须添加文件croutine.c

    0:不启用协程

    22. configMAX_CO_ROUTINE_PRIORITIES

    设置协程的最大优先级,0是最低优先级,configMAX_CO_ROUTINE_PRIORITIES-1是最高优先级

    23. configUSE_TIMERS

    1:启用软件定时器

    宏configUSE_TIMERS和configUSE_DAEMON_TASK_STARTUP_HOOK都为1时需要定义函数vApplicationDaemonTaskStartupHook() 函数原型:

    void vApplicationDaemonTaskStartupHook( void );

    24. configTIMER_TASK_PRIORITY

    设置软件定时器任务的任务优先级

    25. configTIMER_QUEUE_LENGTH

    设置软件定时器命令队列的长度 FreeRTOS的软件定时器API函数会通过命令队列向软件定时器任务发送消息

    26. configTIMER_TASK_STACK_DEPTH

    设置定时器服务任务的任务堆栈大小 这里是两倍的空闲任务使用的堆栈大小

    展开全文
  • freeRTOS指南

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

    千次阅读 2019-10-09 12:26:51
    freertos入门介绍freertos是什么?freertos应用领域为什么使用freertos如何学习freertos freertos是什么? FreeRTOS(读作"free-arr-toss")是一个嵌入式系统使用的开源实时操作系统。FreeRTOS被设计为“小巧,简单,...
  • 开源FreeRTOS V10.1.0 版本 最新版本,修复之前很多BUG。 + FreeRTOS/source contains the FreeRTOS real time kernel source code. + FreeRTOS/demo contains a pre-configured demo project for every official ...
  • FreeRTOS STM32移植笔记

    万次阅读 多人点赞 2013-10-26 22:11:08
    【1】其实说不上移植笔记,FreeRTOS已经移植至众多平台(MCU),包括MSP430,STM32等,这份笔记完全建立在官方代码的基础之上,简单的说就是修改一些设置从而完成一个呼吸灯实验。 【2】虽然有官方移植代码,但是...
  • <div><p>PR for addition of +TCP CBMC proofs to this repo <h2>Description <ul><li> <p>This PR aims to bring all the +TCP CBMC proofs in this repository....FreeRTOS/FreeRTOS</p></div>
  • FreeRTOS系列第6篇---FreeRTOS内核配置说明

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

    万次阅读 多人点赞 2016-05-15 19:31:41
    FreeRTOS任务相关的代码大约占总代码的一半左右,这些代码都在为一件事情而努力,即找到优先级最高的就绪任务,并使之获得CPU运行权。任务切换是这一过程的直接实施者,为了更快的找到优先级最高的就绪任务,任务...
  • FreeRTOS系列第2篇---FreeRTOS入门指南

    万次阅读 多人点赞 2015-11-13 16:06:02
    FreeRTOS可以被移植到很多不同架构的处理器和编译器。每一个RTOS移植都附带一个已经配置好的演示例程,可以方便快速启动开发。更好的是,每个演示例程都附带一个说明网页,提供如何定位RTOS演示工程源代码、如何编译...
  • FreeRTOS 作为开源的轻量级实时性操作系统,不仅实现了基本的实时调度、信号量、队列和存储管理,而 且在商业应用上不需要授权费。 FreeRTOS 的实现主要由 list.c、queue.c、croutine.c 和 tasks.c 4 个文件组成...
  • 是否要在系统中使用FreeRTOS,虽然我想要的也仅仅是一个实时内核,当然更重要的 是免费。之所以翻译这篇文章倒不是因为FreeRTOS有多么优秀,完全是因为这篇文章 还不算太长。而且FreeRTOS.net仿佛致力于这个内核在...
  • FreeRTOS协程

    千次阅读 2019-03-12 17:18:59
    FreeRTOS的协程,实际上是线程并发出来的。从协程控制块中没有栈空间就能够知道,每个线程并发出来的协程共用一个栈空间。 /* 协程控制块 */ typedef struct corCoRoutineControlBlock { crCOROUTINE_CODE ...
  • 配置 FreeRTOS

    万次阅读 2012-08-27 14:55:17
    配置FreeRTOS FreeRTOS 是高度可配置的。所有的可配置项都在FreeRTOSConfig.h 文件中。每一个Demo 程序中都包含了一个配置好的FreeRTOSConfig.h 文件,可以以Demo程序中的FreeRTOSConfig.h 文件作为模板,在其基础...
  • trace FreeRTOS

    2018-06-22 18:51:46
    博客:https://blog.csdn.net/weixin_37058227/article/details/80776249 配置好的Trace+FreeRTOS+stm32 文件
  • FreeRTOS系列第20篇---FreeRTOS信号量API函数

    万次阅读 热门讨论 2016-03-18 10:07:40
    FreeRTOS的信号量包括二进制信号量、计数信号量、互斥信号量(以后简称互斥量)和递归互斥信号量(以后简称递归互斥量)。我们可以把互斥量和递归互斥量看成特殊的信号量。 信号量API函数实际上都是宏,它使用现有的...

空空如也

1 2 3 4 5 ... 20
收藏数 9,530
精华内容 3,812
关键字:

freertos