|  | 
 
| 本程序是使用STM32F1驱动W25Qxx系列FLASH存储的驱动代码: 
 
 注意配置一下此函数
 
  
 
 
 
 
 .H文件
 
 .C文件复制代码#ifndef __FLASH_H
#define __FLASH_H                            
#include "sys.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芯片型号                   
#define        W25QXX_CS                 PCout(5)                  //W25QXX的片选信号        ADC1
//配置SPI信息
#define W25Qxx_ReadWriteByte                SPI1_ReadWriteByte
#define W25Qxx_SPI_init                                SPI1_Init                                
#define W25Qxx_SPI_SetSpeed                        SPI1_SetSpeed
                                 
////////////////////////////////////////////////////////////////////////////
 
//指令表
#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 
u16  W25QXX_Init(void);
u16  W25QXX_ReadID(void);                              //读取FLASH ID
u8         W25QXX_ReadSR(void);                        //读取状态寄存器 
void W25QXX_Write_SR(u8 sr);                          //写状态寄存器
void W25QXX_Write_Enable(void);                  //写使能 
void W25QXX_Write_Disable(void);                //写保护
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);//写入flash
void W25QXX_Erase_Chip(void);                      //整片擦除
void W25QXX_Erase_Sector(u32 Dst_Addr);        //扇区擦除
void W25QXX_Wait_Busy(void);                   //等待空闲
void W25QXX_PowerDown(void);                //进入掉电模式
void W25QXX_WAKEUP(void);                                //唤醒
#endif
 
 复制代码#include "w25qxx.h" 
#include "spi.h"
#include "delay.h"   
u16 W25QXX_TYPE;//默认就是25Q64
//4Kbytes为一个Sector
//16个扇区为1个Block
//W25X16
//容量为2M字节,共有32个Block,512个Sector 
//初始化SPI FLASH的IO口
u16 W25QXX_Init(void)
{
                        GPIO_InitTypeDef GPIO_InitStructure;
                        RCC_APB2PeriphClockCmd(        RCC_APB2Periph_GPIOC, ENABLE );
                        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;  //SPI CS
                        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;  //复用推挽输出
                        GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
                        GPIO_Init(GPIOC, &GPIO_InitStructure);
                        GPIO_SetBits(GPIOC,GPIO_Pin_5);
                        W25Qxx_SPI_init();                   //初始化SPI
                        W25Qxx_SPI_SetSpeed(SPI_BaudRatePrescaler_4);        //设置为18M时钟,高速模式
                        W25QXX_TYPE=W25QXX_ReadID();//读取FLASH ID.
                        return W25QXX_TYPE;
}  
//读取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 W25QXX_ReadSR(void)   
{  
                        u8 byte=0;   
                        W25QXX_CS=0;                            //使能器件   
                        W25Qxx_ReadWriteByte(W25X_ReadStatusReg);    //发送读取状态寄存器命令    
                        byte=W25Qxx_ReadWriteByte(0Xff);             //读取一个字节  
                        W25QXX_CS=1;                            //取消片选     
                        return byte;   
} 
//写SPI_FLASH状态寄存器
//只有SPR,TB,BP2,BP1,BP0(bit 7,5,4,3,2)可以写!!!
void W25QXX_Write_SR(u8 sr)   
{   
                        W25QXX_CS=0;                            //使能器件   
                        W25Qxx_ReadWriteByte(W25X_WriteStatusReg);   //发送写取状态寄存器命令    
                        W25Qxx_ReadWriteByte(sr);               //写入一个字节  
                        W25QXX_CS=1;                            //取消片选                   
}   
//SPI_FLASH写使能        
//将WEL置位   
void W25QXX_Write_Enable(void)   
{
                        W25QXX_CS=0;                            //使能器件   
                        W25Qxx_ReadWriteByte(W25X_WriteEnable);      //发送写使能  
                        W25QXX_CS=1;                            //取消片选                   
} 
//SPI_FLASH写禁止        
//将WEL清零  
void W25QXX_Write_Disable(void)   
{  
                        W25QXX_CS=0;                            //使能器件   
                        W25Qxx_ReadWriteByte(W25X_WriteDisable);     //发送写禁止指令    
                        W25QXX_CS=1;                            //取消片选                   
}                             
//读取芯片ID W25X16的ID:0XEF14
u16 W25QXX_ReadID(void)
{
                        u16 Temp = 0;          
                        W25QXX_CS=0;                                    
                        W25Qxx_ReadWriteByte(0x90);//发送读取ID命令            
                        W25Qxx_ReadWriteByte(0x00);             
                        W25Qxx_ReadWriteByte(0x00);             
                        W25Qxx_ReadWriteByte(0x00);                                     
                        Temp|=W25Qxx_ReadWriteByte(0xFF)<<8;  
                        Temp|=W25Qxx_ReadWriteByte(0xFF);         
                        W25QXX_CS=1;                                    
                        return Temp;
}                       
//读取SPI FLASH  
//在指定地址开始读取指定长度的数据
//pBuffer:数据存储区
//ReadAddr:开始读取的地址(24bit)
//NumByteToRead:要读取的字节数(最大65535)
void W25QXX_Read(u8* pBuffer,u32 ReadAddr,u16 NumByteToRead)   
{ 
                        u16 i;                                                                                                        
                        W25QXX_CS=0;                            //使能器件   
                        W25Qxx_ReadWriteByte(W25X_ReadData);         //发送读取命令   
                        W25Qxx_ReadWriteByte((u8)((ReadAddr)>>16));  //发送24bit地址    
                        W25Qxx_ReadWriteByte((u8)((ReadAddr)>>8));   
                        W25Qxx_ReadWriteByte((u8)ReadAddr);   
                        for(i=0;i<NumByteToRead;i++)
        { 
                        pBuffer[i]=W25Qxx_ReadWriteByte(0XFF);   //循环读数  
        }
                        W25QXX_CS=1;                            //取消片选                   
}  
//SPI在一页(0~65535)内写入少于256个字节的数据
//在指定地址开始写入最大256字节的数据
//pBuffer:数据存储区
//WriteAddr:开始写入的地址(24bit)
//NumByteToWrite:要写入的字节数(最大256),该数不应该超过该页的剩余字节数!!!         
void W25QXX_Write_Page(u8* pBuffer,u32 WriteAddr,u16 NumByteToWrite)
{
                        u16 i;  
                        W25QXX_Write_Enable();                  //SET WEL 
                        W25QXX_CS=0;                            //使能器件   
                        W25Qxx_ReadWriteByte(W25X_PageProgram);      //发送写页命令   
                        W25Qxx_ReadWriteByte((u8)((WriteAddr)>>16)); //发送24bit地址    
                        W25Qxx_ReadWriteByte((u8)((WriteAddr)>>8));   
                        W25Qxx_ReadWriteByte((u8)WriteAddr);   
                        for(i=0;i<NumByteToWrite;i++)W25Qxx_ReadWriteByte(pBuffer[i]);//循环写数  
                        W25QXX_CS=1;                            //取消片选 
                        W25QXX_Wait_Busy();                                           //等待写入结束
} 
//无检验写SPI FLASH 
//必须确保所写的地址范围内的数据全部为0XFF,否则在非0XFF处写入的数据将失败!
//具有自动换页功能 
//在指定地址开始写入指定长度的数据,但是要确保地址不越界!
//pBuffer:数据存储区
//WriteAddr:开始写入的地址(24bit)
//NumByteToWrite:要写入的字节数(最大65535)
//CHECK OK
void W25QXX_Write_NoCheck(u8* pBuffer,u32 WriteAddr,u16 NumByteToWrite)   
{                                           
                        u16 pageremain;           
                        pageremain=256-WriteAddr%256; //单页剩余的字节数                             
                        if(NumByteToWrite<=pageremain)pageremain=NumByteToWrite;//不大于256个字节
                        while(1)
        {           
                        W25QXX_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)                     
u8 SPI_FLASH_BUF[4096];
void W25QXX_Write(u8* pBuffer,u32 WriteAddr,u16 NumByteToWrite)   
{ 
                        u32 secpos;
                        u16 secoff;
                        u16 secremain;           
                        u16 i;    
                        secpos=WriteAddr/4096;//扇区地址 0~511 for w25x16
                        secoff=WriteAddr%4096;//在扇区内的偏移
                        secremain=4096-secoff;//扇区剩余空间大小   
                        if(NumByteToWrite<=secremain)secremain=NumByteToWrite;//不大于4096个字节
                        while(1) 
        {        
                        W25QXX_Read(SPI_FLASH_BUF,secpos*4096,4096);//读出整个扇区的内容
                        for(i=0;i<secremain;i++)//校验数据
                {
                        if(SPI_FLASH_BUF[secoff+i]!=0XFF)break;//需要擦除            
                }
                        if(i<secremain)//需要擦除
                {
                        W25QXX_Erase_Sector(secpos);//擦除这个扇区
                        for(i=0;i<secremain;i++)           //复制
                        {
                        SPI_FLASH_BUF[i+secoff]=pBuffer[i];          
                        }
                        W25QXX_Write_NoCheck(SPI_FLASH_BUF,secpos*4096,4096);//写入整个扇区  
                }
                        else W25QXX_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;                        //下一个扇区可以写完了
                }         
        }                  
}
//擦除整个芯片
//整片擦除时间:
//W25X16:25s 
//W25X32:40s 
//W25X64:40s 
//等待时间超长...
void W25QXX_Erase_Chip(void)   
{                                             
                        W25QXX_Write_Enable();                  //SET WEL 
                        W25QXX_Wait_Busy();   
                        W25QXX_CS=0;                            //使能器件   
                        W25Qxx_ReadWriteByte(W25X_ChipErase);        //发送片擦除命令  
                        W25QXX_CS=1;                            //取消片选                   
                        W25QXX_Wait_Busy();                                      //等待芯片擦除结束
}   
//擦除一个扇区
//Dst_Addr:扇区地址 0~511 for w25x16
//擦除一个山区的最少时间:150ms
void W25QXX_Erase_Sector(u32 Dst_Addr)   
{   
                        Dst_Addr*=4096;
                        W25QXX_Write_Enable();                  //SET WEL          
                        W25QXX_Wait_Busy();   
                        W25QXX_CS=0;                            //使能器件   
                        W25Qxx_ReadWriteByte(W25X_SectorErase);      //发送扇区擦除指令 
                        W25Qxx_ReadWriteByte((u8)((Dst_Addr)>>16));  //发送24bit地址    
                        W25Qxx_ReadWriteByte((u8)((Dst_Addr)>>8));   
                        W25Qxx_ReadWriteByte((u8)Dst_Addr);  
                        W25QXX_CS=1;                            //取消片选                   
                        W25QXX_Wait_Busy();                                      //等待擦除完成
}  
//等待空闲
void W25QXX_Wait_Busy(void)   
{   
                        while ((W25QXX_ReadSR()&0x01)==0x01);   // 等待BUSY位清空
}  
//进入掉电模式
void W25QXX_PowerDown(void)   
{ 
                        W25QXX_CS=0;                            //使能器件   
                        W25Qxx_ReadWriteByte(W25X_PowerDown);        //发送掉电命令  
                        W25QXX_CS=1;                            //取消片选                   
                        delay_us(3);                               //等待TPD  
}   
//唤醒
void W25QXX_WAKEUP(void)   
{  
                        W25QXX_CS=0;                            //使能器件   
                        W25Qxx_ReadWriteByte(W25X_ReleasePowerDown);   //  send W25X_PowerDown command 0xAB    
                        W25QXX_CS=1;                            //取消片选                   
                        delay_us(3);                               //等待TRES1
}   
 
 
 
 
 
 
 | 
 
×本帖子中包含更多资源您需要 登录 才可以下载或查看,没有账号?立即注册 
  |