/ MCUME_teensy41 / teensydoom / tft_t_dma.cpp
tft_t_dma.cpp
   1  /*
   2    Based on C64 ILI9341 dma driver from Frank Bösing, 2017
   3  */
   4  
   5  #include "TFT_T_DMA.h"
   6  
   7  #ifndef HAS_T4_VGA
   8  
   9  #include "font8x8.h"
  10  
  11  // LPSPI4 = SPI0 in Teensy 4.0
  12  // LPSPI3 = SPI1 in Teensy 4.0
  13  // LPSPI1 = SPI2 in Teensy 4.0 (used for SD on T4.0 but not T4.1) 
  14  #ifdef TFTSPI1
  15  #define SPI SPI1
  16  #define LPSPIP_TDR LPSPI3_TDR
  17  #define LPSPIP_CR LPSPI3_CR
  18  #define LPSPIP_CFGR1 LPSPI3_CFGR1
  19  #define LPSPIP_TCR LPSPI3_TCR
  20  #define LPSPIP_DER LPSPI3_DER
  21  #define DMAMUX_SOURCE_LPSPIP_TX DMAMUX_SOURCE_LPSPI3_TX
  22  #else
  23  #define LPSPIP_TDR LPSPI4_TDR
  24  #define LPSPIP_CR LPSPI4_CR
  25  #define LPSPIP_CFGR1 LPSPI4_CFGR1
  26  #define LPSPIP_TCR LPSPI4_TCR
  27  #define LPSPIP_DER LPSPI4_DER
  28  #define DMAMUX_SOURCE_LPSPIP_TX DMAMUX_SOURCE_LPSPI4_TX
  29  #endif
  30  
  31  
  32  #define SPICLOCK 60000000 //144e6 //Just a number..max speed
  33  #ifdef ILI9341
  34  #define SPI_MODE SPI_MODE0
  35  #endif
  36  #ifdef ST7789
  37  #define SPI_MODE SPI_MODE2
  38  #endif
  39  
  40  // touch
  41  #define SPI_SETTING         SPISettings(2500000, MSBFIRST, SPI_MODE)
  42  #define XPT2046_CFG_START   _BV(7)
  43  #define XPT2046_CFG_MUX(v)  ((v&0b111) << (4))
  44  #define XPT2046_CFG_8BIT    _BV(3)
  45  #define XPT2046_CFG_12BIT   (0)
  46  #define XPT2046_CFG_SER     _BV(2)
  47  #define XPT2046_CFG_DFR     (0)
  48  #define XPT2046_CFG_PWR(v)  ((v&0b11))
  49  #define XPT2046_MUX_Y       0b101
  50  #define XPT2046_MUX_X       0b001
  51  #define XPT2046_MUX_Z1      0b011
  52  #define XPT2046_MUX_Z2      0b100
  53  
  54  
  55  #ifdef TFT_STATICFB
  56  static uint16_t fb0[LINES_PER_BLOCK*TFT_WIDTH];
  57  static uint16_t fb1[LINES_PER_BLOCK*TFT_WIDTH];
  58  static uint16_t fb2[LINES_PER_BLOCK*TFT_WIDTH];
  59  static uint16_t fb3[(TFT_HEIGHT-3*LINES_PER_BLOCK)*TFT_WIDTH];
  60  static uint16_t * blocks[NR_OF_BLOCK]={fb0,fb1,fb2,fb3};
  61  #else
  62  static uint16_t * blocks[NR_OF_BLOCK];
  63  #endif
  64  
  65  
  66  static DMASetting dmasettings[SCREEN_DMA_NUM_SETTINGS];
  67  static DMAChannel dmatx;//(false);
  68  static volatile uint8_t rstop = 0;
  69  static volatile bool cancelled = false;
  70  static volatile uint8_t curTransfer = 0;
  71  static uint8_t nbTransfer = 0;
  72  
  73  
  74  PROGMEM static const uint8_t init_commands[] = {
  75  #ifdef ILI9341  
  76    4, 0xEF, 0x03, 0x80, 0x02,
  77    4, 0xCF, 0x00, 0XC1, 0X30,
  78    5, 0xED, 0x64, 0x03, 0X12, 0X81,
  79    4, 0xE8, 0x85, 0x00, 0x78,
  80    6, 0xCB, 0x39, 0x2C, 0x00, 0x34, 0x02,
  81    2, 0xF7, 0x20,
  82    3, 0xEA, 0x00, 0x00,
  83    2, ILI9341_PWCTR1, 0x23, // Power control
  84    2, ILI9341_PWCTR2, 0x10, // Power control
  85    3, ILI9341_VMCTR1, 0x3e, 0x28, // VCM control
  86    2, ILI9341_VMCTR2, 0x86, // VCM control2
  87    2, ILI9341_MADCTL, 0x48, // Memory Access Control
  88    2, ILI9341_PIXFMT, 0x55,
  89    3, ILI9341_FRMCTR1, 0x00, 0x18,
  90    4, ILI9341_DFUNCTR, 0x08, 0x82, 0x27, // Display Function Control
  91    2, 0xF2, 0x00, // Gamma Function Disable
  92    2, ILI9341_GAMMASET, 0x01, // Gamma curve selected
  93    16, ILI9341_GMCTRP1, 0x0F, 0x31, 0x2B, 0x0C, 0x0E, 0x08,
  94    0x4E, 0xF1, 0x37, 0x07, 0x10, 0x03, 0x0E, 0x09, 0x00, // Set Gamma
  95    16, ILI9341_GMCTRN1, 0x00, 0x0E, 0x14, 0x03, 0x11, 0x07,
  96    0x31, 0xC1, 0x48, 0x08, 0x0F, 0x0C, 0x31, 0x36, 0x0F, // Set Gamma
  97  //  3, 0xb1, 0x00, 0x1f, // FrameRate Control 61Hz
  98    3, 0xb1, 0x00, 0x10, // FrameRate Control 119Hz
  99    2, ILI9341_MADCTL, ILI9341_MADCTL_MX | ILI9341_MADCTL_MY | ILI9341_MADCTL_MV | ILI9341_MADCTL_BGR,
 100    0
 101  #endif
 102  #ifdef ST7789
 103  #define DELAY 0x80
 104      9,                       // 9 commands in list:
 105      ST7735_SWRESET,   DELAY,  //  1: Software reset, no args, w/delay
 106        150,                     //    150 ms delay
 107      ST7735_SLPOUT ,   DELAY,  //  2: Out of sleep mode, no args, w/delay
 108        255,                    //     255 = 500 ms delay
 109      ST7735_COLMOD , 1+DELAY,  //  3: Set color mode, 1 arg + delay:
 110        0x55,                   //     16-bit color
 111        10,                     //     10 ms delay
 112      ST7735_MADCTL , 1      ,  //  4: Memory access ctrl (directions), 1 arg:
 113        0x08,                   //     Row addr/col addr, bottom to top refresh
 114      ST7735_CASET  , 4      ,  //  5: Column addr set, 4 args, no delay:
 115        0x00, 
 116        0x00,                   //     XSTART = 0
 117        0x00, 
 118        240,                    //      XEND = 240
 119      ST7735_RASET  , 4      ,  // 6: Row addr set, 4 args, no delay:
 120        0x00, 
 121        0x00,                   //     YSTART = 0
 122        320>>8, 
 123        320 & 0xFF,             //      YEND = 320
 124      ST7735_INVON ,   DELAY,   // 7: hack
 125        10,
 126      ST7735_NORON  ,   DELAY,  // 8: Normal display on, no args, w/delay
 127        10,                     //     10 ms delay
 128      ST7735_DISPON ,   DELAY,  // 9: Main screen turn on, no args, w/delay
 129      255
 130  #endif       
 131  };
 132  
 133  static void dmaInterrupt() {
 134    dmatx.clearInterrupt();
 135    curTransfer++;
 136    if (curTransfer >= nbTransfer) {
 137      curTransfer = 0;
 138      if (cancelled) {
 139          dmatx.disable();
 140          rstop = 1;
 141      }
 142    }
 143    arm_dcache_flush(blocks[curTransfer], LINES_PER_BLOCK*TFT_WIDTH*2);  
 144  }
 145  
 146  static void setDmaStruct() {
 147    uint32_t remaining = TFT_HEIGHT*TFT_WIDTH*2;
 148    int i=0;
 149    uint16_t col=RGBVAL16(0x00,0x00,0x00);;
 150    while (remaining > 0) {
 151      uint16_t * fb = blocks[i];
 152      int32_t len = (remaining >= (LINES_PER_BLOCK*TFT_WIDTH*2)?LINES_PER_BLOCK*TFT_WIDTH*2:remaining);
 153  #ifdef TFT_DEBUG        
 154      Serial.println((unsigned long)blocks[i]);    
 155      Serial.println(remaining);
 156  #endif        
 157      switch (i) {
 158        case 0:
 159          if (fb == 0) fb = (uint16_t*)((int)malloc(len+64)&0xffffffe0);
 160          //fb=&fb0[0];
 161  #ifdef TFT_DEBUG        
 162          col = RGBVAL16(0x00,0xff,0x00);
 163  #endif        
 164          break;
 165        case 1:
 166          if (fb == 0) fb = (uint16_t*)((int)malloc(len+64)&0xffffffe0);
 167          //fb=&fb1[0];
 168  #ifdef TFT_DEBUG        
 169          col = RGBVAL16(0x00,0xff,0xff);
 170  #endif        
 171          break;
 172        case 2:
 173          if (fb == 0) fb = (uint16_t*)((int)malloc(len+64)&0xffffffe0);
 174          //fb=&fb2[0];
 175  #ifdef TFT_DEBUG        
 176          col = RGBVAL16(0x00,0x00,0xff);
 177  #endif        
 178          break;
 179        case 3:
 180          if (fb == 0) fb = (uint16_t*)((int)malloc(len+64)&0xffffffe0);
 181          //fb=&fb3[0];
 182  #ifdef TFT_DEBUG        
 183          col = RGBVAL16(0xff,0x00,0xff);
 184  #endif        
 185          break;
 186      }
 187      blocks[i] = fb;
 188      if (blocks[i] == 0) {
 189        Serial.print("ILI9341 allocaltion failed for block ");
 190        Serial.println(i);
 191        delay(10000);    
 192      }
 193         
 194      for (int j=0;j<len/2;j++) fb[j]=col;
 195  
 196      dmasettings[i].sourceBuffer(fb, len);
 197      dmasettings[i].destination((uint8_t &)  LPSPIP_TDR);
 198      dmasettings[i].TCD->ATTR_DST = 1;
 199      dmasettings[i].replaceSettingsOnCompletion(dmasettings[i+1]);
 200      dmasettings[i].interruptAtCompletion();
 201      remaining -= len;
 202      i++;
 203    }
 204    dmasettings[i-1].replaceSettingsOnCompletion(dmasettings[0]);
 205    nbTransfer = i;
 206  #ifdef TFT_DEBUG        
 207    Serial.println(nbTransfer);
 208  #endif  
 209  }
 210  
 211  
 212  TFT_T_DMA::TFT_T_DMA(uint8_t cs, uint8_t dc, uint8_t rst, uint8_t mosi, uint8_t sclk, uint8_t miso,  uint8_t touch_cs,  uint8_t touch_irq)
 213  {
 214    _cs   = cs;
 215    _dc   = dc;
 216    _rst  = rst;
 217    _mosi = mosi;
 218    _sclk = sclk;
 219    _miso = miso;
 220    pinMode(_dc, OUTPUT);
 221    pinMode(_cs, OUTPUT); 
 222    digitalWrite(_cs, 1);
 223    digitalWrite(_dc, 1);
 224    if ( (touch_cs != 255) && (touch_irq != 255) ) {
 225      _touch_irq = touch_irq;
 226      _touch_cs = touch_cs;
 227      pinMode(_touch_cs, OUTPUT);
 228      pinMode(touch_irq, INPUT_PULLUP);  
 229      digitalWrite(_touch_cs, 1);    
 230    }
 231  }
 232  
 233  
 234  void TFT_T_DMA::setArea(uint16_t x1,uint16_t y1,uint16_t x2,uint16_t y2) {
 235    int dx=0;
 236    int dy=0;
 237  #ifdef ST7789
 238    if (TFT_REALWIDTH == TFT_REALHEIGHT)
 239    {
 240  #ifdef ROTATE_SCREEN
 241      if (!flipped) {
 242        dy += 80;    
 243      }
 244  #else  
 245      if (flipped) {
 246        dx += 80;    
 247      }
 248  #endif      
 249    }
 250  #endif  
 251  
 252    digitalWrite(_dc, 0);
 253    SPI.transfer(TFT_CASET);
 254    digitalWrite(_dc, 1);
 255    SPI.transfer16(x1+dx);
 256    digitalWrite(_dc, 1);
 257    SPI.transfer16(x2+dx);  
 258    digitalWrite(_dc, 0);
 259    SPI.transfer(TFT_PASET);
 260    digitalWrite(_dc, 1);
 261    SPI.transfer16(y1+dy);
 262    digitalWrite(_dc, 1);
 263    SPI.transfer16(y2+dy);  
 264  
 265    digitalWrite(_dc, 0);
 266    SPI.transfer(TFT_RAMWR);
 267    digitalWrite(_dc, 1);
 268    
 269    return;
 270    
 271  
 272    SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE));
 273    digitalWrite(_cs, 0);
 274  
 275    digitalWrite(_dc, 0);
 276    SPI.transfer(TFT_CASET);
 277    digitalWrite(_dc, 1);
 278  
 279    SPI.transfer16(x1+dx);
 280    SPI.transfer16(x2+dx);
 281  
 282    digitalWrite(_dc, 0);
 283    SPI.transfer(TFT_PASET);
 284    digitalWrite(_dc, 1);
 285    SPI.transfer16(y1+dy);
 286    SPI.transfer16(y2+dy);
 287  
 288    digitalWrite(_dc, 0);
 289    SPI.transfer(TFT_RAMWR);
 290    digitalWrite(_dc, 1);
 291    
 292    digitalWrite(_cs, 1);
 293    SPI.endTransaction();  
 294  }
 295  
 296  
 297  
 298  
 299  void TFT_T_DMA::begin(void) {
 300    SPI.setMOSI(_mosi);
 301    SPI.setMISO(_miso);
 302    SPI.setSCK(_sclk);
 303    SPI.begin();
 304        
 305    // Initialize display
 306    if (_rst != 0xff) {
 307      pinMode(_rst, OUTPUT);
 308      digitalWrite(_rst, HIGH);
 309      delay(100);
 310      digitalWrite(_rst, LOW);
 311      delay(100);
 312      digitalWrite(_rst, HIGH);
 313      delay(200);
 314    }
 315  
 316  
 317    SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE));
 318    const uint8_t *addr = init_commands;
 319    digitalWrite(_cs, 0);
 320  #ifdef ILI9341 
 321    while (1) {
 322      uint8_t count = *addr++;
 323      if (count-- == 0) break;
 324  
 325      digitalWrite(_dc, 0);
 326      SPI.transfer(*addr++);
 327  
 328      while (count-- > 0) {
 329        digitalWrite(_dc, 1);
 330        SPI.transfer(*addr++);
 331      }
 332    }
 333    
 334    digitalWrite(_dc, 0);
 335    SPI.transfer(ILI9341_SLPOUT);
 336    digitalWrite(_dc, 1);
 337    digitalWrite(_cs, 1);
 338    SPI.endTransaction();
 339  
 340    digitalWrite(_dc, 1);
 341    digitalWrite(_cs, 1);
 342    SPI.endTransaction();
 343  
 344    SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE));
 345    digitalWrite(_dc, 0);
 346    digitalWrite(_cs, 0);
 347    SPI.transfer(ILI9341_DISPON);
 348    digitalWrite(_dc, 1);
 349    digitalWrite(_cs, 1);
 350  #endif
 351  #ifdef ST7789 
 352    uint8_t  numCommands, numArgs;
 353    uint16_t ms;
 354    numCommands = *addr++;    // Number of commands to follow
 355    while(numCommands--) {        // For each command...
 356      digitalWrite(_dc, 0);
 357      SPI.transfer(*addr++);    
 358      numArgs  = *addr++; //   Number of args to follow
 359      ms       = numArgs & DELAY;   //   If hibit set, delay follows args
 360      numArgs &= ~DELAY;      //   Mask out delay bit
 361      while(numArgs > 1) {      //   For each argument...
 362        digitalWrite(_dc, 1);
 363        SPI.transfer(*addr++);
 364        numArgs--;
 365      }
 366  
 367      if (numArgs)  {
 368        digitalWrite(_dc, 1);
 369        SPI.transfer(*addr++);
 370      }
 371      if(ms) {
 372        ms = *addr++; // Read post-command delay time (ms)
 373        if(ms == 255) ms = 500;   // If 255, delay for 500 ms
 374        digitalWrite(_cs, 1);
 375        SPI.endTransaction();
 376        delay(ms);
 377        SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE));
 378        digitalWrite(_cs, 0);
 379      }
 380    }
 381    digitalWrite(_cs, 1);
 382  #endif
 383    setArea(0, 0, TFT_REALWIDTH-1, TFT_REALHEIGHT-1);  
 384    SPI.endTransaction();
 385  
 386    cancelled = false;
 387  
 388  #ifdef FLIP_SCREEN          
 389    flipscreen(true);           
 390  #else
 391    flipscreen(false);  
 392  #endif   
 393  #ifdef ST7789 
 394    if (TFT_REALWIDTH != TFT_REALHEIGHT)
 395    {
 396      flipscreen(true);      
 397    }
 398  #endif   
 399  };
 400  
 401  
 402    
 403  void TFT_T_DMA::flipscreen(bool flip)
 404  {
 405    SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE));
 406    digitalWrite(_dc, 0);
 407    digitalWrite(_cs, 0);
 408    SPI.transfer(TFT_MADCTL);
 409    digitalWrite(_dc, 1);
 410    if (flip) {
 411      flipped=true;
 412  #ifdef ILI9341         
 413      SPI.transfer(ILI9341_MADCTL_MV | ILI9341_MADCTL_BGR);
 414  #endif
 415  #ifdef ST7789
 416  #ifdef ROTATE_SCREEN
 417      SPI.transfer(ST77XX_MADCTL_RGB);
 418  #else
 419      SPI.transfer(ST77XX_MADCTL_MY | ST77XX_MADCTL_MV |ST77XX_MADCTL_RGB);
 420  #endif
 421  #endif    
 422    }
 423    else {
 424      flipped=false;
 425  #ifdef ILI9341        
 426      SPI.transfer(ILI9341_MADCTL_MX | ILI9341_MADCTL_MY | ILI9341_MADCTL_MV | ILI9341_MADCTL_BGR);
 427  #endif
 428  #ifdef ST7789
 429  #ifdef ROTATE_SCREEN
 430      SPI.transfer(ST77XX_MADCTL_MX | ST77XX_MADCTL_MY | ST77XX_MADCTL_RGB);
 431  #else
 432      SPI.transfer(ST77XX_MADCTL_MX | ST77XX_MADCTL_MV | ST77XX_MADCTL_RGB);
 433  #endif
 434  #endif    
 435    }
 436    digitalWrite(_cs, 1);  
 437    SPI.endTransaction();
 438  }
 439  
 440  boolean TFT_T_DMA::isflipped(void)
 441  {
 442    return(flipped);
 443  }
 444    
 445  
 446  #define PRREG(x) Serial.print(#x" 0x"); Serial.println(x,HEX)
 447  
 448  
 449  void TFT_T_DMA::startDMA(void) {
 450    curTransfer = 0;  
 451    rstop = 0;     
 452    //dmatx.begin(true);
 453    dmatx.attachInterrupt(dmaInterrupt);
 454    setDmaStruct();
 455    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);  
 456    fillScreen(RGBVAL16(0x00,0x00,0x00));
 457    
 458    digitalWrite(_cs, HIGH);
 459    SPI.begin();
 460    SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE0));
 461  
 462  
 463    LPSPIP_CR &= ~LPSPI_CR_MEN;//disable LPSPI:
 464    LPSPIP_CFGR1 |= LPSPI_CFGR1_NOSTALL; //prevent stall from RX
 465    LPSPIP_TCR = 15; // Framesize 16 Bits
 466    //LPSPIP_FCR = 0; // Fifo Watermark
 467    LPSPIP_DER = LPSPI_DER_TDDE; //TX DMA Request Enable
 468    LPSPIP_CR |= LPSPI_CR_MEN; //enable LPSPI:
 469    dmatx.triggerAtHardwareEvent( DMAMUX_SOURCE_LPSPIP_TX );
 470  
 471    dmatx = dmasettings[0];
 472    digitalWrite(_cs, 0); 
 473    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);  
 474    digitalWrite(_dc, 0);
 475    SPI.transfer(TFT_RAMWR); 
 476    digitalWrite(_dc, 1);      
 477    dmatx.enable();
 478  }
 479  
 480  
 481  void TFT_T_DMA::stopDMA(void) {
 482    rstop = 0;
 483    wait();
 484    delay(50);
 485    cancelled = false;  
 486    dmatx.detachInterrupt();
 487    fillScreen(RGBVAL16(0x00,0x00,0x00));
 488    SPI.end();
 489  #ifdef ST7789  
 490    begin();
 491  #endif
 492  #ifdef ILI9341 
 493    SPI.begin();
 494    digitalWrite(_cs, 0);
 495    SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE));  
 496    SPI.endTransaction();
 497    digitalWrite(_cs, 1);
 498    digitalWrite(_dc, 1); 
 499  #endif    
 500    setArea(0, 0, TFT_REALWIDTH-1, TFT_REALHEIGHT-1);    
 501  }
 502  
 503  void TFT_T_DMA::wait(void) {
 504    rstop = 1;
 505    unsigned long m = millis(); 
 506    cancelled = true; 
 507    while (!rstop)  {
 508      if ((millis() - m) > 100) break;
 509      delay(10);
 510      asm volatile("wfi");
 511    };
 512    rstop = 0;
 513  }
 514  
 515  int TFT_T_DMA::get_frame_buffer_size(int *width, int *height){
 516    if (width != nullptr) *width = TFT_REALWIDTH;
 517    if (height != nullptr) *height = TFT_REALHEIGHT;
 518    return TFT_REALWIDTH;  
 519  } 
 520  
 521  
 522  /***********************************************************************************************
 523      Touch functions
 524   ***********************************************************************************************/
 525  /* Code based on ...
 526   *
 527   * @file XPT2046.cpp
 528   * @date 19.02.2016
 529   * @author Markus Sattler
 530   *
 531   * Copyright (c) 2015 Markus Sattler. All rights reserved.
 532   * This file is part of the XPT2046 driver for Arduino.
 533   */
 534  
 535  #define ADC_MAX                 0x0fff  
 536  
 537  void TFT_T_DMA::enableTouchIrq() 
 538  {
 539      SPI.beginTransaction(SPI_SETTING);
 540      digitalWrite(_touch_cs, LOW);
 541      const uint8_t buf[4] = { (XPT2046_CFG_START | XPT2046_CFG_12BIT | XPT2046_CFG_DFR | XPT2046_CFG_MUX(XPT2046_MUX_Y)), 0x00, 0x00, 0x00 };
 542      SPI.transfer((void*)&buf[0],3);   
 543      digitalWrite(_touch_cs, HIGH);
 544      SPI.endTransaction();
 545  }
 546  
 547  //Default callibration for non flipped
 548  #define TX_MIN 30
 549  #define TY_MIN 20
 550  #define TX_MAX 300
 551  #define TY_MAX 220
 552  
 553  //Default callibration for flipped
 554  #define TFX_MIN 20
 555  #define TFY_MIN 25
 556  #define TFX_MAX 288
 557  #define TFY_MAX 221
 558  
 559  static uint16_t txMin;
 560  static uint16_t tyMin;
 561  static uint16_t txMax;
 562  static uint16_t tyMax;
 563  
 564   
 565  void TFT_T_DMA::callibrateTouch(uint16_t xMin,uint16_t yMin,uint16_t xMax,uint16_t yMax)  {
 566    if ( (xMin >= 0) && (yMin >= 0) && (xMax < 320) && (yMax < 200) ) {
 567        txMin = xMin;
 568        tyMin = yMin;
 569        txMax = xMax;
 570        tyMax = yMax;     
 571    }
 572    else {
 573      if (flipped) {
 574        txMin = TFX_MIN;
 575        tyMin = TFY_MIN;
 576        txMax = TFX_MAX;
 577        tyMax = TFY_MAX;              
 578      }
 579      else {
 580        txMin = TX_MIN;
 581        tyMin = TY_MIN;
 582        txMax = TX_MAX;
 583        tyMax = TY_MAX;      
 584      }
 585    }
 586  }
 587  
 588  
 589  void TFT_T_DMA::readRaw(uint16_t * oX, uint16_t * oY, uint16_t * oZ) {
 590    if ( TOUCH_ENABLED() ) {
 591      uint16_t x = 0;
 592      uint16_t y = 0;
 593      uint16_t z1 = 0;
 594      uint16_t z2 = 0;
 595      uint8_t i = 0;
 596      int16_t xraw=0, yraw=0;
 597    
 598      SPI.beginTransaction(SPI_SETTING);
 599      digitalWrite(_touch_cs, LOW);
 600    
 601      for(; i < 15; i++) {
 602        // SPI requirer 32bit aliment
 603        uint8_t buf[12] = {
 604          (XPT2046_CFG_START | XPT2046_CFG_12BIT | XPT2046_CFG_DFR | XPT2046_CFG_MUX(XPT2046_MUX_Y) | XPT2046_CFG_PWR(3)), 0x00, 0x00,
 605          (XPT2046_CFG_START | XPT2046_CFG_12BIT | XPT2046_CFG_DFR | XPT2046_CFG_MUX(XPT2046_MUX_X) | XPT2046_CFG_PWR(3)), 0x00, 0x00,
 606          (XPT2046_CFG_START | XPT2046_CFG_12BIT | XPT2046_CFG_DFR | XPT2046_CFG_MUX(XPT2046_MUX_Z1)| XPT2046_CFG_PWR(3)), 0x00, 0x00,
 607          (XPT2046_CFG_START | XPT2046_CFG_12BIT | XPT2046_CFG_DFR | XPT2046_CFG_MUX(XPT2046_MUX_Z2)| XPT2046_CFG_PWR(3)), 0x00, 0x00
 608        };
 609        SPI.transfer(&buf[0], &buf[0], 12);
 610        y += (buf[1] << 8 | buf[2])>>3;
 611        x += (buf[4] << 8 | buf[5])>>3;
 612        z1 += (buf[7] << 8 | buf[8])>>3;
 613        z2 += (buf[10] << 8 | buf[11])>>3;
 614      }
 615      enableTouchIrq();
 616    
 617      if(i == 0) {
 618          *oX = 0;
 619          *oY = 0;
 620          *oZ = 0;
 621      }
 622      else {
 623          x /= i;
 624          y /= i;
 625          z1 /= i;
 626          z2 /= i;
 627      }
 628    
 629      digitalWrite(_touch_cs, HIGH);
 630      SPI.endTransaction();
 631      int z = z1 + ADC_MAX - z2;
 632      if (flipped) {
 633        xraw = x;
 634        yraw = y;
 635      } else {
 636        xraw = ADC_MAX - x;
 637        yraw = ADC_MAX - y;
 638      }
 639      xraw=(xraw*TFT_REALWIDTH)/(ADC_MAX+1);
 640      yraw=(yraw*TFT_REALHEIGHT)/(ADC_MAX+1);
 641    
 642      *oX = xraw;
 643      *oY = yraw;
 644      *oZ = z;
 645    }
 646    else 
 647    {
 648      *oX = 0;
 649      *oY = 0;
 650      *oZ = 0;    
 651    }
 652  }
 653  
 654  void TFT_T_DMA::readCal(uint16_t * oX, uint16_t * oY, uint16_t * oZ) {
 655    readRaw(oX,oY,oZ);
 656    // callibrate ...
 657    if(*oX >= txMin) *oX = ((*oX - txMin)*TFT_REALWIDTH)/(txMax-txMin);
 658    if(*oY >= tyMin) *oY = ((*oY - tyMin)*TFT_REALHEIGHT)/(tyMax-tyMin);
 659    //Serial.print(*oX);
 660    //Serial.print(" ");
 661    //Serial.println(*oY);
 662  }
 663  
 664  
 665  /***********************************************************************************************
 666      No DMA functions
 667   ***********************************************************************************************/
 668  void TFT_T_DMA::fillScreenNoDma(uint16_t color) {
 669    
 670    SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE));
 671    digitalWrite(_cs, 0);
 672    setArea(0, 0, TFT_REALWIDTH-1, TFT_REALHEIGHT-1);  
 673    //digitalWrite(_dc, 0);
 674    //SPI.transfer(TFT_RAMWR);
 675    int i,j;
 676    for (j=0; j<TFT_REALHEIGHT; j++)
 677    {
 678      for (i=0; i<TFT_REALWIDTH; i++) {
 679        //digitalWrite(_dc, 1);
 680        SPI.transfer16(color);     
 681      }
 682    }
 683  #ifdef ILI9341  
 684    digitalWrite(_dc, 0);
 685    SPI.transfer(ILI9341_SLPOUT);
 686    digitalWrite(_dc, 1);
 687  #endif
 688    digitalWrite(_cs, 1);
 689    setArea(0, 0, (TFT_REALWIDTH-1), (TFT_REALHEIGHT-1));  
 690    SPI.endTransaction();    
 691  }
 692  
 693  void TFT_T_DMA::drawRectNoDma(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color) {
 694    SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE));
 695    digitalWrite(_cs, 0);
 696    setArea(x,y,x+w-1,y+h-1);
 697  //  digitalWrite(_dc, 0);
 698  //  SPI.transfer(TFT_RAMWR);
 699    int i;
 700    for (i=0; i<(w*h); i++)
 701    {
 702      //digitalWrite(_dc, 1);
 703      SPI.transfer16(color);
 704    }
 705  #ifdef ILI9341  
 706    digitalWrite(_dc, 0);
 707    SPI.transfer(ILI9341_SLPOUT);
 708    digitalWrite(_dc, 1);
 709  #endif
 710    digitalWrite(_cs, 1);
 711    setArea(0, 0, (TFT_REALWIDTH-1), (TFT_REALHEIGHT-1));
 712    SPI.endTransaction();    
 713  }
 714  
 715  void TFT_T_DMA::writeScreenNoDma(const uint16_t *pcolors) {  
 716    SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE));
 717    digitalWrite(_cs, 0);
 718    setArea(0, 0, TFT_WIDTH-1, TFT_HEIGHT-1);  
 719    //digitalWrite(_dc, 0);
 720    //SPI.transfer(TFT_RAMWR);
 721    int i,j;
 722    for (j=0; j<240; j++)
 723    {
 724      for (i=0; i<TFT_WIDTH; i++) {
 725   //     digitalWrite(_dc, 1);
 726        SPI.transfer16(*pcolors++);     
 727      }
 728    }
 729  #ifdef ILI9341  
 730    digitalWrite(_dc, 0);
 731    SPI.transfer(ILI9341_SLPOUT);
 732    digitalWrite(_dc, 1);
 733  #endif
 734    digitalWrite(_cs, 1);
 735    setArea(0, 0, (TFT_REALWIDTH-1), (TFT_REALHEIGHT-1));  
 736    SPI.endTransaction();    
 737  }
 738  
 739  void TFT_T_DMA::drawSpriteNoDma(int16_t x, int16_t y, const uint16_t *bitmap) {
 740      drawSpriteNoDma(x,y,bitmap, 0,0,0,0);
 741  }
 742  
 743  void TFT_T_DMA::drawSpriteNoDma(int16_t x, int16_t y, const uint16_t *bitmap, uint16_t arx, uint16_t ary, uint16_t arw, uint16_t arh)
 744  {
 745    int bmp_offx = 0;
 746    int bmp_offy = 0;
 747    uint16_t *bmp_ptr;
 748      
 749    int w =*bitmap++;
 750    int h = *bitmap++;
 751  //Serial.println(w);
 752  //Serial.println(h);
 753  
 754    if ( (arw == 0) || (arh == 0) ) {
 755      // no crop window
 756      arx = x;
 757      ary = y;
 758      arw = w;
 759      arh = h;
 760    }
 761    else {
 762      if ( (x>(arx+arw)) || ((x+w)<arx) || (y>(ary+arh)) || ((y+h)<ary)   ) {
 763        return;
 764      }
 765      
 766      // crop area
 767      if ( (x > arx) && (x<(arx+arw)) ) { 
 768        arw = arw - (x-arx);
 769        arx = arx + (x-arx);
 770      } else {
 771        bmp_offx = arx;
 772      }
 773      if ( ((x+w) > arx) && ((x+w)<(arx+arw)) ) {
 774        arw -= (arx+arw-x-w);
 775      }  
 776      if ( (y > ary) && (y<(ary+arh)) ) {
 777        arh = arh - (y-ary);
 778        ary = ary + (y-ary);
 779      } else {
 780        bmp_offy = ary;
 781      }
 782      if ( ((y+h) > ary) && ((y+h)<(ary+arh)) ) {
 783        arh -= (ary+arh-y-h);
 784      }     
 785    }
 786  
 787    
 788    SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE));
 789    digitalWrite(_cs, 0);
 790    setArea(arx, ary, arx+arw-1, ary+arh-1);  
 791    //digitalWrite(_dc, 0);
 792    //SPI.transfer(TFT_RAMWR);      
 793  
 794    bitmap = bitmap + bmp_offy*w + bmp_offx;
 795    for (int row=0;row<arh; row++)
 796    {
 797      bmp_ptr = (uint16_t*)bitmap;
 798      for (int col=0;col<arw; col++)
 799      {
 800          uint16_t color = *bmp_ptr++;
 801  //        digitalWrite(_dc, 1);
 802          SPI.transfer16(color);             
 803      } 
 804      bitmap +=  w;
 805    }
 806  #ifdef ILI9341  
 807    digitalWrite(_dc, 0);
 808    SPI.transfer(ILI9341_SLPOUT);
 809    digitalWrite(_dc, 1);
 810  #endif
 811    setArea(0, 0, TFT_REALWIDTH-1, TFT_REALHEIGHT-1);  
 812    digitalWrite(_cs, 1);
 813    SPI.endTransaction();   
 814  }
 815  
 816  void TFT_T_DMA::drawTextNoDma(int16_t x, int16_t y, const char * text, uint16_t fgcolor, uint16_t bgcolor, bool doublesize) {
 817    uint16_t c;
 818    while ((c = *text++)) {
 819      const unsigned char * charpt=&font8x8[c][0];
 820  
 821    
 822      SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE));
 823      digitalWrite(_cs, 0);
 824      setArea(x,y,x+7,y+(doublesize?15:7));
 825      //digitalWrite(_dc, 0);
 826      //SPI.transfer(TFT_RAMWR);
 827      //digitalWrite(_dc, 1);
 828      for (int i=0;i<8;i++)
 829      {
 830        unsigned char bits;
 831        if (doublesize) {
 832          bits = *charpt;     
 833          //digitalWrite(_dc, 1);
 834          if (bits&0x01) SPI.transfer16(fgcolor);
 835          else SPI.transfer16(bgcolor);
 836          bits = bits >> 1;     
 837          if (bits&0x01) SPI.transfer16(fgcolor);
 838          else SPI.transfer16(bgcolor);
 839          bits = bits >> 1;     
 840          if (bits&0x01) SPI.transfer16(fgcolor);
 841          else SPI.transfer16(bgcolor);
 842          bits = bits >> 1;     
 843          if (bits&0x01) SPI.transfer16(fgcolor);
 844          else SPI.transfer16(bgcolor);
 845          bits = bits >> 1;     
 846          if (bits&0x01) SPI.transfer16(fgcolor);
 847          else SPI.transfer16(bgcolor);
 848          bits = bits >> 1;     
 849          if (bits&0x01) SPI.transfer16(fgcolor);
 850          else SPI.transfer16(bgcolor);
 851          bits = bits >> 1;     
 852          if (bits&0x01) SPI.transfer16(fgcolor);
 853          else SPI.transfer16(bgcolor);
 854          bits = bits >> 1;     
 855          if (bits&0x01) SPI.transfer16(fgcolor);
 856          else SPI.transfer16(bgcolor);       
 857        }
 858        bits = *charpt++;     
 859        //digitalWrite(_dc, 1);
 860        if (bits&0x01) SPI.transfer16(fgcolor);
 861        else SPI.transfer16(bgcolor);
 862        bits = bits >> 1;     
 863        if (bits&0x01) SPI.transfer16(fgcolor);
 864        else SPI.transfer16(bgcolor);
 865        bits = bits >> 1;     
 866        if (bits&0x01) SPI.transfer16(fgcolor);
 867        else SPI.transfer16(bgcolor);
 868        bits = bits >> 1;     
 869        if (bits&0x01) SPI.transfer16(fgcolor);
 870        else SPI.transfer16(bgcolor);
 871        bits = bits >> 1;     
 872        if (bits&0x01) SPI.transfer16(fgcolor);
 873        else SPI.transfer16(bgcolor);
 874        bits = bits >> 1;     
 875        if (bits&0x01) SPI.transfer16(fgcolor);
 876        else SPI.transfer16(bgcolor);
 877        bits = bits >> 1;     
 878        if (bits&0x01) SPI.transfer16(fgcolor);
 879        else SPI.transfer16(bgcolor);
 880        bits = bits >> 1;     
 881        if (bits&0x01) SPI.transfer16(fgcolor);
 882        else SPI.transfer16(bgcolor);
 883      }
 884      x +=8;
 885  #ifdef ILI9341  
 886    digitalWrite(_dc, 0);
 887    SPI.transfer(ILI9341_SLPOUT);
 888    digitalWrite(_dc, 1);
 889  #endif
 890      digitalWrite(_cs, 1);
 891      SPI.endTransaction();  
 892    }
 893    
 894    SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE));
 895    digitalWrite(_cs, 0);
 896    setArea(0, 0, (TFT_REALWIDTH-1), (TFT_REALHEIGHT-1));  
 897    digitalWrite(_cs, 1);
 898    SPI.endTransaction();  
 899  }
 900  
 901  
 902  
 903  
 904  
 905  
 906  /***********************************************************************************************
 907      DMA functions
 908   ***********************************************************************************************/
 909  uint16_t * TFT_T_DMA::getLineBuffer(int j)
 910  {
 911    uint16_t * block=blocks[j>>6];  
 912    return(&block[(j&0x3F)*TFT_REALWIDTH]);
 913  }
 914  
 915  void TFT_T_DMA::writeScreen(int width, int height, int stride, uint8_t *buf, uint16_t *palette16) {
 916    uint8_t *buffer=buf;
 917    uint8_t *src; 
 918  
 919    int i,j,y=0;
 920    if (width*2 <= TFT_REALWIDTH) {
 921      for (j=0; j<height; j++)
 922      {
 923        uint16_t * block=blocks[y>>6];
 924        uint16_t * dst=&block[(y&0x3F)*TFT_WIDTH];        
 925        src=buffer;
 926        for (i=0; i<width; i++)
 927        {
 928          uint16_t val = palette16[*src++];
 929          *dst++ = val;
 930          *dst++ = val;
 931        }
 932        y++;
 933        if (height*2 <= TFT_HEIGHT) {
 934          block=blocks[y>>6];
 935          dst=&block[(y&0x3F)*TFT_WIDTH];          
 936          src=buffer;
 937          for (i=0; i<width; i++)
 938          {
 939            uint16_t val = palette16[*src++];
 940            *dst++ = val;
 941            *dst++ = val;
 942          }
 943          y++;      
 944        } 
 945        buffer += stride;      
 946      }
 947    }
 948    else if (width <= TFT_REALWIDTH) {
 949      //dst += (TFT_WIDTH-width)/2;
 950      for (j=0; j<height; j++)
 951      {
 952        uint16_t * block=blocks[y>>6];
 953        uint16_t * dst=&block[(y&0x3F)*TFT_WIDTH+(TFT_WIDTH-width)/2];         
 954        src=buffer;
 955        for (i=0; i<width; i++)
 956        {
 957          uint16_t val = palette16[*src++];
 958          *dst++ = val;
 959        }
 960        y++;
 961        if (height*2 <= TFT_HEIGHT) {
 962          block=blocks[y>>6];
 963          dst=&block[(y&0x3F)*TFT_WIDTH+(TFT_WIDTH-width)/2];        
 964          src=buffer;
 965          for (i=0; i<width; i++)
 966          {
 967            uint16_t val = palette16[*src++];
 968            *dst++ = val;
 969          }
 970          y++;
 971        }      
 972        buffer += stride;  
 973      }
 974    }   
 975  }
 976  
 977  void TFT_T_DMA::writeLine(int width, int height, int y, uint8_t *buf, uint16_t *palette16) {
 978    uint16_t * block=blocks[y>>6];
 979    uint16_t * dst=&block[(y&0x3F)*TFT_WIDTH]; 
 980    if (width > TFT_WIDTH) {
 981  #ifdef TFT_LINEARINT    
 982      int delta = (width/(width-TFT_WIDTH))-1;
 983      int pos = delta;
 984      for (int i=0; i<TFT_WIDTH; i++)
 985      {
 986        uint16_t val = palette16[*buf++];
 987        pos--;      
 988        if (pos == 0) {
 989  #ifdef LINEARINT_HACK        
 990          val  = ((uint32_t)palette16[*buf++] + val)/2;
 991  #else
 992          uint16_t val2 = *buf++;
 993          val = RGBVAL16((R16(val)+R16(val2))/2,(G16(val)+G16(val2))/2,(B16(val)+B16(val2))/2);
 994  #endif        
 995          pos = delta;
 996        }
 997        *dst++=val;
 998      }
 999  #else
1000      int step = ((width << 8)/TFT_WIDTH);
1001      int pos = 0;
1002      for (int i=0; i<TFT_WIDTH; i++)
1003      {
1004        *dst++=palette16[buf[pos >> 8]];
1005        pos +=step;
1006      }  
1007  #endif       
1008    }
1009    else if ((width*2) == TFT_WIDTH) {
1010      for (int i=0; i<width; i++)
1011      {
1012        *dst++=palette16[*buf];
1013        *dst++=palette16[*buf++];
1014      }       
1015    }
1016    else {
1017      if (width <= TFT_WIDTH) {
1018        dst += (TFT_WIDTH-width)/2;
1019      }
1020      for (int i=0; i<width; i++)
1021      {
1022        *dst++=palette16[*buf++];
1023      }       
1024    }
1025  }
1026  
1027  void TFT_T_DMA::writeLine(int width, int height, int y, uint16_t *buf) {
1028    uint16_t * block=blocks[y>>6];
1029    uint16_t * dst=&block[(y&0x3F)*TFT_WIDTH];  
1030    if (width > TFT_WIDTH) {
1031  #ifdef TFT_LINEARINT   
1032      int delta = (width/(width-TFT_WIDTH))-1;   
1033      int pos = delta;
1034      for (int i=0; i<TFT_WIDTH; i++)
1035      {
1036        uint16_t val = *buf++;
1037        pos--;      
1038        if (pos == 0) {
1039  #ifdef LINEARINT_HACK        
1040          val  = ((uint32_t)*buf++ + val)/2;
1041  #else
1042          uint16_t val2 = *buf++;
1043          val = RGBVAL16((R16(val)+R16(val2))/2,(G16(val)+G16(val2))/2,(B16(val)+B16(val2))/2);
1044  #endif        
1045          pos = delta;
1046        }
1047        *dst++=val;
1048      }
1049  #else
1050      int step = ((width << 8)/TFT_WIDTH);
1051      int pos = 0;
1052      for (int i=0; i<TFT_WIDTH; i++)
1053      {
1054        *dst++=buf[pos >> 8];
1055        pos +=step;
1056      }  
1057  #endif       
1058    }
1059    else if ((width*2) == TFT_WIDTH) {
1060      for (int i=0; i<width; i++)
1061      {
1062        *dst++=*buf;
1063        *dst++=*buf++;
1064      }       
1065    }
1066    else {
1067      if (width <= TFT_WIDTH) {
1068        dst += (TFT_WIDTH-width)/2;
1069      }
1070      for (int i=0; i<width; i++)
1071      {
1072        *dst++=*buf++;
1073      }       
1074    }
1075  }
1076  
1077  void TFT_T_DMA::fillScreen(uint16_t color) {
1078    int i,j;
1079    for (j=0; j<TFT_HEIGHT; j++)
1080    {
1081      uint16_t * block=blocks[j>>6];
1082      uint16_t * dst=&block[(j&0x3F)*TFT_WIDTH];
1083      for (i=0; i<TFT_WIDTH; i++)
1084      {
1085        *dst++ = color;
1086      }
1087    }
1088  }
1089  
1090  void TFT_T_DMA::drawRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color) {
1091    int i,j,l=y;
1092    color=color;
1093    for (j=0; j<h; j++)
1094    {
1095      uint16_t * block=blocks[l>>6];
1096      uint16_t * dst=&block[(l&0x3F)*TFT_WIDTH+x];
1097      for (i=0; i<w; i++)
1098      {
1099        *dst++ = color;
1100      }
1101      l++;
1102    }
1103  }
1104  
1105  void TFT_T_DMA::drawText(int16_t x, int16_t y, const char * text, uint16_t fgcolor, uint16_t bgcolor, bool doublesize) {
1106    uint16_t c;
1107    uint16_t * block;
1108    uint16_t * dst;
1109    fgcolor = fgcolor;
1110    bgcolor = bgcolor;
1111    
1112    while ((c = *text++)) {
1113      const unsigned char * charpt=&font8x8[c][0];
1114  
1115      int l=y;
1116      for (int i=0;i<8;i++)
1117      {     
1118        unsigned char bits;
1119        if (doublesize) {
1120          block=blocks[l>>6];
1121          dst=&block[(l&0x3F)*TFT_WIDTH+x];         
1122          bits = *charpt;     
1123          if (bits&0x01) *dst++=fgcolor;
1124          else *dst++=bgcolor;
1125          bits = bits >> 1;     
1126          if (bits&0x01) *dst++=fgcolor;
1127          else *dst++=bgcolor;
1128          bits = bits >> 1;     
1129          if (bits&0x01) *dst++=fgcolor;
1130          else *dst++=bgcolor;
1131          bits = bits >> 1;     
1132          if (bits&0x01) *dst++=fgcolor;
1133          else *dst++=bgcolor;
1134          bits = bits >> 1;     
1135          if (bits&0x01) *dst++=fgcolor;
1136          else *dst++=bgcolor;
1137          bits = bits >> 1;     
1138          if (bits&0x01) *dst++=fgcolor;
1139          else *dst++=bgcolor;
1140          bits = bits >> 1;     
1141          if (bits&0x01) *dst++=fgcolor;
1142          else *dst++=bgcolor;
1143          bits = bits >> 1;     
1144          if (bits&0x01) *dst++=fgcolor;
1145          else *dst++=bgcolor;
1146          l++;       
1147        }
1148        block=blocks[l>>6];
1149        dst=&block[(l&0x3F)*TFT_WIDTH+x]; 
1150        bits = *charpt++;     
1151        if (bits&0x01) *dst++=fgcolor;
1152        else *dst++=bgcolor;
1153        bits = bits >> 1;     
1154        if (bits&0x01) *dst++=fgcolor;
1155        else *dst++=bgcolor;
1156        bits = bits >> 1;     
1157        if (bits&0x01) *dst++=fgcolor;
1158        else *dst++=bgcolor;
1159        bits = bits >> 1;     
1160        if (bits&0x01) *dst++=fgcolor;
1161        else *dst++=bgcolor;
1162        bits = bits >> 1;     
1163        if (bits&0x01) *dst++=fgcolor;
1164        else *dst++=bgcolor;
1165        bits = bits >> 1;     
1166        if (bits&0x01) *dst++=fgcolor;
1167        else *dst++=bgcolor;
1168        bits = bits >> 1;     
1169        if (bits&0x01) *dst++=fgcolor;
1170        else *dst++=bgcolor;
1171        bits = bits >> 1;     
1172        if (bits&0x01) *dst++=fgcolor;
1173        else *dst++=bgcolor;
1174        l++;
1175      }
1176      x +=8;
1177    } 
1178  }
1179  
1180  void TFT_T_DMA::drawSprite(int16_t x, int16_t y, const uint16_t *bitmap) {
1181      drawSprite(x,y,bitmap, 0,0,0,0);
1182  }
1183  
1184  void TFT_T_DMA::drawSprite(int16_t x, int16_t y, const uint16_t *bitmap, uint16_t arx, uint16_t ary, uint16_t arw, uint16_t arh)
1185  {
1186    int bmp_offx = 0;
1187    int bmp_offy = 0;
1188    uint16_t *bmp_ptr;
1189      
1190    int w =*bitmap++;
1191    int h = *bitmap++;
1192  
1193  
1194    if ( (arw == 0) || (arh == 0) ) {
1195      // no crop window
1196      arx = x;
1197      ary = y;
1198      arw = w;
1199      arh = h;
1200    }
1201    else {
1202      if ( (x>(arx+arw)) || ((x+w)<arx) || (y>(ary+arh)) || ((y+h)<ary)   ) {
1203        return;
1204      }
1205      
1206      // crop area
1207      if ( (x > arx) && (x<(arx+arw)) ) { 
1208        arw = arw - (x-arx);
1209        arx = arx + (x-arx);
1210      } else {
1211        bmp_offx = arx;
1212      }
1213      if ( ((x+w) > arx) && ((x+w)<(arx+arw)) ) {
1214        arw -= (arx+arw-x-w);
1215      }  
1216      if ( (y > ary) && (y<(ary+arh)) ) {
1217        arh = arh - (y-ary);
1218        ary = ary + (y-ary);
1219      } else {
1220        bmp_offy = ary;
1221      }
1222      if ( ((y+h) > ary) && ((y+h)<(ary+arh)) ) {
1223        arh -= (ary+arh-y-h);
1224      }     
1225    }
1226  
1227     
1228    int l=ary;
1229    bitmap = bitmap + bmp_offy*w + bmp_offx;
1230    for (int row=0;row<arh; row++)
1231    {
1232      uint16_t * block=blocks[l>>6];
1233      uint16_t * dst=&block[(l&0x3F)*TFT_WIDTH+arx];  
1234      bmp_ptr = (uint16_t*)bitmap;
1235      for (int col=0;col<arw; col++)
1236      {
1237          *dst++ = *bmp_ptr++;            
1238      } 
1239      bitmap +=  w;
1240      l++;
1241    } 
1242  }
1243  #endif