KL25利用低功耗定時器進行MCU低功耗喚醒
轉自:http://www.tuicool.com/articles/MN3ANnV
除錯了一天啊!!!!整整一天!!!鬱悶之極,最後才成功。
KL25支援9種低功耗模式,最常用的是LLS模式。在這種模式下,MCU停止運作,大部分外設都不能工作,只有某些外設通過設定還可以繼續工作。比如:TSI按鍵和低功耗定時器(LPTMR)。要想喚醒,只有一個辦法:利用低功耗喚醒模組(LLWU)。這個模組唯一作用就是將KL25從低功耗模式喚醒。
我本來想寫的是讓MCU進入LLS模式,然後用低功耗定時器(LPTMR)每1秒觸發TSI硬體掃描一次,這樣當人手按下TSI按鍵的時候,就可以產生中斷,中斷傳遞到低功耗喚醒模組(LLWU)來喚醒MCU。但是這種辦法需要經歷三級才能喚醒MCU:先要LPTMR每一秒產生一次硬體觸發,TSI模組接收到觸發訊號之後,就會開始掃描,掃描完之後產生中斷,該中斷被傳遞到LLWU模組,LLWU模組就會喚醒MCU,執行LLWU的中斷處理程式,然後返回到正常的程式碼,也就是進入到LLS模式這句話的下一句程式碼。
可惜,這種設定沒有除錯成功。搞了很長時間都不正確。最後不得不用一種簡單的喚醒:直接用LPTMR喚醒,不使用TSI模組。過程是:讓LPTMR每一秒鐘產生一次中斷,該中斷傳遞到LLWU,用來喚醒MCU進入LLWU中斷處理程式碼。果然簡單多了,最後除錯成功。
LLWU模組可以接受16種外部引腳訊號來製造中斷,也可以接收內部模組的中斷拿來自己產生中斷。當它的輸入源是內部模組的時候,比如LPTMR或者TSI按鍵時,感覺更像一箇中斷傳遞模組。它本身接收其他模組的中斷,然後自己用來喚醒MCU。CPU喚醒之後也不是像正常執行那樣,執行該模組的中斷處理程式碼,而是執行LLWU的中斷處理程式碼。這可能是低功耗的中斷和正常執行的中斷不太一樣的地方吧。CPU處於正常模式的時候,某模組產生中斷的時候,直接執行該模組的中斷處理程式碼;但是在低功耗喚醒情況下,必須通過LLWU傳遞內部模組的中斷,中斷的處理程式碼也是LLWU的中斷處理程式碼。不過話說回來,因為LLWU本身並不是什麼產生中斷的模組,更像一個傳遞模組,所以它的中斷處理程式跟傳遞中斷給他的那個模組的中斷處理幾乎沒什麼兩樣。
我們看程式碼:
void LLWU_Init(void);
char nmi_wake_up_flag;
char llwu_wake_up_flag;
uint32 converting = 0;
uint32 result0A = 0;
uint32 dummyread;
int main (void)
{
int i;
LLWU_Init();
lptmr_init(100, LPTMR_USE_LPOCLK);
GPIO_Init(PORTC, 16, GPIO_OUTPUT, 0); //綠燈亮
/* Enable LPTMR wakeup interrupt */
enable_irq(LPTMR_irq_no);
EnableInterrupts;
//Set the STOPM field to 0b011 for LLS mode
SMC_PMCTRL |= SMC_PMCTRL_STOPM(0x3) ;
dummyread=SMC_PMCTRL;
// Set the SLEEPDEEP bit to enable deep sleep mode (STOP)
SCB_SCR |= SCB_SCR_SLEEPDEEP_MASK;
while(1)
{
// WFI instruction will start entry into LLS mode
asm("WFI"); //進入LLS模式
for (i=0;i<1000;i++){
GPIO_ToggleBit(PORTC, 16); //綠燈閃爍
Delay1Us(5000);
}
}
}
貼上幾段關鍵的程式碼:
//低功耗定時器的初始化,主要要注意開啟它的中斷功能。但是雖然開啟了它的中斷,MCU並不會執行它的中斷程式碼,而是執行LLWU的中斷程式碼。
//我曾經以為如果它的中斷也開啟,LLWU的也有中斷,那麼就會同時有兩個中斷,所以關掉了LPTMR中斷,結果不成功。
//其實LLWU只不過對LPTMR產生中斷之後的過程進行了包裝。
void lptmr_init(int count, int clock_source)
{
SIM_SCGC5 |= SIM_SCGC5_LPTMR_MASK;
// LPTMR0_CSR &= !LPTMR_CSR_TEN_MASK;
LPTMR0_PSR = ( LPTMR_PSR_PRESCALE(0) // 0000 is div 2
| LPTMR_PSR_PBYP_MASK // LPO feeds directly to LPT
| LPTMR_PSR_PCS(clock_source)) ; // use the choice of clock
if (clock_source== 0)
printf("\n LPTMR Clock source is the MCGIRCLK \n\r");
if (clock_source== 1)
// printf("\n LPTMR Clock source is the LPOCLK \n\r");
printf("\n LPTMR is OK");
if (clock_source== 2)
printf("\n LPTMR Clock source is the ERCLK32 \n\r");
if (clock_source== 3)
printf("\n LPTMR Clock source is the OSCERCLK \n\r");
LPTMR0_CMR = LPTMR_CMR_COMPARE(count); //Set compare value
LPTMR0_CSR =( LPTMR_CSR_TCF_MASK // Clear any pending interrupt
| LPTMR_CSR_TIE_MASK // LPT interrupt enabled
| LPTMR_CSR_TPS(0) //TMR pin select
|!LPTMR_CSR_TPP_MASK //TMR Pin polarity
|!LPTMR_CSR_TFC_MASK // Timer Free running counter is reset whenever TMR counter equals compare
|!LPTMR_CSR_TMS_MASK //LPTMR0 as Timer
);
LPTMR0_CSR |= LPTMR_CSR_TEN_MASK; //Turn on LPT and start counting
}
//下面是LLWU的中斷處理程式碼。跟LPTMR本身的中斷處理程式碼大同小異。(下面的哦if語句大部分都沒用)
void llwu_isr(void){
printf("go to LLWU INT");
if (LLWU_F1 & LLWU_F1_WUF5_MASK) {
// printf("****WUF5 was set *****\r\n");
LLWU_F1 |= LLWU_F1_WUF5_MASK; // write one to clear the flag
}
if (LLWU_F1 & LLWU_F1_WUF6_MASK) {
// printf("****WUF6 was set *****\r\n");
LLWU_F1 |= LLWU_F1_WUF6_MASK; // write one to clear the flag
}
if (LLWU_F1 & LLWU_F1_WUF7_MASK) {
// printf("****WUF7 was set from PTC3 input *****\r\n");
LLWU_F1 |= LLWU_F1_WUF7_MASK; // write one to clear the flag
}
if (LLWU_F2 & LLWU_F2_WUF8_MASK) {
// printf("****WUF8 was set *****\r\n");
LLWU_F2 |= LLWU_F2_WUF8_MASK; // write one to clear the flag
}
if (LLWU_F2 & LLWU_F2_WUF9_MASK) {
// printf("****WUF9 was set *****\r\n");
LLWU_F2 |= LLWU_F2_WUF9_MASK; // write one to clear the flag
}
if (LLWU_F2 & LLWU_F2_WUF10_MASK) {
// printf("****WUF10 was set *****\r\n");
LLWU_F2 |= LLWU_F2_WUF10_MASK; // write one to clear the flag
}
if (LLWU_F2 & LLWU_F2_WUF11_MASK) {
// printf("****WUF11 was set *****\r\n");
LLWU_F2 |= LLWU_F2_WUF11_MASK; // write one to clear the flag
}
if (LLWU_F2 & LLWU_F2_WUF12_MASK) {
// printf("****WUF12 was set *****\r\n");
LLWU_F2 |= LLWU_F2_WUF12_MASK; // write one to clear the flag
}
if (LLWU_F2 & LLWU_F2_WUF13_MASK) {
// printf("****WUF13 was set *****\r\n");
LLWU_F2 |= LLWU_F2_WUF13_MASK; // write one to clear the flag
}
if (LLWU_F2 & LLWU_F2_WUF14_MASK) {
// printf("****WUF14 was set *****\r\n");
LLWU_F2 |= LLWU_F2_WUF14_MASK; // write one to clear the flag
}
if (LLWU_F2 & LLWU_F2_WUF15_MASK) {
// printf("****WUF15 was set *****\r\n");
LLWU_F2 |= LLWU_F2_WUF15_MASK; // write one to clear the flag
}
/************************************************************************
* Note: This ISR does not write to the LLWU_F3 register because these
* are peripheral module wakeups. The flags contained in the LLWU_F3
* register should be cleared through the associated module interrupt
* and not through the LLWU_F3 per the Kinetis L Family Reference
* Manual (LLWU Chapter)
**********************************************************************/
//喚醒源是LPTMR,這裡的程式碼是關鍵,可以看到它對LPTMR的時鐘進行了重新使能,控制暫存器也重新進行了填值。雖然我不知道這是為什麼,因為使用者手冊說過LPTMR
//模組可以在低功耗模式下執行。而且,我在主函式之中已經做過初始化。
if (LLWU_F3 & LLWU_F3_MWUF0_MASK) {
// printf("****WUF3_MWUF0 IF LPTMR *****\r\n");
SIM_SCGC5 |= SIM_SCGC5_LPTMR_MASK;
LPTMR0_CSR |= LPTMR_CSR_TCF_MASK; // write 1 to TCF to clear the LPT timer compare flag,清除中斷標誌位
LPTMR0_CSR = ( LPTMR_CSR_TEN_MASK | LPTMR_CSR_TIE_MASK | LPTMR_CSR_TCF_MASK );
}
if(LLWU_FILT1 & LLWU_FILT1_FILTF_MASK){
LLWU_FILT1 |= LLWU_FILT1_FILTF_MASK;
}
if(LLWU_FILT2 & LLWU_FILT2_FILTF_MASK){
LLWU_FILT2 |= LLWU_FILT2_FILTF_MASK;
}
NVIC_ICPR |= 1 << (LLWU_irq_no%32);
}
我們看一下LPTMR本身的中斷處理程式碼:
void lptmr_isr(void)
{
printf("\n****LPT ISR entered*****\r\n");
// enable timer
// enable interrupts
// clear the flag
LPTMR0_CSR |= LPTMR_CSR_TCF_MASK; // write 1 to TCF to clear the LPT timer compare flag
LPTMR0_CSR = ( LPTMR_CSR_TEN_MASK | LPTMR_CSR_TIE_MASK | LPTMR_CSR_TCF_MASK );
}
可以發現兩者大同小異,只是沒有重新使能時鐘的程式碼。
程式碼成功執行後,LED不停閃爍,MCU就實現了從低功耗模式喚醒。感覺有以下要點:
1,內部模組要允許中斷
2,LLWU的中斷處理程式碼要對中斷源再次做一些初始化工作,並清除中斷標誌
相關推薦
KL25利用低功耗定時器進行MCU低功耗喚醒
轉自:http://www.tuicool.com/articles/MN3ANnV 除錯了一天啊!!!!整整一天!!!鬱悶之極,最後才成功。 KL25支援9種低功耗模式,最常用的是LLS模式。在這種模式下,MCU停止運作,大部分外設都不能工作,只有某些外設通過設定還
STM32L0Cube之低功耗定時器LPTIM程式設計筆記
1 在STM32Cube中啟用LPTIM 一.LPTIM超時產生中斷詳解 使用的庫函式為: HAL_StatusTypeDefHAL_LPTIM_TimeOut_Start_IT(LPTIM_HandleTypeDef *hlptim, uint32_t Period
CPUIDLE 之低功耗定時器
在 Linux 作業系統中,Idle 程序(又叫 Swapper 程序)的 pid 號是 0,是所有程序的祖先,它是在 Linux 初始化階段從無到有建立的一個核心執行緒。stark_kernel() 函式初始化核心需要的所有資料結構,啟用中斷,建立另一個叫程序
利用deadline_timer實現定時器Timer
second adl span 停止 deadline timer style set hello 1 // 類似QTimer的定時器 2 class Timer 3 { 4 typedef void(* handler)(); 5 public: 6
利用隨機數與定時器做一個簡單的偽隨機抓鬮遊戲
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title></title> <style type="text/css"> *
golang 高效低精度定時器實現
golang預設定時器是通過time模組提供的,不管是golang,libev,libevent也好,定時器都是通過最小堆實現的,導致加入定時器時間複雜度為O(lgn),在需要大量定時器時效率較低,所以Linux提供了基於時間輪的實現,我們本次提供的貼一張Linux時
Linux 核心定時器使用 一 低精度定時器
核心定時器是一個數據結構,它告訴核心在使用者定義的時間點使用使用者定義的引數來執行一個使用者定義的函式。其實現位於 <linux/timer.h>中。 核心提供了一組用來宣告、註冊和刪除核心定時器的函式,相關介面如下: struct timer_list {
使用STM32的定時器進行輸入脈衝的計數
3、外部觸發無濾波器:0000。 可選項: 0:無濾波器,以fDTS取樣 1:取樣頻率fSAMPLING=fCK_INT,N=2 2:取樣頻率fSAMPLING=fCK_INT,N=4 3:取樣頻率fSAMPLING=fCK_INT,N=8 4:取樣頻率fSAMPLING=fDTS/2,N=6
為什麼32的嘀嗒定時器在低功耗stop模式喚醒後會比較緩慢
首先我們看到M4的程式設計手冊,裡面有systick的時鐘來源介紹,可以看到systick的計數源的AHB或者AHB/8。 systick的配置函式如下,可以看到選擇的時鐘源時AHB。 __STATIC_INLINE uint32_t SysTick_Config(u
CC2500RGPR是一種低成本單片2.4G 收發器,為低功耗無線應用而設計
5.6 應用電路 -1 健康 低功耗 電路 分銷商 價格 國內 CC2500RGPR是一種低成本單片2.4G 收發器,為低功耗無線應用而設計。2400~2483.5MHz ISM及SRD頻率波段。高度集成的RF收發芯片,可以配置基帶調制解調,最高速率可以到500Kbps。
利用Zabbix的自動註冊功能添加局域網中的服務器進行監控
監控 自動註冊 zabbix 在PMM監控系統的日常使用過程中發現了一些槽點: 1.監控報警功能不熟悉 2.歷史數據保存問題 3.莫名其妙的在一段時間內缺失監控數據,導致和開發理論的時候心虛決定搭建一套zabbix監控環境進行互補 服務端安裝: yum -y inst
利用ab壓力工具對服務器進行壓力測試
因此 win request 過大 .exe http cond don bin 假如我們需要對http://letv.com進行壓力測試,指定請求總數為100,並發用戶數為10,我們可以以下面的方式進行測試 $ ab -n 100 -c 10 http://letv
利用定時器 1和定時器0控制led1和led2分別 2hz和0.5hz閃爍
fine blog style 0ms log pre del nbsp efi 1 //利用定時器 1和定時器0控制led1和led2分別 2hz和0.5hz閃爍 2 //利用定時器0 1s,led1取反,利用計數器1,(65535-10)%256,取反 3 #i
在 CentOS 中 利用定時器 自動備份 SVN
相關連結: 在MyEclipse中使用SVN提交(自動忽略 .settings .project .classpath等)、檢出(無.settings .project .classpath檔案等)Maven程式碼 在MyEclipse CI 2018.9.0 中安裝 SVN 1.10.13
利用Hog特徵和SVM分類器進行行人檢測
https://blog.csdn.net/qianqing13579/article/details/46509037 梯度直方圖特徵(HOG) 是一種對影象區域性重疊區域的密集型描述符, 它通過計算區域性區域的梯度方向直方圖來構成特徵。Hog特徵結合SVM分類器已經被廣
利用定時器做防止誤觸發功能以及多久後執行某個事件
在程式設計中,經常會碰到需要做到如下功能: 1.有一個不定時執行的方法A,在執行時需要判斷距離上一次執行過了多長時間,如果超過三秒就繼續執行,如果小於三秒就退出。 2.有一個不定時執行的A方法和B方法,假設:A方法執行完成後,如果3秒內B方法沒有被執行,那麼就執行C方法,如果在3秒內執行了B
c#進行web開發的時候使用quartz定時器的詳細講解
一 前提 (1)首先需要引用Common.Logging.dll和Quartz.dll。 (2)其次,我們需要了解一些基本的知識 Job 表示一個具體要執行的工作,需要實現IJob介面. JobDetail JobDetail表示一個具體的可執行的排程程式,它
spring 整合mybatis——多資料來源切換(附帶定時器的配置,儲存過程連線,資料多於50條,分批進行操作)
新建com.millery.utils包在其下新建DataSourceContextHolder類 package com.millery.utils; public class DataSourceContextHolder { private
利用Js中的定時器實現圖片的淡入淡出
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> &
STC8A8K64S4A12——掉電喚醒定時器應用,極大降低產品功耗
【背景】最近做低功耗專案,用到了一款STC的低成本,低功耗MCU,STC8A8K64S4A12,外設較豐富,主要是成本低,2-4元,且功耗很低,按官網介紹,掉電模式下<0.1uA,這種級別用於電池供電裝置上太划算了。 【掉電喚醒定時器】:掉電模式下可以由外部中斷