一、简介:接口与内存一样,代码可以直接在Nor Flash上执行,无需复制到内存中。它能像内存一样读但不能像内存一样写。其写入需要发命令。所以读操作效率非常高,但擦除和写操作效率很低。优点是没有位反转,没有坏块。稳定。一般而言,Nor Flash用于存储程序,NAND Flash用于存储数据。基于NAND Flash的设备通常也要搭配Nor Flash以存储程字。
二、Nor Flash 的读写操作:
notes:
①、CPU 的地址线与 Nor Flash 的接法,关系到数据传输的数值。如果0地址接A0,就无需偏移。如果地址1接A0,需要将数据左移一位,才能给 flash 传入正确参数,从而从正确的地址读出信息。
②、任意模式操作完成后,需要 reset (往任意地址写 f0) ,以便下一个模式正常使用。
③、操作 Nor Flash 时,切忌进入异常、中断模式,会引起不可预期的错误。
④、arm处理器的核使用其对应的arm体系结构版本,每个版本对应指令集不同。可通过在标签中 -march= 选项来指定体系结构。如:ARM7TDMI处理器加入-march=armv4t表示支持V4T的指令集,从而解决了没有加入-march选项时编译器将半字或字的strh和str操作自动编译成了2个strb或4个strb指令,另外使用armv4t替代armv4则解决了armv4对bx指令不支持的错误。
⑤、CPU 写之前必须擦除(解锁+命令):
三、Nor Flash 的两种规范:(Flash 的规格参数等信息)
1、jedec:老式规范。用命令读出ID,并与 Linux 内核中数组(jedec_probe.c 中的 jedec_table[ ])比较。若数组中没有,则还需修改数组。
2、cfi(common flash interface):一般往地址 55H 写入 98H,进入CFI模式。往相应地址写入数值,能得到需要的信息。指令如下:
四、编程规范:
1、读写数据要根据芯片接法进行封装移位:
#define NOR_FLASH_BASE base_addr // base_addr为基地址
void nor_write_word(unsigned int base, unsigned int offset, unsigned int val) {
volatile unsigned short *p = (volatile unsigned short *)(base + (offset << 1));
*p = val;
}
void nor_cmd(unsigned int offset, unsigned int cmd) { // 命令形式。写数据
nor_write_word(NOR_FLASH_BASE, offset, cmd);
}
unsigned int nor_read_word(unsigned int base, unsigned int offset) { // 读
volatile unsigned short *p = (volatile unsigned short *)(base + (offset << temp)); // 位移值 temp 根据芯片位数和接法确定
return *p;
}
unsigned int nor_dat(unsigned int offset) { // 数据形式,读模式
return nor_read_word(NOR_FLASH_BASE, offset);
}
2、CFI 模式:进入之后必须退出,最好写在同一个函数体中。
nor_cmd(0x555, 0xaa); // 解锁
nor_cmd(0x2aa, 0x55); // 解锁
nor_cmd(0x555, 0x90); // read id
vendor = nor_dat(0); // 厂家ID
device = nor_dat(1); // 设备ID
nor_cmd(0, 0xf0); // reset
nor_cmd(0x55, 0x98); //进入cfi模式
size = 1<<(nor_dat(0x27)); // 容量
regions = nor_dat(0x2c); // region 数量。一个 region 中至少有一个 block
region_info_base = 0x2d; // 起始地址
block_addr = 0; // 块首地址
cnt = 0; // 计数器
for (i = 0; i < regions; i++) {
blocks = 1 + nor_dat(region_info_base) + (nor_dat(region_info_base+1)<<8); // block数量。数值表示 index,从0开始
block_size=256*(nor_dat(region_info_base+2)+(nor_dat(region_info_base+3)<<8)); // 每个 block 大小
region_info_base += 4; // 第二个 region。共4个
for (j = 0; j < blocks; j++) { // 打印block的起始地址
printHex(block_addr);
putchar(' ');
block_addr += block_size;
if (++cnt % 5 == 0)
printf("\n\r"); }
}
nor_cmd(0x00, 0xf0); // reset
3、判断操作是否结束:( 读l两次数据, Q6无变化时表示结束)
void wait_ready(unsigned int addr) {
unsigned int val, pre;
pre = nor_dat(addr>>1);
val = nor_dat(addr>>1);
while ((val & (1<<6)) != (pre & (1<<6))) {
pre = val;
val = nor_dat(addr>>1);
}
}
4、擦除:
void do_erase_nor_flash(void) {
unsigned int addr;
printf("Enter the address of sector to erase: "); // 获得地址
addr = get_uint();
printf("erasing ...");
nor_cmd(0x555, 0xaa); // 解锁
nor_cmd(0x2aa, 0x55);
nor_cmd(0x555, 0x80); // erase sector 命令
nor_cmd(0x555, 0xaa); // 解锁
nor_cmd(0x2aa, 0x55);
nor_cmd(addr>>1, 0x30); // 发出扇区地址
wait_ready(addr); // 等待
}
5、写:
void do_write_nor_flash(void) {
unsigned int addr, val;
unsigned char str[100];
int i = 0, j = 1; // 下标
printf("Enter the address of sector to write: ");
addr = get_uint(); // 获得地址
printf("Enter the string to write: ");
gets(str);
printf("writing ...\n\r");
while (str[i] && str[j]) {
val = str[i] + (str[j]<<8); // 两个8位组成一个16位进行存储
nor_cmd(0x555, 0xaa); // 解锁
nor_cmd(0x2aa, 0x55);
nor_cmd(0x555, 0xa0); // program
nor_cmd(addr>>1, val);
wait_ready(addr); // 等待
i += 2; j += 2; addr += 2; // 递增
}
val = str[i]; // 最后一个数据
nor_cmd(0x555, 0xaa); /* 解锁 */
nor_cmd(0x2aa, 0x55);
nor_cmd(0x555, 0xa0); // program
nor_cmd(addr>>1, val);
wait_ready(addr); // 等待
}
6、读:
void do_read_nor_flash(void) {
unsigned int addr;
volatile unsigned char *p;
int i, j;
unsigned char c, str[16];
printf("Enter the address to read: "); //获得地址
addr = get_uint();
p = (volatile unsigned char *)addr;
printf("Data : \n\r");
for (i = 0; i < 4; i++) { // 打印长度固定为16x4
for (j = 0; j < 16; j++) { // 打印数值
c = *p++; // 一元运算符由右向左结合。(unsigned char *)类型使得指针自增之后指向下一个char类型首地址
str[j] = c; // 存入数组
printf("%02x ", c);
}
printf(" ; ");
for (j = 0; j < 16; j++) { // 打印字符
if (str[j] < 0x20 || str[j] > 0x7e) // 不可视字符
putchar('.');
else
putchar(str[j]);
}
printf("\n\r");
}