Skip to content

Commit b51d8c3

Browse files
authored
Merge pull request #41 from adafruit/acephacking
Add ACEP (7-color EPD) support
2 parents 8dd246e + 80b2102 commit b51d8c3

File tree

9 files changed

+476
-45
lines changed

9 files changed

+476
-45
lines changed

.github/workflows/githubci.yml

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,14 @@ jobs:
1919
- name: pre-install
2020
run: bash ci/actions_install.sh
2121

22+
# manually install SDFat
23+
- name: extra libraries
24+
run: |
25+
git clone --quiet https://github.com/adafruit/SdFat.git /home/runner/Arduino/libraries/SdFat
26+
git clone --quiet https://github.com/adafruit/Adafruit_SPIFlash.git /home/runner/Arduino/libraries/Adafruit_SPIFlash
27+
2228
- name: test platforms
23-
run: python3 ci/build_platform.py main_platforms cpb cpx
29+
run: python3 ci/build_platform.py main_platforms metro_m4_tinyusb cpb cpx
2430

2531
- name: clang
2632
run: python3 ci/run-clang-format.py -e "ci/*" -e "bin/*" -r .

examples/acep_7ColorTest/.metro_m4_tinyusb.test.only

Whitespace-only changes.
Lines changed: 263 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,263 @@
1+
/***************************************************
2+
Adafruit invests time and resources providing this open source code,
3+
please support Adafruit and open-source hardware by purchasing
4+
products from Adafruit!
5+
6+
Written by Limor Fried/Ladyada for Adafruit Industries.
7+
MIT license, all text above must be included in any redistribution
8+
****************************************************/
9+
10+
11+
#include <SPI.h>
12+
#include <SdFat.h>
13+
#include <Adafruit_SPIFlash.h>
14+
#include "Adafruit_EPD.h"
15+
16+
17+
#define EPD_CS 9
18+
#define EPD_DC 10
19+
#define SRAM_CS -1 // Use the build in memory, we need 133KB!
20+
#define EPD_RESET 6 // can set to -1 and share with microcontroller Reset!
21+
#define EPD_BUSY 5 // can set to -1 to not use a pin (will wait a fixed delay)
22+
23+
// Uncomment the following line if you are using ACeP 7 color 5.65"
24+
Adafruit_ACEP display(600, 448, EPD_DC, EPD_RESET, EPD_CS, SRAM_CS, EPD_BUSY);
25+
26+
Adafruit_FlashTransport_QSPI flashTransport;
27+
Adafruit_SPIFlash flash(&flashTransport);
28+
FatFileSystem fatfs;
29+
30+
void setup() {
31+
Serial.begin(115200);
32+
while (!Serial) { delay(10); }
33+
34+
Serial.println("Adafruit ACeP EPD test");
35+
36+
if (!flash.begin()) {
37+
Serial.println("Error, failed to initialize flash chip!");
38+
while(1) delay(1);
39+
}
40+
Serial.print("Flash chip JEDEC ID: 0x"); Serial.println(flash.getJEDECID(), HEX);
41+
// First call begin to mount the filesystem. Check that it returns true
42+
// to make sure the filesystem was mounted.
43+
if (!fatfs.begin(&flash)) {
44+
Serial.println("Error, failed to mount newly formatted filesystem!");
45+
Serial.println("Was the flash chip formatted with the fatfs_format example?");
46+
while(1) delay(1);
47+
}
48+
Serial.println("Mounted filesystem!");
49+
File root = fatfs.open("/");
50+
printDirectory(root, 0);
51+
52+
display.begin();
53+
display.setRotation(0);
54+
display.clearBuffer();
55+
// draw 7 color bars
56+
for (uint8_t color=ACEP_COLOR_BLACK; color<=ACEP_COLOR_ORANGE; color++) {
57+
display.fillRect(display.width()*color/7, 0, display.width()/7, display.height(), color);
58+
}
59+
display.display();
60+
}
61+
62+
void loop() {
63+
bmpDraw("adafruit_characters.bmp", 0, 0);
64+
bmpDraw("adabot.bmp", 0, 0);
65+
66+
}
67+
68+
69+
70+
71+
72+
73+
74+
// This function opens a Windows Bitmap (BMP) file and
75+
// displays it at the given coordinates. It's sped up
76+
// by reading many pixels worth of data at a time
77+
// (rather than pixel by pixel). Increasing the buffer
78+
// size takes more of the Arduino's precious RAM but
79+
// makes loading a little faster. 20 pixels seems a
80+
// good balance.
81+
82+
#define BUFFPIXEL 20
83+
84+
bool bmpDraw(char *filename, int16_t x, int16_t y) {
85+
File bmpFile;
86+
int bmpWidth, bmpHeight; // W+H in pixels
87+
uint8_t bmpDepth; // Bit depth (currently must be 24)
88+
uint32_t bmpImageoffset; // Start of image data in file
89+
uint32_t rowSize; // Not always = bmpWidth; may have padding
90+
uint8_t sdbuffer[3*BUFFPIXEL]; // pixel buffer (R+G+B per pixel)
91+
uint8_t buffidx = sizeof(sdbuffer); // Current position in sdbuffer
92+
boolean goodBmp = false; // Set to true on valid header parse
93+
boolean flip = true; // BMP is stored bottom-to-top
94+
int w, h, row, col, x2, y2, bx1, by1;
95+
uint8_t r, g, b;
96+
uint32_t pos = 0, startTime = millis();
97+
98+
if((x >= display.width()) || (y >= display.height())) return false;
99+
100+
Serial.println();
101+
Serial.print(F("Loading image '"));
102+
Serial.print(filename);
103+
Serial.println('\'');
104+
105+
// Open requested file on SD card
106+
if ((bmpFile = fatfs.open(filename, FILE_READ)) == NULL) {
107+
Serial.print(F("File not found"));
108+
return false;
109+
}
110+
111+
// Parse BMP header
112+
if (read16(bmpFile) == 0x4D42) { // BMP signature
113+
Serial.print(F("File size: ")); Serial.println(read32(bmpFile));
114+
(void)read32(bmpFile); // Read & ignore creator bytes
115+
bmpImageoffset = read32(bmpFile); // Start of image data
116+
Serial.print(F("Image Offset: ")); Serial.println(bmpImageoffset, DEC);
117+
// Read DIB header
118+
Serial.print(F("Header size: ")); Serial.println(read32(bmpFile));
119+
bmpWidth = read32(bmpFile);
120+
bmpHeight = read32(bmpFile);
121+
if(read16(bmpFile) == 1) { // # planes -- must be '1'
122+
bmpDepth = read16(bmpFile); // bits per pixel
123+
Serial.print(F("Bit Depth: ")); Serial.println(bmpDepth);
124+
if((bmpDepth == 24) && (read32(bmpFile) == 0)) { // 0 = uncompressed
125+
126+
goodBmp = true; // Supported BMP format -- proceed!
127+
Serial.print(F("Image size: "));
128+
Serial.print(bmpWidth);
129+
Serial.print('x');
130+
Serial.println(bmpHeight);
131+
132+
// BMP rows are padded (if needed) to 4-byte boundary
133+
rowSize = (bmpWidth * 3 + 3) & ~3;
134+
135+
// If bmpHeight is negative, image is in top-down order.
136+
// This is not canon but has been observed in the wild.
137+
if(bmpHeight < 0) {
138+
bmpHeight = -bmpHeight;
139+
flip = false;
140+
}
141+
142+
// Crop area to be loaded
143+
x2 = x + bmpWidth - 1; // Lower-right corner
144+
y2 = y + bmpHeight - 1;
145+
if((x2 >= 0) && (y2 >= 0)) { // On screen?
146+
w = bmpWidth; // Width/height of section to load/display
147+
h = bmpHeight;
148+
bx1 = by1 = 0; // UL coordinate in BMP file
149+
150+
for (row=0; row<h; row++) { // For each scanline...
151+
152+
// Seek to start of scan line. It might seem labor-
153+
// intensive to be doing this on every line, but this
154+
// method covers a lot of gritty details like cropping
155+
// and scanline padding. Also, the seek only takes
156+
// place if the file position actually needs to change
157+
// (avoids a lot of cluster math in SD library).
158+
if(flip) // Bitmap is stored bottom-to-top order (normal BMP)
159+
pos = bmpImageoffset + (bmpHeight - 1 - (row + by1)) * rowSize;
160+
else // Bitmap is stored top-to-bottom
161+
pos = bmpImageoffset + (row + by1) * rowSize;
162+
pos += bx1 * 3; // Factor in starting column (bx1)
163+
if(bmpFile.position() != pos) { // Need seek?
164+
bmpFile.seek(pos);
165+
buffidx = sizeof(sdbuffer); // Force buffer reload
166+
}
167+
for (col=0; col<w; col++) { // For each pixel...
168+
// Time to read more pixel data?
169+
if (buffidx >= sizeof(sdbuffer)) { // Indeed
170+
bmpFile.read(sdbuffer, sizeof(sdbuffer));
171+
buffidx = 0; // Set index to beginning
172+
}
173+
// Convert pixel from BMP to EPD format, push to display
174+
b = sdbuffer[buffidx++];
175+
g = sdbuffer[buffidx++];
176+
r = sdbuffer[buffidx++];
177+
uint32_t color = r;
178+
color <<= 8;
179+
color |= g;
180+
color <<= 8;
181+
color |= b;
182+
183+
uint8_t c;
184+
switch (color) {
185+
case 0x000000: c = ACEP_COLOR_BLACK; break;
186+
case 0xFFFFFF: c = ACEP_COLOR_WHITE; break;
187+
case 0x00FF00: c = ACEP_COLOR_GREEN; break;
188+
case 0x0000FF: c = ACEP_COLOR_BLUE; break;
189+
case 0xFF0000: c = ACEP_COLOR_RED; break;
190+
case 0xFFFF00: c = ACEP_COLOR_YELLOW; break;
191+
case 0xFF8000: c = ACEP_COLOR_ORANGE; break;
192+
default: {
193+
Serial.print("Unknown color 0x");
194+
Serial.println(color, HEX);
195+
c = ACEP_COLOR_WHITE;
196+
}
197+
}
198+
display.writePixel(col, row, c);
199+
} // end pixel
200+
} // end scanline
201+
} // end onscreen
202+
display.display();
203+
Serial.print(F("Loaded in "));
204+
Serial.print(millis() - startTime);
205+
Serial.println(" ms");
206+
} // end goodBmp
207+
}
208+
}
209+
210+
bmpFile.close();
211+
if(!goodBmp) {
212+
Serial.println(F("BMP format not recognized."));
213+
return false;
214+
}
215+
return true;
216+
}
217+
218+
// These read 16- and 32-bit types from the SD card file.
219+
// BMP data is stored little-endian, Arduino is little-endian too.
220+
// May need to reverse subscript order if porting elsewhere.
221+
222+
uint16_t read16(File &f) {
223+
uint16_t result;
224+
((uint8_t *)&result)[0] = f.read(); // LSB
225+
((uint8_t *)&result)[1] = f.read(); // MSB
226+
return result;
227+
}
228+
229+
uint32_t read32(File &f) {
230+
uint32_t result;
231+
((uint8_t *)&result)[0] = f.read(); // LSB
232+
((uint8_t *)&result)[1] = f.read();
233+
((uint8_t *)&result)[2] = f.read();
234+
((uint8_t *)&result)[3] = f.read(); // MSB
235+
return result;
236+
}
237+
238+
239+
void printDirectory(File dir, int numTabs) {
240+
char filename[80];
241+
242+
while (true) {
243+
File entry = dir.openNextFile();
244+
if (! entry) {
245+
// no more files
246+
break;
247+
}
248+
for (uint8_t i = 0; i < numTabs; i++) {
249+
Serial.print('\t');
250+
}
251+
entry.getName(filename, 80);
252+
Serial.print(filename);
253+
if (entry.isDirectory()) {
254+
Serial.println("/");
255+
printDirectory(entry, numTabs + 1);
256+
} else {
257+
// files have sizes, directories do not
258+
Serial.print("\t\t");
259+
Serial.println(entry.size(), DEC);
260+
}
261+
entry.close();
262+
}
263+
}

examples/acep_7ColorTest/adabot.bmp

788 KB
Binary file not shown.
Binary file not shown.

src/Adafruit_EPD.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -290,7 +290,7 @@ void Adafruit_EPD::writeRAMFramebufferToEPD(uint8_t *framebuffer,
290290
dcHigh();
291291
// Serial.printf("Writing from RAM location %04x: \n", &framebuffer);
292292

293-
for (uint16_t i = 0; i < framebuffer_size; i++) {
293+
for (uint32_t i = 0; i < framebuffer_size; i++) {
294294
uint8_t d = framebuffer[i];
295295
if (invertdata)
296296
d = ~d;

src/Adafruit_EPD.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -155,8 +155,8 @@ class Adafruit_EPD : public Adafruit_GFX {
155155

156156
uint8_t layer_colors[EPD_NUM_COLORS];
157157

158-
uint16_t buffer1_size; ///< size of the primary buffer
159-
uint16_t buffer2_size; ///< size of the secondary buffer
158+
uint32_t buffer1_size; ///< size of the primary buffer
159+
uint32_t buffer2_size; ///< size of the secondary buffer
160160
uint8_t *buffer1; ///< the pointer to the primary buffer if using on-chip ram
161161
uint8_t
162162
*buffer2; ///< the pointer to the secondary buffer if using on-chip ram

0 commit comments

Comments
 (0)