SPI 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);
}
时间: 2024-11-05 04:59:36

SPI Flash的相关文章

spi flash偶尔出现写入错误的情况

spi flash W25Q128会偶尔出现写入错误的情况,会发现读出的值和写入的值不一致,需加入2次读出比较判断. W25QXX_Read(&temp_date_count,0x000000,1); //W25QXX_Write((u8*)&temp_date,0x400000,135); //W25QXX_Read((u8*)&temp_data_test,0x400000,135); W25QXX_Write((u8*)&temp_date,(temp_date_co

nand flash,nor flash,spi flash,片上RAM,片外RAM

Flash有掉电数据保存的特点,RAM掉电则数据丢失,但是RAM的速度更高,擦写次数理论上没有限制,而Flash则不行. Nand Flash相比其余的几种flash优势在于可擦写次数多,擦写速度快,但是在使用以及使用过程中会出现坏块因此需要做特殊 处理才可以使用.其主要用于数据存储,大部分U盘都是Nand Flash. Nor Flash读写时序类似于SRAM,只是写的次数较少,速度也慢,由于其读时序类似于SRAM,读地址是线性结构,多用于程序代码的 存储. SPI Flash同Nand Fl

FPGA设计——SPI Flash启动之MC8051设计

1. 概述 本设计采用FPGA技术,在FPGA中实现8051单片机的软核,将外部SPI Flash中的代码数据加载到FPGA内部ram,然后复位MC8051,实现外部flash启动MC8051. 2. 系统框图 8051采用Oregano Systems公司开源的MC8051软核.SPI Flash采用W25Q16芯片存储8051的代码程序.系统框图如下: 3. MC8051简介 Oregano Systems的8051单片机采用VHDL语言开发,具有如下特点: 采用完全同步设计 指令集和标准

Arduino SPI + SPI Flash芯片W25Q80BV

W25Q80BV是台湾华邦电子(Winbond)生产的8M-bit串行flash芯片.主要特性有: 工作电压:2.5 ~ 3.6 V 功耗:读写(active)时4mA,低功耗(power-down)时<1μA 容量:8M-bit/1M-byte,包含4096个页(每页大小256字节) 接口:Standard/Dual/Quad SPI,支持时钟频率最高104MHz 支持以4/32/64k-bytes为单位进行Sector/Block擦除 一次写入最多256字节 软件/硬件写保护功能 大于10万

转载:关于HI3516A 使用SDK06版本更换DDR和SPI FLASH遇到的问题和解决方法

HI3516A 更换DDR 和 FLASH 最近有新的需求需要使用SDK06版本,以及在硬件上更换了DDR和 FLASH,遇到了一些问题,这段时间搜索了很多hisi的资料和帖子,大概做了如下的总结,希望对大家有帮助,若有错误的地方或遗漏的地方,请指出.谢谢. 更换DDR 和 flash,则需要更新uboot,因为里面包含了DDR和flash的配置. 首先需要对hisi的uboot有所了解. hisi uboot分解为两部分.前面一部分为DDR的参数和其他寄存器的配置,总过大小为4K具体的地址为从

让MT7620完美支持32M SPI Flash(W25Q256) — 兼谈设备驱动中的shutdown方法

前言 OpenWrt的最新kernel(3.14.28)已经能够支持32M SPI Flash的读写以及擦除操作.然而,可能是系统考虑不周,亦或是MT7620系统的BUG,在配置了W25Q256的MT7620开发板系统上,无法soft reset!经过查阅相关资料,发现,MT7620默认支持24bit(3byte)的spi地址模式,而要支持32M以上的spi flash,则必须切换到32bit(4byte)地址模式.在soft reset的时候,spi停留在了32bit模式,没有切换回默认的24

Nand Flash,Nor Flash,CFI Flash,SPI Flash 之间的关系

前言:    在嵌入式开发中,如uboot的移植,kernel的移植都需要对Flash 有基本的了解.下面细说一下标题中的中Flash中的关系 一,Flash的内存存储结构    flash按照内部存储结构不同,分为两种:nor flash和nand flash. NorFLASH使用方便,易于连接,可以在芯片上直接运行代码,稳定性出色,传输速率高,在小容量时有很高的性价比,这使其很适合应于嵌入式系统中作为 FLASH ROM.    相对于NorFLASH,NandFLASH强调更高的性能,更

some company&#39;s Spi Flash chip replace altera epcsxxx

由于altera公司的epcsxxx芯片比较贵,所以一般用其它公司的spi flash芯片代替也可以.据AlteraFAE描述:“EPCS器件也是选用某家公司的SPIFlash,只是中间经过Altera公司的严格测试,所以稳定性及耐用性都超过通用的SPIFlash” 如ST 的M25P10-A, M25P40, M25P16 和 M25P64正好可以替代Altera 的EPCS1, EPCS4, EPCS16 和 EPCS64 some company's Spi Flash chip repl

(电工基地笔记)Vivado固化至SPI Flash

如果从头开始做SPI Flash固化是有一些麻烦的,要在完成综合之后,打开 synthesized Design (图) (图) 然后在synthesized Design打开状态下,选择Tools->Edit Device Properties编辑器件属性 (图) 我们这个FPGA有16MFlash,是Master SPIx1,大家有兴趣可以看一下Xilinx官网配置,你在此处修改都会保存在已经激活的xdc文件 (图) (图) (图) Finish就可以了,把synthesis去掉 (图) 我

创龙OMAPL138的SPI FLASH读写

1. 目前最大的疑问是OMAPL138和DSP6748的DSP部分是完全一样的吗(虽然知道芯片完全是引脚兼容的)?因此现在使用OMAPL138的DSP内核去读写一下外部的SPI FLASH芯片,先看下原理图,可惜创龙核心板的原理图不开源,所以我肯定不买他们家的板子 2. 尤其是startware这个软件库,究竟是用在ARM还是DSP的怎么区分?看资料ARM似乎可以唤醒DSP核? 3. 心血来潮,测试一下,同一个工程是不是可以同时用在ARM和DSP内核上,只是用不用的GEL文件.经过测试发现,如果