Last active
May 27, 2021 07:49
-
-
Save fanoush/f91dc52e76e8281a127cce86d8313ec9 to your computer and use it in GitHub Desktop.
DK08 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
function KickWd(){ | |
if(!BTN1.read())E.kickWatchdog(); | |
} | |
var wdint=setInterval(KickWd,5000); // 5 secs | |
E.enableWatchdog(20, false); // 20 secs | |
E.kickWatchdog(); | |
/* | |
// MIT License (c) 2020 fanoush https://github.com/fanoush | |
// see full license text at https://choosealicense.com/licenses/mit/ | |
var SPI2 = E.compiledC(` | |
// int cmd(int,int) | |
// int cmds(int,int) | |
// int cmd4(int,int,int,int) | |
// void setpins(int,int,int,int) | |
// int enable(int,int) | |
// void disable() | |
// void blit_setup(int,int,int,int) | |
// int blt_pal(int,int,int) | |
//// int data(int,int) | |
//// void save() | |
//// void restore() | |
//// int fill_color(int,int) | |
// LCD bpp 16,12 (ST7789) and 8,6 (ST7301 in DK08) supported | |
#define LCD_BPP 6 | |
// with SHARED_SPIFLASH we need to enable SPI only iniside native code and disable it before return | |
// to allow espruino to execute from SPI flash on shared SPI pins | |
//#define SHARED_SPIFLASH | |
// also we may need to unselect flash chip CS pin as Espruino is in a middle of read command | |
//#define SPIFLASH_CS (1<<5) | |
//SPI0 0x40003000 | |
//SPI1 0x40004000 | |
//SPI2 0x40023000 | |
#define SPIBASE 0x40023000 | |
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 __code | |
// _code volatile uint32_t *SPI =(uint32_t*)SPIBASE; | |
// direct constant makes smaller/faster code | |
#define SPI ((volatile uint32_t*)SPIBASE) | |
//divide register offsets by sizeof(uint32_t) | |
#define REG(offset) (offset/4) | |
// SPI master documentation | |
// https://infocenter.nordicsemi.com/topic/com.nordic.infocenter.nrf52832.ps.v1.1/spi.html?cp=4_2_0_47 | |
// 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) | |
#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) | |
__code uint32_t pSCK= -1; | |
__code uint32_t pMOSI= -1; | |
__code uint32_t pMISO= -1; | |
__code uint32_t pCS= 0; | |
__code uint32_t pCD= 0; //command/data | |
void setpins(int sck,int mosi,int cs,int cd){ | |
pSCK=sck;pMOSI=mosi;pCS=1<<cs;pCD=1<<cd; | |
} | |
__code uint32_t savedintflags=0; | |
__code uint32_t savedmode=0; | |
void save(){ | |
savedintflags=SPI[INTENSET]; | |
savedmode=SPI[ENABLE]; | |
} | |
void restore(){ | |
SPI[ENABLE]=0; | |
SPI[INTENSET]=savedintflags; | |
SPI[ENABLE]=savedmode; | |
} | |
// pins need to be already preconfigured as gpio input/outputs | |
int setup(uint32_t speed,uint32_t mode){ | |
if (pSCK>=0 && (pMISO>=0||pMOSI>=0)){ | |
uint32_t flags=SPI[INTENSET]; | |
if (flags) SPI[INTENCLR]=flags; // clear all interrupt 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(){ | |
SPI[ENABLE]=0; | |
SPI[READY]=0; | |
uint32_t flags=SPI[INTENSET]; | |
if (flags) SPI[INTENCLR]=flags; // clear all interrupt flags | |
} | |
int enable(uint32_t speed,uint32_t mode){ | |
if (SPI[ENABLE]) return -1; | |
if (setup(speed,mode)){ | |
#ifndef SHARED_SPIFLASH | |
SPI[ENABLE]=7;//SPIM with DMA | |
SPI[TASKS_STOP]=1; | |
//isDMA=1; | |
#endif | |
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; | |
#ifdef SHARED_SPIFLASH | |
#ifdef SPIFLASH_CS | |
*OUTSET = SPIFLASH_CS; | |
#endif | |
SPI[ENABLE]=7;//SPIM with DMA | |
#endif | |
if(pCS>0) *OUTCLR = pCS; // CHIP SELECT | |
*OUTSET = pCD; // data | |
write_dma(buffer,len,0); | |
if(pCS>0) *OUTSET = pCS; // CHIP SELECT | |
#ifdef SHARED_SPIFLASH | |
SPI[ENABLE]=0;//disable SPI | |
#endif | |
return 0; | |
} | |
int cmd(uint8_t *buffer, int len){ | |
if (pCD==0) return -1; | |
#ifdef SHARED_SPIFLASH | |
#ifdef SPIFLASH_CS | |
*OUTSET = SPIFLASH_CS; | |
#endif | |
SPI[ENABLE]=7;//SPIM with DMA | |
#endif | |
*OUTCLR = pCD; // CMD | |
if(pCS>0) *OUTCLR = pCS; // CHIP SELECT | |
write_dma(buffer,1,0); | |
*OUTSET = pCD; // data | |
if (len>1) | |
write_dma(buffer+1,len-1,0); | |
if(pCS>0) *OUTSET = pCS; // CHIP SELECT | |
#ifdef SHARED_SPIFLASH | |
SPI[ENABLE]=0;//disable SPI | |
#endif | |
return 0; | |
} | |
int cmds(uint8_t *ptr,int bufflen){ | |
int cnt=0; | |
if (!ptr) return cnt; | |
uint8_t *endptr=ptr+bufflen; | |
uint8_t len; | |
while ((len=*ptr++)!=0){ | |
if ((ptr+len)>endptr) return -cnt;// break if we would go past buffer | |
if(cmd(ptr,len)) break; | |
ptr+=len;cnt++; | |
} | |
return cnt; | |
} | |
// send command with up to 3 parameters (espruino allows methods with up to 4 parameters) | |
int cmd4(int c0,int d1,int d2, int d3){ | |
int cnt=0; | |
uint8_t buff[4]; | |
if (c0>=0)buff[cnt++]=c0; else return 0; | |
if (d1>=0)buff[cnt++]=d1; | |
if (d2>=0)buff[cnt++]=d2; | |
if (d3>=0)buff[cnt++]=d3; | |
cmd(buff,cnt); | |
return cnt; | |
} | |
__code uint16_t running=0; | |
void wait_dma(){ | |
if (running) { | |
while (SPI[EVENTS_END] == 0); // wait for previous transfer | |
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; | |
} | |
__code uint16_t blit_bpp=0; | |
__code uint16_t blit_w=0; | |
__code uint16_t blit_h=0; | |
__code uint16_t blit_stride=0; | |
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; //*bpp/8; | |
} | |
#define LCHUNK 36 // divisible by 3 and 2 | |
#if LCD_BPP<=8 | |
//only 8 bit palette entry | |
typedef uint8_t palbuff_t; | |
#else | |
typedef uint16_t palbuff_t; | |
#endif | |
int blt_pal(uint8_t *buff,palbuff_t* palbuff,uint8_t xbitoff){ | |
uint8_t *pxbuff=buff; | |
uint8_t bpp=blit_bpp; | |
if (pxbuff==NULL || palbuff==NULL || bpp==0 || bpp>8) return -1; | |
uint8_t mask=(1<<bpp)-1; //pixel bitmask | |
uint8_t bpos=xbitoff; | |
uint16_t val=(*pxbuff++)|((*pxbuff++)<<8);val>>=bpos; // we prefetch 8-16 bits | |
uint16_t w=blit_w; | |
uint16_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; | |
#ifdef SHARED_SPIFLASH | |
#ifdef SPIFLASH_CS | |
*OUTSET = SPIFLASH_CS; | |
#endif | |
SPI[ENABLE]=7;//SPIM with DMA | |
#endif | |
if(pCS>0) *OUTCLR = pCS; // CHIP SELECT | |
do { | |
w=blit_w; | |
do { | |
#if LCD_BPP==12 | |
// pixel 1 | |
uint16_t px1=palbuff[val&mask]; // get color | |
val=val>>bpp;bpos+=bpp; | |
//pixel 2 | |
uint16_t px2=palbuff[val&mask]; // get color | |
val=val>>bpp;bpos+=bpp; | |
if(bpos>=8){bpos-=8;val=val|(*pxbuff++)<<(8-bpos);} //less than 8 bits, prefetch another byte | |
//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){bpos-=8;val=val|(*pxbuff++)<<(8-bpos);} //less than 8 bits, prefetch another byte | |
//put 16bit pixel into buffer | |
lbuff[lbufpos++]=px1>>8; | |
lbuff[lbufpos++]=px1&255; | |
w--; | |
#elif LCD_BPP==8 | |
// pixel 1 | |
// get color from palette or as direct value if no palette | |
uint8_t px1= (palbuff) ? palbuff[val&mask] : val&mask; | |
val=val>>bpp;bpos+=bpp; | |
if(bpos>=8){bpos-=8;val=val|(*pxbuff++)<<(8-bpos);} //less than 8 bits available, prefetch another byte | |
//put 8bit pixel into buffer | |
lbuff[lbufpos++]= px1<<2 ; //(bpp==6) ? px1<<2 : px1 ; // 6bit to 8bit | |
w--; | |
#elif LCD_BPP==6 | |
// send 4 packed 6bit pixels in 3 bytes | |
uint8_t px[4]; | |
for (int i=0;i<4;i++){ | |
px[i] = (palbuff) ? palbuff[val&mask] : val&mask; | |
val=val>>bpp;bpos+=bpp; | |
if(bpos>=8){bpos-=8;val=val|(*pxbuff++)<<(8-bpos);} //less than 8 bits available, prefetch another byte | |
} | |
//pack into 3 bytes | |
lbuff[lbufpos++]= px[0]<<2 | px[1]>>4; | |
lbuff[lbufpos++]= px[1]<<4 | px[2]>>2; | |
lbuff[lbufpos++]= px[2]<<6 | px[3]; | |
w-=4; | |
#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+=blit_stride; | |
pxbuff=buff;bpos=xbitoff; | |
val=(*pxbuff++)|(*pxbuff++)<<8;val>>=bpos;//val=(*pxbuff++)>>bpos; | |
h--; | |
} while(h>0); | |
// send the rest | |
if (lbufpos>0){ | |
write_dma(lbuff,lbufpos,0); | |
} else { | |
wait_dma(); | |
} | |
if(pCS>0) *OUTSET = pCS; // CHIP SELECT | |
#ifdef SHARED_SPIFLASH | |
SPI[ENABLE]=0;//disable SPI | |
#endif | |
return 0; | |
} | |
#if 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; | |
} | |
#if LCD_BPP==12 | |
int fill_color(uint32_t val,uint32_t len){ | |
uint8_t buff[12]={ // 92ms for 24, 97ms for 12 | |
// 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,12,len/8); | |
} | |
#elif LCD_BPP==16 | |
int fill_color(uint32_t val,uint32_t len){ | |
uint8_t buff[16]= { // 126ms for 16, 121ms for 32 bytes | |
// val>>8,val&0xff, val>>8,val&0xff, val>>8,val&0xff, val>>8,val&0xff, | |
// val>>8,val&0xff, val>>8,val&0xff, val>>8,val&0xff, val>>8,val&0xff, | |
val>>8,val&0xff, val>>8,val&0xff, val>>8,val&0xff, val>>8,val&0xff, | |
val>>8,val&0xff, val>>8,val&0xff, val>>8,val&0xff, val>>8,val&0xff | |
}; | |
return write_many_dma(buff,16,len/8); | |
} | |
#elif LCD_BPP==8 | |
int fill_color(uint32_t val,uint32_t len){ | |
uint8_t v=val&0xff; | |
uint8_t buff[16]= { // 126ms for 16, 121ms for 32 bytes | |
v, v, v, v, | |
v, v, v, v, | |
v, v, v, v, | |
v, v, v, v | |
}; | |
return write_many_dma(buff,16,len/16); | |
} | |
#endif | |
#endif | |
`); | |
*/ | |
///* | |
var SPI2 = (function(){ | |
var bin=atob("AAAAAAAAAAAAAAAAAAAAAAAAAAD///////////////8QtQNMfEQigGCAoYDjgBC92P///wdLe0QbiUOxBEoTaAAr/NAAIxNgA0p6RBOBcEcYMQJAxv///7L///8t6fBHkEYZTBlO//fl/xlK3/hkwAAjASUTYE/w/w5TYKlGI2AQMh9G/ykA6wMKwvgAoIu//zMxYMb4AOAAIYi//znM+ACQuPEADwbQKbkLS3tEHYEAIL3o8IfU+ACguvEAD/rQJ2AAKd7R8+cYMQJASDUCQDQ1AkAQMAJAUP///y3p8E+TRldKnbB6RAKRkvgAoAZGACgA8J6AACkA8JuACvH/MwcrAPKWgAEjA/oK8wE727IDk4McAJMEeEN4svgEgETqAyTTaET6C/SksguxQkoTYERLe0QEkwqrBpNDS0/wAAl7RElGE6gHkwSbW4gBkwmrXUYFkwAiA5sCnyNAVUT7XAWf7bIHLdNVRPoK9FHYpLIBMgQq79Gd+CXAnfgkIE/qLBND6oIDnfgmIENUQxgfRpMQQ+oME3twnfgnMEPqghIBmwHxAg4EOwMxm7IjKQD4DiABkwndASL/91D/2fEBCRO/BphJRhOoACEBmwArwdEHm9uIHkSzHACTNHhzeAjx/zhE6gMkRPoL9B/6iPiksrjxAA+o0cmxQkb/9y//E0t7RNhoELENSxhgACAdsL3o8I8Anwg9F/gBOwCX7bLF8QgMA/oM8xxDpLKh5//3Av/l50/w/zDp5wwFAFAIBQBQFv///8r+//+8/v///P3//xVKekRwtQ5GEWkFRuGxEEsZYNJoArEaYAAiASEoRv/39f4OSwtMe0QBLhppImAE3QAicR5oHP/36f4JS3tE2GgIsSBgACBwvU/w/zD75wC/DAUAUAgFAFCq/f//hv3//3D9//8TtQAoHtsAKaa/jfgFEAIkASQAKqS/AqkJGY34BACkvwE0AfgELAAror8CqhIZATQhRgGoqL8C+AQ8//ev/yBGArAQvQAk+udwtQVGiLFGGAAkKEYQ+AEbGbFFGLVCAtlkQiBGcL3/95n/ACj50QE07+cERvXnAAAPSjC1FGjEuQ5LG2gLsQ5MI2ARSw1Me0QABl1pJWCdaWVg3GkKS0kAHGBYYVlkByMTYAhLASAYYDC9T/D/MPvnADUCQAQzAkAIMwJACDUCQBA1AkAUMAJAuvz//wVKACMTYKL1fnITYANLG2gLscL4ADJwRwA1AkAEMwJAELUGTHxExOkFAQEhAfoC8gH6A/PiYCNhEL0Av1D8//8="); | |
return { | |
cmd:E.nativeCall(593, "int(int,int)", bin), | |
cmds:E.nativeCall(765, "int(int,int)", bin), | |
cmd4:E.nativeCall(693, "int(int,int,int,int)", bin), | |
setpins:E.nativeCall(937, "void(int,int,int,int)", bin), | |
enable:E.nativeCall(813, "int(int,int)", bin), | |
disable:E.nativeCall(905, "void()", bin), | |
blit_setup:E.nativeCall(33, "void(int,int,int,int)", bin), | |
blt_pal:E.nativeCall(221, "int(int,int,int)", bin), | |
}; | |
})(); | |
// this produces code string that can replace bin declaration with heatshrink compressed variant of bin to | |
// save source code size however it looks like it does not save much | |
// shrink:function(){return `var bin=E.toString(require("heatshrink").decompress(atob("${btoa(require("heatshrink").compress(bin))}")))`;} | |
//*/ | |
//DK08 LCD pins | |
CS=D18;DC=D19;RST=D15;BL=D13; | |
CLK=D17;MOSI=D16;PWR=D11; | |
//fontchip SPI pins | |
FCS=D27;//FMOSI=D30;FMISO=D31;FCLK=D29; | |
var fc=new SPI();fc.setup({sck:D29,miso:D31,mosi:D30,mode:0}); | |
//fc.send([0xab],FCS);//wake fontchip from deep sleep | |
//fc.send([0x90,0,0,1,0,0],FCS) // get flash id | |
//fc.send([0x9f,0,0,0],FCS); //get flash id | |
fc.send([0xb9],FCS); // put to deeep sleep | |
//HR sensor over i2c | |
//HPWR=D14;HSCL=D22;HSDA=D20; | |
var hr=new I2C();hr.setup({scl:D20,sda:D22}); | |
function hrRead(reg,len){hr.writeTo(0x24,reg);return hr.readFrom(0x24,len);} | |
function hrWrite(reg,data){hr.writeTo(0x24,reg,data);} | |
//BMA253 SPI accelerometer | |
//AI1=D4;AI2=D3;ACS=D2;AMOSI=D30;AMISO=D31;ACLK=D22;APWR=D7; | |
// | |
function LCD_Init_Off(){ | |
// LCD pins init + reset/turn off | |
BL.reset(); | |
RST.reset(); | |
CLK.write(0);MOSI.write(0);CS.write(0);DC.write(0); | |
PWR.set(); | |
} | |
function LCD_Init(){ | |
// pins init reset done + power up | |
CS.set();CLK.set();MOSI.set();DC.set(); | |
RST.set(); | |
PWR.reset(); | |
} | |
E.kickWatchdog(); | |
LCD_Init_Off(); | |
//SPI2.save(); | |
SPI2.setpins(CLK,MOSI,CS,DC); | |
//SPI2.disable(); | |
function toFlatString(arr){ | |
var b=E.toString(arr);if (b) return b; | |
print("toFlatString() fail&retry!");E.defrag();b=E.toString(arr);if (b) return b; | |
print("fail&retry again!");E.defrag();b=E.toString(arr);if (b) return b; | |
print("failed!"); return b; | |
} | |
function lcd_cmd(a){ | |
var l=a.length; | |
if (!l)return SPI2.cmd4(a,-1,-1,-1); | |
if (l==2)return SPI2.cmd4(a[0],a[1],-1,-1); | |
if (l==3)return SPI2.cmd4(a[0],a[1],a[2],-1); | |
if (l==4)return SPI2.cmd4(a[0],a[1],a[2],a[3]); | |
if (l==1)return SPI2.cmd4(a[0],-1,-1,-1); | |
var b=toFlatString(a); | |
SPI2.cmd(E.getAddressOf(b,true),b.length); | |
} | |
function lcd_cmds(arr){ | |
var b=toFlatString(arr); | |
var c=SPI2.cmds(E.getAddressOf(b,true),b.length); | |
if (c<0)print('lcd_cmds: buffer mismatch, cnt='+c); | |
return c; | |
} | |
function ST7301_INIT(){ | |
return lcd_cmds( | |
//new Uint8Array( | |
[ | |
2, 0xeb, 0x2,// | |
2, 0xd7, 0x68,// | |
2, 0xd1, 0x1, // | |
3, 0xe8, 0x55, 0x06,// | |
2, 0xc0, 0xe5,// | |
3, 0xb2, 0x0, 0, //1,0x2,// refresh rates in hp (25,50Hz) lp (1/4,1/2,1,2,4,8Hz) modes | |
11, 0xb4, 0xc5,0x77,0xf1,0xff,0xff,0x4f,0xf1,0xff,0xff,0x4f, | |
2, 0xb7, 0, | |
2, 0xb0, 0x59, | |
1, 0x11, // sleep out | |
0] | |
//) | |
); | |
} | |
function ST7301_INIT_NEXT(){ | |
return lcd_cmds( | |
//new Uint8Array( | |
[ | |
3, 0xc7, 0x80, 0xe9,// framerate 25/50Hz | |
2, 0xd6, 0x1,// | |
2, 0xcb, 0x15,// | |
2, 0x36, 0x48,// | |
2, 0x3a, 0x11,// 10= 4px=4bytes (LCD_BPP=8), 11 4px=3bytes (LCD_BPP=6) | |
5, 0x72, 0x20, 0x4, 0x80, 0xfa,// de-stress | |
3, 0xb5, 2, 0, | |
2, 0xb9, 0x23, | |
2, 0xb8, 0x8, | |
// 3, 0x2a, 8, 0x33, | |
// 3, 0x2b, 0, 0xaf, | |
// 2, 0x35, 0,// TE on | |
1, 0x34, // TE off | |
2, 0xd0, 0x1f,// | |
1, 0x38, | |
2, 0xd8, 0x1,// | |
2, 0xc4, 0xb1,// | |
2, 0xd8, 0x3,// | |
2, 0xe3, 0x2,// | |
//1, 0x3c, | |
// | |
0] | |
//) | |
); | |
} | |
function delayms(ms){ | |
digitalPulse(DC,0,ms);digitalPulse(DC,0,0); | |
} | |
var mode; | |
function LCD_FastMode(on){ | |
if (mode===on) return; | |
if (on){ | |
lcd_cmd(0x38); // high power mode | |
delayms(125); | |
lcd_cmd([0xcb,0x15]); // VCOMH voltage to 4.05V | |
lcd_cmd([0xd6,0x1]); // change voltage source to vsh/vsl 1 | |
delayms(40); | |
} else { | |
//return; //disable for now | |
lcd_cmd([0xcb,0x1f]); //raise VCOMH voltage to 4.55V for high power mode, why when we are switching to low power mode?) | |
lcd_cmd([0xd6,0x3]); // change voltage source to vsh/vsl 3 | |
delayms(40); | |
lcd_cmd(0x39); // low power mode on | |
} | |
mode=on; | |
} | |
/* not needed | |
var lcd_on=0; | |
function LCD_Off(){ | |
if (lcd_on){ | |
lcd_cmd([0x38); | |
// delay 0xfa - 250ms | |
} | |
lcd_cmd([0xd6,0xd0]); | |
lcd_cmd([0xbd,1]); | |
lcd_cmd([0x75,1]); | |
lcd_cmd(0x28); | |
lcd_cmd(0x10); | |
//delay 100ms | |
lcd_on=0; | |
} | |
function LCD_SleepIn(){ | |
lcd_cmd(0x29); | |
lcd_cmd(0x10); | |
} | |
function LCD_AllDown(){ | |
lcd_cmd(0x28); | |
LCD_Init_Off(); | |
} | |
*/ | |
E.kickWatchdog(); | |
LCD_Init(); | |
SPI2.enable(0x80,0); //8MBit, mode 0 | |
//digitalPulse(RST,0,10); | |
//delayms(10); | |
// http://forum.espruino.com/conversations/316409/ | |
// size of <23 bytes Uint8Array does not create flat string | |
// we need flat arrays to pass to native InlineC code | |
function toFlatBuffer(a){return E.toArrayBuffer(toFlatString(a));} | |
var bpp=4; | |
var g=Graphics.createArrayBuffer(176,176,bpp); | |
var pal; | |
switch(bpp){ | |
case 2: pal= new Uint8Array(toFlatBuffer([0x00,0xc0,0x30,0x0c]));break; // white won't fit | |
// case 1: pal= new Uint8Array([0x00,0xff]);break; | |
case 1: | |
// same as 16color below, use for dynamic colors | |
pal= new Uint8Array(toFlatBuffer( | |
[0,0x2,0x8,0xa,0x20,0x22,0x24,0x2a,0x15,0x17,0x1d,0x1f,0x3d,0x37,0x3d,0x3f] | |
)); | |
g.sc=g.setColor; | |
c1=pal[1]; //save color 1 | |
g.setColor=function(c){ //change color 1 dynamically | |
c=Math.floor(c); | |
if (c > 1) { | |
pal[1]=pal[c]; g.sc(1); | |
} else if (c==1) { | |
pal[1]=c1; g.sc(1); | |
} else g.sc(c); | |
}; break; | |
case 4: pal= | |
// CGA | |
new Uint8Array(toFlatBuffer([ | |
// function RGB444to222(r,g,b){return(((r>>2)<<6)|((g>>2)<<4)|((b>>2)<<2)).toString(16);} | |
// CGA palette 6bit RGB222 | |
0,0x2,0x8,0xa,0x20,0x22,0x24,0x2a,0x15,0x17,0x1d,0x1f,0x3d,0x37,0x3d,0x3f | |
// CGA palette 12bit RGB444 | |
// 0x000,0x00a,0x0a0,0x0aa,0xa00,0xa0a,0xa50,0xaaa, | |
// 0x555,0x55f,0x5f5,0x5ff,0xf55,0xf5f,0xff5,0xfff | |
//16bit RGB565 | |
// 0x0000,0x00a8,0x0540,0x0555,0xa800,0xa815,0xaaa0,0xad55, | |
// 0x52aa,0x52bf,0x57ea,0x57ff,0xfaaa,0xfabf,0xffea,0xffff | |
]));break; | |
case 6: | |
pal = new Uint8Array(64); | |
for(var i=0;i<64;i++) pal[i]=i<<2; | |
} | |
// preallocate setwindow command buffer for flip | |
g.winCmd=toFlatBuffer([ | |
3, 0x2a, 0, 0, | |
3, 0x2b, 0, 0, | |
1, 0x2c, | |
0 ]); | |
// precompute addresses for flip | |
g.winA=E.getAddressOf(g.winCmd,true); | |
g.palA=E.getAddressOf(pal.buffer,true); // pallete address | |
g.buffA=E.getAddressOf(g.buffer,true); // framebuffer address | |
g.stride=g.getWidth()*bpp/8; | |
g.flip=function(){ | |
var r=g.getModified(true); | |
//print(r); | |
if (r === undefined) return; | |
var x1=r.x1&0xfc;var x2=(r.x2+4)&0xfc; //align to 4 pixels | |
var xw=(x2-x1); | |
var yw=(r.y2-r.y1+1); | |
if (xw<1||yw<1) {print("empty rect ",xw,yw);return;} | |
var c=g.winCmd; | |
c[2]=8+(x1>>2);c[3]=8+(x2>>2)-1; //0x2a params | |
c[6]=r.y1;c[7]=r.y2; // 0x2b params | |
/*lcd_cmds([ | |
3, 0x2a, 8+(x1>>2), 8+(x2>>2)-1, | |
3, 0x2b, r.y1, r.y2, | |
1, 0x2c, | |
0 ]);*/ | |
SPI2.blit_setup(xw,yw,bpp,g.stride); | |
var xbits=x1*bpp; | |
var bitoff=xbits%8; | |
var addr=g.buffA+(xbits-bitoff)/8+r.y1*g.stride; // address of upper left corner | |
//VIB.set();//debug | |
SPI2.cmds(g.winA,c.length); | |
SPI2.blt_pal(addr,g.palA,bitoff); | |
//VIB.reset();//debug | |
}; | |
g.bl=function(bl){ | |
if (bl>=1) BL.set(); | |
else if (bl<=0) BL.reset(); | |
else analogWrite(BL,bl); | |
}; | |
var VIB=D6; | |
function vibon(vib){ | |
if(vib.i>=1)VIB.set();else analogWrite(VIB,vib.i); | |
setTimeout(viboff,vib.on,vib); | |
} | |
function viboff(vib){ | |
VIB.reset(); | |
if (vib.c>1){vib.c--;setTimeout(vibon,vib.off,vib);} | |
} | |
vibrate=function(intensity,count,onms,offms){ | |
vibon({i:intensity,c:count,on:onms,off:offms}); | |
}; | |
var CHPOW=D24; // power attached | |
var CHDONE=D23; //charging done | |
CHDONE.mode("input_pullup"); | |
function battState(){ | |
if (!CHPOW.read()) return 0; | |
return CHDONE.read()?2:1; | |
} | |
function battVolts(){ | |
return 4.20/0.29*analogRead(D5); | |
} | |
function battLevel(v){ | |
var l=3.5,h=4.19; | |
v=v?v:battVolts(); | |
if(v>=h)return 100; | |
if(v<=l)return 0; | |
return 100*(v-l)/(h-l); | |
} | |
function battInfo(v){v=v?v:battVolts();return `${battLevel(v)|0}% ${v.toFixed(2)}V`;} | |
function randomLines(){ | |
LCD_FastMode(true); | |
g.clear(); | |
var cols=(bpp==1)?14:(1<<bpp)-1,w=g.getWidth(),h=g.getHeight(),r=Math.random; | |
return setInterval(function(){ | |
g.setColor(1+r()*cols); | |
g.drawLine(r()*w,r()*h,r()*w,r()*h); | |
g.flip(); | |
},30); | |
} | |
function randomShapes(){ | |
LCD_FastMode(true); | |
g.clear(); | |
var cols=(bpp==1)?14:(1<<bpp)-1,w=g.getWidth()-10,h=g.getHeight()-10,r=Math.random; | |
return setInterval(function(){ | |
g.setBgColor(0); | |
g.setColor(1+r()*cols); | |
var x1=r()*w;x2=10+r()*w; | |
var y1=r()*h;y2=10+r()*h; | |
if (bpp==1 && ((x1&31)==1)) g.clear(); // for bpp==1 clear sometimes so we can see ellipses again | |
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(); | |
},30); | |
} | |
// DK08 clock font | |
var fname="36x70"; | |
if (!require("Storage").read("fnt"+fname+".bin")){ (function(){ | |
E.kickWatchdog(); | |
var b=[]; | |
var push=function(a,s){ | |
a.push(require("heatshrink").decompress(atob(s))); | |
}; | |
push(b,"/H/AAsH/gIGh/+BA0fA43/n4I+j5qGnwI/BGjF/BA/+BA0f/gIGh/4BA0HA="); | |
push(b,"AH0YBA8cBA8eBA8fBDP/AA0/BH3+BA/8BA/4BA7Y/AFY"); | |
push(b,"jADC/H/AAMHjgIC/gICh8eBAX+BAUfj4ICA4X/n4I/BAU/AYU+BH4I0QQgI/BAX+BARUDj38BAUPBAUO/AICg4ICgwA="); | |
push(b,"jADCn4DCg0cBA0OjwIGj0fBA0+BH4I/BHn/AA0/BH3+BA0f/gIGh/4BA0HA="); | |
push(b,"/H/AAM/BAf8BA/+BA4HCBH4IEAAYI/BHKGDRQgI+/wIH/gIH/AIH"); | |
push(b,"/H/AAM/A4UG/gIGh3+BA0eA4QIEnwI+j4ECBH4I9RQgI+jwIC/wICj8cBAX8BAUPjAIC/AICg4A="); | |
push(b,"/H/AAsH/gIGh/+BA0fA43/n4I+j5mCn4DCnwI/BHCGIBHUeBAX+BAUfjgIC/gICh8YBAX4BAUHA="); | |
push(b,"ABEYBA8cBA8eBA8fBH4I/BHf/AA0/BH3+BA/8BA/4BA4"); | |
push(b,"/H//9/4ADB/8H/gEC8ADCh/+AgXxAYUfAYQIEn4ID/YIHAAYItj5mCn4DCnwI/BGiz1BBj7E/wEC+IDCj/8AgXgAYUP/ADBv/ABAUHA="); | |
push(b,"/H/AAMHA4UG/gICh4ICh3+BAUfBAUeA4X/n4ICnwI+JgYI/BHKGDRQgI+/wIGj/8BA0P/AIGg4A="); | |
push(b,"ACc4AYUHBAd8AQOAh4ID/wCB4EfBAf/gMA8E/BBgaIFhA+IAB4A="); | |
var fg=Graphics.createArrayBuffer(72,36,1); // one font letter | |
fg.setRotation(3,1); | |
var dgw=36+4; // 36 + 4 pixel space | |
var fnt=Graphics.createArrayBuffer(70,dgw*11,1,{msb:true}); // whole font | |
fnt.setRotation(3,1); | |
var w=new Uint8Array([dgw,dgw,dgw,dgw,dgw,dgw,dgw,dgw,dgw,dgw,12+2]); // widths, colon is thinner | |
E.kickWatchdog(); | |
for (x=0,i=0;i<11;i++){fg.buffer=b[i];fnt.drawImage(fg.asImage(),x,0);x+=w[i];} | |
var s=require("Storage"); | |
E.kickWatchdog(); | |
s.write("fnt"+fname+".bin",fnt.buffer); | |
s.write("fnt"+fname+".wdt",w.buffer); | |
})(); // use anonymous function to free all memory inside | |
} | |
function setClockFont(g,name){ | |
var s=require("Storage"); | |
g.setFontCustom(s.read("fnt"+name+".bin"),0x30,s.read("fnt"+name+".wdt"),70); | |
} | |
var lastmin=-1; | |
var volts; | |
function drawClock(){ | |
var d=Date(); | |
volts= volts ? (volts+battVolts())/2:battVolts(); // average until shown | |
if (d.getMinutes()==lastmin) return; | |
d=d.toString().split(' '); | |
var min=d[4].substr(3,2); | |
var sec=d[4].substr(-2); | |
var tm=d[4].substring(0,5); | |
var hr=d[4].substr(0,2); | |
lastmin=min; | |
g.clear(); | |
var w=g.getWidth(); | |
g.setFont("8x16",1); | |
g.setColor(15); | |
var batt=battInfo(volts);volts=0;// clear average | |
g.drawString(batt,w-g.stringWidth(batt)-2,0); | |
//var tm=hr+" "+min; | |
/* | |
g.drawString(hr,40-g.stringWidth(hr)/2,10); | |
g.drawString(min,40-g.stringWidth(min)/2,80); | |
*/ | |
//g.setFontVector(62); | |
setClockFont(g,fname);g.setColor(16); // for some reason custom font needs color+1, bug? | |
//g.setFontCopasetic40x58Numeric(); | |
//g.drawString(hr,w/2-g.stringWidth(hr)-5,50); | |
//g.drawString(min,w/2+5,50); | |
g.drawString(tm,4+(w-g.stringWidth(tm))/2,48); | |
//g.setColor(8+4); | |
//g.setFontVector(26); | |
//if (sec&1)g.drawString("o o",40-g.stringWidth("o o")/2,60); | |
//if (sec&1)g.drawString(":",40-g.stringWidth(":")/2,42); | |
//if (sec&1)g.drawString(". .",40-g.stringWidth(". .")/2,44); | |
g.setFontVector(28); | |
g.setColor(8+3); | |
var dt=d[0]+" "+d[1]+" "+d[2];//+" "+d[3]; | |
g.drawString(dt,(w-g.stringWidth(dt))/2,130); | |
g.flip(); | |
} | |
function clock(){ | |
lastmin=-1; | |
//LCD_FastMode(true); | |
drawClock(); | |
LCD_FastMode(false); | |
return setInterval(function(){ | |
//LCD_FastMode(true); | |
drawClock(); | |
//LCD_FastMode(false); | |
},1000); | |
} | |
// cube from https://www.espruino.com/Pixl.js+Cube+Badge | |
var rx = 0, ry = 0, cc = 1; | |
// Draw the cube at rotation rx and ry | |
function drawCube(xx,yy,zz) { | |
// precalculate sin&cos for rotations | |
var rcx=Math.cos(rx), rsx=Math.sin(rx); | |
var rcy=Math.cos(ry), rsy=Math.sin(ry); | |
// Project 3D into 2D | |
function p(x,y,z) { | |
var t; | |
t = x*rcy + z*rsy; | |
z = z*rcy - x*rsy; | |
x=t; | |
t = y*rcx + z*rsx; | |
z = z*rcx - y*rsx; | |
y=t; | |
z += 4; | |
return [xx + zz*x/z, yy + yy*y/z]; | |
} | |
var a,b; | |
// -z | |
a = p(-1,-1,-1); b = p(1,-1,-1); | |
g.drawLine(a[0],a[1],b[0],b[1]); | |
a = p(1,1,-1); | |
g.drawLine(a[0],a[1],b[0],b[1]); | |
b = p(-1,1,-1); | |
g.drawLine(a[0],a[1],b[0],b[1]); | |
a = p(-1,-1,-1); | |
g.drawLine(a[0],a[1],b[0],b[1]); | |
// z | |
a = p(-1,-1,1); b = p(1,-1,1); | |
g.drawLine(a[0],a[1],b[0],b[1]); | |
a = p(1,1,1); | |
g.drawLine(a[0],a[1],b[0],b[1]); | |
b = p(-1,1,1); | |
g.drawLine(a[0],a[1],b[0],b[1]); | |
a = p(-1,-1,1); | |
g.drawLine(a[0],a[1],b[0],b[1]); | |
// edges | |
a = p(-1,-1,-1); b = p(-1,-1,1); | |
g.drawLine(a[0],a[1],b[0],b[1]); | |
a = p(1,-1,-1); b = p(1,-1,1); | |
g.drawLine(a[0],a[1],b[0],b[1]); | |
a = p(1,1,-1); b = p(1,1,1); | |
g.drawLine(a[0],a[1],b[0],b[1]); | |
a = p(-1,1,-1); b = p(-1,1,1); | |
g.drawLine(a[0],a[1],b[0],b[1]); | |
} | |
function stepCube() { | |
rx += 0.1; | |
ry += 0.1; | |
g.setColor(0);g.fillRect(40,40,120,120);g.setColor(1+cc);cc=(cc+1)%15; | |
drawCube(80,80,80); | |
g.flip(); | |
} | |
require("Font8x16").add(Graphics); | |
function info(){ | |
g.clear(); | |
g.setFont("8x16",1/*2*/);g.setColor(10); | |
g.drawString("Espruino "+process.version,4,6); | |
if (bpp==1) g.flip(); | |
g.setFont("6x8",1);g.setColor(14); | |
g.drawString("ST7301 6bit RGB222 mode",4,22); | |
if (bpp==1) g.flip(); | |
for (var c=0;c<8;c++){ | |
g.setColor(c+8);g.fillRect(8+20*c,130,28+20*c,146); | |
if (bpp==1) g.flip(); | |
} | |
for ( c=0;c<8;c++) {g.setColor(c);g.fillRect(8+20*c,148,28+20*c,164); | |
if (bpp==1) g.flip(); | |
} | |
g.flip(); | |
LCD_FastMode(true); | |
return setInterval(function(){ | |
stepCube(); | |
},20); | |
} | |
var dayhours=Uint8Array([7,19]); // hours when backlight is not needed | |
function isDark(){ | |
var h=Date().getHours(); | |
return h<dayhours[0] || h>dayhours[1]; | |
} | |
function drawConn(){ | |
g.setFont8x16();g.clear(); | |
if (NRF.connected){ | |
if (!NRF.connection.RSSI) NRF.enableRSSI(); | |
g.drawString("CONN: "+NRF.connection.addr.substr(0,18),4,6); | |
g.setFontVector(19); | |
g.drawString("RSSI: "+NRF.connection.RSSI,12,150); | |
} else { | |
var r; | |
switch (NRF.lastReason){ | |
case 0x13: r="USER TERMINATED";break; | |
case 8: r="TIMEOUT";break; | |
case undefined:r="unknown";break; | |
default: r="0x"+NRF.lastReason.toString(16); | |
} | |
g.drawString("No connection"+(r? "\nReason: "+r:""),4,6); | |
} | |
g.flip(); | |
if (!blt && isDark()) g.bl(0.1); | |
} | |
function conn(){ | |
drawConn(); | |
return setInterval(function(){ | |
drawConn(); | |
},1000); | |
} | |
var screens=[clock,conn,info,randomShapes,randomLines]; | |
var currscr=0; | |
var currint=0; | |
var blt=0; | |
var initdone=false; | |
setTimeout(()=>{ | |
ST7301_INIT(); | |
setTimeout(()=>{ | |
ST7301_INIT_NEXT(); | |
delayms(10); | |
lcd_cmd(0x29); | |
delayms(20); | |
lcd_cmd(0x39); | |
LCD_FastMode(true); | |
//LCD_Clear(); | |
//LCD_FastMode(false); | |
currint=clock(); | |
initdone=true; | |
// analogWrite(BL,0.25); | |
// LCD_FastMode(false); | |
},250);//200 | |
},250);//220 | |
setWatch(function(s){ | |
if (!initdone) return; | |
var blon=isDark(); | |
if (blt) { clearTimeout(blt);blt=0;} else if (blon) g.bl(0.16); // backlight on 20% | |
currscr++;if (currscr>=screens.length) currscr=0; | |
if (currint>0) clearInterval(currint); | |
currint=screens[currscr](); | |
if (blon) | |
blt=setTimeout(function(){ | |
g.bl(0); | |
blt=0; | |
},5000); //backlight off after 5 seconds | |
},BTN1,{ repeat:true, debounce:false, edge:'rising' } | |
); | |
// for unknown devices allow connection only when holding button, then remember device in whitelist | |
NRF.whitelist=[]; | |
NRF.enableRSSI=function(){ | |
if (NRF.connected && !NRF.connection.RSSI) | |
NRF.setRSSIHandler((rssi)=>{NRF.connection.RSSI=rssi;}); //may drain battery | |
}; | |
NRF.disableRSSI=function(){ | |
if (NRF.connection){ | |
NRF.setRSSIHandler(); | |
delete NRF.connection.RSSI; | |
} | |
}; | |
NRF.on('connect',function(addr) { | |
if (false &&/*comment out false to use whitelist*/ !NRF.whitelist.includes(addr)){ | |
if (BTN1.read()){ // add to whitelist when button is held while connecting | |
NRF.whitelist.push(addr); | |
vibrate(1,1,100,0); | |
} else | |
NRF.disconnect(); | |
} | |
NRF.connection = { addr: addr }; | |
NRF.connected=true; | |
NRF.setTxPower(4); | |
}); | |
NRF.on('disconnect',function(reason) { | |
NRF.connected=false; | |
NRF.connection = {}; | |
NRF.lastReason=reason; // google BLE hci status codes | |
NRF.disableRSSI(); | |
NRF.setTxPower(0); | |
}); | |
function BMA2x2(){ | |
var acc; | |
function readreg(r){ | |
return acc.send([0x80|r,0x00],D2)[1]; | |
} | |
function writereg(r,v){ | |
acc.send([0x7f & r,v],D2); | |
} | |
function setbit(r,b){ | |
var v = readreg(r); | |
writereg(r,v | 1<<b); | |
} | |
function resetbit(r,b){ | |
var v = readreg(r); | |
writereg(r,v & ~(1<<b)); | |
} | |
function lowPowerMode(b){ | |
if (b) | |
setbit(0x11,6); | |
else | |
resetbit(0x11,6); | |
} | |
function initAll(spi){ | |
if (spi){ | |
acc=spi; | |
} else { | |
acc=new SPI(); | |
acc.setup({sck:D29,miso:D31,mosi:D30,mode:0}); | |
} | |
D2.set(); // CS | |
D3.mode("input_pulldown"); // INT | |
D4.mode("input_pulldown"); // INT | |
D7.set(); // power on | |
// D2.reset(); | |
// D7.reset(); | |
// setTimeout(()=>{ | |
// D7.set(); | |
// D2.set(); | |
setTimeout(()=>{ | |
writereg(0x21,0x0E); //latch interrupt for 50ms | |
setbit(0x16,5); // single tap enable | |
setbit(0x19,5); // map it to INT1 | |
lowPowerMode(true); | |
},100); | |
// },100); | |
} | |
function readXYZ(){ | |
function conv(i){ | |
return (i & 0x7F)-(i & 0x80); | |
} | |
return { | |
x:conv(readreg(3)), | |
y:conv(readreg(5)), | |
z:conv(readreg(7)) | |
}; | |
} | |
/* | |
acc.writeReg(0x2b,4) //tap sensitivity (3<<6)|4 | |
// values are 4 is face tap, 2 side tap, 1 bottom or top side tap | |
setWatch(()=>{ | |
var rv = acc.readReg(0x0b); | |
var v = (rv&0x7f)>>4; | |
v = rv&0x80?-v:v; | |
// DK08.emit("tap",v); | |
print("tap",v); | |
},D4,{ repeat:true, debounce:false, edge:'rising' }); | |
*/ | |
return { | |
init:initAll, read:readXYZ, lowPower:lowPowerMode, | |
readReg:readreg,writeReg:writereg,setBit:setbit,resetBit:resetbit, | |
}; | |
} | |
/* | |
var ACCEL = ACC223(); | |
ACCEL.init(); | |
DK08.on("tap",(v)=>{ | |
console.log("Tap: "+v); | |
}); | |
*/ | |
// font chip to Espruino font conversion | |
// for font offsets and sizes see https://github.com/RichardBsolut/GT24L24A2Y | |
/* | |
function createFont(off,bs,w,h,c,isprop){ | |
var f=require("Flash"); | |
var fg=Graphics.createArrayBuffer(w,h,1,{vertical_byte:true}); // one letter in fontchip layout | |
var fnt=Graphics.createArrayBuffer(h,w*c,1,{msb:true}); // whole font in Espruino layout | |
fnt.setRotation(3,1); // needed to match espruino font layout | |
off+=0x60000000;//spi flash mapped here | |
var len=w*h/8; | |
var x=0,i=0; | |
var lw=w; | |
var widths=isprop ? Uint8Array(c) : w; | |
while(i<c){ | |
fg.buffer=f.read(len,off);off+=bs; | |
if (isprop){ | |
lw=1+fg.buffer[0]; | |
widths[i]=lw; | |
fg.buffer[0]=0; // real width of letter if proportional, clear | |
} | |
fnt.drawImage(fg.asImage(),x,0); | |
x+=lw; | |
i++; | |
E.kickWatchdog(); | |
} | |
const ret=fnt.buffer; | |
fg=null;fnt=null; | |
if (isprop){ | |
return { font: ret, width: widths, height:h}; | |
} | |
return { font: ret, width: w, height:h}; | |
} | |
function saveFont(name,font){ | |
var s=require("Storage"); | |
if (typeof(font.width)=="number"){ | |
// not proportional | |
s.write(name+".bin",fnt.font); | |
} else { | |
flen=E.sum(fnt.width)*8; | |
s.write(name+".wdt",fnt.width); | |
s.write(name+".bin",new Uint8Array(fnt.font,0,flen)); | |
} | |
} | |
*/ | |
/* | |
var fnt=createFont(0x199e0e,322,40,64,14,true); | |
//E.toString needs lot of unfragmented memory here, better write to storage and load from there | |
//g.setFontCustom(E.toString(fnt.font),0x30,E.toString(fnt.width),64); | |
flen=E.sum(fnt.width)*8; | |
var s=require("Storage"); | |
s.write("FNT-64x40.wdt",fnt.width) | |
s.write("FNT-64x40.bin",new Uint8Array(fnt.font,0,flen)) | |
g.setFontCustom(s.read("FNT-64x40.bin"),0x30,s.read("FNT-64x40.wdt"),64) | |
g.drawString("01234"); | |
g.flip(); | |
*/ |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment