Skip to content

Commit 9f56890

Browse files
committed
Added low power eink clock example
1 parent 2ead295 commit 9f56890

6 files changed

Lines changed: 3420 additions & 3 deletions

File tree

examples/Arduino/simple_clock/Roboto_Black_140.h

Lines changed: 979 additions & 0 deletions
Large diffs are not rendered by default.

examples/Arduino/simple_clock/Roboto_Black_200.h

Lines changed: 1334 additions & 0 deletions
Large diffs are not rendered by default.

examples/Arduino/simple_clock/Roboto_Black_40.h

Lines changed: 328 additions & 0 deletions
Large diffs are not rendered by default.

examples/Arduino/simple_clock/Roboto_Black_80.h

Lines changed: 594 additions & 0 deletions
Large diffs are not rendered by default.
Lines changed: 182 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,182 @@
1+
//
2+
// FastEPD clock example
3+
//
4+
// written by Larry Bank (bitbank@pobox.com)
5+
// This program displays an attractive time, day and date display on your parallel
6+
// eink project. The time is updated once a minute with a non-flickering update.
7+
// To save power, the program uses the ESP32's deep sleep in between updates.
8+
// This creates a new problem - PSRAM contents are lost during deep sleep, so how
9+
// can we do a non-flickering update if we lost the previous image contents?
10+
// The solution is to save the last epoch time displayed in the ESP32's RTC RAM.
11+
// The 8 or 16K of RTC RAM can be retained in deep sleep for a few microamps of power.
12+
// With this info, we draw the previous time/date into PSRAM (not displayed), then draw
13+
// the new time/date and ask FastEPD to do a partial (differential) update.
14+
//
15+
// This program is free to use as you wish; no warranties are implied or granted
16+
//
17+
// N.B. For maximum battery life, remove the uSD card of your device (if present)
18+
//
19+
#include <NTPClient.h> //https://github.com/taranais/NTPClient
20+
#include <WiFi.h>
21+
#include <Wire.h>
22+
#include <esp_wifi.h>
23+
#include <HTTPClient.h>
24+
HTTPClient http;
25+
#include <FastEPD.h>
26+
// Use these fonts for a lower resolution display
27+
//#include "Roboto_Black_140.h"
28+
//#include "Roboto_Black_40.h"
29+
#include "Roboto_Black_80.h"
30+
#include "Roboto_Black_200.h"
31+
//
32+
// Change the SSID and PASSWORD to your local WiFi settings (and set the time zone offset)
33+
//
34+
const char *ssid = "your_sside";
35+
const char *password = "your_password";
36+
// Define your timezone offset in seconds from GMT - e.g. GMT-5 = (-5 * 3600)
37+
// This clock does not automatically adjust for daylight savings time, so you will need
38+
// to manually adjust your timezone offset (e.g. US Eastern time defined below)
39+
#define TIME_OFFSET -3600*5
40+
41+
FASTEPD bbep;
42+
// Keep these variables in the ESP32's RTC RAM which is preserved during deep sleep
43+
RTC_DATA_ATTR static int iCount = 0; // number of wakeups from deep sleep
44+
RTC_DATA_ATTR uint64_t oldEpoch = 0; // previous time for doing partial updates after deep sleep
45+
WiFiUDP ntpUDP;
46+
NTPClient timeClient(ntpUDP, "pool.ntp.org");
47+
// Change these to your favorite language; accented characters are okay too!
48+
const char *szMonths[] = {"January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"};
49+
const char *szDays[] = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"};
50+
//
51+
// Draw the current time
52+
// Parameters:
53+
// bPartial - true = use partial (non-flickering update)
54+
// epoch - the epoch time/date to display
55+
// bUseAsOld - flag indicating to only draw the image internally and not display it
56+
//
57+
void DisplayTime(bool bPartial, uint64_t epoch, bool bUseAsOld)
58+
{
59+
char szTemp[32];
60+
BB_RECT rect;
61+
62+
bbep.fillScreen(BBEP_WHITE);
63+
bbep.setFont(Roboto_Black_200);
64+
bbep.setTextColor(BBEP_BLACK, BBEP_WHITE);
65+
// Get the current time
66+
// localtime_r((time_t *)&epoch, &myTime);
67+
struct tm *myTime = gmtime ((time_t *)&epoch);
68+
sprintf(szTemp, "%02d:%02d", myTime->tm_hour, myTime->tm_min);
69+
bbep.getStringBox(szTemp, &rect);
70+
bbep.setCursor((bbep.width() - rect.w)/2, 350); // horizontal center
71+
bbep.print(szTemp);
72+
bbep.setFont(Roboto_Black_80);
73+
sprintf(szTemp, "%s", szDays[myTime->tm_wday]);
74+
bbep.getStringBox(szTemp, &rect);
75+
bbep.setCursor((bbep.width() - rect.w)/2, 500); // horizontal center
76+
bbep.print(szTemp); // print the day of the week
77+
sprintf(szTemp, "%s %d", szMonths[myTime->tm_mon], myTime->tm_mday);
78+
bbep.getStringBox(szTemp, &rect);
79+
bbep.setCursor((bbep.width() - rect.w)/2, 660); // horizontal center
80+
bbep.print(szTemp); // print the day of the week
81+
82+
if (bUseAsOld) {
83+
bbep.backupPlane(); // copy current image to previous
84+
} else {
85+
int rc;
86+
if (bPartial) {
87+
rc = bbep.partialUpdate(false);
88+
} else {
89+
rc = bbep.fullUpdate(CLEAR_FAST, false);
90+
}
91+
}
92+
} /* DisplayTime() */
93+
94+
void setup() {
95+
bool res;
96+
int rc, iTimeout;
97+
98+
Serial.begin(115200);
99+
delay(3000);
100+
Serial.println("Starting...");
101+
// This demo was written for Martin Fasani's "Sensoria" S3 and C5 boards
102+
// They feature a 5.2" 1280x720 8-bit parallel eink panel
103+
rc = bbep.initPanel(BB_PANEL_V7_RAW);
104+
if (rc != BBEP_SUCCESS) Serial.println("Init panel error");
105+
rc = bbep.setPanelSize(BBEP_DISPLAY_ED052TC4);
106+
if (rc != BBEP_SUCCESS) Serial.println("Init panel size error");
107+
bbep.setRotation(180);
108+
bbep.fillScreen(BBEP_WHITE);
109+
bbep.setPasses(6,6); // depends on the panel you're using - larger number = more contrast
110+
111+
if (iCount == 0) { // First time starting from reset - show WiFi status
112+
bbep.setFont(FONT_12x16);
113+
bbep.setCursor(0, 16);
114+
bbep.setTextColor(BBEP_BLACK, BBEP_WHITE);
115+
bbep.printf("Connecting to WiFi AP: %s\n", ssid);
116+
bbep.fullUpdate(CLEAR_SLOW);
117+
}
118+
119+
if ((iCount & 2047) == 0) { // sync the internal RTC to NTP time every 35 hours
120+
WiFi.begin(ssid, password);
121+
iTimeout = 0;
122+
while (WiFi.status() != WL_CONNECTED && iTimeout < 60) {
123+
delay(500); // allow up to 10 seconds to connect
124+
iTimeout++;
125+
}
126+
if (WiFi.status() == WL_CONNECTED) {
127+
if (iCount == 0) {
128+
bbep.println("\nConnected!");
129+
bbep.partialUpdate(false);
130+
bbep.fillScreen(BBEP_WHITE);
131+
}
132+
} else {
133+
if (iCount == 0) {
134+
bbep.println("\nConnection failed!");
135+
bbep.partialUpdate(false);
136+
}
137+
while (1) {}
138+
}
139+
// Initialize a NTPClient to get time
140+
timeClient.begin();
141+
timeClient.setTimeOffset(TIME_OFFSET);
142+
uint64_t epochTime = 0;
143+
// loop until we get the NTP time; this can take many seconds on the ESP32-C5
144+
while (epochTime < 1577836800) {
145+
timeClient.update();
146+
epochTime = timeClient.getEpochTime();
147+
vTaskDelay(50); // wait until the time is actually set correctly
148+
}
149+
//Get a time structure
150+
struct tm *ptm = gmtime ((time_t *)&epochTime);
151+
timeval tv;
152+
tv.tv_sec = epochTime;
153+
settimeofday(&tv, nullptr); // set internal RTC with the correct time
154+
timeClient.end(); // don't need it any more
155+
WiFi.disconnect(true);
156+
WiFi.mode(WIFI_OFF);
157+
} // need to sync the time
158+
159+
} /* setup() */
160+
161+
void deepSleep(uint64_t time_in_ms)
162+
{
163+
esp_sleep_enable_timer_wakeup(time_in_ms * 1000L);
164+
esp_deep_sleep_start();
165+
}
166+
167+
void loop() {
168+
struct timeval tv;
169+
170+
gettimeofday(&tv, NULL);
171+
if ((iCount % 10) == 0) {
172+
DisplayTime(false, tv.tv_sec, false); // do a full update every 10 times
173+
} else {
174+
DisplayTime(true, oldEpoch, true); // redraw old time buffer for partial update
175+
DisplayTime(true, tv.tv_sec, false); // draw new time and do partial update
176+
}
177+
oldEpoch = tv.tv_sec;
178+
iCount++;
179+
bbep.deInit(); // put eInk hardware in low power mode
180+
deepSleep(60000); // sleep for 1 minute (saves energy when running from a battery)
181+
//delay(60000); // use delay if you want to keep PSRAM and USB active
182+
} /* loop() */

src/FastEPD.inl

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -227,7 +227,7 @@ const BBPANELDEF panelDefs[] = {
227227
10, 0, 2, 42, 1, 0, 46 /* LoRa CS */, u8M5Matrix, sizeof(u8M5Matrix), 16, -1600}, // BB_PANEL_LILYGO_T5PRO
228228
{1440, 720, 40000000, BB_PANEL_FLAG_MIRROR_X, {27,28,29,30,31,32,33,34}, 8, BB_NOT_USED, 36, 13, 25, 0, 26,
229229
24, 0, 7, 8, 0, 0, 11 /* LED1_EN */, u8M5Matrix, sizeof(u8M5Matrix), 16, -1600}, // BB_PANEL_LILYGO_T5P4
230-
{1872, 1404, 26666666, BB_PANEL_FLAG_MIRROR_X | BB_PANEL_FLAG_SLOW_SPH, {8,18,17,16,15,7,6,5,47,21,14,13,12,11,10,9}, 16, 11, 48, 45, 41, 8, 42,
230+
{1872, 1404, 26666666, BB_PANEL_FLAG_MIRROR_X, {8,18,17,16,15,7,6,5,47,21,14,13,12,11,10,9}, 16, 11, 48, 45, 41, 8, 42,
231231
4, 14, 39, 40, BB_NOT_USED, 0, 46, u8GrayMatrix, sizeof(u8GrayMatrix), 16, -1100}, // BB_PANEL_TRMNL_X
232232
{0, 0, 26666666, BB_PANEL_FLAG_NONE, {2,3,4,5,6,7,8,9}, 8, 26, 45, 51, 46, 47, 48,
233233
50, 27, 28, 29, 37, 0, 35, u8GrayMatrix, sizeof(u8GrayMatrix), 32, -1600}, // BB_PANEL_EPDINKY_P4
@@ -1396,7 +1396,7 @@ void EPDiyV7RowControl(void *pBBEP, int iType)
13961396
gpio_set_level(le, 0);
13971397
delayMicroseconds(0);
13981398
}
1399-
}
1399+
} /* EPDiyV7RowControl() */
14001400

14011401
void SensoriaRowControl(void *pBBEP, int iType)
14021402
{
@@ -1620,7 +1620,6 @@ void bbepWriteRow(FASTEPDSTATE *pState, uint8_t *pData, int iLen, int bRowStep)
16201620
}
16211621
if (bSlowSPH) {
16221622
gpio_set_level(u8SPH, 0); // SPH/CS active
1623-
// gpio_set_level(u8CKV, 1); // CKV on
16241623
}
16251624
dma_is_done = false;
16261625
gpio_set_level((gpio_num_t)pState->panelDef.ioCKV, 1); // CKV on
@@ -3582,5 +3581,6 @@ void bbepBackupPlane(FASTEPDSTATE *pState)
35823581
int iSize = (pState->native_width/2) * pState->native_height;
35833582
if (!pState->pPrevious || !pState->pCurrent) return;
35843583
memcpy(pState->pPrevious, pState->pCurrent, iSize);
3584+
pState->prev_mode = pState->mode; // indicate both buffers are the same bpp mode
35853585
}
35863586
#endif // __BB_EP__

0 commit comments

Comments
 (0)