使用了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 ;
    SPI_WRITE_ENABLE();    //设置状态器WEL位为1,在进行写状态寄存器之前必须写使能
    status=SPI_READ_STATUS();

    NSSMD0=;
    SPI0DAT=FLASH_WRITE_STATUS;
    while(!SPIF);
    SPIF=;

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

    NSSMD0=;//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    //擦除一个扇区

];//缓冲区全局变量,可以保存一个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=;

    SPI0DAT=FLASH_READ_ID;
    while(!SPIF);
    SPIF=;

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

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

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

    NSSMD0=;
}

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

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

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

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

    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 ;
    SPI_WRITE_ENABLE();    //设置状态器WEL位为1,在进行写状态寄存器之前必须写使能
    status=SPI_READ_STATUS();

    NSSMD0=;
    SPI0DAT=FLASH_WRITE_STATUS;
    while(!SPIF);
    SPIF=;

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

    NSSMD0=;//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 ;
    SPI_WRITE_ENABLE();

    NSSMD0=;

    SPI0DAT=FLASH_SECTOR_ERASE;
    while(!SPIF);
    SPIF=;

    //any address in the sector,but i choose the first address of sector
    SPI0DAT=0x00;            //high address
    while(!SPIF);
    SPIF=;
    SPI0DAT=sectors<<;        //middle address
    while(!SPIF);
    SPIF=;
    SPI0DAT=0x00;            //low address
    while(!SPIF);
    SPIF=;

    NSSMD0=;

    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 ];
//读一页256 bytes
void SPI_READ_Page(unsigned char sectors,unsigned char pages)
{
    unsigned ;
    NSSMD0=;
    SPI0DAT=FLASH_READ_DATA; //command
    while(!SPIF);
    SPIF=;

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

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

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

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

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

    NSSMD0=;

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

电子工程师名片——SPI NOR Flash的更多相关文章

  1. 电子工程师名片——FAT16文件系统(转)

    源:电子工程师名片——FAT16文件系统 从8月8号开始,连续一个月利用每天下班时间和周末的时间终于初步完成了一个电子工程师的电路板名片,就像U盘一样,不过这个FLASH只有64KB的大小,用的单片机 ...

  2. 电子工程师名片——FAT16文件系统

    从8月8号开始,连续一个月利用每天下班时间和周末的时间终于初步完成了一个电子工程师的电路板名片,就像U盘一样,不过这个FLASH只有64KB的大小,用的单片机是C8051F320,是一个USB型的单片 ...

  3. 电子工程师名片——UFI Command,USB盘符的显示

    USB Mass Storage类规范概述        USB Mass storage Device协议即海量存储设备协议适用于硬盘,U盘等大容量存储设备.协议使用的接口端点有BulkIn.Bul ...

  4. 快速开发MQTT(一)电子工程师眼中的MQTT

    转载:https://zhuanlan.zhihu.com/p/54669124 DigCore 主页http://www.digcore.cn 文章首发于同名微信公众号:DigCore 欢迎关注同名 ...

  5. STM32F10X SPI操作flash MX25L64读写数据(转)

    源:STM32F10X SPI操作flash MX25L64读写数据 前一段时间在弄SPI,之前没接触过嵌入式外围应用,就是单片机也只接触过串口通信,且也是在学校的时候了.从离开手机硬件测试岗位后,自 ...

  6. spi nor flash使用汇总

    Overview SPI flash, 分为spi flash, DUAL spi flash, QUAD spi flash, 3-wire spi, 4-wire spi, 6-wire spi. ...

  7. SPI操作flash MX25L64读写数据

    STM32F10X SPI操作flash MX25L64读写数据 简单的一种应用,ARM芯片作为master,flash为slaver,实现单对单通信.ARM主控芯片STM32F103,flash芯片 ...

  8. 【DSP开发】TMS320C66x DSP SPI Nor Flash的程序烧写

    经过一段时间的研究终于把TMS320C6657单核和双核的SPI Nor Flash的程序烧写调通了.工具都是前辈的工作,有需要的可以留下邮箱,我有空可以发. 原理参考钱丰的<TI c66x 系 ...

  9. STM32—SPI读写FLASH

    目录 FLASH简介 W25Q64 W25Q64简介 FLASH控制指令 FLASH内部存储结构 代码讲解 读取芯片ID 发送写使能信号 等待FLASH不忙 擦除扇区 写入数据 读取数据 注 FLAS ...

随机推荐

  1. Linux系统监控

    http://my.oschina.net/aiguozhe/blog/35730 http://my.oschina.net/aiguozhe/blog/35730

  2. 《Programming WPF》翻译 第7章 1.图形基础

    原文:<Programming WPF>翻译 第7章 1.图形基础 WPF使得在你的应用程序中使用图形很容易,以及更容易开发你的显卡的能力.这有很多图形构架的方面来达到这个目标.其中最重要 ...

  3. 【PAT L2-001】最短路计数

    给定一个无向带权网络,无负边,无重边和自环,每个顶点有一个正数权值.首先求特定原点s到终点d的最短路的个数:然后求所有最短路中顶点权值a[i]之和最大的那条,输出这条路径. 可用dijkstra算法求 ...

  4. postGreSQL数据库部署及简单使用

    1,deployByRuiyIns rpm -ivh http://yum.postgresql.org/9.4/redhat/rhel-6-x86_64/pgdg-centos94-9.4-1.no ...

  5. Java日志终极指南

    Java日志基础 Java使用了一种自定义的.可扩展的方法来输出日志.虽然Java通过java.util.logging包提供了一套基本的日志处理API,但你可以很轻松的使用一种或者多种其它日志解决方 ...

  6. php用apc实现的临界区 解决并发,资源互斥同步访问

    在面对线程或进程的互斥同步的控制问题时,常用的解决办法是:临界区,互斥锁,信号量 临界区保证在某一时刻只有一个线程能够访问到所需资源的方法. 任何时候,只能至多有一个线程处于临界区中.如果多个线程要求 ...

  7. 第01讲- Android背景知识

    第01讲Android背景知识 Android是基于Linux系统 Android系统框图 : 第一.操作系统层(OS) 第二.各种库(Libraries)和Android 运行环境(RunTime) ...

  8. Android --- 字符串\n的换行问题

    我的一段文字"测试文本\n测试文本\n测试文本\n测试文本\n测试文本\n测试文本\n". 该段文字放在一个txt文本内. 我用流读取后,显示在一个TextView里. 我期望的显 ...

  9. UGUI实现摇杆(模仿太极熊猫)

    核心代码: using UnityEngine; using System.Collections; using UnityEngine.UI; public delegate void Joysti ...

  10. pyqt tabWidget例子学习1

    from PyQt4 import QtGui from PyQt4 import QtCore from PyQt4.QtCore import pyqtSlot,SIGNAL,SLOT impor ...