I2C Bootloader Error: PSoC Bootloader sending extra bytes to host?

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

cross mob
lock attach
Attachments are accessible only for community members.
KyTr_1955226
Level 6
Level 6
250 sign-ins 10 likes given 50 solutions authored

Hi there all,

I've been working on creating an I2C Bootloader host application for PC using the CY7C65211 USB-Serial bridge IC aboard the CYUSBS234 Dev Kit.  I am attempting to bootload the PSoC5 on the CY8CKIT-050.

I finally got the USB-I2C API going in C# .NET (thanks to this thread) and now I'm running into errors during the actual data transfer processes.  When I attempt to bootload, I get an error code 0x4019.  This corresponds to the bootloader reporting an error (0x4000 is the mask), but I'm not sure where the 0x19 is coming from (it doesn't match to anything in the ReturnCodes enum).

I have a logic analyzer capture of the activity on the bus for the bootload process.

Transmission from Host (0x38 - Enter Bootloader):

pastedImage_0.png

Response from PSoC (??? - Where did those 0xFF bytes come from?):

pastedImage_1.png

Transmission from Host (0x3B Exit Bootloader):

pastedImage_2.png

At this point, the process ends with the 0x4019 error code.  The first thing I notice is that the second transmission (response from the PSoC) doesn't  to adhere to the response packet structure outlined in the Datasheet for the Bootloader v1.60 component.  I'm only getting what is presumably the Start of Packet (0x01) byte after 12 0xFF bytes.  I'm not getting the End of Packet (0x17) byte at all.

pastedImage_3.png

The twelve 0xFF bytes from the PSoC is almost certainly the issue, but at this point in the execution of the bootload routines, the process is basically out of my hands and in the domain of the bootloader component that's actually handling all the comms to the host.

The length of the start condition on the first transmission from the host and the length of the ACKs at the end of each transmission also seem a bit long, but shouldn't actually matter I don't think?

Any ideas for what I can check to narrow the issue down?  Something I'm getting wrong?  The bootloader on the PSoC should in theory just handle itself, I don't know why the response is the way it is.  I've attached the Creator project.  I can also provide the Visual Studio C# WinForms project I've been using to test this if need be.

Thanks,

-Kyle

0 Likes
1 Solution

Alright, I think I've got it sorted out.  It's a bit of a journey from A to B so here goes:

Firstly, turns out I'm a big dummy and had by Marshal.Copy in the wrong place in my ReadData function.  I was copying data to buffer before anything had actually been read into my data array.  ReadData now looks like:

public unsafe int ReadData(IntPtr buffer, int size)

        {

            int status = 0;

            CY_RETURN_STATUS cy_stat;

            byte[] data = new byte[MaxTransferSize];

            fixed (byte* b = data)

            {

                cyReadDatabuffer.buffer = b;

                cyReadDatabuffer.length = (uint)size;

                fixed (CY_I2C_DATA_CONFIG* data_cfg = &cyI2CDataConfig)

                {

                    fixed (CY_DATA_BUFFER* dta_buff = &cyReadDatabuffer)

                    {

                        cy_stat = CyI2cRead(handle, data_cfg, dta_buff, 5000);

                    }

                }

            }

            Marshal.Copy(data, 0, buffer, size);  //This was originally before the actual read

            if (cy_stat == CY_RETURN_STATUS.CY_SUCCESS)

            {

                status = ERR_SUCCESS;

            }

            else

            {

                status = ERR_READ;

                CyI2cReset(handle, 0);

            }

            return status;

        }

So what has this done? well I get 5 transactions rather than the 3 I was getting before, so I got slightly further in the process, but it still fails.

1)

pastedImage_2.png

2)

pastedImage_3.png

3)

pastedImage_4.png

4)

pastedImage_5.png

5)

pastedImage_6.png

I'm mostly getting "Check Security Key" errors (I don't have security key enabled) error code 0x4005.

Parsing that error code out, it's an invalid command response from the Bootloader on the PSoC.  So it's seeing the 0x33 command from #3 as invalid.  According to the bootloader v1.60 datasheet, this is a command for "Get Application Status (Dual-application bootloader Only).

I'm not using a dual application loader, but I notice in the Bootloader Component when "Dual Application Bootloader" is not selected, "Get Application Status" is by default greyed out.  Presumably this kills support for the command.

I determined the source of the error to be bootloader_utils.dll, in particular, this bit of RunAction_v0:

err = CyBtldr_ParseHeader(lineLen, line, &siliconId, &siliconRev, &chksumtype);

    if (CYRET_SUCCESS == err)

    {

        CyBtldr_SetCheckSumType(chksumtype);

        err = CyBtldr_StartBootloadOperation(comm, siliconId, siliconRev, &blVer, securityKey);

        bootloaderEntered = 1;

        appId -= 1; /* 1 and 2 are legal inputs to function. 0 and 1 are valid for bootloader component */

        if (appId > 1)

        {

            appId = INVALID_APP;

        }

       

        if ((CYRET_SUCCESS == err) && (appId != INVALID_APP))

        {

            /* This will return error if bootloader is for single app */

            err = CyBtldr_GetApplicationStatus(appId, &isValid, &isActive);

            /* Active app can be verified, but not programmed or erased */

            if (CYRET_SUCCESS == err && VERIFY != action && isActive)

            {

                /* This is multi app */

                err = CYRET_ERR_ACTIVE;

            }

        }

    }

/*Function continues if err == CYRET_SUCCESS*/

Looks like there's no contingency for non-multi-application bootloaders.  It will simply error out if the check for multi-application loader returns an error, rather than using that status as a means to detect a single application loader.  Like the comment says, this will return an error if bootloader is single app.  It just doesn't do anything about it if that's the case.  It SHOULD look something like this:

        if ((CYRET_SUCCESS == err) && (appId != INVALID_APP))

        {

            /* This will return error if bootloader is for single app */

            err = CyBtldr_GetApplicationStatus(appId, &isValid, &isActive);

            /* Active app can be verified, but not programmed or erased */

            if (CYRET_SUCCESS == err && VERIFY != action && isActive)

            {

                /* This is multi app */

                err = CYRET_ERR_ACTIVE;

            }

            else if (CYBTLDR_STAT_ERR_CMD == (err ^ (int)CYRET_ERR_BTLDR_MASK))

            {

                /* Single app - restore previous CYRET_SUCCESS */

                err = CYRET_SUCCESS;

            }

        }

This mistake(?) is present in the cybootloader utils source code included with PSoC Creator 4.1.

So when do I get my check in the mail for fixing manufacturer code bugs?

View solution in original post

0 Likes
8 Replies
KyTr_1955226
Level 6
Level 6
250 sign-ins 10 likes given 50 solutions authored

Bump for Visibility

0 Likes
GeonaP_26
Moderator
Moderator
Moderator
250 solutions authored 100 solutions authored 50 solutions authored

If the bootloader is not ready with the response packet, as per the implementation it will send 0xFF. Are you able to recreate the observation with Bridge Control Pannel using steps elaborated in page 33 of AN60317

0 Likes

What "Obeservation" is being referred to here?  I'm not using MABL so what exactly am I recreating?

I'm assuming you mean just entering and exiting the bootloader.

I connected the Miniprog 3 to my I2C bus and got the following:

pastedImage_0.png

So it looks like it responded OK here?  It looks like what I got back is exactly the same as my first post, just without the twelve 0xFF bytes.  These commands successfully launched into and left the bootloader and started the application.

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

A couple of logic analyzer captures from those 3 commands coming from the MiniProg3 hooked into the I2C bus:

From MiniProg (Enter Bootloader):

pastedImage_1.png

Response from PSoC:

pastedImage_0.png

From MiniProg (Exit Bootloader):

pastedImage_2.png

This all looks grand from the MiniProg 3, so why am I getting such long start/stop/ack conditions with the same commands with the CY7C65211?  Is the CY7C65211 just taking longer to bring the bus back to idle after the slave ACK?  Does it matter?

If the bootloader is not ready with the response packet, as per the I2C implementation it will send 0xFF.

If that's the case that would mean I would have to spread out the commands from the Bootloader Host a bit.  Is that something controlled in bootl_utils.dll?  I have attached my projects for both the host app and bootl_utils.dll.

0 Likes

Observations while trying to narrow the problem down:

I tried putting a delay between writes/reads in my bootl_utils.dll in order to give the PSoC more time to be "Ready" to transmit data back.  Putting a time delay (100mS) between the write and read in CyBtldr_TransferData  simply results in a longer ACK and still results in multiple 0xFF bytes returned from the PSoC upon read.  I can't imagine it's taking the PSoC over 100mS to be ready for the next command.

Something is holding SCL low after the PSoC ACKs the last byte of the first write.  I doubt the PSoC is stretching the clock since if that was the case, I should see the same clock stretching behavior when using the MiniProg3.  Further, if the PSoC is the one stretching the clock, one would think it would be ready for the read command once it releases the clock and wouldn't give me 0xFF bytes.  It seems like the CY7C65211 is holding the clock low longer than it should (until it starts the next command it seems like?). 

My question now is why isn't the CY7C65211 returning the bus to idle in a timely way after the PSoC ACKs the write command?  After a failed bootload attempt, SCL takes 11 seconds to return to high from the last ACK from the PSoC.

Of course the real question here is does any of this matter?  Does the PSoC Bootloader component even care if the ACK is held for that long?  If I'm barking up the wrong tree here, please do let me know.

Thanks

- Kyle

0 Likes

Bumping again, still having the same problem.

For reference my read/write callback functions for bootload_utils are below.  I don't see an issue with them but I could very well be missing something.  Entire VS project is attached a few posts above.

public unsafe int WriteData(IntPtr buffer, int size)

        {

            int status = 0;

            CY_RETURN_STATUS cy_stat;

            byte[] data = new byte[MaxTransferSize];

            Marshal.Copy(buffer, data, 0, size);

            fixed (byte* b = data)

            {

                cyDatabuffer.buffer = b;

                cyDatabuffer.length = (uint)size;

                fixed (CY_I2C_DATA_CONFIG* data_cfg = &cyI2CDataConfig)

                {

                    fixed (CY_DATA_BUFFER* dta_buff = &cyDatabuffer)

                    {

                        cy_stat = CyI2cWrite(handle, data_cfg, dta_buff, 5000);

                    }

                }

            }

            if (cy_stat == CY_RETURN_STATUS.CY_SUCCESS)

            {

                status = ERR_SUCCESS;

            }

            else

            {

                status = ERR_WRITE;

                CyI2cReset(handle, 1);

            }

            return status;

        }

public unsafe int ReadData(IntPtr buffer, int size)

        {

            int status = 0;

            CY_RETURN_STATUS cy_stat;

            byte[] data = new byte[MaxTransferSize];

            Marshal.Copy(buffer, data, 0, size);

            fixed (byte* b = data)

            {

                cyReadDatabuffer.buffer = b;

                cyReadDatabuffer.length = (uint)size;

                fixed (CY_I2C_DATA_CONFIG* data_cfg = &cyI2CDataConfig)

                {

                    fixed (CY_DATA_BUFFER* dta_buff = &cyReadDatabuffer)

                    {

                        cy_stat = CyI2cRead(handle, data_cfg, dta_buff, 5000);

                    }

                }

            }

            if (cy_stat == CY_RETURN_STATUS.CY_SUCCESS)

            {

                status = ERR_SUCCESS;

            }

            else

            {

                status = ERR_READ;

                CyI2cReset(handle, 0);

            }

            return status;

        }

0 Likes

I think setting the I2CDataConfig.isStopBit = 1 shortened the ACK bit, but I'm still getting errors from the loader:

From Host:

pastedImage_0.png

From PSoC:

pastedImage_1.png

From Host:

pastedImage_2.png

Note how in the response from the PSoC I get what looks like a legit bootloader packet for the first 15 bytes:
[SoP(0x01)][Status][Length][Data Bytes][Checksum][EoP(0x17)]

But then a whole load of 0xFF bytes.  The host keeps ACKing bytes from the PSoC rather than issuing a NACK and stop condition after the 15th byte (The EoP byte).

This is odd, I've confirmed the argument for size in the call of ReadData(IntPtr buffer, int size) is 15, which when you count up the bytes should NACK after the 0x17 byte.  So why is the CY7C65211 continuing to ACK bytes past that?

0 Likes

Alright, I think I've got it sorted out.  It's a bit of a journey from A to B so here goes:

Firstly, turns out I'm a big dummy and had by Marshal.Copy in the wrong place in my ReadData function.  I was copying data to buffer before anything had actually been read into my data array.  ReadData now looks like:

public unsafe int ReadData(IntPtr buffer, int size)

        {

            int status = 0;

            CY_RETURN_STATUS cy_stat;

            byte[] data = new byte[MaxTransferSize];

            fixed (byte* b = data)

            {

                cyReadDatabuffer.buffer = b;

                cyReadDatabuffer.length = (uint)size;

                fixed (CY_I2C_DATA_CONFIG* data_cfg = &cyI2CDataConfig)

                {

                    fixed (CY_DATA_BUFFER* dta_buff = &cyReadDatabuffer)

                    {

                        cy_stat = CyI2cRead(handle, data_cfg, dta_buff, 5000);

                    }

                }

            }

            Marshal.Copy(data, 0, buffer, size);  //This was originally before the actual read

            if (cy_stat == CY_RETURN_STATUS.CY_SUCCESS)

            {

                status = ERR_SUCCESS;

            }

            else

            {

                status = ERR_READ;

                CyI2cReset(handle, 0);

            }

            return status;

        }

So what has this done? well I get 5 transactions rather than the 3 I was getting before, so I got slightly further in the process, but it still fails.

1)

pastedImage_2.png

2)

pastedImage_3.png

3)

pastedImage_4.png

4)

pastedImage_5.png

5)

pastedImage_6.png

I'm mostly getting "Check Security Key" errors (I don't have security key enabled) error code 0x4005.

Parsing that error code out, it's an invalid command response from the Bootloader on the PSoC.  So it's seeing the 0x33 command from #3 as invalid.  According to the bootloader v1.60 datasheet, this is a command for "Get Application Status (Dual-application bootloader Only).

I'm not using a dual application loader, but I notice in the Bootloader Component when "Dual Application Bootloader" is not selected, "Get Application Status" is by default greyed out.  Presumably this kills support for the command.

I determined the source of the error to be bootloader_utils.dll, in particular, this bit of RunAction_v0:

err = CyBtldr_ParseHeader(lineLen, line, &siliconId, &siliconRev, &chksumtype);

    if (CYRET_SUCCESS == err)

    {

        CyBtldr_SetCheckSumType(chksumtype);

        err = CyBtldr_StartBootloadOperation(comm, siliconId, siliconRev, &blVer, securityKey);

        bootloaderEntered = 1;

        appId -= 1; /* 1 and 2 are legal inputs to function. 0 and 1 are valid for bootloader component */

        if (appId > 1)

        {

            appId = INVALID_APP;

        }

       

        if ((CYRET_SUCCESS == err) && (appId != INVALID_APP))

        {

            /* This will return error if bootloader is for single app */

            err = CyBtldr_GetApplicationStatus(appId, &isValid, &isActive);

            /* Active app can be verified, but not programmed or erased */

            if (CYRET_SUCCESS == err && VERIFY != action && isActive)

            {

                /* This is multi app */

                err = CYRET_ERR_ACTIVE;

            }

        }

    }

/*Function continues if err == CYRET_SUCCESS*/

Looks like there's no contingency for non-multi-application bootloaders.  It will simply error out if the check for multi-application loader returns an error, rather than using that status as a means to detect a single application loader.  Like the comment says, this will return an error if bootloader is single app.  It just doesn't do anything about it if that's the case.  It SHOULD look something like this:

        if ((CYRET_SUCCESS == err) && (appId != INVALID_APP))

        {

            /* This will return error if bootloader is for single app */

            err = CyBtldr_GetApplicationStatus(appId, &isValid, &isActive);

            /* Active app can be verified, but not programmed or erased */

            if (CYRET_SUCCESS == err && VERIFY != action && isActive)

            {

                /* This is multi app */

                err = CYRET_ERR_ACTIVE;

            }

            else if (CYBTLDR_STAT_ERR_CMD == (err ^ (int)CYRET_ERR_BTLDR_MASK))

            {

                /* Single app - restore previous CYRET_SUCCESS */

                err = CYRET_SUCCESS;

            }

        }

This mistake(?) is present in the cybootloader utils source code included with PSoC Creator 4.1.

So when do I get my check in the mail for fixing manufacturer code bugs?

0 Likes