版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1、FreeRTOS内核解析FreeRTOS是一个小型的嵌入式实时系统内核,应用比较广泛,而且开源,商业免费。在STM32F4系列上移植FreeRTOS Start System Peripheral Init OS Init TASK A OS Task Scheduler TASK B TASK C 图1 OS操作流程在FreeRTOS内核中包含的文件: 1. croutine.c 协线程文件,和任务类似,在系统资源比较缺乏下使用。2. list.c 列表结构描述,在内核整体控制上都使用了列表格式数据处理。一切 的数据结构基础。3. queue.c 队列,任务和任务之间的通讯处理。 4. Ti
2、mers.c 软定时,以任务形式存在。5. Port.c 硬件与系统内核交互部分。SVC、PENDSC、中断等设置。汇编与C的结合6. Heap.c 堆栈内存空间。内存空间申请,释放。在这里我们使用heap_4.c。7. tasks.c 所有任务相关函数。8. cmsisi_os.c 系统相关接口CMSISI_OS标准化,接口处理。 heap_4.c 实现原理:申请一块静态内存,按照堆的方式处理。包含内存申请,释放,自动合并相连的空闲内存。 应用API函数: void *pvPortMalloc(size_t xWantedSize); void vPortFree(void *pv); si
3、ze_t xPortGetFreeHeapSize(void); 内部过程函数: static void prvHeapInit(void); static void prvInsertBlockIntoFreeList(xBlockLink *pxBlockToInsert) ; /申请内存空间块描述 可以看做一个节点typedef struct A_BLOCK_LINK struct A_BLOCK_LINK *pxNextFreeBlock; /指向下一块内存 size_t xBlockSize; /空闲块大小xBlockLink;/指向开始和结尾 xStart是静态内存 pxEnd 是
4、个指针 xBlockLink xStart, *pxEnd = NULL节点数据空间。节点数据空间。在系统蛇口中要考虑到字节对齐的问题。所以在申请一块内存时,要先进行内存字节格式对齐。也就是说1-7个字节格式化后也为8个字节。#define portBYTE_ALIGNMENT 8 /8字节对齐#define portBYTE_ALIGNMENT_MASK ( 0x0007 ) /对齐掩码static const unsigned short heapSTRUCT_SIZE = (sizeof(xBlockLink) + (portBYTE_ALIGNMENT - 1) & portB
5、YTE_ALIGNMENT_MASK);/静态内存 作为整个内存空间 configTOTAL_HEAP_SIZE 宏定义设置 根据需求设置大小static unsigned char ucHeapconfigTOTAL_HEAP_SIZE; #define heapADJUSTED_HEAP_SIZE(configTOTAL_HEAP_SIZE - portBYTE_ALIGNMENT) /实际可用大小 在初始化prvHeapInit()函数中 假设configTOTAL_HEAP_SIZE为1024 (0x400)在实际使用空间中 起码可以保持 1024 - 8个字节空间可用pucAlign
6、edHeap 指向了8字节对齐化了的地址xStart.pxNextFreeBlock = ( void * ) pucAlignedHeap;xStart.xBlockSize = (size_t)0;假设ucHeap是一个不对齐的地址 0x00427c58;那么8字节对齐后为0x00427c600x00427c58 0x00428058。 0x00427c60 pucAlignedHeap 指向该位置xStart可以看做独立该空间的一个节点 大小为0 指向空间的开始地址xStart->pxNextFreeBlock 指向pucAlignedHeappucHeapEnd = pucAli
7、gnedHeap + xTotalHeapSize;pucHeapEnd -= heapSTRUCT_SIZE;pxEnd = (void *)pucHeapEnd; 更新pxEnd 指向pxEnd->xBlockSize = 0;pxEnd->pxNextFreeBlock = NULL;0x00428050(pxEnd)。 NULL(pxNextFreeBlock )pxFirstFreeBlock = (void *)pucAlignedHeap;pxFirstFreeBlock->xBlockSize = xTotalHeapSize - heapSTRUCT_SIZ
8、E;pxFirstFreeBlock->pxNextFreeBlock = pxEnd;xFreeBytesRemaining -= heapSTRUCT_SIZE; /更新空闲大小使用标志 高位置1xBlockAllocatedBit = (size_t)1) << (sizeof(size_t) * heapBITS_PER_BYTE) - 1);pxFirstFreeBlock pxFirstFreeBlock->pxNextFreeBlock对齐损失节点数据空间pxEnd申请内存pvPortMalloc(size_t xWantedSize) xWantedSi
9、ze为要申请内存的大小,返回该内存的指针if(pxEnd = NULL)/未初始化 先进行初始化prvHeapInit();xWantedSize += heapSTRUCT_SIZE;/实际使用的空间为节点+内存xWantedSize设置的大小也要字节对齐化处理pxPreviousBlock = &xStart;pxBlock = xStart.pxNextFreeBlock;while(pxBlock->xBlockSize < xWantedSize) && (pxBlock->pxNextFreeBlock != NULL) /遍历全局 查看足
10、够大的空闲内存pxPreviousBlock = pxBlock;pxBlock = pxBlock->pxNextFreeBlock;pxPreviousBlock 指向 xStartpxBlock 注意:这里的B 数据都是空闲内存B空闲B空闲B空闲B。ENDpxPreviousBlock pxBlock B空闲B空闲B空闲B。END pxPreviousBlock pxBlock (该空间足够大)B空闲B空闲B空闲B。END pvReturn pvReturn 返回空间地址pxPreviousBlock->pxNextFreeBlock = pxBlock->pxNext
11、FreeBlock; pxPreviousBlock pxBlock 这里pxBlock不为空 断开空闲链表B空闲B空闲B数据B。END空间大 一分为二pxNewBlockLink = (void *)(unsigned char *)pxBlock) + xWantedSize);pxNewBlockLink->xBlockSize = pxBlock->xBlockSize - xWantedSize;pxBlock->xBlockSize = xWantedSize; 这里可以看出节点中的大小包含节点所占空间 pxBlock pxNewBlockLink B空闲B要用内
12、存空闲B。ENDprvInsertBlockIntoFreeList(pxNewBlockLink); 把新块插入空闲列表xFreeBytesRemaining -= pxBlock->xBlockSize; 更新剩余空间pxBlock->xBlockSize |= xBlockAllocatedBit; 节点长度高位置1pxBlock->pxNextFreeBlock = NULL; 已使用从空闲链表中断开把该块插入空闲链表prvInsertBlockIntoFreeList(xBlockLink *pxBlockToInsert)for(pxIterator = &
13、;xStart; pxIterator->pxNextFreeBlock < pxBlockToInsert; pxIterator = pxIterator->pxNextFreeBlock ) 遍历空闲列表定位pxIterator pxIterator 指向xStartxStart.pxNextFreeBlock 指向第一个空闲 pxBlockToInsertB空闲B要用内存B。ENDpuc = (unsigned char *)pxIterator; 为要插入块的前一个空闲块if(puc + pxIterator->xBlockSize) = ( unsigned
14、 char * )pxBlockToInsert)如果pxIterator这块在插入块pxBlockToInsert前方相邻 那么进行合并pxIterator->xBlockSize += pxBlockToInsert->xBlockSize;pxBlockToInsert = pxIterator; 如果pxIterator 与 pxBlockToInsert相邻 那么合并这2块空闲 pxIterator pxBlockToInsertB空闲B空闲B。ENDpxIterator (pxBlockToInsert) 合并后 B空闲B。ENDpuc = (unsigned char
15、 *)pxBlockToInsert;if(puc+pxBlockToInsert->xBlockSize)=(unsignedchar*)pxIterator->pxNextFreeBlock)如果pxIterator这块在插入块pxBlockToInsert后方相邻 那么进行合并pxBlockToInsert->xBlockSize+=pxIterator->pxNextFreeBlock->xBlockSize;pxBlockToInsert->pxNextFreeBlock=pxIterator->pxNextFreeBlock->pxN
16、extFreeBlock; pxIterator->pxNextFreeBlock 与 pxBlockToInsert相邻 pxIterator pxBlockToInsertB空闲B数据B空闲B空闲ENDif(pxIterator != pxBlockToInsert) 连接2块空闲列表pxIterator->pxNextFreeBlock = pxBlockToInsert;pxIterator pxBlockToInsertB空闲B数据B空闲B数据END释放内存vPortFree(void *pv)if(pxLink->xBlockSize & xBlockAl
17、locatedBit)!= 0)已使用内存的 块大小高位都置1判断pxLink->xBlockSize &= xBlockAllocatedBit 高位清零xFreeBytesRemaining += pxLink->xBlockSize; 更新剩余大小prvInsertBlockIntoFreeList(xBlockLink *)pxLink); 把该块插入空闲列表List.c 列表结构,含有插入、移除的功能。列表中的项目结构struct xLIST_ITEMconfigLIST_VOLATILE portTickType xItemValue; /项目值struct x
18、LIST_ITEM * configLIST_VOLATILE pxNext;/指向下一个ITEMstruct xLIST_ITEM * configLIST_VOLATILE pxPrevious;/指向前一个ITEMvoid * pvOwner;/可指向任务中TCBvoid * configLIST_VOLATILE pvContainer;/指向所属列表;typedef struct xLIST_ITEM xListItem;简化项目结构struct xMINI_LIST_ITEMconfigLIST_VOLATILE portTickType xItemValue;/项目值struct
19、 xLIST_ITEM * configLIST_VOLATILE pxNext; /指向下一个ITEMstruct xLIST_ITEM * configLIST_VOLATILE pxPrevious; /指向上一个ITEM;typedef struct xMINI_LIST_ITEM xMiniListItem;列表结构typedef struct xLISTconfigLIST_VOLATILE unsigned portBASE_TYPE uxNumberOfItems; /项目个数xListItem * configLIST_VOLATILE pxIndex; /指向最后一个ITE
20、MxMiniListItem xListEnd; /申请一个内存表示列表尾 xList; pxIndex &xListEnd(静态内存)ITEM1ITEM2ITEM3ITEM4ITEM5查看list.h中一些宏定义 方便使用,提高效率/设置ITEM的pvOwner #define listSET_LIST_ITEM_OWNER( pxListItem, pxOwner ) ( ( pxListItem )->pvOwner = ( void * ) ( pxOwner ) )/获取ITEM的pvOwner#define listGET_LIST_ITEM_OWNER( pxLis
21、tItem ) ( pxListItem )->pvOwner/设置ITEM的VALUE值#define listSET_LIST_ITEM_VALUE( pxListItem, xValue ) ( ( pxListItem )->xItemValue = ( xValue ) )/获取ITEM的VALUE值#define listGET_LIST_ITEM_VALUE( pxListItem ) ( ( pxListItem )->xItemValue )/获取LIST中第一个ITEM的VALUE值#define listGET_ITEM_VALUE_OF_HEAD_EN
22、TRY( pxList ) ( (&( ( pxList )->xListEnd )->pxNext->xItemValue )/判断LIST是否为空#define listLIST_IS_EMPTY( pxList ) ( ( portBASE_TYPE ) ( ( pxList )->uxNumberOfItems = ( unsigned portBASE_TYPE ) 0 ) )/获取LIST中ITEM个数#define listCURRENT_LIST_LENGTH( pxList ) ( ( pxList )->uxNumberOfItems
23、)/获取pxIndex指向的下一个pvOwner 并且更新了pxIndex#define listGET_OWNER_OF_NEXT_ENTRY( pxTCB, pxList ) 。/获取第一个ITEM的pvOwner #define listGET_OWNER_OF_HEAD_ENTRY( pxList ) ( (&( ( pxList )->xListEnd )->pxNext->pvOwner )/查看该ITEM的所属LIST 是否与pxList一致#define listIS_CONTAINED_WITHIN( pxList, pxListItem ) ( (
24、 portBASE_TYPE ) ( ( pxListItem )->pvContainer = ( void * ) ( pxList ) ) )/获取ITEM所属LIST#define listLIST_ITEM_CONTAINER( pxListItem ) ( ( pxListItem )->pvContainer )列表初始化vListInitialise( xList * const pxList )pxList->pxIndex = ( xListItem * ) &( pxList->xListEnd );pxList->xListEnd.
25、xItemValue = portMAX_DELAY;pxList->xListEnd.pxNext = ( xListItem * ) &( pxList->xListEnd );pxList->xListEnd.pxPrevious = ( xListItem * ) &( pxList->xListEnd );pxList->uxNumberOfItems = ( unsigned portBASE_TYPE ) 0U;初始化了pxIndex 指向xListEnd xListEnd 的值为 portMAX_DELAY(0xffffffff)L
26、IST中包含个数为0 (pxNext ) pxList->pxIndex &( pxList->xListEnd )(静态内存) (pxPrevious )ITEM个数为0插入到末尾vListInsertEnd( xList * const pxList, xListItem * const pxNewListItem )pxIndex = pxList->pxIndex;pxNewListItem->pxNext = pxIndex;pxNewListItem->pxPrevious = pxIndex->pxPrevious;pxIndex-&g
27、t;pxPrevious->pxNext = pxNewListItem;pxIndex->pxPrevious = pxNewListItem;pxNewListItem->pvContainer = ( void * ) pxList;( pxList->uxNumberOfItems )+;LIST的个数加1 该ITEM所属pxList (pxNext ) pxList->pxIndex &( pxList->xListEnd )(静态内存) (pxPrevious ) (pxPrevious) (pxNext )pxNewListItem(插
28、入的ITEM)如果再插入一次 (pxNext ) pxList->pxIndex &( pxList->xListEnd )(静态内存) (pxPrevious ) (pxPrevious) (pxNext )ITEM1pxNewListItemVALUE值插入vListInsert( xList * const pxList, xListItem * const pxNewListItem )if( xValueOfInsertion = portMAX_DELAY ) 插入的值为最大值 与xListEnd一致 指向xListEnd前的一个ITEM pxIterator
29、= pxList->xListEnd.pxPrevious;elsefor( pxIterator = ( xListItem * ) &( pxList->xListEnd ); pxIterator->pxNext->xItemValue <= xValueOfInsertion; pxIterator = pxIterator->pxNext ) 遍历比较VALUE值 获取插入位置假设插入值为3 pxIteratorITEM1(1)ITEM2(2)ITEM3(4)ITEM4(5)pxNewListItem->pxNext = pxIter
30、ator->pxNext;pxNewListItem->pxNext->pxPrevious = pxNewListItem;pxNewListItem->pxPrevious = pxIterator;pxIterator->pxNext = pxNewListItem;pxNewListItem->pvContainer = ( void * ) pxList;( pxList->uxNumberOfItems )+; pxIterator pxNewListItemITEM1(1)ITEM2(2)ITEM3(4)ITEM4(5)移除一个ITEM
31、uxListRemove( xListItem * const pxItemToRemove )pxItemToRemove->pxNext->pxPrevious = pxItemToRemove->pxPrevious;pxItemToRemove->pxPrevious->pxNext = pxItemToRemove->pxNext;假设pxItemToRemove为ITEM2 pxIterator 一般情况下指向xListEnd 也有可能指向其中一个 pxItemToRemoveITEM1(1)ITEM2(2)ITEM3(4)ITEM4(5)pxL
32、ist = ( xList * ) pxItemToRemove->pvContainer;if( pxList->pxIndex = pxItemToRemove ) pxList->pxIndex = pxItemToRemove->pxPrevious; (pxIterator) pxItemToRemove 更新pxIterator指向ITEM1(1)ITEM2(2)ITEM3(4)ITEM4(5) Port.c 端口设置,涉及到内核系统。由汇编及C编写。pxPortInitialiseStack( portSTACK_TYPE *pxTopOfStack, p
33、dTASK_CODE pxCode, void *pvParameters )堆栈初始化设置,在任务建立时执行。每个任务都有一个对应的堆栈,用于任务切换后,寄存器状态的保存。 pxTopOfStack 指向堆栈高地址 (ulong类型) 假设0x20000470XPSR(0x01000000)PC(pxCode)LRR12R3R2R1R0(param)RETURN(0xfffffffd)R11R10R9R8R7R6R5R4 返回更新的pxTopOfStack 0x2000042c进入时寄存器状态函数退出后寄存器状态堆栈中的数据开启任务调度xPortStartScheduler( void )u
34、lOriginalPriority = *pcFirstUserPriorityRegister; /IP0 中断0配置的优先级*pcFirstUserPriorityRegister = portMAX_8_BIT_VALUE;ucMaxPriorityValue = *pcFirstUserPriorityRegister; /0xffucMaxSysCallPriority = configMAX_SYSCALL_INTERRUPT_PRIORITY & ucMaxPriorityValue; /0101 0000 大于这个中断优先级的中断不能被响应 /ISR中可以安全调用系统A
35、PIulMaxPRIGROUPValue = portMAX_PRIGROUP_BITS; /7 组的最大值while( ( ucMaxPriorityValue & portTOP_BIT_OF_BYTE ) = portTOP_BIT_OF_BYTE ) /查看最高位ulMaxPRIGROUPValue-;ucMaxPriorityValue <<= ( unsigned char ) 0x01;优先级组76543抢占位数01234xxxx 0000 使用高4位 厂商只用了4位 15个中断优先级计算出优先级组的设定ulMaxPRIGROUPValue <<=
36、 portPRIGROUP_SHIFT; /AIRCR 10:8ulMaxPRIGROUPValue &= portPRIORITY_GROUP_MASK;*pcFirstUserPriorityRegister = ulOriginalPriority; /重设IP0当前优先级portNVIC_SYSPRI2_REG |= portNVIC_PENDSV_PRI; /0x00F00000 SHP10 portNVIC_SYSPRI2_REG |= portNVIC_SYSTICK_PRI; /0x0F000000 SHP11 设置了PENDSV STSTICK为最低优先级 不影响其他
37、中断vPortSetupTimerInterrupt(); /SYSTICK设置uxCriticalNesting = 0; /进入临界区嵌套计数清0prvEnableVFP(); /使能FPU *( portFPCCR ) |= portASPEN_AND_LSPEN_BITS; /FPCCR使能自动保存和恢复prvStartFirstTask(); /开启第一个任务初始化定时中断vPortSetupTimerInterrupt( void ) portNVIC_SYSTICK_LOAD_REG 重载计数设置 portNVIC_SYSTICK_CTRL_REG 使能SYSTICK时钟 使能S
38、YSTICK 使能SYSTICK中断 使能VFP功能_asm void prvEnableVFP( void )PRESERVE8ldr.w r0, =0xE000ED88 /CPACR中设置ldr r1, r0 /CP11 CP10 23:22 21:20orr r1, r1, #( 0xf << 20 )str r1, r0bx r14nop开启第一个任务_asm void prvStartFirstTask( void )PRESERVE8ldr r0, =0xE000ED08 /向量表偏移ldr r0, r0 ldr r0, r0 /第一个值为堆栈栈顶msr msp, r0
39、 /存入MSPcpsie i /开启中断svc 0 /产生SVC中断nopSVC指令_asm void vPortSVCHandler( void ) 调用SVC来请求任务切换PRESERVE8 8字节对齐ldr r3, =pxCurrentTCB ldr r1, r3 获取当前任务 地址0x20000480ldr r0, r1 获取当前任务的栈顶地址 0x2000068Cldmia r0!, r4-r11, r14 POP R4-R11 R14 R0指向地址更新 R0RETURN(0xfffffffd)R11R10R9R8R7R6R5R4如果LR=0xFFFFFFFD明产生异常的时候使用的是
40、PSPmsr psp, r0 更新堆栈地址 R0从0x2000042C 变0x20000450mov r0, #0 清空r0msr basepri, r0 清除basepribx r14PENDSV _asm void xPortPendSVHandler(void)用于上下文切换extern uxCriticalNesting; /进入临界区嵌套次数extern pxCurrentTCB;extern vTaskSwitchContext;PRESERVE8mrs r0, pspldr r3, =pxCurrentTCB /获取当前TCBldr r2, r3tst r14, #0x10it
41、eqvstmdbeq r0!, s16-s31 /使用FPU PUSH高位VFPstmdb r0!, r4-r11, r14 /保存当前环境str r0, r2 /把新的堆栈存入pxTopOfStackstmdb sp!, r3mov r0, #configMAX_SYSCALL_INTERRUPT_PRIORITYmsr basepri, r0 /设置basepribl vTaskSwitchContext /设置上下文切换 的一些状态参数mov r0, #0msr basepri, r0 /屏蔽baseprildmia sp!, r3 /恢复SP ldr r1, r3 /获取栈顶ldr r
42、0, r1ldmia r0!, r4-r11, r14 /pop内核寄存器tst r14, #0x10it eqvldmiaeq r0!, s16-s31 /PUSH FPU 高位VFPmsr psp, r0bx r14Task.c 任务相关函数状态及参数:typedef enum 任务的几个状态eRunning = 0, 运行eReady, 就绪eBlocked, 阻塞eSuspended, 挂起eDeleted 删除 eTaskState;typedef struct xTASK_PARAMTERS 任务的参数pdTASK_CODE pvTaskCode; 任务函数const signed
43、 char * const pcName; 任务名unsigned short usStackDepth; 堆栈深度void *pvParameters; 参数unsigned portBASE_TYPE uxPriority; 优先级portSTACK_TYPE *puxStackBuffer; 堆栈指针 xMemoryRegion xRegions portNUM_CONFIGURABLE_REGIONS ; MPU部分 xTaskParameters;typedef struct xMEMORY_REGION MPU内存管理void *pvBaseAddress; 分配的内存地址unsi
44、gned long ulLengthInBytes; 内存长度unsigned long ulParameters; 参数 xMemoryRegion;typedef struct xTASK_STATUS 每个任务在系统中的参数xTaskHandle xHandle; 任务句柄const signed char *pcTaskName; 任务名unsigned portBASE_TYPE xTaskNumber; 任务号 唯一eTaskState eCurrentState; 任务当前状态 unsigned portBASE_TYPE uxCurrentPriority; 当前优先级 unsigned portBASE_TYPE uxBasePriority; 任务优先级 互斥信号量中使用 unsigned long ulRunTimeCounter; 运行TICK计数unsigned short usStackHighWaterMark; 堆栈当前使用深度 xTaskStatusType;typedef struct tskTask
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- N-Decyl-N-N-dimethyldecan-1-aminium-chloride-Standard-生命科学试剂-MCE
- 医院年度工作总结
- 中心小学师徒结对方案
- 人教版八年级英语下学期教学工作总结
- 道路交通标志线工程施工方案
- 连锁超市管理系统解决方案
- 2025届山东省师大附中物理高三上期中检测模拟试题含解析
- 湖州师范学院《美国文学史及作品选读》2022-2023学年第一学期期末试卷
- 课程设计论文答辩流程
- 业务审计合同
- 期中试卷(试题)-2024-2025学年三年级上册数学青岛版
- 期中押题卷(试题)-2024-2025学年数学六年级上册北师大版
- 期中模拟(1-3单元)(试题)-2024-2025学年六年级上册数学苏教版
- 点亮文明 课件 2024-2025学年苏少版(2024)初中美术七年级上册
- 廉政法规知识测试及答案
- 2024内蒙古农牧业融资担保限公司招聘28人高频难、易错点500题模拟试题附带答案详解
- 5.1 延续文化血脉 课件-2024-2025学年统编版道德与法治九年级上册-2
- 2024-2030年中国CCUS技术行业现状调查与前景策略分析研究报告
- 2024-2025形势与政策:七十五载砥砺奋进创辉煌 中国式现代化继往开来兴伟业
- “数字城市”公共智慧底座项目解决方案
- 二年级数学上册教案 4、除法的初步认识 苏教版
评论
0/150
提交评论