当前位置: 首页 > news >正文

STM32中用 stop 模式 配合低功耗模式下的自动唤醒(AWU) 能否实现FreeRTOS tickless 模式...

已经实现  ,2018年11月17日11:56:42,具体 如下:

第一步 : 修改 void vPortSetupTimerInterrupt( void ) 函数 ,修改原来的 systick 定时器初始化 改为  RTC 初始化 

    void vPortSetupTimerInterrupt( void )
    {
        NVIC_InitTypeDef NVIC_InitStructure;
        EXTI_InitTypeDef EXTI_InitStructure;
    
            /* Enable PWR and BKP clocks */  /* PWR时钟(电源控制)与BKP时钟(RTC后备寄存器)使能 */  
        RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE);
        
        /* Allow access to BKP Domain */ /*使能RTC和后备寄存器访问 */  
        PWR_BackupAccessCmd(ENABLE);

        RCC_LSICmd(ENABLE); /* 使能内部32.768K时钟 */

        /* 等待内部32.768K时钟就绪 */
        while(RCC_GetFlagStatus(RCC_FLAG_LSIRDY) == RESET);
        
        /* 选择内部32.768K时钟为RTC时钟 */
        RCC_RTCCLKConfig(RCC_RTCCLKSource_LSI);
        
        /* Set RTC prescaler: set RTC period to 1 millisecond */   
        /* suozhang,使用外部32.768K晶振,设置32分频,计数1024次为1S,2018年11月15日09:28:52 */ 
        RTC_SetPrescaler( 40 );

        /* Enable the RTC Interrupt */
    NVIC_InitStructure.NVIC_IRQChannel = RTC_IRQn;                                                                                    
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = configKERNEL_INTERRUPT_PRIORITY;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;                     
    NVIC_Init(&NVIC_InitStructure);
    
        /* Enable the RTC Alarm Interrupt */
        NVIC_InitStructure.NVIC_IRQChannel = RTCAlarm_IRQn;
        NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = configKERNEL_INTERRUPT_PRIORITY;
        NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
        NVIC_Init(&NVIC_InitStructure);  
  
        //闹钟中断接到第17线外部中断
   EXTI_ClearITPendingBit(EXTI_Line17);
    
   EXTI_InitStructure.EXTI_Line = EXTI_Line17;
   EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
   EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising;
   EXTI_InitStructure.EXTI_LineCmd = ENABLE;
   EXTI_Init(&EXTI_InitStructure);
     
        /* 使能电源管理时钟 */
         RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR , ENABLE);
     
         /* Enable RTC Clock */
        RCC_RTCCLKCmd(ENABLE);
        /* Wait until last write operation on RTC registers has finished */
        RTC_WaitForLastTask();
        
        /* 使能RTC根据选择的时钟源以及分频值的设置产生的定时中断,当做FreeRTOS时钟源 */
        RTC_ITConfig(RTC_IT_SEC, ENABLE);
        RTC_WaitForLastTask();
        
    }

第二步:增加 RTC 中断服务函数

 

void RTCAlarm_IRQHandler( void )
{
    //必须加上这个中断服务函数,否则RTC闹钟唤醒后,只能执行中断服务函数,suozhang,2018年11月15日13:47:34
}

void RTC_IRQHandler( void )
{
    
 if(RTC_GetITStatus(RTC_IT_SEC)!= RESET)//RTC定时中断
 {
        RTC_WaitForLastTask();
        RTC_ClearITPendingBit(RTC_IT_SEC);  //清除RTC定时中断
     
        /* 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();
        {
            /* 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;
            }
        }
        vPortClearBASEPRIFromISR();
 
 }

 if(RTC_GetITStatus(RTC_IT_ALR)!= RESET)//闹钟中断
 {
        RTC_WaitForLastTask();
        RTC_ClearITPendingBit(RTC_IT_ALR);  //清闹钟中断

        RTC_WaitForLastTask();
        EXTI_ClearITPendingBit(EXTI_Line17);

        if(PWR_GetFlagStatus(PWR_FLAG_WU) != RESET)
        {
            RTC_WaitForLastTask();
            PWR_ClearFlag(PWR_FLAG_WU); //清自动唤醒中断( AWU )
        }
 }    
            
}

 

第三步:因为要实现 tickless 模式,因此要实现 void vPortSuppressTicksAndSleep( TickType_t xExpectedIdleTime ) 这个函数接口

 void vPortSuppressTicksAndSleep( TickType_t xExpectedIdleTime )
    {
    uint32_t ulReloadValue, ulCompleteTickPeriods, ulCompletedSysTickDecrements;
    TickType_t xModifiableIdleTime;
        
        uint32_t exitTime = 0;

        /* 停止RTC产生 1ms 的定时中断 */     
        RTC_ITConfig(RTC_IT_SEC, DISABLE);    
        /* Wait until last write operation on RTC registers has finished */
        RTC_WaitForLastTask();

        /* Calculate the reload value required to wait xExpectedIdleTime
        tick periods.  -1 is used because this code will execute part way
        through one of the tick periods. */
        //根据参数xExpectIdleTime来计算滴答定时器的重载值,进入低功耗之后,计时由滴答定时器计算。
        ulReloadValue = xExpectedIdleTime - 1UL ;

        if( ulReloadValue > ulStoppedTimerCompensation )
        {
            ulReloadValue -= ulStoppedTimerCompensation;//上面已经停止RTC了,下面一直到启动RTC闹钟的 程序运行时间补偿,小于1mS,因此这里为0
        }

        /* Enter a critical section but don't use the taskENTER_CRITICAL()
        method as that will mask interrupts that should exit sleep mode. */
        __disable_irq();
        __dsb( portSY_FULL_READ_WRITE );
        __isb( portSY_FULL_READ_WRITE );

        /* If a context switch is pending or a task is waiting for the scheduler
        to be unsuspended then abandon the low power entry. */
        if( eTaskConfirmSleepModeStatus() == eAbortSleep )
        {

            /* 再次启动 RTC产生 1ms 的定时中断*/
            RTC_ITConfig(RTC_IT_SEC, ENABLE);

            /* Re-enable interrupts - see comments above __disable_irq() call
            above. */
            __enable_irq();
        }
        else
        {
            /* RTC 计数器清0 */
            RTC_SetCounter( 0 );
            /* Wait until last write operation on RTC registers has finished */
            RTC_WaitForLastTask();
            
            /* RTC 计数器清0 */    
            RTC_SetAlarm( ulReloadValue ); // 设置经过ulReloadValue 计时后,产生闹钟
            /* Wait until last write operation on RTC registers has finished */
            RTC_WaitForLastTask();
            
            RTC_ClearITPendingBit(RTC_IT_ALR);  //清闹钟中断
            /* Wait until last write operation on RTC registers has finished */
            RTC_WaitForLastTask();
            
            PWR_ClearFlag(PWR_FLAG_WU); //清自动唤醒中断( AWU )
            /* Wait until last write operation on RTC registers has finished */
            RTC_WaitForLastTask();
            
            /* 启动 RTC 闹钟中断. */
            RTC_ITConfig(RTC_IT_ALR, ENABLE);
            /* Wait until last write operation on RTC registers has finished */
            RTC_WaitForLastTask();
            
            /* Sleep until something happens.  configPRE_SLEEP_PROCESSING() can
            set its parameter to 0 to indicate that its implementation contains
            its own wait for interrupt or wait for event instruction, and so wfi
            should not be executed again.  However, the original expected idle
            time variable must remain unmodified, so a copy is taken. */
            xModifiableIdleTime = xExpectedIdleTime;
            configPRE_SLEEP_PROCESSING( xModifiableIdleTime );
            if( xModifiableIdleTime > 0 )
            {
                __enable_irq();
                PWR_EnterSTOPMode(PWR_Regulator_LowPower, PWR_STOPEntry_WFE);//进入停止模式
            }
            configPOST_SLEEP_PROCESSING( xExpectedIdleTime );
            
            /* 关闭 RTC 闹钟中断. */
            RTC_ITConfig(RTC_IT_ALR, DISABLE);
            
            /* 再次启动 RTC产生 1ms 的定时中断*/
            RTC_ITConfig(RTC_IT_SEC, ENABLE);
            
            /* Re-enable interrupts to allow the interrupt that brought the MCU
            out of sleep mode to execute immediately.  see comments above
            __disable_interrupt() call above. */
            __enable_irq();
            __dsb( portSY_FULL_READ_WRITE );
            __isb( portSY_FULL_READ_WRITE );

            /* Disable interrupts again because the clock is about to be stopped
            and interrupts that execute while the clock is stopped will increase
            any slippage between the time maintained by the RTOS and calendar
            time. */
            __disable_irq();
            __dsb( portSY_FULL_READ_WRITE );
            __isb( portSY_FULL_READ_WRITE );
            
            /* 读取RTC计数值,用于补偿真正的系统时间,有可能其他事件唤醒,而不是闹钟唤醒,2018年11月16日11:07:31,suozhang */
            exitTime = RTC_GetCounter();
            /* Wait until last write operation on RTC registers has finished */
            RTC_WaitForLastTask();
                
            if( exitTime )
                vTaskStepTick(exitTime-0); //补偿真正的系统时间,进入闹钟定时之前,已经把计数器清0 因此这里减0

            /* Restart SysTick so it runs from portNVIC_SYSTICK_LOAD_REG
            again, then set portNVIC_SYSTICK_LOAD_REG back to its standard
            value. */

            /* Exit with interrpts enabled. */
            __enable_irq();
        }
    }

 

 

最后  有 两个 函数 说明一下:

         configPRE_SLEEP_PROCESSING( xModifiableIdleTime );  // 进入低功耗之前 要执行的函数,用户可自定义!
         configPOST_SLEEP_PROCESSING( xExpectedIdleTime );   // 退出低功耗 第一个 执行的函数,用户可自定义!
 
最后测试一下: 测试代码 如下
void vLedTask( void *pvParameters )
{
    
    for(;;)
    {

            //PC13 LED1 
            bsp_LedToggle(1);
        
            vTaskDelay( 1000*5 ); 


    }
}

功耗测试结果 如下:  5S 高电流 即 LED 点亮时间, 5S低电流 是 13uA  正好达到裸机 进入 STOP 模式 的电流!

 

 

 

转载于:https://www.cnblogs.com/suozhang/p/9946097.html

相关文章:

  • ECMAScript中所有的函数的参数都是按值传递的
  • 《快学 Go 语言》第 3 课 —— 分支与循环
  • spark中的动态executor分配
  • zeroclipboard无法正常使用的解决办法
  • Sublime Text 2 安装Package Control和插件的两种方法
  • SpringBoot整合RabbitMQ之典型应用场景实战一
  • MetaMask/provider-engine-3-test
  • Http长连接200万尝试及调优
  • 压缩图片C#算法
  • SSM框架pom.xml的配置
  • unrecognized import path golang.org/x/sync
  • 〔开发系列〕一次关于小程序开发的深度总结
  • [译]2.1-Key-Value Coding Programming Guide 官方文档第二部分
  • Oracle 11g win32位 window7下安装教程
  • C++容器
  • docker容器内的网络抓包
  • ES6核心特性
  • PhantomJS 安装
  • Python实现BT种子转化为磁力链接【实战】
  • rabbitmq延迟消息示例
  • React-生命周期杂记
  • Service Worker
  • Webpack 4x 之路 ( 四 )
  • -- 查询加强-- 使用如何where子句进行筛选,% _ like的使用
  • 成为一名优秀的Developer的书单
  • 学习ES6 变量的解构赋值
  • 再谈express与koa的对比
  • 正则学习笔记
  • 正则表达式-基础知识Review
  • #每天一道面试题# 什么是MySQL的回表查询
  • (1)(1.13) SiK无线电高级配置(五)
  • (2)MFC+openGL单文档框架glFrame
  • (4.10~4.16)
  • (react踩过的坑)antd 如何同时获取一个select 的value和 label值
  • (TipsTricks)用客户端模板精简JavaScript代码
  • (附源码)springboot电竞专题网站 毕业设计 641314
  • (附源码)计算机毕业设计ssm本地美食推荐平台
  • (论文阅读26/100)Weakly-supervised learning with convolutional neural networks
  • (十)DDRC架构组成、效率Efficiency及功能实现
  • (一)基于IDEA的JAVA基础10
  • (转)shell调试方法
  • (转)创业家杂志:UCWEB天使第一步
  • (转载)Linux网络编程入门
  • .FileZilla的使用和主动模式被动模式介绍
  • .gitignore文件---让git自动忽略指定文件
  • .NET gRPC 和RESTful简单对比
  • .NET 使用 ILMerge 合并多个程序集,避免引入额外的依赖
  • /deep/和 >>>以及 ::v-deep 三者的区别
  • :中兴通讯为何成功
  • @RequestBody与@ModelAttribute
  • [.net 面向对象程序设计进阶] (19) 异步(Asynchronous) 使用异步创建快速响应和可伸缩性的应用程序...
  • [2010-8-30]
  • [2016.7.test1] T2 偷天换日 [codevs 1163 访问艺术馆(类似)]
  • [ARM]ldr 和 adr 伪指令的区别
  • [AutoSar]BSW_OS 02 Autosar OS_STACK