LED Panel with 64x32 Leds controlled by Arduino board

Posted on
  • 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

    • DSC_0110.JPG
    • DSC_0115.JPG
    • DSC_0126.JPG
    • DSC_0139.JPG
    • DSC_0141.JPG
  • 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,R­1,G1,B1],{clk:Clock});
        dfnc = digitalWrite.bind(null,[Enable,Latch,Lat­ch,D,C,B,A,Enable]);
      }
      function initGraphic(){
        gr = Graphics.createArrayBuffer(64,32,4,{inte­rleavex: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-r­ight,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,"Bee­r"],[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();
    }
    
  • Nice! Thank you!

  • @JumJum... checked out your circle... if you rotate your edge coordinates by half of the slices' angle, you can avoid the 'spikes' - single dots - at the 4 winds (N S E W or Top, Bottom, Left, Right).

  • @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

    • Bildschirmfoto 2019-12-05 um 17.56.24.jpg
  • No matter with or without spikes - great work - I like it!

  • 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

    • Bildschirmfoto 2019-12-05 um 19.11.40.jpg
  • Yes, totally - I actually just posted in another thread but I'm definitely up for pulling this in

  • ...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?

  • I think in this case the ellipse function is faster than polygon fill (at least than the one we'll have to implement soon)

  • Post a reply
    • Bold
    • Italics
    • Link
    • Image
    • List
    • Quote
    • code
    • Preview
About

LED Panel with 64x32 Leds controlled by Arduino board

Posted by Avatar for JumJum @JumJum

Actions