Skip to main content
Version: 4.16

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
Skip this step if external flash is not relevant for your board bring up.

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 PointRationale
External flash is readableExternal flash can be used for image storage
External flash performanceGraphics 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:

Configuring QSPI flash

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.