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:
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:
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:
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.