×
单片机 > 单片机程序设计 > 详情

【ARM裸板】Nor Flash基础知识与编程示例

发布时间:2020-08-21 发布时间:
|

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<

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);

}

关键字:ARM裸板  Nor  Flash  基础知识  编程示例

『本文转载自网络,版权归原作者所有,如有侵权请联系删除』

热门文章 更多
ARM 汇编的必知必会