Below is a very simple demonstration to draw a box. All unused code has been removed and there are no dependent files.
I am fairly sure that all the pinouts of these 40 pin displays are the same. The only differences are that some are 3V and some are 5V, but the display adaptor has resistors on each pin to allow for this. So all the code that talks to the ports will be the same for all displays. The things that are different are initiating the display, setting the column and row addresses and changing from portrait to landscape. So to list the routines that need to be changed for each display, these will be:
This makes the whole process a bit more manageable as that is only four routines.
In the link to Tom's board above are a zip file to download, and in that is a folder with drivers, and in there are some .h files and (I think) some code for each type of display. So the next step would be to find the routines for the above four functions and change the hex values.
I have to go to work now but later I'll see if I can dig out some of the other brands of displays I have as I think I might have the one Tom has.
// SSD1289 very simple demo, draw a box.
uint8_t isOrientationLanscape = 0; // portrait mode = default, 1 = landscape
void setup()
{
//Serial.begin(115200); // for debugging
lcdPortDirection(); // enable mega pins for I/O
lcdInitSSD1289(); // initiate the display
clearBlacklandscape(); // clear the screen
fastBox(150,110,20,20,B11111111,B11111111); // draw a white box RRRRRGG GGGBBBBB
}
void loop()
{
}
// **************** low level display control *********
// *** keep all PORT and DDR commands in a group here, easier to change if change boards
void lcdPortDirection() {
DDRA = B11111111; // port A VH = all outputs, high data byte
DDRC = B11111111; // port C VL = all outputs, low data byte
DDRD = B10000000; // port D bit 7 output = RS
DDRG = B00000111; // port G bit 0=reset, 1=CS, 2=WR
}
void lcdResetLow() {
PORTG = PORTG & B11111110; // LCD_REST low
}
void lcdResetHigh() {
PORTG = PORTG | B00000001; // LCD_REST high
}
void lcdCSLow() {
PORTG = PORTG & B11111101; // LCD_CS low
}
void lcdCSHigh() {
PORTG = PORTG | B00000010; // LCD_CS high
}
void lcdRSLow() {
PORTD = PORTD & B01111111; // LCD_RS low
}
void lcdRSHigh() {
PORTD = PORTD | B10000000; // LCD_RS high
}
void lcdWriteBus(uint8_t VH,uint8_t VL)
{
PORTA = VH; // faster by writing directly to the port (original code used digitalWrite). Other routines are not so time critical
PORTC = VL;
PORTG = PORTG & B11111011; // LCD_WR low
PORTG = PORTG & B11111011; // LCD_WR low small hack, if write this three times it is faster than adding in a 1 microsecond delay. Two times is too fast for the display
PORTG = PORTG & B11111011; // LCD_WR low
//delayMicroseconds(1); // small delay as a Mega is a bit fast for the display, but writing three times above is the same and a bit more accurate
PORTG = PORTG | B00000100; // LCD_WR high
}
void fastBox(uint16_t orgX, uint16_t orgY, uint16_t cols, uint16_t rows, uint8_t VH, uint8_t VL) // draw a box or rectangle, send out the pixel data just once
{
uint32_t i;
uint32_t pixels;
uint32_t colsL,rowsL;
lcdStartDraw(orgX, orgY, cols, rows);
rowsL=rows; // cast to a long
colsL=cols;
pixels = rowsL * colsL;
PORTA = VH; // faster by writing directly to the port (original code used digitalWrite). Other routines are not so time critical
PORTC = VL; // only write the color data once, then toggle the write pin n times
delayMicroseconds(1);
for(i=0;i<pixels;i++)
{
PORTG = PORTG & B11111011; // LCD_WR low
PORTG = PORTG & B11111011; // LCD_WR low small hack, if write this three times it is faster than adding in a 1 microsecond delay. Two times is too fast for the display
PORTG = PORTG & B11111011; // LCD_WR low
PORTG = PORTG | B00000100; // LCD_WR high
}
lcdFinishDraw();
}
// **** end all Port dependent code ***
void lcdWriteCommand(uint8_t VH, uint8_t VL)
{
lcdRSLow();
lcdWriteBus(VH, VL);
}
void lcdWriteData(uint8_t VH, uint8_t VL) // see also drawpixel and start and finishdraw as these are faster
{
lcdRSHigh();
lcdWriteBus(VH, VL);
}
void lcdWriteCommandData(int com,int dat)
{
lcdWriteCommand(com>>8,com);
lcdWriteData(dat>>8,dat);
}
void lcdAddressSet(uint16_t x1,uint16_t y1,uint16_t x2,uint16_t y2)
{
if (isOrientationLanscape) {
lcdWriteCommandData(0x44,(y2 << 8) + y1 ); //Column address start2
lcdWriteCommandData(0x45,x1); //Column address start1
lcdWriteCommandData(0x46,x2); //Column address end2
lcdWriteCommandData(0x4e,y1); //Column address end1
lcdWriteCommandData(0x4f,x1); //Row address start2
}
else {
lcdWriteCommandData(0x44,(x2 << 8) + x1 ); //Column address start2
lcdWriteCommandData(0x45,y1); //Column address start1
lcdWriteCommandData(0x46,y2); //Column address end2
lcdWriteCommandData(0x4e,x1); //Column address end1
lcdWriteCommandData(0x4f,y1); //Row address start2
}
lcdWriteCommand(0x00,0x22);
}
void lcdInitSSD1289(void)
{
lcdResetHigh();
delay(5);
lcdResetLow();
delay(15);
lcdResetHigh();
delay(15);
lcdWriteCommandData(0x0000,0x0001); delay(1); //打开晶振
lcdWriteCommandData(0x0003,0xA8A4); delay(1); //0xA8A4
lcdWriteCommandData(0x000C,0x0000); delay(1);
lcdWriteCommandData(0x000D,0x080C); delay(1);
lcdWriteCommandData(0x000E,0x2B00); delay(1);
lcdWriteCommandData(0x001E,0x00B7); delay(1);
lcdWriteCommandData(0x0001,0x2B3F); delay(1); //驱动输出控制320*240 0x6B3F
lcdWriteCommandData(0x0002,0x0600); delay(1);
lcdWriteCommandData(0x0010,0x0000); delay(1);
lcdWriteCommandData(0x0011,0x6070); delay(1); //0x4030 //定义数据格式 16位色
lcdWriteCommandData(0x0005,0x0000); delay(1);
lcdWriteCommandData(0x0006,0x0000); delay(1);
lcdWriteCommandData(0x0016,0xEF1C); delay(1);
lcdWriteCommandData(0x0017,0x0003); delay(1);
lcdWriteCommandData(0x0007,0x0233); delay(1); //0x0233
lcdWriteCommandData(0x000B,0x0000); delay(1);
lcdWriteCommandData(0x000F,0x0000); delay(1); //扫描开始地址
lcdWriteCommandData(0x0041,0x0000); delay(1);
lcdWriteCommandData(0x0042,0x0000); delay(1);
lcdWriteCommandData(0x0048,0x0000); delay(1);
lcdWriteCommandData(0x0049,0x013F); delay(1);
lcdWriteCommandData(0x004A,0x0000); delay(1);
lcdWriteCommandData(0x004B,0x0000); delay(1);
lcdWriteCommandData(0x0044,0xEF00); delay(1);
lcdWriteCommandData(0x0045,0x0000); delay(1);
lcdWriteCommandData(0x0046,0x013F); delay(1);
lcdWriteCommandData(0x0030,0x0707); delay(1);
lcdWriteCommandData(0x0031,0x0204); delay(1);
lcdWriteCommandData(0x0032,0x0204); delay(1);
lcdWriteCommandData(0x0033,0x0502); delay(1);
lcdWriteCommandData(0x0034,0x0507); delay(1);
lcdWriteCommandData(0x0035,0x0204); delay(1);
lcdWriteCommandData(0x0036,0x0204); delay(1);
lcdWriteCommandData(0x0037,0x0502); delay(1);
lcdWriteCommandData(0x003A,0x0302); delay(1);
lcdWriteCommandData(0x003B,0x0302); delay(1);
lcdWriteCommandData(0x0023,0x0000); delay(1);
lcdWriteCommandData(0x0024,0x0000); delay(1);
lcdWriteCommandData(0x0025,0x8000); delay(1);
lcdWriteCommandData(0x004f,0); //行首址0
lcdWriteCommandData(0x004e,0); //列首址0
lcdWriteCommand(0x00,0x22);
}
void lcdStartDraw(uint16_t orgX, uint16_t orgY, uint16_t cols, uint16_t rows)
{
// use lcdWriteBus for each pixel rather than Lcd_write_data as the former doesn't set rs each time
lcdCSLow();
lcdAddressSet(orgX,orgY,orgX+cols-1, orgY+rows-1); // set up the box to draw in
lcdRSHigh();
}
void lcdFinishDraw()
{
lcdCSHigh();
}
void clearBlacklandscape()
{
landscape();
fastBox(0,0,320,240,0x00,0x00);
}
void portrait()
{
isOrientationLanscape = 0;
lcdCSLow();
lcdWriteCommandData(0x0001,0x2B3F);
lcdWriteCommandData(0x0011,0x6070);
lcdWriteCommand(0x00,0x22);
lcdCSHigh();
}
void landscape()
{
isOrientationLanscape = 1;
lcdCSLow();
lcdWriteCommandData(0x0001,0x293F);
lcdWriteCommandData(0x0011,0x6078);
lcdWriteCommand(0x00,0x22);
lcdCSHigh();
}