Target description
This article provides an overview of the External Memory Manager (EMM) and External Memory Loader (EML) for BootFlash applications on STM32H7Rx/7Sx and STM32N6 devices, first introducing their main capabilities and then presenting a detailed tutorial on how to configure and use them with the EMM Custom driver.
The first part of the article:
The first part of the article introduces the External Memory Manager (EMM) and External Memory Loader (EML) middleware features in BootFlash applications on STM32H7Rx/7Sx and STM32N6 products, in order to:
- Provide a unique API that allows access to external memories.
- Launch an application stored in an external memory (XIP (eXecute In Place) or LRUN (Load & Run)).
- Generate an External Memory Loader file (.stldr) for STM32Cube tools and IDEs.
This Getting Started focuses on the EMM Custom driver, which is used when the memory configuration is provided by the user (instead of being discovered from SFDP tables). The example memories used are MX66UW1G45G[1] and M95P32[2].
The second part of the article:
The second part of the article presents a detailed tutorial for STM32H7R/H7S and STM32N6 on how to:
- Configure the External Memory Manager with the Custom driver.
- Select a selected memory configuration matching the external memory (examples: MX66UW1G45G[1], M95P32[2]).
- Configure the External Memory Loader for the same memory.
- Build a BootFlash application and generate a loader file.
- Select each configuration parameter from the memory datasheet as used in the 'EXTMEM_<MEMORY>_INIT' configuration object.
Hardware
- STM32H7Rx/7Sx or STM32N6
Software
- STM32CubeMX.
- An IDE (IAR Systems®, Keil®, STM32CubeIDE).
- STM32CubeProgrammer (for loader usage).
Literature
- Introduction to External Memory Manager and External Memory Loader Middleware for Boot Flash MCU[3]
- External memory datasheet for the selected memory configuration (e.g., MX66UW1G45G[1], M95P32[2])
1. What is a BootFlash product
1.1. Definition
A BootFlash product is a device that contains a small embedded flash memory for the initial boot process and stores the application binary in an external memory.
1.2. What is a BootFlash application?
A BootFlash application is an application generated with STM32CubeMX that uses the External Memory Manager and External Memory Loader middleware to build a boot system capable of launching an application stored in external memory.
The project structure of a BootFlash application is divided into three different contexts:
- Boot: boot code to run from the internal flash memory.
- Appli: application code to run from the external memory.
- ExtMemLoader: code dedicated to generating the External Loader.
When using external memories, loader configuration is a critical step. ST provides multiple drivers and enables customers to adapt the loader behavior through the Custom Driver within the Boot project. The remainder of this article focuses on a configuration example of this Custom Driver for the target memory.
2. External Memory Manager Custom driver
2.1. Why a Custom driver?
The EMM Custom driver is used when the memory configuration (commands, dummy cycles, sizes, timings, etc.) is provided by the user instead of being discovered from SFDP data stored in the device.
Typical reasons to select the Custom driver:
- The memory does not support SFDP, or SFDP content is not usable (missing information).
- Need to improve boot time (no discovery at runtime).
- The memory configuration file is already available.
For an overview of the Custom driver APIs and the meaning of each configuration field, see:
2.2. Where the configuration file should be created
In a Custom-driver workflow, the memory configuration is expected to be written by the user as a C header that defines a 'EXTMEM_DRIVER_CUSTOM_ObjectTypeDef' initializer. The user could either create a new header file containing details about the used memory, or reuse memory configuration files as provided by ST.
For the MX66UW1G45G[1], create a new header or reuse the provided one (recommended location):
- Middlewares\ST\STM32_ExtMem_Manager\custom\memories\stm32_mx66uw1g45g.h
For the M95P32[2], use:
- Middlewares\ST\STM32_ExtMem_Manager\custom\memories\stm32_m95p32.h
This header should define:
- 'EXTMEM_<MEMORY>_INIT' (initializer macro for 'EXTMEM_DRIVER_CUSTOM_ObjectTypeDef')
- 'extmem_<memory>' (the object instance)
Examples:
- MX66UW1G45G[1]: 'EXTMEM_MX66UW1G45G_INIT', 'extmem_mx66uw1g45g'
- M95P32[2]: 'EXTMEM_M95P32_INIT', 'extmem_m95p32'
Other files in Middlewares\ST\STM32_ExtMem_Manager\custom\memories\ can be used as examples of how to structure a memory descriptor (include guards, macros, and the '*_INIT' object layout).
The values inserted in 'EXTMEM_<MEMORY>_INIT' are derived from the memory datasheet (instruction set/opcodes, timing characteristics, erase/program timings, memory organization).
3. How EMM selects a Custom memory configuration
EMM uses the configuration table 'extmem_list_config[]' declared in the generated configuration header (typically 'stm32_extmem_conf.h'). Each extmem_list_config[] array element contains details about a memory managed by the External Memory Manager MW. Each element indicates:
- the memory type ('MemType')
- the instance/physical link ('Handle', 'ConfigType')
- the driver object (for Custom driver: 'CustomObject')
At runtime, 'EXTMEM_Init()' dispatches to the correct driver implementation from the 'MemType' parameter (set to 'EXTMEM_CUSTOM' in our case).
For Custom driver the call path is:
- 'EXTMEM_Init()' → 'EXTMEM_DRIVER_CUSTOM_Init(..., &extmem_list_config[MemId].CustomObject)'
The type layout showing 'CustomObject' in 'EXTMEM_DefinitionTypeDef' is defined in:
- Code/stm32_extmem_type.h
Practical selection: using the MX66UW1G45G[1] object with 'EXTMEM_DRIVER_CUSTOM_Init()'
In a BootFlash application, the EMM middleware normally calls the Custom driver through 'EXTMEM_Init()' using the generated 'extmem_list_config[]' configuration.
For understanding/debug purposes (or for a minimal bring-up), you can also call the Custom driver directly using the MX66UW1G45G[1] object.
The MX66UW1G45G[1] object is defined in Middlewares\ST\STM32_ExtMem_Manager\custom\memories\stm32_mx66uw1g45g.h as 'extmem_mx66uw1g45g' and is initialized with 'EXTMEM_MX66UW1G45G_INIT'.
Minimal example (direct call):
#include "stm32_extmem_conf.h" /* brings the HAL handle declaration (e.g. hxspi2) */
#include "custom/memories/stm32_mx66uw1g45g.h"
#include "custom/stm32_custom_driver_api.h"
/* Example: use the XSPI instance connected to MX66UW1G45G */
static void MX66UW1G45G_BringUp(void)
{
/* ClockInput is the clock frequency of the XSPI, it can be retrieved using a clock fetch function or set directly*/
uint32_t clockInputHz = HAL_RCCEx_GetPeriphCLKFreq(RCC_PERIPHCLK_XSPI2);
/* Initialize the Custom driver with the user-provided memory object */
(void)EXTMEM_DRIVER_CUSTOM_Init((void *)&hxspi2, clockInputHz, &extmem_mx66uw1g45g);
}
4. How to derive 'EXTMEM_<MEMORY>_INIT' from the datasheet
This section explains how each parameter of 'EXTMEM_MX66UW1G45G_INIT' (written by the user or taken from a provided configuration file) is chosen from the MX66UW1G45G[1] datasheet. The user can update some of those values according to the expected memory configuration.
For general guidance on what each field means and where it is used by the Custom driver, see:
General memory configuration
| Field | Description | Datasheet section | Value |
|---|---|---|---|
| MemType | Select the NOR Flash/EEPROM-like command set. | Cover page / features (serial SPI page EEPROM, erase commands, sectors/blocks) | 'EXTMEM_CUSTOM_NOR_FLASH' |
| MemStandard | Select the correct 'EXTMEM_CUSTOM_STD_*' enum matching the memory vendor. | Vendor identification (part number, manufacturer ID) | 'EXTMEM_CUSTOM_STD_MACRONIX' |
| MemSize | Select the correct density enum. | Features / memory organization (1 Gbit) | 'EXTMEM_CUSTOM_SIZE_1GB' |
| ResetMethod | Use the reset instruction sequence required by the device. | Reset / software reset instructions | 'EXTMEM_CUSTOM_RESET_METHOD_6699_9966' |
| ResetDelay | Delay after reset before sending new commands. Adjust based on the datasheet worst-case if required. | Reset / Reset Timing (Reset Recovery time for chip erase operation) | '100' ms |
| SampleShiftCfg | Select sample shift configuration depending on the board signal integrity and interface mode. | Interface / timing recommendations | 'EXTMEM_CUSTOM_SSHIFT_CFG_NONE' |
| MemChipSelectHighTimeCycle | Ensure the chip-select high time between instructions respects the datasheet minimum deselect time. Choose this value so that tCSH >= tSHSL, where tCSH is derived from the XSPI clock period. | AC characteristics (chip-select deselect time, often named like tSHSL) | '8' cycles |
Startup configuration (baseline SPI STR)
StartupConfig is typically a safe configuration that can be used for reset/bring-up and basic reads/writes.
| Field | Description | Datasheet section | Value |
|---|---|---|---|
| StartupConfig.Frequency | Use a frequency compatible with the slowest required instruction class. | Command set / instruction description (frequency limits for read instructions) | '50000000' Hz |
| StartupConfig.CommandRead | Select a read opcode compatible with the selected access mode. | Instruction set / command table (read) | '0x0C' |
| StartupConfig.DummyCycleRead | One dummy byte = 8 dummy clock cycles in STR mode. | Read command description (dummy cycles/dummy byte) | '0x08' |
| StartupConfig.CommandWrite | Use the program opcode supported by the memory in this mode. | Instruction set / command table (program) | '0x12' |
| StartupConfig.DummyCycleWrite | No dummy cycles for page program. | Page program command description | '0x00' |
| StartupConfig.DummyRegisterRead | Dummy cycles required when reading registers in this mode. | Register read access description | '0' |
| StartupConfig.AddressSize | 32-bit addressing. | Address protocol / 4-byte address command set | 'EXTMEM_CUSTOM_ADDRESS_32_BITS' |
| StartupConfig.AccessMode | Instruction/address/data are transferred in single line STR. | Timing diagrams | 'EXTMEM_CUSTOM_1S_1S_1S' |
| StartupConfig.InstructionSize | Standard SPI opcode size. | Instruction set / command table (opcode width) | 'EXTMEM_CUSTOM_INSTRUCTION_8_BITS' |
| StartupConfig.DqsMode | DQS is not used in SPI STR. | Interface description (SPI STR) | 'EXTMEM_CUSTOM_DQS_DISABLE' |
Register configuration sequence before enabling 'OptionalConfig'
Before switching the driver to the octal DTR 'OptionalConfig', the MX66UW1G45G[1] example executes four register-configuration steps. The first two steps program Configuration Register 2 while the memory is still accessed in startup SPI STR mode, the third step applies 'OptionalConfig', and the fourth step verifies register access with the new protocol.
| Parameter | Description | Datasheet section | Value |
|---|---|---|---|
| NbRegisterConfig | Number of configuration steps that must be executed before normal accesses start. The MX66UW1G45G[1] flow needs four steps: program dummy cycles, enable DTR OPI, apply 'OptionalConfig', then verify the new protocol. | Configuration register 2 / protocol-switch procedure | '4' |
Step 0: Program the dummy-cycle selection before the protocol switch
This step uses the '0x71' / '0x72' / '0x71' read-write-read sequence on Configuration Register 2 at address '0x300' to program the dummy-cycle setting that matches the later high-speed read timing.
| Parameter | Description | Datasheet section | Value |
|---|---|---|---|
| RegisterConfig[0]. ConfigStepType | Select a read-write-read register flow so the driver reads Configuration Register 2, updates it, then reads it again to verify the write while still in startup SPI STR mode. | Configuration register 2 / configurable dummy cycle / register access sequence | 'EXTMEM_CUSTOM_CFGSTEP_RWR_REG_ADDR' |
| RegisterConfig[0]. RWConfigStep.CommandRegisterWrite | Register-write opcode used to program Configuration Register 2. | Register write instruction / configuration register 2 access | '0x72' |
| RegisterConfig[0]. RWConfigStep.CommandRegisterRead | Register-read opcode used for the initial readback of Configuration Register 2. | Register read instruction / configuration register 2 access | '0x71' |
| RegisterConfig[0]. RWConfigStep.CommandRegisterReadAW | Register-read opcode used for the post-write verification readback. | Register read after write / configuration register 2 access | '0x71' |
| RegisterConfig[0]. RWConfigStep.RegisterAddress | Selects Configuration Register 2 sub-address '0x300', which is used here for dummy-cycle selection. | Configuration register 2 / dummy-cycle field location | '0x300' |
| RegisterConfig[0]. RWConfigStep.RegisterValue | Programs the dummy-cycle field with value '0x00', matching the default code used by the descriptor before switching to the octal DTR read timing. | Configuration register 2 / dummy-cycle encoding | '0x00' |
| RegisterConfig[0]. RWConfigStep.RegisterMask | Restricts the write to the dummy-cycle selection bits only. | Configuration register 2 / dummy-cycle bit mask | '0x07' |
Step 1: Enable the DTR OPI protocol in Configuration Register 2
This step updates Configuration Register 2 at address '0x00' so the device accepts the octal DTR protocol used by 'OptionalConfig'.
| Parameter | Description | Datasheet section | Value |
|---|---|---|---|
| RegisterConfig[1]. ConfigStepType | Select a read-write register flow so the driver reads the current register value, applies the requested masked update, and writes it back before leaving startup SPI STR mode. | Configuration register 2 / protocol-selection bits / register access sequence | 'EXTMEM_CUSTOM_CFGSTEP_RW_REG_ADDR' |
| RegisterConfig[1]. RWConfigStep.CommandRegisterWrite | Register-write opcode used to set the protocol-selection bit. | Register write instruction / configuration register 2 access | '0x72' |
| RegisterConfig[1]. RWConfigStep.CommandRegisterRead | Register-read opcode used to fetch the current register value before modification. | Register read instruction / configuration register 2 access | '0x71' |
| RegisterConfig[1]. RWConfigStep.RegisterAddress | Selects Configuration Register 2 sub-address '0x00', used here for protocol selection. | Configuration register 2 / protocol-selection field location | '0x00' |
| RegisterConfig[1]. RWConfigStep.RegisterValue | Sets the DTR OPI enable bit required before the memory can be accessed with the octal DTR commands from 'OptionalConfig'. | Configuration register 2 / DTR OPI enable bit | '0x02' |
| RegisterConfig[1]. RWConfigStep.RegisterMask | Restricts the update to the protocol-selection bit only. | Configuration register 2 / protocol-selection bit mask | '0x02' |
Step 2: Execute the Optional configuration
This step is the actual protocol switch from startup (StartupConfig) SPI STR settings to the octal DTR access parameters defined in 'OptionalConfig'.
| Parameter | Description | Datasheet section | Value |
|---|---|---|---|
| RegisterConfig[2]. ConfigStepType | Tells the driver to apply the 'OptionalConfig' block after the prerequisite register writes are complete. This is where the access mode changes to octal DTR ('EXTMEM_CUSTOM_8D_8D_8D', 16-bit instructions, DQS enabled, '200000000' Hz). | Mode-switch procedure / protocol transition to octal DTR | 'EXTMEM_CUSTOM_CFGSTEP_EXEC_OPT_CFG' |
Step 3: Verify register access after the protocol switch
After 'OptionalConfig' has been applied, the driver performs one more register read using the post-switch opcode to confirm that the memory now answers with the new protocol.
| Parameter | Description | Datasheet section | Value |
|---|---|---|---|
| RegisterConfig[3]. ConfigStepType | Select a read-after-write style access using the new protocol, so the driver can verify register communication after the octal DTR switch. | Register read after protocol switch / post-switch verification | 'EXTMEM_CUSTOM_CFGSTEP_RAW_REG_ADDR' |
| RegisterConfig[3]. RWConfigStep.CommandRegisterReadAW | Post-switch register-read opcode used once the device is already in the new octal DTR protocol. | Register read after protocol switch / octal DTR register access | '0x718E' |
| RegisterConfig[3]. RWConfigStep.RegisterAddress | Reads back Configuration Register 2 at sub-address '0x00' to verify the new protocol selection. | Configuration register 2 / protocol-selection field location | '0x00' |
Optional configuration (performance configuration: Octal mode)
The MX66UW1G45G[1] example switches to an octal access mode for higher throughput.
| Field | Description | Datasheet section | Value |
|---|---|---|---|
| OptionalConfig.Frequency | Use the max frequency validated for this interface mode. | Mode timing limits | '200000000' Hz |
| OptionalConfig.CommandRead | Select the octal read opcode for the selected mode. | Instruction set / command table (octal read) | '0xEE11' |
| OptionalConfig.CommandWrite | Select the octal write/program opcode for the selected mode. | Instruction set / command table (octal program) | '0x12ED' |
| OptionalConfig.DummyCycleRead | Configure dummy cycles to meet the memory timing at the selected frequency. | Read command description (dummy cycles) | '20' |
| OptionalConfig.DummyCycleWrite | No dummy cycles are used for the write/program command in this mode. | Page program command description | '0' |
| OptionalConfig.DummyRegisterRead | Dummy cycles required when reading registers in this mode. | Register read access description | '4' |
| OptionalConfig.AccessMode | Instruction/address/data all use octal transfers. | Timing diagrams | 'EXTMEM_CUSTOM_8D_8D_8D' |
| OptionalConfig.InstructionSize | Some octal modes use 16-bit opcodes. | Opcode width in this mode | 'EXTMEM_CUSTOM_INSTRUCTION_16_BITS' |
| OptionalConfig.AddressSize | Keep 32-bit addressing enabled for this 1-Gbit density. | 256Mb Address protocol / 4-byte address command set | 'EXTMEM_CUSTOM_ADDRESS_32_BITS' |
| OptionalConfig.DqsMode | Enable DQS if required/used by the selected mode. | DQS usage for high-speed reads | 'EXTMEM_CUSTOM_DQS_ENABLE' |
NOR Flash specific configuration
| Field | Description | Datasheet section | Value |
|---|---|---|---|
| NorFlashConfig.PageSize | Used by the driver to split writes. | Features / memory organization (page size) / page program description (max bytes) | '256' bytes |
| NorFlashConfig.SectorSize | Used by erase operations. | Features / memory organization (sector size) / sector erase description | '0x1000' (4 KBytes) |
| NorFlashConfig.Startup.Cmd_EraseSector | Sector erase opcode used while the memory is still in startup SPI STR mode. | Sector erase (SE) / 4-byte address command set | '0x21' |
| NorFlashConfig.Startup.Cmd_MassErase | Chip erase opcode used while the memory is still in startup SPI STR mode. | Chip erase (CE) | '0x60' |
| NorFlashConfig.Startup.Cmd_RDSR | Used for WIP/WEL polling while the memory is in startup SPI STR mode. | Read status register (RDSR) | '0x05' |
| NorFlashConfig.Startup.Cmd_WE | Required before modify operations while the memory is in startup SPI STR mode. | Write enable (WREN) | '0x06' |
| MatchMask_WEL / MatchValue_WEL | Confirms write enable latch is set. | Status register description (WEL bit) | '0x02' / '0x02' |
| MatchMask_WIP / MatchValue_WIP | Poll until operation is complete. | Status register description (WIP bit) | '0x01' / '0x00' |
| NorFlashConfig.Startup.SRAccessDetails | Status-register access details for startup SPI STR mode. The standard 'RDSR' command does not need an extra register address in this example. | Read status register (RDSR) | 'EXTMEM_CUSTOM_SR_ACCESS_CFG_UNDEFINED' |
| MaxSectorEraseTime / MaxChipEraseTime | Choose conservative max values for timeout handling; adjust according to the datasheet worst-case. | Programming / erase timing characteristics (sector erase time, chip erase time) | '400 ms' / '300000 ms' |
| NorFlashConfig.OptionalConfigEnable | Enables the dedicated NOR Flash command set to be used after the protocol switch, so erase/status/write-enable operations use the octal DTR values below instead of the startup SPI STR values. | Configuration register 2 / protocol-switch procedure | '1' |
| NorFlashConfig.Optional.Cmd_EraseSector | Sector erase opcode used after 'OptionalConfig' switches the memory to octal DTR mode. | Sector erase (SE) / protocol-specific opcode table | '0x21DE' |
| NorFlashConfig.Optional.Cmd_MassErase | Chip erase opcode used after the protocol switch to octal DTR mode. | Chip erase (CE) / protocol-specific opcode table | '0x609F' |
| NorFlashConfig.Optional.Cmd_RDSR | Status-register read opcode used for WIP/WEL polling after the switch to octal DTR mode. | Read status register (RDSR) / protocol-specific opcode table | '0x05FA' |
| NorFlashConfig.Optional.Cmd_WE | Write-enable opcode used before program or erase operations once octal DTR mode is active. | Write enable (WREN) / protocol-specific opcode table | '0x06F9' |
| NorFlashConfig.Optional.SRAccessDetails | Status-register access details for octal DTR mode. This example uses register address '0x0' for status polling in the post-switch protocol. | Read status register (RDSR) / register access address format | 'EXTMEM_CUSTOM_SR_ACCESS_ADD_0' |
Final MX66UW1G45G[1] configuration example (stm32_mx66uw1g45g.h)
This section provides a complete example of what the final MX66UW1G45G[1] memory descriptor could look like.
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __STM32_MX66UW1G45G__H__
#define __STM32_MX66UW1G45G__H__
#ifdef __cplusplus
extern "C" {
#endif
/* Includes ------------------------------------------------------------------*/
#include "stm32_extmem.h"
#include "stm32_extmem_conf.h"
#if defined(EXTMEM_DRIVER_CUSTOM) && (EXTMEM_DRIVER_CUSTOM == 1)
#include "stm32_custom_driver_api.h"
#include "stm32_custom_driver_type.h"
/** @defgroup CUSTOM CUSTOM driver
* @ingroup EXTMEM_DRIVER
* @{
*/
/* Private Macro ------------------------------------------------------------*/
/** @defgroup CUSTOM_Private_Macro Private Macro
* @{
*/
#define EXTMEM_MX66UW1G45G_CMD_READ 0x0C /*!< Command to read data */
#define EXTMEM_MX66UW1G45G_CMD_WRITE 0x12 /*!< Command to write data */
#define EXTMEM_MX66UW1G45G_DUMMY_READ 0x08 /*!< Number of dummy cycles for read operations */
#define EXTMEM_MX66UW1G45G_DUMMY_WRITE 0x00 /*!< Number of dummy cycles for write operations */
#define EXTMEM_MX66UW1G45G_DUMMY_REG_READ 0 /*!< Number of dummy cycles to read register */
#define EXTMEM_MX66UW1G45G_PAGE_SIZE 256 /*!< Page size 256 Bytes */
#define EXTMEM_MX66UW1G45G_SECTOR_SIZE 0x1000 /*!< Sector size in bytes (4K) */
#define EXTMEM_MX66UW1G45G_CMD_ERASE_SECTOR 0x21 /*!< Command to erase a sector */
#define EXTMEM_MX66UW1G45G_CMD_MASS_ERASE 0x60 /*!< Command to perform mass erase */
#define EXTMEM_MX66UW1G45G_CMD_RDSR 0x05 /*!< Command to read status register */
#define EXTMEM_MX66UW1G45G_CMD_WE 0x06 /*!< Command to enable write operations */
#define EXTMEM_MX66UW1G45G_MASK_WEL 0x02 /*!< Mask for write enable latch */
#define EXTMEM_MX66UW1G45G_VALUE_WEL 0x02 /*!< Match Value for write enable latch */
#define EXTMEM_MX66UW1G45G_MASK_WIP 0x01 /*!< Mask for write in progress */
#define EXTMEM_MX66UW1G45G_VALUE_WIP 0x00 /*!< Match Value for write in progress */
#define EXTMEM_MX66UW1G45G_CMD1_WRITE_CFG2 0x72 /*!< Command to write to a register */
#define EXTMEM_MX66UW1G45G_CMD1_READ_CFG2 0x71 /*!< Command to read from a register */
#define EXTMEM_MX66UW1G45G_CMD1_READAW_CFG2 0x71 /*!< Command to read after write operation */
#define EXTMEM_MX66UW1G45G_CMD1_ADDR_CFG2 0x300 /*!< Address of the register */
#define EXTMEM_MX66UW1G45G_CMD1_VALUE_CFG2 0x00 /*!< Value of the register */
#define EXTMEM_MX66UW1G45G_CMD1_MASK_CFG2 0x07 /*!< Mask for the register */
#define EXTMEM_MX66UW1G45G_CMD2_WRITE_CFG2 0x72 /*!< Command to write to a register */
#define EXTMEM_MX66UW1G45G_CMD2_READ_CFG2 0x71 /*!< Command to read from a register */
#define EXTMEM_MX66UW1G45G_CMD2_ADDR_CFG2 0x00 /*!< Address of the register */
#define EXTMEM_MX66UW1G45G_CMD2_VALUE_CFG2 0x02 /*!< Value of the register */
#define EXTMEM_MX66UW1G45G_CMD2_MASK_CFG2 0x02 /*!< Mask for the register */
#define EXTMEM_MX66UW1G45G_CMD3_READAW_CFG2 0x718E /*!< Command to read after write operation */
#define EXTMEM_MX66UW1G45G_CMD3_ADDR_CFG2 0x00 /*!< Address of the register */
#define EXTMEM_MX66UW1G45G_OCTAL_CMD_ERASE_SECTOR 0x21DE /*!< Command to erase a sector */
#define EXTMEM_MX66UW1G45G_OCTAL_CMD_MASS_ERASE 0x609F /*!< Command to perform mass erase */
#define EXTMEM_MX66UW1G45G_OCTAL_CMD_READ 0xEE11 /*!< Command to read data */
#define EXTMEM_MX66UW1G45G_OCTAL_CMD_WRITE 0x12ED /*!< Command to write data */
#define EXTMEM_MX66UW1G45G_OCTAL_DUMMY_READ 20 /*!< Number of dummy cycles for read operations */
#define EXTMEM_MX66UW1G45G_OCTAL_DUMMY_WRITE 0 /*!< Number of dummy cycles for write operations */
#define EXTMEM_MX66UW1G45G_OCTAL_DUMMY_REG_READ 4 /*!< Dummy cycles to read register */
#define EXTMEM_MX66UW1G45G_OCTAL_CMD_RDSR 0x05FA /*!< Command to read status register in octal mode */
#define EXTMEM_MX66UW1G45G_OCTAL_CMD_WE 0x06F9 /*!< Command to enable write operations in octal mode */
#define EXTMEM_MX66UW1G45G_OCTAL_MASK_WEL 0x02 /*!< Mask for write enable latch */
#define EXTMEM_MX66UW1G45G_OCTAL_VALUE_WEL 0x02 /*!< Match Value for write enable latch */
#define EXTMEM_MX66UW1G45G_OCTAL_MASK_WIP 0x01 /*!< Mask for write in progress */
#define EXTMEM_MX66UW1G45G_OCTAL_VALUE_WIP 0x00 /*!< Match Value for write in progress */
/**
* @}
*/
/* Private typedefs ---------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/* Private functions ---------------------------------------------------------*/
/** @defgroup CUSTOM_Exported_Functions Exported Functions
* @{
*/
#define EXTMEM_MX66UW1G45G_INIT { \
.MemType = EXTMEM_CUSTOM_NOR_FLASH, /*!< Common field for memory type */ \
.MemStandard = EXTMEM_CUSTOM_STD_MACRONIX, /*!< e.g., Macronix, Micron, etc. */ \
.MemSize = EXTMEM_CUSTOM_SIZE_1GB, /*!< Common field for memory Size */ \
.ResetMethod = EXTMEM_CUSTOM_RESET_METHOD_6699_9966, /*!< Reset method based on 6699h and 9966h instructions */ \
.ResetDelay = 100, /*!< Time needed after Reset (in ms, 0 if no required delay */ \
.SampleShiftCfg = EXTMEM_CUSTOM_SSHIFT_CFG_NONE, /*!< Sample Shift setting */ \
.MemChipSelectHighTimeCycle = 8, /*!< Common field for memory Chip select high time */ \
.StartupConfig.Frequency = 50000000, /*!< Operating frequency in Hz*/ \
.StartupConfig.CommandRead = EXTMEM_MX66UW1G45G_CMD_READ, /*!< Command to read data */ \
.StartupConfig.CommandWrite = EXTMEM_MX66UW1G45G_CMD_WRITE, /*!< Command to write data */ \
.StartupConfig.DummyCycleRead = EXTMEM_MX66UW1G45G_DUMMY_READ, /*!< Number of dummy cycles for read operations */ \
.StartupConfig.DummyCycleWrite = EXTMEM_MX66UW1G45G_DUMMY_WRITE, /*!< Number of dummy cycles for write operations */ \
.StartupConfig.DummyRegisterRead = EXTMEM_MX66UW1G45G_DUMMY_REG_READ, /*!< Number of dummy cycles to read register */ \
.StartupConfig.AccessMode = EXTMEM_CUSTOM_1S_1S_1S, /*!< Access mode (e.g., 1S4D4D) */ \
.StartupConfig.InstructionSize = EXTMEM_CUSTOM_INSTRUCTION_8_BITS, /*!< Size of the instruction */ \
.StartupConfig.AddressSize = EXTMEM_CUSTOM_ADDRESS_32_BITS, /*!< Size of the address */ \
.StartupConfig.DqsMode = EXTMEM_CUSTOM_DQS_DISABLE, /*!< Data strobe mode */ \
.NbRegisterConfig = 4, /*!< Common field for memory Chip select */ \
.RegisterConfig[0].ConfigStepType = EXTMEM_CUSTOM_CFGSTEP_RWR_REG_ADDR, /*!< Config step to read/write/read a register */ \
.RegisterConfig[0].RWConfigStep.CommandRegisterWrite = EXTMEM_MX66UW1G45G_CMD1_WRITE_CFG2, /*!< Command to write to a register */ \
.RegisterConfig[0].RWConfigStep.CommandRegisterRead = EXTMEM_MX66UW1G45G_CMD1_READ_CFG2, /*!< Command to read from a register */ \
.RegisterConfig[0].RWConfigStep.CommandRegisterReadAW = EXTMEM_MX66UW1G45G_CMD1_READAW_CFG2, /*!< Command to read from a register after write operation */ \
.RegisterConfig[0].RWConfigStep.RegisterAddress = EXTMEM_MX66UW1G45G_CMD1_ADDR_CFG2, /*!< Address of the register */ \
.RegisterConfig[0].RWConfigStep.RegisterValue = EXTMEM_MX66UW1G45G_CMD1_VALUE_CFG2, /*!< Value of the register */ \
.RegisterConfig[0].RWConfigStep.RegisterMask = EXTMEM_MX66UW1G45G_CMD1_MASK_CFG2, /*!< Mask for the register */ \
.RegisterConfig[1].ConfigStepType = EXTMEM_CUSTOM_CFGSTEP_RW_REG_ADDR, /*!< Config step to read/write/read a register */ \
.RegisterConfig[1].RWConfigStep.CommandRegisterWrite = EXTMEM_MX66UW1G45G_CMD2_WRITE_CFG2, /*!< Command to write to a register */ \
.RegisterConfig[1].RWConfigStep.CommandRegisterRead = EXTMEM_MX66UW1G45G_CMD2_READ_CFG2, /*!< Command to read from a register */ \
.RegisterConfig[1].RWConfigStep.RegisterAddress = EXTMEM_MX66UW1G45G_CMD2_ADDR_CFG2, /*!< Address of the register */ \
.RegisterConfig[1].RWConfigStep.RegisterValue = EXTMEM_MX66UW1G45G_CMD2_VALUE_CFG2, /*!< Value of the register */ \
.RegisterConfig[1].RWConfigStep.RegisterMask = EXTMEM_MX66UW1G45G_CMD2_MASK_CFG2, /*!< Mask for the register */ \
.RegisterConfig[2].ConfigStepType = EXTMEM_CUSTOM_CFGSTEP_EXEC_OPT_CFG, /*!< Config step to use new Optional configuration */ \
.RegisterConfig[3].ConfigStepType = EXTMEM_CUSTOM_CFGSTEP_RAW_REG_ADDR, /*!< Config step to read/write/read a register */ \
.RegisterConfig[3].RWConfigStep.CommandRegisterReadAW = EXTMEM_MX66UW1G45G_CMD3_READAW_CFG2, /*!< Command to read from a register after write operation */ \
.RegisterConfig[3].RWConfigStep.RegisterAddress = EXTMEM_MX66UW1G45G_CMD3_ADDR_CFG2, /*!< Address of the register */ \
.OptionalConfig.Frequency = 200000000, /*!< Operating frequency in Hz*/ \
.OptionalConfig.CommandRead = EXTMEM_MX66UW1G45G_OCTAL_CMD_READ, /*!< Command to read data */ \
.OptionalConfig.CommandWrite = EXTMEM_MX66UW1G45G_OCTAL_CMD_WRITE, /*!< Command to write data */ \
.OptionalConfig.DummyCycleRead = EXTMEM_MX66UW1G45G_OCTAL_DUMMY_READ, /*!< Number of dummy cycles for read operations */ \
.OptionalConfig.DummyCycleWrite = EXTMEM_MX66UW1G45G_OCTAL_DUMMY_WRITE, /*!< Number of dummy cycles for write operations */ \
.OptionalConfig.DummyRegisterRead = EXTMEM_MX66UW1G45G_OCTAL_DUMMY_REG_READ,/*!< Number of dummy cycles to read register */ \
.OptionalConfig.AccessMode = EXTMEM_CUSTOM_8D_8D_8D, /*!< Access mode (e.g., 1S4D4D) */ \
.OptionalConfig.InstructionSize = EXTMEM_CUSTOM_INSTRUCTION_16_BITS, /*!< Size of the instruction */ \
.OptionalConfig.AddressSize = EXTMEM_CUSTOM_ADDRESS_32_BITS, /*!< Size of the address */ \
.OptionalConfig.DqsMode = EXTMEM_CUSTOM_DQS_ENABLE, /*!< Data strobe mode */ \
.NorFlashConfig.PageSize = EXTMEM_MX66UW1G45G_PAGE_SIZE, /*!< Page Size */ \
.NorFlashConfig.SectorSize = EXTMEM_MX66UW1G45G_SECTOR_SIZE, /*!< Sector Size */ \
.NorFlashConfig.MaxSectorEraseTime = 2000, /*!< Max time expected for completing a Sector Erase operation (in ms) */ \
.NorFlashConfig.MaxChipEraseTime = 300000, /*!< Max time expected for completing a Chip Erase operation (in ms) */ \
.NorFlashConfig.Startup.Cmd_EraseSector = EXTMEM_MX66UW1G45G_CMD_ERASE_SECTOR, /*!< Command to erase a sector */ \
.NorFlashConfig.Startup.Cmd_MassErase = EXTMEM_MX66UW1G45G_CMD_MASS_ERASE, /*!< Command to perform mass erase */ \
.NorFlashConfig.Startup.Cmd_RDSR = EXTMEM_MX66UW1G45G_CMD_RDSR, /*!< Command to read status register */ \
.NorFlashConfig.Startup.Cmd_WE = EXTMEM_MX66UW1G45G_CMD_WE, /*!< Command to enable write operations */ \
.NorFlashConfig.Startup.MatchMask_WEL = EXTMEM_MX66UW1G45G_MASK_WEL, /*!< Mask for write enable latch */ \
.NorFlashConfig.Startup.MatchValue_WEL = EXTMEM_MX66UW1G45G_VALUE_WEL, /*!< Match Value for write enable latch */ \
.NorFlashConfig.Startup.MatchMask_WIP = EXTMEM_MX66UW1G45G_MASK_WIP, /*!< Mask for write in progress */ \
.NorFlashConfig.Startup.MatchValue_WIP = EXTMEM_MX66UW1G45G_VALUE_WIP, /*!< Match Value for write in progress */ \
.NorFlashConfig.Startup.SRAccessDetails = EXTMEM_CUSTOM_SR_ACCESS_CFG_UNDEFINED, /*!< No details for SR register access (no address required) */ \
.NorFlashConfig.OptionalConfigEnable = 1, /*!< Optional config for NorFlash is used */ \
.NorFlashConfig.Optional.Cmd_EraseSector = EXTMEM_MX66UW1G45G_OCTAL_CMD_ERASE_SECTOR, /*!< Command to erase a sector */ \
.NorFlashConfig.Optional.Cmd_MassErase = EXTMEM_MX66UW1G45G_OCTAL_CMD_MASS_ERASE, /*!< Command to perform mass erase */ \
.NorFlashConfig.Optional.Cmd_RDSR = EXTMEM_MX66UW1G45G_OCTAL_CMD_RDSR, /*!< Command to read status register in octal mode */ \
.NorFlashConfig.Optional.Cmd_WE = EXTMEM_MX66UW1G45G_OCTAL_CMD_WE, /*!< Command to enable write operations in octal mode */ \
.NorFlashConfig.Optional.MatchMask_WEL = EXTMEM_MX66UW1G45G_OCTAL_MASK_WEL, /*!< Mask for write enable latch */ \
.NorFlashConfig.Optional.MatchValue_WEL = EXTMEM_MX66UW1G45G_OCTAL_VALUE_WEL, /*!< Match Value for write enable latch */ \
.NorFlashConfig.Optional.MatchMask_WIP = EXTMEM_MX66UW1G45G_OCTAL_MASK_WIP, /*!< Mask for write in progress */ \
.NorFlashConfig.Optional.MatchValue_WIP = EXTMEM_MX66UW1G45G_OCTAL_VALUE_WIP, /*!< Match Value for write enable latch */ \
.NorFlashConfig.Optional.SRAccessDetails = EXTMEM_CUSTOM_SR_ACCESS_ADD_0, /*!< Access details for SR register in octal mode*/ \
}
#if defined(EXTMEM_C)
EXTMEM_DRIVER_CUSTOM_ObjectTypeDef extmem_mx66uw1g45g = EXTMEM_MX66UW1G45G_INIT;
#else
extern EXTMEM_DRIVER_CUSTOM_ObjectTypeDef extmem_mx66uw1g45g;
#endif /* EXTMEM_C */
/**
* @}
*/
/**
* @}
*/
#endif /* EXTMEM_DRIVER_CUSTOM == 1 */
#ifdef __cplusplus
}
#endif
#endif /* __STM32_MX66UW1G45G__H__ */
This section explains how each parameter of 'EXTMEM_M95P32_INIT' (written by the user or taken from a provided configuration file) is chosen from the M95P32[2] datasheet.
For general guidance on what each field means and where it is used by the Custom driver, see:
General memory configuration
| Field | Description | Datasheet section | Value |
|---|---|---|---|
| MemType | Select the NOR Flash command set (erase/program/status polling). | Overview / features | 'EXTMEM_CUSTOM_NOR_FLASH' |
| MemStandard | Select the vendor enum used by the Custom driver for this descriptor. | Identification / manufacturer information | 'EXTMEM_CUSTOM_STD_MACRONIX' |
| MemSize | Select the density enum matching the device. | Memory organization / density | 'EXTMEM_CUSTOM_SIZE_32MB' |
| ResetMethod | Use the reset instruction sequence required by the device. | Reset / software reset instructions | 'EXTMEM_CUSTOM_RESET_METHOD_66_99' |
| ResetDelay | Delay after reset before sending new commands. | Reset recovery time characteristics | '2' ms |
| SampleShiftCfg | Keep default sample-shift behavior; tune if needed for the board. | Interface / timing recommendations | 'EXTMEM_CUSTOM_SSHIFT_CFG_UNDEFINED' |
| MemChipSelectHighTimeCycle | Ensure the chip-select high time between commands respects the datasheet minimum. | AC characteristics (chip-select deselect time) | '5' cycles |
Startup configuration (baseline SPI STR)
StartupConfig is typically a safe configuration that can be used for reset/bring-up and basic reads/writes.
| Field | Description | Datasheet section | Value |
|---|---|---|---|
| StartupConfig.Frequency | Choose a frequency within the device limits. | AC characteristics / timing limits | '50000000' Hz |
| StartupConfig.CommandRead | Use a standard STR read opcode. | Instruction set / command table (fast read) | '0x0B' |
| StartupConfig.DummyCycleRead | One dummy byte = 8 dummy clock cycles in STR mode. | Read command description (dummy cycles) | '0x08' |
| StartupConfig.CommandWrite | Use the page program opcode. | Instruction set / command table (program) | '0x0A' |
| StartupConfig.DummyCycleWrite | No dummy cycles for program. | Page program description | '0x00' |
| StartupConfig.DummyRegisterRead | Dummy cycles required when reading registers in this mode. | Register read access description | '0x00' |
| StartupConfig.AddressSize | 24-bit addressing. | Addressing / command description | 'EXTMEM_CUSTOM_ADDRESS_24_BITS' |
| StartupConfig.AccessMode | Instruction/address/data are transferred in single line STR. | Timing diagrams | 'EXTMEM_CUSTOM_1S_1S_1S' |
| StartupConfig.InstructionSize | Standard SPI opcode size. | Instruction set / command table | 'EXTMEM_CUSTOM_INSTRUCTION_8_BITS' |
| StartupConfig.DqsMode | DQS is not used in SPI STR. | Interface description (SPI STR) | 'EXTMEM_CUSTOM_DQS_DISABLE' |
Optional configuration (quad read)
The M95P32[2] example enables an optional configuration to use quad read for higher throughput.
| Field | Description | Datasheet section | Value |
|---|---|---|---|
| RegisterConfig[0].ConfigStepType | Activate the OptionalConfig after startup initialization. | Not from datasheet (driver configuration flow) | 'EXTMEM_CUSTOM_CFGSTEP_EXEC_OPT_CFG' |
| OptionalConfig.Frequency | Keep the same validated clock for this mode. | AC characteristics / timing limits | '50000000' Hz |
| OptionalConfig.CommandRead | Select the quad read opcode. | Instruction set / command table (quad read) | '0x6B' |
| OptionalConfig.CommandWrite | Keep writes in standard SPI. | Instruction set / command table (program) | '0x0A' |
| OptionalConfig.DummyCycleRead | Configure dummy cycles required by the read opcode. | Quad read command description (dummy cycles) | '0x08' |
| OptionalConfig.AccessMode | Quad data transfer for reads. | Timing diagrams | 'EXTMEM_CUSTOM_1S_1S_4S' |
| OptionalConfig.OptWriteAccessMode | Explicitly keep writes in single line mode. | Timing diagrams | 'EXTMEM_CUSTOM_1S_1S_1S' |
| OptionalConfig.InstructionSize | Standard SPI opcode size. | Instruction set / command table | 'EXTMEM_CUSTOM_INSTRUCTION_8_BITS' |
| OptionalConfig.AddressSize | 24-bit addressing. | Addressing / command description | 'EXTMEM_CUSTOM_ADDRESS_24_BITS' |
| OptionalConfig.DqsMode | DQS is not used for this mode. | Interface description | 'EXTMEM_CUSTOM_DQS_DISABLE' |
NOR Flash specific configuration
| Field | Description | Datasheet section | Value |
|---|---|---|---|
| NorFlashConfig.PageSize | Used by the driver to split writes. | Memory organization / program operation | '512' bytes |
| NorFlashConfig.SectorSize | Used by erase operations. | Memory organization / sector erase | '0x1000' (4 KBytes) |
| Cmd_EraseSector | Sector erase opcode. | Instruction set / command table (sector erase) | '0x20' |
| Cmd_MassErase | Chip erase opcode. | Instruction set / command table (chip erase) | '0xC7' |
| Cmd_RDSR | Used for WIP/WEL polling. | Instruction set / command table (read status register) | '0x05' |
| Cmd_WE | Required before modify operations. | Instruction set / command table (write enable) | '0x06' |
| MatchMask_WEL / MatchValue_WEL | Confirms write enable latch is set. | Status register description (WEL bit) | '0x02' / '0x02' |
| MatchMask_WIP / MatchValue_WIP | Poll until operation is complete. | Status register description (WIP bit) | '0x01' / '0x00' |
| MaxSectorEraseTime / MaxChipEraseTime | Choose conservative max values for timeout handling. | Erase timing characteristics | '2000 ms' / '100000 ms' |
Final M95P32[2] configuration example (stm32_m95p32.h)
This section provides a complete example of what the final M95P32[2] memory descriptor could look like.
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __STM32_M95P32__H__
#define __STM32_M95P32__H__
#ifdef __cplusplus
extern "C" {
#endif
/* Includes ------------------------------------------------------------------*/
#include "stm32_extmem.h"
#include "stm32_extmem_conf.h"
#if defined(EXTMEM_DRIVER_CUSTOM) && (EXTMEM_DRIVER_CUSTOM == 1)
#include "stm32_custom_driver_api.h"
#include "stm32_custom_driver_type.h"
/* Private Macro ------------------------------------------------------------*/
#define EXTMEM_M95P32_CMD_READ 0x0B
#define EXTMEM_M95P32_CMD_WRITE 0x0A
#define EXTMEM_M95P32_DUMMY_READ 0x08
#define EXTMEM_M95P32_DUMMY_WRITE 0x00
#define EXTMEM_M95P32_DUMMY_REG_READ 0x00
#define EXTMEM_M95P32_PAGE_SIZE 512
#define EXTMEM_M95P32_SECTOR_SIZE 0x1000
#define EXTMEM_M95P32_CMD_ERASE_SECTOR 0x20
#define EXTMEM_M95P32_CMD_MASS_ERASE 0xC7
#define EXTMEM_M95P32_CMD_RDSR 0x05
#define EXTMEM_M95P32_CMD_WE 0x06
#define EXTMEM_M95P32_MASK_WEL 0x02
#define EXTMEM_M95P32_VALUE_WEL 0x02
#define EXTMEM_M95P32_MASK_WIP 0x01
#define EXTMEM_M95P32_VALUE_WIP 0x00
#define EXTMEM_M95P32_QUAD_CMD_READ 0x6B
#define EXTMEM_M95P32_QUAD_DUMMY_READ 0x08
#define EXTMEM_M95P32_INIT { \
.MemType = EXTMEM_CUSTOM_NOR_FLASH, \
.MemStandard = EXTMEM_CUSTOM_STD_MACRONIX, \
.MemSize = EXTMEM_CUSTOM_SIZE_32MB, \
.ResetMethod = EXTMEM_CUSTOM_RESET_METHOD_66_99, \
.ResetDelay = 2, \
.MemChipSelectHighTimeCycle = 5, \
.StartupConfig.Frequency = 50000000, \
.StartupConfig.CommandRead = EXTMEM_M95P32_CMD_READ, \
.StartupConfig.CommandWrite = EXTMEM_M95P32_CMD_WRITE, \
.StartupConfig.DummyCycleRead = EXTMEM_M95P32_DUMMY_READ, \
.StartupConfig.DummyCycleWrite = EXTMEM_M95P32_DUMMY_WRITE, \
.StartupConfig.DummyRegisterRead = EXTMEM_M95P32_DUMMY_REG_READ, \
.StartupConfig.AccessMode = EXTMEM_CUSTOM_1S_1S_1S, \
.StartupConfig.InstructionSize = EXTMEM_CUSTOM_INSTRUCTION_8_BITS, \
.StartupConfig.AddressSize = EXTMEM_CUSTOM_ADDRESS_24_BITS, \
.StartupConfig.DqsMode = EXTMEM_CUSTOM_DQS_DISABLE, \
.NbRegisterConfig = 1, \
.RegisterConfig[0].ConfigStepType = EXTMEM_CUSTOM_CFGSTEP_EXEC_OPT_CFG, \
.OptionalConfig.Frequency = 50000000, \
.OptionalConfig.CommandRead = EXTMEM_M95P32_QUAD_CMD_READ, \
.OptionalConfig.CommandWrite = EXTMEM_M95P32_CMD_WRITE, \
.OptionalConfig.DummyCycleRead = EXTMEM_M95P32_QUAD_DUMMY_READ, \
.OptionalConfig.DummyCycleWrite = EXTMEM_M95P32_DUMMY_WRITE, \
.OptionalConfig.DummyRegisterRead = EXTMEM_M95P32_DUMMY_REG_READ, \
.OptionalConfig.AccessMode = EXTMEM_CUSTOM_1S_1S_4S, \
.OptionalConfig.OptWriteAccessMode = EXTMEM_CUSTOM_1S_1S_1S, \
.OptionalConfig.InstructionSize = EXTMEM_CUSTOM_INSTRUCTION_8_BITS, \
.OptionalConfig.AddressSize = EXTMEM_CUSTOM_ADDRESS_24_BITS, \
.OptionalConfig.DqsMode = EXTMEM_CUSTOM_DQS_DISABLE, \
.NorFlashConfig.PageSize = EXTMEM_M95P32_PAGE_SIZE, \
.NorFlashConfig.SectorSize = EXTMEM_M95P32_SECTOR_SIZE, \
.NorFlashConfig.MaxSectorEraseTime = 2000, \
.NorFlashConfig.MaxChipEraseTime = 100000, \
.NorFlashConfig.Startup.Cmd_EraseSector = EXTMEM_M95P32_CMD_ERASE_SECTOR, \
.NorFlashConfig.Startup.Cmd_MassErase = EXTMEM_M95P32_CMD_MASS_ERASE, \
.NorFlashConfig.Startup.Cmd_RDSR = EXTMEM_M95P32_CMD_RDSR, \
.NorFlashConfig.Startup.Cmd_WE = EXTMEM_M95P32_CMD_WE, \
.NorFlashConfig.Startup.MatchMask_WEL = EXTMEM_M95P32_MASK_WEL, \
.NorFlashConfig.Startup.MatchValue_WEL = EXTMEM_M95P32_VALUE_WEL, \
.NorFlashConfig.Startup.MatchMask_WIP = EXTMEM_M95P32_MASK_WIP, \
.NorFlashConfig.Startup.MatchValue_WIP = EXTMEM_M95P32_VALUE_WIP, \
}
#if defined(EXTMEM_C)
EXTMEM_DRIVER_CUSTOM_ObjectTypeDef extmem_m95p32 = EXTMEM_M95P32_INIT;
#else
extern EXTMEM_DRIVER_CUSTOM_ObjectTypeDef extmem_m95p32;
#endif /* EXTMEM_C */
#endif /* EXTMEM_DRIVER_CUSTOM == 1 */
#ifdef __cplusplus
}
#endif
#endif /* __STM32_M95P32__H__ */
5. How to create a BootFlash project with the STM32 ecosystem (H7R/H7S or N6)
5.1. STM32CubeMX Ecosystem Tool
STM32CubeMX is a graphical tool used to configure STM32 devices and generate initialization code. For BootFlash projects, it also generates the framework around:
- External Memory Manager (EMM)
- External Memory Loader (EML)
The recommended starting point to create a new EMM project remains the standard BootFlash workflow described in Getting started with External memory Manager and External memory loader.
The important points for the Custom driver are the following:
- The overall BootFlash project structure is the same.
- The calls to 'EXTMEM_Init()' are the same.
- The main manual adaptation is in 'MX_EXTMEM_MANAGER_Init()', where the memory description is provided differently.
In other words, switching from NOR SFDP to Custom driver does not change the BootFlash architecture. It only changes how EMM receives the memory configuration.
5.2. Implementation differences
For a NOR memory connected on XSPI, the differences are limited to the description of the memory entry inside 'extmem_list_config[]'.
With SFDP:
- Set MemType to 'EXTMEM_NOR_SFDP'.
- 'EXTMEM_DRIVER_NOR_SFDP' must be defined and set to 1 in "stm32_extmem_conf.h".
- Set ConfigType depending on the number of lines connected to the memory (ex: 'EXTMEM_LINK_CONFIG_8LINES' for 8 lines).
- In 'EXTMEM_Init', set XSPI clock speed using a RCC fetch function such as 'HAL_RCCEx_GetPeriphCLKFreq(RCC_PERIPHCLK_XSPI2)'.
- the driver reads the memory SFDP tables at runtime to discover commands, timings, and capabilities.
/*** In stm32_extmem_conf.h ***/
#define EXTMEM_DRIVER_NOR_SFDP 1
/*** In MX_EXTMEM_MANAGER_Init function ***/
/* EXTMEMORY_1: NOR discovered through SFDP */
extmem_list_config[EXTMEMORY_1].MemType = EXTMEM_NOR_SFDP;
extmem_list_config[EXTMEMORY_1].Handle = (void *)&hxspi2;
extmem_list_config[EXTMEMORY_1].ConfigType = EXTMEM_LINK_CONFIG_8LINES;
With the Custom driver:
- Set MemType to 'EXTMEM_CUSTOM'.
- 'EXTMEM_DRIVER_CUSTOM' must be defined and set to 1 in "stm32_extmem_conf.h".
- Set CustomObject using the one defined in the memory configuration file (ex: 'extmem_mx66uw1g45g' for the MX66UW1G45G memory).
- In 'EXTMEM_Init', set XSPI clock speed using a RCC fetch function such as 'HAL_RCCEx_GetPeriphCLKFreq(RCC_PERIPHCLK_XSPI2)'.
/*** In stm32_extmem_conf.h ***/
#define EXTMEM_DRIVER_CUSTOM 1
/*** In MX_EXTMEM_MANAGER_Init function ***/
/* EXTMEMORY_1: NOR described by a user-provided custom object */
extmem_list_config[EXTMEMORY_1].MemType = EXTMEM_CUSTOM;
extmem_list_config[EXTMEMORY_1].Handle = (void *)&hxspi2;
extmem_list_config[EXTMEMORY_1].CustomObject = extmem_mx66uw1g45g;
After that, the application still calls:
EXTMEM_Init(EXTMEMORY_1, HAL_RCCEx_GetPeriphCLKFreq(RCC_PERIPHCLK_XSPI2));
So the initialization entry point is unchanged. Only the configuration source is different.
5.3. Example of the migration
This example has been taken from the provided template Template_XIP_Custom. For a BootFlash project using MX66UW1G45G[1] on 'hxspi2', the user should read the code as follows:
- 'EXTMEM_DRIVER_NOR_SFDP' define must be set to 0 and 'EXTMEM_DRIVER_CUSTOM' must be defined and set to 1 in "stm32_extmem_conf.h".
- 'extmem_list_config[EXTMEMORY_1].Handle = (void *)&hxspi2;' identifies the hardware interface.
- 'extmem_list_config[EXTMEMORY_1].MemType = EXTMEM_CUSTOM;' selects the Custom driver path.
- 'extmem_list_config[EXTMEMORY_1].CustomObject = extmem_mx66uw1g45g;' passes the complete memory description written from the datasheet.
- 'EXTMEM_Init(...)' then initializes the memory using that object.
6. References
- ↑ 1.00 1.01 1.02 1.03 1.04 1.05 1.06 1.07 1.08 1.09 1.10 1.11 1.12 1.13 1.14 MX66UW1G45G Macromix page
- ↑ 2.0 2.1 2.2 2.3 2.4 2.5 2.6 2.7 2.8 M95P32 Datasheet
- ↑ Introduction to External Memory Manager and External Memory Loader Middleware for Boot Flash MCU
- ↑ 4.0 4.1 4.2 Introduction to External Memory Manager custom driver configuration
- ↑ MX66U1G45G Datasheet