318 lines
8.5 KiB
C
318 lines
8.5 KiB
C
#include <string.h>
|
||
#include "w25q256.h"
|
||
|
||
///@brief Flash相关引脚初始化
|
||
void Flash_GPIO_Init(void)
|
||
{
|
||
FLASH_CS_DISABLE;
|
||
FLASH_CLK_HIGH;
|
||
FLASH_MOSI_LOW;
|
||
}
|
||
|
||
///@brief 读取一个字节数据
|
||
static uint8_t Flash_ReadOneByte(void)
|
||
{
|
||
uint8_t retValue = 0;
|
||
|
||
FLASH_CLK_HIGH; //时钟线拉高,恢复时钟线为高电平
|
||
for(uint8_t i= 0; i < 8; i++)
|
||
{
|
||
retValue <<= 1;
|
||
FLASH_CLK_HIGH; //时钟线拉高,恢复时钟线为高电平
|
||
if(FLASH_MISO_READ)
|
||
{
|
||
retValue |= 0x01;
|
||
}
|
||
else
|
||
{
|
||
retValue &= 0xFE;
|
||
}
|
||
FLASH_CLK_LOW; //时钟线拉低,产生下降沿读出数据
|
||
}
|
||
FLASH_CLK_HIGH;
|
||
|
||
return (retValue);
|
||
}
|
||
|
||
///@brief 写入一个字节
|
||
static void Flash_WriteOneByte(uint8_t DataBuffer)
|
||
{
|
||
FLASH_CLK_LOW; //时钟线拉低,恢复时钟线为低电平
|
||
for(uint8_t i = 0; i < 8; i++)
|
||
{
|
||
FLASH_CLK_LOW; //时钟线拉低,恢复时钟线为低电平
|
||
if(DataBuffer & 0x80)
|
||
{
|
||
FLASH_MOSI_HIGH;
|
||
}
|
||
else
|
||
{
|
||
FLASH_MOSI_LOW;
|
||
}
|
||
DataBuffer <<= 1;
|
||
FLASH_CLK_HIGH; //时钟线拉高,产生上升沿写入数据
|
||
}
|
||
FLASH_CLK_LOW;
|
||
FLASH_MOSI_HIGH; //一字节数据传送完毕,MOSI数据线置高表示空闲状态
|
||
}
|
||
|
||
///@brief 写指令
|
||
static void Flash_Write_CMD(uint8_t *pCMD)
|
||
{
|
||
#ifdef FLASH_W25Q256
|
||
for(uint8_t i = 0; i < 4; i++) //new add
|
||
{
|
||
Flash_WriteOneByte(pCMD[i]);
|
||
}
|
||
#endif
|
||
|
||
#ifdef FLASH_W25Q128
|
||
for(uint8_t i = 0; i < 3; i++) //new add
|
||
{
|
||
Flash_WriteOneByte(pCMD[i]);
|
||
}
|
||
#endif
|
||
}
|
||
|
||
///@brief 读取SR
|
||
static uint8_t Flash_ReadSR(void)
|
||
{
|
||
uint8_t retValue = 0;
|
||
|
||
FLASH_CS_ENABLE;
|
||
Flash_WriteOneByte(Flash_ReadSR_CMD);
|
||
retValue = Flash_ReadOneByte();
|
||
FLASH_CS_DISABLE;
|
||
|
||
return retValue;
|
||
}
|
||
|
||
///@brief 等待标志位
|
||
static void Flash_Wait_Busy(void)
|
||
{
|
||
uint32_t i =0;
|
||
|
||
while(((Flash_ReadSR() & FLASH_WRITE_BUSYBIT) == 0x01) && (i<0x1ffff))
|
||
{
|
||
i ++;
|
||
}
|
||
}
|
||
|
||
///@brief 写使能
|
||
static void Flash_Write_Enable(void)
|
||
{
|
||
FLASH_CS_ENABLE;
|
||
Flash_WriteOneByte(Flash_WriteEnable_CMD);
|
||
FLASH_CS_DISABLE;
|
||
}
|
||
|
||
#if 0
|
||
///@brief 进入4字节模式
|
||
void Enter4ByteAddrMode(void)
|
||
{
|
||
FLASH_CS_ENABLE; //使能器件
|
||
Flash_WriteOneByte(W25Q_4ByteAddrModeEnable); //进入4Byte地址模式W25Q128以上使用
|
||
FLASH_CS_DISABLE;
|
||
}
|
||
|
||
///@brief 退出4字节模式
|
||
void Exit4ByteAddrMode(void)
|
||
{
|
||
FLASH_CS_ENABLE; //使能器件
|
||
Flash_WriteOneByte(W25Q_Exit4ByteAddrModeEnable); //进入4Byte地址模式W25Q128以上使用
|
||
FLASH_CS_DISABLE;
|
||
}
|
||
#endif
|
||
|
||
///@brief 擦除区域
|
||
void Flash_Erase_Sector(uint8_t Block_Num,uint8_t Sector_Number)
|
||
{
|
||
uint8_t pcmd[3] = {0};
|
||
Flash_Write_Enable();
|
||
FLASH_CS_ENABLE;
|
||
Flash_WriteOneByte(Flash_SecErase_CMD);
|
||
|
||
pcmd[0] = Block_Num;
|
||
pcmd[1] = Sector_Number<<4;
|
||
pcmd[2] = 0;
|
||
Flash_Write_CMD(pcmd);
|
||
FLASH_CS_DISABLE;
|
||
Flash_Wait_Busy();//每次擦除数据都要延时等待写入结束
|
||
|
||
return ;
|
||
}
|
||
|
||
///@brief 擦除块
|
||
void Flash_Erase_Block(uint8_t BlockNum)
|
||
{
|
||
|
||
uint8_t pcmd[3] = {0};
|
||
Flash_Write_Enable(); //写使能
|
||
FLASH_CS_ENABLE; //片选拉低
|
||
Flash_WriteOneByte(Flash_BlockErase_CMD); //传输Block擦除指令
|
||
pcmd[0] = BlockNum ; //传24位地址
|
||
Flash_Write_CMD(pcmd);
|
||
FLASH_CS_DISABLE;
|
||
Flash_Wait_Busy(); //每次擦除数据都要延时等待写入结束
|
||
|
||
return ;
|
||
}
|
||
|
||
///@brief 页写
|
||
void Flash_Write_Page(uint8_t *pBuffer, uint32_t WriteAddr, uint32_t WriteBytesNum)
|
||
{
|
||
uint8_t pcmd[4] = {0};
|
||
|
||
Flash_Write_Enable();
|
||
FLASH_CS_ENABLE;
|
||
Flash_WriteOneByte(Flash_PageProgram_CMD);
|
||
#ifdef FLASH_W25Q256
|
||
pcmd[0] = (uint8_t)((WriteAddr&0xff000000)>>24); //new add
|
||
pcmd[1] = (uint8_t)((WriteAddr&0x00ff0000)>>16);
|
||
pcmd[2] = (uint8_t)((WriteAddr&0x0000ff00)>>8);
|
||
pcmd[3] = (uint8_t)WriteAddr;
|
||
#endif
|
||
|
||
#ifdef FLASH_W25Q128
|
||
pcmd[0] = (uint8_t)((WriteAddr&0x00ff0000)>>16);
|
||
pcmd[1] = (uint8_t)((WriteAddr&0x0000ff00)>>8);
|
||
pcmd[2] = (uint8_t)WriteAddr;
|
||
#endif
|
||
|
||
Flash_Write_CMD(pcmd);
|
||
|
||
for(uint32_t i = 0;i < WriteBytesNum; i++)
|
||
{
|
||
|
||
Flash_WriteOneByte(pBuffer[i]); //向Flash中写入最大一页256bytes字节数据
|
||
}
|
||
FLASH_CS_DISABLE;
|
||
Flash_Wait_Busy(); //每次写入一定数量的数据都要延时等待写入结束
|
||
return;
|
||
}
|
||
|
||
///@brief 连续写入多页
|
||
void Flash_Write_MorePage(uint8_t *pBuffer, uint32_t WriteAddr, uint32_t WriteBytesNum)
|
||
{
|
||
uint16_t PageByteRemain = 0;
|
||
PageByteRemain = Flash_PAGEBYTE_LENGTH - WriteAddr%Flash_PAGEBYTE_LENGTH;
|
||
if(WriteBytesNum <= PageByteRemain)
|
||
{
|
||
PageByteRemain = WriteBytesNum;
|
||
}
|
||
while(1)
|
||
{
|
||
Flash_Write_Page(pBuffer,WriteAddr,PageByteRemain);
|
||
if(WriteBytesNum == PageByteRemain)
|
||
{
|
||
break;
|
||
}
|
||
else
|
||
{
|
||
pBuffer += PageByteRemain;
|
||
WriteAddr += PageByteRemain;
|
||
WriteBytesNum -= PageByteRemain;
|
||
if(WriteBytesNum > Flash_PAGEBYTE_LENGTH)
|
||
{
|
||
PageByteRemain = Flash_PAGEBYTE_LENGTH;
|
||
}
|
||
else
|
||
{
|
||
PageByteRemain = WriteBytesNum;
|
||
}
|
||
}
|
||
}
|
||
|
||
return;
|
||
}
|
||
|
||
///@brief 连续写入多页
|
||
uint8_t W25QXX_BUFFER[4096];
|
||
void W25Q128_Write(uint8_t *pBuffer, uint32_t WriteAddr, uint32_t WriteBytesNum)
|
||
{
|
||
// volatile static int timeReadTemp1, timeReadTemp2, timeReadTemp3, timeReadTemp4, timeReadTemp5, timeReadTemp6;
|
||
|
||
uint32_t secpos;
|
||
uint16_t secoff;
|
||
uint16_t secremain;
|
||
uint16_t i;
|
||
uint8_t *W25QXX_BUF;
|
||
W25QXX_BUF = W25QXX_BUFFER;
|
||
secpos = WriteAddr / 4096; //扇区地址
|
||
secoff = WriteAddr % 4096; //在扇区内的偏移
|
||
secremain = 4096 - secoff; //扇区剩余空间大小
|
||
if (WriteBytesNum <= secremain)
|
||
secremain = WriteBytesNum; //不大于4096个字节
|
||
while (1)
|
||
{
|
||
// timeReadTemp1 = HAL_GetTick();
|
||
Flash_Read(W25QXX_BUF, secpos * 4096, 4096); //读出整个扇区的内容
|
||
// timeReadTemp2 = HAL_GetTick();
|
||
for (i = 0; i < secremain; i++) //校验数据
|
||
{
|
||
if (W25QXX_BUF[secoff + i] != 0XFF)
|
||
break; //需要擦除
|
||
}
|
||
if (i < secremain) //需要擦除
|
||
{
|
||
Flash_Erase_Block(secpos); //擦除这个扇区
|
||
// timeReadTemp3 = HAL_GetTick();
|
||
for (i = 0; i < secremain; i++) //复制
|
||
{
|
||
W25QXX_BUF[i + secoff] = pBuffer[i];
|
||
}
|
||
Flash_Write_Page(W25QXX_BUF, secpos * 4096, 4096); //写入整个扇区
|
||
// timeReadTemp4 = HAL_GetTick();
|
||
// timeReadTemp5 = NumByteToWrite;
|
||
// timeReadTemp6 = WriteAddr;
|
||
}
|
||
else
|
||
Flash_Write_Page(pBuffer, WriteAddr, secremain); //写已经擦除了的,直接写入扇区剩余区间.
|
||
if (WriteBytesNum == secremain)
|
||
break; //写入结束了
|
||
else //写入未结束
|
||
{
|
||
secpos++; //扇区地址增1
|
||
secoff = 0; //偏移位置为0
|
||
|
||
pBuffer += secremain; //指针偏移
|
||
WriteAddr += secremain; //写地址偏移
|
||
WriteBytesNum -= secremain; //字节数递减
|
||
if (WriteBytesNum > 4096)
|
||
secremain = 4096; //下一个扇区还是写不完
|
||
else
|
||
secremain = WriteBytesNum; //下一个扇区可以写完了
|
||
}
|
||
};
|
||
}
|
||
|
||
///@brief 读取数据
|
||
void Flash_Read(uint8_t *pBuffer,uint32_t ReadAddr,uint32_t ReadBytesNum)
|
||
{
|
||
uint8_t pcmd[4] = {0};
|
||
FLASH_CS_ENABLE; //打开spiflash片选
|
||
Flash_WriteOneByte(Flash_ReadData_CMD);
|
||
#ifdef FLASH_W25Q256
|
||
pcmd[0] = (uint8_t)((ReadAddr&0xff000000)>>24); //new add
|
||
pcmd[1] = (uint8_t)((ReadAddr&0x00ff0000)>>16);
|
||
pcmd[2] = (uint8_t)((ReadAddr&0x0000ff00)>>8);
|
||
pcmd[3] = (uint8_t)ReadAddr;
|
||
#endif
|
||
|
||
#ifdef FLASH_W25Q128
|
||
pcmd[0] = (uint8_t)((ReadAddr&0x00ff0000)>>16);
|
||
pcmd[1] = (uint8_t)((ReadAddr&0x0000ff00)>>8);
|
||
pcmd[2] = (uint8_t)ReadAddr;
|
||
#endif
|
||
|
||
Flash_Write_CMD(pcmd);
|
||
|
||
for(uint32_t i = 0;i < ReadBytesNum; i++)
|
||
{
|
||
pBuffer[i] = Flash_ReadOneByte(); //读取SPIflash中指定bytes字节数据
|
||
|
||
}
|
||
FLASH_CS_DISABLE;
|
||
|
||
return ;
|
||
} |