访问FLASH设备-W25X16

时间:2022-01-04 14:46:26
/*************************************
*文件名称:w25x16_spi.c
*
*功能描述:访问和写入数据到闪存w25x16
*
*建立日期:2016-03-16
*
* w25x16
*共8192页*256字节/页=2097152字节
*2097152字节/512个扇区=4096字节/扇区
*
*Block(块)-->Sector(扇区)-->Page(页)-->256(字节)
* 32 512 8192
*************************************/

.H文件的定义

#define W25X16_CS PORTA_OUT(2)   //片选信号

/* w25x16指令 */
#define W25X16_WRITE_ENABLE 0x06
#define W25X16_WRITE_DISABLE 0x04
#define W25X16_READ_DATA 0x03
#define W25X16_READ_QUICK 0x0b
#define W25X16_READ_DOUBLE 0x3b
#define W25X16_READ_STATUS_REG 0x05
#define W25X16_WRITE_STATUS_REG 0x01
#define W25X16_PAGE_PROGRAM 0x02
#define W25X16_SECTOR_ERASE 0x20
#define W25X16_BLOCK_ERASE 0xd8
#define W25X16_CHIP_ERASE 0xc7
#define W25X16_POWER_OFF 0xb9
#define W25X16_POWER_ON 0xab
#define W25X16_DEVICE_ID 0x90
#define W25X16_JEDEC_ID 0x9f
#define W25X16_MANUFACTDEVICE_ID 0x90

.C文件的函数

初始化SPI接口

/*************************************
*文件名称:w25x16_spi.c
*
*功能描述:访问和写入数据到闪存w25x16
*
*建立日期:2016-03-16
*
*FLASH设备名称:w25x16
*共8192页*256字节/页=2097152字节
*2097152字节/512个扇区=4096字节/扇区
*
*Block(块)-->Sector(扇区)-->Page(页)-->256(字节)
* 32 512 8192
*************************************/ mySPI.SPI_BaudRatePrescaler=SPI_BaudRatePrescaler_256; //分频
mySPI.SPI_CPHA =SPI_CPHA_2Edge; //第2个跳变沿数据被采样
mySPI.SPI_CPOL =SPI_CPOL_High; //空闲状态为高电平
mySPI.SPI_CRCPolynomial =; //CRC值计算
mySPI.SPI_DataSize =SPI_DataSize_8b; //以1个byte为单位
mySPI.SPI_Direction =SPI_Direction_2Lines_FullDuplex; //双线双向全双工
mySPI.SPI_FirstBit =SPI_FirstBit_MSB; //数据传输从MSB位开始
mySPI.SPI_Mode =SPI_Mode_Master; //设置为主SPI模式
mySPI.SPI_NSS =SPI_NSS_Soft; //NSS信号由软件控制 SPI_Init(SPI1,&mySPI);
SPI_Cmd(SPI1, ENABLE); //使能SPI外设

读取FLASH的ID

u16 w25x16_spi_read_id(void)
{
u16 temp=;
W25X16_CS=; w25x16_spi_read_write_byte(W25X16_DEVICE_ID); //发送指令
w25x16_spi_read_write_byte(0x00);
w25x16_spi_read_write_byte(0x00);
w25x16_spi_read_write_byte(0x00);
temp|=w25x16_spi_read_write_byte(0xff)<<; //送0xff,读取数据
temp|=w25x16_spi_read_write_byte(0xff);
W25X16_CS=; return temp;
}

SPI的读写操作

/*读取一个字节的数据
//_data:要写入的数据
//SPI特性:如果要得到一个数据,则取返回值;如果要写入一个数据,则忽略返回的数据.
*/
u8 w25x16_spi_read_write_byte(u8 _data)
{
u8 temp=; //如果发送区是空的,则最多尝试100次就返回错误
while(SPI_I2S_GetFlagStatus(SPI1,SPI_I2S_FLAG_TXE == RESET))
{
if(temp++>)
return ;
} SPI_I2S_SendData(SPI1,_data);
temp=; //如果接收区是空的,则最多尝试100次就返回错误
while(SPI_I2S_GetFlagStatus(SPI1,SPI_I2S_FLAG_RXNE) == RESET)
{
if(temp++>)
return ;
} return SPI_I2S_ReceiveData(SPI1);
}

读取FLASH指定位置的数据

/*读取FLASH中指定位置的数据
//_data :数据存储数组
//_readaddr:要开始读取的flash地址,此地址分3次写入,每次写入8位
//_datasize:要读取的数据大小
*/
void w25x16_spi_read(u8* _data,u32 _readaddr,u16 _datasize)
{
u16 i;
W25X16_CS=;
w25x16_spi_read_write_byte(W25X16_READ_DATA); //发送读数据命令,忽略返回的数据
w25x16_spi_read_write_byte((u8)((_readaddr)>>)); //右移16位,但只取低8位,因为有U8的强制转换
w25x16_spi_read_write_byte((u8)((_readaddr)>>)); //右移8位,还是只取低8位,因为有U8的强制转换
w25x16_spi_read_write_byte((u8)((_readaddr))); //将地址的低8位写入s
for(i=;i<_datasize;i++)
{
_data[i]=w25x16_spi_read_write_byte(0xff); //写空数据,得到指定长度的数据
}
W25X16_CS=;
}

等待FLASH忙信号

/*  等待忙信号  */
void w25x16_spi_wait_busy(void)
{
//寄存器第一位如果还是1,则继续等待,直到0为止
while((w25x16_spi_read_sr()&0x01)==0x01); //w25x16_spi_read_sr()&0x01:取结果的第一位数值
}

写入指定位置的数据

/*  写入指定地址的数据  */
//_data :要写入的数据
//_writeaddr:要写入的地址
//_datasize :要写入的数据大小
void w25x16_spi_write_page(u8* _data,u32 _writeaddr,u16 _datasize)
{
u16 i;
W25X16_CS=;
w25x16_spi_write_enable();
w25x16_spi_read_write_byte(W25X16_PAGE_PROGRAM); //发送指令
w25x16_spi_read_write_byte((u8)((_writeaddr)>>));
w25x16_spi_read_write_byte((u8)((_writeaddr)>>));
w25x16_spi_read_write_byte((u8)_writeaddr);
for(i=;i<_datasize;i++)
w25x16_spi_read_write_byte(_data[i]); W25X16_CS=;
w25x16_spi_wait_busy(); //等待完成操作
}
/**************************************
//根据扇区编号写入数据
//_sectorid:删除编号
//一个扇区有16页,每页256字节.一个扇区共16*256=4096字节
//用页编程模式,每次编程256字节,如果要写4096字节,则要连续编程16次
**************************************/
void w25x16_spi_write_by_sectorid(u16 _sectorid,u8* _data,u32 _datasize)
{
u8 i,write_pages_num; //要写入的满页面的数量,一个页面256字节
u32 write_addr=_sectorid*; //要写入的flash首地址 write_pages_num=_datasize/; //要写入的满页面数量 //首先擦除该删除的数据,擦除后数据为0xff
w25x16_spi_erase_sector(_sectorid); //写入满页的数据
for(i=;i<write_pages_num;i++)
{
w25x16_spi_write_page(((u8*)(_data+i*)),write_addr+i*,); //每次写满256个字节,满页的写入数据
} //写入剩余的数据,如果数据小于256,则直接写入
w25x16_spi_write_page(((u8*)(_data + write_pages_num*)),write_addr + write_pages_num*,_datasize - write_pages_num*); }
/*擦除指定的扇区数据
//_sector_id:扇区编号 0~511
*/
void w25x16_spi_erase_sector(u32 _sector_id)
{
u32 sector_addr=_sector_id*;
w25x16_spi_write_enable();
w25x16_spi_wait_busy();
W25X16_CS=;
myspi_read_write_byte(W25X16_SECTOR_ERASE); //送扇区擦除指令
myspi_read_write_byte((u8)((sector_addr)>>)); //右移16位,用u8强制转换,取D23-D16
myspi_read_write_byte((u8)((sector_addr)>>)); //右移8位,用u8强制转换,取D15-D8
myspi_read_write_byte((u8)sector_addr); //用u8强制转换,取D7-D0
W25X16_CS=;
w25x16_spi_wait_busy();
}