@@ -1074,20 +1074,18 @@ void bbepRowControl(FASTEPDSTATE *pState, int iType)
1074
1074
return ;
1075
1075
} /* bbepRowControl() */
1076
1076
1077
- void bbepWriteRow (FASTEPDSTATE *pState, uint8_t *pData, int iLen)
1077
+ // The data needs to come from a DMA buffer or the Espressif DMA driver
1078
+ // will allocate (and leak) an internal buffer each time
1079
+ void bbepWriteRow (FASTEPDSTATE *pState, uint8_t *pData, int iLen, int bRowStep)
1078
1080
{
1079
1081
esp_err_t err;
1080
1082
1081
- if (pData != pState->dma_buf ) {
1082
- // the transaction needs to come from a DMA buffer or the Espressif DMA driver
1083
- // will allocate (and leak) an internal buffer each time
1084
- memcpy (pState->dma_buf , pData, iLen);
1085
- pData = pState->dma_buf ;
1086
- }
1087
-
1088
1083
while (!dma_is_done) {
1089
1084
delayMicroseconds (1 );
1090
1085
}
1086
+ if (bRowStep) {
1087
+ bbepRowControl (pState, ROW_STEP);
1088
+ }
1091
1089
if (bSlowSPH) {
1092
1090
gpio_set_level (u8SPH, 0 ); // SPH/CS active
1093
1091
gpio_set_level (u8CKV, 1 ); // CKV on
@@ -1098,10 +1096,10 @@ void bbepWriteRow(FASTEPDSTATE *pState, uint8_t *pData, int iLen)
1098
1096
if (err != ESP_OK) {
1099
1097
// Serial.printf("Error %d sending LCD data\n", (int)err);
1100
1098
}
1101
- while (!dma_is_done) {
1102
- delayMicroseconds (1 );
1103
- vTaskDelay (0 );
1104
- }
1099
+ // while (!dma_is_done) {
1100
+ // delayMicroseconds(1);
1101
+ // vTaskDelay(0);
1102
+ // }
1105
1103
} /* bbepWriteRow() */
1106
1104
1107
1105
uint8_t TPS65185PowerGood (void )
@@ -1196,7 +1194,7 @@ int bbepSetPanelSize(FASTEPDSTATE *pState, int width, int height, int flags) {
1196
1194
return BBEP_ERROR_NO_MEMORY;
1197
1195
}
1198
1196
// Allocate memory for each line to transmit
1199
- pState->dma_buf = (uint8_t *)heap_caps_malloc ((pState->width / 4 ) + pState->panelDef .iLinePadding + 16 , MALLOC_CAP_DMA);
1197
+ pState->dma_buf = (uint8_t *)heap_caps_malloc ((pState->width / 2 ) + pState->panelDef .iLinePadding + 16 , MALLOC_CAP_DMA);
1200
1198
iPasses = (pState->panelDef .iMatrixSize / 16 ); // number of passes
1201
1199
pGrayLower = (uint32_t *)malloc (256 * iPasses * sizeof (uint32_t ));
1202
1200
if (!pGrayLower) return BBEP_ERROR_NO_MEMORY;
@@ -1278,14 +1276,15 @@ void bbepInitLights(FASTEPDSTATE *pState, uint8_t led1, uint8_t led2)
1278
1276
// Each name points to a configuration with info about the PCB and possibly a display
1279
1277
// e.g. BB_PANEL_M5PAPERs3 has both PCB and display info in a single configuration
1280
1278
//
1281
- int bbepInitPanel (FASTEPDSTATE *pState, int iPanel)
1279
+ int bbepInitPanel (FASTEPDSTATE *pState, int iPanel, uint32_t u32Speed )
1282
1280
{
1283
1281
int rc;
1284
1282
if (iPanel > 0 && iPanel < BB_PANEL_COUNT) {
1285
1283
pState->iPanelType = iPanel;
1286
1284
pState->width = pState->native_width = panelDefs[iPanel].width ;
1287
1285
pState->height = pState->native_height = panelDefs[iPanel].height ;
1288
1286
memcpy (&pState->panelDef , &panelDefs[iPanel], sizeof (BBPANELDEF));
1287
+ if (u32Speed) pState->panelDef .bus_speed = u32Speed; // custom speed
1289
1288
pState->iFlags = pState->panelDef .flags ; // copy flags to main class structure
1290
1289
// get the 3 callback functions
1291
1290
pState->pfnEinkPower = panelProcs[iPanel].pfnEinkPower ;
@@ -1447,9 +1446,8 @@ void bbepClear(FASTEPDSTATE *pState, uint8_t val, uint8_t count, BBEPRECT *pRect
1447
1446
} else { // mask the area we want to change
1448
1447
memcpy (pState->dma_buf , u8Cache, pState->native_width / 4 );
1449
1448
}
1450
- bbepWriteRow (pState, pState->dma_buf , pState->native_width / 4 );
1451
- // delayMicroseconds(15);
1452
- bbepRowControl (pState, ROW_STEP);
1449
+ bbepWriteRow (pState, pState->dma_buf , pState->native_width / 4 , (i!=0 ));
1450
+ // bbepRowControl(pState, ROW_STEP);
1453
1451
}
1454
1452
delayMicroseconds (230 );
1455
1453
}
@@ -1502,8 +1500,8 @@ int bbepSmoothUpdate(FASTEPDSTATE *pState, bool bKeepOn, uint8_t u8Color)
1502
1500
for (i = 0 ; i < pState->native_height ; i++) {
1503
1501
s = &pState->pTemp [i * (pState->native_width / 4 )];
1504
1502
// Send the data for the row
1505
- bbepWriteRow (pState, s, ( pState->native_width / 4 ) );
1506
- // delayMicroseconds(15 );
1503
+ memcpy (pState-> dma_buf , s, pState->native_width / 4 );
1504
+ bbepWriteRow (pState, pState-> dma_buf , (pState-> native_width / 4 ), 0 );
1507
1505
bbepRowControl (pState, ROW_STEP);
1508
1506
}
1509
1507
delayMicroseconds (230 );
@@ -1513,31 +1511,33 @@ int bbepSmoothUpdate(FASTEPDSTATE *pState, bool bKeepOn, uint8_t u8Color)
1513
1511
uint8_t u8Invert = (u8Color = BBEP_WHITE) ? 0x00 : 0xff ;
1514
1512
for (pass = 0 ; pass < iPasses; pass++) { // number of passes to make 16 unique gray levels
1515
1513
uint8_t *s, *d = pState->dma_buf ;
1514
+ uint32_t *pGrayU, *pGrayL;
1515
+ pGrayU = pGrayUpper + (pass * 256 );
1516
+ pGrayL = pGrayLower + (pass * 256 );
1516
1517
bbepRowControl (pState, ROW_START);
1517
1518
for (i = 0 ; i < pState->native_height ; i++) {
1518
1519
dy = (pState->iFlags & BB_PANEL_FLAG_MIRROR_Y) ? pState->native_height - 1 - i : i;
1519
1520
s = &pState->pCurrent [dy * (pState->native_width / 2 )];
1520
1521
if (pState->iFlags & BB_PANEL_FLAG_MIRROR_X) {
1521
1522
s += (pState->native_width / 2 ) - 8 ;
1522
1523
for (n = 0 ; n < (pState->native_width / 4 ); n += 4 ) {
1523
- d[n + 0 ] = u8Invert ^ (pGrayUpper[pass * 256 + (s[7 ] ^ u8Invert)] | pGrayLower[pass * 256 + (s[6 ] ^ u8Invert)]);
1524
- d[n + 1 ] = u8Invert ^ (pGrayUpper[pass * 256 + (s[5 ] ^ u8Invert)] | pGrayLower[pass * 256 + (s[4 ] ^ u8Invert)]);
1525
- d[n + 2 ] = u8Invert ^ (pGrayUpper[pass * 256 + (s[3 ] ^ u8Invert)] | pGrayLower[pass * 256 + (s[2 ] ^ u8Invert)]);
1526
- d[n + 3 ] = u8Invert ^ (pGrayUpper[pass * 256 + (s[1 ] ^ u8Invert)] | pGrayLower[pass * 256 + (s[0 ] ^ u8Invert)]);
1524
+ d[n + 0 ] = u8Invert ^ (pGrayU[ (s[7 ] ^ u8Invert)] | pGrayL[ (s[6 ] ^ u8Invert)]);
1525
+ d[n + 1 ] = u8Invert ^ (pGrayU[ (s[5 ] ^ u8Invert)] | pGrayL[ (s[4 ] ^ u8Invert)]);
1526
+ d[n + 2 ] = u8Invert ^ (pGrayU[ (s[3 ] ^ u8Invert)] | pGrayL[ (s[2 ] ^ u8Invert)]);
1527
+ d[n + 3 ] = u8Invert ^ (pGrayU[ (s[1 ] ^ u8Invert)] | pGrayL[ (s[0 ] ^ u8Invert)]);
1527
1528
s -= 8 ;
1528
1529
} // for n
1529
1530
} else {
1530
1531
for (n = 0 ; n < (pState->native_width / 4 ); n += 4 ) {
1531
- d[n + 0 ] = u8Invert ^ (pGrayUpper[pass * 256 + (s[0 ] ^ u8Invert)] | pGrayLower[pass * 256 + (s[1 ] ^ u8Invert)]);
1532
- d[n + 1 ] = u8Invert ^ (pGrayUpper[pass * 256 + (s[2 ] ^ u8Invert)] | pGrayLower[pass * 256 + (s[3 ] ^ u8Invert)]);
1533
- d[n + 2 ] = u8Invert ^ (pGrayUpper[pass * 256 + (s[4 ] ^ u8Invert)] | pGrayLower[pass * 256 + (s[5 ] ^ u8Invert)]);
1534
- d[n + 3 ] = u8Invert ^ (pGrayUpper[pass * 256 + (s[6 ] ^ u8Invert)] | pGrayLower[pass * 256 + (s[7 ] ^ u8Invert)]);
1532
+ d[n + 0 ] = u8Invert ^ (pGrayU[ (s[0 ] ^ u8Invert)] | pGrayL[ (s[1 ] ^ u8Invert)]);
1533
+ d[n + 1 ] = u8Invert ^ (pGrayU[ (s[2 ] ^ u8Invert)] | pGrayL[ (s[3 ] ^ u8Invert)]);
1534
+ d[n + 2 ] = u8Invert ^ (pGrayU[ (s[4 ] ^ u8Invert)] | pGrayL[ (s[5 ] ^ u8Invert)]);
1535
+ d[n + 3 ] = u8Invert ^ (pGrayU[ (s[6 ] ^ u8Invert)] | pGrayL[ (s[7 ] ^ u8Invert)]);
1535
1536
s += 8 ;
1536
1537
} // for n
1537
1538
// vTaskDelay(0);
1538
1539
}
1539
- bbepWriteRow (pState, pState->dma_buf , (pState->native_width / 4 ));
1540
- // delayMicroseconds(15);
1540
+ bbepWriteRow (pState, pState->dma_buf , (pState->native_width / 4 ), 0 );
1541
1541
bbepRowControl (pState, ROW_STEP);
1542
1542
} // for i
1543
1543
delayMicroseconds (230 );
@@ -1553,25 +1553,43 @@ int bbepSmoothUpdate(FASTEPDSTATE *pState, bool bKeepOn, uint8_t u8Color)
1553
1553
// The time to perform the update can vary greatly depending on the pixel mode
1554
1554
// and selected options
1555
1555
//
1556
- int bbepFullUpdate (FASTEPDSTATE *pState, bool bFast , bool bKeepOn, BBEPRECT *pRect)
1556
+ int bbepFullUpdate (FASTEPDSTATE *pState, int iClearMode , bool bKeepOn, BBEPRECT *pRect)
1557
1557
{
1558
- int i, n, pass, passes ;
1558
+ int i, n, pass, iDMAOff = 0 ;
1559
1559
int iStartCol, iStartRow, iEndCol, iEndRow;
1560
1560
uint8_t u8 ;
1561
1561
1562
1562
#ifdef SHOW_TIME
1563
1563
long l = millis ();
1564
1564
#endif
1565
1565
if (bbepEinkPower (pState, 1 ) != BBEP_SUCCESS) return BBEP_IO_ERROR;
1566
- // Fast mode ~= 600ms, normal mode ~=1000ms
1567
- passes = (bFast) ? 5 :10 ;
1568
- if (!bFast) { // skip initial black phase for fast mode
1569
- bbepClear (pState, BB_CLEAR_DARKEN, passes, pRect);
1570
- bbepClear (pState, BB_CLEAR_NEUTRAL, 1 , pRect);
1566
+ switch (iClearMode) {
1567
+ case CLEAR_SLOW:
1568
+ bbepClear (pState, BB_CLEAR_DARKEN, 10 , pRect);
1569
+ bbepClear (pState, BB_CLEAR_LIGHTEN, 10 , pRect);
1570
+ bbepClear (pState, BB_CLEAR_DARKEN, 10 , pRect);
1571
+ bbepClear (pState, BB_CLEAR_LIGHTEN, 10 , pRect);
1572
+ break ;
1573
+ case CLEAR_FAST:
1574
+ bbepClear (pState, BB_CLEAR_DARKEN, 8 , pRect);
1575
+ bbepClear (pState, BB_CLEAR_LIGHTEN, 8 , pRect);
1576
+ break ;
1577
+ case CLEAR_WHITE:
1578
+ bbepClear (pState, BB_CLEAR_LIGHTEN, 5 , pRect);
1579
+ break ;
1580
+ case CLEAR_BLACK: // probably a mistake
1581
+ bbepClear (pState, BB_CLEAR_DARKEN, 5 , pRect);
1582
+ break ;
1583
+ case CLEAR_NONE: // nothing to do
1584
+ default :
1585
+ break ;
1571
1586
}
1572
- bbepClear (pState, BB_CLEAR_LIGHTEN, passes, pRect);
1573
- bbepClear (pState, BB_CLEAR_DARKEN, passes, pRect);
1574
- bbepClear (pState, BB_CLEAR_LIGHTEN, passes, pRect);
1587
+
1588
+ #ifdef SHOW_TIME
1589
+ l = millis () - l;
1590
+ Serial.printf (" clear time = %dms\n " , (int )l);
1591
+ l = millis ();
1592
+ #endif // SHOW_TIME
1575
1593
1576
1594
if (pRect) {
1577
1595
if (bbepFixRect (pState, pRect, &iStartCol, &iEndCol, &iStartRow, &iEndRow)) return BBEP_ERROR_BAD_PARAMETER;
@@ -1638,39 +1656,46 @@ int bbepFullUpdate(FASTEPDSTATE *pState, bool bFast, bool bKeepOn, BBEPRECT *pRe
1638
1656
// Write N passes of the black data to the whole display
1639
1657
for (pass = 0 ; pass < pState->iFullPasses ; pass++) {
1640
1658
bbepRowControl (pState, ROW_START);
1659
+ iDMAOff = 0 ;
1641
1660
for (i = 0 ; i < pState->native_height ; i++) {
1661
+ d = &pState->dma_buf [iDMAOff];
1642
1662
s = &pState->pTemp [i * (pState->native_width / 4 )];
1643
1663
// Send the data for the row
1644
- bbepWriteRow (pState , s, ( pState->native_width / 4 ) );
1645
- // delayMicroseconds(15 );
1646
- bbepRowControl (pState, ROW_STEP );
1664
+ memcpy (d , s, pState->native_width / 4 );
1665
+ bbepWriteRow (pState, d, (pState-> native_width / 4 ), (i!= 0 ) );
1666
+ iDMAOff ^= (pState-> native_width / 4 );
1647
1667
}
1648
1668
delayMicroseconds (230 );
1649
1669
} // for pass
1650
1670
} else { // must be 4BPP mode
1651
1671
int dy, iPasses = (pState->panelDef .iMatrixSize / 16 ); // number of passes
1652
1672
for (pass = 0 ; pass < iPasses; pass++) { // number of passes to make 16 unique gray levels
1653
- uint8_t *s, *d = pState->dma_buf ;
1673
+ uint8_t *s, *d;
1674
+ uint32_t *pGrayU, *pGrayL;
1675
+ pGrayU = pGrayUpper + (pass * 256 );
1676
+ pGrayL = pGrayLower + (pass * 256 );
1654
1677
bbepRowControl (pState, ROW_START);
1678
+ iDMAOff = 0 ;
1655
1679
for (i = 0 ; i < pState->native_height ; i++) {
1680
+ d = &pState->dma_buf [iDMAOff];
1656
1681
dy = (pState->iFlags & BB_PANEL_FLAG_MIRROR_Y) ? pState->native_height - 1 - i : i;
1657
1682
if (dy >= iStartRow && dy <= iEndRow) { // within the clip rectangle
1658
1683
s = &pState->pCurrent [dy * (pState->native_width / 2 )];
1659
1684
if (pState->iFlags & BB_PANEL_FLAG_MIRROR_X) {
1660
1685
s += (pState->native_width / 2 ) - 8 ;
1661
1686
for (n = 0 ; n < (pState->native_width / 4 ); n += 4 ) {
1662
- d[n + 0 ] = (pGrayUpper[pass * 256 + s[7 ]] | pGrayLower[pass * 256 + s[6 ]]);
1663
- d[n + 1 ] = (pGrayUpper[pass * 256 + s[5 ]] | pGrayLower[pass * 256 + s[4 ]]);
1664
- d[n + 2 ] = (pGrayUpper[pass * 256 + s[3 ]] | pGrayLower[pass * 256 + s[2 ]]);
1665
- d[n + 3 ] = (pGrayUpper[pass * 256 + s[1 ]] | pGrayLower[pass * 256 + s[0 ]]);
1687
+ d[n + 0 ] = (pGrayU[ s[7 ]] | pGrayL[ s[6 ]]);
1688
+ d[n + 1 ] = (pGrayU[ s[5 ]] | pGrayL[ s[4 ]]);
1689
+ d[n + 2 ] = (pGrayU[ s[3 ]] | pGrayL[ s[2 ]]);
1690
+ d[n + 3 ] = (pGrayU[ s[1 ]] | pGrayL[ s[0 ]]);
1666
1691
s -= 8 ;
1667
1692
} // for n
1668
1693
} else {
1669
1694
for (n = 0 ; n < (pState->native_width / 4 ); n += 4 ) {
1670
- d[n + 0 ] = (pGrayUpper[pass * 256 + s[0 ]] | pGrayLower[pass * 256 + s[1 ]]);
1671
- d[n + 1 ] = (pGrayUpper[pass * 256 + s[2 ]] | pGrayLower[pass * 256 + s[3 ]]);
1672
- d[n + 2 ] = (pGrayUpper[pass * 256 + s[4 ]] | pGrayLower[pass * 256 + s[5 ]]);
1673
- d[n + 3 ] = (pGrayUpper[pass * 256 + s[6 ]] | pGrayLower[pass * 256 + s[7 ]]);
1695
+ d[n + 0 ] = (pGrayU[ s[0 ]] | pGrayL[ s[1 ]]);
1696
+ d[n + 1 ] = (pGrayU[ s[2 ]] | pGrayL[ s[3 ]]);
1697
+ d[n + 2 ] = (pGrayU[ s[4 ]] | pGrayL[ s[5 ]]);
1698
+ d[n + 3 ] = (pGrayU[ s[6 ]] | pGrayL[ s[7 ]]);
1674
1699
s += 8 ;
1675
1700
} // for n
1676
1701
// vTaskDelay(0);
@@ -1684,11 +1709,11 @@ int bbepFullUpdate(FASTEPDSTATE *pState, bool bFast, bool bKeepOn, BBEPRECT *pRe
1684
1709
}
1685
1710
}
1686
1711
} else { // outside the clip rectangle
1687
- memset (pState-> dma_buf , 0 , pState->native_width /4 );
1712
+ memset (d , 0 , pState->native_width /4 );
1688
1713
}
1689
- bbepWriteRow (pState, pState-> dma_buf , (pState->native_width / 4 ));
1690
- // delayMicroseconds(15);
1691
- bbepRowControl (pState, ROW_STEP);
1714
+ bbepWriteRow (pState, d , (pState->native_width / 4 ), (i!= 0 ));
1715
+ iDMAOff ^= (pState-> native_width / 4 ); // toggle offset
1716
+ // bbepRowControl(pState, ROW_STEP);
1692
1717
} // for i
1693
1718
delayMicroseconds (230 );
1694
1719
} // for pass
@@ -1710,7 +1735,7 @@ int bbepFullUpdate(FASTEPDSTATE *pState, bool bFast, bool bKeepOn, BBEPRECT *pRe
1710
1735
1711
1736
int bbepPartialUpdate (FASTEPDSTATE *pState, bool bKeepOn, int iStartLine, int iEndLine)
1712
1737
{
1713
- int i, n, pass;
1738
+ int i, n, pass, iDMAOff ;
1714
1739
#ifdef SHOW_TIME
1715
1740
long l = millis ();
1716
1741
#endif
@@ -1770,34 +1795,38 @@ int bbepPartialUpdate(FASTEPDSTATE *pState, bool bKeepOn, int iStartLine, int iE
1770
1795
iEndLine = i;
1771
1796
}
1772
1797
for (pass = 0 ; pass < pState->iPartialPasses ; pass++) { // each pass is about 32ms
1773
- uint8_t *dp = pState->pTemp ;
1798
+ uint8_t *d, * dp = pState->pTemp ;
1774
1799
int iDelta = pState->native_width / 4 ; // 2 bits per pixel
1775
1800
int iSkipped = 0 ;
1776
1801
if (pState->iFlags & BB_PANEL_FLAG_MIRROR_Y) {
1777
1802
dp = &pState->pTemp [(pState->native_height -1 ) * iDelta]; // read the memory upside down
1778
1803
iDelta = -iDelta;
1779
1804
}
1780
1805
bbepRowControl (pState, ROW_START);
1806
+ iDMAOff = 0 ;
1781
1807
for (i = 0 ; i < pState->native_height ; i++) {
1808
+ d = &pState->dma_buf [iDMAOff];
1782
1809
if (i >= iStartLine && i <= iEndLine) {
1783
1810
// Send the data
1784
- bbepWriteRow (pState, dp, (pState->native_width / 4 ));
1811
+ memcpy (d, dp, pState->native_width /4 );
1812
+ bbepWriteRow (pState, d, (pState->native_width / 4 ), (i!=0 ));
1785
1813
iSkipped = 0 ;
1786
1814
} else {
1787
1815
if (iSkipped >= 2 ) {
1788
1816
gpio_set_level ((gpio_num_t )pState->panelDef .ioCKV , 1 ); // CKV_SET;
1789
1817
delayMicroseconds (35 );
1818
+ bbepRowControl (pState, ROW_STEP);
1790
1819
} else {
1791
1820
// write 2 floating rows
1792
1821
if (iSkipped == 0 ) { // skip
1793
- memset ((void *)pState-> dma_buf , 0 , pState->native_width /4 );
1822
+ memset ((void *)d , 0 , pState->native_width /4 );
1794
1823
}
1795
- bbepWriteRow (pState, pState-> dma_buf , (pState->native_width / 4 ));
1824
+ bbepWriteRow (pState, d , (pState->native_width / 4 ), (i!= 0 ));
1796
1825
}
1797
1826
iSkipped++;
1798
1827
}
1799
- bbepRowControl (pState, ROW_STEP);
1800
1828
dp += iDelta;
1829
+ iDMAOff ^= (pState->native_width /4 );
1801
1830
}
1802
1831
// delayMicroseconds(230);
1803
1832
} // for each pass
0 commit comments