Skip to content

Commit f407fc1

Browse files
committed
Added support for IT8951 RPI HAT and two examples
1 parent ae9acd8 commit f407fc1

10 files changed

Lines changed: 236 additions & 37 deletions

File tree

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
CFLAGS=-g -D__LINUX__ -Wall -O2 -I../../
2+
LIBS=-g -lFastEPD -lgpiod
3+
4+
all: grayscale_demo
5+
6+
grayscale_demo: main.o
7+
$(CXX) main.o $(LIBS) -o grayscale_demo
8+
9+
main.o: main.cpp
10+
$(CXX) $(CFLAGS) -c main.cpp
11+
12+
clean:
13+
rm -rf *.o grayscale_demo
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
Important!!!
2+
In order for this code to work on the Raspberry Pi, the CE0 (chip select0)
3+
line of SPI0 must be changed/disabled in /boot/firmware/config.txt
4+
5+
Add this line:
6+
dtoverlay=spi0-1cs,cs0_pin=27
7+
8+
This will cause it to use BCM 27 (otherwise unused on the IT8951 HAT)
9+
10+
Without this change, the code will not work.
11+
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
//
2+
// Example for driving the Waveshare IT8951 "HAT" with FastEPD
3+
//
4+
#include <FastEPD.h>
5+
#include "../../../Fonts/Roboto_Black_40.h"
6+
FASTEPD epaper;
7+
8+
// BCM GPIO numbers for the RPI HAT
9+
#define IT8951_CS 8
10+
#define IT8951_SPI 0
11+
#define IT8951_RST 17
12+
#define IT8951_BUSY 24
13+
#define IT8951_ITE_EN -1
14+
#define IT8951_EN -1
15+
16+
int main(int argc, char *argv[])
17+
{
18+
int i;
19+
20+
// This configuration for this PCB contians info about the Eink connections and display type
21+
// initIT8951(uint8_t u8MOSI, uint8_t u8MISO, uint8_t u8CLK, uint8_t u8CS, uint8_t u8Busy, uint8_t u8RST, uint8_t u8EN, uint8_t u8ITE_EN);
22+
23+
i = epaper.initIT8951(IT8951_SPI, 0, 0, IT8951_CS, IT8951_BUSY, IT8951_RST, IT8951_EN, IT8951_ITE_EN);
24+
if (i != BBEP_SUCCESS) {
25+
printf("initIT8951 returned error: %d\n", i);
26+
return -1;
27+
}
28+
i = epaper.setPanelSize(BBEP_DISPLAY_ED078KC2);
29+
if (i != BBEP_SUCCESS) {
30+
printf("setPanelSize returned %d\n", i);
31+
return -1;
32+
}
33+
epaper.setMode(BB_MODE_4BPP);
34+
epaper.fillScreen(0xf); // white
35+
epaper.drawLine(0,0, 1000,1000, 0);
36+
epaper.setFont(Roboto_Black_40);
37+
epaper.setCursor(0, 60);
38+
for (i=0; i<16; i++) {
39+
epaper.setTextColor(i, 0xf);
40+
epaper.println("FastEPD IT8951 4-bit mode");
41+
}
42+
epaper.fullUpdate(CLEAR_SLOW, false); // the flag (false) tells it to turn off eink power after the update
43+
epaper.einkPower(0);
44+
epaper.deInit(); // save power by shutting down the TI power controller and I/O extender
45+
return 0;
46+
} /* main() */

examples/Linux/it8951_hat/Makefile

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
CFLAGS=-g -D__LINUX__ -Wall -O2 -I../../
2+
LIBS=-g -lFastEPD -lgpiod
3+
4+
all: hat_demo
5+
6+
hat_demo: main.o
7+
$(CXX) main.o $(LIBS) -o hat_demo
8+
9+
main.o: main.cpp
10+
$(CXX) $(CFLAGS) -c main.cpp
11+
12+
clean:
13+
rm -rf *.o hat_demo
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
Important!!!
2+
In order for this code to work on the Raspberry Pi, the CE0 (chip select0)
3+
line of SPI0 must be changed/disabled in /boot/firmware/config.txt
4+
5+
Add this line:
6+
dtoverlay=spi0-1cs,cs0_pin=27
7+
8+
This will cause it to use BCM 27 (otherwise unused on the IT8951 HAT)
9+
10+
Without this change, the code will not work.
11+

examples/Linux/it8951_hat/main.cpp

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
//
2+
// Example for driving the Waveshare IT8951 "HAT" with FastEPD
3+
//
4+
#include <FastEPD.h>
5+
#include "smiley.h"
6+
FASTEPD epaper;
7+
8+
// BCM GPIO numbers for the RPI HAT
9+
#define IT8951_CS 8
10+
#define IT8951_SPI 0
11+
#define IT8951_RST 17
12+
#define IT8951_BUSY 24
13+
#define IT8951_ITE_EN -1
14+
#define IT8951_EN -1
15+
16+
int main(int argc, char *argv[])
17+
{
18+
int i, j;
19+
float f;
20+
21+
// This configuration for this PCB contians info about the Eink connections and display type
22+
// initIT8951(uint8_t u8MOSI, uint8_t u8MISO, uint8_t u8CLK, uint8_t u8CS, uint8_t u8Busy, uint8_t u8RST, uint8_t u8EN, uint8_t u8ITE_EN);
23+
24+
i = epaper.initIT8951(IT8951_SPI, 0, 0, IT8951_CS, IT8951_BUSY, IT8951_RST, IT8951_EN, IT8951_ITE_EN);
25+
if (i != BBEP_SUCCESS) {
26+
printf("initIT8951 returned error: %d\n", i);
27+
return -1;
28+
}
29+
i = epaper.setPanelSize(BBEP_DISPLAY_ED078KC2);
30+
if (i != BBEP_SUCCESS) {
31+
printf("setPanelSize returned %d\n", i);
32+
return -1;
33+
}
34+
epaper.fillScreen(BBEP_WHITE);
35+
// The smiley image is 100x100 pixels; draw it at various scales from 0.5 to 2.0
36+
i = 0;
37+
f = 0.5f; // start at 1/2 size (50x50)
38+
for (j = 0; j < 12; j++) {
39+
epaper.loadG5Image(smiley, i, i, BBEP_WHITE, BBEP_BLACK, f);
40+
i += (int)(100.0f * f);
41+
f += 0.5f;
42+
}
43+
epaper.fullUpdate(CLEAR_SLOW, false); // the flag (false) tells it to turn off eink power after the update
44+
epaper.einkPower(0);
45+
epaper.deInit(); // save power by shutting down the TI power controller and I/O extender
46+
return 0;
47+
} /* main() */

examples/Linux/it8951_hat/smiley.h

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
// Created with image_to_c
2+
// https://github.com/bitbank2/image_to_c
3+
//
4+
// smiley
5+
// Data size = 240 bytes
6+
//
7+
// for non-Arduino builds...
8+
#ifndef PROGMEM
9+
#define PROGMEM
10+
#endif
11+
const uint8_t smiley[] PROGMEM = {
12+
0xbf,0xbb,0x64,0x00,0x64,0x00,0xe8,0x00,0x32,0xff,0x3a,0x82,0x93,0xa3,0x3d,0x04,
13+
0x0e,0x10,0x70,0x83,0x84,0x72,0x62,0x83,0x84,0x72,0x05,0x43,0xa3,0x8d,0x38,0xe1,
14+
0x02,0x06,0x1d,0x04,0x1b,0xa0,0x83,0x70,0x82,0x0d,0xd2,0x61,0xd2,0x6e,0x82,0x0d,
15+
0xd2,0x6e,0x93,0xe9,0xba,0x46,0x5a,0x5b,0xa4,0x61,0xf4,0x20,0xdb,0xa4,0x9a,0x6d,
16+
0xe9,0x6d,0xe9,0x5a,0xb7,0x55,0xbb,0xd5,0xab,0xd2,0xf6,0xf5,0xef,0x55,0xbb,0xd5,
17+
0xab,0xd7,0xef,0x5e,0xf5,0xfb,0xd7,0xbf,0xfe,0xbf,0x7a,0xdd,0xfb,0x5f,0xfa,0xff,
18+
0xbd,0x2f,0xbe,0xd3,0xff,0xaf,0xb4,0xff,0xeb,0xd3,0x4d,0x3f,0x11,0x8a,0xff,0xff,
19+
0xf9,0x88,0x23,0x34,0x5e,0x9a,0x72,0x52,0xf6,0xbe,0xd6,0xd7,0xff,0xd6,0xfe,0xb7,
20+
0xfa,0x7e,0xda,0xda,0x5d,0x26,0xfe,0xb7,0xfb,0x09,0xfb,0x41,0xaa,0xde,0xd6,0xbb,
21+
0x25,0x4c,0x22,0x77,0xf6,0xd3,0x0d,0x26,0x12,0xdc,0x43,0x69,0x0d,0x6d,0x86,0x12,
22+
0x5b,0xb6,0x95,0x6d,0x86,0x12,0x5b,0xb0,0xc2,0x55,0xb6,0x0c,0x10,0x4b,0x6c,0x33,
23+
0x8e,0x10,0x92,0xdb,0x14,0xb7,0x6a,0xad,0x86,0x12,0x5b,0x61,0x2d,0xb0,0xd2,0x56,
24+
0xc1,0x82,0x4a,0xd8,0x30,0x49,0x5b,0x15,0xda,0x56,0xd2,0xb0,0xc2,0x56,0xd2,0x86,
25+
0xd2,0xb0,0xc2,0x0a,0xc3,0x09,0x58,0x61,0x28,0x60,0xc1,0x05,0x67,0x20,0x51,0x43,
26+
0x39,0x31,0x41,0x43,0x10,0xa1,0x85,0x0c,0x28,0x30,0x53,0xa8,0x29,0x32,0xef,0x00};

src/FastEPD.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,7 @@ enum {
100100
BBEP_DISPLAY_ED103TC2,
101101
BBEP_DISPLAY_ED052TC4,
102102
BBEP_DISPLAY_ED1150C1,
103+
BBEP_DISPLAY_ED078KC2,
103104
BBEP_DISPLAY_COUNT
104105
};
105106

src/FastEPD.inl

Lines changed: 56 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,24 @@
3535
#define __BB_EP__
3636
#pragma GCC optimize("O2")
3737

38+
const uint8_t ucMirror[256] PROGMEM =
39+
{0, 128, 64, 192, 32, 160, 96, 224, 16, 144, 80, 208, 48, 176, 112, 240,
40+
8, 136, 72, 200, 40, 168, 104, 232, 24, 152, 88, 216, 56, 184, 120, 248,
41+
4, 132, 68, 196, 36, 164, 100, 228, 20, 148, 84, 212, 52, 180, 116, 244,
42+
12, 140, 76, 204, 44, 172, 108, 236, 28, 156, 92, 220, 60, 188, 124, 252,
43+
2, 130, 66, 194, 34, 162, 98, 226, 18, 146, 82, 210, 50, 178, 114, 242,
44+
10, 138, 74, 202, 42, 170, 106, 234, 26, 154, 90, 218, 58, 186, 122, 250,
45+
6, 134, 70, 198, 38, 166, 102, 230, 22, 150, 86, 214, 54, 182, 118, 246,
46+
14, 142, 78, 206, 46, 174, 110, 238, 30, 158, 94, 222, 62, 190, 126, 254,
47+
1, 129, 65, 193, 33, 161, 97, 225, 17, 145, 81, 209, 49, 177, 113, 241,
48+
9, 137, 73, 201, 41, 169, 105, 233, 25, 153, 89, 217, 57, 185, 121, 249,
49+
5, 133, 69, 197, 37, 165, 101, 229, 21, 149, 85, 213, 53, 181, 117, 245,
50+
13, 141, 77, 205, 45, 173, 109, 237, 29, 157, 93, 221, 61, 189, 125, 253,
51+
3, 131, 67, 195, 35, 163, 99, 227, 19, 147, 83, 211, 51, 179, 115, 243,
52+
11, 139, 75, 203, 43, 171, 107, 235, 27, 155, 91, 219, 59, 187, 123, 251,
53+
7, 135, 71, 199, 39, 167, 103, 231, 23, 151, 87, 215, 55, 183, 119, 247,
54+
15, 143, 79, 207, 47, 175, 111, 239, 31, 159, 95, 223, 63, 191, 127, 255};
55+
3856
// For measuring the performance of each stage of updates
3957
//#define SHOW_TIME
4058
// 8 columns by 16 rows. From white (15) to each gray (0-black to 15-white) at 20C
@@ -1734,6 +1752,10 @@ int bbepSetDefinedPanel(FASTEPDSTATE *pState, int iPanel)
17341752
bbepSetPanelSize(pState, 1872, 1404, BB_PANEL_FLAG_MIRROR_X, -1600);
17351753
bbepSetCustomMatrix(pState, u8TenPointThreeMatrix, sizeof(u8TenPointThreeMatrix));
17361754
break;
1755+
case BBEP_DISPLAY_ED078KC2:
1756+
bbepSetPanelSize(pState, 1872, 1404, BB_PANEL_FLAG_NONE, -1600);
1757+
bbepSetCustomMatrix(pState, u8TenPointThreeMatrix, sizeof(u8TenPointThreeMatrix));
1758+
break;
17371759
case BBEP_DISPLAY_ED052TC4:
17381760
bbepSetPanelSize(pState, 1280, 720, BB_PANEL_FLAG_MIRROR_X, -1600);
17391761
bbepSetCustomMatrix(pState, u8FivePointTwoMatrix, sizeof(u8FivePointTwoMatrix));
@@ -1778,6 +1800,7 @@ int bbepSetPanelSize(FASTEPDSTATE *pState, int width, int height, int flags, int
17781800
free(pState->pCurrent);
17791801
return BBEP_ERROR_NO_MEMORY;
17801802
}
1803+
#endif // LINUX
17811804
if (pState->iPanelType == BB_PANEL_IT8951) {
17821805
pState->pfnSetPixel = bbepSetPixel2Clr;
17831806
pState->pfnSetPixelFast = bbepSetPixelFast2Clr;
@@ -1789,7 +1812,6 @@ int bbepSetPanelSize(FASTEPDSTATE *pState, int width, int height, int flags, int
17891812
pState->rotation = 0;
17901813
return BBEP_SUCCESS; // for it8951 only
17911814
}
1792-
#endif // !__LINUX__
17931815

17941816
// Allocate memory for each line to transmit
17951817
#ifndef __LINUX__
@@ -2146,7 +2168,7 @@ IT8951DevInfo dev_info_;
21462168

21472169
void it8951WriteFramebuffer1Bit(FASTEPDSTATE *pState)
21482170
{
2149-
uint8_t *s;
2171+
uint8_t *s, *d;
21502172
int iPitch;
21512173

21522174
IT8951EinkPower(pState, 1);
@@ -2172,22 +2194,22 @@ int iPitch;
21722194
iPitch = (pState->native_width + 7)/8;
21732195
for (int y = 0; y < pState->native_height; y++) {
21742196
if (pState->iFlags & BB_PANEL_FLAG_MIRROR_X) {
2175-
uint8_t *d = pState->pTemp;
2197+
d = pState->pTemp;
21762198
for (int x = 0; x<iPitch; x++) {
21772199
d[iPitch - 1 - x] = s[x];
21782200
}
2179-
#ifdef ARDUINO
2180-
SPI.writeBytes(d, iPitch);
2181-
#elif defined(__LINUX__)
2182-
linux_spi_write(d, iPitch, pState->spi_frequency);
2183-
#endif
21842201
} else {
2202+
d = pState->pTemp;
2203+
for (int x = 0; x<iPitch; x+=2) { // work 16-bits at a time
2204+
d[x+1] = ucMirror[s[x]];
2205+
d[x] = ucMirror[s[x+1]];
2206+
}
2207+
}
21852208
#ifdef ARDUINO
2186-
SPI.writeBytes(s, iPitch);
2209+
SPI.writeBytes(d, iPitch);
21872210
#elif defined(__LINUX__)
2188-
linux_spi_write(s, iPitch, pState->spi_frequency);
2211+
linux_spi_write(d, iPitch, pState->spi_frequency);
21892212
#endif
2190-
}
21912213
if ((y & 0x07) == 0) {
21922214
yield();
21932215
}
@@ -2209,7 +2231,7 @@ int iPitch;
22092231

22102232
void it8951WriteFramebuffer4Bit(FASTEPDSTATE *pState)
22112233
{
2212-
uint8_t *s;
2234+
uint8_t *s, *d;
22132235
int iPitch;
22142236

22152237
IT8951EinkPower(pState, 1);
@@ -2236,22 +2258,22 @@ int iPitch;
22362258
iPitch = (pState->native_width + 1)/2;
22372259
for (int y = 0; y < pState->native_height; y++) {
22382260
if (pState->iFlags & BB_PANEL_FLAG_MIRROR_X) {
2239-
uint8_t *d = pState->pTemp;
2261+
d = pState->pTemp;
22402262
for (int x = 0; x<iPitch; x++) {
22412263
d[iPitch - 1 - x] = (s[x] >> 4) | (s[x] << 4);
22422264
}
2243-
#ifdef ARDUINO
2244-
SPI.writeBytes(d, iPitch);
2245-
#elif defined(__LINUX__)
2246-
linux_spi_write(d, iPitch, pState->spi_frequency);
2247-
#endif
22482265
} else {
2266+
d = pState->pTemp;
2267+
for (int x = 0; x<iPitch; x+=2) { // work 16-bits at a time
2268+
d[x+1] = (s[x] >> 4) | (s[x] << 4);
2269+
d[x] = (s[x+1] >> 4) | (s[x+1] << 4);
2270+
}
2271+
}
22492272
#ifdef ARDUINO
2250-
SPI.writeBytes(s, iPitch);
2273+
SPI.writeBytes(d, iPitch);
22512274
#elif defined(__LINUX__)
2252-
linux_spi_write(s, iPitch, pState->spi_frequency);
2275+
linux_spi_write(d, iPitch, pState->spi_frequency);
22532276
#endif
2254-
}
22552277
if ((y & 0x07) == 0) {
22562278
yield();
22572279
}
@@ -2269,7 +2291,7 @@ int iPitch;
22692291

22702292
void it8951WriteFramebuffer2Bit(FASTEPDSTATE *pState)
22712293
{
2272-
uint8_t *s;
2294+
uint8_t *s, *d;
22732295
int iPitch;
22742296

22752297
IT8951EinkPower(pState, 1);
@@ -2295,23 +2317,24 @@ int iPitch;
22952317
iPitch = (pState->native_width + 3)/4;
22962318
for (int y = 0; y < pState->native_height; y++) {
22972319
if (pState->iFlags & BB_PANEL_FLAG_MIRROR_X) {
2298-
uint8_t *d = pState->pTemp;
2320+
d = pState->pTemp;
22992321
for (int x = 0; x<iPitch; x++) {
23002322
uint8_t a = s[x];
23012323
d[iPitch - 1 - x] = (a >> 6) | ((a >> 2) & 0xc) | ((a & 0xc) << 2) | ((a & 3) << 6);
23022324
}
2303-
#ifdef ARDUINO
2304-
SPI.writeBytes(d, iPitch);
2305-
#elif defined(__LINUX__)
2306-
linux_spi_write(d, iPitch, pState->spi_frequency);
2307-
#endif
23082325
} else {
2326+
d = pState->pTemp;
2327+
for (int x = 0; x<iPitch; x+=2) { // work 16-bits at a time
2328+
uint8_t a = s[x], b = s[x+1];
2329+
d[x+1] = (a >> 6) | ((a >> 2) & 0xc) | ((a & 0xc) << 2) | ((a & 3) << 6);
2330+
d[x] = (b >> 6) | ((b >> 2) & 0xc) | ((b & 0xc) << 2) | ((b & 3) << 6);
2331+
}
2332+
}
23092333
#ifdef ARDUINO
2310-
SPI.writeBytes(s, iPitch);
2334+
SPI.writeBytes(d, iPitch);
23112335
#elif defined(__LINUX__)
2312-
linux_spi_write(s, iPitch, pState->spi_frequency);
2336+
linux_spi_write(d, iPitch, pState->spi_frequency);
23132337
#endif
2314-
}
23152338
if ((y & 0x07) == 0) {
23162339
yield();
23172340
}
@@ -2351,7 +2374,7 @@ int bbepInitIT8951(FASTEPDSTATE *pState, uint8_t u8MOSI, uint8_t u8MISO, uint8_t
23512374
gpio_set_level((gpio_num_t)u8ITE_EN, HIGH);
23522375
#ifdef ARDUINO
23532376
SPI.begin(u8CLK, u8MISO, u8MOSI, -1);
2354-
#else
2377+
#elif defined(__LINUX__)
23552378
linux_spi_init(u8MISO, u8MOSI, u8CLK);
23562379
#endif // ARDUINO
23572380
pState->spi_frequency = IT8951_SPI_PROBE_FREQUENCY;
@@ -2421,7 +2444,7 @@ int bbepInitIT8951(FASTEPDSTATE *pState, uint8_t u8MOSI, uint8_t u8MISO, uint8_t
24212444
it8951WriteCmdCode(pState, USDEF_I80_CMD_TEMP);
24222445
it8951WriteData(pState, 0x0001);
24232446
it8951WriteData(pState, 14);
2424-
// Serial.println("IT8951 initialization complete");
2447+
//printf("IT8951 initialization complete\n");
24252448
pState->iPanelType = BB_PANEL_IT8951;
24262449
pState->spi_frequency = IT8951_SPI_RUN_FREQUENCY; // switch to data frequency
24272450
return BBEP_SUCCESS;

0 commit comments

Comments
 (0)