t4_dsp.cpp
1 /* 2 TFT/VGA driver 3 DMA TFT driver based on C64 ILI9341 dma driver from Frank Bösing, 2017 4 */ 5 6 #include "T4_DSP.h" 7 8 #include <SPI.h> 9 #include <DMAChannel.h> 10 11 #include "font8x8.h" 12 13 // TFT constants and variables 14 #define TFT_LINEARINT 1 15 #define LINEARINT_HACK 1 16 #define DMA_LINES_PER_BLOCK 64 17 #define DMA_NUM_SETTINGS 4 18 19 #define TFT_SWRESET 0x01 20 #define TFT_SLPOUT 0x11 21 #define TFT_INVON 0x21 22 #define TFT_DISPOFF 0x28 23 #define TFT_DISPON 0x29 24 #define TFT_CASET 0x2A 25 #define TFT_PASET 0x2B 26 #define TFT_RAMWR 0x2C 27 #define TFT_MADCTL 0x36 28 #define TFT_PIXFMT 0x3A 29 #define TFT_MADCTL_MY 0x80 30 #define TFT_MADCTL_MX 0x40 31 #define TFT_MADCTL_MV 0x20 32 #define TFT_MADCTL_ML 0x10 33 #define TFT_MADCTL_RGB 0x00 34 #define TFT_MADCTL_BGR 0x08 35 #define TFT_MADCTL_MH 0x04 36 37 #define RGBVAL16(r,g,b) ( (((r>>3)&0x1f)<<11) | (((g>>2)&0x3f)<<5) | (((b>>3)&0x1f)<<0) ) 38 //#define RGBVAL32(r,g,b) ( (r<<16) | (g<<8) | b ) 39 //#define RGBVAL8(r,g,b) ( (((r>>5)&0x07)<<5) | (((g>>5)&0x07)<<2) | (((b>>6)&0x3)<<0) ) 40 //#define R16(rgb) ((rgb>>8)&0xf8) 41 //#define G16(rgb) ((rgb>>3)&0xfc) 42 //#define B16(rgb) ((rgb<<3)&0xf8) 43 44 // LPSPI4 = SPI0 in Teensy 4.0 45 // LPSPI3 = SPI1 in Teensy 4.0 46 // LPSPI1 = SPI2 in Teensy 4.0 (used for SD on T4.0 but not T4.1) 47 48 #ifdef TFTSPI1 49 #define SPI SPI1 50 #define LPSPIP_TDR LPSPI3_TDR 51 #define LPSPIP_CR LPSPI3_CR 52 #define LPSPIP_CFGR1 LPSPI3_CFGR1 53 #define LPSPIP_TCR LPSPI3_TCR 54 #define LPSPIP_DER LPSPI3_DER 55 #define DMAMUX_SOURCE_LPSPIP_TX DMAMUX_SOURCE_LPSPI3_TX 56 #else 57 #define LPSPIP_TDR LPSPI4_TDR 58 #define LPSPIP_CR LPSPI4_CR 59 #define LPSPIP_CFGR1 LPSPI4_CFGR1 60 #define LPSPIP_TCR LPSPI4_TCR 61 #define LPSPIP_DER LPSPI4_DER 62 #define DMAMUX_SOURCE_LPSPIP_TX DMAMUX_SOURCE_LPSPI4_TX 63 #endif 64 65 #define SPICLOCK 60000000 66 #define SPI_MODE SPI_MODE0 67 68 // VGA constants and macros 69 typedef uint8_t vga_pixel; 70 #define VGA_RGB(r,g,b) ( (((r>>5)&0x07)<<5) | (((g>>5)&0x07)<<2) | (((b>>6)&0x3)<<0) ) 71 72 static DMASetting dmasettings[DMA_NUM_SETTINGS]; 73 static DMAChannel dmatx; 74 static uint16_t * blocks[DMA_NUM_SETTINGS]; // for DMA transfer, you need to divide in blocks < 128K 75 static volatile uint8_t rstop = 0; 76 static volatile bool cancelled = false; 77 static volatile uint8_t curTransfer = 0; 78 static uint8_t nbTransfer = 0; 79 static uint16_t * tft_buffer; 80 static int tft_width; 81 static int tft_height; 82 static int tft_stride; 83 84 #define DELAY_MASK 0x80 85 PROGMEM static const uint8_t init_commands[] = { 86 1+DELAY_MASK, TFT_SWRESET, 150, 87 1+DELAY_MASK, TFT_SLPOUT, 255, 88 2+DELAY_MASK, TFT_PIXFMT, 0x55, 10, 89 2, TFT_MADCTL, TFT_MADCTL_MV | TFT_MADCTL_BGR, 90 1, TFT_INVON, 91 1, TFT_DISPON, 92 0 93 }; 94 95 // VGA constants and variables 96 // Objective: 97 // generates VGA signal fully in hardware with as little as possible CPU help 98 99 // Principle: 100 // QTimer3 (timer3) used to generate H-PUSE and line interrupt (and V-PULSE) 101 // 2 FlexIO shift registers (1 and 2) and 2 DMA channels used to generate 102 // RGB out, combined to create 8bits(/12bits) output. 103 104 // Note: 105 // - supported resolutions: 320x240,320x480,640x240 and 640x480 pixels 106 // - experimental resolution: 352x240,352x480 107 // - experimental resolution: 512x240,512x480 (not stable) 108 // - video memory is allocated using malloc in T4 heap 109 // - as the 2 DMA transfers are not started exactly at same time, there is a bit of color smearing 110 // but tried to be compensated by pixel shifting 111 // - Default is 8bits RRRGGGBB (332) 112 // But 12bits GBB0RRRRGGGBB (444) feasible BUT NOT TESTED !!!! 113 // - Only ok at 600MHz else some disturbances visible 114 115 116 117 #define TOP_BORDER 40 118 #define PIN_HBLANK 15 119 120 #define PIN_R_B2 33 121 #define PIN_R_B1 4 122 #define PIN_R_B0 3 123 #define PIN_G_B2 2 124 #define PIN_G_B1 13 125 #define PIN_G_B0 11 126 #define PIN_B_B1 12 127 #define PIN_B_B0 10 128 129 130 #define DMA_HACK 0x80 131 132 #define R16(rgb) ((rgb>>8)&0xf8) 133 #define G16(rgb) ((rgb>>3)&0xfc) 134 #define B16(rgb) ((rgb<<3)&0xf8) 135 136 // VGA 640x480@60Hz 137 // Screen refresh rate 60 Hz 138 // Vertical refresh 31.46875 kHz 139 // Pixel freq. 25.175 MHz 140 // 141 // Visible area 640 25.422045680238 us 142 // Front porch 16 0.63555114200596 us 143 // Sync pulse 96 3.8133068520357 us 144 // Back porch 48 1.9066534260179 us 145 // Whole line 800 31.777557100298 us 146 147 #define frame_freq 60.0 // Hz 148 #define line_freq 31.46875 // KHz 149 #define pix_freq (line_freq*800) // KHz (25.175 MHz) 150 151 // pix_period = 39.7ns 152 // H-PULSE is 3.8133us = 3813.3ns => 96 pixels (see above for the rest) 153 #define frontporch_pix 20 //16 154 #define backporch_pix 44 //48 155 156 // Flexio Clock 157 // PLL3 SW CLOCK (3) => 480 MHz 158 // PLL5 VIDEO CLOCK (2) => See formula for clock (we take 604200 KHz as /24 it gives 25175) 159 #define FLEXIO_CLK_SEL_PLL3 3 160 #define FLEXIO_CLK_SEL_PLL5 2 161 162 /* Set video PLL */ 163 // There are /1, /2, /4, /8, /16 post dividers for the Video PLL. 164 // The output frequency can be set by programming the fields in the CCM_ANALOG_PLL_VIDEO, 165 // and CCM_ANALOG_MISC2 register sets according to the following equation. 166 // PLL output frequency = Fref * (DIV_SELECT + NUM/DENOM) 167 168 // nfact: 169 // This field controls the PLL loop divider. 170 // Valid range for DIV_SELECT divider value: 27~54. 171 172 #define POST_DIV_SELECT 2 173 174 // Full buffer including back/front porch 175 static vga_pixel * gfxbuffer __attribute__((aligned(32))) = NULL; 176 static uint32_t dstbuffer __attribute__((aligned(32))); 177 178 // Visible vuffer 179 static vga_pixel * vga_buffer; 180 static int vga_width; 181 static int vga_height; 182 static int vga_stride; 183 184 static int maxpixperline; 185 static int left_border; 186 static int right_border; 187 static int line_double; 188 static int pix_shift; 189 static int ref_div_select; 190 static int ref_freq_num; 191 static int ref_freq_denom; 192 static int ref_pix_shift; 193 static int combine_shiftreg; 194 195 #ifdef DEBUG 196 static uint32_t ISRTicks_prev = 0; 197 volatile uint32_t ISRTicks = 0; 198 #endif 199 200 uint8_t T4_DSP::_rst; 201 uint8_t T4_DSP::_cs; 202 uint8_t T4_DSP::_dc; 203 uint8_t T4_DSP::_mosi; 204 uint8_t T4_DSP::_sclk; 205 uint8_t T4_DSP::_vsync_pin = -1; 206 DMAChannel T4_DSP::flexio1DMA; 207 DMAChannel T4_DSP::flexio2DMA; 208 209 static volatile uint32_t VSYNC = 0; 210 static volatile uint32_t currentLine=0; 211 #define NOP asm volatile("nop\n\t"); 212 static gfx_mode_t gfxmode = MODE_UNDEFINED; 213 214 215 FASTRUN void T4_DSP::TFT_isr(void) { 216 dmatx.clearInterrupt(); 217 curTransfer++; 218 if (curTransfer >= nbTransfer) { 219 curTransfer = 0; 220 if (cancelled) { 221 dmatx.disable(); 222 rstop = 1; 223 } 224 } 225 arm_dcache_flush(blocks[curTransfer], DMA_LINES_PER_BLOCK*TFT_WIDTH*2); 226 } 227 228 FASTRUN void T4_DSP::QT3_isr(void) { 229 TMR3_SCTRL3 &= ~(TMR_SCTRL_TCF); 230 TMR3_CSCTRL3 &= ~(TMR_CSCTRL_TCF1|TMR_CSCTRL_TCF2); 231 232 cli(); 233 234 // V-PULSE 235 if (currentLine > 0) { 236 digitalWrite(_vsync_pin, 1); 237 VSYNC = 0; 238 } else { 239 digitalWrite(_vsync_pin, 0); 240 VSYNC = 1; 241 } 242 243 currentLine++; 244 currentLine = currentLine % 525; 245 246 247 uint32_t y = (currentLine - TOP_BORDER) >> line_double; 248 // Visible area 249 250 if (y >= 0 && y < vga_height) { 251 // Disable DMAs 252 //DMA_CERQ = flexio2DMA.channel; 253 //DMA_CERQ = flexio1DMA.channel; 254 255 // Setup source adress 256 // Aligned 32 bits copy 257 unsigned long * p=(uint32_t *)&gfxbuffer[vga_stride*y]; 258 flexio2DMA.TCD->SADDR = p; 259 if (pix_shift & DMA_HACK) 260 { 261 // Unaligned copy 262 uint8_t * p2=(uint8_t *)&gfxbuffer[vga_stride*y+(pix_shift&0xf)]; 263 flexio1DMA.TCD->SADDR = p2; 264 } 265 else { 266 p=(uint32_t *)&gfxbuffer[vga_stride*y+(pix_shift&0xc)]; // multiple of 4 267 flexio1DMA.TCD->SADDR = p; 268 } 269 270 // Enable DMAs 271 //flexio2DMA.enable(); 272 //flexio1DMA.enable(); 273 DMA_SERQ = flexio2DMA.channel; 274 DMA_SERQ = flexio1DMA.channel; 275 arm_dcache_flush_delete((void*)((uint32_t *)&gfxbuffer[vga_stride*y]), vga_stride); 276 } 277 sei(); 278 279 #ifdef DEBUG 280 ISRTicks++; 281 #endif 282 asm volatile("dsb"); 283 } 284 285 static void setDmaStruct() { 286 uint32_t remaining = TFT_HEIGHT*TFT_WIDTH*2; 287 uint16_t * fb = (uint16_t*)malloc(remaining); 288 tft_buffer = fb; 289 tft_width = TFT_WIDTH; 290 tft_height = TFT_HEIGHT; 291 tft_stride = TFT_WIDTH; 292 uint16_t col=RGBVAL16(0x00,0x00,0x00); 293 int i=0; 294 while (remaining > 0) { 295 int32_t len = (remaining >= (DMA_LINES_PER_BLOCK*TFT_WIDTH*2)?DMA_LINES_PER_BLOCK*TFT_WIDTH*2:remaining); 296 blocks[i] = fb; 297 for (int j=0;j<len/2;j++) fb[j]=col; 298 dmasettings[i].sourceBuffer(fb, len); 299 dmasettings[i].destination((uint8_t &)LPSPIP_TDR); 300 dmasettings[i].TCD->ATTR_DST = 1; 301 dmasettings[i].replaceSettingsOnCompletion(dmasettings[i+1]); 302 dmasettings[i].interruptAtCompletion(); 303 fb += len/2; 304 remaining -= len; 305 i++; 306 } 307 dmasettings[i-1].replaceSettingsOnCompletion(dmasettings[0]); 308 nbTransfer = i; 309 } 310 311 static void set_videoClock(int nfact, int32_t nmult, uint32_t ndiv, bool force) // sets PLL5 312 { 313 //if (!force && (CCM_ANALOG_PLL_VIDEO & CCM_ANALOG_PLL_VIDEO_ENABLE)) return; 314 CCM_ANALOG_PLL_VIDEO = CCM_ANALOG_PLL_VIDEO_BYPASS | CCM_ANALOG_PLL_VIDEO_ENABLE 315 | CCM_ANALOG_PLL_VIDEO_POST_DIV_SELECT(1) // 2: 1/1; 1: 1/2; 0: 1/4 316 | CCM_ANALOG_PLL_VIDEO_DIV_SELECT(nfact); 317 CCM_ANALOG_PLL_VIDEO_NUM = nmult /*& CCM_ANALOG_PLL_VIDEO_NUM_MASK*/; 318 CCM_ANALOG_PLL_VIDEO_DENOM = ndiv /*& CCM_ANALOG_PLL_VIDEO_DENOM_MASK*/; 319 CCM_ANALOG_PLL_VIDEO &= ~CCM_ANALOG_PLL_VIDEO_POWERDOWN;//Switch on PLL 320 while (!(CCM_ANALOG_PLL_VIDEO & CCM_ANALOG_PLL_VIDEO_LOCK)) {}; //Wait for pll-lock 321 const int div_post_pll = 1; // other values: 2,4 322 if(div_post_pll>3) CCM_ANALOG_MISC2 |= CCM_ANALOG_MISC2_DIV_MSB; 323 CCM_ANALOG_PLL_VIDEO &= ~CCM_ANALOG_PLL_VIDEO_BYPASS;//Disable Bypass 324 } 325 326 T4_DSP::T4_DSP() 327 { 328 _cs = TFT_CS; 329 _dc = TFT_DC; 330 _rst = TFT_RST; 331 _mosi = TFT_MOSI; 332 _sclk = TFT_SCLK; 333 pinMode(_dc, OUTPUT); 334 pinMode(_cs, OUTPUT); 335 digitalWrite(_cs, 1); 336 digitalWrite(_dc, 1); 337 _vsync_pin = 8; 338 } 339 340 341 void T4_DSP::setArea(uint16_t x1,uint16_t y1,uint16_t x2,uint16_t y2) { 342 int dx=0; 343 int dy=0; 344 digitalWrite(_dc, 0); 345 SPI.transfer(TFT_CASET); 346 digitalWrite(_dc, 1); 347 SPI.transfer16(x1+dx); 348 digitalWrite(_dc, 1); 349 SPI.transfer16(x2+dx); 350 digitalWrite(_dc, 0); 351 SPI.transfer(TFT_PASET); 352 digitalWrite(_dc, 1); 353 SPI.transfer16(y1+dy); 354 digitalWrite(_dc, 1); 355 SPI.transfer16(y2+dy); 356 digitalWrite(_dc, 0); 357 SPI.transfer(TFT_RAMWR); 358 digitalWrite(_dc, 1); 359 return; 360 } 361 362 void T4_DSP::tft_setup(bool isST) { 363 SPI.setMOSI(_mosi); 364 SPI.setSCK(_sclk); 365 SPI.begin(); 366 // RESET if reset pin defined 367 if (_rst != 0xff) { 368 pinMode(_rst, OUTPUT); 369 digitalWrite(_rst, HIGH); 370 delay(100); 371 digitalWrite(_rst, LOW); 372 delay(100); 373 digitalWrite(_rst, HIGH); 374 delay(200); 375 } 376 SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); 377 const uint8_t *addr = init_commands; 378 uint8_t count; 379 digitalWrite(_cs, 0); 380 while (count = *addr++) { 381 uint8_t command = *addr++; 382 if ( (command == TFT_INVON) && (!isST) ) { 383 // Skip TFT_INVON for ILI 384 } 385 else { 386 digitalWrite(_dc, 0); // command 387 SPI.transfer(command); 388 uint16_t ms = count & DELAY_MASK; 389 count &= ~DELAY_MASK; 390 while (--count > 0) { // data 391 uint8_t data = *addr++; 392 if ( (command == TFT_MADCTL) && (isST) ) { 393 data = TFT_MADCTL_MX | TFT_MADCTL_MV |TFT_MADCTL_RGB; 394 } 395 digitalWrite(_dc, 1); 396 SPI.transfer(data); 397 } 398 if (ms) { 399 ms = *addr++; // Read post-command delay time (ms) 400 if(ms == 255) ms = 500; // If 255, delay for 500 ms 401 digitalWrite(_cs, 1); 402 SPI.endTransaction(); 403 delay(2); 404 SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); 405 digitalWrite(_cs, 0); 406 } 407 } 408 } 409 digitalWrite(_cs, 1); 410 SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); 411 setArea(0, 0, TFT_REALWIDTH-1, TFT_REALHEIGHT-1); 412 SPI.endTransaction(); 413 /* 414 SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); 415 digitalWrite(_dc, 0); 416 digitalWrite(_cs, 0); 417 SPI.transfer(TFT_MADCTL); 418 digitalWrite(_dc, 1); 419 SPI.transfer(TFT_MADCTL_MV | TFT_MADCTL_BGR); 420 // SPI.transfer(TFT_MADCTL_MX | TFT_MADCTL_MV |TFT_MADCTL_RGB); 421 digitalWrite(_cs, 1); 422 SPI.endTransaction(); 423 */ 424 cancelled = false; 425 } 426 427 // display VGA image 428 gfx_error_t T4_DSP::begin(gfx_mode_t mode) 429 { 430 uint32_t flexio_clock_div; 431 combine_shiftreg = 0; 432 // int div_select = 49; 433 // int num = 135; 434 // int denom = 100; 435 int div_select = 20; 436 int num = 9800; 437 int denom = 10000; 438 int flexio_clk_sel = FLEXIO_CLK_SEL_PLL5; 439 int flexio_freq = ( 24000*div_select + (num*24000)/denom )/POST_DIV_SELECT; 440 set_videoClock(div_select,num,denom,true); 441 442 #ifdef DEBUG 443 Serial.println(mode); 444 Serial.println("mode"); 445 #endif 446 447 switch(mode) 448 { 449 case MODE_TFTILI_320x240: 450 #ifdef DEBUG 451 Serial.println("TFTILI_320x240"); 452 #endif 453 tft_setup(false); 454 gfxmode = mode; 455 break; 456 case MODE_TFTST_320x240: 457 #ifdef DEBUG 458 Serial.println("TFTST_320x240"); 459 #endif 460 tft_setup(true); 461 gfxmode = mode; 462 break; 463 464 case MODE_VGA_320x240: 465 #ifdef DEBUG 466 Serial.println("VGA_320x240"); 467 #endif 468 left_border = backporch_pix/2; 469 right_border = frontporch_pix/2; 470 vga_width = 320; 471 vga_height = 240 ; 472 vga_stride = left_border+vga_width+right_border; 473 flexio_clock_div = flexio_freq/(pix_freq/2); 474 line_double = 1; 475 pix_shift = 2+DMA_HACK; 476 break; 477 478 case MODE_VGA_320x480: 479 #ifdef DEBUG 480 Serial.println("VGA_320x480"); 481 #endif 482 left_border = backporch_pix/2; 483 right_border = frontporch_pix/2; 484 vga_width = 320; 485 vga_height = 480 ; 486 vga_stride = left_border+vga_width+right_border; 487 flexio_clock_div = flexio_freq/(pix_freq/2); 488 line_double = 0; 489 pix_shift = 2+DMA_HACK; 490 break; 491 492 case MODE_VGA_640x240: 493 #ifdef DEBUG 494 Serial.println("VGA_640x240"); 495 #endif 496 left_border = backporch_pix; 497 right_border = frontporch_pix; 498 vga_width = 640; 499 vga_height = 240 ; 500 vga_stride = left_border+vga_width+right_border; 501 flexio_clock_div = flexio_freq/pix_freq; 502 line_double = 1; 503 pix_shift = 4; 504 combine_shiftreg = 1; 505 break; 506 507 case MODE_VGA_640x480: 508 #ifdef DEBUG 509 Serial.println("VGA_640x480"); 510 #endif 511 left_border = backporch_pix; 512 right_border = frontporch_pix; 513 vga_width = 640; 514 vga_height = 480 ; 515 vga_stride = left_border+vga_width+right_border; 516 flexio_clock_div = (flexio_freq/pix_freq); 517 line_double = 0; 518 pix_shift = 4; 519 combine_shiftreg = 1; 520 break; 521 522 case MODE_VGA_512x240: 523 #ifdef DEBUG 524 Serial.println("VGA_512x240"); 525 #endif 526 left_border = backporch_pix/1.3; 527 right_border = frontporch_pix/1.3; 528 vga_width = 512; 529 vga_height = 240 ; 530 vga_stride = left_border+vga_width+right_border; 531 flexio_clock_div = flexio_freq/(pix_freq/1.3)+2; 532 line_double = 1; 533 pix_shift = 0; 534 break; 535 536 case MODE_VGA_512x480: 537 #ifdef DEBUG 538 Serial.println("VGA_512x480"); 539 #endif 540 left_border = backporch_pix/1.3; 541 right_border = frontporch_pix/1.3; 542 vga_width = 512; 543 vga_height = 480 ; 544 vga_stride = left_border+vga_width+right_border; 545 flexio_clock_div = flexio_freq/(pix_freq/1.3)+2; 546 line_double = 0; 547 pix_shift = 0; 548 break; 549 550 case MODE_VGA_352x240: 551 #ifdef DEBUG 552 Serial.println("VGA_352x240"); 553 #endif 554 left_border = backporch_pix/1.75; 555 right_border = frontporch_pix/1.75; 556 vga_width = 352; 557 vga_height = 240 ; 558 vga_stride = left_border+vga_width+right_border; 559 flexio_clock_div = flexio_freq/(pix_freq/1.75)+2; 560 line_double = 1; 561 pix_shift = 2+DMA_HACK; 562 break; 563 564 case MODE_VGA_352x480: 565 #ifdef DEBUG 566 Serial.println("VGA_352x480"); 567 #endif 568 left_border = backporch_pix/1.75; 569 right_border = frontporch_pix/1.75; 570 vga_width = 352; 571 vga_height = 480 ; 572 vga_stride = left_border+vga_width+right_border; 573 flexio_clock_div = flexio_freq/(pix_freq/1.75)+2; 574 line_double = 0; 575 pix_shift = 2+DMA_HACK; 576 break; 577 } 578 579 if (mode >= MODE_VGA_320x240) 580 { 581 if ( (gfxmode != MODE_UNDEFINED) && (gfxmode < MODE_VGA_320x240) ) { 582 fillScreenNoDma(RGBVAL16(0x0,0x00,0x00)); 583 digitalWrite(_cs, 0); 584 digitalWrite(_dc, 0); 585 SPI.transfer(TFT_DISPOFF); 586 digitalWrite(_cs, 1); 587 delay(20); 588 digitalWrite(_cs, 0); 589 digitalWrite(_cs, 1); 590 } 591 gfxmode = mode; 592 593 maxpixperline = vga_stride; 594 // Save param for tweek adjustment 595 ref_div_select = div_select; 596 ref_freq_num = num; 597 ref_freq_denom = denom; 598 ref_pix_shift = pix_shift; 599 600 #ifdef DEBUG 601 Serial.println("frequency"); 602 Serial.println(flexio_freq); 603 Serial.println("div"); 604 Serial.println(flexio_freq/pix_freq); 605 #endif 606 607 pinMode(_vsync_pin, OUTPUT); 608 pinMode(PIN_HBLANK, OUTPUT); 609 610 /* Basic pin setup FlexIO1 */ 611 pinMode(PIN_G_B2, OUTPUT); // FlexIO1:4 = 0x10 612 pinMode(PIN_R_B0, OUTPUT); // FlexIO1:5 = 0x20 613 pinMode(PIN_R_B1, OUTPUT); // FlexIO1:6 = 0x40 614 pinMode(PIN_R_B2, OUTPUT); // FlexIO1:7 = 0x80 615 /* Basic pin setup FlexIO2 */ 616 pinMode(PIN_B_B0, OUTPUT); // FlexIO2:0 = 0x00001 617 pinMode(PIN_B_B1, OUTPUT); // FlexIO2:1 = 0x00002 618 pinMode(PIN_G_B0, OUTPUT); // FlexIO2:2 = 0x00004 619 pinMode(PIN_G_B1, OUTPUT); // FlexIO2:3 = 0x00008 620 621 /* High speed and drive strength configuration */ 622 *(portControlRegister(PIN_G_B2)) = 0xFF; 623 *(portControlRegister(PIN_R_B0)) = 0xFF; 624 *(portControlRegister(PIN_R_B1)) = 0xFF; 625 *(portControlRegister(PIN_R_B2)) = 0xFF; 626 *(portControlRegister(PIN_B_B0)) = 0xFF; 627 *(portControlRegister(PIN_B_B1)) = 0xFF; 628 *(portControlRegister(PIN_G_B0)) = 0xFF; 629 *(portControlRegister(PIN_G_B1)) = 0xFF; 630 631 /* Set clock for FlexIO1 and FlexIO2 */ 632 CCM_CCGR5 &= ~CCM_CCGR5_FLEXIO1(CCM_CCGR_ON); 633 CCM_CDCDR = (CCM_CDCDR & ~(CCM_CDCDR_FLEXIO1_CLK_SEL(3) | CCM_CDCDR_FLEXIO1_CLK_PRED(7) | CCM_CDCDR_FLEXIO1_CLK_PODF(7))) 634 | CCM_CDCDR_FLEXIO1_CLK_SEL(flexio_clk_sel) | CCM_CDCDR_FLEXIO1_CLK_PRED(0) | CCM_CDCDR_FLEXIO1_CLK_PODF(0); 635 CCM_CCGR3 &= ~CCM_CCGR3_FLEXIO2(CCM_CCGR_ON); 636 CCM_CSCMR2 = (CCM_CSCMR2 & ~(CCM_CSCMR2_FLEXIO2_CLK_SEL(3))) | CCM_CSCMR2_FLEXIO2_CLK_SEL(flexio_clk_sel); 637 CCM_CS1CDR = (CCM_CS1CDR & ~(CCM_CS1CDR_FLEXIO2_CLK_PRED(7)|CCM_CS1CDR_FLEXIO2_CLK_PODF(7)) ) 638 | CCM_CS1CDR_FLEXIO2_CLK_PRED(0) | CCM_CS1CDR_FLEXIO2_CLK_PODF(0); 639 640 641 /* Set up pin mux FlexIO1 */ 642 *(portConfigRegister(PIN_G_B2)) = 0x14; 643 *(portConfigRegister(PIN_R_B0)) = 0x14; 644 *(portConfigRegister(PIN_R_B1)) = 0x14; 645 *(portConfigRegister(PIN_R_B2)) = 0x14; 646 /* Set up pin mux FlexIO2 */ 647 *(portConfigRegister(PIN_B_B0)) = 0x14; 648 *(portConfigRegister(PIN_B_B1)) = 0x14; 649 *(portConfigRegister(PIN_G_B0)) = 0x14; 650 *(portConfigRegister(PIN_G_B1)) = 0x14; 651 652 /* Enable the clock */ 653 CCM_CCGR5 |= CCM_CCGR5_FLEXIO1(CCM_CCGR_ON); 654 CCM_CCGR3 |= CCM_CCGR3_FLEXIO2(CCM_CCGR_ON); 655 /* Enable the FlexIO with fast access */ 656 FLEXIO1_CTRL = FLEXIO_CTRL_FLEXEN | FLEXIO_CTRL_FASTACC; 657 FLEXIO2_CTRL = FLEXIO_CTRL_FLEXEN | FLEXIO_CTRL_FASTACC; 658 659 uint32_t timerSelect, timerPolarity, pinConfig, pinSelect, pinPolarity, shifterMode, parallelWidth, inputSource, stopBit, startBit; 660 uint32_t triggerSelect, triggerPolarity, triggerSource, timerMode, timerOutput, timerDecrement, timerReset, timerDisable, timerEnable; 661 662 /* Shifter 0 registers for FlexIO2 */ 663 parallelWidth = FLEXIO_SHIFTCFG_PWIDTH(4); // 8-bit parallel shift width 664 pinSelect = FLEXIO_SHIFTCTL_PINSEL(0); // Select pins FXIO_D0 through FXIO_D3 665 inputSource = FLEXIO_SHIFTCFG_INSRC*(1); // Input source from next shifter 666 stopBit = FLEXIO_SHIFTCFG_SSTOP(0); // Stop bit disabled 667 startBit = FLEXIO_SHIFTCFG_SSTART(0); // Start bit disabled, transmitter loads data on enable 668 timerSelect = FLEXIO_SHIFTCTL_TIMSEL(0); // Use timer 0 669 timerPolarity = FLEXIO_SHIFTCTL_TIMPOL*(1); // Shift on negedge of clock 670 pinConfig = FLEXIO_SHIFTCTL_PINCFG(3); // Shifter pin output 671 pinPolarity = FLEXIO_SHIFTCTL_PINPOL*(0); // Shifter pin active high polarity 672 shifterMode = FLEXIO_SHIFTCTL_SMOD(2); // Shifter transmit mode 673 /* Shifter 0 registers for FlexIO1 */ 674 FLEXIO2_SHIFTCFG0 = parallelWidth | inputSource | stopBit | startBit; 675 FLEXIO2_SHIFTCTL0 = timerSelect | timerPolarity | pinConfig | pinSelect | pinPolarity | shifterMode; 676 677 /* Shifter 0 registers for FlexIO1 */ 678 parallelWidth = FLEXIO_SHIFTCFG_PWIDTH(4); // 8-bit parallel shift width 679 pinSelect = FLEXIO_SHIFTCTL_PINSEL(4); // Select pins FXIO_D4 through FXIO_D7 680 FLEXIO1_SHIFTCFG0 = parallelWidth | inputSource | stopBit | startBit; 681 FLEXIO1_SHIFTCTL0 = timerSelect | timerPolarity | pinConfig | pinSelect | pinPolarity | shifterMode; 682 683 if (combine_shiftreg) { 684 pinConfig = FLEXIO_SHIFTCTL_PINCFG(0); // Shifter pin output disabled 685 FLEXIO2_SHIFTCFG1 = parallelWidth | inputSource | stopBit | startBit; 686 FLEXIO2_SHIFTCTL1 = timerSelect | timerPolarity | pinConfig | shifterMode; 687 FLEXIO1_SHIFTCFG1 = parallelWidth | inputSource | stopBit | startBit; 688 FLEXIO1_SHIFTCTL1 = timerSelect | timerPolarity | pinConfig | shifterMode; 689 } 690 /* Timer 0 registers for FlexIO2 */ 691 timerOutput = FLEXIO_TIMCFG_TIMOUT(1); // Timer output is logic zero when enabled and is not affected by the Timer reset 692 timerDecrement = FLEXIO_TIMCFG_TIMDEC(0); // Timer decrements on FlexIO clock, shift clock equals timer output 693 timerReset = FLEXIO_TIMCFG_TIMRST(0); // Timer never reset 694 timerDisable = FLEXIO_TIMCFG_TIMDIS(2); // Timer disabled on Timer compare 695 timerEnable = FLEXIO_TIMCFG_TIMENA(2); // Timer enabled on Trigger assert 696 stopBit = FLEXIO_TIMCFG_TSTOP(0); // Stop bit disabled 697 startBit = FLEXIO_TIMCFG_TSTART*(0); // Start bit disabled 698 if (combine_shiftreg) { 699 triggerSelect = FLEXIO_TIMCTL_TRGSEL(1+4*(1)); // Trigger select Shifter 1 status flag 700 } 701 else { 702 triggerSelect = FLEXIO_TIMCTL_TRGSEL(1+4*(0)); // Trigger select Shifter 0 status flag 703 } 704 triggerPolarity = FLEXIO_TIMCTL_TRGPOL*(1); // Trigger active low 705 triggerSource = FLEXIO_TIMCTL_TRGSRC*(1); // Internal trigger selected 706 pinConfig = FLEXIO_TIMCTL_PINCFG(0); // Timer pin output disabled 707 //pinSelect = FLEXIO_TIMCTL_PINSEL(0); // Select pin FXIO_D0 708 //pinPolarity = FLEXIO_TIMCTL_PINPOL*(0); // Timer pin polarity active high 709 timerMode = FLEXIO_TIMCTL_TIMOD(1); // Dual 8-bit counters baud mode 710 // flexio_clock_div : Output clock frequency is N times slower than FlexIO clock (41.7 ns period) (23.980MHz?) 711 712 int shifts_per_transfer; 713 if (combine_shiftreg) { 714 shifts_per_transfer = 8; // Shift out 8 times with every transfer = 64-bit word = contents of Shifter 0+1 715 } 716 else { 717 shifts_per_transfer = 4; // Shift out 4 times with every transfer = 32-bit word = contents of Shifter 0 718 } 719 FLEXIO2_TIMCFG0 = timerOutput | timerDecrement | timerReset | timerDisable | timerEnable | stopBit | startBit; 720 FLEXIO2_TIMCTL0 = triggerSelect | triggerPolarity | triggerSource | pinConfig /*| pinSelect | pinPolarity*/ | timerMode; 721 FLEXIO2_TIMCMP0 = ((shifts_per_transfer*2-1)<<8) | ((flexio_clock_div/2-1)<<0); 722 /* Timer 0 registers for FlexIO1 */ 723 FLEXIO1_TIMCFG0 = timerOutput | timerDecrement | timerReset | timerDisable | timerEnable | stopBit | startBit; 724 FLEXIO1_TIMCTL0 = triggerSelect | triggerPolarity | triggerSource | pinConfig /*| pinSelect | pinPolarity*/ | timerMode; 725 FLEXIO1_TIMCMP0 = ((shifts_per_transfer*2-1)<<8) | ((flexio_clock_div/2-1)<<0); 726 #ifdef DEBUG 727 Serial.println("FlexIO setup complete"); 728 #endif 729 730 /* Enable DMA trigger on Shifter0, DMA request is generated when data is transferred from buffer0 to shifter0 */ 731 if (combine_shiftreg) { 732 FLEXIO2_SHIFTSDEN |= (1<<1); 733 FLEXIO1_SHIFTSDEN |= (1<<1); 734 } 735 else { 736 FLEXIO2_SHIFTSDEN |= (1<<0); 737 FLEXIO1_SHIFTSDEN |= (1<<0); 738 } 739 /* Disable DMA channel so it doesn't start transferring yet */ 740 flexio1DMA.disable(); 741 flexio2DMA.disable(); 742 /* Set up DMA channel to use Shifter 0 trigger */ 743 flexio1DMA.triggerAtHardwareEvent(DMAMUX_SOURCE_FLEXIO1_REQUEST0); 744 flexio2DMA.triggerAtHardwareEvent(DMAMUX_SOURCE_FLEXIO2_REQUEST0); 745 746 747 if (combine_shiftreg) { 748 flexio2DMA.TCD->NBYTES = 8; 749 flexio2DMA.TCD->SOFF = 4; 750 flexio2DMA.TCD->SLAST = -maxpixperline; 751 flexio2DMA.TCD->BITER = maxpixperline / 8; 752 flexio2DMA.TCD->CITER = maxpixperline / 8; 753 flexio2DMA.TCD->DADDR = &FLEXIO2_SHIFTBUF0; 754 flexio2DMA.TCD->DOFF = 0; 755 flexio2DMA.TCD->DLASTSGA = 0; 756 flexio2DMA.TCD->ATTR = DMA_TCD_ATTR_SSIZE(2) | DMA_TCD_ATTR_DSIZE(3); // 32bits => 64bits 757 flexio2DMA.TCD->CSR |= DMA_TCD_CSR_DREQ; 758 759 flexio1DMA.TCD->NBYTES = 8; 760 flexio1DMA.TCD->SOFF = 4; 761 flexio1DMA.TCD->SLAST = -maxpixperline; 762 flexio1DMA.TCD->BITER = maxpixperline / 8; 763 flexio1DMA.TCD->CITER = maxpixperline / 8; 764 flexio1DMA.TCD->DADDR = &FLEXIO1_SHIFTBUFNBS0; 765 flexio1DMA.TCD->DOFF = 0; 766 flexio1DMA.TCD->DLASTSGA = 0; 767 flexio1DMA.TCD->ATTR = DMA_TCD_ATTR_SSIZE(2) | DMA_TCD_ATTR_DSIZE(3); // 32bits => 64bits 768 flexio1DMA.TCD->CSR |= DMA_TCD_CSR_DREQ; 769 } 770 else { 771 // Setup DMA2 Flexio2 copy 772 flexio2DMA.TCD->NBYTES = 4; 773 flexio2DMA.TCD->SOFF = 4; 774 flexio2DMA.TCD->SLAST = -maxpixperline; 775 flexio2DMA.TCD->BITER = maxpixperline / 4; 776 flexio2DMA.TCD->CITER = maxpixperline / 4; 777 flexio2DMA.TCD->DADDR = &FLEXIO2_SHIFTBUF0; 778 flexio2DMA.TCD->DOFF = 0; 779 flexio2DMA.TCD->DLASTSGA = 0; 780 flexio2DMA.TCD->ATTR = DMA_TCD_ATTR_SSIZE(2) | DMA_TCD_ATTR_DSIZE(2); // 32bits 781 flexio2DMA.TCD->CSR |= DMA_TCD_CSR_DREQ; 782 783 // Setup DMA1 Flexio1 copy 784 // Use pixel shift to avoid color smearing? 785 if (pix_shift & DMA_HACK) 786 { 787 if (pix_shift & 0x3 == 0) { 788 // Aligned 32 bits copy (32bits to 32bits) 789 flexio1DMA.TCD->NBYTES = 4; 790 flexio1DMA.TCD->SOFF = 4; 791 flexio1DMA.TCD->SLAST = -maxpixperline; 792 flexio1DMA.TCD->BITER = maxpixperline / 4; 793 flexio1DMA.TCD->CITER = maxpixperline / 4; 794 flexio1DMA.TCD->DADDR = &FLEXIO1_SHIFTBUFNBS0; 795 flexio1DMA.TCD->DOFF = 0; 796 flexio1DMA.TCD->DLASTSGA = 0; 797 flexio1DMA.TCD->ATTR = DMA_TCD_ATTR_SSIZE(2) | DMA_TCD_ATTR_DSIZE(2); // 32bits to 32bits 798 flexio1DMA.TCD->CSR |= DMA_TCD_CSR_DREQ; 799 } 800 else { 801 // Unaligned (source) 32 bits copy (8bits to 32bits) 802 flexio1DMA.TCD->NBYTES = 4; 803 flexio1DMA.TCD->SOFF = 1; 804 flexio1DMA.TCD->SLAST = -maxpixperline; 805 flexio1DMA.TCD->BITER = maxpixperline / 4; 806 flexio1DMA.TCD->CITER = maxpixperline / 4; 807 flexio1DMA.TCD->DADDR = &FLEXIO1_SHIFTBUFNBS0; 808 flexio1DMA.TCD->DOFF = 0; 809 flexio1DMA.TCD->DLASTSGA = 0; 810 flexio1DMA.TCD->ATTR = DMA_TCD_ATTR_SSIZE(0) | DMA_TCD_ATTR_DSIZE(2); // 8bits to 32bits 811 flexio1DMA.TCD->CSR |= DMA_TCD_CSR_DREQ; // disable on completion 812 } 813 } 814 else 815 { 816 // Aligned 32 bits copy 817 flexio1DMA.TCD->NBYTES = 4; 818 flexio1DMA.TCD->SOFF = 4; 819 flexio1DMA.TCD->SLAST = -maxpixperline; 820 flexio1DMA.TCD->BITER = maxpixperline / 4; 821 flexio1DMA.TCD->CITER = maxpixperline / 4; 822 flexio1DMA.TCD->DADDR = &FLEXIO1_SHIFTBUFNBS0; 823 flexio1DMA.TCD->DOFF = 0; 824 flexio1DMA.TCD->DLASTSGA = 0; 825 flexio1DMA.TCD->ATTR = DMA_TCD_ATTR_SSIZE(2) | DMA_TCD_ATTR_DSIZE(2); // 32bits 826 flexio1DMA.TCD->CSR |= DMA_TCD_CSR_DREQ; 827 } 828 } 829 830 #ifdef DEBUG 831 Serial.println("DMA setup complete"); 832 #endif 833 834 // enable clocks for QTIMER3: generates the 15KHz for hsync 835 // Pulse: 836 // low : 3.8133 us => 569x6.7ns 837 // total: 31.777 us => 4743x6.7ns (high = 4174x6.7ns) 838 // (OLD TEST) 839 // (4us low, 28us high => 32us) 840 // (597x6.7ns for 4us) 841 // (4179x6.7ns for 28us) 842 CCM_CCGR6 |= 0xC0000000; //enable clocks to CG15 of CGR6 for QT3 843 //configure QTIMER3 Timer3 for test of alternating Compare1 and Compare2 844 845 #define MARGIN_N 1005 // 1206 at 720MHz //1005 at 600MHz 846 #define MARGIN_D 1000 847 848 TMR3_CTRL3 = 0b0000000000100000; //stop all functions of timer 849 // Invert output pin as we want the interupt on rising edge 850 TMR3_SCTRL3 = 0b0000000000000011; //0(TimerCompareFlag),0(TimerCompareIntEnable),00(TimerOverflow)0000(NoCapture),0000(Capture Disabled),00, 1(INV output),1(OFLAG to Ext Pin) 851 TMR3_CNTR3 = 0; 852 TMR3_LOAD3 = 0; 853 854 /* Inverted timings */ 855 unsigned long long cpu_freq = F_CPU; 856 unsigned long long rate = (1005ULL * cpu_freq) / 600000000ULL; 857 int rate2 = rate; 858 859 int substract = 1; 860 if (cpu_freq > 950000000ULL && cpu_freq < 990000000ULL) { 861 substract=5; 862 rate2=1652; 863 } 864 865 #ifdef DEBUG 866 Serial.print("MARGIN_N is: "); 867 Serial.println(rate2, DEC); 868 Serial.print("SUBSTRACT is: "); 869 Serial.println(substract, DEC); 870 #endif 871 TMR3_COMP13 = ((4174*rate2)/MARGIN_D)-substract; 872 TMR3_CMPLD13 = ((4174*rate2)/MARGIN_D)-substract; 873 TMR3_COMP23 = ((569*rate2)/MARGIN_D)-substract; 874 TMR3_CMPLD23 = ((569*rate2)/MARGIN_D)-substract; 875 /* 876 TMR3_COMP13 = ((4174*MARGIN_N)/MARGIN_D)-1; 877 TMR3_CMPLD13 = ((4174*MARGIN_N)/MARGIN_D)-1; 878 TMR3_COMP23 = ((569*MARGIN_N)/MARGIN_D)-1; 879 TMR3_CMPLD23 = ((569*MARGIN_N)/MARGIN_D)-1; 880 */ 881 TMR3_CSCTRL3 = 0b0000000010000101; //Compare1 only enabled - Compare Load1 control and Compare Load2 control both on 882 TMR3_CTRL3 = 0b0011000000100100; // 001(Count rising edges Primary Source),1000(IP Bus Clock),00 (Secondary Source), 883 // 0(Count Once),1(Count up to Compare),0(Count Up),0(Co Channel Init),100(Toggle OFLAG on alternating Compare1/Compare2) 884 //configure Teensy pin Compare output 885 IOMUXC_SW_MUX_CTL_PAD_GPIO_AD_B1_03 = 1; // QT3 Timer3 is now on pin 15 886 attachInterruptVector(IRQ_QTIMER3, QT3_isr); //declare which routine performs the ISR function 887 NVIC_ENABLE_IRQ(IRQ_QTIMER3); 888 #ifdef DEBUG 889 Serial.println("QTIMER3 setup complete"); 890 Serial.print("V-PIN is "); 891 Serial.println(_vsync_pin); 892 #endif 893 894 /* initialize gfx buffer */ 895 if (gfxbuffer == NULL) gfxbuffer = (vga_pixel*)malloc(vga_stride*vga_height*sizeof(vga_pixel)+4); // 4bytes for pixel shift 896 if (gfxbuffer == NULL) return(GFX_ERROR); 897 #ifdef DEBUG 898 Serial.println("Memory allocated"); 899 #endif 900 901 memset((void*)&gfxbuffer[0],0, vga_stride*vga_height*sizeof(vga_pixel)+4); 902 vga_buffer = (vga_pixel*)&gfxbuffer[left_border]; 903 #ifdef DEBUG 904 Serial.println(vga_stride); 905 Serial.println(vga_height); 906 Serial.println("Screen cleared"); 907 #endif 908 } 909 910 return(GFX_OK); 911 } 912 913 gfx_mode_t T4_DSP::getMode(void) 914 { 915 return gfxmode; 916 } 917 918 void T4_DSP::startRefresh(void) { 919 if (gfxmode < MODE_VGA_320x240) { 920 curTransfer = 0; 921 rstop = 0; 922 //dmatx.begin(true); 923 dmatx.attachInterrupt(TFT_isr); 924 setDmaStruct(); 925 setArea((TFT_REALWIDTH-TFT_WIDTH)/2, (TFT_REALHEIGHT-TFT_HEIGHT)/2, (TFT_REALWIDTH-TFT_WIDTH)/2 + TFT_WIDTH-1, (TFT_REALHEIGHT-TFT_HEIGHT)/2+TFT_HEIGHT-1); 926 fillScreen(RGBVAL16(0x00,0x00,0x00)); 927 928 digitalWrite(_cs, HIGH); 929 SPI.begin(); 930 SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE0)); 931 932 LPSPIP_CR &= ~LPSPI_CR_MEN;//disable LPSPI: 933 LPSPIP_CFGR1 |= LPSPI_CFGR1_NOSTALL; //prevent stall from RX 934 LPSPIP_TCR = 15; // Framesize 16 Bits 935 //LPSPIP_FCR = 0; // Fifo Watermark 936 LPSPIP_DER = LPSPI_DER_TDDE; //TX DMA Request Enable 937 LPSPIP_CR |= LPSPI_CR_MEN; //enable LPSPI: 938 dmatx.triggerAtHardwareEvent( DMAMUX_SOURCE_LPSPIP_TX ); 939 940 dmatx = dmasettings[0]; 941 digitalWrite(_cs, 0); 942 setArea((TFT_REALWIDTH-TFT_WIDTH)/2, (TFT_REALHEIGHT-TFT_HEIGHT)/2, (TFT_REALWIDTH-TFT_WIDTH)/2+TFT_WIDTH-1, (TFT_REALHEIGHT-TFT_HEIGHT)/2+TFT_HEIGHT-1); 943 digitalWrite(_dc, 0); 944 SPI.transfer(TFT_RAMWR); 945 digitalWrite(_dc, 1); 946 dmatx.enable(); 947 } 948 } 949 950 951 void T4_DSP::stopRefresh(void) { 952 if (gfxmode < MODE_VGA_320x240) { 953 rstop = 1; 954 unsigned long m = millis(); 955 cancelled = true; 956 while (!rstop) { 957 if ((millis() - m) > 100) break; 958 delay(10); 959 asm volatile("wfi"); 960 }; 961 rstop = 0; 962 delay(50); 963 cancelled = false; 964 dmatx.detachInterrupt(); 965 fillScreen(RGBVAL16(0x00,0x00,0x00)); 966 SPI.end(); 967 #ifdef ST7789 968 // begin(gfxmode); 969 #endif 970 setArea(0, 0, TFT_REALWIDTH-1, TFT_REALHEIGHT-1); 971 } 972 } 973 974 int T4_DSP::get_frame_buffer_size(int *width, int *height) { 975 if (gfxmode < MODE_VGA_320x240) { 976 if (width != nullptr) *width = tft_width; 977 if (height != nullptr) *height = tft_height; 978 return tft_stride; 979 } 980 else { 981 if (width != nullptr) *width = vga_width; 982 if (height != nullptr) *height = vga_height; 983 return vga_stride; 984 } 985 } 986 987 void T4_DSP::waitSync() 988 { 989 if (gfxmode >= MODE_VGA_320x240) { 990 while (VSYNC == 0) {}; 991 } 992 } 993 994 void T4_DSP::waitLine(int line) 995 { 996 if (gfxmode >= MODE_VGA_320x240) { 997 while (currentLine != line) {}; 998 } 999 } 1000 1001 /*********************************************************************************************** 1002 No DMA functions 1003 ***********************************************************************************************/ 1004 void T4_DSP::fillScreenNoDma(uint16_t color) { 1005 if (gfxmode < MODE_VGA_320x240) { 1006 SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); 1007 digitalWrite(_cs, 0); 1008 setArea(0, 0, TFT_REALWIDTH-1, TFT_REALHEIGHT-1); 1009 int i,j; 1010 for (j=0; j<TFT_REALHEIGHT; j++) 1011 { 1012 for (i=0; i<TFT_REALWIDTH; i++) { 1013 //digitalWrite(_dc, 1); 1014 SPI.transfer16(color); 1015 } 1016 } 1017 digitalWrite(_cs, 1); 1018 setArea(0, 0, (TFT_REALWIDTH-1), (TFT_REALHEIGHT-1)); 1019 SPI.endTransaction(); 1020 } 1021 else { 1022 fillScreen(color); 1023 } 1024 1025 } 1026 1027 void T4_DSP::drawRectNoDma(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color) { 1028 if (gfxmode < MODE_VGA_320x240) { 1029 SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); 1030 digitalWrite(_cs, 0); 1031 setArea(x,y,x+w-1,y+h-1); 1032 int i; 1033 for (i=0; i<(w*h); i++) 1034 { 1035 SPI.transfer16(color); 1036 } 1037 digitalWrite(_cs, 1); 1038 setArea(0, 0, (TFT_REALWIDTH-1), (TFT_REALHEIGHT-1)); 1039 SPI.endTransaction(); 1040 } 1041 else { 1042 drawRect(x, y, w, h, color); 1043 } 1044 } 1045 1046 1047 void T4_DSP::drawSpriteNoDma(int16_t x, int16_t y, const uint16_t *bitmap) { 1048 drawSpriteNoDma(x,y,bitmap, 0,0,0,0); 1049 } 1050 1051 void T4_DSP::drawSpriteNoDma(int16_t x, int16_t y, const uint16_t *bitmap, uint16_t arx, uint16_t ary, uint16_t arw, uint16_t arh) 1052 { 1053 if (gfxmode < MODE_VGA_320x240) { 1054 int bmp_offx = 0; 1055 int bmp_offy = 0; 1056 uint16_t *bmp_ptr; 1057 int w =*bitmap++; 1058 int h = *bitmap++; 1059 if ( (arw == 0) || (arh == 0) ) { 1060 // no crop window 1061 arx = x; 1062 ary = y; 1063 arw = w; 1064 arh = h; 1065 } 1066 else { 1067 if ( (x>(arx+arw)) || ((x+w)<arx) || (y>(ary+arh)) || ((y+h)<ary) ) { 1068 return; 1069 } 1070 // crop area 1071 if ( (x > arx) && (x<(arx+arw)) ) { 1072 arw = arw - (x-arx); 1073 arx = arx + (x-arx); 1074 } else { 1075 bmp_offx = arx; 1076 } 1077 if ( ((x+w) > arx) && ((x+w)<(arx+arw)) ) { 1078 arw -= (arx+arw-x-w); 1079 } 1080 if ( (y > ary) && (y<(ary+arh)) ) { 1081 arh = arh - (y-ary); 1082 ary = ary + (y-ary); 1083 } else { 1084 bmp_offy = ary; 1085 } 1086 if ( ((y+h) > ary) && ((y+h)<(ary+arh)) ) { 1087 arh -= (ary+arh-y-h); 1088 } 1089 } 1090 SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); 1091 digitalWrite(_cs, 0); 1092 setArea(arx, ary, arx+arw-1, ary+arh-1); 1093 bitmap = bitmap + bmp_offy*w + bmp_offx; 1094 for (int row=0;row<arh; row++) 1095 { 1096 bmp_ptr = (uint16_t*)bitmap; 1097 for (int col=0;col<arw; col++) 1098 { 1099 uint16_t color = *bmp_ptr++; 1100 SPI.transfer16(color); 1101 } 1102 bitmap += w; 1103 } 1104 setArea(0, 0, TFT_REALWIDTH-1, TFT_REALHEIGHT-1); 1105 digitalWrite(_cs, 1); 1106 SPI.endTransaction(); 1107 } 1108 else { 1109 drawSprite(x, y, bitmap, arx, ary, arw, arh); 1110 } 1111 } 1112 1113 void T4_DSP::drawTextNoDma(int16_t x, int16_t y, const char * text, uint16_t fgcolor, uint16_t bgcolor, bool doublesize) { 1114 if (gfxmode < MODE_VGA_320x240) { 1115 uint16_t c; 1116 while ((c = *text++)) { 1117 const unsigned char * charpt=&font8x8[c][0]; 1118 SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); 1119 digitalWrite(_cs, 0); 1120 setArea(x,y,x+7,y+(doublesize?15:7)); 1121 for (int i=0;i<8;i++) 1122 { 1123 unsigned char bits; 1124 if (doublesize) { 1125 bits = *charpt; 1126 //digitalWrite(_dc, 1); 1127 if (bits&0x01) SPI.transfer16(fgcolor); 1128 else SPI.transfer16(bgcolor); 1129 bits = bits >> 1; 1130 if (bits&0x01) SPI.transfer16(fgcolor); 1131 else SPI.transfer16(bgcolor); 1132 bits = bits >> 1; 1133 if (bits&0x01) SPI.transfer16(fgcolor); 1134 else SPI.transfer16(bgcolor); 1135 bits = bits >> 1; 1136 if (bits&0x01) SPI.transfer16(fgcolor); 1137 else SPI.transfer16(bgcolor); 1138 bits = bits >> 1; 1139 if (bits&0x01) SPI.transfer16(fgcolor); 1140 else SPI.transfer16(bgcolor); 1141 bits = bits >> 1; 1142 if (bits&0x01) SPI.transfer16(fgcolor); 1143 else SPI.transfer16(bgcolor); 1144 bits = bits >> 1; 1145 if (bits&0x01) SPI.transfer16(fgcolor); 1146 else SPI.transfer16(bgcolor); 1147 bits = bits >> 1; 1148 if (bits&0x01) SPI.transfer16(fgcolor); 1149 else SPI.transfer16(bgcolor); 1150 } 1151 bits = *charpt++; 1152 //digitalWrite(_dc, 1); 1153 if (bits&0x01) SPI.transfer16(fgcolor); 1154 else SPI.transfer16(bgcolor); 1155 bits = bits >> 1; 1156 if (bits&0x01) SPI.transfer16(fgcolor); 1157 else SPI.transfer16(bgcolor); 1158 bits = bits >> 1; 1159 if (bits&0x01) SPI.transfer16(fgcolor); 1160 else SPI.transfer16(bgcolor); 1161 bits = bits >> 1; 1162 if (bits&0x01) SPI.transfer16(fgcolor); 1163 else SPI.transfer16(bgcolor); 1164 bits = bits >> 1; 1165 if (bits&0x01) SPI.transfer16(fgcolor); 1166 else SPI.transfer16(bgcolor); 1167 bits = bits >> 1; 1168 if (bits&0x01) SPI.transfer16(fgcolor); 1169 else SPI.transfer16(bgcolor); 1170 bits = bits >> 1; 1171 if (bits&0x01) SPI.transfer16(fgcolor); 1172 else SPI.transfer16(bgcolor); 1173 bits = bits >> 1; 1174 if (bits&0x01) SPI.transfer16(fgcolor); 1175 else SPI.transfer16(bgcolor); 1176 } 1177 x +=8; 1178 digitalWrite(_cs, 1); 1179 SPI.endTransaction(); 1180 } 1181 SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); 1182 digitalWrite(_cs, 0); 1183 setArea(0, 0, (TFT_REALWIDTH-1), (TFT_REALHEIGHT-1)); 1184 digitalWrite(_cs, 1); 1185 SPI.endTransaction(); 1186 } 1187 else { 1188 drawText(x, y, text, fgcolor, bgcolor, doublesize); 1189 } 1190 } 1191 1192 1193 /*********************************************************************************************** 1194 DMA functions 1195 ***********************************************************************************************/ 1196 void T4_DSP::fillScreen(uint16_t color) { 1197 int i,j; 1198 if (gfxmode < MODE_VGA_320x240) { 1199 for (j=0; j<tft_height; j++) 1200 { 1201 uint16_t * dst=&tft_buffer[j*tft_stride]; 1202 for (i=0; i<tft_width; i++) 1203 { 1204 *dst++ = color; 1205 } 1206 } 1207 } 1208 else { 1209 vga_pixel color8 = VGA_RGB(R16(color),G16(color),B16(color)); 1210 for (j=0; j<vga_height; j++) 1211 { 1212 vga_pixel * dst=&vga_buffer[j*vga_stride]; 1213 for (i=0; i<vga_width; i++) 1214 { 1215 *dst++ = color8; 1216 } 1217 } 1218 } 1219 } 1220 1221 void T4_DSP::drawRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color) { 1222 int i,j,l=y; 1223 if (gfxmode < MODE_VGA_320x240) { 1224 for (j=0; j<h; j++) 1225 { 1226 uint16_t * dst=&tft_buffer[l*tft_stride+x]; 1227 for (i=0; i<w; i++) 1228 { 1229 *dst++ = color; 1230 } 1231 l++; 1232 } 1233 } 1234 else { 1235 vga_pixel color8 = VGA_RGB(R16(color),G16(color),B16(color)); 1236 for (j=0; j<h; j++) 1237 { 1238 vga_pixel * dst=&vga_buffer[l*vga_stride+x]; 1239 for (i=0; i<w; i++) 1240 { 1241 *dst++ = color8; 1242 } 1243 l++; 1244 } 1245 } 1246 } 1247 1248 void T4_DSP::drawText(int16_t x, int16_t y, const char * text, uint16_t fgcolor, uint16_t bgcolor, bool doublesize) { 1249 uint16_t c; 1250 if (gfxmode < MODE_VGA_320x240) { 1251 uint16_t * dst; 1252 while ((c = *text++)) { 1253 const unsigned char * charpt=&font8x8[c][0]; 1254 int l=y; 1255 for (int i=0;i<8;i++) 1256 { 1257 unsigned char bits; 1258 if (doublesize) { 1259 dst=&tft_buffer[l*tft_stride+x]; 1260 bits = *charpt; 1261 if (bits&0x01) *dst++=fgcolor; 1262 else *dst++=bgcolor; 1263 bits = bits >> 1; 1264 if (bits&0x01) *dst++=fgcolor; 1265 else *dst++=bgcolor; 1266 bits = bits >> 1; 1267 if (bits&0x01) *dst++=fgcolor; 1268 else *dst++=bgcolor; 1269 bits = bits >> 1; 1270 if (bits&0x01) *dst++=fgcolor; 1271 else *dst++=bgcolor; 1272 bits = bits >> 1; 1273 if (bits&0x01) *dst++=fgcolor; 1274 else *dst++=bgcolor; 1275 bits = bits >> 1; 1276 if (bits&0x01) *dst++=fgcolor; 1277 else *dst++=bgcolor; 1278 bits = bits >> 1; 1279 if (bits&0x01) *dst++=fgcolor; 1280 else *dst++=bgcolor; 1281 bits = bits >> 1; 1282 if (bits&0x01) *dst++=fgcolor; 1283 else *dst++=bgcolor; 1284 l++; 1285 } 1286 dst=&tft_buffer[l*tft_stride+x]; 1287 bits = *charpt++; 1288 if (bits&0x01) *dst++=fgcolor; 1289 else *dst++=bgcolor; 1290 bits = bits >> 1; 1291 if (bits&0x01) *dst++=fgcolor; 1292 else *dst++=bgcolor; 1293 bits = bits >> 1; 1294 if (bits&0x01) *dst++=fgcolor; 1295 else *dst++=bgcolor; 1296 bits = bits >> 1; 1297 if (bits&0x01) *dst++=fgcolor; 1298 else *dst++=bgcolor; 1299 bits = bits >> 1; 1300 if (bits&0x01) *dst++=fgcolor; 1301 else *dst++=bgcolor; 1302 bits = bits >> 1; 1303 if (bits&0x01) *dst++=fgcolor; 1304 else *dst++=bgcolor; 1305 bits = bits >> 1; 1306 if (bits&0x01) *dst++=fgcolor; 1307 else *dst++=bgcolor; 1308 bits = bits >> 1; 1309 if (bits&0x01) *dst++=fgcolor; 1310 else *dst++=bgcolor; 1311 l++; 1312 } 1313 x +=8; 1314 } 1315 } 1316 else { 1317 vga_pixel fgcolor8 = VGA_RGB(R16(fgcolor),G16(fgcolor),B16(fgcolor)); 1318 vga_pixel bgcolor8 = VGA_RGB(R16(bgcolor),G16(bgcolor),B16(bgcolor)); 1319 vga_pixel * dst; 1320 while ((c = *text++)) { 1321 const unsigned char * charpt=&font8x8[c][0]; 1322 int l=y; 1323 for (int i=0;i<8;i++) 1324 { 1325 unsigned char bits; 1326 if (doublesize) { 1327 dst=&vga_buffer[l*vga_stride+x]; 1328 bits = *charpt; 1329 if (bits&0x01) *dst++=fgcolor8; 1330 else *dst++=bgcolor8; 1331 bits = bits >> 1; 1332 if (bits&0x01) *dst++=fgcolor8; 1333 else *dst++=bgcolor8; 1334 bits = bits >> 1; 1335 if (bits&0x01) *dst++=fgcolor8; 1336 else *dst++=bgcolor8; 1337 bits = bits >> 1; 1338 if (bits&0x01) *dst++=fgcolor8; 1339 else *dst++=bgcolor8; 1340 bits = bits >> 1; 1341 if (bits&0x01) *dst++=fgcolor8; 1342 else *dst++=bgcolor8; 1343 bits = bits >> 1; 1344 if (bits&0x01) *dst++=fgcolor8; 1345 else *dst++=bgcolor8; 1346 bits = bits >> 1; 1347 if (bits&0x01) *dst++=fgcolor8; 1348 else *dst++=bgcolor8; 1349 bits = bits >> 1; 1350 if (bits&0x01) *dst++=fgcolor8; 1351 else *dst++=bgcolor8; 1352 l++; 1353 } 1354 dst=&vga_buffer[l*vga_stride+x]; 1355 bits = *charpt++; 1356 if (bits&0x01) *dst++=fgcolor8; 1357 else *dst++=bgcolor8; 1358 bits = bits >> 1; 1359 if (bits&0x01) *dst++=fgcolor8; 1360 else *dst++=bgcolor8; 1361 bits = bits >> 1; 1362 if (bits&0x01) *dst++=fgcolor8; 1363 else *dst++=bgcolor8; 1364 bits = bits >> 1; 1365 if (bits&0x01) *dst++=fgcolor8; 1366 else *dst++=bgcolor8; 1367 bits = bits >> 1; 1368 if (bits&0x01) *dst++=fgcolor8; 1369 else *dst++=bgcolor8; 1370 bits = bits >> 1; 1371 if (bits&0x01) *dst++=fgcolor8; 1372 else *dst++=bgcolor8; 1373 bits = bits >> 1; 1374 if (bits&0x01) *dst++=fgcolor8; 1375 else *dst++=bgcolor8; 1376 bits = bits >> 1; 1377 if (bits&0x01) *dst++=fgcolor8; 1378 else *dst++=bgcolor8; 1379 l++; 1380 } 1381 x +=8; 1382 } 1383 } 1384 } 1385 1386 void T4_DSP::drawSprite(int16_t x, int16_t y, const uint16_t *bitmap) { 1387 drawSprite(x,y,bitmap, 0,0,0,0); 1388 } 1389 1390 void T4_DSP::drawSprite(int16_t x, int16_t y, const uint16_t *bitmap, uint16_t arx, uint16_t ary, uint16_t arw, uint16_t arh) 1391 { 1392 int bmp_offx = 0; 1393 int bmp_offy = 0; 1394 uint16_t *bmp_ptr; 1395 int w =*bitmap++; 1396 int h = *bitmap++; 1397 if ( (arw == 0) || (arh == 0) ) { 1398 // no crop window 1399 arx = x; 1400 ary = y; 1401 arw = w; 1402 arh = h; 1403 } 1404 else { 1405 if ( (x>(arx+arw)) || ((x+w)<arx) || (y>(ary+arh)) || ((y+h)<ary) ) { 1406 return; 1407 } 1408 1409 // crop area 1410 if ( (x > arx) && (x<(arx+arw)) ) { 1411 arw = arw - (x-arx); 1412 arx = arx + (x-arx); 1413 } else { 1414 bmp_offx = arx; 1415 } 1416 if ( ((x+w) > arx) && ((x+w)<(arx+arw)) ) { 1417 arw -= (arx+arw-x-w); 1418 } 1419 if ( (y > ary) && (y<(ary+arh)) ) { 1420 arh = arh - (y-ary); 1421 ary = ary + (y-ary); 1422 } else { 1423 bmp_offy = ary; 1424 } 1425 if ( ((y+h) > ary) && ((y+h)<(ary+arh)) ) { 1426 arh -= (ary+arh-y-h); 1427 } 1428 } 1429 int l=ary; 1430 bitmap = bitmap + bmp_offy*w + bmp_offx; 1431 1432 if (gfxmode < MODE_VGA_320x240) { 1433 for (int row=0;row<arh; row++) 1434 { 1435 uint16_t * dst=&tft_buffer[l*tft_stride+arx]; 1436 bmp_ptr = (uint16_t*)bitmap; 1437 for (int col=0;col<arw; col++) 1438 { 1439 *dst++ = *bmp_ptr++; 1440 } 1441 bitmap += w; 1442 l++; 1443 } 1444 } 1445 else { 1446 for (int row=0;row<arh; row++) 1447 { 1448 vga_pixel * dst=&vga_buffer[l*vga_stride+arx]; 1449 bmp_ptr = (uint16_t*)bitmap; 1450 for (int col=0;col<arw; col++) 1451 { 1452 uint16_t pix= *bmp_ptr++; 1453 *dst++ = VGA_RGB(R16(pix),G16(pix),B16(pix)); 1454 } 1455 bitmap += w; 1456 l++; 1457 } 1458 } 1459 } 1460 1461 void T4_DSP::writeLine(int width, int height, int y, uint16_t *buf) { 1462 if (gfxmode < MODE_VGA_320x240) { 1463 uint16_t * dst=&tft_buffer[y*tft_stride]; 1464 if (width > tft_width) { 1465 #ifdef TFT_LINEARINT 1466 int delta = (width/(width-tft_width))-1; 1467 int pos = delta; 1468 for (int i=0; i<tft_width; i++) 1469 { 1470 uint16_t val = *buf++; 1471 pos--; 1472 if (pos == 0) { 1473 #ifdef LINEARINT_HACK 1474 val = ((uint32_t)*buf++ + val)/2; 1475 #else 1476 uint16_t val2 = *buf++; 1477 val = RGBVAL16((R16(val)+R16(val2))/2,(G16(val)+G16(val2))/2,(B16(val)+B16(val2))/2); 1478 #endif 1479 pos = delta; 1480 } 1481 *dst++=val; 1482 } 1483 #else 1484 int step = ((width << 8)/tft_width); 1485 int pos = 0; 1486 for (int i=0; i<tft_width; i++) 1487 { 1488 *dst++=buf[pos >> 8]; 1489 pos +=step; 1490 } 1491 #endif 1492 } 1493 else if ((width*2) == tft_width) 1494 { 1495 for (int i=0; i<width; i++) 1496 { 1497 *dst++=*buf; 1498 *dst++=*buf++; 1499 } 1500 } 1501 else 1502 { 1503 if (width <= tft_width) { 1504 dst += (tft_width-width)/2; 1505 } 1506 for (int i=0; i<width; i++) 1507 { 1508 *dst++=*buf++; 1509 } 1510 } 1511 } 1512 else { 1513 if ( (height<vga_height) && (height > 2) ) y += (vga_height-height)/2; 1514 vga_pixel * dst=&vga_buffer[y*vga_stride]; 1515 if (width > vga_width) { 1516 int step = ((width << 8)/vga_width); 1517 int pos = 0; 1518 for (int i=0; i<vga_width; i++) 1519 { 1520 uint16_t pix = buf[pos >> 8]; 1521 *dst++ = VGA_RGB(R16(pix),G16(pix),B16(pix)); 1522 pos +=step; 1523 } 1524 } 1525 else if ((width*2) == vga_width) { 1526 for (int i=0; i<width; i++) 1527 { 1528 uint16_t pix = *buf++; 1529 vga_pixel col = VGA_RGB(R16(pix),G16(pix),B16(pix)); 1530 *dst++= col; 1531 *dst++= col; 1532 } 1533 } 1534 else { 1535 if (width <= vga_width) { 1536 dst += (vga_width-width)/2; 1537 } 1538 for (int i=0; i<width; i++) 1539 { 1540 uint16_t pix = *buf++; 1541 *dst++= VGA_RGB(R16(pix),G16(pix),B16(pix)); 1542 } 1543 } 1544 } 1545 } 1546 1547 void T4_DSP::writeLinePal(int width, int height, int y, uint8_t *buf, uint16_t *palette) { 1548 if (gfxmode < MODE_VGA_320x240) { 1549 if ( (height<tft_height) && (height > 2) ) y += (tft_height-height)/2; 1550 uint16_t * dst=&tft_buffer[y*tft_stride]; 1551 if (width > tft_width) { 1552 #ifdef TFT_LINEARINT 1553 int delta = (width/(width-tft_width))-1; 1554 int pos = delta; 1555 for (int i=0; i<tft_width; i++) 1556 { 1557 uint16_t val = palette[*buf++]; 1558 pos--; 1559 if (pos == 0) { 1560 #ifdef LINEARINT_HACK 1561 val = ((uint32_t)palette[*buf++] + val)/2; 1562 #else 1563 uint16_t val2 = *buf++; 1564 val = RGBVAL16((R16(val)+R16(val2))/2,(G16(val)+G16(val2))/2,(B16(val)+B16(val2))/2); 1565 #endif 1566 pos = delta; 1567 } 1568 *dst++=val; 1569 } 1570 #else 1571 int step = ((width << 8)/tft_width); 1572 int pos = 0; 1573 for (int i=0; i<tft_width; i++) 1574 { 1575 *dst++=palette[buf[pos >> 8]]; 1576 pos +=step; 1577 } 1578 #endif 1579 } 1580 else if ((width*2) == tft_width) { 1581 for (int i=0; i<width; i++) 1582 { 1583 *dst++=palette[*buf]; 1584 *dst++=palette[*buf++]; 1585 } 1586 } 1587 else { 1588 if (width <= tft_width) { 1589 dst += (tft_width-width)/2; 1590 } 1591 for (int i=0; i<width; i++) 1592 { 1593 *dst++=palette[*buf++]; 1594 } 1595 } 1596 } 1597 else { 1598 if ( (height<vga_height) && (height > 2) ) y += (vga_height-height)/2; 1599 vga_pixel * dst=&vga_buffer[y*vga_stride]; 1600 if (width > vga_width) { 1601 int step = ((width << 8)/vga_width); 1602 int pos = 0; 1603 for (int i=0; i<vga_width; i++) 1604 { 1605 uint16_t pix = palette[buf[pos >> 8]]; 1606 *dst++= VGA_RGB(R16(pix),G16(pix),B16(pix)); 1607 pos +=step; 1608 } 1609 } 1610 else if ((width*2) == vga_width) { 1611 for (int i=0; i<width; i++) 1612 { 1613 uint16_t pix = palette[*buf++]; 1614 *dst++= VGA_RGB(R16(pix),G16(pix),B16(pix)); 1615 *dst++= VGA_RGB(R16(pix),G16(pix),B16(pix)); 1616 } 1617 } 1618 else { 1619 if (width <= vga_width) { 1620 dst += (vga_width-width)/2; 1621 } 1622 for (int i=0; i<width; i++) 1623 { 1624 uint16_t pix = palette[*buf++]; 1625 *dst++= VGA_RGB(R16(pix),G16(pix),B16(pix)); 1626 } 1627 } 1628 } 1629 } 1630 1631 void T4_DSP::writeScreenPal(int width, int height, int stride, uint8_t *buf, uint16_t *palette16) { 1632 uint8_t *src; 1633 int i,j,y=0; 1634 int sy = 0; 1635 int systep=(1<<8); 1636 int h = height; 1637 1638 if (gfxmode < MODE_VGA_320x240) { 1639 if (height <= ( (2*tft_height)/3)) { 1640 systep=(systep*height)/tft_height; 1641 h = tft_height; 1642 } 1643 if (width*2 <= tft_width) { 1644 for (j=0; j<h; j++) 1645 { 1646 uint16_t * dst=&tft_buffer[y*tft_stride]; 1647 src=&buf[(sy>>8)*stride]; 1648 for (i=0; i<width; i++) 1649 { 1650 uint16_t val = palette16[*src++]; 1651 *dst++ = val; 1652 *dst++ = val; 1653 } 1654 y++; 1655 sy+=systep; 1656 } 1657 } 1658 else if (width <= tft_width) { 1659 for (j=0; j<h; j++) 1660 { 1661 uint16_t * dst=&tft_buffer[y*tft_stride+(tft_width-width)/2]; 1662 src=&buf[(sy>>8)*stride]; 1663 for (i=0; i<width; i++) 1664 { 1665 uint16_t val = palette16[*src++]; 1666 *dst++ = val; 1667 } 1668 y++; 1669 sy+=systep; 1670 } 1671 } 1672 } 1673 else { // VGA 1674 if (height <= ( (2*vga_height)/3)) { 1675 systep=(systep*height)/vga_height; 1676 h = vga_height; 1677 } 1678 if (width*2 <= vga_width) { 1679 for (j=0; j<h; j++) 1680 { 1681 vga_pixel * dst=&vga_buffer[y*vga_stride]; 1682 src=&buf[(sy>>8)*stride]; 1683 for (i=0; i<width; i++) 1684 { 1685 uint16_t pix = palette16[*src++]; 1686 *dst++ = VGA_RGB(R16(pix),G16(pix),B16(pix)); 1687 *dst++ = VGA_RGB(R16(pix),G16(pix),B16(pix)); 1688 } 1689 y++; 1690 sy+=systep; 1691 } 1692 } 1693 else if (width <= vga_width) { 1694 for (j=0; j<h; j++) 1695 { 1696 vga_pixel * dst=&vga_buffer[y*vga_stride+(vga_width-width)/2]; 1697 src=&buf[(sy>>8)*stride]; 1698 for (i=0; i<width; i++) 1699 { 1700 uint16_t pix = palette16[*src++]; 1701 *dst++ = VGA_RGB(R16(pix),G16(pix),B16(pix)); 1702 } 1703 y++; 1704 sy+=systep; 1705 } 1706 } 1707 } 1708 } 1709 1710 1711 void T4_DSP::writeLine8(int width, int height, int y, uint8_t *buf, uint16_t *palette) { 1712 if (gfxmode < MODE_VGA_320x240) { 1713 uint16_t * dst=&tft_buffer[y*tft_stride]; 1714 if (width > tft_width) { 1715 int step = ((width << 8)/tft_width); 1716 int pos = 0; 1717 for (int i=0; i<tft_width; i++) 1718 { 1719 *dst++=palette[buf[pos >> 8]]; 1720 pos +=step; 1721 } 1722 } 1723 else if ((width*2) == tft_width) 1724 { 1725 for (int i=0; i<width; i++) 1726 { 1727 uint16_t val = palette[*buf++]; 1728 *dst++=val; 1729 *dst++=val; 1730 } 1731 } 1732 else 1733 { 1734 if (width <= tft_width) { 1735 dst += (tft_width-width)/2; 1736 } 1737 for (int i=0; i<width; i++) 1738 { 1739 *dst++=palette[*buf++]; 1740 } 1741 } 1742 } 1743 else { 1744 if ( (height<vga_height) && (height > 2) ) y += (vga_height-height)/2; 1745 vga_pixel * dst=&vga_buffer[y*vga_stride]; 1746 if (width > vga_width) { 1747 int step = ((width << 8)/vga_width); 1748 int pos = 0; 1749 for (int i=0; i<vga_width; i++) 1750 { 1751 uint8_t pix = buf[pos >> 8]; 1752 *dst++ = pix; 1753 pos +=step; 1754 } 1755 } 1756 else if ((width*2) == vga_width) { 1757 for (int i=0; i<width; i++) 1758 { 1759 vga_pixel col = *buf++; 1760 *dst++= col; 1761 *dst++= col; 1762 } 1763 } 1764 else { 1765 if (width <= vga_width) { 1766 dst += (vga_width-width)/2; 1767 } 1768 for (int i=0; i<width; i++) 1769 { 1770 *dst++= *buf++; 1771 } 1772 } 1773 } 1774 }