售货机显示这flashlinux is errr 2是什么意思?

stm32flash编程手册中的pgerr位是什么意思_百度知道
stm32flash编程手册中的pgerr位是什么意思
我有更好的答案
Table 7. Boot modesBoot mode selection pins Boot mode AliasingBOOT1 BOOT0x 0 Main Flash memory Main Flash memory is selected as boot space0 1 System memory System memory is selected as boot space1 1 Embedded SRAM Embedded SRAM is selected as boot space两引脚控制启式 般都用第种 选择flash启 我般都载flash 用JLINK线仿真 载SRAM 需要改启式 SRAM掉电程序消失 flash属于ROM类型存储器 掉电丢失
采纳率:65%
来自团队:
为您推荐:
其他类似问题
您可能关注的内容
换一换
回答问题,赢新手礼包
个人、企业类
违法有害信息,请在下方选择后提交
色情、暴力
我们会通过消息、邮箱等方式尽快将举报结果通知您。增加nor flash功能 - u-boot-2009.08在mini2440上的移植_Linux编程_Linux公社-Linux系统门户网站
你好,游客
u-boot-2009.08在mini2440上的移植
增加nor flash功能
来源:Linux社区&
作者:singleboy
1,主机环境:VMare下 5.5 ,1G内存。
2,集成开发环境:Elipse IDE
3,编译编译环境:arm-linux-gcc v4.4.3,arm-none-eabi-gcc v4.5.1。
4,开发板:mini2440,2M nor flash,128M nand flash。
5,u-boot版本:u-boot-2009.08
通常,在嵌入式bootloader中,有两种方式来引导启动内核:从Nor Flash启动和从Nand Flash启动。u-boot中默认是从Nor Flash启动,再从上一节测试运行的结果的中看,还发现几个问题:第一,我开发板的Nor Flash是2M的,而这里显示的是512kB;第二,出现Warning - bad CRC, using default environment的警告信息。不是u-boot默认是从Nor Flash启动的吗?为什么会有这些错误信息呢?这是因为我们还没有添加对我们自己的Nor Flash的支持,u-boot默认的是其他型号的Nor Flash,而我们的Nor Flash的型号是SST39VF1601。另外怎样将命令行提示符前面的SMDK2410变成我自己定义的呢?下面我们一一来解决这些问题。
2.1,修改u-boot源码,使其完全支持Nor Flash。
【1】添加对我们mini2440开发板上2M的Nor Flash(型号为SST39VF1601)的支持
在虽然 S3C2440 和S3C2410 对于Nor Flash 的链接都是一样的,但是SBC2410 使用的AMD 的Nor Flash 芯片,而mini2440 使用的SST 的Nor Flash。这两款芯片在写入时所使用的块大小、时序和指令代码有差别,所以必须根据芯片的数据手册进行修改。主要的差别请看数据手册的对比:SST39VF1601:
&Am29LV160:
在u-boot中对Nor Flash的操作分别有初始化、擦除和写入,所以我们主要修改与硬件密切相关的三个函数flash_init、flash_erase、write_hword。
用gedit打开board/samsung/mini2440/flash.c,定位到31行附近,修改如下:
#define FLASH_BANK_SIZE&PHYS_FLASH_SIZE//#define MAIN_SECT_SIZE& 0x10000&/* 64 KB */#define MAIN_SECT_SIZE&&&& 0x1000& //定义为4k,刚好是一个扇区的大小
flash_info_t flash_info[CONFIG_SYS_MAX_FLASH_BANKS];
Nor Flash硬件连接
有原理图可知,一般NorFlash放在Bank0.所以CONFIG_SYS_BASE=0,但是开启mmu后baseaddr=地址0映射到的新地址。0x555&&1的原因是LADDR1与A0连接。也就是0x555表示片内第0x555个word(16bit)。
#define CMD_UNLOCK_BYPASS 0x
#if defined(CONFIG_SST_VF1601)#define MEM_FLASH_ADDR1& (*(volatile u16 *)(CONFIG_SYS_FLASH_BASE + (0x && 1)))#define MEM_FLASH_ADDR2& (*(volatile u16 *)(CONFIG_SYS_FLASH_BASE + (0x000002AAA && 1)))#else#define MEM_FLASH_ADDR1& (*(volatile u16 *)(CONFIG_SYS_FLASH_BASE + (0x && 1)))#define MEM_FLASH_ADDR2& (*(volatile u16 *)(CONFIG_SYS_FLASH_BASE + (0x000002AA && 1)))#endif
#define BIT_ERASE_DONE& 0x
在flash_init 函数中修改或添加后代码如下:
ulong flash_init (void){&int i,&ulong size = 0;
for (i = 0; i & CONFIG_SYS_MAX_FLASH_BANKS; i++) {& ulong flashbase = 0;
#elif defined(CONFIG_AMD_LV800)&&&&&&&&&&& (AMD_MANUFACT & FLASH_VENDMASK) |&&&&&&&&&&& (AMD_ID_LV800B & FLASH_TYPEMASK);#elif defined(CONFIG_SST_39VF1601)&& &&&&&&&&&&& (SST_MANUFACT & FLASH_VENDMASK) |&&&&&&&&&&& (SST_ID_xF1601 & FLASH_TYPEMASK);#else#error "Unknown flash configured"#endif
for (j = 0; j & flash_info[i].sector_ j++) {#ifndef CONFIG_SST_VF1601&& if (j &= 3) {&&& /* 1st one is 16 KB */
... ...#else&&& flash_info[i].start[j] =&&&& flashbase + (j) * MAIN_SECT_SIZE;#endif
&}& size += flash_info[i].&}
在flash_print_info 函数中修改或添加后代码如下:
void flash_print_info (flash_info_t * info){&&&&
&&& switch (info-&flash_id & FLASH_VENDMASK) {&&&&&&&&&&&&& case (AMD_MANUFACT & FLASH_VENDMASK):&&&&&&&&&&&&& printf ("AMD: ");&&&&&&&&&&&&&&&&&&&&&&&&&& case (SST_MANUFACT & FLASH_VENDMASK):&&&&&&&&&&&&& printf ("SST: ");&&&&&&&&&&&&&
&&&&&&&&&&&&& default:&&&&&&&&&&&&& printf ("Unknown Vendor ");&&&&&&&&&&&&&&&& }
&&& switch (info-&flash_id & FLASH_TYPEMASK) {&&&&&&&&&&&&&& case (AMD_ID_LV400B & FLASH_TYPEMASK):&&&&&&&&&&&&&& printf ("1x Amd29LV400BB (4Mbit)\n");&&&&&&&&&&&&&&&&&&&&&&&&&&&& case (AMD_ID_LV800B & FLASH_TYPEMASK):&&&&&&&&&&&&&& printf ("1x Amd29LV800BB (8Mbit)\n");&&&&&&&&&&&&&&&&&&&&&&&&&&&& case (SST_ID_xF1601 & FLASH_TYPEMASK):&&&&&&&&&&&&&& printf ("1x SST39VF1610 (16Mbit)\n");&&&&&&&&&&&&&&
&&&&&&&&&&&&&& default:&&&&&&&&&&&&&& printf ("Unknown Chip Type\n");&&&&&&&&&&&&&& goto D&&&&&&&&&&&&&&
&& ... ...
&&& Done:;}
在flash_erase函数中修改或添加后代码如下:
int flash_erase (flash_info_t * info, int s_first, int s_last){&&&&&& int iflag, cflag, prot,&&& int rc = ERR_OK;&&&
&&&& .... ....
&&& if ((s_first & 0) || (s_first & s_last)) {&&& return ERR_INVAL;&&& }
&if ((s_first & 0) || (s_first & s_last)) {& return ERR_INVAL;&}
#ifdef CONFIG_SST_VF1601&if ((info-&flash_id & FLASH_VENDMASK) !=&&&& (SST_MANUFACT & FLASH_VENDMASK)) {& return ERR_UNKNOWN_FLASH_VENDOR;&}#else
&if ((info-&flash_id & FLASH_VENDMASK) !=&&&& (AMD_MANUFACT & FLASH_VENDMASK)) {& return ERR_UNKNOWN_FLASH_VENDOR;&}#endif&prot = 0;
&& if (info-&protect[sect] == 0) { /* not protected */
&& vu_short *addr = (vu_short *) (info-&start[sect]);
&& MEM_FLASH_ADDR1 = CMD_UNLOCK1;&& MEM_FLASH_ADDR2 = CMD_UNLOCK2;&& MEM_FLASH_ADDR1 = CMD_ERASE_SETUP;
&& MEM_FLASH_ADDR1 = CMD_UNLOCK1;&& MEM_FLASH_ADDR2 = CMD_UNLOCK2;&& *addr = CMD_ERASE_CONFIRM;
&& /* wait until flash is ready */
& chip = 0;
&&& printf ("ok.\n");&& } else { /* it was protected */
&&&&&&& printf ("protected!\n");&& }}#endif&& while(1){&&&&&&&&&&&&&&&&&& i = *((volatile unsigned short *)addr) & 0x40;&&&&&&&&& if(i != (*((volatile unsigned short *)addr) & 0x40))&&&&&&&&&&&&&&&&&&&&&&& if((*((volatile unsigned short *)addr)) & 0x80)&&&&&&&&&&&&&&&&& }&&& printf ("ok.\n");&& } else { /* it was protected */&& printf ("protected!\n");& }}
在write_hword函数中修改或添加后代码如下:
tatic int write_hword (flash_info_t * info, ulong dest, ushort data){&&& vu_short *addr = (vu_short *)&&&&&& int rc = ERR_OK;&&& int cflag,&&&
&&& ... ...
&&& MEM_FLASH_ADDR1 = CMD_UNLOCK1;&&& MEM_FLASH_ADDR2 = CMD_UNLOCK2;&&& //MEM_FLASH_ADDR1 = CMD_UNLOCK_BYPASS;&&& MEM_FLASH_ADDR1 = CMD_PROGRAM; &&& //*addr = CMD_PROGRAM;&&& *addr =
&&& /* arm simple, non interrupt dependent timer */&&& reset_timer_masked ();
&&& /* wait until flash is ready */
&chip = 0;&& do {&& result = *
&&& } while (!chip);
&&& *addr = CMD_READ_ARRAY;
&&& if (chip == ERR || *addr != data)&&&&&&& rc = ERR_PROG_ERROR;#endif
& while(1){&&&&&&&& unsigned short i = *(volatile unsigned short *)addr & 0x40;&&&&&&&& if(i != (*(volatile unsigned short *)addr & 0x40))&& //D6 == D6&&&&&&&&&&&&&&&&&&&& if((*(volatile unsigned short *)addr & 0x80) == (data & 0x80)){&&&&&&&&&&&& rc = ERR_OK;&&&&&&&&&&&& //D7 == D7&&&&&&&&& }&&&&&&& }&& if (iflag)&&&& enable_interrupts ();
&& if (cflag)&&&& icache_enable ();
修改完后,保存。
【2】修改lowlevel_init.S 文件
为了匹配mini2440 的存储器配置(总线上连接的Nor Flash 和SDRAM),需要修改lowlevel_init.S文件。这个所连接的Nor Flash位数有关。至于SDRAM的参数,可以从芯片手册查到。据说有人将其64MB的内存升到了128MB,其参数就是在这里修改的,有需要可以看MINI2440: Auto probe for SDRAM size 。以下的64MB 内存的参数修改:
打开/board/samsung/mini2440/lowlevel_init.S,定位到123行,修改如下:
/* REFRESH parameter */#define REFEN&& 0x1 /* Refresh enable */#define TREFMD&& 0x0 /* CBR(CAS before RAS)/Auto refresh *///#define Trp&& 0x0 /* 2clk */#define Trc&&& 0x3 /* 7clk */#define Tchr&& 0x2 /* 3clk */#if defined(CONFIG_S3C2440)#define Trp&&& 0x2 /* 4clk */#define REFCNT&& 1012#else#define Trp&&& 0x0 /* 2clk */#define REFCNT&& 1113 /* period=15.6us, HCLK=60Mhz, (.6*60) */#endif/**************************************/
在这个 lowlevel_init.S 有一个小bug,使得无法使用OpenJTAG 下载到内存中直接运行,修正如下:
lowlevel_init:&/* memory control configuration */&/* make r0 relative the current location so that it */&/* reads SMRDATA out of FLASH rather than memory ! */&ldr&&&& r0, =SMRDATA&//ldr r1, _TEXT_BASE&ldr r1, =lowlevel_init&sub r0, r0, r1&adr r3, lowlevel_init /* r3 &- current position of code */&add r0, r0, r3&ldr r1, =BWSCON /* Bus Width Status Controller */&add&&&& r2, r0, #13*4
修改完后,保存。
【3】修改开发板终端中命令行提示符
用gedit打开include/configs/mini2440.h头文件,定位到116行,其中的 "SMDK2410 # " 就是开发板在终端中显示的提示符,现在将其改为 "[u-boot@MINI2440]# " ,如下所示
/*&* Miscellaneous configurable options&*/#define CONFIG_SYS_LONGHELP&&& /* undef to save memory& */#define CONFIG_SYS_PROMPT& "[u-boot@MINI2440]# " /* Monitor Command Prompt */
&【4】修改Nor Flash参数的部分定义
然后定位到157行附近,注释掉下面两个类型的Nor Flash设置,因为不是我们所使用的型号,然后加入新的定义,如下所示
/*-----------------------------------------------------------------------&* FLASH and environment organization&*/
#if 0 //注释掉下面两个类型的Nor Flash设置,因为不是我们所使用的型号#define CONFIG_AMD_LV400 1 /* uncomment this if you have a LV400 flash */#define CONFIG_AMD_LV800 1 /* uncomment this if you have a LV800 flash */#endif#define CONFIG_SST_39VF1601&&&&&&& 1&&&&&&& //添加mini2440开发板Nor Flash设置
#ifdef CONFIG_AMD_LV400#define PHYS_FLASH_SIZE& 0x /* 512KB */#define CONFIG_SYS_MAX_FLASH_SECT (11) /* max number of sectors on one chip */#define CONFIG_ENV_ADDR& (CONFIG_SYS_FLASH_BASE + 0x070000) /* addr of environment */#endif#ifdef CONFIG_SST_VF1601#define PHYS_FLASH_SIZE& 0x /* 2MB */#define CONFIG_SYS_MAX_FLASH_SECT (32) /* max number of sectors on one chip */#define CONFIG_ENV_ADDR& (CONFIG_SYS_FLASH_BASE + CONFIG_ENV_OFFSET) /* addr of environment */#endif
&宏 CFG_ENV_ADDR定义了存放uboot变量的地址,换算一下为1MB-64KB=960KB地方,而实际uboot编译出来的大小仅为120KB 左右,由此可以得出,即使从新烧录了新编译的uboot到Nor flash内,也不会影响先前设定使用的uboot变量。
修改完后,保存。
2.2,重新编译,运行测试
[root@localhost u-boot-2009.08]# make cleanGenerating include/autoconf.mk[root@localhost u-boot-2009.08]# make... ...
arm-linux-objcopy -O srec u-boot u-boot.srecarm-linux-objcopy --gap-fill=0xff -O binary u-boot u-boot.bin[root@localhost u-boot-2009.08]# 编译完成后,将根目录u-boot-2009.08下的u-boot.bin文件复制到/tftpboot目录下。在与开发板相连的终端中执行如下命令:
##### FriendlyARM BIOS 2.0 for 2440 #####[x] format NAND FLASH for Linux[v] Download vivi[k] Download linux kernel[y] Download root_yaffs image[a] Absolute User Application[n] Download Nboot for WinCE[l] Download WinCE boot-logo[w] Download WinCE NK.bin[d] Download & Run[z] Download zImage into RAM[g] Boot linux from RAM[f] Format the nand flash[b] Boot the system[s] Set the boot parameters[u] Backup NAND Flash to HOST through USB(upload)[r] Restore NAND Flash from HOST through USB[q] Goto shell of viviEnter your selection: dClear the free memoryUSB host is connected. Waiting a download.
Now, Downloading [ADDRESS:h,TOTAL:99674]RECEIVED FILE SIZE:&& 99674 (97KB/S, 1S)Downloaded file at 0x, size = 99664 bytes
U-Boot 2009.08 ( 5鏈?05 2011 - 22:39:33)
DRAM:& 64 MBFlash:& 2 MBIn:&&& serialOut:&& serialErr:&& serial[u-boot@MINI2440]#
从运行结果看,Nor Flash的大小可以正确检测到了,命令行前面的名字也由原来的SMDK2410改成自己定义的[u-boot@MINI2440]# 了,但是有会出现bad CRC的警告信息,其实这并不是什么问题,只是还没有将环境变量设置到Nor Flash中,我们执行一下u-boot的:saveenv命令就可以了。如下所示:
[u-boot@MINI2440]# saveenvSaving Environment to Flash...Un-Protected 16 sectorsErasing Flash...Erasing sector 64 ... ok.Erasing sector 65 ... ok.Erasing sector 66 ... ok.Erasing sector 67 ... ok.Erasing sector 68 ... ok.Erasing sector 69 ... ok.Erasing sector 70 ... ok.Erasing sector 71 ... ok.Erasing sector 72 ... ok.Erasing sector 73 ... ok.Erasing sector 74 ... ok.Erasing sector 75 ... ok.Erasing sector 76 ... ok.Erasing sector 77 ... ok.Erasing sector 78 ... ok.Erasing sector 79 ... ok.Erased 16 sectorsWriting to Flash... doneProtected 16 sectors[u-boot@MINI2440]#
因为DRAM运行的是现在的u-boot,其下载命令还未实现,需要给开发板重新上电,再重新下载u-boot.bin到DRAM中运行
Enter your selection: dClear the free memoryUSB host is connected. Waiting a download.
Now, Downloading [ADDRESS:h,TOTAL:99682]RECEIVED FILE SIZE:&& 99682 (97KB/S, 1S)Downloaded file at 0x, size = 99672 bytes
U-Boot 2009.08 ( 5鏈?05 2011 - 22:50:40)
DRAM:& 64 MBFlash:& 2 MBIn:&&& serialOut:&& serialErr:&& serial[u-boot@MINI2440]#
可以观察到不会出现警告信息了,这时候u-boot已经对我们开发板上的Nor Flash完全支持了。
接下来将进入u-boot的第三阶段,为u-boot-2009.08增加nand flash支持。2
【内容导航】
相关资讯 & & &
& (11/05/:30)
& (03/29/:44)
& (01月28日)
& (09/25/:27)
& (12/27/:58)
   同意评论声明
   发表
尊重网上道德,遵守中华人民共和国的各项有关法律法规
承担一切因您的行为而直接或间接导致的民事或刑事法律责任
本站管理人员有权保留或删除其管辖留言中的任意内容
本站有权在网站内转载或引用您的评论
参与本评论即表明您已经阅读并接受上述条款
mqynms2 发表于 强大的网站,
(7) 匿名 发表于 我按照你的移植,报part.c中有错误,402,403,404行有错误,我搞不懂
(5) 匿名 发表于 dm9000_initialize函数没有定义。。
(6) sourire 发表于 学习了解决中国大陆在更新Chrome 显示Flash过期的问题 – Onlyke
Introduction作者:Daniel Sun
努力成为全栈攻城狮
家有小仙女:
- 2,192 views - 1,803 views
- 28,392 views - 12,873 views - 11,176 views - 9,746 views - 6,674 views - 6,091 views - 5,764 views - 5,430 views - 5,140 views - 5,105 views
分类目录分类目录
选择分类目录
Linux&&(51)
&&&Openwrt&&(7)
&&&macos&&(1)
minecraft&&(3)
Nginx&&(13)
Node.js&&(2)
&&&Laravel&&(14)
Python&&(2)
&&&mysql&&(5)
wordpress&&(3)
未分类&&(2)
生活&&(12)下次自动登录
现在的位置:
& 综合 & 正文
Nor 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);
#error "Unknown flash configured"
//设置 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_ j++)
flash_info[i].start[j] = flashbase + (j - 3) * MAIN_SECT_SIZE;
size += flash_info[i].
//片外所有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]);
//返回 flash 大小
flash_init() 函数主要是做一些 flash 的初始化,比如设置 flash 的 ID、大小、扇区数等来构造flash_info_t 结构体,但是从上面的代码可以看出,在该初始化函数中并没有做任何与硬件有关的初始化,所有的值都是通过外部赋值,也就是说我们可以给这些成员变量赋任何我们想要的值,哪怕这些值并不是
flash 真正的参数,虽然这些值并不影响本函数的调用,但是和下面这些函数就有密切关系。
int flash_erase (flash_info_t * info, int s_first, int s_last)
//参看是否有写保护扇区,有直接返回错误
for (sect = s_ sect &= s_ ++sect)
if (info-&protect[sect])
return ERR_PROTECTED;
//关闭中断等,防止擦除过程被中断
cflag = icache_status ();
icache_disable ();
iflag = disable_interrupts ();
/* Start erase on unprotected sectors */
for (sect = s_ 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 */
result = *
//读取该扇区首地址里面的值
/* check timeout */
if (get_timer_masked () & CONFIG_SYS_FLASH_ERASE_TOUT)
MEM_FLASH_ADDR1 = CMD_READ_ARRAY;
chip = TMO;
//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");
/* it was protected */
printf ("protected!n");
/* allow flash to settle - wait 10 ms */
udelay_masked (10000);
对于擦除工作,不可能瞬间完成,如何检测芯片是否已经完成擦除工作是我们所关心的,当然你可以用一个很长的延时来确保芯片肯定已经完成擦除,但是一款芯片一定会提供相应的状态供我们检测,利用这些状态位可以减少程序中不必要的等待。下面这些描述是摘自芯片手册。
Sector Erase Command Sequence
When the Embedded Erase algorithm is complete, the device returns to reading array data and addresses are no longer latched. The system can determine the status of the erase operation by using DQ7, DQ6, DQ2, or RY/BY#. (Refer to “Write Operation Status” for
information on these status bits.)
WRITE OPERATION STATUS
The device provides several bits to determine the status of a write operation: DQ2, DQ3, DQ5, DQ6,DQ7, and RY/BY#. Table 10 and the following subsections describe the functions of these bits. DQ7, RY/BY#, and DQ6 each offer a method for determining whether
a program or erase operation is complete or in progress. These three bits are discussed first.对于擦除过程:During the Embedded Erase algorithm, Data# Polling produces a “0” on DQ7. When the Embedded Erase algorithm is complete, or if the device enters the Erase Suspend mode, Data# Polling produces a “1” on DQ7. This is analogous to the
complement/true datum output described for the Embedded Program algorithm: the erase function changes all the bits in a sector to “1”; prior to this, the device outputs the “complement,” or“0.” The system must provide an address within any of the sectors selected
for erasure to read valid status information on DQ7.
Embedded Erase algorithm 是指”嵌入的擦除程序“,当我们发出擦除命令的时候 Nor Flash 内部就会执行一系列指令来进行擦除工作,在这过程它通过检测 Data = FF?(如上图所示)来判断擦除状态,但是这是 Nor Flash 内部的判断方法,与之对应,外部的内存控制器可以通过Data# Polling 来检测
。When the system detects DQ7 has changed from the complement to true data, it can read valid data at DQ7–DQ0 on the following read cycles. This is because DQ7 may change asynchronously with DQ0–DQ6 while Output Enable (OE#) is asserted low. Figure 19,
Data#Polling Timings (During Embedded Algorithms), in the“AC Characteristics” section illustrates this.
如果你实在不想花太多时间看手册,或对英文文档头疼,可以看看下面的总结。
Nor Flash 提供几个数据位来确定一个写操作的状态,它们分别是: DQ2, DQ3, DQ5, DQ6,DQ7, and RY/BY# 。其中DQ7, RY/BY#引脚, 和 DQ6 中的每一个都提供了一种方法来判断一个编程或者擦除操作是否已经完成或正在进行中。实际编程中只需要使用其中的一种。
DQ7:Data# Polling bit,在编程过程从正在编程的地址中读出的数据的DQ7为要写入数据位的补码。比如写入的数据为0x0000,即输入的DQ7为 0 ,则在编程中读出的数据为 1 ;当编程完成时读出的数据又变回输入的数据 0 。在擦除过程中DQ7输出为
0 ;擦除完成后输出为 1 ;注意读取的地址必须是擦除范围内的地址。RY/BY#:高电平表示‘就绪’,低电平表示‘忙’。
DQ6:轮转位1(Toggle Bit 1),在编程和擦除期间,读任意地址都会导致DQ6的轮转(0,1间相互变换)。当操作完成后,DQ6停止转换。
DQ2:轮转位2(Toggle Bit 2),当某个扇区被选中擦除时,读有效地址(地址都在擦除的扇区范围内)会导致DQ2的轮转。
注意:DQ2只能判断一个特定的扇区是否被选中擦除,但不能区分这个扇区是否正在擦除中或者正处于擦除暂停状态。相比之下,DQ6可以区分Nor Flash是否处于擦除中或者擦除暂停状态,但不能区分哪个扇区被选中擦除,因此需要这2个位来确定扇区和模式状态信息。
DQ5: 超时位(Exceeded Timing Limits) ,当编程或擦除操作超过了一个特定内部脉冲计数时 DQ5=1,表明操作失败。当编程时把 0 改为 1 就会导致 DQ5=1,因为只有擦除擦做才能把 0 改为 1。当错误发生后需要执行复位命令才能返回到读数据状态。
DQ3: (扇区擦除计时位)Sector Erase Timer ,只在扇区擦除指令时起作用。当擦除指令真正开始工作时 DQ3=1 ,此时输入的命令(除擦除暂停命令外)都被忽略,DQ3=0 时,可以添加附加的扇区用于多扇区擦除。
看了上面的分析就知道为什么在 flash_erase() 函数中当发出擦除命令后要检测 DQ7 是否为 1,if (!chip && (result & 0xFFFF) & BIT_ERASE_DONE) 。因为擦除过程用到了扇区的首地址,所以在 flash_init() 函数中就不能随便设置这些值,要保持和实际的 flash 一致。
/* Copy memory to flash. */
int write_buff (flash_info_t * info, uchar * src, ulong addr, ulong cnt)
//保持16位地址对齐
wp = (addr & ~1);
/* get lower word aligned address */
/* handle unaligned start bytes */
if ((l = addr - wp) != 0)
for (i = 0, cp = i & ++i, ++cp)
data = (data && 8) | (*(uchar *) cp && 8);
for (; i & 2 && cnt & 0; ++i)
data = (data && 8) | (*src++ && 8);
//条件不成立,此语句不起作用
for (; cnt == 0 && i & 2; ++i, ++cp)
data = (data && 8) | (*(uchar *) cp && 8);
if ((rc = write_hword (info, wp, data)) != 0)
return (rc);
/* handle word aligned part */
while (cnt &= 2)
data = *((vu_short *) src);
if ((rc = write_hword (info, wp, data)) != 0)
return (rc);
if (cnt == 0)
return ERR_OK;
/* handle unaligned tail bytes */
for (i = 0, cp = i & 2 && cnt & 0; ++i, ++cp)
data = (data && 8) | (*src++ && 8);
//条件不成立,此语句不起作用
for (; i & 2; ++i, ++cp)
data = (data && 8) | (*(uchar *) cp && 8);
return write_hword (info, wp, data);
write_buff() 函数拷贝内存里面的数据到 Nor Flash ,这个函数首先要保证16位地址对齐,由 /* handle unaligned start bytes */ 包含的语句处理,虽然写得比较复杂,但是做得事情很简单。假如要往 flash 地址 3 处(这里的地址 3 是相对于 ARM 而言)开始写一段数据,先把地址 2 处(这里的地址
2 是相对于 ARM 而言)的数据读出,和要写入地址 3 的数据组成一个16为的数据,写入地址 2 处,这样地址 2 里面的数据不变,地址 3 处就是写入的数据。注意:这里的地址都是站在 ARM 角度说的,对于 flash 地址 2 对于它的地址 1,这里面涉及到地址线的对齐关系。
write_buff() 函数里面是调用 write_hword()来实现底层的写操作。
static int write_hword (flash_info_t * info, ulong dest, ushort data)
vu_short *addr = (vu_short *)
int rc = ERR_OK;
int cflag,
/* Check if Flash is (sufficiently) erased */
result = *
if ((result & data) != data)
return ERR_NOT_ERASED;
* Disable interrupts which might cause a timeout
* here. Remember that our exception vectors are
* at address 0 in the flash, and we don't want a
* (ticker) exception to happen while the flash
* chip is in programming mode.
cflag = icache_status ();
icache_disable ();
iflag = disable_interrupts ();
MEM_FLASH_ADDR1 = CMD_UNLOCK1;
//往地址 0x555&&1 写入 0xAA
MEM_FLASH_ADDR2 = CMD_UNLOCK2;
//往地址 0x2AA&&1 写入 0x55
MEM_FLASH_ADDR1 = CMD_UNLOCK_BYPASS;
//往地址 0x555&&1 写入 0x20
*addr = CMD_PROGRAM;
//往地址 0x555&&1 写入 0xA0
//往地址addr 写入数据
/* arm simple, non interrupt dependent timer */
reset_timer_masked ();
/* wait until flash is ready */
result = *
/* check timeout */
if (get_timer_masked () & CONFIG_SYS_FLASH_ERASE_TOUT)
chip = ERR | TMO;
if (!chip && ((result & 0x80) == (data & 0x80)))
chip = READY;
if (!chip && ((result & 0xFFFF) & BIT_PROGRAM_ERROR))
result = *
if ((result & 0x80) == (data & 0x80))
chip = READY;
chip = ERR;
} while (!chip);
*addr = CMD_READ_ARRAY;
//往地址 0x555&&1 写入 0xF0 复位
写入数据后通过判断 DQ7 是否和写入的一致来确认编程操作结束,对应的代码是if (!chip && ((result & 0x80) == (data
& 0x80)))。
During the Embedded Program algorithm, the device outputs on DQ7 the complement of the datum programmed to DQ7. This DQ7 status also applies to programming during Erase Suspend. When the Embedded Program algorithm is complete, the device outputs the datum programmed
to DQ7. The system
must provide the program address to read valid status information on DQ7. If a program address falls within a protected sector, Data# Polling on DQ7 is active for
approximately 1 μs, then the device returns to reading array data.
关于Unlock Bypass的相关概念和操作可以参考手册里面的介绍,简单来讲,Unlock Bypass 就是忽略解锁的意思,因为每次编程 flash 都要发出解锁命令,再发出编程命令 0xA0,最后才写入16位数据,设想如果写入的数据量很大,每次写入一个 word(16位) 都要重新解锁一下,效率很低。Unlock Bypass 允许我们写入数据的时候忽略解锁命令,直接发出 0xA0 命令后再往相应地址写入数据。Unlock Bypass Command SequenceThe unlock bypass feature allows the system to program bytes or words to the device faster than using the standard program command sequence. The unlock bypass
command sequence is initiated by first writing two unlock cycles. This is followed by a third write cycle containing the unlock bypass command, 20h. The device then enters the unlock bypass mode. A two-cycle unlock bypass program command sequence is all that
is required to program in this mode. The first cycle in this sequence contains the unlock bypass program command, A0h; the second cycle contains the program address and data. Additional data is programmed in the same manner. This mode dispenses with the initial
two unlock cycles required in the standard program command sequence, resulting in faster total programming time. Table 9 shows the requirements for the command sequence.
认真看完这一段,你就会发现其实上面的 write_hword() 函数写得有点问题。
【上篇】【下篇】

我要回帖

更多关于 flash flag wrperr 的文章

 

随机推荐