How to use external QSPI flash
From SomLabs Wiki
How to use external QSPI flash on the StarSOM-STM32H757
This tutorial explains how to write the data to the external QSPI Flash memory on StarSOM-STM32H757 module. Please note, that it does not allow to execute code directly from it. It may serve as a large, static data storage, like graphics, while the application code is executed from internal MCU flash memory.
External flash loader
In order to program the external flash using the ST tools, an additional flash loader application is required. The External flash loader for StarSOM-STM32H757 is available as a pre-compiled binary, as well as the STM32CubeIDE (Version: 1.17.0).
- https://github.com/SoMLabs/starsom-stm32h757-extflashloader/raw/refs/heads/main/CM7/starsom-stm32h757-extflashloader_CM7.stldr
- https://github.com/SoMLabs/starsom-stm32h757-extflashloader
Configuring external flash memory in STM32CubeIDE project
The external flash address and size need to be configured in the linker script located in the project directory: CM7/STM32H757XIHX_FLASH.ld
MEMORY { RAM_D1 (xrw) : ORIGIN = 0x24000000, LENGTH = 512K FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 1024K /* Memory is divided. Actual start is 0x08000000 and actual length is 2048K */ DTCMRAM (xrw) : ORIGIN = 0x20000000, LENGTH = 128K RAM_D2 (xrw) : ORIGIN = 0x30000000, LENGTH = 288K RAM_D3 (xrw) : ORIGIN = 0x38000000, LENGTH = 64K ITCMRAM (xrw) : ORIGIN = 0x00000000, LENGTH = 64K EXTFLASH (r) : ORIGIN = 0x90000000, LENGTH = 16384K }
To easily add static variables to flash location, a new section should also be added in the linker script SECTIONS list, for example:
.big_flash (READONLY) : { . = ALIGN(4); *(.RoDataSection); } >EXTFLASH
After that, each variable declared in .RoDataSection section will be placed in the external QSPI flash.
const __attribute__((section(".RoDataSection"))) uint8_t big_table[] = { ... };
QUADSPI interface configuration
The QSPI interface with required signals can be configured in the Device Configuration Tool:


The generated code looks like this:
static void MX_QUADSPI_Init(void) { /* USER CODE BEGIN QUADSPI_Init 0 */ /* USER CODE END QUADSPI_Init 0 */ /* USER CODE BEGIN QUADSPI_Init 1 */ /* USER CODE END QUADSPI_Init 1 */ /* QUADSPI parameter configuration*/ hqspi.Instance = QUADSPI; hqspi.Init.ClockPrescaler = 1; hqspi.Init.FifoThreshold = 1; hqspi.Init.SampleShifting = QSPI_SAMPLE_SHIFTING_NONE; hqspi.Init.FlashSize = 23; hqspi.Init.ChipSelectHighTime = QSPI_CS_HIGH_TIME_3_CYCLE; hqspi.Init.ClockMode = QSPI_CLOCK_MODE_0; hqspi.Init.FlashID = QSPI_FLASH_ID_1; hqspi.Init.DualFlash = QSPI_DUALFLASH_DISABLE; if (HAL_QSPI_Init(&hqspi) != HAL_OK) { Error_Handler(); } /* USER CODE BEGIN QUADSPI_Init 2 */ /* USER CODE END QUADSPI_Init 2 */ }
void HAL_QSPI_MspInit(QSPI_HandleTypeDef* hqspi) { GPIO_InitTypeDef GPIO_InitStruct = {0}; RCC_PeriphCLKInitTypeDef PeriphClkInitStruct = {0}; if(hqspi->Instance==QUADSPI) { /* USER CODE BEGIN QUADSPI_MspInit 0 */ /* USER CODE END QUADSPI_MspInit 0 */ /** Initializes the peripherals clock */ PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_QSPI; PeriphClkInitStruct.QspiClockSelection = RCC_QSPICLKSOURCE_D1HCLK; if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct) != HAL_OK) { Error_Handler(); } /* Peripheral clock enable */ __HAL_RCC_QSPI_CLK_ENABLE(); __HAL_RCC_GPIOE_CLK_ENABLE(); __HAL_RCC_GPIOG_CLK_ENABLE(); __HAL_RCC_GPIOF_CLK_ENABLE(); __HAL_RCC_GPIOD_CLK_ENABLE(); /**QUADSPI GPIO Configuration PE2 ------> QUADSPI_BK1_IO2 PG6 ------> QUADSPI_BK1_NCS PF10 ------> QUADSPI_CLK PD11 ------> QUADSPI_BK1_IO0 PD12 ------> QUADSPI_BK1_IO1 PD13 ------> QUADSPI_BK1_IO3 */ GPIO_InitStruct.Pin = GPIO_PIN_2; GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; GPIO_InitStruct.Alternate = GPIO_AF9_QUADSPI; HAL_GPIO_Init(GPIOE, &GPIO_InitStruct); GPIO_InitStruct.Pin = GPIO_PIN_6; GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; GPIO_InitStruct.Alternate = GPIO_AF10_QUADSPI; HAL_GPIO_Init(GPIOG, &GPIO_InitStruct); GPIO_InitStruct.Pin = GPIO_PIN_10; GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; GPIO_InitStruct.Alternate = GPIO_AF9_QUADSPI; HAL_GPIO_Init(GPIOF, &GPIO_InitStruct); GPIO_InitStruct.Pin = GPIO_PIN_11|GPIO_PIN_12|GPIO_PIN_13; GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; GPIO_InitStruct.Alternate = GPIO_AF9_QUADSPI; HAL_GPIO_Init(GPIOD, &GPIO_InitStruct); /* USER CODE BEGIN QUADSPI_MspInit 1 */ /* USER CODE END QUADSPI_MspInit 1 */ } }
External QSPI flash mapping
In order to access the external flash from the processor address space it should be first mapped as a read-only region:
HAL_StatusTypeDef QSPI_Flash_Map(void) { QSPI_CommandTypeDef s_command; QSPI_MemoryMappedTypeDef s_mem_mapped_cfg; /* Initialize the read command */ s_command.InstructionMode = QSPI_INSTRUCTION_1_LINE; s_command.Instruction = 0x6b; // fast read quad output s_command.AddressMode = QSPI_ADDRESS_1_LINE; s_command.AddressSize = QSPI_ADDRESS_24_BITS; s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; s_command.DataMode = QSPI_DATA_4_LINES; s_command.DummyCycles = 8; s_command.DdrMode = QSPI_DDR_MODE_DISABLE; s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; s_mem_mapped_cfg.TimeOutActivation = QSPI_TIMEOUT_COUNTER_DISABLE; if (HAL_QSPI_MemoryMapped(&hqspi, &s_command, &s_mem_mapped_cfg) != HAL_OK) { return HAL_ERROR; } return HAL_OK; }
Using external flash loader in STM32CubeIDE
In order to flash the external memory using the STM32CubeIDE, the external loader binary should be added in the Debug Configuration window:

Using external flash loader in STM32CubeProgrammer
The external loader binary (starsom-stm32h757-extflashloader_CM7.stldr) should be copied to the STM32CubeProgrammer directory STM32CubeProgrammer/bin/ExternalLoader. It can be then selected in the application window.
