Created
November 22, 2023 16:23
-
-
Save yngv27/aa5f562597d734928c5d5a1b622c2c13 to your computer and use it in GitHub Desktop.
This file contains hidden or 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
// Test code for GDEH0154D67 e-ink screen (1.54" from WaveShare and others) | |
// should work on any Espruino platform | |
// the top portion is a future module, after that find the SPI pins and modify to your setup | |
console.log("got here"); | |
//var eink = require("eink"); | |
///////////////////////////////////////// | |
var exports={}; | |
function SSD16xx(config){ | |
this.display = config.display; | |
this.spi = config.spi; | |
this.bsPin = config.bsPin; //Used to force this into 8 bit spi mode | |
this.csPin = config.csPin; | |
this.dcPin = config.dcPin; | |
this.busyPin = config.busyPin; | |
this.resetPin = config.resetPin; | |
this.powerPin = config.powerPin; | |
this.g = {bw: this.grfxBlackWhite(), | |
cw : this.grfxColorWhite(), | |
flip:this.flip.bind(this), | |
clear:this.clear.bind(this), | |
partialFlip:this.partialFlip.bind(this)}; | |
digitalWrite(this.csPin, true); | |
digitalWrite(this.dcPin, true); | |
digitalWrite(this.resetPin, true); | |
this.hwResetTimeOut = 100; | |
if (config.clearScreenTimeOut) { | |
this.hwResetTimeOut = config.hardwareResetTimeOut; | |
} | |
} | |
SSD16xx.prototype.on = function() { | |
if(this.powerPin) { | |
digitalWrite(this.powerPin, 1); | |
} | |
}; | |
SSD16xx.prototype.off = function() { | |
if(this.powerPin) { | |
digitalWrite(this.powerPin, 0); | |
} | |
}; | |
SSD16xx.prototype.hwReset = function() { | |
return new Promise((resolve)=>{ | |
digitalWrite(this.resetPin, 0); | |
digitalWrite(this.resetPin, 1); | |
setInterval(function() { | |
resolve(); | |
}, this.hwResetTimeOut); | |
}); | |
}; | |
SSD16xx.prototype.sc = function(command) { | |
digitalWrite(this.dcPin, 0); | |
this.spi.write(command, this.csPin); | |
}; | |
SSD16xx.prototype.psd = function() { | |
digitalWrite(this.dcPin, 1); | |
}; | |
SSD16xx.prototype.sd = function(data) { | |
this.spi.write(data, this.csPin); | |
}; | |
SSD16xx.prototype.scd = function(command, data) { | |
this.sc(command); | |
this.psd(); | |
this.sd(data); | |
}; | |
SSD16xx.prototype.fullReset = function() { | |
return new Promise((resolve)=>{ | |
digitalWrite(this.resetPin, 0); | |
setTimeout(()=>{ | |
digitalWrite(this.resetPin, 1); | |
this.sc(0x12); | |
this.partial=false; | |
setTimeout(resolve,this.hwResetTimeOut); | |
},this.hwResetTimeOut); | |
}); | |
}; | |
//when the busy pin is high no command will work | |
SSD16xx.prototype.waitCmd = function(command){ | |
return new Promise((resolve,reject)=>{ | |
setWatch(resolve, this.busyPin, { repeat:false, edge:'falling' }); | |
console.log("sending a busy command!"); | |
this.sc(command); | |
this.psd(); | |
}); | |
}; | |
// the same, but with data to send | |
SSD16xx.prototype.waitCmdData = function(command, data){ | |
return new Promise((resolve,reject)=>{ | |
console.log("sending a busy command!"); | |
this.sc(command); | |
this.psd(); | |
this.sd(data); | |
if(this.busyPin.read()) | |
setWatch(resolve, this.busyPin, { repeat:false, edge:'falling' }); | |
else | |
resolve(); | |
}); | |
}; | |
SSD16xx.prototype.refreshDisplay = function(command){ | |
return this.waitCmd(0x20); | |
}; | |
SSD16xx.prototype.init = function() { | |
return new Promise((resolve)=>{ | |
if(this.bsPin) { | |
digitalWrite(this.bsPin, 0); | |
} | |
console.log("test"); | |
console.log(this.display.displaySizeX-1); | |
//this.scd(0x10, 0x00); //get out of sleep | |
this.scd(0x01,[this.display.displaySizeY-1,(this.display.displaySizeY-1)%256,0]); | |
this.scd(0x11, 0x03); // point x,y increase | |
this.setPartialRegion(0,0,this.display.displaySizeX, this.display.displaySizeY ); | |
//this.scd(0x32,this.display.lutRegisterData); | |
//this.scd(0x18,0x80); //Tempiture???? don't know if i need | |
//this.scd(0x3c,0x05); //boardercolor???? don't know if i need or even works | |
this.scd(0x22, 0xc0); //refresh style //modded | |
this.waitCmd(0x20).then(()=>{ | |
resolve(); | |
}); | |
/* | |
if(options && options.clearScreenColor){ | |
return this.csb(callback, options.clearScreenColor); | |
} | |
*/ | |
}); | |
}; | |
/* | |
Expecting byte boundries | |
*/ | |
SSD16xx.prototype.setPartialRegion = function(x,y,w,h) { | |
//console.log(w); | |
console.log(h); | |
console.log((x + w - 1)/8); | |
this.scd(0x44, [(x/8), ((x + w - 1)/8)] ); | |
this.scd(0x45, [y%256, y / 256, (y+h-1) % 256, (y+h-1) / 256]); | |
this.scd(0x4E,[x/8]); | |
this.scd(0x4F,[y%256, y/256]); | |
//this.scd(0x44, [1, 16] ); | |
//this.scd(0x45, [0, 0, 39, 1]); | |
//this.scd(0x4E,[1]); | |
//this.scd(0x4F,[0, 0]); | |
}; | |
SSD16xx.prototype.setFastRefresh = function() { | |
const WF_PARTIAL = new Uint8Array([ 0x0,0x40,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x80,0x80,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x40,0x40,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x80,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0xF,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x22,0x22,0x22,0x22,0x22,0x22,0x0,0x0,0x0,0x02,0x17,0x41,0xB0,0x32,0x28, | |
]); | |
return new Promise((resolve)=>{ | |
this.fullReset().then(()=>{ | |
this.waitCmdData(0x32, WF_PARTIAL.slice(0,153)).then(()=>{ | |
this.scd(0x3F, WF_PARTIAL[153]); | |
this.scd(0x03, WF_PARTIAL[154]); | |
this.scd(0x04, WF_PARTIAL.slice(155, 158)); | |
this.scd(0x2C, WF_PARTIAL[158]); | |
this.scd(0x37, [0,0,0,0,0,0x40,0,0,0,0]); | |
this.waitCmdData(0x3C, 0x80).then(()=>{ | |
this.partial = true; | |
this.scd(0x22, 0xcf); // finalize | |
this.refreshDisplay().then(resolve); | |
}); | |
}); | |
}); | |
}); | |
}; | |
SSD16xx.prototype.flip = function() { | |
this.scd(0x4E, 0); | |
this.scd(0x4F, [0,0]); | |
this.scd(0x24, this.g.bw.buffer); | |
if(this.display.coloredDisplay){ | |
this.scd(0x4E, 0); | |
this.scd(0x4F, [0,0]); | |
this.scd(0x26, this.g.cw.buffer); | |
} | |
if(this.partial) { | |
print("flip:partial"); | |
this.scd(0x22, 0xcf); | |
} else { | |
print("flip:full"); | |
//this.scd(0x22, 0xF7); | |
} | |
return this.refreshDisplay(); | |
}; | |
SSD16xx.prototype.partialFlip = function() { | |
if(!this.display.coloredDisplay){ | |
var changed = screen.g.bw.getModified(); | |
if(changed.x1 == 0 && changed.x2 == 0){return;} | |
var w = changed.x2 - changed.x1; | |
var h = changed.y2 - changed.y1; | |
print(`changed: ${changed.x1}.${changed.y1} - ${change.x2}.${changed.y2}`); | |
this.setPartialRegion(changed.x1,changed.y1,w, h); | |
w = w/8; | |
h = h; | |
var newGraphics = new Uint8Array(w * h); | |
var newGraphI = 0; | |
for(var j = changed.y1; j < (changed.y1 + h); j++){ | |
for(var i = changed.x1/8; i < (changed.x1/8 + w); i++) | |
{ | |
newGraphics[newGraphI] = this.g.bw.buffer[j * (200/8) + i]; | |
newGraphI++; | |
} | |
} | |
console.log(newGraphI); | |
console.log(newGraphics.length); | |
console.log(this.g.bw.buffer.length); | |
this.scd(0x24,newGraphics); | |
this.scd(0x22, 0xfc ); | |
return this.refreshDisplay(); | |
} | |
}; | |
SSD16xx.prototype.clear = function(clearColor){ | |
this.g.bw.clear(clearColor); | |
this.g.cw.clear(clearColor); | |
}; | |
/* | |
Might be harder then i thought? | |
Don't have a good way to send the actual parameter into it? | |
I need a function to draw to the display and then remove the same section on | |
the red side | |
*/ | |
SSD16xx.prototype.clearRed = function(func){ | |
if(this.display.coloredDisplay){ | |
console.log(func) | |
}; | |
}; | |
/** | |
* Creates the Graphics object with Graphics.createArrayBuffer(...). | |
* Sets the display x size, y size, bits per pixel and msb:true. | |
* Provides a clear function to fill in-memory buffer with one color for each pixel. | |
* Provides a flip function to flush in-memory buffer to display buffer. | |
*/ | |
SSD16xx.prototype.grfxBlackWhite = function(){ | |
var g = Graphics.createArrayBuffer( | |
this.display.displaySizeX, | |
this.display.displaySizeY, | |
this.display.bpp, | |
{msb: true} | |
); | |
g.clear = function(clearColor){ | |
new Uint8Array(this.buffer).fill(clearColor); | |
}; | |
return g; | |
}; | |
SSD16xx.prototype.grfxColorWhite = function(){ | |
var g = Graphics.createArrayBuffer( | |
this.display.displaySizeX, | |
this.display.displaySizeY, | |
this.display.bpp, | |
{msb: true} | |
); | |
g.clear = function(clearColor){ | |
new Uint8Array(this.buffer).fill(clearColor); | |
}; | |
return g; | |
}; | |
exports.connect = function (options) { | |
return new SSD16xx(options); | |
}; | |
////////////////////////////////////////// | |
/* | |
var sck = D47; | |
var miso = D46; //there is no miso for the display | |
var mosi = D45; | |
SPI1.setup({mosi:mosi, miso:miso, sck:sck, baud: 4000000,order:'msb', bits:8}); | |
var cs = D44; | |
var busyPin = D43; | |
var dcPin = D42; //Data/Command | |
var resetPin = D40; | |
*/ | |
//don't understand why there are so many parameters in this | |
/* | |
Why do you need ramXend and ramY end???? | |
*/ | |
/* | |
var screenSettings = { | |
display: { | |
bpp : 1, | |
displaySizeX : 200, | |
displaySizeY : 200, | |
lutRegisterData : //new Uint8Array([ 0x50,0xAA,0x55,0xAA,0x11,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0x1F,0x00,0x00,0x00,0x00,0x00,0x00,0x00 | |
new Uint8Array([ | |
0x10,0x18,0x18,0x08,0x18,0x18,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x13,0x14,0x44,0x12,0x00,0x00,0x00,0x00,0x00,0x00 | |
]), | |
coloredDisplay : 0, | |
}, | |
spi: SPI1, | |
csPin: D44, | |
busyPin: D43, | |
dcPin: D42, | |
resetPin: D40 | |
}; | |
*/ | |
/* | |
var screenSettings = { | |
display: { | |
bpp : 1, | |
displaySizeX : 128, | |
displaySizeY : 296, | |
//lutRegisterData : //new Uint8Array([ 0x50,0xAA,0x55,0xAA,0x11,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0x1F,0x00,0x00,0x00,0x00,0x00,0x00,0x00 | |
//new Uint8Array([ | |
//0x10,0x18,0x18,0x08,0x18,0x18,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x13,0x14,0x44,0x12,0x00,0x00,0x00,0x00,0x00,0x00 | |
//]), | |
coloredDisplay : 0, | |
}, | |
spi: SPI1, | |
csPin: D44, | |
busyPin: D43, | |
dcPin: D42, | |
resetPin: D40 | |
}; | |
*/ | |
// WATCHY setup : keeping screenSettings out of global memory... | |
// OVERRIDING WITH WATCHY PINS | |
// Watchy pins | |
sck = D18; | |
mosi = D23; | |
cs = D5; | |
busyPin = D19; | |
dcPin = D10; | |
resetPin = D9; | |
var spi1 = new SPI(); | |
spi1.setup({sck: D18, mosi: D23, baud: 2000000}); | |
var screen = exports.connect( | |
{ | |
display: { | |
bpp : 1, | |
displaySizeX : 200, | |
displaySizeY : 200, | |
lutRegisterData : //new Uint8Array([ 0x50,0xAA,0x55,0xAA,0x11,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0x1F,0x00,0x00,0x00,0x00,0x00,0x00,0x00 | |
new Uint8Array([ | |
0x10,0x18,0x18,0x08,0x18,0x18,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x13,0x14,0x44,0x12,0x00,0x00,0x00,0x00,0x00,0x00 | |
]), | |
coloredDisplay : 0, | |
}, | |
spi: spi1, | |
csPin: cs, | |
busyPin: busyPin, | |
dcPin: dcPin, | |
resetPin: D9 | |
} | |
); | |
screen.fullReset().then(()=>{ | |
console.log("-----got here"); | |
screen.g.clear(0xff); | |
screen.g.flip().then(()=>{ | |
//* | |
screen.g.bw.setColor(0x0).fillRect(8,8,121,88); | |
//screen.g.bw.setColor(0xff).fillRect(100,100,199,199) | |
console.log(screen.g.bw.getModified()); | |
console.log("-----got here"); | |
screen.g.flip().then(()=>{ | |
screen.g.bw.setColor(0x0).fillRect(0,0,121,200); | |
screen.g.flip().then(()=>{ | |
screen.g.bw.clear(0xff); | |
screen.g.bw.setRotation(1); | |
screen.g.bw.drawLine(0,100,84,100); | |
screen.g.bw.setFontVector(40); | |
screen.g.bw.setColor(0).drawString("Hello",0,0); | |
// this ERASES what was just written | |
//screen.g.bw.setColor(0xff).fillRect(0,0,100,100) | |
// commenting out RED work | |
//screen.g.bw.setColor(0xff).fillRect.bind(screen.g.cw)(100,100,199,199); | |
//screen.g.cw.setColor(0xff).fillRect(100,100,199,199); | |
//screen.clearRed(Graphics.fillRect); | |
//screen.g.bw.setColor(0xff).forceWhite.bind(screen)(screen.g.bw.fillRect,0,0,100,100); | |
screen.g.flip().then(()=>{ | |
// demo partial refresh | |
screen.setFastRefresh().then(()=>{ | |
screen.g.bw.setBgColor(-1); | |
for(let t=0; t<10; t++) { | |
setTimeout((s,t)=>{s.g.bw.drawString(t, 100, 100, true);s.flip();}, t*1000, screen, t); | |
} | |
}); | |
}); | |
}); | |
}); | |
//*/ | |
}); | |
}); | |
console.log("end of file"); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment