近期 RT-Thread 工程師完成了基于瑞薩CPK-RA2L1 開發(fā)板的BSP適配,支持了GPIO、UART、I2C、SPI、ADC、DAC、PWM、CAN、on-chip Flash、Watchdog、RTC等外設驅(qū)動,并在瑞薩工程師支持下完成了電源組件(低功耗LPM)適配,經(jīng)實際測量,芯片在Software Standby階段可達到的最低平均電流約為0.696uA,本篇筆記記錄低功耗的適配和應用。

可通過以下鏈接查看RA MCU BSP:
https://github.com/RT-Thread/rt-thread/tree/master/bsp/renesas
瑞薩 RA 系列 MCU 開發(fā)板的 BSP 制作教程:
https://www.rt-thread.org/document/site/#/rt-thread-version/rt-thread-standard/tutorial/make-bsp/renesas-ra/RA%E7%B3%BB%E5%88%97BSP%E5%88%B6%E4%BD%9C%E6%95%99%E7%A8%8B
在開始介紹低功耗前,先了解一下 RA2L1 MCU 產(chǎn)品群關(guān)鍵特性
-
支持1.6V-5.5V寬范圍工作電壓
-
超低功耗,提供64μA/MHz工作電流和250nA軟件待機電流,快速喚醒時間小于5μs
-
采用瑞薩110nm低功耗工藝,用于運行和睡眠/待機模式,并且專門為電池驅(qū)動應用設計了特殊掉電模式
-
靈活的供電模式可實現(xiàn)更低的平均功耗,以滿足多種應用需求
-
后臺運行的數(shù)據(jù)閃存,支持一百萬次擦除/編程循環(huán)
-
采用LQFP封裝,產(chǎn)品涵蓋48引腳至100引腳封裝
低功耗基礎(chǔ)
低功耗的本質(zhì)是系統(tǒng)空閑時 CPU 停止工作,中斷或事件喚醒后繼續(xù)工作。在 RTOS 中,通常包含一個 IDLE 任務,該任務的優(yōu)先級最低且一直保持就緒狀態(tài),當高優(yōu)先級任務未就緒時,OS 執(zhí)行 IDLE 任務。一般地,未進行低功耗處理時,CPU 在 IDLE 任務中循環(huán)執(zhí)行空指令。RT-Thread 的電源管理組件在 IDLE 任務中,通過對 CPU 、時鐘和設備等進行管理,從而有效降低系統(tǒng)的功耗。

在上圖所示,當高優(yōu)先級任務運行結(jié)束或被掛起時,系統(tǒng)將進入 IDLE 任務中。在 IDLE 任務執(zhí)行后,它將判斷系統(tǒng)是否可以進入到休眠狀態(tài)(以節(jié)省功耗)。如果可以進入休眠, 將根據(jù)芯片情況關(guān)閉部分硬件模塊,OS Tick 也非常有可能進入暫停狀態(tài)。此時電源管理框架會根據(jù)系統(tǒng)定時器情況,計算出下一個超時時間點,并設置低功耗定時器,讓設備能夠在這個時刻點喚醒,并進行后續(xù)的工作。當系統(tǒng)被(低功耗定時器中斷或其他喚醒中斷源)喚醒后,系統(tǒng)也需要知道睡眠時間長度是多少,并對OS Tick 進行補償,讓系統(tǒng)的OS tick值調(diào)整為一個正確的值。
PM組件
PM組件是RT-Thread系統(tǒng)中針對電源管理而設計的基礎(chǔ)功能組件, 組件采用分層設計思想,分離架構(gòu)和芯片相關(guān)的部分,提取公共部分作為核心。支持多種運行模式和休眠模式的管理切換,以及低功耗定時器的管理。
PM 組件有以下特點:
-
PM 組件是基于模式來管理功耗
-
PM 組件可以根據(jù)模式自動更新設備的頻率配置,確保在不同的運行模式都可以正常工作
-
PM 組件可以根據(jù)模式自動管理設備的掛起和恢復,確保在不同的休眠模式下可以正確的掛起和恢復
-
PM 組件支持可選的休眠時間補償,讓依賴 OS Tick 的應用可以透明使用
-
PM 組件向上層提供設備接口,如果使用了設備文件系統(tǒng)組件,那么也可以用文件系統(tǒng)接口來訪問
PM組件支持的休眠模式有

RA系列LPM功能
RA2 MCU支持的LPM類型有:
-
Sleep mode
-
Software Standby mode
-
Snooze mode

低功耗模式轉(zhuǎn)換和觸發(fā)源如圖所示:

不同模式間的切換如圖所示,從圖中也可以看出三種模式的功耗關(guān)系是Sleep>Snooze>Standby。
RA2芯片的休眠模式對應PM組件的模式關(guān)系:

配置LPM功能
要使用RA2系列芯片的LPM功能,需要進入bsp enesas a2l1-cpk目錄。
-
在menuconfig中使能LPM驅(qū)動,并勾選要開啟的休眠模式,然后保存配置,生成MDK5工程。

-
打開PM組件和驅(qū)動后,需要增加idle的線程棧大小,可改為1024。

-
打開生成的MDK5工程project.uvprojx,然后打開FSP配置工具添加LPM相關(guān)配置。下圖是需要添加的stack,包括三種LPM模式的配置以及低功耗定時器AGT1。

-
創(chuàng)建LPM如下圖所示新建r_lpm,需要根據(jù)使用的模式進行配置且不同模式要創(chuàng)建不同的r_lpm。下面將分別介紹三種不同模式的配置,創(chuàng)建步驟就不再贅述。

Sleep mode休眠模式
創(chuàng)建出r_lpm后需要修改Name和Low Power Mode這兩個配置項。Name需要改為g_lpm_sleep,因為在驅(qū)動文件中已經(jīng)定義了sleep模式對應的stack名稱。Low Power Mode選擇Sleep mode即可。

Standby mode軟件待機模式
Name需要改為g_lpm_sw_standby。Low Power Mode選擇Software Standby mode即可。
另外在此模式下還需要配置喚醒MCU的中斷源,因為會使用到AGT1做為低功耗定時器所以AGT1的中斷需要勾選。如果在應用中還需要其他中斷源在此模式下喚醒MCU,則勾選對應選項即可。

Snooze mode小睡模式
Name需要改為g_lpm_sw_standby_with_snooze。Low Power Mode選擇Snooze mode即可。
另外在此模式下同樣要配置喚醒MCU的中斷源,因為會使用到AGT1做為低功耗定時器所以AGT1的中斷需要勾選。如果在應用中還需要其他中斷源在此模式下喚醒MCU,則勾選對應選項即可。

AGT1低功耗定時器
在驅(qū)動中使用了MCU的AGT1做為PM組件的低功耗定時器,用于在休眠狀態(tài)下的系統(tǒng)時鐘補償。

完成上述配置步驟就已經(jīng)把LPM低功耗模式的相關(guān)配置做完了。然后再根據(jù)應用要實現(xiàn)的功能配置其他外設。
低功耗DEMO
上文介紹了在RT-Thread的RA2L1上怎么配置LPM的不同模式,接下來就用一個小DEMO來驗證下MCU在各種模式下的工作情況。
低功耗DEMO要實現(xiàn)的功能是,在CPK-RA2L1開發(fā)板上用S1按鈕切換不同的低功耗模式,并在msh中打印出模式切換的提示信息。要實現(xiàn)這個功能需要在剛才的基礎(chǔ)上添加一個低功耗的喚醒源。
添加配置
-
創(chuàng)建IRQ中斷,IRQ中斷選擇通道3,詳細配置如下。



-
在剛才的Snooze和Standby模式的配置里添加IRQ3的喚醒源



-
然后保存并生成配置代碼。
添加測試代碼
#include#ifdef BSP_USING_LPM#include#include#include#define WAKEUP_APP_THREAD_STACK_SIZE 512#define WAKEUP_APP__THREAD_PRIORITY RT_THREAD_PRIORITY_MAX / 3#define WAKEUP_EVENT_BUTTON (1 << 0)static rt_event_t wakeup_event;#define USER_INPUT "P004"#define LED2_PIN "P501" /* Onboard LED pins */void rt_lptimer_init(rt_lptimer_t timer,const char *name,void (*timeout)(void *parameter),void *parameter,rt_tick_t time,rt_uint8_t flag);rt_err_t rt_lptimer_detach(rt_lptimer_t timer);rt_err_t rt_lptimer_start(rt_lptimer_t timer);rt_err_t rt_lptimer_stop(rt_lptimer_t timer);rt_err_t rt_lptimer_control(rt_lptimer_t timer, int cmd, void *arg);static struct rt_lptimer lptimer;static void timeout_cb(void *parameter){rt_interrupt_enter();rt_kprintf(" lptimer callback ");rt_interrupt_leave();}static void lptimer_init(void){rt_lptimer_init(&lptimer,"lpm",timeout_cb,(void*)&wakeup_event,1000,RT_TIMER_FLAG_PERIODIC);}static void lptimer_stop(void){rt_lptimer_stop(&lptimer);}static void lptimer_start(void){rt_lptimer_start(&lptimer);}static void led_app(void){static uint8_t key_status = 0x00;rt_uint32_t led2_pin = rt_pin_get(LED2_PIN);rt_pin_write(led2_pin, PIN_HIGH);switch(key_status%4){case 0:/* IDLE */lptimer_stop();rt_pm_release(PM_SLEEP_MODE_NONE);rt_kprintf(" request:IDLE ");rt_pm_request(PM_SLEEP_MODE_IDLE);break;case 1:/* DEEP */lptimer_stop();lptimer_start();rt_pm_release(PM_SLEEP_MODE_IDLE);rt_kprintf(" request:DEEP ");rt_pm_request(PM_SLEEP_MODE_DEEP);break;case 2:/* STANDBY */lptimer_stop();lptimer_start();rt_pm_release(PM_SLEEP_MODE_DEEP);rt_kprintf(" request:STANDBY ");rt_pm_request(PM_SLEEP_MODE_STANDBY);break;case 3:/* NONE */lptimer_stop();rt_pm_release(PM_SLEEP_MODE_STANDBY);rt_kprintf(" request:NONE ");rt_pm_request(PM_SLEEP_MODE_NONE);break;default:break;}key_status++;rt_pin_write(led2_pin, PIN_LOW);}static void wakeup_callback(void* p){rt_event_send(wakeup_event, WAKEUP_EVENT_BUTTON);}void wakeup_sample(void){/* init */rt_uint32_t pin = rt_pin_get(USER_INPUT);rt_kprintf(" pin number : 0x%04X ", pin);rt_err_t err = rt_pin_attach_irq(pin, PIN_IRQ_MODE_RISING, wakeup_callback, RT_NULL);if (RT_EOK != err){rt_kprintf(" attach irq failed. ");}err = rt_pin_irq_enable(pin, PIN_IRQ_ENABLE);if (RT_EOK != err){rt_kprintf(" enable irq failed. ");}}static void wakeup_init(void){wakeup_event = rt_event_create("wakup", RT_IPC_FLAG_FIFO);RT_ASSERT(wakeup_event != RT_NULL);wakeup_sample();}static void pm_mode_init(void){rt_pm_release_all(RT_PM_DEFAULT_SLEEP_MODE);rt_pm_request(PM_SLEEP_MODE_NONE);}void pm_test_entry(void* para){/* 喚醒回調(diào)函數(shù)初始化 */wakeup_init();/* 電源管理初始化 */pm_mode_init();lptimer_init();while (1){/* 等待喚醒事件 */if (rt_event_recv(wakeup_event,WAKEUP_EVENT_BUTTON,RT_EVENT_FLAG_AND | RT_EVENT_FLAG_CLEAR,RT_WAITING_FOREVER, RT_NULL) == RT_EOK){led_app();}}}int pm_test(void){rt_thread_t tid = rt_thread_create("pmtest",pm_test_entry,RT_NULL,512,10,10);if(tid)rt_thread_startup(tid);return 0;}MSH_CMD_EXPORT(pm_test, pm_test);// INIT_APP_EXPORT(pm_test);#endif
將DEMO代碼加入到工程中,可以直接添加到hal_entry.c或新建一個源文件。
測試驗證
然后編譯下載。開發(fā)板連接串口工具,輸入pm_test命令啟動測試DEMO。
按下S1按鈕切換工作模式,在DEEP、STANDBY模式下會啟動低功耗定時器,當定時喚醒后會打印出回調(diào)接口的提示信息。

經(jīng)測試:
(1)串口通中輸入“pm_test”,觀測到電流在8.6mA和5.8mA之間變化。
(2)按下S1后,串口通中打印信息為“requestIDLE”,此時電流約為2.2mA。
(3)再次按下S1后,串口通中打印信息為“requestDEEP”,此時電流約為1593uA,并間隔產(chǎn)生lptimer中斷。
(4)再次按下S1后,串口通中打印信息為“requestSTANDBY”,此時電流約為2.4uA,并間隔產(chǎn)生lptimer中斷。
(5)再次按下S1后,串口通中打印信息為“requestNONE”,恢復為(1)的電流值,然后可循環(huán)執(zhí)行此流程。
-
mcu
+關(guān)注
關(guān)注
147文章
18924瀏覽量
398050 -
瑞薩
+關(guān)注
關(guān)注
37文章
22481瀏覽量
90862 -
RT-Thread
+關(guān)注
關(guān)注
32文章
1613瀏覽量
44868
原文標題:基于瑞薩 RA2L1 MCU 的RT-Thread 低功耗應用筆記
文章出處:【微信號:RTThread,微信公眾號:RTThread物聯(lián)網(wǎng)操作系統(tǒng)】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。
發(fā)布評論請先 登錄
RT-Thread編程指南
RT-Thread用戶手冊
STM32超低功耗之移植 RT-Thread PM 組件原理分析
RT-Thread全球技術(shù)大會:螢石研發(fā)團隊使用RT-Thread的技術(shù)挑戰(zhàn)
RT-Thread全球技術(shù)大會:Kconfig在RT-Thread中的工作機制
RT-Thread全球技術(shù)大會:關(guān)于瑞薩RA2L1-CPK低功耗CPU演示
RT-Thread學習筆記 RT-Thread的架構(gòu)概述
RT-Thread文檔_RT-Thread 潘多拉 STM32L475 上手指南
RT-Thread v5.0.2 發(fā)布
RT-Thread低功耗的適配和應用
評論