/* TFT/VGA driver DMA TFT driver based on C64 ILI9341 dma driver from Frank Bösing, 2017 */ #include "T4_DSP.h" #include #include #include "font8x8.h" // TFT constants and variables #define TFT_LINEARINT 1 #define LINEARINT_HACK 1 #define DMA_LINES_PER_BLOCK 64 #define DMA_NUM_SETTINGS 4 #define TFT_SWRESET 0x01 #define TFT_SLPOUT 0x11 #define TFT_INVON 0x21 #define TFT_DISPOFF 0x28 #define TFT_DISPON 0x29 #define TFT_CASET 0x2A #define TFT_PASET 0x2B #define TFT_RAMWR 0x2C #define TFT_MADCTL 0x36 #define TFT_PIXFMT 0x3A #define TFT_MADCTL_MY 0x80 #define TFT_MADCTL_MX 0x40 #define TFT_MADCTL_MV 0x20 #define TFT_MADCTL_ML 0x10 #define TFT_MADCTL_RGB 0x00 #define TFT_MADCTL_BGR 0x08 #define TFT_MADCTL_MH 0x04 #define RGBVAL16(r,g,b) ( (((r>>3)&0x1f)<<11) | (((g>>2)&0x3f)<<5) | (((b>>3)&0x1f)<<0) ) //#define RGBVAL32(r,g,b) ( (r<<16) | (g<<8) | b ) //#define RGBVAL8(r,g,b) ( (((r>>5)&0x07)<<5) | (((g>>5)&0x07)<<2) | (((b>>6)&0x3)<<0) ) //#define R16(rgb) ((rgb>>8)&0xf8) //#define G16(rgb) ((rgb>>3)&0xfc) //#define B16(rgb) ((rgb<<3)&0xf8) // LPSPI4 = SPI0 in Teensy 4.0 // LPSPI3 = SPI1 in Teensy 4.0 // LPSPI1 = SPI2 in Teensy 4.0 (used for SD on T4.0 but not T4.1) #ifdef TFTSPI1 #define SPI SPI1 #define LPSPIP_TDR LPSPI3_TDR #define LPSPIP_CR LPSPI3_CR #define LPSPIP_CFGR1 LPSPI3_CFGR1 #define LPSPIP_TCR LPSPI3_TCR #define LPSPIP_DER LPSPI3_DER #define DMAMUX_SOURCE_LPSPIP_TX DMAMUX_SOURCE_LPSPI3_TX #else #define LPSPIP_TDR LPSPI4_TDR #define LPSPIP_CR LPSPI4_CR #define LPSPIP_CFGR1 LPSPI4_CFGR1 #define LPSPIP_TCR LPSPI4_TCR #define LPSPIP_DER LPSPI4_DER #define DMAMUX_SOURCE_LPSPIP_TX DMAMUX_SOURCE_LPSPI4_TX #endif #define SPICLOCK 60000000 #define SPI_MODE SPI_MODE0 // VGA constants and macros typedef uint8_t vga_pixel; #define VGA_RGB(r,g,b) ( (((r>>5)&0x07)<<5) | (((g>>5)&0x07)<<2) | (((b>>6)&0x3)<<0) ) static DMASetting dmasettings[DMA_NUM_SETTINGS]; static DMAChannel dmatx; static uint16_t * blocks[DMA_NUM_SETTINGS]; // for DMA transfer, you need to divide in blocks < 128K static volatile uint8_t rstop = 0; static volatile bool cancelled = false; static volatile uint8_t curTransfer = 0; static uint8_t nbTransfer = 0; static uint16_t * tft_buffer; static int tft_width; static int tft_height; static int tft_stride; #define DELAY_MASK 0x80 PROGMEM static const uint8_t init_commands[] = { 1+DELAY_MASK, TFT_SWRESET, 150, 1+DELAY_MASK, TFT_SLPOUT, 255, 2+DELAY_MASK, TFT_PIXFMT, 0x55, 10, 2, TFT_MADCTL, TFT_MADCTL_MV | TFT_MADCTL_BGR, 1, TFT_INVON, 1, TFT_DISPON, 0 }; // VGA constants and variables // Objective: // generates VGA signal fully in hardware with as little as possible CPU help // Principle: // QTimer3 (timer3) used to generate H-PUSE and line interrupt (and V-PULSE) // 2 FlexIO shift registers (1 and 2) and 2 DMA channels used to generate // RGB out, combined to create 8bits(/12bits) output. // Note: // - supported resolutions: 320x240,320x480,640x240 and 640x480 pixels // - experimental resolution: 352x240,352x480 // - experimental resolution: 512x240,512x480 (not stable) // - video memory is allocated using malloc in T4 heap // - as the 2 DMA transfers are not started exactly at same time, there is a bit of color smearing // but tried to be compensated by pixel shifting // - Default is 8bits RRRGGGBB (332) // But 12bits GBB0RRRRGGGBB (444) feasible BUT NOT TESTED !!!! // - Only ok at 600MHz else some disturbances visible #define TOP_BORDER 40 #define PIN_HBLANK 15 #define PIN_R_B2 33 #define PIN_R_B1 4 #define PIN_R_B0 3 #define PIN_G_B2 2 #define PIN_G_B1 13 #define PIN_G_B0 11 #define PIN_B_B1 12 #define PIN_B_B0 10 #define DMA_HACK 0x80 #define R16(rgb) ((rgb>>8)&0xf8) #define G16(rgb) ((rgb>>3)&0xfc) #define B16(rgb) ((rgb<<3)&0xf8) // VGA 640x480@60Hz // Screen refresh rate 60 Hz // Vertical refresh 31.46875 kHz // Pixel freq. 25.175 MHz // // Visible area 640 25.422045680238 us // Front porch 16 0.63555114200596 us // Sync pulse 96 3.8133068520357 us // Back porch 48 1.9066534260179 us // Whole line 800 31.777557100298 us #define frame_freq 60.0 // Hz #define line_freq 31.46875 // KHz #define pix_freq (line_freq*800) // KHz (25.175 MHz) // pix_period = 39.7ns // H-PULSE is 3.8133us = 3813.3ns => 96 pixels (see above for the rest) #define frontporch_pix 20 //16 #define backporch_pix 44 //48 // Flexio Clock // PLL3 SW CLOCK (3) => 480 MHz // PLL5 VIDEO CLOCK (2) => See formula for clock (we take 604200 KHz as /24 it gives 25175) #define FLEXIO_CLK_SEL_PLL3 3 #define FLEXIO_CLK_SEL_PLL5 2 /* Set video PLL */ // There are /1, /2, /4, /8, /16 post dividers for the Video PLL. // The output frequency can be set by programming the fields in the CCM_ANALOG_PLL_VIDEO, // and CCM_ANALOG_MISC2 register sets according to the following equation. // PLL output frequency = Fref * (DIV_SELECT + NUM/DENOM) // nfact: // This field controls the PLL loop divider. // Valid range for DIV_SELECT divider value: 27~54. #define POST_DIV_SELECT 2 // Full buffer including back/front porch static vga_pixel * gfxbuffer __attribute__((aligned(32))) = NULL; static uint32_t dstbuffer __attribute__((aligned(32))); // Visible vuffer static vga_pixel * vga_buffer; static int vga_width; static int vga_height; static int vga_stride; static int maxpixperline; static int left_border; static int right_border; static int line_double; static int pix_shift; static int ref_div_select; static int ref_freq_num; static int ref_freq_denom; static int ref_pix_shift; static int combine_shiftreg; #ifdef DEBUG static uint32_t ISRTicks_prev = 0; volatile uint32_t ISRTicks = 0; #endif uint8_t T4_DSP::_rst; uint8_t T4_DSP::_cs; uint8_t T4_DSP::_dc; uint8_t T4_DSP::_mosi; uint8_t T4_DSP::_sclk; uint8_t T4_DSP::_vsync_pin = -1; DMAChannel T4_DSP::flexio1DMA; DMAChannel T4_DSP::flexio2DMA; static volatile uint32_t VSYNC = 0; static volatile uint32_t currentLine=0; #define NOP asm volatile("nop\n\t"); static gfx_mode_t gfxmode = MODE_UNDEFINED; FASTRUN void T4_DSP::TFT_isr(void) { dmatx.clearInterrupt(); curTransfer++; if (curTransfer >= nbTransfer) { curTransfer = 0; if (cancelled) { dmatx.disable(); rstop = 1; } } arm_dcache_flush(blocks[curTransfer], DMA_LINES_PER_BLOCK*TFT_WIDTH*2); } FASTRUN void T4_DSP::QT3_isr(void) { TMR3_SCTRL3 &= ~(TMR_SCTRL_TCF); TMR3_CSCTRL3 &= ~(TMR_CSCTRL_TCF1|TMR_CSCTRL_TCF2); cli(); // V-PULSE if (currentLine > 0) { digitalWrite(_vsync_pin, 1); VSYNC = 0; } else { digitalWrite(_vsync_pin, 0); VSYNC = 1; } currentLine++; currentLine = currentLine % 525; uint32_t y = (currentLine - TOP_BORDER) >> line_double; // Visible area if (y >= 0 && y < vga_height) { // Disable DMAs //DMA_CERQ = flexio2DMA.channel; //DMA_CERQ = flexio1DMA.channel; // Setup source adress // Aligned 32 bits copy unsigned long * p=(uint32_t *)&gfxbuffer[vga_stride*y]; flexio2DMA.TCD->SADDR = p; if (pix_shift & DMA_HACK) { // Unaligned copy uint8_t * p2=(uint8_t *)&gfxbuffer[vga_stride*y+(pix_shift&0xf)]; flexio1DMA.TCD->SADDR = p2; } else { p=(uint32_t *)&gfxbuffer[vga_stride*y+(pix_shift&0xc)]; // multiple of 4 flexio1DMA.TCD->SADDR = p; } // Enable DMAs //flexio2DMA.enable(); //flexio1DMA.enable(); DMA_SERQ = flexio2DMA.channel; DMA_SERQ = flexio1DMA.channel; arm_dcache_flush_delete((void*)((uint32_t *)&gfxbuffer[vga_stride*y]), vga_stride); } sei(); #ifdef DEBUG ISRTicks++; #endif asm volatile("dsb"); } static void setDmaStruct() { uint32_t remaining = TFT_HEIGHT*TFT_WIDTH*2; uint16_t * fb = (uint16_t*)malloc(remaining); tft_buffer = fb; tft_width = TFT_WIDTH; tft_height = TFT_HEIGHT; tft_stride = TFT_WIDTH; uint16_t col=RGBVAL16(0x00,0x00,0x00); int i=0; while (remaining > 0) { int32_t len = (remaining >= (DMA_LINES_PER_BLOCK*TFT_WIDTH*2)?DMA_LINES_PER_BLOCK*TFT_WIDTH*2:remaining); blocks[i] = fb; for (int j=0;jATTR_DST = 1; dmasettings[i].replaceSettingsOnCompletion(dmasettings[i+1]); dmasettings[i].interruptAtCompletion(); fb += len/2; remaining -= len; i++; } dmasettings[i-1].replaceSettingsOnCompletion(dmasettings[0]); nbTransfer = i; } static void set_videoClock(int nfact, int32_t nmult, uint32_t ndiv, bool force) // sets PLL5 { //if (!force && (CCM_ANALOG_PLL_VIDEO & CCM_ANALOG_PLL_VIDEO_ENABLE)) return; CCM_ANALOG_PLL_VIDEO = CCM_ANALOG_PLL_VIDEO_BYPASS | CCM_ANALOG_PLL_VIDEO_ENABLE | CCM_ANALOG_PLL_VIDEO_POST_DIV_SELECT(1) // 2: 1/1; 1: 1/2; 0: 1/4 | CCM_ANALOG_PLL_VIDEO_DIV_SELECT(nfact); CCM_ANALOG_PLL_VIDEO_NUM = nmult /*& CCM_ANALOG_PLL_VIDEO_NUM_MASK*/; CCM_ANALOG_PLL_VIDEO_DENOM = ndiv /*& CCM_ANALOG_PLL_VIDEO_DENOM_MASK*/; CCM_ANALOG_PLL_VIDEO &= ~CCM_ANALOG_PLL_VIDEO_POWERDOWN;//Switch on PLL while (!(CCM_ANALOG_PLL_VIDEO & CCM_ANALOG_PLL_VIDEO_LOCK)) {}; //Wait for pll-lock const int div_post_pll = 1; // other values: 2,4 if(div_post_pll>3) CCM_ANALOG_MISC2 |= CCM_ANALOG_MISC2_DIV_MSB; CCM_ANALOG_PLL_VIDEO &= ~CCM_ANALOG_PLL_VIDEO_BYPASS;//Disable Bypass } T4_DSP::T4_DSP() { _cs = TFT_CS; _dc = TFT_DC; _rst = TFT_RST; _mosi = TFT_MOSI; _sclk = TFT_SCLK; pinMode(_dc, OUTPUT); pinMode(_cs, OUTPUT); digitalWrite(_cs, 1); digitalWrite(_dc, 1); _vsync_pin = 8; } void T4_DSP::setArea(uint16_t x1,uint16_t y1,uint16_t x2,uint16_t y2) { int dx=0; int dy=0; 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; } void T4_DSP::tft_setup(bool isST) { SPI.setMOSI(_mosi); SPI.setSCK(_sclk); SPI.begin(); // RESET if reset pin defined 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; uint8_t count; digitalWrite(_cs, 0); while (count = *addr++) { uint8_t command = *addr++; if ( (command == TFT_INVON) && (!isST) ) { // Skip TFT_INVON for ILI } else { digitalWrite(_dc, 0); // command SPI.transfer(command); uint16_t ms = count & DELAY_MASK; count &= ~DELAY_MASK; while (--count > 0) { // data uint8_t data = *addr++; if ( (command == TFT_MADCTL) && (isST) ) { data = TFT_MADCTL_MX | TFT_MADCTL_MV |TFT_MADCTL_RGB; } digitalWrite(_dc, 1); SPI.transfer(data); } 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(2); SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); digitalWrite(_cs, 0); } } } digitalWrite(_cs, 1); SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); setArea(0, 0, TFT_REALWIDTH-1, TFT_REALHEIGHT-1); SPI.endTransaction(); /* SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); digitalWrite(_dc, 0); digitalWrite(_cs, 0); SPI.transfer(TFT_MADCTL); digitalWrite(_dc, 1); SPI.transfer(TFT_MADCTL_MV | TFT_MADCTL_BGR); // SPI.transfer(TFT_MADCTL_MX | TFT_MADCTL_MV |TFT_MADCTL_RGB); digitalWrite(_cs, 1); SPI.endTransaction(); */ cancelled = false; } // display VGA image gfx_error_t T4_DSP::begin(gfx_mode_t mode) { uint32_t flexio_clock_div; combine_shiftreg = 0; // int div_select = 49; // int num = 135; // int denom = 100; int div_select = 20; int num = 9800; int denom = 10000; int flexio_clk_sel = FLEXIO_CLK_SEL_PLL5; int flexio_freq = ( 24000*div_select + (num*24000)/denom )/POST_DIV_SELECT; set_videoClock(div_select,num,denom,true); #ifdef DEBUG Serial.println(mode); Serial.println("mode"); #endif switch(mode) { case MODE_TFTILI_320x240: #ifdef DEBUG Serial.println("TFTILI_320x240"); #endif tft_setup(false); gfxmode = mode; break; case MODE_TFTST_320x240: #ifdef DEBUG Serial.println("TFTST_320x240"); #endif tft_setup(true); gfxmode = mode; break; case MODE_VGA_320x240: #ifdef DEBUG Serial.println("VGA_320x240"); #endif left_border = backporch_pix/2; right_border = frontporch_pix/2; vga_width = 320; vga_height = 240 ; vga_stride = left_border+vga_width+right_border; flexio_clock_div = flexio_freq/(pix_freq/2); line_double = 1; pix_shift = 2+DMA_HACK; break; case MODE_VGA_320x480: #ifdef DEBUG Serial.println("VGA_320x480"); #endif left_border = backporch_pix/2; right_border = frontporch_pix/2; vga_width = 320; vga_height = 480 ; vga_stride = left_border+vga_width+right_border; flexio_clock_div = flexio_freq/(pix_freq/2); line_double = 0; pix_shift = 2+DMA_HACK; break; case MODE_VGA_640x240: #ifdef DEBUG Serial.println("VGA_640x240"); #endif left_border = backporch_pix; right_border = frontporch_pix; vga_width = 640; vga_height = 240 ; vga_stride = left_border+vga_width+right_border; flexio_clock_div = flexio_freq/pix_freq; line_double = 1; pix_shift = 4; combine_shiftreg = 1; break; case MODE_VGA_640x480: #ifdef DEBUG Serial.println("VGA_640x480"); #endif left_border = backporch_pix; right_border = frontporch_pix; vga_width = 640; vga_height = 480 ; vga_stride = left_border+vga_width+right_border; flexio_clock_div = (flexio_freq/pix_freq); line_double = 0; pix_shift = 4; combine_shiftreg = 1; break; case MODE_VGA_512x240: #ifdef DEBUG Serial.println("VGA_512x240"); #endif left_border = backporch_pix/1.3; right_border = frontporch_pix/1.3; vga_width = 512; vga_height = 240 ; vga_stride = left_border+vga_width+right_border; flexio_clock_div = flexio_freq/(pix_freq/1.3)+2; line_double = 1; pix_shift = 0; break; case MODE_VGA_512x480: #ifdef DEBUG Serial.println("VGA_512x480"); #endif left_border = backporch_pix/1.3; right_border = frontporch_pix/1.3; vga_width = 512; vga_height = 480 ; vga_stride = left_border+vga_width+right_border; flexio_clock_div = flexio_freq/(pix_freq/1.3)+2; line_double = 0; pix_shift = 0; break; case MODE_VGA_352x240: #ifdef DEBUG Serial.println("VGA_352x240"); #endif left_border = backporch_pix/1.75; right_border = frontporch_pix/1.75; vga_width = 352; vga_height = 240 ; vga_stride = left_border+vga_width+right_border; flexio_clock_div = flexio_freq/(pix_freq/1.75)+2; line_double = 1; pix_shift = 2+DMA_HACK; break; case MODE_VGA_352x480: #ifdef DEBUG Serial.println("VGA_352x480"); #endif left_border = backporch_pix/1.75; right_border = frontporch_pix/1.75; vga_width = 352; vga_height = 480 ; vga_stride = left_border+vga_width+right_border; flexio_clock_div = flexio_freq/(pix_freq/1.75)+2; line_double = 0; pix_shift = 2+DMA_HACK; break; } if (mode >= MODE_VGA_320x240) { if ( (gfxmode != MODE_UNDEFINED) && (gfxmode < MODE_VGA_320x240) ) { fillScreenNoDma(RGBVAL16(0x0,0x00,0x00)); digitalWrite(_cs, 0); digitalWrite(_dc, 0); SPI.transfer(TFT_DISPOFF); digitalWrite(_cs, 1); delay(20); digitalWrite(_cs, 0); digitalWrite(_cs, 1); } gfxmode = mode; maxpixperline = vga_stride; // Save param for tweek adjustment ref_div_select = div_select; ref_freq_num = num; ref_freq_denom = denom; ref_pix_shift = pix_shift; #ifdef DEBUG Serial.println("frequency"); Serial.println(flexio_freq); Serial.println("div"); Serial.println(flexio_freq/pix_freq); #endif pinMode(_vsync_pin, OUTPUT); pinMode(PIN_HBLANK, OUTPUT); /* Basic pin setup FlexIO1 */ pinMode(PIN_G_B2, OUTPUT); // FlexIO1:4 = 0x10 pinMode(PIN_R_B0, OUTPUT); // FlexIO1:5 = 0x20 pinMode(PIN_R_B1, OUTPUT); // FlexIO1:6 = 0x40 pinMode(PIN_R_B2, OUTPUT); // FlexIO1:7 = 0x80 /* Basic pin setup FlexIO2 */ pinMode(PIN_B_B0, OUTPUT); // FlexIO2:0 = 0x00001 pinMode(PIN_B_B1, OUTPUT); // FlexIO2:1 = 0x00002 pinMode(PIN_G_B0, OUTPUT); // FlexIO2:2 = 0x00004 pinMode(PIN_G_B1, OUTPUT); // FlexIO2:3 = 0x00008 /* High speed and drive strength configuration */ *(portControlRegister(PIN_G_B2)) = 0xFF; *(portControlRegister(PIN_R_B0)) = 0xFF; *(portControlRegister(PIN_R_B1)) = 0xFF; *(portControlRegister(PIN_R_B2)) = 0xFF; *(portControlRegister(PIN_B_B0)) = 0xFF; *(portControlRegister(PIN_B_B1)) = 0xFF; *(portControlRegister(PIN_G_B0)) = 0xFF; *(portControlRegister(PIN_G_B1)) = 0xFF; /* Set clock for FlexIO1 and FlexIO2 */ CCM_CCGR5 &= ~CCM_CCGR5_FLEXIO1(CCM_CCGR_ON); CCM_CDCDR = (CCM_CDCDR & ~(CCM_CDCDR_FLEXIO1_CLK_SEL(3) | CCM_CDCDR_FLEXIO1_CLK_PRED(7) | CCM_CDCDR_FLEXIO1_CLK_PODF(7))) | CCM_CDCDR_FLEXIO1_CLK_SEL(flexio_clk_sel) | CCM_CDCDR_FLEXIO1_CLK_PRED(0) | CCM_CDCDR_FLEXIO1_CLK_PODF(0); CCM_CCGR3 &= ~CCM_CCGR3_FLEXIO2(CCM_CCGR_ON); CCM_CSCMR2 = (CCM_CSCMR2 & ~(CCM_CSCMR2_FLEXIO2_CLK_SEL(3))) | CCM_CSCMR2_FLEXIO2_CLK_SEL(flexio_clk_sel); CCM_CS1CDR = (CCM_CS1CDR & ~(CCM_CS1CDR_FLEXIO2_CLK_PRED(7)|CCM_CS1CDR_FLEXIO2_CLK_PODF(7)) ) | CCM_CS1CDR_FLEXIO2_CLK_PRED(0) | CCM_CS1CDR_FLEXIO2_CLK_PODF(0); /* Set up pin mux FlexIO1 */ *(portConfigRegister(PIN_G_B2)) = 0x14; *(portConfigRegister(PIN_R_B0)) = 0x14; *(portConfigRegister(PIN_R_B1)) = 0x14; *(portConfigRegister(PIN_R_B2)) = 0x14; /* Set up pin mux FlexIO2 */ *(portConfigRegister(PIN_B_B0)) = 0x14; *(portConfigRegister(PIN_B_B1)) = 0x14; *(portConfigRegister(PIN_G_B0)) = 0x14; *(portConfigRegister(PIN_G_B1)) = 0x14; /* Enable the clock */ CCM_CCGR5 |= CCM_CCGR5_FLEXIO1(CCM_CCGR_ON); CCM_CCGR3 |= CCM_CCGR3_FLEXIO2(CCM_CCGR_ON); /* Enable the FlexIO with fast access */ FLEXIO1_CTRL = FLEXIO_CTRL_FLEXEN | FLEXIO_CTRL_FASTACC; FLEXIO2_CTRL = FLEXIO_CTRL_FLEXEN | FLEXIO_CTRL_FASTACC; uint32_t timerSelect, timerPolarity, pinConfig, pinSelect, pinPolarity, shifterMode, parallelWidth, inputSource, stopBit, startBit; uint32_t triggerSelect, triggerPolarity, triggerSource, timerMode, timerOutput, timerDecrement, timerReset, timerDisable, timerEnable; /* Shifter 0 registers for FlexIO2 */ parallelWidth = FLEXIO_SHIFTCFG_PWIDTH(4); // 8-bit parallel shift width pinSelect = FLEXIO_SHIFTCTL_PINSEL(0); // Select pins FXIO_D0 through FXIO_D3 inputSource = FLEXIO_SHIFTCFG_INSRC*(1); // Input source from next shifter stopBit = FLEXIO_SHIFTCFG_SSTOP(0); // Stop bit disabled startBit = FLEXIO_SHIFTCFG_SSTART(0); // Start bit disabled, transmitter loads data on enable timerSelect = FLEXIO_SHIFTCTL_TIMSEL(0); // Use timer 0 timerPolarity = FLEXIO_SHIFTCTL_TIMPOL*(1); // Shift on negedge of clock pinConfig = FLEXIO_SHIFTCTL_PINCFG(3); // Shifter pin output pinPolarity = FLEXIO_SHIFTCTL_PINPOL*(0); // Shifter pin active high polarity shifterMode = FLEXIO_SHIFTCTL_SMOD(2); // Shifter transmit mode /* Shifter 0 registers for FlexIO1 */ FLEXIO2_SHIFTCFG0 = parallelWidth | inputSource | stopBit | startBit; FLEXIO2_SHIFTCTL0 = timerSelect | timerPolarity | pinConfig | pinSelect | pinPolarity | shifterMode; /* Shifter 0 registers for FlexIO1 */ parallelWidth = FLEXIO_SHIFTCFG_PWIDTH(4); // 8-bit parallel shift width pinSelect = FLEXIO_SHIFTCTL_PINSEL(4); // Select pins FXIO_D4 through FXIO_D7 FLEXIO1_SHIFTCFG0 = parallelWidth | inputSource | stopBit | startBit; FLEXIO1_SHIFTCTL0 = timerSelect | timerPolarity | pinConfig | pinSelect | pinPolarity | shifterMode; if (combine_shiftreg) { pinConfig = FLEXIO_SHIFTCTL_PINCFG(0); // Shifter pin output disabled FLEXIO2_SHIFTCFG1 = parallelWidth | inputSource | stopBit | startBit; FLEXIO2_SHIFTCTL1 = timerSelect | timerPolarity | pinConfig | shifterMode; FLEXIO1_SHIFTCFG1 = parallelWidth | inputSource | stopBit | startBit; FLEXIO1_SHIFTCTL1 = timerSelect | timerPolarity | pinConfig | shifterMode; } /* Timer 0 registers for FlexIO2 */ timerOutput = FLEXIO_TIMCFG_TIMOUT(1); // Timer output is logic zero when enabled and is not affected by the Timer reset timerDecrement = FLEXIO_TIMCFG_TIMDEC(0); // Timer decrements on FlexIO clock, shift clock equals timer output timerReset = FLEXIO_TIMCFG_TIMRST(0); // Timer never reset timerDisable = FLEXIO_TIMCFG_TIMDIS(2); // Timer disabled on Timer compare timerEnable = FLEXIO_TIMCFG_TIMENA(2); // Timer enabled on Trigger assert stopBit = FLEXIO_TIMCFG_TSTOP(0); // Stop bit disabled startBit = FLEXIO_TIMCFG_TSTART*(0); // Start bit disabled if (combine_shiftreg) { triggerSelect = FLEXIO_TIMCTL_TRGSEL(1+4*(1)); // Trigger select Shifter 1 status flag } else { triggerSelect = FLEXIO_TIMCTL_TRGSEL(1+4*(0)); // Trigger select Shifter 0 status flag } triggerPolarity = FLEXIO_TIMCTL_TRGPOL*(1); // Trigger active low triggerSource = FLEXIO_TIMCTL_TRGSRC*(1); // Internal trigger selected pinConfig = FLEXIO_TIMCTL_PINCFG(0); // Timer pin output disabled //pinSelect = FLEXIO_TIMCTL_PINSEL(0); // Select pin FXIO_D0 //pinPolarity = FLEXIO_TIMCTL_PINPOL*(0); // Timer pin polarity active high timerMode = FLEXIO_TIMCTL_TIMOD(1); // Dual 8-bit counters baud mode // flexio_clock_div : Output clock frequency is N times slower than FlexIO clock (41.7 ns period) (23.980MHz?) int shifts_per_transfer; if (combine_shiftreg) { shifts_per_transfer = 8; // Shift out 8 times with every transfer = 64-bit word = contents of Shifter 0+1 } else { shifts_per_transfer = 4; // Shift out 4 times with every transfer = 32-bit word = contents of Shifter 0 } FLEXIO2_TIMCFG0 = timerOutput | timerDecrement | timerReset | timerDisable | timerEnable | stopBit | startBit; FLEXIO2_TIMCTL0 = triggerSelect | triggerPolarity | triggerSource | pinConfig /*| pinSelect | pinPolarity*/ | timerMode; FLEXIO2_TIMCMP0 = ((shifts_per_transfer*2-1)<<8) | ((flexio_clock_div/2-1)<<0); /* Timer 0 registers for FlexIO1 */ FLEXIO1_TIMCFG0 = timerOutput | timerDecrement | timerReset | timerDisable | timerEnable | stopBit | startBit; FLEXIO1_TIMCTL0 = triggerSelect | triggerPolarity | triggerSource | pinConfig /*| pinSelect | pinPolarity*/ | timerMode; FLEXIO1_TIMCMP0 = ((shifts_per_transfer*2-1)<<8) | ((flexio_clock_div/2-1)<<0); #ifdef DEBUG Serial.println("FlexIO setup complete"); #endif /* Enable DMA trigger on Shifter0, DMA request is generated when data is transferred from buffer0 to shifter0 */ if (combine_shiftreg) { FLEXIO2_SHIFTSDEN |= (1<<1); FLEXIO1_SHIFTSDEN |= (1<<1); } else { FLEXIO2_SHIFTSDEN |= (1<<0); FLEXIO1_SHIFTSDEN |= (1<<0); } /* Disable DMA channel so it doesn't start transferring yet */ flexio1DMA.disable(); flexio2DMA.disable(); /* Set up DMA channel to use Shifter 0 trigger */ flexio1DMA.triggerAtHardwareEvent(DMAMUX_SOURCE_FLEXIO1_REQUEST0); flexio2DMA.triggerAtHardwareEvent(DMAMUX_SOURCE_FLEXIO2_REQUEST0); if (combine_shiftreg) { flexio2DMA.TCD->NBYTES = 8; flexio2DMA.TCD->SOFF = 4; flexio2DMA.TCD->SLAST = -maxpixperline; flexio2DMA.TCD->BITER = maxpixperline / 8; flexio2DMA.TCD->CITER = maxpixperline / 8; flexio2DMA.TCD->DADDR = &FLEXIO2_SHIFTBUF0; flexio2DMA.TCD->DOFF = 0; flexio2DMA.TCD->DLASTSGA = 0; flexio2DMA.TCD->ATTR = DMA_TCD_ATTR_SSIZE(2) | DMA_TCD_ATTR_DSIZE(3); // 32bits => 64bits flexio2DMA.TCD->CSR |= DMA_TCD_CSR_DREQ; flexio1DMA.TCD->NBYTES = 8; flexio1DMA.TCD->SOFF = 4; flexio1DMA.TCD->SLAST = -maxpixperline; flexio1DMA.TCD->BITER = maxpixperline / 8; flexio1DMA.TCD->CITER = maxpixperline / 8; flexio1DMA.TCD->DADDR = &FLEXIO1_SHIFTBUFNBS0; flexio1DMA.TCD->DOFF = 0; flexio1DMA.TCD->DLASTSGA = 0; flexio1DMA.TCD->ATTR = DMA_TCD_ATTR_SSIZE(2) | DMA_TCD_ATTR_DSIZE(3); // 32bits => 64bits flexio1DMA.TCD->CSR |= DMA_TCD_CSR_DREQ; } else { // Setup DMA2 Flexio2 copy flexio2DMA.TCD->NBYTES = 4; flexio2DMA.TCD->SOFF = 4; flexio2DMA.TCD->SLAST = -maxpixperline; flexio2DMA.TCD->BITER = maxpixperline / 4; flexio2DMA.TCD->CITER = maxpixperline / 4; flexio2DMA.TCD->DADDR = &FLEXIO2_SHIFTBUF0; flexio2DMA.TCD->DOFF = 0; flexio2DMA.TCD->DLASTSGA = 0; flexio2DMA.TCD->ATTR = DMA_TCD_ATTR_SSIZE(2) | DMA_TCD_ATTR_DSIZE(2); // 32bits flexio2DMA.TCD->CSR |= DMA_TCD_CSR_DREQ; // Setup DMA1 Flexio1 copy // Use pixel shift to avoid color smearing? if (pix_shift & DMA_HACK) { if (pix_shift & 0x3 == 0) { // Aligned 32 bits copy (32bits to 32bits) flexio1DMA.TCD->NBYTES = 4; flexio1DMA.TCD->SOFF = 4; flexio1DMA.TCD->SLAST = -maxpixperline; flexio1DMA.TCD->BITER = maxpixperline / 4; flexio1DMA.TCD->CITER = maxpixperline / 4; flexio1DMA.TCD->DADDR = &FLEXIO1_SHIFTBUFNBS0; flexio1DMA.TCD->DOFF = 0; flexio1DMA.TCD->DLASTSGA = 0; flexio1DMA.TCD->ATTR = DMA_TCD_ATTR_SSIZE(2) | DMA_TCD_ATTR_DSIZE(2); // 32bits to 32bits flexio1DMA.TCD->CSR |= DMA_TCD_CSR_DREQ; } else { // Unaligned (source) 32 bits copy (8bits to 32bits) flexio1DMA.TCD->NBYTES = 4; flexio1DMA.TCD->SOFF = 1; flexio1DMA.TCD->SLAST = -maxpixperline; flexio1DMA.TCD->BITER = maxpixperline / 4; flexio1DMA.TCD->CITER = maxpixperline / 4; flexio1DMA.TCD->DADDR = &FLEXIO1_SHIFTBUFNBS0; flexio1DMA.TCD->DOFF = 0; flexio1DMA.TCD->DLASTSGA = 0; flexio1DMA.TCD->ATTR = DMA_TCD_ATTR_SSIZE(0) | DMA_TCD_ATTR_DSIZE(2); // 8bits to 32bits flexio1DMA.TCD->CSR |= DMA_TCD_CSR_DREQ; // disable on completion } } else { // Aligned 32 bits copy flexio1DMA.TCD->NBYTES = 4; flexio1DMA.TCD->SOFF = 4; flexio1DMA.TCD->SLAST = -maxpixperline; flexio1DMA.TCD->BITER = maxpixperline / 4; flexio1DMA.TCD->CITER = maxpixperline / 4; flexio1DMA.TCD->DADDR = &FLEXIO1_SHIFTBUFNBS0; flexio1DMA.TCD->DOFF = 0; flexio1DMA.TCD->DLASTSGA = 0; flexio1DMA.TCD->ATTR = DMA_TCD_ATTR_SSIZE(2) | DMA_TCD_ATTR_DSIZE(2); // 32bits flexio1DMA.TCD->CSR |= DMA_TCD_CSR_DREQ; } } #ifdef DEBUG Serial.println("DMA setup complete"); #endif // enable clocks for QTIMER3: generates the 15KHz for hsync // Pulse: // low : 3.8133 us => 569x6.7ns // total: 31.777 us => 4743x6.7ns (high = 4174x6.7ns) // (OLD TEST) // (4us low, 28us high => 32us) // (597x6.7ns for 4us) // (4179x6.7ns for 28us) CCM_CCGR6 |= 0xC0000000; //enable clocks to CG15 of CGR6 for QT3 //configure QTIMER3 Timer3 for test of alternating Compare1 and Compare2 #define MARGIN_N 1005 // 1206 at 720MHz //1005 at 600MHz #define MARGIN_D 1000 TMR3_CTRL3 = 0b0000000000100000; //stop all functions of timer // Invert output pin as we want the interupt on rising edge TMR3_SCTRL3 = 0b0000000000000011; //0(TimerCompareFlag),0(TimerCompareIntEnable),00(TimerOverflow)0000(NoCapture),0000(Capture Disabled),00, 1(INV output),1(OFLAG to Ext Pin) TMR3_CNTR3 = 0; TMR3_LOAD3 = 0; /* Inverted timings */ unsigned long long cpu_freq = F_CPU; unsigned long long rate = (1005ULL * cpu_freq) / 600000000ULL; int rate2 = rate; int substract = 1; if (cpu_freq > 950000000ULL && cpu_freq < 990000000ULL) { substract=5; rate2=1652; } #ifdef DEBUG Serial.print("MARGIN_N is: "); Serial.println(rate2, DEC); Serial.print("SUBSTRACT is: "); Serial.println(substract, DEC); #endif TMR3_COMP13 = ((4174*rate2)/MARGIN_D)-substract; TMR3_CMPLD13 = ((4174*rate2)/MARGIN_D)-substract; TMR3_COMP23 = ((569*rate2)/MARGIN_D)-substract; TMR3_CMPLD23 = ((569*rate2)/MARGIN_D)-substract; /* TMR3_COMP13 = ((4174*MARGIN_N)/MARGIN_D)-1; TMR3_CMPLD13 = ((4174*MARGIN_N)/MARGIN_D)-1; TMR3_COMP23 = ((569*MARGIN_N)/MARGIN_D)-1; TMR3_CMPLD23 = ((569*MARGIN_N)/MARGIN_D)-1; */ TMR3_CSCTRL3 = 0b0000000010000101; //Compare1 only enabled - Compare Load1 control and Compare Load2 control both on TMR3_CTRL3 = 0b0011000000100100; // 001(Count rising edges Primary Source),1000(IP Bus Clock),00 (Secondary Source), // 0(Count Once),1(Count up to Compare),0(Count Up),0(Co Channel Init),100(Toggle OFLAG on alternating Compare1/Compare2) //configure Teensy pin Compare output IOMUXC_SW_MUX_CTL_PAD_GPIO_AD_B1_03 = 1; // QT3 Timer3 is now on pin 15 attachInterruptVector(IRQ_QTIMER3, QT3_isr); //declare which routine performs the ISR function NVIC_ENABLE_IRQ(IRQ_QTIMER3); #ifdef DEBUG Serial.println("QTIMER3 setup complete"); Serial.print("V-PIN is "); Serial.println(_vsync_pin); #endif /* initialize gfx buffer */ if (gfxbuffer == NULL) gfxbuffer = (vga_pixel*)malloc(vga_stride*vga_height*sizeof(vga_pixel)+4); // 4bytes for pixel shift if (gfxbuffer == NULL) return(GFX_ERROR); #ifdef DEBUG Serial.println("Memory allocated"); #endif memset((void*)&gfxbuffer[0],0, vga_stride*vga_height*sizeof(vga_pixel)+4); vga_buffer = (vga_pixel*)&gfxbuffer[left_border]; #ifdef DEBUG Serial.println(vga_stride); Serial.println(vga_height); Serial.println("Screen cleared"); #endif } return(GFX_OK); } gfx_mode_t T4_DSP::getMode(void) { return gfxmode; } void T4_DSP::startRefresh(void) { if (gfxmode < MODE_VGA_320x240) { curTransfer = 0; rstop = 0; //dmatx.begin(true); dmatx.attachInterrupt(TFT_isr); 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)); LPSPIP_CR &= ~LPSPI_CR_MEN;//disable LPSPI: LPSPIP_CFGR1 |= LPSPI_CFGR1_NOSTALL; //prevent stall from RX LPSPIP_TCR = 15; // Framesize 16 Bits //LPSPIP_FCR = 0; // Fifo Watermark LPSPIP_DER = LPSPI_DER_TDDE; //TX DMA Request Enable LPSPIP_CR |= LPSPI_CR_MEN; //enable LPSPI: dmatx.triggerAtHardwareEvent( DMAMUX_SOURCE_LPSPIP_TX ); 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 T4_DSP::stopRefresh(void) { if (gfxmode < MODE_VGA_320x240) { rstop = 1; unsigned long m = millis(); cancelled = true; while (!rstop) { if ((millis() - m) > 100) break; delay(10); asm volatile("wfi"); }; rstop = 0; delay(50); cancelled = false; dmatx.detachInterrupt(); fillScreen(RGBVAL16(0x00,0x00,0x00)); SPI.end(); #ifdef ST7789 // begin(gfxmode); #endif setArea(0, 0, TFT_REALWIDTH-1, TFT_REALHEIGHT-1); } } int T4_DSP::get_frame_buffer_size(int *width, int *height) { if (gfxmode < MODE_VGA_320x240) { if (width != nullptr) *width = tft_width; if (height != nullptr) *height = tft_height; return tft_stride; } else { if (width != nullptr) *width = vga_width; if (height != nullptr) *height = vga_height; return vga_stride; } } void T4_DSP::waitSync() { if (gfxmode >= MODE_VGA_320x240) { while (VSYNC == 0) {}; } } void T4_DSP::waitLine(int line) { if (gfxmode >= MODE_VGA_320x240) { while (currentLine != line) {}; } } /*********************************************************************************************** No DMA functions ***********************************************************************************************/ void T4_DSP::fillScreenNoDma(uint16_t color) { if (gfxmode < MODE_VGA_320x240) { SPI.beginTransaction(SPISettings(SPICLOCK, MSBFIRST, SPI_MODE)); digitalWrite(_cs, 0); setArea(0, 0, TFT_REALWIDTH-1, TFT_REALHEIGHT-1); int i,j; for (j=0; j(arx+arw)) || ((x+w)(ary+arh)) || ((y+h) 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); bitmap = bitmap + bmp_offy*w + bmp_offx; for (int row=0;row> 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; 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(); } else { drawText(x, y, text, fgcolor, bgcolor, doublesize); } } /*********************************************************************************************** DMA functions ***********************************************************************************************/ void T4_DSP::fillScreen(uint16_t color) { int i,j; if (gfxmode < MODE_VGA_320x240) { for (j=0; j> 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++; } dst=&tft_buffer[l*tft_stride+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; } } else { vga_pixel fgcolor8 = VGA_RGB(R16(fgcolor),G16(fgcolor),B16(fgcolor)); vga_pixel bgcolor8 = VGA_RGB(R16(bgcolor),G16(bgcolor),B16(bgcolor)); vga_pixel * dst; 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) { dst=&vga_buffer[l*vga_stride+x]; bits = *charpt; if (bits&0x01) *dst++=fgcolor8; else *dst++=bgcolor8; bits = bits >> 1; if (bits&0x01) *dst++=fgcolor8; else *dst++=bgcolor8; bits = bits >> 1; if (bits&0x01) *dst++=fgcolor8; else *dst++=bgcolor8; bits = bits >> 1; if (bits&0x01) *dst++=fgcolor8; else *dst++=bgcolor8; bits = bits >> 1; if (bits&0x01) *dst++=fgcolor8; else *dst++=bgcolor8; bits = bits >> 1; if (bits&0x01) *dst++=fgcolor8; else *dst++=bgcolor8; bits = bits >> 1; if (bits&0x01) *dst++=fgcolor8; else *dst++=bgcolor8; bits = bits >> 1; if (bits&0x01) *dst++=fgcolor8; else *dst++=bgcolor8; l++; } dst=&vga_buffer[l*vga_stride+x]; bits = *charpt++; if (bits&0x01) *dst++=fgcolor8; else *dst++=bgcolor8; bits = bits >> 1; if (bits&0x01) *dst++=fgcolor8; else *dst++=bgcolor8; bits = bits >> 1; if (bits&0x01) *dst++=fgcolor8; else *dst++=bgcolor8; bits = bits >> 1; if (bits&0x01) *dst++=fgcolor8; else *dst++=bgcolor8; bits = bits >> 1; if (bits&0x01) *dst++=fgcolor8; else *dst++=bgcolor8; bits = bits >> 1; if (bits&0x01) *dst++=fgcolor8; else *dst++=bgcolor8; bits = bits >> 1; if (bits&0x01) *dst++=fgcolor8; else *dst++=bgcolor8; bits = bits >> 1; if (bits&0x01) *dst++=fgcolor8; else *dst++=bgcolor8; l++; } x +=8; } } } void T4_DSP::drawSprite(int16_t x, int16_t y, const uint16_t *bitmap) { drawSprite(x,y,bitmap, 0,0,0,0); } 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) { 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)(ary+arh)) || ((y+h) 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; if (gfxmode < MODE_VGA_320x240) { for (int row=0;row tft_width) { #ifdef TFT_LINEARINT int delta = (width/(width-tft_width))-1; int pos = delta; for (int i=0; i> 8]; pos +=step; } #endif } else if ((width*2) == tft_width) { for (int i=0; i 2) ) y += (vga_height-height)/2; vga_pixel * dst=&vga_buffer[y*vga_stride]; if (width > vga_width) { int step = ((width << 8)/vga_width); int pos = 0; for (int i=0; i> 8]; *dst++ = VGA_RGB(R16(pix),G16(pix),B16(pix)); pos +=step; } } else if ((width*2) == vga_width) { for (int i=0; i 2) ) y += (tft_height-height)/2; uint16_t * dst=&tft_buffer[y*tft_stride]; if (width > tft_width) { #ifdef TFT_LINEARINT int delta = (width/(width-tft_width))-1; int pos = delta; for (int i=0; i> 8]]; pos +=step; } #endif } else if ((width*2) == tft_width) { for (int i=0; i 2) ) y += (vga_height-height)/2; vga_pixel * dst=&vga_buffer[y*vga_stride]; if (width > vga_width) { int step = ((width << 8)/vga_width); int pos = 0; for (int i=0; i> 8]]; *dst++= VGA_RGB(R16(pix),G16(pix),B16(pix)); pos +=step; } } else if ((width*2) == vga_width) { for (int i=0; i>8)*stride]; for (i=0; i>8)*stride]; for (i=0; i>8)*stride]; for (i=0; i>8)*stride]; for (i=0; i tft_width) { int step = ((width << 8)/tft_width); int pos = 0; for (int i=0; i> 8]]; pos +=step; } } else if ((width*2) == tft_width) { for (int i=0; i 2) ) y += (vga_height-height)/2; vga_pixel * dst=&vga_buffer[y*vga_stride]; if (width > vga_width) { int step = ((width << 8)/vga_width); int pos = 0; for (int i=0; i> 8]; *dst++ = pix; pos +=step; } } else if ((width*2) == vga_width) { for (int i=0; i