完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
需求描述:
我采用的是STM32F071这个芯片,采用FREERTOS,使用的电池供电,所以要求低功耗,我采用的tiCKLESS官方推荐的方式,配置 #define configUSE_TICKLESS_IDLE 1 ,然后编写函数 vPortMySuppressTicksAndSleep 在这里 进入STOP模式,采用RTC的闹钟中断唤醒,和 外部中断唤醒; 但是 经过测试,在外部中断中发送任务信号量(不是xSemaphoreTake创建的 而是任务自带的内部信号量),可以唤醒对应的任务, 然后测试 xSemaphoreTake 创建的独立信号量的方式,测试代码为 创建一个信号量,然后一个线程设置5秒等待这个信号量,然后输出调试信息,但是一旦唤醒,系统就死机了 然后不再进入SYSTICK中断了,,,,调试了 快一个月了,,,实在没办法了,,论坛里 希望有使用过 这种 低功耗方式的,可以指导一下,非常感谢! |
|
相关推荐
4个回答
|
|
自己解决了 采用官方 CUBE生成的 HAL库的方式使用的,估计是我采用标准库 移植 或者系统移植移植的 哪个地方出了问题,采用官方生成的代码就OK了
|
|
|
|
你写的有点乱。。。TICKLESS机制在中断唤醒后不是立刻进入你的中断
在进入低功耗前已经把中断关闭了,中断唤醒后执行了一些必要的操作后才开启中断,这时系统开始正常运作 至于你说的不再进入SYSTICK中断,是不是你写的TICKLESS代码有问题呢?还是说API调用有问题? |
|
|
|
void vPortMySuppressTicksAndSleep( TickType_t xExpectedIdleTime )
{ u32 t0=0; u32 t1=0; u32 tt=0; eSleepModeStatus eReturn ; printf("rn daozheli xExpectedIdleTime = %d *",xExpectedIdleTime); RTC_WaitForSynchro(); t0=RTC_GetCounter();//读取 当前的RTC计时值 没49天一复位 RTC if(xExpectedIdleTime>MAX_ALARM_TIME)//限制最大为 定时器RTC单一循环所能表示的时间 { xExpectedIdleTime=MAX_ALARM_TIME; } printf("rn shiji wei= xExpectedIdleTime = %d *",xExpectedIdleTime); portENTER_CRITICAL(); eReturn = eTaskConfirmSleepModeStatus(); portEXIT_CRITICAL(); //需要调用系统的函数去 判断是否需要进入低功耗 休眠 if( eReturn == eAbortSleep )//不用休眠 就直接返回即可 { printf("rn eReturn == eAbortSleep hu lue xiu mian *rn"); return ; } else //标准休眠 和 没有任务会等待超时(都在无线等待的状态 是需要配置外部中断唤醒源的 否则会休眠到定时器最大值时唤醒) { if(eNoTasksWaitingTimeout==eReturn)//这里 所有任务都无限等待 那就休眠一辈子 ,前提是 配置外部中断的线程要把配置唤醒中断的代码执行了 这样才会 {//可能产生所有任务都无限等待的情况 等待 唤醒中断发送的 系统对象 //直接进入休眠即可 printf("rn zhijie xiumian stop *rn"); SysTick->CTRL &= ~SysTick_CTRL_ENABLE_Msk; /* 关闭滴答定时器 */ //EXTI_ClearITPendingBit(EXTI_Line0); //清除中断标志位 RTC_ITConfig(RTC_IT_ALR, DISABLE);//禁止闹钟中断 直到需要时 RTC_ClearITPendingBit(RTC_IT_OW|RTC_IT_ALR|RTC_IT_SEC); //这里如果中断导致 任务切换 ,这里不会被其他任务抢占 因为 这个函数执行前 系统调度器已经被挂起 此函数执行完了 才会切换 //进入 STOPMode 低功耗模式 PWR_EnterSTOPMode(PWR_Regulator_LowPower, PWR_STOPEntry_WFE); //如果这里有中断标志 会直接跳过这天指令 //__set_PRIMASK(1); //关闭中断 一直到最后 唤醒CPU的中断还是会先执行的 然后才执行关闭中断 //portENTER_CRITICAL(); RCC_HSEConfig(RCC_HSE_ON); while (RCC_GetFlagStatus(RCC_FLAG_HSERDY) == RESET){} RCC_PLLCmd(ENABLE); while (RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET){} RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK); while (RCC_GetSYSCLKSource() != 0x08){} SysTick->CTRL |= SysTick_CTRL_ENABLE_Msk; /* 使能滴答定时器 不能再没有更新系统滴答延时就*/ //portEXIT_CRITICAL(); delay_ms_tickless_shiyong(2); printf("rn vPortMySuppressTicksAndSleep *rn"); //EXTI_ClearITPendingBit(EXTI_Line0); // __set_PRIMASK(0); //打开中断 测试下 } else { printf("rn xiu mian need dalay *rn"); //没有单独执行 全部都是 无限等待 的分支 是没有影响的,后果就是 会最大时间后唤醒一次,如果执行了这个分支 那么可实现 连续 一辈子休眠 除非有外部中断唤醒 //执行STOP休眠 /////////////////////////////////////////////////////////////////////////////////////////////////////////////// SysTick->CTRL &= ~SysTick_CTRL_ENABLE_Msk; /* 关闭滴答定时器 */ //这里提前设置好 闹钟定时 设置唤醒源 RTC_EntryAlarmMode_StopModeLowPower(xExpectedIdleTime);//休眠时间 毫秒MS为单位 //EXTI_ClearITPendingBit(EXTI_Line0); //清除中断标志位 //RTC_ClearITPendingBit(RTC_IT_OW|RTC_IT_ALR|RTC_IT_SEC); //进入 STOPMode 低功耗模式 PWR_EnterSTOPMode(PWR_Regulator_LowPower, PWR_STOPEntry_WFE); //如果这里有中断标志 会直接跳过这天指令 portENTER_CRITICAL(); //但是如果有中断标志 之前就已经执行了 所以出现此种情况的机会比较小,处理了中断 才会执行到这里 所以之前都不用 关闭总中断 //之后可以选择关闭中断 测试下 //__set_PRIMASK(1); //关闭中断 一直到最后 唤醒CPU的中断还是会先执行的 然后才执行关闭中断 //portENTER_CRITICAL(); //这里是采用的 将系统管理的 中断都给禁止了 是采用的硬件支持的 中断屏蔽寄存器的方式 如果在进入低功耗前就执行 会把闹钟中断也禁止了 就无法唤醒 所以只能在这里执行 /* 1、当一个中断或唤醒事件导致退出停止模式时, HSI RC振荡器被选为系统时钟。 2、退出低功耗的停机模式后,需要重新配置使用HSE。 */ RCC_HSEConfig(RCC_HSE_ON); while (RCC_GetFlagStatus(RCC_FLAG_HSERDY) == RESET){} RCC_PLLCmd(ENABLE); while (RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET){} RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK); while (RCC_GetSYSCLKSource() != 0x08){} /* 唤醒后 会立即执行 闹钟中断 ,然后才会从 唤醒处执行 所以需要先同步 rtc,然后才能读取 rtc值 第一: 闹钟唤醒,也是需要 得到休眠时间,然后修正 这里也可以执行一次 关闭RTC中断的代码 第二: 被其他外部中断唤醒,需要先关闭闹钟中断,读取休眠失眠 然后修正即可 所以RTC的中断代码只是防止系统跑飞,同时关闭定时器 所以总的执行流程是: 中断:只执行关闭的代码中断和清除中断标志的代码 空闲代码中: 读取当前时间,设置闹钟关闭滴答,执行休眠,......被唤醒(执行了中断代码), 进入临界段, 打开MCU外部高速时钟HSE 等待稳定可用,等待同步RTC完成,关闭RTC中断,清除RTC中断标志, 读取RTC值,计算出休眠时间(RTC CNT循环计数),修正时间,打开滴答,退出临界段 */ RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE); PWR_BackupAccessCmd(ENABLE); RTC_WaitForSynchro(); RTC_WaitForLastTask(); RTC_ITConfig(RTC_IT_ALR, DISABLE);//禁止闹钟中断 直到需要时 RTC_WaitForLastTask(); RTC_ClearITPendingBit(RTC_IT_OW|RTC_IT_ALR|RTC_IT_SEC); RTC_WaitForLastTask(); //修正 系统滴答的代码 RTC_WaitForSynchro(); t1=RTC_GetCounter();//读取 唤醒后的 RTC 及时时间点 //计算出睡眠的了多长时间 要修正到系统个任务控制块的 结构体元素中 if(t1>=t0) { tt=t1-t0; } else { tt=MAX_ALARM_TIME-t0 + t1; } if(tt>=xExpectedIdleTime) { tt=xExpectedIdleTime-1;//防止 刚刚是休眠的时间值 不知道内部是如何处理的 所以规避一下 最后一个时钟不休眠 实际是加一个时钟 } printf("rn daozheli 实际休眠值为 tt = %d rn",tt); //执行修正 这里临界执行 //portENTER_CRITICAL(); vTaskStepTick( tt );//这里面有 陷阱指令 保证 递进修正的时间只能小于 传进来需要休眠的时间 所以需要对 tt做修正 如果相等就减去 1 即可 portEXIT_CRITICAL(); SysTick->CTRL |= SysTick_CTRL_ENABLE_Msk; /* 使能滴答定时器 不能再没有更新系统滴答延时就*/ //printf("rn portEXIT_CRITICAL "); //__set_PRIMASK(0); //打开中断 测试下 } } } |
|
|
|
这是 我在 F103上移植实现的代码 经过测试 独立的 消息队列和信号量 ,在中断函数中发送都是没有问题的,任务内部信号量也是可以的; 就是 在F072上有问题
|
|
|
|
只有小组成员才能发言,加入小组>>
663 浏览 0 评论
1083 浏览 1 评论
2456 浏览 5 评论
2784 浏览 9 评论
移植了freeRTOS到STMf103之后显示没有定义的原因?
2619 浏览 6 评论
使用eim外接fpga可是端口一点反应都没有有没有大哥指点一下啊
639浏览 9评论
636浏览 7评论
请教大神怎样去解决iMX6Q在linux3.0.35内核上做AP失败的问题呢
766浏览 6评论
610浏览 5评论
651浏览 5评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-11-10 15:11 , Processed in 0.751498 second(s), Total 52, Slave 44 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号