Skip to content

Instantly share code, notes, and snippets.

@fanoush
Last active June 16, 2021 22:12
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save fanoush/7f12afc474be509a37f13aa558e5f6dd to your computer and use it in GitHub Desktop.
Save fanoush/7f12afc474be509a37f13aa558e5f6dd to your computer and use it in GitHub Desktop.
E.kickWatchdog();
function KickWd(){
if( (typeof(BTN1)=='undefined')||(!BTN1.read()) ) E.kickWatchdog();
}
var wdint=setInterval(KickWd,2000);
E.enableWatchdog(15, false);
// set name to F10
// NRF.setAdvertising({},{name:"F10 "+NRF.getAddress().split(':').slice(-2).join('')});
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+bsM3pARJQSnpEBkaS+ACQACgA8JGAACkA8I6ACfH/MwcrAPKJgAEjA/oJ8wE727IDkwR4Q3iXiETqAyQCmxxB02gA8QILpLILsT1KE2BP6kkD27IEkz1Le0QRqAWTCKvN6QYwT/AACEFGBZsCnbP4AqADmwGaI0BE+gn0MvgTwAObI0BE+gn0MvgTIASbHUTtsgctQNiksk/qLBNDVBMSAfECDkPqDBxDGAMxqvECCiMpg/gBwB/6ivoA+A4gCd0BIv/3W//Y8QEIC78HmAaYQUYAIbrxAA/L0R1Le0QBP9uIHkS/snN4NHhE6gMkApscQQbxAguksgAvttHJsTpG//c8/xNLe0TYaBCxDUsYYAAgG7C96PCP3kYIPR74ATvtssXxCAsD+gvzHEOksvNGsuf/9w//5edP8P8w6ecAvwwFAFAIBQBQFP///8T+//9A/v//Fv7//xVKekRwtQ5GEWkFRuGxEEsZYNJoArEaYAAiASEoRv/3Af8OSwtMe0QBLhppImAE3QAicR5oHP/39f4JS3tE2GgIsSBgACBwvU/w/zD75wC/DAUAUAgFAFDC/f//nv3//4j9//8TtQAoHtsAKaa/jfgFEAIkASQAKqS/AqkJGY34BACkvwE0AfgELAAror8CqhIZATQhRgGoqL8C+AQ8//ev/yBGArAQvQAk+udwtQVGiLFGGAAkKEYQ+AEbGbFFGLVCAtlkQiBGcL3/95n/ACj50QE07+cERvXnAAA4tQ9Le0QaaZKxiLGBsdtoC7EJShNgC00ITH1EACIraSNg//eR/uhoCLEgYAAgOL1P8P8w++cAvwwFAFAIBQBQ5Pz//878//8PSjC1FGjEuQ5LG2gLsQ5MI2ARSw1Me0QABl1pJWCdaWVg3GkKS0kAHGBYYVlkByMTYAhLASAYYDC9T/D/MPvnADUCQAQzAkAIMwJACDUCQBA1AkAUMAJAivz//wVKACMTYKL1fnITYANLG2gLscL4ADJwRwA1AkAEMwJAELUGTHxExOkFAQEhAfoC8gH6A/PiYCNhEL0AvyD8//8=");
return {
cmd:E.nativeCall(569, "int(int,int)", bin),
cmds:E.nativeCall(741, "int(int,int)", bin),
cmd4:E.nativeCall(669, "int(int,int,int,int)", bin),
data:E.nativeCall(789, "int(int,int)", bin),
setpins:E.nativeCall(985, "void(int,int,int,int)", bin),
enable:E.nativeCall(861, "int(int,int)", bin),
disable:E.nativeCall(953, "void()", bin),
blit_setup:E.nativeCall(33, "void(int,int,int,int)", bin),
blt_pal:E.nativeCall(221, "int(int,int,int)", bin),
};
})();
E.kickWatchdog();
// F07 display pins
var RST=D7,CS=D8,DC=D6,PWR=D11,SCK=D3,MOSI=D2;
CS.write(1); // CS
DC.write(1); // CD
RST.write(1); // RESET
//PWR.write(0);
digitalPulse(RST,0,10);
//SPI2.save();
SPI2.setpins(SCK,MOSI,CS,DC); // CLK,MOSI,CS,DC
SPI2.disable();SPI2.enable(0x80,0); //8MBit, mode 0
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 toFlatBuffer(a){return E.toArrayBuffer(toFlatString(a));}
function 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 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 delayms(ms){
digitalPulse(DC,0,ms); // just to wait 10ms
digitalPulse(DC,0,0);
}
function init(){
cmd(0x11); // sleep out
delayms(10); // just to wait 10ms
cmd([0xb1,1,8,5]);
cmd([0xb2,1,8,5]);
cmd([0xb3,1,8,5,5,8,5]);
cmd([0xb4,0]);
cmd([0xc0,0x28,8,4]);
cmd([0xc1,0xc0]);
cmd([0xc2,0xd,0]);
cmd([0xc3,0x8d,0x2a]);
cmd([0xc4,0x8d,0xee]);
cmd([0xc5,0x1d]);
cmd([0x36,200]);
cmd([0xe0,7,0x17,0xc,0x15,0x2e,0x2a,0x23,0x28,0x28,0x28,0x2e,0x39,0,3,2,0x10]);
cmd([0xe1,6,0x21,0xd,0x17,0x35,0x30,0x2a,0x2d,0x2c,0x29,0x31,0x3b,0,2,3,0x12]);
// GMCTRP1 Gamma correction
//cmd([0xE0, 0x02, 0x1C, 0x07, 0x12, 0x37, 0x32, 0x29, 0x2D, 0x29, 0x25, 0x2B, 0x39, 0x00, 0x01, 0x03, 0x10]);
// GMCTRP2 Gamma Polarity correction
//cmd([0xE1, 0x03, 0x1d, 0x07, 0x06, 0x2E, 0x2C, 0x29, 0x2D, 0x2E, 0x2E, 0x37, 0x3F, 0x00, 0x00, 0x02, 0x10]);
cmd([0x3a,3]);//3=12bit mode, 5=16bit mode
}
var bpp=4; // powers of two work, 3=8 colors would be nice
var g=Graphics.createArrayBuffer(80,160,bpp);
var pal;
switch(bpp){
case 2: pal= Uint16Array([0x000,0xf00,0x0f0,0x00f]);break; // white won't fit
// case 1: pal= Uint16Array([0x000,0xfff]);break;
case 1:
pal= Uint16Array( // same as 16color below, use for dynamic colors
[ 0x000,0x00a,0x0a0,0x0aa,0xa00,0xa0a,0xa50,0xaaa,
0x555,0x55f,0x5f5,0x5ff,0xf55,0xf5f,0xff5,0xfff ]);
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= Uint16Array( // CGA
[
// 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;
}
// preallocate setwindow command buffer for flip
g.winCmd=toFlatBuffer([
5, 0x2a, 0, 0, 0,0,
5, 0x2b, 0, 0, 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(force){
var r=g.getModified(true);
if (force)
r={x1:0,y1:0,x2:this.getWidth()-1,y2:this.getHeight()-1};
if (r === undefined) return;
var x1=r.x1&0xfe;var x2=(r.x2+2)&0xfe; // for 12bit mode align to 2 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[3]=24+x1;c[5]=23+x2; //0x2a params
c[9]=r.y1;c[11]=r.y2; // 0x2b params
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
SPI2.cmds(g.winA,c.length);
SPI2.blt_pal(addr,g.palA,bitoff);
};
g.lev=256;
g.setBrightness=function(lev){
if (lev>=0 && lev<=256)
this.lev=lev;
else
lev=this.lev;
if (this.isOn){
var val=1-lev/256;
if (val==0||val==1)
digitalWrite(PWR,val);
else
analogWrite(PWR,val);
}
};
g.isOn=false;
g.on=function(){
if (this.isOn) return;
[DC,SCK,MOSI,RST,CS].forEach((p)=>{p.mode("input_pullup");p.mode("output");});
CS.write(1); // CS
DC.write(1); // CD
RST.write(1); // RESET
SCK.write(0);
MOSI.write(0);
PWR.reset(); // enable power
SPI2.enable(0x80,0);
PWR.set();//turn off brightness for now (it feeds off other pins now)
init();
this.flip(true);
cmd(0x13); //ST7735_NORON: Set Normal display on, no args, w/delay: 10 ms delay
cmd(0x29); //ST7735_DISPON: Set Main screen turn on, no args w/delay: 100 ms delay
//PWR.reset(); // full brightness
this.isOn=true;
this.setBrightness();
};
g.off=function(){
if (!this.isOn) return;
cmd(0x28);
cmd(0x10);
PWR.set();
SPI2.disable();
//6,3,2,8,7
[DC,SCK,MOSI,RST,CS].forEach((p)=>{p.mode("analog");} ); // disconnect like poke32(0x50000700+4*pin,2);
this.isOn=false;
};
var VIB=D25;
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});
};
function battVolts(){
return 4.20/0.18*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(){
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();
},5);
}
function randomShapes(){
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);
x1=r()*w;x2=10+r()*w;
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();
},5);
}
// 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(0,40,80,120);g.setColor(1+cc);cc=(cc+1)%15;
drawCube(40,80,80);
g.flip();
}
require("Font6x8").add(Graphics);
//require("Font6x12").add(Graphics);
//require("Font8x12").add(Graphics);
//require("Font8x16").add(Graphics);
function info(){
g.clear();
g.setFont("4x6",1/*2*/);g.setColor(10);
g.drawString("Espruino "+process.version,5,10);
if (bpp==1) g.flip();
g.setFont("4x6",1);g.setColor(14);
g.drawString("ST7735 12 bit mode\n8Mbps SPI with DMA",4,22);
if (bpp==1) g.flip();
for (var c=0;c<8;c++){
g.setColor(c+8);g.fillRect(8+8*c,130,16+8*c,138);
if (bpp==1) g.flip();
}
for ( c=0;c<8;c++) {g.setColor(c);g.fillRect(8+8*c,142,16+8*c,150);
if (bpp==1) g.flip();
}
g.flip();
return setInterval(function(){
stepCube();
},5);
}
var lastsec=-1;
var volts;
var batt=battInfo();
function drawClock(){
var d=Date();
volts= volts ? (volts+battVolts())/2:battVolts(); // average until shown
if (d.getSeconds()==lastsec) return;
lastsec=d.getSeconds();
g.clear();
if (lastsec%10==0){
batt=battInfo(volts);volts=0;
}
g.setFont("6x8",1);g.setColor(15);
g.drawString(batt,40-g.stringWidth(batt)/2,0);
g.setFontVector(50);
g.setColor(8+2);
d=d.toString().split(' ');
var sec=d[4].substr(-2);
//var tm=d[4].substring(0,5);
var hr=d[4].substr(0,2);
var min=d[4].substr(3,2);
g.drawString(hr,40-g.stringWidth(hr)/2,15);
g.drawString(min,40-g.stringWidth(min)/2,80);
//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,50);
/*
if (sec&1)g.drawString(":",36-g.stringWidth(":")/2,3);
var sx=sec*72/60;
g.drawLine(sx,0,71,0);
g.drawLine(sx,1,71,1);
//g.setFont8x16();
*/
g.setFontVector(16);
g.setColor(8+3);
var dt=/*d[0]+" "+*/d[1]+" "+d[2];//+" "+d[3];
g.drawString(dt,40-g.stringWidth(dt)/2,140);
g.flip();
}
function clock(){
volts=0;
drawClock();
return setInterval(function(){
drawClock();
},100);
}
function sleep(){
g.clear();//g.flip();
g.off();
currscr=-1;
return 0;
}
var screens=[clock,info,randomShapes,randomLines,sleep];
var currscr= -1;
var currint=0;
setWatch(function(){
if (!g.isOn) g.on();
currscr++;if (currscr>=screens.length) currscr=0;
if (currint>0) clearInterval(currint);
currint=screens[currscr]();
},BTN1,{ repeat:true, edge:'rising',debounce:25 }
);
/* uncomment to allow connection only when button is held while connecting
NRF.whitelist=[];
NRF.on('connect',function(addr) {
if (!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 = {};
NRF.connection.addr = addr;
NRF.connected=true;
NRF.setRSSIHandler((rssi)=>{NRF.connection.RSSI=rssi;});
});
NRF.on('disconnect',function(reason) {
NRF.connected=false;
NRF.connection = {};
NRF.lastReason=reason;
});
*/
var fc=new SPI(); // font chip - 2MB SPI flash
D23.write(1);
fc.setup({sck:D19,miso:D22,mosi:D20,mode:0});
fc.send([0xb9],D23); //put to deep sleep
// BMA 222E accelerometer on shared spi with fontchip, CS=D18
D18.set()
D31.set()
function accRegRead(r){
return fc.send([0x80|r,0x00],D18)[1];
}
function accWriteReg(r,v){
fc.send([0x7f & r,v],D18);
}
function accSetBit(r,b){
var v = accRegRead(r);
accWriteReg(r,v | 1<<b);
}
function accResetBit(r,b){
var v = accRegRead(r);
accWriteReg(r,v & ~(1<<b));
}
function accLowPowerMode(b){
if (b)
accSetBit(0x11,6);
else
accResetBit(0x11,6);
}
function accCoords(){
var coords=Int8Array(fc.send([0x82,0,0,0,0,0,0],D18).buffer,2);
return ({x:coords[0],y:coords[2],z:coords[4]});
}
/* try tap detection feature
D17.mode("input_pulldown"); // irq2 pin
accWriteReg(0x21,0x0E); // //latch irq for 50ms
accSetBit(0x16,5); // single tap enable
accSetBit(0x1b,5); // map it to int2
accLowPowerMode(1);
accWriteReg(0x2b,(3<<6)|4) //tap sensitivity
// values are 4=face tap, 2=side tap, 1=bottom or top side tap
setWatch(()=>{
var rv = accRegRead(0x0b);
var v = (rv&0x7f)>>4;
v = rv&0x80?-v:v;
print("tap ",v);
},D17,{ repeat:true, debounce:false, edge:'rising' });
*/
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment