Bye Bye Moore

PoCソルジャーな零細事業主が作業メモを残すブログ

M5StackでCPUクロックを変更する前にシリアルのボーレートを弄ると表示がバグるので注意

M5StackのコアであるESP32系にはCPUクロックを落として省電力化する機能があります。
ただし、これの呼び出しタイミングを誤ると、シリアル通信などクロック依存のタスクに影響がでます。
そのため、CPUクロック変更命令はM5.begin()の前に呼び出しましょう。

実際のところ

状況

試作中の環境ノードの省電力化を試み、CPU速度を落としてみました。

void setup() {
  // M5Stack初期化
  M5.begin();
  M5.Power.begin();
  //...

  // CPU周波数削減(省電力化のため)
  setCpuFrequencyMhz(40);

  // シリアル通信初期化
  Serial.begin(115200);
  while (!Serial) {
    delay(100);
  }
  
  //...
}

目論見通り消費電力は落ち、計測ロジックも遅くならなかったので特に不満は無かったのですが……
ちょっと挙動を見ようとシリアルを繋いだところ

rst:0x1 (POWERON_RESET),boot:0x17 (SPI_FAST_FLASH_BOOT)
configsip: 0, SPIWP:0xee
clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00
mode:DIO, clock div:1
load:0x3fff0030,len:1344
load:0x40078000,len:13964
load:0x40080400,len:3600
entry 0x400805f0
M5Stack initializing...
[ 377][E][sd_diskio.cpp:199] sdCommand(): Card Failed! cmd: 0x00
[ 383][E][sd_diskio.cpp:806] sdcard_mount(): f_mount failed: (3) The physical drive cannot work
[ 692][E][sd_diskio.cpp:199] sdCommand(): Card Failed! cmd: 0x00
OK
�f␘����`f~␆��...

などと、それまで動いていたデバッグログが滅茶苦茶なことに

対策

M5stack BasicのコアであるESP32シリーズのシリアル通信は、(考えてみりゃ当然なのですが)CPUクロックを基準に生成されています。
beginした後にクロックを弄ると、ボーレートが狂うので今回のような事態になるという事。
という訳で、setCpuFrequencyMhzメソッドはM5.begin()の前に置かないとダメです。

void setup() {
  // CPU周波数削減(省電力化のため)
  // 重要: M5.begin()の前に設定しないとシリアル通信が文字化けする
  setCpuFrequencyMhz(40);

  // M5Stack初期化
  M5.begin();
  M5.Power.begin();

  // シリアル通信初期化
  Serial.begin(115200);
  while (!Serial) {
    delay(100);
  }
  
  //...
}

補足情報

M5stackは仕様上、先にCPUクロックを弄ってしまうとアウトのようですが、
素のESP32系ボードは必ずしもそういう仕様ではないようで

// ESP32の普通のボードなら以下のような書き方もOKなケースがある
uint32_t Freq = 0;

void setup() 
{
  pinMode(GPIO_pin, OUTPUT); 
  Serial.begin(115200);
  setCpuFrequencyMhz(10);
  Freq = getCpuFrequencyMhz();
  Serial.print("CPU Freq = ");
  Serial.print(Freq);
  Serial.println(" MHz");
  // ....

ESP32 Change CPU Speed (Clock Frequency) – DeepBlue

参考もと

github.com