下载站

展开
精品推荐
FreeRTOS stm32 完整移植包

FreeRTOS stm32 完整移植包

源码相关大小:522.85MB语言: / 类别:编程书集系统: / WinAll, WinXP 提供:
应用介绍

介绍freertos在stm32上的移植说明,每一步都很详细,让你学会在stm32+freeRTOS的平台上开发应用程序

一、各文件关键部分的实现:1、PORTMACRO.H宏定义部分1)定义编译器相关的各种数据类型#defineportCHARchar#defineportFLOATfloat#defineportDOUBLEdouble#defineportLONGlong#defineportSHORTshort#defineportSTACK_TYPEunsignedportLONG#defineportBASE_TYPElong2)架构相关的定义Cortex-M3的堆栈增长方向为高地址向低地址增长#defineportSTACK_GROWTH(-1)每毫秒的心跳次数#defineportTICK_RATE_MS((portTickType)1000/configTICK_RATE_HZ)访问SRAM的字节对齐#defineportBYTE_ALIGNMENT83)定义用户主动引起内核调度的2个函数强制上下文切换,用在任务环境中调用#defineportYIELD()vPortYieldFromISR()强制上下文切换,用在中断处理环境中调用#defineportEND_SWITCHING_ISR(xSwitchRequired)if(xSwitchRequired)vPortYieldFromISR()4)定义临界区的管理函数中断允许和关闭#defineportDISABLE_INTERRUPTS()vPortSetInterruptMask()#defineportENABLE_INTERRUPTS()vPortClearInterruptMask()临界区进入和退出#defineportENTER_CRITICAL()vPortEnterCritical()#defineportEXIT_CRITICAL()vPortExitCritical()用于在中断环境的中断允许和关闭#defineportSET_INTERRUPT_MASK_FROM_ISR()0;vPortSetInterruptMask()#defineportCLEAR_INTERRUPT_MASK_FROM_ISR(x)vPortClearInterruptMask();(void)x2、PORT.CC接口部分1)堆栈初始化portSTACK_TYPE*pxPortInitialiseStack(portSTACK_TYPE*pxTopOfStack,pdTASK_CODEpxCode,void*pvParameters){*pxTopOfStack=portINITIAL_XPSR;/*程序状态寄存器*/pxTopOfStack--;*pxTopOfStack=(portSTACK_TYPE)pxCode;/*任务的入口点*/pxTopOfStack--;*pxTopOfStack=0;/*LR*/pxTopOfStack-=5;/*R12,R3,R2andR1.*/*pxTopOfStack=(portSTACK_TYPE)pvParameters;/*任务的参数*/pxTopOfStack-=8;/*R11,R10,R9,R8,R7,R6,R5andR4.*/returnpxTopOfStack;}2)启动任务调度portBASE_TYPExPortStartScheduler(void){让任务切换中断和心跳中断位于最低的优先级,使更高优先级可以抢占mcu*(portNVIC_SYSPRI2)|=portNVIC_PENDSV_PRI;*(portNVIC_SYSPRI2)|=portNVIC_SYSTICK_PRI;设置并启动系统的心跳时钟prvSetupTimerInterrupt();初始化临界区的嵌套的个数uxCriticalNesting=0;启动第一个任务vPortStartFirstTask();执行到vPortStartFirstTask函数,内核已经开始正常的调度return0;}3)主动释放mcu使用权voidvPortYieldFromISR(void){触发PendSV系统服务中断,中断到来时由汇编函数xPortPendSVHandler()处理*(portNVIC_INT_CTRL)=portNVIC_PENDSVSET;}进入临界区时,首先关闭中断;当退出所以嵌套的临界区后再使能中断voidvPortEnterCritical(void){portDISABLE_INTERRUPTS();uxCriticalNesting++;}voidvPortExitCritical(void){uxCriticalNesting--;if(uxCriticalNesting==0){portENABLE_INTERRUPTS();}}4)心跳时钟处理函数voidxPortSysTickHandler(void){unsignedportLONGulDummy;如果是抢占式调度,首先看一下有没有需要调度的任务#ifconfigUSE_PREEMPTION==1*(portNVIC_INT_CTRL)=portNVIC_PENDSVSET;#endifulDummy=portSET_INTERRUPT_MASK_FROM_ISR();{通过task.c的心跳处理函数vTaskIncrementTick(),进行时钟计数和延时任务的处理vTaskIncrementTick();}portCLEAR_INTERRUPT_MASK_FROM_ISR(ulDummy);}3、PORTASM.S汇编处理部分1)请求切换任务xPortPendSVHandler:保存当前任务的上下文到其任务控制块mrsr0,pspldrr3,=pxCurrentTCB获取当前任务的任务控制块指针ldrr2,[r3]stmdbr0!,{r4-r11}保存R4-R11到该任务的堆栈strr0,[r2]将最后的堆栈指针保存到任务控制块的pxTopOfStackstmdbsp!,{r3,r14}关闭中断movr0,#configMAX_SYSCALL_INTERRUPT_PRIORITYmsrbasepri,r0切换任务的上下文,pxCurrentTCB已指向新的任务blvTaskSwitchContextmovr0,#0msrbasepri,r0ldmiasp!,{r3,r14}恢复新任务的上下文到各寄存器ldrr1,[r3]ldrr0,[r1]/*ThefirstiteminpxCurrentTCBisthetasktopofstack.*/ldmiar0!,{r4-r11}/*Poptheregisters.*/msrpsp,r0bxr142.)中断允许和关闭的实现,通过BASEPRI屏蔽相应优先级的中断源vPortSetInterruptMask:push{r0}movR0,#configMAX_SYSCALL_INTERRUPT_PRIORITYmsrBASEPRI,R0pop{R0}bxr14vPortClearInterruptMask:PUSH{r0}MOVR0,#0MSRBASEPRI,R0POP{R0}bxr143)直接切换任务,用于vPortStartFirstTask第一次启动任务时初始化堆栈和各寄存器vPortSVCHandler;ldrr3,=pxCurrentTCBldrr1,[r3]ldrr0,[r1]ldmiar0!,{r4-r11}msrpsp,r0movr0,#0msrbasepri,r0orrr14,r14,#13bxr144)启动第一个任务的汇编实现vPortStartFirstTask通过中断向量表的定位堆栈的地址ldrr0,=0xE000ED08向量表偏移量寄存器(VTOR)ldrr0,[r0]ldrr0,[r0]msrmsp,r0将堆栈地址保存到主堆栈指针msp中触发SVC软中断,由vPortSVCHandler()完成第一个任务的具体切换工作svc0FreeRTOS内核调度器启动的流程如下:以上3个文件实现了FreeRTOS内核调度所需的底层接口,相关代码十分精简。

二、创建测试任务:下面创建第一个测试任务,LED测试intmain(void){设置系统时钟,中断向量表和LED使用的GPIO使用stm32的固件包提供的初始化函数,具体说明见相关手册prvSetupHardware();通过xTaskCreate()创建4个LED任务vLEDFlashTask(),每个任务根据各自的频率闪烁,分别对应开发板上的4个LEDvStartLEDFlashTasks(mainFLASH_TASK_PRIORITY);?创建一个IDLE任务后,通过xPortStartScheduler启动调度器vTaskStartScheduler();调度器工作不正常时返回return0;}portTASK_FUNCTION()是FreeRTOS定义的函数声明,没特殊作用staticportTASK_FUNCTION(vLEDFlashTask,pvParameters){……省略……,具体为计算各LED的闪烁频率for(;;){vTaskDelayUntil(&xLastFlashTime,xFlashRate);vParTestToggleLED(uxLED);vTaskDelayUntil()的延时时间xFlashRate,是从上一次的延时时间xLastFlashTime算起的,相对vTaskDelay()的直接延时更为精准。vTaskDelayUntil(&xLastFlashTime,xFlashRate);vParTestToggleLED(uxLED);}}FreeRTOS的任务创建与UC/OSII差异不大,主要参数为任务函数,堆栈大小和任务的优先级。如:xTaskCreate(vLEDFlashTask,(signedportCHAR*)"LEDx",ledSTACK_SIZE,NULL,uxPriority,(xTaskHandle*)NULL);下面再创建一个LCD显示任务,以最低优先级运行:xTaskCreate(vLCDTask,(signedportCHAR*)"LCD",configMINIMAL_STACK_SIZE,NULL,tskIDLE_PRIORITY,NULL);voidvLCDTask(void*pvParameters){……省略……for(;;){vTaskDelay(1000);printf("%c",usDisplayChar);}}该任务很简单,每隔1000个ticks(就是1000ms),从LCD上刷新一个数字。至此,FreeRTOS在STM32上的移植基本完成。与UC/OSII相比,FreeRTOS精简的实现更适合用来学习实时操作系统的工作原理,对其进行剖析也相对容易。接下来,我们将会移植CAN,RS485,SD卡和USB等接口到FreeRTOS,使其在STM32平台上更加完善。

Tags:FreeRTOS.

应用推荐查看更多
热门下载查看更多
精选应用
点击查看更多
专题合集查看更多
热门专题查看更多
友情链接0投诉联系:ichaoinc@gmail.com