HC32F460 系列的四线式串行外设接口(QSPI)是一个存储器控制模块,主要用于和带 SPI 兼容接口的串行 ROM 进行通信,其对象主要包括有串行闪存、串行 EEPROM 以及串行FeRAM。本例程通过QSPI接口实现对QSPI FLASH进行擦除、写入数据和读取数据的操作,将写入和读取出的数据进行对比,将结果通过串口进行打印输出。
QSPI接口的主要特性:
--- 标准读/快速读
--- 二线式输出快速读取/二线式输入输出快速读取
--- 四线式输出快速读取/四线式输入输出快速读取
内存映射:
HC32F460开发板配置了1颗8MB板载QSPI FLASH芯片W25Q64,硬件原理图如下图所示:
/*******************************************************************************
* @file QSPI_FLASH.h
* @author xld0932
* [url=home.php?mod=space&uid=252314]@version[/url] V1.00
* [url=home.php?mod=space&uid=311857]@date[/url] 31-Mar-2021
* [url=home.php?mod=space&uid=159083]@brief[/url] ......
*******************************************************************************/
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __QSPI_FLASH_H__
#define __QSPI_FLASH_H__
#ifdef __cplusplus
extern "C" {
#endif
#undef EXTERN
#ifdef __QSPI_FLASH_C__
#define EXTERN
#else
#define EXTERN extern
#endif
/* Includes ------------------------------------------------------------------*/
#include "config.h"
/* Exported constants --------------------------------------------------------*/
/* Exported types ------------------------------------------------------------*/
/* Exported macro ------------------------------------------------------------*/
/* Exported functions --------------------------------------------------------*/
EXTERN void QSPI_FLASH_Init(void);
EXTERN void QSPI_FLASH_Demo(void);
#ifdef __cplusplus
}
#endif
#endif
/******************* (C) COPYRIGHT 2021 *************************END OF FILE***/
程序源文件:
/*******************************************************************************
* @file QSPI_FLASH.c
* @author xld0932
* @version V1.00
* @date 31-Mar-2021
* @brief ......
*******************************************************************************/
/* Define to prevent recursive inclusion -------------------------------------*/
#define __QSPI_FLASH_C__
/* Includes ------------------------------------------------------------------*/
#include "QSPI_FLASH.h"
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/* QSPI memory bus address definition */
#define QSPI_BUS_ADDRESS (0x98000000ul)
/* FLASH parameters definition */
#define FLASH_PAGE_SIZE (0x100u)
#define FLASH_SECTOR_SIZE (0x1000u)
#define FLASH_MAX_ADDR (0x800000ul)
#define FLASH_DUMMY_BYTE_VALUE (0xFFu)
#define FLASH_BUSY_BIT_MASK (0x01u)
/* FLASH instruction definition */
#define FLASH_INSTR_WRITE_ENABLE (0x06u)
#define FLASH_INSTR_PAGE_PROGRAM (0x02u)
#define FLASH_INSTR_ERASE_4KB_SECTOR (0x20u)
#define FLASH_INSTR_ERASE_CHIP (0xC7u)
#define FLASH_INSTR_READ_SR1 (0x05u)
#define FLASH_INSTR_READ_SR2 (0x35u)
#define FLASH_INSTR_READ_SR3 (0x15u)
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/* Private function prototypes -----------------------------------------------*/
/* Private functions ---------------------------------------------------------*/
/* Exported variables --------------------------------------------------------*/
/* Exported function prototypes ----------------------------------------------*/
/*******************************************************************************
* @brief
* @param
* @retval
* [url=home.php?mod=space&uid=1020061]@attention[/url] *******************************************************************************/
void QSPI_FLASH_Init(void)
{
stc_qspi_init_t stcQspiInit;
/* configuration structure initialization */
MEM_ZERO_STRUCT(stcQspiInit);
/* Configuration peripheral clock */
PWC_Fcg1PeriphClockCmd(PWC_FCG1_PERIPH_QSPI, Enable);
/* Configuration QSPI pin */
PORT_SetFunc(PortC, Pin06, Func_Qspi, Disable);
PORT_SetFunc(PortC, Pin07, Func_Qspi, Disable);
PORT_SetFunc(PortD, Pin08, Func_Qspi, Disable);
PORT_SetFunc(PortD, Pin09, Func_Qspi, Disable);
PORT_SetFunc(PortD, Pin10, Func_Qspi, Disable);
PORT_SetFunc(PortD, Pin11, Func_Qspi, Disable);
/* Configuration QSPI structure */
stcQspiInit.enClkDiv = QspiHclkDiv3;
stcQspiInit.enSpiMode = QspiSpiMode3;
stcQspiInit.enBusCommMode = QspiBusModeRomAccess;
stcQspiInit.enPrefetchMode = QspiPrefetchStopComplete;
stcQspiInit.enPrefetchFuncEn = Disable;
stcQspiInit.enQssnValidExtendTime = QspiQssnValidExtendSck32;
stcQspiInit.enQssnIntervalTime = QspiQssnIntervalQsck8;
stcQspiInit.enQsckDutyCorr = QspiQsckDutyCorrHalfHclk;
stcQspiInit.enVirtualPeriod = QspiVirtualPeriodQsck6;
stcQspiInit.enWpPinLevel = QspiWpPinOutputHigh;
stcQspiInit.enQssnSetupDelayTime = QspiQssnSetupDelay1Dot5Qsck;
stcQspiInit.enQssnHoldDelayTime = QspiQssnHoldDelay1Dot5Qsck;
stcQspiInit.enFourByteAddrReadEn = Disable;
stcQspiInit.enAddrWidth = QspiAddressByteThree;
stcQspiInit.stcCommProtocol.enReadMode = QspiReadModeFourWiresIO;
stcQspiInit.stcCommProtocol.enTransInstrProtocol = QspiProtocolExtendSpi;
stcQspiInit.stcCommProtocol.enTransAddrProtocol = QspiProtocolExtendSpi;
stcQspiInit.stcCommProtocol.enReceProtocol = QspiProtocolExtendSpi;
stcQspiInit.u8RomAccessInstr = QSPI_3BINSTR_FOUR_WIRES_IO_READ;
QSPI_Init(&stcQspiInit);
}
/*******************************************************************************
* @brief
* @param
* @retval
* @attention
*******************************************************************************/
void QSPI_FLASH_WriteEnable(void)
{
QSPI_EnterDirectCommMode();
QSPI_WriteDirectCommValue(FLASH_INSTR_WRITE_ENABLE);
QSPI_ExitDirectCommMode();
}
/*******************************************************************************
* @brief
* @param
* @retval
* @attention
*******************************************************************************/
en_result_t QSPI_FLASH_WaitForWriteEnd(void)
{
en_result_t Result = Ok;
uint8_t Status = 0u;
uint32_t Timeout;
stc_clk_freq_t stcClkFreq;
CLK_GetClockFreq(&stcClkFreq);
Timeout = stcClkFreq.sysclkFreq / 1000u;
QSPI_EnterDirectCommMode();
QSPI_WriteDirectCommValue(FLASH_INSTR_READ_SR1);
do
{
Status = QSPI_ReadDirectCommValue();
Timeout--;
} while((Timeout != 0u) &&
((Status & FLASH_BUSY_BIT_MASK) == FLASH_BUSY_BIT_MASK));
if(FLASH_BUSY_BIT_MASK == Status)
{
Result = ErrorTimeout;
}
QSPI_ExitDirectCommMode();
return Result;
}
/*******************************************************************************
* @brief
* @param
* @retval
* @attention
*******************************************************************************/
en_result_t QSPI_FLASH_WritePage(uint32_t Address, const uint8_t Buffer[], uint16_t Length)
{
en_result_t Result = Ok;
uint16_t Index = 0u;
if((Address > FLASH_MAX_ADDR) || (NULL == Buffer) || (Length > FLASH_PAGE_SIZE))
{
Result = Error;
}
else
{
QSPI_FLASH_WriteEnable();
/* Send data to flash */
QSPI_EnterDirectCommMode();
QSPI_WriteDirectCommValue(FLASH_INSTR_PAGE_PROGRAM);
QSPI_WriteDirectCommValue((uint8_t)((Address & 0x00FF0000ul) >> 16));
QSPI_WriteDirectCommValue((uint8_t)((Address & 0x0000FF00ul) >> 8));
QSPI_WriteDirectCommValue((uint8_t)((Address & 0x000000FFul) >> 0));
while(Length--)
{
QSPI_WriteDirectCommValue(Buffer[Index++]);
}
QSPI_ExitDirectCommMode();
/* Wait for flash idle */
Result = QSPI_FLASH_WaitForWriteEnd();
}
return Result;
}
/*******************************************************************************
* @brief
* @param
* @retval
* @attention
*******************************************************************************/
en_result_t QSPI_FLASH_Erase4KbSector(uint32_t Address)
{
en_result_t Result = Ok;
if(Address >= FLASH_MAX_ADDR)
{
Result = Error;
}
else
{
QSPI_FLASH_WriteEnable();
/* Send instruction to flash */
QSPI_EnterDirectCommMode();
QSPI_WriteDirectCommValue(FLASH_INSTR_ERASE_4KB_SECTOR);
QSPI_WriteDirectCommValue((uint8_t)((Address & 0x00FF0000ul) >> 16));
QSPI_WriteDirectCommValue((uint8_t)((Address & 0x0000FF00ul) >> 8));
QSPI_WriteDirectCommValue((uint8_t)((Address & 0x000000FFul) >> 0));
QSPI_ExitDirectCommMode();
/* Wait for flash idle */
Result = QSPI_FLASH_WaitForWriteEnd();
}
return Result;
}
/*******************************************************************************
* @brief
* @param
* @retval
* @attention
*******************************************************************************/
void QSPI_FLASH_EraseChip(void)
{
QSPI_FLASH_WriteEnable();
/* Send instruction to flash */
QSPI_EnterDirectCommMode();
QSPI_WriteDirectCommValue(FLASH_INSTR_ERASE_CHIP);
QSPI_ExitDirectCommMode();
/* Wait for flash idle */
QSPI_FLASH_WaitForWriteEnd();
}
/*******************************************************************************
* @brief
* @param
* @retval
* @attention
*******************************************************************************/
uint8_t QSPI_FLASH_ReadStatusRegister(uint8_t RegAddress)
{
uint8_t Status = 0u;
QSPI_EnterDirectCommMode();
QSPI_WriteDirectCommValue(RegAddress);
Status = QSPI_ReadDirectCommValue();
QSPI_ExitDirectCommMode();
return Status;
}
/*******************************************************************************
* @brief
* @param
* @retval
* @attention
*******************************************************************************/
void QSPI_FLASH_Demo(void)
{
char TxBuffer[] = "QSPI read and write flash example: Welcome to use HDSC micro chip";
uint8_t *pFlashReadAddr;
stc_qspi_comm_protocol_t stcQspiCommProtocol;
/* configure structure initialization */
MEM_ZERO_STRUCT(stcQspiCommProtocol);
/* Switch to standard read mode */
stcQspiCommProtocol.enReadMode = QspiReadModeStandard;
QSPI_CommProtocolConfig(&stcQspiCommProtocol);
/* Erase sector */
QSPI_FLASH_Erase4KbSector(0);
/* Write data to flash */
QSPI_FLASH_WritePage(0, (uint8_t *)&TxBuffer[0], sizeof(TxBuffer));
/* Switch to four wire i/o fast read mode */
stcQspiCommProtocol.enReadMode = QspiReadModeFourWiresIO;
QSPI_CommProtocolConfig(&stcQspiCommProtocol);
/* Pointer to flash address map */
pFlashReadAddr = (uint8_t *)((uint32_t)QSPI_BUS_ADDRESS + 0);
if(memcmp(TxBuffer, pFlashReadAddr, sizeof(TxBuffer)) != 0)
{
printf("\r\nQSPI Write And Read Failed!!!");
}
else
{
printf("\r\nQSPI Write And Read Success!\r\n");
}
}
/******************* (C) COPYRIGHT 2021 *************************END OF FILE***/
运行结果:
工程源码:
qspi会比spi难上一些,原理虽然懂,但是编程的配置会复杂许多!