acid-drop

- Hacking the planet from a LilyGo T-Deck using custom firmware
git clone git://git.acid.vegas/acid-drop.git
Log | Files | Refs | Archive | README | LICENSE

Arduino_ESP32LCD16.cpp (12325B)

      1 /*
      2  * start rewrite from:
      3  * https://github.com/lovyan03/LovyanGFX/blob/master/src/lgfx/v0/platforms/LGFX_PARALLEL_ESP32.hpp
      4  */
      5 #include "Arduino_ESP32LCD16.h"
      6 
      7 #if defined(ESP32) && (CONFIG_IDF_TARGET_ESP32S3)
      8 
      9 #define WAIT_LCD_NOT_BUSY while (LCD_CAM.lcd_user.val & LCD_CAM_LCD_START)
     10 
     11 Arduino_ESP32LCD16::Arduino_ESP32LCD16(
     12     int8_t dc, int8_t cs, int8_t wr, int8_t rd,
     13     int8_t d0, int8_t d1, int8_t d2, int8_t d3, int8_t d4, int8_t d5, int8_t d6, int8_t d7,
     14     int8_t d8, int8_t d9, int8_t d10, int8_t d11, int8_t d12, int8_t d13, int8_t d14, int8_t d15)
     15     : _dc(dc), _cs(cs), _wr(wr), _rd(rd),
     16       _d0(d0), _d1(d1), _d2(d2), _d3(d3), _d4(d4), _d5(d5), _d6(d6), _d7(d7),
     17       _d8(d8), _d9(d9), _d10(d10), _d11(d11), _d12(d12), _d13(d13), _d14(d14), _d15(d15)
     18 {
     19 }
     20 
     21 bool Arduino_ESP32LCD16::begin(int32_t speed, int8_t dataMode)
     22 {
     23   if (speed == GFX_NOT_DEFINED)
     24   {
     25     _speed = 8000000UL; // safe frequency
     26   }
     27   else
     28   {
     29     _speed = speed;
     30   }
     31 
     32   pinMode(_dc, OUTPUT);
     33   digitalWrite(_dc, HIGH); // Data mode
     34 
     35   if (_cs != GFX_NOT_DEFINED)
     36   {
     37     pinMode(_cs, OUTPUT);
     38     digitalWrite(_cs, HIGH); // disable chip select
     39   }
     40   if (_cs >= 32)
     41   {
     42     _csPinMask = digitalPinToBitMask(_cs);
     43     _csPortSet = (PORTreg_t)&GPIO.out1_w1ts.val;
     44     _csPortClr = (PORTreg_t)&GPIO.out1_w1tc.val;
     45   }
     46   else if (_cs != GFX_NOT_DEFINED)
     47   {
     48     _csPinMask = digitalPinToBitMask(_cs);
     49     _csPortSet = (PORTreg_t)&GPIO.out_w1ts;
     50     _csPortClr = (PORTreg_t)&GPIO.out_w1tc;
     51   }
     52 
     53   pinMode(_wr, OUTPUT);
     54   digitalWrite(_wr, HIGH); // Set write strobe high (inactive)
     55 
     56   if (_rd != GFX_NOT_DEFINED)
     57   {
     58     pinMode(_rd, OUTPUT);
     59     digitalWrite(_rd, HIGH);
     60   }
     61 
     62   esp_lcd_i80_bus_config_t bus_config = {
     63       .dc_gpio_num = _dc,
     64       .wr_gpio_num = _wr,
     65       .clk_src = LCD_CLK_SRC_PLL160M,
     66       .data_gpio_nums = {
     67           _d0, _d1, _d2, _d3, _d4, _d5, _d6, _d7,
     68           _d8, _d9, _d10, _d11, _d12, _d13, _d14, _d15},
     69       .bus_width = 16,
     70       .max_transfer_bytes = LCD_MAX_PIXELS_AT_ONCE * 2,
     71       .psram_trans_align = 0,
     72       .sram_trans_align = 0};
     73   esp_lcd_new_i80_bus(&bus_config, &_i80_bus);
     74 
     75   uint32_t diff = INT32_MAX;
     76   uint32_t div_n = 256;
     77   uint32_t div_a = 63;
     78   uint32_t div_b = 62;
     79   uint32_t clkcnt = 64;
     80   uint32_t start_cnt = std::min<uint32_t>(64u, (F_CPU / (_speed * 2) + 1));
     81   uint32_t end_cnt = std::max<uint32_t>(2u, F_CPU / 256u / _speed);
     82   if (start_cnt <= 2)
     83   {
     84     end_cnt = 1;
     85   }
     86   for (uint32_t cnt = start_cnt; diff && cnt >= end_cnt; --cnt)
     87   {
     88     float fdiv = (float)F_CPU / cnt / _speed;
     89     uint32_t n = std::max<uint32_t>(2u, (uint32_t)fdiv);
     90     fdiv -= n;
     91 
     92     for (uint32_t a = 63; diff && a > 0; --a)
     93     {
     94       uint32_t b = roundf(fdiv * a);
     95       if (a == b && n == 256)
     96       {
     97         break;
     98       }
     99       uint32_t freq = F_CPU / ((n * cnt) + (float)(b * cnt) / (float)a);
    100       uint32_t d = abs(_speed - (int)freq);
    101       if (diff <= d)
    102       {
    103         continue;
    104       }
    105       diff = d;
    106       clkcnt = cnt;
    107       div_n = n;
    108       div_b = b;
    109       div_a = a;
    110       if (b == 0 || a == b)
    111       {
    112         break;
    113       }
    114     }
    115   }
    116   if (div_a == div_b)
    117   {
    118     div_b = 0;
    119     div_n += 1;
    120   }
    121   int wait = 24 - (div_n * clkcnt);
    122   _fast_wait = (wait < 0) ? 0 : wait;
    123 
    124   lcd_cam_lcd_clock_reg_t lcd_clock;
    125   lcd_clock.lcd_clkcnt_n = std::max(1u, clkcnt - 1);
    126   lcd_clock.lcd_clk_equ_sysclk = (clkcnt == 1);
    127   lcd_clock.lcd_ck_idle_edge = true;
    128   lcd_clock.lcd_ck_out_edge = false;
    129   lcd_clock.lcd_clkm_div_num = div_n;
    130   lcd_clock.lcd_clkm_div_b = div_b;
    131   lcd_clock.lcd_clkm_div_a = div_a;
    132   lcd_clock.lcd_clk_sel = 2; // clock_select: 1=XTAL CLOCK / 2=240MHz / 3=160MHz
    133   lcd_clock.clk_en = true;
    134 
    135   LCD_CAM.lcd_clock.val = lcd_clock.val;
    136 
    137   _dma_chan = _i80_bus->dma_chan;
    138   _dmadesc = (dma_descriptor_t *)heap_caps_malloc(sizeof(dma_descriptor_t), MALLOC_CAP_DMA);
    139 
    140   return true;
    141 }
    142 
    143 void Arduino_ESP32LCD16::beginWrite()
    144 {
    145   CS_LOW();
    146 
    147   LCD_CAM.lcd_misc.val = LCD_CAM_LCD_CD_IDLE_EDGE;
    148   LCD_CAM.lcd_user.val = 0;
    149   LCD_CAM.lcd_user.val = LCD_CAM_LCD_2BYTE_EN | LCD_CAM_LCD_CMD | LCD_CAM_LCD_UPDATE_REG;
    150 }
    151 
    152 void Arduino_ESP32LCD16::endWrite()
    153 {
    154   WAIT_LCD_NOT_BUSY;
    155 
    156   CS_HIGH();
    157 }
    158 
    159 void Arduino_ESP32LCD16::writeCommand(uint8_t c)
    160 {
    161   WRITECOMMAND16(c);
    162 }
    163 
    164 void Arduino_ESP32LCD16::writeCommand16(uint16_t c)
    165 {
    166   WRITECOMMAND16(c);
    167 }
    168 
    169 void Arduino_ESP32LCD16::write(uint8_t d)
    170 {
    171   WRITE16(d);
    172 }
    173 
    174 void Arduino_ESP32LCD16::write16(uint16_t d)
    175 {
    176   WRITE16(d);
    177 }
    178 
    179 void Arduino_ESP32LCD16::writeRepeat(uint16_t p, uint32_t len)
    180 {
    181   if (len < USE_DMA_THRESHOLD)
    182   {
    183     while (len--)
    184     {
    185       WRITE16(p);
    186     }
    187   }
    188   else
    189   {
    190     uint32_t bufLen = (len < LCD_MAX_PIXELS_AT_ONCE) ? len : LCD_MAX_PIXELS_AT_ONCE;
    191     uint32_t xferLen, l;
    192     uint32_t c32 = p * 0x10001;
    193 
    194     l = (bufLen + 1) / 2;
    195     for (uint32_t i = 0; i < l; i++)
    196     {
    197       _buffer32[i] = c32;
    198     }
    199 
    200     while (len) // While pixels remain
    201     {
    202       xferLen = (bufLen <= len) ? bufLen : len; // How many this pass?
    203 
    204       l = (xferLen - 2) * 2;
    205       *(uint32_t *)_dmadesc = ((l + 3) & (~3)) | l << 12 | 0xC0000000;
    206       _dmadesc->buffer = _buffer;
    207       _dmadesc->next = nullptr;
    208       gdma_start(_dma_chan, (intptr_t)(_dmadesc));
    209       LCD_CAM.lcd_misc.val = LCD_CAM_LCD_CD_IDLE_EDGE;
    210       LCD_CAM.lcd_cmd_val.val = c32;
    211 
    212       uint32_t wait = _fast_wait;
    213       if (wait > 0)
    214       {
    215         do
    216         {
    217           __asm__ __volatile__("nop");
    218         } while (--wait);
    219       }
    220 
    221       len -= xferLen;
    222 
    223       LCD_CAM.lcd_user.val = LCD_CAM_LCD_ALWAYS_OUT_EN | LCD_CAM_LCD_2BYTE_EN | LCD_CAM_LCD_CMD_2_CYCLE_EN | LCD_CAM_LCD_DOUT | LCD_CAM_LCD_CMD | LCD_CAM_LCD_UPDATE_REG | LCD_CAM_LCD_START;
    224 
    225       WAIT_LCD_NOT_BUSY;
    226     }
    227   }
    228 }
    229 
    230 void Arduino_ESP32LCD16::writePixels(uint16_t *data, uint32_t len)
    231 {
    232   uint32_t xferLen, l;
    233 
    234   while (len > USE_DMA_THRESHOLD) // While pixels remain
    235   {
    236     xferLen = (len < LCD_MAX_PIXELS_AT_ONCE) ? len : LCD_MAX_PIXELS_AT_ONCE; // How many this pass?
    237     _data32.value16 = *data++;
    238     _data32.value16_2 = *data++;
    239 
    240     l = xferLen - 2;
    241     l <<= 1;
    242     *(uint32_t *)_dmadesc = ((l + 3) & (~3)) | l << 12 | 0xC0000000;
    243     _dmadesc->buffer = data;
    244     _dmadesc->next = nullptr;
    245     gdma_start(_dma_chan, (intptr_t)(_dmadesc));
    246     LCD_CAM.lcd_misc.val = LCD_CAM_LCD_CD_IDLE_EDGE;
    247     LCD_CAM.lcd_cmd_val.val = _data32.value;
    248 
    249     uint32_t wait = _fast_wait;
    250     while (wait--)
    251     {
    252       __asm__ __volatile__("nop");
    253     }
    254 
    255     data += xferLen - 2;
    256     len -= xferLen;
    257 
    258     LCD_CAM.lcd_user.val = LCD_CAM_LCD_ALWAYS_OUT_EN | LCD_CAM_LCD_2BYTE_EN | LCD_CAM_LCD_CMD_2_CYCLE_EN | LCD_CAM_LCD_DOUT | LCD_CAM_LCD_CMD | LCD_CAM_LCD_UPDATE_REG | LCD_CAM_LCD_START;
    259 
    260     WAIT_LCD_NOT_BUSY;
    261   }
    262 
    263   while (len--)
    264   {
    265     WRITE16(*data++);
    266   }
    267 }
    268 
    269 void Arduino_ESP32LCD16::writeC8D8(uint8_t c, uint8_t d)
    270 {
    271   WRITECOMMAND16(c);
    272   WRITE16(d);
    273 }
    274 
    275 void Arduino_ESP32LCD16::writeC8D16(uint8_t c, uint16_t d)
    276 {
    277   WRITECOMMAND16(c);
    278   WRITE16(d);
    279 }
    280 
    281 void Arduino_ESP32LCD16::writeC8D16D16(uint8_t c, uint16_t d1, uint16_t d2)
    282 {
    283   WRITECOMMAND16(c);
    284   WRITE16(d1);
    285   WRITE16(d2);
    286 }
    287 
    288 void Arduino_ESP32LCD16::writeC8D16D16Split(uint8_t c, uint16_t d1, uint16_t d2)
    289 {
    290   WRITECOMMAND16(c);
    291 
    292   _data16.value = d1;
    293   WRITE16(_data16.msb);
    294   WRITE16(_data16.lsb);
    295 
    296   _data16.value = d2;
    297   WRITE16(_data16.msb);
    298   WRITE16(_data16.lsb);
    299 }
    300 
    301 void Arduino_ESP32LCD16::writeBytes(uint8_t *data, uint32_t len)
    302 {
    303   uint32_t xferLen, l;
    304 
    305   while (len > (USE_DMA_THRESHOLD * 2)) // While pixels remain
    306   {
    307     xferLen = (len < (LCD_MAX_PIXELS_AT_ONCE * 2)) ? len : (LCD_MAX_PIXELS_AT_ONCE * 2); // How many this pass?
    308     _data32.msb = *data++;
    309     _data32.lsb = *data++;
    310     _data32.msb_2 = *data++;
    311     _data32.lsb_2 = *data++;
    312 
    313     l = xferLen - 4;
    314     l >>= 1;
    315     for (int i = 0; i < l; ++i)
    316     {
    317       _buffer[(i * 2) + 1] = *data++;
    318       _buffer[i * 2] = *data++;
    319     }
    320 
    321     l <<= 1;
    322     *(uint32_t *)_dmadesc = ((l + 3) & (~3)) | l << 12 | 0xC0000000;
    323     _dmadesc->buffer = _buffer;
    324     _dmadesc->next = nullptr;
    325     gdma_start(_dma_chan, (intptr_t)(_dmadesc));
    326     LCD_CAM.lcd_misc.val = LCD_CAM_LCD_CD_IDLE_EDGE;
    327     LCD_CAM.lcd_cmd_val.val = _data32.value;
    328 
    329     uint32_t wait = _fast_wait;
    330     while (wait--)
    331     {
    332       __asm__ __volatile__("nop");
    333     }
    334 
    335     len -= xferLen;
    336 
    337     LCD_CAM.lcd_user.val = LCD_CAM_LCD_ALWAYS_OUT_EN | LCD_CAM_LCD_2BYTE_EN | LCD_CAM_LCD_CMD_2_CYCLE_EN | LCD_CAM_LCD_DOUT | LCD_CAM_LCD_CMD | LCD_CAM_LCD_UPDATE_REG | LCD_CAM_LCD_START;
    338     WAIT_LCD_NOT_BUSY;
    339   }
    340 
    341   while (len)
    342   {
    343     if (len == 1)
    344     {
    345       WRITE16(*data);
    346       len--;
    347     }
    348     else
    349     {
    350       _data16.lsb = *data++;
    351       _data16.msb = *data++;
    352       WRITE16(_data16.value);
    353       len -= 2;
    354     }
    355   }
    356 }
    357 
    358 void Arduino_ESP32LCD16::writePattern(uint8_t *data, uint8_t len, uint32_t repeat)
    359 {
    360   while (repeat--)
    361   {
    362     writeBytes(data, len);
    363   }
    364 }
    365 
    366 void Arduino_ESP32LCD16::writeIndexedPixels(uint8_t *data, uint16_t *idx, uint32_t len)
    367 {
    368   uint32_t xferLen, l;
    369   uint32_t p;
    370 
    371   while (len > USE_DMA_THRESHOLD) // While pixels remain
    372   {
    373     xferLen = (len < LCD_MAX_PIXELS_AT_ONCE) ? len : LCD_MAX_PIXELS_AT_ONCE; // How many this pass?
    374     l = xferLen - 2;
    375     p = idx[*data++];
    376     p <<= 16;
    377     p |= idx[*data++];
    378 
    379     for (int i = 0; i < l; ++i)
    380     {
    381       _buffer16[i] = idx[*data++];
    382     }
    383 
    384     l <<= 1;
    385     *(uint32_t *)_dmadesc = ((l + 3) & (~3)) | l << 12 | 0xC0000000;
    386     _dmadesc->buffer = _buffer;
    387     _dmadesc->next = nullptr;
    388     gdma_start(_dma_chan, (intptr_t)(_dmadesc));
    389     LCD_CAM.lcd_misc.val = LCD_CAM_LCD_CD_IDLE_EDGE;
    390     LCD_CAM.lcd_cmd_val.val = p;
    391 
    392     uint32_t wait = _fast_wait;
    393     while (wait--)
    394     {
    395       __asm__ __volatile__("nop");
    396     }
    397 
    398     len -= xferLen;
    399 
    400     LCD_CAM.lcd_user.val = LCD_CAM_LCD_ALWAYS_OUT_EN | LCD_CAM_LCD_2BYTE_EN | LCD_CAM_LCD_CMD_2_CYCLE_EN | LCD_CAM_LCD_DOUT | LCD_CAM_LCD_CMD | LCD_CAM_LCD_UPDATE_REG | LCD_CAM_LCD_START;
    401     WAIT_LCD_NOT_BUSY;
    402   }
    403 
    404   while (len--)
    405   {
    406     WRITE16(idx[*data++]);
    407   }
    408 }
    409 
    410 void Arduino_ESP32LCD16::writeIndexedPixelsDouble(uint8_t *data, uint16_t *idx, uint32_t len)
    411 {
    412   len <<= 1; // double length
    413   uint32_t xferLen, l;
    414   uint32_t p;
    415 
    416   while (len > USE_DMA_THRESHOLD) // While pixels remain
    417   {
    418     xferLen = (len < LCD_MAX_PIXELS_AT_ONCE) ? len : LCD_MAX_PIXELS_AT_ONCE; // How many this pass?
    419     l = (xferLen - 2) / 2;
    420     p = idx[*data++] * 0x10001;
    421 
    422     for (int i = 0; i < l; ++i)
    423     {
    424       _buffer32[i] = idx[*data++] * 0x10001;
    425     }
    426 
    427     l <<= 2;
    428     *(uint32_t *)_dmadesc = ((l + 3) & (~3)) | l << 12 | 0xC0000000;
    429     _dmadesc->buffer = _buffer;
    430     _dmadesc->next = nullptr;
    431     gdma_start(_dma_chan, (intptr_t)(_dmadesc));
    432     LCD_CAM.lcd_misc.val = LCD_CAM_LCD_CD_IDLE_EDGE;
    433     LCD_CAM.lcd_cmd_val.val = p;
    434 
    435     uint32_t wait = _fast_wait;
    436     while (wait--)
    437     {
    438       __asm__ __volatile__("nop");
    439     }
    440 
    441     len -= xferLen;
    442 
    443     LCD_CAM.lcd_user.val = LCD_CAM_LCD_ALWAYS_OUT_EN | LCD_CAM_LCD_2BYTE_EN | LCD_CAM_LCD_CMD_2_CYCLE_EN | LCD_CAM_LCD_DOUT | LCD_CAM_LCD_CMD | LCD_CAM_LCD_UPDATE_REG | LCD_CAM_LCD_START;
    444     WAIT_LCD_NOT_BUSY;
    445   }
    446 
    447   len >>= 1;
    448   while (len--)
    449   {
    450     p = idx[*data++] * 0x10001;
    451     WRITE32(p);
    452   }
    453 }
    454 
    455 INLINE void Arduino_ESP32LCD16::WRITECOMMAND16(uint16_t c)
    456 {
    457   LCD_CAM.lcd_misc.val = LCD_CAM_LCD_CD_IDLE_EDGE | LCD_CAM_LCD_CD_CMD_SET;
    458   LCD_CAM.lcd_cmd_val.val = c;
    459   WAIT_LCD_NOT_BUSY;
    460   LCD_CAM.lcd_user.val = LCD_CAM_LCD_2BYTE_EN | LCD_CAM_LCD_CMD | LCD_CAM_LCD_UPDATE_REG | LCD_CAM_LCD_START;
    461 }
    462 
    463 INLINE void Arduino_ESP32LCD16::WRITE16(uint16_t d)
    464 {
    465   LCD_CAM.lcd_misc.val = LCD_CAM_LCD_CD_IDLE_EDGE;
    466   LCD_CAM.lcd_cmd_val.val = d;
    467   WAIT_LCD_NOT_BUSY;
    468   LCD_CAM.lcd_user.val = LCD_CAM_LCD_2BYTE_EN | LCD_CAM_LCD_CMD | LCD_CAM_LCD_UPDATE_REG | LCD_CAM_LCD_START;
    469 }
    470 
    471 INLINE void Arduino_ESP32LCD16::WRITE32(uint32_t d)
    472 {
    473   LCD_CAM.lcd_misc.val = LCD_CAM_LCD_CD_IDLE_EDGE;
    474   LCD_CAM.lcd_cmd_val.val = d;
    475   WAIT_LCD_NOT_BUSY;
    476   LCD_CAM.lcd_user.val = LCD_CAM_LCD_CMD_2_CYCLE_EN | LCD_CAM_LCD_2BYTE_EN | LCD_CAM_LCD_CMD | LCD_CAM_LCD_UPDATE_REG | LCD_CAM_LCD_START;
    477 }
    478 
    479 /******** low level bit twiddling **********/
    480 
    481 INLINE void Arduino_ESP32LCD16::CS_HIGH(void)
    482 {
    483   if (_cs != GFX_NOT_DEFINED)
    484   {
    485     *_csPortSet = _csPinMask;
    486   }
    487 }
    488 
    489 INLINE void Arduino_ESP32LCD16::CS_LOW(void)
    490 {
    491   if (_cs != GFX_NOT_DEFINED)
    492   {
    493     *_csPortClr = _csPinMask;
    494   }
    495 }
    496 
    497 #endif // #if defined(ESP32) && (CONFIG_IDF_TARGET_ESP32S3)