Flash基础入门之SPI Flash
小标 2019-01-24 来源 : 阅读 1530 评论 0

摘要:本文主要向大家介绍了Flash基础入门之SPI Flash,通过具体的内容向大家展现,希望对大家学习Flash基础入门有所帮助。

本文主要向大家介绍了Flash基础入门之SPI Flash,通过具体的内容向大家展现,希望对大家学习Flash基础入门有所帮助。

使用了MX25L512的SPI接口的Flash

电路连接图:

总的大小512kb,即64kB,sector的大小为256 Bytes,block的大小为4k Bytes
 
调试时出现的问题:
1、Flash只能读数据,不能写数据
        根源在于Flash的软件写保护没有去掉,这样,写、擦除,甚至写状态寄存器都不能执行。
1)Hardware Protection
Hardware Protection Mode(HPM):by using WP# going low to protect the BP0-BP1 bits and SRWD bit from data change

因为WP#是高电平,所以没有硬件保护,再来看软件保护。
 
2)Software Protection
Software Protection Mode(SPM):by using BP0-BP1 bits to set the part of flash protected from data change

通过下面几幅图可知,在WP#高电平情况下write status register可以改变SRWD、BP0、BP1的值为0,从而去掉软件写保护。
 

 

 
3)代码实现去除保护

//在所有需要修改的操作之前必须去除软件保护BP0,BP1
//FLASH的状态寄存器
//bit7        bit6    bit5    bit4    bit3    bit2    bit1            bit0
//SRWD        0         0          0        BP1        BP0        WEL                WIP
// 1=status write disable                            1=write enable    1=write in process
#define MASK_CLEAR_BPX 0x73    //掩码,设置使能写状态寄存器,清除BP1、BP0
void SPI_WRITE_STATUS()     //主要是清除保护,可以写数据
{
    unsigned char status=0;    
    SPI_WRITE_ENABLE();    //设置状态器WEL位为1,在进行写状态寄存器之前必须写使能
    status=SPI_READ_STATUS();
    
    NSSMD0=0;
    SPI0DAT=FLASH_WRITE_STATUS;
    while(!SPIF);
    SPIF=0;

    SPI0DAT=status&MASK_CLEAR_BPX;
    while(!SPIF);
    SPIF=0;

    NSSMD0=1;//cs must go high at the byte boundary,otherwise instruction will be reject and not executed

    do        //query until WIP convert from 1 to 0 when write status register cycle is finished
    {
        status=SPI_READ_STATUS();
        status=status&0x01;
    }while(status);
}

2、sector大小为256 Bytes,但是连续写256 Bytes,只有最后的32 Bytes写进去了
        在测试MX25L512的扇区的时候,老是遇到一个问题,写入256个字节,但是读出的是最后32个Bytes,前面的总是0xFF,于是就怀疑是不是扇区
的大小没有datasheet所说的那么大呢?最后测试发现扇区的大小只有32Bytes,如果连续写入的字节数大于32 Bytes,就会把除最后32 Bytes之外
的数据丢弃,只写最后的32 Bytes。仔细翻看datasheet,发现MX25L512MC-12G的扇区为256 Bytes,而MX25L512IE的扇区只有32Bytes原来具体
芯片规格和元件后缀名也有关系。
说明:sector是读写数据的最小单元,block是擦除的最小单元。(有时候sector概念类似于page,要看具体的芯片)
扇区被擦除后内部的数据变为0xFF。
 
3、SPI接口波形不对

虽然C8051F320已经交叉配置为串口和SPI接口,但是实际情况是还是要在输出的管脚PushPull,
P0MDOUT=0x1D;//0001 1101
否则可能SPI口的OUT输出驱动不了,导致波形都没有。
 
贴上Flash操作的代码:

#ifndef _SPI_CMD_H_
#define _SPI_CMD_H_

#include"misc.h"
////////////////////////////////////////////////
//////////////////MX25L512的flash说明///////////////////
//page:256byte
//sector:4kbyte
//注意MX25L512MC-12G page为256 bytes
//MX25L512IE.. page为32 bytes
///////////////////////////////////////////////

#define FLASH_READ_ID            0x9F     //读设备ID
#define FLASH_WRITE_ENABLE     0x06    //写使能
#define FLASH_WRITE_DISABLE     0x04    //写禁止
#define FLASH_READ_STATUS         0x05    //读状态寄存器
#define FLASH_WRITE_STATUS    0x01    //写状态寄存器
#define FLASH_READ_DATA        0x03    //读数据
#define FLASH_WRITE_DATA         0x02    //写数据
#define FLASH_SECTOR_ERASE     0x20    //擦除一个扇区

extern unsigned char xdata buff[256];//缓冲区全局变量,可以保存一个page的256字节
//在头文件中只是申明一下,不能定义,定义变量要在相应的C文件中定义
//以上不然会报错:multiple public definitions

void SPI_READ_ID();
void SPI_WRITE_ENABLE();
void SPI_WRITE_DISABLE();
unsigned char SPI_READ_STATUS();
void SPI_WRITE_STATUS();
void SPI_SECTOR_ERASE(unsigned char sectors);
void SPI_READ_Page(unsigned char sectors,unsigned char pages);
void SPI_WRITE_Page(unsigned char *str,unsigned char sectors,unsigned char pages);
void FillDBR();

#endif


#include"SPI_CMD.h"

//#define SPI0INT(x) {SPI0DAT=x;while(!SPIF);SPIF=0;}
//可以用这个定义来取代以下一大段的代码
//SPI0DAT=FLASH_READ_ID;
//while(!SPIF);               ----->SPI0DAT=FLASH_READ_ID;
//SPIF=0;
void SPI_READ_ID()
{
    NSSMD0=0;
    
    SPI0DAT=FLASH_READ_ID;
    while(!SPIF);
    SPIF=0;

    SPI0DAT=0;    //dummy write to output serial clock
    while(!SPIF); //wait for value to be read
    SPIF=0;
    sendChar(SPI0DAT);
    
    SPI0DAT=0;
    while(!SPIF);
    SPIF=0;
    sendChar(SPI0DAT);    

    SPI0DAT=0;
    while(!SPIF);
    SPIF=0;
    sendChar(SPI0DAT);

    NSSMD0=1;
}

void SPI_WRITE_ENABLE()
{
    NSSMD0=0;
    SPI0DAT=FLASH_WRITE_ENABLE;
    while(!SPIF);
    SPIF=0;
    NSSMD0=1;    
}

void SPI_WRITE_DISABLE()
{
    NSSMD0=0;
    SPI0DAT=FLASH_WRITE_DISABLE;
    while(!SPIF);
    SPIF=0;
    NSSMD0=1;    
}

unsigned char SPI_READ_STATUS()
{
    NSSMD0=0;
    SPI0DAT=FLASH_READ_STATUS;//可以将类似的这种形式做成一个宏定义
    while(!SPIF);
    SPIF=0;

    SPI0DAT=0;
    while(!SPIF);
    SPIF=0;
    NSSMD0=1;

    return SPI0DAT;
}

//在所有需要修改的操作之前必须去除软件保护BP0,BP1
//FLASH的状态寄存器
//bit7        bit6    bit5    bit4    bit3    bit2    bit1            bit0
//SRWD        0         0          0        BP1        BP0        WEL                WIP
// 1=status write disable                            1=write enable    1=write in process
#define MASK_CLEAR_BPX 0x73    //掩码,设置使能写状态寄存器,清除BP1、BP0
void SPI_WRITE_STATUS()     //主要是清除保护,可以写数据
{
    unsigned char status=0;    
    SPI_WRITE_ENABLE();    //设置状态器WEL位为1,在进行写状态寄存器之前必须写使能
    status=SPI_READ_STATUS();
    
    NSSMD0=0;
    SPI0DAT=FLASH_WRITE_STATUS;
    while(!SPIF);
    SPIF=0;

    SPI0DAT=status&MASK_CLEAR_BPX;
    while(!SPIF);
    SPIF=0;

    NSSMD0=1;//cs must go high at the byte boundary,otherwise instruction will be reject and not executed

    do        //query until WIP convert from 1 to 0 when write status register cycle is finished
    {
        status=SPI_READ_STATUS();
        status=status&0x01;
    }while(status);
}

void SPI_SECTOR_ERASE(unsigned char sectors)
{
    unsigned char status=0;
    SPI_WRITE_ENABLE();
        
    NSSMD0=0;
    
    SPI0DAT=FLASH_SECTOR_ERASE;
    while(!SPIF);
    SPIF=0;
    
    //any address in the sector,but i choose the first address of sector
    SPI0DAT=0x00;            //high address 
    while(!SPIF);
    SPIF=0;
    SPI0DAT=sectors<<4;        //middle address
    while(!SPIF);
    SPIF=0;
    SPI0DAT=0x00;            //low address
    while(!SPIF);
    SPIF=0;

    NSSMD0=1;

    do        //query until WIP convert from 1 to 0 when write status register cycle is finished
    {
        status=SPI_READ_STATUS();
        status=status&0x01;
    }while(status);
}

unsigned char xdata buff[256];
//读一页256 bytes
void SPI_READ_Page(unsigned char sectors,unsigned char pages)
{
    unsigned int i=0;
    NSSMD0=0;
    SPI0DAT=FLASH_READ_DATA; //command
    while(!SPIF);
    SPIF=0;

    SPI0DAT=0x00;             //read address
    while(!SPIF);
    SPIF=0;
    SPI0DAT=(sectors<<4) + pages;
    while(!SPIF);
    SPIF=0;
    SPI0DAT=0x00;
    while(!SPIF);
    SPIF=0;

    for(i=0;i<256;i++)            //read a page 256 bytes
    {                        //实测每页的数据只有32byte,所以一次连续写32byte
        SPI0DAT=0;                 //read datas out
        while(!SPIF);
        SPIF=0;
        buff[i]=SPI0DAT;
    }
    NSSMD0=1;
}

//写一页256 bytes
void SPI_WRITE_Page(unsigned char *str,unsigned char sectors,unsigned char pages)
{
    unsigned int i=0;
    unsigned char status=0;
    SPI_WRITE_ENABLE();      //在改变数据之前都要进行写使能操作
    NSSMD0=0;
    SPI0DAT=FLASH_WRITE_DATA; //write command
    while(!SPIF);
    SPIF=0;

    SPI0DAT=0x00;             //write address
    while(!SPIF);                //最高地址默认为0x00,所以不用传他的参数
    SPIF=0;
    SPI0DAT=(sectors<<4) + pages;
    while(!SPIF);
    SPIF=0;
    SPI0DAT=0x00;
    while(!SPIF);
    SPIF=0;

    for(i=0;i<256;i++)        //write a page 256 bytes
    {
        SPI0DAT=str[i];    //write data in
        while(!SPIF);
        SPIF=0;
    }
    
    NSSMD0=1;

    do        //query until WIP convert from 1 to 0 when write cycle is finished
    {
        status=SPI_READ_STATUS();
        status=status&0x01;
    }while(status);
}

以上就介绍了Flash的相关知识,希望对Flash有兴趣的朋友有所帮助。了解更多内容,请关注职坐标常用软件Flash频道!

本文由 @小标 发布于职坐标。未经许可,禁止转载。
喜欢 | 0 不喜欢 | 0
看完这篇文章有何感觉?已经有0人表态,0%的人喜欢 快给朋友分享吧~
评论(0)
后参与评论

您输入的评论内容中包含违禁敏感词

我知道了

助您圆梦职场 匹配合适岗位
验证码手机号,获得海同独家IT培训资料
选择就业方向:
人工智能物联网
大数据开发/分析
人工智能Python
Java全栈开发
WEB前端+H5

请输入正确的手机号码

请输入正确的验证码

获取验证码

您今天的短信下发次数太多了,明天再试试吧!

提交

我们会在第一时间安排职业规划师联系您!

您也可以联系我们的职业规划师咨询:

小职老师的微信号:z_zhizuobiao
小职老师的微信号:z_zhizuobiao

版权所有 职坐标-一站式IT培训就业服务领导者 沪ICP备13042190号-4
上海海同信息科技有限公司 Copyright ©2015 www.zhizuobiao.com,All Rights Reserved.
 沪公网安备 31011502005948号    

©2015 www.zhizuobiao.com All Rights Reserved

208小时内训课程