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)