FreeRTOS笔记
任务的创建和删除(静态方法)
任务创建后要开启调度器。
FreeRTOSConfig.h
1. 改宏 使能静态创建函数。
会出现,有两个函数未定义。
Cortex-M中断管理(上)
NVIC:嵌套向量中断控制器。
与中断有关的寄存器都在NVIC和SCB中
Cortex-M中断管理(下)
中断优先级设置
IP[240U]
中断向量表中定义具体对应关系。
IP[0]
IP[1]
IP[2]
port.c 中设置PendSV和SysTick优先级
中断屏蔽寄存器有三个:
PRIMASK
FAULTMASK
BASEPRI
11.FreeRTOS中断检测试验
FreeRTOS中优先级低于configMAX_SYSCALL_INTERRUPT_PRIORITY的中断会被屏蔽掉,高于的就不会。
使用两个定时器,一个优先级为4,一个优先级为5,两个定时器每间隔1s通过串口输出一串字符串。然后在某个任务中关闭中断一段时间,查看两个定时器的输出情况。
设计两个任务start_task()和interrupt_task(),这两个任务的任务功能如下:
start_task():创建另一个任务。
interrupt_task():中断测试任务,任务中会调用FreeRTOS中的关中断函数portDISABLE_INTERRUPTS()来将中断关闭一段时间。
FreeRTOS开关中断函数
portENABLE_INTERRUPTS() 开中断函数
portDISABLE_INTERRUPTS() 关中断函数
1. 中断优先级分组,组4:全部是抢占优先级。
2. 中断驱动移植,使用定时器中断
12. FreeRTOS列表与列表项简介
列表和列表项是FreeRTOS的一个数据结构,FreeRTOS大量使用到了列表和列表项。
它是FreeRTOS的基石。
列表:是FreeRTOS中的一个数据结构,概念上和链表有点类似,列表被用来跟踪FreeRTOS中的任务。列表结构为List_t,在文件list.h中定义。
typedef struct xLIST
{
listFIRST_LIST_INTEGRITY_CHECK_VALUE /*< Set to a known value if configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES is set to 1. */
configLIST_VOLATILE UBaseType_t uxNumberOfItems;
ListItem_t * configLIST_VOLATILE pxIndex; /*< Used to walk through the list. Points to the last item returned by a call to listGET_OWNER_OF_NEXT_ENTRY (). */
MiniListItem_t 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. */
listSECOND_LIST_INTEGRITY_CHECK_VALUE /*< Set to a known value if configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES is set to 1. */
} List_t;
3行和7行,这两个都是用来检查列表完整性的。需要将宏configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES 设置为1,开启以后会想这两地方分别添加一个变量xListIntegrityValue1和xListIntegrityVlue2,在初始化列表的时候会把这两个变量中写入一个特殊的值,默认不开启这个功能。
uxNumerOfItems 用来记录列表中列表项的数量。
pxIndex 用来记录当前列表项索引号,用于遍历列表。
列表的最后一个列表项,用来表示列表结束,此变量类型为MiniListItem_t,这是一个mini列表项。
列表结构示意图:
上图中并未列出用于列表完整性检查的成员变量。
列表项,mini列表项。
列表项就是存放在列表中的项目,FreeRTOS提供了两种列表项:列表项和迷你列表项。这两个都在文件list.h中有定义,先来看一下列表项,定义如下:
struct xLIST_ITEM
{
listFIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE /*< Set to a known value if configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES is set to 1. */
configLIST_VOLATILE TickType_t xItemValue; /*< The value being listed. In most cases this is used to sort the list in descending order. */
struct xLIST_ITEM * configLIST_VOLATILE pxNext; /*< Pointer to the next ListItem_t in the list. */
struct xLIST_ITEM * configLIST_VOLATILE pxPrevious; /*< Pointer to the previous ListItem_t 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 * configLIST_VOLATILE pvContainer; /*< Pointer to the list in which this list item is placed (if any). */
listSECOND_LIST_ITEM_INTEGRITY_CHECK_VALUE /*< Set to a known value if configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES is set to 1. */
};
typedef struct xLIST_ITEM ListItem_t; /* For some reason lint wants this as two separate definitions. */
3行和9行,用法和列表一样,用来检查列表项完整性的。
xItemValue 为列表项值。
pxNext 指向下一个列表项。
pxPrevious 指向前一个列表项,和pxNext配合起来实现类似双向链表的功能。
pvOwner 记录此链表项归谁拥有通常是任务控制块。
pvContainer 用来记录此列表项归哪个列表。注意和pvOwner的区别,在前面讲解任务控制块TCB_t的时候说了在TCB_t中有两个变量xStateListItem和xEventListItem,这两个变量的类型就是ListItem_t,也就是说,这两个成员都是列表项。以xStateListItem为例,当创建一个任务以后xStateListItem的pvOwner变量指向这个任务的任务控制块,表示xStateListItem属于此任务。当任务就绪态以后,xStateListItem的pvContainer就执行就绪列表,表明此列表项在就绪列表中。
列表项结构示意图:
上图中并未列出用于列表项完整性检查的成员变量
迷你列表项
迷你列表项在文件list.h中有定义:
struct xMINI_LIST_ITEM
{
listFIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE /*< Set to a known value if configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES is set to 1. */
configLIST_VOLATILE TickType_t xItemValue;
struct xLIST_ITEM * configLIST_VOLATILE pxNext;
struct xLIST_ITEM * configLIST_VOLATILE pxPrevious;
};
typedef struct xMINI_LIST_ITEM MiniListItem_t;
3行用于检查迷你列表项的完整性。
xItemValue 记录列表列表项值。
pxNext 指向下一个列表项
pxPrevious 指向上一个列表项
可以看出迷你列表项只是比列表项少了几个成员变量,迷你列表项有的成员变量列表项都有,没有感觉有什么本质区别。那为什么弄个迷你列表项出来呢?那是因为有些情况下我们不需要列表项这么全的功能,可能之炫耀其中的某几个成员变量,如果此时用列表项的话会造成内存浪费!比如上上列表结构体List_t中表示最后一个列表项的成员变量xListEnd就是MiniListIten_t类型的。
迷你列表项结构示意图:
上图中并未列出用于迷你列表项完整性检查的成员变量!
列表和列表项初始化
列表初始化
新创建或者定义的列表需要对其进行初始化处理,列表的初始化其实就是初始化列表结构体List_t中各个成员变量,列表的初始化通过使用函数vListInitialise()来完成,此函数在list.c中有定义:
void vListInitialise( List_t * const pxList )
{
/* The list structure contains a list item which is used to mark the
end of the list. To initialise the list the list end is inserted
as the only list entry. */
pxList->pxIndex = ( ListItem_t * ) &( pxList->xListEnd ); /*lint !e826 !e740 The mini list structure is used as the list end to save RAM. This is checked and valid. */ /* The list end value is the highest possible value in the list to
ensure it remains at the end of the list. */
pxList->xListEnd.xItemValue = portMAX_DELAY; /* The list end next and previous pointers point to itself so we know
when the list is empty. */
pxList->xListEnd.pxNext = ( ListItem_t * ) &( pxList->xListEnd ); /*lint !e826 !e740 The mini list structure is used as the list end to save RAM. This is checked and valid. */
pxList->xListEnd.pxPrevious = ( ListItem_t * ) &( pxList->xListEnd );/*lint !e826 !e740 The mini list structure is used as the list end to save RAM. This is checked and valid. */ pxList->uxNumberOfItems = ( UBaseType_t ) 0U; /* Write known values into the list if
configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES is set to 1. */
listSET_LIST_INTEGRITY_CHECK_1_VALUE( pxList );
listSET_LIST_INTEGRITY_CHECK_2_VALUE( pxList );
}
xListEnd用来表示列表的末尾,而pxIndex表示列表项的索引号,此时列表只有一个列表项,那就是xListEnd,所以pxIndex指向xListEnd。
xListEnd的列表项值初始化为portMAX_DELAY,portMAX_DELAY是个宏,在文件portmacro.h中有定义。根据所使用的MCU的不同,portMAX_DELAY值也不相同,可以为0xffff或者oxffffffffUL,这里使用oxffffffffUL。
初始化列表项xLIstEnd的pxNext变量,因为此时列表只有一个列表项xListEnd,因此pcNext只能指向自身。
初始化xListEnd的pxPrevious变量,指向xListEnd自身。
由于此时没有其他列表项,一次uxNumberOfItems为0,注意,这里没有算xListEnd。
21、22 初始化列表项中用于完整性检查字段,只有宏
configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES 为1的时候才有效。
同样的,根据所选的MCU不同,其写入的值也不同,可以为ox5a5a或者0x5a5a5a5aUL。STM32是32位系统,写入0x5a5a5a5aUL,
列表初始化完成后如图:
列表项初始化
同列表一样,列表项在使用的时候也需要初始化,列表项初始化由函数vListInitialiseItem()来完成:
void vListInitialiseItem( ListItem_t * const pxItem )
{
/* Make sure the list item is not recorded as being on a list. */
pxItem->pvContainer = NULL; /* Write known values into the list item if
configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES is set to 1. */
listSET_FIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE( pxItem );
listSET_SECOND_LIST_ITEM_INTEGRITY_CHECK_VALUE( pxItem );
}
列表项的初始化很简单,只是将列表项成员变量pvContainer初始化为NULL,并且给用于完整性检查的变量赋值。列表项的成员变量比列表要要多,怎么初始化函数就这么短?其他的成员变量什么时候初始化?这是因为列表项要根据实际使用情况来初始化,比如任务创建函数xTaskCreate()就会对任务堆栈中的xStateListItem和xEventListItem这两个列表项中的其他成员变量在做初始化。
列表项插入
列表项插入函数分析
列表项的插入操作通过函数vListInsert()来完成:
void vListInsert( List_t * const pxList, ListItem_t * const pxNewListItem )
{
ListItem_t *pxIterator;
const TickType_t xValueOfInsertion = pxNewListItem->xItemValue; /* Only effective when configASSERT() is also defined, these tests may catch
the list data structures being overwritten in memory. They will not catch
data errors caused by incorrect configuration or use of FreeRTOS. */
listTEST_LIST_INTEGRITY( pxList );
listTEST_LIST_ITEM_INTEGRITY( pxNewListItem ); /* Insert the new list item into the list, sorted in xItemValue order. If the list already contains a list item with the same item value then the
new list item should be placed after it. This ensures that TCB's which are
stored in ready lists (all of which have the same xItemValue value) get a
share of the CPU. However, if the xItemValue is the same as the back marker
the iteration loop below will not end. Therefore the value is checked
first, and the algorithm slightly modified if necessary. */
if( xValueOfInsertion == portMAX_DELAY )
{
pxIterator = pxList->xListEnd.pxPrevious;
}
else
{
/* *** NOTE ***********************************************************
If you find your application is crashing here then likely causes are
listed below. In addition see http://www.freertos.org/FAQHelp.html for
more tips, and ensure configASSERT() is defined!
http://www.freertos.org/a00110.html#configASSERT 1) Stack overflow -
see http://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
http://www.freertos.org/RTOS-Cortex-M3-M4.html and the definition
of configMAX_SYSCALL_INTERRUPT_PRIORITY on
http://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?).
**********************************************************************/ for( pxIterator = ( ListItem_t * ) &( pxList->xListEnd ); pxIterator->pxNext->xItemValue <= xValueOfInsertion; pxIterator = pxIterator->pxNext ) /*lint !e826 !e740 The mini list structure is used as the list end to save RAM. This is checked and valid. */
{
/* There is nothing to do here, just iterating to the wanted
insertion position. */
}
} pxNewListItem->pxNext = pxIterator->pxNext;
pxNewListItem->pxNext->pxPrevious = pxNewListItem;
pxNewListItem->pxPrevious = pxIterator;
pxIterator->pxNext = pxNewListItem; /* Remember which list the item is in. This allows fast removal of the
item later. */
pxNewListItem->pvContainer = ( void * ) pxList; ( pxList->uxNumberOfItems )++;
}
参数:
pxList:列表项要插入的列表
pxNewListItem:要插入的列表项。
函数vListInsert()的参数pxList决定了列表项要插入到哪个列表中,pxNewListItem决定了要插入的列表项,但是这个列表项具体插入到什么地方呢?要插入的位置由列表项中成员变量xItemValue来决定。列表项的插入根据xItemValue的值按照升序的方式排列!
4行:获取要插入的列表项值,即列表项成员变量xItemValue的值,因为要根据整个值来确定列表项要插入的位置。
9行、10行:用来检查列表和列表项的完整性。其实就是检查列表和列表项中用于完成性检查的变量值是否被改变。这些变量的值在列表和列表项初始化的时候就被写入了,这两行代码需要实现函数configASSERT()!
20行:要掺入列表项,第一步就是要获取该列表项要插入到什么位置!如果要插入的列表项的值等于portMAX_DELAY,也就是说列表项值为最大值,这种情况最好办了,要插入的位置就是
列表项相关API:
vListInitialise() 列表初始化
vListInitialiseItem() 列表初始化
vListInsert() 列表项插入
vListInsertEnd() 列表项末尾插入
uxListRemove() 列表项删除
listGET_OWNER_OF_NEXT_ENTRY() 列表的遍历
列表项的插入和删除实验
本实验设计3个任务,start_task、task1_task和list_task
start_task:用来创建其他2个任务。
task1_task:应用任务1,控制LED0闪烁,用来提示系统正在运行。
list_task: 列表和列表项操作任务,调用列表和列表项相关API函数,并且通过串口输出相应的信息来观察这些API函数的运行过程。
任务的特性
在使用RTOS的时候,一个实时应用可以作为一个独立的任务。每个任务都有自己的运行环境,不依赖于系统中其他任务或者RTOS调度器。任何一个时间点只能有一个任务运行,具体运行哪个任务是由RTOS调度器来决定,RTOS调度器因此就会重复地开启、关闭每个任务。任务不需要了解RTOS调度器的具体行为,RTOS调度器的职责是确保当一个任务开始执行的时候其上下文环境(寄存器值,堆栈内容)和任务上一次退出的时候相同。为了做到这一点,每个任务都必须有个堆栈,当任务切换的时候将上下文环境保存在堆栈中,这样当任务再次执行的时候就可以从堆栈中取出上下文环境,任务恢复运行。
任务状态:
FreeRTOS中的任务永远处于下面几个状态中的某一个:
运行态:当一个任务正在运行时,那么就说这个任务处于运行态,处于运行态的任务就是当前正在使用处理器的任务。如果使用的是单核处理器的话,那么不管在任何时刻永远都只有一个任务处于运行态。
就绪态:处于就绪态的任务就是那些准备就绪(这些任务没有被阻塞或者挂起),可以运行的任务,但是处于就绪态的任务还没有运行,因为有一个同优先级或者更高优先级的任务正在运行!
阻塞态:如果一个任务当前正在等待某个外部事件的话就说它处于阻塞态,比如说如果某个任务调度使用了函数vTaskDelay()的话就会进入阻塞态,直到延时周期完成。任务在等待队列、信号量。事件组。通知或互斥信号量的时候也会进入阻塞态。任务进入阻塞态会有一个超时时间,当超过这个超市时间,任务就会推出阻塞状态,即时所有等待的事件还没有来临。
挂起态:像阻塞态一样,任务进入挂起态以后,也不能被调度器调用进入运行态,但是进入挂起态的任务没有超时时间。任务进入和退出挂起态通过调用vTaskSuspend()和xTaskResume()。
任务状态之间的
FreeRTOS队列
队列简介
队列是为了任务与任务、任务与中断之间的通信而准备的,可以在任务与任务、任务与中断之间传递消息,队列中可以存储有限的、大小固定的数据项目。任务与任务、任务与中断之间要交流的数据保存在对了中,叫做队列项目。队列所能保存的最大数据项目的数量叫做队列的长度,创建队列的时候会指定数据项目的大小和队列的长度。由于队列是用来传递消息的,所以也成为消息队列。FreeRTOS中的信号量也是根据队列实现的!所有有必要深入地了解FreeRTOS的队列。
1. 数据存储
通常队列采用先进先出(FIFO)的存储缓冲机制,也就是往队列发送数据的时候永远都是发送到队列的尾部,而从队列提取数据的时候是同队列的头部提取。但是也可以使用LIFO的存储缓冲,也就是后进先出,FreeRTOS中的队列也提供了LIFO的缓存缓冲机制。
数据发送到队列中会导致数据拷贝,也就是将要发送的数据拷贝到队列中,这就意味着在队列中存储的是数据的原始值,而不是原数据的引用(即只传递数据的指针),这个也叫做值传递。UCOS的消息队列采用的是引用传递,传递的是消息指针。采用引用传递的话,消息内容必须一直保持可见性,也就是消息内容必须有效,那么局部变量这种可能会随时被删掉的东西就不能用来传递消息,但是采用引用传递会节省时间,因为不用进行数据拷贝。
采用值传递的话虽然会导致数据拷贝,会浪费一点时间,但是一旦将消息发送到队列中,原始的数据缓冲区就可以删除或者覆写,这样的话这些缓冲区就可以被重复的使用。FreeRTOS中使用队列传递消息的虽然使用的是数据拷贝,但是也可以使用引用来传递消息,直接往队列里发送指向这个消息的地址指针就可以了。这样当我要发送的消息数据太大的时候就可以直接发送消息缓冲区的地址指针,比如在网络应用环境中,网络的数据量往往都很大,才用数据拷贝的话就不现实。
1. 多任务访问
队列不是属于某个特别指定的任务的,任何任务都可以向队列中发送消息,或者从队列中提取消息。
FreeRTOS笔记的更多相关文章
- STM32F103移值FreeRtos笔记
RTOS版本:FreeRTOS_V8.2.2 一.下载FreeRTOS源文件 这个可以在百度上下载,或者在官网上面下载http://www.freertos.org/a00104.html ...
- FREERTOS 手册阅读笔记
郑重声明,版权所有! 转载需说明. FREERTOS堆栈大小的单位是word,不是byte. 根据处理器架构优化系统的任务优先级不能超过32,If the architecture optimized ...
- FreeRTOS学习及移植笔记之二:在IAR和STM32F103VET上移植FreeRTOS
上一次,我们简单的测试了FreeRTOS的基于IAR EWARM v6.4和STM32F103VET6平台的Demo,对其有了一个基本认识.接下来我们开始自己移植FreeRTOS的过程. 1.创建一个 ...
- FreeRTOS学习及移植笔记之一:开始FreeRTOS之旅
1.必要的准备工作 工欲善其事,必先利其器,在开始学习和移植之前,相应的准备工作必不可少.所以在开始我们写要准备如下: 测试环境:我准备在STM32F103平台上移植和测试FreeRTOS系统 准备F ...
- FreeRTOS学习笔记——任务间使用队列同步数据
1.前言 在嵌入式操作系统中队列是任务间数据交换的常用手段,队列是生产者消费者模型的重要组成部分.FreeRTOS的队列简单易用,下面结合一个具体例子说明FreeRTOS中的队列如何使用. 2.参考代 ...
- FREERTOS学习笔记
2012-02-25 21:43:40 为提升自己对实时操作系统(RTOS)的认识,我学习了freeRTOS. 理解了OS任务的状态.优先级的概念.信号量的概念.互斥的概念.队列.内存管理.这都是和R ...
- FreeRTOS学习笔记--任务优先级
FreeRTOSConfig.h 中的常量configMAX_PRIORITIES的值就是任务优先级的最大数值,这个数值可以按照自己的需要改动,当然值越大,内核对内存的开销就越大,一般设置一个满足自己 ...
- STM32F412应用开发笔记之九:移植FreeRTOS到F412ZG平台
在开发实际应用系统时,我们经常需要考虑数据的实时性和多任务,嵌入式实时操作系统的出现为实现这一目的提供了很好的助力.FreeRTOS是近年来比较流行的嵌入式实时操作系统,而且是开源免费的,STM32C ...
- 嵌入式学习笔记(综合提高篇 第二章) -- FreeRTOS的移植和应用
1.1 资料准备和分析 上章节通过实现双机通讯,了解如何设计和实现自定义协议,不过对于嵌入式系统来说,当然不仅仅包含协议,还有其它很多需要深入学习了解的知识,下面将列出我在工作和学习上遇到的嵌入 ...
随机推荐
- UVa 10213 How Many Pieces of Land ? (计算几何+大数)欧拉定理
题意:一块圆形土地,在圆周上选n个点,然后两两连线,问把这块土地分成多少块? 析:这个题用的是欧拉公式,在平面图中,V-E+F=2,其中V是顶点数,E是边数,F是面数.对于这个题只要计算V和E就好. ...
- 记一次前端面试~终于拿到理想中的offer!
2019年已经过去一半,终于拿到一直想去的公司offer,也算是实现了今年的一个小目标. 由于这家公司是我从去年到现在最想去的公司,本次换工作一直没有投,希望先积累下面试经验再投. 没有想到居然先在b ...
- [原创]内网SSH密码爆破工具sshcrack(配合Cscan批量弱口令检测)
0x000 前言 sshcrack是一个命令行下的SSH密码爆破工具,适用于内渗中SSH密码检测 当然也可用于外网SSH密码爆破,支持Windows/Linux,其它系统未测.Tip1 0x001 目 ...
- EXP-00000: Message 0 not found; No message file for product=RDBMS, facility=EXP问题的解决方案
EXP-00000: Message 0 not found; No message file for product=RDBMS, facility=EXP 最近在服务器上准备做一个批处理,定时备份 ...
- ERROR 1366 (HY000): Incorrect string value: '\xB3\xA4\xC9\xB3' for column
在用以下方法之前,请先执行下面命令查看. show variables like 'character%'; ——查看所有编码方式 show create table table_name; — ...
- [Andoird]Andoird之Log
一.Log Android中的日志工具类是 Log(android.util.Log),这个类中提供了如下几个方法来供我们打印日志. Log.v() 这个方法用于打印那些最为琐碎的,意义最小的日志信息 ...
- [LOJ 2039] 「SHOI2015」激光发生器
[LOJ 2039] 「SHOI2015」激光发生器 链接 链接 题解 分为两个部分 第一个是求直线之间的交点找到第一个触碰到的镜面 第二个是求直线经过镜面反射之后的出射光线 第一个很好做,第二个就是 ...
- M-HJ浇花
题目描述: 链接:https://ac.nowcoder.com/acm/contest/322/M来源:牛客网 HJ养了很多花(99999999999999999999999999999999999 ...
- python 8 函数
调用函数 Python内置了很多有用的函数,我们可以直接调用. 要调用一个函数,需要知道函数的名称和参数,比如求绝对值的函数abs,只有一个参数.可以直接从Python的官方网站查看文档: 也可以在交 ...
- TDH-search汇报理解
题目:海量数据查询开头:1.自我介绍:2.题目切入: 什么是海量数据查询?(海量数据,快速,符合要求) 几个常用场景(搜索引擎,百度:话单查询:影像平台,高铁)3.展示目录:架构,案例,平台规划 4. ...