系统上电前,外部硬线 NAND BOOT 开关选择从 NAND FLASH 启动。芯片设计时,默认 DMA 占有系统总线, DMA 按照配置寄存器的默认值工作,其源地址指向 NAND FLASH ,目标地址指向片上 SRAM , NANDFLASH 控制器在 NAND BOOT 选中的情况下,默认向 NAND FLASH 的首页发出读命令。即上电后, DMA 控制器以及 NAND FLASH 控制器默认的把 FLASH 存储器中的第一页搬到了片上 SRAM 中。一直到 DMA 的工作完成前, ARM 核无法占用总线。此时零地址映射在片上 SRAM , DMA 完成搬运后, ARM 开始执行程序。此段代码完成的工作包括对 SDRAM 控制器的初始化,从 NAND FLASH 搬运核心代码至 SDRAM ,配置地址重映射寄存器至零地址处,最后将 PC 指向零地址的 SDRAM 。在 SDRAM 执行的代码开始真正启动系统。
5 NAND FLASH 系统启动的新方法
一般情况下,片上存储器在作为启动代码转移阶石的同时,往往在启动后也有其特殊的作用。可以作为特殊的程序区,譬如在进行 MP3 解码过程中,核心解码函数作为频繁调用的程序,可以安排在片上 SRAM 中,以提高读取速度,提升系统性能。在 SoC 芯片开发过程中,在整体架构以及模块功能的变化之后,这块内嵌的 SRAM 失去了原来的作用,而仅作为 NAND FLASH 启动时的代码跳板,对于整个芯片而言,付出的代价比较大。于是提出了在没有片上存储器的架构下,从 NAND FLASH 启动的一种新模式。
在上述一般模式启动过程中,片上 SRAM 所起到的作用,就是执行 NAND FLASH 中第一页的代码,将真正的启动代码引入到 SDRAM ,最后将 PC 指针指向 SDRAM 。在失去片上 SRAM 的支持后,可以在控制器的 FIFO 中去执行此段代码,这需要在硬件以及软件代码中作出适当的改变。 (1) 首先需要改变的是地址映射的机制,系统上电后, ARM 即从零地址开始执行指令,零地址映射到 NAND FLASH 的 FIFO 入口地址,地址的译码过程由 AMBA 总线模块完成。在外部硬线 NAND BOOT 拉高的条件下, AMBA 从设备地址译码模块在启动过程中,将零地址的设备选择权给到缓冲 FIFO 。在第一页的指令执行完毕后, PC 指针也指向 SDRAM 。
(2) 其次是 NAND FLASH 控制器在启动过程中,对数据的读取方式。鉴于 NAND FLASH 大批量数据读写的特性,往往采用 DMA 方式对数据进行操作。启动过程中,由 ARM core 直接向 FIFO 读取数据,在 FIFO 读空的情况下,将从没备 READY 信号拉低,等待 NAND 中的数据读出。并且在此读取过程中, DMA 的请求被屏蔽。
(3) NAND FLASH 型号类型众多,从每页容量大小、数据宽度、地址级数以及各型号芯片不同的时序参数,决定了一个控制器接口的兼容性要求相当的高。为了兼容从不同的 NAND FLASH 启动,设置了 4 根硬线作为选择。 NAND BOOT 选择是否从 NAND FLASH 启动; PAGESIZE 选择每页大小,支持 512 B / page , 2 kB / page ; IOWIDE 选择数据端口的宽度,支持 8 位、 16 位; AD-DRESSCYCLE 选择发送地址级数,支持 3 级、 4 级、 5 级地址。时序参数的配置值可以采用默认的宽松值,在读取首页信息之后,将配置值根据当前的时钟频率以及芯片类型,选择舍适的时序值以达到******的性能。 (4) 存储器首页的代码是在缓冲 FIFO 中执行的, FIFO 的入口地址是一个高 24 位的选通地址,因此当系统启动时,零地址开始增加,对 FIFO 中读出的指令而言,低 8 位地址的变化是无关的, FIFO 始终被选通。指令的输出是默认的顺序输出。这就要求首页的代码中不可以出现循环、跳转等语句,并且要求在 128 条指令内完成需要的操作。
6 启动代码和流程的分析
上述的汇编程序即是存放在 NAND FLASH 首页的启动代码,启动的流程如下:
(1) 配置 DMA 控制器的 4 个寄存器,通道使能后,等待 FLASH 发出的搬运请求;
(2) 配置 NAND FLASH 控制器的 3 个寄存器,选择适合的地址、时序参数与所用的 FLASH 芯片吻合;
(3) 分别在 r8 ~ r11 中放入程序需要的备用值;
(4) 将需要在 SDRAM 中运行的 4 条指令搬入 SDRAM 0x30000000 处;
(5) 执行 Nop 指令, Nop 指令用于填充一页 NANDFLASH 中的剩余空间;
(6) 执行在页末的指令,将 PC 指针指向 SDRAM 的 0x30000000 处;
(7) 执行 SDRAM 中的指令,首先启动 NANDFLASH 的数据传输,将程序搬往 SDRAM 的 0x30001000 处。其次执行一个循环语句,等待第一页的程序搬完,之后将 PC 指针指向 0x30001000 处,启动程序从 0x30001000 处正式开始执行。