E-Ink, 2 Arduinos connected via Serial and my cats litter

Hello from Barcelona.

I’ve two cats and for me it’s hard sometimes to remember when I’ve cleaned their cat litters.

Instead of putting a post-it with the last date, I decided to do something more fancy:

As I have an e-ink Waveshare display I tried to create a device that, clicking a simple push-button would keep on-screen the date when I cleaned the cat’s litter.

The idea was that the display would keep the last date without the need for electricity until the next use.

For my setup, I tried with an Arduino Nano, the e-ink display and a DS3231 RTC.

Thanks to ZinggJM I was able to print on screen a static text, but trying to get the date from the screen and the time form the DS3231 didn’t work. I searched in the forum and there was another guy with a similar problem. (It look like that both the screen and the RTC module were using the I2C channel).

I tried to store the date, stop the RTC and then print on the screen, but I didn’t find any way of doing it.

In any case, including the e-ink display libraries and an array with the name of the days and the months the sketch couldn’t be uploaded to a single Arduino Nano due to the lack of free memory.

So the final setup was to use 2 Arduinos Nano: one for the Real-Time Clock that will send the data to the main Arduino via Serial. And the main Arduino will print it in the e-ink display.

My wiring at the moment looks like this:


(As I needed more GND pins, I have used the ones from the ICSP, I hope that it is correct in case of need)

HD version of the image

I decided that I do not want to keep the push-button pressed until the whole thing ends, so I have added the relay module to keep the system on until it ends.

The code that I send to the RTC Arduino (Number 2 in the image) is:

#include <Wire.h>
#include "RTClib.h"
 
RTC_DS3231 rtc;
 
// I'm going to declare two arrays with the name of the days and the names of the months.
// As I should clean the litters, at least twice a week
// I'm not interested into getting the day of the month number instead of the name of the day in the week
String daysOfTheWeek[7] = { "SUNDAY", "MONDAY", "TUESDAY", "WEDNESDAY", "THURSDAY", "FRIDAY", "SATURDAY" };
String monthsNames[12] = {"FEBRUARY", "MARCH", "APRIL", "MAY",  "JUNE", "JULY","AUGUST","SEPTEMBER","OCTOBER","NOVEMBER","DECEMBER","JANUARY" };
int monthNumber = 1;
String currentDate = "";
String currentDay = "";
 
void setup() {
  delay(4000); // I'm giving it some time before it does starts sending things to the main Arduino
   Serial.begin(115200); // I've tried with bigger baud rates, and it eventually worked 1 of every 20 times
 
   if (!rtc.begin()) {
      while (1);
   }
 
   if (rtc.lostPower()) {
      rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
   }
}
 

void printDate(DateTime date)
{
  monthNumber = (date.month(), DEC) - 1;
  currentDay = (date.day(), DEC);
  currentDate = currentDay + " " + (monthsNames[monthNumber]); //I create a string with the current day + the month name
   Serial.print(daysOfTheWeek[date.dayOfTheWeek()]);
   Serial.print("\n");// I also add this line break charachter for the screen
   Serial.print(date.day(), DEC);
   Serial.print(" ");
   Serial.println(monthsNames[monthnumber]);
}
 
void loop() {
   // Get the current date and send it via Serial
   DateTime now = rtc.now();
   printDate(now);
   delay(2000);
}

If I open the serial it sends me correctly the data.

The code for the main Arduino is this one:

#include <string.h>
#include <GxEPD.h>
#include <GxGDEH029A1/GxGDEH029A1.h>      // 2.9" b/w
#include <GxIO/GxIO_SPI/GxIO_SPI.h>
#include <GxIO/GxIO.h>
#include <Fonts/FreeMonoBold12pt7b.h>
#include <Fonts/FreeMonoBold24pt7b.h>

// constructor for AVR Arduino, copy from GxEPD_Example else
GxIO_Class io(SPI, /*CS=*/ SS, /*DC=*/ 8, /*RST=*/ 9); // arbitrary selection of 8, 9 selected for default of GxEPD_Class
GxEPD_Class display(io, /*RST=*/ 9, /*BUSY=*/ 7); // default selection of (9), 7
String currentDate;

void setup()
{
  pinMode(3, OUTPUT);
  digitalWrite(3, LOW); //I turn the realy pin on, so now there's no need to keep the push button pressed
  Serial.begin(115200);
  delay(2000);
  display.init();
  display.eraseDisplay(); //This works fine beacuse the screen flashes.
  pinMode(4, OUTPUT);
  digitalWrite(4, HIGH); //With this instruction I turn the second Arduino on.
}

void drawHelloWorld()
{
  display.fillScreen(GxEPD_WHITE);
  display.setTextColor(GxEPD_BLACK);
  display.setFont(&FreeMonoBold12pt7b);
  display.setRotation(15);
  display.setCursor(0, 15);
  display.print("LITTERS CLEANED:");
  display.setCursor(0, 70);
  display.setFont(&FreeMonoBold24pt7b);
  display.print(currentDate);
  delay(10000); // I give it some time to update the e-ink display
  digitalWrite(3, HIGH); //Finally I turn down the whole system desactivating the relay
}


void drawHelloWorld0() // If I call this function as a welcome screen, it always works 
{
  display.fillScreen(GxEPD_BLACK);
  display.setTextColor(GxEPD_WHITE);
  display.setFont(&FreeMonoBold24pt7b);
  display.setRotation(15);
  display.setCursor(0, 25);
  display.print("   _/)\n (^.^) MIU\n       MIU");
  display.setCursor(37, 25);
  display.print("/)");
  display.setCursor(58, 100);
  display.print(">^<");
  display.setCursor(15, 120);
  display.print("(    )");
}

void loop() {
  while (Serial.available()) {
    currentDate= Serial.readString();
    delay(3);
    if (currentDate.length() > 5) { //just a little checking to see if the is longer that a simple char
      display.drawPaged(drawHelloWorld); // version for AVR using paged drawing, works also on other processors
    }
  }
}

This code also claims that there is no so much free memory available (90% used).

The firsts test with the Arduinos plugged via USB to the computer worked 1 of 20 times.

I honestly don’t know what I’m doing wrong. I guess that there’s something wrong with the serial communication between both Arduinos, but when I click the push button the system starts and there’s a point that the main Arduino disconnects the relay, so it is receiving the data from the second Arduino.

Any help would be truly appreciated.

Greets from Barcelona

@Adolfito121,

For Newbies or new projects I recommend to use GxEPD2 instead of GxEPD. Both are available with Library Manager.

GxEPD2 has the advantage that you can specify the page_height to use for paged buffered drawing, thus controlling the amount of RAM to use for graphics buffer in the application, in the constructor statement.
The example GxEPD2_Example.ino shows e.g. for AVR processors how to let the compiler calculate the page_height starting from memory size MAX_DISPLAY_BUFFER_SIZE, e.g. 800.
(GxEPD uses a fixed number of pages for AVR processors in each driver class, and larger buffers.)

You should avoid the use of the String class with low memory processors such as Arduino UNO or NANO (AVR).
Using dynamically allocated and de-allocated memory (heap) on low memory processors is not a good idea.
It can lead to random hang-ups of the processor.

Declare all buffers on module level, not on function local level, to let the compiler check memory usage.

Note that the newer Waveshare e-paper boards have an issue with their "clever" reset circuit.
It has been reported that a reset pulse longer than 2ms can cause malfunction of the e-paper controller.
GxEPD2 has an optional parameter reset_duration for init() to cope with this. Use a value of 2.

Good Luck!

Jean-Marc

Thanks a lot for the help.

This evening I'll try your suggestions.

Greets from Barcelona

Sorry, I've been busy and I haven't been able to post until today.

Thanks a lot for the suggestions. Even using the GxEPD2 library the whole system failed, so the problem was in the Serial reading part.

I have simplified the whole project to one Arduino and hardcoded the code to reduce memory usage.

Now it works fine... and of course, I'm looking to complicate it a little bit :-[

I'm going to check if I can easily put a splash screen with a bitmap.

Greets from Barcelona