Fixed 2-byte command bug

This commit is contained in:
Laurence Bank
2024-09-15 00:34:44 +01:00
parent 44d3868dcc
commit 8f8fe2f26d
6 changed files with 304 additions and 154 deletions
+1
View File
@@ -8,3 +8,4 @@ category=Display
url=https://github.com/bitbank2/bb_eink
architectures=*
includes=bb_eink.h
depends=Group5
+72 -9
View File
@@ -17,8 +17,6 @@
// bb_ei.inl
// display interfacing/control code for bb_eink library
//
// EPD command and LUT tables
// 2.7" 176x264 LUTs
#ifndef __BB_EI__
#define __BB_EI__
@@ -131,7 +129,7 @@ const uint8_t epd42r_init_sequence[] PROGMEM = {
0x03, 0x4f, 0x2b, 0x01, // RAM Y counter
0x00
};
const uint8_t epd29r_init_sequence[] PROGMEM = {
const uint8_t epd29r_init_sequence_full[] PROGMEM = {
0x01, 0x12, // soft reset
BUSY_WAIT,
0x02, 0x74, 0x54, // set analog block control
@@ -141,7 +139,7 @@ const uint8_t epd29r_init_sequence[] PROGMEM = {
0x04, 0x01, 0x27, 0x01, 0x00, // output control
0x02, 0x11, 0x03, // data entry mode
0x03, 0x44, 0x00, 0x0f, // RAM X start/end
0x05, 0x45, 0,0,0x27, 0x01, // RAM Y start/end
0x05, 0x45, 0x00, 0x00, 0x27, 0x01, // RAM Y start/end
0x02, 0x3c, 0x01, // border (0=bk,1=wh,2=red)
0x02, 0x18, 0x80, // temp sensor = internal
0x02, 0x21, 0x00, // display update ctrl 1
@@ -154,7 +152,7 @@ const uint8_t epd29r_init_sequence[] PROGMEM = {
};
// for 152x152 BWR
const uint8_t epd29r_init_sequence_152[] PROGMEM = {
const uint8_t epd154r_init_sequence_full[] PROGMEM = {
0x01, 0x12, // soft reset
BUSY_WAIT,
0x02, 0x74, 0x54, // set analog block control
@@ -164,7 +162,7 @@ const uint8_t epd29r_init_sequence_152[] PROGMEM = {
0x04, 0x01, 0x97, 0x00, 0x00, // output control
0x02, 0x11, 0x03, // data entry mode
0x03, 0x44, 0x00, 0x12, // RAM X start/end
0x05, 0x45, 0,0,0x97, 0x00, // RAM Y start/end
0x05, 0x45, 0x00, 0x00, 0x97, 0x00, // RAM Y start/end
0x02, 0x3c, 0x01, // border (0=bk,1=wh,2=red)
0x02, 0x18, 0x80, // temp sensor = internal
0x02, 0x21, 0x00, // display update ctrl 1
@@ -441,6 +439,57 @@ const uint8_t epd102_init_sequence_part[] PROGMEM =
0
};
const uint8_t epd122_init_sequence_full[] PROGMEM =
{
0x01, SSD1608_SW_RESET,
BUSY_WAIT,
0x04, 0x01, 0xaf, 0x00, 0x00, // driver output control
0x02, 0x11, 0x03, // data entry mode
0x03, 0x44, 0x00, 0x17, // ram start/end
0x05, 0x45, 0x00, 0x00, 0xbf, 0x00,
0x02, 0x3c, 0x05, // border waveform
0x02, 0x18, 0x80, // read built-in temp sensor
0x02, 0x4e, 0x00,
0x03, 0x4f, 0x00, 0x00,
BUSY_WAIT,
0x00 // end of table
};
const uint8_t epd122_init_sequence_fast[] PROGMEM =
{
0x01, SSD1608_SW_RESET,
BUSY_WAIT,
0x02, 0x11, 0x03, // data entry mode
0x02, 0x18, 0x80, // read built-in temp sensor
0x02, 0x22, 0xb1, // load temp value
0x01, 0x20, // execute
BUSY_WAIT,
0x03, 0x1a, 0x64, 0x00, // write temp value
0x02, 0x22, 0x91, // load temp
0x01, 0x20, // execute
BUSY_WAIT,
0x03, 0x44, 0x00, 0x17, // ram start/end
0x05, 0x45, 0x00, 0x00, 0xaf, 0x00,
0x02, 0x4e, 0x00,
0x03, 0x4f, 0x00, 0x00,
BUSY_WAIT,
0x00 // end of table
};
const uint8_t epd122_init_sequence_part[] PROGMEM =
{
0x02, 0x3c, 0x80, // border waveform
0x02, 0x11, 0x03, // data entry mode
0x03, 0x44, 0x00, 0x17, // ram start/end
0x05, 0x45, 0x00, 0x00, 0xaf, 0x00,
0x02, 0x4e, 0x00,
0x03, 0x4f, 0x00, 0x00,
BUSY_WAIT,
0x00 // end of table
};
const uint8_t epd293_init_sequence_full[] PROGMEM =
{
0x01, SSD1608_SW_RESET,
@@ -890,11 +939,12 @@ const uint8_t epd294_init_sequence_part[] =
}; /* epd294_init_sequence_part */
uint8_t u8Cache[128]; // buffer a single line of up to 1024 pixels
//
// Definitions for each supported panel
// The order tracks that of the enumerated panel types
// ** ONLY ADD NEW PANELS TO THE END OF THE LIST **
//
const EPD_PANEL panelDefs[] = {
const EPD_PANEL panelDefs[] PROGMEM = {
{0}, // undefined panel
{400, 300, epd42_init_sequence_full, NULL, epd42_init_sequence_part, 0, BBEI_CHIP_UC81xx}, // EPD42_400x300
{400, 300, epd42b_init_sequence_full, epd42b_init_sequence_fast, epd42b_init_sequence_part, 0, BBEI_CHIP_SSD16xx}, // EPD42B_400x300
@@ -905,6 +955,9 @@ const EPD_PANEL panelDefs[] = {
{152, 296, epd266_init_sequence_full, NULL, epd266_init_sequence_part, 0, BBEI_CHIP_SSD16xx}, // EPD266_152x296
{80, 128, epd102_init_sequence_full, NULL, epd102_init_sequence_part, 0, BBEI_CHIP_UC81xx}, // EPD102_80x128
{176, 264, epd27_init_sequence_full, NULL, epd27_init_sequence_part, 0, BBEI_CHIP_SSD16xx}, // EPD27B_176x264
{128, 296, epd29r_init_sequence_full, NULL, NULL, BBEI_3COLOR, BBEI_CHIP_SSD16xx}, // EPD29R_128x296
{192, 176, epd122_init_sequence_full, epd122_init_sequence_fast, epd122_init_sequence_part, 0, BBEI_CHIP_SSD16xx}, // EPD122_192x176
{152, 152, epd154r_init_sequence_full, NULL, NULL, BBEI_3COLOR, BBEI_CHIP_SSD16xx}, // EPD154R_152x152
};
int bbeiSetPanelType(BBEIDISP *pBBEI, int iPanel)
{
@@ -919,6 +972,7 @@ int bbeiSetPanelType(BBEIDISP *pBBEI, int iPanel)
pBBEI->pInitFull = panelDefs[iPanel].pInitFull;
pBBEI->pInitFast = panelDefs[iPanel].pInitFast;
pBBEI->pInitPart = panelDefs[iPanel].pInitPart;
pBBEI->type = iPanel;
return BBEI_SUCCESS;
} /* bbeiSetPanelType() */
@@ -926,7 +980,7 @@ void bbeiSetPosition(BBEIDISP *pBBEI, int x, int y, int cx, int cy)
{
uint8_t uc[12];
int i, tx, ty;
tx = x/8; // round down to next lower byte
ty = y;
cx = (cx + 7) & 0xfff8; // make width an even number of bytes
@@ -957,23 +1011,26 @@ void bbeiSetPosition(BBEIDISP *pBBEI, int x, int y, int cx, int cy)
bbeiWriteData(pBBEI, uc, i);
// EPDWriteCmd(UC8151_PTOU); // partial out
} else { // SSD16xx
// bbeiCMD2(pBBEI, SSD1608_DATA_MODE, 0x3);
bbeiWriteCmd(pBBEI, SSD1608_SET_RAMXPOS);
uc[0] = tx; // start x (byte boundary)
uc[1] = tx+((cx-1)>>3); // end x
bbeiWriteData(pBBEI, uc, 2);
bbeiWriteCmd(pBBEI, SSD1608_SET_RAMYPOS);
uc[0] = (uint8_t)ty; // start y
uc[1] = (uint8_t)(ty>>8);
uc[2] = (uint8_t)(ty+cy-1); // end y
uc[3] = (uint8_t)((ty+cy-1)>>8);
bbeiWriteData(pBBEI, uc, 4);
// set ram counter to start of this region
bbeiCMD2(pBBEI, SSD1608_SET_RAMXCOUNT, tx);
uc[0] = ty;
uc[1] = (ty>>8);
bbeiWriteCmd(pBBEI, SSD1608_SET_RAMYCOUNT);
bbeiWriteData(pBBEI, uc, 2);
// EPD_CMD2(SSD1608_DATA_MODE, 0x3);
// bbeiCMD2(pBBEI, SSD1608_DATA_MODE, 0x3);
}
} /* bbeiSetPosition() */
//
@@ -984,6 +1041,8 @@ void bbeiSendCMDSequence(BBEIDISP *pBBEI, const uint8_t *pSeq)
int iLen;
uint8_t *s;
if (pBBEI == NULL || pSeq == NULL) return;
s = (uint8_t *)pSeq;
while (s[0] != 0) {
iLen = *s++;
@@ -1004,6 +1063,7 @@ int bbeiRefresh(BBEIDISP *pBBEI, int iMode)
{
if (iMode != REFRESH_FULL && iMode != REFRESH_FAST && iMode != REFRESH_PARTIAL)
return BBEI_ERROR_BAD_PARAMETER;
bbeiWakeUp(pBBEI); // tickle the reset line
switch (iMode) {
case REFRESH_FULL:
@@ -1027,6 +1087,9 @@ int bbeiRefresh(BBEIDISP *pBBEI, int iMode)
bbeiWriteCmd(pBBEI, UC8151_DRF);
} else {
const uint8_t u8CMD[3] = {0xf7, 0xc7, 0xff}; // normal, fast, partial
if (pBBEI->iFlags & BBEI_3COLOR) {
iMode = REFRESH_FAST;
} // 3-color = 0xc7
bbeiCMD2(pBBEI, SSD1608_DISP_CTRL2, u8CMD[iMode]);
bbeiWriteCmd(pBBEI, SSD1608_MASTER_ACTIVATE); // refresh
}
+165 -120
View File
@@ -18,7 +18,9 @@
//
#ifndef __BB_EI_GFX__
#define __BB_EI_GFX__
#include <Group5.h>
#include "bb_font.h"
G5DECIMAGE g5dec;
// forward declarations
void InvertBytes(uint8_t *pData, uint8_t bLen);
@@ -566,21 +568,129 @@ void bbeiSetTextWrap(BBEIDISP *pBBEI, int bWrap)
pBBEI->wrap = bWrap;
} /* bbeiSetTextWrap() */
//
// Draw a string of BB_FONT characters directly into the EPD framebuffer
//
void bbeiWriteStringCustom(BBEIDISP *pBBEI, BB_FONT *pFont, int x, int y, char *szMsg, int iColor, uint8_t iPlane)
{
int rc, i, h, w, end_y, dx, dy, ty, iSrcPitch, iPitch;
unsigned int c;
uint8_t *s;
BB_GLYPH *pGlyph;
uint8_t *pBits, u8CMD, u8EndMask;
if (x == -1)
x = pBBEI->iCursorX;
if (y == -1)
y = pBBEI->iCursorY;
if (x == CENTER_X) { // center the string on the e-paper
dx = i = 0;
while (szMsg[i]) {
c = szMsg[i++];
if (c < pFont->first || c > pFont->last) // undefined character
continue; // skip it
c -= pFont->first; // first char of font defined
pGlyph = &pFont->glyphs[c]; // glyph info for this character
dx += pGlyph->xAdvance;
}
x = (pBBEI->native_width - dx)/2;
if (x < 0) x = 0;
}
// Point to the start of the compressed data
pBits = (uint8_t *)pFont;
pBits += sizeof(BB_FONT);
pBits += (pFont->last - pFont->first + 1) * sizeof(BB_GLYPH);
i = 0;
while (szMsg[i] && x < pBBEI->native_width && y < pBBEI->native_height) {
c = szMsg[i++];
if (c < pFont->first || c > pFont->last) // undefined character
continue; // skip it
c -= pFont->first; // first char of font defined
pGlyph = &pFont->glyphs[c]; // glyph info for this character
if (pGlyph->width > 1) { // skip this if drawing a space
dx = x + pGlyph->xOffset; // offset from character UL to start drawing
dy = y + pGlyph->yOffset;
s = pBits + pGlyph->bitmapOffset; // start of compressed bitmap data
if (pFont->rotation == 0 || pFont->rotation == 180) {
h = pGlyph->height;
w = pGlyph->width;
} else { // rotated
w = pGlyph->height;
h = pGlyph->width;
}
if ((dy + h) > pBBEI->native_height) { // trim it
h = pBBEI->native_height - dy;
}
u8EndMask = 0xff;
if (w & 7) { // width ends on a partial byte
u8EndMask <<= (8-(w & 7));
}
end_y = dy + h;
ty = (pGlyph[1].bitmapOffset - (intptr_t)(s - pBits)); // compressed size
if (ty < 0 || ty > 4096) ty = 4096; // DEBUG
rc = g5_decode_init(&g5dec, w, h, s, ty);
if (rc != G5_SUCCESS) return; // corrupt data?
// set the memory window for this character
iSrcPitch = (w+7)/8;
w += (dx & 7); // add parital byte
bbeiSetPosition(pBBEI, dx, dy, w, h);
iPitch = (w+7)/8;
// start writing into the correct plane
if (pBBEI->chip_type == BBEI_CHIP_UC81xx) {
u8CMD = /*(iPlane) ? UC8151_DTM1 : */UC8151_DTM2;
} else {
u8CMD = /*(iPlane) ? SSD1608_WRITE_ALTRAM :*/ SSD1608_WRITE_RAM;
}
bbeiWriteCmd(pBBEI, u8CMD); // memory write command
for (ty=dy; ty<end_y && ty < pBBEI->native_height; ty++) {
g5_decode_line(&g5dec, u8Cache);
u8Cache[iSrcPitch-1] &= u8EndMask; // clean pixels beyond character width
u8Cache[iSrcPitch] = 0;
if (dx & 7) { // need to shift it over by 1-7 bits
uint8_t *s = u8Cache, uc1, uc0 = 0; // last shifted byte
uint8_t n = dx & 7; // shift amount
for (int j=0; j<w+7; j+= 8) {
uc1 = *s;
uc0 |= (uc1 >> n);
*s++ = uc0;
uc0 = uc1 << (8-n);
}
*s++ = uc0; // store final byte
*s++ = 0; // and a zero for good measure
}
if (iColor == BBEI_BLACK) InvertBytes(u8Cache, iPitch);
bbeiWriteData(pBBEI, u8Cache, iPitch); // write each row into the EPD framebuffer
} // for y
} // if not drawing a space
if (pFont->rotation == 0 || pFont->rotation == 180) {
x += pGlyph->xAdvance; // width of this character
} else {
y += pGlyph->xAdvance;
}
} // while drawing characters
pBBEI->iCursorX = x;
pBBEI->iCursorY = y;
} /* EPDWriteStringDirect() *///
// Draw a string of normal (8x8), small (6x8) or large (16x32) characters
// At the given col+row
//
int bbeiWriteString(BBEIDISP *pBBEI, int iScroll, int x, int y, char *szMsg, int iSize, int iColor, int bRender)
int bbeiWriteString(BBEIDISP *pBBEI, int x, int y, char *szMsg, int iSize, int iColor)
{
int i, iFontOff, iLen, iFontSkip;
unsigned char c, *s;
int i, iFontOff, iLen;
uint8_t c, *s, ucCMD1, ucCMD2;
int iOldFG; // old fg color to make sure red works
uint8_t u8Temp[128];
uint8_t u8Temp[128];
if (pBBEI == NULL) return BBEI_ERROR_BAD_PARAMETER;
if (pBBEI->chip_type == BBEI_CHIP_UC81xx) {
ucCMD1 = UC8151_DTM2;
ucCMD2 = UC8151_DTM1;
} else {
ucCMD1 = SSD1608_WRITE_RAM;
ucCMD2 = SSD1608_WRITE_ALTRAM;
}
// e-paper color is inverted compared to OLED/LCD. If we're in bufferless mode, we'll need to
// invert the requested color
if (pBBEI->type >= EPD42_400x300 && !pBBEI->ucScreen) {
// If we're in bufferless mode, we'll need to invert the requested color
if (!pBBEI->ucScreen) {
iColor = 1 - iColor; // invert the color
}
if (x == -1 || y == -1) // use the cursor position
@@ -592,7 +702,6 @@ int iOldFG; // old fg color to make sure red works
if (pBBEI->iCursorX >= pBBEI->width || pBBEI->iCursorY >= pBBEI->height)
return BBEI_ERROR_BAD_PARAMETER; // can't draw off the display
bbeiSetPosition(pBBEI, pBBEI->iCursorX, pBBEI->iCursorY, 8, 16);
iOldFG = pBBEI->iFG; // save old fg color
if (iColor >= BBEI_YELLOW) {
pBBEI->iFG = iColor;
@@ -600,106 +709,42 @@ int iOldFG; // old fg color to make sure red works
if (iSize == FONT_8x8) // 8x8 font
{
i = 0;
iFontSkip = iScroll & 7; // number of columns to initially skip
if (!pBBEI->ucScreen) { // bufferless mode, rotate the coordinate system to fit the situation
// bbeiSetPosition(pBBEI, √, pBBEI->iCursorX, 8, pBBEI->native_height-pBBEI->iCursorX);
// bbeiWriteCmd(pBBEI, ucCMD1); // write to "new" plane
}
while (pBBEI->iCursorX < pBBEI->width && szMsg[i] != 0 && pBBEI->iCursorY < pBBEI->height)
{
if (iScroll < 8) // only display visible characters
{
c = (unsigned char)szMsg[i];
iFontOff = (int)(c-32) * 7;
// we can't directly use the pointer to FLASH memory, so copy to a local buffer
u8Temp[0] = 0; // first column is blank
memcpy_P(&u8Temp[1], &ucFont[iFontOff], 7);
if (iColor == BBEI_WHITE) InvertBytes(u8Temp, 8);
iLen = 8 - iFontSkip;
if (pBBEI->iCursorX + iLen > pBBEI->width) // clip right edge
iLen = pBBEI->width - pBBEI->iCursorX;
bbeiWriteData(pBBEI, &u8Temp[iFontSkip], iLen);
// obdWriteDataBlock(pBBEI, &ucTemp[iFontSkip], iLen, bRender); // write character pattern
pBBEI->iCursorX += iLen;
if (pBBEI->iCursorX >= pBBEI->width-7 && pBBEI->wrap) // word wrap enabled?
{
pBBEI->iCursorX = 0; // start at the beginning of the next line
pBBEI->iCursorY+=8;
bbeiSetPosition(pBBEI, pBBEI->iCursorX, pBBEI->iCursorY, 8, 8);
}
iFontSkip = 0;
c = (unsigned char)szMsg[i];
iFontOff = (int)(c-32) * 7;
// we can't directly use the pointer to FLASH memory, so copy to a local buffer
u8Temp[0] = 0; // first column is blank
memcpy_P(&u8Temp[1], &ucFont[iFontOff], 7); // only needed on AVR
if (iColor == BBEI_WHITE) InvertBytes(u8Temp, 8);
iLen = 8;
if (pBBEI->iCursorX + iLen > pBBEI->width) { // clip right edge
iLen = pBBEI->width - pBBEI->iCursorX;
}
if (!pBBEI->ucScreen) { // bufferless mode, rotate the coordinate system to fit the situation
bbeiSetPosition(pBBEI, pBBEI->native_width-8-pBBEI->iCursorY, pBBEI->iCursorX, 8, pBBEI->native_height-pBBEI->iCursorX);
bbeiWriteCmd(pBBEI, ucCMD1); // write to "new" plane
bbeiWriteData(pBBEI, u8Temp, iLen);
} else { // draw in memory
// DEBUG
}
pBBEI->iCursorX += iLen;
if (pBBEI->iCursorX >= pBBEI->width-7 && pBBEI->wrap) { // word wrap enabled?
pBBEI->iCursorX = 0; // start at the beginning of the next line
pBBEI->iCursorY+=8;
}
iScroll -= 8;
i++;
} // while
pBBEI->iFG = iOldFG; // restore color
return BBEI_SUCCESS;
} // 8x8
else if (iSize == FONT_16x16) // 8x8 stretched to 16x16
{
} else if (iSize == FONT_12x16) { // 6x8 stretched to 12x16
i = 0;
iFontSkip = iScroll & 15; // number of columns to initially skip
while (pBBEI->iCursorX < pBBEI->width && pBBEI->iCursorY < pBBEI->height && szMsg[i] != 0)
{
while (pBBEI->iCursorX < pBBEI->width && pBBEI->iCursorY < pBBEI->height && szMsg[i] != 0) {
// stretch the 'normal' font instead of using the big font
if (iScroll < 16) // if characters are visible
{
int tx, ty;
c = szMsg[i] - 32;
unsigned char uc1, uc2, ucMask, *pDest;
s = (unsigned char *)&ucFont[(int)c*7];
u8Temp[0] = 0; // first column is blank
memcpy_P(&u8Temp[1], s, 7);
if (iColor == BBEI_WHITE)
InvertBytes(u8Temp, 8);
// Stretch the font to double width + double height
memset(&u8Temp[8], 0, 32); // write 32 new bytes
for (tx=0; tx<8; tx++)
{
ucMask = 3;
pDest = &u8Temp[8+tx*2];
uc1 = uc2 = 0;
c = u8Temp[tx];
for (ty=0; ty<4; ty++)
{
if (c & (1 << ty)) // a bit is set
uc1 |= ucMask;
if (c & (1 << (ty + 4)))
uc2 |= ucMask;
ucMask <<= 2;
}
pDest[0] = uc1;
pDest[1] = uc1; // double width
pDest[16] = uc2;
pDest[17] = uc2;
}
iLen = 16 - iFontSkip;
if (pBBEI->iCursorX + iLen > pBBEI->width) // clip right edge
iLen = pBBEI->width - pBBEI->iCursorX;
bbeiSetPosition(pBBEI, pBBEI->iCursorX, pBBEI->iCursorY, 8, iLen);
bbeiWriteData(pBBEI, &u8Temp[8+iFontSkip], iLen);
bbeiSetPosition(pBBEI, pBBEI->iCursorX, pBBEI->iCursorY+8, 8, iLen);
bbeiWriteData(pBBEI, &u8Temp[24+iFontSkip], iLen);
pBBEI->iCursorX += iLen;
if (pBBEI->iCursorX >= pBBEI->width-15 && pBBEI->wrap) // word wrap enabled?
{
pBBEI->iCursorX = 0; // start at the beginning of the next line
pBBEI->iCursorY += 16;
bbeiSetPosition(pBBEI, pBBEI->iCursorX, pBBEI->iCursorY, 8, 16);
}
iFontSkip = 0;
} // if characters are visible
iScroll -= 16;
i++;
} // while
pBBEI->iFG = iOldFG; // restore color
return BBEI_SUCCESS;
} // 16x16
else if (iSize == FONT_12x16) // 6x8 stretched to 12x16
{
i = 0;
iFontSkip = iScroll % 12; // number of columns to initially skip
while (pBBEI->iCursorX < pBBEI->width && pBBEI->iCursorY < pBBEI->height && szMsg[i] != 0)
{
// stretch the 'normal' font instead of using the big font
if (iScroll < 12) // if characters are visible
{
int tx, ty;
c = szMsg[i] - 32;
unsigned char uc1, uc2, ucMask, *pDest;
@@ -807,23 +852,25 @@ int iOldFG; // old fg color to make sure red works
ucMask <<= 1; ucMask2 <<= 1;
}
}
iLen = 12 - iFontSkip;
iLen = 12;
if (pBBEI->iCursorX + iLen > pBBEI->width) // clip right edge
iLen = pBBEI->width - pBBEI->iCursorX;
bbeiSetPosition(pBBEI, pBBEI->iCursorX, pBBEI->iCursorY, 8, iLen);
bbeiWriteData(pBBEI, &u8Temp[6+iFontSkip], iLen);
bbeiSetPosition(pBBEI, pBBEI->iCursorX, pBBEI->iCursorY+8, 8, iLen);
bbeiWriteData(pBBEI, &u8Temp[18+iFontSkip], iLen);
if (!pBBEI->ucScreen) { // bufferless mode
bbeiSetPosition(pBBEI, pBBEI->native_width-8-pBBEI->iCursorY, pBBEI->iCursorX, 8, iLen);
bbeiWriteCmd(pBBEI, ucCMD1); // write to "new" plane
bbeiWriteData(pBBEI, &u8Temp[6], iLen);
bbeiSetPosition(pBBEI, pBBEI->native_width-16-pBBEI->iCursorY, pBBEI->iCursorX, 8, iLen);
bbeiWriteCmd(pBBEI, ucCMD1); // write to "new" plane
bbeiWriteData(pBBEI, &u8Temp[18], iLen);
} else { // write to RAM
// DEBUG
}
pBBEI->iCursorX += iLen;
if (pBBEI->iCursorX >= pBBEI->width-11 && pBBEI->wrap) // word wrap enabled?
{
pBBEI->iCursorX = 0; // start at the beginning of the next line
pBBEI->iCursorY += 16;
bbeiSetPosition(pBBEI, pBBEI->iCursorX, pBBEI->iCursorY, 8, 16);
}
iFontSkip = 0;
} // if characters are visible
iScroll -= 12;
i++;
} // while
pBBEI->iFG = iOldFG; // restore color
@@ -832,31 +879,29 @@ int iOldFG; // old fg color to make sure red works
else if (iSize == FONT_6x8)
{
i = 0;
iFontSkip = iScroll % 6;
while (pBBEI->iCursorX < pBBEI->width && pBBEI->iCursorY < pBBEI->height && szMsg[i] != 0)
{
if (iScroll < 6) // if characters are visible
{
c = szMsg[i] - 32;
// we can't directly use the pointer to FLASH memory, so copy to a local buffer
u8Temp[0] = 0; // first column is blank
memcpy_P(&u8Temp[1], &ucSmallFont[(int)c*5], 5);
if (iColor == BBEI_WHITE) InvertBytes(u8Temp, 6);
iLen = 6 - iFontSkip;
iLen = 6;
if (pBBEI->iCursorX + iLen > pBBEI->width) // clip right edge
iLen = pBBEI->width - pBBEI->iCursorX;
bbeiWriteData(pBBEI, &u8Temp[iFontSkip], iLen);
// obdWriteDataBlock(pBBEI, &ucTemp[iFontSkip], iLen, bRender); // write character pattern
if (!pBBEI->ucScreen) { // bufferless mode
bbeiSetPosition(pBBEI, pBBEI->iCursorX, pBBEI->iCursorY, 8, iLen);
bbeiWriteCmd(pBBEI, ucCMD1); // write to "new" plane
bbeiWriteData(pBBEI, u8Temp, iLen);
} else { // write to RAM
// DEBUG
}
pBBEI->iCursorX += iLen;
iFontSkip = 0;
if (pBBEI->iCursorX >= pBBEI->width-5 && pBBEI->wrap) // word wrap enabled?
{
pBBEI->iCursorX = 0; // start at the beginning of the next line
pBBEI->iCursorY +=8;
bbeiSetPosition(pBBEI, pBBEI->iCursorX, pBBEI->iCursorY, 8, 16);
}
} // if characters are visible
iScroll -= 6;
i++;
}
pBBEI->iFG = iOldFG; // restore color
@@ -869,7 +914,7 @@ int iOldFG; // old fg color to make sure red works
//
// Get the width of text in a custom font
//
void bbeiGetStringBox(GFXfont *pFont, char *szMsg, int *width, int *top, int *bottom)
void bbeiGetStringBox(BB_FONT *pFont, char *szMsg, int *width, int *top, int *bottom)
{
int cx = 0;
unsigned int c, i = 0;
+34 -13
View File
@@ -1,5 +1,5 @@
//
// bb_eink I/O functions
// bb_eink I/O wrapper functions for Arduino
// Copyright (c) 2024 BitBank Software, Inc.
// Written by Larry Bank (bitbank@pobox.com)
// Project started 9/11/2024
@@ -14,12 +14,17 @@
// See the License for the specific language governing permissions and
// limitations under the License.
//
// 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__
#ifdef ARDUINO
#include <Arduino.h>
#include <SPI.h>
//
// Initialize the GPIO pins and SPI for use by bb_eink
//
void bbeiInitIO(BBEIDISP *pBBEI, uint32_t u32Speed)
{
pinMode(pBBEI->iDCPin, OUTPUT);
@@ -42,7 +47,9 @@ void bbeiInitIO(BBEIDISP *pBBEI, uint32_t u32Speed)
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
} /* bbeiInitIO() */
//
// Toggle the reset line to wake up the eink from deep sleep
//
void bbeiWakeUp(BBEIDISP *pBBEI)
{
digitalWrite(pBBEI->iRSTPin, LOW);
@@ -50,15 +57,23 @@ void bbeiWakeUp(BBEIDISP *pBBEI)
digitalWrite(pBBEI->iRSTPin, HIGH);
delay(10);
} /* bbeiWakeUp() */
//
// 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)
{
uint8_t busy_idle = (pBBEI->chip_type == BBEI_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;
}
} /* bbeiWaitBusy() */
//
// 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)
{
digitalWrite(pBBEI->iDCPin, LOW);
@@ -66,14 +81,16 @@ void bbeiCMD2(BBEIDISP *pBBEI, uint8_t cmd1, uint8_t cmd2)
digitalWrite(pBBEI->iCSPin, LOW);
#endif
SPI.transfer(cmd1);
SPI.transfer(cmd2);
digitalWrite(pBBEI->iDCPin, HIGH); // leave data mode as the default
digitalWrite(pBBEI->iDCPin, HIGH);
SPI.transfer(cmd2); // second byte is data
#ifndef ARDUINO_ARCH_ESP32
digitalWrite(pBBEI->iCSPin, HIGH);
#endif
// digitalWrite(pBBEI->iDCPin, HIGH); // leave data mode as the default
} /* bbeiCMD2() */
//
// Write a single byte as a COMMAND (D/C set low)
//
void bbeiWriteCmd(BBEIDISP *pBBEI, uint8_t cmd)
{
digitalWrite(pBBEI->iDCPin, LOW);
@@ -81,12 +98,14 @@ void bbeiWriteCmd(BBEIDISP *pBBEI, uint8_t cmd)
digitalWrite(pBBEI->iCSPin, LOW);
#endif
SPI.transfer(cmd);
digitalWrite(pBBEI->iDCPin, HIGH); // leave data mode as the default
#ifndef ARDUINO_ARCH_ESP32
digitalWrite(pBBEI->iCSPin, HIGH);
#endif
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) {
@@ -101,10 +120,12 @@ void bbeiSleep(BBEIDISP *pBBEI, int bDeep)
return;
}
} /* bbeiSleep() */
//
// Write 1 or more bytes as DATA (D/C set high)
//
void bbeiWriteData(BBEIDISP *pBBEI, uint8_t *pData, int iLen)
{
// digitalWrite(pBBEI->iDCPin, HIGH);
#ifdef ARDUINO_ARCH_ESP32
SPI.transferBytes(pData, NULL, iLen);
#else
+23 -5
View File
@@ -37,7 +37,8 @@ void delay(int);
#include "bb_ei_io.inl" // I/O (non-portable) code is in here
#include "bb_ei.inl" // All of the display interface code is in here
#include "bb_ei_gfx.inl" // drawing code
#include "Group5.h" // Group5 data compression library
#include "bb_font.h" // bitbank compressed font info
#ifdef __cplusplus
//
// C++ Class implementation
@@ -64,6 +65,8 @@ void BBEINK::initIO(int iDC, int iReset, int iBusy, int iCS, int iMOSI, int iSCL
_bbei.iRSTPin = iReset;
_bbei.iBUSYPin = iBusy;
bbeiInitIO(&_bbei, u32Speed);
bbeiWakeUp(&_bbei);
bbeiSendCMDSequence(&_bbei, _bbei.pInitFull);
} /* initIO() */
int BBEINK::writePlane(int iPlane)
@@ -98,9 +101,9 @@ void BBEINK::setBuffer(uint8_t *pBuffer)
int BBEINK::allocBuffer(void)
{
int iSize = ((_bbei.width+7)>>3) * _bbei.height;
// if (_bbei.iFlags & (BBEI_3COLOR | BBEI_4COLOR) || _bbei.chip_type == BBEI_CHIP_UC81xx)
// iSize *= 2; // 2 bit planes
int iSize = ((_bbei.native_width+7)>>3) * _bbei.native_height;
if (_bbei.iFlags & (BBEI_3COLOR | BBEI_4COLOR) || _bbei.chip_type == BBEI_CHIP_UC81xx)
iSize *= 2; // 2 bit planes
_bbei.ucScreen = (uint8_t *)malloc(iSize);
if (_bbei.ucScreen != NULL) {
return BBEI_SUCCESS;
@@ -189,7 +192,13 @@ int BBEINK::loadBMP3(const uint8_t *pBMP, int x, int y)
void BBEINK::setFont(int iFont)
{
_bbei.iFont = iFont;
// _bbei.pFreeFont = NULL;
_bbei.pFont = NULL;
} /* setFont() */
void BBEINK::setFont(const void *pFont)
{
_bbei.iFont = -1;
_bbei.pFont = (void *)pFont;
} /* setFont() */
//void BBEINK::setFreeFont(const GFXfont *pFont)
@@ -449,4 +458,13 @@ void BBEINK::wait(bool bQuick)
{
bbeiWaitBusy(&_bbei);
}
void BBEINK::drawString(const char *pText, int x, int y)
{
if (_bbei.pFont) {
bbeiWriteStringCustom(&_bbei, (BB_FONT *)_bbei.pFont, x, y, (char *)pText, _bbei.iFG, 0); // iPlane);
} else if (_bbei.iFont >= FONT_6x8 && _bbei.iFont < FONT_COUNT) {
bbeiWriteString(&_bbei, x, y, (char *)pText, _bbei.iFont, _bbei.iFG);
}
} /* drawString() */
#endif // __cplusplus
+9 -7
View File
@@ -69,13 +69,11 @@ enum {
FONT_6x8 = 0,
FONT_8x8,
FONT_12x16,
FONT_16x16,
FONT_16x32,
FONT_CUSTOM0,
FONT_CUSTOM1,
FONT_CUSTOM2,
FONT_COUNT
};
// Centering coordinates to pass to the character drawing functions
#define CENTER_X 9998
#define CENTER_Y 9999
typedef struct epd_panel {
uint16_t width;
@@ -99,6 +97,9 @@ enum {
EPD266_152x296, // GDEY0266T90
EPD102_80x128, // GDEW0102T4
EPD27B_176x264, // GDEY027T91
EPD29R_128x296,
EPD122_192x176, // GDEM0122T61
EPD154R_152x152,
EPD_PANEL_COUNT
};
#ifdef FUTURE
@@ -106,7 +107,6 @@ enum {
EPD42Y_400x300, // DEPG0420YN
EPD29_128x296,
EPD29B_128x296,
EPD29R_128x296,
EPD29Y_128x296, // DEPG0290YN
EPD42R_400x300,
EPD42R2_400x300, // GDEQ042Z21
@@ -254,6 +254,7 @@ int width, height, native_width, native_height;
int iScreenOffset, iOrientation;
int iFG, iBG; //current color
int iFont, iFlags;
void *pFont;
int iDataTime, iOpTime; // time in milliseconds for data transmission and operation
uint32_t iSpeed;
uint32_t iTimeout; // for e-ink panels
@@ -301,6 +302,7 @@ class BBEINK
int loadBMP(const uint8_t *pBMP, int x, int y, int iFG, int iBG);
int loadBMP3(const uint8_t *pBMP, int x, int y);
void setFont(int iFont);
void setFont(const void *pFont);
void drawLine(int x1, int y1, int x2, int y2, int iColor);
void drawPixel(int16_t x, int16_t y, uint8_t color);
int16_t getCursorX(void);
@@ -317,6 +319,7 @@ class BBEINK
void fillEllipse(int16_t x, int16_t y, int32_t rx, int32_t ry, uint16_t color);
void sleep(int bDeep);
void wait(bool bQuick = false);
void drawString(const char *pText, int x, int y);
#ifdef FUTURE
void setPlane(int iPlane);
@@ -328,7 +331,6 @@ class BBEINK
void writeCommand(uint8_t ucCMD);
void writeRaw(uint8_t *pData, int iLen);
void pushImage(int x, int y, int w, int h, uint16_t *pixels);
void drawString(const char *pText, int x, int y);
void drawString(String text, int x, int y);
#endif // FUTURE