PSOC 4 UART to I2C bridge for bootload host communication

Tip / Sign in to post questions, reply, level up, and achieve exciting badges. Know more

cross mob
ErNo_1148106
Level 4
Level 4
First solution authored 50 replies posted 25 replies posted

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

0 Likes
1 Solution

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

Regards,
Bragadeesh

View solution in original post

21 Replies
GeonaP_26
Moderator
Moderator
Moderator
250 solutions authored 100 solutions authored 50 solutions authored

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.

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

0 Likes
lock attach
Attachments are accessible only for community members.

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

Alakananda
0 Likes

Hi Alakananda,

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

Thanks,

Eric

0 Likes

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

0 Likes

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

0 Likes

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

0 Likes

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)

pastedImage_1.png

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.

pastedImage_2.png

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

Regards,

Bragadeesh

Regards,
Bragadeesh

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-anal...  comes with an example project to demonstrate bootloader host project using UART interface.

Regards,

Bragadeesh

Regards,
Bragadeesh
0 Likes

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

0 Likes

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

Regards,
Bragadeesh

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

0 Likes

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

Regards,
Bragadeesh
0 Likes

Hi Bragadeesh,

Ok sounds good. The I2C communication is the most important timing wise in my design so that is set to the highest priority and then the UART which gets processed right after the I2C functions.

Thanks,

Eric

0 Likes

Hi Bragadeesh,

I had a wild idea and need your input to see if it will work. I have a main application and I also have a bootloader application. The main application does the run time stuff and I know the bootloader application does the bootload stuff. The question I have is can I create a usable application in the bootloader application? I want to run the usb to i2c bridge code provided here in the bootloader application to load the other four psoc devices and when I am done exit to the main application through a switched event toggled by my c# program. The reason for this is there is too much going on in the main application and im afraid ill break something trying to integrate the new code in with the main code. I know it sounds crazy but is it doable? Please let me know. Ill try not to bother you too much. I know you have others with questions too.

Thanks,

Eric

0 Likes

Hi ErNo_1148106​,

Yes, it is possible to have the bootloader project to perform useful application but note that the hardware resources are lost once the control goes to the bootloadable. Also, you have mentioned that most of your flash is over with the present design it should be noted that when you divide the application to bootloader and bootloadable you are going to lose some flash area to the bootloader. We recommend you to integrate the present project to your existing design and if that does not have enough CPU bandwidth you can go for dividing the application between bootloader and bootloadable.

With that said, we highly recommend you to evaluate your PSoC 6 devices for newer applications that has cortex M4 CPU with higher flash and RAM specifications Up to 2MB flash, 1MB SRAM, Up to 104 GPIOs, Upto : 32 x Timer/Counter/Pulse-width Modulators (TCPWMs), Upto 13 x Serial Communication Blocks (SCBs) the CM4 and CM4 can operate upto 150 MHz speed.

https://www.cypress.com/products/32-bit-arm-cortex-m4-psoc-6

https://www.cypress.com/documentation/application-notes/an221774-getting-started-psoc-6-mcu

https://www.cypress.com/documentation/application-notes/an228571-getting-started-psoc-6-mcu-modustoo...

Best Regards,

Bragadeesh

Regards,
Bragadeesh
0 Likes

Hi Bragadeesh,

I like the PSOC 6 and I have two prototype boards and have run initial testing and they look like a good fit but due to the fact they are BGA, CSP parts and the ble module its a no go until the QFN and TQFP parts become available. I cannot use the radio/ble version on this board. Any idea when they will be available for sampling? I see them in the datasheets and they said it would be available last year but don't see anything mentioning the launch of the new devices. The product I will be selling will be low in quantity at first and it just wouldn't make sense starting out with BGA or CSP components because of the board costs and I don't have the equipment to solder them. If you have new news please let me know maybe I can push my design out a little further and wait for the new chips if they will be available soon.

Thanks,

Eric

0 Likes

Hi Eric,

You can use the PSOC-62  2M part for your application since you do not want the radio/ble version .

Here is the link for the datasheet - https://www.cypress.com/file/460816/download

Regards

Alakananda

Alakananda
0 Likes

Hi Alakananda,

Can I get samples and if so when? I'd like to get the tqfp part engineering samples... Does this device work with PSOC creator?

Thanks,

Eric

0 Likes

Hi Bragadeesh,

Do you have experience with FM4 devices? I am currently using a PSOC 5 80 mhz part and would like to know if going to the FM4 160 mhz part is a good idea? For one I don't know much about the FM4 parts and two I don't know what programmer i need or IDE to use. Is it really worth the trouble to go to the higher speed FM4 part compared to the PSOC 5? I know the PSOC 5 is a beast of a chip and I know it pretty well now I am just worried about the performance of my current design. The current discussion above is in reference to this as all of this is connected.

The PSOC 5 handles quite a lot in terms of high speed UART data and then further processing and then driving motors, receiving interrupt events from outside sources and driving other components in the design. Its sort of like a high speed printing application with lots of bells and whistles. The PSOC 5's 256kb flash and hardware peripherals are almost all used up. What are your thoughts on this? Please let me know.

Thanks,

Eric

0 Likes

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 = (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=0;

                    i2creadbuf=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

0 Likes