stm32F103、GD32F103读写Nor Flash实战指南
一、NOR Flash基础与硬件连接
1. NOR Flash简介
NOR Flash是一种非易失性存储器,支持随机访问和XIP(Execute In Place)特性,常用于存储固件代码、特定数据。典型型号如GD25Q128(128Mbit容量,SPI接口),其擦写寿命约10万次,适合嵌入式系统扩展存储。
2. GD32F103硬件设计
以SPI接口的GD25Q系列为例:
引脚连接:
GD32F103 | Nor Flash |
PB12 | CS |
PB13 (SPI_SCK) | SCLK |
PB14 (SPI_MISO) | SO(Data Out) |
PB15 (SPI_MOSI) | SI (Data IN) |
二、SPI外设配置与驱动开发
1. SPI初始化代码
void SPI_FLASH_Init(void)
{u32 temp;SPI_InitTypeDef SPI_InitStructure;GPIO_InitTypeDef GPIO_InitStructure;/* Enable SPI1 and GPIO clocks *//*!< SPI_FLASH_SPI_CS_GPIO, SPI_FLASH_SPI_MOSI_GPIO, SPI_FLASH_SPI_MISO_GPIO, SPI_FLASH_SPI_DETECT_GPIO and SPI_FLASH_SPI_SCK_GPIO Periph clock enable */RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB | RCC_APB2Periph_GPIOD, ENABLE);/*!< SPI_FLASH_SPI Periph clock enable */RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2, ENABLE);/*!< Configure SPI_FLASH_SPI pins: SCK */GPIO_InitStructure.GPIO_Pin = GPIO_FONT_SPI_SCK;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_InitStructure.GPIO_Mode = GPIO_FONT_SPI_SCK_FLAG;GPIO_Init(GPIO_FONT_SPI, &GPIO_InitStructure);/*!< Configure SPI_FLASH_SPI pins: MISO */GPIO_InitStructure.GPIO_Pin = GPIO_FONT_SPI_MISO;GPIO_Init(GPIO_FONT_SPI, &GPIO_InitStructure);/*!< Configure SPI_FLASH_SPI pins: MOSI */GPIO_InitStructure.GPIO_Pin = GPIO_FONT_SPI_MOSI;GPIO_Init(GPIO_FONT_SPI, &GPIO_InitStructure);/*!< Configure SPI_FLASH_SPI_CS_PIN pin: SPI_FLASH Card CS pin */GPIO_InitStructure.GPIO_Pin = GPIO_FONT_SPI_NSS;GPIO_InitStructure.GPIO_Mode = GPIO_FONT_SPI_NSS_FLAG;GPIO_Init(GPIO_FONT_SPI, &GPIO_InitStructure);/* Deselect the FLASH: Chip Select high */SPI_FLASH_CS_HIGH();/* SPI1 configuration */// W25X16: data input on the DIO pin is sampled on the rising edge of the CLK. // Data on the DO and DIO pins are clocked out on the falling edge of CLK.SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;SPI_InitStructure.SPI_Mode = SPI_Mode_Master;SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;SPI_InitStructure.SPI_CPOL = SPI_CPOL_High;SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_4;SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;SPI_InitStructure.SPI_CRCPolynomial = 7;SPI_Init(SPI2, &SPI_InitStructure);/* Enable SPI1 */SPI_Cmd(SPI2, ENABLE);
//temp = SPI_FLASH_ReadID();
}
根据temp = SPI_FLASH_ReadID()返回的值,可以判断Nor Flash的一些信息,比如型号、容量大小等。
2. NOR Flash控制函数
发送一个字节数据或命令
u8 SPI_FLASH_SendByte(u8 byte)
{/* Loop while DR register in not emplty */while (SPI_I2S_GetFlagStatus(FONT_SPI, SPI_I2S_FLAG_TXE) == RESET);/* Send byte through the SPI1 peripheral */SPI_I2S_SendData(FONT_SPI, byte);/* Wait to receive a byte */while (SPI_I2S_GetFlagStatus(FONT_SPI, SPI_I2S_FLAG_RXNE) == RESET);/* Return the byte read from the SPI bus */return SPI_I2S_ReceiveData(FONT_SPI);
}
发送半字数据
u16 SPI_FLASH_SendHalfWord(u16 HalfWord)
{/* Loop while DR register in not emplty */while (SPI_I2S_GetFlagStatus(FONT_SPI, SPI_I2S_FLAG_TXE) == RESET);/* Send Half Word through the SPI1 peripheral */SPI_I2S_SendData(FONT_SPI, HalfWord);/* Wait to receive a Half Word */while (SPI_I2S_GetFlagStatus(FONT_SPI, SPI_I2S_FLAG_RXNE) == RESET);/* Return the Half Word read from the SPI bus */return SPI_I2S_ReceiveData(FONT_SPI);
}
读取一个字节
u8 SPI_FLASH_ReadByte(void)
{return (SPI_FLASH_SendByte(Dummy_Byte));
}
三、关键操作实现
1. 数据读取(Read Data)
void SPI_FLASH_BufferRead(u8* pBuffer, u32 ReadAddr, u16 NumByteToRead)
{/* Select the FLASH: Chip Select low */SPI_FLASH_CS_LOW();/* Send "Read from Memory " instruction */SPI_FLASH_SendByte(W25X_ReadData);/* Send ReadAddr high nibble address byte to read from */SPI_FLASH_SendByte((ReadAddr & 0xFF0000) >> 16);/* Send ReadAddr medium nibble address byte to read from */SPI_FLASH_SendByte((ReadAddr& 0xFF00) >> 8);/* Send ReadAddr low nibble address byte to read from */SPI_FLASH_SendByte(ReadAddr & 0xFF);while (NumByteToRead--) /* while there is data to be read */{/* Read a byte from the FLASH */*pBuffer = SPI_FLASH_SendByte(Dummy_Byte);/* Point to the next location where the byte read will be saved */pBuffer++;}/* Deselect the FLASH: Chip Select high */SPI_FLASH_CS_HIGH();
}
2. 扇区擦除(Sector Erase)
void SPI_FLASH_SectorErase(u32 SectorAddr)
{/* Send write enable instruction */SPI_FLASH_WriteEnable();SPI_FLASH_WaitForWriteEnd();/* Sector Erase *//* Select the FLASH: Chip Select low */SPI_FLASH_CS_LOW();/* Send Sector Erase instruction */SPI_FLASH_SendByte(W25X_SectorErase);/* Send SectorAddr high nibble address byte */SPI_FLASH_SendByte((SectorAddr & 0xFF0000) >> 16);/* Send SectorAddr medium nibble address byte */SPI_FLASH_SendByte((SectorAddr & 0xFF00) >> 8);/* Send SectorAddr low nibble address byte */SPI_FLASH_SendByte(SectorAddr & 0xFF);/* Deselect the FLASH: Chip Select high */SPI_FLASH_CS_HIGH();/* Wait the end of Flash writing */SPI_FLASH_WaitForWriteEnd();
}
3. 写数据
void SPI_FLASH_BufferWrite(u8* pBuffer, u32 WriteAddr, u16 NumByteToWrite)
{u8 NumOfPage = 0, NumOfSingle = 0, Addr = 0, count = 0, temp = 0;Addr = WriteAddr % SPI_FLASH_PageSize;count = SPI_FLASH_PageSize - Addr;NumOfPage = NumByteToWrite / SPI_FLASH_PageSize;NumOfSingle = NumByteToWrite % SPI_FLASH_PageSize;if (Addr == 0) /* WriteAddr is SPI_FLASH_PageSize aligned */{if (NumOfPage == 0) /* NumByteToWrite < SPI_FLASH_PageSize */{SPI_FLASH_PageWrite(pBuffer, WriteAddr, NumByteToWrite);}else /* NumByteToWrite > SPI_FLASH_PageSize */{while (NumOfPage--){SPI_FLASH_PageWrite(pBuffer, WriteAddr, SPI_FLASH_PageSize);WriteAddr += SPI_FLASH_PageSize;pBuffer += SPI_FLASH_PageSize;}SPI_FLASH_PageWrite(pBuffer, WriteAddr, NumOfSingle);}}else /* WriteAddr is not SPI_FLASH_PageSize aligned */{if (NumOfPage == 0) /* NumByteToWrite < SPI_FLASH_PageSize */{if (NumOfSingle > count) /* (NumByteToWrite + WriteAddr) > SPI_FLASH_PageSize */{temp = NumOfSingle - count;SPI_FLASH_PageWrite(pBuffer, WriteAddr, count);WriteAddr += count;pBuffer += count;SPI_FLASH_PageWrite(pBuffer, WriteAddr, temp);}else{SPI_FLASH_PageWrite(pBuffer, WriteAddr, NumByteToWrite);}}else /* NumByteToWrite > SPI_FLASH_PageSize */{NumByteToWrite -= count;NumOfPage = NumByteToWrite / SPI_FLASH_PageSize;NumOfSingle = NumByteToWrite % SPI_FLASH_PageSize;SPI_FLASH_PageWrite(pBuffer, WriteAddr, count);WriteAddr += count;pBuffer += count;while (NumOfPage--){SPI_FLASH_PageWrite(pBuffer, WriteAddr, SPI_FLASH_PageSize);WriteAddr += SPI_FLASH_PageSize;pBuffer += SPI_FLASH_PageSize;}if (NumOfSingle != 0){SPI_FLASH_PageWrite(pBuffer, WriteAddr, NumOfSingle);}}}
}
四、完整代码
/*********************************************************************************** ÎļþÃû £ºspi_flash.c* ÃèÊö £ºspi µ×²ãÓ¦Óú¯Êý¿â * ʵÑéÆ½Ì¨£ºÒ°»ðSTM32¿ª·¢°å* Ó²¼þÁ¬½Ó ----------------------------* | PA4-SPI1-NSS : W25X16-CS |* | PA5-SPI1-SCK : W25X16-CLK |* | PA6-SPI1-MISO : W25X16-DO |* | PA7-SPI1-MOSI : W25X16-DIO |* ----------------------------* ¿â°æ±¾ £ºST3.5.0* ×÷Õß £º±£Áô * ÂÛ̳ £ºhttp://www.amobbs.com/forum-1008-1.html* ÌÔ±¦ £ºhttp://firestm32.taobao.com
**********************************************************************************/
#include "spi_flash.h"/* Private typedef -----------------------------------------------------------*/
//#define SPI_FLASH_PageSize 4096
#define SPI_FLASH_PageSize 256
#define SPI_FLASH_PerWritePageSize 256/* Private define ------------------------------------------------------------*/
#define W25X_WriteEnable 0x06
#define W25X_WriteDisable 0x04
#define W25X_ReadStatusReg 0x05
#define W25X_WriteStatusReg 0x01
#define W25X_ReadData 0x03
#define W25X_FastReadData 0x0B
#define W25X_FastReadDual 0x3B
#define W25X_PageProgram 0x02
#define W25X_BlockErase 0xD8
#define W25X_SectorErase 0x20
#define W25X_ChipErase 0xC7
#define W25X_PowerDown 0xB9
#define W25X_ReleasePowerDown 0xAB
#define W25X_DeviceID 0xAB
#define W25X_ManufactDeviceID 0x90
#define W25X_JedecDeviceID 0x9F #define WIP_Flag 0x01 /* Write In Progress (WIP) flag */#define Dummy_Byte 0xFF/*******************************************************************************
* Function Name : SPI_FLASH_Init
* Description : Initializes the peripherals used by the SPI FLASH driver.
* Input : None
* Output : None
* Return : None
*******************************************************************************/
void SPI_FLASH_Init(void)
{
#ifdef _DRIVER_IN_u32 temp;
#endif SPI_InitTypeDef SPI_InitStructure;GPIO_InitTypeDef GPIO_InitStructure;/* Enable SPI1 and GPIO clocks *//*!< SPI_FLASH_SPI_CS_GPIO, SPI_FLASH_SPI_MOSI_GPIO, SPI_FLASH_SPI_MISO_GPIO, SPI_FLASH_SPI_DETECT_GPIO and SPI_FLASH_SPI_SCK_GPIO Periph clock enable */RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB | RCC_APB2Periph_GPIOD, ENABLE);/*!< SPI_FLASH_SPI Periph clock enable */RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2, ENABLE);/*!< Configure SPI_FLASH_SPI pins: SCK */GPIO_InitStructure.GPIO_Pin = GPIO_FONT_SPI_SCK;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_InitStructure.GPIO_Mode = GPIO_FONT_SPI_SCK_FLAG;GPIO_Init(GPIO_FONT_SPI, &GPIO_InitStructure);/*!< Configure SPI_FLASH_SPI pins: MISO */GPIO_InitStructure.GPIO_Pin = GPIO_FONT_SPI_MISO;GPIO_Init(GPIO_FONT_SPI, &GPIO_InitStructure);/*!< Configure SPI_FLASH_SPI pins: MOSI */GPIO_InitStructure.GPIO_Pin = GPIO_FONT_SPI_MOSI;GPIO_Init(GPIO_FONT_SPI, &GPIO_InitStructure);/*!< Configure SPI_FLASH_SPI_CS_PIN pin: SPI_FLASH Card CS pin */GPIO_InitStructure.GPIO_Pin = GPIO_FONT_SPI_NSS;GPIO_InitStructure.GPIO_Mode = GPIO_FONT_SPI_NSS_FLAG;GPIO_Init(GPIO_FONT_SPI, &GPIO_InitStructure);/* Deselect the FLASH: Chip Select high */SPI_FLASH_CS_HIGH();/* SPI1 configuration */// W25X16: data input on the DIO pin is sampled on the rising edge of the CLK. // Data on the DO and DIO pins are clocked out on the falling edge of CLK.SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;SPI_InitStructure.SPI_Mode = SPI_Mode_Master;SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;SPI_InitStructure.SPI_CPOL = SPI_CPOL_High;SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_4;SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;SPI_InitStructure.SPI_CRCPolynomial = 7;SPI_Init(SPI2, &SPI_InitStructure);/* Enable SPI1 */SPI_Cmd(SPI2, ENABLE);
#ifdef _DRIVER_IN_temp = SPI_FLASH_ReadID();if ((temp == GD25Q32)||(temp == PY25Q32))MassType = MASS_25Q32;elseMassType = MASS_25Q16;
#elseMassType = MASS_25Q16;
#endif
}
/*******************************************************************************
* Function Name : SPI_FLASH_SectorErase
* Description : Erases the specified FLASH sector.
* Input : SectorAddr: address of the sector to erase.
* Output : None
* Return : None
*******************************************************************************/
void SPI_FLASH_SectorErase(u32 SectorAddr)
{/* Send write enable instruction */SPI_FLASH_WriteEnable();SPI_FLASH_WaitForWriteEnd();/* Sector Erase *//* Select the FLASH: Chip Select low */SPI_FLASH_CS_LOW();/* Send Sector Erase instruction */SPI_FLASH_SendByte(W25X_SectorErase);/* Send SectorAddr high nibble address byte */SPI_FLASH_SendByte((SectorAddr & 0xFF0000) >> 16);/* Send SectorAddr medium nibble address byte */SPI_FLASH_SendByte((SectorAddr & 0xFF00) >> 8);/* Send SectorAddr low nibble address byte */SPI_FLASH_SendByte(SectorAddr & 0xFF);/* Deselect the FLASH: Chip Select high */SPI_FLASH_CS_HIGH();/* Wait the end of Flash writing */SPI_FLASH_WaitForWriteEnd();
}/*******************************************************************************
* Function Name : SPI_FLASH_BlockErase
* Description : Erases the specified FLASH sector.
* Input : SectorAddr: address of the sector to erase.
* Output : None
* Return : None
*******************************************************************************/
void SPI_FLASH_BlockErase(u32 BlockAddr)
{/* Send write enable instruction */SPI_FLASH_WriteEnable();SPI_FLASH_WaitForWriteEnd();/* Sector Erase *//* Select the FLASH: Chip Select low */SPI_FLASH_CS_LOW();/* Send Sector Erase instruction */SPI_FLASH_SendByte(W25X_BlockErase);/* Send SectorAddr high nibble address byte */SPI_FLASH_SendByte((BlockAddr & 0xFF0000) >> 16);/* Send SectorAddr medium nibble address byte */SPI_FLASH_SendByte((BlockAddr & 0xFF00) >> 8);/* Send SectorAddr low nibble address byte */SPI_FLASH_SendByte(BlockAddr & 0xFF);/* Deselect the FLASH: Chip Select high */SPI_FLASH_CS_HIGH();/* Wait the end of Flash writing */SPI_FLASH_WaitForWriteEnd();
}
/*******************************************************************************
* Function Name : SPI_FLASH_BulkErase
* Description : Erases the entire FLASH.
* Input : None
* Output : None
* Return : None
*******************************************************************************/
void SPI_FLASH_BulkErase(void)
{/* Send write enable instruction */SPI_FLASH_WriteEnable();/* Bulk Erase *//* Select the FLASH: Chip Select low */SPI_FLASH_CS_LOW();/* Send Bulk Erase instruction */SPI_FLASH_SendByte(W25X_ChipErase);/* Deselect the FLASH: Chip Select high */SPI_FLASH_CS_HIGH();/* Wait the end of Flash writing */SPI_FLASH_WaitForWriteEnd();
}/*******************************************************************************
* Function Name : SPI_FLASH_PageWrite
* Description : Writes more than one byte to the FLASH with a single WRITE
* cycle(Page WRITE sequence). The number of byte can't exceed
* the FLASH page size.
* Input : - pBuffer : pointer to the buffer containing the data to be
* written to the FLASH.
* - WriteAddr : FLASH's internal address to write to.
* - NumByteToWrite : number of bytes to write to the FLASH,
* must be equal or less than "SPI_FLASH_PageSize" value.
* Output : None
* Return : None
*******************************************************************************/
void SPI_FLASH_PageWrite(u8* pBuffer, u32 WriteAddr, u16 NumByteToWrite)
{/* Enable the write access to the FLASH */SPI_FLASH_WriteEnable();/* Select the FLASH: Chip Select low */SPI_FLASH_CS_LOW();/* Send "Write to Memory " instruction */SPI_FLASH_SendByte(W25X_PageProgram);/* Send WriteAddr high nibble address byte to write to */SPI_FLASH_SendByte((WriteAddr & 0xFF0000) >> 16);/* Send WriteAddr medium nibble address byte to write to */SPI_FLASH_SendByte((WriteAddr & 0xFF00) >> 8);/* Send WriteAddr low nibble address byte to write to */SPI_FLASH_SendByte(WriteAddr & 0xFF);if(NumByteToWrite > SPI_FLASH_PerWritePageSize){NumByteToWrite = SPI_FLASH_PerWritePageSize;//printf("\n\r Err: SPI_FLASH_PageWrite too large!");}/* while there is data to be written on the FLASH */while (NumByteToWrite--){/* Send the current byte */SPI_FLASH_SendByte(*pBuffer);/* Point on the next byte to be written */pBuffer++;}/* Deselect the FLASH: Chip Select high */SPI_FLASH_CS_HIGH();/* Wait the end of Flash writing */SPI_FLASH_WaitForWriteEnd();
}/*******************************************************************************
* Function Name : SPI_FLASH_BufferWrite
* Description : Writes block of data to the FLASH. In this function, the
* number of WRITE cycles are reduced, using Page WRITE sequence.
* Input : - pBuffer : pointer to the buffer containing the data to be
* written to the FLASH.
* - WriteAddr : FLASH's internal address to write to.
* - NumByteToWrite : number of bytes to write to the FLASH.
* Output : None
* Return : None
*******************************************************************************/
void SPI_FLASH_BufferWrite(u8* pBuffer, u32 WriteAddr, u16 NumByteToWrite)
{u8 NumOfPage = 0, NumOfSingle = 0, Addr = 0, count = 0, temp = 0;Addr = WriteAddr % SPI_FLASH_PageSize;count = SPI_FLASH_PageSize - Addr;NumOfPage = NumByteToWrite / SPI_FLASH_PageSize;NumOfSingle = NumByteToWrite % SPI_FLASH_PageSize;if (Addr == 0) /* WriteAddr is SPI_FLASH_PageSize aligned */{if (NumOfPage == 0) /* NumByteToWrite < SPI_FLASH_PageSize */{SPI_FLASH_PageWrite(pBuffer, WriteAddr, NumByteToWrite);}else /* NumByteToWrite > SPI_FLASH_PageSize */{while (NumOfPage--){SPI_FLASH_PageWrite(pBuffer, WriteAddr, SPI_FLASH_PageSize);WriteAddr += SPI_FLASH_PageSize;pBuffer += SPI_FLASH_PageSize;}SPI_FLASH_PageWrite(pBuffer, WriteAddr, NumOfSingle);}}else /* WriteAddr is not SPI_FLASH_PageSize aligned */{if (NumOfPage == 0) /* NumByteToWrite < SPI_FLASH_PageSize */{if (NumOfSingle > count) /* (NumByteToWrite + WriteAddr) > SPI_FLASH_PageSize */{temp = NumOfSingle - count;SPI_FLASH_PageWrite(pBuffer, WriteAddr, count);WriteAddr += count;pBuffer += count;SPI_FLASH_PageWrite(pBuffer, WriteAddr, temp);}else{SPI_FLASH_PageWrite(pBuffer, WriteAddr, NumByteToWrite);}}else /* NumByteToWrite > SPI_FLASH_PageSize */{NumByteToWrite -= count;NumOfPage = NumByteToWrite / SPI_FLASH_PageSize;NumOfSingle = NumByteToWrite % SPI_FLASH_PageSize;SPI_FLASH_PageWrite(pBuffer, WriteAddr, count);WriteAddr += count;pBuffer += count;while (NumOfPage--){SPI_FLASH_PageWrite(pBuffer, WriteAddr, SPI_FLASH_PageSize);WriteAddr += SPI_FLASH_PageSize;pBuffer += SPI_FLASH_PageSize;}if (NumOfSingle != 0){SPI_FLASH_PageWrite(pBuffer, WriteAddr, NumOfSingle);}}}
}
//ÎÞ¼ìÑéдSPI FLASH
//±ØÐëÈ·±£ËùдµÄµØÖ··¶Î§ÄÚµÄÊý¾ÝÈ«²¿Îª0XFF,·ñÔòÔÚ·Ç0XFF´¦Ð´ÈëµÄÊý¾Ý½«Ê§°Ü!
//¾ßÓÐ×Ô¶¯»»Ò³¹¦ÄÜ
//ÔÚÖ¸¶¨µØÖ·¿ªÊ¼Ð´ÈëÖ¸¶¨³¤¶ÈµÄÊý¾Ý,µ«ÊÇҪȷ±£µØÖ·²»Ô½½ç!
//pBuffer:Êý¾Ý´æ´¢Çø
//WriteAddr:¿ªÊ¼Ð´ÈëµÄµØÖ·(24bit)
//NumByteToWrite:ҪдÈëµÄ×Ö½ÚÊý(×î´ó65535)
//CHECK OK
void SPI_Flash_Write_NoCheck(u8* pBuffer,u32 WriteAddr,u16 NumByteToWrite)
{ u16 pageremain; pageremain=256-WriteAddr%256; //µ¥Ò³Ê£ÓàµÄ×Ö½ÚÊý if(NumByteToWrite<=pageremain)pageremain=NumByteToWrite;//²»´óÓÚ256¸ö×Ö½Úwhile(1){ SPI_FLASH_PageWrite(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¸ö×Ö½ÚÁË}};
} u8 SPI_FLASH_BUF[4096];
void SPI_Flash_Read(u8* pBuffer, u32 ReadAddr, u16 NumByteToRead);
void SPI_Flash_Write(u8* pBuffer,u32 WriteAddr,u16 NumByteToWrite)
{ u32 secpos;u16 secoff;u16 secremain; u16 i; secpos=WriteAddr/4096;//ÉÈÇøµØÖ· 0~511 for w25x16secoff=WriteAddr%4096;//ÔÚÉÈÇøÄ򵀮«ÒÆsecremain=4096-secoff;//ÉÈÇøÊ£Óà¿Õ¼ä´óС if(NumByteToWrite<=secremain)secremain=NumByteToWrite;//²»´óÓÚ4096¸ö×Ö½Úwhile(1) { SPI_Flash_Read(SPI_FLASH_BUF,secpos*4096,4096);//¶Á³öÕû¸öÉÈÇøµÄÄÚÈÝfor(i=0;i<secremain;i++)//УÑéÊý¾Ý{if(SPI_FLASH_BUF[secoff+i]!=0XFF)break;//ÐèÒª²Á³ý }if(i<secremain)//ÐèÒª²Á³ý{SPI_FLASH_SectorErase(secpos * 4096);//²Á³ýÕâ¸öÉÈÇøfor(i=0;i<secremain;i++) //¸´ÖÆ{SPI_FLASH_BUF[i+secoff]=pBuffer[i]; }SPI_Flash_Write_NoCheck(SPI_FLASH_BUF,secpos*4096,4096);//дÈëÕû¸öÉÈÇø }else SPI_Flash_Write_NoCheck(pBuffer,WriteAddr,secremain);//дÒѾ²Á³ýÁ˵Ä,Ö±½ÓдÈëÉÈÇøÊ£ÓàÇø¼ä. if(NumByteToWrite==secremain)break;//дÈë½áÊøÁËelse//дÈëδ½áÊø{secpos++;//ÉÈÇøµØÖ·Ôö1secoff=0;//Æ«ÒÆÎ»ÖÃΪ0 pBuffer+=secremain; //Ö¸ÕëÆ«ÒÆWriteAddr+=secremain;//дµØÖ·Æ«ÒÆ NumByteToWrite-=secremain; //×Ö½ÚÊýµÝ¼õif(NumByteToWrite>4096)secremain=4096; //ÏÂÒ»¸öÉÈÇø»¹ÊÇд²»Íêelse secremain=NumByteToWrite; //ÏÂÒ»¸öÉÈÇø¿ÉÒÔдÍêÁË} };
}
/*******************************************************************************
* Function Name : SPI_FLASH_BufferRead
* Description : Reads a block of data from the FLASH.
* Input : - pBuffer : pointer to the buffer that receives the data read
* from the FLASH.
* - ReadAddr : FLASH's internal address to read from.
* - NumByteToRead : number of bytes to read from the FLASH.
* Output : None
* Return : None
*******************************************************************************/
void SPI_FLASH_BufferRead(u8* pBuffer, u32 ReadAddr, u16 NumByteToRead)
{/* Select the FLASH: Chip Select low */SPI_FLASH_CS_LOW();/* Send "Read from Memory " instruction */SPI_FLASH_SendByte(W25X_ReadData);/* Send ReadAddr high nibble address byte to read from */SPI_FLASH_SendByte((ReadAddr & 0xFF0000) >> 16);/* Send ReadAddr medium nibble address byte to read from */SPI_FLASH_SendByte((ReadAddr& 0xFF00) >> 8);/* Send ReadAddr low nibble address byte to read from */SPI_FLASH_SendByte(ReadAddr & 0xFF);while (NumByteToRead--) /* while there is data to be read */{/* Read a byte from the FLASH */*pBuffer = SPI_FLASH_SendByte(Dummy_Byte);/* Point to the next location where the byte read will be saved */pBuffer++;}/* Deselect the FLASH: Chip Select high */SPI_FLASH_CS_HIGH();
}void SPI_Flash_Read(u8* pBuffer, u32 ReadAddr, u16 NumByteToRead)
{SPI_FLASH_BufferRead(pBuffer,ReadAddr,NumByteToRead);return;
}
/*******************************************************************************
* Function Name : SPI_FLASH_ReadID
* Description : Reads FLASH identification.
* Input : None
* Output : None
* Return : FLASH identification
*******************************************************************************/
u32 SPI_FLASH_ReadID(void)
{u32 Temp = 0, Temp0 = 0, Temp1 = 0, Temp2 = 0;/* Select the FLASH: Chip Select low */SPI_FLASH_CS_LOW();/* Send "RDID " instruction */SPI_FLASH_SendByte(W25X_JedecDeviceID);/* Read a byte from the FLASH */Temp0 = SPI_FLASH_SendByte(Dummy_Byte);/* Read a byte from the FLASH */Temp1 = SPI_FLASH_SendByte(Dummy_Byte);/* Read a byte from the FLASH */Temp2 = SPI_FLASH_SendByte(Dummy_Byte);/* Deselect the FLASH: Chip Select high */SPI_FLASH_CS_HIGH();Temp = (Temp0 << 16) | (Temp1 << 8) | Temp2;return Temp;
}
/*******************************************************************************
* Function Name : SPI_FLASH_ReadID
* Description : Reads FLASH identification.
* Input : None
* Output : None
* Return : FLASH identification
*******************************************************************************/
u32 SPI_FLASH_ReadDeviceID(void)
{u32 Temp = 0;/* Select the FLASH: Chip Select low */SPI_FLASH_CS_LOW();/* Send "RDID " instruction */SPI_FLASH_SendByte(W25X_DeviceID);SPI_FLASH_SendByte(Dummy_Byte);SPI_FLASH_SendByte(Dummy_Byte);SPI_FLASH_SendByte(Dummy_Byte);/* Read a byte from the FLASH */Temp = SPI_FLASH_SendByte(Dummy_Byte);/* Deselect the FLASH: Chip Select high */SPI_FLASH_CS_HIGH();return Temp;
}
/*******************************************************************************
* Function Name : SPI_FLASH_StartReadSequence
* Description : Initiates a read data byte (READ) sequence from the Flash.
* This is done by driving the /CS line low to select the device,
* then the READ instruction is transmitted followed by 3 bytes
* address. This function exit and keep the /CS line low, so the
* Flash still being selected. With this technique the whole
* content of the Flash is read with a single READ instruction.
* Input : - ReadAddr : FLASH's internal address to read from.
* Output : None
* Return : None
*******************************************************************************/
void SPI_FLASH_StartReadSequence(u32 ReadAddr)
{/* Select the FLASH: Chip Select low */SPI_FLASH_CS_LOW();/* Send "Read from Memory " instruction */SPI_FLASH_SendByte(W25X_ReadData);/* Send the 24-bit address of the address to read from -----------------------*//* Send ReadAddr high nibble address byte */SPI_FLASH_SendByte((ReadAddr & 0xFF0000) >> 16);/* Send ReadAddr medium nibble address byte */SPI_FLASH_SendByte((ReadAddr& 0xFF00) >> 8);/* Send ReadAddr low nibble address byte */SPI_FLASH_SendByte(ReadAddr & 0xFF);
}/*******************************************************************************
* Function Name : SPI_FLASH_ReadByte
* Description : Reads a byte from the SPI Flash.
* This function must be used only if the Start_Read_Sequence
* function has been previously called.
* Input : None
* Output : None
* Return : Byte Read from the SPI Flash.
*******************************************************************************/
u8 SPI_FLASH_ReadByte(void)
{return (SPI_FLASH_SendByte(Dummy_Byte));
}/*******************************************************************************
* Function Name : SPI_FLASH_SendByte
* Description : Sends a byte through the SPI interface and return the byte
* received from the SPI bus.
* Input : byte : byte to send.
* Output : None
* Return : The value of the received byte.
*******************************************************************************/
u8 SPI_FLASH_SendByte(u8 byte)
{/* Loop while DR register in not emplty */while (SPI_I2S_GetFlagStatus(FONT_SPI, SPI_I2S_FLAG_TXE) == RESET);/* Send byte through the SPI1 peripheral */SPI_I2S_SendData(FONT_SPI, byte);/* Wait to receive a byte */while (SPI_I2S_GetFlagStatus(FONT_SPI, SPI_I2S_FLAG_RXNE) == RESET);/* Return the byte read from the SPI bus */return SPI_I2S_ReceiveData(FONT_SPI);
}/*******************************************************************************
* Function Name : SPI_FLASH_SendHalfWord
* Description : Sends a Half Word through the SPI interface and return the
* Half Word received from the SPI bus.
* Input : Half Word : Half Word to send.
* Output : None
* Return : The value of the received Half Word.
*******************************************************************************/
u16 SPI_FLASH_SendHalfWord(u16 HalfWord)
{/* Loop while DR register in not emplty */while (SPI_I2S_GetFlagStatus(FONT_SPI, SPI_I2S_FLAG_TXE) == RESET);/* Send Half Word through the SPI1 peripheral */SPI_I2S_SendData(FONT_SPI, HalfWord);/* Wait to receive a Half Word */while (SPI_I2S_GetFlagStatus(FONT_SPI, SPI_I2S_FLAG_RXNE) == RESET);/* Return the Half Word read from the SPI bus */return SPI_I2S_ReceiveData(FONT_SPI);
}/*******************************************************************************
* Function Name : SPI_FLASH_WriteEnable
* Description : Enables the write access to the FLASH.
* Input : None
* Output : None
* Return : None
*******************************************************************************/
void SPI_FLASH_WriteEnable(void)
{/* Select the FLASH: Chip Select low */SPI_FLASH_CS_LOW();/* Send "Write Enable" instruction */SPI_FLASH_SendByte(W25X_WriteEnable);/* Deselect the FLASH: Chip Select high */SPI_FLASH_CS_HIGH();
}/*******************************************************************************
* Function Name : SPI_FLASH_WaitForWriteEnd
* Description : Polls the status of the Write In Progress (WIP) flag in the
* FLASH's status register and loop until write opertaion
* has completed.
* Input : None
* Output : None
* Return : None
*******************************************************************************/
void SPI_FLASH_WaitForWriteEnd(void)
{u8 FLASH_Status = 0;/* Select the FLASH: Chip Select low */SPI_FLASH_CS_LOW();/* Send "Read Status Register" instruction */SPI_FLASH_SendByte(W25X_ReadStatusReg);/* Loop as long as the memory is busy with a write cycle */do{/* Send a dummy byte to generate the clock needed by the FLASHand put the value of the status register in FLASH_Status variable */FLASH_Status = SPI_FLASH_SendByte(Dummy_Byte); }while ((FLASH_Status & WIP_Flag) == SET); /* Write in progress *//* Deselect the FLASH: Chip Select high */SPI_FLASH_CS_HIGH();
}//½øÈëµôµçģʽ
void SPI_Flash_PowerDown(void)
{ /* Select the FLASH: Chip Select low */SPI_FLASH_CS_LOW();/* Send "Power Down" instruction */SPI_FLASH_SendByte(W25X_PowerDown);/* Deselect the FLASH: Chip Select high */SPI_FLASH_CS_HIGH();
} //»½ÐÑ
void SPI_Flash_WAKEUP(void)
{/* Select the FLASH: Chip Select low */SPI_FLASH_CS_LOW();/* Send "Power Down" instruction */SPI_FLASH_SendByte(W25X_ReleasePowerDown);/* Deselect the FLASH: Chip Select high */SPI_FLASH_CS_HIGH(); //µÈ´ýTRES1
} /******************************END OF FILE*****************************/
这里说的完整代码并不是整个工程的全部代码,只是与Nor Flash读写有关的代码。
五、总结
通过GD32F103的SPI接口操作NOR Flash,开发者可灵活扩展嵌入式系统的存储能力。本文提供了从底层驱动NOR Flash的方式。