加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

SPI FLASH_W25Q64驱动 代码

发布时间:2020-12-15 18:05:23 所属栏目:百科 来源:网络整理
导读:#include "flash.h" #include "spi.h" #include "delay.h"??? #include "usart.h"??? //////////////////////////////////////////////////////////////////////////////////? //本程序只供学习使用,未经作者许可,不得用于其它任何用途 //SPI FLASH_W25Q64

#include "flash.h"
#include "spi.h"
#include "delay.h"???
#include "usart.h"???
//////////////////////////////////////////////////////////////////////////////////?
//本程序只供学习使用,未经作者许可,不得用于其它任何用途
//SPI FLASH_W25Q64驱动 代码??????????
//////////////////////////////////////////////////////////////////////////////////

u16 SPI_FLASH_TYPE=W25Q64;//默认就是25Q64

//4Kbytes为一个Sector
//16个扇区为1个Block
//W25Q64
//容量为8M字节,共有128个Block,2048个Sector
?????????????
//初始化SPI FLASH的IO口
void SPI_Flash_Init(void)
{
?RCC->APB2ENR|=1<<3;???? //使能PORTB时钟 ????
??RCC->APB2ENR|=1<<5;??//使能PORTD时钟
??RCC->APB2ENR|=1<<8;??//使能PORTG时钟
?GPIOB->CRH&=0XFFF0FFFF;
?GPIOB->CRH|=0X00030000;?//PB12 推挽 ????
?GPIOB->ODR|=1<<12;??? ?//PB12上拉
?//这里pd2和pg7拉高,是为了防止NRF24L01和SD卡影响FLASH的烧写.
?//因为他们共用一个SPI口.
?GPIOD->CRL&=0XFFFFF0FF;
?GPIOD->CRL|=0X00000300;?//PD2 推挽 ????
?GPIOD->ODR|=1<<2;??? ?//PD2上拉

?GPIOG->CRL&=0X0FFFFFFF;
?GPIOG->CRL|=0X30000000;?//PG7 推挽 ????
?GPIOG->ODR|=1<<7;??? ?//PG7 上拉
?SPI2_Init();???? ?//初始化SPI
?SPI2_SetSpeed(SPI_SPEED_2);//设置为18M时钟,高速模式
?SPI_FLASH_TYPE=SPI_Flash_ReadID();//读取FLASH ID.
}?

//读取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=0;??????????????????????????? //使能器件??
?SPI2_ReadWriteByte(W25X_ReadStatusReg);??? //发送读取状态寄存器命令???
?byte=SPI2_ReadWriteByte(0Xff);???????????? //读取一个字节?
?SPI_FLASH_CS=1;??????????????????????????? //取消片选????
?return byte;??
}
//写SPI_FLASH状态寄存器
//只有SPR,TB,BP0(bit 7,5,4,3,2)可以写!!!
void SPI_FLASH_Write_SR(u8 sr)??
{??
?SPI_FLASH_CS=0;??????????????????????????? //使能器件??
?SPI2_ReadWriteByte(W25X_WriteStatusReg);?? //发送写取状态寄存器命令???
?SPI2_ReadWriteByte(sr);?????????????? //写入一个字节?
?SPI_FLASH_CS=1;??????????????????????????? //取消片选???? ??????
}??
//SPI_FLASH写使能?
//将WEL置位??
void SPI_FLASH_Write_Enable(void)??
{
?SPI_FLASH_CS=0;??????????????????????????? //使能器件??
??? SPI2_ReadWriteByte(W25X_WriteEnable);????? //发送写使能?
?SPI_FLASH_CS=1;??????????????????????????? //取消片选???? ??????
}
//SPI_FLASH写禁止?
//将WEL清零?
void SPI_FLASH_Write_Disable(void)??
{?
?SPI_FLASH_CS=0;??????????????????????????? //使能器件??
??? SPI2_ReadWriteByte(W25X_WriteDisable);???? //发送写禁止指令???
?SPI_FLASH_CS=1;??????????????????????????? //取消片选???? ??????
} ??
//读取芯片ID
//返回值如下:??????
//0XEF13,表示芯片型号为W25Q80?
//0XEF14,表示芯片型号为W25Q16???
//0XEF15,表示芯片型号为W25Q32?
//0XEF16,表示芯片型号为W25Q64?? ??
u16 SPI_Flash_ReadID(void)
{
?u16 Temp = 0;??
?SPI_FLASH_CS=0;???????
?SPI2_ReadWriteByte(0x90);//发送读取ID命令????
?SPI2_ReadWriteByte(0x00); ????
?SPI2_ReadWriteByte(0x00); ????
?SPI2_ReadWriteByte(0x00); ? ?????
?Temp|=SPI2_ReadWriteByte(0xFF)<<8;?
?Temp|=SPI2_ReadWriteByte(0xFF);?
?SPI_FLASH_CS=1;???????
?return Temp;
}?? ?????
//读取SPI FLASH?
//在指定地址开始读取指定长度的数据
//pBuffer:数据存储区
//ReadAddr:开始读取的地址(24bit)
//NumByteToRead:要读取的字节数(最大65535)
void SPI_Flash_Read(u8* pBuffer,u32 ReadAddr,u16 NumByteToRead)??
{
??u16 i;?? ?????????????
?SPI_FLASH_CS=0;??????????????????????????? //使能器件??
??? SPI2_ReadWriteByte(W25X_ReadData);???????? //发送读取命令??
??? SPI2_ReadWriteByte((u8)((ReadAddr)>>16));? //发送24bit地址???
??? SPI2_ReadWriteByte((u8)((ReadAddr)>>8));??
??? SPI2_ReadWriteByte((u8)ReadAddr);??
??? for(i=0;i<NumByteToRead;i++)
?{
??????? pBuffer[i]=SPI2_ReadWriteByte(0XFF);?? //循环读数?
??? }
?SPI_FLASH_CS=1;? ??????? ??????
}?
//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=0;??????????????????????????? //使能器件??
??? SPI2_ReadWriteByte(W25X_PageProgram);????? //发送写页命令??
??? SPI2_ReadWriteByte((u8)((WriteAddr)>>16)); //发送24bit地址???
??? SPI2_ReadWriteByte((u8)((WriteAddr)>>8));??
??? SPI2_ReadWriteByte((u8)WriteAddr);??
??? for(i=0;i<NumByteToWrite;i++)SPI2_ReadWriteByte(pBuffer[i]);//循环写数?
?SPI_FLASH_CS=1;??????????????????????????? //取消片选
?SPI_Flash_Wait_Busy();??????? //等待写入结束
}
//无检验写SPI FLASH
//必须确保所写的地址范围内的数据全部为0XFF,否则在非0XFF处写入的数据将失败!
//具有自动换页功能
//在指定地址开始写入指定长度的数据,但是要确保地址不越界!
//pBuffer:数据存储区
//WriteAddr:开始写入的地址(24bit)
//NumByteToWrite:要写入的字节数(最大65535)
//CHECK OK
void SPI_Flash_Write_NoCheck(u8* pBuffer,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)??
u8 SPI_FLASH_BUFFER[4096];??
void SPI_Flash_Write(u8* pBuffer,u16 NumByteToWrite)??
{
?u32 secpos;
?u16 secoff;
?u16 secremain;???
??u16 i;???
?u8 * SPI_FLASH_BUF;??
?? ?SPI_FLASH_BUF=SPI_FLASH_BUFFER;?????
??secpos=WriteAddr/4096;//扇区地址?
?secoff=WriteAddr%4096;//在扇区内的偏移
?secremain=4096-secoff;//扇区剩余空间大小??
??//printf("ad:%X,nb:%Xrn",NumByteToWrite);//测试用
??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,4096);//写入整个扇区?

??}else SPI_Flash_Write_NoCheck(pBuffer,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;???//下一个扇区可以写完了 ??}? ?};? } //擦除整个芯片??? //等待时间超长... void SPI_Flash_Erase_Chip(void)?? {?????????????????????????????????? ??? SPI_FLASH_Write_Enable();????????????????? //SET WEL ??? SPI_Flash_Wait_Busy();?? ? ?SPI_FLASH_CS=0;??????????????????????????? //使能器件?? ??? SPI2_ReadWriteByte(W25X_ChipErase);??????? //发送片擦除命令? ?SPI_FLASH_CS=1;??????????????????????????? //取消片选???? ?????? ?SPI_Flash_Wait_Busy();?? ?????? //等待芯片擦除结束 }?? //擦除一个扇区 //Dst_Addr:扇区地址 根据实际容量设置 //擦除一个山区的最少时间:150ms void SPI_Flash_Erase_Sector(u32 Dst_Addr)?? {? ?//监视falsh擦除情况,测试用?? ??printf("fe:%xrn",Dst_Addr);?? ??Dst_Addr*=4096; ??? SPI_FLASH_Write_Enable();????????????????? //SET WEL ? ??? SPI_Flash_Wait_Busy();?? ? ?SPI_FLASH_CS=0;??????????????????????????? //使能器件?? ??? SPI2_ReadWriteByte(W25X_SectorErase);????? //发送扇区擦除指令 ??? SPI2_ReadWriteByte((u8)((Dst_Addr)>>16));? //发送24bit地址??? ??? SPI2_ReadWriteByte((u8)((Dst_Addr)>>8));?? ??? SPI2_ReadWriteByte((u8)Dst_Addr);? ?SPI_FLASH_CS=1;??????????????????????????? //取消片选???? ?????? ??? SPI_Flash_Wait_Busy();?? ?????? //等待擦除完成 }? //等待空闲 void SPI_Flash_Wait_Busy(void)?? {?? ?while((SPI_Flash_ReadSR()&0x01)==0x01);?? // 等待BUSY位清空 }? //进入掉电模式 void SPI_Flash_PowerDown(void)?? { ? ?SPI_FLASH_CS=0;??????????????????????????? //使能器件?? ??? SPI2_ReadWriteByte(W25X_PowerDown);??????? //发送掉电命令? ?SPI_FLASH_CS=1;??????????????????????????? //取消片选???? ?????? ??? delay_us(3);?????????????????????????????? //等待TPD? }?? //唤醒 void SPI_Flash_WAKEUP(void)?? {? ? ?SPI_FLASH_CS=0;??????????????????????????? //使能器件?? ??? SPI2_ReadWriteByte(W25X_ReleasePowerDown);?? //? send W25X_PowerDown command 0xAB??? ?SPI_FLASH_CS=1;??????????????????????????? //取消片选???? ?????? ??? delay_us(3);?????????????????????????????? //等待TRES1 }??

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读