M5Stamp C3で時計<その2>


 前の記事では、7segmentLEDに時刻を表示しました。
  M5Stamp C3で時計
ここでは、OLEDディスプレイに表示をします。
 しかし、現時点では、長時間は稼働できません。

OLEDディスプレイ

 アマゾンで普通に入手できる128x64のOLEDディスプレイです。I2CとSPIがありますが、I2Cバス用を使います。

 接続は、SDA = 8番ピン、SCL = 9番ピン、Vccは3.3V、GNDはGNDです。

SSD1306のライブラリ

 OLEDのライブラリは、AdafruitのSSD1306を使いました。
 しかし、暴走します。早いときは10分ぐらいで、止まってしまいます。
 そこで、ESP32用watchdogタイマを入れ、3秒間、タイマを初期化しないと、rebootがかかるようにします。こちらの記事を参照してプログラムを追加しました。ありがとうございます。
  Arduino-ESP32 WatchDogTimer
 リブートしている間、時計の表示は止まります。
 プログラムの暴走とのタイミングによっては数時間でデッドロックしてしまうことがあるようです。もちろん、SSD1306のライブラリがESP32-C3(RISC-V)に対応すれば、問題は解決します。Adafrutiは、新しいESP32シリーズでは、S2(Xtensa 32-bit LX7 CPU)、S3(XTensa LX7 MCU)には対応しているようですが、C3は製品を持っていないので、当分先になるかもしれません。

プログラム

 loop()の最初に入っているtimerWrite(timer, 0);がwatchdogタイマの初期化です。暴走して、この初期化が実施されないと、watchdogタイマのresetModule()が実行され、リブートします。

#include "esp_system.h"

const int wdtTimeout = 3000;  //time in ms to trigger the watchdog
hw_timer_t *timer = NULL;

void IRAM_ATTR resetModule() {
  ets_printf("reboot\n");
  esp_restart();
}

#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 64 // OLED display height, in pixels
#define SCREEN_ADDRESS 0x3c ///< See datasheet for Address; 0x3D for 128x64, 0x3C for 128x32
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire);

#include <WiFi.h>
#include <WiFiMulti.h>
#include <NTPClient.h>

WiFiMulti WiFiMulti;

WiFiUDP ntpUDP;
NTPClient timeClient(ntpUDP, "ntp.nict.jp", 3600*9, 60000);

void setup() {
  Serial.begin(115200);
    WiFiMulti.addAP("Buffalo-G-20EA", "********");
    //Serial.print("\nWaiting for WiFi... ");

    while(WiFiMulti.run() != WL_CONNECTED) {
    //    Serial.print(".");
        delay(500);
    }
    //Serial.println("WiFi connected");
    //Serial.println("IP address: ");
    //Serial.println(WiFi.localIP());

  timeClient.begin(); 
  delay(500); 
    //Serial.println("NTP start");    
  Wire.begin();
  // SSD1306_SWITCHCAPVCC = generate display voltage from 3.3V internally
  if(!display.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS)) {
    Serial.println(F("SSD1306 allocation failed"));
    for(;;); // Don't proceed, loop forever
  }

  Serial.println("timer start");

  display.clearDisplay();
  timer = timerBegin(0, 80, true);                  //timer 0, div 80
  timerAttachInterrupt(timer, &resetModule, true);  //attach callback
  timerAlarmWrite(timer, wdtTimeout * 1000, false); //set time in us
  timerAlarmEnable(timer);                      //enable interrupt                       
}

void loop() {
  timerWrite(timer, 0); //reset timer (feed watchdog)
  // Clear the buffer
  display.clearDisplay();
  display.setTextSize(2); // Draw 2X-scale text
  display.setTextColor(SSD1306_WHITE);
  display.setCursor(20, 10);

  delay(1000);
  timeClient.update();
  String TIME = timeClient.getFormattedTime();
  //Serial.println(TIME);
  display.println(TIME);
  display.display();
}

 暴走してリブートした直後の様子です。