FreeRTOS中Systick的问题

在cortex-m内核中,系统节拍由systick时钟提供,当配置好系统滴答时钟后,每次时钟中断就会触发中断处理数xportsystickhandler()。
void xportsystickhandler( void ){ /* the systick runs at the lowest interrupt priority, so when this interrupt * executes all interrupts must be unmasked. there is therefore no need to * save and then restore the interrupt mask value as its value is already * known - therefore the slightly faster vportraisebasepri() function is used * in place of portset_interrupt_mask_from_isr(). */ vportraisebasepri();//屏蔽归属freertos的中断优先级 { /* increment the rtos tick. */ if( xtaskincrementtick() != pdfalse )//时钟计数处理 { /* a context switch is required. context switching is performed in * the pendsv interrupt. pend the pendsv interrupt. */ portnvic_int_ctrl_reg = portnvic_pendsvset_bit;//如果需要切换上下文操作,pendsv标记置位 } }
vportclearbaseprifromisr();}
这部分主要是依靠 xtaskincrementtick(),来判断任务切换是否在此次系统时钟中断时被需要。如果是,则pendsv标记置位,等待触发pendsv中断。来看看 xtaskincrementtick()。
                                                             basetype_t xtaskincrementtick( void ){ tcb_t * pxtcb; ticktype_t xitemvalue; basetype_t xswitchrequired = pdfalse;
/* called by the portable layer each time a tick interrupt occurs. * increments the tick then checks to see if the new tick value will cause any * tasks to be unblocked. */ tracetask_increment_tick( xtickcount );
if( uxschedulersuspended == ( ubasetype_t ) pdfalse ) //调度是否被挂起,默认为否 { /* minor optimisation. the tick count cannot change in this * block. */ const ticktype_t xconsttickcount = xtickcount + ( ticktype_t ) 1;
/* increment the rtos tick, switching the delayed and overflowed * delayed lists if it wraps to 0. */ xtickcount = xconsttickcount;
if( xconsttickcount == ( ticktype_t ) 0u ) /*lint !e774 'if' does not always evaluate to false as it is looking for an overflow. 如果xconsttickcount为0,说明溢出了*/ { taskswitch_delayed_lists();/*切换延迟列表*/ } else { mtcoverage_test_marker(); }
/* see if this tick has made a timeout expire. tasks are stored in * the queue in the order of their wake time - meaning once one task * has been found whose block time has not expired there is no need to * look any further down the list. */ if( xconsttickcount >= xnexttaskunblocktime ) { for( ; ; ) { if( listlist_is_empty( pxdelayedtasklist ) != pdfalse ) { /* the delayed list is empty. set xnexttaskunblocktime * to the maximum possible value so it is extremely * unlikely that the * if( xtickcount >= xnexttaskunblocktime ) test will pass * next time through. */ xnexttaskunblocktime = portmax_delay; /*lint !e961 misra exception as the casts are only redundant for some ports. */ break; } else { /* the delayed list is not empty, get the value of the * item at the head of the delayed list. this is the time * at which the task at the head of the delayed list must * be removed from the blocked state. */ pxtcb = listget_owner_of_head_entry( pxdelayedtasklist ); /*lint !e9079 void * is used as this macro is used with timers and co-routines too. alignment is known to be fine as the type of the pointer stored and retrieved is the same. */ xitemvalue = listget_list_item_value( &( pxtcb->xstatelistitem ) );
关键问题是,这个函数使用到了 pxdelayedtasklist, 这定义在本文件
 privileged_data static list_t * volatile pxdelayedtasklist;
该变量初始化为0,该变量正常初始化位置在创建 task 对象等的函数中, 也就是说,如果在tick中断到来时,如果还没有任务被创建,就会导致不可预期的结果,中断服务函数会使用这个野指针,执行任务切换。这会导致触发栈溢出钩子函数,或者是直接hardfault。有些硬件初始化需要借助delay功能,不得不在初始化之前配置systick。而又不希望在硬件初始化阶段触发这个bug。所以在配置systick之前,先创建一个初始化任务,初始化 pxdelayedtasklist 这个指针,在初始化任务里配置systick,和其他初始化,这样能够避免此类问题。或者是在配置systick的时候屏蔽中断,一切准备就绪后,开启中断。执行vtaskstartscheduler()默认创建一个空闲任务。

亚马逊未来将逆袭苹果iPad,成为“黑马” 你觉得呢?
云计算+大数据:下一个系统设计关键所在
DHT11驱动通过串口打印采集到的环境温湿度数据
美国专利商标局公布了谷歌的一项专利,谷歌似乎也在研发折叠屏设备
巨哥科技推出台式光谱仪,可方便地测量各类物质的反射光谱
FreeRTOS中Systick的问题
浅谈古文物三维扫描的应用有哪些?
OLED拼接屏在昆明市场中,有哪些场景化应用?
双电源开关的使用说明
知识产权战全球开打 燃向中国企业
采用DQPSK调制与PDM技术提高光纤链路的数据传输
性爱机器人能够呼吸 未来或将越来越像人类
88e6060是什么芯片
从应用侧出发来给大家介绍一下MOS管里面最常见的NMOS
你觉得物联网增长的速度太快了吗
无人机“监管潮”势起,产业发展寻求平衡是关键
降噪蓝牙耳机性价比排行,无线蓝牙耳机的推荐
TM89系列四核MCU产品TM89P55M正式推出
步进电机总线控制与脉冲控制的区别,一文给你详细解读!
双极性对称稳压电源电路(LM7812、LM7912)