logo资料库

norflash读写操作.pdf

第1页 / 共9页
第2页 / 共9页
第3页 / 共9页
第4页 / 共9页
第5页 / 共9页
第6页 / 共9页
第7页 / 共9页
第8页 / 共9页
资料共9页,剩余部分请下载后查看
NOR FLASH 烧写指南 TWENTYONE WWW.HJTAG.COM 在后面的介绍里,如无特别说明,处理器指的是 ARM 处理器,FLASH 指的都是 NOR FLASH。另外,BYTE 指的是 从支持的最小访问单元来看,NOR FLASH 一般分为 8 位的和 16 位的(当然,也有很多 NOR FLASH 芯片同时支持 8 对于硬件工程师和嵌入式软件工程师,在完成设计后,常常需要验证 FLASH 是否工作。在应用中,也有很多时候需要 对 FLASH 进行写操作。这篇文章简单介绍了基于 ARM 芯片的 NOR FLASH 烧写,并提供了 2 个具体的实例和源代码,希 望对有需要的朋友有点帮助。在开始之前,先声明一下,这篇文章只是介绍了如何写 NOR FLASH 的烧写驱动,和 H-JTAG/H-FLASHER 没有直接的联系。 8-BIT 的数据单元,HALF-WORD 代表的是 16-BIT 的数据单元,而 WORD 则代表了 32-BIT 的数据单元。 1. NOR FLASH 的简单介绍 NOR FLASH 是很常见的一种存储芯片,数据掉电不会丢失。NOR FLASH 支持 Execute On Chip,即程序可以直接在 FLASH 片内执行。这点和 NAND FLASH 不一样。因此,在嵌入是系统中,NOR FLASH 很适合作为启动程序的存储介质。 NOR FLASH 的读取和 RAM 很类似,但不可以直接进行写操作。对 NOR FLASH 的写操作需要遵循特定的命令序列,最终 由芯片内部的控制单元完成写操作。 位模式和是 16 位模式,具体的工作模式通过特定的管脚进行选择)。 对 8 位的 NOR FLASH 芯片,或是工作在 8-BIT 模式的芯片来说,一个地址对应一个 BYTE(8-BIT)的数据。例如一 块 8-BIT 的 NOR FLASH,假设容量为 4 个 BYTE。那芯片应该有 8 个数据信号 D7-D0 和 2 个地址信号,A1-A0。地址 0x0 对应第 0 个 BYTE,地址 0x1 对应于第 1BYTE,地址 0x2 对应于第 2 个 BYTE,而地址 0x3 则对应于第 3 个 BYTE。. 对 16 位的 NOR FLASH 芯片,或是工作在 16-BIT 模式的芯片来说,一个地址对应于一个 HALF-WORD(16-BIT)的 数据。例如,一块 16-BIT 的 NOR FLASH,假设其容量为 4 个 BYTE。那芯片应该有 16 个数据信号线 D15-D0 和 1 个地址 信号 A0。地址 0x0 对应于芯片内部的第 0 个 HALF-WORD,地址 0x1 对应于芯片内部的第 1 个 HALF-WORD。 FLASH 一般都分为很多个 SECTOR,每个 SECTOR 包括一定数量的存储单元。对有些大容量的 FLASH,还分为不同 的 BANK,每个 BANK 包括一定数目的 SECTOR。FLASH 的擦除操作一般都是以 SECTOR,BANK 或是整片 FLASH 为单 位的。 在对 FLASH 进行写操作的时候,每个 BIT 可以通过编程由 1 变为 0,但不可以有 0 修改为 1。为了保证写操作的正确 性,在执行写操作前,都要执行擦除操作。擦除操作会把 FLASH 的一个 SECTOR,一个 BANK 或是整片 FLASH 的值全修 改为 0xFF。这样,写操作就可以正确完成了。 2. ARM 处理器的寻址 ARM 可以说是目前最流行的 32 位嵌入式处理器。在这里只提一下 ARM 处理器的寻址,为后面做个铺垫。从处理器 Copyright © 2008 WWW.HJTAG.COM All Rights Reserved
的角度来看,系统中每个地址对应的是一个 BYTE 的数据单元。这和很多别的处理器都是一样的。 3. 处理器和 NOR FLASH 的硬件连接 从前面的介绍,我们知道从处理器的角度来看,每个地址对应的是一个 BYTE 的数据单元。而,NOR FLASH 的每个 地址有可能对应的是一个 BYTE 的数据单元,也有可能对应的是一个 HALF-WORD 的数据单元。所以在硬件设计中,连接 ARM 处理器和 NOR FLASH 时,必须根据实际情况对地址信号做特别的处理。 如果 ARM 处理器外部扩展的是 8-BIT 的 NOR FLASH,数据线和地址线的连接应该如图 1 所示。从图中我们可以看到, 处理器的数据信号 D0-D7 和 FLASH 的数据信号 D0-D7 是一一对应连接的,处理器的地址信号 A0-An 和 NOR FLASH 的地 址信号 A0-An 也是一一对应连接的。 图 1 – ARM 处理器和 8-BIT FLASH 的连接示意图 如果 ARM 处理器外部扩展的是 16-BIT 的 NOR FLASH,数据线必须要错位连接。图 2 给了一个 ARM 处理器和 16-BIT NOR FLASH 的连接示意图。如图 2 所示,ARM 处理器的数据信号 D0-D15 和 FLASH 的数据信号 D0-D15 是一一对应的。 而 ARM 处理器的地址信号和 NOR FLASH 的地址信号是错位连接的,ARM 的 A0 悬空,ARM 的 A1 连接 FLASH 的 A0, ARM 的 A1 连接 FLASH 的 A2,依次类推。需要错位连接的原因是:ARM 处理器的每个地址对应的是一个 BYTE 的数据单 元,而 16-BIT 的 FLASH 的每个地址对应的是一个 HALF-WORD(16-BIT)的数据单元。为了保持匹配,所以必须错位连 接。这样,从 ARM 处理器发送出来的地址信号的最低位 A0 对 16-BIT FLASH 来说就被屏蔽掉了。 图 2 – ARM 处理器和 16-BIT FLASH 的连接示意图 Copyright © 2008 WWW.HJTAG.COM All Rights Reserved
补充说明: 1. 一般来说,ARM 处理器内部要设置相应的寄存器,告诉处理器外部扩展的 FLASH 的位宽(8-BIT/16-BIT/32-BIT)。这 样,处理器才知道在访问的时候如何从 FLASH 正确的读取数据。 2. 有些 ARM 处理器内部可以设置地址的错位。对于支持软件选择地址错位的处理器,在连接 16-BIT FLASH 的时候,硬 件上可以不需要把地址线错位。读者设计的时候,请参考 MCU 的数据手册,以手册为准,以免造成不必要的麻烦。 3. 如果处理器支持内部设置地址错位,在实际访问的时候,送出的地址实际上是在 MCU 内部做了错位处理,其作用是等 效于硬件连接上的错位的。 上面的描述可能比较抽象,下面让我们来看 2 个 ARM 处理器访问 16-BIT FLASH 的例子: 例子 1:ARM 处理器需要读取在地址 0x0 的一个 BYTE 1 - ARM 处理器在地址线 An-A0 上送出信号 0x0; 2 – 16-BIT FLASH 在自己的地址信号 An-A0 上看到的地址是 0x0,然后将地址 0x0 对应的 16-BIT 数据单元输出到 D15-D0 上; 3 – ARM 处理器知道访问的是 16-BIT 的 FLASH,从 D7-D0 上读取所需要的一个 BYTE 的数据; 例子 2:ARM 处理器需要读取在地址 0x1 的一个 BYTE 1 - ARM 处理器在地址线 An-A0 上送出信号 0x1; 2 – 16-BIT FLASH 在自己的地址信号 An-A0 上看到的地址依然是 0x0,然后将地址 0x0 对应的 16-BIT 数据单元输出到 D15-D0 上; 3 –ARM 处理器知道访问的是 16-BIT 的 FLASH,从 D15-D8 上读取所需要的一个 BYTE 的数据; 4. 从软件角度来看 ARM 处理器和 NOR FLASH 的连接 在上一个小节里,我们简单了解了 ARM 处理器和 FLASH 的硬件连接。在这个小节里面,我们从软件的角度来理解 ARM 处理器和 FLASH 的连接。对于 8-BIT 的 FLASH 的连接,很好理解,因为 ARM 处理器和 8-BIT FLASH 的每个地址对 应的都是一个 BYTE 的数据单元。所以地址连接毫无疑问是一一对应的。如果 ARM 处理器连接的是 16-BIT 的处理器,因 为 ARM 处理器的每个地址对应的是一个 BYTE 的数据单元,而 16-BIT FLASH 的每个地址对应的是一个 HALF-WORD 的 16-BIT 的数据单元。所以,也毫无疑问,ARM 处理器访问 16-BIT 处理器的时候,地址肯定是要错开一位的。在写 FLASH 驱动的时候,我们不需要知道地址错位由硬件实现的,还是是通过设置 ARM 处理器内部的寄存器来实现的,只需要记住 2 点: 1 – ARM 处理器访问 8-BIT FLASH 的时候,地址是一一对应的; 2 – ARM 处理器访问 16-BIT FLASH 的时候,地址肯定是错位的。这一点对理解后面的例子会很有帮助。 Copyright © 2008 WWW.HJTAG.COM All Rights Reserved
HY29F040 是现代公司的一款 8-BIT 的 NOR FLASH。在这个小节里,我们以这个芯片为例子,介绍如何对 8-BIT NOR 5. 8-BIT FLASH 烧写驱动实例 - HY29F040 FLASH 进行操作。 擦除,整片擦除和以 BYTE 为基本单位的写操作。HY29F040 的命令定义如表-1 所示。 HY29F040 的容量为 512K-BYTE,总共包括 8 个 SECTOR,每个 SECTOR 的容量是 64K-BYTE。该芯片支持 SECTOR 表 1. HY29F040 的命令定义 下面,我们来看看如何实现基本的擦除和编程操作。在本节后面的描述中,我们使用了下面的 2 个定义: U32 sysbase; #define SysAddr8(sysbase, offset) ((volatile U8*)(sysbase)+(offset)) 先解释一下 SysAddr8 的定义。这个宏定义了一个 BYTE(8-BIT)指针,其地址为(sysbase + offset)。假设 FLASH 的起始地 //该变量用来表示 FLASH 的起始地址 //用来方便对指定的 FALSH 地址进行操作 址为 0x10000000,如果要将 0xAB 写到 FLASH 的第一个 BYTE 中去,可以用下面的代码: *SysAddr8(0x10000000, 0x1) = 0xAB; 注意: 在本节后面的描述中,SYSBASE 代表的是 FLASH 的起始地址,而 SysAddr8 中的 OFFSET 则代表了相对于 FLASH 起 始地址的 BYTE 偏移量。OFFSET 也是 8-BIT FLASH 在自己的地址信号 An-A0 上看到的地址。 整片擦除操作 整片擦除操作共需要 6 个周期的总线写操作 1 – 将 0xAA 写到 FLASH 地址 0x5555 2 – 将 0x55 写到 FLASH 地址 0x2AAA 3 – 将 0x80 写到 FLASH 地址 0x5555 4 – 将 0xAA 写到 FLASH 地址 0x5555 5 – 将 0x55 写到 FLASH 地址 0x2AAA 6 – 将 0x10 写到 FLASH 地址 0x5555 Copyright © 2008 WWW.HJTAG.COM All Rights Reserved
对应的代码: *SysAddr8(sysbase, 0x5555) = 0xAA; *SysAddr8(sysbase, 0x2AAA) = 0x55; *SysAddr8(sysbase, 0x5555) = 0x80; *SysAddr8(sysbase, 0x5555) = 0xAA; *SysAddr8(sysbase, 0x2AAA) = 0x55; *SysAddr8(sysbase, 0x5555) = 0x10; SECTOR 擦除操作 //将值 0xAA 写到 FLASH 地址 0x5555 //将值 0x55 写到 FLASH 地址 0x2AAA //将值 0x80 写到 FLASH 地址 0x5555 //将值 0xAA 写到 FLASH 地址 0x5555 //将值 0x55 写到 FLASH 地址 0x2AAA //将值 0x10 写到 FLASH 地址 0x5555 SECTOR 的擦除操作共需要 6 个周期的总线写操作 1 – 将 0xAA 写到 FLASH 地址 0x5555 2 – 将 0x55 写到 FLASH 地址 0x2AAA 3 – 将 0x80 写到 FLASH 地址 0x5555 4 – 将 0xAA 写到 FLASH 地址 0x5555 5 – 将 0x55 写到 FLASH 地址 0x2AAA 6 – 将 0x30 写到要擦除的 SECTOR 对应的地址 对应的代码: *SysAddr8(sysbase, 0x5555) = 0xAA; *SysAddr8(sysbase, 0x2AAA) = 0x55; *SysAddr8(sysbase, 0x5555) = 0x80; *SysAddr8(sysbase, 0x5555) = 0xAA; *SysAddr8(sysbase, 0x2AAA) = 0x55; *SysAddr8(sysbase, addr) = 0x30; //将值 0xAA 写到 FLASH 地址 0x5555 //将值 0x55 写到 FLASH 地址 0x2AAA //将值 0x80 写到 FLASH 地址 0x5555 //将值 0xAA 写到 FLASH 地址 0x5555 //将值 0x55 写到 FLASH 地址 0x2AAA //将值 0x30 写到要擦除的 SECTOR 对应的地址 BYTE 编程操作 写一个 BYTE 的数据到 FLASH 中去,需要 4 个周期的总线写操作 1 – 将 0xAA 写到 FLASH 地址 0x5555 2 – 将 0x55 写到 FLASH 地址 0x2AAA 3 – 将 0xA0 写到 FLASH 地址 0x5555 4 – 将编程数据(BYTE)写到对应的编程地址上去 对应的代码: *SysAddr8(sysbase, 0x5555) = 0xAA; *SysAddr8(sysbase, 0x2AAA) = 0x55; *SysAddr8(sysbase, 0x5555) = 0xA0; *SysAddr8(sysbase, addr) = data; //将值 0xAA 写到 FLASH 地址 0x5555 //将值 0x55 写到 FLASH 地址 0x2AAA //将值 0xA0 写到 FLASH 地址 0x5555 //将一个 BYTE 的数据写到期望的地址 Copyright © 2008 WWW.HJTAG.COM All Rights Reserved
6. 16-BIT FLASH 烧写驱动实例 - SST39VF160 对 8-BIT FLASH 的操作很好理解,但对 16-BIT FLASH 的操作理解起来要晦涩很多。我尽力描述得清楚些。SST39VF160 是 SST 公司的一款 16-BIT 的 NOR FLASH。在这个小节里,我们以这个芯片为例子,介绍如何对 16-BIT NOR FLASH 进行 操作。 SST39VF160 的容量为 2M-BYTE ,总共包括 512 个 SECTOR,每个 SECTOR 的容量是 4K-BYTE。该芯片支持 SECTOR 擦除,整片擦除和以 HALF-WORD 为基本单位的写操作。SST39VF160 的命令定义如表-2 所示。在表 2 中,因为所有命令 都是从 FLASH 的角度来定义的。所以, 所有的地址都是 HALF-WORD 地址,指的是 16-BIT FLASH 在自己的地址信号 An-A0 上看到的地址。 表 2. SST39VF160 的命令定义 在本节后面的描述中,我们使用了下面的 2 个定义: U32 sysbase; #define SysAddr16(sysbase, offset) ((volatile U16*)(sysbase)+(offset)) //该变量用来表示 FLASH 的起始地址 //用来方便对指定的 FALSH 地址进行操作 SysAddr16(sysbase, offset)首先定义了一个 16-BIT HALF-WORD 的指针,指针的地址为 sysbase,然后根据 offset 做个偏移操作。因为 HALF-WORD 指针的地址是 2 个 BYTE 对齐的,所以每个偏移操作会使得地址加 2。 最终,SysAddr16(sysbase, offset)相当于定义了一个 HALF-WORD 的指针,其最终地址为(sysbase + 2*offset)。在使用 SysAddr16 的时候,将 sysbase 设置成 FLASH 的起始地址,offset 则可以理解为相对于 FLASH 起始地址的 HALF-WORD 偏移量或是偏移地址。假设 FLASH 的 起始地址为 0x10000000,SysAddr16(0x10000000, 0)指向 16-BIT FLASH 的第 0 个 HALF-WORD, SysAddr16(0x10000000, 1) 指向 16-BIT FLASH 的第 1 个 HALF-WORD。依次类推。如果要将 0xABCD 分别写到 FLASH 的第 0 个和第 1 个 HALF-WORD 中去, 可以用下面的代码: *SysAddr16(0x10000000, 0x0) = 0xABCD; *SysAddr16(0x10000000, 0x1) = 0xABCD; 接下来,我们分别从 ARM 处理器的角度和 FLASH 的角度来具体分析一下。 从 ARM 的角度来看: 假设 FLASH 的起始地址为 0x10000000,因为 ARM 处理器知道 FLASH 的地址空间为 0x10000000 ~ (0x10000000 +FLASH 容量 – 1),所以在对这个地址空间进行访问的时候,会设置好 FLASH 的片选信号,并将低位的地址输出到 Copyright © 2008 WWW.HJTAG.COM All Rights Reserved
地址信号上。以 *SysAddr16(0x10000000, 0x1) = 0xABCD 为例。从 ARM 处理器的角度来看,该操作是把 0xABCD 写到 地址 0x10000002 上去。所以 ARM 处理器最终会在它的地址信号 An-A0 输出地址 0x2,同时会在 D15-D0 上输出 0xABCD。 从 FLASH 的角度来看: 还是以 *SysAddr16(0x10000000, 0x1) = 0xABCD 为例,FLASH 看到的地址是多少呢?接着分析。ARM 处理器在执行 操作的时候,会设置好相应的 FLASH 片选使能信号,并在 ARM 的地址信号 An-A0 上输出 0x2。因为 ARM 和 16-BIT FLASH 的地址信号的连接是错开一位的,所以,FLASH 最终在自己的地址 An-A0 上看到的信号是 0x1,相当于将 ARM 处理器输出的地址往右做了一个移位操作,刚好对应的是 FLASH 的第 1 个 HALF-WORD。同时,FLASH 会在自己的 D15-D0 上看到数据 0xABCD。 通过上面的分析,我们知道 SysAddr16 中指定的 offset 的值就是 16-BIT FLASH 在自己的地址 An-A0 上看到的值。所以, 我们可以很方便的通过 SysAddr16(sysbase, offset) 对 FLASH 进行操作,其中 sysbase 代表 FLASH 起始地址,offset 则 对应 FLASH 的第几个 HALF-WORD(HALF-WORD 偏移量或偏移地址)。 注意: 1. 在本节后面的描述中,SysAddr16 中的 SYSBASE 代表的是 FLASH 的起始地址,而 SysAddr16 中的 OFFSET 则代表 了相对于 FLASH 起始地址的 HALF-WORD 偏移量或偏移地址。OFFSET 的值也是 16-BIT FLASH 在自己的地址信号 An-A0 上看到的值。 2.在 SST39VF160 的命令定义中,所有的地址都是针对 FLASH 的 HALF-WORD 地址,指的是在 FLASH 自己的地址 信号 An-A0 上看到的地址。 整片擦除操作 整片擦除操作共需要 6 个周期的总线写操作 1 – 将 0x00AA 写到 FLASH HALF-WORD 地址 0x5555 2 – 将 0x0055 写到 FLASH HALF-WORD 地址 0x2AAA 3 – 将 0x0080 写到 FLASH HALF-WORD 地址 0x5555 4 – 将 0x00AA 写到 FLASH HALF-WORD 地址 0x5555 5 – 将 0x0055 写到 FLASH HALF-WORD 地址 0x2AAA 6 – 将 0x0010 写到 FLASH HALF-WORD 地址 0x5555 对应的代码: *SysAddr16(sysbase, 0x5555) = 0x00AA; *SysAddr16(sysbase, 0x2AAA) = 0x0055; *SysAddr16(sysbase, 0x5555) = 0x0080; *SysAddr16(sysbase, 0x5555) = 0x00AA; *SysAddr16(sysbase, 0x2AAA) = 0x0055; *SysAddr16(sysbase, 0x5555) = 0x0010; //将值 0x00AA 写到 FLASH HALF-WORD 地址 0x5555 //将值 0x0055 写到 FLASH HALF-WORD 地址 0x2AAA //将值 0x0080 写到 FLASH HALF-WORD 地址 0x5555 //将值 0x00AA 写到 FLASH HALF-WORD 地址 0x5555 //将值 0x0055 写到 FLASH HALF-WORD 地址 0x2AAA //将值 0x0010 写到 FLASH HALF-WORD 地址 0x5555 SECTOR 擦除操作 SECTOR 的擦除操作共需要 6 个周期的总线写操作 1 – 将 0x00AA 写到 FLASH HALF-WORD 地址 0x5555 2 – 将 0x0055 写到 FLASH HALF-WORD 地址 0x2AAA Copyright © 2008 WWW.HJTAG.COM All Rights Reserved
3 – 将 0x0080 写到 FLASH HALF-WORD 地址 0x5555 4 – 将 0x00AA 写到 FLASH HALF-WORD 地址 0x5555 5 – 将 0x0055 写到 FLASH HALF-WORD 地址 0x2AAA 6 – 将 0x0030 写到要擦除的 SECTOR 对应的 HALF-WORD 地址 对应的代码: *SysAddr16(sysbase, 0x5555) = 0x00AA; *SysAddr16(sysbase, 0x2AAA) = 0x0055; *SysAddr16(sysbase, 0x5555) = 0x0080; *SysAddr16(sysbase, 0x5555) = 0x00AA; *SysAddr16(sysbase, 0x2AAA) = 0x0055; *SysAddr16(sysbase, addr >> 1) = 0x0030; //将值 0x00AA 写到 FLASH HALF-WORD 地址 0x5555 //将值 0x0055 写到 FLASH HALF-WORD 地址 0x2AAA //将值 0x0080 写到 FLASH HALF-WORD 地址 0x5555 //将值 0x00AA 写到 FLASH HALF-WORD 地址 0x5555 //将值 0x0055 写到 FLASH HALF-WORD 地址 0x2AAA //将值 0x0030 写到要擦除的 SECTOR 对应的 HALF-WORD 地址 注意: 上面的代码中第 6 个操作周期中的 ADDR 是从 ARM 处理器的角度来看的 BYTE 地址,因为在擦除的时候,用户 希望指定的是从 ARM 的角度看到的地址,这样更方便和更直观。而在 SysAddr16 的宏定义中,OFFSET 表示的 是相对于 FLASH 起始地址的 HALF-WORD 偏移量,或是 FLASH 在自己的地址信号 An-A0 上看到的地址。所以 需要执行一个右移操作,把 ADDR 转换成 HALF-WORD 地址。 举例说明,SST39VF160 每个 SECTOR 的大小是 4K-BYTE。从 ARM 处理器的角度和用户的角度来看,SECTOR-0 相 对于 FLASH 起始地址的 BYTE 地址是 0x0;从 FLASH 来看 SECTOR-0 的 HALF-WORD 地址是 0x0。从 ARM 处理器 的角度和用户的角度来看,FLASH SECTOR-1 相对于 FLASH 起始地址的 BYTE 地址 0x1000;从 FLASH 来看,SECTOR-1 的 HALF-WORD 地址应该是(0x1000 >> 1) = 0x800。 如果要擦除 SECTOR-0,上面代码的第 6 条指令应该是: 如果要擦除 SECTOR-1,上面代码的第 6 条指令应该是: *SysAddr16(sysbase, 0x1000 >> 1) = 0x0030; *SysAddr16(sysbase, 0x0 >> 1) = 0x0030; HALF-WORD 编程操作 写一个 HALF-WORD 的数据到 FLASH 中去,需要 4 个周期的总线写操作 1 – 将 0x00AA 写到 FLASH HALF-WORD 地址 0x5555 2 – 将 0x0055 写到 FLASH HALF-WORD 地址 0x2AAA 3 – 将 0x00A0 写到 FLASH HALF-WORD 地址 0x5555 4 – 将编程数据(HALF-WORD)写到对应的 HALF-WORD 地址 对应的代码: *SysAddr16(sysbase, 0x5555) = 0x00AA; *SysAddr16(sysbase, 0x2AAA) = 0x0055; *SysAddr16(sysbase, 0x5555) = 0x00A0; *SysAddr16(sysbase, addr >> 1) = data; //将值 0x00AA 写到 FLASH 地址 0x5555 //将值 0x0055 写到 FLASH 地址 0x2AAA //将值 0x00A0 写到 FLASH 地址 0x5555 //将数据写到对应的 HALF-WORD 地址 Copyright © 2008 WWW.HJTAG.COM All Rights Reserved
分享到:
收藏