2025-06-15 21:31:45 +08:00

2165 lines
82 KiB
C

/***********************************************************************************************************************
PicoMite MMBasic
SPI-LCD.c
<COPYRIGHT HOLDERS> Geoff Graham, Peter Mather
Copyright (c) 2021, <COPYRIGHT HOLDERS> All rights reserved.
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the distribution.
3. The name MMBasic be used when referring to the interpreter in any documentation and promotional material and the original copyright message be displayed
on the console at startup (additional copyright messages may be added).
4. All advertising materials mentioning features or use of this software must display the following acknowledgement: This product includes software developed
by the <copyright holder>.
5. Neither the name of the <copyright holder> nor the names of its contributors may be used to endorse or promote products derived from this software
without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY <COPYRIGHT HOLDERS> AS IS AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDERS> BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
************************************************************************************************************************/
#include <stdarg.h>
#include "MMBasic_Includes.h"
#include "Hardware_Includes.h"
#include "hardware/dma.h"
int CurrentSPIDevice=NONE_SPI_DEVICE;
const struct Displays display_details[]={
{0,"", SDCARD_SPI_SPEED, 0, 0, 0, 0, SPI_POLARITY_LOW, SPI_PHASE_1EDGE},
{1,"", SDCARD_SPI_SPEED, 0, 0, 0, 0, SPI_POLARITY_LOW, SPI_PHASE_1EDGE},
{2,"SSD1306I2C", 400, 128, 64, 1, 1, SPI_POLARITY_LOW, SPI_PHASE_1EDGE},
{3,"SSD1306I2C32", 400, 128, 32, 1, 1, SPI_POLARITY_LOW, SPI_PHASE_1EDGE},
{4,"ILI9163", LCD_SPI_SPEED, 128, 128, 16, 0, SPI_POLARITY_LOW, SPI_PHASE_1EDGE},
{5,"ILI9341", 50000000, 320, 240, 16, 0, SPI_POLARITY_LOW, SPI_PHASE_1EDGE},
{6,"ST7735", LCD_SPI_SPEED, 160, 128, 16, 0, SPI_POLARITY_LOW, SPI_PHASE_1EDGE},
{7,"ST7735S", LCD_SPI_SPEED, 160, 80, 16, 0, SPI_POLARITY_LOW, SPI_PHASE_1EDGE},
{8,"SSD1331", LCD_SPI_SPEED, 96, 64, 16, 0, SPI_POLARITY_LOW, SPI_PHASE_1EDGE},
{9,"ST7789", LCD_SPI_SPEED, 240, 240, 16, 0, SPI_POLARITY_LOW, SPI_PHASE_1EDGE},
{10,"ILI9481", LCD_SPI_SPEED, 480, 320, 16, 0, SPI_POLARITY_LOW, SPI_PHASE_1EDGE},
{11,"ILI9488", LCD_SPI_SPEED, 480, 320, 16, 0, SPI_POLARITY_LOW, SPI_PHASE_1EDGE},
{12,"ILI9488P", LCD_SPI_SPEED, 320, 320, 16, 0, SPI_POLARITY_LOW, SPI_PHASE_1EDGE},
{13,"ST7789_135", LCD_SPI_SPEED, 240, 135, 16, 0, SPI_POLARITY_LOW, SPI_PHASE_1EDGE},
{14,"ST7789_320", 50000000, 320, 240, 16, 0, SPI_POLARITY_LOW, SPI_PHASE_1EDGE},
{15,"ILI9488W", LCD_SPI_SPEED, 480, 320, 16, 0, SPI_POLARITY_LOW, SPI_PHASE_1EDGE},
{16,"ST7796S", 50000000, 480, 320, 16, 0, SPI_POLARITY_LOW, SPI_PHASE_1EDGE},
{17,"ST7796SP",50000000, 320, 320, 16, 0, SPI_POLARITY_LOW, SPI_PHASE_1EDGE},
{18,"ST7735S_W", LCD_SPI_SPEED, 128, 128, 16, 0, SPI_POLARITY_LOW, SPI_PHASE_1EDGE},
{19,"GC9A01", LCD_SPI_SPEED, 240, 240, 16, 0, SPI_POLARITY_LOW, SPI_PHASE_1EDGE},
{20,"ILI9481IPS", 12000000, 480, 320, 16, 0, SPI_POLARITY_LOW, SPI_PHASE_1EDGE},
{21,"N5110", NOKIA_SPI_SPEED, 84, 48, 1, 1, SPI_POLARITY_LOW, SPI_PHASE_1EDGE},
{22,"SSD1306SPI", LCD_SPI_SPEED, 128, 64, 1, 1, SPI_POLARITY_LOW, SPI_PHASE_1EDGE},
{23,"ST7920", ST7920_SPI_SPEED, 128, 64, 1, 1, SPI_POLARITY_HIGH, SPI_PHASE_2EDGE},
{24,"", TOUCH_SPI_SPEED, 0, 0, 0, 0, SPI_POLARITY_LOW, SPI_PHASE_1EDGE},
{25,"SPIReadSpeed", 12000000, 480, 320, 16, 0, SPI_POLARITY_LOW, SPI_PHASE_1EDGE},
{26,"ST7789RSpeed", 6000000, 320, 240, 16, 0, SPI_POLARITY_LOW, SPI_PHASE_1EDGE},
{27,"", SLOW_TOUCH_SPEED, 0, 0, 0, 0, SPI_POLARITY_LOW, SPI_PHASE_1EDGE},
{28,"User", 0, 0, 0, 0, 0, 0 ,0},
{29,"Dummy", 0, 0, 0, 0, 0, 0 ,0},
{30,"Dummy", 0, 0, 0, 0, 0, 0 ,0},
{31,"Dummy", 0, 0, 0, 0, 0, 0 ,0},
{32,"Dummy", 0, 0, 0, 0, 0, 0 ,0},
{33,"Dummy", 0, 0, 0, 0, 0, 0 ,0},
{34,"Dummy", 0, 0, 0, 0, 0, 0 ,0},
{35,"Dummy", 0, 0, 0, 0, 0, 0 ,0},
{36,"SSD1963_4", 0, 0, 0, 0, 0, 0 ,0},
{37,"SSD1963_5", 0, 0, 0, 0, 0, 0 ,0},
{38,"SSD1963_5A", 0, 0, 0, 0, 0, 0 ,0},
{39,"SSD1963_7", 0, 0, 0, 0, 0, 0 ,0},
{40,"SSD1963_7A", 0, 0, 0, 0, 0, 0 ,0},
{41,"SSD1963_8", 0, 0, 0, 0, 0, 0 ,0},
{42,"ILI9341_8", 0, 0, 0, 0, 0, 0 ,0},
{43,"SSD1963_4_16", 0, 0, 0, 0, 0, 0 ,0},
{44,"SSD1963_5_16", 0, 0, 0, 0, 0, 0 ,0},
{45,"SSD1963_5A_16" , 0, 0, 0, 0, 0, 0 ,0},
{46,"SSD1963_7_16", 0, 0, 0, 0, 0, 0 ,0},
{47,"SSD1963_7A_16", 0, 0, 0, 0, 0, 0 ,0},
{48,"SSD1963_8_16", 0, 0, 0, 0, 0, 0 ,0},
{49,"ILI9341_16", 0, 0, 0, 0, 0, 0 ,0},
{50,"IPS_4_16", 0, 0, 0, 0, 0, 0 ,0},
{51,"SSD1963_5E_16", 0, 0, 0, 0, 0, 0 ,0},
{52,"SSD1963_7E_16", 0, 0, 0, 0, 0, 0 ,0},
{53,"ILI9486_16", 0, 0, 0, 0, 0, 0 ,0},
{54,"VIRTUAL_C", 0, 320, 240, 0, 0, 0, 0},
{55,"VIRTUAL_M", 0, 640, 480, 0, 0, 0, 0},
{56,"VS1053slow", 200000, 0, 0, 0, 0, SPI_POLARITY_LOW, SPI_PHASE_1EDGE},
{57,"VS1053fast", 4000000, 0, 0, 0, 0, SPI_POLARITY_LOW, SPI_PHASE_1EDGE},
};
void __not_in_flash_func(spi_write_fast)(spi_inst_t *spi, const uint8_t *src, size_t len) {
// Write to TX FIFO whilst ignoring RX, then clean up afterward. When RX
// is full, PL022 inhibits RX pushes, and sets a sticky flag on
// push-on-full, but continues shifting. Safe if SSPIMSC_RORIM is not set.
for (size_t i = 0; i < len; ++i) {
while (!spi_is_writable(spi))
tight_loop_contents();
spi_get_hw(spi)->dr = (uint32_t)src[i];
}
}
void __not_in_flash_func(spi_finish)(spi_inst_t *spi){
// Drain RX FIFO, then wait for shifting to finish (which may be *after*
// TX FIFO drains), then drain RX FIFO again
while (spi_is_readable(spi))
(void)spi_get_hw(spi)->dr;
while (spi_get_hw(spi)->sr & SPI_SSPSR_BSY_BITS)
tight_loop_contents();
while (spi_is_readable(spi))
(void)spi_get_hw(spi)->dr;
// Don't leave overrun flag set
spi_get_hw(spi)->icr = SPI_SSPICR_RORIC_BITS;
}
#ifndef PICOMITEVGA
int LCD_CS_PIN=0;
int LCD_CD_PIN=0;
int LCD_Reset_PIN=0;
unsigned char LCDBuffer[1440]={0};
void DefineRegionSPI(int xstart, int ystart, int xend, int yend, int rw);
void DrawBitmapSPI(int x1, int y1, int width, int height, int scale, int fc, int bc, unsigned char *bitmap);
extern const int SPISpeeds[];
extern void spi_write_command(unsigned char command);
extern void I2C_Send_Data(unsigned char* data, int n);
void I2C_Send_Command(char command);
extern int mmI2Cvalue; // value of MM.I2C
void waitwhilebusy(void);
#define SPIsend(a) {uint8_t b=a;xmit_byte_multi(&b,1);}
#define SPIqueue(a) {(Option.DISPLAY_TYPE==ILI9488 || Option.DISPLAY_TYPE == ILI9488P || Option.DISPLAY_TYPE==ILI9481IPS) ? xmit_byte_multi(a,3) : xmit_byte_multi(a,2) ;}
#define SPIsend2(a) {SPIsend(0);SPIsend(a);}
int PackHorizontal=0;
int fullrefreshcount=0;
void DrawRectangleMEM(int x1, int y1, int x2, int y2, int c);
void DrawBitmapMEM(int x1, int y1, int width, int height, int scale, int fc, int bc, unsigned char *bitmap);
void DrawBufferMEM(int x1, int y1, int x2, int y2, unsigned char* p) ;
void ReadBufferMEM(int x1, int y1, int x2, int y2, unsigned char* buff);
void spi_write_CommandData(const uint8_t* pCommandData, uint8_t datalen);
void ST7920command(unsigned char data);
// utility function for routines that want to reserve a pin for special I/O
// this ignores any previous settings and forces the pin to its new state
// pin is the pin number
// inp is true if an input or false if an output
// init is the value used to initialise the pin if it is an output (hi or lo)
// type is the final tag for the pin in ExtCurrentConfig[]
void SetAndReserve(int pin, int inp, int init, int type) {
if(pin == 0) return; // do nothing if not set
}
void MIPS16 ConfigDisplaySPI(unsigned char *p) {
char code,CD,RESET,CS=0;
uint8_t BACKLIGHT=0;
int DISPLAY_TYPE=0;
int orientation=1;
getargs(&p, 13, (unsigned char *)",");
if(checkstring(argv[0], (unsigned char *)"ILI9163")) {
DISPLAY_TYPE = ILI9163;
} else if(checkstring(argv[0], (unsigned char *)"SSD1331")) {
DISPLAY_TYPE = SSD1331;
} else if(checkstring(argv[0], (unsigned char *)"ST7735S")) {
DISPLAY_TYPE = ST7735S;
} else if(checkstring(argv[0], (unsigned char *)"ST7735")) {
DISPLAY_TYPE = ST7735;
} else if(checkstring(argv[0], (unsigned char *)"ST7789")) {
DISPLAY_TYPE = ST7789;
} else if(checkstring(argv[0], (unsigned char *)"ST7789_135")) {
DISPLAY_TYPE = ST7789A;
} else if(checkstring(argv[0], (unsigned char *)"ST7789_320")) {
DISPLAY_TYPE = ST7789B;
} else if(checkstring(argv[0], (unsigned char *)"ILI9481IPS")) {
DISPLAY_TYPE = ILI9481IPS;
} else if(checkstring(argv[0], (unsigned char *)"ILI9481")) {
DISPLAY_TYPE = ILI9481;
} else if(checkstring(argv[0], (unsigned char *)"ILI9488")) {
DISPLAY_TYPE = ILI9488;
} else if(checkstring(argv[0], (unsigned char *)"ILI9488P")) {
DISPLAY_TYPE = ILI9488P;
} else if(checkstring(argv[0], (unsigned char *)"ILI9488W")) {
DISPLAY_TYPE = ILI9488W;
} else if(checkstring(argv[0], (unsigned char *)"ST7796S")) {
DISPLAY_TYPE = ST7796S;
} else if(checkstring(argv[0], (unsigned char *)"ST7796SP")) {
DISPLAY_TYPE = ST7796SP;
} else if(checkstring(argv[0], (unsigned char *)"ILI9341")) {
DISPLAY_TYPE = ILI9341;
} else if(checkstring(argv[0], (unsigned char *)"ST7735S_W")) {
DISPLAY_TYPE = ST7735S_W;
} else if(checkstring(argv[0], (unsigned char *)"GC9A01")) {
DISPLAY_TYPE = GC9A01;
} else if(checkstring(argv[0], (unsigned char *)"N5110")) {
DISPLAY_TYPE = N5110;
} else if(checkstring(argv[0], (unsigned char *)"SSD1306SPI")) {
DISPLAY_TYPE = SSD1306SPI;
} else if(checkstring(argv[0], (unsigned char *)"ST7920")) {
DISPLAY_TYPE = ST7920;
} else return;
if(!Option.SYSTEM_CLK)error("System SPI not configured");
if(!(argc == 7 || argc == 9 || argc==11 || argc==13)) error("Argument count");
if(*argv[2]){
if(checkstring(argv[2], (unsigned char *)"L") || checkstring(argv[2], (unsigned char *)"LANDSCAPE"))
orientation = LANDSCAPE;
else if(checkstring(argv[2], (unsigned char *)"P") || checkstring(argv[2], (unsigned char *)"PORTRAIT"))
orientation = PORTRAIT;
else if(checkstring(argv[2], (unsigned char *)"RL") || checkstring(argv[2], (unsigned char *)"RLANDSCAPE"))
orientation = RLANDSCAPE;
else if(checkstring(argv[2], (unsigned char *)"RP") || checkstring(argv[2], (unsigned char *)"RPORTRAIT"))
orientation = RPORTRAIT;
else error("Orientation");
}
Option.DISPLAY_ORIENTATION=orientation;
if(DISPLAY_TYPE==ST7789 || DISPLAY_TYPE == ST7789A|| DISPLAY_TYPE == ST7789A)Option.DISPLAY_ORIENTATION=(Option.DISPLAY_ORIENTATION+2) % 4;
if(!(code=codecheck(argv[4])))argv[4]+=2;
CD = getinteger(argv[4]);
if(!code)CD=codemap(CD);
if(!(code=codecheck(argv[6])))argv[6]+=2;
RESET = getinteger(argv[6]);
if(!code)RESET=codemap(RESET);
if(DISPLAY_TYPE!=ST7920){
if(!(code=codecheck(argv[8])))argv[8]+=2;
CS = getinteger(argv[8]);
if(!code)CS=codemap(CS);
Option.LCDVOP=0xB1;
Option.I2Coffset=0;
if(argc>=11 && *argv[10]){
if(DISPLAY_TYPE == N5110)Option.LCDVOP=getint(argv[10],0,255);
else if(DISPLAY_TYPE == SSD1306SPI)Option.I2Coffset=getint(argv[10],0,10);
else {
if(!(code=codecheck(argv[10])))argv[10]+=2;
BACKLIGHT = getinteger(argv[10]);
if(!code)BACKLIGHT=codemap(BACKLIGHT);
CheckPin(BACKLIGHT, CP_IGNORE_INUSE);
if((PinDef[BACKLIGHT].slice & 0x7f) == Option.AUDIO_SLICE) error("Channel in use for Audio");
}
}
CheckPin(CS, CP_IGNORE_INUSE);
Option.LCD_CS = CS;
if(argc==13){
if(checkstring(argv[12],(unsigned char *)"INVERT"))Option.BGR=1;
} else Option.BGR=0;
}
CheckPin(CD, CP_IGNORE_INUSE);
CheckPin(RESET, CP_IGNORE_INUSE);
if(CS==CD || CS==RESET || (CS==BACKLIGHT && DISPLAY_TYPE!=ST7920) || CD==RESET || CD==BACKLIGHT || RESET==BACKLIGHT)error("Duplicated pin");
Option.LCD_CD = CD;
Option.LCD_Reset = RESET;
Option.DISPLAY_BL = BACKLIGHT;
Option.DISPLAY_TYPE=DISPLAY_TYPE;
if(!(Option.DISPLAY_TYPE>I2C_PANEL && Option.DISPLAY_TYPE < BufferedPanel)) Option.Refresh = 1;
}
// initialise the display controller
// this is used in the initial boot sequence of the Micromite
void MIPS16 InitDisplaySPI(int InitOnly) {
if(Option.DISPLAY_TYPE==0 || Option.DISPLAY_TYPE >= DISP_USER || Option.DISPLAY_TYPE <= I2C_PANEL) return;
DisplayHRes = display_details[Option.DISPLAY_TYPE].horizontal;
DisplayVRes = display_details[Option.DISPLAY_TYPE].vertical;
if(!InitOnly) {
// SPI2on();
// open the SPI port and reserve the I/O pins
// setup the pointers to the drawing primitives
if(Option.DISPLAY_TYPE>I2C_PANEL && Option.DISPLAY_TYPE < BufferedPanel){
if(Option.DISPLAY_ORIENTATION==PORTRAIT){
DrawRectangle = DrawRectangleSPISCR;
DrawBitmap = DrawBitmapSPISCR;
DrawBuffer = DrawBufferSPISCR;
DrawPixel = DrawPixelNormal;
ScrollLCD = ScrollLCDSPISCR;
DrawBLITBuffer = DrawBufferSPISCR;
if(Option.DISPLAY_TYPE == ILI9341 || Option.DISPLAY_TYPE == ST7796SP || Option.DISPLAY_TYPE == ST7796S || Option.DISPLAY_TYPE == ILI9488 || Option.DISPLAY_TYPE == ILI9488P || Option.DISPLAY_TYPE == ST7789B){
ReadBuffer = ReadBufferSPISCR;
ReadBLITBuffer = ReadBufferSPISCR;
}
} else {
DrawRectangle = DrawRectangleSPI;
DrawBitmap = DrawBitmapSPI;
DrawBuffer = DrawBufferSPI;
DrawBLITBuffer = DrawBufferSPI;
DrawPixel = DrawPixelNormal;
if(Option.DISPLAY_TYPE == ILI9341 || Option.DISPLAY_TYPE == ST7796SP || Option.DISPLAY_TYPE == ST7796S || Option.DISPLAY_TYPE == ILI9488 || Option.DISPLAY_TYPE == ILI9488P || Option.DISPLAY_TYPE == ST7789B){
ReadBLITBuffer = ReadBufferSPI;
ReadBuffer = ReadBufferSPI;
ScrollLCD = ScrollLCDSPI;
}
}
} else {
DrawRectangle = DrawRectangleMEM;
DrawBitmap = DrawBitmapMEM;
DrawBuffer = DrawBufferMEM;
ReadBuffer = ReadBufferMEM;
DrawBLITBuffer = DrawBufferMEM;
ReadBLITBuffer = ReadBufferMEM;
}
DrawPixel=DrawPixelNormal;
}
// the parameters for the display panel are set here
// the initialisation sequences and the SPI driver code was written by Peter Mather (matherp on The Back Shed forum)
switch(Option.DISPLAY_TYPE) {
case ST7796S:
case ST7796SP:
ResetController();
spi_write_cd(0xC5, 1, 0x1C); //VCOM Control 1 [1C]
spi_write_cd(0x3A, 1, 0x55); //565
spi_write_command(0xB0); //Interface [00]
uSec(150000);
//0xB1, 2, 0xB0, 0x11, //Frame Rate Control [A0 10]
spi_write_cd(0xB4, 1, 0x01); //Inversion Control [01]
if(Option.BGR)spi_write_command(0x21);
else spi_write_command(0x20);
spi_write_cd(0xB6, 3, 0x80, 0x02, 0x3B); // Display Function Control [80 02 3B] .kbv SS=1, NL=480
spi_write_cd(0xB7, 1, 0xC6); //Entry Mode [06]
// 0xF7, 4, 0xA9, 0x51, 0x2C, 0x82, //Adjustment Control 3 [A9 51 2C 82]
spi_write_cd(0xF0, 1, 0xC3); //?? lock manufacturer commands
spi_write_cd(0xF0, 1, 0x96); //
// spi_write_cd(0xFB, 1, 0x3C); //
switch(Option.DISPLAY_ORIENTATION) {
case LANDSCAPE: spi_write_cd(ILI9341_MEMCONTROL,1,ILI9341_Landscape); break;
case PORTRAIT: spi_write_cd(ILI9341_MEMCONTROL,1,ILI9341_Portrait); break;
case RLANDSCAPE: spi_write_cd(ILI9341_MEMCONTROL,1,ILI9341_Landscape180); break;
case RPORTRAIT: spi_write_cd(ILI9341_MEMCONTROL,1,ILI9341_Portrait180); break;
}
if(Option.DISPLAY_TYPE==ST7796SP){
spi_write_cd(0x33,6,0x00,0x00,0x01,0x40,0x00,0xA0);
} else {
spi_write_cd(0x33,6,0x00,0x00,0x01,0xE0,0x00,0x00);
}
spi_write_command(0x11);
uSec(150000);
spi_write_command(0x29); //Display on
uSec(150000);
break;
case ILI9488:
case ILI9488P:
case ILI9488W:
ResetController();
if(Option.DISPLAY_TYPE==ILI9488 || Option.DISPLAY_TYPE==ILI9488P){
spi_write_command(0xE0); // Positive Gamma Control
spi_write_data(0x00);
spi_write_data(0x03);
spi_write_data(0x09);
spi_write_data(0x08);
spi_write_data(0x16);
spi_write_data(0x0A);
spi_write_data(0x3F);
spi_write_data(0x78);
spi_write_data(0x4C);
spi_write_data(0x09);
spi_write_data(0x0A);
spi_write_data(0x08);
spi_write_data(0x16);
spi_write_data(0x1A);
spi_write_data(0x0F);
spi_write_command(0XE1); // Negative Gamma Control
spi_write_data(0x00);
spi_write_data(0x16);
spi_write_data(0x19);
spi_write_data(0x03);
spi_write_data(0x0F);
spi_write_data(0x05);
spi_write_data(0x32);
spi_write_data(0x45);
spi_write_data(0x46);
spi_write_data(0x04);
spi_write_data(0x0E);
spi_write_data(0x0D);
spi_write_data(0x35);
spi_write_data(0x37);
spi_write_data(0x0F);
spi_write_command(0XC0); // Power Control 1
spi_write_data(0x17);
spi_write_data(0x15);
spi_write_command(0xC1); // Power Control 2
spi_write_data(0x41);
spi_write_command(0xC5); // VCOM Control
spi_write_data(0x00);
spi_write_data(0x12);
spi_write_data(0x80);
spi_write_command(TFT_MADCTL); // Memory Access Control
spi_write_data(0x48); // MX, BGR
spi_write_command(0x3A); // Pixel Interface Format
spi_write_data(0x66); // 18 bit colour for SPI
spi_write_command(0xB0); // Interface Mode Control
spi_write_data(0x00);
spi_write_command(0xB1); // Frame Rate Control
spi_write_data(0xA0);
if(Option.BGR)spi_write_command(0x21);
spi_write_command(0xB4); // Display Inversion Control
spi_write_data(0x02);
spi_write_command(0xB6); // Display Function Control
spi_write_data(0x02);
spi_write_data(0x02);
spi_write_data(0x3B);
spi_write_command(0xB7); // Entry Mode Set
spi_write_data(0xC6);
spi_write_command(0xF7); // Adjust Control 3
spi_write_data(0xA9);
spi_write_data(0x51);
spi_write_data(0x2C);
spi_write_data(0x82);
spi_write_command(TFT_SLPOUT); //Exit Sleep
uSec(120000);
if(Option.DISPLAY_TYPE==ILI9488P){
spi_write_command(0x33);
spi_write_data(0x00);
spi_write_data(0x00);
spi_write_data(0x01);
spi_write_data(0x40);
spi_write_data(0x00);
spi_write_data(0xA0);
} else {
spi_write_command(0x33);
spi_write_data(0x00);
spi_write_data(0x00);
spi_write_data(0x01);
spi_write_data(0xE0);
spi_write_data(0x00);
spi_write_data(0x00);
}
spi_write_command(TFT_DISPON); //Display on
uSec(25000);
} else {
if(Option.BGR)spi_write_command(0x20);
else spi_write_command(0x21);
spi_write_command(0xC2); //Normal mode, increase can change the display quality, while increasing power consumption
spi_write_data(0x33);
spi_write_command(0XC5);
spi_write_data(0x00);
spi_write_data(0x1e);//VCM_REG[7:0]. <=0X80.
spi_write_data(0x80);
spi_write_command(0xB1);//Sets the frame frequency of full color normal mode
spi_write_data(0xB0);//0XB0 =70HZ, <=0XB0.0xA0=62HZ
spi_write_command(0x36);
spi_write_data(0x28); //2 DOT FRAME MODE,F<=70HZ.
spi_write_command(0XE0);
spi_write_data(0x0);
spi_write_data(0x13);
spi_write_data(0x18);
spi_write_data(0x04);
spi_write_data(0x0F);
spi_write_data(0x06);
spi_write_data(0x3a);
spi_write_data(0x56);
spi_write_data(0x4d);
spi_write_data(0x03);
spi_write_data(0x0a);
spi_write_data(0x06);
spi_write_data(0x30);
spi_write_data(0x3e);
spi_write_data(0x0f);
spi_write_command(0XE1);
spi_write_data(0x0);
spi_write_data(0x13);
spi_write_data(0x18);
spi_write_data(0x01);
spi_write_data(0x11);
spi_write_data(0x06);
spi_write_data(0x38);
spi_write_data(0x34);
spi_write_data(0x4d);
spi_write_data(0x06);
spi_write_data(0x0d);
spi_write_data(0x0b);
spi_write_data(0x31);
spi_write_data(0x37);
spi_write_data(0x0f);
spi_write_command(0X3A); //Set Interface Pixel Format
spi_write_data(0x55);
spi_write_command(0x11);//sleep out
uSec(120000);
spi_write_command(0x29);//Turn on the LCD display
}
// spi_write_command(TFT_MADCTL);
switch(Option.DISPLAY_ORIENTATION) {
case LANDSCAPE: spi_write_cd(ILI9341_MEMCONTROL,1,ILI9341_Landscape); break;
case PORTRAIT: spi_write_cd(ILI9341_MEMCONTROL,1,ILI9341_Portrait); break;
case RLANDSCAPE: spi_write_cd(ILI9341_MEMCONTROL,1,ILI9341_Landscape180); break;
case RPORTRAIT: spi_write_cd(ILI9341_MEMCONTROL,1,ILI9341_Portrait180); break;
}
break;
case ILI9481IPS:
ResetController();
//3.5IPS ILI9481+CMI
spi_write_command(0x01); //Soft_rese
uSec(220000);
spi_write_command(0x11);
uSec(280000);
spi_write_command(0xd0); //Power_Setting
spi_write_data(0x07);//07 VC[2:0] Sets the ratio factor of Vci to generate the reference voltages Vci1
spi_write_data(0x44);//41 BT[2:0] Sets the Step up factor and output voltage level from the reference voltages Vci1
spi_write_data(0x1E);//1f 17 1C VRH[3:0]: Sets the factor to generate VREG1OUT from VCILVL
uSec(220000);
spi_write_command(0xd1); //VCOM Control
spi_write_data(0x00);//00
spi_write_data(0x0C);//1A VCM [6:0] is used to set factor to generate VCOMH voltage from the reference voltage VREG1OUT 15 09
spi_write_data(0x1A);//1F VDV[4:0] is used to set the VCOM alternating amplitude in the range of VREG1OUT x 0.70 to VREG1OUT 1F 18
spi_write_command(0xC5); //Frame Rate
spi_write_data(0x03); // 03 02
spi_write_command(0xd2); //Power_Setting for Normal Mode
spi_write_data(0x01); //01
spi_write_data(0x11); //11
spi_write_command(0xE4); //?
spi_write_data(0xa0);
spi_write_command(0xf3);
spi_write_data(0x00);
spi_write_data(0x2a);
//1 OK
spi_write_command(0xc8);
spi_write_data(0x00);
spi_write_data(0x26);
spi_write_data(0x21);
spi_write_data(0x00);
spi_write_data(0x00);
spi_write_data(0x1f);
spi_write_data(0x65);
spi_write_data(0x23);
spi_write_data(0x77);
spi_write_data(0x00);
spi_write_data(0x0f);
spi_write_data(0x00);
//GAMMA SETTING
spi_write_command(0xC0); //Panel Driving Setting
spi_write_data(0x00); //1//00 REV SM GS
spi_write_data(0x3B); //2//NL[5:0]: Sets the number of lines to drive the LCD at an interval of 8 lines.
spi_write_data(0x00); //3//SCN[6:0]
spi_write_data(0x02); //4//PTV: Sets the Vcom output in non-display area drive period
spi_write_data(0x11); //5//NDL: Sets the source output level in non-display area. PTG: Sets the scan mode in non-display area.
spi_write_command(0xc6); //Interface Control
spi_write_data(0x83);
//GAMMA SETTING
spi_write_command(0xf0); //?
spi_write_data(0x01);
spi_write_command(0xE4);//?
spi_write_data(0xa0);
spi_write_command(0x3a);
spi_write_data(0x66);
uSec(280000);
switch(Option.DISPLAY_ORIENTATION) {
case LANDSCAPE: spi_write_cd(ILI9341_MEMCONTROL,1,ILI9481_Landscape); break;
case PORTRAIT: spi_write_cd(ILI9341_MEMCONTROL,1,ILI9481_Portrait); break;
case RLANDSCAPE: spi_write_cd(ILI9341_MEMCONTROL,1,ILI9481_Landscape180); break;
case RPORTRAIT: spi_write_cd(ILI9341_MEMCONTROL,1,ILI9481_Portrait180); break;
}
spi_write_command(0x2a);
spi_write_data(0x00);
spi_write_data(0x00);
spi_write_data(0x01);
spi_write_data(0x3F); //3F
spi_write_command(0x2b);
spi_write_data(0x00);
spi_write_data(0x00);
spi_write_data(0x01);
spi_write_data(0xDf); //DF
if(Option.BGR) spi_write_command(0x21);
spi_write_command(0x29);
break;
case ILI9481:
DisplayHRes = 480;
DisplayVRes = 320;
ResetController();
spi_write_command(0x11);
uSec(20000);
spi_write_cd(0xD0,3,0x07,0x42,0x18);
spi_write_cd(0xD1,3,0x00,0x07,0x10);
spi_write_cd(0xD2,2,0x01,0x02);
spi_write_cd(0xC0,5,0x10,0x3B,0x00,0x02,0x11);
// spi_write_cd(0xC1, 3,0x10, 0x12, 0xC8);
// spi_write_cd(0xC5,1,0x01);
spi_write_cd(0xB3,4,0x00,0x00,0x00,0x10);
spi_write_cd(0xC8,12,0x00,0x32,0x36,0x45,0x06,0x16,0x37,0x75,0x77,0x54,0x0C,0x00);
spi_write_cd(0xE0,15,0x0f,0x24,0x1c,0x0a,0x0f,0x08,0x43,0x88,0x03,0x0f,0x10,0x06,0x0f,0x07,0x00);
spi_write_cd(0xE1,15,0x0F,0x38,0x30,0x09,0x0f,0x0f,0x4e,0x77,0x3c,0x07,0x10,0x05,0x23,0x1b,0x00);
spi_write_cd(0x36,0x0A);
spi_write_cd(0x3A,1,0x55);
spi_write_cd(0x2A,4,0x00,0x00,0x01,0x3F);
spi_write_cd(0x2B,4,0x00,0x00,0x01,0xE0);
if(Option.BGR) spi_write_command(0x21);
uSec(120000);
spi_write_command(0x29);
switch(Option.DISPLAY_ORIENTATION) {
case LANDSCAPE: spi_write_cd(ILI9341_MEMCONTROL,1,ILI9341_Landscape); break;
case PORTRAIT: spi_write_cd(ILI9341_MEMCONTROL,1,ILI9341_Portrait); break;
case RLANDSCAPE: spi_write_cd(ILI9341_MEMCONTROL,1,ILI9341_Landscape180); break;
case RPORTRAIT: spi_write_cd(ILI9341_MEMCONTROL,1,ILI9341_Portrait180); break;
}
break;
case SSD1331:
ResetController();
spi_write_command(SSD1331_CMD_DISPLAYOFF); // 0xAE
spi_write_command(SSD1331_CMD_SETREMAP); // 0xA0
if(Option.DISPLAY_ORIENTATION==1) spi_write_command(0x72);
else if(Option.DISPLAY_ORIENTATION==2) spi_write_command(0x63);
else if(Option.DISPLAY_ORIENTATION==3) spi_write_command(0x60);
else spi_write_command(0x71);
spi_write_command(SSD1331_CMD_STARTLINE); // 0xA1
spi_write_command(0x0);
spi_write_command(SSD1331_CMD_DISPLAYOFFSET); // 0xA2
spi_write_command(0x0);
spi_write_command(SSD1331_CMD_NORMALDISPLAY); // 0xA4
spi_write_command(SSD1331_CMD_SETMULTIPLEX); // 0xA8
spi_write_command(0x3F); // 0x3F 1/64 duty
spi_write_command(SSD1331_CMD_SETMASTER); // 0xAD
spi_write_command(0x8E);
spi_write_command(SSD1331_CMD_POWERMODE); // 0xB0
spi_write_command(0x0B);
spi_write_command(SSD1331_CMD_PRECHARGE); // 0xB1
spi_write_command(0x31);
spi_write_command(SSD1331_CMD_CLOCKDIV); // 0xB3
spi_write_command(0xF0); // 7:4 = Oscillator Frequency, 3:0 = CLK Div Ratio (A[3:0]+1 = 1..16)
spi_write_command(SSD1331_CMD_PRECHARGEA); // 0x8A
spi_write_command(0x64);
spi_write_command(SSD1331_CMD_PRECHARGEB); // 0x8B
spi_write_command(0x78);
spi_write_command(SSD1331_CMD_PRECHARGEA); // 0x8C
spi_write_command(0x64);
spi_write_command(SSD1331_CMD_PRECHARGELEVEL); // 0xBB
spi_write_command(0x3A);
spi_write_command(SSD1331_CMD_VCOMH); // 0xBE
spi_write_command(0x3E);
spi_write_command(SSD1331_CMD_MASTERCURRENT); // 0x87
spi_write_command(0x06);
spi_write_command(SSD1331_CMD_CONTRASTA); // 0x81
spi_write_command(0x91);
spi_write_command(SSD1331_CMD_CONTRASTB); // 0x82
spi_write_command(0x50);
spi_write_command(SSD1331_CMD_CONTRASTC); // 0x83
spi_write_command(0x7D);
spi_write_command(SSD1331_CMD_DISPLAYON); //--turn on oled panel
break;
case ILI9341:
ResetController();
spi_write_command(ILI9341_SOFTRESET); //software reset
uSec(20000);
spi_write_command(ILI9341_DISPLAYOFF);
spi_write_cd(ILI9341_POWERCONTROL1,1,0x23);
spi_write_cd(ILI9341_POWERCONTROL2,1,0x10);
spi_write_cd(ILI9341_VCOMCONTROL1,2,0x2B,0x2B);
spi_write_cd(ILI9341_VCOMCONTROL2,1,0xC0);
spi_write_cd(ILI9341_PIXELFORMAT,1,0x55);
spi_write_cd(ILI9341_FRAMECONTROL,2,0x00,0x1B);
spi_write_cd(ILI9341_ENTRYMODE,1,0x07);
spi_write_cd(ILI9341_SLEEPOUT,1,0);
uSec(50000);
spi_write_command(ILI9341_NORMALDISP);
if(Option.BGR) spi_write_command(ILI9341_INVERTON);
spi_write_command(ILI9341_DISPLAYON);
uSec(100000);
switch(Option.DISPLAY_ORIENTATION) {
case LANDSCAPE: spi_write_cd(ILI9341_MEMCONTROL,1,ILI9341_Landscape); break;
case PORTRAIT: spi_write_cd(ILI9341_MEMCONTROL,1,ILI9341_Portrait); break;
case RLANDSCAPE: spi_write_cd(ILI9341_MEMCONTROL,1,ILI9341_Landscape180); break;
case RPORTRAIT: spi_write_cd(ILI9341_MEMCONTROL,1,ILI9341_Portrait180); break;
}
break;
case GC9A01:
ResetController();
spi_write_command(0xEF);
spi_write_cd(0xEB,1,0x14);
spi_write_command(0xFE);
spi_write_command(0xEF);
spi_write_cd(0xEB,1,0x14);
spi_write_cd(0x84,1,0x40);
spi_write_cd(0x85,1,0xFF);
spi_write_cd(0x86,1,0xFF);
spi_write_cd(0x87,1,0xFF);
spi_write_cd(0x88,1,0x0A);
spi_write_cd(0x89,1,0x21);
spi_write_cd(0x8A,1,0x00);
spi_write_cd(0x8B,1,0x80);
spi_write_cd(0x8C,1,0x01);
spi_write_cd(0x8D,1,0x01);
spi_write_cd(0x8E,1,0xFF);
spi_write_cd(0x8F,1,0xFF);
spi_write_cd(0xB6,2,0x00,0x20);
spi_write_cd(0x3A,1,0x05);
spi_write_cd(0x90,4,0x08, 0x08, 0x08, 0x08);
spi_write_cd(0xBD,1,0x06);
spi_write_cd(0xBC,1,0x00);
spi_write_cd(0xFF,3,0x60, 0x01, 0x04);
spi_write_cd(0xC3,1,0x13);
spi_write_cd(0xC4,1,0x13);
spi_write_cd(0xC9,1,0x22);
spi_write_cd(0xBE,1,0x11);
spi_write_cd(0xE1,2,0x10,0x0E);
spi_write_cd(0xDF,3,0x21, 0x0c, 0x02);
spi_write_cd(0xF0,6,0x45, 0x09, 0x08, 0x08, 0x26, 0x2A);
spi_write_cd(0xF1,6,0x43, 0x70, 0x72, 0x36, 0x37, 0x6F);
spi_write_cd(0xF2,6,0x45, 0x09, 0x08, 0x08, 0x26, 0x2A);
spi_write_cd(0xF3,6,0x43, 0x70, 0x72, 0x36, 0x37, 0x6F);
spi_write_cd(0xED,2,0x1B, 0x0B);
spi_write_cd(0xAE,1,0x77);
spi_write_cd(0xCD,1,0x63);
spi_write_cd(0x70,9, 0x07, 0x07, 0x04, 0x0E, 0x0F, 0x09, 0x07, 0x08, 0x03);
spi_write_cd(0xE8,1,0x34);
spi_write_cd(0x62,12, 0x18, 0x0D, 0x71, 0xED, 0x70, 0x70, 0x18, 0x0F, 0x71, 0xEF, 0x70, 0x70);
spi_write_cd(0x63,12, 0x18, 0x11, 0x71, 0xF1, 0x70, 0x70, 0x18, 0x13, 0x71, 0xF3, 0x70, 0x70);
spi_write_cd(0x64,7, 0x28, 0x29, 0xF1, 0x01, 0xF1, 0x00, 0x07);
spi_write_cd(0x66,10, 0x3C, 0x00, 0xCD, 0x67, 0x45, 0x45, 0x10, 0x00, 0x00, 0x00);
spi_write_cd(0x67,10, 0x00, 0x3C, 0x00, 0x00, 0x00, 0x01, 0x54, 0x10, 0x32, 0x98);
spi_write_cd(0x74,7, 0x10, 0x85, 0x80, 0x00, 0x00, 0x4E, 0x00);
spi_write_cd(0x98,2,0x3e, 0x07);
spi_write_command(0x35);
spi_write_command(GC9A01_SLPOUT);
uSec(10000);
spi_write_command(GC9A01_DISPON);
switch(Option.DISPLAY_ORIENTATION) {
case LANDSCAPE: spi_write_cd(GC9A01_MADCTL,1,0x08); break;
case PORTRAIT: spi_write_cd(GC9A01_MADCTL,1,0x68); break;
case RLANDSCAPE: spi_write_cd(GC9A01_MADCTL,1,0xc8); break;
case RPORTRAIT: spi_write_cd(GC9A01_MADCTL,1,0xa8); break;
}
break;
case ILI9163:
ResetController();
spi_write_command(ILI9341_SOFTRESET); //software reset
uSec(20000);
spi_write_command(ILI9163_SLPOUT); //exit sleep
uSec(5000);
spi_write_cd(ILI9163_PIXFMT,1,0x05);
uSec(5000);
spi_write_cd(ILI9163_GAMMASET,1,0x04); //0x04
uSec(1000);
spi_write_cd(ILI9163_GAMRSEL,1,0x01);
uSec(1000);
if(Option.BGR) spi_write_command(ILI9163_DINVON);
spi_write_command(ILI9163_NORML);
spi_write_cd(ILI9163_DFUNCTR,2,0b11111111,0b00000110); //
spi_write_cd(ILI9163_PGAMMAC,15,0x36,0x29,0x12,0x22,0x1C,0x15,0x42,0xB7,0x2F,0x13,0x12,0x0A,0x11,0x0B,0x06);//Positive Gamma Correction Setting
spi_write_cd(ILI9163_NGAMMAC,15,0x09,0x16,0x2D,0x0D,0x13,0x15,0x40,0x48,0x53,0x0C,0x1D,0x25,0x2E,0x34,0x39);//Negative Gamma Correction Setting
spi_write_cd(ILI9163_FRMCTR1,2,0x08,0x02); //0x0C//0x08
uSec(1000);
spi_write_cd(ILI9163_DINVCTR,1,0x07);
uSec(1000);
spi_write_cd(ILI9163_PWCTR1,2,0x0A,0x02); //4.30 - 0x0A
uSec(1000);
spi_write_cd(ILI9163_PWCTR2,1,0x02);
uSec(1000);
spi_write_cd(ILI9163_VCOMCTR1,2,0x50,99); //0x50
uSec(1000);
spi_write_cd(ILI9163_VCOMOFFS,1,0); //0x40
uSec(1000);
spi_write_cd(ILI9163_VSCLLDEF,5,0,0,DisplayVRes,0,0);
spi_write_command(ILI9163_DISPON); //display ON
uSec(1000);
switch(Option.DISPLAY_ORIENTATION) {
case LANDSCAPE: spi_write_cd(ILI9163_MADCTL,1,ILI9163_Landscape); break;
case PORTRAIT: spi_write_cd(ILI9163_MADCTL,1,ILI9163_Portrait); break;
case RLANDSCAPE: spi_write_cd(ILI9163_MADCTL,1,ILI9163_Landscape180); break;
case RPORTRAIT: spi_write_cd(ILI9163_MADCTL,1,ILI9163_Portrait180); break;
}
uSec(1000);
break;
case ST7735:
case ST7735S:
case ST7735S_W:
ResetController();
spi_write_command(ILI9341_SOFTRESET); //software reset
uSec(20000);
spi_write_command(ST7735_SLPOUT); //out of sleep mode
uSec(500000);
spi_write_cd(ST7735_FRMCTR1,3,0x01,0x2C,0x2d); //frame rate control - normal mode
spi_write_cd(ST7735_FRMCTR2,3,0x01,0x2C,0x2D); //frame rate control - idle mode
spi_write_cd(ST7735_FRMCTR3,6,0x01,0x2c,0x2D,0x01,0x2C,0x2D);//frame rate control - partial mode
spi_write_cd(ST7735_INVCTR,1,0x07); //display inversion control
spi_write_cd(ST7735_PWCTR1,3,0xA2,0x02,0x84); //power control
spi_write_cd(ST7735_PWCTR2,1,0xC5); //power control
spi_write_cd(ST7735_PWCTR3,2,0x0A,0x00); //power control
spi_write_cd(ST7735_PWCTR4,2,0x8A,0x2A); //power control
spi_write_cd(ST7735_PWCTR5,2,0x8A,0xEE); //power control
spi_write_cd(ST7735_VMCTR1,1,0x0E); //power control
if(Option.DISPLAY_TYPE==ST7735 || Option.DISPLAY_TYPE==ST7735S_W)Option.BGR ? spi_write_command(ST7735_INVON): spi_write_command(ST7735_INVOFF); //don't invert display
else Option.BGR ? spi_write_command(ST7735_INVOFF): spi_write_command(ST7735_INVON);
spi_write_cd(ST7735_COLMOD,1,0x05); //set color mode
spi_write_cd(ST7735_CASET,4,0,0,0,0x7F); //column addr set
spi_write_cd(ST7735_RASET,4,0,0,0,0x9F); //row addr set
spi_write_cd(ST7735_GMCTRP1,16,0x02,0x1c,0x07,0x12,0x37,0x32,0x29,0x2D,0x25,0x29,0x2B,0x39,0x00,0x01,0x03,0x10);
spi_write_cd(ST7735_GMCTRN1,16,0x03,0x1d,0x07,0x06,0x2E,0x2c,0x29,0x2d,0x2E,0x2E,0x37,0x3f,0x00,0x00,0x02,0x10);
spi_write_command(ST7735_NORON); //normal display on
uSec(10000);
spi_write_command(ST7735_DISPON);
switch(Option.DISPLAY_ORIENTATION) {
case LANDSCAPE: spi_write_cd(ST7735_MADCTL, 1, ST7735_Landscape | (Option.DISPLAY_TYPE==ST7735 ? 0 : 8)); break;
case PORTRAIT: spi_write_cd(ST7735_MADCTL, 1, ST7735_Portrait | (Option.DISPLAY_TYPE==ST7735 ? 0 : 8)); break;
case RLANDSCAPE: spi_write_cd(ST7735_MADCTL, 1, ST7735_Landscape180 | (Option.DISPLAY_TYPE==ST7735 ? 0 : 8)); break;
case RPORTRAIT: spi_write_cd(ST7735_MADCTL, 1, ST7735_Portrait180 | (Option.DISPLAY_TYPE==ST7735 ? 0 : 8)); break;
}
break;
case ST7789:
case ST7789A:
case ST7789B:
ResetController();
spi_write_command(ST77XX_SWRESET); uSec(150000);
spi_write_command(ST77XX_SLPOUT); uSec(500000);
spi_write_command(ST77XX_COLMOD); spi_write_data(0x55);uSec(10000);
// if(Option.DISPLAY_TYPE==ST7789){spi_write_command(ST77XX_CASET); spi_write_data(0x0); spi_write_data(0x0); spi_write_data(0x0); spi_write_data(239);}
// else if(Option.DISPLAY_ORIENTATION & 1){spi_write_command(ST77XX_CASET); spi_write_data(0x0); spi_write_data(40); spi_write_data(0x1); spi_write_data(23);}
// else {spi_write_command(ST77XX_CASET); spi_write_data(0x0); spi_write_data(52); spi_write_data(0x0); spi_write_data(186);}
// if(Option.DISPLAY_TYPE==ST7789){spi_write_command(ST77XX_RASET); spi_write_data(0x0); spi_write_data(0); spi_write_data(0); spi_write_data(239);}
// else if(Option.DISPLAY_ORIENTATION & 1){spi_write_command(ST77XX_RASET); spi_write_data(0x0); spi_write_data(53); spi_write_data(0); spi_write_data(187);}
// else {spi_write_command(ST77XX_RASET); spi_write_data(0x0); spi_write_data(40); spi_write_data(1); spi_write_data(23);}
if(Option.BGR)spi_write_command(ST77XX_INVOFF);
else spi_write_command(ST77XX_INVON);
uSec(10000);
spi_write_command(ST77XX_NORON); uSec(10000);
spi_write_command(ST77XX_DISPON); uSec(500000);
switch(Option.DISPLAY_ORIENTATION) {
case LANDSCAPE: spi_write_cd(ST7735_MADCTL, 1, ST7735_Landscape); break;
case PORTRAIT: spi_write_cd(ST7735_MADCTL, 1, ST7735_Portrait); break;
case RLANDSCAPE: spi_write_cd(ST7735_MADCTL, 1, ST7735_Landscape180); break;
case RPORTRAIT: spi_write_cd(ST7735_MADCTL, 1, ST7735_Portrait180); break;
}
break;
case N5110:
ResetController();
spi_write_command(0x21); // LCD Extended Commands.
uSec(20000);
spi_write_command(Option.LCDVOP); // Set LCD Vop (Contrast). //0xB0 for 5V, 0XB1 for 3.3v, 0XBF if screen too dark
uSec(20000);
spi_write_command(0x04); // Set Temp coefficient. //0x04
uSec(20000);
spi_write_command(0x14); // LCD bias mode 1:48. //0x13 or 0X14
uSec(20000);
spi_write_command(0x20); //We must send 0x20 before modifying the display control mode
uSec(20000);
spi_write_command(0x0C); // Set display control, normal mode. 0x0D for inverse, 0x0C for normal
uSec(20000);
break;
case SSD1306SPI:
ResetController();
spi_write_command(0xAE);//DISPLAYOFF
spi_write_command(0xD5);//DISPLAYCLOCKDIV
spi_write_command(0x80);//the suggested ratio &H80
spi_write_command(0xA8);//MULTIPLEX
spi_write_command(0x3F);//
spi_write_command(0xD3);//DISPLAYOFFSET
spi_write_command(0x0);//no offset
spi_write_command(0x40);//STARTLINE
spi_write_command(0x8D);//CHARGEPUMP
spi_write_command(0x14);
spi_write_command(0x20);//MEMORYMODE
spi_write_command(0x00);//&H0 act like ks0108
spi_write_command(0xA1);//SEGREMAP OR 1
spi_write_command(0xC8);//COMSCANDEC
spi_write_command(0xDA);//COMPINS
spi_write_command(0x12);
spi_write_command(0x81);//SETCONTRAST
spi_write_command(0xCF);
spi_write_command(0xd9);//SETPRECHARGE
spi_write_command(0xF1);
spi_write_command(0xDB);//VCOMDETECT
spi_write_command(0x40);
spi_write_command(0xA4);//DISPLAYALLON_RESUME
spi_write_command(0xA6);//NORMALDISPLAY
spi_write_command(0xAF);//DISPLAYON
break;
case ST7920:
PackHorizontal=1;
gpio_put(LCD_CD_PIN,GPIO_PIN_RESET);
uSec(40000);
SetCS();
ResetController();
ST7920command(1);
uSec(20000);
ST7920command(0b00001100);//display on
uSec(20000);
ST7920command(1);//DISPLAY CLEAR
uSec(20000);
ST7920command(0b00100110);//graphic mode
uSec(20000);
ClearCS(Option.LCD_CD);
break;
}
if(Option.DISPLAY_ORIENTATION & 1) {
HRes=DisplayHRes;
VRes=DisplayVRes;
} else {
HRes=DisplayVRes;
VRes=DisplayHRes;
}
if(!InitOnly) {
ResetDisplay();
ClearScreen(Option.DISPLAY_CONSOLE ? Option.DefaultBC : 0);
if(Option.Refresh)Display_Refresh();
}
}
// set Chip Select for the LCD low
// this also checks the configuration of the SPI channel and if required reconfigures it to suit the LCD controller
void SetCS(void) {
SPISpeedSet(Option.DISPLAY_TYPE);
if(Option.DISPLAY_TYPE != ST7920)gpio_put(LCD_CS_PIN,GPIO_PIN_RESET); // set CS low
else gpio_put(LCD_CD_PIN,GPIO_PIN_SET);
}
void spi_write_data(unsigned char data){
gpio_put(LCD_CD_PIN,GPIO_PIN_SET);
SetCS();
if(Option.DISPLAY_TYPE == ILI9481 || Option.DISPLAY_TYPE == ILI9488W) {SPIsend2(data);}
else {SPIsend(data);}
ClearCS(Option.LCD_CS);
}
void spi_write_command(unsigned char data){
gpio_put(LCD_CD_PIN,GPIO_PIN_RESET);
SetCS();
if(Option.DISPLAY_TYPE == ILI9481 || Option.DISPLAY_TYPE == ILI9488W) {SPIsend2(data);}
else {SPIsend(data);}
ClearCS(Option.LCD_CS);
}
void ST7920command(unsigned char data){
unsigned char a[3];
a[0]=ST7920setcommand;
a[1]=data & 0xF0;
a[2]=((data & 0x0F)<<4) & 0xF0;
SetCS();
xmit_byte_multi(a,3);
ClearCS(Option.LCD_CD);
}
void spi_write_cd(unsigned char command, int data, ...){
int i;
va_list ap;
va_start(ap, data);
spi_write_command(command);
for(i = 0; i < data; i++) spi_write_data((char)va_arg(ap, int));
va_end(ap);
}
void spi_write_CommandData(const uint8_t* pCommandData, uint8_t datalen){
int i;
spi_write_command(*pCommandData++);
gpio_put(LCD_CD_PIN,GPIO_PIN_SET);
for(i=1;i<datalen;i++){
spi_write_data(*pCommandData++);
}
}
void MIPS16 ResetController(void){
PinSetBit(Option.LCD_Reset, LATSET);
uSec(10000);
PinSetBit(Option.LCD_Reset, LATCLR);
uSec(10000);
PinSetBit(Option.LCD_Reset, LATSET);
uSec(200000);
}
void DefineRegionSPI(int xstart, int ystart, int xend, int yend, int rw) {
unsigned char coord[4];
if(Option.DISPLAY_TYPE == ILI9481 || Option.DISPLAY_TYPE == ILI9488W){
SetCS();
gpio_put(LCD_CD_PIN,GPIO_PIN_RESET);
SPIsend2(ILI9341_COLADDRSET);
gpio_put(LCD_CD_PIN,GPIO_PIN_SET);
SPIsend2(xstart >> 8);
SPIsend2(xstart);
SPIsend2(xend >> 8);
SPIsend2(xend);
gpio_put(LCD_CD_PIN,GPIO_PIN_RESET);
SPIsend2(ILI9341_PAGEADDRSET);
gpio_put(LCD_CD_PIN,GPIO_PIN_SET);
SPIsend2(ystart >> 8);
SPIsend2(ystart);
SPIsend2(yend >> 8);
SPIsend2(yend);
gpio_put(LCD_CD_PIN,GPIO_PIN_RESET);
if(rw) {
SPIsend2(ILI9341_MEMORYWRITE);
} else {
SPIsend2(ILI9341_RAMRD);
}
gpio_put(LCD_CD_PIN,GPIO_PIN_SET);
} else if(Option.DISPLAY_TYPE==SSD1331){
if(Option.DISPLAY_ORIENTATION&1){
spi_write_command(0x15); // Column addr set
spi_write_command(xstart);
spi_write_command(xend);
spi_write_command(0x75); // Row addr set
spi_write_command(ystart);
spi_write_command(yend);
} else {
spi_write_command(0x75); // Row addr set
spi_write_command(xstart);
spi_write_command(xend);
spi_write_command(0x15); // Column addr set
spi_write_command(ystart);
spi_write_command(yend);
}
SetCS();
gpio_put(LCD_CD_PIN,GPIO_PIN_SET);
} else {
if(Option.DISPLAY_TYPE == 0) error("Display not configured");
if(Option.DISPLAY_TYPE==ST7789){
if(Option.DISPLAY_ORIENTATION==2){
ystart+=80;
yend+=80;
}
if(Option.DISPLAY_ORIENTATION==1){
xstart+=80;
xend+=80;
}
}
if(Option.DISPLAY_TYPE==ST7789A){
if(Option.DISPLAY_ORIENTATION ==1 ){
xstart+=40;
xend+=40;
ystart+=52;
yend+=52;
}
else if(Option.DISPLAY_ORIENTATION ==3 ){
xstart+=40;
xend+=40;
ystart+=53;
yend+=53;
}
else if(Option.DISPLAY_ORIENTATION==0){
ystart+=40;
yend+=40;
xstart+=52;
xend+=52;
}
else if(Option.DISPLAY_ORIENTATION==2){
ystart+=40;
yend+=40;
xstart+=53;
xend+=53;
}
}
if(Option.DISPLAY_TYPE==ST7735S){
if(Option.DISPLAY_ORIENTATION & 1){
ystart+=26;
yend+=26;
xstart++;
xend++;
} else {
xstart+=26;
xend+=26;
ystart++;
yend++;
}
}
if(Option.DISPLAY_TYPE==ST7735S_W){
switch(Option.DISPLAY_ORIENTATION) {
case LANDSCAPE:
ystart+=2;
yend+=2;
xstart+=3;
xend+=3;
break;
case PORTRAIT:
xstart+=2;
xend+=2;
ystart+=3;
yend+=3;
break;
case RLANDSCAPE:
ystart+=2;
yend+=2;
xstart+=1;
xend+=1;
break;
case RPORTRAIT:
xstart+=2;
xend+=2;
ystart+=1;
yend+=1;
break;
}
}
SetCS();
gpio_put(LCD_CD_PIN,GPIO_PIN_RESET);//gpio_put(LCD_CD_PIN,GPIO_PIN_RESET);
SPIsend(ILI9341_COLADDRSET);
gpio_put(LCD_CD_PIN,GPIO_PIN_SET);
coord[0]=xstart >> 8;
coord[1]=xstart;
coord[2]=xend >> 8;
coord[3]=xend;
xmit_byte_multi(coord,4);// HAL_SPI_Transmit(&hspi3,coord,4,500);
gpio_put(LCD_CD_PIN,GPIO_PIN_RESET);
SPIsend(ILI9341_PAGEADDRSET);
gpio_put(LCD_CD_PIN,GPIO_PIN_SET);
coord[0]=ystart >> 8;
coord[1]=ystart;
coord[2]=yend >> 8;
coord[3]=yend;
xmit_byte_multi(coord,4);// HAL_SPI_Transmit(&hspi3,coord,4,500);
gpio_put(LCD_CD_PIN,GPIO_PIN_RESET);
if(rw) {
SPIsend(ILI9341_MEMORYWRITE);
} else {
SPIsend(ILI9341_RAMRD);
}
gpio_put(LCD_CD_PIN,GPIO_PIN_SET);
}
}
/****************************************************************************************************
****************************************************************************************************
Basic drawing primitives
all drawing on the LCD is done using either one of these two functions
****************************************************************************************************
****************************************************************************************************/
void spisendfast(unsigned char *n, int i){
xmit_byte_multi(n,i);// HAL_SPI_Transmit(&hspi3,coord,4,500);
}
// Draw a filled rectangle
// this is the basic drawing promitive used by most drawing routines
// x1, y1, x2, y2 - the coordinates
// c - the colour
void DrawRectangleSPI(int x1, int y1, int x2, int y2, int c){
// convert the colours to 565 format
unsigned char col[3];
if(x1==x2 && y1==y2){
if(x1 < 0) return;
if(x1 >= HRes) return;
if(y1 < 0) return;
if(y1 >= VRes) return;
DefineRegionSPI(x1, y1, x2, y2, 1);
if(Option.DISPLAY_TYPE==ILI9488 || Option.DISPLAY_TYPE == ILI9488P || Option.DISPLAY_TYPE==ILI9481IPS ){
col[0]=(c>>16) & 0xFC;
col[1]=(c>>8) & 0xFC;
col[2]=(c & 0xFC);
} else {
col[0]= ((c >> 16) & 0b11111000) | ((c >> 13) & 0b00000111);
col[1] = ((c >> 5) & 0b11100000) | ((c >> 3) & 0b00011111);
}
if(Option.DISPLAY_TYPE == GC9A01){
col[0]=~col[0];
col[1]=~col[1];
}
SPIqueue(col);
} else {
int i,t,y;
unsigned char *p;
// make sure the coordinates are kept within the display area
if(x2 <= x1) { t = x1; x1 = x2; x2 = t; }
if(y2 <= y1) { t = y1; y1 = y2; y2 = t; }
if(x1 < 0) x1 = 0;
if(x1 >= HRes) x1 = HRes - 1;
if(x2 < 0) x2 = 0;
if(x2 >= HRes) x2 = HRes - 1;
if(y1 < 0) y1 = 0;
if(y1 >= VRes) y1 = VRes - 1;
if(y2 < 0) y2 = 0;
if(y2 >= VRes) y2 = VRes - 1;
DefineRegionSPI(x1, y1, x2, y2, 1);
if(Option.DISPLAY_TYPE==ILI9488 || Option.DISPLAY_TYPE == ILI9488P || Option.DISPLAY_TYPE==ILI9481IPS ){
i = x2 - x1 + 1;
i*=3;
p=LCDBuffer;
col[0]=(c>>16) & 0xFC;
col[1]=(c>>8) & 0xFC;
col[2]=(c & 0xFC);
for(t=0;t<i;t+=3){p[t]=col[0];p[t+1]=col[1];p[t+2]=col[2];}
for(y=y1;y<=y2;y++){
if(PinDef[Option.SYSTEM_CLK].mode & SPI0SCK)spi_write_fast(spi0,p,i);
else spi_write_fast(spi1,p,i);
}
} else {
i = x2 - x1 + 1;
i*=2;
p=LCDBuffer;
col[0]= ((c >> 16) & 0b11111000) | ((c >> 13) & 0b00000111);
col[1] = ((c >> 5) & 0b11100000) | ((c >> 3) & 0b00011111);
if(Option.DISPLAY_TYPE == GC9A01){
col[0]=~col[0];
col[1]=~col[1];
}
for(t=0;t<i;t+=2){p[t]=col[0];p[t+1]=col[1];}
if(PinDef[Option.SYSTEM_CLK].mode & SPI0SCK){
for(t=y1;t<=y2;t++){
spi_write_fast(spi0,p,i);
}
} else {
for(t=y1;t<=y2;t++){
spi_write_fast(spi1,p,i);
}
}
}
}
if(PinDef[Option.SYSTEM_CLK].mode & SPI0SCK)spi_finish(spi0);
else spi_finish(spi1);
ClearCS(Option.LCD_CS); //set CS high
}
void PhysicalDrawRectSPI(int x1, int y1, int x2, int y2, int c){
int i,t,y;
unsigned char *p;
unsigned char col[3];
DefineRegionSPI(x1, y1, x2, y2, 1);
if(Option.DISPLAY_TYPE==ILI9488 || Option.DISPLAY_TYPE == ILI9488P || Option.DISPLAY_TYPE==ILI9481IPS ){
i = x2 - x1 + 1;
i*=3;
p=LCDBuffer;
col[0]=(c>>16) & 0xFC;
col[1]=(c>>8) & 0xFC;
col[2]=(c & 0xFC);
for(t=0;t<i;t+=3){p[t]=col[0];p[t+1]=col[1];p[t+2]=col[2];}
for(y=y1;y<=y2;y++){
if(PinDef[Option.SYSTEM_CLK].mode & SPI0SCK)spi_write_fast(spi0,p,i);
else spi_write_fast(spi1,p,i);
}
} else {
i = x2 - x1 + 1;
i*=2;
p=LCDBuffer;
col[0]= ((c >> 16) & 0b11111000) | ((c >> 13) & 0b00000111);
col[1] = ((c >> 5) & 0b11100000) | ((c >> 3) & 0b00011111);
if(Option.DISPLAY_TYPE == GC9A01){
col[0]=~col[0];
col[1]=~col[1];
}
for(t=0;t<i;t+=2){p[t]=col[0];p[t+1]=col[1];}
if(PinDef[Option.SYSTEM_CLK].mode & SPI0SCK){
for(t=y1;t<=y2;t++){
spi_write_fast(spi0,p,i);
}
} else {
for(t=y1;t<=y2;t++){
spi_write_fast(spi1,p,i);
}
}
}
if(PinDef[Option.SYSTEM_CLK].mode & SPI0SCK)spi_finish(spi0);
else spi_finish(spi1);
ClearCS(Option.LCD_CS); //set CS high
}
void DrawRectangleSPISCR(int x1, int y1, int x2, int y2, int c){
// convert the colours to 565 format
int t;
// make sure the coordinates are kept within the display area
if(x2 <= x1) { t = x1; x1 = x2; x2 = t; }
if(y2 <= y1) { t = y1; y1 = y2; y2 = t; }
if(x1 < 0) x1 = 0;
if(x1 >= HRes) x1 = HRes - 1;
if(x2 < 0) x2 = 0;
if(x2 >= HRes) x2 = HRes - 1;
if(y1 < 0) y1 = 0;
if(y1 >= VRes) y1 = VRes - 1;
if(y2 < 0) y2 = 0;
if(y2 >= VRes) y2 = VRes - 1;
t = y2 - y1; // get the distance between the top and bottom
// set y1 to the physical location in the frame buffer (only really has an effect when scrolling is in action)
y1 = (y1 + ScrollStart) % VRes;
y2 = y1 + t; // and set y2 to the same
if(y2 >= VRes) { // if the box splits over the frame buffer boundary
PhysicalDrawRectSPI(x1, y1, x2, VRes - 1, c); // draw the top part
PhysicalDrawRectSPI(x1, 0, x2, y2 - VRes , c); // and the bottom part
} else
PhysicalDrawRectSPI(x1, y1, x2, y2, c); // the whole box is within the frame buffer - much easier
}
//Print the bitmap of a char on the video output
// x, y - the top left of the char
// width, height - size of the char's bitmap
// scale - how much to scale the bitmap
// fc, bc - foreground and background colour
// bitmap - pointer to the bitmap
void DrawBitmapSPI(int x1, int y1, int width, int height, int scale, int fc, int bc, unsigned char *bitmap){
int i, j, k, m, n;
char f[3],b[3];
int vertCoord, horizCoord, XStart, XEnd, YEnd;
char *p=0;
union colourmap {
char rgbbytes[4];
unsigned int rgb;
} c;
if(bc == -1 && (void *)ReadBuffer == (void *)DisplayNotSet) bc = 0x0;
if(x1>=HRes || y1>=VRes || x1+width*scale<0 || y1+height*scale<0)return;
// adjust when part of the bitmap is outside the displayable coordinates
vertCoord = y1; if(y1 < 0) y1 = 0; // the y coord is above the top of the screen
XStart = x1; if(XStart < 0) XStart = 0; // the x coord is to the left of the left marginn
XEnd = x1 + (width * scale) - 1; if(XEnd >= HRes) XEnd = HRes - 1; // the width of the bitmap will extend beyond the right margin
YEnd = y1 + (height * scale) - 1; if(YEnd >= VRes) YEnd = VRes - 1;// the height of the bitmap will extend beyond the bottom margin
if(bc == -1) { //special case of overlay text
i = 0;
j = width * height * scale * scale * 3;
p = GetMemory(j); //allocate some temporary memory
ReadBuffer(XStart, y1, XEnd, YEnd, (unsigned char *)p);
}
// convert the colours to 565 format
if(Option.DISPLAY_TYPE==ILI9488 || Option.DISPLAY_TYPE == ILI9488P || Option.DISPLAY_TYPE==ILI9481IPS ){
f[0]=(fc>>16);
f[1]=(fc>>8) & 0xFF;
f[2]=(fc & 0xFF);
b[0]=(bc>>16);
b[1]=(bc>>8) & 0xFF;
b[2]=(bc & 0xFF);
} else {
f[0]= ((fc >> 16) & 0b11111000) | ((fc >> 13) & 0b00000111);
f[1] = ((fc >> 5) & 0b11100000) | ((fc >> 3) & 0b00011111);
b[0] = ((bc >> 16) & 0b11111000) | ((bc >> 13) & 0b00000111);
b[1] = ((bc >> 5) & 0b11100000) | ((bc >> 3) & 0b00011111);
}
if(Option.DISPLAY_TYPE == GC9A01){
f[0]=~f[0];
b[0]=~b[0];
f[1]=~f[1];
b[1]=~b[1];
}
DefineRegionSPI(XStart, y1, XEnd, YEnd, 1);
n = 0;
for(i = 0; i < height; i++) { // step thru the font scan line by line
for(j = 0; j < scale; j++) { // repeat lines to scale the font
if(vertCoord++ < 0) continue; // we are above the top of the screen
if(vertCoord > VRes) { // we have extended beyond the bottom of the screen
ClearCS(Option.LCD_CS); //set CS high
if(p != NULL) FreeMemory((unsigned char *)p);
return;
}
horizCoord = x1;
for(k = 0; k < width; k++) { // step through each bit in a scan line
for(m = 0; m < scale; m++) { // repeat pixels to scale in the x axis
if(horizCoord++ < 0) continue; // we have not reached the left margin
if(horizCoord > HRes) continue; // we are beyond the right margin
if((bitmap[((i * width) + k)/8] >> (((height * width) - ((i * width) + k) - 1) %8)) & 1) {
SPIqueue((uint8_t *)&f);
} else {
if(bc == -1){
c.rgbbytes[0] = p[n];
c.rgbbytes[1] = p[n+1];
c.rgbbytes[2] = p[n+2];
if(Option.DISPLAY_TYPE==ILI9488 || Option.DISPLAY_TYPE == ILI9488P || Option.DISPLAY_TYPE==ILI9481IPS ){
b[0]=c.rgbbytes[2];
b[1]=c.rgbbytes[1];
b[2]=c.rgbbytes[0];
} else {
b[0] = ((c.rgb >> 16) & 0b11111000) | ((c.rgb >> 13) & 0b00000111);
b[1] = ((c.rgb >> 5) & 0b11100000) | ((c.rgb >> 3) & 0b00011111);
}
}
SPIqueue((uint8_t *)&b);
}
n += 3;
}
}
}
}
ClearCS(Option.LCD_CS); //set CS high
// revert to non enhanced SPI mode
if(p != NULL) FreeMemory((unsigned char *)p);
}
void DrawBitmapSPISCR(int x1, int y1, int width, int height, int scale, int fc, int bc, unsigned char *bitmap){
int i, j, k, m, y, yt, n;
char f[3],b[3];
int vertCoord, horizCoord, XStart, XEnd, YEnd;
char *p=0;
union colourmap {
char rgbbytes[4];
unsigned int rgb;
} c;
// convert the colours to 565 format
if(Option.DISPLAY_TYPE==ILI9488 || Option.DISPLAY_TYPE == ILI9488P || Option.DISPLAY_TYPE==ILI9481IPS ){
f[0]=(fc>>16);
f[1]=(fc>>8) & 0xFF;
f[2]=(fc & 0xFF);
b[0]=(bc>>16);
b[1]=(bc>>8) & 0xFF;
b[2]=(bc & 0xFF);
} else {
f[0]= ((fc >> 16) & 0b11111000) | ((fc >> 13) & 0b00000111);
f[1] = ((fc >> 5) & 0b11100000) | ((fc >> 3) & 0b00011111);
b[0] = ((bc >> 16) & 0b11111000) | ((bc >> 13) & 0b00000111);
b[1] = ((bc >> 5) & 0b11100000) | ((bc >> 3) & 0b00011111);
}
if(Option.DISPLAY_TYPE == GC9A01){
f[0]=~f[0];
b[0]=~b[0];
f[1]=~f[1];
b[1]=~b[1];
}
if(bc == -1 && (void *)ReadBuffer == (void *)DisplayNotSet) bc = 0x0;
if(x1>=HRes || y1>=VRes || x1+width*scale<0 || y1+height*scale<0)return;
// adjust when part of the bitmap is outside the displayable coordinates
vertCoord = y1; if(y1 < 0) y1 = 0; // the y coord is above the top of the screen
XStart = x1; if(XStart < 0) XStart = 0; // the x coord is to the left of the left marginn
XEnd = x1 + (width * scale) - 1; if(XEnd >= HRes) XEnd = HRes - 1; // the width of the bitmap will extend beyond the right margin
if(bc == -1) { //special case of overlay text
j = width * height * scale * scale * 3;
p = GetMemory(j); //allocate some temporary memory
ReadBuffer(XStart, y1, XEnd, (y1 + (height * scale) - 1) , (unsigned char *)p);
}
yt = y = (y1 + ScrollStart) % VRes;
YEnd=(y + (height * scale) - 1) % VRes;
if(YEnd<y)YEnd=VRes-1;
DefineRegionSPI(XStart, y, XEnd, YEnd, 1);
n = 0;
for(i = 0; i < height; i++) { // step thru the font scan line by line
for(j = 0; j < scale; j++) { // repeat lines to scale the font
if(vertCoord++ < 0) continue; // we are above the top of the screen
if(vertCoord > VRes) { // we have extended beyond the bottom of the screen
ClearCS(Option.LCD_CS); //set CS high
if(p != NULL) FreeMemory((unsigned char *)p);
return;
}
if(y++ == VRes) {
DefineRegionSPI(XStart, 0, XEnd, ((yt + (height * scale) - 1) % VRes) , 1);
}
horizCoord = x1;
for(k = 0; k < width; k++) { // step through each bit in a scan line
for(m = 0; m < scale; m++) { // repeat pixels to scale in the x axis
if(horizCoord++ < 0) continue; // we have not reached the left margin
if(horizCoord > HRes) continue; // we are beyond the right margin
if((bitmap[((i * width) + k)/8] >> (((height * width) - ((i * width) + k) - 1) %8)) & 1) {
SPIqueue((uint8_t *)&f);
} else {
if(bc == -1){
c.rgbbytes[0] = p[n];
c.rgbbytes[1] = p[n+1];
c.rgbbytes[2] = p[n+2];
if(Option.DISPLAY_TYPE==ILI9488 || Option.DISPLAY_TYPE == ILI9488P || Option.DISPLAY_TYPE==ILI9481IPS ){
b[0]=c.rgbbytes[2];
b[1]=c.rgbbytes[1];
b[2]=c.rgbbytes[0];
} else {
b[0] = ((c.rgb >> 16) & 0b11111000) | ((c.rgb >> 13) & 0b00000111);
b[1] = ((c.rgb >> 5) & 0b11100000) | ((c.rgb >> 3) & 0b00011111);
}
}
SPIqueue((uint8_t *)&b);
}
n += 3;
}
}
}
}
ClearCS(Option.LCD_CS); //set CS high
// revert to non enhanced SPI mode
if(p != NULL) FreeMemory((unsigned char *)p);
}
const unsigned char map32[256];
void ReadBufferSPI(int x1, int y1, int x2, int y2, unsigned char* p) {
int r, N, t;
unsigned char h,l;
// SInt(x1);SIntComma(y1);SIntComma(x2);SIntComma(y2);SRet();
// make sure the coordinates are kept within the display area
if(x2 <= x1) { t = x1; x1 = x2; x2 = t; }
if(y2 <= y1) { t = y1; y1 = y2; y2 = t; }
if(x1 < 0) x1 = 0;
if(x1 >= HRes) x1 = HRes - 1;
if(x2 < 0) x2 = 0;
if(x2 >= HRes) x2 = HRes - 1;
if(y1 < 0) y1 = 0;
if(y1 >= VRes) y1 = VRes - 1;
if(y2 < 0) y2 = 0;
if(y2 >= VRes) y2 = VRes - 1;
N=(x2- x1+1) * (y2- y1+1) * ((Option.DISPLAY_TYPE==ST7796S || Option.DISPLAY_TYPE == ST7796SP)? 2 : 3);
if(Option.DISPLAY_TYPE==ILI9341 || Option.DISPLAY_TYPE==ST7789B )spi_write_cd(ILI9341_PIXELFORMAT,1,0x66); //change to RGB666 for read
DefineRegionSPI(x1, y1, x2, y2, 0);
SPISpeedSet( (Option.DISPLAY_TYPE==ILI9488 || Option.DISPLAY_TYPE == ILI9488P || Option.DISPLAY_TYPE==ST7789B || Option.DISPLAY_TYPE==ILI9481IPS) ? ST7789RSpeed : SPIReadSpeed); //need to slow SPI for read on this display
rcvr_byte_multi((uint8_t *)p, 1);
r=0;
rcvr_byte_multi((uint8_t *)p,N);
gpio_put(LCD_CD_PIN,GPIO_PIN_RESET);
ClearCS(Option.LCD_CS); //set CS high
SPISpeedSet(Option.DISPLAY_TYPE);
// revert to non enhanced SPI mode
if(Option.DISPLAY_TYPE==ILI9341 || Option.DISPLAY_TYPE==ST7789B )spi_write_cd(ILI9341_PIXELFORMAT,1,0x55); //change back to rdb565
r=0;
if(Option.DISPLAY_TYPE==ST7796S || Option.DISPLAY_TYPE == ST7796SP){
int n=(x2- x1+1) * (y2- y1+1)*3;
while(N){
h=p[N-2];
l=p[N-1];
N-=2;
p[n-1]=h & 0xF8;
p[n-2]=((h & 0x7)<<5) | ((l & 0xE0)>>3);
p[n-3]=(l & 0x1F)<<3;
n-=3;
}
} else {
while(N) {
h=(uint8_t)p[r+2];
l=(uint8_t)p[r];
p[r]=(h & 0xFC);
p[r+1] &= 0xFC;
p[r+2]=(l & 0xFC);
r+=3;
N-=3;
}
}
}
void ReadBufferSPISCR(int x1, int y1, int x2, int y2, unsigned char* p) {
int r, N, t;
unsigned char h,l;
// PInt(x1);PIntComma(y1);PIntComma(x2);PIntComma(y2);PRet();
// make sure the coordinates are kept within the display area
if(x2 <= x1) { t = x1; x1 = x2; x2 = t; }
if(y2 <= y1) { t = y1; y1 = y2; y2 = t; }
if(x1 < 0) x1 = 0;
if(x1 >= HRes) x1 = HRes - 1;
if(x2 < 0) x2 = 0;
if(x2 >= HRes) x2 = HRes - 1;
if(y1 < 0) y1 = 0;
if(y1 >= VRes) y1 = VRes - 1;
if(y2 < 0) y2 = 0;
if(y2 >= VRes) y2 = VRes - 1;
if(Option.DISPLAY_TYPE==ILI9341 || Option.DISPLAY_TYPE==ST7789B )spi_write_cd(ILI9341_PIXELFORMAT,1,0x66); //change to RDB666 for read
t = y2 - y1; // get the distance between the top and bottom
y1 = (y1 + ScrollStart) % VRes;
y2 = y1 + t;
if(y2 >= VRes) {
N=(x2- x1+1) * (y2- VRes) * ((Option.DISPLAY_TYPE==ST7796S || Option.DISPLAY_TYPE == ST7796SP) ? 2 : 3);
DefineRegionSPI(x1, y1, x2, VRes - 1,0);
SPISpeedSet( (Option.DISPLAY_TYPE==ILI9488 || Option.DISPLAY_TYPE == ILI9488P || Option.DISPLAY_TYPE==ST7789B || Option.DISPLAY_TYPE==ILI9481IPS) ? ST7789RSpeed : SPIReadSpeed); //need to slow SPI for read on this display
rcvr_byte_multi((uint8_t *)p, 1);
r=0;
rcvr_byte_multi((uint8_t *)p,N);
gpio_put(LCD_CD_PIN,GPIO_PIN_RESET);
ClearCS(Option.LCD_CS); //set CS high
SPISpeedSet(Option.DISPLAY_TYPE);
p+=N;
N=(x2- x1+1) * (y2 - VRes) * ((Option.DISPLAY_TYPE==ST7796S || Option.DISPLAY_TYPE == ST7796SP) ? 2 : 3);
DefineRegionSPI(x1, 0, x2, y2 - VRes,0);
SPISpeedSet( (Option.DISPLAY_TYPE==ILI9488 || Option.DISPLAY_TYPE == ILI9488P || Option.DISPLAY_TYPE==ST7789B || Option.DISPLAY_TYPE==ILI9481IPS) ? ST7789RSpeed : SPIReadSpeed); //need to slow SPI for read on this display
rcvr_byte_multi((uint8_t *)p, 1);
r=0;
rcvr_byte_multi((uint8_t *)p,N);
gpio_put(LCD_CD_PIN,GPIO_PIN_RESET);
ClearCS(Option.LCD_CS); //set CS high
SPISpeedSet(Option.DISPLAY_TYPE);
N=(x2- x1+1) * (y2- y1+1) * 3;
} else {
N=(x2- x1+1) * (y2- y1+1) * ((Option.DISPLAY_TYPE==ST7796S || Option.DISPLAY_TYPE == ST7796SP) ? 2 : 3);
DefineRegionSPI(x1, y1, x2, y2, 0);
SPISpeedSet( (Option.DISPLAY_TYPE==ILI9488 || Option.DISPLAY_TYPE == ILI9488P || Option.DISPLAY_TYPE==ST7789B || Option.DISPLAY_TYPE==ILI9481IPS) ? ST7789RSpeed : SPIReadSpeed); //need to slow SPI for read on this display
rcvr_byte_multi((uint8_t *)p, 1);
r=0;
rcvr_byte_multi((uint8_t *)p,N);
gpio_put(LCD_CD_PIN,GPIO_PIN_RESET);
ClearCS(Option.LCD_CS); //set CS high
SPISpeedSet(Option.DISPLAY_TYPE);
// revert to non enhanced SPI mode
}
if(Option.DISPLAY_TYPE==ILI9341 || Option.DISPLAY_TYPE==ST7789B )spi_write_cd(ILI9341_PIXELFORMAT,1,0x55); //change back to rdb565
r=0;
if(Option.DISPLAY_TYPE==ST7796S || Option.DISPLAY_TYPE == ST7796SP){
N=(x2- x1+1) * (y2- y1+1)*2;
int n=(x2- x1+1) * (y2- y1+1)*3;
while(N){
h=p[N-2];
l=p[N-1];
N-=2;
p[n-1]=h & 0xF8;
p[n-2]=((h & 0x7)<<5) | ((l & 0xE0)>>3);
p[n-3]=(l & 0x1F)<<3;
n-=3;
}
} else {
N=(x2- x1+1) * (y2- y1+1)*3;
while(N) {
h=(uint8_t)p[r+2];
l=(uint8_t)p[r];
p[r]=(h & 0xFC);
p[r+1] &= 0xFC;
p[r+2]=(l & 0xFC);
r+=3;
N-=3;
}
}
}
void DrawBufferSPI(int x1, int y1, int x2, int y2, unsigned char* p) {
union colourmap
{
char rgbbytes[4];
unsigned int rgb;
} c;
unsigned char q[3];
int i,t;
if(x2 <= x1) { t = x1; x1 = x2; x2 = t; }
if(y2 <= y1) { t = y1; y1 = y2; y2 = t; }
if(x1 < 0) x1 = 0;
if(x1 >= HRes) x1 = HRes - 1;
if(x2 < 0) x2 = 0;
if(x2 >= HRes) x2 = HRes - 1;
if(y1 < 0) y1 = 0;
if(y1 >= VRes) y1 = VRes - 1;
if(y2 < 0) y2 = 0;
if(y2 >= VRes) y2 = VRes - 1;
i=(x2-x1+1) * (y2-y1+1);
DefineRegionSPI(x1, y1, x2, y2, 1);
while(i--){
c.rgbbytes[0]=*p++; //this order swaps the bytes to match the .BMP file
c.rgbbytes[1]=*p++;
c.rgbbytes[2]=*p++;
// convert the colours to 565 format
// convert the colours to 565 format
if(Option.DISPLAY_TYPE==ILI9488 || Option.DISPLAY_TYPE == ILI9488P || Option.DISPLAY_TYPE==ILI9481IPS ){
q[0]=c.rgbbytes[2];
q[1]=c.rgbbytes[1];
q[2]=c.rgbbytes[0];
} else {
q[0]= ((c.rgb >> 16) & 0b11111000) | ((c.rgb >> 13) & 0b00000111);
q[1] = ((c.rgb >> 5) & 0b11100000) | ((c.rgb >> 3) & 0b00011111);
}
if(Option.DISPLAY_TYPE == GC9A01){
q[0]=~q[0];
q[1]=~q[1];
}
SPIqueue(q);
}
ClearCS(Option.LCD_CS); //set CS high
}
void DrawBufferSPISCR(int x1, int y1, int x2, int y2, unsigned char* p) {
union colourmap
{
char rgbbytes[4];
unsigned int rgb;
} c;
unsigned char q[3];
int i,t;
if(x2 <= x1) { t = x1; x1 = x2; x2 = t; }
if(y2 <= y1) { t = y1; y1 = y2; y2 = t; }
if(x1 < 0) x1 = 0;
if(x1 >= HRes) x1 = HRes - 1;
if(x2 < 0) x2 = 0;
if(x2 >= HRes) x2 = HRes - 1;
if(y1 < 0) y1 = 0;
if(y1 >= VRes) y1 = VRes - 1;
if(y2 < 0) y2 = 0;
if(y2 >= VRes) y2 = VRes - 1;
t = y2 - y1; // get the distance between the top and bottom
y1 = (y1 + ScrollStart) % VRes;
y2 = y1 + t;
i=(x2-x1+1) * (y2-y1+1);
if(y2 >= VRes) {
DefineRegionSPI(x1, y1, x2, VRes - 1, 1);
for(i = (x2 - x1 + 1) * ((VRes - 1) - y1 + 1); i > 0; i--){
c.rgbbytes[0]=*p++; //this order swaps the bytes to match the .BMP file
c.rgbbytes[1]=*p++;
c.rgbbytes[2]=*p++;
// convert the colours to 565 format
// convert the colours to 565 format
if(Option.DISPLAY_TYPE==ILI9488 || Option.DISPLAY_TYPE == ILI9488P || Option.DISPLAY_TYPE==ILI9481IPS ){
q[0]=c.rgbbytes[2];
q[1]=c.rgbbytes[1];
q[2]=c.rgbbytes[0];
} else {
q[0]= ((c.rgb >> 16) & 0b11111000) | ((c.rgb >> 13) & 0b00000111);
q[1] = ((c.rgb >> 5) & 0b11100000) | ((c.rgb >> 3) & 0b00011111);
}
if(Option.DISPLAY_TYPE == GC9A01){
q[0]=~q[0];
q[1]=~q[1];
}
SPIqueue(q);
}
DefineRegionSPI(x1, 0, x2, y2 - VRes, 1 );
for(i = (x2 - x1 + 1) * (y2 - VRes + 1); i > 0; i--) {
c.rgbbytes[0]=*p++; //this order swaps the bytes to match the .BMP file
c.rgbbytes[1]=*p++;
c.rgbbytes[2]=*p++;
// convert the colours to 565 format
// convert the colours to 565 format
if(Option.DISPLAY_TYPE==ILI9488 || Option.DISPLAY_TYPE == ILI9488P || Option.DISPLAY_TYPE==ILI9481IPS ){
q[0]=c.rgbbytes[2];
q[1]=c.rgbbytes[1];
q[2]=c.rgbbytes[0];
} else {
q[0]= ((c.rgb >> 16) & 0b11111000) | ((c.rgb >> 13) & 0b00000111);
q[1] = ((c.rgb >> 5) & 0b11100000) | ((c.rgb >> 3) & 0b00011111);
}
if(Option.DISPLAY_TYPE == GC9A01){
q[0]=~q[0];
q[1]=~q[1];
}
SPIqueue(q);
}
} else {
DefineRegionSPI(x1, y1, x2, y2, 1);
while(i--){
c.rgbbytes[0]=*p++; //this order swaps the bytes to match the .BMP file
c.rgbbytes[1]=*p++;
c.rgbbytes[2]=*p++;
// convert the colours to 565 format
// convert the colours to 565 format
if(Option.DISPLAY_TYPE==ILI9488 || Option.DISPLAY_TYPE == ILI9488P || Option.DISPLAY_TYPE==ILI9481IPS ){
q[0]=c.rgbbytes[2];
q[1]=c.rgbbytes[1];
q[2]=c.rgbbytes[0];
} else {
q[0]= ((c.rgb >> 16) & 0b11111000) | ((c.rgb >> 13) & 0b00000111);
q[1] = ((c.rgb >> 5) & 0b11100000) | ((c.rgb >> 3) & 0b00011111);
}
if(Option.DISPLAY_TYPE == GC9A01){
q[0]=~q[0];
q[1]=~q[1];
}
SPIqueue(q);
}
}
ClearCS(Option.LCD_CS); //set CS high
}
void ScrollLCDSPISCR(int lines){
if(lines==0)return;
int t;
t = ScrollStart;
if(lines >= 0) {
DrawRectangle(0, 0, HRes - 1, lines - 1, gui_bcolour); // erase the line to be scrolled off
while(lines--) {
if(++t >= VRes) t = 0;
}
} else {
while(lines++) {
if(--t < 0) t = VRes - 1;
}
// DrawRectangle(0, 0, HRes - 1, linesave - 1, gui_bcolour); // erase the line introduced at the top
}
spi_write_command(CMD_SET_SCROLL_START);
spi_write_data(t >> 8);
spi_write_data(t);
ScrollStart = t;
}
void ScrollLCDSPI(int lines){
if(lines==0)return;
unsigned char *buff=GetMemory(3*HRes);
if(lines >= 0) {
for(int i=0;i<VRes-lines;i++) {
ReadBLITBuffer(0, i+lines, HRes -1, i+lines, buff);
DrawBLITBuffer(0, i, HRes - 1, i, buff);
}
DrawRectangle(0, VRes-lines, HRes - 1, VRes - 1, gui_bcolour); // erase the lines to be scrolled off
} else {
lines=-lines;
for(int i=VRes-1;i>=lines;i--) {
ReadBLITBuffer(0, i-lines, HRes -1, i-lines, buff);
DrawBLITBuffer(0, i, HRes - 1, i, buff);
}
DrawRectangle(0, 0, HRes - 1, lines - 1, gui_bcolour); // erase the lines introduced at the top
}
FreeMemory(buff);
}
void DrawBufferMEM(int x1, int y1, int x2, int y2, unsigned char* p) {
int x,y;
union colourmap
{
char rgbbytes[4];
unsigned int rgb;
} c;
for(y=y1;y<=y2;y++){
for(x=x1;x<=x2;x++){
c.rgbbytes[0]=*p++; //this order swaps the bytes to match the .BMP file
if(c.rgbbytes[0]<0x40)c.rgbbytes[0]=0;
c.rgbbytes[1]=*p++;
if(c.rgbbytes[1]<0x40)c.rgbbytes[1]=0;
c.rgbbytes[2]=*p++;
if(c.rgbbytes[2]<0x40)c.rgbbytes[2]=0;
c.rgbbytes[3]=0;
DrawPixel(x,y,c.rgb);
}
}
}
void ReadBufferMEM(int x1, int y1, int x2, int y2, unsigned char* buff) {
unsigned char* p=(void *)((unsigned int)LCDBuffer);
int x,y,loc,t;
unsigned char mask;
if(x1 < 0) x1 = 0;
if(x1 >= HRes) x1 = HRes - 1;
if(x2 < 0) x2 = 0;
if(x2 >= HRes) x2 = HRes - 1;
if(y1 < 0) y1 = 0;
if(y1 >= VRes) y1 = VRes - 1;
if(y2 < 0) y2 = 0;
if(y2 >= VRes) y2 = VRes - 1;
if(x2 <= x1) { t = x1; x1 = x2; x2 = t; }
if(y2 <= y1) { t = y1; y1 = y2; y2 = t; }
if(Option.DISPLAY_ORIENTATION==PORTRAIT){
t=x1;
x1=VRes-y2-1;
y2=t;
t=x2;
x2=VRes-y1-1;
y1=t;
}
if(Option.DISPLAY_ORIENTATION==RLANDSCAPE){
x1=HRes-x1-1;
x2=HRes-x2-1;
y1=VRes-y1-1;
y2=VRes-y2-1;
}
if(Option.DISPLAY_ORIENTATION==RPORTRAIT){
t=y1;
y1=HRes-x1-1;
x1=t;
t=y2;
y2=HRes-x2-1;
x2=t;
}
if(x2 <= x1) { t = x1; x1 = x2; x2 = t; }
if(y2 <= y1) { t = y1; y1 = y2; y2 = t; }
if(y1<low_y)low_y=y1;
if(y2>high_y)high_y=y2;
if(x1<low_x)low_x=x1;
if(x2>high_x)high_x=x2;
for(x=x1;x<=x2;x++){
for(y=y1;y<=y2;y++){
if(!PackHorizontal){
loc=x+(y/8)*DisplayHRes; //get the byte address for this bit
mask=1<<(y % 8); //get the bit position for this bit
} else {
loc=x/8+y*DisplayHRes/8; //get the byte address for this bit
mask=1<<(7-(x % 8)); //get the bit position for this bit
}
if(p[loc]&mask){
*buff++=0xFF;
*buff++=0xFF;
*buff++=0xFF;
} else {
*buff++=0x0;
*buff++=0x0;
*buff++=0x0;
}
}
}
}
void DrawRectangleMEM(int x1, int y1, int x2, int y2, int c){
unsigned char* p=(void *)((unsigned int)LCDBuffer);
int x,y,loc,t;
unsigned char mask;
if(x1 < 0) x1 = 0;
if(x1 >= HRes) x1 = HRes - 1;
if(x2 < 0) x2 = 0;
if(x2 >= HRes) x2 = HRes - 1;
if(y1 < 0) y1 = 0;
if(y1 >= VRes) y1 = VRes - 1;
if(y2 < 0) y2 = 0;
if(y2 >= VRes) y2 = VRes - 1;
if(x2 <= x1) { t = x1; x1 = x2; x2 = t; }
if(y2 <= y1) { t = y1; y1 = y2; y2 = t; }
if(Option.DISPLAY_ORIENTATION==PORTRAIT){
t=x1;
x1=VRes-y2-1;
y2=t;
t=x2;
x2=VRes-y1-1;
y1=t;
}
if(Option.DISPLAY_ORIENTATION==RLANDSCAPE){
x1=HRes-x1-1;
x2=HRes-x2-1;
y1=VRes-y1-1;
y2=VRes-y2-1;
}
if(Option.DISPLAY_ORIENTATION==RPORTRAIT){
t=y1;
y1=HRes-x1-1;
x1=t;
t=y2;
y2=HRes-x2-1;
x2=t;
}
if(x2 <= x1) { t = x1; x1 = x2; x2 = t; }
if(y2 <= y1) { t = y1; y1 = y2; y2 = t; }
if(y1<low_y)low_y=y1;
if(y2>high_y)high_y=y2;
if(x1<low_x)low_x=x1;
if(x2>high_x)high_x=x2;
for(x=x1;x<=x2;x++){
for(y=y1;y<=y2;y++){
if(!PackHorizontal){
loc=x+(y/8)*DisplayHRes; //get the byte address for this bit
mask=1<<(y % 8); //get the bit position for this bit
} else {
loc=x/8+y*DisplayHRes/8; //get the byte address for this bit
mask=1<<(7-(x % 8)); //get the bit position for this bit
}
if(c){
p[loc]|=mask;
} else {
p[loc]&=(~mask);
}
}
}
}
void DrawPixelMEM(int x1,int y1, int c){
DrawRectangleMEM(x1,y1,x1,y1,c);
}
void DrawBitmapMEM(int x1, int y1, int width, int height, int scale, int fc, int bc, unsigned char *bitmap){
int i, j, k, m, x, y,t, loc;
unsigned char omask, amask;
unsigned char* p=(void *)((unsigned int)LCDBuffer);
if(x1>=HRes || y1>=VRes || x1+width*scale<0 || y1+height*scale<0)return;
for(i = 0; i < height; i++) { // step thru the font scan line by line
for(j = 0; j < scale; j++) { // repeat lines to scale the font
for(k = 0; k < width; k++) { // step through each bit in a scan line
for(m = 0; m < scale; m++) { // repeat pixels to scale in the x axis
x=x1 + k * scale + m ;
y=y1 + i * scale + j ;
if(Option.DISPLAY_ORIENTATION==PORTRAIT){
t=x;
x=VRes-y-1;
y=t;
}
if(Option.DISPLAY_ORIENTATION==RLANDSCAPE){
x=HRes-x-1;
y=VRes-y-1;
}
if(Option.DISPLAY_ORIENTATION==RPORTRAIT){
t=y;
y=HRes-x-1;
x=t;
}
if(y<low_y)low_y=y;
if(y>high_y)high_y=y;
if(x<low_x)low_x=x;
if(x>high_x)high_x=x;
if(!PackHorizontal){
loc=x+(y/8)*DisplayHRes; //get the byte address for this bit
omask=1<<(y % 8); //get the bit position for this bit
amask=~omask;
} else {
loc=x/8+y*DisplayHRes/8; //get the byte address for this bit
omask=1<<(7-(x % 8)); //get the bit position for this bit
amask=~omask;
}
if(x >= 0 && x < DisplayHRes && y >= 0 && y < DisplayVRes) { // if the coordinates are valid
if((bitmap[((i * width) + k)/8] >> (((height * width) - ((i * width) + k) - 1) %8)) & 1) {
if(fc){
p[loc]|=omask;
} else {
p[loc]&=amask;
}
} else {
if(bc>0){
p[loc]|=omask;
} else if(bc==0) {
p[loc]&=amask;
}
}
}
}
}
}
}
}
void N5110SetXY(int x, int y){
int LcdData;
LcdData=0b01000000 | y ; spi_write_command(LcdData);
LcdData=0b10000000 | x ; spi_write_command(LcdData);
}
void SSD1306I2CSetXY(uint8_t x, uint8_t y){
uint8_t xn=x;
I2C_Send_Command(0xB0 | y);
I2C_Send_Command(0x10 | ((xn>>4) & 0xF));
I2C_Send_Command(0x00 | (xn & 0xF));
}
void SSD1306SPISetXY(uint8_t x, uint8_t y){
uint8_t xn=x;
spi_write_command(0xB0 | y);
spi_write_command(0x10 | ((xn>>4) & 0xF));
spi_write_command(0x00 | (xn & 0xF));
}
void ST7920SetXY(int x, int y){
int xx=x, yy=y;
if(yy>31){
xx=xx+8;
yy=yy-32;
}
unsigned char a[5];
a[0]=ST7920setcommand;
a[1]=(yy & 0x10) | 0x80;
a[2]=(yy & 0x0F) <<4;
a[3]=0x80;
a[4]=xx<<4;
SetCS();
xmit_byte_multi(a,5);
// HAL_SPI_Transmit(&hspi3,a,5,500);
uSec(50);
ClearCS(Option.LCD_CD);
}
void Display_Refresh(void){
if(!(Option.DISPLAY_TYPE<=I2C_PANEL || Option.DISPLAY_TYPE>=BufferedPanel)) return;
unsigned char* p=(void *)((unsigned int)LCDBuffer);
if(low_x==2000 && high_x==-1 && low_y==2000 && high_y==-1)return; //Nothing to do
if(low_x<0)low_x=0;
if(low_y<0)low_y=0;
if(high_x>DisplayHRes)high_x=DisplayHRes-1;
if(high_y>DisplayVRes)high_y=DisplayVRes-1;
if(Option.DISPLAY_TYPE==N5110){
int y;
for(y=low_y/8;y<(high_y & 0xf8)/8+1;y++){
N5110SetXY(low_x, y);
SetCS();
gpio_put(LCD_CD_PIN,GPIO_PIN_SET);
xmit_byte_multi(p+(y*DisplayHRes)+low_x,high_x-low_x+1);
ClearCS(Option.LCD_CS);
}
} else if(Option.DISPLAY_TYPE<=I2C_PANEL){
int y;
for(y=low_y/8;y<(high_y & 0xf8)/8+1;y++){
SSD1306I2CSetXY(Option.I2Coffset+low_x,y);
I2C_Send_Data(p+(y*DisplayHRes)+low_x,high_x-low_x+1);
}
} else if(Option.DISPLAY_TYPE==SSD1306SPI){
int y;
for(y=low_y/8;y<(high_y & 0xf8)/8+1;y++){
SSD1306SPISetXY(Option.I2Coffset+low_x,y);
SetCS();
gpio_put(LCD_CD_PIN,GPIO_PIN_SET);
xmit_byte_multi(p+(y*DisplayHRes)+low_x,high_x-low_x+1);
// HAL_SPI_Transmit(&hspi3,p+(y*DisplayHRes)+low_x,high_x-low_x+1,500);
ClearCS(Option.LCD_CS);
}
} else if(Option.DISPLAY_TYPE==ST7920){
int y,i;
unsigned char x_array[33];
unsigned char *q;
for(y=low_y;y<=high_y;y++){
q=p+y*16;
x_array[0]=ST7920setata;
for(i=1;i<33;i+=2){
x_array[i]=*q & 0xF0;
x_array[i+1]=((*q++)<<4) & 0xF0;
}
ST7920SetXY(0,y);
SetCS();
xmit_byte_multi(x_array,33);
// HAL_SPI_Transmit(&hspi3,x_array,33,500);
ClearCS(Option.LCD_CD);
}
}
low_y=2000; high_y=-1; low_x=2000; high_x=-1;
}
#endif
void DisplayNotSet(void) {
error("Display not configured");
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// These three functions allow the SPI port to be used by multiple drivers (LCD/touch/SD card)
// The BASIC use of the SPI port does NOT use these functions
// The MX170 uses SPI channel 1 which is shared by the BASIC program
// The MX470 uses SPI channel 2 which it has exclusive control of (needed because touch can be used at any time)
//
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
extern uint16_t SPI_CLK_PIN;
// config the SPI port for output
// it will not touch the port if it has already been opened
void SPISpeedSet(int device){
if(CurrentSPIDevice != device){
if(device==SDSLOW || (device==SDFAST && SPI_CLK_PIN!= SD_CLK_PIN)) {
// MMPrintString("Slow Bitbang\r\n");
xchg_byte= BitBangSwapSPI;
xmit_byte_multi=BitBangSendSPI;
rcvr_byte_multi=BitBangReadSPI;
SET_SPI_CLK=BitBangSetClk;
SET_SPI_CLK(SD_SPI_SPEED, false, false);
} else {
if(PinDef[Option.SYSTEM_CLK].mode & SPI0SCK && PinDef[Option.SYSTEM_MOSI].mode & SPI0TX && PinDef[Option.SYSTEM_MISO].mode & SPI0RX ) {
// MMPrintString("SPI0\r\n");
xchg_byte= HW0SwapSPI;
xmit_byte_multi=HW0SendSPI;
rcvr_byte_multi=HW0ReadSPI;
SET_SPI_CLK=HW0Clk;
gpio_set_input_enabled(PinDef[Option.SYSTEM_CLK].GPno,false);
gpio_set_input_enabled(PinDef[Option.SYSTEM_MOSI].GPno,false);
gpio_set_input_enabled(PinDef[Option.SYSTEM_MISO].GPno,false);
} else if(PinDef[Option.SYSTEM_CLK].mode & SPI1SCK && PinDef[Option.SYSTEM_MOSI].mode & SPI1TX && PinDef[Option.SYSTEM_MISO].mode & SPI1RX ){
// MMPrintString("SPI1\r\n");
xchg_byte= HW1SwapSPI;
xmit_byte_multi=HW1SendSPI;
rcvr_byte_multi=HW1ReadSPI;
SET_SPI_CLK=HW1Clk;
} else {
// MMPrintString("Fast Bitbang\r\n");
xchg_byte= BitBangSwapSPI;
xmit_byte_multi=BitBangSendSPI;
rcvr_byte_multi=BitBangReadSPI;
SET_SPI_CLK=BitBangSetClk;
}
SET_SPI_CLK(display_details[device].speed, display_details[device].CPOL, display_details[device].CPHASE);
}
CurrentSPIDevice=device;
}
}
// set the chip select for SPI to high (disabled)
void ClearCS(int pin) {
if(pin) {
if(Option.DISPLAY_TYPE != ST7920) gpio_put(PinDef[pin].GPno,GPIO_PIN_SET);
else gpio_put(PinDef[pin].GPno,GPIO_PIN_RESET);
}
}
#ifndef PICOMITEVGA
int GetLineILI9341(void){
unsigned char q;
SetCS();
SPISpeedSet(Option.DISPLAY_TYPE==ILI9341 ? SPIReadSpeed : ST7789RSpeed);
gpio_put(LCD_CD_PIN,GPIO_PIN_RESET);
SPIsend(ILI9341_GETSCANLINE);
gpio_put(LCD_CD_PIN,GPIO_PIN_SET);
uSec(3);
xchg_byte(0);
q=xchg_byte(0);
xchg_byte(0);
ClearCS(Option.LCD_CS);
SPISpeedSet(Option.DISPLAY_TYPE);
return (int)(q);
}
#endif