Matrix Orbital GTT43A: PSoC 4 Interface

Summary

In the last several articles I have written about how to use and talk to the Matrix Orbital GTT43A.  Now it is time to write some code.  The PSoC4 program that I am going to show you has evolved over time as I added stuff to it.  For instance, while I was working on this program I ran into a problem where the I2C Bus would hang (the subject of the next article).  As such, some of the code that is in this program was written to help me debug that problem.  With that said, I wanted a program that:

  1. Is command line driven i.e. I can interact with my program via serial commands through the PC COM Port
  2. Can read 1 byte at a time (like I do on the bridge control panel)
  3. Can test the “read whole packet” code
  4. Can selectively send commands via a I2C or the UART
  5. Send test commands to the display e.g. reset, clear
  6. Test the display generated messages (like button presses)

All of this code was built to run on the CY8CKIT-044 which has a PSoC 4200M MCU

Schematic & Pin Assignment

All PSoC 4 projects start with a schematic.  In my schematic I have a UART setup to talk to the KitProg (called UART) and serve as the command processor, an I2C which directly attaches to the I2C bus that drives the display, and a UART that is also attached to the display which I called SCRUART.

The I2CFAIL pin in the schematic I used to help me debug the I2C problem (the subject of the next article)

PSoC 4200m Schematic

The pin assignment has the UART attached to the KitProg UART, the I2C attached to KitProg and the Display.  The SCRUART is attached to UART on the Display.

PSoC 4200M Pin Assignment

 

Main Event Loop

The main event loop has the following parts

  1. Read a character from the keyboard
  2. Process the keyboard command character
  3. Read data from the screen
    1. If you are in packet mode read a whole packet
    2. If you are in streaming mode read one byte

There are three system modes.

  1. IDLE = Dont read from the screen
  2. PACKET = Read whole packets (poll for complete packets)
  3. STREAMING = read bytes (polling)

I also have setup the program to read/write bytes to the UART and I2C.  This is called the “comInterface”.

The enumerated type systemMode is used to setup the polling mode (each time through the main loop, what does it do?).

typedef enum {
    MODE_IDLE,
    MODE_PACKET,
    MODE_STREAMING
} systemMode_t;

systemMode_t systemMode=MODE_IDLE;

typedef enum {
    INTERFACE_I2C,
    INTERFACE_UART
} cominterface_t;

cominterface_t comInterface=INTERFACE_I2C;

The actual main section of the code

  1. Starts by initializing the UART, SCRUART and I2C.
  2. On line 299 it reads a character, then switches on the character to figure out which command the user has type.

You can see that ‘u’ and ‘U’ change the communication interface from UART to I2C and back.

int main(void)
{
    CyGlobalIntEnable; /* Enable global interrupts. */
    uint32 returncode;
    
    UART_Start();
    UART_UartPutString("Started\r\n");
    I2C_Start();
    SCRUART_Start();
    
    char c;
     
    for(;;)
    {
        c = UART_UartGetChar();
        switch(c)
        {
            case 0:
            break;
            
            case 'u':
                UART_UartPutString("I2C Mode\r\n");
                comInterface = INTERFACE_I2C;
            break;
            
            case 'U':
                UART_UartPutString("UART Mode\r\n");
                comInterface = INTERFACE_UART;
            break;

The end of the loop handles the “?” case… in other words print out all of the commands.  Then based on the system mode, it either reads a whole message packet from the display or it reads only byte.

           case '?':
                UART_UartPutString("------Communication Mode------\r\n");
                UART_UartPutString("u\tI2C Mode\r\n");
                UART_UartPutString("U\tUART Mode\r\n");
                
                UART_UartPutString("------GTT43A Commands------\r\n");
                UART_UartPutString("N\tDefault Comm None\r\n");
                UART_UartPutString("I\tDefault Comm I2C\r\n");
                UART_UartPutString("S\tDefault Comm Serial\r\n");
                
                UART_UartPutString("e\tEcho abc\r\n");
                UART_UartPutString("R\tReset\r\n");
                UART_UartPutString("c\tSend Clear Screen\r\n");
                
                UART_UartPutString("------Communcation Commands------\r\n");
                UART_UartPutString("r\tRead one byte if IDLE\r\n");
                UART_UartPutString("p\tRead Packet if IDLE\r\n");
                
                UART_UartPutString("------System Mode------\r\n");
                UART_UartPutString("0\tTurn I2C polling off \r\n");
                UART_UartPutString("1\tTurn on I2C packet polling\r\n");
                UART_UartPutString("2\tRead i2c bytes \r\n");
                
                UART_UartPutString("------I2C Debugging------\r\n");
                UART_UartPutString("s\tPrint SCB Status\r\n");
                UART_UartPutString("z\tSend I2C Reset Sequence\r\n");
                UART_UartPutString("x\tPrint I2C SCL and SDA value\r\n");
            break;
        }
        
        switch(systemMode)
        {
            case MODE_IDLE:
            break;
            
            case MODE_PACKET:
                readPacket();
            break;
                
            case MODE_STREAMING:
                readByte();
            break;
        }

I created three keys (0,1,2) to change the system mode, from IDLE, to reading whole packets to reading bytes.

            // System Modes
            case '0':
                    I2CFAIL_Write(0);
                    UART_UartPutString("Packet Poling Off\r\n");
                    systemMode = MODE_IDLE;
                break;
               
            case '1':
                    I2CFAIL_Write(0);
                    UART_UartPutString("Packet Poling On\r\n");
                    systemMode = MODE_PACKET;
            break;
            case '2':
                    I2CFAIL_Write(0);
                    UART_UartPutString("Read continuous\r\n");
                    systemMode = MODE_STREAMING;
                    break;

While I was trying to figure out how things worked I wanted to be able to do one thing at a time. So I create ‘r’ to read one byte (like Bridge Control Panel) and ‘p’ to read a whole packet.  Notice that you really really only want to do this why you are not polling the display.

            // If you are IDLE you can read 1 byte with 'r' or read a whole packet with 'p'
            case 'r':  // Read byte
                if(systemMode != MODE_IDLE)
                    break;
                readByte(&data);
                
            break;
            case 'p': // read packet
                if(systemMode == MODE_IDLE)
                    readPacketI2C();
            break;

The last section of commands send various GTT2.0 commands to the display.  Notice that the writePacket function knows which system interface to use (either I2C or UART).

First, I declare some commands, just an array of bytes.

// These commands come the GTT 2.0 and GTT2.5 Protocol Manuals
uint8 clearCMD[] = { 0x58 };
uint8 resetCMD[] = { 0x01};
uint8 comI2CCMD[] = { 0x05, 0x02};
uint8 comNONECMD[] = { 0x05, 0x00};
uint8 comSERIALCMD[] = { 0x05, 0x01};
uint8 comECHOCMD[] = {0xFF,'a','b','c', 0};

Then I use them:

            case 'e':
                UART_UartPutString("Send Echo Command\r\n");
                writePacket(sizeof(comECHOCMD) , comECHOCMD);
            break;
                
            case 'c':
                UART_UartPutString("Sent Clear String\r\n");
                writePacket(sizeof(clearCMD),clearCMD);
            break;
            case 'R':
                UART_UartPutString("Sent Reset String\r\n");
                writePacket(sizeof(resetCMD),resetCMD);
            break;
            case 'I':
                UART_UartPutString("I2C Communcation Channel\r\n");
                writePacket(sizeof(comI2CCMD),comI2CCMD);
            break;
            case 'N':
                UART_UartPutString("NONE Communcation Channel\r\n");
                writePacket(sizeof(comNONECMD),comNONECMD);
            break;

Read Byte

In order to read one byte from the display I first determine which mode Im in, then call the appropriate sub-function.

uint32_t readByte(uint8_t *data)
{
    uint32_t returncode=0;
    switch(comInterface)
    {
        case INTERFACE_I2C:
            returncode = readByteI2C(data);
        break;
        case INTERFACE_UART:
            returncode = readByteUART(data);
        break;
    }
    sprintf(buff,"Returncode = %X Data=%d\r\n",(unsigned int)returncode,*data);
    UART_UartPutString(buff);

    return returncode;
}

The first sub function to read bytes via I2C.  To read a byte with no error checking you have to

  1. Send a Start
  2. Send the address
  3. Send the Read bit
  4. Clock it 8 times (this is exactly what the I2CMasterReadByte function does)
  5. Send an NAK
  6. Send a Stop

I ran into an I2C issue which I will talk about in the next article, however, if I see an error from any of these commands Ill put the system into MODE_IDLE and throw an error.  In addition I write a 1 to the I2CFAIL pin, which I am using to trigger the Oscilliscope (so I can see what is happening)

uint32_t readByteI2C(uint8_t *data)
{
    uint32 returncode;
    returncode = I2C_I2CMasterSendStart(I2CADDR,I2C_I2C_READ_XFER_MODE , I2CTIMEOUT);
    if(returncode)
    {
        sprintf(buff,"send start error %lX status %lX\r\n",returncode,I2C_I2CMasterStatus());
        UART_UartPutString(buff);
        I2CFAIL_Write(1);
        systemMode = MODE_IDLE;
        goto cnt;
    }
            
    returncode = I2C_I2CMasterReadByte(I2C_I2C_ACK_DATA,data,I2CTIMEOUT);
    if(returncode)
    {
        sprintf(buff,"read byte error %lX status %lX sda=%d scl =%d\r\n",returncode,I2C_I2CMasterStatus(),I2C_sda_Read(),I2C_scl_Read());
        UART_UartPutString(buff);
        I2CFAIL_Write(1);
        systemMode = MODE_IDLE;
        goto cnt;
    }
            
    returncode = I2C_I2CMasterSendStop(I2CTIMEOUT);
    if(returncode)
    {
        sprintf(buff,"send stop error %lX status %lX\r\n",returncode,I2C_I2CMasterStatus());
        UART_UartPutString(buff);
        I2CFAIL_Write(1);
        systemMode = MODE_IDLE;
        goto cnt;
    }
    
    cnt:
    return returncode;
}

Read Packet

For the packet read code I did the same thing as the byte read code.  Specifically I wrote an overall get packet, then called the correct read packet based on the

If you read the source code that Matrix Orbital gives you for drivers, you will find that it reads one byte at a time.  The problem with doing this is that you

  1. Send a start
  2. Send an I2C address
  3. Send a read bit
  4. Read the ACK
  5. Read a byte
  6. Send a NAK
  7. Send a stop

The problem with this approach is that it uses 11 bit-times extra per byte of overhead (steps 1-4) which kinda sucks.  So I wanted to write a complete packet reader.  My packet reader will

  1. Send a start
  2. Send an I2C address
  3. Send a read bit
  4. Read the ACK
  5. Read a byte  [This is the 254 that marks the start of the packet]
  6. ACK
  7. Read a byte [This is the command which identifies the packet]
  8. ACK
  9. Read a byte [The MSB of the Length]
  10. ACK
  11. Read a byte [The LSB of the Length]
  12. NAK
  13. If there is a length then:
  14. Send the start
  15. Send an I2C address
  16. Send a read bit
  17. Read the ACK
  18. read length -1 bytes
  19. ACK
  20. Read the last byte
  21. Send a NAK
  22. Send a stop

By spec you are supposed to NAK your last read byte to indicate that your read transaction is over… that means you have to NAK the last Length byte because there could be 0 bytes to read, in which case you would need to stop.  It would have been nice if the protocol let you send only one start, but Im pretty sure it was designed for UART, which doesn’t suffer from this problem.  Also as a side note, Im pretty sure that the MCU they are using doesn’t really care, but Im not willing to implement it incorrectly.

Here is the code:

void readPacketI2C()
{
    int length;
    int command;
    uint8_t data;
    uint32_t returncode;
    
    returncode = I2C_I2CMasterSendStart(I2CADDR,I2C_I2C_READ_XFER_MODE , I2CTIMEOUT);
    returncode |= I2C_I2CMasterReadByte(I2C_I2C_NAK_DATA,&data,I2CTIMEOUT);
    returncode |= I2C_I2CMasterSendStop(I2CTIMEOUT);
    
    // Something bad happened on the I2C Bus ....
    if(returncode)
    {
        systemMode = MODE_IDLE; 
        sprintf(buff,"I2C Return Code %X\r\n",(unsigned int)returncode);
        UART_UartPutString(buff);
    }
 
    // The screen returns a 0 when there is nothing in the buffer.
    if(data == 0)
    {
        return;
    }

    // This is bad because there was something other than a packet start byte
    if(data != 252)
    {
        sprintf(buff,"bad data = %d\r\n",data);
        UART_UartPutString(buff);
        systemMode = MODE_IDLE; // put it into nothing mode...
        return;
    }
    
    // We know that we have a command
    returncode = I2C_I2CMasterSendStart(I2CADDR,I2C_I2C_READ_XFER_MODE , I2CTIMEOUT);
    returncode |= I2C_I2CMasterReadByte(I2C_I2C_ACK_DATA,&data,I2CTIMEOUT); // command
    command = data;
    
    returncode |= I2C_I2CMasterReadByte(I2C_I2C_ACK_DATA,&data,I2CTIMEOUT); // length
    length = data<<8;
    returncode |= I2C_I2CMasterReadByte(I2C_I2C_NAK_DATA,&data,I2CTIMEOUT); // length
    length = length + data;
    returncode |= I2C_I2CMasterSendStop(I2CTIMEOUT);
    
    // If the packet has any data... then read it.
    if(length != 0)
    {
        returncode |= I2C_I2CMasterSendStart(I2CADDR,I2C_I2C_READ_XFER_MODE , I2CTIMEOUT);
    
        for(int i=0;i<length-1; i++)
        {
            I2C_I2CMasterReadByte(I2C_I2C_ACK_DATA,&data,I2CTIMEOUT); // length
            inbuff[i] = data;
        }

        // Read the last byte
        I2C_I2CMasterReadByte(I2C_I2C_NAK_DATA,&data,I2CTIMEOUT); // length
        inbuff[length-1] = data;
        returncode |= I2C_I2CMasterSendStop(I2CTIMEOUT);
        
        I2C_I2CMasterSendStop(I2CTIMEOUT);
    }
      
    sprintf(buff,"command = %d length = %d bytes= ",command,length);
    UART_UartPutString(buff);
    for(int i=0;i<length;i++)
    {
        sprintf(buff,"%d ",inbuff[i]);
        UART_UartPutString(buff);
    }
    UART_UartPutString("\r\n");
    
}

You can "git" these projects from

https://github.com/iotexpert/GTT43A

And the driver library from 

https://github.com/iotexpert/GTT-Client-Library

Title
Matrix Orbital GTT43: A Cool Display
Matrix Orbital GTT43A: Serial Interface
Matrix Orbital GTT43A: GTT Scripts
Matrix Orbital GTT43A: A PSoC 4 Interface
Matrix Orbital GTT43A: Debugging the I2C
Matrix Orbital GTT43A: GTT Driver Library - Part 1
Matrix Orbital GTT43A: GTT Driver Library - Part 1
Matrix Orbital GTT43A: PSoC 6 using RTOS and the GTT Driver Library

Matrix Orbital GTT43A: GTT Scripts

Summary

As I have been working my way through understanding the Matrix Orbital displays, I think that the whole scheme for programming them is very clever.  The bottom line of this article is that Matrix Orbital created a command language for making things work in the display, then the built the rest of their toolset around that language.  In this article Ill show you how it is all connected.

A Buffer Full of Mystery

While I was trying to understand how the GTT Support Tool works, I send a “Reset Module” also known as {254, 1}.  When I ran the script, the screen rebooted, and then the serial monitor dumped out a boat load of stuff.  You can see it in the picture below:

This was not very different than when I first attached to the screen using the Bridge Control Panel.  Here are the first I2C reads after the reboot.

So, what is all of this stuff?  The answer to that question resides in how this whole thing is put together.

GTT Scripts

All interactions with the display are done via the command language.  There are multiple paths for sending commands to the screen, the ones we have talked about so far, I2C, USB and UART.  And the one path that I have not specifically talked about but works exactly the same way, the mass storage sd-card.

When you design a screen in GTT Designer, what it does is take that screen, and spit out a text based command language.  Here is a screenshot of that for the test project that I am working on.

Then GTT Designer compiles the text into a binary file with the GTT2.0 and GTT2.5 commands.  You can look at the binary file with a binary file editor.  Here it is for Screen1.bin

And you should recognize the bytes you see.  Look at the top and you will see {FE, 05, 00} which in decimal is {254, 05, 00} and if you look in the GTT20 manual you will find that is “Set Communication Channel to None”.  Here is the screenshot from the manual.

But, what happens when the device boots?  Well, they followed the lead from MS-DOS and created a file called “autoexec”.  And, if you look in that file they so graciously tell you what happens.

How cool is that?  All of these commands are just the things that you did on the project setting and the display settings.  And the last line of the file launches just launches Screen1.bin, which is just the binary file of the commands it takes to load the Screen1.

Now back to the original question.  What is the buffer full of mystery?  Simple, it is the output of all of the commands (if they make output) that are in the autoexec binary and the screen1 binary.  If you had happened to set the default channel to “none” you will find that the buffer doesnt have anything in it… which should make sense.

So, when the manual says to delete the autoexec at the top level directory in order to reset the board.  All that does it remove all of the settings that you created in your project.

The only thing that I wish is that they gave you access to the txt–>bin compiler.  But oh well.

You can "git" these projects from

https://github.com/iotexpert/GTT43A

And the driver library from 

https://github.com/iotexpert/GTT-Client-Library

Title
Matrix Orbital GTT43: A Cool Display
Matrix Orbital GTT43A: Serial Interface
Matrix Orbital GTT43A: GTT Scripts
Matrix Orbital GTT43A: A PSoC 4 Interface
Matrix Orbital GTT43A: Debugging the I2C
Matrix Orbital GTT43A: GTT Driver Library - Part 1
Matrix Orbital GTT43A: GTT Driver Library - Part 1
Matrix Orbital GTT43A: PSoC 6 using RTOS and the GTT Driver Library

Internet Insanity

Summary

It was pure Internet Insanity at my house this weekend.  On Saturday I was looking at one of my Meraki MR18 access points and realized that it was not plugged into  the LAN via Ethernet.  In other words it was operating as a mesh repeater.  That situation really sucked given that it was only about 20 feet (through a wall) to the main LAN switch.

But it was even worse than it seemed because I had 20 years of networking equipment stacked up in my wiring closet.  Yes, my house has a wiring closet.  Doesn’t yours?  The first order of business was to yank it all out except the current stuff.  Check out this pile of old stuff.

Apparently over the years I have used about 7 different WiFI and Ethernet solutions.  How is that given that there hasn’t been that many 802.11s?  Hell if I know.  But this turned into a major major job.  Everywhere I looked there was a pile of wires.

And this insanity … you wouldn’t believe how many ethernet cables there were hidden in the cabinet…

So Nicholas and I headed to Lowes (actually 4 times) and got shelfs, wire zip ties etc.  Then I put him to work. My wiring closet is actually under the stairs, so he first installed rubber tiles on the floor.  Then a shelf, and finally reinstalled all of the networking gear.

Now things are much better on my network.  I use Meraki MR18’s which are 802.11ac radios.  They also have the ability to mesh with each other.  The three radios that you see in the picture with the green circle (not filled) are meshed into the network.

And my gigabit ethernet switch.

The MR18s can look at the spectrum usage… looks like 5ghz is basically empty.

While I was cleaning I found two of this cable… Ill bet you don’t know what it is…

 

Matrix Orbital GTT43A: Serial Interface

Summary

In this article I will show you how to interact with the Matrix Orbital GTT43A display using the GTT Support Tool via the KitProg UART on a CY8CKIT-044  and the Bridge Control Panel via I2C.  This article will be broken up into four parts

  1. Building a Test Project in GTT Designer
  2. GTT Protocol 2.0
  3. GTT Protocol 2.5
  4. GTT Support Tool
  5. Bridge Control Panel

Build a Test Project

In order to understand the whole serial interface, I will build a very simple project with two buttons.  You can find this project in my GitHub site at git@github.com:iotexpert/GTT43A

Start up a new project called “BasicTest”.  Accept the defaults for Project settings.  On the Display Settings screen change the “Default Channel” to Serial and the Flow Control to Off.  I am using the CY8CKIT-044 to talk to the screen.  On that development kit there is a KitProg which serves as a programmer (for the PSoC 4200M) and as a serial bridge.  That serial bridge does not have the flow control pins turned on.  If you leave the flow control on, the screen will never transmit and you will need to poke your eyeballs out trying to figure out why.

  

Drag a Circle Button (GTT2.5) onto the screen.  Change the Text value (on the right panel) to “GTT25”

 

Now click on the “Legacy” tab and drag a “Circle Button” onto the screen.  Then change the text label to “Legacy”.  In addition change the “ID” from “Auto” to “2”.  I noticed that later in this article that if the button ID is “auto” it will not be identified in the messages.  Im not sure if this is a bug or my lack of understanding.

When I click “Deploy” I end up with this error message.  This appears to be a bug in the GTT Designer.

Click on the “Font” and go to the directory where the Font is supposed to be… and find that it is actually empty.

So.  I navigate up a directory and then down into “LibraSans” instead of “libra-sans-modern”.

Once that is done press “Deploy”, and I get Success!

Now that I have the project built I need to wire the whole mess together.  I am going to use a CY8CKIT-044.  This development kit has a PSoC4200M.  Although the project is using a PSoC6, I didnt have any level translators at my house (bad Alan) and I wanted to get going … so I used the 5V tolerant PSoC 4. [note: it turns out that the MCU used on the display has 5V tolerant serial I/Os but is a 3.3v MCU so I could have used it directly on the PSoC 6 without this work around]  On the far left of the development kit, right next to the USB is the KitProg connector.  This connector has an I2C Master and a UART Bridge.  In addition I can connect the I2C pins to PSoC, the Display and the Bridge.  Here is the schematic for the whole mess.

When you look on the back of the CY8CKIT-044 you can see the same wiring diagram on the silkscreen.

Here is a picture of the development kit.  You can see the top green/yellow wires go to P40/P41 (that is the I2C Bus) and the other green/yellow set goes to P12[6] and P12[7] that is the KitProg UART.  I suppose I should have used different colors for I2C and UART… oh well.

And finally the whole mess.

GTT43A Protocol 2.0

They way that the system works is you can send a command data packet to the display via one of the serial interfaces and then if there is a response required,  it will respond with a response data packet.  In addition when some event occurs on the display (like a touch screen button being pressed) it will send you a response data packet.

There are two GTT Protocols, one called 2.0 and one called 2.5.  First the 2.0 protocol.  You send messages in the GTT2.0 command data packet format.  That format is simple:

  1. 254 – 1 byte
  2. Message ID (look in the manual for all of the legal message codes) – 1 byte
  3. Optional data 0-n bytes

If there is a required response, the screen will respond with a data packet in the following format

  1. 252 – 1 byte
  2. Message ID – 1 byte
  3. Length MSB – 1 byte
  4. Length LSB – 1 byte
  5. Optional Data – 0–>65535 bytes

The total length of the response will be (length msb) << 8 | length lsb – big endian.

For example a command with no optional data …. like reset will look like this { 252, 1 }. [obviously dont send the braces or the comma]

A command with some optional data is “Set Backlight Brightness”. If you want the brightness set to 23% you would send is {252, 153, 23}.

An example of a command that will respond with a response data packet is “Get Module Type” where you would send {254, 55 } and the screen would respond with {252, 55, 00 02 147 01}.  Here is the picture from the manual.

When you look at the picture above there are several things to be VERY careful about.

First, the Matrix Orbital people appear to think in decimal not hex.  So they show you {252,55,00,02,147,01) instead of (0xFE, 0x37, 0x00, 0x02, 0x93, 0x01}.  Notice that my GTT43A value is decimal 37633 which is also known as Hex 0x9301.  I  often found myself typing hex when I mean decimal and vice versa.

The second thing to be careful about is that they send values in big endian… so if you are using an ARM processor be aware as ARM is almost always little endian.

The third thing to be careful about is that the length parameter in the message is always 16-bit Big Endian even though the documentation often shortens this to “Length”

Lastly, if they send you a 16-bit value it will show up as big endian, and they will probably show it to you in decimal (like table 14 above).  Which can look kinda weird in decimal as it is two bytes.

GTT43A Protocol 2.5

As I worked on understanding what the screen is doing, I noticed that I was getting message codes that were not documented in the GTT2.0 Manual.  For example when you press a button you will get {252,235,0,5,21,0,0,1,1}.  When you look at this packet you can recognize the 252… and the message code 235 … and the length seems to make sense 5 … but the rest of the message is less clear.

So I called technical support, which is excellent, and Daniel agreed to send me a prerelease of the new manual.  When you look at the manual you will find:

Which makes good sense as I pressed a button, and the object ID was “1”.  The pre release version of the manual that I got seems to be missing information, but Im hopeful they will get it done and released soon.  But for now, I can work with it.  If you need a copy of the manual you will need to contact them directly.

GTT Support Tool

When you install GTT Designer, it will also install a program called the GTT Support Tool.  This tool will allow you to send and receive GTT messages to/from the screen.   I have the screen attached to the UART on the KitProg Serial bridge (with jumper wires).  This means I will see the screen in the Device Manger under the Ports->KitProg (see the COM5)

You can run the GTT Support Tool from the Start menu or from the Tools menu on the GTT Designer.

When the tool starts you can pick out which ComPort to talk to and setup the Flow Control (meaning use or not CTS/RTS).  The KitProg on the 4200M does not have the CTS/RTS so you need to disable it or things will not work.

When you press the “Test Connection” it will send a message via the UART/ComPort and wait for a response. I am not sure, but I suspect that it is sending a “Get Module” command.  In the picture below you can see that I got both the send and the receive message to work.

I was struggling over the weekend to get the communication to work correctly.  Specifically I was not getting return messages.  It turned out that the project that you build in the GTT Designer must have “Flow Control” turned off and the Default Channel set to Serial or the serial communication responses will not work.  Remember you can set this on the “Display Settings”

You can also send the commands to set the communication channel and flow control, but I found it easier to get the project to the correct settings in the GTT Designer.

One you have a functional connection you can click on the “Commands” tab.  On the left of the screen you will see a list of commands (well… actually on GTT2.0 commands).  On the right side of the screen you will see your “script”, which obviously starts blank.

The first thing that you should do is press the little split screen button just to the right of the red “X”.  When you do this it will bring up a new window that will show what is sent, and what is received.  Obviously it starts blank.

Now you can double click on a command, like “Get Module Version” and it will bring up the command.  When you press “OK” it will add it to the script.  You CAN change the command and it will add it the script (but with a misleading name)

Here is what the window looks like after I add the “Get Module Type” command.

In order to Run the command, you need to click in the script window and then press the green run button.  If you have not clicked in the script window it will not run. Once you have run the command your viewer window will look like this.

In the window above you can see that I wrote to the serial port a {254,55} and the screen responded {252,55,0,2,147,14}.  When you decode this message don’t forget that the data above is in decimal.  In this the example the message the 147,14 is actually 0x930E which is 37646.  Unfortunately 37646 is not documented in the GTT 2.0 protocol manual (but my screen is a GTT43A).

Another cool thing that that happens in the Debug view is that it shows events that are initiated from the screen.  For instance in the picture below I pressed the “GTT25” button from my example project.  It show the button press and the button release.

 

Bridge Control Panel

For my real project I want to interact with the GTT43A via I2C.  For this kind of thing I always like to use the Bridge Control Panel first. I have written a bunch of articles about using BCP to debug.  This allows me to act as an I2C Master and see how the device acts as a slave.  The first thing that I do is press “List Devices” on the BCP.  It shows me that there are a number of things connected to the I2C bus.

You might recall that from the Display Settings that the default I2C address is 80.

That 80 is also known as 0x50 (here we go with the Hex / Decimal thing again).  Moreover that 80 (0x50) is an 8-Bit address, in other words shifted left 1 from the 7-bit address of 0x28.

After I verified that the screen was attached to the bridge control panel.  The next thing to do was to set the default communication via I2C.  Here is the section of the documentation

This means that I need to send {0xFE, ox05, 0x02}.  When I send that command I get ACKs … good.

The next thing that I do is test to make sure that the legacy button is working correctly.  When I press it and then read some bytes I get

Then I press the GTT 25 Button and get {FC,EB,00,05,15,00,00,01,01} and then {FC,EB,00,05,14,00,00,01,00} in other words a press of button ID 1 and then a release of button ID 1.

Now that we understand the command protocol and we know how to talk to the screen, in the next article Ill talk about GTT Scripts.

You can "git" these projects from

https://github.com/iotexpert/GTT43A

And the driver library from 

https://github.com/iotexpert/GTT-Client-Library

Title
Matrix Orbital GTT43: A Cool Display
Matrix Orbital GTT43A: Serial Interface
Matrix Orbital GTT43A: GTT Scripts
Matrix Orbital GTT43A: A PSoC 4 Interface
Matrix Orbital GTT43A: Debugging the I2C
Matrix Orbital GTT43A: GTT Driver Library - Part 1
Matrix Orbital GTT43A: GTT Driver Library - Part 1
Matrix Orbital GTT43A: PSoC 6 using RTOS and the GTT Driver Library

Matrix Orbital GTT43A: A Cool Display

Summary

I have recently found myself way way down a rabbit hole on a project that uses a Matrix Orbital GTT43A.   This display is a super cool, though expensive, intelligent touch screen display.  Here is a picture:

I call it intelligent because it has a fully featured CPU that runs all of the display and touch functions for you.  Basically you build all of the screens with GTT GUI elements (sliders, buttons, text etc.) using the Matrix Orbital design tool called GTT Designer.  Then you program that configuration into an sd-card that is attached to the display.  When you power up the display, your configuration comes up and you are off to the races.  Then, in your system you can then simply interact with the display via I2C, UART, USB or SPI.

I know that it seems simple, but I will say that this has turned into quite an adventure which has, in turn, been an awesome learning experience.

Matrix Orbital GTT43A

The Matrix Orbital GTT43A is a 4.3″ backlit LCD display with a capacitive touch screen.  Here is a screenshot from the Matrix Orbital website.  Yes, you read the price right, it is $155.84…. well actually $165.84 with capacitive touch.

 

Here is a picture of the back of the screen.

On the far left you can see the connector labeled “Keyboard Power”.  This is a place where you can plug in a matrix keyboard that looks like the next picture.  Though I am not exactly sure why you would make a nice touch screen interface and then use a mechanical button interface?

In the middle of the picture you can see a micro-sd card which holds all of your screen configuration information.  The sd-card is a normal mass storage card and you can drag and drop your configuration, or new firmware for the screen using normal Windows.  You can also put the display into mass-storage mode and then access the card via the mini-usb-b connector that is in the upper left.

The display also supports 6 digital GPIOs (which you can see on the lower left of the picture).  It also has a piezoelectric buzzer and a haptic vibrator.

In order to talk to the display with your system controller you can use I2C, UART, SPI or USB.  It is interesting that you seem to be able to use multiple interfaces at the same time, which is pretty convenient for debugging.

The display requires a decent amount of juice.  Here is a picture on my desk, 5V and 375mA,  which is more than the development kit I was using will provide.  In fact it, will sort of work for a while off the devkit power supply, but when you push a button on the screen it will reboot the display.

GTT Designer

GTT Designer is a Windows GUI building tool.  It is straight forward to use.  When you start up the software it will give you a choice of displays to build for.  In the picture below you can see that it detected that I had a GTT43A attached to my computer via USB.

 

After setting up the name of my project and clicking “New Project” I am given the choice of customizing the global settings for the display.

Once the project is setup, you are now given the ability to configure the display settings.  On this screen you can setup a number of things, including the I2C address of the display.  Also, on the screen below you can see “Default Channel” is set to none.  What this means is that any GUI thing that happens will send messages to the default channel.  In this case none.  But that isnt what I want so I change it to I2C (next picture)

What I really want it all of the output to go to the I2C.  But given that the screen is an I2C slave, and it cant send out data, what does that really mean?  What it means is that all of the output goes into a buffer, that slowly fills up until you read the data out of it via I2C.  If you setup the Default channel as Serial, the data will go directly out via UART.

Once the display settings are done you will end up with a screen that looks like this.  On the left side of the screen you can pick out the different GUI elements (buttons, text labels, sliders, images etc) and the drag them onto the screen.  Notice that there are four tabs, Tools, Legacy Tools, Assets, Overview.  At some point very recently Matrix Orbital did a massive re-engineering project to make things simpler to interact with the screen.  When they did this, the created a who new set of widgets called “GTT2.5” widgets.  You can still use the old widgets which they now call “Legacy”

On the screen below you can see that I placed a bunch of different GUI elements for my test project.  When you click on an element, the right hand side of the screen will let you update properties of the object e.g. color, size, name.  You can also create events (more on that in the next article)

One you have drawn your screen you then want to build and program the project.  Or in their language generate and deploy.  To do this you can either click generate then click deploy, or just click deploy.  When you do this it will first build all of your project into a directory on your computer called “Output”.  There are three interesting things in the output directory.

  1. autoexec.txt/bin – files that contains a script that runs when the display turns on (more on that in the next article)
  2. Report.txt – a file that contains information about the objects, names, ids etc (this is important for your software)
  3. GTTProject1 – a directory with all of the files required for your project.

When you look in the GTTProject1 directory you will see that it contains a directory for “Screen1”.  If I had made multiple screens it would have made multiple directories.  It also has a directory called “Fonts”, which big surprise, contains the Fonts that are used by the project.

In the “Screen1” directory you will see a bunch of bitmap files, text files etc.

Screen1.txt contains a textual version of the “program” that creates the screen.  Here is a snapshot of the top of the file.

And “Screen1.bin” which is the compiled version of the “Screen1.txt”- more on this in the next article.

When you click the deploy button, it sends a command to the screen to put it into mass storage mode which just turns the screen into a flash disk which can be written/read by your PC.  Here is what the screen looks like when it is in mass storage mode:

After the device is in mass storage mode, GTT Designer copies all of the file onto the sd-card of the display and the reboots the display to run the program.

When you are running GTT Designer you can switch the display back and forth between Mass Storage mode and Display mode on the Tools menu by selecting “Switch Mode”

In the next several articles Ill show you how to build firmware to talk to the screen.

You can "git" these projects from

https://github.com/iotexpert/GTT43A

And the driver library from 

https://github.com/iotexpert/GTT-Client-Library

Title
Matrix Orbital GTT43: A Cool Display
Matrix Orbital GTT43A: Serial Interface
Matrix Orbital GTT43A: GTT Scripts
Matrix Orbital GTT43A: A PSoC 4 Interface
Matrix Orbital GTT43A: Debugging the I2C
Matrix Orbital GTT43A: GTT Driver Library - Part 1
Matrix Orbital GTT43A: GTT Driver Library - Part 1
Matrix Orbital GTT43A: PSoC 6 using RTOS and the GTT Driver Library