diff --git a/rpi/examples/hello_epaper/Makefile b/rpi/examples/hello_epaper/Makefile new file mode 100644 index 0000000..115051f --- /dev/null +++ b/rpi/examples/hello_epaper/Makefile @@ -0,0 +1,16 @@ +CFLAGS=-D_LINUX_ -Wall -O2 -I../../ +LIBS=-lgpiod + +all: hello_epaper + +hello_epaper: main.o bb_epaper.o + $(CXX) main.o bb_epaper.o $(LIBS) -o hello_epaper + +main.o: main.cpp + $(CXX) $(CFLAGS) -c main.cpp + +bb_epaper.o: ../../../src/bb_epaper.cpp ../../../src/bb_epaper.h + $(CXX) $(CFLAGS) -c ../../../src/bb_epaper.cpp + +clean: + rm -rf *.o hello_epaper diff --git a/rpi/examples/hello_epaper/main.cpp b/rpi/examples/hello_epaper/main.cpp new file mode 100644 index 0000000..9ba593f --- /dev/null +++ b/rpi/examples/hello_epaper/main.cpp @@ -0,0 +1,14 @@ +// +// C++ example for bb_epaper library +// written by Larry Bank (bitbank@pobox.com) +// Project started 9/23/2024 +// Copyright (c) 2024 BitBank Software, Inc. +// +#include "../../../src/bb_epaper.h" +BBEPAPER bbep(EPD27_176x264); // Waveshare 2.7" e-paper HAT + +int main(int argc, const char * argv[]) { + return 0; +} /* main() */ + + diff --git a/rpi/rpi_io.inl b/rpi/rpi_io.inl index a217bfc..15c5af9 100644 --- a/rpi/rpi_io.inl +++ b/rpi/rpi_io.inl @@ -17,8 +17,8 @@ // Adapt these functions to whatever target platform you're using // and the rest of the code can remain unchanged // -#ifndef __BB_EI_IO__ -#define __BB_EI_IO__ +#ifndef __BB_EP_IO__ +#define __BB_EP_IO__ #include #include @@ -31,17 +31,22 @@ #include #include #include +#ifndef CONSUMER +#define CONSUMER "Consumer" +#endif +#define pgm_read_byte(a) *(uint8_t *)a +#define memcpy_P memcpy struct gpiod_chip *chip = NULL; struct gpiod_line *lines[64]; static int spi_fd; // SPI handle -void SPI_transfer(BBEIDISP *pBBEI, uint8_t *pBuf, int iLen) +void SPI_transfer(BBEPDISP *pBBEP, uint8_t *pBuf, int iLen) { struct spi_ioc_transfer spi; memset(&spi, 0, sizeof(spi)); spi.tx_buf = (unsigned long)pBuf; spi.len = iLen; - spi.speed_hz = pBBEI->iSpeed; + spi.speed_hz = pBBEP->iSpeed; spi.bits_per_word = 8; ioctl(spi_fd, SPI_IOC_MESSAGE(1), &spi); } /* SPI_transfer() */ @@ -71,7 +76,7 @@ void pinMode(int iPin, int iMode) } } /* pinMode() */ -static void delay(int iMS) +void delay(int iMS) { usleep(iMS * 1000); } /* delay() */ @@ -84,105 +89,92 @@ static void delayMicroseconds(int iMS) // // Initialize the GPIO pins and SPI for use by bb_eink // -void bbeiInitIO(BBEIDISP *pBBEI, uint32_t u32Speed) +void bbepInitIO(BBEPDISP *pBBEP, uint32_t u32Speed) { - pinMode(pBBEI->iDCPin, OUTPUT); - pinMode(pBBEI->iRSTPin, OUTPUT); - digitalWrite(pBBEI->iRSTPin, LOW); +char szName[32]; + + pinMode(pBBEP->iDCPin, OUTPUT); + pinMode(pBBEP->iRSTPin, OUTPUT); + digitalWrite(pBBEP->iRSTPin, LOW); delay(100); - digitalWrite(pBBEI->iRSTPin, HIGH); + digitalWrite(pBBEP->iRSTPin, HIGH); delay(100); - if (pBBEI->iBUSYPin != 0xff) { - pinMode(pBBEI->iBUSYPin, INPUT); + if (pBBEP->iBUSYPin != 0xff) { + pinMode(pBBEP->iBUSYPin, INPUT); } - pBBEI->iSpeed = u32Speed; - pinMode(pBBEI->iCSPin, OUTPUT); - digitalWrite(pBBEI->iCSPin, HIGH); // we have to manually control the CS pin - spi_fd = open("/dev/spidev0.1", O_RDWR); // DEBUG - open SPI channel 0 -} /* bbeiInitIO() */ + pBBEP->iSpeed = u32Speed; + pinMode(pBBEP->iCSPin, OUTPUT); + digitalWrite(pBBEP->iCSPin, HIGH); // we have to manually control the CS pin + sprintf(szName, "/dev/spidev%d.0", pBBEP->iMOSIPin); // SPI channel # + spi_fd = open(szName, O_RDWR); + //spi_fd = open("/dev/spidev0.1", O_RDWR); // DEBUG - open SPI channel 0 +} /* bbepInitIO() */ // // Toggle the reset line to wake up the eink from deep sleep // -void bbeiWakeUp(BBEIDISP *pBBEI) +void bbepWakeUp(BBEPDISP *pBBEP) { - digitalWrite(pBBEI->iRSTPin, LOW); + digitalWrite(pBBEP->iRSTPin, LOW); delay(10); - digitalWrite(pBBEI->iRSTPin, HIGH); + digitalWrite(pBBEP->iRSTPin, HIGH); delay(10); -} /* bbeiWakeUp() */ +} /* bbepWakeUp() */ // // Wait for the busy status line to show idle // The polarity of the busy signal is reversed on the UC81xx compared // to the SSD16xx controllers // -void bbeiWaitBusy(BBEIDISP *pBBEI) +void bbepWaitBusy(BBEPDISP *pBBEP) { - uint8_t busy_idle = (pBBEI->chip_type == BBEI_CHIP_UC81xx) ? HIGH : LOW; + uint8_t busy_idle = (pBBEP->chip_type == BBEP_CHIP_UC81xx) ? HIGH : LOW; delay(1); // some panels need a short delay before testing the BUSY line while (1) { - if (digitalRead(pBBEI->iBUSYPin) == busy_idle) break; + if (digitalRead(pBBEP->iBUSYPin) == busy_idle) break; } -} /* bbeiWaitBusy() */ +} /* bbepWaitBusy() */ // // Convenience function to write a command byte along with a data // byte (it's single parameter) // -void bbeiCMD2(BBEIDISP *pBBEI, uint8_t cmd1, uint8_t cmd2) +void bbepCMD2(BBEPDISP *pBBEP, uint8_t cmd1, uint8_t cmd2) { - if (!pBBEI->is_awake) { + if (!pBBEP->is_awake) { // if it's asleep, it can't receive commands - bbeiWakeUp(pBBEI); - pBBEI->is_awake = 1; + bbepWakeUp(pBBEP); + pBBEP->is_awake = 1; } - digitalWrite(pBBEI->iDCPin, LOW); - digitalWrite(pBBEI->iCSPin, LOW); - SPI_transfer(pBBEI, &cmd1, 1); - digitalWrite(pBBEI->iDCPin, HIGH); - SPI_transfer(pBBEI, &cmd2, 1); // second byte is data - digitalWrite(pBBEI->iCSPin, HIGH); - digitalWrite(pBBEI->iDCPin, HIGH); // leave data mode as the default -} /* bbeiCMD2() */ + digitalWrite(pBBEP->iDCPin, LOW); + digitalWrite(pBBEP->iCSPin, LOW); + SPI_transfer(pBBEP, &cmd1, 1); + digitalWrite(pBBEP->iDCPin, HIGH); + SPI_transfer(pBBEP, &cmd2, 1); // second byte is data + digitalWrite(pBBEP->iCSPin, HIGH); + digitalWrite(pBBEP->iDCPin, HIGH); // leave data mode as the default +} /* bbepCMD2() */ // // Write a single byte as a COMMAND (D/C set low) // -void bbeiWriteCmd(BBEIDISP *pBBEI, uint8_t cmd) +void bbepWriteCmd(BBEPDISP *pBBEP, uint8_t cmd) { - if (!pBBEI->is_awake) { + if (!pBBEP->is_awake) { // if it's asleep, it can't receive commands - bbeiWakeUp(pBBEI); - pBBEI->is_awake = 1; + bbepWakeUp(pBBEP); + pBBEP->is_awake = 1; } - digitalWrite(pBBEI->iDCPin, LOW); - digitalWrite(pBBEI->iCSPin, LOW); - SPI_transfer(pBBEI, &cmd, 1); - digitalWrite(pBBEI->iCSPin, HIGH); - digitalWrite(pBBEI->iDCPin, HIGH); // leave data mode as the default -} /* bbeiWriteCmd() */ -// -// Put the eink into light or deep sleep -// -void bbeiSleep(BBEIDISP *pBBEI, int bDeep) -{ - if (pBBEI->chip_type == BBEI_CHIP_UC81xx) { - bbeiCMD2(pBBEI, UC8151_CDI, 0x17); // border floating - bbeiWriteCmd(pBBEI, UC8151_POFF); // power off - bbeiWaitBusy(pBBEI); - if (bDeep) { - bbeiCMD2(pBBEI, UC8151_DSLP, 0xa5); // deep sleep - } - } else { - bbeiCMD2(pBBEI, SSD1608_DEEP_SLEEP, (bDeep) ? 0x02 : 0x01); // deep sleep mode 1 keeps RAM, mode 2 loses RAM - } - pBBEI->is_awake = 0; -} /* bbeiSleep() */ + digitalWrite(pBBEP->iDCPin, LOW); + digitalWrite(pBBEP->iCSPin, LOW); + SPI_transfer(pBBEP, &cmd, 1); + digitalWrite(pBBEP->iCSPin, HIGH); + digitalWrite(pBBEP->iDCPin, HIGH); // leave data mode as the default +} /* bbepWriteCmd() */ // // Write 1 or more bytes as DATA (D/C set high) // -void bbeiWriteData(BBEIDISP *pBBEI, uint8_t *pData, int iLen) +void bbepWriteData(BBEPDISP *pBBEP, uint8_t *pData, int iLen) { - digitalWrite(pBBEI->iCSPin, LOW); - SPI_transfer(pBBEI, pData, iLen); - digitalWrite(pBBEI->iCSPin, HIGH); -} /* bbeiWriteData() */ + digitalWrite(pBBEP->iCSPin, LOW); + SPI_transfer(pBBEP, pData, iLen); + digitalWrite(pBBEP->iCSPin, HIGH); +} /* bbepWriteData() */ -#endif // __BB_EI_IO__ +#endif // __BB_EP_IO__ diff --git a/src/bb_ep.inl b/src/bb_ep.inl index acde699..9b62603 100644 --- a/src/bb_ep.inl +++ b/src/bb_ep.inl @@ -587,6 +587,15 @@ const uint8_t epd266_init_sequence_full[] PROGMEM = 0x00 // end of table }; /* epd266_init_sequence_full[] */ +const uint8_t epd27_ws_init_sequence_full[] = { + 1, UC8151_PON, + BUSY_WAIT, + 3, 0x00, 0x1f, 0x0b, // panel setting + 5, UC8151_TRES, 0x01, 0x08, 0x00, 0xb0, + 2, 0x50, 0x97, // VCOM + 0 +}; + const uint8_t epd266_init_sequence_part[] PROGMEM = { 0x02, 0x11, 0x03, @@ -960,6 +969,7 @@ const EPD_PANEL panelDefs[] PROGMEM = { {400, 300, epd42r_init_sequence_full, NULL, NULL, BBEP_3COLOR, BBEP_CHIP_SSD16xx}, // EPD42R_400x300 {400, 300, epd42r2_init_sequence_full, NULL, NULL, BBEP_3COLOR, BBEP_CHIP_UC81xx}, // EPD42R2_400x300 {240, 416, epd37_init_sequence_full, NULL, epd37_init_sequence_part, 0, BBEP_CHIP_UC81xx}, // EPD37_240x416 + {176, 264, epd27_ws_init_sequence_full, NULL, NULL, BBEP_CS_EVERY_BYTE, BBEP_CHIP_UC81xx}, // EPD27_176x264 Waveshare 2.7" e-paper HAT }; int bbepSetPanelType(BBEPDISP *pBBEP, int iPanel) { diff --git a/src/bb_ep_gfx.inl b/src/bb_ep_gfx.inl index 5508c3f..093e3af 100644 --- a/src/bb_ep_gfx.inl +++ b/src/bb_ep_gfx.inl @@ -16,7 +16,7 @@ // #ifndef __BB_EP_GFX__ #define __BB_EP_GFX__ -#include +#include "Group5.h" #include "g5dec.inl" #include "bb_font.h" static G5DECIMAGE g5dec; diff --git a/src/bb_epaper.cpp b/src/bb_epaper.cpp index 352c6cf..1148e5e 100644 --- a/src/bb_epaper.cpp +++ b/src/bb_epaper.cpp @@ -20,10 +20,9 @@ #include #include #include -// convert wire library constants into ArmbianIO values -#define OUTPUT GPIO_OUT -#define INPUT GPIO_IN -#define INPUT_PULLUP GPIO_IN_PULLUP +#define OUTPUT 0 +#define INPUT 1 +#define INPUT_PULLUP 2 #define HIGH 1 #define LOW 0 void delay(int); @@ -32,7 +31,11 @@ void delay(int); #endif // _LINUX_ #include "bb_epaper.h" +#ifdef _LINUX_ +#include "rpi_io.inl" +#else #include "arduino_io.inl" // I/O (non-portable) code is in here +#endif #include "bb_ep.inl" // All of the display interface code is in here #include "bb_ep_gfx.inl" // drawing code #include "bb_font.h" // bitbank compressed font info @@ -57,6 +60,7 @@ void BBEPAPER::setAddrWindow(int x, int y, int w, int h) bbepSetAddrWindow(&_bbep, x, y, w, h); } +#ifdef ARDUINO void BBEPAPER::initIO(int iDC, int iReset, int iBusy, int iCS, int iMOSI, int iSCLK, uint32_t u32Speed) { _bbep.iCSPin = iCS; @@ -69,7 +73,19 @@ void BBEPAPER::initIO(int iDC, int iReset, int iBusy, int iCS, int iMOSI, int iS bbepWakeUp(&_bbep); bbepSendCMDSequence(&_bbep, _bbep.pInitFull); } /* initIO() */ - +#else // Linux +void BBEPAPER::initIO(int iDC, int iReset, int iBusy, int iCS, int iSPIChannel, uint32_t u32Speed) +{ + _bbep.iCSPin = iCS; + _bbep.iDCPin = iDC; + _bbep.iBUSYPin = iBusy; + _bbep.iRSTPin = iReset; + _bbep.iMOSIPin = iSPIChannel; + bbepInitIO(&_bbep, u32Speed); + bbepWakeUp(&_bbep); + bbepSendCMDSequence(&_bbep, _bbep.pInitFull); +} /* initIO() */ +#endif int BBEPAPER::writePlane(int iPlane) { return bbepWritePlane(&_bbep, iPlane); @@ -388,10 +404,12 @@ void BBEPAPER::getTextBounds(const char *string, int16_t x, int16_t y, int16_t * *h = (bottom - top + 1); } } +#ifdef ARDUINO void BBEPAPER::getTextBounds(const String &str, int16_t x, int16_t y, int16_t *x1, int16_t *y1, uint16_t *w, uint16_t *h) { getTextBounds(str.c_str(), x, y, x1, y1, w, h); } +#endif int BBEPAPER::dataTime(void) { return _bbep.iDataTime; diff --git a/src/bb_epaper.h b/src/bb_epaper.h index 542fb64..657c936 100644 --- a/src/bb_epaper.h +++ b/src/bb_epaper.h @@ -24,6 +24,7 @@ #define OCT 8 #define BIN 2 #define PROGMEM +#include #include #include #include @@ -102,6 +103,7 @@ enum { EPD42R_400x300, EPD42R2_400x300, // GDEQ042Z21 EPD37_240x416, // GDEY037T03 + EPD27_176x264, // Waveshare 2.7" e-paper HAT EPD_PANEL_COUNT }; #ifdef FUTURE @@ -119,7 +121,6 @@ enum { EPD154Y_152x152, // DEPG0154YN EPD154_200x200, // waveshare EPD154B_200x200, // DEPG01540BN - EPD27_176x264, // waveshare EPD266B_152x296, // DEPG0266BN EPD266Y_152x296, // DEPG0266YN EPD31R_168x296, // DEPG0310RW @@ -279,7 +280,11 @@ class BBEPAPER public: BBEPAPER(int iPanel); void setAddrWindow(int x, int y, int w, int h); +#ifdef ARDUINO void initIO(int iDC, int iReset, int iBusy, int iCS = SS, int iMOSI = MOSI, int iSCLK = SCK, uint32_t u32Speed = 8000000); +#else + void initIO(int iDC, int iReset, int iBusy, int iCS, int iSPIChannel, uint32_t u32Speed = 8000000); +#endif int writePlane(int iPlane = PLANE_DUPLICATE); void startWrite(int iPlane); void writeData(uint8_t *pData, int iLen); @@ -307,7 +312,9 @@ class BBEPAPER int16_t getCursorX(void); int16_t getCursorY(void); void getTextBounds(const char *string, int16_t x, int16_t y, int16_t *x1, int16_t *y1, uint16_t *w, uint16_t *h); +#ifdef ARDUINO void getTextBounds(const String &str, int16_t x, int16_t y, int16_t *x1, int16_t *y1, uint16_t *w, uint16_t *h); +#endif int dataTime(); int opTime(); int16_t height(void);