[其他ST产品] STM32通用低功耗组件——PM

[复制链接]
3818|47
 楼主| 欢乐家园 发表于 2022-4-29 14:53 | 显示全部楼层
在空闲线程中
会调用rt_system_power_manager接口来进入低功耗模式:
75126626b8b645e06a.png
 楼主| 欢乐家园 发表于 2022-4-29 14:54 | 显示全部楼层
  1. /**
  2. * This function will enter corresponding power mode.
  3. */
  4. void rt_system_power_manager(void)
  5. {
  6.     rt_uint8_t mode;

  7.     if (_pm_init_flag == 0)
  8.         return;

  9.     /* CPU frequency scaling according to the runing mode settings */
  10.     _pm_frequency_scaling(&_pm);

  11.     /* Low Power Mode Processing */
  12.     mode = _pm_select_sleep_mode(&_pm);
  13.     _pm_change_sleep_mode(&_pm, mode);
  14. }
 楼主| 欢乐家园 发表于 2022-4-29 14:55 | 显示全部楼层
保存后,可以看到pm.c已经被添加到了工程:
67037626b8bbb30b79.png
然后添加PM组件的设备驱动,驱动的最新地址:pm-ports-stm32-new 分支:https://gitee.com/sunwancn/rt-thread/tree/pm-ports-stm32-new注意: 目前所使用的驱动不是最新版本,移植请到gitee下载最新pm驱动。
 楼主| 欢乐家园 发表于 2022-4-29 14:55 | 显示全部楼层
从\rt-thread\bsp\stm32\libraries\HAL_Drivers,拷贝如下四个文件到工程的drivers文件夹下:
23412626b8bf4aabb5.png
 楼主| 欢乐家园 发表于 2022-4-29 14:56 | 显示全部楼层
本项目选择的是使用RTC作为STOP后的时间补偿,所以需要打开rtc设备和所使用的宏:
91519626b8c1db1708.png
注: 如果没有使用RTT的自身的RTC函数的话,前面2个宏可以不要。
 楼主| 欢乐家园 发表于 2022-4-29 14:57 | 显示全部楼层
  1. 应用示例:此程序主要实现开机后经过10秒后进入 STOP 模式,然后每经过5秒 SLEEP 模式和 STOP 模式互相切换,如此循环往复,同时经过一个循环后,切换 MCU 的运行频率,验证运行的稳定性。并且打开了回调和中断唤醒,在进入睡眠和唤醒后会分别熄灭和点亮LED灯,在睡眠时间可以通过外部中断唤醒:

  2. /*
  3. * Copyright (c) 2006-2018, RT-Thread Development Team
  4. *
  5. * SPDX-License-Identifier: Apache-2.0
  6. *
  7. * Change Logs:
  8. * Date           Author       Notes
  9. * 2018-11-06     SummerGift   first version
  10. */

  11. #include
  12. #include
  13. #include
  14. #include
  15. #define LOG_TAG             'PM.test'
  16. #define LOG_LVL             LOG_LVL_DBG
  17. #include
  18. /* defined the LED0 pin: PB13 */
  19. #define LED0_PIN   GET_PIN(C, 6)
  20. #define MCU_IRQ_WAKE_PIN   GET_PIN(C, 9)
  21. static RTC_HandleTypeDef hrtc;
  22. static RTC_TimeTypeDef curtime = {0};
  23. static RTC_TimeTypeDef alarmtime = {0};
  24. static RTC_AlarmTypeDef alarm = {0};
  25. static struct rt_semaphore  wake_sem;
  26. static rt_uint8_t sleep_mode = PM_SLEEP_MODE_DEEP; /* STOP 模式 */

  27. static rt_uint8_t run_mode = PM_RUN_MODE_NORMAL_SPEED;

  28. static rt_uint32_t get_interval(void);
  29. static void get_rtc_time(RTC_TimeTypeDef *time);
  30. static rt_uint8_t mode_loop(void);
  31. static rt_uint8_t issleep = 0;
  32. /* 中断回调函数 */
  33. static void MCU_IRQ_WAKE(void *args)
  34. {

  35.    if(issleep)
  36.   {
  37.        rt_kprintf('MCU_IRQ_WAKE!\n');
  38.        rt_sem_release(&wake_sem);
  39.        issleep = 0;
  40.   }

  41. }
  42. static void pm_botify(uint8_t event, uint8_t mode, void *data)
  43. {

  44.    if(event == RT_PM_ENTER_SLEEP && mode == PM_SLEEP_MODE_DEEP)
  45.   {
  46.        rt_pin_write(LED0_PIN, PIN_HIGH);
  47.        issleep = 1;
  48.   }
  49.    else if (event == RT_PM_EXIT_SLEEP && mode == PM_SLEEP_MODE_DEEP )
  50.   {
  51.        rt_pin_write(LED0_PIN, PIN_LOW);
  52.   }
  53. }

  54. int pm_test(void)
  55. {
  56.    hrtc.Instance = RTC;

  57.    rt_sem_init(&wake_sem, 'wake_sem', 0, RT_IPC_FLAG_FIFO);
  58.    rt_pm_notify_set(pm_botify,0);
  59.    /* 按键0引脚为输入模式 */
  60.    rt_pin_mode(MCU_IRQ_WAKE_PIN, PIN_MODE_INPUT_PULLDOWN);
  61.    /* 绑定中断,上升沿模式,回调函数名为beep_on */
  62.    rt_pin_attach_irq(MCU_IRQ_WAKE_PIN, PIN_IRQ_MODE_RISING, MCU_IRQ_WAKE, RT_NULL);
  63.    /* 使能中断 */
  64.    rt_pin_irq_enable(MCU_IRQ_WAKE_PIN, PIN_IRQ_ENABLE);

  65.    rt_thread_mdelay(10000);


  66. #ifdef RT_USING_PM
  67.    /* 申请低功耗模式 */
  68.    rt_pm_request(sleep_mode);
  69. #endif

  70.    get_rtc_time(&curtime);

  71.    if (sleep_mode == PM_SLEEP_MODE_STANDBY)
  72.   {
  73.        /* 设置休眠,闹钟 20 秒后唤醒,简化版闹钟,只支持 1分钟内有效 */
  74.        alarmtime.Hours = curtime.Hours;
  75.        alarmtime.Minutes = curtime.Minutes;
  76.        alarmtime.SubSeconds = curtime.SubSeconds;
  77.        alarmtime.Seconds = curtime.Seconds + 20;
  78.        if (alarmtime.Seconds >= 60)
  79.       {
  80.            alarmtime.Seconds -= 60;
  81.            alarmtime.Minutes ++;
  82.            if (alarmtime.Minutes >= 60)
  83.                alarmtime.Minutes -= 60;
  84.       }

  85.        alarm.Alarm = RTC_ALARM_A;
  86.        alarm.AlarmTime = alarmtime;
  87.        alarm.AlarmTime.DayLightSaving = RTC_DAYLIGHTSAVING_NONE;
  88.        alarm.AlarmTime.StoreOperation = RTC_STOREOPERATION_RESET;
  89.        alarm.AlarmMask = RTC_ALARMMASK_DATEWEEKDAY | RTC_ALARMMASK_HOURS;
  90.        alarm.AlarmSubSecondMask = RTC_ALARMSUBSECONDMASK_NONE;
  91.        alarm.AlarmDateWeekDaySel = RTC_ALARMDATEWEEKDAYSEL_DATE;
  92.        alarm.AlarmDateWeekDay = 0x1;

  93.        /* 开启闹钟 */
  94.        HAL_RTC_SetAlarm_IT(&hrtc, &alarm, RTC_FORMAT_BIN);
  95.   }

  96.    while (1)
  97.   {
  98.        /* 开始进入低功耗模式 */
  99.        rt_sem_take(&wake_sem, rt_tick_from_millisecond(5000));

  100.        /* 退出低功耗模式 */
  101.        rt_kprintf('Sleep %d ms\n', get_interval());

  102. #ifdef RT_USING_PM
  103.        /* 申请正常模式 */
  104.        rt_pm_request(PM_SLEEP_MODE_NONE);
  105. #endif

  106.        rt_thread_mdelay(5000);

  107.        rt_kprintf('Wakeup %d ms\n', get_interval());

  108.        /* 运行模式切换 */
  109.        rt_pm_run_enter(mode_loop());

  110. #ifdef RT_USING_PM
  111.        rt_pm_release(PM_SLEEP_MODE_NONE);
  112. #endif
  113.   }

  114.    return RT_EOK;
  115. }
  116. //MSH_CMD_EXPORT(pm_test, PM TEST);

  117. static rt_uint32_t get_interval(void)
  118. {
  119.    rt_uint32_t seconds;

  120.    rt_uint32_t last_seconds = curtime.Seconds;
  121.    rt_uint32_t last_subseconds = curtime.SubSeconds;

  122.    get_rtc_time(&curtime);

  123.    if (curtime.Seconds < last_seconds)
  124.        seconds = 60 + curtime.Seconds - last_seconds;
  125.    else
  126.        seconds = curtime.Seconds - last_seconds;

  127.    return (rt_uint32_t)(seconds * 1000 + ((int32_t)last_subseconds - (int32_t)curtime.SubSeconds) * 1000 \
  128.                         / (int32_t)(((RTC->PRER & RTC_PRER_PREDIV_S) >> RTC_PRER_PREDIV_S_Pos) + 1U));
  129. }

  130. static void get_rtc_time(RTC_TimeTypeDef *time)
  131. {
  132.    rt_uint32_t st, datetmpreg;

  133.    HAL_RTC_GetTime(&hrtc, time, RTC_FORMAT_BIN);
  134.    datetmpreg = RTC->DR;
  135.    if (HAL_RCC_GetPCLK1Freq() < 32000U * 7U)
  136.   {
  137.        st = time->SubSeconds;
  138.        HAL_RTC_GetTime(&hrtc, time, RTC_FORMAT_BIN);
  139.        datetmpreg = RTC->DR;

  140.        if (st != time->SubSeconds)
  141.       {
  142.            HAL_RTC_GetTime(&hrtc, time, RTC_FORMAT_BIN);
  143.            datetmpreg = RTC->DR;
  144.       }
  145.   }
  146.   (void)datetmpreg;
  147. }

  148. rt_uint8_t mode_loop(void)
  149. {
  150.    rt_uint8_t mode = 1;

  151.    run_mode++;
  152.    switch (run_mode)
  153.   {
  154.    case 0:
  155.    case 1:
  156.    case 2:
  157.    case 3:
  158.        mode = run_mode;
  159.        break;
  160.    case 4:
  161.        mode = 2;
  162.        break;
  163.    case 5:
  164.        mode = 1;
  165.        break;
  166.    case 6:
  167.        mode = run_mode = 0;
  168.        break;
  169.   }

  170.    return mode;
  171. }
 楼主| 欢乐家园 发表于 2022-4-29 14:58 | 显示全部楼层
运行效果:

63385626b8c7fa7b01.png
foxsbig 发表于 2022-5-3 08:55 | 显示全部楼层
怎么个通用法呢
您需要登录后才可以回帖 登录 | 注册

本版积分规则

快速回复 在线客服 返回列表 返回顶部