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表示返回类型为viodTask表示在tasks.c中定义
    xQueueReceive()前缀x表示返回BaseType_t类型数据,Queue表示该函数在queue.c中定义;
    pvTimerGetTimerID()前缀pv表示返回void类型指针Timer表示该函数在timer.c.中定义;
    prv前缀prv表示作用范围当前的文件
  • 宏定义

    FreeRTOS的大多数宏都是用大写字母写的,并以小写字母作为前缀来表示

    前缀定义所属文件
    tasktaskENTER_CRITICAL()task.h
    pdpdTRUEprojdefs.h
    configconfigUSE_PREEMPTIONFreeRTOSConfig.h
    errerrQUEUE_FULLprojdefs.h
    portportMAX_DELAYportable.h or portmacro.h
  • FreeRTOS核心内容有哪些?

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(定时) and synchronisation 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 with add-on components. from

  • 什么是线程安全?

并发编程(Concurrency)时,如果多个线程访问同一资源,我们需要保证访问的时候不会产生冲突,数据修改不会发生错误,这就是我们常说的 线程安全

  • 什么是原子操作?

原子操作(atomic operation),指不会被线程调度机制打断的操作,这种操作一旦开始,就一直运行到结束,中间不会切换到其他线程。

  • 如何实现人工原子操作?

多线程下,我们并不能保证我们的代码都具有原子性,因此如何让我们的代码变得具有原子性,就是一件很重要的事。
方法也很简单,就是当你在访问一个多线程间共享的资源时,加锁可以实现类似原子操作的效果,一个代码要嘛不执行,执行了的话就要执行完毕,才能接受线程的调度。
因此,我们使用加锁的方法,使其具备原子性

  • Context SwitchingCortex-M3

Context Switching:上下文切换
Cortex-M:一种ARM处理器架构(Processor Architecture),处理器架构还有Cortex-A , MSP430 , RISC-VXtensa

  • 什么是上下文切换

在这里插入图片描述

上图显示了SP指针和PC指针、寄存器R1R2R3、代码段.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 resources together (the processor registers, stack, etc.) comprise the task execution context (上下文)
A task is a sequential piece of code- it does not know when it is going to get suspended (swapped out or switched out) or resumed (swapped in or switched in) by the kernel and does not even know when 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 suspended other tasks will execute and may modify the 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 for ensuring this is the case- and does so by saving 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 of saving the context of a task being suspended and restoring the context of a task being resumed is called context switching上下文切换).
from

  • GCC 的Signal 和Naked __attribute__

  • __attribute__的记录

attribute 机制使用
attribute 机制使用

  • Signal __attribute__

  • Naked __attribute__

  • 任务间通信为什么不使用全局变量?

  1. 无论是消息队列还是邮箱队列,都是利用了全局变量可以被随意访问的特性,所以使用时都会被定义为全局变量。
  2. 普通全局变量可用于一些简单的任务间通信场合。ps:volatile关键字比较重要。
  3. 相较于普通全局变量,加入队列机制可以存储多个消息,加入pend-post机制可以拥有任务等待和唤醒的机制,用于解决队列已满或队列为空的问题。

多任务访问全局变量会带来共享资源管理问题。
消息队列最终是用的全局变量!但是消息队列对这个全局变量做了保护,重点就是资源管理的保护!
假如你直接使用全局变量,那么在代码中任何任务都可以随时随地的访问、修改这个全局变量!
如果在mov指令之后发生一次任务切换,在其它任务中global的值被修改,则这段代码中使用的仍然是global的旧值,执行结果将不符合预期。其他arch也有类似的问题。
如果使用消息队列的话,A任务要使用队列S,先申请,申请成功以后才可以使用。B任务也要使用S的时候也要先申请,当时发现S已经被A任务使用了,所以B任务就没法使用(假设当前的队列长度为1),直到A任务使用完S并且释放掉B任务才申请使用!
(from:Mculover666)


版权声明:本文为sinat_36912383原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。