/ MCUME_teensy41 / teensy64 / t4_dsp.cpp
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  }