STM32H7B0VB OSPI 操作 25QXX FLASH
实测使用CUBE MX生成 的 osp 库会有问题,读到的ID 是错的。
#include "w25qxx.h"
#include "octospi.h"
#include "stm32h7xx_hal_ospi.h"
/**
* @brief 初始化OSPI存储器
* @retval OSPI存储器状态
*/
uint8_t W25Qxx_OSPI_Init(uint16_t ClockPrescaler)
{
OSPI_RegularCmdTypeDef s_command;
uint16_t w25qxx_id;
uint8_t value = W25QxJV_FSR_QE;
GPIO_InitTypeDef GPIO_InitStruct;
/**OCTOSPI1 GPIO Configuration
PE2 ------> OCTOSPIM_P1_IO2
PD11 ------> OCTOSPIM_P1_IO0
PD12 ------> OCTOSPIM_P1_IO1
PD13 ------> OCTOSPIM_P1_IO3
PB6 ------> OCTOSPIM_P1_NCS
*/
RCC_PeriphCLKInitTypeDef PeriphClkInitStruct;
PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_OSPI;
PeriphClkInitStruct.PLL2.PLL2M = 5;
PeriphClkInitStruct.PLL2.PLL2N = 50;
PeriphClkInitStruct.PLL2.PLL2P = 5;
PeriphClkInitStruct.PLL2.PLL2Q = 100;
PeriphClkInitStruct.PLL2.PLL2R = 50;
PeriphClkInitStruct.PLL2.PLL2RGE = RCC_PLL2VCIRANGE_3;
PeriphClkInitStruct.PLL2.PLL2VCOSEL = RCC_PLL2VCOWIDE;
PeriphClkInitStruct.PLL2.PLL2FRACN = 0;
PeriphClkInitStruct.OspiClockSelection = RCC_OSPICLKSOURCE_PLL2;
HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct);
__HAL_RCC_GPIOB_CLK_ENABLE();
__HAL_RCC_GPIOD_CLK_ENABLE();
__HAL_RCC_GPIOE_CLK_ENABLE();
__HAL_RCC_OCTOSPIM_CLK_ENABLE();
__HAL_RCC_OSPI1_CLK_ENABLE();
GPIO_InitStruct.Pin = GPIO_PIN_2;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF9_OCTOSPIM_P1;
HAL_GPIO_Init(GPIOE, &GPIO_InitStruct);
GPIO_InitStruct.Pin = GPIO_PIN_2;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF9_OCTOSPIM_P1;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
GPIO_InitStruct.Pin = GPIO_PIN_11|GPIO_PIN_12|GPIO_PIN_13;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF9_OCTOSPIM_P1;
HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);
GPIO_InitStruct.Pin = GPIO_PIN_6;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF10_OCTOSPIM_P1;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
hospi1.Instance = OCTOSPI1;
hospi1.Init.FifoThreshold = 24;
hospi1.Init.DualQuad = HAL_OSPI_DUALQUAD_DISABLE;
hospi1.Init.MemoryType = HAL_OSPI_MEMTYPE_MACRONIX;
hospi1.Init.DeviceSize = OSPI_FLASH_SIZE;
hospi1.Init.ChipSelectHighTime =6;
hospi1.Init.FreeRunningClock = HAL_OSPI_FREERUNCLK_DISABLE;
hospi1.Init.ClockMode = HAL_OSPI_CLOCK_MODE_0;
hospi1.Init.WrapSize = HAL_OSPI_WRAP_NOT_SUPPORTED;
hospi1.Init.ClockPrescaler =ClockPrescaler;
hospi1.Init.SampleShifting = HAL_OSPI_SAMPLE_SHIFTING_HALFCYCLE;
hospi1.Init.DelayHoldQuarterCycle = HAL_OSPI_DHQC_DISABLE;
hospi1.Init.ChipSelectBoundary = 8;
hospi1.Init.ClkChipSelectHighTime = 0;
hospi1.Init.DelayBlockBypass = HAL_OSPI_DELAY_BLOCK_BYPASSED;
hospi1.Init.MaxTran = 0;
hospi1.Init.Refresh = 0;
HAL_OSPI_Init(&hospi1);
/* OSPI存储器复位 */
if (W25Qxx_OSPI_ResetMemory() != OSPI_OK)
{
return OSPI_NOT_SUPPORTED;
}
/* 使能写操作 */
if (W25Qxx_OSPI_WriteEnable() != OSPI_OK)
{
return OSPI_ERROR;
}
/* 设置四路使能的状态寄存器,使能四通道IO2和IO3引脚 */
s_command.OperationType = HAL_OSPI_OPTYPE_COMMON_CFG;
s_command.FlashId = HAL_OSPI_FLASH_ID_1;
s_command.InstructionMode = HAL_OSPI_INSTRUCTION_1_LINE;
s_command.Instruction = WRITE_STATUS_REG2_CMD;
s_command.AddressMode = HAL_OSPI_ADDRESS_NONE;
s_command.AlternateBytesMode = HAL_OSPI_ALTERNATE_BYTES_NONE;
s_command.DataMode = HAL_OSPI_DATA_1_LINE;
s_command.DummyCycles = 0;
s_command.NbData = 1;
s_command.DataDtrMode = HAL_OSPI_DATA_DTR_DISABLE;
s_command.SIOOMode = HAL_OSPI_SIOO_INST_EVERY_CMD;
s_command.InstructionSize = HAL_OSPI_INSTRUCTION_8_BITS;
s_command.InstructionDtrMode = HAL_OSPI_INSTRUCTION_DTR_DISABLE;
s_command.AddressDtrMode = HAL_OSPI_ADDRESS_DTR_DISABLE;
s_command.DQSMode = HAL_OSPI_DQS_DISABLE;
/* 配置命令 */
if (HAL_OSPI_Command(&hospi1, &s_command, HAL_OSPI_TIMEOUT_DEFAULT_VALUE)
!= HAL_OK)
{
return OSPI_ERROR;
}
/* 传输数据 */
if (HAL_OSPI_Transmit(&hospi1, &value, HAL_OSPI_TIMEOUT_DEFAULT_VALUE)
!= HAL_OK)
{
return OSPI_ERROR;
}
/* 自动轮询模式等待存储器就绪 */
if (W25Qxx_OSPI_AutoPollingMemReady(W25QxJV_SUBSECTOR_ERASE_MAX_TIME) != OSPI_OK)
{
return OSPI_ERROR;
}
w25qxx_id=W25Qxx_OSPI_FLASH_ReadDeviceID();
/* 配置地址模式为 4 字节 , 非W25Q256直接跳过*/
if ( w25qxx_id!= W25Qxx_ID)
return OSPI_OK;
if (W25Qxx_OSPI_Addr_Mode_Init() != OSPI_OK)
{
return OSPI_ERROR;
}
return OSPI_OK;
}
/**
* @brief 检查地址模式不是4字节地址,配置为4字节
* @retval OSPI存储器状态
*/
uint8_t W25Qxx_OSPI_Addr_Mode_Init(void)
{
OSPI_RegularCmdTypeDef s_command;
uint8_t reg;
/* 初始化读取状态寄存器命令 */
s_command.OperationType = HAL_OSPI_OPTYPE_COMMON_CFG;
s_command.FlashId = HAL_OSPI_FLASH_ID_1;
s_command.InstructionMode = HAL_OSPI_INSTRUCTION_1_LINE;
s_command.Instruction = WRITE_STATUS_REG3_CMD;
s_command.AddressMode = HAL_OSPI_ADDRESS_NONE;
s_command.AlternateBytesMode = HAL_OSPI_ALTERNATE_BYTES_NONE;
s_command.DataMode = HAL_OSPI_DATA_1_LINE;
s_command.DummyCycles = 0;
s_command.NbData = 1;
s_command.DataDtrMode = HAL_OSPI_DATA_DTR_DISABLE;
s_command.SIOOMode = HAL_OSPI_SIOO_INST_EVERY_CMD;
s_command.InstructionSize = HAL_OSPI_INSTRUCTION_8_BITS;
s_command.InstructionDtrMode = HAL_OSPI_INSTRUCTION_DTR_DISABLE;
s_command.AddressDtrMode = HAL_OSPI_ADDRESS_DTR_DISABLE;
s_command.DQSMode = HAL_OSPI_DQS_DISABLE;
/* 配置命令 */
if (HAL_OSPI_Command(&hospi1, &s_command, HAL_OSPI_TIMEOUT_DEFAULT_VALUE)
!= HAL_OK)
{
return OSPI_ERROR;
}
/* 接收数据 */
if (HAL_OSPI_Receive(&hospi1, ®, HAL_OSPI_TIMEOUT_DEFAULT_VALUE)
!= HAL_OK)
{
return OSPI_ERROR;
}
/* 检查寄存器的值 */
if ((reg & W25Q256FV_FSR_4ByteAddrMode) == 1) // 4字节模式
{
return OSPI_OK;
}
else // 3字节模式
{
/* 配置进入 4 字节地址模式命令 */
s_command.Instruction = Enter_4Byte_Addr_Mode_CMD;
s_command.DataMode = HAL_OSPI_DATA_NONE;
/* 配置并发送命令 */
if (HAL_OSPI_Command(&hospi1, &s_command, HAL_OSPI_TIMEOUT_DEFAULT_VALUE)
!= HAL_OK)
{
return OSPI_ERROR;
}
/* 自动轮询模式等待存储器就绪 */
if (W25Qxx_OSPI_AutoPollingMemReady(
W25QxJV_SUBSECTOR_ERASE_MAX_TIME) != OSPI_OK)
{
return OSPI_ERROR;
}
return OSPI_OK;
}
}
/**
* @brief 从OSPI存储器中读取大量数据.
* @param pData: 指向要读取的数据的指针
* @param ReadAddr: 读取起始地址
* @param Size: 要读取的数据大小
* @retval OSPI存储器状态
*/
uint8_t W25Qxx_OSPI_Read(uint8_t *pData, uint32_t ReadAddr, uint32_t Size)
{
OSPI_RegularCmdTypeDef s_command;
if(Size == 0) return OSPI_OK;
/* 初始化读命令 */
s_command.OperationType = HAL_OSPI_OPTYPE_COMMON_CFG;
s_command.FlashId = HAL_OSPI_FLASH_ID_1;
s_command.InstructionMode = HAL_OSPI_INSTRUCTION_1_LINE;
s_command.Instruction = QUAD_INOUT_FAST_READ_CMD;
s_command.AddressMode = HAL_OSPI_ADDRESS_4_LINES;
#if W25Qxx_ID==W25Q256
s_command.AddressSize = HAL_OSPI_ADDRESS_32_BITS;
#else
s_command.AddressSize = HAL_OSPI_ADDRESS_24_BITS;
#endif
s_command.Address = ReadAddr;
s_command.AlternateBytesMode = HAL_OSPI_ALTERNATE_BYTES_NONE;
s_command.DataMode = HAL_OSPI_DATA_4_LINES;
s_command.DummyCycles = 6;
s_command.NbData = Size;
s_command.DataDtrMode = HAL_OSPI_DATA_DTR_DISABLE;
s_command.SIOOMode = HAL_OSPI_SIOO_INST_EVERY_CMD;
s_command.InstructionSize = HAL_OSPI_INSTRUCTION_8_BITS;
s_command.InstructionDtrMode = HAL_OSPI_INSTRUCTION_DTR_DISABLE;
s_command.AddressDtrMode = HAL_OSPI_ADDRESS_DTR_DISABLE;
s_command.DQSMode = HAL_OSPI_DQS_DISABLE;
/* 配置命令 */
if (HAL_OSPI_Command(&hospi1, &s_command, HAL_OSPI_TIMEOUT_DEFAULT_VALUE)
!= HAL_OK)
{
return OSPI_ERROR;
}
/* 接收数据 */
if (HAL_OSPI_Receive(&hospi1, pData, HAL_OSPI_TIMEOUT_DEFAULT_VALUE)
!= HAL_OK)
{
return OSPI_ERROR;
}
return OSPI_OK;
}
/**
* @brief 将大量数据写入OSPI存储器
* @param pData: 指向要写入数据的指针
* @param WriteAddr: 写起始地址
* @param Size: 要写入的数据大小
* @retval OSPI存储器状态
*/
uint8_t W25Qxx_OSPI_WritePage(uint8_t *pData, uint32_t WriteAddr, uint32_t Size)
{
OSPI_RegularCmdTypeDef s_command;
/* 启用写操作 */
if (W25Qxx_OSPI_WriteEnable() != OSPI_OK)
{
return OSPI_ERROR;
}
/* 初始化程序命令 */
s_command.OperationType = HAL_OSPI_OPTYPE_COMMON_CFG;
s_command.FlashId = HAL_OSPI_FLASH_ID_1;
s_command.InstructionMode = HAL_OSPI_INSTRUCTION_1_LINE;
s_command.Instruction = QUAD_INPUT_PAGE_PROG_CMD;
s_command.AddressMode = HAL_OSPI_ADDRESS_1_LINE;
#if W25Qxx_ID==W25Q256
s_command.AddressSize = HAL_OSPI_ADDRESS_32_BITS;
#else
s_command.AddressSize = HAL_OSPI_ADDRESS_24_BITS;
#endif
s_command.AlternateBytesMode = HAL_OSPI_ALTERNATE_BYTES_NONE;
s_command.DataMode = HAL_OSPI_DATA_4_LINES;
s_command.DummyCycles = 0;
s_command.DataDtrMode = HAL_OSPI_DATA_DTR_DISABLE;
s_command.SIOOMode = HAL_OSPI_SIOO_INST_ONLY_FIRST_CMD;
s_command.InstructionSize = HAL_OSPI_INSTRUCTION_8_BITS;
s_command.InstructionDtrMode = HAL_OSPI_INSTRUCTION_DTR_DISABLE;
s_command.AddressDtrMode = HAL_OSPI_ADDRESS_DTR_DISABLE;
s_command.DQSMode = HAL_OSPI_DQS_DISABLE;
s_command.Address = WriteAddr;
s_command.NbData = Size;
/* 配置命令 */
if (HAL_OSPI_Command(&hospi1, &s_command, HAL_OSPI_TIMEOUT_DEFAULT_VALUE)
!= HAL_OK)
{
return OSPI_ERROR;
}
/* 传输数据 */
if (HAL_OSPI_Transmit(&hospi1, pData, HAL_OSPI_TIMEOUT_DEFAULT_VALUE)
!= HAL_OK)
{
return OSPI_ERROR;
}
/* 配置自动轮询模式等待程序结束 */
if (W25Qxx_OSPI_AutoPollingMemReady(HAL_OSPI_TIMEOUT_DEFAULT_VALUE) != OSPI_OK)
{
return OSPI_ERROR;
}
return OSPI_OK;
}
//无检验写SPI FLASH
//必须确保所写的地址范围内的数据全部为0XFF,否则在非0XFF处写入的数据将失败!
//具有自动换页功能
//在指定地址开始写入指定长度的数据,但是要确保地址不越界!
//pBuffer:数据存储区
//WriteAddr:开始写入的地址(24bit)
//CHECK OK
void W25Qxx_OSPI_Write_NoCheck(uint8_t* pBuffer,uint32_t WriteAddr,uint32_t NumByteToWrite)
{
uint32_t pageremain;
pageremain=256-WriteAddr%256; //单页剩余的字节数
if(NumByteToWrite<=pageremain)
{
pageremain=NumByteToWrite;//不大于256个字节
}
while(1)
{
W25Qxx_OSPI_WritePage(pBuffer,WriteAddr,pageremain);
if(NumByteToWrite==pageremain)
{
break;//写入结束了
}
else //NumByteToWrite>pageremain
{
pBuffer+=pageremain;
WriteAddr+=pageremain;
NumByteToWrite-=pageremain; //减去已经写入了的字节数
if(NumByteToWrite>256)
{
pageremain=256; //一次可以写入256个字节
}
else
{
pageremain=NumByteToWrite; //不够256个字节了
}
}
}
}
//写SPI FLASH
//在指定地址开始写入指定长度的数据
//该函数带擦除操作!
//pBuffer:数据存储区
//WriteAddr:开始写入的地址(24bit)
uint8_t W25QXX_BUFFER[4096];
void W25Qxx_OSPI_Write(uint8_t* pBuffer,uint32_t WriteAddr,uint32_t Size)
{
uint32_t secpos;
uint32_t secoff;
uint32_t secremain;
uint32_t i;
uint8_t *W25QXX_BUF;
W25QXX_BUF=W25QXX_BUFFER;
secpos=WriteAddr/4096;//扇区地址
secoff=WriteAddr%4096;//在扇区内的偏移
secremain=4096-secoff;//扇区剩余空间大小
if(Size<=secremain)
{
secremain=Size;//不大于4096个字节
}
while(1)
{
W25Qxx_OSPI_Read(W25QXX_BUF,secpos*4096,4096);//读出整个扇区的内容
for(i=0;i<secremain;i++)//校验数据
{
if(W25QXX_BUF[secoff+i]!=0XFF)
{
break;//需要擦除
}
}
if(i<secremain)//需要擦除
{
W25Qxx_OSPI_Erase_Block(secpos); //擦除这个扇区
for(i=0;i<secremain;i++) //复制
{
W25QXX_BUF[i+secoff]=pBuffer[i];
}
W25Qxx_OSPI_Write_NoCheck(W25QXX_BUF,secpos*4096,4096);//写入整个扇区
}
else
{
W25Qxx_OSPI_Write_NoCheck(pBuffer,WriteAddr,secremain);//写已经擦除了的,直接写入扇区剩余区间.
}
if(Size==secremain)
{
break;//写入结束了
}
else//写入未结束
{
secpos++;//扇区地址增1
secoff=0;//偏移位置为0
pBuffer+=secremain; //指针偏移
WriteAddr+=secremain; //写地址偏移
Size-=secremain; //字节数递减
if(Size > 4096)
{
secremain = 4096;//下一个扇区还是写不完
}
else
{
secremain = Size; //下一个扇区可以写完了
}
}
}
}
/**
* @brief 擦除OSPI存储器的指定块
* @param BlockAddress: 需要擦除的块地址
* @retval OSPI存储器状态
*/
uint8_t W25Qxx_OSPI_Erase_Block(uint32_t BlockAddress)
{
OSPI_RegularCmdTypeDef s_command;
/* 初始化擦除命令 */
s_command.OperationType = HAL_OSPI_OPTYPE_COMMON_CFG;
s_command.FlashId = HAL_OSPI_FLASH_ID_1;
s_command.InstructionMode = HAL_OSPI_INSTRUCTION_1_LINE;
s_command.Instruction = SECTOR_ERASE_CMD;
s_command.AddressMode = HAL_OSPI_ADDRESS_1_LINE;
#if W25Qxx_ID==W25Q256
s_command.AddressSize = HAL_OSPI_ADDRESS_32_BITS;
#else
s_command.AddressSize = HAL_OSPI_ADDRESS_24_BITS;
#endif
s_command.Address = BlockAddress*4096;
s_command.AlternateBytesMode = HAL_OSPI_ALTERNATE_BYTES_NONE;
s_command.DataMode = HAL_OSPI_DATA_NONE;
s_command.DummyCycles = 0;
s_command.DataDtrMode = HAL_OSPI_DATA_DTR_DISABLE;
s_command.SIOOMode = HAL_OSPI_SIOO_INST_EVERY_CMD;
s_command.InstructionSize = HAL_OSPI_INSTRUCTION_8_BITS;
s_command.InstructionDtrMode = HAL_OSPI_INSTRUCTION_DTR_DISABLE;
s_command.AddressDtrMode = HAL_OSPI_ADDRESS_DTR_DISABLE;
s_command.DQSMode = HAL_OSPI_DQS_DISABLE;
/* 启用写操作 */
if (W25Qxx_OSPI_WriteEnable() != OSPI_OK)
{
return OSPI_ERROR;
}
/* 发送命令 */
if (HAL_OSPI_Command(&hospi1, &s_command, HAL_OSPI_TIMEOUT_DEFAULT_VALUE)
!= HAL_OK)
{
return OSPI_ERROR;
}
/* 配置自动轮询模式等待擦除结束 */
if (W25Qxx_OSPI_AutoPollingMemReady(W25QxJV_SUBSECTOR_ERASE_MAX_TIME) != OSPI_OK)
{
return OSPI_ERROR;
}
return OSPI_OK;
}
/**
* @brief 擦除整个OSPI存储器
* @retval OSPI存储器状态
*/
uint8_t W25Qxx_OSPI_Erase_Chip(void)
{
OSPI_RegularCmdTypeDef s_command;
/* 初始化擦除命令 */
s_command.OperationType = HAL_OSPI_OPTYPE_COMMON_CFG;
s_command.FlashId = HAL_OSPI_FLASH_ID_1;
s_command.InstructionMode = HAL_OSPI_INSTRUCTION_1_LINE;
s_command.Instruction = CHIP_ERASE_CMD;
s_command.AddressMode = HAL_OSPI_ADDRESS_NONE;
s_command.AlternateBytesMode = HAL_OSPI_ALTERNATE_BYTES_NONE;
s_command.DataMode = HAL_OSPI_DATA_NONE;
s_command.DummyCycles = 0;
s_command.DataDtrMode = HAL_OSPI_DATA_DTR_DISABLE;
s_command.SIOOMode = HAL_OSPI_SIOO_INST_EVERY_CMD;
s_command.InstructionSize = HAL_OSPI_INSTRUCTION_8_BITS;
s_command.InstructionDtrMode = HAL_OSPI_INSTRUCTION_DTR_DISABLE;
s_command.AddressDtrMode = HAL_OSPI_ADDRESS_DTR_DISABLE;
s_command.DQSMode = HAL_OSPI_DQS_DISABLE;
/* 启用写操作 */
if (W25Qxx_OSPI_WriteEnable() != OSPI_OK)
{
return OSPI_ERROR;
}
/* 发送命令 */
if (HAL_OSPI_Command(&hospi1, &s_command, HAL_OSPI_TIMEOUT_DEFAULT_VALUE)
!= HAL_OK)
{
return OSPI_ERROR;
}
/* 配置自动轮询模式等待擦除结束 */
if (W25Qxx_OSPI_AutoPollingMemReady(W25QxJV_BULK_ERASE_MAX_TIME) != OSPI_OK)
{
return OSPI_ERROR;
}
return OSPI_OK;
}
/**
* @brief 读取OSPI存储器的当前状态
* @retval OSPI存储器状态
*/
uint8_t W25Qxx_OSPI_GetStatus(void)
{
OSPI_RegularCmdTypeDef s_command;
uint8_t reg;
/* 初始化读取状态寄存器命令 */
s_command.OperationType = HAL_OSPI_OPTYPE_COMMON_CFG;
s_command.FlashId = HAL_OSPI_FLASH_ID_1;
s_command.InstructionMode = HAL_OSPI_INSTRUCTION_1_LINE;
s_command.Instruction = READ_STATUS_REG1_CMD;
s_command.AddressMode = HAL_OSPI_ADDRESS_NONE;
s_command.AlternateBytesMode = HAL_OSPI_ALTERNATE_BYTES_NONE;
s_command.DataMode = HAL_OSPI_DATA_1_LINE;
s_command.DummyCycles = 0;
s_command.NbData = 1;
s_command.DataDtrMode = HAL_OSPI_DATA_DTR_DISABLE;
s_command.SIOOMode = HAL_OSPI_SIOO_INST_EVERY_CMD;
s_command.InstructionSize = HAL_OSPI_INSTRUCTION_8_BITS;
s_command.InstructionDtrMode = HAL_OSPI_INSTRUCTION_DTR_DISABLE;
s_command.AddressDtrMode = HAL_OSPI_ADDRESS_DTR_DISABLE;
s_command.DQSMode = HAL_OSPI_DQS_DISABLE;
/* 配置命令 */
if (HAL_OSPI_Command(&hospi1, &s_command, HAL_OSPI_TIMEOUT_DEFAULT_VALUE)
!= HAL_OK)
{
return OSPI_ERROR;
}
/* 接收数据 */
if (HAL_OSPI_Receive(&hospi1, ®, HAL_OSPI_TIMEOUT_DEFAULT_VALUE)
!= HAL_OK)
{
return OSPI_ERROR;
}
/* 检查寄存器的值 */
if ((reg & W25QxJV_FSR_BUSY) != 0)
{
return OSPI_BUSY;
}
else
{
return OSPI_OK;
}
}
/**
* @brief 复位OSPI存储器。
* @param hOSPI: OSPI句柄
* @retval 无
*/
uint8_t W25Qxx_OSPI_ResetMemory(void)
{
OSPI_RegularCmdTypeDef s_command;
/* 初始化复位使能命令 */
s_command.OperationType = HAL_OSPI_OPTYPE_COMMON_CFG;
s_command.FlashId = HAL_OSPI_FLASH_ID_1;
s_command.InstructionMode = HAL_OSPI_INSTRUCTION_1_LINE;
s_command.Instruction = RESET_ENABLE_CMD;
s_command.AddressMode = HAL_OSPI_ADDRESS_NONE;
s_command.AlternateBytesMode = HAL_OSPI_ALTERNATE_BYTES_NONE;
s_command.DataMode = HAL_OSPI_DATA_NONE;
s_command.DummyCycles = 0;
s_command.DataDtrMode = HAL_OSPI_DATA_DTR_DISABLE;
s_command.SIOOMode = HAL_OSPI_SIOO_INST_EVERY_CMD;
s_command.InstructionSize = HAL_OSPI_INSTRUCTION_8_BITS;
s_command.InstructionDtrMode = HAL_OSPI_INSTRUCTION_DTR_DISABLE;
s_command.AddressDtrMode = HAL_OSPI_ADDRESS_DTR_DISABLE;
s_command.DQSMode = HAL_OSPI_DQS_DISABLE;
/* 发送命令 */
if (HAL_OSPI_Command(&hospi1, &s_command, HAL_OSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
{
return OSPI_ERROR;
}
/* 发送复位存储器命令 */
s_command.Instruction = RESET_MEMORY_CMD;
if (HAL_OSPI_Command(&hospi1, &s_command, HAL_OSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
{
return OSPI_ERROR;
}
s_command.InstructionMode = HAL_OSPI_INSTRUCTION_4_LINES;
s_command.Instruction = RESET_ENABLE_CMD;
s_command.InstructionSize = HAL_OSPI_INSTRUCTION_8_BITS;
/* 发送命令 */
if (HAL_OSPI_Command(&hospi1, &s_command, HAL_OSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
{
return OSPI_ERROR;
}
/* 发送复位存储器命令 */
s_command.Instruction = RESET_MEMORY_CMD;
if (HAL_OSPI_Command(&hospi1, &s_command, HAL_OSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
{
return OSPI_ERROR;
}
/* 配置自动轮询模式等待存储器就绪 */
if (W25Qxx_OSPI_AutoPollingMemReady(HAL_OSPI_TIMEOUT_DEFAULT_VALUE) != OSPI_OK)
{
return OSPI_ERROR;
}
return OSPI_OK;
}
/**
* @brief 发送写入使能,等待它有效.
* @param hOSPI: OSPI句柄
* @retval 无
*/
uint8_t W25Qxx_OSPI_WriteEnable(void)
{
OSPI_RegularCmdTypeDef s_command;
OSPI_AutoPollingTypeDef s_config;
/* 启用写操作 */
s_command.OperationType = HAL_OSPI_OPTYPE_COMMON_CFG;
s_command.FlashId = HAL_OSPI_FLASH_ID_1;
s_command.InstructionMode = HAL_OSPI_INSTRUCTION_1_LINE;
s_command.Instruction = WRITE_ENABLE_CMD;
s_command.AddressMode = HAL_OSPI_ADDRESS_NONE;
s_command.AlternateBytesMode = HAL_OSPI_ALTERNATE_BYTES_NONE;
s_command.DataMode = HAL_OSPI_DATA_NONE;
s_command.DummyCycles = 0;
s_command.DataDtrMode = HAL_OSPI_DATA_DTR_DISABLE;
s_command.SIOOMode = HAL_OSPI_SIOO_INST_EVERY_CMD;
s_command.InstructionSize = HAL_OSPI_INSTRUCTION_8_BITS;
s_command.InstructionDtrMode = HAL_OSPI_INSTRUCTION_DTR_DISABLE;
s_command.AddressDtrMode = HAL_OSPI_ADDRESS_DTR_DISABLE;
s_command.DQSMode = HAL_OSPI_DQS_DISABLE;
if (HAL_OSPI_Command(&hospi1, &s_command, HAL_OSPI_TIMEOUT_DEFAULT_VALUE)
!= HAL_OK)
{
return OSPI_ERROR;
}
s_command.Instruction = READ_STATUS_REG1_CMD;
s_command.DataMode = HAL_OSPI_DATA_1_LINE;
s_command.NbData = 1;
if (HAL_OSPI_Command(&hospi1, &s_command, HAL_OSPI_TIMEOUT_DEFAULT_VALUE)!= HAL_OK)
{
return OSPI_ERROR;
}
/* 配置自动轮询模式等待写启用 */
s_config.Match = W25QxJV_FSR_WREN;;
s_config.Mask = W25QxJV_FSR_WREN;;
s_config.MatchMode = HAL_OSPI_MATCH_MODE_AND;
s_config.Interval = 0x10;
s_config.AutomaticStop = HAL_OSPI_AUTOMATIC_STOP_ENABLE;
if (HAL_OSPI_AutoPolling(&hospi1, &s_config, HAL_OSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
{
return OSPI_ERROR;
}
return OSPI_OK;
}
/**
* @brief 读取存储器的SR并等待EOP
* @param hOSPI: OSPI句柄
* @param Timeout 超时
* @retval 无
*/
uint8_t W25Qxx_OSPI_AutoPollingMemReady(uint32_t Timeout)
{
OSPI_RegularCmdTypeDef s_command;
OSPI_AutoPollingTypeDef s_config;
/* 配置自动轮询模式等待存储器准备就绪 */
s_command.OperationType = HAL_OSPI_OPTYPE_COMMON_CFG;
s_command.FlashId = HAL_OSPI_FLASH_ID_1;
s_command.InstructionMode = HAL_OSPI_INSTRUCTION_1_LINE;
s_command.Instruction = READ_STATUS_REG1_CMD;
s_command.AddressMode = HAL_OSPI_ADDRESS_NONE;
s_command.AlternateBytesMode = HAL_OSPI_ALTERNATE_BYTES_NONE;
s_command.DataMode = HAL_OSPI_DATA_1_LINE;
s_command.DummyCycles = 0;
s_command.DataDtrMode = HAL_OSPI_DATA_DTR_DISABLE;
s_command.SIOOMode = HAL_OSPI_SIOO_INST_EVERY_CMD;
s_command.InstructionSize = HAL_OSPI_INSTRUCTION_8_BITS;
s_command.InstructionDtrMode = HAL_OSPI_INSTRUCTION_DTR_DISABLE;
s_command.AddressDtrMode = HAL_OSPI_ADDRESS_DTR_DISABLE;
s_command.DQSMode = HAL_OSPI_DQS_DISABLE;
if (HAL_OSPI_Command(&hospi1, &s_command, HAL_OSPI_TIMEOUT_DEFAULT_VALUE)
!= HAL_OK)
{
return OSPI_ERROR;
}
s_config.Match = 0x00;
s_config.Mask = W25QxJV_FSR_BUSY;
s_config.MatchMode = HAL_OSPI_MATCH_MODE_AND;
s_config.Interval = 0x10;
s_config.AutomaticStop = HAL_OSPI_AUTOMATIC_STOP_ENABLE;
if (HAL_OSPI_AutoPolling(&hospi1, &s_config, Timeout) != HAL_OK)
{
return OSPI_ERROR;
}
return OSPI_OK;
}
/**
* @brief 读取FLASH Device ID
* @param 无
* @retval FLASH Device ID
*/
uint32_t W25Qxx_OSPI_FLASH_ReadDeviceID(void)
{
OSPI_RegularCmdTypeDef s_command;
uint32_t Temp = 0;
uint8_t pData[3]={0,0,0};
/*##-2-读取设备ID测试 ###########################################*/
/* 读取制造/设备 ID */
s_command.OperationType = HAL_OSPI_OPTYPE_COMMON_CFG;
s_command.FlashId = HAL_OSPI_FLASH_ID_1;
s_command.InstructionMode = HAL_OSPI_INSTRUCTION_1_LINE;
s_command.Instruction = READ_ID_CMD;
s_command.AddressMode = HAL_OSPI_ADDRESS_1_LINE;
s_command.AddressSize = HAL_OSPI_ADDRESS_24_BITS;
s_command.Address = 0x000000;
s_command.AlternateBytesMode = HAL_OSPI_ALTERNATE_BYTES_NONE;
s_command.DataMode = HAL_OSPI_DATA_1_LINE;
s_command.DummyCycles = 0;
s_command.NbData = 2;
s_command.DataDtrMode = HAL_OSPI_DATA_DTR_DISABLE;
s_command.SIOOMode = HAL_OSPI_SIOO_INST_EVERY_CMD;
s_command.InstructionSize = HAL_OSPI_INSTRUCTION_8_BITS;
s_command.InstructionDtrMode = HAL_OSPI_INSTRUCTION_DTR_DISABLE;
s_command.AddressDtrMode = HAL_OSPI_ADDRESS_DTR_DISABLE;
s_command.DQSMode = HAL_OSPI_DQS_DISABLE;
HAL_OSPI_Command(&hospi1, &s_command, HAL_OSPI_TIMEOUT_DEFAULT_VALUE);
HAL_OSPI_Receive(&hospi1, pData, HAL_OSPI_TIMEOUT_DEFAULT_VALUE);
Temp = pData[1] | (pData[0] << 8);
return Temp;
}
uint32_t W25Qxx_OSPI_EnableMemoryMappedMode(void)
{
OSPI_RegularCmdTypeDef s_command;
OSPI_MemoryMappedTypeDef s_mem_mapped_cfg;
/* Configure the command for the read instruction */
s_command.OperationType = HAL_OSPI_OPTYPE_COMMON_CFG;
s_command.FlashId = HAL_OSPI_FLASH_ID_1;
s_command.InstructionMode = HAL_OSPI_INSTRUCTION_1_LINE;
s_command.Instruction = QUAD_INOUT_FAST_READ_CMD;
s_command.AddressMode = HAL_OSPI_ADDRESS_4_LINES;
#if W25Qxx_ID==W25Q256
s_command.AddressSize = HAL_OSPI_ADDRESS_32_BITS;
#else
s_command.AddressSize = HAL_OSPI_ADDRESS_24_BITS;
#endif
s_command.AlternateBytesMode = HAL_OSPI_ALTERNATE_BYTES_NONE;
s_command.DataMode = HAL_OSPI_DATA_4_LINES;
s_command.DummyCycles = 6;
s_command.DataDtrMode = HAL_OSPI_DATA_DTR_DISABLE;
s_command.SIOOMode = HAL_OSPI_SIOO_INST_EVERY_CMD;
s_command.InstructionSize = HAL_OSPI_INSTRUCTION_8_BITS;
s_command.InstructionDtrMode = HAL_OSPI_INSTRUCTION_DTR_DISABLE;
s_command.AddressDtrMode = HAL_OSPI_ADDRESS_DTR_DISABLE;
s_command.DQSMode = HAL_OSPI_DQS_DISABLE;
/* Configure the memory mapped mode */
s_mem_mapped_cfg.TimeOutActivation = HAL_OSPI_TIMEOUT_COUNTER_DISABLE;
s_mem_mapped_cfg.TimeOutPeriod = 0;
HAL_OSPI_Command(&hospi1, &s_command, HAL_OSPI_TIMEOUT_DEFAULT_VALUE);
return HAL_OSPI_MemoryMapped(&hospi1, &s_mem_mapped_cfg);
}
#ifndef W25QXX_OSPI_H_
#define W25QXX_OSPI_H_
#include "stm32h7xx_hal.h"
#define W25Q80 0XEF13
#define W25Q16 0XEF14
#define W25Q32 0XEF15
#define W25Q64 0XEF16
#define W25Q128 0XEF17
#define W25Q256 0XEF18
#define W25Qxx_ID W25Q64
/* OSPI Error codes */
#define OSPI_OK ((uint8_t)0x00)
#define OSPI_ERROR ((uint8_t)0x01)
#define OSPI_BUSY ((uint8_t)0x02)
#define OSPI_NOT_SUPPORTED ((uint8_t)0x04)
#define OSPI_SUSPENDED ((uint8_t)0x08)
/* W25QxJV Micron memory */
/* Size of the flash */
#define OSPI_FLASH_SIZE 23 /* 地址总线宽度访问整个内存空间 */
#define OSPI_PAGE_SIZE 256
/* OSPI Info */
typedef struct {
uint32_t FlashSize; /*!< 闪存大小 */
uint32_t EraseSectorSize; /*!< 擦除操作的扇区大小 */
uint32_t EraseSectorsNumber; /*!< 擦除操作的扇区数 */
uint32_t ProgPageSize; /*!< 编程操作的页面大小 */
uint32_t ProgPagesNumber; /*!< 编程操作的页面数 */
} OSPI_Info;
/* Private define ------------------------------------------------------------*/
/*命令定义-开头*******************************/
/**
* @brief W25QxJV配置
*/
#define W25QxJV_DUMMY_CYCLES_READ 4
#define W25QxJV_DUMMY_CYCLES_READ_QUAD 10
#define W25QxJV_BULK_ERASE_MAX_TIME 250000
#define W25QxJV_SECTOR_ERASE_MAX_TIME 3000
#define W25QxJV_SUBSECTOR_ERASE_MAX_TIME 800
/**
* @brief W25QxJV 指令
*/
/* 复位操作 */
#define RESET_ENABLE_CMD 0x66
#define RESET_MEMORY_CMD 0x99
#define ENTER_QPI_MODE_CMD 0x38
#define EXIT_QPI_MODE_CMD 0xFF
/* 识别操作 */
#define READ_ID_CMD 0x90
#define DUAL_READ_ID_CMD 0x92
#define QUAD_READ_ID_CMD 0x94
#define READ_JEDEC_ID_CMD 0x9F
/* 读操作 */
#define READ_CMD 0x03
#define FAST_READ_CMD 0x0B
#define DUAL_OUT_FAST_READ_CMD 0x3B
#define DUAL_INOUT_FAST_READ_CMD 0xBB
#define QUAD_OUT_FAST_READ_CMD 0x6B
#define QUAD_INOUT_FAST_READ_CMD 0xEB
/* 写操作 */
#define WRITE_ENABLE_CMD 0x06
#define WRITE_DISABLE_CMD 0x04
/* 寄存器操作 */
#define READ_STATUS_REG1_CMD 0x05
#define READ_STATUS_REG2_CMD 0x35
#define READ_STATUS_REG3_CMD 0x15
#define WRITE_STATUS_REG1_CMD 0x01
#define WRITE_STATUS_REG2_CMD 0x31
#define WRITE_STATUS_REG3_CMD 0x11
/* 编程操作 */
#define PAGE_PROG_CMD 0x02
#define QUAD_INPUT_PAGE_PROG_CMD 0x32
#define EXT_QUAD_IN_FAST_PROG_CMD 0x12
#define Enter_4Byte_Addr_Mode_CMD 0xB7
/* 擦除操作 */
#define SECTOR_ERASE_CMD 0x20 //0xD8擦:64K 0x52擦:32K 0x20擦:4K
#define CHIP_ERASE_CMD 0xC7
#define PROG_ERASE_RESUME_CMD 0x7A
#define PROG_ERASE_SUSPEND_CMD 0x75
/* 状态寄存器标志 */
#define W25QxJV_FSR_BUSY ((uint8_t)0x01) /*!< busy */
#define W25QxJV_FSR_WREN ((uint8_t)0x02) /*!< write enable */
#define W25QxJV_FSR_QE ((uint8_t)0x02) /*!< quad enable */
#define W25Q256FV_FSR_4ByteAddrMode ((uint8_t)0x01) /*!< 4字节地址模式 */
/*命令定义-结尾*******************************/
uint8_t W25Qxx_OSPI_Init(uint16_t ClockPrescaler);
uint8_t W25Qxx_OSPI_Addr_Mode_Init(void);
uint8_t W25Qxx_OSPI_Read(uint8_t *pData, uint32_t ReadAddr, uint32_t Size);
uint8_t W25Qxx_OSPI_WritePage(uint8_t *pData, uint32_t WriteAddr, uint32_t Size);
void W25Qxx_OSPI_Write(uint8_t* pBuffer,uint32_t WriteAddr,uint32_t Size);
uint8_t W25Qxx_OSPI_Erase_Block(uint32_t BlockAddress);
uint8_t W25Qxx_OSPI_Erase_Chip(void);
uint8_t W25Qxx_OSPI_GetStatus(void);
uint8_t W25Qxx_OSPI_ResetMemory(void);
uint8_t W25Qxx_OSPI_WriteEnable(void);
uint8_t W25Qxx_OSPI_AutoPollingMemReady(uint32_t Timeout);
uint32_t W25Qxx_OSPI_FLASH_ReadDeviceID(void);
uint32_t W25Qxx_OSPI_EnableMemoryMappedMode(void);
#endif /* W25QXX_OSPI_H_ */