Skip to content

Instantly share code, notes, and snippets.

@fanoush

fanoush/P8-SPILCD-demo.js

Last active Oct 11, 2020
Embed
What would you like to do?
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

This comment has been minimized.

Copy link

@enteshari enteshari commented Jun 28, 2020

What are DC and BL in pins?

@fanoush

This comment has been minimized.

Copy link
Owner Author

@fanoush 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

This comment has been minimized.

Copy link

@enteshari enteshari commented Jun 29, 2020

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
You can’t perform that action at this time.