RTOS随笔之FreeRTOS第一篇

RTOS随笔之FreeRTOS第一篇
RTOS几点思考为什么使用RTOS?1. 先考虑OS有什么特点2. 再考虑什么情况下使用OS?FreeRTOS调试技巧任务管理1. 任务调度流程2. 任务栈大小栈溢出检测3. 中断管理4. 内存管理FreeRTOS API接口1. 任务创建为什么使用RTOS?1. 先考虑OS有什么特点无OS开发情况下就是一个while循环中执行所有模块功能顺序执行模块依次执行不能调换顺序更不能同步实时执行voidmain(){BSP_Init();//硬件初始化while(1){task1();//模块1执行.......task4();//模块4执行}}状态调度模块根据状态变化执行可以调换顺序不能同步实时执行unsignedintswitchflag;voidmain(){BSP_Init();//硬件初始化while(1){switch(switchflag){casestatus1:task1();//模块1执行break;casestatus2:task2();//模块2执行break;.......}}}上面的任务都需要执行完才能跳转到其它任务不能在任务运行期间跳转。也有一种情况是任务自己提前break但是你能让自己break你不能让别人break啊所以我们需要一个东西管理任务切换执行这个就是OS了。基于这个最初的需求可以看一下现在的OS实现了什么功能支持抢占切换/合作切换/时间片切换任务支持低功耗模式支持多种系统架构支持任务同步机制支持堆栈溢出检测工具免费源码免费版权免费2. 再考虑什么情况下使用OS?1.项目功能单一程序简单各模块没有强烈同步执行的需求实时性需求不强不需要OS2.项目功能复杂模块交织多个模块有强烈同步执行的需求实时性需求强需要OS根据项目考量没有明确界限FreeRTOS调试技巧重定向printf/scanf函数进行串口打印/*重定向printf函数*/intfputc(intdata,FILE*file){USART_SendData(USARTx,(char)data);//发送一个字节while(USART_GetFlagStatus(USARTx,USART_FLAG_TXE)RESET);//等待发送成功returndata;}/*重定向scanf函数*/intfgetc(FILE*file){chardata;while(USART_GetFlagStatus(USARTx,USART_FLAG_RXNE)RESET);//等待接收成功dataUSART_ReceiveData(USARTx);//接收一个字节return(int)data;}调试任务运行状态任务栈余量CPU占用率实现计数器volatileuint32_tOS_DebugTimeTicks0;//调试心跳voidBSP_Timex(){//实现20KHz频率的定时器//开定时器中断//OS_DebugTimeTicks在中断中自增}FreeRTOSConfig.h文件宏配置externuint32_tOS_DebugTimeTicks;#defineconfigUSE_TRACE_FACILITY1#defineconfigGENERATE_RUN_TIME_STATS1#defineconfigUSE_STATS_FORMATTING_FUNCTIONS1#defineportCONFIGURE_TIMER_FOR_RUN_TIME_STATS()(OS_DebugTimeTicks0UL)#defineportGET_RUN_TIME_COUNTER_VALUE()OS_DebugTimeTicks调用RTOS调试函数vTaskList()vTaskGetRunTimeStats()输出任务信息staticvoidvTaskTaskUserIF(void*pvParameters){uint8_tucKeyCode;uint8_tDebugInfoBuff[500];while(1){printf(\r\n);printf(任务名 任务状态 优先级 剩余栈 任务序号\r\n);vTaskList((char*)DebugInfoBuff);printf(%s\r\n,DebugInfoBuff);printf(\r\n任务名 运行计数 使用率\r\n);vTaskGetRunTimeStats((char*)DebugInfoBuff);printf(%s\r\n,DebugInfoBuff);vTaskDelay(20);}}任务管理1. 任务调度流程2. 任务栈大小栈溢出检测栈大小最小栈空间栈内容函数每层函数局部变量形参返回地址状态保存任务切换部分CPU寄存器 FPU寄存器中断部分CPU寄存器 FPU寄存器可变参函数函数指针递归无法确定栈大小标准栈空间最小栈大小的1.5~2倍大小函数栈大小及嵌套深度可以参考工程编译文件.htm文件RTOS调试技巧测试栈空间适当调整栈溢出检测栈生长地址由高到低如果栈指针下移的地址越过了任务栈的基地址则栈溢出。软件预设检测在栈生长方向的末端开辟一段空间专门存放固定值定时判断固定值有没有被修改被修改说明栈溢出了。存在栈溢出超过判断区间直接宕机的可能。MPU内存保护通过MPU对栈生长方向的末端区间进行保护如果出现栈溢出触发MPU异常在异常中分析栈溢出情况。FreeRTOS栈溢出检测方法1任务切换时检测栈指针是否越界栈溢出触发溢出回调函数vApplicationStackOverflowHook#defineconfigCHECK_FOR_STACK_OVERFLOW1voidvApplicationStackOverflowHook(TaskHandle_t xTask,signedchar*pcTaskName);//溢出回调函数方法2 任务栈初始化为固定值任务切换时检测栈尾16个字节是否都是初始化设置的固定值。#defineconfigCHECK_FOR_STACK_OVERFLOW2voidvApplicationStackOverflowHook(TaskHandle_t xTask,signedchar*pcTaskName);//溢出回调函数任务切换时进行栈溢出检测无法确保任务运行期间栈不溢出。任务切换时进行栈溢出检测无问题只能说明栈尾的数据是固定值但是不能说明是初始时设置的固定值还是运行时保存的固定值存在第2种情况的可能性。3. 中断管理M3/M4内核MCU中断优先级取寄存器8位中的高4位表示共有16种组合。几点原则RTOS采用中断分组4也就是0~15级全抢占式优先级高抢占级中断可以抢占低抢占级中断同抢占级中断不能互相抢占先到先行ResetNMI不可屏蔽中断Hard Fault高于普通中断优先级固定RTOS中断配置Systick中断产生心跳触发PendSV中断PendSV中断任务切换SVC中断启动任务只执行一次#defineconfigPRIO_BITS4//优先级占用bits#defineconfigLIBRARY_LOWEST_INTERRUPT_PRIORITY15//RTOS用的Systick和PendSV中断优先级#defineconfigKERNEL_INTERRUPT_PRIORITY(configLIBRARY_LOWEST_INTERRUPT_PRIORITY(8-configPRIO_BITS))//Systick和PendSV中断配置的优先级左移4位写进优先级配置寄存器#defineconfigLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY2//可以使用RTOS函数的最高优先级2~15优先级中断中可用RTOS接口#defineconfigMAX_SYSCALL_INTERRUPT_PRIORITY(configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY(8-configPRIO_BITS))//可以使用RTOS函数的最高优先级左移4位写进优先级配置寄存器RTOS管理的中断会出现中断延迟的可能对于实时性要求强的中断不能被RTOS管理否则会出现中断无法及时响应的情况。FreeRTOS使用basepri寄存器uCOS使用primask寄存器。寄存器功能primask这是个只有 1 个 bit 的寄存器。 在它被置 1 后就关掉所有可屏蔽的异常只剩下NMI 和硬 fault 可以响应。它的缺省值是 0表示没有关中断faultmask这是个只有 1 个 bit 的寄存器。当它置 1 时只有 NMI 才能响应所有其它的异常甚至是硬 fault也通通闭嘴。它的缺省值也是 0表示没有关异常basepri这个寄存器最多有 9 位由表达优先级的位数决定。它定义了被屏蔽优先级的阈值。当它被设成某个值后所有优先级号大于等于此值的中断都被关优先级号越大优先级越低。但若被设成 0则不关闭任何中断 0 也是缺省值4. 内存管理FreeRTOS提供5种内存管理接口FreeRTOS API接口1. 任务创建函数描述xTaskCreate( )动态创建一个任务从RTOS的堆上分配栈空间xTaskCreateStatic( )静态创建一个任务用户手动分配栈空间xTaskCreateRestricted( )任务控制块从RTOS堆上分配用户手动分配栈空间 (和FreeRTOS-MPU一起使用)xTaskCreateRestrictedStatic( )用户手动分配任务控制块和栈空间 (和FreeRTOS-MPU一起使用)

最新新闻

日新闻

周新闻

月新闻