Converting M5CoreInk sketch to M5Paper



  • I have tried to convert a working sketch for the M5CoreInk to work on the M5Paper. The M5CoreInk sketch deliberately doesn't use the loop() in order to extend battery charge life by shutting down and restarting the device. The working CoreInk sketch can be seen at the bottom of this post.

    Meanwhile here is the non working M5Paper version. I have been working on it for a few days now and have probably messed it up too much but I would appreciate a few pointers as to what is going wrong. The main problem seems to be that the sketch loads and displays the daty but then just stops and never wakes up.

    #include <M5EPD.h>
    #include <WiFi.h>
    #include "Secrets.h"
    
    
    
    rtc_time_t RTCtime;
    char timeStrbuff[64];
    rtc_date_t RTCDate;
    char dateStrbuff[64];
    char connStrbuff[64];
    
    // every hour at minute 45 do a full ink display refresh
    #define FULL_REFRESH_MINUTE (45)
    
    static const char* wd[7] = { "SUN", "MON", "TUE", "WED", "THU", "FRI", "SAT" };
    char temStr[10];
    char humStr[10];
    char Humidity[10];
    
    M5EPD_Canvas canvas(&M5.EPD);
    M5EPD_Canvas canvas2(&M5.EPD);
    M5EPD_Canvas canvasTime(&M5.EPD);
    M5EPD_Canvas canvasConnect(&M5.EPD);
    
    
    RTC_SLOW_ATTR bool ntpDataFlag = false;
    
    const char* ssid = SECRET_SSID;
    const char* password = SECRET_PASS;
    const char* ntpServer = SECRET_NTP;
    const long gmtOffset_sec = 3600;
    const int daylightOffset_sec = 3600;
    time_t t;
    struct tm* tm;
    struct tm timeinfo;
    //tm = localtime(&t);
    
    void getRTCtime() {
      M5.RTC.getTime(&RTCtime);
      sprintf(timeStrbuff, "%02d:%02d:%02d", RTCtime.hour, RTCtime.min, RTCtime.sec);
      sprintf(dateStrbuff, "%02d:%02d:%02d", RTCDate.day, RTCDate.mon, RTCDate.year);
    }
    
    
    void SetRTC() {
      //  struct tm timeinfo;
      tm = localtime(&t);
    
      if (getLocalTime(&timeinfo) == false) {
        Serial.println("Failed to obtain time");
        return;
      }
      Serial.println(&timeinfo, "%A, %B %d %Y %H:%M:%S");
    
      RTCtime.hour = timeinfo.tm_hour;
      RTCtime.min = timeinfo.tm_min;
      RTCtime.sec = timeinfo.tm_sec;
      M5.RTC.setTime(&RTCtime);
    
      RTCDate.week = timeinfo.tm_wday;
      RTCDate.day = timeinfo.tm_mday;
      RTCDate.mon = timeinfo.tm_mon + 1;
      RTCDate.year = timeinfo.tm_year + 1900;
      M5.RTC.setDate(&RTCDate);
    }
    
    void getNTPTime() {
      // Try to connect for 10 seconds
      uint32_t connect_timeout = millis() + 10000;
      Serial.printf("Connecting to %s ", ssid);
    
      WiFi.begin(ssid, password);
      while ((WiFi.status() != WL_CONNECTED) && (millis() < connect_timeout)) {
        delay(500);
        Serial.print(".");
      }
      if (WiFi.status() != WL_CONNECTED) {
        Serial.print("Connection failed");
        //WiFi connection failed - set fantasy time and date RTCtime.hour = 00;
        RTCtime.min = 00;
        RTCtime.sec = 00;
        M5.RTC.setTime(&RTCtime);
    
        RTCDate.year = 2022;
        RTCDate.mon = 11;
        RTCDate.day = 27;
        M5.RTC.setDate(&RTCDate);
        return;
      }
    
      //Serial.println("Connected");
      canvasConnect.drawString("Connecting to NTP", 00, 00);  //Draw a string.
      canvasConnect.pushCanvas(10, 900, UPDATE_MODE_DU4);
      configTime(gmtOffset_sec, daylightOffset_sec, ntpServer);
      SetRTC();
    
      WiFi.disconnect(true);
      WiFi.mode(WIFI_OFF);
      //Serial.println("Disconnected");
      canvasConnect.drawString("Disconnected from WiFi", 00, 00);  //Draw a string.
      canvasConnect.pushCanvas(10, 900, UPDATE_MODE_DU4);
    }
    
    void getTempHum() {
      M5.SHT30.UpdateData();
      float tem = M5.SHT30.GetTemperature();
      float hum = M5.SHT30.GetRelHumidity();
      String bufTem;
      bufTem += String(tem, 2);
      bufTem += F("*C");
      String bufHum;
      bufHum += String(hum, 2);
      bufHum += F("%");
      float batLevel = M5.getBatteryVoltage();
      batLevel = batLevel * 100 / 4350;
      String bufBat;
      bufBat += String(batLevel);
      bufBat += F("%");
      canvasTime.drawString(bufTem, 0, 150);
      canvasTime.drawString(bufHum, 0, 200);
      canvasTime.drawString(bufBat, 0, 250);
      canvasTime.pushCanvas(250, 500, UPDATE_MODE_DU4);
    }
    
    void drawTimeAndDate() {
      getRTCtime();
    
      int weekday = RTCDate.week;
      const char* wday = wd[weekday];
    
      canvasTime.createCanvas(270, 300);  //Create a canvas.
      canvasTime.setTextSize(4);          //Set the text size.
      canvasTime.drawString(timeStrbuff, 0, 0);
      canvasTime.drawString(dateStrbuff, 0, 50);
      canvasTime.drawString(wday, 0, 100);
    
      getTempHum();
    }
    
    void setup() {
      Wire1.begin(21, 22);
      uint8_t data = M5.RTC.readReg(0x01);
    
      M5.begin();
    
      canvasConnect.createCanvas(540, 80);  //Create a canvas.
      canvasConnect.setTextSize(4);         //Set the text size.
    
      bool flagRTC = false;
    
      // Check timer flag
      if ((data & 0b00000100) == 0b00000100) {
        flagRTC = true;
        Serial.println("Power on by: RTC timer");
      } else {
        Serial.println("Power on by: PWR Btn");
      }
    
      M5.EPD.SetRotation(90);
      M5.EPD.Clear(true);
      M5.RTC.begin();
    
      getNTPTime();
    
      canvas.createCanvas(450, 500);  // 450 wide and 500 high
      canvas.drawPngFile(SD, "/ClockwoBG.png");
      //canvas.fillCanvas(0xFFFF);  // Fill the drawn area with black.
      canvas.pushCanvas(90, 10, UPDATE_MODE_GC16);  //Place 90 in and 10 down
    
      canvas2.createCanvas(270, 300);           //Create a canvas.
      canvas2.setTextSize(4);                   //Set the text size.
      canvas2.drawString("TIME IS..", 00, 00);  //Draw a string.
      canvas2.drawString("DATE IS..", 00, 50);  //Draw a string.
      canvas2.drawString("DAY IS...", 00, 100);
      canvas2.drawString("TEMP IS..", 00, 150);
      canvas2.drawString("HUM IS...", 00, 200);
      canvas2.drawString("BATTERY..", 00, 250);
      canvas2.pushCanvas(20, 500, UPDATE_MODE_DU4);  //Update the screen
    
      drawTimeAndDate();
    
      if (flagRTC)
        Serial.println("Power on by: RTC timer");
      else
        Serial.println("Power on by: PWR Btn");
    
      // Wait until full minute, e.g. seconds are 0
      while (timeinfo.tm_sec != 0) {
        Serial.println(timeinfo.tm_sec);
        delay(200);
    
        Serial.printf("Shutdown...\n");
    
        // Full refresh once per hour
        if (timeinfo.tm_min == FULL_REFRESH_MINUTE - 1) {
          // Allow extra time for full ink refresh
          // Shutdown for 55 seconds only
          M5.shutdown(55);
          return;
        }
        // Shutdown for 58 seconds
        M5.shutdown(5);
      }
    }
    
    void loop() {
    }
    

    Here is the CoreInk working sketch:

    
    #include "M5CoreInk.h"
    #include <WiFi.h>
    #include "time.h"
    #include "esp_adc_cal.h"
    #include "secrets.h"
    
    
    const char* ssid = SECRET_SSID;
    const char* password = SECRET_PASS;
    const char* ntpServer = SECRET_NTP;
    const long gmtOffset_sec = 3600;
    const int daylightOffset_sec = 3600;
    
    // every hour at minute 45 do a full ink display refresh
    #define FULL_REFRESH_MINUTE (45)
    
    Ink_Sprite TimePageSprite(&M5.M5Ink);
    
    void printLocalTimeAndSetRTC() {
      struct tm timeinfo;
    
      if (getLocalTime(&timeinfo) == false) {
        Serial.println("Failed to obtain time");
        return;
      }
      Serial.println(&timeinfo, "%A, %B %d %Y %H:%M:%S");
    
      RTC_TimeTypeDef time;
      time.Hours = timeinfo.tm_hour;
      time.Minutes = timeinfo.tm_min;
      time.Seconds = timeinfo.tm_sec;
      M5.rtc.SetTime(&time);
    
      RTC_DateTypeDef date;
      date.WeekDay = timeinfo.tm_wday;
      date.Date = timeinfo.tm_mday;
      date.Month = timeinfo.tm_mon + 1;
      date.Year = timeinfo.tm_year + 1900;
      M5.rtc.SetDate(&date);
    }
    
    String getBatteryVoltage() {
      analogSetPinAttenuation(35, ADC_11db);
      esp_adc_cal_characteristics_t* adc_chars = (esp_adc_cal_characteristics_t*)calloc(1, sizeof(esp_adc_cal_characteristics_t));
      esp_adc_cal_characterize(ADC_UNIT_1, ADC_ATTEN_DB_11, ADC_WIDTH_BIT_12, 3600, adc_chars);
      uint16_t adcValue = analogRead(35);
      float floatvoltage = esp_adc_cal_raw_to_voltage(adcValue, adc_chars) * 25.1 / 5.1 / 1000;
      int batteryPercentage = ((floatvoltage < 3.2) ? 0 : (floatvoltage - 3.2) * 100) - 10;
      String battPercent;
      battPercent += F("BATT ");
      battPercent += String(batteryPercentage);
      battPercent += F("%");
      return battPercent;
    }
    
    void getNTPTime() {
      // Try to connect for 10 seconds
      uint32_t connect_timeout = millis() + 10000;
      Serial.printf("Connecting to %s ", ssid);
      
      WiFi.begin(ssid, password);
      while ((WiFi.status() != WL_CONNECTED) && (millis() < connect_timeout)) {
        delay(500);
        Serial.print(".");
      }
      if (WiFi.status() != WL_CONNECTED) {
        // WiFi connection failed - set fantasy time and date
        RTC_TimeTypeDef time;
        time.Hours = 6;
        time.Minutes = 43;
        time.Seconds = 50;
        M5.rtc.SetTime(&time);
    
        RTC_DateTypeDef date;
        date.Date = 4;
        date.Month = 12;
        date.Year = 2020;
        M5.rtc.SetDate(&date);
        return;
      }
    
      Serial.println("Connected");
    
      configTime(gmtOffset_sec, daylightOffset_sec, ntpServer);
      printLocalTimeAndSetRTC();
    
      WiFi.disconnect(true);
      WiFi.mode(WIFI_OFF);
    }
    
    String getDay(int day) {
      String weekday = "Non";
      switch (day) {
        case 0:
          weekday = "SUN";
          break;
    
        case 1:
          weekday = "MON";
          break;
    
        case 2:
          weekday = "TUE";
          break;
    
        case 3:
          weekday = "WED";
          break;
    
        case 4:
          weekday = "THU";
          break;
    
        case 5:
          weekday = "FRI";
          break;
    
        case 6:
          weekday = "SAT";
          break;
    
    Default:
          Serial.println("This shouldn't happen");
          break;
      }
      return weekday;
    }
    
    void drawTimeAndDate(RTC_TimeTypeDef time, RTC_DateTypeDef date) {
      char buf[15];
      snprintf(buf, 4, "%03s", getDay(date.WeekDay));
      TimePageSprite.drawString(65, 00, buf, &AsciiFont24x48);
      snprintf(buf, 6, "%02d:%02d", time.Hours, time.Minutes);
      TimePageSprite.drawString(40, 40, buf, &AsciiFont24x48);
      snprintf(buf, 11, "%02d.%02d.%02d", date.Date, date.Month,
               date.Year - 2000);
      TimePageSprite.drawString(4, 80, buf, &AsciiFont24x48);
      String volts = getBatteryVoltage();
      snprintf(buf, 15, "%s", volts);
      TimePageSprite.drawString(04, 160, buf, &AsciiFont24x48);
    }
    
    void setup() {
      // Check power on reason before calling M5.begin()
      //  which calls Rtc.begin() which clears the timer flag.
      Wire1.begin(21, 22);
      uint8_t data = M5.rtc.ReadReg(0x01);
    
      M5.begin();
      // Green LED - indicates ESP32 is running
      digitalWrite(LED_EXT_PIN, LOW);
    
      if (M5.M5Ink.isInit() == false) {
        Serial.printf("Ink Init failed");
        while (1) delay(100);
      }
    
      RTC_TimeTypeDef time;
      RTC_DateTypeDef date;
    
      // Check timer flag
      if ((data & 0b00000100) == 0b00000100) {
        Serial.println("Power on by: RTC timer");
        M5.rtc.GetTime(&time);
        M5.rtc.GetDate(&date);
        // Full refresh once per hour
        if (time.Minutes == FULL_REFRESH_MINUTE - 1) {
          M5.M5Ink.clear();
        }
      } else {
        Serial.println("Power on by: power button");
        M5.M5Ink.clear();
        // Fetch current time from Internet
        getNTPTime();
        M5.rtc.GetTime(&time);
        M5.rtc.GetDate(&date);
      }
    
    
      // After every shutdown the sprite is created anew.
      // But the sprite doesn't know about the current image on the
      //  ink display therefore the same time and date, as have been
      //  drawn before the shutdown, are redrawn.
      // This is required, else drawing new time and date only adds
      //  pixels to the already drawn pixels instead of clearing the
      //  previous time and date and then draw the new time and date.
      TimePageSprite.creatSprite(0, 0, 200, 200);
    
      drawTimeAndDate(time, date);
      TimePageSprite.pushSprite();
    
      // Wait until full minute, e.g. seconds are 0
      while ((time.Seconds != 0)) {
        M5.rtc.GetTime(&time);
        delay(200);
      }
      M5.rtc.GetDate(&date);
    
      // Draw new time and date
      drawTimeAndDate(time, date);
      TimePageSprite.pushSprite();
    
      Serial.printf("Shutdown...\n");
      Serial.flush();
    
      // Full refresh once per hour
      if (time.Minutes == FULL_REFRESH_MINUTE - 1) {
        // Allow extra time for full ink refresh
        // Shutdown for 55 seconds only
        M5.shutdown(55);
        return;
      }
      // Shutdown for 58 seconds
      M5.shutdown(58);
    }
    
    void loop() {
    }
    
    


  • Hello @Steve1

    what makes you think it doesn't wake up anymore? Knowing whether M5Paper is actually running or not can be tricky as the data on the display stays w/ or w/o power.

    Anyways, when I run your code with USB power connected, then yes, it looks like it never wakes up, but in reality it stays powered on and just idles in loop().

    In contrast, when I run your code from battery, it actually does shutdown and restarts after about 5 seconds.

    Note: M5Paper cannot shutdown as long as it is powered by USB.

    Thanks
    Felix



  • Ah, thanks. Now I realise that I will develope the sketch further.