历史上的今天
今天是:2025年03月05日(星期三)
2020年03月05日 | 【ARM裸板】Nor Flash基础知识与编程示例
2020-03-05 来源:eefocus
1.NOR与NAND的区别
Flash NOR NAND
接口 RAM-Like,引脚多 引脚少,复用(地址数据共用)
容量 小(1-32M) 大(128M+)
读 简单 复杂
写 发出特定命令(慢) 发出特定命令(快)
价格 贵 较便宜
缺点 无位反转、坏块 位反转、坏块
一般存放 bootloader(关键程序) 大文件、视频
xip 可以 不可以
xip(eXecute In Place),即芯片内执行,指应用程序可以直接在flash闪存内运行,不必再把代码读到系统RAM中。flash内执行是指nor flash 不需要初始化,可以直接在flash内执行代码。但往往只执行部分代码,比如初始化RAM.
2.命令表


UBOOT下读写数据
2.1 读数据
md.b为读命令
mw.w为写命令
md.b 0
2.2 读ID
Nor手册
往(555H)写入AAH
往(2AAH)写入55H
往(555H)写入90H
读(0)得到厂家(Manifacture)ID:C2H
读(1)得到设备(Device)ID:22C4/2249

但是由于地址是错开1位的(具体原因可查看第15章),则往CPU写的地址需要addr<<1,即(地址*2)因此:
UBOOT下
往(AAAH)写入AAH
往(554H)写入55H (这两步为解锁命令)
往(AAAH)写入90H(90H为命令)
读(0H)得到厂家(Manifacture)ID:C2H
读(2H)得到设备(Device)ID:22C4/2249
退出读ID状态(即复位)
mw.w aaa aa
mw.w 554 55
mw.w aaa 90
md.w 0 1 #读0地址1次
md.w 2 1
mw.w 0 F0
2.3 CFI模式
CFI(Common Flash Interface)
Nor手册
往(55H)写入98H(进入CFI模式)
读(27H)得到容量2^n的n
退出CFI模式(复位)
UBOOT下
往(AAH)写入98H(进入CFI模式)
读(4EH)得到容量2^n的n
往(0H)写入F0H
3.基本函数
3.1 写函数
Nor Flash 地址线21:即可访问2M内存,0x1FFFFF,其范围地址为 0~0x1FFFFF
#define NOR_FLASH_BASE 0 /* Nor Flash基地址 nor-->cs0,base_addr = 0 */
/* Nor Flash写入一个字
* 基地址:base,偏移地址:offset,写入的值:value
* eg: 55 98
* 往(0 + (0x55)<<1 )写入0x98
*/
void nor_write_word(unsigned int base,unsigned int offset,unsigned short value)
{
volatile unsigned short *p = (volatile unsigned short *) (base + offset<<1);
*p = value;
}
进行封装
void nor_cmd(unsigned int offset,unsigned short cmd)
{
nor_write_word(NOR_FLASH_BASE, offset, cmd);
}
3.2 读函数
/* Nor Flash读取一个字
* 基地址:base,偏移地址:offset
* eg: 55 98
* 往(0 + (0x55)<<1 )写入0x98
*/
unsigned int nor_read_word(unsigned int base,unsigned int offset)
{
volatile unsigned short *p = (volatile unsigned short *) (base + offset<<1);
return *p;
}
进行封装
unsigned int nor_dat(unsigned int offset)
{
return nor_read_word(NOR_FLASH_BASE, offset);
}
4.识别NOR
4.1 读取ID号
往(555H)写入AAH
往(2AAH)写入55H
往(555H)写入90H
读(0)得到厂家(Manifacture)ID:C2H
读(1)得到设备(Device)ID:22C4/2249
/* 1.打印 Manifacture ID、Device ID */
nor_unlock(); //解锁
nor_cmd(0x555,0x90);//读命令
manifa_id = nor_dat(0x00); //读厂家ID
device_id = nor_dat(0x01); //读设备ID
nor_reset_mode(); //复位

4.2 进入CFI Mode
往(55H)写98H
CFI(Common Flash Interface)
/* 1.进入CFI Mode */
nor_cmd(0x55,0x98);

4.3 读取容量
读(27H)得到容量bytes
/* 2.打印容量 */
size = 1<<(nor_dat(0x27));
printf("nor size = 0x%x, %dMrn",size,size>>20);

4.4 读取各个扇区
4.4.1 获得region数量
regions = nor_dat(0x2C);
1
4.4.2 region详细信息
erase block region :里面含有1个或多个block,它们大小都一样,一个nor含有1个或多个region,一个region含有1个或多个block(扇区)
Erase block region information:
前2字节+1:表示该region有多少个block
后2字节*256:表示该block的大小(bytes)

参考CFI标准:

regions的基址从0x2D开始
region_info_base = 0x2D;
block_addr = 0;
for(i = 0;i < regions; i++){
/* 获取block的数量和大小 */
blocks = 1 + nor_dat(region_info_base) + (nor_dat(region_info_base+1)<<8);//低2字节,获取block数量
block_size = 256 * (nor_dat(region_info_base+2) + (nor_dat(region_info_base+3)<<8));//高2字节,获取block大小
region_info_base += 4;//region读取的基址+4
/* 打印每个block的起始地址 */
for(j = 0;j < blocks; j++){
printf("0x%08x ",block_addr);
block_addr += block_size;
if( ((++cnt) % 5) == 0){ //每打印5个换行
printf("rn");
}
}
}
4.5 退出CFI Mode
nor_cmd(0x00,0xF0);//复位

5.写数据
5.1 写入
需要注意一个点,写入的数据是16位的,也就是两个字节,需要一次性写入一个字节,所以在写入之前需要对数据进行整合。
while(str[i] && str[i+1]){//两个字符都不为0时
data = str[i] + (str[i+1]<<8);
nor_unlock();//解锁
nor_cmd(0x555,0xA0); //写命令
nor_cmd(addr>>1,data);
/* 等待烧写完成:读数据Q6,无变化时表示完成*/
wait_ready(addr);
i += 2;
addr += 2;
}

5.2 判断数据写入完成
等待烧写完成:读数据Q6,无变化时表示完成
两次读取的结果不一致,说明数据还在变化,继续等待
//等待读取或擦除完毕
void wait_ready(unsigned int addr)
{
unsigned int pre_val;//上一次的值
unsigned int cur_val;
pre_val = nor_dat(addr>>1);
cur_val = nor_dat(addr>>1);
/* 两次读取的结果不一致,说明数据还在变化,继续等待 */
while((cur_val & (1<<6) != (pre_val &(1<<6)))){//当前的Q6不等于上一次的Q6则等待
pre_val = cur_val;//更新上一次的值
val = nor_dat(addr>>1);//重新获取
}
}


6.测试
6.1 读取

6.2 写入

6.3 擦除

7.问题
7.1 系统异常卡死
执行多次的菜单选择,导致系统卡死
该为定时器造成的异常错误,关闭定时器,则不会卡死
因为当测试nor进入CFI模式时,如果发生了中断,CPU必定读NOR,那么读不到正确的指令,导致程序异常崩溃
7.2 nor数据错误
读取设备ID时,读到的是0x002f,0xea00,改为反汇编中text的[0]上的数据
编译程序加上选项:指定ARM版本指令集-march=armv4 或者指定芯片类型 -mcpu=arm9tdmi
否则像如下的写入操作会被分成两个strb步骤(我们需要的是strh,一次性写入两个字节),最后导致读取设备ID和厂家ID的时候出错。
volatile unsigned short *p =value;
*p = value;
没加编译指定选项(分两次存2个字节)

加了编译指定芯片类型 -mcpu=arm9tdmi(一次性存2个字节)

8.擦除扇区
void erase_nor_flash(void)
{
unsigned int addr;
/* 获得地址*/
printf("Enter the address of sector to erase:");
addr = get_uint();
printf("Erase...rn");
nor_unlock();
nor_cmd(0x555,0x80); //擦除扇区命令
nor_unlock();
nor_cmd(addr>>1,0x30); //发出扇区地址
wait_ready(addr);
}
史海拾趣
|
【瑞萨 CPK-RA2L1 开发板】测评 - 1:安装 BSP 本帖最后由 MianQi 于 2022-11-12 20:34 编辑 从用户的角度来说,E2 Studio 中最重要的组成部分是两个: 1、 Flexible Software Package (FSP) ,下载地址:https://github.com/renesas/fsp;这个类似于Android 的 SDK - 软件开发包,它有版 ...… 查看全部问答> |
|
[RTT&瑞萨超低功耗MCU RA2L1开发板]测评之基于MDK+RT-Thread的开发环境搭建 本帖最后由 qinyunti 于 2022-11-12 10:27 编辑 准备 前提已经安装MDK和JLINK我这里 MDK版本 V5.37 JLINK版本 V7.82(V7.5以上) 开发板资料参考 https://www2.renesas.cn/cn/zh/products/microcontrollers-microprocess ...… 查看全部问答> |
|
[RTT&瑞萨超低功耗MCU RA2L1开发板]测评之SPI模块介绍驱动分析与测试 SPI模块介绍 参考<<Renesas RA2L1 Group User’s Manual: Hardware>>的章节<<28. Serial Peripheral Interface (SPI) >> 特征 2通道 支持全双工和仅发送模式,支持3线制和4线制 RSPCK极性反转,相位 ...… 查看全部问答> |
|
以前有一个树莓派: 但是。。。没有HDMI的小头的线。。。 这一次,又弄了线,又弄了盒子,甚至于还有天线,也许可以好好的玩玩树莓派了。。。 感谢电子工程世界(eeworld),感谢e络盟(element14) … 查看全部问答> |
|
【行空板 Python编程学习主控板】开箱报告 首先真诚感谢eeword、DFRobot给了我这次参与《DFRobot行空板Python编程学习板》评测的机会。11月7日收到快递通知,因最近一直出差在外,周五回来后拿到快递,立即开箱,首先映入眼帘的是印有行空板及lo ...… 查看全部问答> |
|
一周工作终于结束,每天加班到很晚,都没有什么时间来学习行空板,赶紧趁着周末把玩一下。 所谓工欲善其事必先利其器,我玩任何开发板都有个习惯,那就是上手前先要熟悉一下该板子的硬件设计, ...… 查看全部问答> |
|
【行空板 Python编程学习主控板】评测三、开发板初探之连接方式介绍 在上篇测评二中,对行空板的硬件系统进行了初步的了解,这篇文章对行空板的几种连接方式进行介绍。 行空板支持四种连接方式与开发者的电脑进行连 ...… 查看全部问答> |
|
[RTT&瑞萨超低功耗MCU RA2L1开发板]测评之DAC模块介绍与测试 [localvideo]9fb1cabad83ad0154eb76903f1caaa2f[/localvideo] DAC模块介绍 参考<<Renesas RA2L1 Group User’s Manual: Hardware>>的章节<<31. 12-Bit D/A Converter (DAC12)>> 特征 12位带运放,1通道 ...… 查看全部问答> |
|
【行空板 Python编程学习主控板】评测四、开发板初探之WEB服务器介绍 本帖最后由 天意无罪 于 2022-11-13 20:29 编辑 在上篇评测三中,对行空板的4种连接方式进行了简单介绍,这篇测评文章便介绍通过USB Type-C线连接到行空板自带的WEB服务器,并查看其WEB服务功能有哪 ...… 查看全部问答> |




