From 3a95a4136a75f5b70ed7e1a068d916abf24c3305 Mon Sep 17 00:00:00 2001 From: Xukun Li Date: Sun, 18 Jan 2026 17:16:59 -0500 Subject: [PATCH 1/4] QSPI inital settings --- include/qspi_flash.h | 17 +++++++++++++++ stm32h7/mx25l25645g.c | 42 ++++++++++++++++++++++++++++++++++++++ stm32h7/mx25l25645g_defs.h | 25 +++++++++++++++++++++++ 3 files changed, 84 insertions(+) create mode 100644 include/qspi_flash.h create mode 100644 stm32h7/mx25l25645g.c create mode 100644 stm32h7/mx25l25645g_defs.h diff --git a/include/qspi_flash.h b/include/qspi_flash.h new file mode 100644 index 0000000..1f1564a --- /dev/null +++ b/include/qspi_flash.h @@ -0,0 +1,17 @@ +#ifndef ROCKETLIB_QSPI_FLASH.H +#define ROCKETLIB_QSPI_FLASH.H + +#include +#include + +#include "common.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* ROCKETLIB_QSPI_FLASH.H */ \ No newline at end of file diff --git a/stm32h7/mx25l25645g.c b/stm32h7/mx25l25645g.c new file mode 100644 index 0000000..7282042 --- /dev/null +++ b/stm32h7/mx25l25645g.c @@ -0,0 +1,42 @@ +#include "stm32h7xx_hal.h" + +// Normal SPI +const QSPI_CommandTypeDef command = { + .Instruction = 0x0; + .Address = 0x014; + .AlternateBytes = 0x0; + .AdressSize = 0x0; // 8-bits + .AlternateBytesSize = 0x0; + .DummyCycles = 0x8; + .InstructionMode = 0x1; // Mode for a single line + .AddressMode = 0x1; + .AlternateBytesMode = 0x1; + .DataMode = 0x1; + .NbData = 0x0; + .DdrMode = 0; // DDR disabled + .DdrHoldHalfCycle = 0x0; + .SIOOMode = 0x0; +} + +// Quad SPI +const QSPI_CommandTypeDef command = { + .Instruction = 0x0; + .Address = 0x014; + .AlternateBytes = 0x0; + .AdressSize = 0x0; // 8-bits + .AlternateBytesSize = 0x0; + .DummyCycles = 0x8; + .InstructionMode = 0x3; // Mode for four lines + .AddressMode = 0x3; + .AlternateBytesMode = 0x3; + .DataMode = 0x3; + .NbData = 0x0; + .DdrMode = 0x1; // DDR enabled + .DdrHoldHalfCycle = 0x0; + .SIOOMode = 0x0; +} + +// send to switch flash to qpsi mode +wstatus_t qspi_switch() { + HAL_StatusTypeDef HAL_QSPI_Command (QSPI_HandleTypeDef * hqspi, QSPI_CommandTypeDef * cmd, uint32_t Timeout) +} \ No newline at end of file diff --git a/stm32h7/mx25l25645g_defs.h b/stm32h7/mx25l25645g_defs.h new file mode 100644 index 0000000..a703f3f --- /dev/null +++ b/stm32h7/mx25l25645g_defs.h @@ -0,0 +1,25 @@ +#ifndef ROCKETLIB_MX25l25645G_DEFS_H +#define ROCKETLIB_MX25l25645G_DEFS_H + +#include +#include + +#include "common.h" + +typedef enum { + MX_CMD_READ = 0x03, + MX_CMD_FAST_READ = 0x0B, + MX_CMD_2READ = 0xBB, + MX_CMD_DREAD = 0x3B, + MX_CMD_4READ = 0xEB, + MX_CMD_QREAD = 0x6B, + MX_CMD_4DTRD = 0xED, + MX_CMD_PP = 0x02, + MX_CMD_4PP = 0x38, + MX_CMD_SE = 0x20, + MX_CMD_BE32K = 0x52, + MX_CMD_BE = 0xD8, + MX_CMD_CE = 0xC7 +} command_t; + +#endif /* ROCKETLIB_MX25l25645G_DEFS_H */ \ No newline at end of file From 03edb08db14055ccb6517148febda679d10cfbf9 Mon Sep 17 00:00:00 2001 From: Xukun Li Date: Sun, 1 Feb 2026 15:33:49 -0500 Subject: [PATCH 2/4] Switch controller to qspi --- include/littlefs_sd_shim.h | 6 +- include/mx25l25645g.h | 12 ++ include/qspi_flash.h | 2 +- stm32h7/mx25l25645g.c | 218 ++++++++++++++++++++++++++++++------- stm32h7/mx25l25645g_defs.h | 119 +++++++++++++++++--- 5 files changed, 301 insertions(+), 56 deletions(-) create mode 100644 include/mx25l25645g.h diff --git a/include/littlefs_sd_shim.h b/include/littlefs_sd_shim.h index 7706d03..8f0be3d 100644 --- a/include/littlefs_sd_shim.h +++ b/include/littlefs_sd_shim.h @@ -1,5 +1,5 @@ -#ifndef ROCKETLIB_LITTLEFS_SHIM_H -#define ROCKETLIB_LITTLEFS_SHIM_H +#ifndef ROCKETLIB_LITTLEFS_SD_SHIM_H +#define ROCKETLIB_LITTLEFS_SD_SHIM_H #include "lfs.h" #include "stm32h7xx_hal_sd.h" @@ -16,4 +16,4 @@ int lfsshim_sd_mount_mbr(lfs_t *lfs, SD_HandleTypeDef *hsd); } #endif -#endif // ROCKETLIB_LITTLEFS_SHIM_H +#endif // ROCKETLIB_LITTLEFS_SD_SHIM_H diff --git a/include/mx25l25645g.h b/include/mx25l25645g.h new file mode 100644 index 0000000..cb5592d --- /dev/null +++ b/include/mx25l25645g.h @@ -0,0 +1,12 @@ +#ifndef ROCKETLIB_MX25L225645G_H +#define ROCKETLIB_MX25L225645G_H + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef __cplusplus +} +#endif + +#endif // ROCKETLIB_MX25L225645G_H \ No newline at end of file diff --git a/include/qspi_flash.h b/include/qspi_flash.h index 1f1564a..641d46d 100644 --- a/include/qspi_flash.h +++ b/include/qspi_flash.h @@ -1,5 +1,5 @@ #ifndef ROCKETLIB_QSPI_FLASH.H -#define ROCKETLIB_QSPI_FLASH.H +#define ROCKETLIB_QSPI_FLASH .H #include #include diff --git a/stm32h7/mx25l25645g.c b/stm32h7/mx25l25645g.c index 7282042..2e63000 100644 --- a/stm32h7/mx25l25645g.c +++ b/stm32h7/mx25l25645g.c @@ -1,42 +1,182 @@ +#include "mx25l25645g_defs.h" #include "stm32h7xx_hal.h" -// Normal SPI -const QSPI_CommandTypeDef command = { - .Instruction = 0x0; - .Address = 0x014; - .AlternateBytes = 0x0; - .AdressSize = 0x0; // 8-bits - .AlternateBytesSize = 0x0; - .DummyCycles = 0x8; - .InstructionMode = 0x1; // Mode for a single line - .AddressMode = 0x1; - .AlternateBytesMode = 0x1; - .DataMode = 0x1; - .NbData = 0x0; - .DdrMode = 0; // DDR disabled - .DdrHoldHalfCycle = 0x0; - .SIOOMode = 0x0; -} - -// Quad SPI -const QSPI_CommandTypeDef command = { - .Instruction = 0x0; - .Address = 0x014; - .AlternateBytes = 0x0; - .AdressSize = 0x0; // 8-bits - .AlternateBytesSize = 0x0; - .DummyCycles = 0x8; - .InstructionMode = 0x3; // Mode for four lines - .AddressMode = 0x3; - .AlternateBytesMode = 0x3; - .DataMode = 0x3; - .NbData = 0x0; - .DdrMode = 0x1; // DDR enabled - .DdrHoldHalfCycle = 0x0; - .SIOOMode = 0x0; -} - -// send to switch flash to qpsi mode -wstatus_t qspi_switch() { - HAL_StatusTypeDef HAL_QSPI_Command (QSPI_HandleTypeDef * hqspi, QSPI_CommandTypeDef * cmd, uint32_t Timeout) +QSPI_HandleTypeDef hqspi; +static uint32_t Timeout = 100; + +static const QSPI_InitTypeDef qspi_init_cfg = { + .ClockPrescaler = 4, + .FifoThreshold = 4, + .SampleShifting = QSPI_SAMPLE_SHIFTING_NONE, + .FlashSize = 24, // MX25L25645G = 32MB + .ChipSelectHighTime = QSPI_CS_HIGH_TIME_2_CYCLE, + .ClockMode = QSPI_CLOCK_MODE_0, + .FlashID = QSPI_FLASH_ID_1, + .DualFlash = QSPI_DUALFLASH_DISABLE, +}; + +void MX_QUADSPI_Init(void) { + hqspi.Instance = QUADSPI; + hqspi.Init = qspi_init_cfg; + if (HAL_QSPI_Init(&hqspi) != HAL_OK) { + Error_Handler(); + } +} + +// Normal SPI command for flash +const QSPI_CommandTypeDef CMD_BASE = {.Instruction = 0x0; +.Address = 0x014; +.AlternateBytes = 0x0; +.AddressSize = QSPI_ADDRESS_8_BITS; +.AlternateBytesSize = QSPI_ALTERNATE_BYTES_8_BITS; +.DummyCycles = 0; +.InstructionMode = QSPI_INSTRUCTION_NONE; +.AddressMode = QSPI_ADDRESS_NONE; +.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; +.DataMode = QSPI_DATA_NONE; +.NbData = 0x0; +.DdrMode = QSPI_DDR_MODE_DISABLE; +.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; +.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; +} +; + +// Quad SPI command for flash +QSPI_CommandTypeDef QSPI_CMD_BASE = {.Instruction = 0x0; +.Address = 0x014; +.AlternateBytes = 0x0; +.AddressSize = QSPI_ADDRESS_8_BITS; +.AlternateBytesSize = + QSPI_ALTERNATE_BYTES_8_BITS; // may need to change to QSPI_ADDRESS_24_BITS or 32 +.DummyCycles = 0; // was 8 +.InstructionMode = QSPI_INSTRUCTION_1_LINE; +.AddressMode = QSPI_ADDRESS_NONE; +.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; +.DataMode = QSPI_DATA_NONE; +.NbData = 0; +.DdrMode = QSPI_DDR_MODE_DISABLE; +.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; +.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; +} +; + +static HAL_StatusTypeDef qspi_read_status(uint8_t *sr) { + QSPI_CommandTypeDef cmd = QSPI_CMD_BASE; + cmd.InstructionMode = QSPI_INSTRUCTION_1_LINE; + cmd.Instruction = MX_CMD_RDSR; + cmd.DataMode = QSPI_DATA_1_LINE; + cmd.NbData = 1; + + if (HAL_QSPI_Command(&hqspi, &cmd, Timeout) != HAL_OK) { + return HAL_ERROR; + } + return HAL_QSPI_Receive(&hqspi, sr, Timeout); +} + +static HAL_StatusTypeDef qspi_read_config(uint8_t *cr) { + QSPI_CommandTypeDef cmd = QSPI_CMD_BASE; + cmd.InstructionMode = QSPI_INSTRUCTION_1_LINE; + cmd.Instruction = MX_CMD_RDCR; + cmd.DataMode = QSPI_DATA_1_LINE; + cmd.NbData = 1; + + if (HAL_QSPI_Command(&hqspi, &cmd, Timeout) != HAL_OK) { + return HAL_ERROR; + } + return HAL_QSPI_Receive(&hqspi, cr, Timeout); +} + +static HAL_StatusTypeDef qspi_write_enable(void) { + QSPI_CommandTypeDef cmd = QSPI_CMD_BASE; + cmd.InstructionMode = QSPI_INSTRUCTION_1_LINE; + cmd.Instruction = MX_CMD_WREN; + cmd.DataMode = QSPI_DATA_1_LINE; + cmd.NbData = 0; + + return HAL_QSPI_Command(&hqspi, &cmd, Timeout); +} + +static HAL_StatusTypeDef qspi_mx25l_wait_wip0(void) { + // Command: Read Status Register (RDSR) + QSPI_CommandTypeDef cmd = {0}; + cmd.InstructionMode = QSPI_INSTRUCTION_1_LINE; + cmd.Instruction = MX_CMD_RDSR; + cmd.AddressMode = QSPI_ADDRESS_NONE; + cmd.DataMode = QSPI_DATA_1_LINE; + cmd.NbData = 1; + cmd.DummyCycles = 0; + cmd.DdrMode = QSPI_DDR_MODE_DISABLE; + cmd.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; + + // Polling config: wait until WIP=0 + QSPI_AutoPollingTypeDef cfg = {0}; + cfg.Match = 0x00; // WIP must become 0 + cfg.Mask = 0x01; // Check only bit0 + cfg.MatchMode = QSPI_MATCH_MODE_AND; + cfg.StatusBytesSize = 1; + cfg.Interval = 0x10; + cfg.AutomaticStop = QSPI_AUTOMATIC_STOP_ENABLE; + + return HAL_QSPI_AutoPolling(&hqspi, &cmd, &cfg, Timeout); +} + +// Enable QSPI mode on the MCU +HAL_StatusTypeDef mx25l_enable_qe(void) { + // Initialize status register and config register + uint8_t sr = 0, cr = 0; + + if (qspi_read_status(&sr) != HAL_OK) { + return HAL_ERROR; + } + if (qspi_read_config(&cr) != HAL_OK) { + return HAL_ERROR; + } + + sr |= (1u << 6); // QE = bit 6 + uint8_t status_config_bytes[2] = {sr, cr}; + + if (qspi_write_enable() != HAL_OK) { + return HAL_ERROR; + } + + QSPI_CommandTypeDef cmd = QSPI_CMD_BASE; + cmd.InstructionMode = QSPI_INSTRUCTION_1_LINE; + cmd.Instruction = MX_CMD_WRSR; + cmd.DataMode = QSPI_DATA_1_LINE; + cmd.NbData = 2; + + if (HAL_QSPI_Command(&hqspi, &cmd, Timeout) != HAL_OK) { + return HAL_ERROR; + } + if (HAL_QSPI_Transmit(&hqspi, status_config_bytes, Timeout) != HAL_OK) { + return HAL_ERROR; + } + + // Wait for the write to finish (WIP = 0) + if (qspi_mx25l_wait_wip0() != HAL_OK) { + return HAL_ERROR; + } + + // Verify QE really latched + if (qspi_read_status(&sr) != HAL_OK) { + return HAL_ERROR; + } + return (sr & (1u << 6)) ? HAL_OK : HAL_ERROR; +} + +int main(void) { + // Change flash to qspi + + HAL_Init(); + SystemClock_Config(); + + // Initialize the QSPI MSP + MX_GPIO_Init(); + // Initialize the QSPI mode according to the parameters in the QSPI_InitTypeDef + MX_QUADSPI_Init(); + + // Enable quad mode + mx25l_enable_qe(); + + while (1) {} } \ No newline at end of file diff --git a/stm32h7/mx25l25645g_defs.h b/stm32h7/mx25l25645g_defs.h index a703f3f..8e096b2 100644 --- a/stm32h7/mx25l25645g_defs.h +++ b/stm32h7/mx25l25645g_defs.h @@ -7,19 +7,112 @@ #include "common.h" typedef enum { - MX_CMD_READ = 0x03, - MX_CMD_FAST_READ = 0x0B, - MX_CMD_2READ = 0xBB, - MX_CMD_DREAD = 0x3B, - MX_CMD_4READ = 0xEB, - MX_CMD_QREAD = 0x6B, - MX_CMD_4DTRD = 0xED, - MX_CMD_PP = 0x02, - MX_CMD_4PP = 0x38, - MX_CMD_SE = 0x20, - MX_CMD_BE32K = 0x52, - MX_CMD_BE = 0xD8, - MX_CMD_CE = 0xC7 + + // ============================================================ + // Read/Write Array Commands (3-Byte Address) + // ============================================================ + + MX_CMD_READ = 0x03, // Normal Read + MX_CMD_FAST_READ = 0x0B, // Fast Read (requires dummy cycles) + + MX_CMD_DREAD = 0x3B, // Dual Output Fast Read + MX_CMD_2READ = 0xBB, // Dual I/O Fast Read + + MX_CMD_QREAD = 0x6B, // Quad Output Fast Read + MX_CMD_4READ = 0xEB, // Quad I/O Fast Read + + MX_CMD_4DTRD = 0xED, // Quad I/O DDR Read (DTR) + + MX_CMD_PP = 0x02, // Page Program + MX_CMD_4PP = 0x38, // Quad Page Program + + MX_CMD_SE = 0x20, // Sector Erase (4KB) + MX_CMD_BE32K = 0x52, // Block Erase (32KB) + MX_CMD_BE = 0xD8, // Block Erase (64KB) + + MX_CMD_CE = 0xC7, // Chip Erase (also possible: 0x60) + + // ============================================================ + // Read/Write Array Commands (4-Byte Address Command Set) + // ============================================================ + + MX_CMD_READ4B = 0x13, // Normal Read (4-byte address) + MX_CMD_FAST_READ4B = 0x0C, // Fast Read (4-byte address) + + MX_CMD_DREAD4B = 0x3C, // Dual Output Fast Read (4B) + MX_CMD_2READ4B = 0xBC, // Dual I/O Fast Read (4B) + + MX_CMD_QREAD4B = 0x6C, // Quad Output Fast Read (4B) + MX_CMD_4READ4B = 0xEC, // Quad I/O Fast Read (4B) + + MX_CMD_4DTRD4B = 0xEE, // Quad I/O DDR Read (4B) + + MX_CMD_PP4B = 0x12, // Page Program (4B) + MX_CMD_4PP4B = 0x3E, // Quad Page Program (4B) + + MX_CMD_SE4B = 0x21, // Sector Erase (4KB, 4B) + MX_CMD_BE32K4B = 0x5C, // Block Erase (32KB, 4B) + MX_CMD_BE4B = 0xDC, // Block Erase (64KB, 4B) + + // ============================================================ + // Register / Setting Commands + // ============================================================ + + MX_CMD_WREN = 0x06, // Write Enable + MX_CMD_WRDI = 0x04, // Write Disable + + MX_CMD_RDSR = 0x05, // Read Status Register + MX_CMD_WRSR = 0x01, // Write Status + Configuration Register + + MX_CMD_RDCR = 0x15, // Read Configuration Register + + MX_CMD_RDEAR = 0xC8, // Read Extended Address Register + MX_CMD_WREAR = 0xC5, // Write Extended Address Register + + MX_CMD_WPSEL = 0x68, // Write Protection Selection + + MX_CMD_EQIO = 0x35, // Enable QPI Mode + MX_CMD_RSTQIO = 0xF5, // Reset / Exit QPI Mode + + MX_CMD_EN4B = 0xB7, // Enter 4-byte Address Mode + MX_CMD_EX4B = 0xE9, // Exit 4-byte Address Mode + + MX_CMD_PGM_ERS_SUSPEND = 0xB0, // Program/Erase Suspend + MX_CMD_PGM_ERS_RESUME = 0x30, // Program/Erase Resume + + MX_CMD_DP = 0xB9, // Deep Power Down + MX_CMD_RDP = 0xAB, // Release from Deep Power Down + + MX_CMD_SBL = 0xC0, // Set Burst Length + + // ============================================================ + // ID / Security Commands + // ============================================================ + + MX_CMD_RDID = 0x9F, // Read JEDEC ID + + MX_CMD_RES = 0xAB, // Read Electronic ID (Legacy) + + MX_CMD_REMS = 0x90, // Read Manufacturer / Device ID + + MX_CMD_ENSO = 0xB1, // Enter Secured OTP Mode + MX_CMD_EXSO = 0xC1, // Exit Secured OTP Mode + + MX_CMD_RDSCUR = 0x2B, // Read Security Register + MX_CMD_WRSCUR = 0x2F, // Write Security Register + + MX_CMD_RDDPB = 0xE0, // Read DPB (Dynamic Protection Bits) + MX_CMD_WRDPB = 0xE1, // Write DPB + + MX_CMD_RDECC = 0x18, // Read ECC Status + + // ============================================================ + // Reset Commands + // ============================================================ + + MX_CMD_RSTEN = 0x66, // Reset Enable + MX_CMD_RST = 0x99, // Reset Memory Device + } command_t; #endif /* ROCKETLIB_MX25l25645G_DEFS_H */ \ No newline at end of file From 17b8ff9dee33ca54fd26853c4796483f81b498ac Mon Sep 17 00:00:00 2001 From: Xukun Li Date: Sun, 8 Feb 2026 12:47:17 -0500 Subject: [PATCH 3/4] Switch both MCU and flash to QSPI mode --- stm32h7/mx25l25645g.c | 165 +++++++++++++++--------------------------- 1 file changed, 58 insertions(+), 107 deletions(-) diff --git a/stm32h7/mx25l25645g.c b/stm32h7/mx25l25645g.c index 2e63000..a4e8376 100644 --- a/stm32h7/mx25l25645g.c +++ b/stm32h7/mx25l25645g.c @@ -25,31 +25,30 @@ void MX_QUADSPI_Init(void) { // Normal SPI command for flash const QSPI_CommandTypeDef CMD_BASE = {.Instruction = 0x0; -.Address = 0x014; -.AlternateBytes = 0x0; -.AddressSize = QSPI_ADDRESS_8_BITS; -.AlternateBytesSize = QSPI_ALTERNATE_BYTES_8_BITS; +// .Address = 0x014; +// .AlternateBytes = 0x0; +// .AlternateBytesSize = QSPI_ALTERNATE_BYTES_8_BITS; .DummyCycles = 0; -.InstructionMode = QSPI_INSTRUCTION_NONE; +.InstructionMode = QSPI_INSTRUCTION_1_LINE; .AddressMode = QSPI_ADDRESS_NONE; .AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; .DataMode = QSPI_DATA_NONE; -.NbData = 0x0; +// .NbData = 0x0; .DdrMode = QSPI_DDR_MODE_DISABLE; -.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; +// .DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; .SIOOMode = QSPI_SIOO_INST_EVERY_CMD; } ; // Quad SPI command for flash -QSPI_CommandTypeDef QSPI_CMD_BASE = {.Instruction = 0x0; -.Address = 0x014; -.AlternateBytes = 0x0; -.AddressSize = QSPI_ADDRESS_8_BITS; +QSPI_CommandTypeDef CMD_BASE_QSPI = {.Instruction = 0x0; +// .Address = 0x014; +// .AlternateBytes = 0x0; +// .AddressSize = QSPI_ADDRESS_8_BITS; .AlternateBytesSize = QSPI_ALTERNATE_BYTES_8_BITS; // may need to change to QSPI_ADDRESS_24_BITS or 32 .DummyCycles = 0; // was 8 -.InstructionMode = QSPI_INSTRUCTION_1_LINE; +.InstructionMode = QSPI_INSTRUCTION_4_LINES; .AddressMode = QSPI_ADDRESS_NONE; .AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; .DataMode = QSPI_DATA_NONE; @@ -60,123 +59,75 @@ QSPI_CommandTypeDef QSPI_CMD_BASE = {.Instruction = 0x0; } ; -static HAL_StatusTypeDef qspi_read_status(uint8_t *sr) { - QSPI_CommandTypeDef cmd = QSPI_CMD_BASE; - cmd.InstructionMode = QSPI_INSTRUCTION_1_LINE; - cmd.Instruction = MX_CMD_RDSR; - cmd.DataMode = QSPI_DATA_1_LINE; - cmd.NbData = 1; - - if (HAL_QSPI_Command(&hqspi, &cmd, Timeout) != HAL_OK) { - return HAL_ERROR; - } - return HAL_QSPI_Receive(&hqspi, sr, Timeout); -} - -static HAL_StatusTypeDef qspi_read_config(uint8_t *cr) { - QSPI_CommandTypeDef cmd = QSPI_CMD_BASE; - cmd.InstructionMode = QSPI_INSTRUCTION_1_LINE; - cmd.Instruction = MX_CMD_RDCR; - cmd.DataMode = QSPI_DATA_1_LINE; - cmd.NbData = 1; - - if (HAL_QSPI_Command(&hqspi, &cmd, Timeout) != HAL_OK) { - return HAL_ERROR; - } - return HAL_QSPI_Receive(&hqspi, cr, Timeout); +static HAL_StatusTypeDef mx25l_exit_qpi(void) +{ + QSPI_CommandTypeDef cmd = CMD_BASE_QSPI; + cmd.Instruction = MX_CMD_RSTQIO; // 0xF5 + cmd.DataMode = QSPI_DATA_NONE; + cmd.NbData = 0; + return HAL_QSPI_Command(&hqspi, &cmd, Timeout); } -static HAL_StatusTypeDef qspi_write_enable(void) { - QSPI_CommandTypeDef cmd = QSPI_CMD_BASE; - cmd.InstructionMode = QSPI_INSTRUCTION_1_LINE; - cmd.Instruction = MX_CMD_WREN; - cmd.DataMode = QSPI_DATA_1_LINE; +// Enable QSPI mode on the flash +HAL_StatusTypeDef mx25l_enter_qpi(void) { + QSPI_CommandTypeDef cmd = CMD_BASE; + cmd.Instruction = MX_CMD_EQIO; + cmd.DataMode = QSPI_DATA_NONE; cmd.NbData = 0; - return HAL_QSPI_Command(&hqspi, &cmd, Timeout); } -static HAL_StatusTypeDef qspi_mx25l_wait_wip0(void) { - // Command: Read Status Register (RDSR) - QSPI_CommandTypeDef cmd = {0}; - cmd.InstructionMode = QSPI_INSTRUCTION_1_LINE; - cmd.Instruction = MX_CMD_RDSR; - cmd.AddressMode = QSPI_ADDRESS_NONE; - cmd.DataMode = QSPI_DATA_1_LINE; - cmd.NbData = 1; - cmd.DummyCycles = 0; - cmd.DdrMode = QSPI_DDR_MODE_DISABLE; - cmd.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; - - // Polling config: wait until WIP=0 - QSPI_AutoPollingTypeDef cfg = {0}; - cfg.Match = 0x00; // WIP must become 0 - cfg.Mask = 0x01; // Check only bit0 - cfg.MatchMode = QSPI_MATCH_MODE_AND; - cfg.StatusBytesSize = 1; - cfg.Interval = 0x10; - cfg.AutomaticStop = QSPI_AUTOMATIC_STOP_ENABLE; - - return HAL_QSPI_AutoPolling(&hqspi, &cmd, &cfg, Timeout); -} - -// Enable QSPI mode on the MCU -HAL_StatusTypeDef mx25l_enable_qe(void) { - // Initialize status register and config register - uint8_t sr = 0, cr = 0; +// static HAL_StatusTypeDef qspi_write_enable(void) { +// QSPI_CommandTypeDef cmd = CMD_BASE_QSPI; +// cmd.Instruction = MX_CMD_WREN; +// cmd.DataMode = QSPI_DATA_NONE; +// cmd.NbData = 0; - if (qspi_read_status(&sr) != HAL_OK) { - return HAL_ERROR; - } - if (qspi_read_config(&cr) != HAL_OK) { - return HAL_ERROR; - } +// return HAL_QSPI_Command(&hqspi, &cmd, Timeout); +// } - sr |= (1u << 6); // QE = bit 6 - uint8_t status_config_bytes[2] = {sr, cr}; +// static HAL_StatusTypeDef qspi_mx25l_wait_wip0(void) { +// // Command: Read Status Register (RDSR) +// QSPI_CommandTypeDef cmd = {0}; +// cmd.InstructionMode = QSPI_INSTRUCTION_1_LINE; +// cmd.Instruction = MX_CMD_RDSR; +// cmd.AddressMode = QSPI_ADDRESS_NONE; +// cmd.DataMode = QSPI_DATA_1_LINE; +// cmd.NbData = 1; +// cmd.DummyCycles = 0; +// cmd.DdrMode = QSPI_DDR_MODE_DISABLE; +// cmd.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; - if (qspi_write_enable() != HAL_OK) { - return HAL_ERROR; - } +// // Polling config: wait until WIP=0 +// QSPI_AutoPollingTypeDef cfg = {0}; +// cfg.Match = 0x00; // WIP must become 0 +// cfg.Mask = 0x01; // Check only bit0 +// cfg.MatchMode = QSPI_MATCH_MODE_AND; +// cfg.StatusBytesSize = 1; +// cfg.Interval = 0x10; +// cfg.AutomaticStop = QSPI_AUTOMATIC_STOP_ENABLE; - QSPI_CommandTypeDef cmd = QSPI_CMD_BASE; - cmd.InstructionMode = QSPI_INSTRUCTION_1_LINE; - cmd.Instruction = MX_CMD_WRSR; - cmd.DataMode = QSPI_DATA_1_LINE; - cmd.NbData = 2; +// return HAL_QSPI_AutoPolling(&hqspi, &cmd, &cfg, Timeout); +// } - if (HAL_QSPI_Command(&hqspi, &cmd, Timeout) != HAL_OK) { - return HAL_ERROR; - } - if (HAL_QSPI_Transmit(&hqspi, status_config_bytes, Timeout) != HAL_OK) { - return HAL_ERROR; - } - // Wait for the write to finish (WIP = 0) - if (qspi_mx25l_wait_wip0() != HAL_OK) { - return HAL_ERROR; - } - // Verify QE really latched - if (qspi_read_status(&sr) != HAL_OK) { - return HAL_ERROR; - } - return (sr & (1u << 6)) ? HAL_OK : HAL_ERROR; -} int main(void) { - // Change flash to qspi - HAL_Init(); SystemClock_Config(); // Initialize the QSPI MSP MX_GPIO_Init(); - // Initialize the QSPI mode according to the parameters in the QSPI_InitTypeDef + + // Initialize the QSPI mode with 1 instruction line, CMD_BASE MX_QUADSPI_Init(); - // Enable quad mode - mx25l_enable_qe(); + // Enable QPI mode on flash + mx25l_enter_qpi(); + + // From now on instruction becomes 4 lines since qspi is enabled, QSPI_CMD_BASE + while (1) {} } \ No newline at end of file From 01e5aca5869733b8d9007c5c1094464f169285d2 Mon Sep 17 00:00:00 2001 From: Xukun Li Date: Sun, 8 Feb 2026 12:48:06 -0500 Subject: [PATCH 4/4] Switch both MCU and flash to QSPI mode --- stm32h7/mx25l25645g.c | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/stm32h7/mx25l25645g.c b/stm32h7/mx25l25645g.c index a4e8376..ad3e8b4 100644 --- a/stm32h7/mx25l25645g.c +++ b/stm32h7/mx25l25645g.c @@ -59,13 +59,12 @@ QSPI_CommandTypeDef CMD_BASE_QSPI = {.Instruction = 0x0; } ; -static HAL_StatusTypeDef mx25l_exit_qpi(void) -{ - QSPI_CommandTypeDef cmd = CMD_BASE_QSPI; - cmd.Instruction = MX_CMD_RSTQIO; // 0xF5 - cmd.DataMode = QSPI_DATA_NONE; - cmd.NbData = 0; - return HAL_QSPI_Command(&hqspi, &cmd, Timeout); +static HAL_StatusTypeDef mx25l_exit_qpi(void) { + QSPI_CommandTypeDef cmd = CMD_BASE_QSPI; + cmd.Instruction = MX_CMD_RSTQIO; // 0xF5 + cmd.DataMode = QSPI_DATA_NONE; + cmd.NbData = 0; + return HAL_QSPI_Command(&hqspi, &cmd, Timeout); } // Enable QSPI mode on the flash @@ -92,7 +91,7 @@ HAL_StatusTypeDef mx25l_enter_qpi(void) { // cmd.InstructionMode = QSPI_INSTRUCTION_1_LINE; // cmd.Instruction = MX_CMD_RDSR; // cmd.AddressMode = QSPI_ADDRESS_NONE; -// cmd.DataMode = QSPI_DATA_1_LINE; +// cmd.DataMode = QSPI_DATA_1_LINE; // cmd.NbData = 1; // cmd.DummyCycles = 0; // cmd.DdrMode = QSPI_DDR_MODE_DISABLE; @@ -110,9 +109,6 @@ HAL_StatusTypeDef mx25l_enter_qpi(void) { // return HAL_QSPI_AutoPolling(&hqspi, &cmd, &cfg, Timeout); // } - - - int main(void) { HAL_Init(); SystemClock_Config(); @@ -128,6 +124,5 @@ int main(void) { // From now on instruction becomes 4 lines since qspi is enabled, QSPI_CMD_BASE - while (1) {} } \ No newline at end of file