-
• #2
Software with some demos, including some special commands for high speed.
require("Font8x16").add(Graphics); require("Font6x8").add(Graphics); function Led64x32(){ var me = this; var Pen; //pin Enable var sfnc,dfnc; // bound functions to shift data and set address var ledBuf;//graphics.buffer for LED var arr; //array of drawing functions var boardDur; //refresh time for panel in mS var tmr; //interval timer for refresh me.init = function(board){ switch(board){ case "ESP32": initPins(D2,D16,D4,D17,D15,D27, D5,D18,D19,D21, D26,D22,D25); boarDur = 20; break; case "Espruino": initPins(B3,B5,B4,B6,C11,C10,B7,C9,B8,C8,C6,B9,C12); boardDur = 10; break; default: console.log(board + " not supported (yet?)"); } return initGraphic(); }; me.stop = function(){if(tmr) clearInterval(tmr);}; function initPins(R1,R2,B1,B2,G1,G2,A,B,C,D,Latch,Clock,Enable){ Pen = Enable; sfnc = shiftOut.bind(null,[R2,G2,B2,undefined,R1,G1,B1],{clk:Clock}); dfnc = digitalWrite.bind(null,[Enable,Latch,Latch,D,C,B,A,Enable]); } function initGraphic(){ gr = Graphics.createArrayBuffer(64,32,4,{interleavex:true}); ledBuf = gr.buffer; createFuncArr(); return gr; } function createFuncArr(){ arr = []; arr.push({callback:Pen.reset.bind(Pen)}); for(i = 0; i < 16; i++){ arr.push(new Uint8Array(ledBuf,i*64,64)); arr.push({callback:dfnc.bind(null,33|i<<1)}); } arr.push({callback:Pen.set.bind(Pen)}); } me.start = function(){ tmr = setInterval(function(){ sfnc(arr); },boardDur); }; me.frame = function(c){ me.clear(); if(!c) c = 7; grf.setColor(c); grf.drawRect(0,0,63,31); grf.drawRect(1,1,62,30); }; me.clear = function(c){ clearInterval(); grf.setBgColor(0); grf.clear(); }; } var lf = new Led64x32(); var grf = lf.init("Espruino"); //Some demos function color(col){ clearInterval(); if(!col) col = 0; grf.setBgColor(col); grf.clear(); lf.start(); } function graph(){ clearInterval(); var barh = 5; grf.setBgColor(6); grf.clear(); grf.setColor(2); grf.fillRect(5,12,50,25); grf.setColor(4); grf.fillRect(10,14,40,20); grf.fillRect(10,0,40,0); grf.setColor(7); grf.drawRect(0,31,5,5); lf.start(); setInterval(function(){ barh++; if(barh>24) barh = 1; grf.setColor(0); grf.fillRect(1,30,4,6); grf.setColor(1); grf.fillRect(1,30,4,30 - barh); },200); } function xmas(){ var pnt = 0; var px = [[10,10],[25,20],[30,15],[40,14]]; function flicker(){ grf.setPixel(px[pnt][0],px[pnt][1],2); pnt++;if(pnt>3)pnt = 0; grf.setPixel(px[pnt][0],px[pnt][1],7); } lf.frame(7); grf.setColor(2); grf.fillPoly([1,1,1,31,30,16,1,1]); grf.fillPoly([15,3,15,28,40,16,15,3]); grf.fillPoly([28,6,28,25,50,16,28,6]); grf.setColor(7); grf.drawLine(6,2,8,2); grf.drawLine(6,30,8,30); lf.start(); setInterval(function(){flicker();},300); } function txt(t,c){ if(!t) t = "Open"; if(!c) c = 2; var cbg = 7; lf.frame(cbg); grf.setColor(cbg); grf.drawEllipse(2,2,62,30); grf.setFont8x16(); grf.setColor(c); grf.drawString(t,36 - grf.stringWidth(t) / 2,7); lf.start(); setInterval(function(){ cbg--;if(cbg<1) cbg=7; grf.setColor(cbg);grf.drawEllipse(2,2,62,30); grf.setColor(8 - cbg); grf.drawString(t,36 - grf.stringWidth(t) / 2,7); },500); } function magic(){ var col = 1;radius = 15; clearInterval(); grf.setBgColor(0); grf.clear(); lf.start(); setInterval(function(){ col++; if(col>7) col = 1; radius--; if(radius < 3){ radius = 15; grf.setColor(0); grf.fillCircle(30,15,15); } grf.setColor(col); grf.fillCircle(30,15,radius); },100); } function mondrinator(){ var rndCol = function(){ return Math.random() * 6;}; var rndBorder = function(){ return 1 + Math.random() * 7;}; var rndRect = function(){ return Math.random() * 4;}; clearInterval(); lf.start(); function showNext(){ var right,left,top,bottom,rectId; grf.setBgColor(7);grf.clear(); grf.setColor(rndCol());left = rndBorder();grf.drawLine(left,0,left,31); grf.setColor(rndCol());right = rndBorder();grf.drawLine(63-right,0,63-right,31); grf.setColor(rndCol());top = rndBorder();grf.drawLine(0,top,63,top); grf.setColor(rndCol());bottom = rndBorder();grf.drawLine(0,31-bottom,63,31-bottom); rectId = parseInt(rndRect());grf.setColor(rndCol()); switch(rectId){ case 0: grf.fillRect(0,0,left - 1,top - 1);break; case 1: grf.fillRect(64-right,0,63,top - 1);break; case 2: grf.fillRect(0,32 - bottom,left-1,31);break; case 3: grf.fillRect(64-right,31,63,32 - bottom);break; } setTimeout(function(){showNext();},2000); } setTimeout(function(){showNext();},2000); } function pie(){ var i,last; lf.clear(); last = 0; centerX = 45; centerY = 16; var data = [[20,1,"Apple"],[30,2,"Beef"],[40,4,"Beer"],[10,6,"Pills"]]; function drawPie(pnt){ grf.setColor(7); grf.drawLine(0,0,0,31); grf.drawLine(1,0,1,31); var i,dt = data[pnt]; var polyData = [centerX,centerY]; var s = Math.PI * last / 100; var x = centerX + Math.round(Math.cos(s) * 15); var y = centerY + Math.round(Math.sin(s) * 15); polyData.push(x); polyData.push(y); for(i = 0; i < 10; i++){ last += dt[0] / 10; s = Math.PI * (last + dt[0] / 10 * i) / 100; x = centerX + Math.round(Math.cos(s) * 15); y = centerY + Math.round(Math.sin(s) * 15); polyData.push(x);polyData.push(y); } last += dt[0]; grf.setColor(dt[1]); grf.fillPoly(polyData,true); } function drawText(pnt){ var dt = data[pnt]; grf.setFont6x8(); grf.setColor(dt[1]); grf.drawString(dt[2],4,pnt * 8); } for(i = 0; i < data.length;i++){ drawPie(i); drawText(i); } lf.start(); }
-
• #3
Nice! Thank you!
-
• #5
@JumJum ... or use this function to draw circle:
function circle(xm, ym, r) { var x = -r, y = 0, err = 2 - 2 * r; do { g.setPixel(xm - x, ym + y); g.setPixel(xm - y, ym - x); g.setPixel(xm + x, ym - y); g.setPixel(xm + y, ym + x); r = err; if (r <= y) err += ++y * 2 + 1; if (r > x || err > y) err += ++x * 2 + 1; } while (x < 0); }
The 'spikes' come from the optimized algorithm that can handle ellipses and circles incl. fill (4 auf einen Streich).
1 Attachment
-
• #6
No matter with or without spikes - great work - I like it!
-
• #7
After sneaking and testing, got this:
function ellipse(int xm, int ym, int a, int b) { var dx = 0; var dy = b; var a2 = a*a var b2 = b*b; var err = b2-(2*b-1)*a2 var e2; /* Fehler im 1. Schritt */ do { g.setPixel(xm+dx, ym+dy); g.setPixel(xm-dx, ym+dy); g.setPixel(xm-dx, ym-dy); g.setPixel(xm+dx, ym-dy); e2 = 2*err; if (e2 < (2*dx+1)*b2) { dx++; err += (2*dx+1)*b2; } if (e2 > -(2*dy-1)*a2) { dy--; err -= (2*dy-1)*a2; } } while (dy >= 0); while (dx++ < a) { g.setPixel(xm+dx, ym); g.setPixel(xm-dx, ym); } }
@Gordon, would it be worth the effort (original source )?
1 Attachment
-
• #8
Yes, totally - I actually just posted in another thread but I'm definitely up for pulling this in
-
• #9
...though circles, ellipses: Could be a performance killer? I'd prefer the segmentation as alternative. On the other hand, I expect it to be better than trigo functions - is it?
-
• #10
I think in this case the ellipse function is faster than polygon fill (at least than the one we'll have to implement soon)
-
• #11
Got a P5 64x64 panel with fm6126 chip and a ESP32 .
Is is now running Espruino with @JumJum code after some small changes.
/* jshint esversion: 6 */ var P_A = D19, P_B = D23, P_C = D18, P_D = D5, P_E = D15, P_R1 = D13, P_R2 = D27, P_G1 = D21, P_G2 = D17, P_B1 = D12, P_B2 = D4, P_LAT = D22, P_OE = D2, P_CLK = D14, MaxLed = 256, X = 64, Y = 64; var BLACK = 0, RED = 1, BLUE = 2, MAGENTA = 3, GREEN = 4, YELLOW = 5, TUTQUOISE = 6, // .... WHITE = 15; function Led64x64() { var me = this; var Pen; //pin Enable var sfnc, dfnc; // bound functions to shift data and set address var ledBuf; //graphics.buffer for LED var arr; //array of drawing functions var boardDur; //refresh time for panel in mS var tmr; //interval timer for refresh me.init = function() { initFM6126(); initPins(P_R1, P_R2, P_B1, P_B2, P_G1, P_G2, P_A, P_B, P_C, P_D, P_E, P_LAT, P_CLK, P_OE); boarDur = 20; return initGraphic(); }; me.stop = function() { if (tmr) clearInterval(tmr); }; me.start = function() { tmr = setInterval(function() { sfnc(arr); }, boardDur); }; me.clear = function(c) { clearInterval(); grf.setBgColor(0); grf.clear(); }; function initFM6126() { var C12 = [1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; var C13 = [0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0]; digitalWrite([P_OE, P_LAT, P_CLK], 0b100); // Send Data to control register 11 for (var l = 0; l < MaxLed; l++) { y = l % 16; if (C12[y]) { digitalWrite([P_R1, P_G1, P_B1, P_R2, P_B2, P_G2], 0b111111); } else { digitalWrite([P_R1, P_G1, P_B1, P_R2, P_B2, P_G2], 0); } digitalWrite(P_LAT, (l > MaxLed - 12) ? 1 : 0); digitalWrite(P_CLK, 1); digitalWrite(P_CLK, 0); } digitalWrite(P_LAT, 0); digitalWrite(P_CLK, 0); // Send Data to control register 12 for (l = 0; l < MaxLed; l++) { y = l % 16; if (C13[y]) { digitalWrite([P_R1, P_G1, P_B1, P_R2, P_B2, P_G2], 0b111111); } else { digitalWrite([P_R1, P_G1, P_B1, P_R2, P_B2, P_G2], 0); } digitalWrite(P_LAT, (l > MaxLed - 13) ? 1 : 0); digitalWrite(P_CLK, 1); digitalWrite(P_CLK, 0); } digitalWrite(P_LAT, 0); digitalWrite(P_CLK, 0); } function initPins(R1, R2, B1, B2, G1, G2, A, B, C, D, E, Latch, Clock, Enable) { Pen = Enable; sfnc = shiftOut.bind(null, [R2, G2, B2, undefined, R1, G1, B1], { clk: Clock }); dfnc = digitalWrite.bind(null, [Enable, Latch, Latch, E, D, C, B, A, Enable]); } function initGraphic() { gr = Graphics.createArrayBuffer(X, Y, 4, { interleavex: true }); ledBuf = gr.buffer; createFuncArr(); return gr; } function createFuncArr() { arr = []; arr.push({ callback: Pen.reset.bind(Pen) }); for (i = 0; i < 32; i++) { arr.push(new Uint8Array(ledBuf, i * X, Y)); arr.push({ callback: dfnc.bind(null, 65 | i << 1) }); } arr.push({ callback: Pen.set.bind(Pen) }); } } test = function() { setInterval(function() { grf.setColor(Math.random() * 10); grf.fillPoly([Math.random() * 63, Math.random() * 63, Math.random() * 63, Math.random() * 63, Math.random() * 63, Math.random() * 63 ], true); grf.setColor(0xffff); grf.setFont("6x8", 2).drawString(times, 0, 0, true); times++; }, 1E3); lf.start(); }; var lf = new Led64x64(); var grf = lf.init(); var times = 0; setTimeout(test, 1E3);
If you watch the video you will immediately figure that refresh is too slow to have a stable picture.
Any idea how to improve speed?
Could i2s be the kicker?
Have to try this code with a original Espruino board, hopefully it is faster.
-
• #12
Original Espruino Boards are faster than ESP32, at least for functions like this.
But I'm pretty sure, based on my experience with 32x64, 64x64 even Espruino boards will still be too slow.
Watching prices for 64x64 boards, they are really cheap, P2.5 for less than 13€ shipping includedI2S would be an option, if parallel mode is supported. Have in mond you have to set 11(5+6) data and 3 control ports for a 64x64 Matrix
Special driver like the one for Neopixel could be an option.
If I would be Gordon, I would not like this. Support for several boards could end in a nightmare. -
• #13
Just tested a P4 64x64 with a Espruino Wifi board - it work's, without flicker!
Unbelievable how fast those STM32 chips are, compare with the ESP32.
-
• #14
I think it's because on STM32 you have each pin memory mapped to an address, which means functions like
shiftOut
can really be optimised.ESP32
shiftOut
could definitely be improved a lot, and it may be that if the IO pins are memory mapped too you could just implement the relevant GetPinAddress functions and get a massive speed boost -
• #15
created this issue Why is shiftOut on ESP32 so much slower than on original Espruino boads?.
About a year ago, Gordon added some functions to support Led panel with 64x32 color pixel.
At that time, I got it running on an ESP32.
Some days ago this came back to my fingers, and I tried to get it running with one of the first Espruino boards.
Big surprise, these older boards are much faster than the ESP32. To make it more visible, some lines are witten and the result is what you see in attached images showing a P5 board.
5 Attachments