foggia2004

访问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编辑  收藏  举报

导航