uCOS-II
/****************************************************/
**关于移植,ucos官网上给的有template,主要思想是实现任务切换的两个函数(任务级别切换函数和中断级别切换函数)、禁止中断、使能中断、创建任务时的堆栈初始化函数。
**在stm32上,systick用来作为系统时钟,所以systick的中断需要配置到timetick上,这步和上面的pendsv中断都可以放到stm32的启动文件的中断向量表中。
##关于操作系统的理解,操作系统就是一个裸机程序,掌控所有被赋予的硬件的控制权,利用硬件资源为软件提供运行效率、编程底层建筑(中断、DMA、任务锁、临界段)和使用方法(APIs)的优化。
/************************************************/
2018年7月24日 19:44
OS_EventTaskRdy这个函数位于 os_core.c 文件中,很重要,是连接任务控制块和事件控制块的重要函数,当任务从阻塞态到就绪态时,需要调用它,他将任务在任务就绪表中就绪,设置任务控制块的状态信息,最后从事件控制块中删除掉该任务。
所有基于事件控制块的通信机制都是基于此,比如 MBox、Mqueue、semaphore,他们最终都要调用到 Event Control (事件管理)模块。应该可以这样理解,时间管控模块被嵌入到了基于事件驱动的通信中,也有点类似基类(父类)和扩展类(子类)的关系。
对了 这里涉及到两个链表,任务控制块链表和事件控制块链表,类似Linux,都是这样组织系统的,这些东西都放在内存中。
好了,吃饭,已经做好了。miantiao,tomato,
-----------------------------------
2018年07月30日 13:15
拿semaphore举例,看看优先级、任务控制表、事件控制表之间的关系,
1. pevent->OSEventTbl[] 的初始化。每创建一个资源(semaphore、mbox、mutex、queue etc)就需要从链表上申请一个事件控制块。
注意,这里的 pevent->OSEventTbl[] 是个事件控制块结构体里的一个成员,也就是说,不同的semaphore、Mbox、queue、里的pevent->OSEventTbl[]都是相互独立的,没有任何关系。虽然这个表也是用来表示该资源的调度位图用的,但是它有很多个,不像任务就绪表只有一个,因为不同的资源的pevent->OSEventTbl[]肯定是相互独立的。
事件控制块结构体
2. 对于每个等待某个资源的任务,都在该资源的 pevent->OSEventTbl[] 里排队,调度算法完全和任务调度算法一样,数据结构也是一样的,都有就绪表和就绪组。
/***********************************************************************************************************************/
2018年07月24日 00:08 by Mapleay
uCOS-II是一个多任务、实时性、可抢占内核,它由唯一的任务优先级来标识。它只实现了任务的管理(任务管理的实现的数据结构、任务切换)、通信(任务间对硬件资源的合理分配)。
在单核计算机的世界里,一个任务运行时,他的运行时环境由一些特定的资源组成,如CPU的寄存器、RAM中的资源(比如局部变量)、其他硬件状态资源等。
uCOS-II必须保证任务间无缝地切换,即这个单核runtime environment的seamless地切换,也可以说是必须要要无缝地切换这些资源(CPU寄存器、RAM变量)。
uCOS-II是怎么样实现任务的管理的呢?
答:是通过“OSTCBPrioTbl”这个表(或者数组,一个存放指向OSTCB类型结构体的指针),他的原型是,OS_TCB* OSTCBPrioTbl[OS_LOWEST_PRIO + 1u]; 和它密切相关的自然是实际存放任务状态、资源记录等信息的任务块,“OSTCBTbl”(存放任务块结构体的数组),原型是,OS_TCB OSTCBTbl[OS_MAX_TASKS + OS_N_SYS_TASKS];
uCOS-II是怎么实现任务调度的呢?
为了更快地,固定时间地实现任务调度和切换,uCOS-II使用了位图算法(OSUnMapTbl)、一些全局变量(OSTCBCur、OSTCBHighRdy;OSRdyGrp、OSRdyTbl;OSPrioCur、OSPrioHighRdy等)。任务调度先通过位图算法处理OSRdyGrp、OSRdyTbl数据,找到最高的就绪优先级,通过OSTCBPrioTbl找到OSTCBTbl里的任务控制块,如果需要切换,那么就利用之前移植好的代码做切换(中断级别的上下文切换和任务级别的上下文切换)。
任务在运行时,需要协同也会涉及到资源的竞争分配等问题,如何协同?如何合理的使用CPU,涉及到事件控制块派生出的信号量、消息队列、邮箱等概念。
好晚了,去睡觉了。哈。
/***********************************************************************************************************************/
1.
RTOS的调度算法以及系统任务如何协同运行
OS_EXT OS_PRIO OSRdyGrp;
OS_EXT OS_PRIO OSRdyTbl[OS_RDY_TBL_SIZE];
OS_EXT OS_EVENT *OSEventFreeList;
OS_EXT OS_EVENT OSEventTbl[OS_MAX_EVENTS];
如果优先级个数小于64,定义 OS_PRIO INT8U,否则默认为256个优先级 定义为INT16U。
#if OS_LOWEST_PRIO <= 63u
typedef INT8U OS_PRIO;
#else
typedef INT16U OS_PRIO;
#endif
uCOS-II中设计了一个优先级表OSxxxTbl表中的每个bit定义对应一个优先级,该优先级就绪则该bit置1,否则置0,有多少个位就有多少个优先级,优先级按照位的顺序排列。
OS_PRIO OSxxxGrp和OS_PRIO OSxxxTbl[OS_xxx_TBL_SIZE]配合起来使用;系统有(OS_xxx_TBL_SIZE x (SizeofBits(OS_PRIO)))个优先级,也就是 SizeofBits(OSxxxTbl[OS_xxx_TBL_SIZE])。
设Grpx 为就绪组中优先级最高的那个组,MaxPrio为就绪组中最高优先级
Grpx = OSUnMapTbl [OSxxxGrp]
MaxPrio = OSUnMapTbl[OSxxxTbl[Grpx]]
OSUnMapTbl的含义是,在8个位(8个优先级任意状态),即 28 =256种情况中,确定优先级最高的就绪位。所以64个优先级,需要先确定8个组中优先级最高的那个组,再确定组中优先级最高的那个位。
#############非重要话题
/* 关于底层 keil stm32f407, 0x08000000 ,FLSAH, 0x20000000 RAM*/
1. 全局变量, 全局变量的初始化和不初始化,都存放在RAM中,怎么存放的RAM中的?(这不是UOCS的重点)
1.1 全局常量
extern INT8U const OSUnMapTbl[256]; /* Priority->Index lookup table */
const 指定存储属性,全局只读变量,全局常量。在map文件中的位置如下:
OSUnMapTbl 0x0800190a Data 256 os_core.o(.constdata)
1.2 全局变量如何初始化?
参考,AN241 - ARM Compiler C Library Startup and Initialization Application Note 241, URL, http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dai0241b/index.html,
data和.bss是在__main里进行初始化的。对于gcc汇编文件startup_stm32f10x_hd.s里面Reset_Handler
已经对.data和.bss进行了初始化。
__scatterload
Application code and data can be in a root region or a non-root region. Root regions have the same load-time and execution-time addresses. Non-root regions have different load-time and execution-time addresses. The root region contains a region table output by the ARM linker.
The region table contains the addresses of the non-root code and data regions that require initialization. The region table also contains a function pointer that indicates what initialization is needed for the region, for example a copying, zeroing, or decompressing function.
__scatterload goes through the region table and initializes the various execution-time regions. The function: !!!这里类似 uboot 里的启动,这类代码叫boot代码。这个函数的作用就是把ZI等加载地址和执行地址不一致的变量重定位一下。
? Initializes the Zero Initialized (ZI) regions to zero
? Copies or decompresses the non-root code and data region from their load-time locations to the execute-time regions.
__main always calls this function during startup before calling __rt_entry.
__rt_entry
__main calls __rt_entry to initialize the stack, heap and other C library sub systems. __rt_entry calls various initialization functions and then calls the user-level main()