for TFT2P0327 aitendo.com 128*160 TFT LCD. LCD driver is S6D0151 Sumsung.
Dependents: FRDM_tocos_x2_FIXED
Diff: S6D0151_TFT.cpp
- Revision:
- 0:de7db46990d0
- Child:
- 1:a3651128e297
diff -r 000000000000 -r de7db46990d0 S6D0151_TFT.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/S6D0151_TFT.cpp Sun Aug 23 12:28:24 2015 +0000 @@ -0,0 +1,864 @@ + /* mbed library for 128*160 pixel display TFT based on ST7735 LCD Controller + * ST7735 specific routines (initialization, window addressing, pixel output) + * Copyright (c) 2011 Jonne Valola + * + * WARNING !! WORK IN PROGRESS !!! + * + * Graphics routines and SPI routines derived work used with permission from: + * mbed library for 240*320 pixel display TFT based on HX8347D LCD Controller + * Copyright (c) 2011 Peter Drescher - DC2PD + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + + +#include "S6D0151_TFT.h" +#include "mbed.h" + +#define BPP 16 // Bits per pixel + +S6D0151_TFT::S6D0151_TFT(PinName mosi, PinName miso, PinName sclk, PinName cs, PinName reset, const char *name) + : _spi(mosi, miso, sclk), _cs(cs), _reset(reset),GraphicsDisplay(name) { + tft_reset(); + orientation = 2; + char_x = 0; +} + + +int S6D0151_TFT::width() { + if (orientation == 0 || orientation == 2) return 128; + else return 160; +} + + +int S6D0151_TFT::height() { + if (orientation == 0 || orientation == 2) return 160; + else return 128; +} + + +void S6D0151_TFT::set_orientation(unsigned int o) { + orientation = o; +#if 0 + switch (orientation) { + case 0: + wr_reg(ST7735_MADCTL, 0x0000); + break; + case 1: + wr_reg(ST7735_MADCTL, 0x0060); + break; + case 2: + wr_reg(ST7735_MADCTL, 0x00C0); + break; + case 3: + wr_reg(ST7735_MADCTL, 0x00A0); + break; + } +#endif +} + +void S6D0151_TFT::wr_dat_start(void) { +// _rs = 1; // rs high, cs low for transmitting data + _cs = 0; + _spi.write( 0x72 ); // Start byte +} + + + +void S6D0151_TFT::wr_dat_stop (void) { + _cs = 1; +} + + +void S6D0151_TFT::set_start_address(int left,int top){ + unsigned short addr; + addr = (((top&0xff)<<8)|(left&0xff)); + + regwr( 0x0021 , addr ); +} + + +/** +* +*/ +void S6D0151_TFT::regwr(unsigned short reg,unsigned short dat){ + int data; + _cs = 0; + _spi.write(0x70); // RW=0,ID=0,RS=0(Index Register write) + data = (reg>>8)&0x00ff; + _spi.write( data ); + data = (reg )&0x00ff; + _spi.write( data ); + _cs = 1; + wait_us(1); // cs=highの時間規定は無かった + _cs = 0; + _spi.write(0x72); // RW=0,ID=0,RS=1(data write) + data = (dat>>8)&0x00ff; + _spi.write( data ); + data = (dat )&0x00ff; + _spi.write( data ); + _cs = 1; +} +void S6D0151_TFT::reg0(unsigned short reg){ + int data; + _cs = 0; + _spi.write(0x70); // RW=0,ID=0,RS=0(Index Register write) + data = (reg>>8)&0x00ff; + _spi.write( data ); + data = (reg )&0x00ff; + _spi.write( data ); + _cs = 1; +} + +void S6D0151_TFT::tft_reset() { + // init SPI + _spi.format(8,3); // 8 bit spi mode 3 + _spi.frequency(6000000); // 6Mhz SPI clock ... 10Mhz is maximum for display, but it seems to work + + // reset exactly like in Arduino version + _cs = 0; + _reset = 1; // reset + wait_ms(500); + _reset = 0; // reset + wait_ms(500); + _reset = 1; // reset + wait_ms(500); + + /* Start Initial Sequence ----------------------------------------------------*/ + regwr(0x0007,0x0020); //DISPLAY CONTROL (R07h) + // X X X PT1 PT0 X X SPT X X GON DTE CL REV D1 D0 + //PT[1:0]=00 V63/V0 Normal Drive + //SPT=0 Split Screen Driving Function is Not performed + //GON=1,DTE=0 Normal operation + //CL=0 262,144 colors / 65,536 colors + //REV=0 Displays all character and graphics display sections with Normal + //D[1:0]=00 the internal display operation halts and the display is off. + + regwr(0x00b6,0x013f); //Module Vendor (RB6h) + // TEST_IN4 TEST_IN3 X X X X PSMD1(0) PSM D0(1) X X 1 1 1 1 1 1 + //TEST_IN4,TEST_IN3 User can know the Module Vendor through this register is accessed. + //PSMD[1:0]=01 5680*(1/fosc) Select the power on time delay of step-up circuit. + + regwr(0x00b4,0x0010); //MTP CONTROL (RB4h) + // X X X MTP_SEL X X X MTP_INIT X X X MTP_WRB X X X MTP_LOAD + //MTP_SEL=0 VCOMH Control Data is VCM Register + //MTP_INIT=0 + //MTP_WRB=1 Cannot write MTP data + //MTP_LOAD=0 + + regwr(0x0012,0x00b2); //POWER CONTROL 2 (R12h) + // X X X X X X X X SVC3 SVC2 SVC1 SVC0 X 0 VRH5 VRH4 + //SVC Adjust reference voltage of AVDD, VGH, VGL and VCL + // SVC[3:0]=1011 VCI1=2.76V + + regwr(0x0013,0x080e); //POWER CONTROL 3 (R13h) + // X X X X VCMR X X X X X X PON VRH3 VRH2 VRH1 VRH0 + //PON=0 The operational amplifier is stop. + //VCMR=1 VCOMH voltage=Internal electronic volume + //VRH[5:0]=1e=011110 VCIR_EXIN X 2.250 = 4.50V + + regwr(0x0014,0x5bca); //POWER CONTROL 4 (R14h) + // X VDV6 VDV5 VDV4 VDV3 VDV2 VDV1 VDV0 VCOMG VCM6 VCM5 VCM4 VCM3 VCM2 VCM1 VCM0 + //VDV Set the alternating amplitudes of Vcom at the Vcom alternating drive. + // VDV[6:0]=5b=1011011 GVDD x 0.984 + //VCOMG=1 VcomL voltage can output to negative voltage. + //Set the VcomH voltage (a high-level voltage at the Vcom alternating drive). + // VCM[6:0]=1001010 GVDD x 0.8085 + + regwr(0x0061,0x0018); //OSCILLATOR CONTROL (R61h) + // X X X X X X X X X X X RADJ4 RADJ3 RADJ2 RADJ1 RADJ0 + //RADJ[4:0]=11000 Oscillation Speed=x 1.000 Default + + regwr(0x0010,0x190c); //POWER CONTROL 1 (R10h) + // DSTB X SAP2 SAP1 SAP0 BT2 BT1 BT0 DC2 DC1 DC0 AP2 AP1 AP0 SLP STB + //DSTB=0 Noraml + //Adjust the slew-rate of the operational amplifier for the source driver. + // SAP[2:0]=011 Medium Medium + //BT[2:0]=001 VGH=AVDDx3 VGL=-(AVDDx2) VGH = Vci1 X six times + //DC[2:0]=000 AVDD,VCL=DCCLK/1 VGH,VGL=DCCLK/2 + //AP[2:0]=011 Amount of Current in Operational Amplifier=Medium + //SLP=0 setting Sleep. Normal mode + //STB=0 setting standby. normal mode + wait_ms(80); + + regwr(0x0013,0x081e); //POWER CONTROL 3 (R13h) + // X X X X VCMR X X X X X X PON VRH3 VRH2 VRH1 VRH0 + //PON=1 The operational amplifier is Start. + //VCMR=1 VCOMH voltage=Internal electronic volume + //VRH[5:0]=1e=011110 VCIR_EXIN X 2.250 = 4.50V + wait_ms(20); + + regwr(0x0001,0x0014); //DRIVER OUTPUT CONTROL (R01h) + // X X X DPL EPL SM GS SS X X X NL4 NL3 NL2 NL1 NL0 + // demo codeは0x0114だったが、SSビットを0にすると方向が正常になった。 + //DPL=0,EPL=0 + //SM=0 even/odd division is selected + //GS=0 G1 is output first and G160 is finally output. + //SS=1 Select the direction of the source driver channel in pixel unit. + //NL[4:0]=10100 Drive Duty=384 X 160 dots 160 G1 to G160 + + regwr(0x0002,0x0100); //LCD INVERSION CONTROL (R02h) + // X X X X X X FL1 FL0 X X X FLD X X X X + //FL[1:0]=01 FLD=0 Line Inversion-1 field interlace + + regwr(0x0003,0x0030); //ENTRY MODE (R03h) + // X X X BGR X X MDT1 MDT0 X X ID1 ID0 AM X X X + //BGR=0 assigned to {R, G, B}.When 18-bit data is written to GRAM through DB bus + //MDT[1:0]=00 260k color data is transferred by 3or2-times(setting for IM) Data Transfer. + // When user wants to transfer 260k color data on 8/16-bit parallel bus + //ID[1:0]=11 When ID[1], ID[0] = 1, the address counter (AC) is automatically increased by 1 after the data is written to the GRAM + //AM=0 the data is continuously written in horizontally. + + regwr(0x0008,0x0202); //BLANK PERIOD CONTROL 1 (R08h) + // X X X X FP3 FP2 FP1 FP0 X X X X BP3 BP2 BP1 BP0 + //FP[3:0]=0010 + //BP[3:0]=0010 + //Number of Raster Periods In Front (Back) Porch Default=2; + + regwr(0x000b,0x0000); //FRAME CYCLE CONTROL (R0Bh) + // X X X X X X DIV1 DIV0 X X X X RTN3 RTN2 RTN1 RTN0 + //DIV[1:0]=00 Division Ratio=1 Internal operation clock frequency=fosc/1 + //RTN[3:0]=Clock Cycles per horizontal Line= 16 (INCLKs) + + regwr(0x000c,0x0000); //EXTERNAL DISPLAY INTERFACE CONTROL (R0Ch) + // X X X X X X X RM X X DM1 DM0 X X RIM1 RIM0 + //RM=0 GRAM Access Interface=System interface + //DM[1:0]=00 Display operation mode = Internal clock operation + + regwr(0x0061,0x0018); //OSCILLATOR CONTROL (R61h) + // X X X X X X X X X X X RADJ4 RADJ3 RADJ2 RADJ1 RADJ0 + //RADJ[4:0]=11000 Oscillation Speed=x 1.000 Default + + regwr(0x0069,0x0000); //DC/DC CONVERT LOW POWER MODE SETTING (R69h) + // 0 0 0 0 0 0 0 0 0 0 0 NLDC3 NLDC2 NLDC1 NLDC0 NLPM + //NLPM=0 Normal operation mode + //NLDC[1:0]=00 DCCLK/1 + //NLDC[3:2]=00 DCCLK/2 + + regwr(0x0070,0x0000); //SOURCE DRIVER PRE-DRIVING PERIOD SETTING (R70h) + // X X X X X X X X SDT1 SDT0 X X X X EQ1 EQ0 + //STD[1:0]=00 Source Output Delay Control=1 DISP_CK + //EQ=00 No Equalization Control + regwr(0x0071,0x0000); //GATE OUTPUT PERIOD CONTROL (R71h) + // X X X X GNO1 GNO0 X X X X X X X X X X + //GN)=00 Non-Overlap Period Control =2 DISP_CKs + + regwr(0x0011,0x0000); //GAMMA CONTROL 1 (R11h) + // VR1C X X VRN14 VRN13 VRN12 VRN11 VRN10 X X X VRP14 VRP13 VRP12 VRP11 VRP10 + //VR1C=0 Control step of amplitude positive and negative of 64-grayscale. + //VRP1[4:0]=00000 Control amplitude positive polarity of 64-grayscale. + //VRN1[4:0]=00000 Control amplitude negative polarity of 64-grayscale. + + /* Gamma settings -----------------------------------------------------------*/ +///////r CONTROL + regwr(0x0030,0x0303); //GAMMA CONTROL 2 (R30h to R37h) + regwr(0x0031,0x0303); //GAMMA CONTROL 2 (R30h to R37h) + regwr(0x0032,0x0303); //GAMMA CONTROL 2 (R30h to R37h) + regwr(0x0033,0x0000); //GAMMA CONTROL 2 (R30h to R37h) + regwr(0x0034,0x0404); //GAMMA CONTROL 2 (R30h to R37h) + regwr(0x0035,0x0404); //GAMMA CONTROL 2 (R30h to R37h) + regwr(0x0036,0x0404); //GAMMA CONTROL 2 (R30h to R37h) + regwr(0x0037,0x0000); //GAMMA CONTROL 2 (R30h to R37h) + regwr(0x0038,0x0707); //GAMMA CONTROL 2 (R38h) +///////Coordinatioontrol setting + regwr(0x0040,0x0000); // GATE SCAN POSITION (R40h) + // 1 X X X X X X X X X X X SCN4 SCN3 SCN2 SCN1 SCN0 + //Set the scanning starting position of the gate driver. + + regwr(0x0042,0x9f00); //1st SCREEN DRIVING POSITION (R42h) + // SE17 SE16 SE15 SE14 SE13 SE12 SE11 SE10 SS17 SS16 SS15 SS14 SS13 SS12 SS11 SS10 + + regwr(0x0043,0x0000); //2nd SCREEN DRIVING POSITION (R43h) + // SE27 SE26 SE25 SE24 SE23 SE22 SE21 SE20 SS27 SS26 SS25 SS24 SS23 SS22 SS21 SS20 + regwr(0x0044,0x7f00); //HORIZONTAL RAM ADDRESS POSITION (R44h) + + regwr(0x0045,0x9f00); //VERTICAL RAM ADDRESS POSITION (R45h) + + regwr(0x0069,0x0000); //DC/DC CONVERT LOW POWER MODE SETTING (R69h) + // 0 0 0 0 0 0 0 0 0 0 0 NLDC3 NLDC2 NLDC1 NLDC0 NLPM + //NLPM=0 Normal operation mode + //NLDC[1:0]=00 DCCLK/1 + //NLDC[3:2]=00 DCCLK/2 + + regwr(0x0070,0x0000); //SOURCE DRIVER PRE-DRIVING PERIOD SETTING (R70h) + // X X X X X X X X SDT1 SDT0 X X X X EQ1 EQ0 + //STD[1:0]=00 Source Output Delay Control=1 DISP_CK + //EQ=00 No Equalization Control + + regwr(0x0071,0x0000); //GATE OUTPUT PERIOD CONTROL (R71h) + // X X X X GNO1 GNO0 X X X X X X X X X X + //GNO=00 Non-Overlap Period Control =2 DISP_CKs + + regwr(0x0073,0x0000); //TEST_KEY (R73h) + // X X X X X X X X TEST_KEY[7:0] + //When you want to update MTP data, “A5” should be written to this register. + + regwr(0x00B3,0x0000); //PUMPING CLOCK SOURCE SELECTION (RB3h) + // X 0 0 0 X 0 1 0 X X X DCR_EX X X X 1 + //Select the source of pumping clock. + //In RGB mode, DCR_EX should be set before power setting. + + regwr(0x00BD,0x0000); //MTP DATA READ (RBDh) + // X X X X X X X DISEN X MTP_DOUT[6:0] + //DISEN=0 Standby mode discharge circuit operation stop. + //MTP_DOUT MTP data read using MTP_READ register. + + regwr(0x00BE,0x0000); //INTERFACE MODE SELECTION (RBEh) + // X X X X X X X X X X X IM_SEL IM_3 X X FLM_MSK + //IM_SEL register selects interface mode. + //IM_SEL=0 is IM[3:0] setting + + regwr(0x0021,0x0000); //GRAM ADDRESS SET (R21h) + // AD15 AD14 AD13 AD12 AD11 AD10 AD9 AD8 AD7 AD6 AD5 AD4 AD3 AD2 AD1 AD0 + // You can write initial GRAM address into internal Address Counter (AC). + + reg0(0x0022); //WRITE DATA TO GRAM (R22h) + // RAM write data (WD17 ~ WB0). Interface mode controls the width of WD + // Data on DB bus is expanded to 18-bits before being written to GRAM and the data determines grayscale level of S6D0151’s source output. + wait_ms(20); + + regwr(0x0007,0x0020); //DISPLAY CONTROL (R07h) + // X X X PT1 PT0 X X SPT X X GON DTE CL REV D1 D0 + //PT[1:0]=00 V63/V0 Normal Drive + //SPT=0 Split Screen Driving Function is Not performed + //GON=1,DTE=0 Normal operation + //CL=0 262,144 colors / 65,536 colors + //REV=0 Displays all character and graphics display sections with Normal + //D[1:0]=00 the internal display operation halts and the display is off. + wait_ms(5); + + regwr(0x0007,0x0021); //DISPLAY CONTROL (R07h) + // X X X PT1 PT0 X X SPT X X GON DTE CL REV D1 D0 + //D[1:0]=01 the internal display operation halts and the display is off. + + regwr(0x0007,0x0027); //DISPLAY CONTROL (R07h) + // X X X PT1 PT0 X X SPT X X GON DTE CL REV D1 D0 + //REV=1 Displays all character and graphics display sections with Reverse + //D[1:0]=11 the internal display operation halts and the display is off. + + wait_ms(50); + regwr(0x0007,0x0037); //DISPLAY CONTROL (R07h) + // X X X PT1 PT0 X X SPT X X GON DTE CL REV D1 D0 + //GON=1,DTE=1 VGH/VGL Normal operation + //Revは色反転の模様 + //REV=1 Displays all character and graphics display sections with Reverse + //D[1:0]=11 Display is RAM data + + WindowMax (); +} + + +void S6D0151_TFT::pixel(int x, int y, int color) { + if ((x >= width()) || (y >= height())) return; + +// window(x,y,x+1,y+1); + window(x,y,1,1); + + wr_dat_start(); + _spi.write(color >> 8); + _spi.write(color & 0xFF); + wr_dat_stop(); + +} + +void S6D0151_TFT::window (unsigned int x, unsigned int y, unsigned int w, unsigned int h) { + unsigned int hea,hsa,vea,vsa,dd; + hea=x+w-1; + hsa=x; + vea=y+h-1; + vsa=y; + + dd=((hea&0xff)<<8)|(hsa&0xff); + regwr(0x0044, dd ); //HORIZONTAL RAM ADDRESS POSITION (R44h) + dd=((vea&0xff)<<8)|(vsa&0xff); + regwr(0x0045, dd ); //VERTICAL RAM ADDRESS POSITION (R45h) + +// wr_cmd(ST7735_RAMWR); // write to RAM + set_start_address(hea,vea); + reg0(0x0022); //Write data to GRAM +} + + +void S6D0151_TFT::WindowMax (void) { + window (0, 0, width(), height()); +} + + +void S6D0151_TFT::cls (void) { + unsigned int i; + WindowMax(); + + wr_dat_start(); + for (i = 0; i < ( (width()+1) * (height()+3)); i++) { + _spi.write(_background >> 8); + _spi.write(_background & 0xFF); + } + wr_dat_stop(); +} + + +void S6D0151_TFT::circle(int x0, int y0, int r, int color) { + + int draw_x0, draw_y0; + int draw_x1, draw_y1; + int draw_x2, draw_y2; + int draw_x3, draw_y3; + int draw_x4, draw_y4; + int draw_x5, draw_y5; + int draw_x6, draw_y6; + int draw_x7, draw_y7; + int xx, yy; + int di; + WindowMax(); + if (r == 0) { /* no radius */ + return; + } + + draw_x0 = draw_x1 = x0; + draw_y0 = draw_y1 = y0 + r; + if (draw_y0 < height()) { + pixel(draw_x0, draw_y0, color); /* 90 degree */ + } + + draw_x2 = draw_x3 = x0; + draw_y2 = draw_y3 = y0 - r; + if (draw_y2 >= 0) { + pixel(draw_x2, draw_y2, color); /* 270 degree */ + } + + draw_x4 = draw_x6 = x0 + r; + draw_y4 = draw_y6 = y0; + if (draw_x4 < width()) { + pixel(draw_x4, draw_y4, color); /* 0 degree */ + } + + draw_x5 = draw_x7 = x0 - r; + draw_y5 = draw_y7 = y0; + if (draw_x5>=0) { + pixel(draw_x5, draw_y5, color); /* 180 degree */ + } + + if (r == 1) { + return; + } + + di = 3 - 2*r; + xx = 0; + yy = r; + while (xx < yy) { + + if (di < 0) { + di += 4*xx + 6; + } else { + di += 4*(xx - yy) + 10; + yy--; + draw_y0--; + draw_y1--; + draw_y2++; + draw_y3++; + draw_x4--; + draw_x5++; + draw_x6--; + draw_x7++; + } + xx++; + draw_x0++; + draw_x1--; + draw_x2++; + draw_x3--; + draw_y4++; + draw_y5++; + draw_y6--; + draw_y7--; + + if ( (draw_x0 <= width()) && (draw_y0>=0) ) { + pixel(draw_x0, draw_y0, color); + } + + if ( (draw_x1 >= 0) && (draw_y1 >= 0) ) { + pixel(draw_x1, draw_y1, color); + } + + if ( (draw_x2 <= width()) && (draw_y2 <= height()) ) { + pixel(draw_x2, draw_y2, color); + } + + if ( (draw_x3 >=0 ) && (draw_y3 <= height()) ) { + pixel(draw_x3, draw_y3, color); + } + + if ( (draw_x4 <= width()) && (draw_y4 >= 0) ) { + pixel(draw_x4, draw_y4, color); + } + + if ( (draw_x5 >= 0) && (draw_y5 >= 0) ) { + pixel(draw_x5, draw_y5, color); + } + if ( (draw_x6 <=width()) && (draw_y6 <= height()) ) { + pixel(draw_x6, draw_y6, color); + } + if ( (draw_x7 >= 0) && (draw_y7 <= height()) ) { + pixel(draw_x7, draw_y7, color); + } + } + return; +} + +void S6D0151_TFT::fillcircle(int x, int y, int r, int color) { + int i; + for (i = 0; i <= r; i++) + circle(x,y,i,color); +} + +void S6D0151_TFT::fillcircle2(int x0, int y0, int r, int color){ + int x = -r, y = 0, err = 2-2*r, e2; + do { + vline(x0-x, y0-y, y0+y, color); + vline(x0+x, y0-y, y0+y, color); + e2 = err; + if (e2 <= y) { + err += ++y*2+1; + if (-x == y && e2 <= x) e2 = 0; + } + if (e2 > x) err += ++x*2+1; + } while (x <= 0); +} + +void S6D0151_TFT::hline(int x0, int x1, int y, int color) { + int w; + w = x1 - x0 + 1; + window(x0,y,w,1); + wr_dat_start(); + for (int x=0; x<w; x++) { + _spi.write(color >> 8); + _spi.write(color); + } + wr_dat_stop(); + return; +} + + + +void S6D0151_TFT::vline(int x, int y0, int y1, int color) { + int h; + h = y1 - y0 + 1; + window(x,y0,1,h); + wr_dat_start(); + for (int y=0; y<h; y++) { + _spi.write(color >> 8); + _spi.write(color); + } + wr_dat_stop(); + return; +} + + + +void S6D0151_TFT::line(int x0, int y0, int x1, int y1, int color) { + WindowMax(); + int dx = 0, dy = 0; + int dx_sym = 0, dy_sym = 0; + int dx_x2 = 0, dy_x2 = 0; + int di = 0; + + dx = x1-x0; + dy = y1-y0; + + if (dx == 0) { /* vertical line */ + if (y1 > y0) vline(x0,y0,y1,color); + else vline(x0,y1,y0,color); + return; + } + + if (dx > 0) { + dx_sym = 1; + } else { + dx_sym = -1; + } + if (dy == 0) { /* horizontal line */ + if (x1 > x0) hline(x0,x1,y0,color); + else hline(x1,x0,y0,color); + return; + } + + if (dy > 0) { + dy_sym = 1; + } else { + dy_sym = -1; + } + + dx = dx_sym*dx; + dy = dy_sym*dy; + + dx_x2 = dx*2; + dy_x2 = dy*2; + + if (dx >= dy) { + di = dy_x2 - dx; + while (x0 != x1) { + + pixel(x0, y0, color); + x0 += dx_sym; + if (di<0) { + di += dy_x2; + } else { + di += dy_x2 - dx_x2; + y0 += dy_sym; + } + } + pixel(x0, y0, color); + } else { + di = dx_x2 - dy; + while (y0 != y1) { + pixel(x0, y0, color); + y0 += dy_sym; + if (di < 0) { + di += dx_x2; + } else { + di += dx_x2 - dy_x2; + x0 += dx_sym; + } + } + pixel(x0, y0, color); + } + return; +} + + + + +void S6D0151_TFT::rect(int x0, int y0, int x1, int y1, int color) { + + if (x1 > x0) hline(x0,x1,y0,color); + else hline(x1,x0,y0,color); + + if (y1 > y0) vline(x0,y0,y1,color); + else vline(x0,y1,y0,color); + + if (x1 > x0) hline(x0,x1,y1,color); + else hline(x1,x0,y1,color); + + if (y1 > y0) vline(x1,y0,y1,color); + else vline(x1,y1,y0,color); + + return; +} + + + +void S6D0151_TFT::fillrect(int x0, int y0, int x1, int y1, int color) { + + int h = y1 - y0 + 1; + int w = x1 - x0 + 1; + int pixel = h * w; + window(x0,y0,w,h); + wr_dat_start(); + for (int p=0; p<pixel; p++) { + _spi.write(color >> 8); + _spi.write(color); + } + wr_dat_stop(); + return; +} + + + +void S6D0151_TFT::locate(int x, int y) { + char_x = x; + char_y = y; +} + + + +int S6D0151_TFT::columns() { + return width() / font[1]; +} + + + +int S6D0151_TFT::rows() { + return height() / font[2]; +} + + + +int S6D0151_TFT::_putc(int value) { + if (value == '\n') { // new line + char_x = 0; + char_y = char_y + font[2]; + if (char_y >= height() - font[2]) { + char_y = 0; + } + } else { + character(char_x, char_y, value); + } + return value; +} + + + + +void S6D0151_TFT::character(int x, int y, int c) { + unsigned int hor,vert,offset,bpl,j,i,b; + unsigned char* zeichen; + unsigned char z,w; + + if ((c < 31) || (c > 156)) return; // test char range + + // read font parameter from start of array + offset = font[0]; // bytes / char + hor = font[1]; // get hor size of font + vert = font[2]; // get vert size of font + bpl = font[3]; // bytes per line + + if (char_x + hor > width()) { + char_x = 0; + char_y = char_y + vert; + if (char_y >= height() - font[2]) { + char_y = 0; + } + } + + window(char_x, char_y,hor,vert); // char box + wr_dat_start(); + zeichen = &font[((c -32) * offset) + 4]; // start of char bitmap + w = zeichen[0]; // width of actual char + + for (j=0; j<vert; j++) { // vert line + for (i=0; i<hor; i++) { // horz line + z = zeichen[bpl * i + ((j & 0xF8) >> 3)+1]; + b = 1 << (j & 0x07); + if (( z & b ) == 0x00) { + _spi.write(_background >> 8); + _spi.write(_background & 0xff); + } else { + _spi.write(_foreground >> 8); + _spi.write(_foreground & 0xff); + } + } + } + wr_dat_stop(); + if ((w + 2) < hor) { // x offset to next char + char_x += w + 2; + } else char_x += hor; +} + +void S6D0151_TFT::set_font(unsigned char* f) { + font = f; +} + + + +void S6D0151_TFT::Bitmap(unsigned int x, unsigned int y, unsigned int w, unsigned int h,unsigned char *bitmap) { + unsigned int i,j; + unsigned short *bitmap_ptr = (unsigned short *)bitmap; + window(x, y, w, h); + wr_dat_start(); + for (j = 0; j < h; j++) { //Lines + for (i = 0; i < w; i++) { // copy pixel data to TFT + + _spi.write(*bitmap_ptr >> 8); + _spi.write(*bitmap_ptr); // one line + + bitmap_ptr++; + } + } + wr_dat_stop(); +} + + +int S6D0151_TFT::BMP_16(unsigned int x, unsigned int y, const char *Name_BMP) { +// BEWARE ! +// NOT TESTED +#define OffsetPixelWidth 18 +#define OffsetPixelHeigh 22 +#define OffsetFileSize 34 +#define OffsetPixData 10 +#define OffsetBPP 28 + + char filename[50]; + unsigned char BMP_Header[54]; + unsigned short BPP_t; + unsigned int PixelWidth,PixelHeigh,start_data; + unsigned int i,off; + int padd,j; + unsigned short *line; + + // get the filename +#if 0 + LocalFileSystem local("local"); +#endif + sprintf(&filename[0],"/local/"); + i=7; + while (*Name_BMP!='\0') { + filename[i++]=*Name_BMP++; + } + FILE *Image = fopen((const char *)&filename[0], "r"); // open the bmp file + if (!Image) { + return(0); // error file not found ! + } + + fread(&BMP_Header[0],1,54,Image); // get the BMP Header + + if (BMP_Header[0] != 0x42 || BMP_Header[1] != 0x4D) { // check magic byte + fclose(Image); + return(-1); // error no BMP file + } + + BPP_t = BMP_Header[OffsetBPP] + (BMP_Header[OffsetBPP + 1] << 8); + if (BPP_t != 0x0010) { + fclose(Image); + return(-2); // error no 16 bit BMP + } + + PixelHeigh = BMP_Header[OffsetPixelHeigh] + (BMP_Header[OffsetPixelHeigh + 1] << 8) + (BMP_Header[OffsetPixelHeigh + 2] << 16) + (BMP_Header[OffsetPixelHeigh + 3] << 24); + PixelWidth = BMP_Header[OffsetPixelWidth] + (BMP_Header[OffsetPixelWidth + 1] << 8) + (BMP_Header[OffsetPixelWidth + 2] << 16) + (BMP_Header[OffsetPixelWidth + 3] << 24); + if (PixelHeigh > height() + y || PixelWidth > width() + x) { + fclose(Image); + return(-3); // to big + } + + start_data = BMP_Header[OffsetPixData] + (BMP_Header[OffsetPixData + 1] << 8) + (BMP_Header[OffsetPixData + 2] << 16) + (BMP_Header[OffsetPixData + 3] << 24); + + line = (unsigned short *) malloc (PixelWidth); // we need a buffer for a line + if (line == NULL) { + return(-4); // error no memory + } + + // the lines are padded to multiple of 4 bytes + padd = -1; + do { + padd ++; + } while ((PixelWidth * 2 + padd)%4 != 0); + + window(x, y,PixelWidth,PixelHeigh); + //wr_cmd(0x2C); + wr_dat_start(); + #ifndef TARGET_KL25Z // only 8 Bit SPI + _spi.format(16,3); + #endif // switch to 16 bit Mode 3 + for (j = PixelHeigh - 1; j >= 0; j--) { //Lines bottom up + off = j * (PixelWidth * 2 + padd) + start_data; // start of line + fseek(Image, off ,SEEK_SET); + fread(line,1,PixelWidth * 2,Image); // read a line - slow ! + for (i = 0; i < PixelWidth; i++) { // copy pixel data to TFT + #ifndef TARGET_KL25Z // only 8 Bit SPI + _spi.write(line[i]); // one 16 bit pixel + #else + _spi.write(line[i] >> 8); + _spi.write(line[i]); + #endif + } + } + _spi.format(8,3); + wr_dat_stop(); + free (line); + fclose(Image); + return(1); +} \ No newline at end of file