Skip to content

Advanced topics

Reprogramming the SPI flash

Introduction

The EOS-S3 SoC does not have internal nonvolatile memory, so it boots from an external SPI flash. The breakout board has a bootloader pre-installed in the flash memory, which can be used to program the device using it's USB port. However, if the bootloader becomes corrupted for whatever reason, it can be useful to restore the whole SPI flash.

To do this, you'll need a Teensy with the spiflash firmware loaded.

First, some technical details. This is the flash memory layout that the quickfeather bootloader is expecting:

Item Status Start Size End Start Size End
bootloader Used 0x0000_0000 0x0001_0000 0x0000_FFFF 0 65,536 65,536
bootfpga CRC Used 0x0001_0000 8 0x0001_0007 65,536 8 65,544
appfpga CRC Future 0x0001_1000 8 0x0001_1007 69,632 8 69,640
appffe CRC Future 0x0001_2000 8 0x0001_2007 73,728 8 73,736
M4app CRC Used 0x0001_3000 8 0x0001_3007 77,824 8 77,832
bootloader CRC Used 0x0001_4000 8 0x0001_4007 81,920 8 81,928
bootfpga Used 0x0002_0000 0x0002_0000 0x0003_FFFF 131,072 131,072 262,144
appfpga Future 0x0004_0000 0x0002_0000 0x0005_FFFF 262,144 131,072 393,216
appffe Future 0x0006_0000 0x0002_0000 0x0007_FFFF 393,216 131,072 524,288
M4app Used 0x0008_0000 0x0006_E000 0x000E_DFFF 524,288 450,560 974,848

The hardware in the SoC only cares about the first section, which contains the bootloader. When it comes out of reset, configuration logic in the SoC reads 32 bits of data from the SPI flash location 0x120, which contains a device ID, the size of the bootloader image, and the desired SPI clock setting. If these are valid, the configuration logic then copies the bootloader into the device SRAM, and then starts the ARM processor.

Once it starts, the bootloader displays a prompt on the UART pins, then waits 5 seconds. If the user button is pressed during these 5 seconds, then it loads the bootfpga image into the FPGA, which allows the user to reprogram the device using the TinyFPGA programmer. If the button is not pressed within 5 seconds, the bootloader attempts to load the user program from the SPI flash into SRAM. It then verifies that the CRC makes (TODO: Does it actually do this?), and if it does, reconfigures the ARM to point to that code, to enter the user program.

The TLDR here is that if we want to write a raw image to the flash, we'll need at least the bootloader, bootloader CRC, bootfpga, andd bootfpga CRC sections to be present. For extra points, we can also preinstall a user app by filling the M4app and M4app CRC sections.

Step 1: Build the bootloader

First, let's build the bootloader:

cd ~/ql-eos-s3/qorc-sdk/bl_apps/bl_bootloader/GCC_Project
make

TODO: what sets up the 0x120 offset in the bootloader binary?

Step 2: Make a flash image

A tool to build a suitable image is included in the bl apps. Using it with the default options will grab the bootloader binary image that we just compiled above, as well as a (for now) precompiled appfpga image:

cd ~/ql-eos-s3/qorc-sdk/bl_apps/tools
python3 build_flash_image.py
added section:bootloader at:0x00000000 size:38228 crc:0x555d0a3e
added section:bootfpga at:0x00020000 size:75960 crc:0x82fc1983
Wrote 0xee000 bytes to image.bin

This should create a file called 'image.bin', which we can then load on the SPI flash chip, starting at offset 0.

Step 3: Flash it

Connect the Teensy to the dev board like so. Be sure to short the 'RST' pin on the board to 'GND', to prevent the SoC from booting:

Teensy flash diagram

TODO: text version of the pin table

Next, connect both the Teensy and the board to your computer using USB. Use your favorite serial terminal to connect to the Teensy. Issue the 'i' command to check if the SPI flash can be identified:

i
C84015C8

Note: The device ID for the flash on your board may differ, this is for the 2MB version

Now, tell the Teensy that we want to write EE000 bytes to the SPI flash, starting at offset 0. If the flash image was a different length, use that instead:

u0 EE0000
G 00000000 EE0000

Note: The 'u' will not be echoed to the terminal

Exit the serial terminal, and then use the PV command to write the image:

pv image.bin > /dev/ttyACM0

Now, detach the Teensy, then remove the jumper between RST and GND to boot flash image.

Set the IO pins in Bank A to a different reference voltage

Introduction

If you need to interface with a device that uses a different logic voltage than 3.3V, it is possible to set the reference voltage for the pins on Bank A.

Step 1: Cut the VCCIOA trace on the back of the board

On the back side of the board, cut the short copper trace in the middle of the 'VCCIOA' pad. This will disconnect the VCCIOA power line from the on-board 3.3V regulator: Cut the VCCIO trace

Step 2: Provide a 1.71 - 3.6V reference on the VCCA pin

Once the trace has been cut, you'll need to connect an external voltage to the header pin marked 'VCCA'. Then, all of the pins on the right-hand side of the board will be referenced to the external supply: VCCIOA pins

Note: The datasheet specifies a range of 1.71-3.6V for safe operation

Attach a JTAG debugger

TODO

Using JTAG with the RevB board reuqires pulling up both IO_8 and IO_9, and supplying a clock to FCLK. Additionally, the 10k pullups on SWD and SCK may not be present, and would need to be added externally. A future revision will use an alternate JTAG pin mapping, to allow it to be used with the on-board oscillator.