/*******************************************************************************
* W25W256FV 256 M-Bit 32K Byte
*
* 256 Byte One Page
*
*******************************************************************************/
#define CMD_RESET (INT8U)(0x99)
#define CMD_RESETEN (INT8U)(0x66)
#define SET_4BYTEMODE_CMD (INT8U)(0x11) //设置4Byte_Mode
#define WREN_CMD (INT8U)(0x06) //写使能命令 使WEL 位置1;
#define ERASE_ALL_CMD (INT8U)(0x60) //擦除整片
#define ERASE_SECTOR_CMD (INT8U)(0x20) //擦除一个扇区
#define PAGE_WR_CMD (INT8U)(0x02) //页写
#define STAREG1_RD_CMD (INT8U)(0x05) //读状态寄存器1
#define STAREG2_RD_CMD (INT8U)(0x35) //读状态寄存器2
#define STAREG3_RD_CMD (INT8U)(0x15) //读状态寄存器3
#define STAREG3_WT_CMD (INT8U)(0x11) //对状态寄存器3
#define IBU_CMD (INT8U)(0x39) //解除对整个W25Q256的写保护
#define READ_ID_CMD (INT8U)(0x90) //读manu id and device id
#define FLASH_RD_CMD (INT8U)(0x13) //整块Flash读
#define ADDRESS_MAX 0x1FFFFFF
#define READ_ID 0x18
#define OFFSET_64K 1024 * 64 //64K偏移量,用于解锁
#define START_ADDR 0x00000000
#define SECTOR_SIZE 4096 //扇区大小
#define PAGE_SIZE 256 //页大小
void MEM_Init(void);
void MEM_FlashChipErase(void);
void MEM_FlashLock(void);
void MEM_FlashUnLock(void);
void MEM_FlashRead(INT32U Addr,INT8U* pBuff,INT16U tNum);
void MEM_FlashWrite(INT32U Addr,INT8U* pBuff, INT16U tNum);
static void Flash_4ByteModeSet(void);
static void MEM_UnProtect(void);
INT32U Flash_Read_ID(void);
static void Flash_WriteEn(void);
static INT8U Flash_Buff[SECTOR_SIZE]@0x20002000;
void MEM_Test(void)
{
INT8U cConstBuf[16] = {0x22,0x24,0x26,0x78,0x90,
0x22,0x34,0x56,0x78,0x90,
0x22,0x34,0x56,0x78,0x90,0x12};
INT8U cBuff[16];
MEM_Init();
MEM_FlashRead(0x0000,cBuff,16);
MEM_FlashWrite(0x0000,cConstBuf,16);
MEM_FlashRead(0x0000,cBuff,16);
MEM_FlashRead(0x0000,cBuff,16);
}
void MEM_Init(void)
{
Flash_4ByteModeSet();
MEM_UnProtect();
}
void Flash_SndCmd(INT8U cCmd)
{
MCU_MemSPI_CS(IOHILO_LO);
MCU_MemSPI_Snd(&cCmd,1);
MCU_MemSPI_CS(IOHILO_HI);
}
BOOL Flash_ReadMode4(INT8U* pStatus)
{
INT8U cBuff[2];
BOOL bSta;
bSta = FALSE;
cBuff[0] = STAREG3_RD_CMD;
MCU_MemSPI_CS(IOHILO_LO);
MCU_MemSPI_Snd(cBuff, 1); /*发读状态寄存器3 命令*/
MCU_MemSPI_Rcv(pStatus,1);
MCU_MemSPI_CS(IOHILO_HI);
if ((*pStatus) & (1 << 0) == 1) /*判断当前的模式是3Byte还是4Byte*/
{
bSta = TRUE;
}
return bSta;
}
/***********************************************************************
函数名称: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] = STAREG1_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_4ByteModeSet
函数功能:把Flash设置成4字节模式。
*********************************************************************/
static void Flash_4ByteModeSet(void)
{
INT8U cBuff[4];
INT8U status;
if(Flash_ReadMode4(&status)==TRUE)
{
return;
}
while (1)
{
Flash_SndCmd(WREN_CMD);
cBuff[0] = SET_4BYTEMODE_CMD; /*设置4 字节编程模式*/
cBuff[1] = status | (1 << 1); /**** S17置1 ****/
MCU_MemSPI_CS(IOHILO_LO);
MCU_MemSPI_Snd(cBuff,2);
MCU_MemSPI_CS(IOHILO_HI);
FLASH_WaitForWriteEnd(); /*等待写完*/
Flash_SndCmd(CMD_RESETEN);
MCU_DlyXus(1);
Flash_SndCmd(CMD_RESET);
MCU_DlyXus(30);// Delay 30Us
if(Flash_ReadMode4(&status)==TRUE)
{
return ;
}
}/*loop for the 4bye mode set*/
}
/*********************************************************************
函数名称: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 & 0xff000000) >> 24;
cSendCmd[2] = (tWriteAddr & 0xff0000) >> 16;
cSendCmd[3] = (tWriteAddr & 0xff00) >> 8;
cSendCmd[4] = tWriteAddr & 0xff;
MCU_MemSPI_CS(IOHILO_LO);
MCU_MemSPI_Snd(cSendCmd,5);
MCU_MemSPI_CS(IOHILO_HI);
FLASH_WaitForWriteEnd(); //等待擦除完成
}
/************************************************************************
函数名称:Flash_PageWrite
函数功能:Flash 页写
入口参数:
tBuf---------->待发数据指针
tWriteAddr---->发送至Flash的地址(字节对齐)(4字节地址最大2000000(即32M个字节))
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 & 0xff000000) >> 24;
cSendCmd[2] = (tWriteAddr & 0xff0000) >> 16;
cSendCmd[3] = (tWriteAddr & 0xff00) >> 8;
cSendCmd[4] = tWriteAddr & 0xff;
MCU_MemSPI_CS(IOHILO_LO);
MCU_MemSPI_Snd(cSendCmd,5);
MCU_MemSPI_Snd(tBuf,tNum);
MCU_MemSPI_CS(IOHILO_HI);
FLASH_WaitForWriteEnd();
}
/************************************************************************
函数名称:Flash_Write_NoCheck
函数功能:在指定地址开始写入指定长度的数据,但是要确保地址不越界! 具有自动换页功能
注意:在写之前先擦除将要写入的地址
入口参数:
tBuf---------->待发数据指针
tWriteAddr---->发送至Flash的地址(4字节地址最大2000000(即32M个字节))
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 & 0xff000000) >> 24;
cSend[2] = (tReadAddr & 0xff0000) >> 16;
cSend[3] = (tReadAddr & 0xff00) >> 8;
cSend[4] = tReadAddr & 0xff;
MCU_MemSPI_CS(IOHILO_LO);
MCU_MemSPI_Snd(cSend,5);
MCU_MemSPI_Rcv(pBuf, tNum);
MCU_MemSPI_CS(IOHILO_HI);
}
/************************************************************************
函数名称:Spi_UnlockMemery
函数功能:对于W25Q64,上电后要进行解锁操作
入口参数:无
*************************************************************************/
/*The device does't use the protect scheme of the Individual Block Locks by default,
*so there is no neccessary to use the function.
*/
void MEM_FlashUnLock(void)
{
INT8U cBuff[4];
INT32U i;
for (i = 0; i < 64; i++)
{
cBuff[0] = IBU_CMD;
cBuff[1] = START_ADDR + i * OFFSET_64K;
MCU_MemSPI_CS(IOHILO_LO);
MCU_MemSPI_Snd(cBuff, 2);
MCU_MemSPI_CS(IOHILO_HI);
}
}
int MEM_Check(void)
{
INT8U cBuff[8];
INT32U cError;
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, 5);
MCU_MemSPI_Rcv(cBuff,2);
MCU_MemSPI_CS(IOHILO_HI);
if(READ_ID!=cBuff[0])
{
cError = 1;
}
else
{
if(0xEF!=cBuff[1])
{
cError = 2;
}
}
return cError;
}
INT32U Flash_Read_ID(void)
{
INT8U cBuff[8];
INT32U Id;
cBuff[0] = READ_ID_CMD;
cBuff[1] = 0;
cBuff[2] = 0;
cBuff[3] = 0;
cBuff[4] = 0;
MCU_MemSPI_CS(IOHILO_LO);
MCU_MemSPI_Snd(cBuff, 5);
MCU_MemSPI_Rcv(cBuff,2);
MCU_MemSPI_CS(IOHILO_HI);
Id = cBuff[0] << 8;
Id |= cBuff[1];
return Id;
}
/*关闭写独立扇区/块保护*/
static void MEM_UnProtect(void)
{
INT8U cBuff[4];
INT8U status;
do {
cBuff[0] = STAREG3_RD_CMD;
MCU_MemSPI_CS(IOHILO_LO);
MCU_MemSPI_Snd(cBuff, 1);
MCU_MemSPI_Rcv(&status,1);
MCU_MemSPI_CS(IOHILO_HI);
if ((status & (1 << 2)) == 0)
{
return ;
}
Flash_WriteEn();
cBuff[0] = STAREG3_WT_CMD;
cBuff[1] = status & ~(1 << 2);
MCU_MemSPI_CS(IOHILO_LO);
MCU_MemSPI_Snd(cBuff,2);
MCU_MemSPI_CS(IOHILO_HI);
}while (1);
}