Last active
September 22, 2021 12:33
-
-
Save fanoush/3dede6a16cef85fbf55f9d925521e4a0 to your computer and use it in GitHub Desktop.
Inline C P8 LCD DMA demo
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
E.kickWatchdog(); | |
function P8KickWd(){ | |
if(!D17.read())E.kickWatchdog(); | |
} | |
var wdint=setInterval(P8KickWd,1000); | |
E.enableWatchdog(10, false); | |
var SPI2 = E.compiledC(` | |
// int cmd(int,int) | |
// int data(int,int) | |
// int write(int,int) | |
// int write_async(int, int) | |
// void async_wait() | |
// int fill_color(int,int) | |
// void setpins(int,int,int,int) | |
// int enable(int,int) | |
// void disable() | |
// void save() | |
// void restore() | |
// void blit_setup(int,int,int,int) | |
// int blt_pal(int,int,int,int) | |
//// int fill(int,int) | |
//// int send(int,int) | |
typedef unsigned int uint32_t; | |
typedef signed int int32_t; | |
typedef unsigned short uint16_t; | |
typedef unsigned char uint8_t; | |
typedef signed char int8_t; | |
#define NULL ((void*)0) | |
// if code is in RAM we can put global data into text/code segment | |
// this allows simpler pc-relative addressing and shorter/faster code | |
#define __code __attribute__((section(".text"))) | |
#define SPI0BASE 0x40003000 | |
#define SPI1BASE 0x40004000 | |
#define SPI2BASE 0x40023000 | |
#define USE_DMA | |
#define LCD_BPP 12 | |
// _code volatile uint32_t *SPI =(uint32_t*)SPI2BASE; | |
// direct constant makes smaller/faster code | |
#define SPI ((volatile uint32_t*)SPI2BASE) | |
//divide register offsets by sizeof(uint32_t) | |
#define REG(offset) (offset/4) | |
// common/nonDMA registers | |
#define READY REG(0x108) | |
#define INTENSET REG(0x304) | |
#define INTENCLR REG(0x308) | |
#define ENABLE REG(0x500) | |
#define PSELSCK REG(0x508) | |
#define PSELMOSI REG(0x50c) | |
#define PSELMISO REG(0x510) | |
#define RXD REG(0x518) | |
#define TXD REG(0x51c) | |
#define FREQUENCY REG(0x524) | |
#define CONFIG REG(0x554) | |
/// EasyDMA registers | |
#define TASKS_START REG(0x010) | |
#define TASKS_STOP REG(0x014) | |
#define EVENTS_STOPPED REG(0x104) | |
#define EVENTS_ENDRX REG(0x110) | |
#define EVENTS_END REG(0x118) | |
#define EVENTS_ENDTX REG(0x120) | |
#define EVENTS_STARTED REG(0x14C) | |
#define SHORTS REG(0x200) | |
#define RXDPTR REG(0x534) | |
#define RXDMAXCNT REG(0x538) | |
#define RXDAMOUNT REG(0x53C) | |
#define RXDLIST REG(0x540) | |
#define TXDPTR REG(0x544) | |
#define TXDMAXCNT REG(0x548) | |
#define TXDAMOUNT REG(0x54C) | |
#define TXDLIST REG(0x550) | |
#define ORC REG(0x5c0) | |
__code static int pSCK= -1; | |
__code static int pMOSI= -1; | |
__code static int pMISO= -1; | |
__code static int pCD= -1; //command/data | |
#define GPIO(x) ((volatile uint32_t*)(0x50000000+x)) | |
#define OUT GPIO(0x504) | |
#define OUTSET GPIO(0x508) | |
#define OUTCLR GPIO(0x50c) | |
#define IN GPIO(0x510) | |
// direction 1=output | |
#define DIR GPIO(0x514) | |
#define DIRSET GPIO(0x518) | |
#define DIRCLR GPIO(0x51c) | |
void setpins(int sck,int mosi,int miso,int cd){ | |
pSCK=sck;pMOSI=mosi;pMISO=miso;pCD=cd; | |
} | |
__code uint32_t savedintflags=0; | |
__code uint32_t savedmode=0; | |
//__code uint32_t isDMA=0; | |
void save(){ | |
savedintflags=SPI[INTENSET]; | |
savedmode=SPI[ENABLE]; | |
} | |
void restore(){ | |
SPI[ENABLE]=0; | |
SPI[INTENSET]=savedintflags; | |
SPI[ENABLE]=savedmode; | |
} | |
int setup(uint32_t speed,uint32_t mode){ | |
if (pSCK>=0 && (pMISO>=0||pMOSI>=0)){ | |
SPI[INTENCLR]=SPI[INTENSET]; // clear all flags | |
SPI[PSELSCK]=pSCK; | |
SPI[PSELMOSI]=pMOSI; | |
SPI[PSELMISO]=pMISO; | |
SPI[FREQUENCY]=speed<<24; // 0x80=8mbits,0x40=4mbits,... | |
SPI[CONFIG]=mode<<1; //msb first | |
return 1; | |
} | |
return 0; | |
} | |
void disable(){ | |
uint32_t flags=SPI[INTENSET]; | |
if (flags) SPI[INTENCLR]=flags; // clear all interrupt flags | |
SPI[ENABLE]=0; | |
SPI[READY]=0; | |
} | |
#if 0 | |
// sends and also receives data over SPI | |
int send(uint8_t *buffer, int len){ | |
if(buffer==NULL || len==0) return 0; | |
SPI[READY]=0; | |
SPI[TXD]=*buffer++; | |
while (--len){ | |
SPI[TXD]=*buffer++; | |
int t=100; | |
while (SPI[READY]==0 && --t); | |
if (t==0) return -len; // timeout | |
SPI[READY]=0; | |
buffer[-2]=SPI[RXD]; | |
} | |
buffer[-1]=SPI[RXD]; | |
return 0; | |
} | |
#endif | |
#ifndef USE_DMA | |
// pins need to be already preconfigured as gpio input/outputs | |
int enable(uint32_t speed,uint32_t mode){ | |
if (SPI[ENABLE]) return -1; | |
if (setup(speed,mode)){ | |
SPI[ENABLE]=1; | |
SPI[READY]=0; | |
//isDMA=0; | |
return 1; | |
} | |
return 0; | |
} | |
int write(uint8_t *buffer, int len); | |
int write_loop(uint8_t *buffer, int len); | |
int data(uint8_t *buffer, int len); | |
// sends first byte as command, rest as data | |
int cmd(uint8_t *buffer, int len){ | |
if(buffer==NULL || len==0) return -1; | |
if (pCD>0) *OUTCLR = 1<<pCD; // CMD | |
SPI[RXD]; // flush RX | |
SPI[READY]=0; | |
SPI[TXD]=*buffer++; | |
int t=100; | |
while (SPI[READY]==0 && --t); | |
if (pCD>0) *OUTSET = 1<<pCD; // DATA | |
if (t==0) return -1; // timeout | |
if (--len == 0) return 0; // no command data | |
return data(buffer,len); | |
} | |
// send as data (with CD pin high) | |
int data(uint8_t *buffer, int len){ | |
// if(buffer==NULL || len==0) return -1; | |
if (pCD>0) *OUTSET = 1<<pCD; // DATA | |
return write(buffer,len); | |
} | |
int write(uint8_t *buffer, int len){ | |
if(buffer==NULL || len==0) return -1; | |
SPI[READY]=0; | |
SPI[RXD]; // flush RX | |
SPI[TXD]=*buffer++; | |
return write_loop(buffer,len); | |
} | |
// just the write loop with transfer already started | |
// len is +1 since the first byte was already sent | |
int write_loop(uint8_t *buffer, int len){ | |
while (--len){ | |
SPI[TXD]=*buffer++; | |
int t=100; | |
while (SPI[READY]==0 && --t); | |
SPI[READY]=0; | |
SPI[RXD]; | |
if (t==0) return -len; //timeout | |
} | |
return 0; | |
} | |
// write same buffer more times | |
int write_many(uint8_t *buffer, int len, int count){ | |
if(buffer==NULL || len==0) return 0; | |
SPI[READY]=0; | |
SPI[RXD]; // flush RX | |
SPI[TXD]=*buffer; | |
int res=write_loop(buffer+1,len++); //next time we write one more | |
//SPI[RXD]; // flush RX | |
while (--count && res>=0) res=write_loop(buffer,len); | |
return res; | |
} | |
#if 1 | |
// 12bit fill version, inline buffer, faster | |
int fill_12bit(uint32_t val,int len){ | |
len=(len*3)/2; | |
SPI[RXD]; // flush RX | |
SPI[READY]=0; | |
int w=0; // number if wait states, just for info | |
// uint8_t buff[3]= {val>>4,(val&0xf)<<4|val>>8,val&0xff}; | |
uint8_t buff[3]= { (val&0xf)<<4|val>>8, val>>4, val&0xff }; // backwards due to --len | |
uint8_t txbyte=buff[0]; | |
SPI[TXD]=val>>4; // start transfer, we can write one more value without waiting | |
int t=100; // timeout, if not ready after this something went wrong? | |
while (--len){ | |
SPI[TXD]=txbyte; | |
txbyte = buff[len%3]; | |
t=100; | |
while (SPI[READY]==0 && --t) w++; // t prevents endless loop if ready signal got lost | |
SPI[READY]=0; | |
SPI[RXD]; //flush RX | |
if (t==0) return -1; // timeout | |
} | |
SPI[RXD]; // flush RX | |
return w; | |
} | |
#else | |
// 12bit fill version | |
int fill_12bit(uint32_t val,int len){ | |
uint8_t buff[3]={val>>4,(val&0xf)<<4|val>>8,val&0xff}; | |
return write_many(buff,3,len/2); | |
} | |
#endif | |
int fill_16bit(uint32_t val,int len){ | |
uint8_t buff[4]= {val>>8,val&0xff,val>>8,val&0xff}; | |
return write_many(buff,4,len/2); | |
} | |
#else // USE_DMA | |
int enable(uint32_t speed,uint32_t mode){ | |
if (SPI[ENABLE]) return -1; | |
if (setup(speed,mode)){ | |
SPI[ENABLE]=7; | |
SPI[TASKS_STOP]=1; | |
//isDMA=1; | |
return 1; | |
} | |
return 0; | |
} | |
int write_dma(uint8_t *buffer, uint32_t len,int async); | |
int data(uint8_t *buffer, int len){ | |
if (pCD<0) return -1; | |
if(buffer==NULL || len==0) return -1; | |
*OUTSET = 1<<pCD; // data | |
write_dma(buffer,len,0); | |
return 0; | |
} | |
int cmd(uint8_t *buffer, int len){ | |
if (pCD<0) return -1; | |
*OUTCLR = 1<<pCD; // CMD | |
write_dma(buffer,1,0); | |
*OUTSET = 1<<pCD; // data | |
if (len<=1) return 0; | |
write_dma(buffer+1,len-1,0); | |
return 0; | |
} | |
int write(uint8_t *buffer, int len){ | |
if(buffer==NULL || len==0) return -1; | |
return write_dma(buffer,len,0); | |
} | |
int write_async(uint8_t *buffer, int len){ | |
if(buffer==NULL || len==0) return -1; | |
return write_dma(buffer,len,1); | |
} | |
void wait_dma(); | |
void async_wait(){ | |
wait_dma(); | |
} | |
int write_many_dma(uint8_t *buffer, int len, int count); | |
#if LCD_BPP==12 | |
#if 0 | |
// 12bit fill version | |
int fill_12bit3(uint32_t val,int len){ | |
uint8_t buff[3]={val>>4,(val&0xf)<<4|val>>8,val&0xff}; | |
return write_many_dma(buff,3,len/2); | |
} | |
int fill_12bit6(uint32_t val,int len){ | |
uint8_t buff[6]={val>>4,(val&0xf)<<4|val>>8,val&0xff,val>>4,(val&0xf)<<4|val>>8,val&0xff}; | |
return write_many_dma(buff,6,len/4); | |
} | |
#else | |
int fill_color(uint32_t val,int len){ | |
uint8_t buff[24]={ | |
val>>4,(val&0xf)<<4|val>>8,val&0xff, | |
val>>4,(val&0xf)<<4|val>>8,val&0xff, | |
val>>4,(val&0xf)<<4|val>>8,val&0xff, | |
val>>4,(val&0xf)<<4|val>>8,val&0xff, | |
val>>4,(val&0xf)<<4|val>>8,val&0xff, | |
val>>4,(val&0xf)<<4|val>>8,val&0xff, | |
val>>4,(val&0xf)<<4|val>>8,val&0xff, | |
val>>4,(val&0xf)<<4|val>>8,val&0xff | |
}; | |
return write_many_dma(buff,24,len/16); | |
} | |
#endif | |
#elif LCD_BPP==16 | |
int fill_color(uint32_t val,int len){ | |
uint8_t buff[8]= { | |
val>>8,val&0xff,val>>8,val&0xff,val>>8,val&0xff,val>>8,val&0xff | |
}; | |
return write_many_dma(buff,8,len/4); | |
} | |
#endif | |
__code int running=0; | |
void wait_dma(){ | |
if (running) { | |
while (SPI[EVENTS_END] == 0); // wait for previous finish | |
SPI[EVENTS_END]=0; | |
running=0; | |
} | |
} | |
int write_dma(uint8_t *ptr, uint32_t len, int async) | |
{ | |
wait_dma(); | |
int offset = 0; | |
SPI[RXDPTR]=0; | |
SPI[RXDMAXCNT]=0; | |
SPI[EVENTS_END]=0; | |
do { | |
SPI[TXDPTR]=(uint32_t)(ptr + offset); | |
if (len < 0x100) { | |
SPI[TXDMAXCNT]=len; | |
len = 0; | |
} else { | |
SPI[TXDMAXCNT]=0xff; | |
offset = offset + 0xff; | |
len = len - 0xff; | |
} | |
SPI[TASKS_START]=1; | |
if (async && len==0){ | |
running=1; // do not wait for last part | |
} else { | |
while (SPI[EVENTS_END] == 0); | |
SPI[EVENTS_END]=0; | |
} | |
} while (len != 0); | |
return 0; | |
} | |
// write same buffer many times repeatedly | |
int write_many_dma(uint8_t *buffer, int len, int count){ | |
wait_dma(); | |
SPI[RXDPTR]=0; | |
SPI[RXDMAXCNT]=0; | |
SPI[EVENTS_END]=0; | |
SPI[TXDPTR]=(uint32_t)(buffer); | |
SPI[TXDMAXCNT]=len; | |
if (count > 1) | |
SPI[SHORTS]=1<<17; | |
SPI[TASKS_START]=1; | |
do { | |
while (SPI[EVENTS_END] == 0); // wait | |
SPI[EVENTS_END]=0; | |
if (count <= 2) SPI[SHORTS]=0; // stop shortcut for next loop | |
} while (--count); | |
return 0; | |
} | |
__code uint16_t blit_bpp; | |
__code uint16_t blit_w; | |
__code uint16_t blit_h; | |
__code uint16_t blit_stride; | |
void blit_setup(uint16_t w,uint16_t h,uint16_t bpp, uint16_t stride){ | |
blit_bpp=bpp;blit_w=w;blit_h=h;blit_stride=stride; | |
} | |
#define LCHUNK 30 | |
int blt_pal(uint8_t *buff,uint16_t* palbuff,uint8_t xbitoff,int async){ | |
uint8_t *pxbuff=buff; | |
uint8_t bpp=blit_bpp; | |
if (pxbuff==NULL || palbuff==NULL || bpp==0 || bpp>8) return -1; | |
int stride=blit_stride/(8/bpp); //pixels per byte | |
uint8_t mask=(1<<bpp)-1; //pixel bitmask | |
uint8_t bpos=xbitoff; | |
uint8_t val=(*pxbuff++)>>(bpos*bpp); | |
uint8_t w=blit_w; | |
uint8_t h=blit_h; | |
uint8_t lbuff_1[LCHUNK]; | |
uint8_t lbuff_2[LCHUNK]; | |
uint8_t *lbuff=lbuff_1; | |
int lbufpos=0; | |
int lbuffnum=0; | |
do { | |
w=blit_w; | |
do { | |
#if LCD_BPP==12 | |
// pixel 1 | |
uint16_t px1=palbuff[val&mask]; // get color | |
val=val>>bpp;bpos+=bpp; | |
if(bpos==8){val=*pxbuff++;;bpos=0;} | |
//pixel 2 | |
uint16_t px2=palbuff[val&mask]; // get color | |
val=val>>bpp;bpos+=bpp; | |
if(bpos==8){val=*pxbuff++;;bpos=0;} | |
//put 2x 12bit pixels into buffer | |
lbuff[lbufpos++]=px1>>4; | |
lbuff[lbufpos++]=(px1<<4)|(px2>>8); | |
lbuff[lbufpos++]=px2&255; | |
w-=2; | |
#elif LCD_BPP==16 | |
// pixel 1 | |
uint16_t px1=palbuff[val&mask]; // get color | |
val=val>>bpp;bpos+=bpp; | |
if(bpos==8){val=*pxbuff++;;bpos=0;} | |
//put 16bit pixel into buffer | |
lbuff[lbufpos++]=px1>>8; | |
lbuff[lbufpos++]=px1&255; | |
w++; | |
#endif | |
if (lbufpos >= LCHUNK){ | |
// buffer full, start async draw and switch to other buffer | |
write_dma(lbuff,lbufpos,1); | |
lbuffnum=1-lbuffnum; | |
lbuff = lbuffnum ? lbuff_2 : lbuff_1; | |
lbufpos=0; | |
} | |
} while(w>0); | |
buff+=stride; | |
pxbuff=buff;bpos=xbitoff; | |
val=(*pxbuff++)>>(bpos*bpp); | |
h--; | |
} while(h>0); | |
// send the rest | |
if (lbufpos>0){ | |
// buffer full, draw and switch to other buffer | |
write_dma(lbuff,lbufpos,async); | |
} | |
return 0; | |
} | |
#endif //USE_DMA | |
`); | |
/* | |
var SPI2 = (function(){ | |
var bin=atob("AAAAAAAAAAAAAAAA/////////////////////wAAAAAAAAAAELUDTHxEIoBggKGA44AQvdT///8HS3tEm2hDsQRKE2gAK/zQACMTYANKekSTYHBHGDECQML///+u////LenwR5BGGUwZTv/35f8ZSt/4ZMAAIwElE2BP8P8OU2CpRiNgEDIfRv8pAOsDCsL4AKCLv/8zMWDG+ADgACGIv/85zPgAkLjxAA8G0Cm5C0t7RJ1gACC96PCH1PgAoLrxAA/60CdgACne0fPnGDECQEg1AkA0NQJAEDACQEz///8t6fBPmbCJRgOSSEoFk3pEkvgAgAAoAPCFgAApAPCCgAjx/zMHK33Y0YiS+ASwBpIII7P7+POx+/PzBJMBIwP6CPMBO9uyB0YCkwObF/gBSxj7A/McQU/wAAoBk+SyUUYQqAabA56beACTCKs9RgeTAptGRCNA9rIILhi/RPoI9Dn4E8AIvxX4AUsCmxi/5LIE6gMDCL8AJjn4EyBP6iwTQ1QTEkPqDBxDGEZE9rKD+AHAAJsILhi/RPoI9AHxAg6j8QIDAfEDARS/5LIV+AFLAPgOIAi/ACbbsh0pAJMJ3QEi//dN/9rxAQoTvweYUUYQqAAhAJsAK7rRBJsfRAGbF/gBTBxBC/H/MxPw/wvksqfRGbEFmv/3M/9ZRghGGbC96PCPT/D/MfjnAL8O////ELXDssDzBxIACoawQOoDEMCyACmN+AEAjfgEAI34BwCN+AoAjfgNAI34EACN+BMAjfgWAAhGuL8B8Q8AjfgAII34AjCN+AMgjfgFMI34BiCN+AgwjfgJII34CzCN+AwgjfgOMI34DyCN+BEwjfgSII34FDCN+BUgjfgXMAAR//fT/hJLEkwAIhpgWmCj8hxDHykaYGpGImAOSk/wGAQUYMK/ovVSck/0ADERYApKASERYApJACIcaAAs/NACKBpg2L8KYAE49tEGsBC9NDUCQEQ1AkBINQJAEDACQAAyAkD/96K+GLERsQEi//exvk/w/zBwRxixEbEAIv/3qb5P8P8wcEf4tRJOfkQHRvNoACsNRhXbASQMSgT6A/MTYCFGACL/95X+82icQAhLAS0cYATdACJpHngc//eK/gAgAeBP8P8w+L0AvwwFAFAIBQBQ5Pz//wpKekQQtdJoACoK20ixQbEBI5NABEoTYAAi//dv/gAgEL1P8P8w++cIBQBQlvz//zC1FUwDRiBoELsZSnpEFWkALRzbVWkALQLakmkAKhbbDkoQaFBgE0oNSHpEGwYVaQVglWlFYFBpCkoQYFNhCktJABlgByMjYAhLASAYYDC9T/D/MPvnAL8ANQJABDMCQAg1AkAQNQJAVDUCQBQwAkBc/P//Pvz//wVLG2gLsQVKE2AFSgAjE2Ci9X5yE2BwRwQzAkAIMwJAADUCQAVLBkkAIhpgBUp6RNBpCGASahpgcEcAvwA1AkAEMwJAwvv//wRLGmgFS3tE2mEDShJoGmJwRwC/BDMCQAA1AkCi+///ELUDTHxExOkFISBh42AQvYT7//8="); | |
return { | |
cmd:E.nativeCall(789, "int(int,int)", bin), | |
data:E.nativeCall(869, "int(int,int)", bin), | |
write:E.nativeCall(773, "int(int,int)", bin), | |
write_async:E.nativeCall(757, "int(int, int)", bin), | |
async_wait:E.nativeCall(753, "void()", bin), | |
fill_color:E.nativeCall(529, "int(int,int)", bin), | |
setpins:E.nativeCall(1141, "void(int,int,int,int)", bin), | |
enable:E.nativeCall(917, "int(int,int)", bin), | |
disable:E.nativeCall(1037, "void()", bin), | |
save:E.nativeCall(1109, "void()", bin), | |
restore:E.nativeCall(1073, "void()", bin), | |
blit_setup:E.nativeCall(37, "void(int,int,int,int)", bin), | |
blt_pal:E.nativeCall(225, "int(int,int,int,int)", bin), | |
}; | |
})(); | |
*/ | |
//P8 pins | |
CS=D25;DC=D18;RST=D26;BL=D14; | |
RST.reset(); | |
// CLK,MOSI,CS,DC | |
D2.write(0);D3.write(0);CS.write(1);DC.write(1); | |
SPI2.save(); | |
SPI2.setpins(2,3,-1,18); | |
SPI2.disable();SPI2.enable(0x80,0); //8MBit, mode 0 | |
function lcd_cmd(arr){ | |
var b=E.toString(arr); // flat string buffer | |
if (!b){print("lcd_cmd: OOPS, undefined");E.defrag();b=E.toString(arr); } | |
if (!b){print("lcd_cmd: OOPS again!");E.defrag();b=E.toString(arr); } | |
CS.reset(); | |
SPI2.cmd(E.getAddressOf(b,true),b.length); | |
CS.set(); | |
} | |
function lcd_data(arr){ | |
const b=E.toString(arr); // flat string | |
CS.reset(); | |
SPI2.cmd(E.getAddressOf(b,true),b.length); | |
CS.set(); | |
} | |
RST.set(); | |
// CS.reset(); t=getTime();SPI2.fill_color(0xfff,240*240);t=getTime()-t; CS.set();t | |
// digitalPulse(RST,0,10);BL.set(); | |
var bpp=4; // powers of two work, 3=8 colors would be nice | |
var g=Graphics.createArrayBuffer(240,240,bpp); | |
var pal; | |
switch(bpp){ | |
case 1: pal= Uint16Array([0x000,0xfff]);break; | |
case 2: pal= Uint16Array([0x000,0xf00,0x0f0,0x00f]);break; // white won't fit | |
case 4: pal= Uint16Array( // CGA | |
[0x000,0x00a,0x0a0,0x0aa,0xa00,0xa0a,0xa50,0xaaa, 0x555,0x55f,0x5ff,0xf55,0xf5f,0xff5,0xfff]);break; | |
} | |
INITCMDS = [ | |
// This is an unrotated screen | |
[0x36, 0], // MADCTL | |
[0x37,0,0], | |
// These 2 rotate the screen by 180 degrees | |
//[0x36,0xC0], // MADCTL | |
//[0x37,0,80], // VSCSAD (37h): Vertical Scroll Start Address of RAM | |
[0x3A, 0x03], // COLMOD - interface pixel format - 12bpp, 05 - 16bpp | |
[0xB2, 0xC, 0xC, 0, 0x33, 0x33], // PORCTRL (B2h): Porch Setting | |
[0xB7, 0], // GCTRL (B7h): Gate Control | |
[0xBB, 0x3E], // VCOMS (BBh): VCOM Setting | |
[0xC2, 1], // VDVVRHEN (C2h): VDV and VRH Command Enable | |
[0xC3, 0x19], // VRHS (C3h): VRH Set | |
[0xC4, 0x20], // VDVS (C4h): VDV Set | |
[0xC5, 0xF], // VCMOFSET (C5h): VCOM Offset Set . | |
[0xD0, 0xA4, 0xA1], // PWCTRL1 (D0h): Power Control 1 | |
[0xe0, 0x70, 0x15, 0x20, 0x15, 0x10, 0x09, 0x48, 0x33, 0x53, 0x0B, 0x19, 0x15, 0x2a, 0x2f], // PVGAMCTRL (E0h): Positive Voltage Gamma Control | |
[0xe1, 0x70, 0x15, 0x20, 0x15, 0x10, 0x09, 0x48, 0x33, 0x53, 0x0B, 0x19, 0x15, 0x2a, 0x2f], // NVGAMCTRL (E1h): Negative Voltage Gamma Contro | |
[0x29], // DISPON (29h): Display On | |
[0x21], // INVON (21h): Display Inversion On | |
[0x2a,0,0,0,239], | |
[0x2b,0,0,0,239], | |
[0x2c] | |
]; | |
g.init=function(f){ | |
lcd_cmd([0x11]); // sleep out | |
setTimeout(()=>{ | |
BL.reset(); | |
CS.reset(); | |
INITCMDS.forEach((a)=>{var cmd=E.toString(a);SPI2.cmd(E.getAddressOf(cmd,true),cmd.length);}); | |
if (f !== undefined) f(); | |
},120); | |
}; | |
g.off=function(){ | |
lcd_cmd([0x10]); | |
BL.set(); | |
}; | |
g.on=function(){ | |
lcd_cmd([0x11]); | |
BL.reset(); | |
}; | |
g.flip=function(){ | |
var r=g.getModified(true); | |
//print(r); | |
if (r === undefined) return; | |
var x1=r.x1&0xfe;var x2=(r.x2+2)&0xfe; | |
var xw=(x2-x1); | |
var yw=(r.y2-r.y1+1); | |
var stride=g.getWidth(); | |
lcd_cmd([0x2a,0,x1,0,x2-1]); | |
lcd_cmd([0x2b,0,r.y1,0,r.y2]); | |
lcd_cmd([0x2c]); | |
SPI2.blit_setup(xw,yw,bpp,stride); | |
//print("setup ",xw,yw,bpp,stride); | |
var ppb=8/bpp; //pixels per byte | |
var bpos=x1%ppb; //first pixel offset | |
var pa=E.getAddressOf(pal.buffer,true); | |
var a=E.getAddressOf(g.buffer,true); | |
a+=(x1-bpos+r.y1*stride)/ppb; // address of upper left corner | |
CS.reset(); | |
SPI2.blt_pal(a,pa,bpos,0); // 0=not async, becasuse of CS | |
//print("blit",a.toString(16),pa.toString(16),bpos); | |
CS.set(); | |
}; | |
/* | |
g.jsflip=function(){ // very slow but works the same | |
var lbuffs=[new Uint8Array(30),new Uint8Array(30)]; | |
var r=g.getModified(true); | |
if (r === undefined) return; | |
var x1=r.x1&0xfe;var x2=(r.x2+2)&0xfe; | |
var xw=(x2-x1); | |
var yw=(r.y2-r.y1+1); | |
lcd_cmd([0x2a,0,x1,0,x2-1]); | |
lcd_cmd([0x2b,0,r.y1,0,r.y2]); | |
lcd_cmd([0x2c]); | |
// | |
lbuffidx=0; | |
lbuff=lbuffs[lbuffidx]; | |
lbufpos=0; | |
// | |
CS.reset(); | |
var a=E.getAddressOf(g.buffer,true); | |
var ppb=8/bpp;//pixels per byte | |
var mask=(1<<bpp)-1;//pixel bitmask | |
var bpos=x1%ppb; | |
var stride=g.getWidth(); | |
a+=(x1-bpos+r.y1*stride)/ppb; // address of upper left corner | |
var xa,x,s,val,c; | |
for (y=r.y1;y<=r.y2;y++){ | |
xa=a; | |
val=(peek8(xa))>>(bpos*bpp); | |
x=xw;s=""; | |
//print("width "+x); | |
P8KickWd(); // this very slow so kick watchdog | |
do { | |
// pixel 1 | |
px1=pal[val&mask]; // get color | |
//s+= (" 12345678")[val&mask]; // draw | |
val=val>>bpp;bpos+=bpp; | |
if(bpos==8){xa++;val=peek8(xa);bpos=0;} | |
//pixel 2 | |
px2=pal[val&mask]; // get color | |
//s+= (" 12345678")[val&mask]; // draw | |
val=val>>bpp;bpos+=bpp; | |
if(bpos==8){xa++;val=peek8(xa);bpos=0;} | |
//put 2x 12bit pixels into buffer | |
lbuff[lbufpos++]=px1>>4; | |
lbuff[lbufpos++]=(px1<<4)|(px2>>8); | |
lbuff[lbufpos++]=px2&255; | |
if (lbufpos >= lbuff.length){ | |
// buffer full, draw and switch to other buffer | |
t=getTime();SPI2.write_async(E.getAddressOf(lbuff.buffer,true),lbufpos);t=getTime()-t; | |
//print("buff fill "+t); | |
lbuffidx=1-lbuffidx; | |
lbuff=lbuffs[lbuffidx]; | |
lbufpos=0; | |
} | |
x-=2; | |
} while(x>0); | |
// finish draw | |
//console.log(s); | |
a+=stride/ppb; | |
} | |
if (lbufpos>0){ | |
// flush the rest | |
SPI2.write(E.getAddressOf(lbuff.buffer,true),lbufpos); | |
lbuffidx=1-lbuffidx; | |
lbuff=lbuffs[lbuffidx]; | |
lbufpos=0; | |
} | |
CS.set(); | |
}; | |
*/ | |
function fillTest(){ | |
// direct fill test , no framebuffer | |
var w=40; | |
[ | |
0xf00,0x0f0,0x00f,0xfff, | |
0xff0,0x0ff,0xf0f,0xfff, | |
0x000,0xf00 | |
].forEach((c)=>{ | |
[ | |
[0x2a,0,w/2,0,239-w/2], | |
[0x2b,0,w/2,0,239-w/2], | |
[0x2c] | |
].forEach((a)=>{lcd_cmd(a);}); | |
CS.reset();SPI2.fill_color(c,(240-w)*(240-w));w+=20; | |
}); | |
CS.set(); | |
} | |
function randomLines(){ | |
g.clear(); | |
while (!D17.read()) { | |
g.setColor(Math.random()*(1<<bpp)); | |
g.drawLine( | |
Math.random()*g.getWidth(), Math.random()*g.getHeight(), | |
Math.random()*g.getWidth(),Math.random()*g.getHeight()); | |
P8KickWd();g.flip(); | |
} | |
g.clear();g.flip(); | |
} | |
function randomShapes(){ | |
g.clear(); | |
var cols=(1<<bpp)-1,w=g.getWidth()-10,h=g.getHeight()-10,r=Math.random; | |
var id=setInterval(function(){ | |
g.setColor(1+r()*cols); | |
x1=10+r()*w;x2=10+r()*w; | |
y1=10+r()*h;y2=10+r()*h; | |
if (x1&1) | |
g.fillEllipse(Math.min(x1,x2), Math.min(y1,y2),Math.max(x1,x2), Math.max(y1,y2)); | |
else | |
g.fillRect(Math.min(x1,x2), Math.min(y1,y2),Math.max(x1,x2), Math.max(y1,y2)); | |
g.flip(); | |
if(D17.read()){ | |
clearInterval(id); | |
g.clear(); | |
g.setFont("Vector20"); | |
g.flip(); | |
} | |
},10); | |
} | |
setTimeout(()=>{ | |
g.init(function(){ | |
fillTest(); | |
}); | |
},500); |
DC=data/command, BL=backlight, backlight is on pins 14,22,23 i am using just first one (14) for lowest brightness
Thanks Fanoush.
Is DC the same as SWO?
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
What are DC and BL in pins?