• Can someone point me to an Espruino driver for the Waveshare 1.28inch round LCD display (SPI interface)? Or, something possibly close it that I can hack?

    Thanks

    Larry

  • Hi - @user134932 - Larry,

    took a quick peek at the datasheet (attached for convenience) and it looks close to just many of these TFT drivers: the GC9A01 doc is in many parts identical to ILI9341 doc, even looking at the internals it is the same: 240x320 memory.... So I took the command lists for comparison to start out from a copy the ILI9341 driver (http://www.espruino.com/modules/ILI9341.js) and adjust it to work with the GC9A01. For easy dev place the driver module inline and give it a shot (see Module development - using example of Temperature Nodes with 1-Wire PT100 / DS18B20 Sensor at multiple Locations, Module creation at runtime). I hope this is not carrying awls to Athens. ;-}

    • ao

    PS: The ILI9341 command list (and comparison / map) is in the next post.


    5 Attachments

  • ILI9341 Command List (and datasheet) attached.

    Since searching in attachments (imgs) is not that great, I'm instrumentalizing the data copied from the .pdf and get myself a little tooling going... you may notice where it is going... (done up to line #32 far for the GC9A01 commands, more and code will follow in a bit).

    var ct /* cmds target GC9A01 */ = `
    A| Command Function
    +| D/CX | RDX | WRX | D17-8 | D7 | D6 | D5 | D4 | D3 | D2 | D1 | D0 | HEX |
    5| Read Display Identification Information 2
    +| 0 | 1 | ↑ | XX | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 04h |
    -| 1 | ↑ | 1 | XX | X | X | X | X | X | X | X | X | XX |
    -| 1 | ↑ | 1 | XX |8 ID_1[7:0]                    | 00 |
    -| 1 | ↑ | 1 | XX |8 ID_2[7:0]                    | 9A |
    -| 1 | ↑ | 1 | XX |8 ID_3[7:0]                    | 01 |
    6| Read | Display Status
    +| 0 | 1 | ↑ | XX | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 1 | 09h |
    -| 1 | ↑ | 1 | XX | X | X | X | X | X | X | X | X | XX |
    -| 1 | ↑ | 1 | XX |7 D[31:25]                 | X | 00 |
    -| 1 | ↑ | 1 | XX | X |3 D[22:20] |4 D[19:16]     | 61 |
    -| 1 | ↑ | 1 | XX | X | X | X | X | X |3 D[10:8]  | 00 |
    -| 1 | ↑ | 1 | XX |3 D[7:5]   | X | X | X | X | X | 00 |
    1| Enter Sleep Mode
    +| 0 | 1 | ↑ | XX | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 10h |
    1| Sleep OUT
    -| 0 | 1 | ↑ | XX | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 1 | 11h |
    1| Partial Mode ON
    -| 0 | 1 | ↑ | XX | 0 | 0 | 0 | 1 | 0 | 0 | 1 | 0 | 12h |
    1| Normal Display Mode ON
    -| 0 | 1 | ↑ | XX | 0 | 0 | 0 | 1 | 0 | 0 | 1 | 1 | 13h |
    1| Display Inversion OFF
    -| 0 | 1 | ↑ | XX | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 20h |
    1| Display Inversion ON
    -| 0 | 1 | ↑ | XX | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 1 | 21h |
    1| Display OFF
    -| 0 | 1 | ↑ | XX | 0 | 0 | 1 | 0 | 1 | 0 | 0 | 0 | 28h |
    1| Display ON
    -| 0 | 1 | ↑ | XX | 0 | 0 | 1 | 0 | 1 | 0 | 0 | 1 | 29h |
    Column
    Address | Set
    0 | 1 | ↑ | XX | 0 | 0 | 1 | 0 | 1 | 0 | 1 | 0 | 2Ah
    1 | 1 | ↑ | XX | SC[15:8] | 00
    1 | 1 | ↑ | XX | SC[7:0] | 00
    1 | 1 | ↑ | XX | EC[15:8] | 01
    1 | 1 | ↑ | XX | EC[7:0] | 3Fh
    Page | Address
    Set
    0 | 1 | ↑ | XX | 0 | 0 | 1 | 0 | 1 | 0 | 1 | 1 | 2Bh
    1 | 1 | ↑ | XX | SP[15:8] | 00
    1 | 1 | ↑ | XX | SP[7:0] | 00
    1 | 1 | ↑ | XX | EP[15:8] | 00h
    
    1 | 1 | ↑ | XX | EP[7:0] | EFh |
    Memory | Write
    0 | 1 | ↑ | XX | 0 | 0 | 1 | 0 | 1 | 1 | 0 | 0 | 2Ch |
    1 | 1 | ↑ | D[17:0] | XX
    .....
    ...
    .
    `;
    

    5 Attachments

    • ILI9341_cmds1.png
    • ILI9341_cmds2.png
    • ILI9341_cmds3.png
    • ILI9341_cmds4.png
    • ILI9341_cmds5.png
  • Completed annotations in both command list files as taken from respective data sheet .pdf files and wrote some standalone GC9A01_ILI9341_cmds_map.html file that consumes the annotated data and renders it in the browser in various ways:

    ** Main representations of the commands for each of the controllers

    • 16x16 matrixes with the command placed by their 0x00 - high / low Nibble code value
    • Lists with all commands with merged in commands of the other controller
    • Pure lists of all command

    Clicking on the ## and 0x## command ids (in bold) is forward cycling from/thru:

    • matrix
    • mixed in list
    • pure list

    Clicking on the command names (in bold) is navigating 'backwards' from/to:

    • pures list
    • mixed in list
    • matrix

    Note *The gray marked matrix cell and list entries in the mixed in list show which command id (0x##) is not available in the other matrix or list. Colons in a matrix cell indicated that the other controller has a command with that code.

    Attached is the browser loadable GC9A01_ILI9341_cmds_map.html file - just click on it - and two screenshots. The first one shows the matrixes and the second one shows part of the a merged in list.

    The next post has a brief about the JavaScript in the .html file.


    3 Attachments

  • The JavaScript for rendering the matrixes and lists:

    • 'Reads' the annotated command list data from a multi-line JavaScript string...
    • ...and re-composes for each command 1 to n lines (in loadGC9A01 and loadILI9341(...) functions).
    • Creates for each controller a Commands-object (using function Cmds(...) constructor).
    • Creates command-objects for all commands and headers as 'round pegs in square holes' (using function Cmd(...) constructor) and some other data-objects and places references of them in multiple lists for the various needs in rendering and usage:
      • Plain array list with command AND header objects
      • An object with a property for each command with the 0x## command id as name
      • The 16x16 matrix withe the coverage of the commands
    • Updates the matrixes with the commands-commands object (change . to : where other controller has a command for the code).
    • Renders the matrixes.
    • Renders the mixed-in lists.
    • Renders the pure lists.

    Rendering is plain generation of html with short inline event handlers invoking global JavaScript functions. Some CSS is defined and as classes and some is inline (looking for TCL).

    It was a fun experience to come up with minimal annotation on tables copied from .pdf and write the complementing logic for the rendering. Noteworthy is the debug support for getting the annotations right: an incrementing line counter - lCnt - set to the line number of the first line of the multiline of the command list data and some other intermediary data and the initial pure list rendering helped to quickly get all annotations complete and straight.

    To see the annotated, complete command list data string, click/'run' the .html filein/from the previous post and look at the source in the browser (or download it and look at it in an editor).

    Here the html code w/ only fragments of the annotated, complete command list data string:

    <html>
    <!-- GC9A01  240x240 round/square clock display dirver /
         ILI9341 240x320 rectangular display w/ and w/o (resistive) touch screen
         commands comparions / mapping
         in space of Espruino.com
         20211005_allObjects;
      -->
    <head>
    <title>GC9A01 / ILI9341 LCD Controller Commands Comparison / Mapping by ao</title>
    <style>
    table { border: 1; }
    h, td, th { border: 1px solid grey; }
    td { text-align: center; vertical-align: top; font-family: Monaco, Lucida Sans Typewriter, Couorier New, sans-serif; }
    th { text-align: center; vertical-align: top; font-family: Monaco, Lucida Sans Typewriter, Couorier New, sans-serif; }
    tr.cmd1_mx>td { background-color: [#FFFFE0](https://forum.espruino.com/search/?q=%23FFFFE0); border-top: 3px solid [#FFFFFF](https://forum.espruino.com/search/?q=%23FFFFFF); border-left: 3px solid [#FFFFFF](https://forum.espruino.com/search/?q=%23FFFFFF); padding: 0.2em; cursor: pointer; }
    tr.cmd1_l0>td { background-color: [#FFFFE0](https://forum.espruino.com/search/?q=%23FFFFE0); border-top: 1px solid #171717; }
    tr.cmd1_lx>td { background-color: [#FFFFF0](https://forum.espruino.com/search/?q=%23FFFFF0); } 
    tr.cmd2_mx>td { background-color: [#E0FFFF](https://forum.espruino.com/search/?q=%23E0FFFF); border-top: 3px solid [#FFFFFF](https://forum.espruino.com/search/?q=%23FFFFFF); border-left: 3px solid [#FFFFFF](https://forum.espruino.com/search/?q=%23FFFFFF); padding: 0.2em; cursor: pointer; }
    tr.cmd2_l0>td { background-color: [#E0FFFF](https://forum.espruino.com/search/?q=%23E0FFFF); border-top: 1px solid #171717; }
    tr.cmd2_lx>td { background-color: [#F0FFFF](https://forum.espruino.com/search/?q=%23F0FFFF); }
    tr.cmd3_l0>td { background-color: [#D8BFD8](https://forum.espruino.com/search/?q=%23D8BFD8); border-top: 1px solid #171717; }
    tr.cmd3_lx>td { background-color: [#E6E6FA](https://forum.espruino.com/search/?q=%23E6E6FA); }
    table.cmds { border-collapse: collapse; }
    table.cmds>td { margin:0; padding:2px; border:1px solid grey; }
    .hbar { margin: 0.8em 0 0 0; height:2em; background-color:#FFC0CB; }
    .topLink { margin: 0 0 0.6em 0; height:1em; }
    </style>
    </head>
    <body onload="loadCmds(); renderCmds();">
    <a id="top"><h3>GC9A01 / ILI9341 LCD Controller Commands Comparison / Mapping by allObjects</h3>
    <p><i>Information is taken from respective data sheet .pdfs and annotated for rendering.</i></p>
    <div style="display:none;">
    <button onclick="loadCmds();">Load</button> -
    <button onclick="renderCmds();">Render</button>
    </div>
    <div>
    Table of content:<ul>
    <li><a href="ILI9341_GC9A01_mxs">ILI9341 <--> GC9A01 Command Matrixes</a> - Hover over and click cells</li>
    <li><a href="#ILI9341_GC9A01">ILI9341 ---> GC9A01 commands mixed in</a> - Click bold 0x## command id or name</li>
    <li><a href="#GC9A01_ILI9341">GC9A01 ---> ILI9341 commands mixed in</a> - Click bold 0x## command id or name</li>
    <li><a href="#GC9A01">GC9A01 commands</a> - Click bold 0x## command id or name</li>
    <li><a href="#ILI9341">ILI9341 commands</a> - Click bold 0x## command id or name</li>
    </div>
    <div class="hbar""></div>
    <div class="topLink"><a id="ILI9341_GC9A01_mxs"></a><a href="#top">top</a></div>
    <div><table><tr><td id="ILI9341mx" style="border:0;"></td>
            <td style="border:0;">&nbsp;&nbsp;&nbsp;</td>
            <td id="GC9A01mx" style="border:0;"></td></tr></table></div>
    <div class="hbar""></div>
    <div class="topLink"><a id="ILI9341_GC9A01"></a><a href="#top">top</a></div>
    <div id="cmdsILI9341_mi_cmdsGC9A01"></div>
    <div class="topLink"><a id="ILI9341_GC9A01"></a><a href="#top">top</a></div>
    <div id="cmdsGC9A01_mi_cmdsILI9341"></div>
    <div class="hbar""></div>
    <div class="topLink"><a id="GC9A01"></a><a href="#top">top</a></div>
    <div id="cmdsGC9A01"></div>
    <div class="hbar""></div>
    <div class="topLink"><a id="ILI9341"></a><a href="#top">top</a></div>
    <div id="cmdsILI9341"></div>
    <div class="hbar""></div>
    <div class="topLink"><a id="bot"></a><a href="#top">top</a></div>
    <script>
    var cmdsGC9A01, cmdsILI9341;
    function loadCmds() {
      loadGC9A01(1); loadILI9341(2);
    }
    function renderCmds() {
      cmdsILI9341.adjustWith(cmdsGC9A01);    cmdsGC9A01.adjustWith(cmdsILI9341);
      cmdsILI9341.renderMx(cmdsGC9A01);      cmdsGC9A01.renderMx(cmdsILI9341);
      cmdsILI9341.renderMixedIn(cmdsGC9A01); cmdsGC9A01.renderMixedIn(cmdsILI9341);
      cmdsGC9A01.render();                   cmdsILI9341.render();
    }
    </script><script>
    
    // --------------------------
    
    function loadGC9A01(clrId) {
    
    var lCntDataStart = 80; // for annotation debugging - 1st line where multi-line cmds data starts / opening back tick
    var cmdsData /* cmds source ILI9341 */ = `
    A|e GC9A01 Regular Command Set |
    A| C_ID | Command Function
    -| D/CX | RDX | WRX | D17-8 | D7 | D6 | D5 | D4 | D3 | D2 | D1 | D0 | HEX |
    5| Read Display Identification Information 2
    -| 0 | 1 | ^ | XX | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 04h |
    -| 1 | ^ | 1 | XX | X | X | X | X | X | X | X | X | XX |
    -| 1 | ^ | 1 | XX |8 ID_1[7:0]                    | 00 |
    -| 1 | ^ | 1 | XX |8 ID_2[7:0]                    | 9A |
    -| 1 | ^ | 1 | XX |8 ID_3[7:0]                    | 01 |
    6| Read Display Status
    -| 0 | 1 | ^ | XX | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 1 | 09h |
    -| 1 | ^ | 1 | XX | X | X | X | X | X | X | X | X | XX |
    -| 1 | ^ | 1 | XX |7 D[31:25]                 | X | 00 |
    -| 1 | ^ | 1 | XX | X |3 D[22:20] |4 D[19:16]     | 61 |
    -| 1 | ^ | 1 | XX | X | X | X | X | X |3 D[10:8]  | 00 |
    -| 1 | ^ | 1 | XX |3 D[7:5]   | X | X | X | X | X | 00 |
    1| Enter Sleep Mode
    -| 0 | 1 | ^ | XX | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 10h |
    1| Sleep OUT
    -| 0 | 1 | ^ | XX | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 1 | 11h |
    1| Partial Mode ON
    -| 0 | 1 | ^ | XX | 0 | 0 | 0 | 1 | 0 | 0 | 1 | 0 | 12h |
    #
    # ....
    # for complete annotated command list, sie source of clickable .html
    # ....
    #
    7| SET_GAMMA4
    -| 0 | 1 | ^ | XX | 1 | 1 | 1 | 1 | 0 | 0 | 1 | 1 | F3h |
    -| 1 | 1 | ^ | XX | 0 |7 dig2gam_vr43_p[6:0]                  | 3F |
    -| 1 | 1 | ^ | XX |3 dig2gam_vr27_p[2:0] |5 dig2gam_vr57_p[4:0] | 98 |
    -| 1 | 1 | ^ | XX |3 dig2gam_vr36_p[2:0] |5 dig2gam_vr59_p[4:0] | B4 |
    -| 1 | 1 | ^ | XX | 0 | 0 |6 dig2gam_vr61_p[5:0]  | 14 |
    -| 1 | 1 | ^ | XX | 0 | 0 |6 dig2gam_vr62_p[5:0]              | 18 |
    -| 1 | 1 | ^ | XX |4 dig2gam_vr50_p[3:0] |4 dig2gam_vr63_p[3:0] | CD |
    `;
    cmdsGC9A01 = new Cmds("GC9A01",clrId,cmdsData);
    cmdsGC9A01.load(lCntDataStart);
    }
    </script><script>
    
    // --------------------------
    
    function loadILI9341(clrId) {
    
    var lCntDataStart = 127; // for annotation debugging - 1st line where multi-line cmds data starts / opening back tick
    var cmdsData /* cmds source ILI9341 */ = `
    A|e ILI9341 Regular Command Set |
    A| Command Function
    -| D/CX | RDX | WRX | D17-8 | D7 | D6 | D5 | D4 | D3 | D2 | D1 | D0 | Hex |
    1| No Operation
    -| 0 | 1 | ^ | XX | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 00h |
    1| Software Reset
    -| 0 | 1 | ^ | XX | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 01h |
    5| Read Display Identification Information
    -| 0 | 1 | ^ | XX | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 04h |
    -| 1 | 1 | ^ | XX | X | X | X | X | X | X | X | X | XX |
    -| 1 | ^ | 1 | XX |8 ID1 [7:0]                    | XX |
    -| 1 | ^ | 1 | XX |8 ID2 [7:0]                    | XX |
    -| 1 | ^ | 1 | XX |8 ID3 [7:0]                    | XX |
    6| Read Display Status
    -| 0 | 1 | ^ | XX | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 1 | 09h |
    -| 1 | ^ | 1 | XX | X | X | X | X | X | X | X | X | XX |
    -| 1 | ^ | 1 | XX |7 D [31:25]                | X | 00 |
    -| 1 | ^ | 1 | XX | X |3 D [22:20] |4 D [19:16]   | 61 |
    -| 1 | ^ | 1 | XX | X | X | X | X | X |3 D [10:8] | 00 |
    -| 1 | ^ | 1 | XX |3 D [7:5]  | X | X | X | X | X | 00 |
    3| Read Display Power Mode
    -| 0 | 1 | ^ | XX | 0 | 0 | 0 | 0 | 1 | 0 | 1 | 0 | 0Ah |
    -| 1 | ^ | 1 | XX | X | X | X | X | X | X | X | X | XX |
    -| 1 | ^ | 1 | XX |6 D [7:2]              | 0 | 0 | 08 |
    3| Read Display MADCTL
    -| 0 | 1 | ^ | XX | 0 | 0 | 0 | 0 | 1 | 0 | 1 | 1 | 0Bh |
    -| 1 | ^ | 1 | XX | X | X | X | X | X | X | X | X | XX |
    -| 1 | ^ | 1 | XX |6 D [7:2]              | 0 | 0 | 00 |
    3| Read Display Pixel Format
    -| 0 | 1 | ^ | XX | 0 | 0 | 0 | 0 | 1 | 1 | 0 | 0 | 0Ch |
    -| 1 | ^ | 1 | XX | X | X | X | X | X | X | X | X | XX |
    -| 1 | ^ | 1 | XX | RIM |3 DPI [2:0] | X |3 DBI [2:0] | 06 |
    3| Read Display Image Format
    -| 0 | 1 | ^ | XX | 0 | 0 | 0 | 0 | 1 | 1 | 0 | 1 | 0Dh |
    -| 1 | ^ | 1 | XX | X | X | X | X | X | X | X | X | XX |
    -| 1 | ^ | 1 | XX | X | X | X | X | X |3 D [2:0]  | 00 |
    3| Read Display Signal Mode
    -| 0 | 1 | ^ | XX | 0 | 0 | 0 | 0 | 1 | 1 | 1 | 0 | 0Eh |
    -| 1 | ^ | 1 | XX | X | X | X | X | X | X | X | X | XX |
    -| 1 | ^ | 1 | XX |6 D [7:2]              | 0 | 0 | 00 |
    3| Read Display Self-Diagnostic Result
    -| 0 | 1 | ^ | XX | 0 | 0 | 0 | 0 | 1 | 1 | 1 | 1 | 0Fh |
    -| 1 | ^ | 1 | XX | X | X | X | X | X | X | X | X | XX |
    -| 1 | ^ | 1 | XX |2 D [7:6] | X | X | X | X | X | X | 00 |
    1| Enter Sleep Mode
    -| 0 | 1 | ^ | XX | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 10h |
    1| Sleep OUT
    -| 0 | 1 | ^ | XX | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 1 | 11h |
    1| Partial Mode ON
    -| 0 | 1 | ^ | XX | 0 | 0 | 0 | 1 | 0 | 0 | 1 | 0 | 12h |
    #
    # ....
    # for complete annotated command list, sie source of clickable .html
    # ....
    #
    4| Interface Control
    -| 0 | 1 | ^ | XX | 1 | 1 | 1 | 1 | 0 | 1 | 1 | 0 | F6h |
    -| 1 | 1 | ^ | XX | MY_EOR | MX_EOR | MV_EOR | X | BGR_EOR | X | X | WEMODE | 01 |
    -| 1 | 1 | ^ | XX | X | X |2 EPF [1:0] | X | X |2 MDT [1:0] | 00 |
    -| 1 | 1 | ^ | XX | X | X | ENDIAN | X |2 DM [1:0] | RM | RIM | 00 |
    `;
    cmdsILI9341 = new Cmds("ILI9341",clrId,cmdsData);
    cmdsILI9341.load(lCntDataStart);
    }
    </script>
    <script>
    var p; // prototype
    
    // -----------------------------
    
    function Cmds(id, clrId, data) {
    
      this.id = id;
      this.clrId = clrId;
      this.data = data;
      this.cmdsById = {};
      this.cmds = [];
      this.cmx = [];
      for (var j=0; j<16; j++) { var r = [];
        for (var i=0; i<16; i++) { r.push([j,i,"."]); // [0]high Nib, [1]lowNib, [2]commandHex }
        } this.cmx.push(r); }
    } p = Cmds.prototype;
    p.gtNodeId = function() { return "cmds"+this.id; } // "cmdsILI9341"
    p.load = function(lCntDataStart) { // <---- source code line where multi-line string begins / line of opening back tick
      var loadC = { lCnt:lCntDataStart - 1 // because it does inc at the beginning
                  , pos:0, eodPos:this.data.length, lin:"" }
        , cmd = null
        , lin, bLCt, lCnt, lChr, linSeg, eChr, segs, cmdh, cmdId, hiN, loN
        ;
      while ((linSeg = this._nexLin(loadC).lin).length > 0) {
        // console.log(loadC.lCnt+": "+linSeg);
        if (! cmd) { // cmd does not exist yet / has not started yet expecting line with num or Alpha lines begin
          if ((lCnt = "A".indexOf(lChr = linSeg.charAt(0))+1) > 0) { // ABC... 123...line(s) heading, currently only 1 lines
            cmd = new Cmd("H",loadC.lCnt,lCnt,linSeg);
          } else if ((lCnt = "123456789abcdefg".indexOf(lChr)+1) > 0) { // 123... 123...line(s) cmd, currently 1..6 lines
            cmd = new Cmd("C",loadC.lCnt,lCnt,linSeg);
          } else { throw "Unexpected first line(Segment) "+loadC.lCnt+": "+linSeg; }
          this.cmds.push(cmd); lin=linSeg.substr(1);
        } else { // cmd exists, append to current 'open' line
          if ((lChr = linSeg.charAt(0)) == "-") { // continuation
            lin+=linSeg.substr(1); // drop line char and concatenate
          } else { throw "Unexpected 2nd to n-nth line(Segment) "+loadC.lCnt+": "+linSeg; }
        }
        eChr = lin.charAt(lin.length - 1);
        if (eChr == "|") { // e<a href="GC9A01_ILI9341_cmds_map.html">GC9A01 / ILI9341 LCD Controller Commands Comparison / Mapping by ao</a>nd of line - finish line
          if (cmd.lins.length == 0) { // 1st line complete - first line(segment) added to lines on cmd construction
            if        (cmd.typ == "C") { // A command line (not a header one) - has command code / id as last arg
              segs = lin.split ("|"); cmdh = segs[segs.length - 2].trim().toUpperCase();
              hiN = "0123456789ABCDEF".indexOf(cmdh.charAt(0)); loN = "0123456789ABCDEF".indexOf(cmdh.charAt(1));
              if (cmdh.length != 3 || hiN < 0 || loN < 0) {
                throw "Unexpected XXh(ex) of command at/near n-nth line(Segment) "+loadC.lCnt+": "+linSeg; }
              cmd.stId(cmdId = "0x"+cmdh.substring(0,2)); this.cmdsById[cmd.id] = cmd;
              this.cmx[hiN][loN][2] = cmdId.substr(2); // occupying command coverage matrix
            } else if (cmd.typ == "H") { // A header line (not a command one)
              // nothing id-wise to do for header
            } else { throw "Unexpected line type: "+cmd.typ+" (line: "+lin+")" }
          }
          if (cmd.lins.length < cmd.lCnt) { // check for too many lines / should actually never fire
            cmd.lins.push(lin); lin = "";
            if (cmd.lins.length == cmd.lCnt) { // command complete, 'close' it - all lines added
              cmd.close();
              cmd = null; // setup for next cmd / controls start of next cmd
            }
          } else { throw "Unexpected to many lines at line(Segment) "+loadC.lCnt+": "+linSeg; }
        }
        linSeg = ""; 
      }   
      return this;
    }
    p._nexLin = function(c) { // skip empty and # commented linea
      var lin = "", eolPos;
      while ( c.pos < c.eodPos && ! lin.length > 0) {
        c.lCnt++; // inc source line count
        eolPos = this.data.indexOf("\n",c.pos);
        if (eolPos < 0) { eolPos = c.eodPos; }
        if (c.pos < eolPos) { lin = this.data.substring(c.pos, eolPos).trim(); }
        c.pos = eolPos + 1;
        if (lin.length > 0 && lin.charAt(0) == "#") { lin == ""; }
      }
      c.lin = lin;
      return c;
    }
    p.adjustWith = function(aCmds) { // adjust mainly matrix (replace . with : when other cmd code present)
      var cmx = this.cmx, r, c, v
        , aCmx = aCmds.cmx, aR, aC, aV
        , j, i
        ;
        for (j=0;j<16;j++) { r = cmx[j]; aR = aCmx[j];
          for (i=0;i<16;i++) { c = r[i]; aC = aR[i]; 
            if (c[2] == "." && aC[2] != ".") {
              c[2] = ":"; 
        } } }
    }
    p.render = function() { // render all own
      var _ = this
        , hfs = ['<table class="cmds">'
                +'<tr style="display:none;"><td>.</td>'
                +   '<td>.</td><td>.</td><td>.</td><td>.</td><td>.</td><td>.</td><td>.</td>'
                +   '<td>.</td><td>.</td><td>.</td><td>.</td><td>.</td><td>.</td><td>.</td></tr>'
                ]
        , id = this.id
        , idSel = "_"+id
        , clrId = this.clrId
        ;
      this.cmds.forEach(function(cmd) { hfs.push(cmd.render(idSel, clrId, clrId)); });
      hfs.push('</table>');
      document.getElementById(this.gtNodeId()).innerHTML = hfs.join("");
    }
    p.renderMixedIn = function(mCmds) { // render own and mix in other cmds where available
      var _ = this
        , id = _.id
        , idSel = "mi"+id
        , clrId = _.clrId
        , mId = mCmds.id
        , mClrId = mCmds.clrId // color id of cmd to mix in
        , hfs = ['<table class="cmds">'
                +'<tr style="display:none;"><td>.</td>'
                +   '<td>.</td><td>.</td><td>.</td><td>.</td><td>.</td><td>.</td><td>.</td>'
                +   '<td>.</td><td>.</td><td>.</td><td>.</td><td>.</td><td>.</td><td>.</td></tr>'
                +'<tr class="cmd'+clrId+ '_l0"><td colspan="15" style="text-align:left;">'+id+' commands</td><tr>'
                +'<tr class="cmd'+mClrId+'_l0"><td colspan="15" style="text-align:left;">mixed-in with '+mId+' commands:</td></tr>'
                +'<tr><td colspan="15" style="text-align:left;">GRAY MARKED ones are NOT AVALABLE in '+mId+'</td></tr>'
                ]
        , mCmd // cmd to mix in
        ;
      this.cmds.forEach(function(cmd) {
        if (cmd.typ == "C") { // only commands
          mCmd = mCmds.cmdsById[cmd.id];
          hfs.push(cmd.render(idSel, clrId, (mCmd) ? clrId : 0));
          if (mCmd) { hfs.push(mCmd.render(null, mClrId, mClrId)); }
        }
      });
      hfs.push('</table>');
      document.getElementById(this.gtNodeId()+"_mi_"+mCmds.gtNodeId()).innerHTML = hfs.join("");
    }
    p.renderMx = function(mCmds) {
      var id = this.id, csById = this.cmdsById, cmx = this.cmx, cr, c, j, i, h, cc, cId
        , mCmdsById = mCmds.cmdsById, mCmd
        , trBeg = '<tr class="cmd'+this.clrId+'_mx" style="border-left:1px solid [#EFEFEF](https://forum.espruino.com/search/?q=%23EFEFEF);">', hStr
        , hs = ['<table><tr class="cmd'+this.clrId+'_mx" style="visibility:hidden;">'
               +'<td>XX</td><td>XX</td><td>XX</td><td>XX</td><td>XX</td><td>XX</td><td>XX</td><td>XX</td>'
               +'<td>XX</td><td>XX</td><td>XX</td><td>XX</td><td>XX</td><td>XX</td><td>XX</td><td>XX</td>'
               +'</tr>']
        ;
      hs.push('<tr><th colspan="16">'+id+' Commands Matrix / Coverage</th></tr>');
      hs.push('<tr><td colspan="16" id="inmc'+id+'"'
             +' style="text-align:left; padding-left:0.3em;">&nbsp;<br>&nbsp;</td></tr>');
      for (j=0; j<16; j++) { cr = cmx[j]; hs.push(trBeg);
        for (i=0; i<16; i++) {  h = "0123456789ABCDEF".charAt(j)+"0123456789ABCDEF".charAt(i);
          hs.push('<td id="0x'+h+'m'+id+'"');
          if (( cc = cr[i][2]) != "." && cc != ":") { cId = "0x"+cc;
            hs.push(' onclick="mxcClicked(this);" onmouseenter="mxcEnter(this);" onmouseleave="mxcLeave(this);"');
            hs.push(' title="'+cId+' - '+csById[cId].nam);
            if (mCmd = mCmdsById[cId]) {
              hs.push('\n     ---> '+mCmd.nam+'"');
              hs.push(' style="');
            } else {
              hs.push('" style="background-color:#F0F0F0;');
            }
          } else {
            hs.push(' style="cursor: default;')
          }
          if (i === 0) { hs.push(' border-left:1px solid [#EFEFEF](https://forum.espruino.com/search/?q=%23EFEFEF);'); } 
          hs.push('">'+cc+'</td>'); // close style in td beg tag
      } hs.push('</tr>'); } hs.push('</table>');
      hStr = hs.join("");
      document.getElementById(id+"mx").innerHTML = hStr;
    }
    </script>
    <script>
    
    // -----------------------------
    
    function Cmd(typ,lBeg,lCnt,linSeg0) {
    
      this.id = "";
      this.nam = "";
      this.typ = typ;
      this.lBeg = lBeg;
      this.lCnt = lCnt;
      this.lins = [];
      this.linSeg0 = linSeg0;
    } p = Cmd.prototype;
    p.stId  = function(id) { this.id = id; }
    p.close = function() {
      var elt, elts = this.lins[0].split("|");
      this.nam = (((elt = elts[1]).charAt(0) == " ") ? elt : elt.substr(1)).trim();
      this.linSeg0 = "";
      console.log(((this.typ == "C") ? this.id+": " : "***** ")+this.nam);
    }
    p.render = function(cmdsIdSel, clrId, clrIdAlt) {
      var _ = this, h = [], elts, edx, edxMax, elt, cChr, cols, xCols, cCols, bPos;
      if (this.typ == "C") { // command
        this.lins.forEach(function(lin,x) {
          elts = lin.split("|");
          edxMax = elts.length - 2; 
          if (x == 0) {
            h.push('<tr class="cmd'+clrId+'_l0">');
            h.push('<td style="text-align:left; padding:0 0.5em 0 0.5em;');
            if (clrId != clrIdAlt) { h.push(' background-color: [#C0C0C0](https://forum.espruino.com/search/?q=%23C0C0C0);'); } // [#DDA0DD](https://forum.espruino.com/search/?q=%23DDA0DD) [#C0C0C0](https://forum.espruino.com/search/?q=%23C0C0C0)
            if (cmdsIdSel) { h.push(' font-weight:bold; cursor:pointer;'); }
            h.push('"');
            if (_.lCnt > 1) { h.push(' rowspan="'+_.lCnt+'"'); }
            if (cmdsIdSel) {
              h.push(' id="'+_.id+cmdsIdSel+'_id"');
              h.push(' onclick="'+((cmdsIdSel.charAt(0) == "m") ? 'miIdClicked' : 'lIdClicked')+'(this);"'); }
            h.push('>');
            h.push(_.id);
            h.push('</td>')
            h.push('<td style="width:12.0em; text-align:left; font-family:Arial;');
            if (cmdsIdSel) { h.push(' font-weight:bold; cursor:pointer;'); }
            h.push('"');
            if (_.lCnt > 1) { h.push(' rowspan="'+_.lCnt+'"'); }
            if (cmdsIdSel) {
              h.push(' id="'+_.id+cmdsIdSel+'_nam"');
              h.push(' onclick="'+((cmdsIdSel.charAt(0) == "m") ? 'miNameClicked' : 'lNameClicked')+'(this);"'); }
            h.push('>');
            h.push(_.nam);
            h.push('</td>');
            edx = 1;
          } else {
            h.push('<tr class="cmd'+clrId+'_lx">');
            edx = 0
          }
          while (++edx <= edxMax) {
            elt = elts[edx]; cChr = elt.charAt(0);
            h.push('<td');
            if (edx == edxMax) { h.push(' style="text-align:left; padding:0 0.5em 0 0.5em;"'); }
            if (cChr == " ") {
              bPos = 0;
            } else {
              if ((cols = "123456789abcde".indexOf(cChr)+1)>1) { h.push(' colspan="'+cols+'"'); }
              bPos = 1;
            }
            h.push('>'+elt.substr(bPos).trim());
            h.push('</td>');
          }
          h.push('</tr>');
        } );
      } else { // header
        this.lins.forEach(function(lin,x) {
          elts = lin.split("|");
          edxMax = elts.length - 2; 
          h.push('<tr class="cmd'+clrId+'_hdr">');
          edx = 0;
          while (++edx <= edxMax) {
            elt = elts[edx]; cChr = elt.charAt(0);
            h.push('<th');
            if (x == 0 && edx == 1) {
              if (edx == 1 && _.lCnt > 1) { h.push(' rowspan="'+_.lCnt+'"'); }
              xCols = 1;
            } else {
              xCols = 0;
            }
            cols = xCols + 1; bPos = 0;
            if (cChr != " ") {
              if ((cCols = "123456789abcde".indexOf(cChr)+1)>1) { cols = xCols + cCols; }
              bPos = 1;
            }
            if (cols > 1) { h.push(' colspan="'+cols+'"'); }
            h.push('>'+elt.substr(bPos).trim());
            h.push('</th>');
          }
          h.push('</tr>');
        } );
      }
      h = h.join("");
      return h;
    }
    </script>
    <script>
    
    //  -----------------------------
    
    // (value driven) event handlers; function name (and 'evented' dom node id) determine action
    
    function mxcEnter(mxc) { // matrix cell entering
      var elts =  mxc.title.split("\n");
      if (elts.length == 2) { elts[1] = '&nbsp;&nbsp;'+elts[1]; } else { elts.push('&nbsp;'); }
      document.getElementById("inmc"+mxc.id.substring(5)).innerHTML = elts.join("<br>")
    }
    function mxcLeave(mxc) { // matrix cell leaving
      document.getElementById("inmc"+mxc.id.substring(5)).innerHTML = '&nbsp;<br>&nbsp;'; }
    function mxcClicked(mxc) { // matrix cell (cmd id) clicked --> mixed in list
      location.hash = "#"+mxc.id.replace("m","mi")+"_id"; }
    function miIdClicked(miIdC) { // mixed in list cmd id clicked -->  pure list
      location.hash = "#"+miIdC.id.replace("mi","_"); }
    function miNameClicked(miNameC) { // mixed in list cmd name clicked ---> back to matrix
      location.hash = "#ILI9341_GC9A01_mxs"; }
    function lIdClicked(lIdC) { // pure list cmd id clicked ---> wrap-around back to matrix
      location.hash = "#ILI9341_GC9A01_mxs"; }
    function lNameClicked(lNameC) { // [ire list cmd name clicked ---> back to mixed in list
      location.hash = "#"+lNameC.id.replace("_","mi").replace("minam","_id"); }
    </script>
    </body>
    </html>
    
  • Holy cats! let me catch up on this. I'm waiting for my device to arrive in the post, should hit my door this week. Thank you so much for your efforts. Looking forward to getting some pixels moving.

  • @user134932

    Glad to hear; looking forward to see you succeed. Since a have a feeble - or love - for (all kinds of) displays, I could but go forward and order some for me of the sort you reference with the GC9A01/SPI display controller and another kind of using the ILI9391/8..18bit 'paralell' (8080 interface). When I started with displays, Espruino was on slower hardware and the serial communication did not help with speed (many enhancements though came along and made it much better and what it is today). At that time, @Gordon 'cheered' me on to go ahead and add a prallel interface... Espruino Original board had enough pins do do so... but my brain did not have the skills-legs to tackle that. May be now has come the time to do that. (Exploring 2.8" Color TFT Touch LCD by Pacman Game attempt - More what you see published there was going on afterwards, but it never came to full fruition. Speed was one thing. The other one was memory: the definition of the pac man 'board' - even when heavily optimized - landed me in OUT OF MEMORY dungeon... for good... May be I go back and pick it up again).

    Some of my other display endeavors you can find in my conversations on this forum, and many posts in other forum members' posts.

    I list of some:

  • updated posts #4 and #5 with most recent versions of description and code. Some more enhancement could be implemented, but I'd like to make some use of it to see it 'work' in practice.

  • user134932, is there some progress / success to report on your side regarding driving these displays with Espruino?

  • That's some nice work there, thank you for that! I have a hopefully easy Q. I am simply trying to identify the display that I have, a round 1.3" (probably a GC9A01) but I don't think I've got the read part of spi correct. I'm trying to ure spi.send:
    let c = new Uint8Array([4,0,0,0]); JSON.stringify(SPI1.send(c,CS)); assuming SPI1 and CS are initialized correctly, should that code return the manufacturer information (command is 0x4, returns 4 bytes)?
    I've tried it on a known GC9A01 and it doesn't work. Bad syntax? Do I need to lower DC? any help appreciated!

  • Your spi should work the way you presented. With so little code you share it is though impossible to figure what is not going well. Setup/init of SPI1 and definition of CS would have to be known. Furthermore, the HW setup on breadboards can be challenging due to the quality of spring contacts and cables. The display controller needs a timely correct initialization sequence in order to operate.

  • Other thing is: have you set up MISO for SPI1? I doubt much example code for displays bothers with it as generally you don't read much from the display, it's usually writing.

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

Waveshare 1.28inch Round LCD Display 65K RGB Colors 240×240

Posted by Avatar for user134932 @user134932

Actions