/*************************************************************************************************************************
* 函数 : bool W25QxxJV_Write(W25QxxJV_HANDLE *pHandle,u8* pBuffer,u32 WriteAddr,u16 NumByteToWrite)
* 功能 : 写SPI FLASH 在指定地址开始写入指定长度的数据
* 参数 : pHandle:句柄,pBuffer :数据存储区
WriteAddr:开始写入的地址(24bit)
NumByteToWrite:要写入的字节数(最大65535)
* 返回 : 无
* 依赖 : 底层读写函数
* 作者 : cp1300@139.com
* 时间 : 20110630
* 最后修改时间 : 2021-08-25
* 说明 : 该函数带擦除操作!
该函数需要的堆栈很大,注意
*************************************************************************************************************************/
bool W25QxxJV_Write(W25QxxJV_HANDLE *pHandle,u8* pBuffer,u32 WriteAddr,u16 NumByteToWrite)
{
u32 secpos;
u16 secoff;
u16 secremain;
u16 i;
secpos = WriteAddr / 4096; //扇区地址 0~511 for W25Q16
secoff = WriteAddr % 4096; //在扇区内的偏移
secremain = 4096 - secoff; //扇区剩余空间大小
if(NumByteToWrite <= secremain)
secremain = NumByteToWrite; //不大于4096个字节
while(1)
{
W25QxxJV_Read(pHandle,pHandle->SwapBuff,secpos*4096,4096);//读出整个扇区的内容
for(i = 0;i < secremain;i ++) //校验数据
{
if(pHandle->SwapBuff[secoff+i] != 0xff)break; //需要擦除
}
if(i < secremain) //需要擦除
{
if(W25QxxJV_EraseSector(pHandle,secpos)==FALSE) //擦除这个扇区
{
return FALSE;
}
for(i = 0;i < secremain;i ++) //复制
{
pHandle->SwapBuff[i + secoff] = pBuffer;
}
if(W25QxxJV_WriteNoCheck(pHandle,pHandle->SwapBuff,secpos*4096,4096)==FALSE)//写入整个扇区
{
return FALSE;
}
}
else
{
if(W25QxxJV_WriteNoCheck(pHandle,pBuffer,WriteAddr,secremain)==FALSE)//写已经擦除了的,直接写入扇区剩余区间.
{
return FALSE;
}
}
if(NumByteToWrite==secremain) break; //写入结束了
else//写入未结束
{
secpos ++; //扇区地址增1
secoff = 0; //偏移位置为0
pBuffer += secremain; //指针偏移
WriteAddr += secremain; //写地址偏移
NumByteToWrite -= secremain; //字节数递减
if(NumByteToWrite > 4096)
secremain = 4096; //下一个扇区还是写不完
else
secremain = NumByteToWrite; //下一个扇区可以写完了
}
}
return TRUE;
}
/*************************************************************************************************************************
* 函数 : bool W25QxxJV_WriteAboveOneSector(W25QxxJV_HANDLE *pHandle,u8* pBuffer,u32 WriteAddr,u16 NumByteToWrite)
* 功能 : 写SPI FLASH 在指定地址开始使用增量方式写入指定长度的数据(保留之前的数据,会清除当前地址之后的数据,只能在一个扇区范围内)
* 参数 : pHandle:句柄,pBuffer :数据存储区
WriteAddr:开始写入的地址(24bit)
NumByteToWrite:要写入的字节数(最大65535)
* 返回 : 无
* 依赖 : 底层读写函数
* 作者 : cp1300@139.com
* 时间 : 20110630
* 最后修改时间 : 2021-08-25
* 说明 : 该函数带擦除操作,不会判断是否需要擦除,会直接执行擦除操作!
该函数需要的堆栈很大,注意
只会将当前地址之前的数据进行重写写入,并且写入当前的数据,之后的数据将不会进行还原,不能超出一个扇区范围
*************************************************************************************************************************/
bool W25QxxJV_WriteAboveOneSector(W25QxxJV_HANDLE *pHandle,u8* pBuffer,u32 WriteAddr,u16 NumByteToWrite)
{
u32 secpos;
u16 secoff;
u16 secremain;
u16 i;
secpos = WriteAddr / 4096; //扇区地址 0~511 for W25Q16
secoff = WriteAddr % 4096; //在扇区内的偏移
secremain = 4096 - secoff; //扇区剩余空间大小
if(NumByteToWrite > secremain)
NumByteToWrite = secremain; //不大于剩余空间
W25QxxJV_Read(pHandle, pHandle->SwapBuff,secpos*4096, secoff); //读出需要写入之前的数据
if(W25QxxJV_EraseSector(pHandle,secpos)==FALSE) //擦除这个扇区
{
return FALSE;
}
for(i = 0;i < NumByteToWrite;i ++) //复制当前要写入的数据
{
pHandle->SwapBuff[i + secoff] = pBuffer;
}
if(W25QxxJV_WriteNoCheck(pHandle,pHandle->SwapBuff,secpos*4096,secoff+NumByteToWrite)==FALSE)//写入数据
{
return FALSE;
}
return TRUE;
}
/*************************************************************************************************************************
* 函数 : void W25QxxJV_PowerDown(W25QxxJV_HANDLE *pHandle)
* 功能 : 进入掉电模式
* 参数 : pHandle:句柄
* 返回 : 无
* 依赖 : 底层读写函数
* 作者 : cp1300@139.com
* 时间 : 20110630
* 最后修改时间 : 2021-08-25
* 说明 : 函数不带信号量保护,使用需要注意,调用后将无法读写flash
*************************************************************************************************************************/
void W25QxxJV_PowerDown(W25QxxJV_HANDLE *pHandle)
{
pHandle->EnterDirectMode(); //进入直接模式
pHandle->ExtendedSPI_WriteByte(W25Q_PowerDown); //发送掉电命令
pHandle->ExitDirectMode(); //退出直接模式
}
/*************************************************************************************************************************
* 函数 : void W25QxxJV_WAKEUP(W25QxxJV_HANDLE *pHandle)
* 功能 : 唤醒W25QxxJV
* 参数 : pHandle:句柄
* 返回 : 无
* 依赖 : 底层读写函数
* 作者 : cp1300@139.com
* 时间 : 20110630
* 最后修改时间 : 2021-08-25
* 说明 : 函数不带信号量保护
*************************************************************************************************************************/
void W25QxxJV_WAKEUP(W25QxxJV_HANDLE *pHandle)
{
pHandle->EnterDirectMode(); //进入直接模式
pHandle->ExtendedSPI_WriteByte(W25Q_ReleasePowerDown); // send W25Q_PowerDown command 0xAB
pHandle->ExitDirectMode(); //退出直接模式
pHandle->DelayMs(1); //等待TRES1
}
/*************************************************************************************************************************
* 函数 : bool W25QxxJV_EraseBlock64KB(W25QxxJV_HANDLE *pHandle,u32 Block_Addr)
* 功能 : 擦除一个64KB块
* 参数 : pHandle:句柄,Block_Addr:块地址,1块=64KB
* 返回 : TRUE:成功;FALSE:失败,超时
* 依赖 : 底层读写函数
* 作者 : cp1300@139.com
* 时间 : 2016-12-03
* 最后修改时间 : 2021-08-25
* 说明 : 擦除一个的最少时间:150ms
*************************************************************************************************************************/
bool W25QxxJV_EraseBlock64KB(W25QxxJV_HANDLE *pHandle,u32 Block_Addr)
{
bool status;
Block_Addr *= 64*1024; //计算块的起始地址
W25QxxJV_WriteEnable(pHandle); //写使能
if(W25QxxJV_WaitBusy(pHandle) == FALSE) //检测忙信号
{
W25QxxJV_WriteDisable(pHandle); //写禁止
return FALSE;
}
pHandle->EnterDirectMode(); //进入直接模式
pHandle->ExtendedSPI_WriteByte(W25Q_BlockErase); //发送64KB块擦除指令
pHandle->ExtendedSPI_WriteByte((u8)((Block_Addr) >> 16)); //发送24bit地址
pHandle->ExtendedSPI_WriteByte((u8)((Block_Addr) >> 8));
pHandle->ExtendedSPI_WriteByte((u8)Block_Addr);
pHandle->ExitDirectMode(); //退出直接模式
status = W25QxxJV_WaitBusy(pHandle); //等待擦除完成
W25QxxJV_WriteDisable(pHandle); //写禁止
return status;
}
/*************************************************************************************************************************
* 函数 : void W25QxxJV_ResetDevice(W25QxxJV_HANDLE *pHandle)
* 功能 : 复位设备
* 参数 : pHandle:句柄
* 返回 : 无
* 依赖 : 底层读写函数
* 作者 : cp1300@139.com
* 时间 : 2021-08-25
* 最后修改时间 : 2021-08-25
* 说明 :
*************************************************************************************************************************/
void W25QxxJV_ResetDevice(W25QxxJV_HANDLE *pHandle)
{
pHandle->EnterDirectMode(); //进入直接模式
pHandle->ExtendedSPI_WriteByte(W25QxxJV_EnableReset); //使能复位
pHandle->ExitDirectMode(); //退出直接模式
pHandle->DelayMs(1);
pHandle->EnterDirectMode(); //进入直接模式
pHandle->ExtendedSPI_WriteByte(W25QxxJV_Reset); //复位
pHandle->ExitDirectMode(); //退出直接模式
pHandle->DelayMs(1);
}
|