|
#include "w25qxx.h"
#include "spi.h"
#include "delay.h"
u16 W25QXX_TYPE=W25Q64; //默認(rèn)是W25Q128
//4Kbytes為一個(gè)Sector
//16個(gè)扇區(qū)為1個(gè)Block
//W25Q128
//容量為16M字節(jié),共有128個(gè)Block,4096個(gè)Sector
//初始化SPI FLASH的IO口
void W25QXX_Init(void)
{
RCC->AHB1ENR|=1<<1; //使能PORTB時(shí)鐘
RCC->AHB1ENR|=1<<6; //使能PORTG時(shí)鐘
GPIOB->MODER |=(0X1<<(2*14)); //配置成復(fù)用輸出
GPIOB->OTYPER &=~(1<<14); //配置成輸出推挽
GPIOB->OSPEEDR &=~(0X3<<(2*14)); //清零
GPIOB->OSPEEDR |=(0X3<<(2*14)); //配置成輸出速率100M
GPIOB->PUPDR &=~(0X3<<28); //清零
GPIOB->PUPDR |=(0X1<<14); //管腳初始化時(shí)輸出高電平
GPIOB->MODER |=(0X1<<(2*7)); //配置成復(fù)用輸出
GPIOB->OTYPER &=~(1<<7); //配置成輸出推挽
GPIOB->OSPEEDR &=~(0X3<<(2*7)); //清零
GPIOB->OSPEEDR |=(0X3<<(2*7)); //配置成輸出速率100M
GPIOB->PUPDR &=~(0X3<<14); //清零
GPIOB->PUPDR |=(0X1<<7); //管腳初始化時(shí)輸出高電平
GPIOG->ODR|=1<<7; //PG7輸出1,防止NRF干擾SPI FLASH的通信
GPIOB->ODR |= 1<<14; //SPI FLASH不選中
SPI1_Init(); //初始化SPI
SPI1_SetSpeed(SPI_SPEED_2); //設(shè)置為42M時(shí)鐘(超頻了一點(diǎn)點(diǎn)),高速模式
W25QXX_TYPE=W25QXX_ReadID(); //讀取FLASH ID.
}
//讀取W25QXX的狀態(tài)寄存器
//BIT7 6 5 4 3 2 1 0
//SPR RV TB BP2 BP1 BP0 WEL BUSY
//SPR:默認(rèn)0,狀態(tài)寄存器保護(hù)位,配合WP使用
//TB,BP2,BP1,BP0:FLASH區(qū)域?qū)懕Wo(hù)設(shè)置
//WEL:寫(xiě)使能鎖定
//BUSY:忙標(biāo)記位(1,忙;0,空閑)
//默認(rèn):0x00
u8 W25QXX_ReadSR(void)
{
u8 byte=0;
GPIOB->ODR &= ~(1<<14); //使能器件
SPI1_ReadWriteByte(W25X_ReadStatusReg); //發(fā)送讀取狀態(tài)寄存器命令
byte=SPI1_ReadWriteByte(0Xff); //讀取一個(gè)字節(jié)
GPIOB->ODR |= 1<<14; //取消片選
return byte;
}
//寫(xiě)W25QXX狀態(tài)寄存器
//只有SPR,TB,BP2,BP1,BP0(bit 7,5,4,3,2)可以寫(xiě)!!!
void W25QXX_Write_SR(u8 sr)
{
GPIOB->ODR &= ~(1<<14); //使能器件
SPI1_ReadWriteByte(W25X_WriteStatusReg); //發(fā)送寫(xiě)取狀態(tài)寄存器命令
SPI1_ReadWriteByte(sr); //寫(xiě)入一個(gè)字節(jié)
GPIOB->ODR |= 1<<14; //取消片選
}
//W25QXX寫(xiě)使能
//將WEL置位
void W25QXX_Write_Enable(void)
{
GPIOB->ODR &= ~(1<<14); //使能器件
SPI1_ReadWriteByte(W25X_WriteEnable); //發(fā)送寫(xiě)使能
GPIOB->ODR |= 1<<14; //取消片選
}
//W25QXX寫(xiě)禁止
//將WEL清零
void W25QXX_Write_Disable(void)
{
GPIOB->ODR &= ~(1<<14); //使能器件
SPI1_ReadWriteByte(W25X_WriteDisable); //發(fā)送寫(xiě)禁止指令
GPIOB->ODR |= 1<<14; //取消片選
}
//讀取芯片ID
//返回值如下:
//0XEF13,表示芯片型號(hào)為W25Q80
//0XEF14,表示芯片型號(hào)為W25Q16
//0XEF15,表示芯片型號(hào)為W25Q32
//0XEF16,表示芯片型號(hào)為W25Q64
//0XEF17,表示芯片型號(hào)為W25Q128
u16 W25QXX_ReadID(void)
{
u16 Temp = 0;
GPIOB->ODR &= ~(1<<14);
SPI1_ReadWriteByte(0x90);//發(fā)送讀取ID命令
SPI1_ReadWriteByte(0x00);
SPI1_ReadWriteByte(0x00);
SPI1_ReadWriteByte(0x00);
Temp|=SPI1_ReadWriteByte(0xFF)<<8;
Temp|=SPI1_ReadWriteByte(0xFF);
GPIOB->ODR |= 1<<14;
return Temp;
}
//讀取SPI FLASH
//在指定地址開(kāi)始讀取指定長(zhǎng)度的數(shù)據(jù)
//pBuffer:數(shù)據(jù)存儲(chǔ)區(qū)
//ReadAddr:開(kāi)始讀取的地址(24bit)
//NumByteToRead:要讀取的字節(jié)數(shù)(最大65535)
void W25QXX_Read(u8* pBuffer,u32 ReadAddr,u16 NumByteToRead)
{
u16 i;
GPIOB->ODR &= ~(1<<14); //使能器件
SPI1_ReadWriteByte(W25X_ReadData); //發(fā)送讀取命令
SPI1_ReadWriteByte((u8)((ReadAddr)>>16)); //發(fā)送24bit地址
SPI1_ReadWriteByte((u8)((ReadAddr)>>8));
SPI1_ReadWriteByte((u8)ReadAddr);
for(i=0;i<NumByteToRead;i++)
{
pBuffer[i]=SPI1_ReadWriteByte(0XFF); //循環(huán)讀數(shù)
}
GPIOB->ODR |= 1<<14;
}
//SPI在一頁(yè)(0~65535)內(nèi)寫(xiě)入少于256個(gè)字節(jié)的數(shù)據(jù)
//在指定地址開(kāi)始寫(xiě)入最大256字節(jié)的數(shù)據(jù)
//pBuffer:數(shù)據(jù)存儲(chǔ)區(qū)
//WriteAddr:開(kāi)始寫(xiě)入的地址(24bit)
//NumByteToWrite:要寫(xiě)入的字節(jié)數(shù)(最大256),該數(shù)不應(yīng)該超過(guò)該頁(yè)的剩余字節(jié)數(shù)!!!
void W25QXX_Write_Page(u8* pBuffer,u32 WriteAddr,u16 NumByteToWrite)
{
u16 i;
W25QXX_Write_Enable(); //SET WEL
GPIOB->ODR &= ~(1<<14); //使能器件
SPI1_ReadWriteByte(W25X_PageProgram); //發(fā)送寫(xiě)頁(yè)命令
SPI1_ReadWriteByte((u8)((WriteAddr)>>16)); //發(fā)送24bit地址
SPI1_ReadWriteByte((u8)((WriteAddr)>>8));
SPI1_ReadWriteByte((u8)WriteAddr);
for(i=0;i<NumByteToWrite;i++)SPI1_ReadWriteByte(pBuffer[i]);//循環(huán)寫(xiě)數(shù)
GPIOB->ODR |= 1<<14; //取消片選
W25QXX_Wait_Busy(); //等待寫(xiě)入結(jié)束
}
//無(wú)檢驗(yàn)寫(xiě)SPI FLASH
//必須確保所寫(xiě)的地址范圍內(nèi)的數(shù)據(jù)全部為0XFF,否則在非0XFF處寫(xiě)入的數(shù)據(jù)將失敗!
//具有自動(dòng)換頁(yè)功能
//在指定地址開(kāi)始寫(xiě)入指定長(zhǎng)度的數(shù)據(jù),但是要確保地址不越界!
//pBuffer:數(shù)據(jù)存儲(chǔ)區(qū)
//WriteAddr:開(kāi)始寫(xiě)入的地址(24bit)
//NumByteToWrite:要寫(xiě)入的字節(jié)數(shù)(最大65535)
//CHECK OK
void W25QXX_Write_NoCheck(u8* pBuffer,u32 WriteAddr,u16 NumByteToWrite)
{
u16 pageremain;
pageremain=256-WriteAddr%256; //單頁(yè)剩余的字節(jié)數(shù)
if(NumByteToWrite<=pageremain)pageremain=NumByteToWrite;//不大于256個(gè)字節(jié)
while(1)
{
W25QXX_Write_Page(pBuffer,WriteAddr,pageremain);
if(NumByteToWrite==pageremain)break;//寫(xiě)入結(jié)束了
else //NumByteToWrite>pageremain
{
pBuffer+=pageremain;
WriteAddr+=pageremain;
NumByteToWrite-=pageremain; //減去已經(jīng)寫(xiě)入了的字節(jié)數(shù)
if(NumByteToWrite>256)pageremain=256; //一次可以寫(xiě)入256個(gè)字節(jié)
else pageremain=NumByteToWrite; //不夠256個(gè)字節(jié)了
}
};
}
//寫(xiě)SPI FLASH
//在指定地址開(kāi)始寫(xiě)入指定長(zhǎng)度的數(shù)據(jù)
//該函數(shù)帶擦除操作!
//pBuffer:數(shù)據(jù)存儲(chǔ)區(qū)
//WriteAddr:開(kāi)始寫(xiě)入的地址(24bit)
//NumByteToWrite:要寫(xiě)入的字節(jié)數(shù)(最大65535)
u8 W25QXX_BUFFER[4096];
void W25QXX_Write(u8* pBuffer,u32 WriteAddr,u16 NumByteToWrite)
{
u32 secpos;
u16 secoff;
u16 secremain;
u16 i;
u8 * W25QXX_BUF;
W25QXX_BUF=W25QXX_BUFFER;
secpos=WriteAddr/4096;//扇區(qū)地址
secoff=WriteAddr%4096;//在扇區(qū)內(nèi)的偏移
secremain=4096-secoff;//扇區(qū)剩余空間大小
//printf("ad:%X,nb:%X\r\n",WriteAddr,NumByteToWrite);//測(cè)試用
if(NumByteToWrite<=secremain)secremain=NumByteToWrite;//不大于4096個(gè)字節(jié)
while(1)
{
W25QXX_Read(W25QXX_BUF,secpos*4096,4096);//讀出整個(gè)扇區(qū)的內(nèi)容
for(i=0;i<secremain;i++)//校驗(yàn)數(shù)據(jù)
{
if(W25QXX_BUF[secoff+i]!=0XFF)break;//需要擦除
}
if(i<secremain)//需要擦除
{
W25QXX_Erase_Sector(secpos);//擦除這個(gè)扇區(qū)
for(i=0;i<secremain;i++) //復(fù)制
{
W25QXX_BUF[i+secoff]=pBuffer[i];
}
W25QXX_Write_NoCheck(W25QXX_BUF,secpos*4096,4096);//寫(xiě)入整個(gè)扇區(qū)
}else W25QXX_Write_NoCheck(pBuffer,WriteAddr,secremain);//寫(xiě)已經(jīng)擦除了的,直接寫(xiě)入扇區(qū)剩余區(qū)間.
if(NumByteToWrite==secremain)break;//寫(xiě)入結(jié)束了
else//寫(xiě)入未結(jié)束
{
secpos++;//扇區(qū)地址增1
secoff=0;//偏移位置為0
pBuffer+=secremain; //指針偏移
WriteAddr+=secremain;//寫(xiě)地址偏移
NumByteToWrite-=secremain; //字節(jié)數(shù)遞減
if(NumByteToWrite>4096)secremain=4096; //下一個(gè)扇區(qū)還是寫(xiě)不完
else secremain=NumByteToWrite; //下一個(gè)扇區(qū)可以寫(xiě)完了
}
};
}
//擦除整個(gè)芯片
//等待時(shí)間超長(zhǎng)...
void W25QXX_Erase_Chip(void)
{
W25QXX_Write_Enable(); //SET WEL
W25QXX_Wait_Busy();
GPIOB->ODR &= ~(1<<14); //使能器件
SPI1_ReadWriteByte(W25X_ChipErase); //發(fā)送片擦除命令
GPIOB->ODR |= 1<<14; //取消片選
W25QXX_Wait_Busy(); //等待芯片擦除結(jié)束
}
//擦除一個(gè)扇區(qū)
//Dst_Addr:扇區(qū)地址 根據(jù)實(shí)際容量設(shè)置
//擦除一個(gè)山區(qū)的最少時(shí)間:150ms
void W25QXX_Erase_Sector(u32 Dst_Addr)
{
//監(jiān)視falsh擦除情況,測(cè)試用
//printf("fe:%x\r\n",Dst_Addr);
Dst_Addr*=4096;
W25QXX_Write_Enable(); //SET WEL
W25QXX_Wait_Busy();
GPIOB->ODR &= ~(1<<14); //使能器件
SPI1_ReadWriteByte(W25X_SectorErase); //發(fā)送扇區(qū)擦除指令
SPI1_ReadWriteByte((u8)((Dst_Addr)>>16)); //發(fā)送24bit地址
SPI1_ReadWriteByte((u8)((Dst_Addr)>>8));
SPI1_ReadWriteByte((u8)Dst_Addr);
GPIOB->ODR |= 1<<14; //取消片選
W25QXX_Wait_Busy(); //等待擦除完成
}
//等待空閑
void W25QXX_Wait_Busy(void)
{
while((W25QXX_ReadSR()&0x01)==0x01); // 等待BUSY位清空
}
//進(jìn)入掉電模式
void W25QXX_PowerDown(void)
{
GPIOB->ODR &= ~(1<<14); //使能器件
SPI1_ReadWriteByte(W25X_PowerDown); //發(fā)送掉電命令
GPIOB->ODR |= 1<<14; //取消片選
Delay_ms(3); //等待TPD
}
//喚醒
void W25QXX_WAKEUP(void)
{
GPIOB->ODR &= ~(1<<14); //使能器件
SPI1_ReadWriteByte(W25X_ReleasePowerDown); // send W25X_PowerDown command 0xAB
GPIOB->ODR |= 1<<14; //取消片選
Delay_ms(3); //等待TRES1
}
//以上是c文件 下面的是h文件
#ifndef __W25QXX_H
#define __W25QXX_H
#include "stm32f4xx.h"
//////////////////////////////////////////////////////////////////////////////////
//W25X系列/Q系列芯片列表
//W25Q80 ID 0XEF13
//W25Q16 ID 0XEF14
//W25Q32 ID 0XEF15
//W25Q64 ID 0XEF16
//W25Q128 ID 0XEF17
#define W25Q80 0XEF13
#define W25Q16 0XEF14
#define W25Q32 0XEF15
#define W25Q64 0XEF16
#define W25Q128 0XEF17
extern u16 W25QXX_TYPE; //定義W25QXX芯片型號(hào)
#define W25QXX_CS PBout(14) //W25QXX的片選信號(hào)
//////////////////////////////////////////////////////////////////////////////////
//指令表
#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
void W25QXX_Init(void);
u16 W25QXX_ReadID(void); //讀取FLASH ID
u8 W25QXX_ReadSR(void); //讀取狀態(tài)寄存器
void W25QXX_Write_SR(u8 sr); //寫(xiě)狀態(tài)寄存器
void W25QXX_Write_Enable(void); //寫(xiě)使能
void W25QXX_Write_Disable(void); //寫(xiě)保護(hù)
void W25QXX_Write_NoCheck(u8* pBuffer,u32 WriteAddr,u16 NumByteToWrite);
void W25QXX_Read(u8* pBuffer,u32 ReadAddr,u16 NumByteToRead); //讀取flash
void W25QXX_Write(u8* pBuffer,u32 WriteAddr,u16 NumByteToWrite);//寫(xiě)入flash
void W25QXX_Erase_Chip(void); //整片擦除
void W25QXX_Erase_Sector(u32 Dst_Addr); //扇區(qū)擦除
void W25QXX_Wait_Busy(void); //等待空閑
void W25QXX_PowerDown(void); //進(jìn)入掉電模式
void W25QXX_WAKEUP(void); //喚醒
#endif
|
|