访问FLASH设备-W25X16
/************************************* *文件名称: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 =7; //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=0; W25X16_CS=0; 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)<<8; //送0xff,读取数据 temp|=w25x16_spi_read_write_byte(0xff); W25X16_CS=1; return temp; }
SPI的读写操作
/*读取一个字节的数据 //_data:要写入的数据 //SPI特性:如果要得到一个数据,则取返回值;如果要写入一个数据,则忽略返回的数据. */ u8 w25x16_spi_read_write_byte(u8 _data) { u8 temp=0; //如果发送区是空的,则最多尝试100次就返回错误 while(SPI_I2S_GetFlagStatus(SPI1,SPI_I2S_FLAG_TXE == RESET)) { if(temp++>100) return 0; } SPI_I2S_SendData(SPI1,_data); temp=0; //如果接收区是空的,则最多尝试100次就返回错误 while(SPI_I2S_GetFlagStatus(SPI1,SPI_I2S_FLAG_RXNE) == RESET) { if(temp++>100) return 0; } 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=0; w25x16_spi_read_write_byte(W25X16_READ_DATA); //发送读数据命令,忽略返回的数据 w25x16_spi_read_write_byte((u8)((_readaddr)>>16)); //右移16位,但只取低8位,因为有U8的强制转换 w25x16_spi_read_write_byte((u8)((_readaddr)>>8)); //右移8位,还是只取低8位,因为有U8的强制转换 w25x16_spi_read_write_byte((u8)((_readaddr))); //将地址的低8位写入s for(i=0;i<_datasize;i++) { _data[i]=w25x16_spi_read_write_byte(0xff); //写空数据,得到指定长度的数据 } W25X16_CS=1; }
等待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=0; w25x16_spi_write_enable(); w25x16_spi_read_write_byte(W25X16_PAGE_PROGRAM); //发送指令 w25x16_spi_read_write_byte((u8)((_writeaddr)>>16)); w25x16_spi_read_write_byte((u8)((_writeaddr)>>8)); w25x16_spi_read_write_byte((u8)_writeaddr); for(i=0;i<_datasize;i++) w25x16_spi_read_write_byte(_data[i]); W25X16_CS=1; 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*4096; //要写入的flash首地址 write_pages_num=_datasize/256; //要写入的满页面数量 //首先擦除该删除的数据,擦除后数据为0xff w25x16_spi_erase_sector(_sectorid); //写入满页的数据 for(i=0;i<write_pages_num;i++) { w25x16_spi_write_page(((u8*)(_data+i*256)),write_addr+i*256,256); //每次写满256个字节,满页的写入数据 } //写入剩余的数据,如果数据小于256,则直接写入 w25x16_spi_write_page(((u8*)(_data + write_pages_num*256)),write_addr + write_pages_num*256,_datasize - write_pages_num*256); }
/*擦除指定的扇区数据 //_sector_id:扇区编号 0~511 */ void w25x16_spi_erase_sector(u32 _sector_id) { u32 sector_addr=_sector_id*4096; w25x16_spi_write_enable(); w25x16_spi_wait_busy(); W25X16_CS=0; myspi_read_write_byte(W25X16_SECTOR_ERASE); //送扇区擦除指令 myspi_read_write_byte((u8)((sector_addr)>>16)); //右移16位,用u8强制转换,取D23-D16 myspi_read_write_byte((u8)((sector_addr)>>8)); //右移8位,用u8强制转换,取D15-D8 myspi_read_write_byte((u8)sector_addr); //用u8强制转换,取D7-D0 W25X16_CS=1; w25x16_spi_wait_busy(); }
posted on 2016-03-28 15:45 foggia2004 阅读(973) 评论(0) 编辑 收藏 举报