Skip to content

Instantly share code, notes, and snippets.

@yngv27
Created November 22, 2023 16:23
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 yngv27/aa5f562597d734928c5d5a1b622c2c13 to your computer and use it in GitHub Desktop.
Save yngv27/aa5f562597d734928c5d5a1b622c2c13 to your computer and use it in GitHub Desktop.
// 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