1. Nor Flash与Nand Flash基础概念解析
在嵌入式系统中,Nor Flash和Nand Flash是两种最常见的非易失性存储介质。虽然它们都属于Flash存储器家族,但在硬件接口和操作方式上存在显著差异。
Nor Flash的特点是具有独立的地址总线和数据总线,支持XIP(eXecute In Place)特性,这意味着CPU可以直接从Nor Flash中读取指令执行,无需将代码复制到RAM中。这种特性使得Nor Flash非常适合存储启动代码和小型操作系统。我曾在项目中遇到过这样的情况:当系统需要快速启动时,直接从Nor Flash运行代码可以节省宝贵的毫秒级时间。
Nand Flash则采用了完全不同的架构,它仅有8个I/O引脚,通过分时复用来传输命令、地址和数据。这种设计使得Nand Flash在容量和成本上具有明显优势,但操作起来更为复杂。在实际开发中,Nand Flash通常需要专门的控制器来管理读写操作。
从可靠性角度来看,Nor Flash几乎没有坏块问题,位翻转概率极低,这使得它成为高可靠性应用的理想选择。而Nand Flash则存在坏块管理和位翻转问题,需要配合EDC/ECC校验算法使用。记得有一次在产品量产测试中,我们发现某些批次的Nand Flash芯片出厂时就带有坏块,这促使我们在驱动程序中加入了更严格的坏块检测机制。
2. S3C2440的存储控制器架构
S3C2440处理器集成了强大的存储控制器,能够同时支持Nor Flash和Nand Flash。理解这个控制器的架构对于后续的uboot操作至关重要。
内存地址映射是首先需要理解的概念。当开发板设置为Nor启动时,CPU看到的0地址就是Nor Flash的起始地址。而在Nand启动模式下,前4K内容会被自动拷贝到片内SRAM中,此时0地址指向的是这片SRAM区域。这个差异在实际调试中经常造成困扰,我曾经就因为在Nand启动模式下尝试直接访问Nor Flash而浪费了大半天时间。
Bank0配置对于Nor Flash操作特别重要。S3C2440的内存控制器将存储空间划分为多个Bank,其中Bank0专门用于启动设备。在硬件设计时需要注意总线宽度设置(8位或16位),这直接影响后续的uboot配置。我们的开发板采用的是16位总线宽度,因此在uboot中需要相应设置。
对于Nand Flash控制器,S3C2440提供了全套硬件支持,包括:
- NFCONF:配置时序参数
- NFCONT:控制寄存器
- NFCMD:命令寄存器
- NFADDR:地址寄存器
- NFDATA:数据寄存器
这些寄存器大大简化了Nand Flash的操作,开发者无需手动控制CLE、ALE等信号线。不过在实际使用中,我发现时序参数的设置非常关键,不当的设置会导致读写不稳定。
3. Uboot下Nor Flash操作实战
在uboot环境中操作Nor Flash可以快速验证硬件连接和基本功能。以下是我总结的实用操作流程:
识别Flash芯片是第一步,通过uboot命令可以读取厂商ID和设备ID:
mw.w 555 aa mw.w 2aa 55 mw.w 555 90 md.w 0 1 # 读取厂商ID md.w 2 1 # 读取设备ID mw.w 0 f0 # 退出识别模式CFI模式查询能获取更详细的芯片信息:
mw.w 55 98 # 进入CFI模式 md.w 10 1 # 应返回'Q' md.w 11 1 # 应返回'R' md.w 12 1 # 应返回'Y' md.w 27 1 # 读取容量信息 mw.w 0 f0 # 退出CFI模式擦除和编程操作需要特别注意地址选择,避免覆盖uboot本身:
mw.w 555 aa mw.w 2aa 55 mw.w 555 80 # 准备擦除 mw.w 555 aa mw.w 2aa 55 mw.w 100000 30 # 擦除100000开始的块数据写入需要先确保目标区域已擦除:
mw.w 555 aa mw.w 2aa 55 mw.w 555 a0 mw.w 100000 1234 # 写入数据在实际项目中,我开发了一个简单的菜单驱动测试程序,可以方便地进行Nor Flash的扫描、擦除、读写操作。这个程序的核心函数包括:
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; } unsigned int nor_read_word(unsigned int base, unsigned int offset) { volatile unsigned short *p = (volatile unsigned short *)(base + (offset << 1)); return *p; }4. Uboot下Nand Flash操作实战
Nand Flash的操作比Nor Flash复杂得多,但uboot已经提供了良好的支持。以下是关键操作步骤:
初始化Nand控制器是首要任务:
#define TACLS 0 #define TWRPH0 1 #define TWRPH1 0 NFCONF = (TACLS<<12)|(TWRPH0<<8)|(TWRPH1<<4); NFCONT = (1<<4)|(1<<1)|(1<<0);读取ID信息验证硬件连接:
mw.b 4E000008 90 # 发送90h命令 mw.b 4E00000C 00 # 发送地址00h md.b 4E000010 1 # 读取厂商ID(应返回ECh) md.b 4E000010 1 # 读取设备ID mw.b 4E000008 ff # 退出识别模式页读取操作的完整流程:
- 发送00h命令
- 分5个周期发送地址(2个列地址+3个行地址)
- 发送30h命令
- 等待就绪
- 读取数据
在代码实现上,我通常封装以下函数:
void nand_addr(unsigned int addr) { unsigned int col = addr % 2048; unsigned int page = addr / 2048; NFADDR = col & 0xff; NFADDR = (col >> 8) & 0xff; NFADDR = page & 0xff; NFADDR = (page >> 8) & 0xff; NFADDR = (page >> 16) & 0xff; } void nand_read(unsigned int addr, unsigned char *buf, unsigned int len) { nand_select(); nand_cmd(0x00); nand_addr(addr); nand_cmd(0x30); nand_wait_ready(); for(int i=0; i<len; i++) { buf[i] = nand_data(); } nand_deselect(); }坏块管理是Nand Flash特有的挑战。在实际项目中,我们会在uboot中实现坏块检测算法,通常是在擦除时检查状态字。一个实用的技巧是在OOB区域存储特殊标记来标识坏块。
5. 开发中的常见问题与解决方案
在长期使用S3C2440开发过程中,我积累了一些宝贵的排错经验:
地址对齐问题是最常见的错误来源。Nor Flash操作时,地址需要左移一位(乘以2)因为我们的开发板采用16位总线。我曾经花了整整一天时间追踪一个bug,最终发现就是因为忘记了这个转换。
时序配置不当会导致Nand Flash操作不稳定。不同厂商的芯片对tACLS、tWRPH0等参数要求不同。我的经验是先用保守值(较大的数值)确保基本功能,再逐步优化。
uboot环境变量存储也是一个容易出问题的地方。当同时使用Nor和Nand Flash时,需要明确指定环境变量存储位置。我推荐的做法是在Nor Flash中保留一个小的区域专门存储环境变量。
调试技巧方面,我强烈建议:
- 充分利用uboot的md/mw命令直接操作寄存器
- 在关键操作后检查状态寄存器
- 使用示波器观察实际波形时序
- 分阶段验证,先确保识别正常再测试读写
记得有一次,Nand Flash的读写始终失败,最后用示波器发现是硬件连接上的一个虚焊导致ALE信号不稳定。这种问题通过软件调试是很难发现的。