LPC1343 ディープスリープモード(Deep Sleep mode)移行 とGPIOからの復帰

やったこと

1. ディープスリープモード(Deep Sleep mode)へ移行とGPIOからの復帰

開発Listへ戻る

前回はSleep modeを行ったので
次はDeep Sleep modeを試してみたいと思います。

Sleep modeよりもめんどくさかった。。。

まず、マニュアル UM10375を見てもよくわからないので
アプリケーションノートのAN10973を見るわけですが
こいつにもDeep Sleep modeの入り方のサンプルはあっても、復帰のさせ方のサンプルは無く・・
たらい回しにされたのに目的達成できず!
なんだか公務員関係の施設に行ったときのような対応に感じるのです。
(あくまでイメージです。。あしからず!)

結局のところ、英語でググってNXPのCommunityのスレッドを参考に試してみてわかったという感じです。
やっぱりインターネットってスゲー、グローバルってスゲーとつくづく思います。

前置きはこれくらいで、本題です。

Deep sleep modeですがマニュアルを読むと

  • レジスタ情報やSRAMの情報は維持されたまま、ほぼ全部がストップする。
  • "ほぼ"に入らないファンクションはBOD(電圧降下検出)とWatch dog

ということらしいです。

復帰方法は以下4種類のようです。

  • PIO0_〜PIO0_11, PIO1_0計13本のGPIOのどれか一つを利用 ←今回はコレを確認
  • BOD回路からのリセット
  • Watch Dog Timerからのリセット
  • Reset pinからのリセット


確認方法

Timerを使ったLEDの点滅を設定後に、Deep sleep modeに入ります。
→Deep sleep modeに入ったので点滅しないことを確認します。
P0.2をGNDに接続することでDeep sleep modeから抜けるようにします。
→点滅開始を確認します。

回路: 特別なものはありません。LPCexpresso1343のP0.7についているLEDを使用します。
   またP0.2 (SSEL)を直接ブレッドボードでワイヤを使ってGNDに接続しDeep Sleepから抜け出します。

動作イメージ図


コード
main.cを空にして、以下をCopy & Pasteすれば動きます。

#ifdef __USE_CMSIS
#include "LPC13xx.h"
#endif

#include
#include

// Variable to store CRP value in. Will be placed automatically
// by the linker when "Enable Code Read Protect" selected.
// See crp.h header for more information
__CRP const unsigned int CRP_WORD = CRP_NO_CRP ;



int main(void) {

// Test circuit code //
LPC_IOCON->PIO0_7 = 0x00; // set as GPIO (LPCexpresso LED control PIN)
LPC_GPIO0->DIR |= 0x80; // p0_7 as output
LPC_GPIO0->MASKED_ACCESS[0x080]=0x080; //P0_7=1(LED on)

// 32bit counter
NVIC_EnableIRQ(TIMER_32_1_IRQn); // enable Timer32_1 interrupt handler

LPC_SYSCON->SYSAHBCLKCTRL |=0x400; // Timer32B1 Turn ON
LPC_TMR32B1->PR =7200-1; // 0.1ms ,10kHz(Max 32bit dec:4294967295)
LPC_TMR32B1->MCR=0x003; // Reset timer on MR0 and interrupt
LPC_TMR32B1->MR0 = 5000; // 0.5sec
LPC_TMR32B1->TCR =2; // TCR Reset
LPC_TMR32B1->IR =0x0F; // Clear interrupt flag
LPC_TMR32B1->TCR =1; // TCR start


// Deep Sleep mode code//
LPC_SYSCON->PDRUNCFG &= ~( (1<<0) | (1<<1) | (1<<2));

//Switch MAINCLK to IRC clock
LPC_SYSCON->MAINCLKSEL =0;
LPC_SYSCON->MAINCLKUEN =0;
LPC_SYSCON->MAINCLKUEN =1;
while(!(LPC_SYSCON->MAINCLKUEN & 0x01));

LPC_SYSCON->PDSLEEPCFG = 0x00000FFF; // BOD & Watch dog both off

//Specify peripherals to be powerd up again when wake up
LPC_SYSCON->PDAWAKECFG = LPC_SYSCON->PDRUNCFG;


LPC_SYSCON->STARTAPRP0 &=~(1<<2);//Falling Edge of P0.2 is Wake up logic
LPC_SYSCON->STARTRSRP0CLR |= (1<<2); // Clear pending bit of P0.2
LPC_SYSCON->STARTERP0 |=(1<<2);// Enable Start Logic of P0.2
NVIC_ClearPendingIRQ(WAKEUP2_IRQn);
NVIC_EnableIRQ(WAKEUP2_IRQn);

SCB->SCR |=(1<<2); // Set deepsleep bit

__WFI(); // Go to Deep Sleep mode


// Enter an infinite loop, just incrementing a counter
volatile static int i = 0 ;
while(1) {
i++ ;
}
return 0 ;
}


void WAKEUP_IRQHandler(void) {

LPC_SYSCON->STARTRSRP0CLR |= (1<<2); //Clear pending bit of P0.2
LPC_SYSCON->STARTERP0 &=~(1<<2); //Disable Start logic of P0.2

// Change MAINCLK to System PLL clock
LPC_SYSCON->MAINCLKSEL =3;
LPC_SYSCON->MAINCLKUEN =0;
LPC_SYSCON->MAINCLKUEN =1;
while(!(LPC_SYSCON->MAINCLKUEN & 0x01));
}


void TIMER32_1_IRQHandler(void) {

LPC_GPIO0->DATA ^=0x80; // Toggle P0_7
LPC_TMR32B1->IR =0x0F; // Clear interrupt flag
}

コード解説 
TimerやLEDの動作は割愛してDeepSleepの動作のみ説明します。

まず、RCクロックとFlashのパワーをONにします。リセットバリューでオンになっているようですので
明示的に行っているようです。

LPC_SYSCON->PDRUNCFG &= ~( (1<<0) | (1<<1) | (1<<2));


次はメインクロックをRCクロックに変えています。
MAINCLKENを0→1にする件はマニュアルに指示があります(UM10375の3.5.15項)
ちなみにRCクロックにする理由は低消費電力にするためです。
以下の記載をコメントアウトして試しましたがちゃんと動作しました。
(PLLクロックを使ってもDeep Sleepに入って復帰できます)

LPC_SYSCON->MAINCLKSEL =0;
LPC_SYSCON->MAINCLKUEN =0;
LPC_SYSCON->MAINCLKUEN =1;
while(!(LPC_SYSCON->MAINCLKUEN & 0x01));


BODとWatch dogのコントロールです。
DeepSleep中でもBODとWatch Dogを動かすかを選択します。今回は両方OFFです。
選択方法はアプリケーションノートのAN10973に載ってます。

LPC_SYSCON->PDSLEEPCFG = 0x00000FFF; // BOD & Watch dog both off


Deep sleepから復帰するときに、Power ONする設定です。こいつが無いと動かなかったです。

LPC_SYSCON->PDAWAKECFG = LPC_SYSCON->PDRUNCFG;


P0.2でWake upするための設定です。
Falling edgeでWake upするようにしています。
Pending bitのClearも必要です。Status registerの初期値が不安定で
Start logic(Wake up条件)が入った状態となっていた場合、直ぐに割り込み状態に遷移してしまいます。
割り込みを有効にする前にしっかりとクリアしておく必要があります。
STARTERP0でスタートロジックを受け付けるようにします。
その後割り込みを有効化します。どのPIOを利用するかでWAKEUP2_IRQnの数字の部分が変わることに注意です。
(マニュアルではP0.1〜P0.11,P1.0の13本が使えるということでした)

LPC_SYSCON->STARTAPRP0 &=~(1<<2);//Falling Edge of P0.2 is Wake up logic
LPC_SYSCON->STARTRSRP0CLR |= (1<<2); // Clear pending bit of P0.2
LPC_SYSCON->STARTERP0 |=(1<<2);// Enable Start Logic of P0.2
NVIC_ClearPendingIRQ(WAKEUP2_IRQn);
NVIC_EnableIRQ(WAKEUP2_IRQn);


そしてSleep modeをDeep sleepに設定して眠りに落ちます。

SCB->SCR |=(1<<2); // Set deepsleep bit
__WFI(); // Go to Deep Sleep mode


Wake upの方法です。
まず、関数名ですがWAKEUPとなっています。WAKEUP2では無いところに注意です。
最初の2行です。
Pending bitをClearは念のためみたいなものです。(Start logicをDisableすれば不要です)
Start logicをDisableすることでこの割り込みには入ってこないようになります。
(Start logicのDisableなしで、Pending bitをClearしないと
割り込み処理を抜けてから直ぐまた割り込み処理に入るループになりました)
ちなみに割り込み名にWAKEUPとついているのでSleepに入っているときだけ有効!というわけではありません。
WAKEUPしている通常状態でも条件になれば割り込みが入ります。
なのでDisableすることが必要です
(今回も__WFI();をコメントアウトしてSleepに入らずにあらかたの動作確認をしていました)

void WAKEUP_IRQHandler(void) {
LPC_SYSCON->STARTRSRP0CLR |= (1<<2); //Clear pending bit of P0.2
LPC_SYSCON->STARTERP0 &=~(1<<2); //Disable Start logic of P0.2

// Change MAINCLK to System PLL clock
LPC_SYSCON->MAINCLKSEL =3;
LPC_SYSCON->MAINCLKUEN =0;
LPC_SYSCON->MAINCLKUEN =1;
while(!(LPC_SYSCON->MAINCLKUEN & 0x01));
}

WAKEUPから復帰でき無い状態だと、ROM焼きができません。
その場合はFT/GPIO pinをGNDにすることで解決できます。
(参考以前のエントリ: LPC1343 SWDIOをGPIOに設定したときのリカバリ法

Deep Sleepの時の電力まで確認する設備が無いのでやりませんが
LPC_SYSCON->PDRUNCFGで余分なものをパワーダウンすれば電力はもっと減るんじゃないかと思います。


開発Listにもどる