当前位置: 首页 > news >正文

stm32F103、GD32F103读写Nor Flash实战指南

 一、NOR Flash基础与硬件连接

1. NOR Flash简介
NOR Flash是一种非易失性存储器,支持随机访问和XIP(Execute In Place)特性,常用于存储固件代码、特定数据。典型型号如GD25Q128(128Mbit容量,SPI接口),其擦写寿命约10万次,适合嵌入式系统扩展存储。

2. GD32F103硬件设计
以SPI接口的GD25Q系列为例:
引脚连接:

GD32F103Nor Flash
PB12CS
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的方式。

相关文章:

  • 吉利矩阵(DFS)
  • [AI]浅谈大模型应用开发的认知构建
  • ecovadis审核有什么原则?什么是ecovadis审核,有什么意义
  • 递归函数详解
  • Langchain-构建向量数据库和检索器
  • 【APM】NET Traces, Metrics and Logs to OLTP
  • 期货数据API对接实战指南
  • win11改回win10
  • 每日一题(小白)暴力娱乐篇31
  • Electricity Market Optimization(VI) - 机组组合问题的 GAMS 求解
  • 论文研读: LLaVA, 微调大模型以理解图像内容
  • pycharm配置python编译器,安装第三方库 (通俗易懂)
  • 【web考试系统的设计】
  • 前端开发 + Vue 2 + 卡片拖拽(带坐标系、左右互拖、多卡同容器)+ 学习参考
  • QT日历控件重写美化
  • T113S3学习记录—软件说明(三)
  • Linux:初学者的简单指令
  • CST仿真天线流程
  • 【Linux】第十章 配置和保护SSH
  • 探索Adobe软件的冷门技巧
  • 法院为“外卖骑手”人身权益撑腰:依法认定实际投保人地位
  • 国家能源局:支持民营企业参股投资核电项目
  • 借助AI应用,自闭症人群开始有可能真正“读懂他人”
  • 中国黄金协会:一季度我国黄金产量同比增1.49%,黄金消费量同比降5.96%
  • 新加坡选情渐热:播客、短视频各显神通,总理反对身份政治
  • 子公司神州信息十年来首次亏损,神州控股遭国有股东广州城投派驻董事问责