You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
incubator_embeded/HARDWARE/W25Q128.c

216 lines
9.9 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

#include "W25Q128_Ins.h"
#include "MYSPI.h"
#include "SysTick.h"
#include "USART.h"
u16 W25QXX_TYPE=W25Q128; //型号W25Q1284K字节为一个扇区16个扇区为1个块容量为16M字节,共128个块,4096个扇区//
//初始化SPI FLASH的IO口//
void W25QXX_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOA, ENABLE );//PORTB时钟使能
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4; // PB12对应该闪存的CS引脚//
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //推挽输出//
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_SetBits(GPIOA,GPIO_Pin_4); //PB12置高电平//
W25QXX_CS=1; //SPI FLASH不选中其实跟上一行代码实现功能一样//
SPI1_Init(); //初始化SPI//
SPI1_SetSpeed(SPI_BaudRatePrescaler_2); //重新设置波特率为18M时钟,高速模式//
W25QXX_TYPE=W25QXX_ReadID(); //读取FLASH ID//
}
//编写读取W25QXX的状态寄存器函数这里只读取S0-S7位的值//
u8 W25QXX_ReadSR(void)
{
u8 byte=0;
W25QXX_CS=0; //使能器件//
SPI1_ReadWriteByte(W25X_ReadStatusReg); //发送读取状态寄存器指令W25X_ReadStatusReg=0x05可忽略接收值//
byte=SPI1_ReadWriteByte(0Xff); //读取一个字节发送0xff读取回来的值传至byte//
W25QXX_CS=1; //取消片选
return byte;
}
//编写写入W25QXX状态寄存器函数这里只有SPR,TB,BP2,BP1,BP0(bit 7,5,4,3,2)可以写???//
void W25QXX_Write_SR(u8 sr)
{
W25QXX_CS=0; //使能器件//
SPI1_ReadWriteByte(W25X_WriteStatusReg);//发送写入状态寄存器指令W25X_WriteStatusReg=0x01忽略接收值//
SPI1_ReadWriteByte(sr); //写入一个字节,忽略接收值//
W25QXX_CS=1; //取消片选//
}
//W25QXX写入使能将WEL置1//
void W25QXX_Write_Enable(void)
{
W25QXX_CS=0; //W25QXX_CS对应PBout(12)即PB12置0//
SPI1_ReadWriteByte(W25X_WriteEnable); //写入使能W25X_WriteEnable的指令为0x06//
W25QXX_CS=1; //取消片选即PB12置1//
}
//W25QXX写入禁止将WEL清零即置0//
void W25QXX_Write_Disable(void)
{
W25QXX_CS=0; //使能器件//
SPI1_ReadWriteByte(W25X_WriteDisable); //发送写入禁止指令W25X_WriteDisable为0x04//
W25QXX_CS=1; //取消片选//
}
//读取芯片ID本开发版返回值0XEF17,表示芯片型号为W25Q128//
u16 W25QXX_ReadID(void)
{
u16 Temp = 0;
W25QXX_CS=0;
SPI1_ReadWriteByte(0x90); //发送读取ID命令即0x90//
SPI1_ReadWriteByte(0x00); //后面跟一个24位0x000000地址//
SPI1_ReadWriteByte(0x00);
SPI1_ReadWriteByte(0x00);
Temp|=SPI1_ReadWriteByte(0xFF)<<8; //读取Manufacturer ID号即0xEF//
Temp|=SPI1_ReadWriteByte(0xFF); //读取Device ID号即0x17//
W25QXX_CS=1;
return Temp;
}
//pBuffer:数据存储区ReadAddr:开始读取的地址(24bit)NumByteToRead:要读取的字节数(最大65535)//
void W25QXX_Read(u8* pBuffer,u32 ReadAddr,u16 NumByteToRead)
{
u16 i;
W25QXX_CS=0; //使能器件//
SPI1_ReadWriteByte(W25X_ReadData); //发送读取指令,W25X_ReadData为0x03//
SPI1_ReadWriteByte((u8)((ReadAddr)>>16)); //发送24bit地址最低的8位//
SPI1_ReadWriteByte((u8)((ReadAddr)>>8)); //发送24bit地址次低的8位//
SPI1_ReadWriteByte((u8)ReadAddr); //发送24bit地址高8位//
for(i=0;i<NumByteToRead;i++)
{
pBuffer[i]=SPI1_ReadWriteByte(0XFF); //循环读数每次读1个字节//
}
W25QXX_CS=1;
}
//SPI在一页(0~65535个字节)内写入少于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; //使能器件//
SPI1_ReadWriteByte(W25X_PageProgram); //发送写页命令W25X_PageProgram为0x02//
SPI1_ReadWriteByte((u8)((WriteAddr)>>16)); //发送24bit地址最低的8位//
SPI1_ReadWriteByte((u8)((WriteAddr)>>8)); //发送24bit地址次低的8位//
SPI1_ReadWriteByte((u8)WriteAddr); //发送24bit地址高8位//
for(i=0;i<NumByteToWrite;i++)
SPI1_ReadWriteByte(pBuffer[i]); //循环写数,每次写1个字节//
W25QXX_CS=1; //取消片选//
W25QXX_Wait_Busy(); //等待写入结束//
}
//无检验写入SPI FLASH确保所写地址范围内的数据全部为0XFF,否则在非0XFF处写入的数据将失败//
//具有自动换页功能,在指定地址开始写入指定长度的数据,但是要确保地址不越界//
//pBuffer:数据存储区WriteAddr:开始写入的地址(24bit)NumByteToWrite:要写入的字节数(最大65535)//
void W25QXX_Write_NoCheck(u8* pBuffer,u32 WriteAddr,u16 NumByteToWrite)
{
u16 pageremain;
pageremain=256-WriteAddr%256; //单页剩余的字节数//
if(NumByteToWrite<=pageremain) //判断要写入的字节数是否小于单页剩余的字节数//
pageremain=NumByteToWrite; //如果小于就将NumByteToWrite值赋给pageremain//
while(1)
{
W25QXX_Write_Page(pBuffer,WriteAddr,pageremain); //一次写入少于256个字节的数据//
if(NumByteToWrite==pageremain)break; //如果写入字节数小于剩余字节数,则写完//
else
{
pBuffer+=pageremain;
WriteAddr+=pageremain;
NumByteToWrite-=pageremain; //减去已经写入了的字节数//
if(NumByteToWrite>256)pageremain=256; //一次可以写入256个字节//
else pageremain=NumByteToWrite; //不够256个字节//
}
};
}
//写SPI FLASH在指定地址开始写入指定长度的数据该函数带擦除操作//
//pBuffer:数据存储区WriteAddr:开始写入的地址(24bit)NumByteToWrite:要写入的字节数(最大65535)//
u8 W25QXX_BUFFER[4096]; //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; //扇区起始地址//
secoff=WriteAddr%4096; //在该扇区内的偏移量//
secremain=4096-secoff; //扇区剩余空间大小//
if(NumByteToWrite<=secremain)
secremain=NumByteToWrite; //不大于4096个字节//
while(1)
{
W25QXX_Read(W25QXX_BUF,secpos*4096,4096); //读出整个扇区的内容保存在W25QXX_BUF里//
for(i=0;i<secremain;i++) //校验数据
{
if(W25QXX_BUF[secoff+i]!=0XFF)break; //判断是否需要擦除//
}
if(i<secremain)
{
W25QXX_Erase_Sector(secpos); //擦除这个扇区//
for(i=0;i<secremain;i++)
{
W25QXX_BUF[i+secoff]=pBuffer[i]; //把要写的数据写到W25QXX_BUF缓存中//
}
W25QXX_Write_NoCheck(W25QXX_BUF,secpos*4096,4096); //一次性吧缓存W25QXX_BUFFER的数据写到对应的sector//
}
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; //下一个扇区可以写完//
}
};
}
//擦除整个芯片,等待时间超长//
void W25QXX_Erase_Chip(void)
{
W25QXX_Write_Enable(); //SET WEL//
W25QXX_Wait_Busy();
W25QXX_CS=0; //使能器件//
SPI1_ReadWriteByte(W25X_ChipErase); //发送片擦除命令,W25X_ChipErase为0xC7//
W25QXX_CS=1; //取消片选//
W25QXX_Wait_Busy(); //等待芯片擦除结束//
}
//擦除一个扇区Dst_Addr:扇区地址 根据实际容量设置,擦除一个扇区的最少时间:150ms//
void W25QXX_Erase_Sector(u32 Dst_Addr)
{
Dst_Addr*=4096;
W25QXX_Write_Enable(); //SET WEL//
W25QXX_Wait_Busy();
W25QXX_CS=0; //使能器件//
SPI1_ReadWriteByte(W25X_SectorErase); //发送扇区擦除指令,W25X_SectorErase为0x20//
SPI1_ReadWriteByte((u8)((Dst_Addr)>>16)); //发送24bit地址//
SPI1_ReadWriteByte((u8)((Dst_Addr)>>8));
SPI1_ReadWriteByte((u8)Dst_Addr);
W25QXX_CS=1; //取消片选//
W25QXX_Wait_Busy(); //等待擦除完成//
}
//等待空闲函数只有当状态寄存器的S0位BUSY置0时循环结束//
void W25QXX_Wait_Busy(void)
{
while((W25QXX_ReadSR()&0x01)==0x01);
}
//进入掉电模式//
void W25QXX_PowerDown(void)
{
W25QXX_CS=0; //使能器件//
SPI1_ReadWriteByte(W25X_PowerDown); //发送掉电命令W25X_PowerDown为0xB9//
W25QXX_CS=1; //取消片选//
delay_us(3); //等待tDP//
}
//唤醒,释放掉电模式//
void W25QXX_WAKEUP(void)
{
W25QXX_CS=0; //使能器件//
SPI1_ReadWriteByte(W25X_ReleasePowerDown); //发生释放掉电指令ReleasePowerDown为0xAB//
W25QXX_CS=1; //取消片选//
delay_us(3); //等待TRES1//
}