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 |
TFT_eSPI_STM32.c (28199B)
1 //////////////////////////////////////////////////// 2 // TFT_eSPI Driver functions for STM32 processors // 3 //////////////////////////////////////////////////// 4 5 //////////////////////////////////////////////////////////////////////////////////////// 6 // Global variables 7 //////////////////////////////////////////////////////////////////////////////////////// 8 9 #if defined (TFT_PARALLEL_8_BIT) 10 // No globals 11 #else 12 // Use STM32 default SPI port 13 #if !defined (TFT_MOSI) || !defined (TFT_MISO) || !defined (TFT_SCLK) 14 SPIClass& spi = SPI; 15 #else 16 SPIClass spi(TFT_MOSI, TFT_MISO, TFT_SCLK); 17 #endif 18 // SPI HAL peripheral handle 19 SPI_HandleTypeDef spiHal; 20 #endif 21 22 #ifdef STM32_DMA 23 // DMA HAL handle 24 DMA_HandleTypeDef dmaHal; 25 #endif 26 27 // Buffer for SPI transmit byte padding and byte order manipulation 28 uint8_t spiBuffer[8]; 29 30 //////////////////////////////////////////////////////////////////////////////////////// 31 #if defined (TFT_SDA_READ) && !defined (TFT_PARALLEL_8_BIT) 32 //////////////////////////////////////////////////////////////////////////////////////// 33 34 /***************************************************************************************############# UNTESTED ################### 35 ** Function name: tft_Read_8 36 ** Description: STM32 software SPI to read bidirectional SDA line 37 ***************************************************************************************/ 38 uint8_t TFT_eSPI::tft_Read_8(void) 39 { 40 uint8_t ret = 0; 41 uint32_t reg = 0; 42 43 for (uint8_t i = 0; i < 8; i++) { // read results 44 ret <<= 1; 45 SCLK_L; 46 if (digitalRead(TFT_MOSI)) ret |= 1; 47 SCLK_H; 48 } 49 50 return ret; 51 } 52 53 /***************************************************************************************############# UNTESTED ################### 54 ** Function name: beginSDA 55 ** Description: Detach SPI from pin to permit software SPI 56 ***************************************************************************************/ 57 void TFT_eSPI::begin_SDA_Read(void) 58 { 59 // Release configured SPI port for SDA read 60 spi.end();// Code missing here! <<<<<<<<<<<<<<Missing code<<<<<<<<<<<<<<<<< 61 } 62 63 /***************************************************************************************############# UNTESTED ################### 64 ** Function name: endSDA 65 ** Description: Attach SPI pins after software SPI 66 ***************************************************************************************/ 67 void TFT_eSPI::end_SDA_Read(void) 68 { 69 // Configure SPI port ready for next TFT access 70 spi.begin();// Code missing here! <<<<<<<<<<<<<<Missing code<<<<<<<<<<<<<<<<< 71 } 72 73 //////////////////////////////////////////////////////////////////////////////////////// 74 #endif // #if defined (TFT_SDA_READ) 75 //////////////////////////////////////////////////////////////////////////////////////// 76 77 78 //////////////////////////////////////////////////////////////////////////////////////// 79 #if defined (TFT_PARALLEL_8_BIT) // Code for STM32 8 bit parallel 80 //////////////////////////////////////////////////////////////////////////////////////// 81 82 /*************************************************************************************** 83 ** Function name: pushBlock - for ESP32 and parallel display 84 ** Description: Write a block of pixels of the same colour 85 ***************************************************************************************/ 86 void TFT_eSPI::pushBlock(uint16_t color, uint32_t len){ 87 // Loop unrolling improves speed dramatically graphics test 0.634s => 0.374s 88 while (len>31) { 89 #if !defined (SSD1963_DRIVER) 90 // 32D macro writes 16 bits twice 91 tft_Write_32D(color); tft_Write_32D(color); 92 tft_Write_32D(color); tft_Write_32D(color); 93 tft_Write_32D(color); tft_Write_32D(color); 94 tft_Write_32D(color); tft_Write_32D(color); 95 tft_Write_32D(color); tft_Write_32D(color); 96 tft_Write_32D(color); tft_Write_32D(color); 97 tft_Write_32D(color); tft_Write_32D(color); 98 tft_Write_32D(color); tft_Write_32D(color); 99 #else 100 tft_Write_16(color); tft_Write_16(color); tft_Write_16(color); tft_Write_16(color); 101 tft_Write_16(color); tft_Write_16(color); tft_Write_16(color); tft_Write_16(color); 102 tft_Write_16(color); tft_Write_16(color); tft_Write_16(color); tft_Write_16(color); 103 tft_Write_16(color); tft_Write_16(color); tft_Write_16(color); tft_Write_16(color); 104 tft_Write_16(color); tft_Write_16(color); tft_Write_16(color); tft_Write_16(color); 105 tft_Write_16(color); tft_Write_16(color); tft_Write_16(color); tft_Write_16(color); 106 tft_Write_16(color); tft_Write_16(color); tft_Write_16(color); tft_Write_16(color); 107 tft_Write_16(color); tft_Write_16(color); tft_Write_16(color); tft_Write_16(color); 108 #endif 109 len-=32; 110 } 111 112 while (len>7) { 113 #if !defined (SSD1963_DRIVER) 114 tft_Write_32D(color); tft_Write_32D(color); 115 tft_Write_32D(color); tft_Write_32D(color); 116 #else 117 tft_Write_16(color); tft_Write_16(color); tft_Write_16(color); tft_Write_16(color); 118 tft_Write_16(color); tft_Write_16(color); tft_Write_16(color); tft_Write_16(color); 119 #endif 120 len-=8; 121 } 122 123 while (len--) {tft_Write_16(color);} 124 } 125 126 127 /*************************************************************************************** 128 ** Function name: pushPixels - for ESP32 and parallel display 129 ** Description: Write a sequence of pixels 130 ***************************************************************************************/ 131 void TFT_eSPI::pushPixels(const void* data_in, uint32_t len){ 132 133 uint16_t *data = (uint16_t*)data_in; 134 135 if(_swapBytes) { 136 while (len>1) {tft_Write_16(*data); data++; tft_Write_16(*data); data++; len -=2;} 137 if (len) {tft_Write_16(*data);} 138 return; 139 } 140 141 while (len>1) {tft_Write_16S(*data); data++; tft_Write_16S(*data); data++; len -=2;} 142 if (len) {tft_Write_16S(*data);} 143 } 144 145 146 /*************************************************************************************** 147 ** Function name: GPIO direction control - supports class functions 148 ** Description: Set parallel bus to INPUT or OUTPUT 149 ***************************************************************************************/ 150 void TFT_eSPI::busDir(uint32_t mask, uint8_t mode) 151 { 152 #if defined (STM_PORTA_DATA_BUS) 153 #if defined (STM32F1xx) 154 if (mode == OUTPUT) GPIOA->CRL = 0x33333333; 155 else GPIOA->CRL = 0x88888888; 156 #else 157 if (mode == OUTPUT) GPIOA->MODER = (GPIOA->MODER & 0xFFFF0000) | 0x00005555; 158 else GPIOA->MODER &= 0xFFFF0000; 159 #endif 160 #elif defined (STM_PORTB_DATA_BUS) 161 #if defined (STM32F1xx) 162 if (mode == OUTPUT) GPIOB->CRL = 0x33333333; 163 else GPIOB->CRL = 0x88888888; 164 #else 165 if (mode == OUTPUT) GPIOB->MODER = (GPIOB->MODER & 0xFFFF0000) | 0x00005555; 166 else GPIOB->MODER &= 0xFFFF0000; 167 #endif 168 #elif defined (STM_PORTC_DATA_BUS) 169 #if defined (STM32F1xx) 170 if (mode == OUTPUT) GPIOC->CRL = 0x33333333; 171 else GPIOC->CRL = 0x88888888; 172 #else 173 if (mode == OUTPUT) GPIOC->MODER = (GPIOC->MODER & 0xFFFF0000) | 0x00005555; 174 else GPIOC->MODER &= 0xFFFF0000; 175 #endif 176 #elif defined (STM_PORTD_DATA_BUS) 177 #if defined (STM32F1xx) 178 if (mode == OUTPUT) GPIOD->CRL = 0x33333333; 179 else GPIOD->CRL = 0x88888888; 180 #else 181 if (mode == OUTPUT) GPIOD->MODER = (GPIOD->MODER & 0xFFFF0000) | 0x00005555; 182 else GPIOD->MODER &= 0xFFFF0000; 183 #endif 184 #else 185 if (mode == OUTPUT) { 186 LL_GPIO_SetPinMode(D0_PIN_PORT, D0_PIN_MASK, LL_GPIO_MODE_OUTPUT); 187 LL_GPIO_SetPinMode(D1_PIN_PORT, D1_PIN_MASK, LL_GPIO_MODE_OUTPUT); 188 LL_GPIO_SetPinMode(D2_PIN_PORT, D2_PIN_MASK, LL_GPIO_MODE_OUTPUT); 189 LL_GPIO_SetPinMode(D3_PIN_PORT, D3_PIN_MASK, LL_GPIO_MODE_OUTPUT); 190 LL_GPIO_SetPinMode(D4_PIN_PORT, D4_PIN_MASK, LL_GPIO_MODE_OUTPUT); 191 LL_GPIO_SetPinMode(D5_PIN_PORT, D5_PIN_MASK, LL_GPIO_MODE_OUTPUT); 192 LL_GPIO_SetPinMode(D6_PIN_PORT, D6_PIN_MASK, LL_GPIO_MODE_OUTPUT); 193 LL_GPIO_SetPinMode(D7_PIN_PORT, D7_PIN_MASK, LL_GPIO_MODE_OUTPUT); 194 } 195 else { 196 LL_GPIO_SetPinMode(D0_PIN_PORT, D0_PIN_MASK, LL_GPIO_MODE_INPUT); 197 LL_GPIO_SetPinMode(D1_PIN_PORT, D1_PIN_MASK, LL_GPIO_MODE_INPUT); 198 LL_GPIO_SetPinMode(D2_PIN_PORT, D2_PIN_MASK, LL_GPIO_MODE_INPUT); 199 LL_GPIO_SetPinMode(D3_PIN_PORT, D3_PIN_MASK, LL_GPIO_MODE_INPUT); 200 LL_GPIO_SetPinMode(D4_PIN_PORT, D4_PIN_MASK, LL_GPIO_MODE_INPUT); 201 LL_GPIO_SetPinMode(D5_PIN_PORT, D5_PIN_MASK, LL_GPIO_MODE_INPUT); 202 LL_GPIO_SetPinMode(D6_PIN_PORT, D6_PIN_MASK, LL_GPIO_MODE_INPUT); 203 LL_GPIO_SetPinMode(D7_PIN_PORT, D7_PIN_MASK, LL_GPIO_MODE_INPUT); 204 } 205 #endif 206 } 207 208 209 /*************************************************************************************** 210 ** Function name: GPIO direction control - supports class functions 211 ** Description: Set STM32 GPIO pin to input or output (set high) ASAP 212 ***************************************************************************************/ 213 void TFT_eSPI::gpioMode(uint8_t gpio, uint8_t mode) 214 { 215 PinName pn = digitalPinToPinName(gpio); 216 // Push-pull output with no pullup 217 if (mode == OUTPUT) pin_function(pn, STM_PIN_DATA(STM_MODE_OUTPUT_PP, GPIO_NOPULL, 0)); 218 // Input with pullup 219 else pin_function(pn, STM_PIN_DATA(STM_MODE_INPUT, GPIO_PULLUP, 0)); 220 } 221 222 /***************************************************************************************############# UNTESTED ################### 223 ** Function name: read byte - supports class functions 224 ** Description: Read a byte - parallel bus only 225 ***************************************************************************************/ 226 uint8_t TFT_eSPI::readByte(void) 227 { 228 uint8_t b = 0; 229 230 RD_L; 231 #if defined (STM_PORTA_DATA_BUS) 232 b = GPIOA->IDR; 233 b = GPIOA->IDR; 234 b = GPIOA->IDR; 235 b = (GPIOA->IDR) & 0xFF; 236 #elif defined (STM_PORTB_DATA_BUS) 237 b = GPIOB->IDR; 238 b = GPIOB->IDR; 239 b = GPIOB->IDR; 240 b = (GPIOB->IDR) & 0xFF; 241 #elif defined (STM_PORTC_DATA_BUS) 242 b = GPIOC->IDR; 243 b = GPIOC->IDR; 244 b = GPIOC->IDR; 245 b = (GPIOC->IDR) & 0xFF; 246 #elif defined (STM_PORTD_DATA_BUS) 247 b = GPIOD->IDR; 248 b = GPIOD->IDR; 249 b = GPIOD->IDR; 250 b = (GPIOD->IDR) & 0xFF; 251 #else 252 b = RD_TFT_D0 | RD_TFT_D0 | RD_TFT_D0 | RD_TFT_D0; //Delay for bits to settle 253 254 b = RD_TFT_D0 | RD_TFT_D1 | RD_TFT_D2 | RD_TFT_D3; 255 b |= RD_TFT_D4 | RD_TFT_D5 | RD_TFT_D6 | RD_TFT_D7; 256 #endif 257 RD_H; 258 259 return b; 260 } 261 262 //////////////////////////////////////////////////////////////////////////////////////// 263 #elif defined (RPI_WRITE_STROBE) // For RPi TFT with write strobe ############# UNTESTED ################### 264 //////////////////////////////////////////////////////////////////////////////////////// 265 266 /*************************************************************************************** 267 ** Function name: pushBlock - for ESP32 or STM32 RPi TFT 268 ** Description: Write a block of pixels of the same colour 269 ***************************************************************************************/ 270 void TFT_eSPI::pushBlock(uint16_t color, uint32_t len) 271 { 272 if(len) { tft_Write_16(color); len--; } 273 while(len--) {WR_L; WR_H;} 274 } 275 276 /*************************************************************************************** 277 ** Function name: pushPixels - for ESP32 or STM32 RPi TFT 278 ** Description: Write a sequence of pixels 279 ***************************************************************************************/ 280 void TFT_eSPI::pushPixels(const void* data_in, uint32_t len) 281 { 282 uint16_t *data = (uint16_t*)data_in; 283 284 if (_swapBytes) while ( len-- ) { tft_Write_16S(*data); data++;} 285 else while ( len-- ) {tft_Write_16(*data); data++;} 286 } 287 288 //////////////////////////////////////////////////////////////////////////////////////// 289 #elif defined (SPI_18BIT_DRIVER) // SPI 18 bit colour 290 //////////////////////////////////////////////////////////////////////////////////////// 291 292 /*************************************************************************************** 293 ** Function name: pushBlock - for STM32 and 3 byte RGB display 294 ** Description: Write a block of pixels of the same colour 295 ***************************************************************************************/ 296 #define BUF_SIZE 240*3 297 void TFT_eSPI::pushBlock(uint16_t color, uint32_t len) 298 { 299 uint8_t col[BUF_SIZE]; 300 // Always using swapped bytes is a peculiarity of this function... 301 //color = color>>8 | color<<8; 302 uint8_t r = (color & 0xF800)>>8; // Red 303 uint8_t g = (color & 0x07E0)>>3; // Green 304 uint8_t b = (color & 0x001F)<<3; // Blue 305 306 if (len<BUF_SIZE/3) { 307 for (uint32_t i = 0; i < len*3; i++) { 308 col[i] = r; 309 col[++i] = g; 310 col[++i] = b; 311 } 312 HAL_SPI_Transmit(&spiHal, col, len*3, HAL_MAX_DELAY); 313 return; 314 } 315 316 for (uint32_t i = 0; i < BUF_SIZE; i++) { 317 col[i] = r; 318 col[++i] = g; 319 col[++i] = b; 320 } 321 do { 322 HAL_SPI_Transmit(&spiHal, col, BUF_SIZE, HAL_MAX_DELAY); 323 len -= BUF_SIZE/3; 324 } while ( len>=BUF_SIZE/3 ) ; 325 // Send remaining pixels 326 if (len) HAL_SPI_Transmit(&spiHal, col, len*3, HAL_MAX_DELAY); //*/ 327 } 328 /*************************************************************************************** 329 ** Function name: pushPixels - for STM32 and 3 byte RGB display 330 ** Description: Write a sequence of pixels 331 ***************************************************************************************/ 332 void TFT_eSPI::pushPixels(const void* data_in, uint32_t len) 333 { 334 uint16_t *data = (uint16_t*)data_in; 335 336 if(_swapBytes) { 337 while ( len-- ) { 338 // Split out the colours 339 spiBuffer[0] = (*data & 0xF8); // Red 340 spiBuffer[1] = (*data & 0xE000)>>11 | (*data & 0x07)<<5; // Green 341 spiBuffer[2] = (*data & 0x1F00)>>5; // Blue 342 data++; 343 HAL_SPI_Transmit(&spiHal, spiBuffer, 3, HAL_MAX_DELAY); 344 } 345 } 346 else { 347 while ( len-- ) { 348 // Split out the colours 349 spiBuffer[0] = (*data & 0xF800)>>8; // Red 350 spiBuffer[1] = (*data & 0x07E0)>>3; // Green 351 spiBuffer[2] = (*data & 0x001F)<<3; // Blue 352 data++; 353 HAL_SPI_Transmit(&spiHal, spiBuffer, 3, HAL_MAX_DELAY); 354 } 355 } 356 } 357 358 //////////////////////////////////////////////////////////////////////////////////////// 359 #else // Standard SPI 16 bit colour TFT All Tested 360 //////////////////////////////////////////////////////////////////////////////////////// 361 362 /*************************************************************************************** 363 ** Function name: pushBlock - for STM32 364 ** Description: Write a block of pixels of the same colour 365 ***************************************************************************************/ 366 #define BUF_SIZE 480 367 void TFT_eSPI::pushBlock(uint16_t color, uint32_t len) 368 { 369 uint16_t col[BUF_SIZE]; 370 // Always using swapped bytes is a peculiarity of this function... 371 uint16_t swapColor = color>>8 | color<<8; 372 if (len<BUF_SIZE) { 373 for (uint32_t i = 0; i < len; i++) col[i] = swapColor; 374 HAL_SPI_Transmit(&spiHal, (uint8_t*)col, len<<1, HAL_MAX_DELAY); 375 return; 376 } 377 378 for (uint32_t i = 0; i < BUF_SIZE; i++) col[i] = swapColor; 379 do { 380 HAL_SPI_Transmit(&spiHal, (uint8_t*)col, BUF_SIZE<<1, HAL_MAX_DELAY); 381 len -= BUF_SIZE; 382 } while ( len>=BUF_SIZE ) ; 383 // Send remaining pixels 384 if (len) HAL_SPI_Transmit(&spiHal, (uint8_t*)col, len<<1, HAL_MAX_DELAY); //*/ 385 } 386 387 388 /*************************************************************************************** 389 ** Function name: pushPixels - for STM32 390 ** Description: Write a sequence of pixels 391 ***************************************************************************************/ 392 void TFT_eSPI::pushPixels(const void* data_in, uint32_t len) 393 { 394 uint16_t *data = (uint16_t*)data_in; 395 if(_swapBytes) { 396 uint16_t col[BUF_SIZE]; // Buffer for swapped bytes 397 while ( len>=BUF_SIZE ) { 398 for (uint32_t i = 0; i < BUF_SIZE; i++) { col[i] = (*data>>8) | (*data<<8); data++; } 399 HAL_SPI_Transmit(&spiHal, (uint8_t*)col, BUF_SIZE<<1, HAL_MAX_DELAY); 400 len -= BUF_SIZE; 401 } 402 for (uint32_t i = 0; i < len; i++) { col[i] = (*data>>8) | (*data<<8); data++; } 403 HAL_SPI_Transmit(&spiHal, (uint8_t*)col, len<<1, HAL_MAX_DELAY); 404 } 405 else { 406 // HAL byte count for transmit is only 16 bits maximum so to avoid this constraint 407 // transfers of small blocks are performed until HAL capacity is reached. 408 while(len>0x7FFF) { // Transfer 16 bit pixels in blocks if len*2 over 65534 bytes 409 HAL_SPI_Transmit(&spiHal, (uint8_t*)data, 0x800<<1, HAL_MAX_DELAY); 410 len -= 0x800; data+= 0x800; // Arbitrarily use 2KByte blocks 411 } 412 // Send remaining pixels (max 65534 bytes) 413 HAL_SPI_Transmit(&spiHal, (uint8_t*)data, len<<1, HAL_MAX_DELAY); 414 } 415 } 416 417 //////////////////////////////////////////////////////////////////////////////////////// 418 #endif // End of display interface specific functions 419 //////////////////////////////////////////////////////////////////////////////////////// 420 421 422 //////////////////////////////////////////////////////////////////////////////////////// 423 #if defined STM32_DMA && !defined (TFT_PARALLEL_8_BIT) // DMA FUNCTIONS 424 //////////////////////////////////////////////////////////////////////////////////////// 425 426 /*************************************************************************************** 427 ** Function name: dmaBusy 428 ** Description: Check if DMA is busy (usefully non-blocking!) 429 ***************************************************************************************/ 430 // Use while( tft.dmaBusy() ) {Do-something-useful;}" 431 bool TFT_eSPI::dmaBusy(void) 432 { 433 //return (dmaHal.State == HAL_DMA_STATE_BUSY); // Do not use, SPI may still be busy 434 return (spiHal.State == HAL_SPI_STATE_BUSY_TX); // Check if SPI Tx is busy 435 } 436 437 438 /*************************************************************************************** 439 ** Function name: dmaWait 440 ** Description: Wait until DMA is over (blocking!) 441 ***************************************************************************************/ 442 void TFT_eSPI::dmaWait(void) 443 { 444 //return (dmaHal.State == HAL_DMA_STATE_BUSY); // Do not use, SPI may still be busy 445 while (spiHal.State == HAL_SPI_STATE_BUSY_TX); // Check if SPI Tx is busy 446 } 447 448 449 /*************************************************************************************** 450 ** Function name: pushPixelsDMA 451 ** Description: Push pixels to TFT (len must be less than 32767) 452 ***************************************************************************************/ 453 // This will byte swap the original image if setSwapBytes(true) was called by sketch. 454 void TFT_eSPI::pushPixelsDMA(uint16_t* image, uint32_t len) 455 { 456 if (len == 0) return; 457 458 // Wait for any current DMA transaction to end 459 while (spiHal.State == HAL_SPI_STATE_BUSY_TX); // Check if SPI Tx is busy 460 461 if(_swapBytes) { 462 for (uint32_t i = 0; i < len; i++) (image[i] = image[i] << 8 | image[i] >> 8); 463 } 464 465 HAL_SPI_Transmit_DMA(&spiHal, (uint8_t*)image, len << 1); 466 } 467 468 469 /*************************************************************************************** 470 ** Function name: pushImageDMA 471 ** Description: Push image to a window (w*h must be less than 65536) 472 ***************************************************************************************/ 473 // This will clip and also swap bytes if setSwapBytes(true) was called by sketch 474 void TFT_eSPI::pushImageDMA(int32_t x, int32_t y, int32_t w, int32_t h, uint16_t* image, uint16_t* buffer) 475 { 476 if ((x >= _vpW) || (y >= _vpH)) return; 477 478 int32_t dx = 0; 479 int32_t dy = 0; 480 int32_t dw = w; 481 int32_t dh = h; 482 483 if (x < _vpX) { dx = _vpX - x; dw -= dx; x = _vpX; } 484 if (y < _vpY) { dy = _vpY - y; dh -= dy; y = _vpY; } 485 486 if ((x + dw) > _vpW ) dw = _vpW - x; 487 if ((y + dh) > _vpH ) dh = _vpH - y; 488 489 if (dw < 1 || dh < 1) return; 490 491 uint32_t len = dw*dh; 492 493 if (buffer == nullptr) { 494 buffer = image; 495 while (spiHal.State == HAL_SPI_STATE_BUSY_TX); // Check if SPI Tx is busy 496 } 497 498 // If image is clipped, copy pixels into a contiguous block 499 if ( (dw != w) || (dh != h) ) { 500 if(_swapBytes) { 501 for (int32_t yb = 0; yb < dh; yb++) { 502 for (int32_t xb = 0; xb < dw; xb++) { 503 uint32_t src = xb + dx + w * (yb + dy); 504 (buffer[xb + yb * dw] = image[src] << 8 | image[src] >> 8); 505 } 506 } 507 } 508 else { 509 for (int32_t yb = 0; yb < dh; yb++) { 510 memcpy((uint8_t*) (buffer + yb * dw), (uint8_t*) (image + dx + w * (yb + dy)), dw << 1); 511 } 512 } 513 } 514 // else, if a buffer pointer has been provided copy whole image to the buffer 515 else if (buffer != image || _swapBytes) { 516 if(_swapBytes) { 517 for (uint32_t i = 0; i < len; i++) (buffer[i] = image[i] << 8 | image[i] >> 8); 518 } 519 else { 520 memcpy(buffer, image, len*2); 521 } 522 } 523 524 setWindow(x, y, x + dw - 1, y + dh - 1); 525 526 // DMA byte count for transmit is only 16 bits maximum, so to avoid this constraint 527 // small transfers are performed using a blocking call until DMA capacity is reached. 528 // User sketch can prevent blocking by managing pixel count and splitting into blocks 529 // of 32767 pixels maximum. (equivalent to an area of ~320 x 100 pixels) 530 while(len>0x7FFF) { // Transfer 16 bit pixels in blocks if len*2 over 65534 bytes 531 HAL_SPI_Transmit(&spiHal, (uint8_t*)buffer, 0x800<<1, HAL_MAX_DELAY); 532 len -= 0x800; buffer+= 0x800; // Arbitrarily send 1K pixel blocks (2Kbytes) 533 } 534 // Send remaining pixels using DMA (max 65534 bytes) 535 HAL_SPI_Transmit_DMA(&spiHal, (uint8_t*)buffer, len << 1); 536 } 537 538 //////////////////////////////////////////////////////////////////////////////////////// 539 // Processor specific DMA initialisation 540 //////////////////////////////////////////////////////////////////////////////////////// 541 542 // The DMA functions here work with SPI only (not parallel) 543 #if defined (STM32F2xx) || defined (STM32F4xx) || defined (STM32F7xx) 544 /*************************************************************************************** 545 ** Function name: DMAX_StreamX_IRQHandler 546 ** Description: Override the default HAL stream X interrupt handler 547 ***************************************************************************************/ 548 #if (TFT_SPI_PORT == 1) 549 extern "C" void DMA2_Stream3_IRQHandler(); 550 void DMA2_Stream3_IRQHandler(void) 551 #elif (TFT_SPI_PORT == 2) 552 extern "C" void DMA1_Stream4_IRQHandler(); 553 void DMA1_Stream4_IRQHandler(void) 554 #elif (TFT_SPI_PORT == 3) 555 extern "C" void DMA1_Stream5_IRQHandler(); 556 void DMA1_Stream5_IRQHandler(void) 557 #endif 558 { 559 // Call the default end of buffer handler 560 HAL_DMA_IRQHandler(&dmaHal); 561 } 562 563 /*************************************************************************************** 564 ** Function name: initDMA 565 ** Description: Initialise the DMA engine - returns true if init OK 566 ***************************************************************************************/ 567 // This initialisation is for STM32F2xx/4xx/7xx processors and may not work on others 568 // Dual core H7xx series not supported yet, they are different and have a DMA MUX: 569 // https://electronics.stackexchange.com/questions/379813/configuring-the-dma-request-multiplexer-on-a-stm32h7-mcu 570 bool TFT_eSPI::initDMA(bool ctrl_cs) 571 { 572 ctrl_cs = ctrl_cs; // Not used for STM32, so stop compiler warning 573 574 #if (TFT_SPI_PORT == 1) 575 __HAL_RCC_DMA2_CLK_ENABLE(); // Enable DMA2 clock 576 dmaHal.Init.Channel = DMA_CHANNEL_3; // DMA channel 3 is for SPI1 TX 577 #elif (TFT_SPI_PORT == 2) 578 __HAL_RCC_DMA1_CLK_ENABLE(); // Enable DMA1 clock 579 dmaHal.Init.Channel = DMA_CHANNEL_0; // DMA channel 0 is for SPI2 TX 580 #elif (TFT_SPI_PORT == 3) 581 __HAL_RCC_DMA1_CLK_ENABLE(); // Enable DMA1 clock 582 dmaHal.Init.Channel = DMA_CHANNEL_0; // DMA channel 0 is for SPI3 TX 583 584 #endif 585 586 dmaHal.Init.Mode = DMA_NORMAL; //DMA_CIRCULAR; // // Normal = send buffer once 587 dmaHal.Init.Direction = DMA_MEMORY_TO_PERIPH; // Copy memory to the peripheral 588 dmaHal.Init.PeriphInc = DMA_PINC_DISABLE; // Don't increment peripheral address 589 dmaHal.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE; // Peripheral is byte aligned 590 dmaHal.Init.MemInc = DMA_MINC_ENABLE; // Increment memory address 591 dmaHal.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE; // Memory is byte aligned 592 593 if (HAL_DMA_Init(&dmaHal) != HAL_OK){ // Init DMA with settings 594 // Insert error message here? 595 return DMA_Enabled = false; 596 }; 597 #if (TFT_SPI_PORT == 1) 598 HAL_NVIC_EnableIRQ(DMA2_Stream3_IRQn); // Enable DMA end interrupt handler 599 #elif (TFT_SPI_PORT == 2) 600 HAL_NVIC_EnableIRQ(DMA1_Stream4_IRQn); // Enable DMA end interrupt handler 601 #elif (TFT_SPI_PORT == 3) 602 HAL_NVIC_EnableIRQ(DMA1_Stream5_IRQn); 603 #endif 604 605 __HAL_LINKDMA(&spiHal, hdmatx, dmaHal); // Attach DMA engine to SPI peripheral 606 607 return DMA_Enabled = true; 608 } 609 610 #elif defined (STM32F1xx) // Supports "Blue Pill" boards 611 /*************************************************************************************** 612 ** Function name: DMA1_ChannelX_IRQHandler 613 ** Description: Override the default HAL stream 3 interrupt handler 614 ***************************************************************************************/ 615 #if (TFT_SPI_PORT == 1) 616 extern "C" void DMA1_Channel3_IRQHandler(); 617 void DMA1_Channel3_IRQHandler(void) 618 #elif (TFT_SPI_PORT == 2) 619 extern "C" void DMA1_Channel5_IRQHandler(); 620 void DMA1_Channel5_IRQHandler(void) 621 #endif 622 { 623 // Call the default end of buffer handler 624 HAL_DMA_IRQHandler(&dmaHal); 625 } 626 627 //*/ 628 /*************************************************************************************** 629 ** Function name: initDMA 630 ** Description: Initialise the DMA engine - returns true if init OK 631 ***************************************************************************************/ 632 bool TFT_eSPI::initDMA(bool ctrl_cs) 633 { 634 ctrl_cs = ctrl_cs; // Not used for STM32, so stop compiler warning 635 636 __HAL_RCC_DMA1_CLK_ENABLE(); // Enable DMA1 clock 637 638 dmaHal.Init.Mode = DMA_NORMAL; //DMA_CIRCULAR; // // Normal = send buffer once 639 dmaHal.Init.Direction = DMA_MEMORY_TO_PERIPH; // Copy memory to the peripheral 640 dmaHal.Init.PeriphInc = DMA_PINC_DISABLE; // Don't increment peripheral address 641 dmaHal.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE; // Peripheral is byte aligned 642 dmaHal.Init.MemInc = DMA_MINC_ENABLE; // Increment memory address 643 dmaHal.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE; // Memory is byte aligned 644 dmaHal.Init.Priority = DMA_PRIORITY_LOW; // Added this line - needed ? 645 646 __HAL_LINKDMA(&spiHal, hdmatx, dmaHal); // Attach DMA engine to SPI peripheral 647 648 if (HAL_DMA_Init(&dmaHal) != HAL_OK){ // Init DMA with settings 649 // Insert error message here? 650 return DMA_Enabled = false; 651 }; 652 653 #if (TFT_SPI_PORT == 1) 654 HAL_NVIC_SetPriority(DMA1_Channel3_IRQn, 1, 0); 655 HAL_NVIC_EnableIRQ(DMA1_Channel3_IRQn); // Enable DMA end interrupt handler 656 #elif (TFT_SPI_PORT == 2) 657 HAL_NVIC_SetPriority(DMA1_Channel5_IRQn, 1, 0); 658 HAL_NVIC_EnableIRQ(DMA1_Channel5_IRQn); // Enable DMA end interrupt handler 659 #endif 660 661 return DMA_Enabled = true; 662 } 663 #endif // End of STM32F1/2/4/7xx 664 665 /*************************************************************************************** 666 ** Function name: deInitDMA 667 ** Description: Disconnect the DMA engine from SPI 668 ***************************************************************************************/ 669 void TFT_eSPI::deInitDMA(void) 670 { 671 HAL_DMA_DeInit(&dmaHal); 672 DMA_Enabled = false; 673 } 674 675 //////////////////////////////////////////////////////////////////////////////////////// 676 #endif // End of DMA FUNCTIONS 677 ////////////////////////////////////////////////////////////////////////////////////////