1 2 Previous Next 21 Replies Latest reply on Feb 25, 2020 12:31 PM by ErNo_1148106

    PSOC 4 UART to I2C bridge for bootload host communication

    ErNo_1148106

      Hi All,

       

      I have an application that requires bootloading code updates to four PSOC 4 devices chained onto the I2C bus that is controlled by another PSOC 4 which is the custom UART to I2C Master. What I would like to do is implement a secondary protocol to bootload all four devices with a custom program written in visual C#. I have used the UART bootloader with success but have not used the I2C bus to bootload devices and do not know where to really begin. I assume the interface is similar to the UART interface is this correct? Is there a datasheet showing how the I2C protocol is used like the START, STOP, DATA, ADDRESS etc? What I would really like to know is if there is C code to implement a UART to I2C bridge type of interface so I can use my existing UART bootloader program. I looked at the kitprog but that is USB to I2C. Any help would be GREATLY appreciated!!!!!!!

       

      Thanks,

       

      Eric Norton

        • 1. Re: PSOC 4 UART to I2C bridge for bootload host communication
          GeonaP_26

          You can refer to PSoC 4 based I2C Bootloader Application Note available here. The bootloader command - response protocol remains the same for I2C and UART bootloader. Please refer to section 'Bootloader Packet Structure' in Bootloader component datasheet for details.

          • 2. Re: PSOC 4 UART to I2C bridge for bootload host communication
            ErNo_1148106

            Hi Geona,

             

            Ive seen those but still kind of scratching my head. It might be late and im tired. As you said in your reply "The bootloader command - response protocol remains the same for I2C and UART bootloader". Does this mean that I can use a uart and have an i2c master and basically do this:

             

            receive byte from uart -> send same byte to I2C

            transmit byte from I2C <- receive byte from I2C

             

            How do I handle the slave addresses? How does the UART and the I2C share the data? There is supposed to be a I2C start, address, data, stop etc or am I wrong? Do you have code examples? Right now I have a CP2105 dual UART going to two different parts of my design (I tried the CY7C65215 but it failed). One channel goes to control a function of the design and the second channel controls another part of my design. The second channel communicates with the custom protocol uart to i2c psoc 4 micro and this same micro configures four psoc 4 i2c slaves. I want to be able to upload new code by selecting the hard coded unique i2c address in one of the four controllers. Any help is greatly appreciated!!!

             

            Thanks,

             

            Eric

            • 3. Re: PSOC 4 UART to I2C bridge for bootload host communication
              AlakanandaB_86

              Hi Eric,

               

              Please check with the attached project where we tried to implement UART to I2C bridge.

              Please refer the I2C Bootloader app note to understand the sequence.

              Please let us know if this meets your requirement.

               

               

              Regards

              Alakananda

              • 4. Re: PSOC 4 UART to I2C bridge for bootload host communication
                ErNo_1148106

                Hi Alakananda,

                 

                Thank you very much for the example. I will test it and let you know :-).

                 

                Thanks,

                 

                Eric

                • 5. Re: PSOC 4 UART to I2C bridge for bootload host communication
                  ErNo_1148106

                  Hi Alakananda,

                   

                  I tried a bench test with the code you provided and get:Bootload_error_0xFF.JPG

                   

                  Any ideas? Please let me know.

                   

                  Id like to send you the bootloader test software but don't see an upload link for files; only for html and images???

                   

                  Thanks,

                   

                  Eric

                  • 6. Re: PSOC 4 UART to I2C bridge for bootload host communication
                    ErNo_1148106

                    Hi Alakananda,

                     

                    I dug into the bootloader data transfer a little more and have found that the first transfer "Enter Bootloader" is sent and converted ok with a response that is also ok. The second transfer is where it stops communicating. It sends the "Get Flash Size" command and converts to I2C Write which is ok but when it receives the I2C Read data it is a buffer size of 0x0F BUT the data is only 0x0B (11 bytes) response with four bytes of 0xFF. I have attached a logic analyzer shot:

                     

                    I2C_Bootloader.JPG

                     

                    Is the response supposed to be a fixed 15 bytes from the bootloaded device? Should this vary and if so how do i receive a variable sized I2C packet?

                     

                    Btw I loaded the code you gave me on a CY8C4025LQI-S411 chip with 24 Mhz clock, code has not been altered accept for the 0x08 I2C address. I found out the chip has a WDT that is hard to disable and not sure if that is causing this problem but worth mentioning. The chip to be bootloaded is a CY8C4245PVI-482 running a 24 Mhz clock.

                     

                    Any ideas would be greatly appreciated!!!

                     

                    Thanks,

                     

                    Eric

                    • 7. Re: PSOC 4 UART to I2C bridge for bootload host communication
                      ErNo_1148106

                      Hi Alakananda,

                       

                      I figured out what was going on and I can now program the device using the bridge software you provided with the changes I made. The response packet does change in size and that is what was causing the problem because the packet size was set at 0x0F (15)  and therefore sending the wrong response to the host. Let me know if you want an updated copy of the new firmware with the changes.

                       

                      Thanks,

                       

                      Eric

                       

                       

                      • 8. Re: PSOC 4 UART to I2C bridge for bootload host communication
                        BragadeeshV_41

                        Hi ErNo_1148106,

                         

                        The above project shared should be considered as a reference to perform UART to I2C bridge and it is not a complete project.

                        We developed the above project for the EnterBootloadCommand alone.

                         

                        Each command will receive x no of bytes in the response packet from the bootloader target (through I2C). The I2C master in the bridge project must receive these x no of bytes from the I2C slave based on the previously sent command.

                         

                        For this, you need to set the receive buffer of the I2C based on the command that was sent. You can get the no of bytes received in the response packet from the table provided in the following app note https://www.cypress.com/documentation/application-notes/an86526-psoc-4-i2c-bootloader  (Pg 35)

                         

                        Therefore, in the present firmware, you need to do the following:

                         

                        command = i2cTransmitBuffer[1]; // Since the second byte in the command packet contains the command byte.

                         

                        switch(command)

                        {

                        case 0x31:

                        i2creadbytecount = 8;

                        break;

                         

                        case 0x32:

                        i2creadbytecount = 11;

                        break;

                         

                        case 0x34:

                        i2creadybytecount = 7;

                        break;

                         

                        case 0x38:

                        i2cbytereadcount = 15; // we did this for you as an example

                        break;

                         

                        //other cases similar to above

                         

                        default:

                        //invalid comment

                        }

                        ....

                        ....

                        ....

                        if(i2cread==1)

                                    {

                                     //   CyDelay(100);

                                    

                                        if(I2C_I2C_MSTR_NO_ERROR ==  I2C_I2CMasterReadBuf(I2C_SLAVE_ADDR,

                                                            i2creadbuf, i2cbytereadcount,

                                                                        I2C_I2C_MODE_COMPLETE_XFER)) // set i2cbytereadcount based on command received

                                        {

                                            /* If I2C read started without errors,

                                            / wait until master complete read transfer */

                                            while (0u == (I2C_I2CMasterStatus() & I2C_I2C_MSTAT_RD_CMPLT))

                                            {

                                                /* Wait */

                                            }

                                            i2cread=0;

                                        }

                         

                                        CyDelay(10);

                                        UART_SpiUartPutArray(i2creadbuf,0x0F);            

                                        CyDelay(10);

                        }

                         

                        In addition, in the UART component make the TX and RX buffer size as 64 to prevent FIFO overflows. The above project might not work if the received bytes from UART is greater than 8.

                         

                         

                        Please let us know if you face any difficulties. We are happy to help

                         

                        Regards,

                        Bragadeesh

                        1 of 1 people found this helpful
                        • 9. Re: PSOC 4 UART to I2C bridge for bootload host communication
                          BragadeeshV_41

                          Also, the Cypress bootloader host app is capable of boot loading via I2C (it will act as the I2C master). You can specify the address of the slave device in the host app. But this requires an USB to I2C bridge. Is there any reason you can't use this option?

                           

                          In addition, you can create your own host in PSoC device. In that case one controller can bootload the other controller through any custom interface. The following app note https://www.cypress.com/documentation/application-notes/an68272-psoc-3-psoc-4-psoc-5lp-and-psoc-analog-coprocessor-uart  comes with an example project to demonstrate bootloader host project using UART interface.

                           

                          Regards,

                          Bragadeesh

                          • 10. Re: PSOC 4 UART to I2C bridge for bootload host communication
                            ErNo_1148106

                            Hi Bragadeesh,

                             

                            I would have never figured out the expected packet length if I didn't have the logic analyzer and the reason why is the documentation is unclear until you pointed out the above code changes. This drove me crazy because it is not evident in the documentation. I see the box outlined in red in your response but it was not clear and I did see that section in the app note.

                             

                            Here is what I did to get it to work:

                             

                            #define I2C_SLAVE_ADDR  0x08

                             

                            #define I2C_RD_DATA_LSB             my_i2c_rd_data_length.i2c_data_lsb00

                            #define I2C_RD_DATA_MSB             my_i2c_rd_data_length.i2c_data_msb10

                            #define I2C_RD_DATA_LENGTH_BYTE     my_i2c_rd_data_length.i2c_rd_data_length_byte

                             

                            typedef union

                            {

                                struct

                                {

                                    uint8_t i2c_data_lsb00:8;

                                    uint8_t i2c_data_msb10:8;

                                };

                                uint16_t i2c_rd_data_length_byte;

                               

                            }i2c_rd_data_length;           

                             

                            i2c_rd_data_length      my_i2c_rd_data_length;

                             

                             

                            uint8 command;

                            uint8 i2csend;

                            uint8 i2cread;

                             

                            uint8 i2cwritebuf[100];

                            uint8 i2creadbuf[100]={1};

                             

                             

                            int main(void)

                            {

                                CyGlobalIntEnable; /* Enable global interrupts. */

                               

                                //CySysWdtDisable();  /* The Watchdog timer is not used so therefor disabled */

                               

                                I2C_scl_SetDriveMode(I2C_scl_DM_RES_UP);

                                I2C_sda_SetDriveMode(I2C_sda_DM_RES_UP);

                               

                                /* Place your initialization/startup code here (e.g. MyInst_Start()) */

                                UART_Start();

                                I2C_Start();

                               

                                for(;;)

                                {

                                    cystatus status;

                                    uint32_t byteCount_wr;

                                    uint32_t byteCount_rd;

                                    uint32 timeoutMs;

                                    uint32 i;

                                    uint8 timeOut = 10;

                             

                                    status = CYRET_TIMEOUT;

                                    timeoutMs = ((uint32) 10u * timeOut); /* Convert from 10mS check to 1mS checks */

                             

                             

                                    /* Wait with timeout 1mS for packet end */

                                    byteCount_wr = 0u;

                                    do

                                    {

                                        /* Check packet start */

                                        if (0u != UART_SpiUartGetRxBufferSize())

                                        {

                                            /* Wait for end of packet */

                                            do

                                            {

                                                byteCount_wr = UART_SpiUartGetRxBufferSize();

                                                CyDelayUs(UART_UART_BYTE_TO_BYTE);

                                            }

                                            while (byteCount_wr != UART_SpiUartGetRxBufferSize());

                                            status = CYRET_SUCCESS;

                                            i2csend = 1;

                                            break;

                                        }

                             

                                        CyDelay(UART_WAIT_1_MS);

                                        --timeoutMs;

                                    }

                                    while (0u != timeoutMs);

                                    /* Place your application code here. */

                                   

                                    for (uint16 i = 0u; i < byteCount_wr; ++i)

                                    {

                                        i2cwritebuf[i] = (uint8) UART_SpiUartReadRxData();

                                    }

                                   

                                    command=i2cwritebuf[1];

                                          

                                    if(i2csend)

                                    {           

                                        CyDelay(100);           

                                        if(I2C_I2C_MSTR_NO_ERROR == I2C_I2CMasterWriteBuf(I2C_SLAVE_ADDR, i2cwritebuf, byteCount_wr                                                                                           ,I2C_I2C_MODE_COMPLETE_XFER))

                                        {

                                        /*If I2C write started without errors,

                                        / wait until I2C Master completes write transfer

                                        */

                                        while (0u == (I2C_I2CMasterStatus() & I2C_I2C_MSTAT_WR_CMPLT))

                                        {

                                            /* Wait */

                                        }

                                        i2csend = 0;

                                        i2cread=1;

                                    }

                                       

                                        if(i2cread==1)

                                        {

                                            byteCount_rd = 0u;

                                           

                                            CyDelay(100);

                                            if(I2C_I2C_MSTR_NO_ERROR ==  I2C_I2CMasterReadBuf(I2C_SLAVE_ADDR, i2creadbuf, 0x0F,                                                                                           I2C_I2C_MODE_COMPLETE_XFER))

                                            {

                                                /* If I2C read started without errors,

                                                / wait until master complete read transfer */

                                                while (0u == (I2C_I2CMasterStatus() & I2C_I2C_MSTAT_RD_CMPLT))

                                                {

                                                    /* Wait */

                                                }

                                               

                                                I2C_RD_DATA_LSB = i2creadbuf[2];    /* Copy data length */

                                                I2C_RD_DATA_MSB = i2creadbuf[3];

                                               

                                                byteCount_rd = I2C_RD_DATA_LENGTH_BYTE + 7;     /* Copy data to byteCount and add seven bytes */

                                               

                                                i2cread=0;

                                            }

                              

                                            CyDelay(10);

                                            UART_SpiUartPutArray(i2creadbuf, byteCount_rd);               

                                            CyDelay(10);

                                           

                                           

                                            //refresh buffers

                                            for(i=0;i<100;i++)

                                            {

                                                i2cwritebuf[i]=0;

                                                i2creadbuf[i]=0;

                                            }              

                                        }      

                                    }

                                }

                            }

                             

                            Its not as clean as your solution but it works. Initially I was thinking of doing it the way you did it but could not find the correlation between the sent commands expected return byte details until you sent me your response. All in all I appreciate your help clarifying the extra needed details.

                             

                            Is it possible to enter into the bootloader mode without an added input pin? I would like to enter into the bootloader mode through the I2C interface if possible. That way I don't have to run a control wire to each of the chips to enter the bootloader. Please let me know if this is doable or not. Many thanks for your help :-)...

                             

                            Eric

                            • 11. Re: PSOC 4 UART to I2C bridge for bootload host communication
                              ErNo_1148106

                              Hi Bragadeesh,

                               

                              Oh and yes I did update both of the UART buffers to 64. Also the reason why I needed a uart to i2c bridge is I didn't have the USB to I2C function in my design.

                               

                              I am using the CP2105 to split to two UARTS one for control of a part of my circuit and another to control another part with the added bootloader control to a chain of four more psoc 4 devices linked by I2C. I know this sounds confusing but really cant go into much detail.

                               

                              On another note is it possible I can get the Bootloader host software so I can add buttons and a few other functions to it? I really like the layout of the bootloader host tool in the picture I posted above. Please let me know.

                               

                              Thanks,

                               

                              Eric

                              • 12. Re: PSOC 4 UART to I2C bridge for bootload host communication
                                BragadeeshV_41

                                Hi ErNo_1148106,

                                 

                                Yes it is possible to launch the bootloader mode through I2C interface.

                                 

                                For this you can fix a command byte, say 0x01 as enter boodload mode command.  The i2c master has to send this command byte to the psoc device that needs to be updated with the new application using the slave address. When the slave with the matched address receive this command byte they will enter the bootload mode by calling Bootloadable_Load();

                                 

                                In master side,

                                 

                                if(bootloadRequired)

                                {

                                    I2CMasterWrite(slave_address,  0x01); // For illustration

                                }

                                In the slave side,

                                //Receive the byte from the master and enter the bootloader mode.

                                if(command_byte == 0x01)

                                {

                                    Bootloadable_Load();

                                }

                                 

                                On another note is it possible I can get the Bootloader host software so I can add buttons and a few other functions to it? I really like the layout of the bootloader host tool in the picture I posted above. Please let me know.

                                --> Yes, this can be developed. But unfortunately we may not be able to provide source code for the Cypress bootloader host app. This may have to be developed on your own.

                                 

                                Also, let me know if you face difficulties in understanding the no of expected receive bytes for a particular command byte sent.

                                 

                                Regards,

                                Bragadeesh

                                1 of 1 people found this helpful
                                • 13. Re: PSOC 4 UART to I2C bridge for bootload host communication
                                  ErNo_1148106

                                  Hi Bragadeesh,

                                   

                                  That's a great idea :-D!! I implemented it and it works...

                                   

                                  I was hoping you would say yes to the bootloader host software but thats ok. I have an older version just hate going through all the code and making changes in C#. Im not a huge fan of Visual Studio!!

                                   

                                  By the way what is the theoretical max buffer size for I2C transmit and receive buffers before it gives me problems? I currently have a twenty seven byte transmit buffer and a thirty four byte receive buffer. Would this be an issue? If so could I just go to 400 kHz?

                                   

                                  Thanks,

                                   

                                  Eric

                                  • 14. Re: PSOC 4 UART to I2C bridge for bootload host communication
                                    BragadeeshV_41

                                    Hi ErNo_1148106,

                                     

                                    The byte count in the receive and transmit buffer is uint32. So theoretically it is only limited by the SRAM of your device (you can have external memory to store larger data also). Also, I2C uses interrupts to manage data transfer between the software and the hardware FIFO (see scb component datasheet for the hardware FIFO size).

                                    Therefore, make sure to assign proper priority for I2C interrupts to prevent clock stretching.

                                     

                                    Regards,

                                    Bragadeesh

                                    1 2 Previous Next