STM32H7 XiP poor performance with QSPI NOR Flash
I've been developing a solution around the STM32H750 that requires external flash to run relatively large firmware images, up to around 2Mb.
The NOR Flash part used is the Cypress s25fl064l, in QSPI configuration. It has quad read rates of up to 54Mbps.
A bootloader configures the QSPI interface, and then jumps to the main firmware on the memory mapped external flash.
Using the DWT to measure the number of cycles initially provided some promising numbers. In a 1-2-2 configuration (Single Instruction, Dual IO read) without SIOO (sending instruction on every read), our computations ran at around 180% cycles compared to running from internal flash. Not so bad, considering this is a slow configuration option with lots of overhead.
/* QSPI clock = 480MHz / (1+9) = 48MHz */
QSPIHandle.Init.ClockPrescaler = 9;
QSPIHandle.Init.FifoThreshold = 4;
QSPIHandle.Init.SampleShifting = QSPI_SAMPLE_SHIFTING_NONE;
QSPIHandle.Init.FlashSize = 22; // 2^(22+1) = 8M / 64Mbit
QSPIHandle.Init.ChipSelectHighTime = QSPI_CS_HIGH_TIME_1_CYCLE;
QSPIHandle.Init.ClockMode = QSPI_CLOCK_MODE_0;However the elapsed time turned out to be 40x greater than internal flash, taking 84 seconds to run a neural network classification instead of just over 2 seconds. Presumably that's down to lots of wait states incurred.
With a full 4-4-4 QSPI configuration, setting the 'Alternative byte' to read continuously and with SIOO enabled, we expected this to be improved many times. What we found was that the elapsed time roughly halved, while the cycle count went up.
This is what the read command looks like (sent after other commands have configured the NOR flash):
// Quad I/O 4-4-4, mode cycles 2
sCommand.Instruction = QSPI_FLASH_CMD_QIOR;
sCommand.InstructionMode = QSPI_INSTRUCTION_4_LINES;
sCommand.AddressMode = QSPI_ADDRESS_4_LINES;
sCommand.DataMode = QSPI_DATA_4_LINES;
sCommand.AddressSize = QSPI_ADDRESS_24_BITS;
sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_4_LINES;
sCommand.AlternateBytes = 0xA0; // Continuous read feature is enabled if the mode bits value is Axh.
sCommand.DummyCycles = 8;
sCommand.SIOOMode = QSPI_SIOO_INST_ONLY_FIRST_CMD;A computation cycle now takes 20x longer, while the cycle count is 3.5x greater.
We are in this instance running an STM32H753 at 480Mhz.
It's difficult to make much sense of this. There are things we can do to improve performance, such as putting (part of) the code into RAM or enabling DDR mode, but the numbers are so off the mark that simply doubling or even quadrupling performance is not going to fix the problem.
Our results are at odds with e.g. AN4760, which indicates (Performance Analysis, p.78) XiP with code and data in flash to run at 1.52x the speed (and with code in RAM at 1.12x). If we could get close to this I'd be happy, but at the moment we're at 20x.
Another question: when running in XiP mode, memory mapped to 0x90000000 (bank 2), it seems we are not able to put breakpoints in while debugging with OpenOCD and gdb. Is there a particular reason why?
Any help or insight offered would be very much appreciated!
