MCUME/MCUME_teensy/teensynofrendo/tft_t_dma.cpp

1238 wiersze
32 KiB
C++

/*
Based on C64 ILI9341 dma driver from Frank Bösing, 2017
*/
#include "TFT_T_DMA.h"
#include "font8x8.h"
#define SPICLOCK 60000000 //144e6 //Just a number..max speed
#ifdef ILI9341
#define SPI_MODE SPI_MODE0
#endif
#ifdef ST7789
#define SPI_MODE SPI_MODE2
#endif
// touch
#define SPI_SETTING SPISettings(2500000, MSBFIRST, SPI_MODE)
#define XPT2046_CFG_START _BV(7)
#define XPT2046_CFG_MUX(v) ((v&0b111) << (4))
#define XPT2046_CFG_8BIT _BV(3)
#define XPT2046_CFG_12BIT (0)
#define XPT2046_CFG_SER _BV(2)
#define XPT2046_CFG_DFR (0)
#define XPT2046_CFG_PWR(v) ((v&0b11))
#define XPT2046_MUX_Y 0b101
#define XPT2046_MUX_X 0b001
#define XPT2046_MUX_Z1 0b011
#define XPT2046_MUX_Z2 0b100
#ifdef TFT_STATICFB
static uint16_t fb0[LINES_PER_BLOCK*TFT_WIDTH];
static uint16_t fb1[LINES_PER_BLOCK*TFT_WIDTH];
static uint16_t fb2[LINES_PER_BLOCK*TFT_WIDTH];
static uint16_t fb3[(TFT_HEIGHT-3*LINES_PER_BLOCK)*TFT_WIDTH];
static uint16_t * blocks[NR_OF_BLOCK]={fb0,fb1,fb2,fb3};
#else
static uint16_t * blocks[NR_OF_BLOCK];
#endif
static DMASetting dmasettings[SCREEN_DMA_NUM_SETTINGS];
static DMAChannel dmatx;//(false);
static volatile uint8_t rstop = 0;
static volatile bool cancelled = false;
static volatile uint8_t curTransfer = 0;
static uint8_t nbTransfer = 0;
PROGMEM static const uint8_t init_commands[] = {
#ifdef ILI9341
4, 0xEF, 0x03, 0x80, 0x02,
4, 0xCF, 0x00, 0XC1, 0X30,
5, 0xED, 0x64, 0x03, 0X12, 0X81,
4, 0xE8, 0x85, 0x00, 0x78,
6, 0xCB, 0x39, 0x2C, 0x00, 0x34, 0x02,
2, 0xF7, 0x20,
3, 0xEA, 0x00, 0x00,
2, ILI9341_PWCTR1, 0x23, // Power control
2, ILI9341_PWCTR2, 0x10, // Power control
3, ILI9341_VMCTR1, 0x3e, 0x28, // VCM control
2, ILI9341_VMCTR2, 0x86, // VCM control2
2, ILI9341_MADCTL, 0x48, // Memory Access Control
2, ILI9341_PIXFMT, 0x55,
3, ILI9341_FRMCTR1, 0x00, 0x18,
4, ILI9341_DFUNCTR, 0x08, 0x82, 0x27, // Display Function Control
2, 0xF2, 0x00, // Gamma Function Disable
2, ILI9341_GAMMASET, 0x01, // Gamma curve selected
16, ILI9341_GMCTRP1, 0x0F, 0x31, 0x2B, 0x0C, 0x0E, 0x08,
0x4E, 0xF1, 0x37, 0x07, 0x10, 0x03, 0x0E, 0x09, 0x00, // Set Gamma
16, ILI9341_GMCTRN1, 0x00, 0x0E, 0x14, 0x03, 0x11, 0x07,
0x31, 0xC1, 0x48, 0x08, 0x0F, 0x0C, 0x31, 0x36, 0x0F, // Set Gamma
// 3, 0xb1, 0x00, 0x1f, // FrameRate Control 61Hz
3, 0xb1, 0x00, 0x10, // FrameRate Control 119Hz
2, ILI9341_MADCTL, ILI9341_MADCTL_MX | ILI9341_MADCTL_MY | ILI9341_MADCTL_MV | ILI9341_MADCTL_BGR,
0
#endif
#ifdef ST7789
#define DELAY 0x80
9, // 9 commands in list:
ST7735_SWRESET, DELAY, // 1: Software reset, no args, w/delay
150, // 150 ms delay
ST7735_SLPOUT , DELAY, // 2: Out of sleep mode, no args, w/delay
255, // 255 = 500 ms delay
ST7735_COLMOD , 1+DELAY, // 3: Set color mode, 1 arg + delay:
0x55, // 16-bit color
10, // 10 ms delay
ST7735_MADCTL , 1 , // 4: Memory access ctrl (directions), 1 arg:
0x08, // Row addr/col addr, bottom to top refresh
ST7735_CASET , 4 , // 5: Column addr set, 4 args, no delay:
0x00,
0x00, // XSTART = 0
0x00,
240, // XEND = 240
ST7735_RASET , 4 , // 6: Row addr set, 4 args, no delay:
0x00,
0x00, // YSTART = 0
320>>8,
320 & 0xFF, // YEND = 320
ST7735_INVON , DELAY, // 7: hack
10,
ST7735_NORON , DELAY, // 8: Normal display on, no args, w/delay
10, // 10 ms delay
ST7735_DISPON , DELAY, // 9: Main screen turn on, no args, w/delay
255
#endif
};
static void dmaInterrupt() {
dmatx.clearInterrupt();
curTransfer++;
if (curTransfer >= nbTransfer) {
curTransfer = 0;
if (cancelled) {
dmatx.disable();
rstop = 1;
}
}
#if defined(__IMXRT1052__) || defined(__IMXRT1062__)
arm_dcache_flush(blocks[curTransfer], LINES_PER_BLOCK*TFT_WIDTH*2);
#endif
}
static void setDmaStruct() {
uint32_t remaining = TFT_HEIGHT*TFT_WIDTH*2;
int i=0;
uint16_t col=RGBVAL16(0x00,0x00,0x00);;
while (remaining > 0) {
uint16_t * fb = blocks[i];
int32_t len = (remaining >= (LINES_PER_BLOCK*TFT_WIDTH*2)?LINES_PER_BLOCK*TFT_WIDTH*2:remaining);
#ifdef TFT_DEBUG
Serial.println((unsigned long)blocks[i]);
Serial.println(remaining);
#endif
switch (i) {
case 0:
if (fb == 0) fb = (uint16_t*)((int)malloc(len+64)&0xffffffe0);
//fb=&fb0[0];
#ifdef TFT_DEBUG
col = RGBVAL16(0x00,0xff,0x00);
#endif
break;
case 1:
if (fb == 0) fb = (uint16_t*)((int)malloc(len+64)&0xffffffe0);
//fb=&fb1[0];
#ifdef TFT_DEBUG
col = RGBVAL16(0x00,0xff,0xff);
#endif
break;
case 2:
if (fb == 0) fb = (uint16_t*)((int)malloc(len+64)&0xffffffe0);
//fb=&fb2[0];
#ifdef TFT_DEBUG
col = RGBVAL16(0x00,0x00,0xff);
#endif
break;
case 3:
if (fb == 0) fb = (uint16_t*)((int)malloc(len+64)&0xffffffe0);
//fb=&fb3[0];
#ifdef TFT_DEBUG
col = RGBVAL16(0xff,0x00,0xff);
#endif
break;
}
blocks[i] = fb;
if (blocks[i] == 0) {
Serial.print("ILI9341 allocaltion failed for block ");
Serial.println(i);
delay(10000);
}
for (int j=0;j<len/2;j++) fb[j]=col;
#if defined(__IMXRT1052__) || defined(__IMXRT1062__)
dmasettings[i].sourceBuffer(fb, len);
dmasettings[i].destination((uint8_t &) LPSPI4_TDR);
dmasettings[i].TCD->ATTR_DST = 1;
#else
dmasettings[i].sourceBuffer(fb, len);
dmasettings[i].destination((uint8_t &) SPI0_PUSHR);
dmasettings[i].TCD->ATTR_DST = 1;
#endif
dmasettings[i].replaceSettingsOnCompletion(dmasettings[i+1]);
dmasettings[i].interruptAtCompletion();
remaining -= len;
i++;
}
dmasettings[i-1].replaceSettingsOnCompletion(dmasettings[0]);
nbTransfer = i;
#ifdef TFT_DEBUG
Serial.println(nbTransfer);
#endif
}
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)
{
_cs = cs;
_dc = dc;
_rst = rst;
_mosi = mosi;
_sclk = sclk;
_miso = miso;
pinMode(_dc, OUTPUT);
pinMode(_cs, OUTPUT);
digitalWrite(_cs, 1);
digitalWrite(_dc, 1);
if ( (touch_cs != 255) && (touch_irq != 255) ) {
_touch_irq = touch_irq;
_touch_cs = touch_cs;
pinMode(_touch_cs, OUTPUT);
pinMode(touch_irq, INPUT_PULLUP);
digitalWrite(_touch_cs, 1);
}
}
void TFT_T_DMA::setArea(uint16_t x1,uint16_t y1,uint16_t x2,uint16_t y2) {
int dx=0;
int dy=0;
#ifdef ST7789
if (TFT_REALWIDTH == TFT_REALHEIGHT)
{
#ifdef ROTATE_SCREEN
if (!flipped) {
dy += 80;
}
#else
if (flipped) {
dx += 80;
}
#endif
}
#endif
digitalWrite(_dc, 0);
SPI.transfer(TFT_CASET);
digitalWrite(_dc, 1);
SPI.transfer16(x1+dx);
digitalWrite(_dc, 1);
SPI.transfer16(x2+dx);
digitalWrite(_dc, 0);
SPI.transfer(TFT_PASET);
digitalWrite(_dc, 1);
SPI.transfer16(y1+dy);
digitalWrite(_dc, 1);
SPI.transfer16(y2+dy);
digitalWrite(_dc, 0);
SPI.transfer(TFT_RAMWR);
digitalWrite(_dc, 1);
return;
SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE));
digitalWrite(_cs, 0);
digitalWrite(_dc, 0);
SPI.transfer(TFT_CASET);
digitalWrite(_dc, 1);
SPI.transfer16(x1+dx);
SPI.transfer16(x2+dx);
digitalWrite(_dc, 0);
SPI.transfer(TFT_PASET);
digitalWrite(_dc, 1);
SPI.transfer16(y1+dy);
SPI.transfer16(y2+dy);
digitalWrite(_dc, 0);
SPI.transfer(TFT_RAMWR);
digitalWrite(_dc, 1);
digitalWrite(_cs, 1);
SPI.endTransaction();
}
void TFT_T_DMA::begin(void) {
SPI.setMOSI(_mosi);
SPI.setMISO(_miso);
SPI.setSCK(_sclk);
SPI.begin();
// Initialize display
if (_rst != 0xff) {
pinMode(_rst, OUTPUT);
digitalWrite(_rst, HIGH);
delay(100);
digitalWrite(_rst, LOW);
delay(100);
digitalWrite(_rst, HIGH);
delay(200);
}
SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE));
const uint8_t *addr = init_commands;
digitalWrite(_cs, 0);
#ifdef ILI9341
while (1) {
uint8_t count = *addr++;
if (count-- == 0) break;
digitalWrite(_dc, 0);
SPI.transfer(*addr++);
while (count-- > 0) {
digitalWrite(_dc, 1);
SPI.transfer(*addr++);
}
}
digitalWrite(_dc, 0);
SPI.transfer(ILI9341_SLPOUT);
digitalWrite(_dc, 1);
digitalWrite(_cs, 1);
SPI.endTransaction();
digitalWrite(_dc, 1);
digitalWrite(_cs, 1);
SPI.endTransaction();
SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE));
digitalWrite(_dc, 0);
digitalWrite(_cs, 0);
SPI.transfer(ILI9341_DISPON);
digitalWrite(_dc, 1);
digitalWrite(_cs, 1);
#endif
#ifdef ST7789
uint8_t numCommands, numArgs;
uint16_t ms;
numCommands = *addr++; // Number of commands to follow
while(numCommands--) { // For each command...
digitalWrite(_dc, 0);
SPI.transfer(*addr++);
numArgs = *addr++; // Number of args to follow
ms = numArgs & DELAY; // If hibit set, delay follows args
numArgs &= ~DELAY; // Mask out delay bit
while(numArgs > 1) { // For each argument...
digitalWrite(_dc, 1);
SPI.transfer(*addr++);
numArgs--;
}
if (numArgs) {
digitalWrite(_dc, 1);
SPI.transfer(*addr++);
}
if(ms) {
ms = *addr++; // Read post-command delay time (ms)
if(ms == 255) ms = 500; // If 255, delay for 500 ms
digitalWrite(_cs, 1);
SPI.endTransaction();
delay(ms);
SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE));
digitalWrite(_cs, 0);
}
}
digitalWrite(_cs, 1);
#endif
setArea(0, 0, TFT_REALWIDTH-1, TFT_REALHEIGHT-1);
SPI.endTransaction();
cancelled = false;
#ifdef FLIP_SCREEN
flipscreen(true);
#else
flipscreen(false);
#endif
#ifdef ST7789
if (TFT_REALWIDTH != TFT_REALHEIGHT)
{
flipscreen(true);
}
#endif
};
void TFT_T_DMA::flipscreen(bool flip)
{
SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE));
digitalWrite(_dc, 0);
digitalWrite(_cs, 0);
SPI.transfer(TFT_MADCTL);
digitalWrite(_dc, 1);
if (flip) {
flipped=true;
#ifdef ILI9341
SPI.transfer(ILI9341_MADCTL_MV | ILI9341_MADCTL_BGR);
#endif
#ifdef ST7789
#ifdef ROTATE_SCREEN
SPI.transfer(ST77XX_MADCTL_RGB);
#else
SPI.transfer(ST77XX_MADCTL_MY | ST77XX_MADCTL_MV |ST77XX_MADCTL_RGB);
#endif
#endif
}
else {
flipped=false;
#ifdef ILI9341
SPI.transfer(ILI9341_MADCTL_MX | ILI9341_MADCTL_MY | ILI9341_MADCTL_MV | ILI9341_MADCTL_BGR);
#endif
#ifdef ST7789
#ifdef ROTATE_SCREEN
SPI.transfer(ST77XX_MADCTL_MX | ST77XX_MADCTL_MY | ST77XX_MADCTL_RGB);
#else
SPI.transfer(ST77XX_MADCTL_MX | ST77XX_MADCTL_MV | ST77XX_MADCTL_RGB);
#endif
#endif
}
digitalWrite(_cs, 1);
SPI.endTransaction();
}
boolean TFT_T_DMA::isflipped(void)
{
return(flipped);
}
#define PRREG(x) Serial.print(#x" 0x"); Serial.println(x,HEX)
void TFT_T_DMA::startDMA(void) {
curTransfer = 0;
rstop = 0;
//dmatx.begin(true);
dmatx.attachInterrupt(dmaInterrupt);
setDmaStruct();
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);
fillScreen(RGBVAL16(0x00,0x00,0x00));
digitalWrite(_cs, HIGH);
SPI.begin();
SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE0));
#if defined(__IMXRT1052__) || defined(__IMXRT1062__)
#ifdef TFT_DEBUG
PRREG(LPSPI4_CCR);
PRREG(LPSPI4_TCR);
PRREG(LPSPI4_FCR);
Serial.printf("SPI CLOCK %d CCR freq %.1f MHz\n", SPICLOCK, 528. / 7 / ((0xff & LPSPI4_CCR) + 2));
#endif
LPSPI4_CR &= ~LPSPI_CR_MEN;//disable LPSPI:
LPSPI4_CFGR1 |= LPSPI_CFGR1_NOSTALL; //prevent stall from RX
LPSPI4_TCR = 15; // Framesize 16 Bits
//LPSPI4_FCR = 0; // Fifo Watermark
LPSPI4_DER = LPSPI_DER_TDDE; //TX DMA Request Enable
LPSPI4_CR |= LPSPI_CR_MEN; //enable LPSPI:
dmatx.triggerAtHardwareEvent( DMAMUX_SOURCE_LPSPI4_TX );
#else
SPI0_RSER |= SPI_RSER_TFFF_DIRS | SPI_RSER_TFFF_RE; // Set ILI_DMA Interrupt Request Select and Enable register
SPI0_MCR &= ~SPI_MCR_HALT; //Start transfers.
SPI0_CTAR0 = SPI0_CTAR1;
(*(volatile uint16_t *)((int)&SPI0_PUSHR + 2)) = (SPI_PUSHR_CTAS(1) | SPI_PUSHR_CONT) >> 16; //Enable 16 Bit Transfers + Continue-Bit
dmatx.triggerAtHardwareEvent(DMAMUX_SOURCE_SPI0_TX );
#endif
dmatx = dmasettings[0];
digitalWrite(_cs, 0);
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);
digitalWrite(_dc, 0);
SPI.transfer(TFT_RAMWR);
digitalWrite(_dc, 1);
dmatx.enable();
}
void TFT_T_DMA::stopDMA(void) {
rstop = 0;
wait();
delay(50);
cancelled = false;
dmatx.detachInterrupt();
fillScreen(RGBVAL16(0x00,0x00,0x00));
SPI.end();
#ifdef ST7789
begin();
#endif
#ifdef ILI9341
SPI.begin();
digitalWrite(_cs, 0);
SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE));
SPI.endTransaction();
digitalWrite(_cs, 1);
digitalWrite(_dc, 1);
#endif
setArea(0, 0, TFT_REALWIDTH-1, TFT_REALHEIGHT-1);
}
void TFT_T_DMA::wait(void) {
rstop = 1;
unsigned long m = millis();
cancelled = true;
while (!rstop) {
if ((millis() - m) > 100) break;
delay(10);
asm volatile("wfi");
};
rstop = 0;
}
/***********************************************************************************************
Touch functions
***********************************************************************************************/
/* Code based on ...
*
* @file XPT2046.cpp
* @date 19.02.2016
* @author Markus Sattler
*
* Copyright (c) 2015 Markus Sattler. All rights reserved.
* This file is part of the XPT2046 driver for Arduino.
*/
#define ADC_MAX 0x0fff
void TFT_T_DMA::enableTouchIrq()
{
SPI.beginTransaction(SPI_SETTING);
digitalWrite(_touch_cs, LOW);
const uint8_t buf[4] = { (XPT2046_CFG_START | XPT2046_CFG_12BIT | XPT2046_CFG_DFR | XPT2046_CFG_MUX(XPT2046_MUX_Y)), 0x00, 0x00, 0x00 };
SPI.transfer((void*)&buf[0],3);
digitalWrite(_touch_cs, HIGH);
SPI.endTransaction();
}
//Default callibration for non flipped
#define TX_MIN 30
#define TY_MIN 20
#define TX_MAX 300
#define TY_MAX 220
//Default callibration for flipped
#define TFX_MIN 20
#define TFY_MIN 25
#define TFX_MAX 288
#define TFY_MAX 221
static uint16_t txMin;
static uint16_t tyMin;
static uint16_t txMax;
static uint16_t tyMax;
void TFT_T_DMA::callibrateTouch(uint16_t xMin,uint16_t yMin,uint16_t xMax,uint16_t yMax) {
if ( (xMin >= 0) && (yMin >= 0) && (xMax < 320) && (yMax < 200) ) {
txMin = xMin;
tyMin = yMin;
txMax = xMax;
tyMax = yMax;
}
else {
if (flipped) {
txMin = TFX_MIN;
tyMin = TFY_MIN;
txMax = TFX_MAX;
tyMax = TFY_MAX;
}
else {
txMin = TX_MIN;
tyMin = TY_MIN;
txMax = TX_MAX;
tyMax = TY_MAX;
}
}
}
void TFT_T_DMA::readRaw(uint16_t * oX, uint16_t * oY, uint16_t * oZ) {
if ( TOUCH_ENABLED() ) {
uint16_t x = 0;
uint16_t y = 0;
uint16_t z1 = 0;
uint16_t z2 = 0;
uint8_t i = 0;
int16_t xraw=0, yraw=0;
SPI.beginTransaction(SPI_SETTING);
digitalWrite(_touch_cs, LOW);
for(; i < 15; i++) {
// SPI requirer 32bit aliment
uint8_t buf[12] = {
(XPT2046_CFG_START | XPT2046_CFG_12BIT | XPT2046_CFG_DFR | XPT2046_CFG_MUX(XPT2046_MUX_Y) | XPT2046_CFG_PWR(3)), 0x00, 0x00,
(XPT2046_CFG_START | XPT2046_CFG_12BIT | XPT2046_CFG_DFR | XPT2046_CFG_MUX(XPT2046_MUX_X) | XPT2046_CFG_PWR(3)), 0x00, 0x00,
(XPT2046_CFG_START | XPT2046_CFG_12BIT | XPT2046_CFG_DFR | XPT2046_CFG_MUX(XPT2046_MUX_Z1)| XPT2046_CFG_PWR(3)), 0x00, 0x00,
(XPT2046_CFG_START | XPT2046_CFG_12BIT | XPT2046_CFG_DFR | XPT2046_CFG_MUX(XPT2046_MUX_Z2)| XPT2046_CFG_PWR(3)), 0x00, 0x00
};
SPI.transfer(&buf[0], &buf[0], 12);
y += (buf[1] << 8 | buf[2])>>3;
x += (buf[4] << 8 | buf[5])>>3;
z1 += (buf[7] << 8 | buf[8])>>3;
z2 += (buf[10] << 8 | buf[11])>>3;
}
enableTouchIrq();
if(i == 0) {
*oX = 0;
*oY = 0;
*oZ = 0;
}
else {
x /= i;
y /= i;
z1 /= i;
z2 /= i;
}
digitalWrite(_touch_cs, HIGH);
SPI.endTransaction();
int z = z1 + ADC_MAX - z2;
if (flipped) {
xraw = x;
yraw = y;
} else {
xraw = ADC_MAX - x;
yraw = ADC_MAX - y;
}
xraw=(xraw*TFT_REALWIDTH)/(ADC_MAX+1);
yraw=(yraw*TFT_REALHEIGHT)/(ADC_MAX+1);
*oX = xraw;
*oY = yraw;
*oZ = z;
}
else
{
*oX = 0;
*oY = 0;
*oZ = 0;
}
}
void TFT_T_DMA::readCal(uint16_t * oX, uint16_t * oY, uint16_t * oZ) {
readRaw(oX,oY,oZ);
// callibrate ...
if(*oX >= txMin) *oX = ((*oX - txMin)*TFT_REALWIDTH)/(txMax-txMin);
if(*oY >= tyMin) *oY = ((*oY - tyMin)*TFT_REALHEIGHT)/(tyMax-tyMin);
//Serial.print(*oX);
//Serial.print(" ");
//Serial.println(*oY);
}
/***********************************************************************************************
No DMA functions
***********************************************************************************************/
void TFT_T_DMA::fillScreenNoDma(uint16_t color) {
SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE));
digitalWrite(_cs, 0);
setArea(0, 0, TFT_REALWIDTH-1, TFT_REALHEIGHT-1);
//digitalWrite(_dc, 0);
//SPI.transfer(TFT_RAMWR);
int i,j;
for (j=0; j<TFT_REALHEIGHT; j++)
{
for (i=0; i<TFT_REALWIDTH; i++) {
//digitalWrite(_dc, 1);
SPI.transfer16(color);
}
}
#ifdef ILI9341
digitalWrite(_dc, 0);
SPI.transfer(ILI9341_SLPOUT);
digitalWrite(_dc, 1);
#endif
digitalWrite(_cs, 1);
setArea(0, 0, (TFT_REALWIDTH-1), (TFT_REALHEIGHT-1));
SPI.endTransaction();
}
void TFT_T_DMA::drawRectNoDma(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color) {
SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE));
digitalWrite(_cs, 0);
setArea(x,y,x+w-1,y+h-1);
// digitalWrite(_dc, 0);
// SPI.transfer(TFT_RAMWR);
int i;
for (i=0; i<(w*h); i++)
{
//digitalWrite(_dc, 1);
SPI.transfer16(color);
}
#ifdef ILI9341
digitalWrite(_dc, 0);
SPI.transfer(ILI9341_SLPOUT);
digitalWrite(_dc, 1);
#endif
digitalWrite(_cs, 1);
setArea(0, 0, (TFT_REALWIDTH-1), (TFT_REALHEIGHT-1));
SPI.endTransaction();
}
void TFT_T_DMA::writeScreenNoDma(const uint16_t *pcolors) {
SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE));
digitalWrite(_cs, 0);
setArea(0, 0, TFT_WIDTH-1, TFT_HEIGHT-1);
//digitalWrite(_dc, 0);
//SPI.transfer(TFT_RAMWR);
int i,j;
for (j=0; j<240; j++)
{
for (i=0; i<TFT_WIDTH; i++) {
// digitalWrite(_dc, 1);
SPI.transfer16(*pcolors++);
}
}
#ifdef ILI9341
digitalWrite(_dc, 0);
SPI.transfer(ILI9341_SLPOUT);
digitalWrite(_dc, 1);
#endif
digitalWrite(_cs, 1);
setArea(0, 0, (TFT_REALWIDTH-1), (TFT_REALHEIGHT-1));
SPI.endTransaction();
}
void TFT_T_DMA::drawSpriteNoDma(int16_t x, int16_t y, const uint16_t *bitmap) {
drawSpriteNoDma(x,y,bitmap, 0,0,0,0);
}
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)
{
int bmp_offx = 0;
int bmp_offy = 0;
uint16_t *bmp_ptr;
int w =*bitmap++;
int h = *bitmap++;
//Serial.println(w);
//Serial.println(h);
if ( (arw == 0) || (arh == 0) ) {
// no crop window
arx = x;
ary = y;
arw = w;
arh = h;
}
else {
if ( (x>(arx+arw)) || ((x+w)<arx) || (y>(ary+arh)) || ((y+h)<ary) ) {
return;
}
// crop area
if ( (x > arx) && (x<(arx+arw)) ) {
arw = arw - (x-arx);
arx = arx + (x-arx);
} else {
bmp_offx = arx;
}
if ( ((x+w) > arx) && ((x+w)<(arx+arw)) ) {
arw -= (arx+arw-x-w);
}
if ( (y > ary) && (y<(ary+arh)) ) {
arh = arh - (y-ary);
ary = ary + (y-ary);
} else {
bmp_offy = ary;
}
if ( ((y+h) > ary) && ((y+h)<(ary+arh)) ) {
arh -= (ary+arh-y-h);
}
}
SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE));
digitalWrite(_cs, 0);
setArea(arx, ary, arx+arw-1, ary+arh-1);
//digitalWrite(_dc, 0);
//SPI.transfer(TFT_RAMWR);
bitmap = bitmap + bmp_offy*w + bmp_offx;
for (int row=0;row<arh; row++)
{
bmp_ptr = (uint16_t*)bitmap;
for (int col=0;col<arw; col++)
{
uint16_t color = *bmp_ptr++;
// digitalWrite(_dc, 1);
SPI.transfer16(color);
}
bitmap += w;
}
#ifdef ILI9341
digitalWrite(_dc, 0);
SPI.transfer(ILI9341_SLPOUT);
digitalWrite(_dc, 1);
#endif
setArea(0, 0, TFT_REALWIDTH-1, TFT_REALHEIGHT-1);
digitalWrite(_cs, 1);
SPI.endTransaction();
}
void TFT_T_DMA::drawTextNoDma(int16_t x, int16_t y, const char * text, uint16_t fgcolor, uint16_t bgcolor, bool doublesize) {
uint16_t c;
while ((c = *text++)) {
const unsigned char * charpt=&font8x8[c][0];
SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE));
digitalWrite(_cs, 0);
setArea(x,y,x+7,y+(doublesize?15:7));
//digitalWrite(_dc, 0);
//SPI.transfer(TFT_RAMWR);
//digitalWrite(_dc, 1);
for (int i=0;i<8;i++)
{
unsigned char bits;
if (doublesize) {
bits = *charpt;
//digitalWrite(_dc, 1);
if (bits&0x01) SPI.transfer16(fgcolor);
else SPI.transfer16(bgcolor);
bits = bits >> 1;
if (bits&0x01) SPI.transfer16(fgcolor);
else SPI.transfer16(bgcolor);
bits = bits >> 1;
if (bits&0x01) SPI.transfer16(fgcolor);
else SPI.transfer16(bgcolor);
bits = bits >> 1;
if (bits&0x01) SPI.transfer16(fgcolor);
else SPI.transfer16(bgcolor);
bits = bits >> 1;
if (bits&0x01) SPI.transfer16(fgcolor);
else SPI.transfer16(bgcolor);
bits = bits >> 1;
if (bits&0x01) SPI.transfer16(fgcolor);
else SPI.transfer16(bgcolor);
bits = bits >> 1;
if (bits&0x01) SPI.transfer16(fgcolor);
else SPI.transfer16(bgcolor);
bits = bits >> 1;
if (bits&0x01) SPI.transfer16(fgcolor);
else SPI.transfer16(bgcolor);
}
bits = *charpt++;
//digitalWrite(_dc, 1);
if (bits&0x01) SPI.transfer16(fgcolor);
else SPI.transfer16(bgcolor);
bits = bits >> 1;
if (bits&0x01) SPI.transfer16(fgcolor);
else SPI.transfer16(bgcolor);
bits = bits >> 1;
if (bits&0x01) SPI.transfer16(fgcolor);
else SPI.transfer16(bgcolor);
bits = bits >> 1;
if (bits&0x01) SPI.transfer16(fgcolor);
else SPI.transfer16(bgcolor);
bits = bits >> 1;
if (bits&0x01) SPI.transfer16(fgcolor);
else SPI.transfer16(bgcolor);
bits = bits >> 1;
if (bits&0x01) SPI.transfer16(fgcolor);
else SPI.transfer16(bgcolor);
bits = bits >> 1;
if (bits&0x01) SPI.transfer16(fgcolor);
else SPI.transfer16(bgcolor);
bits = bits >> 1;
if (bits&0x01) SPI.transfer16(fgcolor);
else SPI.transfer16(bgcolor);
}
x +=8;
#ifdef ILI9341
digitalWrite(_dc, 0);
SPI.transfer(ILI9341_SLPOUT);
digitalWrite(_dc, 1);
#endif
digitalWrite(_cs, 1);
SPI.endTransaction();
}
SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE));
digitalWrite(_cs, 0);
setArea(0, 0, (TFT_REALWIDTH-1), (TFT_REALHEIGHT-1));
digitalWrite(_cs, 1);
SPI.endTransaction();
}
/***********************************************************************************************
DMA functions
***********************************************************************************************/
uint16_t * TFT_T_DMA::getLineBuffer(int j)
{
uint16_t * block=blocks[j>>6];
return(&block[(j&0x3F)*TFT_REALWIDTH]);
}
void TFT_T_DMA::writeScreen(int width, int height, int stride, uint8_t *buf, uint16_t *palette16) {
uint8_t *buffer=buf;
uint8_t *src;
int i,j,y=0;
if (width*2 <= TFT_REALWIDTH) {
for (j=0; j<height; j++)
{
uint16_t * block=blocks[y>>6];
uint16_t * dst=&block[(y&0x3F)*TFT_WIDTH];
src=buffer;
for (i=0; i<width; i++)
{
uint16_t val = palette16[*src++];
*dst++ = val;
*dst++ = val;
}
y++;
if (height*2 <= TFT_HEIGHT) {
block=blocks[y>>6];
dst=&block[(y&0x3F)*TFT_WIDTH];
src=buffer;
for (i=0; i<width; i++)
{
uint16_t val = palette16[*src++];
*dst++ = val;
*dst++ = val;
}
y++;
}
buffer += stride;
}
}
else if (width <= TFT_REALWIDTH) {
//dst += (TFT_WIDTH-width)/2;
for (j=0; j<height; j++)
{
uint16_t * block=blocks[y>>6];
uint16_t * dst=&block[(y&0x3F)*TFT_WIDTH+(TFT_WIDTH-width)/2];
src=buffer;
for (i=0; i<width; i++)
{
uint16_t val = palette16[*src++];
*dst++ = val;
}
y++;
if (height*2 <= TFT_HEIGHT) {
block=blocks[y>>6];
dst=&block[(y&0x3F)*TFT_WIDTH+(TFT_WIDTH-width)/2];
src=buffer;
for (i=0; i<width; i++)
{
uint16_t val = palette16[*src++];
*dst++ = val;
}
y++;
}
buffer += stride;
}
}
}
void TFT_T_DMA::writeLine(int width, int height, int y, uint8_t *buf, uint16_t *palette16) {
uint16_t * block=blocks[y>>6];
uint16_t * dst=&block[(y&0x3F)*TFT_WIDTH];
if (width > TFT_WIDTH) {
#ifdef TFT_LINEARINT
int delta = (width/(width-TFT_WIDTH))-1;
int pos = delta;
for (int i=0; i<TFT_WIDTH; i++)
{
uint16_t val = palette16[*buf++];
pos--;
if (pos == 0) {
#ifdef LINEARINT_HACK
val = ((uint32_t)palette16[*buf++] + val)/2;
#else
uint16_t val2 = *buf++;
val = RGBVAL16((R16(val)+R16(val2))/2,(G16(val)+G16(val2))/2,(B16(val)+B16(val2))/2);
#endif
pos = delta;
}
*dst++=val;
}
#else
int step = ((width << 8)/TFT_WIDTH);
int pos = 0;
for (int i=0; i<TFT_WIDTH; i++)
{
*dst++=palette16[buf[pos >> 8]];
pos +=step;
}
#endif
}
else if ((width*2) == TFT_WIDTH) {
for (int i=0; i<width; i++)
{
*dst++=palette16[*buf];
*dst++=palette16[*buf++];
}
}
else {
if (width <= TFT_WIDTH) {
dst += (TFT_WIDTH-width)/2;
}
for (int i=0; i<width; i++)
{
*dst++=palette16[*buf++];
}
}
}
void TFT_T_DMA::writeLine(int width, int height, int y, uint16_t *buf) {
uint16_t * block=blocks[y>>6];
uint16_t * dst=&block[(y&0x3F)*TFT_WIDTH];
if (width > TFT_WIDTH) {
#ifdef TFT_LINEARINT
int delta = (width/(width-TFT_WIDTH))-1;
int pos = delta;
for (int i=0; i<TFT_WIDTH; i++)
{
uint16_t val = *buf++;
pos--;
if (pos == 0) {
#ifdef LINEARINT_HACK
val = ((uint32_t)*buf++ + val)/2;
#else
uint16_t val2 = *buf++;
val = RGBVAL16((R16(val)+R16(val2))/2,(G16(val)+G16(val2))/2,(B16(val)+B16(val2))/2);
#endif
pos = delta;
}
*dst++=val;
}
#else
int step = ((width << 8)/TFT_WIDTH);
int pos = 0;
for (int i=0; i<TFT_WIDTH; i++)
{
*dst++=buf[pos >> 8];
pos +=step;
}
#endif
}
else if ((width*2) == TFT_WIDTH) {
for (int i=0; i<width; i++)
{
*dst++=*buf;
*dst++=*buf++;
}
}
else {
if (width <= TFT_WIDTH) {
dst += (TFT_WIDTH-width)/2;
}
for (int i=0; i<width; i++)
{
*dst++=*buf++;
}
}
}
void TFT_T_DMA::fillScreen(uint16_t color) {
int i,j;
for (j=0; j<TFT_HEIGHT; j++)
{
uint16_t * block=blocks[j>>6];
uint16_t * dst=&block[(j&0x3F)*TFT_WIDTH];
for (i=0; i<TFT_WIDTH; i++)
{
*dst++ = color;
}
}
}
void TFT_T_DMA::drawRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color) {
int i,j,l=y;
color=color;
for (j=0; j<h; j++)
{
uint16_t * block=blocks[l>>6];
uint16_t * dst=&block[(l&0x3F)*TFT_WIDTH+x];
for (i=0; i<w; i++)
{
*dst++ = color;
}
l++;
}
}
void TFT_T_DMA::drawText(int16_t x, int16_t y, const char * text, uint16_t fgcolor, uint16_t bgcolor, bool doublesize) {
uint16_t c;
uint16_t * block;
uint16_t * dst;
fgcolor = fgcolor;
bgcolor = bgcolor;
while ((c = *text++)) {
const unsigned char * charpt=&font8x8[c][0];
int l=y;
for (int i=0;i<8;i++)
{
unsigned char bits;
if (doublesize) {
block=blocks[l>>6];
dst=&block[(l&0x3F)*TFT_WIDTH+x];
bits = *charpt;
if (bits&0x01) *dst++=fgcolor;
else *dst++=bgcolor;
bits = bits >> 1;
if (bits&0x01) *dst++=fgcolor;
else *dst++=bgcolor;
bits = bits >> 1;
if (bits&0x01) *dst++=fgcolor;
else *dst++=bgcolor;
bits = bits >> 1;
if (bits&0x01) *dst++=fgcolor;
else *dst++=bgcolor;
bits = bits >> 1;
if (bits&0x01) *dst++=fgcolor;
else *dst++=bgcolor;
bits = bits >> 1;
if (bits&0x01) *dst++=fgcolor;
else *dst++=bgcolor;
bits = bits >> 1;
if (bits&0x01) *dst++=fgcolor;
else *dst++=bgcolor;
bits = bits >> 1;
if (bits&0x01) *dst++=fgcolor;
else *dst++=bgcolor;
l++;
}
block=blocks[l>>6];
dst=&block[(l&0x3F)*TFT_WIDTH+x];
bits = *charpt++;
if (bits&0x01) *dst++=fgcolor;
else *dst++=bgcolor;
bits = bits >> 1;
if (bits&0x01) *dst++=fgcolor;
else *dst++=bgcolor;
bits = bits >> 1;
if (bits&0x01) *dst++=fgcolor;
else *dst++=bgcolor;
bits = bits >> 1;
if (bits&0x01) *dst++=fgcolor;
else *dst++=bgcolor;
bits = bits >> 1;
if (bits&0x01) *dst++=fgcolor;
else *dst++=bgcolor;
bits = bits >> 1;
if (bits&0x01) *dst++=fgcolor;
else *dst++=bgcolor;
bits = bits >> 1;
if (bits&0x01) *dst++=fgcolor;
else *dst++=bgcolor;
bits = bits >> 1;
if (bits&0x01) *dst++=fgcolor;
else *dst++=bgcolor;
l++;
}
x +=8;
}
}
void TFT_T_DMA::drawSprite(int16_t x, int16_t y, const uint16_t *bitmap) {
drawSprite(x,y,bitmap, 0,0,0,0);
}
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)
{
int bmp_offx = 0;
int bmp_offy = 0;
uint16_t *bmp_ptr;
int w =*bitmap++;
int h = *bitmap++;
if ( (arw == 0) || (arh == 0) ) {
// no crop window
arx = x;
ary = y;
arw = w;
arh = h;
}
else {
if ( (x>(arx+arw)) || ((x+w)<arx) || (y>(ary+arh)) || ((y+h)<ary) ) {
return;
}
// crop area
if ( (x > arx) && (x<(arx+arw)) ) {
arw = arw - (x-arx);
arx = arx + (x-arx);
} else {
bmp_offx = arx;
}
if ( ((x+w) > arx) && ((x+w)<(arx+arw)) ) {
arw -= (arx+arw-x-w);
}
if ( (y > ary) && (y<(ary+arh)) ) {
arh = arh - (y-ary);
ary = ary + (y-ary);
} else {
bmp_offy = ary;
}
if ( ((y+h) > ary) && ((y+h)<(ary+arh)) ) {
arh -= (ary+arh-y-h);
}
}
int l=ary;
bitmap = bitmap + bmp_offy*w + bmp_offx;
for (int row=0;row<arh; row++)
{
uint16_t * block=blocks[l>>6];
uint16_t * dst=&block[(l&0x3F)*TFT_WIDTH+arx];
bmp_ptr = (uint16_t*)bitmap;
for (int col=0;col<arw; col++)
{
*dst++ = *bmp_ptr++;
}
bitmap += w;
l++;
}
}