/*******************************************************************************
* GD25Q32C 32 M-Bit 4M Byte
*
* 256 Byte One Page
*
*******************************************************************************/
#include "DataType.h"
#include "McuSpiMem.h"
#include "mcuDrv.h"
#define CMD_RESET (INT8U)(0x99)
#define CMD_RESETEN (INT8U)(0x66)
#define WREN_CMD (INT8U)(0x06) //写使能命令 使WEL 位置1;
#define ERASE_ALL_CMD (INT8U)(0xc7) //擦除整片
#define ERASE_SECTOR_CMD (INT8U)(0x20) //擦除一个扇区
#define PAGE_WR_CMD (INT8U)(0x02) //页写
#define READ_ID_CMD (INT8U)(0x90) //读manu id and device id
#define FLASH_RD_CMD (INT8U)(0x03)
#define STAREG_WT_CMD (INT8U)(0x01) //写状态寄存器
#define STAREG_RD_CMD (INT8U)(0x05) //读状态寄存器
#define STAREG_WREN_CMD (INT8U)(0x50) //状态寄存器写使能
#define ADDRESS_MAX 0x3fffff
#define READ_ID 0x15
#define OFFSET_64K 1024 * 64 //64K偏移量,用于解锁
#define START_ADDR 0x00000000
#define SECTOR_SIZE 4096 //扇区大小
#define PAGE_SIZE 256 //页大小
void MEM_FlashInit(void);
void MEM_FlashChipErase(void);
void MEM_FlashRead(INT32U Addr,INT8U* pBuff,INT16U tNum);
void MEM_FlashWrite(INT32U Addr,INT8U* pBuff, INT16U tNum);
static void MEM_UnProtect(void);
static void Flash_WriteEn(void);
INT8U FLASH_ReadStatusRegister(void);
BOOL FLASH_WriteStatusRegister(INT8U cSta);
static INT8U Flash_Buff[SECTOR_SIZE]@0x20002000;
void MEM_FLASH_Test(void)
{
INT8U cConstBuf[16] = {
0x21,0x24,0x26,0x78,0x90,
0x22,0x34,0x56,0x78,0x90,
0x22,0x34,0x56,0x78,0x90,
0x11};
INT8U cBuff[16];
//MEM_FlashInit();
//MEM_FlashChipErase();
//MEM_UnProtect();
MEM_FlashRead(0x000000,cBuff,16);
MEM_FlashWrite(0x000000,cConstBuf,16);
MEM_FlashRead(0x000000,cBuff,16);
}
void MEM_FlashInit(void)
{
//Flash_4ByteModeSet();
//MEM_UnProtect();
INT8U staReg;
staReg = FLASH_ReadStatusRegister();
FLASH_WriteStatusRegister(0);
staReg = FLASH_ReadStatusRegister();
MEM_Check();
}
void Flash_SndCmd(INT8U cCmd)
{
MCU_MemSPI_CS(IOHILO_LO);
MCU_MemSPI_Snd(&cCmd,1);
MCU_MemSPI_CS(IOHILO_HI);
}
/***********************************************************************
函数名称:Flash_WriteEn
函数功能:SPI写使能
入口参数:无
出口参数:无
************************************************************************/
static void Flash_WriteEn(void)
{
INT8U Cmd;
MCU_MemSPI_CS(IOHILO_LO);
Cmd = WREN_CMD;
MCU_MemSPI_Snd(&Cmd,1);
MCU_MemSPI_CS(IOHILO_HI);
}
/**************************************************************************
函数名称:FLASH_WaitForWriteEnd
函数功能:读Flash芯片状态寄存器的值并且循环读取标志位直到写周期结束
入口参数:无
出口参数:无
*************************************************************************/
static void FLASH_WaitForWriteEnd(void)
{
INT8U cBuff[4];
cBuff[0] = STAREG_RD_CMD;
MCU_MemSPI_CS(IOHILO_LO);
MCU_MemSPI_Snd(cBuff,1); //读取Flash 状态寄存器1
do
{
MCU_MemSPI_Rcv(cBuff,1); //读状态寄存器的数据;
}while ((cBuff[0] & 0x01) == 0x01); //若没有写完则一直等待,保持CS=0
MCU_MemSPI_CS(IOHILO_HI);
}
/*********************************************************************
函数名称:Flash_ChipErase
函数功能:整片擦除
*********************************************************************/
void MEM_FlashChipErase(void)
{
INT8U cCmdBuff[4];
Flash_WriteEn();
cCmdBuff[0] = ERASE_ALL_CMD;
MCU_MemSPI_CS(IOHILO_LO);
MCU_MemSPI_Snd(cCmdBuff,1);
MCU_MemSPI_CS(IOHILO_HI);
//等待擦除完成
FLASH_WaitForWriteEnd();
}
/************************************************************************
函数名称:Flash_Sector_Erase
函数功能:Flash的扇区擦除
入口参数:@Sector_Num: 将要擦除的扇区号
*************************************************************************/
void MEM_FlashEraseSector(INT16U Sector_Num)
{
INT8U cSendCmd[8];
INT32U tWriteAddr;
tWriteAddr = Sector_Num * SECTOR_SIZE;
Flash_WriteEn();
cSendCmd[0] = ERASE_SECTOR_CMD;
cSendCmd[1] = (tWriteAddr & 0xff0000) >> 16;
cSendCmd[2] = (tWriteAddr & 0xff00) >> 8;
cSendCmd[3] = tWriteAddr & 0xff;
MCU_MemSPI_CS(IOHILO_LO);
MCU_MemSPI_Snd(cSendCmd,4);
MCU_MemSPI_CS(IOHILO_HI);
FLASH_WaitForWriteEnd(); //等待擦除完成
}
/************************************************************************
函数名称:Flash_PageWrite
函数功能:Flash 页写
入口参数:
tBuf---------->待发数据指针
tWriteAddr---->发送至Flash的地址(字节对齐)(4字节地址最大0X3FFFFF(即4M个字节))
tNum---------->发送数据个数(最大256个)
*************************************************************************/
static void Flash_PageWrite(INT8U* tBuf,INT32U tWriteAddr,INT16U tNum)
{
INT8U cSendCmd[8];
if (tWriteAddr > ADDRESS_MAX)
return ;
Flash_WriteEn();
cSendCmd[0] = PAGE_WR_CMD;
cSendCmd[1] = (tWriteAddr & 0xff0000) >> 16;
cSendCmd[2] = (tWriteAddr & 0xff00) >> 8;
cSendCmd[3] = tWriteAddr & 0xff;
MCU_MemSPI_CS(IOHILO_LO);
MCU_MemSPI_Snd(cSendCmd,4);
MCU_MemSPI_Snd(tBuf,tNum);
MCU_MemSPI_CS(IOHILO_HI);
FLASH_WaitForWriteEnd();
}
/************************************************************************
函数名称:Flash_Write_NoCheck
函数功能:在指定地址开始写入指定长度的数据,但是要确保地址不越界! 具有自动换页功能
注意:在写之前先擦除将要写入的地址
入口参数:
tBuf---------->待发数据指针
tWriteAddr---->发送至Flash的地址(4字节地址最大3FFFFF(即4M个字节))
tNum---------->发送数据个数(65536)
返回值:
*************************************************************************/
static void Flash_Write_NoCheck(INT8U* pBuffer, INT32U WriteAddr, INT32U NumByteToWrite)
{
INT16U Page_Remain;
Page_Remain = PAGE_SIZE - WriteAddr % PAGE_SIZE; //计算当前页剩余字节数;
if (NumByteToWrite <= Page_Remain)
{
Page_Remain = NumByteToWrite;
}
while (1)
{
Flash_PageWrite(pBuffer, WriteAddr, Page_Remain);
if (NumByteToWrite == Page_Remain)
{
break; /*表示当前数据已经写完*/
}
else
{
pBuffer += Page_Remain;
WriteAddr += Page_Remain;
NumByteToWrite -= Page_Remain;
if (NumByteToWrite > PAGE_SIZE)
{
Page_Remain = PAGE_SIZE; //将写入数据大于256个
}
else
{
Page_Remain = NumByteToWrite; //将写数据不足256个
}
}
}
}
/************************************************************************
函数名称:Flash_Write
函数功能:在指定地址开始写入指定长度的数据(该函数带擦除操作!);
入口参数:
pBuffer---------->数据缓冲区指针
WriteAddr---->任意Flash地址,不用担心该地址处是否已经擦除
NumByteToWrite---------->将写入到数据个数(最大65535即一个Block大小)
*************************************************************************/
void MEM_FlashWrite(INT32U WriteAddr, INT8U *pBuffer, INT16U NumByteToWrite)
{
INT32U i;
INT32U Sector_Addr;
INT32U Sector_Num;
INT32U Sector_Offest;
INT32U Sector_Remain;
/*calculate the beginning address of the current sector*/
Sector_Addr = (WriteAddr / SECTOR_SIZE) * SECTOR_SIZE;
/*calculate the Sector number according to the WriteAddr*/
Sector_Num = WriteAddr / SECTOR_SIZE;
/*calculate the offest number of the sector*/
Sector_Offest = WriteAddr % SECTOR_SIZE;
/*calculate the remain of the sector*/
Sector_Remain = SECTOR_SIZE - Sector_Offest;
if (NumByteToWrite <= Sector_Remain)
Sector_Remain = NumByteToWrite;
while (1)
{
/*copy the data writen previously into the sector to Flash_Buff*/
MEM_FlashRead(Sector_Addr, Flash_Buff, SECTOR_SIZE);
for(i = 0; i < Sector_Remain; i++)
{
if (Flash_Buff[Sector_Offest + i] != 0xFF) break; //表明需要擦除
}
if(i < Sector_Remain)
{
/*erase the Sector_Num*/
MEM_FlashEraseSector(Sector_Num);
for(i = 0; i < Sector_Remain; i++)
Flash_Buff[Sector_Offest + i] = pBuffer[i];
/*write the data including previous data and the portion of new input data into the whole sector*/
Flash_Write_NoCheck(Flash_Buff, Sector_Addr, SECTOR_SIZE);
}
else
{
Flash_Write_NoCheck(pBuffer, WriteAddr, Sector_Remain);
}
if (NumByteToWrite == Sector_Remain)
break;
else
{
Sector_Addr += SECTOR_SIZE;
Sector_Num++; //下一个扇区号
Sector_Offest = 0;
pBuffer += Sector_Remain;
NumByteToWrite -=Sector_Remain;
Sector_Remain = SECTOR_SIZE; //默认写入4096个字节
if (NumByteToWrite < SECTOR_SIZE) Sector_Remain = NumByteToWrite; //当此次写入的数据不足一个扇区大小时。
}
}
}
/************************************************************************
函数名称:Flash_Read
函数功能:在整个Flash 范围内读取任意指定的地址开始处的数据
入口参数:
pBuf---------->接收数据缓冲区指针
tWriteAddr---->读取的Flash地址
tNum---------->读取数据个数
*************************************************************************/
void MEM_FlashRead(INT32U tReadAddr, INT8U* pBuf, INT16U tNum)
{
INT8U cSend[8];
cSend[0] = FLASH_RD_CMD;
cSend[1] = (tReadAddr & 0xff0000) >> 16;
cSend[2] = (tReadAddr & 0xff00) >> 8;
cSend[3] = tReadAddr & 0xff;
MCU_MemSPI_CS(IOHILO_LO);
MCU_MemSPI_Snd(cSend,4);
MCU_MemSPI_Rcv(pBuf, tNum);
MCU_MemSPI_CS(IOHILO_HI);
}
int MEM_Check(void)
{
INT8U cBuff[8];
INT32U cError=0;
cError = 0;
cBuff[0] = READ_ID_CMD;
cBuff[1] = 0;
cBuff[2] = 0;
cBuff[3] = 0;
MCU_MemSPI_CS(IOHILO_LO);
MCU_MemSPI_Snd(cBuff, 4);
MCU_MemSPI_Rcv(cBuff,2);
MCU_MemSPI_CS(IOHILO_HI);
if(0xc8 !=cBuff[0])
{
cError = 1;
}
else
{
if(READ_ID!=cBuff[1])
{
cError = 2;
}
}
return cError;
}
/*关闭写独立扇区/块保护*/
static void MEM_UnProtect(void)
{
INT8U cBuff[4];
INT8U status;
do {
cBuff[0] = STAREG_RD_CMD;
MCU_MemSPI_CS(IOHILO_LO);
MCU_MemSPI_Snd(cBuff, 1);
MCU_MemSPI_Rcv(&status,1);
MCU_MemSPI_CS(IOHILO_HI);
if ((status & (0x18)) == (0x18))
{
return ;
}
Flash_WriteEn();
cBuff[0] = STAREG_WT_CMD;
cBuff[1] = (status|0x18);
MCU_MemSPI_CS(IOHILO_LO);
MCU_MemSPI_Snd(cBuff,2);
MCU_MemSPI_CS(IOHILO_HI);
}while (1);
}
INT8U FLASH_ReadStatusRegister(void)
{
INT8U cBuff[4];
cBuff[0] = STAREG_RD_CMD;
MCU_MemSPI_CS(IOHILO_LO);
MCU_MemSPI_Snd(cBuff, 1);
MCU_MemSPI_Rcv(cBuff,1);
MCU_MemSPI_CS(IOHILO_HI);
return cBuff[0];
}
BOOL FLASH_WriteStatusRegister(INT8U cSta)
{
INT8U cBuff[4];
cBuff[0] = STAREG_WREN_CMD;
MCU_MemSPI_CS(IOHILO_LO);
MCU_MemSPI_Snd(cBuff, 1);
MCU_MemSPI_CS(IOHILO_HI);
Flash_WriteEn();
cBuff[0] = STAREG_WT_CMD;
cBuff[1] = cSta;
MCU_MemSPI_CS(IOHILO_LO);
MCU_MemSPI_Snd(cBuff, 2);
MCU_MemSPI_CS(IOHILO_HI);
return TRUE;
}
INT8U FLASH_IsBusy(void)
{
INT8U cBuff[4];
INT8U timeOutCnt = 0;
cBuff[0] = STAREG_RD_CMD;
MCU_MemSPI_CS(IOHILO_LO);
MCU_MemSPI_Snd(cBuff,1); //读取Flash 状态寄存器1
do
{
MCU_MemSPI_Rcv(cBuff,1); //读状态寄存器的数据;
if(++timeOutCnt >= 8)
{
break;
}
}while ((cBuff[0] & 0x01) == 0x01); //若没有写完则一直等待,保持CS=0
MCU_MemSPI_CS(IOHILO_HI);
if(timeOutCnt >= 8)
{
return 1;
}
return 0;
}
GD25Q32C FLASH DRV
于 2022-04-07 10:27:18 首次发布