A flash loader for Red-V development board with FE310 RISC-V microcontroller
Basic Info:
MCU: FE310
QSPI Flash: IS25LP032D
Dev board: Sparkfun Red-V with on-board J-Link
Loader usage example: OpenOCD
Languages: RISC-V RV32IMAC Assembly, C
The loader structure could be used to create further loaders for different MCUs or to support other QSPI Flash.
Loader building (see CMakeLists.txt):
Compilation: -march=rv32imac -mabi=ilp32 -nostdlib -nostartfiles -Wall -Wextra -Os
Linking: -Wl,--nostdlib,-e,loader
Usage/Inner workings:
The loader is a compiled into a binary that has executable code and a configuration table embedded into it.
Alternatively, precompiled loader.bin can also be used as-is (compiled with parameters set as in the provided source code and examples).
The user of the loader uses a host debugger tool (such as OpenOCD) to load the loader into RAM (Position-independent),
and then sets the MCU program counter to the same load address and resumes execution.
The loader initializes itself:
- sets its own stack as set in the code (see headers)
- switches MCU clock to PLL clock with external XTAL source
- resets QSPI Flash (forcing the flash into the default single-line SPI mode regardless of its initial configuration)
- halts at the breakpoint instruction waiting for commands
The loader halted the CPU and is ready to accept commands:
- The host uses the debugger tool to set operation code and parameters right in the memory structure of loader. Parameters include:
- Command code
- Flash memory address (non-memory-mapped, starting from 0)
- Flash data length (read length/write length; ignored for erase)
- If writing into flash, the host also writes data (max. 1 256-byte page at a time) into data buffer located at the configured location (header)
- The host advances program counter of the MCU by 4 (past breakpoint, into a small nop field landing area)
- The host resumes execution
The loader received command and resumed execution:
- The loader detects non-zero command code, jumps to the specific handler and performs read/write/erase
- Once the operation finished, the MCU resets the command code to zero, and halts at the same breakpoint instruction waiting for the next command
- If reading from the flash, the data read from the flash is now in the data buffer in RAM. Read length is limited only by MCU RAM size.
Stack space used by the loader:
~220 bytes (256 bytes of dedicated stack space is more than enough)
Supported commands:
- Read flash (any length as long as it fits into RAM)
- Write flash (max. 1 x 256-byte page per command)
- Erase 4KiB sector
- Erase 64KiB sector
- Mass erase
Provided OpenOCD scripts allow the user to read/write/erase data of arbitrary size, the script will handle sending as many commands as necessary.
WARNING: Erase length 0 means MASS ERASE
WARNING: OpenOCD script may occasionally fail to connect to the target. It seems pretty random. If it happens, try again. It typically succeeds within 1-3 attempts.
WARNING: The loader functions correctly, but is pretty slow (unfortunately, OpenOCD + J-Link is a slow combo)