acidportal- 😈 Worlds smallest Evil Portal on a LilyGo T-QT |
git clone git://git.acid.vegas/acidportal.git |
Log | Files | Refs | Archive | README | LICENSE |
TFT_eSPI_RP2040.c (25195B)
1 //////////////////////////////////////////////////// 2 // TFT_eSPI generic driver functions // 3 //////////////////////////////////////////////////// 4 5 //////////////////////////////////////////////////////////////////////////////////////// 6 // Global variables 7 //////////////////////////////////////////////////////////////////////////////////////// 8 9 #if !defined (RP2040_PIO_INTERFACE) // SPI 10 11 // Select the SPI port and board package to use 12 #ifdef ARDUINO_ARCH_MBED 13 // Arduino RP2040 board package 14 MbedSPI spi = MbedSPI(TFT_MISO, TFT_MOSI, TFT_SCLK); 15 #else 16 // Community RP2040 board package by Earle Philhower 17 //SPIClass& spi = SPI; // will use board package default pins 18 SPIClassRP2040 spi = SPIClassRP2040(SPI_X, TFT_MISO, -1, TFT_SCLK, TFT_MOSI); 19 #endif 20 21 #else // PIO interface used (8-bit parallel or SPI) 22 23 #ifdef RP2040_PIO_SPI 24 #if defined (SPI_18BIT_DRIVER) 25 // SPI PIO code for 18 bit colour transmit 26 #include "pio_SPI_18bit.pio.h" 27 #else 28 // SPI PIO code for 16-bit colour transmit 29 #include "pio_SPI.pio.h" 30 #endif 31 #elif defined (TFT_PARALLEL_8_BIT) 32 #if defined (SSD1963_DRIVER) 33 // PIO code for 8-bit parallel interface (18 bit colour) 34 #include "pio_8bit_parallel_18bpp.pio.h" 35 #else 36 // PIO code for 8-bit parallel interface (16-bit colour) 37 #include "pio_8bit_parallel.pio.h" 38 #endif 39 #else // must be TFT_PARALLEL_16_BIT 40 // PIO code for 16-bit parallel interface (16-bit colour) 41 #include "pio_16bit_parallel.pio.h" 42 #endif 43 44 // Board package specific differences 45 #ifdef ARDUINO_ARCH_MBED 46 // Not supported at the moment 47 #error The Arduino RP2040 MBED board package is not supported when PIO is used. Use the community package by Earle Philhower. 48 #endif 49 50 // Community RP2040 board package by Earle Philhower 51 PIO tft_pio = pio0; // Code will try both pio's to find a free SM 52 int8_t pio_sm = 0; // pioinit will claim a free one 53 // Updated later with the loading offset of the PIO program. 54 uint32_t program_offset = 0; 55 56 // SM stalled mask 57 uint32_t pull_stall_mask = 0; 58 59 // SM jump instructions to change SM behaviour 60 uint32_t pio_instr_jmp8 = 0; 61 uint32_t pio_instr_fill = 0; 62 uint32_t pio_instr_addr = 0; 63 64 // SM "set" instructions to control DC control signal 65 uint32_t pio_instr_set_dc = 0; 66 uint32_t pio_instr_clr_dc = 0; 67 68 #endif 69 70 #ifdef RP2040_DMA 71 int32_t dma_tx_channel; 72 dma_channel_config dma_tx_config; 73 #endif 74 75 //////////////////////////////////////////////////////////////////////////////////////// 76 #if defined (TFT_SDA_READ) && !defined (RP2040_PIO_INTERFACE) 77 //////////////////////////////////////////////////////////////////////////////////////// 78 79 /*************************************************************************************** 80 ** Function name: tft_Read_8 81 ** Description: Bit bashed SPI to read bidirectional SDA line 82 ***************************************************************************************/ 83 uint8_t TFT_eSPI::tft_Read_8(void) 84 { 85 uint8_t ret = 0; 86 87 /* 88 for (uint8_t i = 0; i < 8; i++) { // read results 89 ret <<= 1; 90 SCLK_L; 91 if (digitalRead(TFT_MOSI)) ret |= 1; 92 SCLK_H; 93 } 94 */ 95 96 ret = spi.transfer(0x00); 97 98 return ret; 99 } 100 101 /*************************************************************************************** 102 ** Function name: beginSDA 103 ** Description: Detach SPI from pin to permit software SPI 104 ***************************************************************************************/ 105 void TFT_eSPI::begin_SDA_Read(void) 106 { 107 // Release configured SPI port for SDA read 108 spi.end(); 109 } 110 111 /*************************************************************************************** 112 ** Function name: endSDA 113 ** Description: Attach SPI pins after software SPI 114 ***************************************************************************************/ 115 void TFT_eSPI::end_SDA_Read(void) 116 { 117 // Configure SPI port ready for next TFT access 118 spi.begin(); 119 } 120 121 //////////////////////////////////////////////////////////////////////////////////////// 122 #endif // #if defined (TFT_SDA_READ) 123 //////////////////////////////////////////////////////////////////////////////////////// 124 125 //////////////////////////////////////////////////////////////////////////////////////// 126 #if defined (RP2040_PIO_INTERFACE) 127 //////////////////////////////////////////////////////////////////////////////////////// 128 #ifdef RP2040_PIO_SPI 129 void pioinit(uint32_t clock_freq) { 130 131 // Find enough free space on one of the PIO's 132 tft_pio = pio0; 133 if (!pio_can_add_program(tft_pio, &tft_io_program)) { 134 tft_pio = pio1; 135 if (!pio_can_add_program(tft_pio, &tft_io_program)) { 136 // Serial.println("No room for PIO program!"); 137 return; 138 } 139 } 140 141 pio_sm = pio_claim_unused_sm(tft_pio, false); 142 143 // Load the PIO program 144 program_offset = pio_add_program(tft_pio, &tft_io_program); 145 146 // Associate pins with the PIO 147 pio_gpio_init(tft_pio, TFT_DC); 148 pio_gpio_init(tft_pio, TFT_SCLK); 149 pio_gpio_init(tft_pio, TFT_MOSI); 150 151 // Configure the pins to be outputs 152 pio_sm_set_consecutive_pindirs(tft_pio, pio_sm, TFT_DC, 1, true); 153 pio_sm_set_consecutive_pindirs(tft_pio, pio_sm, TFT_SCLK, 1, true); 154 pio_sm_set_consecutive_pindirs(tft_pio, pio_sm, TFT_MOSI, 1, true); 155 156 // Configure the state machine 157 pio_sm_config c = tft_io_program_get_default_config(program_offset); 158 159 sm_config_set_set_pins(&c, TFT_DC, 1); 160 // Define the single side-set pin 161 sm_config_set_sideset_pins(&c, TFT_SCLK); 162 // Define the pin used for data output 163 sm_config_set_out_pins(&c, TFT_MOSI, 1); 164 // Set clock divider, frequency is set up to 2% faster than specified, or next division down 165 uint16_t clock_div = 0.98 + clock_get_hz(clk_sys) / (clock_freq * 2.0); // 2 cycles per bit 166 sm_config_set_clkdiv(&c, clock_div); 167 // Make a single 8 words FIFO from the 4 words TX and RX FIFOs 168 sm_config_set_fifo_join(&c, PIO_FIFO_JOIN_TX); 169 // The OSR register shifts to the left, sm designed to send MS byte of a colour first, autopull off 170 sm_config_set_out_shift(&c, false, false, 0); 171 // Now load the configuration 172 pio_sm_init(tft_pio, pio_sm, program_offset + tft_io_offset_start_tx, &c); 173 174 // Start the state machine. 175 pio_sm_set_enabled(tft_pio, pio_sm, true); 176 177 // Create the pull stall bit mask 178 pull_stall_mask = 1u << (PIO_FDEBUG_TXSTALL_LSB + pio_sm); 179 180 // Create the assembler instruction for the jump to byte send routine 181 pio_instr_jmp8 = pio_encode_jmp(program_offset + tft_io_offset_start_8); 182 pio_instr_fill = pio_encode_jmp(program_offset + tft_io_offset_block_fill); 183 pio_instr_addr = pio_encode_jmp(program_offset + tft_io_offset_set_addr_window); 184 185 pio_instr_set_dc = pio_encode_set((pio_src_dest)0, 1); 186 pio_instr_clr_dc = pio_encode_set((pio_src_dest)0, 0); 187 } 188 #else // 8 or 16-bit parallel 189 void pioinit(uint16_t clock_div, uint16_t fract_div) { 190 191 // Find enough free space on one of the PIO's 192 tft_pio = pio0; 193 if (!pio_can_add_program(tft_pio, &tft_io_program)) { 194 tft_pio = pio1; 195 if (!pio_can_add_program(tft_pio, &tft_io_program)) { 196 // Serial.println("No room for PIO program!"); 197 return; 198 } 199 } 200 201 pio_sm = pio_claim_unused_sm(tft_pio, false); 202 203 #if defined (TFT_PARALLEL_8_BIT) 204 uint8_t bits = 8; 205 #else // must be TFT_PARALLEL_16_BIT 206 uint8_t bits = 16; 207 #endif 208 209 // Load the PIO program 210 program_offset = pio_add_program(tft_pio, &tft_io_program); 211 212 // Associate pins with the PIO 213 pio_gpio_init(tft_pio, TFT_DC); 214 pio_gpio_init(tft_pio, TFT_WR); 215 216 for (int i = 0; i < bits; i++) { 217 pio_gpio_init(tft_pio, TFT_D0 + i); 218 } 219 220 // Configure the pins to be outputs 221 pio_sm_set_consecutive_pindirs(tft_pio, pio_sm, TFT_DC, 1, true); 222 pio_sm_set_consecutive_pindirs(tft_pio, pio_sm, TFT_WR, 1, true); 223 pio_sm_set_consecutive_pindirs(tft_pio, pio_sm, TFT_D0, bits, true); 224 225 // Configure the state machine 226 pio_sm_config c = tft_io_program_get_default_config(program_offset); 227 // Define the set pin 228 sm_config_set_set_pins(&c, TFT_DC, 1); 229 // Define the single side-set pin 230 sm_config_set_sideset_pins(&c, TFT_WR); 231 // Define the consecutive pins that are used for data output 232 sm_config_set_out_pins(&c, TFT_D0, bits); 233 // Set clock divider and fractional divider 234 sm_config_set_clkdiv_int_frac(&c, clock_div, fract_div); 235 // Make a single 8 words FIFO from the 4 words TX and RX FIFOs 236 sm_config_set_fifo_join(&c, PIO_FIFO_JOIN_TX); 237 // The OSR register shifts to the left, sm designed to send MS byte of a colour first 238 sm_config_set_out_shift(&c, false, false, 0); 239 // Now load the configuration 240 pio_sm_init(tft_pio, pio_sm, program_offset + tft_io_offset_start_tx, &c); 241 242 // Start the state machine. 243 pio_sm_set_enabled(tft_pio, pio_sm, true); 244 245 // Create the pull stall bit mask 246 pull_stall_mask = 1u << (PIO_FDEBUG_TXSTALL_LSB + pio_sm); 247 248 // Create the instructions for the jumps to send routines 249 pio_instr_jmp8 = pio_encode_jmp(program_offset + tft_io_offset_start_8); 250 pio_instr_fill = pio_encode_jmp(program_offset + tft_io_offset_block_fill); 251 pio_instr_addr = pio_encode_jmp(program_offset + tft_io_offset_set_addr_window); 252 253 // Create the instructions to set and clear the DC signal 254 pio_instr_set_dc = pio_encode_set((pio_src_dest)0, 1); 255 pio_instr_clr_dc = pio_encode_set((pio_src_dest)0, 0); 256 } 257 #endif 258 259 /*************************************************************************************** 260 ** Function name: pushBlock - for generic processor and parallel display 261 ** Description: Write a block of pixels of the same colour 262 ***************************************************************************************/ 263 #ifdef RP2040_PIO_PUSHBLOCK 264 // PIO handles pixel block fill writes 265 void TFT_eSPI::pushBlock(uint16_t color, uint32_t len) 266 { 267 #if defined (SPI_18BIT_DRIVER) || (defined (SSD1963_DRIVER) && defined (TFT_PARALLEL_8_BIT)) 268 uint32_t col = ((color & 0xF800)<<8) | ((color & 0x07E0)<<5) | ((color & 0x001F)<<3); 269 if (len) { 270 WAIT_FOR_STALL; 271 tft_pio->sm[pio_sm].instr = pio_instr_fill; 272 273 TX_FIFO = col; 274 TX_FIFO = --len; // Decrement first as PIO sends n+1 275 } 276 #else 277 if (len) { 278 WAIT_FOR_STALL; 279 tft_pio->sm[pio_sm].instr = pio_instr_fill; 280 281 TX_FIFO = color; 282 TX_FIFO = --len; // Decrement first as PIO sends n+1 283 } 284 #endif 285 } 286 287 #else 288 void TFT_eSPI::pushBlock(uint16_t color, uint32_t len){ 289 290 while (len > 4) { 291 // 5 seems to be the optimum for maximum transfer rate 292 WAIT_FOR_FIFO_FREE(5); 293 TX_FIFO = color; 294 TX_FIFO = color; 295 TX_FIFO = color; 296 TX_FIFO = color; 297 TX_FIFO = color; 298 299 len -= 5; 300 } 301 302 if (len) { 303 // There could be a maximum of 4 words left to send 304 WAIT_FOR_FIFO_FREE(4); 305 while (len--) TX_FIFO = color; 306 } 307 } 308 #endif 309 310 /*************************************************************************************** 311 ** Function name: pushPixels - for generic processor and parallel display 312 ** Description: Write a sequence of pixels 313 ***************************************************************************************/ 314 void TFT_eSPI::pushPixels(const void* data_in, uint32_t len){ 315 #if defined (SPI_18BIT_DRIVER) || (defined (SSD1963_DRIVER) && defined (TFT_PARALLEL_8_BIT)) 316 uint16_t *data = (uint16_t*)data_in; 317 if (_swapBytes) { 318 while ( len-- ) { 319 uint32_t col = *data++; 320 tft_Write_16(col); 321 } 322 } 323 else { 324 while ( len-- ) { 325 uint32_t col = *data++; 326 tft_Write_16S(col); 327 } 328 } 329 #else 330 const uint16_t *data = (uint16_t*)data_in; 331 332 // PIO sends MS byte first, so bytes are already swapped on transmit 333 if(_swapBytes) { 334 while (len > 4) { 335 WAIT_FOR_FIFO_FREE(5); 336 TX_FIFO = data[0]; 337 TX_FIFO = data[1]; 338 TX_FIFO = data[2]; 339 TX_FIFO = data[3]; 340 TX_FIFO = data[4]; 341 data += 5; 342 len -= 5; 343 } 344 345 if (len) { 346 WAIT_FOR_FIFO_FREE(4); 347 while(len--) TX_FIFO = *data++; 348 } 349 } 350 else { 351 while (len > 4) { 352 WAIT_FOR_FIFO_FREE(5); 353 TX_FIFO = data[0] << 8 | data[0] >> 8; 354 TX_FIFO = data[1] << 8 | data[1] >> 8; 355 TX_FIFO = data[2] << 8 | data[2] >> 8; 356 TX_FIFO = data[3] << 8 | data[3] >> 8; 357 TX_FIFO = data[4] << 8 | data[4] >> 8; 358 data += 5; 359 len -= 5; 360 } 361 362 if (len) { 363 WAIT_FOR_FIFO_FREE(4); 364 while(len--) { 365 TX_FIFO = *data << 8 | *data >> 8; 366 data++; 367 } 368 } 369 } 370 #endif 371 } 372 373 /*************************************************************************************** 374 ** Function name: GPIO direction control - supports class functions 375 ** Description: Set parallel bus to INPUT or OUTPUT 376 ***************************************************************************************/ 377 void TFT_eSPI::busDir(uint32_t mask, uint8_t mode) 378 { 379 // Avoid warnings 380 mask = mask; 381 mode = mode; 382 /* 383 // mask is unused for generic processor 384 // Arduino native functions suited well to a generic driver 385 pinMode(TFT_D0, mode); 386 pinMode(TFT_D1, mode); 387 pinMode(TFT_D2, mode); 388 pinMode(TFT_D3, mode); 389 pinMode(TFT_D4, mode); 390 pinMode(TFT_D5, mode); 391 pinMode(TFT_D6, mode); 392 pinMode(TFT_D7, mode); 393 */ 394 } 395 396 /*************************************************************************************** 397 ** Function name: GPIO direction control - supports class functions 398 ** Description: Faster GPIO pin input/output switch 399 ***************************************************************************************/ 400 void TFT_eSPI::gpioMode(uint8_t gpio, uint8_t mode) 401 { 402 // Avoid warnings 403 gpio = gpio; 404 mode = mode; 405 406 } 407 408 /*************************************************************************************** 409 ** Function name: read byte - supports class functions 410 ** Description: Read a byte - parallel bus only - not supported yet 411 ***************************************************************************************/ 412 uint8_t TFT_eSPI::readByte(void) 413 { 414 uint8_t b = 0; 415 /* 416 busDir(0, INPUT); 417 digitalWrite(TFT_RD, LOW); 418 419 b |= digitalRead(TFT_D0) << 0; 420 b |= digitalRead(TFT_D1) << 1; 421 b |= digitalRead(TFT_D2) << 2; 422 b |= digitalRead(TFT_D3) << 3; 423 b |= digitalRead(TFT_D4) << 4; 424 b |= digitalRead(TFT_D5) << 5; 425 b |= digitalRead(TFT_D6) << 6; 426 b |= digitalRead(TFT_D7) << 7; 427 428 digitalWrite(TFT_RD, HIGH); 429 busDir(0, OUTPUT); 430 */ 431 return b; 432 } 433 434 //////////////////////////////////////////////////////////////////////////////////////// 435 #elif defined (RPI_WRITE_STROBE) // For RPi TFT with write strobe 436 //////////////////////////////////////////////////////////////////////////////////////// 437 438 /*************************************************************************************** 439 ** Function name: pushBlock - for ESP32 or RP2040 RPi TFT 440 ** Description: Write a block of pixels of the same colour 441 ***************************************************************************************/ 442 void TFT_eSPI::pushBlock(uint16_t color, uint32_t len){ 443 444 if(len) { tft_Write_16(color); len--; } 445 while(len--) {WR_L; WR_H;} 446 } 447 448 /*************************************************************************************** 449 ** Function name: pushPixels - for ESP32 or RP2040 RPi TFT 450 ** Description: Write a sequence of pixels 451 ***************************************************************************************/ 452 void TFT_eSPI::pushPixels(const void* data_in, uint32_t len) 453 { 454 uint16_t *data = (uint16_t*)data_in; 455 456 if (_swapBytes) while ( len-- ) {tft_Write_16S(*data); data++;} 457 else while ( len-- ) {tft_Write_16(*data); data++;} 458 } 459 460 //////////////////////////////////////////////////////////////////////////////////////// 461 #elif defined (SPI_18BIT_DRIVER) // SPI 18 bit colour 462 //////////////////////////////////////////////////////////////////////////////////////// 463 464 /*************************************************************************************** 465 ** Function name: pushBlock - for RP2040 and 3 byte RGB display 466 ** Description: Write a block of pixels of the same colour 467 ***************************************************************************************/ 468 void TFT_eSPI::pushBlock(uint16_t color, uint32_t len) 469 { 470 uint16_t r = (color & 0xF800)>>8; 471 uint16_t g = (color & 0x07E0)>>3; 472 uint16_t b = (color & 0x001F)<<3; 473 474 // If more than 32 pixels then change to 16-bit transfers with concatenated pixels 475 if (len > 32) { 476 uint32_t rg = r<<8 | g; 477 uint32_t br = b<<8 | r; 478 uint32_t gb = g<<8 | b; 479 // Must wait before changing to 16-bit 480 while (spi_get_hw(SPI_X)->sr & SPI_SSPSR_BSY_BITS) {}; 481 hw_write_masked(&spi_get_hw(SPI_X)->cr0, (16 - 1) << SPI_SSPCR0_DSS_LSB, SPI_SSPCR0_DSS_BITS); 482 while ( len > 1 ) { 483 while (!spi_is_writable(SPI_X)){}; spi_get_hw(SPI_X)->dr = rg; 484 while (!spi_is_writable(SPI_X)){}; spi_get_hw(SPI_X)->dr = br; 485 while (!spi_is_writable(SPI_X)){}; spi_get_hw(SPI_X)->dr = gb; 486 len -= 2; 487 } 488 // Must wait before changing back to 8-bit 489 while (spi_get_hw(SPI_X)->sr & SPI_SSPSR_BSY_BITS) {}; 490 hw_write_masked(&spi_get_hw(SPI_X)->cr0, (8 - 1) << SPI_SSPCR0_DSS_LSB, SPI_SSPCR0_DSS_BITS); 491 } 492 493 // Mop up the remaining pixels 494 while ( len-- ) {tft_Write_8N(r);tft_Write_8N(g);tft_Write_8N(b);} 495 } 496 497 /*************************************************************************************** 498 ** Function name: pushPixels - for RP2040 and 3 byte RGB display 499 ** Description: Write a sequence of pixels 500 ***************************************************************************************/ 501 void TFT_eSPI::pushPixels(const void* data_in, uint32_t len){ 502 503 uint16_t *data = (uint16_t*)data_in; 504 if (_swapBytes) { 505 while ( len-- ) { 506 uint32_t col = *data++; 507 tft_Write_16(col); 508 } 509 } 510 else { 511 while ( len-- ) { 512 uint32_t col = *data++; 513 tft_Write_16S(col); 514 } 515 } 516 } 517 518 //////////////////////////////////////////////////////////////////////////////////////// 519 #else // Standard SPI 16-bit colour TFT 520 //////////////////////////////////////////////////////////////////////////////////////// 521 522 /*************************************************************************************** 523 ** Function name: pushBlock - for RP2040 524 ** Description: Write a block of pixels of the same colour 525 ***************************************************************************************/ 526 void TFT_eSPI::pushBlock(uint16_t color, uint32_t len){ 527 while(len--) 528 { 529 while (!spi_is_writable(SPI_X)){}; 530 spi_get_hw(SPI_X)->dr = (uint32_t)color; 531 } 532 } 533 534 /*************************************************************************************** 535 ** Function name: pushPixels - for RP2040 536 ** Description: Write a sequence of pixels 537 ***************************************************************************************/ 538 void TFT_eSPI::pushPixels(const void* data_in, uint32_t len){ 539 uint16_t *data = (uint16_t*)data_in; 540 if (_swapBytes) { 541 while(len--) 542 { 543 while (!spi_is_writable(SPI_X)){}; 544 spi_get_hw(SPI_X)->dr = (uint32_t)(*data++); 545 } 546 } 547 else 548 { 549 while(len--) 550 { 551 uint16_t color = *data++; 552 color = color >> 8 | color << 8; 553 while (!spi_is_writable(SPI_X)){}; 554 spi_get_hw(SPI_X)->dr = (uint32_t)color; 555 } 556 } 557 } 558 559 //////////////////////////////////////////////////////////////////////////////////////// 560 #endif // End of display interface specific functions 561 //////////////////////////////////////////////////////////////////////////////////////// 562 563 564 //////////////////////////////////////////////////////////////////////////////////////// 565 #ifdef RP2040_DMA // DMA functions for 16-bit SPI and 8/16-bit parallel displays 566 //////////////////////////////////////////////////////////////////////////////////////// 567 /* 568 These are created in header file: 569 uint32_t dma_tx_channel; 570 dma_channel_config dma_tx_config; 571 */ 572 573 /*************************************************************************************** 574 ** Function name: dmaBusy 575 ** Description: Check if DMA is busy 576 ***************************************************************************************/ 577 bool TFT_eSPI::dmaBusy(void) { 578 if (!DMA_Enabled) return false; 579 580 if (dma_channel_is_busy(dma_tx_channel)) return true; 581 582 #if !defined (RP2040_PIO_INTERFACE) 583 // For SPI must also wait for FIFO to flush and reset format 584 while (spi_get_hw(SPI_X)->sr & SPI_SSPSR_BSY_BITS) {}; 585 hw_write_masked(&spi_get_hw(SPI_X)->cr0, (16 - 1) << SPI_SSPCR0_DSS_LSB, SPI_SSPCR0_DSS_BITS); 586 #endif 587 588 return false; 589 } 590 591 /*************************************************************************************** 592 ** Function name: dmaWait 593 ** Description: Wait until DMA is over (blocking!) 594 ***************************************************************************************/ 595 void TFT_eSPI::dmaWait(void) 596 { 597 while (dma_channel_is_busy(dma_tx_channel)); 598 599 #if !defined (RP2040_PIO_INTERFACE) 600 // For SPI must also wait for FIFO to flush and reset format 601 while (spi_get_hw(SPI_X)->sr & SPI_SSPSR_BSY_BITS) {}; 602 hw_write_masked(&spi_get_hw(SPI_X)->cr0, (16 - 1) << SPI_SSPCR0_DSS_LSB, SPI_SSPCR0_DSS_BITS); 603 #endif 604 } 605 606 /*************************************************************************************** 607 ** Function name: pushPixelsDMA 608 ** Description: Push pixels to TFT 609 ***************************************************************************************/ 610 void TFT_eSPI::pushPixelsDMA(uint16_t* image, uint32_t len) 611 { 612 if ((len == 0) || (!DMA_Enabled)) return; 613 614 dmaWait(); 615 616 channel_config_set_bswap(&dma_tx_config, !_swapBytes); 617 618 #if !defined (RP2040_PIO_INTERFACE) 619 dma_channel_configure(dma_tx_channel, &dma_tx_config, &spi_get_hw(SPI_X)->dr, (uint16_t*)image, len, true); 620 #else 621 dma_channel_configure(dma_tx_channel, &dma_tx_config, &tft_pio->txf[pio_sm], (uint16_t*)image, len, true); 622 #endif 623 } 624 625 /*************************************************************************************** 626 ** Function name: pushImageDMA 627 ** Description: Push image to a window 628 ***************************************************************************************/ 629 // This will clip to the viewport 630 void TFT_eSPI::pushImageDMA(int32_t x, int32_t y, int32_t w, int32_t h, uint16_t* image, uint16_t* buffer) 631 { 632 if ((x >= _vpW) || (y >= _vpH) || (!DMA_Enabled)) return; 633 634 int32_t dx = 0; 635 int32_t dy = 0; 636 int32_t dw = w; 637 int32_t dh = h; 638 639 if (x < _vpX) { dx = _vpX - x; dw -= dx; x = _vpX; } 640 if (y < _vpY) { dy = _vpY - y; dh -= dy; y = _vpY; } 641 642 if ((x + dw) > _vpW ) dw = _vpW - x; 643 if ((y + dh) > _vpH ) dh = _vpH - y; 644 645 if (dw < 1 || dh < 1) return; 646 647 uint32_t len = dw*dh; 648 649 if (buffer == nullptr) { 650 buffer = image; 651 dmaWait(); 652 } 653 654 // If image is clipped, copy pixels into a contiguous block 655 if ( (dw != w) || (dh != h) ) { 656 for (int32_t yb = 0; yb < dh; yb++) { 657 memmove((uint8_t*) (buffer + yb * dw), (uint8_t*) (image + dx + w * (yb + dy)), dw << 1); 658 } 659 } 660 // else, if a buffer pointer has been provided copy whole image to the buffer 661 else if (buffer != image || _swapBytes) { 662 memcpy(buffer, image, len*2); 663 } 664 665 dmaWait(); // In case we did not wait earlier 666 667 setAddrWindow(x, y, dw, dh); 668 669 channel_config_set_bswap(&dma_tx_config, !_swapBytes); 670 671 #if !defined (RP2040_PIO_INTERFACE) 672 dma_channel_configure(dma_tx_channel, &dma_tx_config, &spi_get_hw(SPI_X)->dr, (uint16_t*)buffer, len, true); 673 #else 674 dma_channel_configure(dma_tx_channel, &dma_tx_config, &tft_pio->txf[pio_sm], (uint16_t*)buffer, len, true); 675 #endif 676 } 677 678 /*************************************************************************************** 679 ** Function name: initDMA 680 ** Description: Initialise the DMA engine - returns true if init OK 681 ***************************************************************************************/ 682 bool TFT_eSPI::initDMA(bool ctrl_cs) 683 { 684 if (DMA_Enabled) return false; 685 686 ctrl_cs = ctrl_cs; // stop unused parameter warning 687 688 dma_tx_channel = dma_claim_unused_channel(false); 689 690 if (dma_tx_channel < 0) return false; 691 692 dma_tx_config = dma_channel_get_default_config(dma_tx_channel); 693 694 channel_config_set_transfer_data_size(&dma_tx_config, DMA_SIZE_16); 695 #if !defined (RP2040_PIO_INTERFACE) 696 channel_config_set_dreq(&dma_tx_config, spi_get_index(SPI_X) ? DREQ_SPI1_TX : DREQ_SPI0_TX); 697 #else 698 channel_config_set_dreq(&dma_tx_config, pio_get_dreq(tft_pio, pio_sm, true)); 699 #endif 700 701 DMA_Enabled = true; 702 return true; 703 } 704 705 /*************************************************************************************** 706 ** Function name: deInitDMA 707 ** Description: Disconnect the DMA engine from SPI 708 ***************************************************************************************/ 709 void TFT_eSPI::deInitDMA(void) 710 { 711 if (!DMA_Enabled) return; 712 dma_channel_unclaim(dma_tx_channel); 713 DMA_Enabled = false; 714 } 715 716 //////////////////////////////////////////////////////////////////////////////////////// 717 #endif // End of DMA FUNCTIONS 718 ////////////////////////////////////////////////////////////////////////////////////////