Flash基础入门之Nor Flash工作原理
小标 2018-06-11 来源 : 阅读 1479 评论 0

摘要:本文主要向大家介绍了Flash基础入门的Nor Flash工作原理,通过具体的内容向大家展现,希望对大家学习Flash基础入门有所帮助。

    本文主要向大家介绍了Flash基础入门的Nor Flash工作原理,通过具体的内容向大家展现,希望对大家学习Flash基础入门有所帮助。

    Nor Flash 具有像内存一样的接口,它可以像内存一样读,却不可以像内存一样写,Nor Flash 的写、擦除都需要发出特定的命令。谈到 Nor Flash 通常就会涉及到 CFI ([Common Flash Interface) 接口,一般 Nor Flash 都支持发命令来读取厂家 ID 和 设备 ID 等基本信息,但并不是所有的 Nor Flash 都支持发命令来获取和芯片本身容量大小、扇区数、擦除块大小等信息。为了让将来的 Nor Flash 兼容性更好,引进了 CFI 接口,将芯片有关的信息都写入芯片内部,通过 CFI 命令就可以获取这些信息。
    Linux 内核中对各种型号的 Nor Flash 都有很好的支持 ,但是其组织复杂,不利于分析。这里选用 u-boot 里面的 Nor Flash 代码来分析。代码位于:u-boot-2010.06/board/samsung/smdk2410/flash.c 。
    通常内核里面要识别一个 Nor Flash 有两种方法:一种是 jedec 探测,就是在内核里面事先定义一个数组,该数组里面放有不同厂家各个芯片的一些参数,探测的时候将 flash 的 ID 和数组里面的 ID 一一比较,如果发现相同的,就使用该数组的参数。另一种是 cfi 探测,就是直接发各种命令来读取芯片的信息,比如 ID、容量等。jedec 探测的优点就是简单,缺点是如果内核要支持的 flash 种类很多,这个数组就会很庞大。../samsung/smdk2410/flash.c 文件采用的是第一种方法,但是还是有些区别的,内核里面用 jedec 探测一个芯片时,是先通过发命令来获取 flash 的 ID,然后和数组比较,但是 flash.c 中连 ID 都是自己通过宏配置的。

unsigned long flash_init (void)
{
    for (i = 0; i < CONFIG_SYS_MAX_FLASH_BANKS; i++) 
    {
        ulong flashbase = 0;
        //设置 flash_id ,这个标志保存厂家 ID 和 设备 ID
        flash_info[i].flash_id =
#if defined(CONFIG_AMD_LV400)
            (AMD_MANUFACT & FLASH_VENDMASK) | (AMD_ID_LV400B & FLASH_TYPEMASK);
#elif defined(CONFIG_AMD_LV800)
            (AMD_MANUFACT & FLASH_VENDMASK) | (AMD_ID_LV800B & FLASH_TYPEMASK);
#else
            #error "Unknown flash configured"
#endif
        //设置 flash 大小和扇区数
        flash_info[i].size = FLASH_BANK_SIZE;
        flash_info[i].sector_count = CONFIG_SYS_MAX_FLASH_SECT;
        //对于 flash 的每个扇区,都需要保存扇区的首地址
        for (j = 0; j < flash_info[i].sector_count; j++)     
        {
            ......      
            flash_info[i].start[j] = flashbase + (j - 3) * MAIN_SECT_SIZE;
        }
        size += flash_info[i].size;    //片外所有flash 的总大小
    }
    //对代码区的扇区设置写保护,这里只是软件的一种设定
    flash_protect (FLAG_PROTECT_SET, CONFIG_SYS_FLASH_BASE,
               CONFIG_SYS_FLASH_BASE + monitor_flash_len - 1,
               &flash_info[0]);  
    //如果环境变量保存在 nor 里面,还需对这些扇区设置写保护
    flash_protect (FLAG_PROTECT_SET, CONFIG_ENV_ADDR,
               CONFIG_ENV_ADDR + CONFIG_ENV_SIZE - 1, &flash_info[0]);
                            
    return size;    //返回 flash 大小
}


    flash_init() 函数主要是做一些 flash 的初始化,比如设置 flash 的 ID、大小、扇区数等来构造 flash_info_t 结构体,但是从上面的代码可以看出,在该初始化函数中并没有做任何与硬件有关的初始化,所有的值都是通过外部赋值,也就是说我们可以给这些成员变量赋任何我们想要的值,哪怕这些值并不是 flash 真正的参数,虽然这些值并不影响本函数的调用,但是和下面这些函数就有密切关系。 

int flash_erase (flash_info_t * info, int s_first, int s_last)
{
    //参看是否有写保护扇区,有直接返回错误
    prot = 0;
    for (sect = s_first; sect <= s_last; ++sect)
    {
        if (info->protect[sect]) 
            prot++;
    }
    if (prot)
        return ERR_PROTECTED;
    //关闭中断等,防止擦除过程被中断
    cflag = icache_status ();
    icache_disable ();
    iflag = disable_interrupts ();
    /* Start erase on unprotected sectors */
    for (sect = s_first; sect <= s_last && !ctrlc (); sect++) 
    {
        printf ("Erasing sector %2d ... ", sect);
        /* arm simple, non interrupt dependent timer */
        reset_timer_masked ();
        if (info->protect[sect] == 0)    //此处的判断有点多余 
        {   /* not protected */
            //取扇区的首地址
            vu_short *addr = (vu_short *) (info->start[sect]);    
            //发解锁和擦除扇区命令
            MEM_FLASH_ADDR1 = CMD_UNLOCK1;    //往地址 0x555<<1 写入 0xAA
            MEM_FLASH_ADDR2 = CMD_UNLOCK2;    //往地址 0x2AA<<1 写入 0x55
            MEM_FLASH_ADDR1 = CMD_ERASE_SETUP;//往地址 0x555<<1 写入 0x80
            MEM_FLASH_ADDR1 = CMD_UNLOCK1;    
            MEM_FLASH_ADDR2 = CMD_UNLOCK2;
            *addr = CMD_ERASE_CONFIRM;    //往地址 0x555<<1 写入 0x30
            /* wait until flash is ready */
            chip = 0;
            do 
            {
                result = *addr;    //读取该扇区首地址里面的值
                /* check timeout */
                if (get_timer_masked () > CONFIG_SYS_FLASH_ERASE_TOUT)
                {
                    MEM_FLASH_ADDR1 = CMD_READ_ARRAY;
                    chip = TMO;
                    break;
                }
                //BIT_ERASE_DONE = 0x80,即判断 DQ7 是否为 1
                if (!chip && (result & 0xFFFF) & BIT_ERASE_DONE)  
                    chip = READY;
                //BIT_PROGRAM_ERROR = 0x20,即判断 DQ5 是否为 1
                if (!chip && (result & 0xFFFF) & BIT_PROGRAM_ERROR)
                    chip = ERR;
            } while (!chip);
            MEM_FLASH_ADDR1 = CMD_READ_ARRAY; //往地址 0x555<<1 写入 0xF0
            ......
            printf ("ok.\n");
        } 
        else 
        {    /* it was protected */
            printf ("protected!\n");
        }
    }
    ......
    /* allow flash to settle - wait 10 ms */
    udelay_masked (10000);
    return rc;
}


    对于擦除工作,不可能瞬间完成,如何检测芯片是否已经完成擦除工作是我们所关心的,当然你可以用一个很长的延时来确保芯片肯定已经完成擦除,但是一款芯片一定会提供相应的状态供我们检测,利用这些状态位可以减少程序中不必要的等待。下面这些描述是摘自芯片手册。  
Flash基础入门之Nor Flash工作原理

    以上就介绍了Flash的相关知识,希望对Flash有兴趣的朋友有所帮助。了解更多内容,请关注职坐标常用软件Flash频道!

本文由 @小标 发布于职坐标。未经许可,禁止转载。
喜欢 | 0 不喜欢 | 0
看完这篇文章有何感觉?已经有0人表态,0%的人喜欢 快给朋友分享吧~
评论(0)
后参与评论

您输入的评论内容中包含违禁敏感词

我知道了

助您圆梦职场 匹配合适岗位
验证码手机号,获得海同独家IT培训资料
选择就业方向:
人工智能物联网
大数据开发/分析
人工智能Python
Java全栈开发
WEB前端+H5

请输入正确的手机号码

请输入正确的验证码

获取验证码

您今天的短信下发次数太多了,明天再试试吧!

提交

我们会在第一时间安排职业规划师联系您!

您也可以联系我们的职业规划师咨询:

小职老师的微信号:z_zhizuobiao
小职老师的微信号:z_zhizuobiao

版权所有 职坐标-一站式IT培训就业服务领导者 沪ICP备13042190号-4
上海海同信息科技有限公司 Copyright ©2015 www.zhizuobiao.com,All Rights Reserved.
 沪公网安备 31011502005948号    

©2015 www.zhizuobiao.com All Rights Reserved

208小时内训课程