脳トレゲーム用基板として設計をしましたので、最終的には電池駆動のゲーム機を想定しています。この時にゲームをしていないときには、少しでも電力を抑えたいものです。この時にマイコンでは「スリープ」モードが利用されます。
CH32V003でもスリープモードがあります。スリープモードには、「スタンバイモード(DEEP SLEEP)」と「スリープモード」があり、モードになると、約10μA程度の電流になるようです。今回は「スタンバイモード」にします。
スタンバイモードの動作とプログラム
スタンバイモードを使うときに、必要なのは、復帰するために何らかの「割り込み」が必要です。タイマや外部割り込みなどいろいろあるのですが、今回はスイッチを押したときにスリープから復帰するようにします。まずは、動画を見てください。
7セグメントLEDの「g」のLED(中央)が点滅しています。一番左のスイッチを押すと、スリープモードになります。この時に、確認するため、LED「d」(下側)を点灯させてからスリープしています。一番右のスイッチ(緑)を押すと復帰します。 プログラムは次です。
//割り込み処理
void ISR() {
NVIC->SCTLR &= ~(1 << 2 | 1 << 3); // deepsleep off
NVIC->SCTLR &= ~(1 << 1); //SLEEPONEXIT enters the main program
digitalWrite(PD2, 0);
}
void setup() {
// RESET button シームレススイッチ
if (FLASH->STATR & (1 << 14)) NVIC_SystemReset();
SystemReset_StartMode(Start_Mode_BOOT);
pinMode(PD4, OUTPUT);
pinMode(PD2, OUTPUT); // seg_d
pinMode(PC0, OUTPUT); // seg_g
pinMode(PC7, INPUT_PULLUP); // sw1
pinMode(PC1, INPUT_PULLUP); // sw6
// sw6 PC1(3)による割り込み
attachInterrupt(digitalPinToInterrupt(PC1), GPIO_Mode_IPU, ISR, EXTI_Mode_Interrupt, EXTI_Trigger_Falling);
}
void loop() {
digitalWrite(PC0, 1); delay(50);
digitalWrite(PC0, 0); delay(50);
if(digitalRead(PC7)==0){
digitalWrite(PD2, 1);
// sleep mode
NVIC->SCTLR |= (1 << 2 | 1 << 3); //SLEEPDEEP deepsleep
NVIC->SCTLR |= (1 << 1); //SLEEPONEXIT low-power mode
PWR->CTLR &= PWR_CTLR_PDDS;
__WFE(); // sleep mode
}
}
19行目で「PC1」を外部割り込みのスイッチをして割り当てをしています。この割り込み設定で、2行目からの「ISR」関数が呼び出される設定です。
25行目でスイッチ「PC7」を押すと、設定後にスタンバイモードに入ります。
あとはスイッチ(PC1)が押されると外部割込みがかかり、ISR関数が実行されます。
はじめは、先人たちのサイトを眺めてプログラムを行ったのですが、割り込みがかかって、ISR関数が実行されても、スタンバイから復帰しませんでした。
スタンバイモードに関連する部分のドキュメント(右図)を見ていると、「SLEEPONEXIT」ビットを「1」にすると、スタンバイとなり、「0」にすると、通常の状態になるということが分かりました。
割り込み処理でこのビットを「0」にする処理を加えました。プログラムの3行目です。この行を加えると、割り込み後に、通常のプログラムが実行されるようになりました。
他の端子で、スタンバイモードから復帰するには、19行目の「PC1」の割り当てを変えることで変更できます。
スタンバイモードからの復帰後の処理(追記)
スタンバイモードから復帰したときに、LEDの点滅が遅くなっていることに気づきました。内部状態をシリアルモニタで出力して確認すると、CPUクロックのPLL設定が変わっていました。PLLが無効になっているので、クロックが1/2となり、delay関数などの動作が2倍かかります。
//割り込み処理
void ISR() {
NVIC->SCTLR &= ~(1 << 2 | 1 << 3); // deepsleep off
NVIC->SCTLR &= ~(1 << 1); //SLEEPONEXIT enters the main program
SystemInit();
digitalWrite(PD2, 0);
}
これを解消するために、CPUクロックを設定している関数「SystemInit」を入れました(5行目)。CPUクロック変化すると、delay関数の他、シリアルモニタも文字化けしてしまいます。注意が必要です。
0 件のコメント:
コメントを投稿