FreeRTOS问答
怎么看FreeRTOS代码?
源码结构
数据类型
FreeRTOS的数据类型基本上都定义在
portmacro.h文件中,比如在FreeRTOS\Source\portable\RVDS\ARM_CM3下就可以找到这个文件;除此之外,FreeRTOS中还有两个特定的数据类型;
BaseType_t:这个类型被定义为架构中最有效的数据类型;比如32位体系结构使用32 bit数据类型/int32_t,16位架构使用16 bit数据类型/int16_t,8位架构上使用8 bit数据类型/int8_t。BaseType_t适用于数据范围比它小的类型的值,所以也适用于pdTRUE/pdFALSE类型的布尔值;
TickType_t:FreeRTOS配置一个称为tick interrupt的定时中断;两次滴答中断之间的时间称为滴答中断周期;所以tick number是指定滴答中断周期的倍数,TickType_t是用来保存滴答计数值和to的数据类型指定时间。命名规则
变量名
前缀 类型 前缀 cchar前缀 sint16_t前缀 p指针变量大写 lint32_t小写 x表示类型为 BaseType_t:其他非标准类型(结构、任务句柄、队列句柄等等)前缀 u变量是 无符号的如果一个变量是一个 指针它也是带前缀的,例如,类型为 uint8_t的变量将前缀为uc函数名
前缀返回的类型/其中定义的文件vTaskPrioritySet()前缀 v表示返回类型为viod,Task表示在tasks.c中定义xQueueReceive()前缀 x表示返回BaseType_t类型数据,Queue表示该函数在queue.c中定义;pvTimerGetTimerID()前缀 pv表示返回void类型指针,Timer表示该函数在timer.c.中定义;prv前缀 prv表示作用范围为当前的文件;宏定义
FreeRTOS的大多数宏都是用
大写字母写的,并以小写字母作为前缀来表示前缀 定义 所属文件 tasktaskENTER_CRITICAL()task.hpdpdTRUEprojdefs.hconfigconfigUSE_PREEMPTIONFreeRTOSConfig.herrerrQUEUE_FULLprojdefs.hportportMAX_DELAYportable.h or portmacro.hFreeRTOS核心内容有哪些?
Microcontrollers are used in deeply embedded applications (those applications where you never actually see the processors themselves, or the software they are running) that normally have a very specific and dedicated job to do. The size constraints, and dedicated end application nature, rarely warrant the use of a full RTOS implementation - or indeed make the use of a full RTOS implementation possible. FreeRTOS therefore provides
the core real time scheduling functionality(实时调度功能),inter-task communication(任务间通信),timing(定时) andsynchronisation primitives(同步原语、原子操作) only. This means it is more accurately described as a real time kernel, or real time executive. Additional functionality, such as a command console interface, or networking stacks, can then be included withadd-on components. from
在
并发编程(Concurrency)时,如果多个线程访问同一资源,我们需要保证访问的时候不会产生冲突,数据修改不会发生错误,这就是我们常说的线程安全。
原子操作(atomic operation),指不会被
线程调度机制打断的操作,这种操作一旦开始,就一直运行到结束,中间不会切换到其他线程。
在
多线程下,我们并不能保证我们的代码都具有原子性,因此如何让我们的代码变得具有原子性,就是一件很重要的事。
方法也很简单,就是当你在访问一个多线程间共享的资源时,加锁可以实现类似原子操作的效果,一个代码要嘛不执行,执行了的话就要执行完毕,才能接受线程的调度。
因此,我们使用加锁的方法,使其具备原子性。
Context Switching:上下文切换
Cortex-M:一种ARM处理器架构(Processor Architecture),处理器架构还有Cortex-A , MSP430 , RISC-V,Xtensa …

上图显示了
SP指针和PC指针、寄存器R1、R2、R3、代码段.code(Program Memory)、数据段.data(Data Memory).的情况。这些资源被称为上下文
As a task executes it utilizes the processor / microcontroller registers and accesses RAM and ROM just as any other program. These
resourcestogether (the processor registers, stack, etc.) comprise the task execution context (上下文)
A task is asequential piece of code- it does not know when it is going to getsuspended(swapped out or switched out) orresumed(swapped in or switched in) by the kernel and does not even knowwhen this has happened. Consider the example of a task being suspended immediately before executing an instruction that sums the values contained within two processor registers. While the task is suspendedother taskswillexecute and may modifythe processor register values. Upon resumption the task will not know that the processor registers have been altered - if it used the modified values the summation would result in an incorrect value.
To prevent this type of error it is essential that upon resumption a task has a context identical to that immediately prior to its suspension. The operating system kernel is responsible forensuring this is the case- and does so bysaving the context of a task as it is suspended. When the task is resumed its saved context is restored by the operating system kernel prior to its execution. The process ofsavingthe context of a task being suspended andrestoringthe context of a task being resumed is called context switching(上下文切换).
from
- 无论是消息队列还是邮箱队列,都是利用了
全局变量可以被随意访问的特性,所以使用时都会被定义为全局变量。- 普通全局变量可用于一些简单的任务间通信场合。ps:
volatile关键字比较重要。- 相较于普通全局变量,加入
队列机制可以存储多个消息,加入pend-post机制可以拥有任务等待和唤醒的机制,用于解决队列已满或队列为空的问题。
多任务访问全局变量会带来
共享资源管理问题。
消息队列最终是用的全局变量!但是消息队列对这个全局变量做了保护,重点就是资源管理的保护!
假如你直接使用全局变量,那么在代码中任何任务都可以随时随地的访问、修改这个全局变量!
如果在mov指令之后发生一次任务切换,在其它任务中global的值被修改,则这段代码中使用的仍然是global的旧值,执行结果将不符合预期。其他arch也有类似的问题。
如果使用消息队列的话,A任务要使用队列S,先申请,申请成功以后才可以使用。B任务也要使用S的时候也要先申请,当时发现S已经被A任务使用了,所以B任务就没法使用(假设当前的队列长度为1),直到A任务使用完S并且释放掉B任务才申请使用!
(from:Mculover666)