2026年2月26日木曜日

CH32V003マイコン5 スリープ機能(低電力)

  脳トレゲーム用基板として設計をしましたので、最終的には電池駆動のゲーム機を想定しています。この時にゲームをしていないときには、少しでも電力を抑えたいものです。この時にマイコンでは「スリープ」モードが利用されます。

 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 件のコメント:

コメントを投稿

LEDマトリックス表示装置の設計・製作 9(画像表示)

  LEDマトリックスに画像を表示させるには、いろいろな画像形式を知る必要があります。現在、よく使われるJPG形式やPNG形式は圧縮処理されて保存されています。これに対して、BMP形式やTIFF形式は非圧縮形式で、画像データがそのまま保存されています。このため、ファイルは大きくな...