电子工程师名片——SPI NOR 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 ;
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的更多相关文章
- 电子工程师名片——FAT16文件系统(转)
源:电子工程师名片——FAT16文件系统 从8月8号开始,连续一个月利用每天下班时间和周末的时间终于初步完成了一个电子工程师的电路板名片,就像U盘一样,不过这个FLASH只有64KB的大小,用的单片机 ...
- 电子工程师名片——FAT16文件系统
从8月8号开始,连续一个月利用每天下班时间和周末的时间终于初步完成了一个电子工程师的电路板名片,就像U盘一样,不过这个FLASH只有64KB的大小,用的单片机是C8051F320,是一个USB型的单片 ...
- 电子工程师名片——UFI Command,USB盘符的显示
USB Mass Storage类规范概述 USB Mass storage Device协议即海量存储设备协议适用于硬盘,U盘等大容量存储设备.协议使用的接口端点有BulkIn.Bul ...
- 快速开发MQTT(一)电子工程师眼中的MQTT
转载:https://zhuanlan.zhihu.com/p/54669124 DigCore 主页http://www.digcore.cn 文章首发于同名微信公众号:DigCore 欢迎关注同名 ...
- STM32F10X SPI操作flash MX25L64读写数据(转)
源:STM32F10X SPI操作flash MX25L64读写数据 前一段时间在弄SPI,之前没接触过嵌入式外围应用,就是单片机也只接触过串口通信,且也是在学校的时候了.从离开手机硬件测试岗位后,自 ...
- spi nor flash使用汇总
Overview SPI flash, 分为spi flash, DUAL spi flash, QUAD spi flash, 3-wire spi, 4-wire spi, 6-wire spi. ...
- SPI操作flash MX25L64读写数据
STM32F10X SPI操作flash MX25L64读写数据 简单的一种应用,ARM芯片作为master,flash为slaver,实现单对单通信.ARM主控芯片STM32F103,flash芯片 ...
- 【DSP开发】TMS320C66x DSP SPI Nor Flash的程序烧写
经过一段时间的研究终于把TMS320C6657单核和双核的SPI Nor Flash的程序烧写调通了.工具都是前辈的工作,有需要的可以留下邮箱,我有空可以发. 原理参考钱丰的<TI c66x 系 ...
- STM32—SPI读写FLASH
目录 FLASH简介 W25Q64 W25Q64简介 FLASH控制指令 FLASH内部存储结构 代码讲解 读取芯片ID 发送写使能信号 等待FLASH不忙 擦除扇区 写入数据 读取数据 注 FLAS ...
随机推荐
- TypeError: not enough arguments for format string
到一个问题,表示100% 的时候,出现这个问题. 因为python语法会认为是你需要转移符,这个时候你可以选择100%% 来表示
- 关于sencha touch 的JSONP跨域请求的学习研究
此篇文章是对自己在研究学习sencha touch的过程中的点滴记录,主要是JSONP的跨域请求这方面,对于何为是跨域概念还有不熟悉的,可以自己问下度娘. 先上张图: 我要完成的功能就是表格下拉刷新, ...
- VS2008资源问题解决方法
错误提示:C:/Program Files/Microsoft SDKs/Windows/v6.0A// Include/PrSht.h(0) error RC2247 : SYMBOL name t ...
- 通过Excel来集中管理资源文件
在支持双语或多语种项目中,常常需要编辑多个文件来添加资源项,感觉比较繁琐,所以想做一个可以集中管理资源文件的工具.借助Excel,使用Excel来记录,并且通过Excel可以进行分页分模块来规划 ...
- c++ 05
一.单例模式 二.成员指针 class Student { public: string m_name; void print (void) { ... } }; 1.指向成员变量的指针 成员 ...
- 利用sql 存储过程把表中内容自动生成insert语句
选中所在数据库 执行创建存储过程的sql CREATE proc [dbo].[spGenInsertSQL] (@tablename nvarchar(256),@sqlwhere varchar( ...
- Android_Studio 及SDK下载
Android Studio includes all the tools you need to build apps for Android. DOWNLOAD ANDROID STUDIO 2. ...
- 可持久化Trie树
代码 ; struct PerTrie { ][ChSize]; ]; void init() { memset(next[],,])); inf[]=; id=; } int GetId(char ...
- 12 个 Linux 进程管理命令介绍
执行中的程序在称作进程.当程序以可执行文件存放在存储中,并且运行的时候,每个进程会被动态得分配系统资源.内存.安全属性和与之相关的状态.可以有多个进程关联到同一个程序,并同时执行不会互相干扰.操作系统 ...
- Linux 块设备驱动 (二)
linux下Ramdisk驱动 1 什么是Ramdisk Ramdisk是一种模拟磁盘,其数据实际上是存储在RAM中,它使用一部分内存空间来模拟出一个磁盘设备,并以块设备的方式来组织和访问这片内存.对 ...