23.硬件 - Nor Flash

一、简介:接口与内存一样,代码可以直接在Nor Flash上执行,无需复制到内存中。它能像内存一样读但不能像内存一样写。其写入需要发命令。所以读操作效率非常高,但擦除和写操作效率很低。优点是没有位反转,没有坏块。稳定。一般而言,Nor Flash用于存储程序,NAND Flash用于存储数据。基于NAND Flash的设备通常也要搭配Nor 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 写之前必须擦除(解锁+命令):

Word方式



三、Nor Flash 的两种规范:(Flash 的规格参数等信息)

    1、jedec:老式规范。用命令读出ID,并与 Linux 内核中数组(jedec_probe.c 中的 jedec_table[ ])比较。若数组中没有,则还需修改数组。

    2、cfi(common flash interface):一般往地址 55H 写入 98H,进入CFI模式。往相应地址写入数值,能得到需要的信息。指令如下:

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

}

你可能感兴趣的:(23.硬件 - Nor Flash)