Failsafe Firmware on SPI

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

cross mob
GeLe_3002426
Level 1
Level 1
First question asked First solution authored First reply posted

Hi, was following this example (FX3 Fail Safe Firmware Update ) and code but modified this code to boot to SPI.

So, firstly, what works. As demonstrated in the above example, I have separated my EEPROM into multiple sections with these hardcoded addresses

EEPROM Memory organization:

START ADDRESS

CONTENT

0x0000

Second Stage Boot-loader image

0x2800

Primary Firmware image

0x34800

Secondary Firmware image

0x2600(Single Byte)

Firmware Update Byte (0x00 – Primary FW, 0xFF – Secondary FW)

Using the Imgcombine.zip file, I made something that did not require C# and verified that it writes multiple image files into a single image file. That is, I write the Bootloader to 0x0, the Primary firmware image to 0x2800, and the Secondary firmware image to 0x34800.

I've used the Cypress flash tool to download this image to SPI

By flipping the Firmware Update byte, I have successfully used the second stage bootloader into the Primary or the Secondary firmware images.

What has NOT been successful is when I boot to the Primary firmware image and try to write a new secondary image. While running the primary image, I have a function that writes a new image that it transfers over USB and writes to SPI address 0x34800. I have verified that the SPI writes are correct (doing a read after the entire contents are written and comparing), and I have also verified that the entire 180+kB image is correctly written byte for byte into SPI starting @ 0x23800.

On reset, the software does not boot.

In stranger behaviour, when I boot to the secondary firmware (starting at 0x34800) and write the USB image to the SPI starting at 0x2800, the software hangs mid write and when power cycled, the hardware I assume has tried to boot from SPI but has done a failsafe fallback to USB. Seems like I'm overwriting the active RAM instance??

Lastly, I have used my read utilities to pull the first 200k off my SPI EEPROM. Other than the first four bytes ( 0x43, 0x59, 0x1C, 0xB0) the data between what is written on the SPI and the image that I flashed on using the Cypress utility is different!

This suggests that the SPI flash process does something to the image?

Is this documented anywhere?

What do I need to do with a compiled .img file to directly burn it to a specific SPI address and have it run?

0 Likes
1 Solution

Thanks again for the reply

To quickly answer your question, yes it shows as a bootloader on reset, however, I've uncovered the "reason": the sectorErase call actually deletes the entire sector, and being at 0x2600 with the primary firmware at 0x2800, they are both deleted with this call. In fact the entire sector from 0x00000 to 0x0FFFF is erased with this call, thus there is an invalid firmware image. Fall back is that it goes to bootloader.

So in good news, moving everything to the following addresses makes the code work "ALMOST" as expected:

EEPROM Memory organization:

START ADDRESS

CONTENT

0x0000

Second Stage Boot-loader image

0x10000

Firmware Update Byte

0x20000

Primary Firmware image

0x50000

Secondary Firmware image

I can now flash the board through my application, check that the firmware update byte has been flipped. On reboot, it boots into the secondary firmware!

Now the strange behaviour: on a cold power on (i.e. unplug USB cable and then re-plug it back in) the boot loader hangs, until I hit the reset button (currently using the Denebola board which wires the manual reset button to C5 (RESET) on the CX3) when the board boots correctly.

If the Firmware Update Byte is at 0x2600, the board boots fine. However, this cannot be the solution as I cannot then write to 0x2600 as I need to erase prior to writing and my erase would delete the entire sector.

I put UART debug code in and writing debug messages to UART, the problem disappeared. Once I remove the UART prints, the hang returns.

Any suggestions on killing this Heisenbug?

View solution in original post

0 Likes
6 Replies
Hemanth
Moderator
Moderator
Moderator
First like given First question asked 750 replies posted

Hi,

Regarding the comments:

"By flipping the Firmware Update byte, I have successfully used the second stage bootloader into the Primary or the Secondary firmware images.":

1. Can I know how you performed the data toggle at location 0x2600:

- Is it through your primary/ secondary firmware? Or

- By generating the combined image file to contain different data @0x2600?

2. After you program flash @0x34800 using the running primary firmware, I note that you have a read routine in the primary firmware which verified if the image is correctly written - which shows it correctly programmed the Flash as you said. After this, you mentioned that software does not boot. So, is it coming up as Bootloader device?

Regards,

Hemanth

Hemanth
0 Likes

Thanks for the quick reply Hemanth

1) Good question -

I have written to 0x2600 only when I generate the combined image. I just tried writing in primary / secondary firmware and it goes back to the bootloader

2) Yes - here is a dump from my syslog verifying that once I write to the 0x2600 byte, the device comes up as a bootloader.

Mar 29 12:22:45  kernel: [  318.484492] usb 2-3: New USB device found, idVendor=04b4, idProduct=4720, bcdDevice= 0.00

Mar 29 12:22:45  kernel: [  318.484500] usb 2-3: New USB device strings: Mfr=1, Product=2, SerialNumber=0

Mar 29 12:22:45  kernel: [  318.484504] usb 2-3: Product: FX3

Mar 29 12:22:45  kernel: [  318.484508] usb 2-3: Manufacturer: Cypress

Mar 29 12:22:45  mtp-probe: checking bus 2, device 13: "/sys/devices/pci0000:00/0000:00:14.0/usb2/2-3"

I've included a brief section of the code here that controls the byte. The functions waitForSpiStatus and spiReadBytes are from the spi_test.c file from https://community.cypress.com/servlet/JiveServlet/download/38-42518/Fx3BootAppGcc_Project.zip

#define BOOT_INDEX 0x2600

uint8_t glDataBuf[5];

else if ((wValue == 0x0699)) {

uint8_t flipped_bit[1];

status = CyU3PUsbGetEP0Data(1, glDataBuf, &readCount);

status = waitForSpiStatus();

status = spiReadBytes( BOOT_INDEX,4,glDataBuf);

status = CyU3PDebugPrint(4, "\n\rFlipping boot index from %x ",glDataBuf[0]);

flipped_bit[0]=( (glDataBuf[0]==1)?0:1);//toggle the bit on the boot index

status = CyU3PDebugPrint(4, " to %x ",flipped_bit[0]);

do {

status = spiWriteEnable();

status = sectorErase(BOOT_INDEX);

status = waitForSpiStatus ();

status = spiWriteBytes(BOOT_INDEX, 1, flipped_bit);

status = waitForSpiStatus ();

status = spiReadBytes( BOOT_INDEX,1 ,glDataBuf);

status = CyU3PDebugPrint(4, "\n\rRead Boot Index is now:%x (desired %x) ",glDataBuf[0], flipped_bit[0]);

} while (glDataBuf[0]!= flipped_bit[0]);

isHandled = CyTrue;

} else if ((wValue == 0x0670)) { //read firmware image

0 Likes
Hemanth
Moderator
Moderator
Moderator
First like given First question asked 750 replies posted

Hi,

In the sys log above, the pid shown is of Boot programmer. so, is that the log after toggling the byte @0x2600 using bootprogrammer firmware and then board is reset to check if it boots well?

Regards,

Hemanth

Hemanth
0 Likes
Hemanth
Moderator
Moderator
Moderator
First like given First question asked 750 replies posted

Adding to my previous comment, you can try this:

1. Program the combined image such that primary boots

2. Ensue primary fw is running

3. Now through primary fw, change the 0x2600 byte

4. Now make Fx3 boot as USB Bootloader device (PID 0x00F3)

5. Use firmware example in the below path to read out the byte @0x2600. Verify whether it is as expected.

$Fx3_Sdk_Install_Path$\1.3\firmware\serialif_examples\cyfxusbspiregmode

Regards,

Hemanth

Hemanth
0 Likes

Thanks again for the reply

To quickly answer your question, yes it shows as a bootloader on reset, however, I've uncovered the "reason": the sectorErase call actually deletes the entire sector, and being at 0x2600 with the primary firmware at 0x2800, they are both deleted with this call. In fact the entire sector from 0x00000 to 0x0FFFF is erased with this call, thus there is an invalid firmware image. Fall back is that it goes to bootloader.

So in good news, moving everything to the following addresses makes the code work "ALMOST" as expected:

EEPROM Memory organization:

START ADDRESS

CONTENT

0x0000

Second Stage Boot-loader image

0x10000

Firmware Update Byte

0x20000

Primary Firmware image

0x50000

Secondary Firmware image

I can now flash the board through my application, check that the firmware update byte has been flipped. On reboot, it boots into the secondary firmware!

Now the strange behaviour: on a cold power on (i.e. unplug USB cable and then re-plug it back in) the boot loader hangs, until I hit the reset button (currently using the Denebola board which wires the manual reset button to C5 (RESET) on the CX3) when the board boots correctly.

If the Firmware Update Byte is at 0x2600, the board boots fine. However, this cannot be the solution as I cannot then write to 0x2600 as I need to erase prior to writing and my erase would delete the entire sector.

I put UART debug code in and writing debug messages to UART, the problem disappeared. Once I remove the UART prints, the hang returns.

Any suggestions on killing this Heisenbug?

0 Likes
Hemanth
Moderator
Moderator
Moderator
First like given First question asked 750 replies posted

Hi,

Based on the above comments, problem most likely is because of EEPROM content getting changed incorrectly. The change which occurs by adding/ removing UART debug code, is the code size.

Regards,

Hemanth

Hemanth
0 Likes