CubeMX STM32H7 OctoSPI
·
CubeMX STM32H7 OctoSPI Quad SPI Flash

QSPI NOR Flash结构
1 OctoSPI
1.1 SPI(Serial Peripheral Interface)
基本特性:
- 数据线数量: 1 条数据线(MOSI/MISO,半双工或全双工)
- 通信模式: 主从模式,支持多从机
- 时钟频率: 通常几 MHz 到几十 MHz
- 典型应用: 传感器、EEPROM、ADC/DAC 等低速外设
优点: 接口简单,引脚少,成本低
缺点: 带宽有限,不适合大数据量传输
1.2 DualSPI
基本特性:
- 数据线数量: 2 条数据线(IO0、IO1)
- 工作模式: 两条数据线同时传输数据
- 理论带宽: 相比 SPI 翻倍
- 典型应用: NOR Flash、串行存储器
特点: 在 SPI 基础上增加了一条数据线,提高了传输速率
1.3 QSPI(Quad SPI)
基本特性:
- 数据线数量: 4 条数据线(IO0、IO1、IO2、IO3)
- 工作模式: 四条数据线同时传输数据
- 理论带宽: 相比 SPI 提高 4 倍
- 典型应用: 大容量 NOR/NAND Flash、执行代码(XIP)
特点:
- 支持 Execute-in-Place(XIP)模式,可直接从 Flash 执行代码
- 常用于需要较高带宽的存储应用
1.4 OSPI(Octo SPI / Octal SPI)
基本特性:
- 数据线数量: 8 条数据线
- 工作模式: 八条数据线同时传输数据
- 理论带宽: 相比 SPI 提高 8 倍
- 时钟模式: 支持 SDR(单倍数据率)和 DDR(双倍数据率)
- 典型应用: 高性能存储、AI 加速器、图形显示缓冲
STM32H7 OctoSPI 特点:
- 支持 8 线模式(Octal)和 4 线模式(Quad)
- 最高时钟频率可达 133MHz(SDR)或 266MHz(DDR)
- 支持内存映射模式,外部 Flash 可映射到 CPU 地址空间
- 支持双 Flash 模式,可同时连接两个 Flash 器件
1.5 对比总结
| 特性 | SPI | DualSPI | QSPI | OSPI |
|---|---|---|---|---|
| 数据线 | 1 线 | 2 线 | 4 线 | 8 线 |
| 理论带宽 | 1× | 2× | 4× | 8× |
| 引脚需求 | 少 | 中等 | 较多 | 多 |
| 成本 | 低 | 较低 | 中等 | 高 |
| 适用场景 | 低速外设 | 中等速率存储 | 高速存储/XIP | 超高速存储/图形 |
| STM32 支持 | 全系列 | H7/F7 等 | H7/F7 等 | H7 系列 |
1.6 选择建议
- SPI: 适合传感器、配置芯片等低速通信
- DualSPI: 适合中等数据量的串行存储器
- QSPI: 适合需要从 Flash 直接执行代码的应用
- OSPI: 适合图形显示、AI 推理、高速数据采集等高性能场景
对于 STM32H7 项目,如果使用大容量 Flash 存储程序或数据,QSPI/OSPI 是更好的选择,特别是需要 XIP 功能时。
2 CubeMX STM32H7 OctoSPI配置QSPI
2.1 CubeMX OctoSPI模式配置

2.2 CubeMX OctoSPI参数配置

2.3 MPU配置

必须添加内存管理单元的0X90000000,否则无法使用内存映射(XIP)模式
3 XT25F128 NOR Flash
3.1 头文件
/**
******************************************************************************
* @file XT25F128F.h
* @brief XT25F128F Quad SPI Flash Driver Header File
* Based on STM32H723 OctoSPI Peripheral
* XT25F128F-W: 128Mbit (16MB) Quad I/O Serial Flash
******************************************************************************
* @attention
*
* - Flash Size: 128Mbit = 16MByte
* - Sector Size: 64KB (Block), 4KB (Subsector)
* - Page Size: 256 Bytes
* - Quad I/O Fast Read (EBH): up to 133MHz
* - Quad Page Program (32H): up to 133MHz
*
******************************************************************************
*/
#ifndef __XT25F128F_H
#define __XT25F128F_H
#ifdef __cplusplus
extern "C" {
#endif
#include "stm32h7xx_hal.h"
/* ========================================================================== */
/* XT25F128F Device Configuration */
/* ========================================================================== */
/** @defgroup XT25F128F_Size Flash Size Definitions
* @{
*/
#define XT25F_FLASH_SIZE 0x1000000U /* 128 MBits => 16MBytes */
#define XT25F_SECTOR_SIZE 0x10000U /* 256 sectors of 64KBytes */
#define XT25F_SUBSECTOR_SIZE 0x1000U /* 4096 subsectors of 4kBytes */
#define XT25F_PAGE_SIZE 0x100U /* 65536 pages of 256 bytes */
#define XT25F_DUMMY_CYCLES_READ_QUAD 6U /* Default dummy cycles for Quad I/O Read (DC0=0) */
#define XT25F_DUMMY_CYCLES_READ_QUAD_DC1 10U /* Dummy cycles when DC0=1 */
#define XT25F_AUTOPOLLING_INTERVAL_TIME 0x10U /* Auto-polling interval */
#define XT25F_MEMORY_BASE_ADDR 0x90000000U
/**
* @}
*/
/* ========================================================================== */
/* XT25F128F Command Definitions */
/* ========================================================================== */
/** @defgroup XT25F128F_Commands Flash Command Definitions
* @{
*/
/* Write Enable / Disable Commands */
#define XT25F_WRITE_ENABLE_CMD 0x06U /* Set Write Enable Latch */
#define XT25F_WRITE_DISABLE_CMD 0x04U /* Reset Write Enable Latch */
#define XT25F_ENABLE_VOLATILE_SR_CMD 0x50U /* Enable Volatile Status Register */
/* ID Commands */
#define XT25F_READ_JEDEC_ID_CMD 0x9FU /* Read JEDEC ID (3 bytes) */
#define XT25F_FULLID_CMD 0x90U /* Read Manufacturer & Device ID */
#define XT25F_READ_UID_CMD 0x4BU /* Read Unique 64-bit ID */
#define XT25F_POWERUP_CMD 0xABU /* Release Power-down / Read Device ID */
/* Read Commands */
#define XT25F_READ_DATA_CMD 0x03U /* Standard Read (1-1-1) */
#define XT25F_FAST_READ_CMD 0x0BU /* Fast Read (1-1-1) with dummy */
#define XT25F_FAST_READ_DUAL_OUT_CMD 0x3BU /* Fast Read Dual Output (1-1-2) */
#define XT25F_FAST_READ_DUAL_IO_CMD 0xBBU /* Fast Read Dual I/O (1-2-2) */
#define XT25F_FAST_READ_QUAD_OUT_CMD 0x6BU /* Fast Read Quad Output (1-1-4) */
#define XT25F_FAST_READ_QUAD_IO_CMD 0xEBU /* Fast Read Quad I/O (1-4-4) */
/* Program Commands */
#define XT25F_PAGE_PROGRAM_CMD 0x02U /* Page Program (1-1-1) */
#define XT25F_PAGE_PROGRAM_QUAD_INP_CMD 0x32U /* Quad Page Program (1-1-4) */
/* Erase Commands */
#define XT25F_SECTOR_ERASE_CMD 0x20U /* Sector Erase (4KB) */
#define XT25F_32KB_BLOCK_ERASE_CMD 0x52U /* 32KB Block Erase */
#define XT25F_64KB_BLOCK_ERASE_CMD 0xD8U /* 64KB Block Erase */
#define XT25F_CHIP_ERASE_CMD 0xC7U /* Chip Erase (or 60H) */
/* Status Register Commands */
#define XT25F_READ_SR1_CMD 0x05U /* Read Status Register 1 */
#define XT25F_READ_SR2_CMD 0x35U /* Read Status Register 2 */
#define XT25F_READ_SR3_CMD 0x15U /* Read Status Register 3 */
#define XT25F_WRITE_SR1_CMD 0x01U /* Write Status Register 1 */
#define XT25F_WRITE_SR2_CMD 0x31U /* Write Status Register 2 */
#define XT25F_WRITE_SR3_CMD 0x11U /* Write Status Register 3 */
/* Reset Commands */
#define XT25F_ENABLE_RST_CMD 0x66U /* Enable Reset */
#define XT25F_RESET_CMD 0x99U /* Reset Device */
/* Power Control */
#define XT25F_POWERDOWN_CMD 0xB9U /* Deep Power Down */
/* Security Register Commands */
#define XT25F_READ_SECURITY_REG_CMD 0x48U /* Read Security Registers */
#define XT25F_PROG_SECURITY_REG_CMD 0x42U /* Program Security Registers */
#define XT25F_ERASE_SECURITY_REG_CMD 0x44U /* Erase Security Registers */
/* Block Lock Commands */
#define XT25F_GLOBAL_LOCK_CMD 0x7EU /* Global Block Lock */
#define XT25F_GLOBAL_UNLOCK_CMD 0x98U /* Global Block Unlock */
#define XT25F_IND_BLOCK_LOCK_CMD 0x36U /* Individual Block Lock */
#define XT25F_IND_BLOCK_UNLOCK_CMD 0x39U /* Individual Block Unlock */
#define XT25F_READ_BLOCK_LOCK_CMD 0x3DU /* Read Block Lock */
/* Advanced Commands */
#define XT25F_READ_SFDP_CMD 0x5AU /* Read SFDP Register */
#define XT25F_ERASEPROG_SUSPEND_CMD 0x75U /* Erase/Program Suspend */
#define XT25F_ERASEPROG_RESUME_CMD 0x7AU /* Erase/Program Resume */
#define XT25F_SET_BURST_WRAP_CMD 0x77U /* Set Burst with Wrap */
/**
* @}
*/
/* ========================================================================== */
/* XT25F128F Status Register Bits */
/* ========================================================================== */
/** @defgroup XT25F128F_Status_Register Status Register Bit Definitions
* @{
*/
/* Status Register 1 (S7-S0) */
#define XT25F_SR1_SRP0 ((uint8_t)0x80) /* Status Register Protect 0 */
#define XT25F_SR1_SEC ((uint8_t)0x40) /* Sector Protect Bit */
#define XT25F_SR1_TB ((uint8_t)0x20) /* Top/Bottom Protect */
#define XT25F_SR1_BP2 ((uint8_t)0x10) /* Block Protect 2 */
#define XT25F_SR1_BP1 ((uint8_t)0x08) /* Block Protect 1 */
#define XT25F_SR1_BP0 ((uint8_t)0x04) /* Block Protect 0 */
#define XT25F_SR1_WEL ((uint8_t)0x02) /* Write Enable Latch */
#define XT25F_SR1_WIP ((uint8_t)0x01) /* Write In Progress */
/* Status Register 2 (S15-S8) */
#define XT25F_SR2_SRP1 ((uint8_t)0x80) /* Status Register Protect 1 */
#define XT25F_SR2_QE ((uint8_t)0x02) /* Quad Enable (S9) */
#define XT25F_SR2_SUS ((uint8_t)0x01) /* Suspend Status */
/* Status Register 3 (S23-S16) */
#define XT25F_SR3_DRV1 ((uint8_t)0x40) /* Driver Strength 1 */
#define XT25F_SR3_DRV0 ((uint8_t)0x20) /* Driver Strength 0 */
#define XT25F_SR3_WPS ((uint8_t)0x04) /* Write Protect Selection */
/**
* @}
*/
/* ========================================================================== */
/* XT25F128F JEDEC ID Definition */
/* ========================================================================== */
/** @defgroup XT25F128F_ID Device ID Definitions
* @{
*/
#define XT25F_MANUFACTURER_ID 0x0BU /* XTX Manufacturer ID */
#define XT25F_MEMORY_TYPE 0x40U /* Memory Type */
#define XT25F_CAPACITY_128MBIT 0x18U /* 128Mbit Capacity */
/**
* @}
*/
/* ========================================================================== */
/* OctoSPI Configuration Defaults */
/* ========================================================================== */
/** @defgroup XT25F128F_OSPI_Config OctoSPI Configuration
* @{
*/
#define XT25F_OSPI_FLASH_ID HAL_OSPI_FLASH_ID_1
#define XT25F_OSPI_TIMEOUT 5000U /* 5s timeout for safety */
/**
* @}
*/
/* ========================================================================== */
/* Public Function Prototypes */
/* ========================================================================== */
/** @defgroup XT25F128F_Functions Public Functions
* @{
*/
/* Initialization / Configuration */
HAL_StatusTypeDef XT25F_Init(OSPI_HandleTypeDef *hospi);
HAL_StatusTypeDef XT25F_Reset(OSPI_HandleTypeDef *hospi);
HAL_StatusTypeDef XT25F_EnableQuadMode(OSPI_HandleTypeDef *hospi);
/* ID Functions */
HAL_StatusTypeDef XT25F_ReadJEDECID(OSPI_HandleTypeDef *hospi, uint8_t *pData);
HAL_StatusTypeDef XT25F_ReadUID(OSPI_HandleTypeDef *hospi, uint8_t *pData);
/* Read Functions - Quad SPI Mode */
HAL_StatusTypeDef XT25F_Read(OSPI_HandleTypeDef *hospi, uint8_t *pData,
uint32_t ReadAddr, uint32_t Size);
HAL_StatusTypeDef XT25F_FastReadQuadIO(OSPI_HandleTypeDef *hospi, uint8_t *pData,
uint32_t ReadAddr, uint32_t Size);
HAL_StatusTypeDef XT25F_FastReadQuadOut(OSPI_HandleTypeDef *hospi, uint8_t *pData,
uint32_t ReadAddr, uint32_t Size);
/* Write Functions */
HAL_StatusTypeDef XT25F_Write(OSPI_HandleTypeDef *hospi, uint8_t *pData,
uint32_t WriteAddr, uint32_t Size);
HAL_StatusTypeDef XT25F_PageProgram(OSPI_HandleTypeDef *hospi, uint8_t *pData,
uint32_t WriteAddr, uint32_t Size);
HAL_StatusTypeDef XT25F_QuadPageProgram(OSPI_HandleTypeDef *hospi, uint8_t *pData,
uint32_t WriteAddr, uint32_t Size);
/* Write Mode Selection */
typedef enum {
XT25F_WRITE_MODE_STANDARD = 0, /* Standard Page Program (02H), 1-1-1 */
XT25F_WRITE_MODE_QUAD = 1 /* Quad Page Program (32H), 1-1-4 */
} XT25F_WriteModeTypeDef;
void XT25F_SetWriteMode(XT25F_WriteModeTypeDef mode);
XT25F_WriteModeTypeDef XT25F_GetWriteMode(void);
/* Erase Functions */
HAL_StatusTypeDef XT25F_EraseSector(OSPI_HandleTypeDef *hospi, uint32_t SectorAddress);
HAL_StatusTypeDef XT25F_EraseBlock32K(OSPI_HandleTypeDef *hospi, uint32_t BlockAddress);
HAL_StatusTypeDef XT25F_EraseBlock64K(OSPI_HandleTypeDef *hospi, uint32_t BlockAddress);
HAL_StatusTypeDef XT25F_EraseChip(OSPI_HandleTypeDef *hospi);
/* Status Register Functions */
HAL_StatusTypeDef XT25F_ReadStatusRegister(OSPI_HandleTypeDef *hospi,
uint8_t *pData, uint8_t RegNum);
HAL_StatusTypeDef XT25F_WriteStatusRegister(OSPI_HandleTypeDef *hospi,
uint8_t Value, uint8_t RegNum);
/* Memory Mapped Mode */
HAL_StatusTypeDef XT25F_EnableMemoryMappedMode(OSPI_HandleTypeDef *hospi);
HAL_StatusTypeDef XT25F_DisableMemoryMappedMode(OSPI_HandleTypeDef *hospi);
/* Polling / Status Functions */
HAL_StatusTypeDef XT25F_AutoPollingMemReady(OSPI_HandleTypeDef *hospi);
HAL_StatusTypeDef XT25F_WriteEnable(OSPI_HandleTypeDef *hospi);
HAL_StatusTypeDef XT25F_IsBusy(OSPI_HandleTypeDef *hospi);
/* Power Control */
HAL_StatusTypeDef XT25F_EnterPowerDown(OSPI_HandleTypeDef *hospi);
HAL_StatusTypeDef XT25F_ReleasePowerDown(OSPI_HandleTypeDef *hospi);
/**
* @}
*/
#ifdef __cplusplus
}
#endif
#endif /* __XT25F128F_H */
3.2 源文件
/**
******************************************************************************
* @file XT25F128F.c
* @brief XT25F128F Quad SPI Flash Driver
* Based on STM32H723 OctoSPI Peripheral
* Quad I/O Mode (1-4-4) with Memory-Mapped Support
******************************************************************************
* @attention
*
* 本驱动基于STM32H723的OctoSPI外设,实现XT25F128F的Quad SPI模式驱动。
* 支持间接模式读写、自动轮询、内存映射模式等功能。
*
* Quad I/O Fast Read (EBH): 指令(1线) + 地址(4线) + 数据(4线)
* Quad Page Program (32H): 指令(1线) + 地址(1线) + 数据(4线)
*
******************************************************************************
*/
#include "XT25F128F.h"
/* ========================================================================== */
/* Private Variables */
/* ======================================================================= */
static XT25F_WriteModeTypeDef g_write_mode = XT25F_WRITE_MODE_QUAD; /* Default Quad mode */
/* ========================================================================== */
/* Private Function Prototypes */
/* ========================================================================== */
static HAL_StatusTypeDef XT25F_Command_CommonCfg(OSPI_RegularCmdTypeDef *sCommand);
static HAL_StatusTypeDef XT25F_Command_ReadCfg(OSPI_RegularCmdTypeDef *sCommand);
static HAL_StatusTypeDef XT25F_Command_WriteCfg(OSPI_RegularCmdTypeDef *sCommand);
static HAL_StatusTypeDef XT25F_EnsureReady(OSPI_HandleTypeDef *hospi);
/* ========================================================================== */
/* Private Helper Functions */
/* ========================================================================== */
/**
* @brief Ensure OSPI is in ready state, abort if necessary
* @param hospi: OSPI handle
* @retval HAL status
*/
static HAL_StatusTypeDef XT25F_EnsureReady(OSPI_HandleTypeDef *hospi)
{
uint32_t state = HAL_OSPI_GetState(hospi);
/* If already ready, return OK */
if (state == HAL_OSPI_STATE_READY) {
return HAL_OK;
}
/* If not in ready state, try to abort to reset state machine */
if (HAL_OSPI_Abort(hospi) != HAL_OK) {
/* If abort fails, try a more aggressive reset */
hospi->State = HAL_OSPI_STATE_READY;
hospi->ErrorCode = HAL_OSPI_ERROR_NONE;
}
/* Wait for ready state after abort */
uint32_t timeout = 10000;
while ((HAL_OSPI_GetState(hospi) != HAL_OSPI_STATE_READY) && (timeout > 0)) {
timeout--;
}
/* If still not ready, force reset the state */
if (HAL_OSPI_GetState(hospi) != HAL_OSPI_STATE_READY) {
hospi->State = HAL_OSPI_STATE_READY;
hospi->ErrorCode = HAL_OSPI_ERROR_NONE;
}
return HAL_OK;
}
/**
* @brief Configure common OSPI command parameters
* @param sCommand: Pointer to OSPI command structure
* @retval HAL status
*/
static HAL_StatusTypeDef XT25F_Command_CommonCfg(OSPI_RegularCmdTypeDef *sCommand)
{
sCommand->OperationType = HAL_OSPI_OPTYPE_COMMON_CFG;
sCommand->FlashId = XT25F_OSPI_FLASH_ID;
sCommand->InstructionDtrMode = HAL_OSPI_INSTRUCTION_DTR_DISABLE;
sCommand->AddressDtrMode = HAL_OSPI_ADDRESS_DTR_DISABLE;
sCommand->DataDtrMode = HAL_OSPI_DATA_DTR_DISABLE;
sCommand->DQSMode = HAL_OSPI_DQS_DISABLE;
sCommand->SIOOMode = HAL_OSPI_SIOO_INST_EVERY_CMD;
sCommand->AlternateBytesMode = HAL_OSPI_ALTERNATE_BYTES_NONE;
sCommand->AlternateBytes = 0;
sCommand->AlternateBytesSize = HAL_OSPI_ALTERNATE_BYTES_NONE;
sCommand->AlternateBytesDtrMode = HAL_OSPI_ALTERNATE_BYTES_DTR_DISABLE;
sCommand->InstructionMode = HAL_OSPI_INSTRUCTION_1_LINE;
sCommand->InstructionSize = HAL_OSPI_INSTRUCTION_8_BITS;
sCommand->AddressSize = HAL_OSPI_ADDRESS_24_BITS;
sCommand->DummyCycles = 0;
sCommand->NbData = 0;
return HAL_OK;
}
/**
* @brief Configure read OSPI command parameters
* @param sCommand: Pointer to OSPI command structure
* @retval HAL status
*/
static HAL_StatusTypeDef XT25F_Command_ReadCfg(OSPI_RegularCmdTypeDef *sCommand)
{
sCommand->OperationType = HAL_OSPI_OPTYPE_READ_CFG;
sCommand->FlashId = XT25F_OSPI_FLASH_ID;
sCommand->InstructionDtrMode = HAL_OSPI_INSTRUCTION_DTR_DISABLE;
sCommand->AddressDtrMode = HAL_OSPI_ADDRESS_DTR_DISABLE;
sCommand->DataDtrMode = HAL_OSPI_DATA_DTR_DISABLE;
sCommand->DQSMode = HAL_OSPI_DQS_DISABLE;
sCommand->SIOOMode = HAL_OSPI_SIOO_INST_EVERY_CMD;
sCommand->AlternateBytesMode = HAL_OSPI_ALTERNATE_BYTES_NONE;
sCommand->AlternateBytes = 0;
sCommand->AlternateBytesSize = HAL_OSPI_ALTERNATE_BYTES_NONE;
sCommand->AlternateBytesDtrMode = HAL_OSPI_ALTERNATE_BYTES_DTR_DISABLE;
sCommand->InstructionMode = HAL_OSPI_INSTRUCTION_1_LINE;
sCommand->InstructionSize = HAL_OSPI_INSTRUCTION_8_BITS;
sCommand->AddressSize = HAL_OSPI_ADDRESS_24_BITS;
return HAL_OK;
}
/**
* @brief Configure write OSPI command parameters
* @param sCommand: Pointer to OSPI command structure
* @retval HAL status
*/
static HAL_StatusTypeDef XT25F_Command_WriteCfg(OSPI_RegularCmdTypeDef *sCommand)
{
sCommand->OperationType = HAL_OSPI_OPTYPE_WRITE_CFG;
sCommand->FlashId = XT25F_OSPI_FLASH_ID;
sCommand->InstructionDtrMode = HAL_OSPI_INSTRUCTION_DTR_DISABLE;
sCommand->AddressDtrMode = HAL_OSPI_ADDRESS_DTR_DISABLE;
sCommand->DataDtrMode = HAL_OSPI_DATA_DTR_DISABLE;
sCommand->DQSMode = HAL_OSPI_DQS_DISABLE;
sCommand->SIOOMode = HAL_OSPI_SIOO_INST_EVERY_CMD;
sCommand->AlternateBytesMode = HAL_OSPI_ALTERNATE_BYTES_NONE;
sCommand->AlternateBytes = 0;
sCommand->AlternateBytesSize = HAL_OSPI_ALTERNATE_BYTES_NONE;
sCommand->AlternateBytesDtrMode = HAL_OSPI_ALTERNATE_BYTES_DTR_DISABLE;
sCommand->InstructionMode = HAL_OSPI_INSTRUCTION_1_LINE;
sCommand->InstructionSize = HAL_OSPI_INSTRUCTION_8_BITS;
sCommand->AddressSize = HAL_OSPI_ADDRESS_24_BITS;
return HAL_OK;
}
/* ========================================================================== */
/* Initialization Functions */
/* ========================================================================== */
/**
* @brief Initialize the XT25F128F Flash and OctoSPI interface
* @param hospi: OSPI handle
* @retval HAL status
*/
HAL_StatusTypeDef XT25F_Init(OSPI_HandleTypeDef *hospi)
{
HAL_StatusTypeDef status;
/* 1. Reset the Flash device */
status = XT25F_Reset(hospi);
if (status != HAL_OK) {
return HAL_ERROR;
}
HAL_Delay(1);
/* 2. Wait for Flash to be ready */
status = XT25F_AutoPollingMemReady(hospi);
if (status != HAL_OK) {
return HAL_ERROR;
}
/* 3. Enable Quad Mode (set QE bit in Status Register 2) */
status = XT25F_EnableQuadMode(hospi);
if (status != HAL_OK) {
return HAL_ERROR;
}
/* 4. Wait for Flash to be ready */
status = XT25F_AutoPollingMemReady(hospi);
if (status != HAL_OK) {
return HAL_ERROR;
}
return HAL_OK;
}
/**
* @brief Reset the XT25F128F Flash device
* @param hospi: OSPI handle
* @retval HAL status
*/
HAL_StatusTypeDef XT25F_Reset(OSPI_HandleTypeDef *hospi)
{
OSPI_RegularCmdTypeDef sCommand = {0};
/* Enable Reset Command (66H) */
XT25F_Command_CommonCfg(&sCommand);
sCommand.Instruction = XT25F_ENABLE_RST_CMD;
sCommand.AddressMode = HAL_OSPI_ADDRESS_NONE;
sCommand.Address = 0;
sCommand.DataMode = HAL_OSPI_DATA_NONE;
if (HAL_OSPI_Command(hospi, &sCommand, XT25F_OSPI_TIMEOUT) != HAL_OK) {
return HAL_ERROR;
}
/* Reset Command (99H) */
sCommand.Instruction = XT25F_RESET_CMD;
if (HAL_OSPI_Command(hospi, &sCommand, XT25F_OSPI_TIMEOUT) != HAL_OK) {
return HAL_ERROR;
}
HAL_Delay(1);
return HAL_OK;
}
/**
* @brief Enable Quad SPI mode by setting QE bit
* @param hospi: OSPI handle
* @retval HAL status
*/
HAL_StatusTypeDef XT25F_EnableQuadMode(OSPI_HandleTypeDef *hospi)
{
uint8_t sr2 = 0;
/* Read Status Register 2 */
if (XT25F_ReadStatusRegister(hospi, &sr2, 2) != HAL_OK) {
return HAL_ERROR;
}
/* Check if Quad Enable bit is already set */
if ((sr2 & XT25F_SR2_QE) != 0) {
return HAL_OK; /* Quad mode already enabled */
}
/* Set Quad Enable bit */
sr2 |= XT25F_SR2_QE;
/* Write Status Register 2 */
if (XT25F_WriteStatusRegister(hospi, sr2, 2) != HAL_OK) {
return HAL_ERROR;
}
return HAL_OK;
}
/* ========================================================================== */
/* ID Functions */
/* ========================================================================== */
/**
* @brief Read JEDEC ID (Manufacturer ID + Memory Type + Capacity)
* @param hospi: OSPI handle
* @param pData: Pointer to data buffer (3 bytes)
* @retval HAL status
*/
HAL_StatusTypeDef XT25F_ReadJEDECID(OSPI_HandleTypeDef *hospi, uint8_t *pData)
{
OSPI_RegularCmdTypeDef sCommand = {0};
XT25F_Command_CommonCfg(&sCommand);
sCommand.Instruction = XT25F_READ_JEDEC_ID_CMD;
sCommand.AddressMode = HAL_OSPI_ADDRESS_NONE;
sCommand.Address = 0;
sCommand.DataMode = HAL_OSPI_DATA_1_LINE;
sCommand.DummyCycles = 0;
sCommand.NbData = 3;
if (HAL_OSPI_Command(hospi, &sCommand, XT25F_OSPI_TIMEOUT) != HAL_OK) {
return HAL_ERROR;
}
if (HAL_OSPI_Receive(hospi, pData, XT25F_OSPI_TIMEOUT) != HAL_OK) {
return HAL_ERROR;
}
return HAL_OK;
}
/**
* @brief Read Unique 64-bit ID
* @param hospi: OSPI handle
* @param pData: Pointer to data buffer (8 bytes / 64 bits)
* @retval HAL status
*/
HAL_StatusTypeDef XT25F_ReadUID(OSPI_HandleTypeDef *hospi, uint8_t *pData)
{
OSPI_RegularCmdTypeDef sCommand = {0};
XT25F_Command_CommonCfg(&sCommand);
sCommand.Instruction = XT25F_READ_UID_CMD;
sCommand.AddressMode = HAL_OSPI_ADDRESS_NONE;
sCommand.Address = 0;
sCommand.DataMode = HAL_OSPI_DATA_1_LINE;
sCommand.DummyCycles = 32; /* 4 Dummy Bytes = 32 bits */
sCommand.NbData = 8; /* 64-bit Unique ID */
if (HAL_OSPI_Command(hospi, &sCommand, XT25F_OSPI_TIMEOUT) != HAL_OK) {
return HAL_ERROR;
}
if (HAL_OSPI_Receive(hospi, pData, XT25F_OSPI_TIMEOUT) != HAL_OK) {
return HAL_ERROR;
}
return HAL_OK;
}
/* ========================================================================== */
/* Read Functions - Quad SPI Mode */
/* ========================================================================== */
/**
* @brief Read data from Flash using Quad I/O Fast Read (EBH command)
* This is the default high-speed read function (1-4-4 mode)
* @param hospi: OSPI handle
* @param pData: Pointer to data buffer
* @param ReadAddr: Start address to read from
* @param Size: Number of bytes to read
* @retval HAL status
*/
HAL_StatusTypeDef XT25F_Read(OSPI_HandleTypeDef *hospi, uint8_t *pData,
uint32_t ReadAddr, uint32_t Size)
{
return XT25F_FastReadQuadIO(hospi, pData, ReadAddr, Size);
}
/**
* @brief Quad I/O Fast Read (EBH command, 1-4-4 mode)
* Instruction: 1 line, Address: 4 lines, Data: 4 lines
* Default dummy cycles: 6 (DC0=0)
* @param hospi: OSPI handle
* @param pData: Pointer to data buffer
* @param ReadAddr: Start address to read from
* @param Size: Number of bytes to read
* @retval HAL status
*/
HAL_StatusTypeDef XT25F_FastReadQuadIO(OSPI_HandleTypeDef *hospi, uint8_t *pData,
uint32_t ReadAddr, uint32_t Size)
{
OSPI_RegularCmdTypeDef sCommand = {0};
if (Size == 0) {
return HAL_OK;
}
XT25F_Command_CommonCfg(&sCommand);
sCommand.Instruction = XT25F_FAST_READ_QUAD_IO_CMD;
sCommand.AddressMode = HAL_OSPI_ADDRESS_4_LINES; /* Address: 4 lines */
sCommand.Address = ReadAddr;
sCommand.DataMode = HAL_OSPI_DATA_4_LINES; /* Data: 4 lines */
sCommand.DummyCycles = XT25F_DUMMY_CYCLES_READ_QUAD; /* 6 dummy cycles */
sCommand.NbData = Size;
if (HAL_OSPI_Command(hospi, &sCommand, XT25F_OSPI_TIMEOUT) != HAL_OK) {
return HAL_ERROR;
}
if (HAL_OSPI_Receive(hospi, pData, XT25F_OSPI_TIMEOUT) != HAL_OK) {
return HAL_ERROR;
}
return HAL_OK;
}
/**
* @brief Quad Output Fast Read (6BH command, 1-1-4 mode)
* Instruction: 1 line, Address: 1 line, Data: 4 lines
* @param hospi: OSPI handle
* @param pData: Pointer to data buffer
* @param ReadAddr: Start address to read from
* @param Size: Number of bytes to read
* @retval HAL status
*/
HAL_StatusTypeDef XT25F_FastReadQuadOut(OSPI_HandleTypeDef *hospi, uint8_t *pData,
uint32_t ReadAddr, uint32_t Size)
{
OSPI_RegularCmdTypeDef sCommand = {0};
if (Size == 0) {
return HAL_OK;
}
XT25F_Command_CommonCfg(&sCommand);
sCommand.Instruction = XT25F_FAST_READ_QUAD_OUT_CMD;
sCommand.AddressMode = HAL_OSPI_ADDRESS_1_LINE; /* Address: 1 line */
sCommand.Address = ReadAddr;
sCommand.DataMode = HAL_OSPI_DATA_4_LINES; /* Data: 4 lines */
sCommand.DummyCycles = 8; /* 1 Dummy Byte = 8 clocks */
sCommand.NbData = Size;
if (HAL_OSPI_Command(hospi, &sCommand, XT25F_OSPI_TIMEOUT) != HAL_OK) {
return HAL_ERROR;
}
if (HAL_OSPI_Receive(hospi, pData, XT25F_OSPI_TIMEOUT) != HAL_OK) {
return HAL_ERROR;
}
return HAL_OK;
}
/* ========================================================================== */
/* Write Mode Control Functions */
/* ========================================================================== */
/**
* @brief Set write mode (standard or quad)
* @param mode: Write mode
* @retval None
*/
void XT25F_SetWriteMode(XT25F_WriteModeTypeDef mode)
{
g_write_mode = mode;
}
/**
* @brief Get current write mode
* @retval Current write mode
*/
XT25F_WriteModeTypeDef XT25F_GetWriteMode(void)
{
return g_write_mode;
}
/* ========================================================================== */
/* Write Functions */
/* ========================================================================== */
/**
* @brief Write data to Flash (page-by-page programming)
* Uses the currently selected write mode (standard or quad)
* @param hospi: OSPI handle
* @param pData: Pointer to data buffer
* @param WriteAddr: Start address to write to
* @param Size: Number of bytes to write
* @retval HAL status
*/
HAL_StatusTypeDef XT25F_Write(OSPI_HandleTypeDef *hospi, uint8_t *pData,
uint32_t WriteAddr, uint32_t Size)
{
uint32_t end_addr;
uint32_t current_size;
uint32_t current_addr;
uint8_t *data_ptr;
HAL_StatusTypeDef status;
if (Size == 0) {
return HAL_OK;
}
/* Calculate first page boundary */
current_addr = WriteAddr;
end_addr = WriteAddr + Size;
data_ptr = pData;
/* Calculate size for first page */
current_size = XT25F_PAGE_SIZE - (WriteAddr % XT25F_PAGE_SIZE);
if (current_size > Size) {
current_size = Size;
}
/* Perform the write page by page */
while (current_addr < end_addr) {
/* Enable write operations */
status = XT25F_WriteEnable(hospi);
if (status != HAL_OK) {
return HAL_ERROR;
}
/* Program current page based on selected mode */
if (g_write_mode == XT25F_WRITE_MODE_QUAD) {
status = XT25F_QuadPageProgram(hospi, data_ptr, current_addr, current_size);
} else {
status = XT25F_PageProgram(hospi, data_ptr, current_addr, current_size);
}
if (status != HAL_OK) {
return HAL_ERROR;
}
/* Wait for write operation to complete */
status = XT25F_AutoPollingMemReady(hospi);
if (status != HAL_OK) {
return HAL_ERROR;
}
/* Update address and size for next page */
current_addr += current_size;
data_ptr += current_size;
/* Calculate size for next page */
current_size = (end_addr - current_addr) > XT25F_PAGE_SIZE
? XT25F_PAGE_SIZE
: (end_addr - current_addr);
}
return HAL_OK;
}
/**
* @brief Standard Page Program (02H command, 1-1-1 mode)
* Instruction: 1 line, Address: 1 line, Data: 1 line
* Note: Data must be within a single page
* @param hospi: OSPI handle
* @param pData: Pointer to data buffer
* @param WriteAddr: Start address to write to
* @param Size: Number of bytes to write (max 256 bytes per page)
* @retval HAL status
*/
HAL_StatusTypeDef XT25F_PageProgram(OSPI_HandleTypeDef *hospi, uint8_t *pData,
uint32_t WriteAddr, uint32_t Size)
{
OSPI_RegularCmdTypeDef sCommand = {0};
if ((Size == 0) || (Size > XT25F_PAGE_SIZE)) {
return HAL_ERROR;
}
/* Ensure OSPI is in ready state */
if (XT25F_EnsureReady(hospi) != HAL_OK) {
return HAL_ERROR;
}
XT25F_Command_CommonCfg(&sCommand);
sCommand.Instruction = XT25F_PAGE_PROGRAM_CMD;
sCommand.AddressMode = HAL_OSPI_ADDRESS_1_LINE;
sCommand.Address = WriteAddr;
sCommand.DataMode = HAL_OSPI_DATA_1_LINE;
sCommand.DummyCycles = 0;
sCommand.NbData = Size;
/* Temporarily set FIFO threshold to 1 to prevent timeout
* with small transfer sizes (< original FifoThreshold) */
uint32_t orig_fifo = hospi->Init.FifoThreshold;
if (Size < orig_fifo) {
hospi->Init.FifoThreshold = 1;
HAL_OSPI_Init(hospi);
}
if (HAL_OSPI_Command(hospi, &sCommand, XT25F_OSPI_TIMEOUT) != HAL_OK) {
if (Size < orig_fifo) {
hospi->Init.FifoThreshold = orig_fifo;
HAL_OSPI_Init(hospi);
}
return HAL_ERROR;
}
if (HAL_OSPI_Transmit(hospi, pData, XT25F_OSPI_TIMEOUT) != HAL_OK) {
if (Size < orig_fifo) {
hospi->Init.FifoThreshold = orig_fifo;
HAL_OSPI_Init(hospi);
}
return HAL_ERROR;
}
/* Restore original FIFO threshold */
if (Size < orig_fifo) {
hospi->Init.FifoThreshold = orig_fifo;
HAL_OSPI_Init(hospi);
}
return HAL_OK;
}
/**
* @brief Quad Page Program (32H command, 1-1-4 mode)
* Instruction: 1 line, Address: 1 line, Data: 4 lines
* Note: Data must be within a single page
* @param hospi: OSPI handle
* @param pData: Pointer to data buffer
* @param WriteAddr: Start address to write to
* @param Size: Number of bytes to write (max 256 bytes per page)
* @retval HAL status
*/
HAL_StatusTypeDef XT25F_QuadPageProgram(OSPI_HandleTypeDef *hospi, uint8_t *pData,
uint32_t WriteAddr, uint32_t Size)
{
OSPI_RegularCmdTypeDef sCommand = {0};
if ((Size == 0) || (Size > XT25F_PAGE_SIZE)) {
return HAL_ERROR;
}
/* Ensure OSPI is in ready state */
if (XT25F_EnsureReady(hospi) != HAL_OK) {
return HAL_ERROR;
}
XT25F_Command_CommonCfg(&sCommand);
sCommand.Instruction = XT25F_PAGE_PROGRAM_QUAD_INP_CMD;
sCommand.AddressMode = HAL_OSPI_ADDRESS_1_LINE; /* Address: 1 line */
sCommand.Address = WriteAddr;
sCommand.DataMode = HAL_OSPI_DATA_4_LINES; /* Data: 4 lines */
sCommand.DummyCycles = 0;
sCommand.NbData = Size;
/* Temporarily set FIFO threshold to 1 to prevent timeout
* with small transfer sizes (< original FifoThreshold) */
uint32_t orig_fifo_q = hospi->Init.FifoThreshold;
if (Size < orig_fifo_q) {
hospi->Init.FifoThreshold = 1;
HAL_OSPI_Init(hospi);
}
/* Send command, address, and data */
if (HAL_OSPI_Command(hospi, &sCommand, XT25F_OSPI_TIMEOUT) != HAL_OK) {
if (Size < orig_fifo_q) {
hospi->Init.FifoThreshold = orig_fifo_q;
HAL_OSPI_Init(hospi);
}
return HAL_ERROR;
}
if (HAL_OSPI_Transmit(hospi, pData, XT25F_OSPI_TIMEOUT) != HAL_OK) {
if (Size < orig_fifo_q) {
hospi->Init.FifoThreshold = orig_fifo_q;
HAL_OSPI_Init(hospi);
}
return HAL_ERROR;
}
/* Restore original FIFO threshold */
if (Size < orig_fifo_q) {
hospi->Init.FifoThreshold = orig_fifo_q;
HAL_OSPI_Init(hospi);
}
return HAL_OK;
}
/* ========================================================================== */
/* Erase Functions */
/* ========================================================================== */
/**
* @brief Erase a 4KB sector
* @param hospi: OSPI handle
* @param SectorAddress: Address within the sector to erase
* @retval HAL status
*/
HAL_StatusTypeDef XT25F_EraseSector(OSPI_HandleTypeDef *hospi, uint32_t SectorAddress)
{
OSPI_RegularCmdTypeDef sCommand = {0};
/* Enable write operations */
if (XT25F_WriteEnable(hospi) != HAL_OK) {
return HAL_ERROR;
}
XT25F_Command_CommonCfg(&sCommand);
sCommand.Instruction = XT25F_SECTOR_ERASE_CMD;
sCommand.AddressMode = HAL_OSPI_ADDRESS_1_LINE;
sCommand.Address = SectorAddress & 0xFFFFFFU;
sCommand.DataMode = HAL_OSPI_DATA_NONE;
sCommand.DummyCycles = 0;
sCommand.NbData = 0;
if (HAL_OSPI_Command(hospi, &sCommand, XT25F_OSPI_TIMEOUT) != HAL_OK) {
return HAL_ERROR;
}
/* Wait for erase operation to complete */
if (XT25F_AutoPollingMemReady(hospi) != HAL_OK) {
return HAL_ERROR;
}
return HAL_OK;
}
/**
* @brief Erase a 32KB block
* @param hospi: OSPI handle
* @param BlockAddress: Address within the block to erase
* @retval HAL status
*/
HAL_StatusTypeDef XT25F_EraseBlock32K(OSPI_HandleTypeDef *hospi, uint32_t BlockAddress)
{
OSPI_RegularCmdTypeDef sCommand = {0};
/* Enable write operations */
if (XT25F_WriteEnable(hospi) != HAL_OK) {
return HAL_ERROR;
}
XT25F_Command_CommonCfg(&sCommand);
sCommand.Instruction = XT25F_32KB_BLOCK_ERASE_CMD;
sCommand.AddressMode = HAL_OSPI_ADDRESS_1_LINE;
sCommand.Address = BlockAddress & 0xFFFFFFU;
sCommand.DataMode = HAL_OSPI_DATA_NONE;
sCommand.DummyCycles = 0;
sCommand.NbData = 0;
if (HAL_OSPI_Command(hospi, &sCommand, XT25F_OSPI_TIMEOUT) != HAL_OK) {
return HAL_ERROR;
}
/* Wait for erase operation to complete */
if (XT25F_AutoPollingMemReady(hospi) != HAL_OK) {
return HAL_ERROR;
}
return HAL_OK;
}
/**
* @brief Erase a 64KB block
* @param hospi: OSPI handle
* @param BlockAddress: Address within the block to erase
* @retval HAL status
*/
HAL_StatusTypeDef XT25F_EraseBlock64K(OSPI_HandleTypeDef *hospi, uint32_t BlockAddress)
{
OSPI_RegularCmdTypeDef sCommand = {0};
/* Enable write operations */
if (XT25F_WriteEnable(hospi) != HAL_OK) {
return HAL_ERROR;
}
XT25F_Command_CommonCfg(&sCommand);
sCommand.Instruction = XT25F_64KB_BLOCK_ERASE_CMD;
sCommand.AddressMode = HAL_OSPI_ADDRESS_1_LINE;
sCommand.Address = BlockAddress & 0xFFFFFFU;
sCommand.DataMode = HAL_OSPI_DATA_NONE;
sCommand.DummyCycles = 0;
sCommand.NbData = 0;
if (HAL_OSPI_Command(hospi, &sCommand, XT25F_OSPI_TIMEOUT) != HAL_OK) {
return HAL_ERROR;
}
/* Wait for erase operation to complete */
if (XT25F_AutoPollingMemReady(hospi) != HAL_OK) {
return HAL_ERROR;
}
return HAL_OK;
}
/**
* @brief Erase the entire chip
* @param hospi: OSPI handle
* @retval HAL status
* @note This operation can take up to 100 seconds
*/
HAL_StatusTypeDef XT25F_EraseChip(OSPI_HandleTypeDef *hospi)
{
OSPI_RegularCmdTypeDef sCommand = {0};
/* Enable write operations */
if (XT25F_WriteEnable(hospi) != HAL_OK) {
return HAL_ERROR;
}
XT25F_Command_CommonCfg(&sCommand);
sCommand.Instruction = XT25F_CHIP_ERASE_CMD;
sCommand.AddressMode = HAL_OSPI_ADDRESS_NONE;
sCommand.Address = 0;
sCommand.DataMode = HAL_OSPI_DATA_NONE;
sCommand.DummyCycles = 0;
sCommand.NbData = 0;
if (HAL_OSPI_Command(hospi, &sCommand, XT25F_OSPI_TIMEOUT) != HAL_OK) {
return HAL_ERROR;
}
/* Wait for erase operation to complete */
if (XT25F_AutoPollingMemReady(hospi) != HAL_OK) {
return HAL_ERROR;
}
return HAL_OK;
}
/* ========================================================================== */
/* Status Register Functions */
/* ========================================================================== */
/**
* @brief Read Status Register
* @param hospi: OSPI handle
* @param pData: Pointer to store register value
* @param RegNum: Register number (1, 2, or 3)
* @retval HAL status
*/
HAL_StatusTypeDef XT25F_ReadStatusRegister(OSPI_HandleTypeDef *hospi,
uint8_t *pData, uint8_t RegNum)
{
OSPI_RegularCmdTypeDef sCommand = {0};
XT25F_Command_CommonCfg(&sCommand);
sCommand.AddressMode = HAL_OSPI_ADDRESS_NONE;
sCommand.Address = 0;
sCommand.DataMode = HAL_OSPI_DATA_1_LINE;
sCommand.DummyCycles = 0;
sCommand.NbData = 1;
switch (RegNum) {
case 1:
sCommand.Instruction = XT25F_READ_SR1_CMD;
break;
case 2:
sCommand.Instruction = XT25F_READ_SR2_CMD;
break;
case 3:
sCommand.Instruction = XT25F_READ_SR3_CMD;
break;
default:
return HAL_ERROR;
}
if (HAL_OSPI_Command(hospi, &sCommand, XT25F_OSPI_TIMEOUT) != HAL_OK) {
return HAL_ERROR;
}
if (HAL_OSPI_Receive(hospi, pData, XT25F_OSPI_TIMEOUT) != HAL_OK) {
return HAL_ERROR;
}
return HAL_OK;
}
/**
* @brief Write Status Register
* @param hospi: OSPI handle
* @param Value: Value to write to the register
* @param RegNum: Register number (1, 2, or 3)
* @retval HAL status
*/
HAL_StatusTypeDef XT25F_WriteStatusRegister(OSPI_HandleTypeDef *hospi,
uint8_t Value, uint8_t RegNum)
{
OSPI_RegularCmdTypeDef sCommand = {0};
uint8_t cmd = 0;
switch (RegNum) {
case 1:
cmd = XT25F_WRITE_SR1_CMD;
break;
case 2:
cmd = XT25F_WRITE_SR2_CMD;
break;
case 3:
cmd = XT25F_WRITE_SR3_CMD;
break;
default:
return HAL_ERROR;
}
/* Enable Volatile Status Register Write (50H command) */
XT25F_Command_CommonCfg(&sCommand);
sCommand.Instruction = XT25F_ENABLE_VOLATILE_SR_CMD;
sCommand.AddressMode = HAL_OSPI_ADDRESS_NONE;
sCommand.Address = 0;
sCommand.DataMode = HAL_OSPI_DATA_NONE;
sCommand.DummyCycles = 0;
sCommand.NbData = 0;
if (HAL_OSPI_Command(hospi, &sCommand, XT25F_OSPI_TIMEOUT) != HAL_OK) {
return HAL_ERROR;
}
/* Write Enable */
if (XT25F_WriteEnable(hospi) != HAL_OK) {
return HAL_ERROR;
}
/* Write Status Register */
sCommand.Instruction = cmd;
sCommand.DataMode = HAL_OSPI_DATA_1_LINE;
sCommand.NbData = 1;
if (HAL_OSPI_Command(hospi, &sCommand, XT25F_OSPI_TIMEOUT) != HAL_OK) {
return HAL_ERROR;
}
if (HAL_OSPI_Transmit(hospi, &Value, XT25F_OSPI_TIMEOUT) != HAL_OK) {
return HAL_ERROR;
}
/* Wait for write operation to complete */
if (XT25F_AutoPollingMemReady(hospi) != HAL_OK) {
return HAL_ERROR;
}
return HAL_OK;
}
/* ========================================================================== */
/* Memory Mapped Mode Functions */
/* ========================================================================== */
/**
* @brief Enable Memory-Mapped mode for Quad I/O Fast Read
* After enabling, Flash can be accessed like internal memory at address 0x90000000
* @param hospi: OSPI handle
* @retval HAL status
*/
HAL_StatusTypeDef XT25F_EnableMemoryMappedMode(OSPI_HandleTypeDef *hospi)
{
OSPI_RegularCmdTypeDef sCommand = {0};
OSPI_MemoryMappedTypeDef sMemMappedCfg = {0};
/* Configure Read Configuration for Memory-Mapped Mode */
XT25F_Command_ReadCfg(&sCommand);
sCommand.Instruction = XT25F_FAST_READ_QUAD_IO_CMD;
sCommand.AddressMode = HAL_OSPI_ADDRESS_4_LINES; /* Address: 4 lines */
sCommand.Address = 0;
sCommand.DataMode = HAL_OSPI_DATA_4_LINES; /* Data: 4 lines */
sCommand.DummyCycles = XT25F_DUMMY_CYCLES_READ_QUAD; /* 6 dummy cycles */
sCommand.NbData = 0;
if (HAL_OSPI_Command(hospi, &sCommand, XT25F_OSPI_TIMEOUT) != HAL_OK) {
return HAL_ERROR;
}
/* Configure Write Configuration for Memory-Mapped Mode */
XT25F_Command_WriteCfg(&sCommand);
sCommand.Instruction = XT25F_PAGE_PROGRAM_QUAD_INP_CMD;
sCommand.AddressMode = HAL_OSPI_ADDRESS_1_LINE; /* Address: 1 line */
sCommand.Address = 0;
sCommand.DataMode = HAL_OSPI_DATA_4_LINES; /* Data: 4 lines */
sCommand.DummyCycles = 0;
sCommand.NbData = 0;
if (HAL_OSPI_Command(hospi, &sCommand, XT25F_OSPI_TIMEOUT) != HAL_OK) {
return HAL_ERROR;
}
/* Initialize Memory Mapped Mode */
sMemMappedCfg.TimeOutActivation = HAL_OSPI_TIMEOUT_COUNTER_DISABLE;
if (HAL_OSPI_MemoryMapped(hospi, &sMemMappedCfg) != HAL_OK) {
return HAL_ERROR;
}
return HAL_OK;
}
/**
* @brief Disable Memory-Mapped mode and return to indirect mode
* @param hospi: OSPI handle
* @retval HAL status
*/
HAL_StatusTypeDef XT25F_DisableMemoryMappedMode(OSPI_HandleTypeDef *hospi)
{
/* Abort any ongoing operation to exit memory-mapped mode */
if (HAL_OSPI_Abort(hospi) != HAL_OK) {
return HAL_ERROR;
}
return HAL_OK;
}
/* ========================================================================== */
/* Polling / Status Functions */
/* ========================================================================== */
/**
* @brief Auto-polling to wait for Flash to be ready (WIP bit = 0)
* @param hospi: OSPI handle
* @retval HAL status
*/
HAL_StatusTypeDef XT25F_AutoPollingMemReady(OSPI_HandleTypeDef *hospi)
{
OSPI_RegularCmdTypeDef sCommand = {0};
OSPI_AutoPollingTypeDef sConfig = {0};
XT25F_Command_CommonCfg(&sCommand);
sCommand.Instruction = XT25F_READ_SR1_CMD;
sCommand.AddressMode = HAL_OSPI_ADDRESS_NONE;
sCommand.Address = 0;
sCommand.DataMode = HAL_OSPI_DATA_1_LINE;
sCommand.DummyCycles = 0;
sCommand.NbData = 1;
if (HAL_OSPI_Command(hospi, &sCommand, XT25F_OSPI_TIMEOUT) != HAL_OK) {
return HAL_ERROR;
}
sConfig.Match = 0x00U;
sConfig.Mask = XT25F_SR1_WIP;
sConfig.MatchMode = HAL_OSPI_MATCH_MODE_AND;
sConfig.Interval = XT25F_AUTOPOLLING_INTERVAL_TIME;
sConfig.AutomaticStop = HAL_OSPI_AUTOMATIC_STOP_ENABLE;
if (HAL_OSPI_AutoPolling(hospi, &sConfig, XT25F_OSPI_TIMEOUT) != HAL_OK) {
return HAL_ERROR;
}
return HAL_OK;
}
/**
* @brief Send Write Enable command
* @param hospi: OSPI handle
* @retval HAL status
*/
HAL_StatusTypeDef XT25F_WriteEnable(OSPI_HandleTypeDef *hospi)
{
OSPI_RegularCmdTypeDef sCommand = {0};
OSPI_AutoPollingTypeDef sConfig = {0};
/* Ensure OSPI is in ready state */
if (XT25F_EnsureReady(hospi) != HAL_OK) {
return HAL_ERROR;
}
/* Send Write Enable Command */
XT25F_Command_CommonCfg(&sCommand);
sCommand.Instruction = XT25F_WRITE_ENABLE_CMD;
sCommand.AddressMode = HAL_OSPI_ADDRESS_NONE;
sCommand.Address = 0;
sCommand.DataMode = HAL_OSPI_DATA_NONE;
sCommand.DummyCycles = 0;
sCommand.NbData = 0;
if (HAL_OSPI_Command(hospi, &sCommand, XT25F_OSPI_TIMEOUT) != HAL_OK) {
return HAL_ERROR;
}
/* Read Status Register 1 and poll for WEL bit set */
sCommand.Instruction = XT25F_READ_SR1_CMD;
sCommand.DataMode = HAL_OSPI_DATA_1_LINE;
sCommand.NbData = 1;
if (HAL_OSPI_Command(hospi, &sCommand, XT25F_OSPI_TIMEOUT) != HAL_OK) {
return HAL_ERROR;
}
sConfig.Match = XT25F_SR1_WEL; /* WEL bit = 1 */
sConfig.Mask = XT25F_SR1_WEL;
sConfig.MatchMode = HAL_OSPI_MATCH_MODE_AND;
sConfig.Interval = XT25F_AUTOPOLLING_INTERVAL_TIME;
sConfig.AutomaticStop = HAL_OSPI_AUTOMATIC_STOP_ENABLE;
if (HAL_OSPI_AutoPolling(hospi, &sConfig, XT25F_OSPI_TIMEOUT) != HAL_OK) {
return HAL_ERROR;
}
return HAL_OK;
}
/**
* @brief Check if Flash is busy (WIP bit)
* @param hospi: OSPI handle
* @retval HAL_OK if not busy, HAL_ERROR if busy
*/
HAL_StatusTypeDef XT25F_IsBusy(OSPI_HandleTypeDef *hospi)
{
uint8_t status_register = 0;
if (XT25F_ReadStatusRegister(hospi, &status_register, 1) != HAL_OK) {
return HAL_ERROR;
}
status_register = status_register & XT25F_SR1_WIP;
return (status_register ? HAL_ERROR : HAL_OK);
}
/* ========================================================================== */
/* Power Control Functions */
/* ========================================================================== */
/**
* @brief Enter Deep Power-Down mode
* @param hospi: OSPI handle
* @retval HAL status
*/
HAL_StatusTypeDef XT25F_EnterPowerDown(OSPI_HandleTypeDef *hospi)
{
OSPI_RegularCmdTypeDef sCommand = {0};
XT25F_Command_CommonCfg(&sCommand);
sCommand.Instruction = XT25F_POWERDOWN_CMD;
sCommand.AddressMode = HAL_OSPI_ADDRESS_NONE;
sCommand.Address = 0;
sCommand.DataMode = HAL_OSPI_DATA_NONE;
sCommand.DummyCycles = 0;
sCommand.NbData = 0;
if (HAL_OSPI_Command(hospi, &sCommand, XT25F_OSPI_TIMEOUT) != HAL_OK) {
return HAL_ERROR;
}
return HAL_OK;
}
/**
* @brief Release from Deep Power-Down mode
* @param hospi: OSPI handle
* @retval HAL status
*/
HAL_StatusTypeDef XT25F_ReleasePowerDown(OSPI_HandleTypeDef *hospi)
{
OSPI_RegularCmdTypeDef sCommand = {0};
XT25F_Command_CommonCfg(&sCommand);
sCommand.Instruction = XT25F_POWERUP_CMD;
sCommand.AddressMode = HAL_OSPI_ADDRESS_NONE;
sCommand.Address = 0;
sCommand.DataMode = HAL_OSPI_DATA_NONE;
sCommand.DummyCycles = 0;
sCommand.NbData = 0;
if (HAL_OSPI_Command(hospi, &sCommand, XT25F_OSPI_TIMEOUT) != HAL_OK) {
return HAL_ERROR;
}
HAL_Delay(1); /* Wait for device to wake up */
return HAL_OK;
}
3.3 主函数
XT25F_Init(&hospi1);
XT25F_EnableQuadMode(&hospi1);
XT25F_WriteEnable(&hospi1);
uint8_t flash_data[] = {0x55,0x5a,0xa5,0xaa};
XT25F_EraseSector(&hospi1, 0x000000);
XT25F_Write(&hospi1,flash_data,0x000000,4);
XT25F_EnableMemoryMappedMode(&hospi1);
uint8_t* ptr = (uint8_t *)(XT25F_MEMORY_BASE_ADDR);
printf("%02X\n\r",*ptr);
printf("%02X\n\r",*++ptr);
printf("%02X\n\r",*++ptr);
printf("%02X\n\r",*++ptr);
4 注意事项
1、写入数据前进行写使能
2、时钟配置不能只看宣传页的最高频率,得看所有模式下的最低频率
3、Chip Select High Time必须大于数据电平跳变的时间
4、浮栅晶体管存储单元特性必须先擦除再写入,擦除后所有的位为高电平
更多推荐

所有评论(0)