M5 Paper e-ink CalculatorΒΆ

I added an M5 Paper to my collection of dev boards and decided to make a basic calculator to teach my son to count. Since he is only a few months old he mostly uses it as an expensive teething device.

The functionality is as follows:

  • Has a button to perform addition and add 1 to the current number

  • Has a button to reset to zero

  • Displays the number in decimal, binary and hex

  • Render the total as a dice depiction

  • Refresh will use fastest refresh type

  • Every 10th reset will do a full screen refresh to clear ink artefact

  • Shutdown after 15 minutes

M5 Ink Simple Calculator

I did notice that the platformio output for the serial monitor was producing garbage output which was fixed by hard coding the monitor_speed in the platformio.ini file as follows:

[env:m5stack-core2]
platform = espressif32
board = m5stack-core2
framework = arduino
lib_extra_dirs = ~/Documents/Arduino/libraries
lib_deps = m5stack/M5EPD@^0.1.1
monitor_speed = 115200

Sample CodeΒΆ

#include <string>
#include "Free_Fonts.h" // Include the header file attached to this sketch
#include <bitset>
#include<bits/stdc++.h>

using namespace std;

uint counter = 1;

void touchDectector() {

    if (M5.TP.avaliable())// check if touch driver is reachable
    {
        int c = 0;
        M5.TP.flush();// reset values
        while (M5.TP.getFingerNum() == 0)// while no fingers are detected
        {
            delay(50);
            M5.TP.update();
            // Serial.println("waiting...");
            c++;
            if (c >= 18000)// to go to sleep if nothing has happened after 15 mins-> energy saving
            {
                c = 0;
                Turn_off();
            }

        }
        if (M5.TP.getFingerNum() > 0)// if a finger has been detected
        {
            c = 0;
            while (M5.TP.getFingerNum() == 0) // waiting for input
            {
                delay(50);
                M5.TP.update();
                c++;
                if (c >= 18000) {
                    c = 0;
                    M5.TP.flush();
                    Turn_off();
                }
            }
            if (M5.TP.getFingerNum() > 0) // when input is received
            {
                int i;
                int b = 15;
                tp_finger_t FingerItem = M5.TP.readFinger(i);
                point[i][0] = FingerItem.x;
                point[i][1] = FingerItem.y;

                Serial.print("finger x: ");
                Serial.println(FingerItem.x);
                Serial.print("finger y: ");
                Serial.println(FingerItem.y);
                //if reset area pushed
                if (FingerItem.y <= 520 && FingerItem.x <= 140) {
                    counter = 1;
                    canvas.fillRect(0, 220, 550, 380, 0); //middle
                    canvas.useFreetypeFont(false);
                    canvas.setFreeFont(&FreeSansBold9pt7b);
                    canvas.setTextSize(4);
                    canvas.drawString("1", 260, 30, GFXFF);
                    drawDie();
                    canvas.pushCanvas(0, 0, UPDATE_MODE_DU4);
                    M5.TP.flush();
                } else {
                    counter++;
                }


                canvas.useFreetypeFont(false);
                canvas.setFreeFont(&FreeSansBold24pt7b);


                char res[1000];
                itoa(counter, res, 2); //binary
                // itoa(a,res,8);  //octal
                canvas.useFreetypeFont(false);
                canvas.setFreeFont(&FreeMono9pt7b);
                canvas.setTextSize(2);
                canvas.fillRect(25, 125, 500, 100, 0); //top
                canvas.drawString(res, 25, 125, GFXFF);  //left binary
                itoa(counter, res, 16); //hex
                canvas.drawString(res, 455, 125, GFXFF);  //right hex

                String myString = String(counter);
                canvas.useFreetypeFont(false);
                canvas.setFreeFont(&FreeSansBold24pt7b);

                canvas.setTextSize(30);
                canvas.fillRect(20, 220, 510, 340, 0); //middle
                canvas.drawString(myString, 90, 230, GFXFF);

                //dice here
                drawDie();
                // decide if full refresh
                if (counter % 10 == 0) {
                    canvas.pushCanvas(0, 0, UPDATE_MODE_GC16);
                } else {
                    canvas.pushCanvas(0, 0, UPDATE_MODE_DU4);

                }
                M5.TP.flush();
            }
        }
    }
}

void drawDie() {
    int xoffset = 25;
    int yoffset = 530;
    int diameter = 10;
    int xincrement = diameter * 2.5;
    int yincrement = diameter * 2.5;
    int currentDie = 1;
    int dotsleft = 0;
    int diecount = (counter + 6 - 1) / 6; //round to highest like ceil(conter/6)

    for (int i = 1; i <= counter; i++) {

        if (currentDie >= 2) {
            dotsleft = i - ((currentDie - 1) * 6);
        } else {
            dotsleft = i;
        }

        switch (dotsleft) {
            case 1:
                //middle dot
                canvas.fillCircle(xoffset + ((xincrement * 2) / 2), yoffset + (yincrement * 2 / 2), diameter, 255);
                break;
            case 2:
                canvas.fillCircle(xoffset, yoffset, diameter, 255); //top left
                canvas.fillCircle(xoffset + xincrement * 2, yoffset + yincrement * 2, diameter, 255); //bottom right
                canvas.fillCircle(xoffset + ((xincrement * 2) / 2), yoffset + (yincrement * 2 / 2), diameter,
                                  0); //white out middle
                break;
            case 3:
                canvas.fillCircle(xoffset, yoffset, diameter, 255); //top left
                canvas.fillCircle(xoffset + xincrement * 2, yoffset + yincrement * 2, diameter, 255); //bottom right

                //middle dot
                canvas.fillCircle(xoffset + ((xincrement * 2) / 2), yoffset + (yincrement * 2 / 2), diameter, 255);

                break;
            case 4:
                //clear dice here
                canvas.fillRect(xoffset, yoffset, diameter * 6, diameter * 6, 0); //cear dice area
                canvas.fillCircle(xoffset, yoffset, diameter, 255); //top left
                canvas.fillCircle(xoffset + xincrement * 2, yoffset, diameter, 255); //top right

                canvas.fillCircle(xoffset, yoffset + yincrement * 2, diameter, 255); //bottom left
                canvas.fillCircle(xoffset + xincrement * 2, yoffset + yincrement * 2, diameter, 255); //bottom right


                break;
            case 5:
                canvas.fillRect(xoffset, yoffset, diameter * 6, diameter * 6, 0); //cear dice area
                canvas.fillRect(xoffset, yoffset, diameter * 6, diameter * 6, 0); //cear dice area
                canvas.fillCircle(xoffset, yoffset, diameter, 255); //top left
                canvas.fillCircle(xoffset + xincrement * 2, yoffset, diameter, 255); //top right

                canvas.fillCircle(xoffset, yoffset + yincrement * 2, diameter, 255); //bottom left
                canvas.fillCircle(xoffset + xincrement * 2, yoffset + yincrement * 2, diameter, 255); //bottom right

                canvas.fillCircle(xoffset + ((xincrement * 2) / 2), yoffset + (yincrement * 2 / 2), diameter,
                                  255); //middle

                break;
            case 6:
                canvas.fillRect(xoffset, yoffset, diameter * 6, diameter * 6, 0); //cear dice area
                canvas.fillCircle(xoffset, yoffset, diameter, 255); //top left
                canvas.fillCircle(xoffset + xincrement * 2, yoffset, diameter, 255); //top right

                canvas.fillCircle(xoffset, yoffset + yincrement * 2, diameter, 255); //bottom left
                canvas.fillCircle(xoffset + xincrement * 2, yoffset + yincrement * 2, diameter, 255); //bottom right
                // canvas.fillCircle(xoffset + ((xincrement*2)/2),yoffset + (yincrement*2/2) ,diameter,255); //middle
                canvas.fillCircle(xoffset, yoffset + (yincrement * 2 / 2), diameter, 255); //middle left
                canvas.fillCircle(xoffset + xincrement * 2, yoffset + (yincrement * 2 / 2), diameter,
                                  255); //middle right

                break;

        }

        if (i % 6 == 0) {
            currentDie++;
            xoffset += diameter + (3 * 25);
        }
    }
}


void mode1() {
    canvas.deleteCanvas();
    canvas.createCanvas(540, 960);
    canvas.setTextSize(22);
    canvas.useFreetypeFont(false);
    canvas.setFreeFont(&FreeSansBold24pt7b);
    canvas.drawString("1", 90, 230, GFXFF);
    canvas.setTextSize(8);
    canvas.drawString("+1", 75, 655, GFXFF);
    canvas.useFreetypeFont(false);
    canvas.setFreeFont(&FreeSansBold9pt7b);
    canvas.setTextSize(4);
    canvas.drawString("1", 260, 30, GFXFF);
    drawDie();

    canvas.drawRect(20, 15 + (118 * 0), 500, 100, 15); //top
    canvas.drawRect(20, 45 + (118 * 5), 500, 300, 15); //bottom

    canvas.pushCanvas(0, 0, UPDATE_MODE_GC16);
    while (true) {
        touchDectector();
        delay(250);
    }
    delay(5000);
    Turn_off();

}

Comments

comments powered by Disqus