Skip to content

Instantly share code, notes, and snippets.

@fanoush
Last active September 22, 2021 12:33
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save fanoush/3dede6a16cef85fbf55f9d925521e4a0 to your computer and use it in GitHub Desktop.
Save fanoush/3dede6a16cef85fbf55f9d925521e4a0 to your computer and use it in GitHub Desktop.
Inline C P8 LCD DMA demo
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);
@enteshari
Copy link

What are DC and BL in pins?

@fanoush
Copy link
Author

fanoush commented Jun 28, 2020

DC=data/command, BL=backlight, backlight is on pins 14,22,23 i am using just first one (14) for lowest brightness

@enteshari
Copy link

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