diff --git a/src/arduino_io.inl b/src/arduino_io.inl index ac1426f..f3c5280 100644 --- a/src/arduino_io.inl +++ b/src/arduino_io.inl @@ -22,6 +22,7 @@ #include // foreward references void bbepWakeUp(BBEPDISP *pBBEP); +void bbepSendCMDSequence(BBEPDISP *pBBEP, const uint8_t *pSeq); // // Initialize the GPIO pins and SPI for use by bb_eink // @@ -44,39 +45,57 @@ void bbepInitIO(BBEPDISP *pBBEP, uint8_t u8DC, uint8_t u8RST, uint8_t u8BUSY, ui pinMode(pBBEP->iBUSYPin, INPUT); } pBBEP->iSpeed = u32Speed; -#ifdef ARDUINO_ARCH_ESP32 - SPI.begin(pBBEP->iCLKPin, -1, pBBEP->iMOSIPin, pBBEP->iCSPin); -#else pinMode(pBBEP->iCSPin, OUTPUT); - digitalWrite(pBBEP->iCSPin, HIGH); // we have to manually control the CS pin + digitalWrite(pBBEP->iCSPin, HIGH); // manually control the CS pin +#ifdef ARDUINO_ARCH_ESP32 + SPI.begin(pBBEP->iCLKPin, -1, pBBEP->iMOSIPin, -1); //pBBEP->iCSPin); +#else SPI.begin(); // other architectures have fixed SPI pins #endif SPI.beginTransaction(SPISettings(u32Speed, MSBFIRST, SPI_MODE0)); SPI.endTransaction(); // N.B. - if you call beginTransaction() again without a matching endTransaction(), it will hang on ESP32 -} /* bbepInitIO() */ -// -// Convenience function to write a command byte along with a data -// byte (it's single parameter) -// -void bbepCMD2(BBEPDISP *pBBEP, uint8_t cmd1, uint8_t cmd2) -{ - if (!pBBEP->is_awake) { - // if it's asleep, it can't receive commands - bbepWakeUp(pBBEP); - pBBEP->is_awake = 1; + if (pBBEP->iFlags & BBEP_7COLOR) { // need to send before you can send it data + bbepSendCMDSequence(pBBEP, pBBEP->pInitFull); } - digitalWrite(pBBEP->iDCPin, LOW); -#ifndef ARDUINO_ARCH_ESP32 +} /* bbepInitIO() */ + +void bbepWriteIT8951Cmd(BBEPDISP *pBBEP, uint16_t cmd) +{ + uint8_t ucTemp[4]; + ucTemp[0] = 0x60; // command introducer = 0x6000 + ucTemp[1] = 0; + ucTemp[2] = (uint8_t)(cmd >> 8); + ucTemp[3] = (uint8_t)cmd; digitalWrite(pBBEP->iCSPin, LOW); +#ifdef ARDUINO_ARCH_ESP32 + SPI.transferBytes(ucTemp, NULL, 4); +#else + SPI.transfer(ucTemp, 4); #endif - SPI.transfer(cmd1); - digitalWrite(pBBEP->iDCPin, HIGH); - SPI.transfer(cmd2); // second byte is data -#ifndef ARDUINO_ARCH_ESP32 digitalWrite(pBBEP->iCSPin, HIGH); +} /* bbepWriteIT8951Cmd() */ + +void bbepWriteIT8951Data(BBEPDISP *pBBEP, uint8_t *pData, int iLen) +{ + digitalWrite(pBBEP->iCSPin, LOW); + SPI.transfer(0); + SPI.transfer(0); // 0x0000 is the data introducer +#ifdef ARDUINO_ARCH_ESP32 + SPI.transferBytes(pData, NULL, iLen); +#else + SPI.transfer(pData, iLen); #endif -// digitalWrite(pBBEP->iDCPin, HIGH); // leave data mode as the default -} /* bbepCMD2() */ + digitalWrite(pBBEP->iCSPin, HIGH); +} /* bbepWriteIT8951Data() */ + +void bbepWriteIT8951CmdArgs(BBEPDISP *pBBEP, uint16_t cmd, uint16_t *pArgs, int iCount) +{ + bbepWriteIT8951Cmd(pBBEP, cmd); + for (int i=0; iis_awake = 1; } digitalWrite(pBBEP->iDCPin, LOW); -#ifndef ARDUINO_ARCH_ESP32 + delay(1); digitalWrite(pBBEP->iCSPin, LOW); -#endif SPI.transfer(cmd); -#ifndef ARDUINO_ARCH_ESP32 digitalWrite(pBBEP->iCSPin, HIGH); -#endif digitalWrite(pBBEP->iDCPin, HIGH); // leave data mode as the default } /* bbepWriteCmd() */ // @@ -104,7 +120,17 @@ void bbepWriteData(BBEPDISP *pBBEP, uint8_t *pData, int iLen) { // digitalWrite(pBBEP->iDCPin, HIGH); #ifdef ARDUINO_ARCH_ESP32 - SPI.transferBytes(pData, NULL, iLen); + if (pBBEP->iFlags & BBEP_CS_EVERY_BYTE) { + for (int i=0; iiCSPin, LOW); + SPI.transfer(pData[i]); + digitalWrite(pBBEP->iCSPin, HIGH); + } + } else { + digitalWrite(pBBEP->iCSPin, LOW); + SPI.transferBytes(pData, NULL, iLen); + digitalWrite(pBBEP->iCSPin, HIGH); + } #else if (pBBEP->iFlags & BBEP_CS_EVERY_BYTE) { for (int i=0; ipInitFast = panelDefs[iPanel].pInitFast; pBBEP->pInitPart = panelDefs[iPanel].pInitPart; pBBEP->type = iPanel; - // select the correct pixel drawing functions (2/3/4 color) + // select the correct pixel drawing functions (2/3/4/7 color) if (pBBEP->iFlags & BBEP_4COLOR) { pBBEP->pfnSetPixel = bbepSetPixel4Clr; pBBEP->pfnSetPixelFast = bbepSetPixelFast4Clr; } else if (pBBEP->iFlags & BBEP_3COLOR) { pBBEP->pfnSetPixel = bbepSetPixel3Clr; pBBEP->pfnSetPixelFast = bbepSetPixelFast3Clr; + } else if (pBBEP->iFlags & BBEP_7COLOR) { + pBBEP->pfnSetPixel = bbepSetPixel16Clr; + pBBEP->pfnSetPixelFast = bbepSetPixelFast16Clr; } else { // must be B/W pBBEP->pfnSetPixel = bbepSetPixel2Clr; pBBEP->pfnSetPixelFast = bbepSetPixelFast2Clr; @@ -1280,6 +1352,9 @@ int bbepCreateVirtual(BBEPDISP *pBBEP, int iWidth, int iHeight, int iFlags) } else if (iFlags & BBEP_3COLOR) { pBBEP->pfnSetPixel = bbepSetPixel3Clr; pBBEP->pfnSetPixelFast = bbepSetPixelFast3Clr; + } else if (pBBEP->iFlags & BBEP_7COLOR) { + pBBEP->pfnSetPixel = bbepSetPixel16Clr; + pBBEP->pfnSetPixelFast = bbepSetPixelFast16Clr; } else { // must be B/W pBBEP->pfnSetPixel = bbepSetPixel2Clr; pBBEP->pfnSetPixelFast = bbepSetPixelFast2Clr; @@ -1300,6 +1375,7 @@ void bbepWaitBusy(BBEPDISP *pBBEP) if (!pBBEP) return; if (pBBEP->iBUSYPin == 0xff) return; + delay(10); // give time for the busy status to be valid 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 (iTimeout < 5000) { @@ -1316,7 +1392,7 @@ void bbepWakeUp(BBEPDISP *pBBEP) digitalWrite(pBBEP->iRSTPin, LOW); delay(10); digitalWrite(pBBEP->iRSTPin, HIGH); - delay(10); + delay(20); bbepWaitBusy(pBBEP); } /* bbepWakeUp() */ // @@ -1328,8 +1404,18 @@ void bbepSetAddrWindow(BBEPDISP *pBBEP, int x, int y, int cx, int cy) int i, tx, ty; if (!pBBEP) return; - if (pBBEP->iFlags & BBEP_4COLOR) return; - + if (pBBEP->iFlags & (BBEP_4COLOR | BBEP_7COLOR)) return; + + if (pBBEP->chip_type == BBEP_CHIP_IT8951) { + uint16_t u16Temp[6]; + u16Temp[0] = 0; // DEBUG (_endian_type << 8 | _pix_bpp << 4 | _rotate); + u16Temp[1] = x; + u16Temp[2] = y; + u16Temp[3] = cx; + u16Temp[4] = cy; + bbepWriteIT8951CmdArgs(pBBEP, IT8951_TCON_LD_IMG_AREA, u16Temp, 5); + return; + } tx = x/8; // round down to next lower byte ty = y; cx = (cx + 7) & 0xfff8; // make width an even number of bytes @@ -1390,11 +1476,15 @@ void bbepSleep(BBEPDISP *pBBEP, int bDeep) { if (!pBBEP) return; if (pBBEP->chip_type == BBEP_CHIP_UC81xx) { - bbepCMD2(pBBEP, UC8151_CDI, 0x17); // border floating - bbepWriteCmd(pBBEP, UC8151_POFF); // power off - bbepWaitBusy(pBBEP); - if (bDeep) { - bbepCMD2(pBBEP, UC8151_DSLP, 0xa5); // deep sleep + if (pBBEP->iFlags & BBEP_7COLOR) { + bbepCMD2(pBBEP, UC8151_POFF, 0x00); // power off + } else { + bbepCMD2(pBBEP, UC8151_CDI, 0x17); // border floating + bbepWriteCmd(pBBEP, UC8151_POFF); // power off + bbepWaitBusy(pBBEP); + if (bDeep) { + bbepCMD2(pBBEP, UC8151_DSLP, 0xa5); // deep sleep + } } } else { bbepCMD2(pBBEP, SSD1608_DEEP_SLEEP, 0x01); // deep sleep mode 1 keeps RAM,only uses about 1uA @@ -1487,7 +1577,11 @@ void bbepFill(BBEPDISP *pBBEP, unsigned char ucData, int iPlane) pBBEP->iCursorX = pBBEP->iCursorY = 0; iPitch = ((pBBEP->native_width+7)/8); iSize = pBBEP->native_height * iPitch; - if (pBBEP->iFlags & BBEP_3COLOR) { + if (pBBEP->iFlags & BBEP_7COLOR) { + uc1 = ucData | (ucData << 4); + iPitch = pBBEP->native_width / 2; + iSize = pBBEP->native_height * iPitch; + } else if (pBBEP->iFlags & BBEP_3COLOR) { if (ucData == BBEP_WHITE) { uc1 = 0xff; uc2 = 0x00; // red plane has priority } else if (ucData == BBEP_BLACK) { @@ -1504,12 +1598,15 @@ void bbepFill(BBEPDISP *pBBEP, unsigned char ucData, int iPlane) } else { // B/W if (ucData == BBEP_WHITE) { uc1 = uc2 = 0xff; - } else { + } else { uc1 = uc2 = 0x00; - } + } } if (pBBEP->ucScreen) { // there's a local framebuffer, use it - if ((pBBEP->iFlags & BBEP_3COLOR) || iPlane == PLANE_BOTH) { + if (pBBEP->iFlags & BBEP_7COLOR) { + memset(pBBEP->ucScreen, uc1, iSize); + return; + } else if ((pBBEP->iFlags & BBEP_3COLOR) || iPlane == PLANE_BOTH) { memset(pBBEP->ucScreen, uc1, iSize); memset(&pBBEP->ucScreen[iSize], uc2, iSize); } else if (iPlane == PLANE_DUPLICATE) { @@ -1589,7 +1686,7 @@ int bbepRefresh(BBEPDISP *pBBEP, int iMode) return BBEP_ERROR_BAD_PARAMETER; } // switch on mode if (pBBEP->chip_type == BBEP_CHIP_UC81xx) { - if (pBBEP->iFlags & BBEP_4COLOR) { + if (pBBEP->iFlags & (BBEP_4COLOR | BBEP_7COLOR)) { bbepCMD2(pBBEP, 0x12, 0x00); } else { bbepWriteCmd(pBBEP, UC8151_PTOU); // partial out (update the entire panel, not just the last memory window) @@ -1635,6 +1732,68 @@ void bbepSetRotation(BBEPDISP *pBBEP, int iRotation) } } /* bbepSetRotation() */ +void bbepWriteImage4bpp(BBEPDISP *pBBEP, uint8_t ucCMD) +{ + int tx, ty, iPitch; + uint8_t uc, *s, *d; + + if (ucCMD) { + bbepWriteCmd(pBBEP, ucCMD); // start write + } + if (pBBEP->iOrientation == 0) { + iPitch = pBBEP->native_width / 2; + s = pBBEP->ucScreen; + for (ty=0; tyheight; ty++) { + bbepWriteData(pBBEP, s, iPitch); + s += iPitch; // 2 pixels per byte + } // for ty + } else if (pBBEP->iOrientation == 180) { + iPitch = pBBEP->native_width / 2; + for (ty=pBBEP->height-1; ty>=0; ty--) { + s = &pBBEP->ucScreen[(ty * iPitch) + iPitch - 1]; + // reverse the pixel direction + for (tx=0; txnative_width; tx+=2) { + uc = *s--; + uc = (uc >> 4) | (uc << 4); // swap nibbles + u8Cache[tx/2] = uc; + } + bbepWriteData(pBBEP, u8Cache, iPitch); + } // for ty + } else if (pBBEP->iOrientation == 90) { + iPitch = pBBEP->native_height / 2; + for (tx=0; txwidth; tx++) { + d = u8Cache; + for (ty=pBBEP->height-1; ty > 0; ty-=2) { + s = &pBBEP->ucScreen[(tx>>1) + (ty * iPitch)]; + if (tx & 1) { + uc = (s[0] << 4) | (s[-iPitch] & 0x0f); + } else { + uc = (s[0] & 0xf0) | (s[-iPitch] >> 4); + } + s -= iPitch*2; + *d++ = uc; // store 4 pixels + } // for ty + bbepWriteData(pBBEP, u8Cache, pBBEP->height/2); + } // for tx + } else if (pBBEP->iOrientation == 270) { + iPitch = pBBEP->native_height / 2; + for (tx=pBBEP->width-1; tx>= 0; tx--) { + d = u8Cache; + for (ty=0; ty < pBBEP->height; ty+=2) { + s = &pBBEP->ucScreen[(tx>>1) + (ty * iPitch)]; + if (tx & 1) { + uc = (s[0] << 4) | (s[iPitch] & 0x0f); + } else { + uc = (s[0] & 0xf0) | (s[iPitch] >> 4); + } + s += iPitch*2; + *d++ = uc; // store 4 pixels + } // for ty + bbepWriteData(pBBEP, u8Cache, pBBEP->height/2); + } // for tx + } +} /* bbepWriteImage4bpp() */ + void bbepWriteImage2bpp(BBEPDISP *pBBEP, uint8_t ucCMD) { int tx, ty; @@ -1795,10 +1954,15 @@ int bbepWritePlane(BBEPDISP *pBBEP, int iPlane) uint8_t ucCMD1, ucCMD2; int iOffset; - if (pBBEP == NULL || pBBEP->ucScreen == NULL || iPlane < PLANE_0 || iPlane > PLANE_DUPLICATE) + if (pBBEP == NULL || pBBEP->ucScreen == NULL || iPlane < PLANE_0 || iPlane > PLANE_DUPLICATE) { return BBEP_ERROR_BAD_PARAMETER; + } bbepSetAddrWindow(pBBEP, 0,0, pBBEP->native_width, pBBEP->native_height); + if (pBBEP->iFlags & BBEP_7COLOR) { + bbepWriteImage4bpp(pBBEP, 0x10); + return BBEP_SUCCESS; + } if (pBBEP->iFlags & BBEP_4COLOR) { // 4-color only has 1 way to go bbepWriteImage2bpp(pBBEP, 0x10); return BBEP_SUCCESS; diff --git a/src/bb_ep_gfx.inl b/src/bb_ep_gfx.inl index 36ebb42..41a8630 100644 --- a/src/bb_ep_gfx.inl +++ b/src/bb_ep_gfx.inl @@ -430,6 +430,56 @@ void bbepSetPixelFast2Clr(void *pb, int x, int y, unsigned char ucColor) pBBEP->ucScreen[i] = u8; } /* bbepSetPixelFast2Clr() */ +int bbepSetPixel16Clr(void *pb, int x, int y, unsigned char ucColor) +{ + int i; + int iPitch, iSize; + uint8_t u8; + BBEPDISP *pBBEP = (BBEPDISP *)pb; + + // only available for local buffer operations + if (!pBBEP || !pBBEP->ucScreen) return BBEP_ERROR_BAD_PARAMETER; + + iPitch = pBBEP->width >> 1; + iSize = (pBBEP->native_width >> 1) * pBBEP->native_height; + + i = (x >> 1) + (y * iPitch); + if (x < 0 || x >= pBBEP->width || i < 0 || i > iSize-1) { // off the screen + pBBEP->last_error = BBEP_ERROR_BAD_PARAMETER; + return BBEP_ERROR_BAD_PARAMETER; + } + u8 = pBBEP->ucScreen[i]; + if (x & 1) { + u8 &= 0xf0; + u8 |= ucColor; + } else { + u8 &= 0x0f; + u8 |= (ucColor << 4); + } + pBBEP->ucScreen[i] = u8; + return BBEP_SUCCESS; +} /* bbepSetPixel16Clr() */ + +void bbepSetPixelFast16Clr(void *pb, int x, int y, unsigned char ucColor) +{ + int i; + int iPitch; + uint8_t u8; + BBEPDISP *pBBEP = (BBEPDISP *)pb; + + iPitch = pBBEP->width >> 1; + i = (x >> 1) + (y * iPitch); + u8 = pBBEP->ucScreen[i]; + if (x & 1) { + u8 &= 0xf0; + u8 |= ucColor; + } else { + u8 &= 0x0f; + u8 |= (ucColor << 4); + } + pBBEP->ucScreen[i] = u8; +} /* bbepSetPixelFast16Clr() */ + // // Invert font data // @@ -1390,13 +1440,34 @@ void bbepGetStringBox(BBEPDISP *pBBEP, BB_FONT *pFont, const char *szMsg, int *w *bottom = maxy; } /* bbepGetStringBox() */ -void bbepAllocBuffer(BBEPDISP *pBBEP) +int bbepAllocBuffer(BBEPDISP *pBBEP) { #ifndef NO_RAM - pBBEP->ucScreen = (uint8_t *)malloc(pBBEP->width * ((pBBEP->height+7)>>3)); - pBBEP->iScreenOffset = 0; + int iSize; + if (pBBEP->iFlags & (BBEP_7COLOR | BBEP_16GRAY)) { // 4-bpp + iSize = (pBBEP->native_width >> 1) * pBBEP->native_height; + } else { // B/W or B/W/R or B/W/R/Y + iSize = ((pBBEP->native_width+7)>>3) * pBBEP->native_height; + iSize *= 2; // 2 bit planes + } +#if defined (HAL_ESP32_HAL_H_) && !defined(__riscv) + if (iSize > 90000) { // need to use PSRAM +#ifndef BOARD_HAS_PSRAM +#error "Please enable PSRAM!" #endif -} /* obdAllocBuffer() */ + pBBEP->ucScreen = (uint8_t *)ps_malloc(iSize); + } else { + pBBEP->ucScreen = (uint8_t *)malloc(iSize); + } +#else // not ESP32 or no PSRAM + pBBEP->ucScreen = (uint8_t *)malloc(iSize); +#endif // ESP32 + if (pBBEP->ucScreen != NULL) { + return BBEP_SUCCESS; + } +#endif + return BBEP_ERROR_NO_MEMORY; // failed +} /* bbepAllocBuffer() */ // // Draw a line from x1,y1 to x2,y2 in the given color // This function supports both buffered and bufferless drawing @@ -1421,18 +1492,6 @@ void bbepDrawLine(BBEPDISP *pBBEP, int x1, int y1, int x2, int y2, uint8_t ucCol pBBEP->last_error = BBEP_ERROR_BAD_PARAMETER; return; } - iPitch = (pBBEP->width + 7)>>3; - if (ucColor >= BBEP_YELLOW && pBBEP->iFlags & (BBEP_3COLOR | BBEP_4COLOR)) { - // use the second half of the image buffer - iRedOffset = iPitch * pBBEP->height; - } - if (!pBBEP->ucScreen) { // no back buffer, draw in local buffer - if (ucColor == BBEP_BLACK) // fill with opposite color - ucFill = 0xff; - else - ucFill = 0; - memset(u8Cache, ucFill, sizeof(u8Cache)); - } if(abs(dx) > abs(dy)) { // X major case if(x2 < x1) { @@ -1454,46 +1513,14 @@ void bbepDrawLine(BBEPDISP *pBBEP, int x1, int y1, int x2, int y2, uint8_t ucCol dy = -dy; yinc = -1; } - if (pBBEP->ucScreen) { - p = pStart = &pBBEP->ucScreen[iRedOffset + (x1>>3) + (y * iPitch)]; // point to current spot in back buffer - } else { // no back buffer, draw directly to the display RAM - p = pStart = u8Cache; - } - mask = 0x80 >> (x1 & 7); // current bit offset - for(x=x1; x1 <= x2; x1++) { - if (ucColor == BBEP_BLACK) { - *p &= ~mask; // set pixel and increment x pointer - } else { - *p |= mask; - } - mask >>= 1; - if (mask == 0) { - p++; - mask = 0x80; // next byte - } + for(; x1 <= x2; x1++) { + (*pBBEP->pfnSetPixelFast)(pBBEP, x1, y1, ucColor); error -= dy; if (error < 0) { error += dx; - if (pBBEP->ucScreen) { - p += (yinc > 0) ? iPitch : -iPitch; - pStart = p; - } else { // no buffer - // y is changing, dump the pixels we modified - bbepSetAddrWindow(pBBEP, x, y1, 16+x1-x, 1); - bbepStartWrite(pBBEP, pBBEP->iPlane); - bbepWriteData(pBBEP, pStart, (16+x1-x)>>3); // write the row we changed - memset(pStart, ucFill, (16+x1-x)>>3); - p = pStart; - } - x = x1+1; // we've already written the byte at x1 y1 += yinc; } } // for x1 - if (x != x1 && !pBBEP->ucScreen) { // some data needs to be written - bbepSetAddrWindow(pBBEP, x, y1, 16+x1-x, 1); - bbepStartWrite(pBBEP, pBBEP->iPlane); - bbepWriteData(pBBEP, pStart, (16+x1-x)>>3); - } } else { // Y major case if(y1 > y2) { @@ -1513,31 +1540,8 @@ void bbepDrawLine(BBEPDISP *pBBEP, int x1, int y1, int x2, int y2, uint8_t ucCol xinc = -1; } for(; y1 <= y2; y1++) { - mask = 0x80 >> (x1 & 7); // current bit offset - if (pBBEP->ucScreen) { - p = &pBBEP->ucScreen[iRedOffset + (x1>>3) + (y1 * iPitch)]; // point - bOld = bNew = p[0]; // current pixels - } else { - bOld = bNew = ucFill; - } - if (ucColor == BBEP_BLACK) { - bNew &= ~mask; // set the pixel - } else { - bNew |= mask; - } + (*pBBEP->pfnSetPixelFast)(pBBEP, x1, y1, ucColor); error -= dx; - if (bOld != bNew) { - if (pBBEP->ucScreen) { - p[0] = bNew; // save to RAM - p += iPitch; // next line - bOld = bNew = p[0]; - } else { - bbepSetAddrWindow(pBBEP, x1, y1, 8, 1); - bbepStartWrite(pBBEP, pBBEP->iPlane); - bbepWriteData(pBBEP, &bNew, 1); - bOld = bNew = ucFill; - } - } if (error < 0) { error += dy; x1 += xinc; @@ -1563,35 +1567,7 @@ static void DrawScaledPixel(BBEPDISP *pBBEP, int iCX, int iCY, int x, int y, int pBBEP->last_error = BBEP_ERROR_BAD_PARAMETER; return; // off the screen } - if (pBBEP->iFlags & BBEP_4COLOR) { - iPitch = (pBBEP->width + 3) >> 2; - ucMask = 0xc0 >> ((x & 3)*2); - d = &pBBEP->ucScreen[(x>>2) + (y * iPitch)]; - d[0] &= ~ucMask; - d[0] |= (ucColor << ((3-(x & 3))*2)); - return; - } - iPitch = (pBBEP->width + 7) >> 3; - ucMask = 0x80 >> (x & 7); - d = &pBBEP->ucScreen[(x>>3) + (y * iPitch)]; - if (pBBEP->iFlags & BBEP_3COLOR) { - // use the second half of the image buffer - iRedOffset = iPitch * pBBEP->height; - if (ucColor == BBEP_RED) { - d[iRedOffset] |= ucMask; // red has priority - } else { - d[iRedOffset] &= ~ucMask; // must remove red first - if (ucColor == BBEP_WHITE) - *d |= ucMask; - else - *d &= ~ucMask; - } - } else { - if (ucColor == BBEP_WHITE) - *d |= ucMask; - else - *d &= ~ucMask; - } + (*pBBEP->pfnSetPixelFast)(pBBEP, x, y, ucColor); } /* DrawScaledPixel() */ // // For drawing filled ellipses @@ -1698,7 +1674,7 @@ void bbepRectangle(BBEPDISP *pBBEP, int x1, int y1, int x2, int y2, uint8_t ucCo int iPitch; int iRedOffset = 0; - if (ucColor >= BBEP_YELLOW) { + if (!(pBBEP->iFlags & BBEP_7COLOR) && ucColor >= BBEP_YELLOW) { if (pBBEP->iFlags & (BBEP_3COLOR | BBEP_4COLOR)) { // use the second half of the image buffer iRedOffset = pBBEP->width * ((pBBEP->height+7)/8); diff --git a/src/bb_epaper.cpp b/src/bb_epaper.cpp index fb70fcc..01dad16 100644 --- a/src/bb_epaper.cpp +++ b/src/bb_epaper.cpp @@ -141,13 +141,7 @@ void BBEPAPER::backupPlane(void) } int BBEPAPER::allocBuffer(void) { - int iSize = ((_bbep.native_width+7)>>3) * _bbep.native_height; - iSize *= 2; // 2 bit planes - _bbep.ucScreen = (uint8_t *)malloc(iSize); - if (_bbep.ucScreen != NULL) { - return BBEP_SUCCESS; - } - return BBEP_ERROR_NO_MEMORY; // failed + return bbepAllocBuffer(&_bbep); } /* allocBuffer() */ void * BBEPAPER::getBuffer(void) @@ -212,7 +206,7 @@ bool BBEPAPER::hasPartialRefresh() void BBEPAPER::setTextColor(int iFG, int iBG) { - if ((_bbep.iFlags & (BBEP_3COLOR | BBEP_4COLOR)) == 0) { + if ((_bbep.iFlags & (BBEP_3COLOR | BBEP_4COLOR | BBEP_7COLOR)) == 0) { if (iFG == BBEP_RED || iFG == BBEP_YELLOW) iFG = BBEP_BLACK; // can't set red color if (iBG == BBEP_RED || iFG == BBEP_YELLOW) iBG = BBEP_BLACK; } diff --git a/src/bb_epaper.h b/src/bb_epaper.h index 4268c5f..3a211c0 100644 --- a/src/bb_epaper.h +++ b/src/bb_epaper.h @@ -64,6 +64,7 @@ enum { BBEP_CHIP_NOT_DEFINED = 0, BBEP_CHIP_SSD16xx, BBEP_CHIP_UC81xx, + BBEP_CHIP_IT8951, BBEP_CHIP_NONE, // for virtual display BBEP_CHIP_COUNT }; @@ -97,7 +98,7 @@ typedef struct epd_panel { const uint8_t *pInitFull; const uint8_t *pInitFast; const uint8_t *pInitPart; - uint8_t flags; + uint16_t flags; uint8_t chip_type; } EPD_PANEL; @@ -132,6 +133,9 @@ enum { EP583_648x480, // DEPG0583BN EP296_128x296, // Waveshare 2.9" 128x296 B/W V2 EP26R_152x296, // Solum 2.6" B/W/R harvested panel + EP47_540x960, // M5Paper + EP73_800x480, // GEDY073D46 (slower, EOL 7-color) + EP73_SPECTRA_800x480, // Spectra 6 7-color 800x480 // EP583R_600x448, // 4-bits per pixel needs different support EP_PANEL_COUNT }; @@ -166,8 +170,10 @@ enum { #define BBEP_3COLOR 0x0004 #define BBEP_4COLOR 0x0008 #define BBEP_4GRAY 0x0010 -#define BBEP_CS_EVERY_BYTE 0x0020 -#define BBEP_PARTIAL2 0x0040 +#define BBEP_7COLOR 0x0020 +#define BBEP_16GRAY 0x0040 +#define BBEP_CS_EVERY_BYTE 0x0080 +#define BBEP_PARTIAL2 0x0100 #define BBEP_BLACK 0 #define BBEP_WHITE 1 @@ -175,6 +181,16 @@ enum { #define BBEP_RED 3 #define BBEP_TRANSPARENT 255 +// colors for Spectra 6 +#define BBEP_SPECTRA_BLACK 0x00 +#define BBEP_SPECTRA_WHITE 0x01 +#define BBEP_SPECTRA_GREEN 0x02 +#define BBEP_SPECTRA_BLUE 0x03 +#define BBEP_SPECTRA_RED 0x04 +#define BBEP_SPECTRA_YELLOW 0x05 +#define BBEP_SPECTRA_ORANGE 0x06 +#define BBEP_SPECTRA_CLEAN 0x07 + // 4 gray levels #define BBEP_GRAY0 0 #define BBEP_GRAY1 1 @@ -182,6 +198,88 @@ enum { #define BBEP_GRAY3 3 #ifndef __ONEBITDISPLAY__ +// (IT8951 commands) +// Built in I80 Command Code +#define IT8951_TCON_SYS_RUN 0x0001 +#define IT8951_TCON_STANDBY 0x0002 +#define IT8951_TCON_SLEEP 0x0003 +#define IT8951_TCON_REG_RD 0x0010 +#define IT8951_TCON_REG_WR 0x0011 + +#define IT8951_TCON_MEM_BST_RD_T 0x0012 +#define IT8951_TCON_MEM_BST_RD_S 0x0013 +#define IT8951_TCON_MEM_BST_WR 0x0014 +#define IT8951_TCON_MEM_BST_END 0x0015 + +#define IT8951_TCON_LD_IMG 0x0020 +#define IT8951_TCON_LD_IMG_AREA 0x0021 +#define IT8951_TCON_LD_IMG_END 0x0022 + +// I80 User defined command code +#define IT8951_I80_CMD_DPY_AREA 0x0034 +#define IT8951_I80_CMD_GET_DEV_INFO 0x0302 +#define IT8951_I80_CMD_DPY_BUF_AREA 0x0037 +#define IT8951_I80_CMD_VCOM 0x0039 +// Rotate mode +#define IT8951_ROTATE_0 0 +#define IT8951_ROTATE_90 1 +#define IT8951_ROTATE_180 2 +#define IT8951_ROTATE_270 3 + +// Pixel mode (Bit per Pixel) +#define IT8951_2BPP 0 +#define IT8951_3BPP 1 +#define IT8951_4BPP 2 +#define IT8951_8BPP 3 + +// Endian Type +#define IT8951_LDIMG_L_ENDIAN 0 +#define IT8951_LDIMG_B_ENDIAN 1 +/*----------------------------------------------------------------------- +IT8951 Registers defines +------------------------------------------------------------------------*/ +// Register Base Address +#define IT8951_DISPLAY_REG_BASE 0x1000 // Register RW access + +// Base Address of Basic LUT Registers +#define IT8951_LUT0EWHR \ + (IT8951_DISPLAY_REG_BASE + 0x00) // LUT0 Engine Width Height Reg +#define IT8951_LUT0XYR (IT8951_DISPLAY_REG_BASE + 0x40) // LUT0 XY Reg +#define IT8951_LUT0BADDR \ + (IT8951_DISPLAY_REG_BASE + 0x80) // LUT0 Base Address Reg +#define IT8951_LUT0MFN \ + (IT8951_DISPLAY_REG_BASE + 0xC0) // LUT0 Mode and Frame number Reg +#define IT8951_LUT01AF \ + (IT8951_DISPLAY_REG_BASE + 0x114) // LUT0 and LUT1 Active Flag Reg + +// Update Parameter Setting Register +#define IT8951_UP0SR \ + (IT8951_DISPLAY_REG_BASE + 0x134) // Update Parameter0 Setting Reg +#define IT8951_UP1SR \ + (IT8951_DISPLAY_REG_BASE + 0x138) // Update Parameter1 Setting Reg +#define IT8951_LUT0ABFRV \ + (IT8951_DISPLAY_REG_BASE + \ + 0x13C) // LUT0 Alpha blend and Fill rectangle Value +#define IT8951_UPBBADDR \ + (IT8951_DISPLAY_REG_BASE + 0x17C) // Update Buffer Base Address +#define IT8951_LUT0IMXY \ + (IT8951_DISPLAY_REG_BASE + 0x180) // LUT0 Image buffer X/Y offset Reg +#define IT8951_LUTAFSR \ + (IT8951_DISPLAY_REG_BASE + \ + 0x224) // LUT Status Reg (status of All LUT Engines) +#define IT8951_BGVR \ + (IT8951_DISPLAY_REG_BASE + 0x250) // Bitmap (1bpp) image color table + +// System Registers +#define IT8951_SYS_REG_BASE 0x0000 + +// Address of System Registers +#define IT8951_I80CPCR (IT8951_SYS_REG_BASE + 0x04) +// Memory Converter Registers +#define IT8951_MCSR_BASE_ADDR 0x0200 +#define IT8951_MCSR (IT8951_MCSR_BASE_ADDR + 0x0000) +#define IT8951_LISAR (IT8951_MCSR_BASE_ADDR + 0x0008) + // (UC81xx commands) enum { UC8151_PSR = 0x00, @@ -391,6 +489,9 @@ class BBEPAPER private: BBEPDISP _bbep; + uint32_t _tar_memaddr = 0x001236E0; + uint16_t _dev_memaddr_l = 0x36E0; + uint16_t _dev_memaddr_h = 0x0012; }; // class BBEPAPER #endif // __cplusplus