6. External addressable flash
Motivation
In this step we will enable an external quad or octo SPI flash in memory mapped mode. An external flash is recommended for most project as it allows the application to use many and large images. The internal flash will quickly be full even for modest applications.
Note
When data is to be placed in external flash it is important that the external flash can be read by the MCU. The external flash should run at desired (typically maximum) speed to get the best performance.
Goal
The goal for this section is to enable the external flash, change it to memory mapped mode, and read data from it. As the read speed of the external flash is very important to graphics, you should also test the reading speed.
Verification
Here are the verification points for this section:
Verification Point | Rationale |
---|---|
External flash is readable | External flash can be used for image storage |
External flash Performance | Graphics performance depends a lot of the performance of the image memory |
Prerequisites
The following are the prerequisites for this step:
- Information about the flash, typically a datasheet
- Information about the connections between the MCU and the external flash
Do
The QSPI controller is configured in CubeMX under Connectivity -> QUADSPI:
In the mode section you can configure the flash to single/dual/quad data lines. Quad lines are the fastest. Similar to the external RAM, you also here need to select and configure the GPIOs used for the data lines, chip select and clock signal.
Block Mode
After enabling the flash, we can test it by reading data from it. The Cube Firmware package contains examples for that.
Memory Mapped mode
After enabling the flash and testing it in block mode, it is necessary to change it to memory mapped mode. This will allow the cpu to fetch data directly from the flash.
The STM32 Cube HAL contains functions to change to memory mapped mode. An example is given here. It is necessary to consult the datasheet for the configuration data. The Cube Firmware package for your MCU contains more examples.
main.c
QSPI_CommandTypeDef s_command;
QSPI_MemoryMappedTypeDef s_mem_mapped_cfg;
/* Configure the command for the read instruction */
s_command.InstructionMode = QSPI_INSTRUCTION_1_LINE;
s_command.Instruction = QUAD_INOUT_FAST_READ_CMD;
s_command.AddressMode = QSPI_ADDRESS_4_LINES;
s_command.AddressSize = QSPI_ADDRESS_24_BITS;
s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;
s_command.DataMode = QSPI_DATA_4_LINES;
s_command.DummyCycles = N25Q128A_DUMMY_CYCLES_READ_QUAD;
s_command.DdrMode = QSPI_DDR_MODE_DISABLE;
s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY;
s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD;
/* Configure the memory mapped mode */
s_mem_mapped_cfg.TimeOutActivation = QSPI_TIMEOUT_COUNTER_DISABLE;
if (HAL_QSPI_MemoryMapped(&QSPIHandle, &s_command, &s_mem_mapped_cfg) != HAL_OK)
{
return QSPI_ERROR;
}
If you are using the same flash as one of the STM32 evaluation kits, then the BSP packages for these boards (also in the Cube Firmware) contains valuable examples that can be modified for your hardware.
When the flash is in memory mapped mode, you can test it with code similar to what we used for external RAM (find the address in your MCU datasheet):
volatile uint32_t *externalFlash = 0x90000000;
const uint32_t size = 1000;
volatile uint32_t result = 0;
//read external Flash
for(int i = 0; i < size; i++)
{
result += externalFlash[i];
}
Reuse the memory performance tests you did in earlier steps to also test the performance of the external flash.