Avatar for stephaneAG

stephaneAG

Member since Jun 2014 • Last active Dec 2019
  • 18 conversations
  • 194 comments

'love hackety trick

Most recent activity

  • in Projects
    Avatar for stephaneAG

    All right, that one good news ! :)

    -> I was currently disconnecting the battery when connecting over USB but it seemed I could control the leds "ok" ( but maybe not as reliabiliy as when running everything off the battery ;p )

    I'm currently working on how to optimise the leds/leds strip chunks so that I have the shortest non-crossing traces across the board ( I'm quite afraid using short wires 'll be quite hard since it'd unsolder one end while solderng the other due to heat .. I experienced that when joining two strip with a wire between both .. )
    I plan to try two different approaches:

    • 1st: "Pyralux" flexible pcb for proto ( or cheaper flexible fab pcb ? )
    • 2nd non-flexible pcbS ( as "sections" soldered together to form the circuit )
      The ability to get two layers flexible boards 'd be awesome ;p

    Ps: do you think I may have killed the last led on the strip by getting electrically shocked by touching it or is it just some code-side pb ? ( fact is: I tried loading previous versions of my code: still same trouble with the last one, aside from the scheduling maybe not as fast as expected & my test patterns not doing correctly .. yup, I have some mess to fix .. ) or would it come from me controlling leds powered via bat+ pin & no battery while connecting over usb ? :| .. ( I'm not sure how to test if an APA102 is dead or not, aside from directly connecting to it & sending controls to it only - thus this 'd mean a crack in the strip connection, which I doubt since it's not where I joined chuncks .. )

    -> I'll check that once done with my mapping problems ;)

    ps: do you / does anyone have any knowledge / experience with "breadth-first search" & the TSP problem ? ( I could really get some help on either writing or modding an Illustrator plugin to do some related stuff .. )

    thanks for the hints :)
    +

  • in Projects
    Avatar for stephaneAG

    Back with an alpha ( some things doesn't work as they should, and I'm still missing the finalized data ( timed mouth indices & mouths data ) ), but it's cleaner than previously ;)

    also, I managed to wreck my code somehow somewhere & now I can't control the last led any more :|

    if anyone's feeling brave enough to visually troubleshoot, be my guest ;)
    ( as always, I'll do so after some rest ;) )

    this being said, the pre-pre-pre-alpha code

    /* ==== Akali's Mask V0.1a ==== */
    
    // -- MODULES --
    // - little 'dotstar' module -
    // usage:
    // var dotStar = exports(spi); // pass spi obj
    //dotStar.write(ledsValues); // pass array of leds colors
    var exports = function (spi) {
      return { 
        write: function(ledsData){
          spi.write([0x00,0x00,0x00,0x00]); // start frame
          spi.write(ledsData); // led frames
          for(var y=0; y<(ledsData.length/2)/8; y++){ spi.write(0x00); } // end frame
        }
      };
    };
    
    // -- COLORS/PATTERNS HELPER --
    // R: APA102 are BGR for me
    function getColoredPattern(colR, colG, colB, start, end, clear) {
      var tstart = (start > 0)? start*4-3 : 0 || 0;
      var tend = end*4 || ledsBuff.length;
      for (var i=0;i<ledsBuff.length;i+=4) { // Q: is it where my 'one less led' comes from ? :/
        if(i>=tstart && i < tend){
          ledsBuff[i] = 0xe0+31;
          ledsBuff[i+1] = colB;
          ledsBuff[i+2] = colG;
          ledsBuff[i+3] = colR;
        } else if(clear) { // doesn't work ? :/
          ledsBuff[i] = 0xe0+31;
          ledsBuff[i+1] = 0;
          ledsBuff[i+2] = 0;
          ledsBuff[i+3] = 0;
        }
      }
      return ledsBuff;
    }
    
    // R: steps may (later ) be used to either:
    // - map '0' to '255, 0, 0, 0' & '1' to '255, 255, 255, 255' ( by def we store 1 & 0's, but lookup table set with R,G,B vals at each index can be used )
    //   Nb: we could then for example get the color of the item above a dot on Illustrator as an idx of its color in our 'shared' palette
    // - map 'R, G, B' to '255, B, G, R', what we currently do
    var colorsPalette = [[0, 0, 0], [255, 255, 255]];
    function getPattern(array, steps) {
      for (var i=0, y=0; i<ledsBuff.length;i+=4, y+=steps) {
        if(steps == 1){
          ledsBuff[i] = 0xe0+31;
          //var val = (array[y] == 1)? 255 : 0; // would only support on/ff instead of paletted idx which offer 255 choices
          ledsBuff[i+1] = colorsPalette[array[y]][2]; // B
          ledsBuff[i+2] = colorsPalette[array[y]][1]; // G
          ledsBuff[i+3] = colorsPalette[array[y]][0]; // R
        } else if(steps == 3){
          ledsBuff[i] = 0xe0+31;
          ledsBuff[i+1] = array[y+2]; // B
          ledsBuff[i+2] = array[y+1]; // G
          ledsBuff[i+3] = array[y]; // R
        } else if(steps == 4){
          ledsBuff[i] = array[y]; // brightness
          ledsBuff[i+1] = array[y+1]; // R
          ledsBuff[i+2] = array[y+2]; // G
          ledsBuff[i+3] = array[y+3]; // B
        }
      }
      return ledsBuff;
    }
    
    
    // -- LEDS WORKING CHECK --
    function checkLeds(delay){
      setTimeout(function(){
        dotStar.write(getColoredPattern(255, 0, 0, 0, ledsCount));
        setTimeout(function(){
          dotStar.write(getColoredPattern(0, 255, 0, 0, ledsCount));
          setTimeout(function(){
            dotStar.write(getColoredPattern(0, 0, 255, 0, ledsCount));
            setTimeout(function(){
              dotStar.write(getColoredPattern(255, 255, 255, 0, ledsCount));
              setTimeout(function(){
                dotStar.write(getColoredPattern(0, 0, 0, 0, ledsCount));
              },delay);
            },delay);
          },delay);
        },delay);
      },delay);
    }
    
    
    // -- MOUTHS --
    // TODO: generate dummys & finalize the leds mouths in Illustrator
    // for finalized: how many ? number of leds in each ? which leds are on for each ?
    // R: since we have to store at least 8 different mouths ( and by default, only on/off states of leds in those ),  storing 1's & 0's ( or paletted color idx)
    //    make more sense to lessen the space taken
    // ex: leds * BrRGB * mouths = 45 * 4 * 8 = 1440 bytes ( with brightness control )
    //     leds * RGB * mouths = 45 * 3 * 8 = 1080 bytes ( any color, no brightness control )
    //     leds * paletted idx * mouths = 45 * 1 * 8 = 360 bytes ( 255 possible colors )
    var ledsBuff = new Uint8ClampedArray(45*4); // used as tmp to fill in /map in values while keeping constant brightness
    var mouthsLedsArrays = [
      //new Uint8ClampedArray([0,0,0,0,0,0,255,255,2­55,255,255,255,255,255,255,0,0,0,0,0,0,0­,0,0,0,0,0,255,255,255,255,255,255,255,2­55,255,0,0,0,0,0,0]),
      //new Uint8ClampedArray(45*3),
    ];
    // dummies generator, to test stuff before finalizing the mouths leds arrays
    function generateDummies(howMany){
      for(var i=0; i<howMany; i++){ // R/ testing with 45 leds
        console.log('pushing dummy: [' + (i*9) + '..' + (i*9+9) + ']' );
        //ledsBuff = new Uint8ClampedArray(45*4); // fill buff with 0's
        getColoredPattern(0, 0, 0, 0, ledsCount); // same as above, faster way that doesn't re-allocate a clamped array
        //mouthsLedsArrays.push(getColoredPatter­n(255, 255, 255, i*9, i*9+9)); // push 9/45 of leds to our array ( uses buff internally ) - increasing
        //mouthsLedsArrays.push(getColoredPatter­n(255, 255, 255, i*9, i*9+9)); // push 9/45 of leds to our array ( uses buff internally ) - moving .. not ? :/
        mouthsLedsArrays.push(getColoredPattern(­255/9*i, 255/9*i, 255/9*i, i*9, i*9+9)); // push 9/45 of leds to our array ( uses buff internally )
      }
    }
    
    
    // -- TIMING --
    // TODO: get final timings ( absolute or relative )
    // R: we have generated 5 mouths for our debug, each with 9 leds
    var absTimeMouthsIdxsArray = [
      //[<ms_from_start>, <mouth_idx>]
      [37,    0],
      [38,    1],
      [40,    2],
      [45,    3],
      [45.2,  4],
      [45.5,  3],
      [45.7,  2],
      [45.8,  1],
      [45.9,  0],
      [45.95, 1],
      [45.99, 2],
      [46,    3],
      [50,    4]
    ];
    // R: to map abolute times to relative timing in ms: relTime = (absTime * 1000) - (1stAbsTime * 1000)
    var reTimeMouthsIdxsArray = [];
    for(var i=0; i< absTimeMouthsIdxsArray.length; i++){
      var relTime = (i === 0) ? ((absTimeMouthsIdxsArray[i][0] * 1000) - (absTimeMouthsIdxsArray[i][0] * 1000)) :
                                 (absTimeMouthsIdxsArray[i][0] * 1000) - (absTimeMouthsIdxsArray[i-1][0] * 1000);
      reTimeMouthsIdxsArray[i] = [relTime, absTimeMouthsIdxsArray[i][1]];
    }
    
    
    // -- ANIMATION --
    // transition between mouths
    function nxtMouth(){
      if(currMouthAnimIdx+1 < reTimeMouthsIdxsArray.length){ // didn't reach end of array yet
        currMouthAnimIdx = currMouthAnimIdx+1;
        timr = setTimeout(function(){
          currMouth = mouthsLedsArrays[reTimeMouthsIdxsArray[c­urrMouthAnimIdx][1]];
          // useful for generated dummies
          console.log('currMouthIdx: ' +currMouthAnimIdx);
          //dotStar.write(getPattern(currMouth, 4));// update leds - we pass an array of paletted idx, rgb values or BrRGB values & a 'step' to indicate format
          getColoredPattern(0, 0, 0, 0, ledsCount); // clear buffer 
          dotStar.write(getColoredPattern(0, 0, 100, 0, currMouthAnimIdx*4, true)); // debuuuuug
          // for final impl
          //dotStar.write(getPattern(currMouth, 1));// update leds - we pass an array of paletted idx, rgb values or BrRGB values & a 'step' to indicate format
          nxtMouth(); // schedule next call
        }, reTimeMouthsIdxsArray[currMouthAnimIdx][­0]);
      } else {
        timr = -1;
        console.log('end of mouth timed array reached -> animation complete !');
        resetState();
      }
    }
    
    
    // -- BUTTON PRESS HANDLER: START/RESET --
    function handleBtnPress(){
      if(animating){ // currently animating: reset
        resetState();
      }
      else { // currently stopped: animate
        animating = true;
        console.log('animating !');
        nxtMouth(); // TODO: uncomment once we have final mouths arrays or generated dummys
      }
    }
    
    function resetState(){
      console.log('resetting !');
      if(timr !== -1){
        clearTimeout(timr);
        timr = -1;
      }
      currMouthAnimIdx = 0;
      currMouth = mouthsLedsArrays[reTimeMouthsIdxsArray[c­urrMouthAnimIdx][1]];
      dotStar.write(getColoredPattern(0, 0, 0, 0, ledsCount)); // clear
      animating = false;
    }
    
    
    // -- SETUP --
    // - modules -
    var spi;
    var dotStar;
    // - pins -
    var btn = BTN1;
    var dotStarSck = B3;
    var dotStarMosi = B5;
    // - watches -
    var btnW;
    // - vars -
    var ledsCount = 45;
    var animating = false;
    var timr = -1;
    var currMouthAnimIdx = 0; // where we're at in the 'reTimeMouthsIdxsArray'
    //var currMouthIdx = 0;
    var currMouth = mouthsLedsArrays[reTimeMouthsIdxsArray[c­urrMouthAnimIdx][1]];
    
    
    function onInit(){
      // setup modules
      spi = SPI1;
      spi.setup({miso:B4, mosi:dotStarMosi, sck:dotStarSck, mode:0,order:"msb", baud: 4000000});
      //spi.setup({mosi:dotStarMosi, sck:dotStarSck, mode:0,order:"msb", baud: 4000000});
      dotStar = exports(spi);
      dotStar.write(getColoredPattern(0, 0, 0, 0, ledsCount)); // start with all leds fully off
    
      // setup button
      //pinMode(btn, 'input_pullup');
      btnW = setWatch(function(e) { handleBtnPress(); }, btn, { repeat:true, edge:'rising', debounce: 100 });
      
      // debug logs
      console.log('currMouthAnimIdx : ' + currMouthAnimIdx);
      console.log('currMouth : ' + currMouth);
      console.log('reTimeMouthsIdxsArray : ' + reTimeMouthsIdxsArray);
      console.log('reTimeMouthsIdxsArray.lengt­h : ' + reTimeMouthsIdxsArray.length);
      
      // generate dummies to test until we have final mouths
      generateDummies(5); // we pass how many we want
    
      // quick leds feedback
      checkLeds(1000); // we pass the delay between color change
      
      // feedback - fully booted indication
      digitalWrite(LED3, 1);
    }
    
  • in Projects
    Avatar for stephaneAG

    Hi there !

    back on this project ;p

    -> I received the said charger/booster and 'll test the pullups pins stuff ;)
    -> I also had answers from the Adafruit support team, as such:

    forget about voltage boosting and associated limitations and inefficiencies. You are better off powering both processor and pixels direct from your battery pack. We regularly run Neopixels and Dotstars directly from 3.7v LiPos

    https://forums.adafruit.com/viewtopic.ph­p?f=8&t=147139.

    So, before trying the said pullup thing, I have to try powering ~40 leds fully bright from one ( or more in parallel ? ) 3.7V 18650 batteries & powering an original Espruino board ( maybe later a Pico but I no longer have any handy ; ) ), yet for programming/flashing/debug reasons, I wish to be able to keep the USB connection to the laptop.

    I currently disconnect the battery jst connector when being connected using USB while the leds are getting power from the 3.7V battery & no problem has rosen yet, but I'm wondering how the board would react if I were to keep both USB and battery on JST connected ( the leds are getting power directly from the battery, not from the Bat pin, when usb is connected or not )
    Also, it seems I couldn't talk to the board when putting a 1000uF 16V cap across the battery power source & Gnd ? ( the board was recognized, but I couldn't get a working serial comm, even when using an external ftdi adapter & trying on hardware serial ports .. ( espruino original ) .. may it come from CTS/DTR left unconnected ? I'll have to try using bluetooth .. )

    This being said, I'm onto modding my current code to try the said ~40 leds, hoping I can have them 'blinking in sync' & last longer at least a minute ..

    ps: mode 0 seems to work reliably on my current setup, big thanks for the hint ;)

    last but not least, would you advise using external pullups when running off 3.7V & controlling 3.7V-powered leds ( without opendrain since no more needed ? I wonder how to fasten the said "voltage swing" .. )

    -> I'll see if I can adapt some "rainbow scrolleré onto those as a test ;p

  • in Projects
    Avatar for stephaneAG

    Hi there !

    'll be back on the subject later this week ( I hope :) ), although I've just added the "partial flip" we talked about aside a little benchmarking on the subject ( see http://forum.espruino.com/conversations/­269808/#comment14607110)

  • in Projects
    Avatar for stephaneAG

    hello :)

    thanks for the hints ! ;)

    I'll have a try on this subject later today & 'll come back with the result

  • in Interfacing
    Avatar for stephaneAG

    hi there !

    got it ;p
    For my early tests, it seems the benefits of line by line VS 16 of them is ok unless area modified is bigger than LCD_WIDTH/2 ( or a little more ).
    Also, I currently have no idea of how to optimize this using either inlineC or "compiled" :/ ( or just another way to do it in js )
    I stumbled upon this topic, but not sure at all if & which concepts could be useful here ..
    This being said, porting this to oled screens instead of colored ones may get quite handy for even faster updates :D

    Also, as a side subject, any idea of a hack to allow stuff already on screen of color other than black ( for ex ) to be all set to a particular color ?

    this being said, here's the code for partial flip :D

    /* black + 1x16bit color instant refresh on ST7735S
      ( https://www.displayfuture.com/Display/da­tasheet/controller/ST7735.pdf ? )
      LCD screen: 0.96" 80x160 RGB IPS 65K 4-wire SPI
      --> currently fixing & dev stuff on 1.44" 128x128 ;p
    */
    
    // Backlight is always on
    var DCpin = A4; //B0;
    var CSpin = B0;
    var RESpin = B1;
    
    var SCKpin = A5;
    var MOSIpin = A7;
    
    require("Font8x12").add(Graphics);
    
    // -- modded module --
    var exports = {};
    
    var LCD_WIDTH = 128;
    var LCD_HEIGHT = 128;
    
    var colStart = 2;
    var rowStart = 3;
    
    function init(spi, dc, ce, rst, callback) {
      function cmd(c,d) {
        dc.reset();
        spi.write(c, ce);
        if (d!==undefined) {
          dc.set();
          spi.write(d, ce);
        }
      }
      
      if (rst) {
        digitalPulse(rst,0,10);
      } else {
        cmd(0x01); //Software reset
      }
      setTimeout(function() {
        cmd(0x11); //Exit Sleep
        setTimeout(function() {
          cmd(0x26, 0x04); //Set Default Gamma
          //cmd(0xF2, 0x00) //E0h & E1h Enable/Disable ( from ILI9163AN datasheet - Laibo1.8" / CMO1.8" )
          cmd(0xB1, [0x0e,0x10]); //Set Frame Rate -> default
          //cmd(0xB1, [0x0C,0x14]); //Set Frame Rate ( from ILI9163AN datasheet - Laibo1.8" / CMO1.8" )
          cmd(0xC0, [0x08,0]); //Set VRH1[4:0] & VC[2:0] for VCI1 & GVDD
          //cmd(0xC0, [0x0C,0x05]); // Set VRH1[4:0] & VC[2:0] for VCI1 & GVDD ( from ILI9163AN datasheet - Laibo1.8" / CMO1.8" )
          cmd(0xC1, 0x05); //Set BT[2:0] for AVDD & VCL & VGH & VGL
          //cmd(0xC1, 0x02); //Set BT[2:0] for AVDD & VCL & VGH & VGL ( from ILI9163AN datasheet )
          cmd(0xC5, [0x38,0x40]); //Set VMH[6:0] & VML[6:0] for VOMH & VCOML
          //cmd(0xC5, [0x32,0x3B]); //Set VMH[6:0] & VML[6:0] for VOMH & VCOML ( from ILI9163AN datasheet - Laibo1.8" )
          ////cmd(0xC5, [0x29,0x43]); //Set VMH[6:0] & VML[6:0] for VOMH & VCOML ( from ILI9163AN datasheet - CMO1.8" )
          //cmd(0xC7, 0x40); // ??? ( from ILI9163AN datasheet )
          
          cmd(0x3a, 5); //Set Color Format, 5=16 bit,3=12 bit
          //cmd(0x36, 0xc8); //RGB - nope, on my screen its BRG -> produces artifacts
          cmd(0x36, 0xce); //RGB - nope, on my screen its BRG -> same, less artifacts
          
          cmd(0x2A,[0,0,0,LCD_WIDTH]); //Set Column Address R: digg if we can set the offset only here instead of within 3 fcns
          //cmd(0x2A,[0,0,0,0x7F]); //Set Column Address 0x7F = 127 ( from ILI9163AN datasheet )
          cmd(0x2B,[0,0,0,LCD_HEIGHT]); //Set Page Address R: digg if we can set the offset only here instead of within 3 fcns
          //cmd(0x2B,[0,0,0,0x9F]); //Set Page Address 0x9F = 135 ( from ILI9163AN datasheet )
          
          //cmd(0x36, 0xC0); // Set Scanning Direction ( from ILI9163AN datasheet - Laibo1.8" / CMO1.8" )
          
          cmd(0xB4, 0); // display inversion
          
          //cmd(0xB7, 0x00); // Set Source Output Direction ( from ILI9163AN datasheet - CMO1.8" )
          cmd(0xf2, 1); //Enable Gamma bit
          cmd(0xE0,[0x3f,0x22,0x20,0x30,0x29,0x0c,­0x4e,0xb7,0x3c,0x19,0x22,0x1e,0x02,0x01,­0x00]); 
          cmd(0xE1,[0x00,0x1b,0x1f,0x0f,0x16,0x13,­0x31,0x84,0x43,0x06,0x1d,0x21,0x3d,0x3e,­0x3f]);
          cmd(0x29); // Display On
          cmd(0x2C); // reset frame ptr      
          if (callback) callback();
        },20);
      } ,100);
    }
    // modded 'connect()' to fix the offset & pixel artifacts
    exports.connect = function(spi, dc, ce, rst, callback) {
      var g = Graphics.createCallback(LCD_WIDTH, LCD_HEIGHT, 16, {
        setPixel:function(x,y,c){
          ce.reset();
          spi.write(0x2A,dc);
          //spi.write(0,x,0,x+1); // default
          spi.write(0,x+colStart,0,x+colStart+1);
          spi.write(0x2B,dc);
          //spi.write(0,y,0,y+1); // default
          spi.write(0,y+rowStart,0,y+rowStart+1);
          spi.write(0x2C,dc);
          spi.write(c>>8,c);
          ce.set();
        },
        fillRect:function(x1,y1,x2,y2,c){
          ce.reset();
          spi.write(0x2A,dc);
          //spi.write(0,x1,0,x2); // default
          spi.write(0,x1+colStart,0,x2+colStart);
          spi.write(0x2B,dc);
          //spi.write(0,y1,0,y2); // default
          spi.write(0,y1+rowStart,0,y2+rowStart);
          spi.write(0x2C,dc);
          //spi.write({data:String.fromCharCode(c>­>8,c), count:(x2-x1+1)*(y2-y1+1)}); // default
          spi.write({data:String.fromCharCode(c>>8­,c), count:((x2+colStart)-(x1+colStart)+1)*((­y2+rowStart)-(y1+rowStart)+1)}); // USELESS ?! -> test with above
          ce.set();
        }
      });
      // quick & hacky fix
      g.flip = function() { /*prevents error during my quick tests*/ };
      init(spi, dc, ce, rst, callback);
      return g;
    };
    // modded 'connectPaletted()' to fix 'italic" text
    exports.connectPaletted = function(palette, spi, dc, ce, rst, callback) {
      //var bits = 8;
      /**/
      var bits;
      if (palette.length>16) bits=8;
      else if (palette.length>4) bits=4;
      else if (palette.length>2) bits=2;
      else bits=1;
      /**/
      var g = Graphics.createArrayBuffer(LCD_WIDTH, LCD_HEIGHT, bits, { msb:true, vertical_byte: false });
      g.flip = function() {
        ce.reset();
        spi.write(0x2A,dc);
        //spi.write(0,0,0,LCD_WIDTH); // default - otherwise, we had spi.write(0,x+colStart,0,x+colStart+1);
        //spi.write(0,2,0,LCD_WIDTH); // thx to @Jorgen who inspired this - italic but other orientation
        spi.write(0,1,0,LCD_WIDTH); // WORKS: made the trick for non-italic text drawn at once ! :D
        spi.write(0x2B,dc);
        spi.write(0,1,0,LCD_HEIGHT); // otherwise, we had spi.write(0,y+rowStart,0,y+rowStart+1);
        //spi.write(0,3,0,LCD_HEIGHT); // thx to @Jorgen who inspired this - italic but other orientation
        spi.write(0x2C,dc);
        var lines = 16; // size of buffer to use for un-paletting
        var a = new Uint16Array(LCD_WIDTH*lines); // default
        for (var y=0;y<LCD_HEIGHT;y+=lines) { // default
          E.mapInPlace(new Uint8Array(g.buffer, y*LCD_WIDTH*bits/8, a.length), a, palette, bits); // default
          spi.write(a.buffer);
        }
        ce.set();
      };
      
      /* ---- HUGE WIP: PARTIAL FLIP USING GETMODIFIED ---- */
      // wip usage: g.flipP(g.getModified())
      g.flipP = function(options) {
       // check if modified
      //var tmp = g.getModified();
      var tmp = g.getModified(true); // check & clear for update if so
      if(typeof tmp === "undefined"){
        // nothing to update: force ?
        console.log('nothing to flip');
      } else {
        console.log('flipping modified stuff ..');
        console.log(tmp);
        if(typeof options === "undefined") options = {};
        var y1 = options.y1 || tmp.y1 || 0;
        var y2 = options.y2 || tmp.y2 || LCD_HEIGHT;
        var x1 = options.x1 || tmp.x1 || 0;
        var x2 = options.x2 || tmp.x2 || LCD_WIDTH;
        // -- TMP OVERRIDE --
        //x1 = 0;
        //x2= 11;
        //x2 = LCD_WIDTH; // => COMMENT OUT FOR PARTIAL FLIP WITHOUT LINE CHUNKS
        //x2 = LCD_WIDTH/4;
        //x2 = LCD_WIDTH/2;
        var twidth = x2-x1;
        var theight = y2-y1;
        /*
        var tpxNum = twidth*theight;
        //var tbits = tpxNum*16/5; // may not be always tru ? ( found while trying to make sense of debug pokes values ..)
        //var tbits = tpxNum*bits/8; //same as tpxNum*16/8;
        var tbits = tpxNum*bits;
        //var tbits2 = tpxNum*(16-theight);
        var tbytes = tbits/8;
        console.log('area width: '+twidth+'\nheight: '+theight+'\npixels count: '+tpxNum+'\nbits / bytes: '+tbits+' / ' +tbytes); //+'\ntbits2: '+tbits2);
        */
        
        ce.reset();
        
        spi.write(0x2A,dc);
        //spi.write(0,x1+1,0,(x2-x1));
        //spi.write(0,x1+1+colStart,0,(x2-x1)+co­lStart);
        //spi.write(0,x1+1+colStart,0,twidth+col­Start);
        spi.write(0,x1+1+colStart,0,twidth+colSt­art);
        
        spi.write(0x2B,dc);
        //spi.write(0,y1+1,-2,(y2-y1)+1);
        spi.write(0,y1+rowStart,0,theight+rowSta­rt);
        
        spi.write(0x2C,dc);
        var lines = 1; // gives us 19 loops for the two squares to be drawn ( these totalize 20 in height ) & 256 bits buffer
        //var lines = 16; // => COMMENT OUT FOR PARTIAL FLIP WITHOUT LINE CHUNKS
        //var lines = 10; // => COMMENT OUT FOR PARTIAL FLIP WITHOUT LINE CHUNKS
        var a = new Uint16Array(twidth*lines);
        
        // debug bits counter
        //var bitsCntr = 0;
        
        for (var y=0;y<theight;y+=lines) { // shall stay as is !!
          //E.mapInPlace(new Uint8Array(g.buffer, y1*LCD_WIDTH*bits/8 + y*LCD_WIDTH*bits/8, a.length), a, palette, bits);
          E.mapInPlace(new Uint8Array(g.buffer, y1*LCD_WIDTH*bits/8 + y*LCD_WIDTH*bits/8+ x1*bits/8, a.length), a, palette, bits); // WORKS WITH lines=1
          
          spi.write(a.buffer);
          //bitsCntr += a.buffer.length;
          //console.log('y = '+y+' -> bitsCntr + ' + a.buffer.length + " = " + bitsCntr);
        }
        
        // ---- trying to optimize stuff via "compiled" ----
        /*
        //loopSendBufferChunks(a, x1, y1, theight, bits); // trying to get faster using "compiled" helper to loop over n lines, map & send over spi
        for (var y=0;y<theight;y+=lines) { // shall stay as is !!
          //E.mapInPlace(new Uint8Array(g.buffer, y1*LCD_WIDTH*bits/8 + y*LCD_WIDTH*bits/8, a.length), a, palette, bits);
          var arr = new Uint8Array(g.buffer, y1*LCD_WIDTH*bits/8 + y*LCD_WIDTH*bits/8+ x1*bits/8, a.length);
          mapAndSend(arr, a, bits, palette); // no gain whatsoever :/ ..
          //bitsCntr += a.buffer.length;
          //console.log('y = '+y+' -> bitsCntr + ' + a.buffer.length + " = " + bitsCntr);
        }
        */
        ce.set();
        //console.log('bits written ' + bitsCntr);
      }
      };
      
      
      init(spi, dc, ce, rst, callback);
      return g;
    };
    
    // compiled js helper to decrease transfer time ?
    function mapAndSend(arr, a, bits, palette){
      "compiled";
      E.mapInPlace(arr, a, palette, bits); // WORKS WITH lines=1
      spi.write(a.buffer);
    }
    function createNewArr(offset, length){
      return new Uint8Array(g.buffer, y1*LCD_WIDTH*bits/8 + y*LCD_WIDTH*bits/8+ x1*bits/8, a.length);
    }
    function loopSendBufferChunks(a, x1, y1, height, bits){
      "compiled";
      var sp = spi; // assign to local variable so no name lookup on each call
      for (var y=0;y<height;y+=lines) {
        //E.mapInPlace(new Uint8Array(g.buffer, y1*LCD_WIDTH*bits/8 + y*LCD_WIDTH*bits/8+ x1*bits/8, a.length), a, palette, bits);
        var arr = createNewArr(y1*LCD_WIDTH*bits/8 + y*LCD_WIDTH*bits/8+ x1*bits/8, a.length); // create new array externally to "compiled" code ?
        E.mapInPlace(arr, a, palette, bits);
        spi.write(a.buffer);
      }
    }
    
    // ---- test code ----
    var spi = new SPI();
    //spi.setup({mosi:MOSIpin /* sda */, sck:SCKpin /* scl */, baud: 1000000});
    spi.setup({mosi:MOSIpin /* sda */, sck:SCKpin /* scl */, baud: 16000000});
    //spi.setup({mosi:MOSIpin /* sda */, sck:SCKpin /* scl */, baud: 100000});
    //spi.setup({mosi:MOSIpin /* sda */, sck:SCKpin /* scl */});
    
    //var colorPalette = new Uint16Array([0, 0xf8, 0xe007, 0x1f00]); // black, red, green ,blue, finally ? ... YES !!
    // the following helper does the RGB888 -> GBRG565 mapping trick
    // wip fix: remapping the RGB565 as
    // GGGBBBBBRRRRRGGG: ( weird 'GBRG' ?)
    // G3,G2,G1,  B5,B4,B4,B2,B1,  R5,R4,R3,R2,R1,  G6,G5,G4
    //      LSB   MSB        LSB   MSB        LSB   MSB
    function rgb888To565t2(rgb888){
      return ((rgb888 & 0x1c00) << 3)|((rgb888 & 0xf8) << 5)|((rgb888 & 0xf80000) >> 16)|((rgb888 & 0xe000) >> 13);
    }
    var colMap = rgb888To565t2;
    var colorPalette = new Uint16Array([0, colMap(0xff0000), colMap(0x00ff00), colMap(0x0000ff)]); // black, red, green ,blue, finally ? ... YES !!
    
    //var g = exports.connect(spi, DCpin, CSpin, RESpin, function() { // works fine
    var g = exports.connectPaletted(colorPalette, spi, DCpin, CSpin, RESpin, function() {
      g.clear();
      g.flip(); // needed when using 'paletted' mode
      g.setFont8x12(); // perfect size for 128x128 :)
      g.setColor(1);
      g.drawString("should be red !", 2, 2);
      g.setColor(2);
      g.drawString("should be green !", 2, 20);
      g.setColor(3);
      g.drawString("should be blue !", 2, 40);
      g.flip(); // needed when using 'paletted' mode
      
      // from now, assume that nothing new was drawn
      g.setColor(3);
      //g.fillRect(0,10, 10, 20);
      g.fillRect(2,10, 12, 20);
      g.flip();
      
      g.getModified(true);
      g.flipP(); // 'll try clearing modified & flipping stuff if found anything -> should say 'nothing to update'
      setTimeout(function(){
        g.setColor(1);
        //g.setColor(1); // modifies stuff, even if its blanking it ..
        //g.fillRect(0,0, 10, 10);
        
        //testing y on flipP
        //g.fillRect(0,50, 10, 60);
        
        //testing x on flipP
        //g.setColor(2);
        //g.fillRect(10,50+10, 20, 60+10); // the +10 forces a second loop (20 > 16, the un-paletting buffer size )
        
        //g.fillRect(10+26,50+6, 20+26, 60+6);
        
        // benchmarking partial flip with lines chunks VS partial flip, to know when one becomes faster than the other ( both should be faster than flip ;) )
        //g.fillRect(0,50, LCD_WIDTH/4, 60); // 32px for 128px screen: 57ms for 'line chunk' version, 179.252ms for 16lines pflip
        //g.fillRect(0,50, LCD_WIDTH/3, 60); // 32px for 128px screen: 57ms for 'line chunk' version, 179.295ms for 16lines pflip, 113.227ms for 10lines pflip
        //g.fillRect(0,50, LCD_WIDTH/2, 60); // 32px for 128px screen: 83.032ms for 'line chunk' version, 113.348ms for 10lines pflip
        g.fillRect(0,50, LCD_WIDTH-1, 60); // 32px for 128px screen: 133.300ms for 'line chunk' version, 113.680ms for 10lines pflip
        
        //g.drawString("HELLO FLIP-P", 2, 30);
        //g.flip();
        var bFlipT = getTime();
        g.flipP(); // 'll try clearing modified & flipping stuff if found anything -> should update stuff CORRECTLY ? ..
        var aFlipT = getTime();
        console.log('partial flip took ' + (aFlipT-bFlipT)*1000+ 'ms');
        //console.log('partial flip took ' + (aFlipT-bFlipT)+ 's');
      },2000);
      
    });
    
  • in Interfacing
    Avatar for stephaneAG

    Hi there !

    I had a quick take on getting that partial flip thing to work, but for a reason I can't figure out ( I'm either too dumb, tired, or both ;p ) I can't make it work for only a vertical portion of the screen ( smaller than LCD_WIDTH )

    any quick hint on this ?
    ( --> currently fixing & dev stuff on 1.44" 128x128 ;p )

    // working version
    // ..
    spi.write(0x2A,dc);
    spi.write(0,1,0,LCD_WIDTH);
    // ..
    spi.write(0x2B,dc);
    spi.write(0,y1+1,-2,(y2-y1)+1);
    // ..
    var lines = 16; // size of buffer to use for un-paletting
    var a = new Uint16Array(LCD_WIDTHlines);
    for (var y=0;y<y2-y1;y+=lines) {
      E.mapInPlace(new Uint8Array(g.buffer, y1LCD_WIDTHbits/8 + yLCD_WIDTHbits/8, a.length), a, palette, bits); //works whatever x & y !!!
    spi.write(a.buffer);
    }
    
    // not working version :frowning: ..
    // ..
    spi.write(0x2A,dc);
    spi.write(0,x1+1,0,(x2-x1));
    // ..
    spi.write(0x2B,dc);
    spi.write(0,y1+1,-2,(y2-y1)+1);
    // ..
    var lines = 16; // size of buffer to use for un-paletting
    var a = new Uint16Array((x2-x1)lines);
    for (var y=0;y<y2-y1;y+=lines) {
      E.mapInPlace(new Uint8Array(g.buffer, y1LCD_WIDTHbits/8 + yLCD_WIDTHbits/8+ x1*bits/8, a.length), a, palette, bits); // wip ... FIX THIS !! :|
    spi.write(a.buffer);
    }
    

    Also, I've been able to figure out that my screen seems to accept either RBG or BRG, not RGB, and thanks to the following link /code, here's a quick & handy remapper for those in need ;)

    // txh to http://www.barth-dev.de/online/rgb565-co­lor-picker/
    function rgb888To565(rgb888){
      //return ( (((rgb888&0xf80000)>>8) + ((rgb888&0xfc00)>>5) + ((rgb888&0xf8)>>3)) ).toString(16);
      return ( (((rgb888&0xf80000)>>8) | ((rgb888&0xfc00)>>5) | ((rgb888&0xf8)>>3)) ).toString(16);
    }
    
    // wip fix: remapping the RGB565 as
    // GGGBBBBBRRRRRGGG: ( weird 'GBRG' ?)
    // G3,G2,G1,  B5,B4,B4,B2,B1,  R5,R4,R3,R2,R1,  G6,G5,G4
    //      LSB   MSB        LSB   MSB        LSB   MSB
    function rgb888To565t2(rgb888){
      return ((rgb888 & 0x1c00) << 3)|((rgb888 & 0xf8) << 5)|((rgb888 & 0xf80000) >> 16)|((rgb888 & 0xe000) >> 13);
    }
    

    -> I hope I'll be able to draw things faster in "unicolor" that way ;p ( one of the goals is to be able to draw in 2 colors, one black & the other dynamically changing )

Actions