spi.send with Uint16Array

Posted on
  • For the ILI99341 driver, I would like to send an Uint16Array via spi.send
    I tried 3 versions yet

        1. for(i = 0; i < sData.length; i++){
       2. spi.send(sData.buffer);
       3. spi.send(sData);

    1st version is slowest, but works fine
    2nd shows wrong colors and other minor problems
    3rd is totally wrong
    I did not test another option given with Graphics.drawImage. In my (poor) understanding, this is based on setPixel, which would be very slow.
    For now I live with 1st solution, any other idea ?

  • Well, #2 should work - or: spi.send(new Uint8Array(sData.buffer));

    Is it possible that the byte ordering is wrong? I'm not 100% sure but does #2 have the same result as:

    for(i = 0; i < sData.length; i++)

    The other option (faster than #1) may be:

    sData.forEach(function(s) {SPI.send([s>>8,s]);});

    But if #2 (or some variant) will work, that would be ideal.

  • Thanks for the feedback, I now have some more options:

        1. sData.forEach(function(s) {spi.send([s>>8,s]);});
        2. for(i = 0; i < cnt; i++){spi.send(String.fromCharCode(sData[­i]>>8)+String.fromCharCode(sData[i]));}
        3. spi.send(sData.buffer);
        4. spi.send(new Uint8Array(sData.buffer));
        5. spi.send(sData);

    I'm sending 0xf800, which for ILI9341 is red
    1st works fine and is very slow
    2nd works fine and doubles speed
    3rd and 4th are really fast, but dont display red, its blue. So 0xF800(63488) becomes 248(0x00F8)

    So,where is the problem, between my ears, or in interpretation of data ?

    Oh, just checked version from yesterday, there is a new parameter for SPI called order. Will check it later today or tomorrow.

  • @JumJum the SPI bit order won't help you - it's byte order that's your problem... It's whether you're storing data in little endian or big endian formats.

    This isn't a regression is it? I thought that the ILI9341 module worked just fine with the Graphics lib?

    Where are you getting the Uint16Array from? can't you just create the 16 bit numbers in the right order in the first place?

  • @Gordon,
    I've added a function to read screendata. This data is given as 3 bytes for r/g/b.
    Colourdata for writing is a word (5 bit for red, 6 bits for green and 5 for blue).
    Reading data is done this way.

    sData = new Uint16Array(cnt);  //cnt is number of pixels to be read
    writeCMD(0x2E);    //read memory command
        spi.send(z);    //z is any value, this needs to be sent for unknown reason
        for(var i = 0; i < cnt; i++){ 
          r = spi.send(z)>>3;g = spi.send(z)>>2; b = spi.send(z)>>3; //read 3 bytes for 3 colours
          sData[i] = (r<<11) + (g<<5) + b;
        return sData;       

    Data should have same format as for writing. I could switch upper and lower byte, thats correct. Any suggestion, how to do that ? May be a short assembler is best solution ?
    BTW, reading data this way is very slow, any suggestion to do better ?

  • You could try:

    var zzz = new Uint8Array([0,0,0]);
    sData = sData.map(function() {
      var d = spi.send(zzz);
      return (((d[0]<<11) + (d[1]<<5) + d[2])*0x10001) >> 8;

    (...*0x10001) >> 8; should swap the byte order

  • It's very interesting, to see, what experts like Gordon can do with Javascript on this small board.
    I learned a lot. But still the function is very slow. Reading a block of 20*20 pixel takes 0.6 seconds.
    Therefore I gave the new assembler interface a chance and created a short function with flat assembler.

            lsr r0,#3
            lsr r1,#2
            lsr r2,#3
            lsl r0,#11
            lsl r1,#5
            add r0,r1
            add r0,r2
            mov r1,r0
            lsl r0,#8
            lsr r1,#8
            add r0,r1
            mov r1,#65535
            and r0,r1
    return: bx lr

    Next changed reading function in displaydriver to:

    var zzz = new Uint8Array([0,0,0]);
    sData = sData.map(function() {
      var d = spi.send(zzz);
      return ILIcalc(d[0],d[1],d[2]);  //ILIcalc is the name of new assembler based function

    Now it takes 0.34 seconds, 44% faster.
    This is still not as fast as I would like, but it shows how helpful assembler can be.

  • Some more timing info:
    loop without calculating data takes 0.24 secs
    loop returning a value only takes 0.14 secs

    sending data to Display with spi.send(uintarray) needs 0,02 secs only

  • It's a real shame it's not easier to iterate over the array 3 at a time! You could just use SPI.send to read all the data at once, and could convert it with the assembler.

    You might get some speed improvement by doing:

    var zzz = new Uint8Array([0,0,0]);
    sData = sData.map(function() {return ILIcalc.apply(0,spi.send(zzz))});
  • Post a reply
    • Bold
    • Italics
    • Link
    • Image
    • List
    • Quote
    • code
    • Preview

spi.send with Uint16Array

Posted by Avatar for JumJum @JumJum