?? w25x16.h
字號:
#define SPI_FLASH_CS_H GPIOA->BSRR=1<<2
#define SPI_FLASH_CS_L GPIOA->BRR=1<<2
#define FLASH_ID 0XEF14
//指令表
#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
//讀取SPI_FLASH的狀態寄存器
//BIT7 6 5 4 3 2 1 0
//SPR RV TB BP2 BP1 BP0 WEL BUSY
//SPR:默認0,狀態寄存器保護位,配合WP使用
//TB,BP2,BP1,BP0:FLASH區域寫保護設置
//WEL:寫使能鎖定
//BUSY:忙標記位(1,忙;0,空閑)
//默認:0x00
u8 SPI_Flash_ReadSR(void)
{
u8 byte=0;
SPI_FLASH_CS_L; //使能器件
SPIx_ReadWriteByte(W25X_ReadStatusReg); //發送讀取狀態寄存器命令
byte=SPIx_ReadWriteByte(0Xff); //讀取一個字節
SPI_FLASH_CS_H; //取消片選
return byte;
}
//寫SPI_FLASH狀態寄存器
//只有SPR,TB,BP2,BP1,BP0(bit 7,5,4,3,2)可以寫!!!
void SPI_FLASH_Write_SR(u8 sr)
{
SPI_FLASH_CS_L; //使能器件
SPIx_ReadWriteByte(W25X_WriteStatusReg); //發送寫取狀態寄存器命令
SPIx_ReadWriteByte(sr); //寫入一個字節
SPI_FLASH_CS_H; //取消片選
}
//SPI_FLASH寫使能
//將WEL置位
void SPI_FLASH_Write_Enable(void)
{
SPI_FLASH_CS_L; //使能器件
SPIx_ReadWriteByte(W25X_WriteEnable); //發送寫使能
SPI_FLASH_CS_H; //取消片選
}
//SPI_FLASH寫禁止
//將WEL清零
void SPI_FLASH_Write_Disable(void)
{
SPI_FLASH_CS_L; //使能器件
SPIx_ReadWriteByte(W25X_WriteDisable); //發送寫禁止指令
SPI_FLASH_CS_H; //取消片選
}
//等待空閑
void SPI_Flash_Wait_Busy(void)
{
while ((SPI_Flash_ReadSR()&0x01)==0x01); // 等待BUSY位清空
}
//進入掉電模式
void SPI_Flash_PowerDown(void)
{
SPI_FLASH_CS_L; //使能器件
SPIx_ReadWriteByte(W25X_PowerDown); //發送掉電命令
SPI_FLASH_CS_H; //取消片選
delay_us(3); //等待TPD
}
//喚醒
void SPI_Flash_WAKEUP(void)
{
SPI_FLASH_CS_L; //使能器件
SPIx_ReadWriteByte(W25X_ReleasePowerDown); // send W25X_PowerDown command 0xAB
SPI_FLASH_CS_H; //取消片選
delay_us(3); //等待TRES1
}
//擦除一個扇區
//Dst_Addr:扇區地址 0~511 for w25x16
//擦除一個山區的最少時間:150ms
void SPI_Flash_Erase_Sector(u32 Dst_Addr)
{
Dst_Addr*=4096;
SPI_FLASH_Write_Enable(); //SET WEL
SPI_Flash_Wait_Busy();
SPI_FLASH_CS_L; //使能器件
SPIx_ReadWriteByte(W25X_SectorErase); //發送扇區擦除指令
SPIx_ReadWriteByte((u8)((Dst_Addr)>>16)); //發送24bit地址
SPIx_ReadWriteByte((u8)((Dst_Addr)>>8));
SPIx_ReadWriteByte((u8)Dst_Addr);
SPI_FLASH_CS_H; //取消片選
SPI_Flash_Wait_Busy(); //等待擦除完成
}
//讀取芯片ID
//返回值如下:
//0XEF13,表示芯片型號為W25Q80
//0XEF14,表示芯片型號為W25Q16
//0XEF15,表示芯片型號為W25Q32
//0XEF16,表示芯片型號為W25Q64
u16 SPI_Flash_ReadID(void)
{
u16 Temp = 0;
SPI_FLASH_CS_L;
SPIx_ReadWriteByte(0x90);//發送讀取ID命令
SPIx_ReadWriteByte(0x00);
SPIx_ReadWriteByte(0x00);
SPIx_ReadWriteByte(0x00);
Temp|=SPIx_ReadWriteByte(0xFF)<<8;
Temp|=SPIx_ReadWriteByte(0xFF);
SPI_FLASH_CS_H;
return Temp;
}
//讀取SPI FLASH
//在指定地址開始讀取指定長度的數據
//pBuffer:數據存儲區
//ReadAddr:開始讀取的地址(24bit)
//NumByteToRead:要讀取的字節數(最大65535)
void SPI_Flash_Read(u8* pBuffer,u32 ReadAddr,u16 NumByteToRead)
{
u16 i;
#ifdef OS_CRITICAL_METHOD //如果OS_CRITICAL_METHOD定義了,說明使用ucosII了.
OS_ENTER_CRITICAL();//停止調度
#endif
SPI_FLASH_CS_L; //使能器件
SPIx_ReadWriteByte(W25X_ReadData); //發送讀取命令
SPIx_ReadWriteByte((u8)((ReadAddr)>>16)); //發送24bit地址
SPIx_ReadWriteByte((u8)((ReadAddr)>>8));
SPIx_ReadWriteByte((u8)ReadAddr);
for(i=0;i<NumByteToRead;i++)
{
pBuffer[i]=SPIx_ReadWriteByte(0XFF); //循環讀數
}
SPI_FLASH_CS_H; //取消片選
#ifdef OS_CRITICAL_METHOD //如果OS_CRITICAL_METHOD定義了,說明使用ucosII了.
OS_EXIT_CRITICAL();//準許調度
#endif
}
//SPI在一頁(0~65535)內寫入少于256個字節的數據
//在指定地址開始寫入最大256字節的數據
//pBuffer:數據存儲區
//WriteAddr:開始寫入的地址(24bit)
//NumByteToWrite:要寫入的字節數(最大256),該數不應該超過該頁的剩余字節數!!!
void SPI_Flash_Write_Page(u8* pBuffer,u32 WriteAddr,u16 NumByteToWrite)
{
u16 i;
SPI_FLASH_Write_Enable(); //SET WEL
SPI_FLASH_CS_L; //使能器件
SPIx_ReadWriteByte(W25X_PageProgram); //發送寫頁命令
SPIx_ReadWriteByte((u8)((WriteAddr)>>16)); //發送24bit地址
SPIx_ReadWriteByte((u8)((WriteAddr)>>8));
SPIx_ReadWriteByte((u8)WriteAddr);
for(i=0;i<NumByteToWrite;i++)SPIx_ReadWriteByte(pBuffer[i]);//循環寫數
SPI_FLASH_CS_H; //取消片選
SPI_Flash_Wait_Busy(); //等待寫入結束
}
//無檢驗寫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_Write_Page(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個字節了
}
};
}
//寫SPI FLASH
//在指定地址開始寫入指定長度的數據
//該函數帶擦除操作!
//pBuffer:數據存儲區
//WriteAddr:開始寫入的地址(24bit)
//NumByteToWrite:要寫入的字節數(最大65535)
#ifndef SRAMIN
u8 SPI_FLASH_BUFFER[4096];
#endif
void SPI_Flash_Write(u8* pBuffer,u32 WriteAddr,u16 NumByteToWrite)
{
u32 secpos;
u16 secoff;
u16 secremain;
u16 i;
u8 * SPI_FLASH_BUF;
#ifdef OS_CRITICAL_METHOD //如果OS_CRITICAL_METHOD定義了,說明使用ucosII了.
OS_ENTER_CRITICAL();//停止調度
#endif
#ifdef SRAMIN
SPI_FLASH_BUF=mymalloc(SRAMIN,4096);//申請內存
if(SPI_FLASH_BUF==NULL)return ;//申請失敗
#else
SPI_FLASH_BUF=SPI_FLASH_BUFFER;
#endif
secpos=WriteAddr/4096;//扇區地址 0~511 for w25x16
secoff=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_Erase_Sector(secpos);//擦除這個扇區
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++;//扇區地址增1
secoff=0;//偏移位置為0
pBuffer+=secremain; //指針偏移
WriteAddr+=secremain;//寫地址偏移
NumByteToWrite-=secremain; //字節數遞減
if(NumByteToWrite>4096)secremain=4096; //下一個扇區還是寫不完
else secremain=NumByteToWrite; //下一個扇區可以寫完了
}
};
#ifdef SRAMIN
myfree(SRAMIN,SPI_FLASH_BUF);//釋放內存
#endif
#ifdef OS_CRITICAL_METHOD //如果OS_CRITICAL_METHOD定義了,說明使用ucosII了.
OS_EXIT_CRITICAL();//準許調度
#endif
}
//擦除整個芯片
//整片擦除時間:
//W25X16:25s
//W25X32:40s
//W25X64:40s
//等待時間超長...
void SPI_Flash_Erase_Chip(void)
{
SPI_FLASH_Write_Enable(); //SET WEL
SPI_Flash_Wait_Busy();
SPI_FLASH_CS_L; //使能器件
SPIx_ReadWriteByte(W25X_ChipErase); //發送片擦除命令
SPI_FLASH_CS_H; //取消片選
SPI_Flash_Wait_Busy(); //等待芯片擦除結束
}
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -