基于AT91RM9200与LINUX2.6.26内核的嵌入式平台开发全过程

 

一、ARM9+LINUX开发历程

    使用了51系列和MOTOROLA单片机若干年,觉得自己已经跟不上嵌入式发展的时代了。决定开发一种新的硬件平台,综合比较了一下,觉得ARM9+LINUX模式不错。先从头捋一遍32位嵌入式开发平台的流程:

芯片选型——使用DXP画原理图(如果有可能买块开发板可以极快加快进度)——使用DXP画PCB图——芯片购买/PCB投板生产——芯片焊接—— 使用ADS编写简单硬件测试程序,调试硬件——搭建LINUX服务器,在服务器建立交叉编译环境——利用服务器和本机超级终端开发U-BOOT- 1.3.4——利用U-BOOT-1.3.4的以太网FTP功能和服务器移植开发LINUX-2.6.26 内核——开发文件系统——开发驱动程序——应用程序开发,项目完基本成后回过头来想就是这个一个过程,中间走了不少弯路,在本博客中都有记载,很多问题有 的也没有来得及记。

说干就干,时间安排如下:

(1)5~7月硬件设计(芯片,型号,预测价格),已初步完成

CPU:AT91RM9200,81

SDRAM:MT48LC16M16A2TG-75IT(两片32MB*2) 74*2

FLASH:S29GL256N10TAI010(NOR型,32MB,存代码,写慢读快)57.52

FLASH∶K9F2G08U0B(NAND256MB,预留存测试数据,写快读慢)41.1

铁电存储器:FM24CL64(代替EEPROM24LC65,8KB)8.29

以太网物理层控制器:DM9161E(100M/10M自适应)9.4

从USB接口:用于与PC机通信

主USB接口:用于后续移植LINUX时软件更新

触摸屏驱动器:TSC2046(预留)

液晶显示屏模块-TFT液晶显示接口(预留)

 

(2)ADS+AXD+J-LINK调试过程

   目的是为了熟悉ARM开发流程,ADS开发环境,以便为将来U-BOOT的移植打下基础.由于网上资料不多,本步骤走了不少冤枉路,特总结在此,以便以后可以参考.容易步骤省略.

 安装ADS>>创建ADS工程>>添加所需要文件>>DEBUG SETTING,将程序的RO_Base设为0X200000则将程序导入AT91RM9200的片内16K的SRAM中运行,实践证明此时不需要管 BMS引脚是高是低都能正常运行,也不需要进行REMAP;若将程序的RO_Base设为0X20000000则将程序导入片外64M的SDRAM中运 行,此时程序导进SDRAM后需要SETMEM命令将SDRAM初始化,才能正常运行。

    通常出现RDI Warning 00005:Data abort的告警时是由于CPU复位时间不购导致的,且程序会莫名其妙出现Read memory error @address 0x00200020,word access : Memory access timeout的J-Link RDI Error告警。此时只需要在AXD的Option>target Configure>选择J-LINK,然后点击Configure>选择CPU页,在Reset strategy框中选择Hardware,halt after reset(normal),在Delay after reset中填写所需要的芯片复位时间,由于AT91RM9200的慢时钟需要900ms左右的启动时间,所以将复位时间设为2000ms即可正常调 试。(图片无法帖出,遗憾!)

   ADS+AXD的主要功能是进行硬件调试,检测SDRAM,FLASH是否能正常工作。源码调试不一定非要AXD不可,有GDB等优秀的调试手段

 

(3)硬件调试过程

     8月25日拿终于拿到了呕心沥血设计的板子,外协厂家的手艺还不错,板子焊得干净漂亮。首先用万用表测量各电源等级的正负端,判定 12V,5V,3.3V,1.8V,-5V,-12V等电源回路不存在短路现象,免得烧掉板子后悔莫及。一切OK,愈发佩服焊接工人,这么多芯片,电容, 电阻居然没有什么大问题!找来USB转串口线,接上板子的DBUG口,紧张时刻来临,打开超级终端,设置波特率115200,数据位8,无奇偶,1停止 位,无数据流控制,给开发板上电,很遗憾传说中的CCCCC一直没有出现,哪里出问题?反复查看原理图和电路板,发现R122电阻居然给我焊成了10K 的,没有办法,飞吧。继续上电,涛声依旧,再看电路板,有个6800P的DPLL用滤波电容的颜色怎么跟0.1U的电容颜色一致?我汗,居然这么多问题, 刚才还在赞扬外协,实在无语!重新找来6800P电容,焊上。感觉没有问题,用示波器测32.768KHZ晶振有波形,BMS引脚已经拉高。最后怀疑 RS232的接线有问题,反复折腾,2,3,5各线换来换去,在某个刹那超级终端终于捕捉到了一个C,虽然只有一个,但让我信心大增,继续查找。终于发现 原来DB-9的232接口焊成了公头,设置时按母头设计,我晕阿。记住了,公头5-母头1,公头4-母头2,公头3-母头3。。。。。。。还需要紧记与电 脑连接时,2,3需要调换才行。电烙铁来,我飞,上电,一切OK。久违的CCCCCCC犹如洪水泛滥,一发不可收拾,逛激动。。。。。。。找来 loader,使用XMODEN协议传下去,正常,继续使用XMODEN协议传编译好的U-BOOT.BIN,U-BOOT终于转起来。快下班了,匆匆忙 忙用网线连了一下,灯居然亮了,感觉人生原来是如此美好!是夜睡了晚好觉。

   8月27,loader ,boot,u-boot使用超级终端折腾得差不多了,才想起来网线一直没有用过,找来网线我插。??没有反应?继续插还没有反应。难道前天眼花了?反复 插,终于灯亮了一下,激动。在U-BOOT里使用setenv addrip 172.21.26.1设置IP,在笔记本里我反复ping,反复超时,郁闷。复位,糟糕灯不亮了,重新上电,灯还不亮,为什么?探索中。。。。。。。原 来U-BOOT没有相应PING命令,只能测到ACTIVE即可算连接通上,而PC机的PING命令对U-BOOT也无效,能将内核通过以太网以FTP协 议传下去即可认为网络通信正常。

   9月1日发现使用MAX660和MAX765产生负电源功率太小,准备采用模块电源供电。调试模拟电路发现DA电压经单/双极性运放输出后带负载时电压下降厉害,加一个电压跟随器后正常。所以在需要提高输入阻抗降低输出阻抗的场合使用电压跟随器是最好的选择。

(3)U-BOOT的移植

     下载了U-BOOT-1.3.4版本,按文档设置好编译器路径及前缀 LINUX下的环境变量。

修改Makefile文件中以下部分:

ifeq ($(ARCH),arm)
CROSS_COMPILE = arm-unknown-linux-gnueabi-
endif

修改include〉configs〉at91rm9200dk.h(修改配置,主要是SDRAM的大小,NORFLASH的信息)

修改board>atmel>at91rm9200dk>at91rm9200dk.c(主要修改片选及NANDFLASH的引脚配置)

 

 进入U-BOOT-1.3.4的文件夹,执行如下命令:

make distclean     删除原先的配置文件

make clean         删除原来编译生成的目标文件和中间文件

make at91rm9200dk_config   U-Boot设为for 9200

     make               编译最终的可执行文件

 

     gzip u-boot.bin     压缩成U-BOOT.BIN.GZ,u-boot-1.3.4对AT91RM9200的支持非常棒,几乎没有修改什么咚咚就可以正常转起来了。

(4) U-BOOT的下载固化

1、将loader.bin通过超级终端下载到板子中,使用XMODEN协议,下载完继续出现CCCCC

2、继续在超级终端使用XMODEN协议下载U-BOOT.bin到板子中,出现以下内容:

Loader 1.0 (Mar  1 2008 - 21:44:40)                                    

XMODEM: Download U-BOOT (to address 20F00                                       
CCCCCCCCCC         
U-Boot downloaded successfully                             


U-Boot 1.3.4 (Sep 22 2008 - 13:46:33)                                    

DRAM:  64 MB           
Spansion: S29GL256N (32M Byte)                             
Flash: 32 MB           
NAND:    No SmartMedia card inserted                                   
   0 MB      
*** Warning - bad CRC, using default environment    

SSC 510T-Boot>

至此,U-BOOT已经在板子中正常运行起来。将U-BOOT和BOOT.bin固化到板子中(U-BOOT的FLASH驱动此前已经修改完成,有时间再另写)

SSC 510T-Boot> protect off all (去掉FLASH写保护功能)

SSC 510T-Boot> erase 1:0  (擦除第一块FLASH的0扇区,128KB)

SSC 510T-Boot> loadb 0x21000000   (使用KERMIT协议下传BOOT.BIN)

SSC 510T-Boot> cp.b 0x21000000 0x10000000 0x5000 (将BOOT.BIN固化到FLASH中)

SSC 510T-Boot> loadb 0x22000000    (使用KERMIT协议下传U-BOOT.BIN.TAR)

SSC 510T-Boot> cp.b 0x22000000 0x10010000 0xFFFF (将U-BOOT.BIN.TAR固化到FLASH中)

SSC 510T-Boot> protect on all

 

但是发现boot.bin只能执行到下面:
**Welcome to ATMEL AT91RM9200**                              
*******************************                              
WFG: Bootloader 2                
BOOT 1.0 (Sep 25 2008 - 12:40:29)                                

Uncompressing image...

由 于无法进行源码级调试,只能将调试信息发到超级终端了.逐步证明makecrc()函数没有问题,问题出现在gunzip()函数上的magic[0] = (unsigned char)get_byte()此语句中.想象可能跟编译时出现了-mshort-load-bytes错误有关,为了编译通过我去掉了该选项,导致了 CPU在以字(16位)组织的FLASH中按字节(8位)读取时出现了错误,估计可能是类似于M68K系列CPU的双总线错误差不多.折腾了两天才解决此 问题.
原来我使用了4.2版本的编译器编译U-BOOT-1.3.4和内核,都没有出什么错误,就想当然用它来编译BOOT,结果发生了cc1: error: unrecognized command line option "-mshort-load-bytes"错误,在网上查找,试图使用-malignment-traps来代替也不行.后来找了个3.2版本的编译器编 译通过却发射了如我其他帖子所描述那样的无法BOOT的过程.在网上反复查找,确定BOOT只能用cross-2.95.3的编译器来编译.事实证明确实 如此,将编译好的boot.bin和u-boot.bin.gz烧到FLASH中去后,我FLASH使用S29GL256N,正常启动!启动画面如下:
Loading: T T T T ************************                                        
**Welcome to ATMEL AT91RM9200**                              
*******************************                              
WFG: Bootloader 2                
BOOT 1.0 (Sep 25 2008 - 12:40:29)                                

Uncompressing image...                     

Uncompressing ...                

 gunzip() out! (这个就是我调试用的输出信息,证明程序运行到此处没有问题!)           

done....       


U-Boot 1.3.4 (Sep 25 2008 - 12:49:14)                                    

DRAM:  64 MB           
Spansion: S29GL256N (32M Byte)                             
Flash:     
NAND:    No SmartMedia card inserted                                   
   0 MB      
In:    serial            
Out:   serial            
Err:   serial            
SSC 510T-Boot> protect off all  (去掉FLASH保护,准备写入内核)                        
Un-Protect Flash Bank # 1                        
SSC 510T-Boot> printenv                      
bootdelay=3          
baudrate=115200              
ethaddr=08:00:3e:26:0a:5b                        
serverip=172.21.26.148                     
netmask=255.255.0.0                  
ipaddr=172.21.16.1                 
stdin=serial           
stdout=serial            
stderr=serial            

Environment size: 157/131068 bytes                                 
SSC 510T-Boot> setenv ipaddr 172.21.26.100 (设置环境变量)                                     
SSC 510T-Boot> setenv bootcmd 0x10040000 (内核位置)                                      
SSC 510T-Boot> setenv bootm 0x10240000   (文件系统位置)                                 
SSC 510T-Boot> saveenv                     
Saving Environmen              
Un-Protected 1 sectors                     
Erasing Flash...Erasing sector  1 ... ok.                                        
Erased 1 sectors               
Writing to Flash... done                       
Protected 1 sectors
SSC 510T-Boot> erase 1:2-17 (擦除2-17扇区,存放内核)
SSC 510T-Boot> erase 1:18-36 (擦除18-36扇区,存放文件系统)
SSC 510T-Boot> tftpboot 20000000 zImage.img (通过以太网下载内核)
TFTP from server 172.21.26.148; our IP address is 172.21.26.100
Filename 'zImage.img'.
Load address: 0x20000000
Loading: T T T T ###############################################################
##
         #############
done
Bytes transferred = 1134056 (114de8 hex)
SSC 510T-Boot> cp.b 20000000 10040000 1fffff (将内核写道FLASH中,1分钟左右)
Copy to Flash... done
SSC 510T-Boot> tftpboot 21000000 ramdisk.cramfs (通过以太网下载文件系统)
TFTP from server 172.21.26.148; our IP address is 172.21.26.100
Filename 'ramdisk.cramfs'.
Load address: 0x21000000
Loading: #################################################################
         #################################################################
         #####################################
done
Bytes transferred = 2449408 (256000 hex)
SSC 510T-Boot> cp.b 21000000 10240000 300000 (将文件系统写到FLASH中,5分钟左右)
Copy to Flash... done
SSC 510T-Boot>

到这里成功了一半了,但发现在star kernel.......后再也没有什么反应,分析如下:
内存中:
20000000-内核
20410000-文件系统
20F00000-U-BOOT.BIN
21000000-内核解压到此处运行
发 现U-BOOT.BIN与内核运行处只有1M空间,察看源码U-BOOT除了本身占用了115K外还须留了不小的空间传递参数给内核,可能是此空间被覆盖 了造成所传递参数被破坏,导致内核无法启动.将U-BOOT移到21F00000处,重新倒入内核文件系统,系统正常运行了!

在移植内核时发生machine ID 错误,把U-BOOT的at91rm9200_config改成at91rm9200dk_config就可以了。或者在LINUX- 2.26.3/arch/arm/mach-at91/board-dk.c中的AT91RM9200DK修改为AT91RM9200,如下:

MACHINE_START(AT91RM9200, "Atmel AT91RM9200-DK")
   
    .phys_io    = AT91_BASE_SYS,
    .io_pg_offst    = (AT91_VA_BASE_SYS >> 18) & 0xfffc,
    .boot_params    = AT91_SDRAM_BASE + 0x100,
    .timer        = &at91rm9200_timer,
    .map_io        = dk_map_io,
    .init_irq    = dk_init_irq,
    .init_machine    = dk_board_init,
MACHINE_END

(5)内核编译

  1、安装

从www.kernel.org上下载Linux2.6.26版的kernel,解压到 /usr/src/arm/linux-2.6.26
从http://maxim.org.za/AT91ARM9200/2.6/ 上下载针对rm9200的补丁(这个网站很难上,多试几次),文件名:2.6.26-at91.patch.gz,复制到 /usr/src/arm/linux-2.6.26,然后在命令行界面中执行 zcat 2.6.26-at91.patch.gz |patch -p1
下载GCC编译器,文件名:arm-linux-gcc-4.1.2.tar.bz2,解压到 /usr/local/arm/4.1.2

2、修改

打开内核原代码根目录下的Makefile,找到如下两行:
ARCH ?=$(SUBARCH)
CROSS_COMPILE ?=
修改为:
ARCH ?=arm
CROSS_COMPILE ?=/usr/local/arm/4.1.2/bin/arm-linux-

3、编译内核

执行如下命令:
make at91rm9200dk_config
make menuconfig
make zImage
大约15分钟内核就会编译好,生成的内核文件在/usr/src/arm/linux-2.6.16/arch/arm/boot/zImage

4、配置选项

当执行make menuconfig后,进入配置菜单,有些选项必须改成如下的内容,否则生成的内核不能运行:

boot options->Compressed ROM boot loader base address=0x21000000
boot options->Compressed ROM boot loader BSS address= 0x21200000
boot options->Default kernel command string= "mem=64M console=ttyS0,115200 initrd=0x20410000,900000 root=/dev/ram0 rw"

如果打算使用NFS,必须选中以下这一选项:
File systems->Network file systems->NFS file system support

到此处后发现生成的Image和zImage文件用FTP倒入板子中均不能用GO命令正常启动。Image老是报告machine ID 错误,而zImage则是发生CRC错误,如下界面:
crc error

 -- System halted*****************************
而使用如下命令:
gzip Image
./mkimage -A arm -O linux -T kernel -C gzip  -a 0x20000000 -e 0x21000000 -d Image.gz uImage
生成的Image.gz则发生解压错误:
## Booting kernel from Legacy Image at 20000000 ...
   Image Name:
   Image Type:   ARM Linux Kernel Image (gzip compressed)
   Data Size:    1241675 Bytes =  1.2 MB
   Load Address: 20000000
   Entry Point:  21000000
   Verifying Checksum ... OK
   Uncompressing Kernel Image ... Error: inflate() returned -3
GUNZIP: uncompress or overwrite error - must RESET board to recover***********
而试图不使用压缩文件格式时(即去掉-c gzip)
./mkimage -A arm -O linux -T kernel  -a 0x20000000 -e 0x21000000 -d Image uImage
则会有如下错误:
## Booting kernel from Legacy Image at 20000000 ...
   Image Name:
   Image Type:   ARM Linux Kernel Image (gzip compressed)
   Data Size:    2564216 Bytes =  2.4 MB
   Load Address: 20000000
   Entry Point:  21000000
   Verifying Checksum ... OK
   Uncompressing Kernel Image ... Error: Bad gzipped data
GUNZIP: uncompress or overwrite error - must RESET board to recover************
*******************
到此处颇有黔驴技穷的感觉!
10 月9日再记,以上参数中 -a指定的内核加载地址和-e指定的入口地址不一致,所以无法正常启动,其进一步机理尚有待研究。这个参数和u-boot使用tftp 0x20000000 uImage中的地址是不相干的,只是内核下载到内存中哪里就必须bootm哪里即可,前两天一直误解了加载地址以为就是TFTP的下载地址。
10 月5日解决了此问题。原来在内核源码编译后在linux-2.6.26.3/arch/arm/boot/生成了Image和zImage两个文件,应该 说配合u-boot-1.3.4/tools/mkimage工具的-C 选项共有4种组合决定使用压缩与否的格式,事实证明到目前为止只有使用以下参数格式的mkimage内核才能正常引导:
./u-boot-1.3.4/u-boot-1.3.4/tools/mkimage -A arm -O linux -T kernel -C none -a 0x21000000 -e 0x21000000 -d ./linux-2.6.26.3/arch/arm/boot/zImage uImage.bin
使用上述生成的uImage.bin终于能正常启动了。且看传说中的ping命令:
[linux:]ls -l
-rw-r--r--    1 1004     233          1244 Jan  1  1970 exapme1.bin
-rwxrwxrwx    1 1004     233           984 Jan  1  1970 hello.bin
-rwxrwxrwx    1 1004     233           134 Jan  1  1970 main.c
[linux:]ping 172.21.26.148
PING 172.21.26.148 (172.21.26.148): 56 data bytes
64 bytes from 172.21.26.148: seq=0 ttl=128 time=7.995 ms
64 bytes from 172.21.26.148: seq=1 ttl=128 time=0.977 ms
64 bytes from 172.21.26.148: seq=2 ttl=128 time=1.190 ms
64 bytes from 172.21.26.148: seq=3 ttl=128 time=1.130 ms
64 bytes from 172.21.26.148: seq=4 ttl=128 time=0.976 ms
64 bytes from 172.21.26.148: seq=5 ttl=128 time=1.221 ms
64 bytes from 172.21.26.148: seq=6 ttl=128 time=1.129 ms
64 bytes from 172.21.26.148: seq=7 ttl=128 time=1.068 ms
64 bytes from 172.21.26.148: seq=8 ttl=128 time=1.251 ms
^C
--- 172.21.26.148 ping statistics ---
9 packets transmitted, 9 packets received, 0% packet loss
round-trip min/avg/max = 0.976/1.881/7.995 ms
[linux:](太长了被我ctrl+c了)

 

(6) 建立NFS文件系统

10月10日,在建立NFS文件系统过程中老出现eth0无法配置的问题,反复百度没有解决。一开始以为是硬件问题,郁闷了很长时间,后来发现,如 果启动时经U-BOOT初始化一下以太网控制器会好些,初步断定为LINUX2.6.26的内核问题。在 driver>net>arm>at91_ether.c中找到static void __init get_mac_address(struct net_device *dev)函数,该函数是初始化MAC地址的,如果U-BOOT也不去初始化以太网控制器,很显然AT91RM9200的 AT91_EMAC_SA1H/AT91_EMAC_SA1L~AT91_EMAC_SA4H/AT91_EMAC_SA4L的值将是复位值。而经过U- BOOT初始化后会将默认的CONFIG_ETHADDR所定义的MAC地址写入以上寄存器中,然后LINUX启动时可以正常读到;而如果U-BOOT自 动启动应用程序时,很显然MAC地址没有初始化。所以解决办法就是MAC地址需要和IP地址一样由U-BOOT以环境变量的形式固化在FLASH中,然传 递给内核。

在服务器端建立NFS服务,将所编译器所需要的库全部搬到NFS下的LIB文件夹中;修改etc>init.d>rcs,如下,主要修改板子的IP及网关地址:

#! /bin/sh
echo "----------mount all"
/bin/mount -a


echo "----------Starting mdev......"
/bin/echo /sbin/mdev > /proc/sys/kernel/hotplug
mdev -s

 

echo "*********************************************************"
echo " 2008 arm-linux "
echo " OK "
echo "********************************************************"


echo "----------config bet......"

/sbin/ifconfig eth0 172.21.26.23 netmask 255.255.0.0 (板子的IP地址/子网掩码)

/sbin/route add default gw 172.21.26.254

内核则需修改启动配置命令行(可以直接修改根目录下的.config文件)

CONFIG_CMDLINE="mem=64M console=ttyS0,115200 noinitrd root=/dev/nfs rw nfsroot=172.21.25.211:/home/wfg/rootnfs,nolock   ip=172.21.26.123:172.21.25.211:172.21.26.254:255.255.255.0::eth0:off"

 其中板子IP为172.21.26.123,服务器的IP为172.21.25.211,服务器则所建NFS文件夹为:/home/wfg/rootnfs

内核中还需在FILE SYSTEM〉NETWORK FILE SYSTEM中选择NFS file system support 和Root files system on NFS支持。

注意:u-boot中的启动参数设置和LINUX内核的CONFIG_CMDLINE作用是相同的,只要在一边设即可。

(7)内核的修改

针对一款CPU内核的修改主要在arch>arm>mach-at91.c中修改。

(8)NAND FLASH驱动支持

至此,该嵌入式应用平台已经可以提供最基本的功能,接下来开始编写LINUX2.6.26内核下的各种硬件驱动,以及应用程序开发。首先需要提供NAND FLASH支持。虽然程序已经存储在NOR FLASH中了,但由于NOR FLASH的擦除速度太慢,所以测试数据还是应该保留在NAND FLASH中的。

10月25日拿到新板子,怎么测试都无法读出芯片ID,都是0,奇怪!原来错用了MM74HC32或门,其实应该是MM74HC08与门才对。没办 法,飞线.注意NAND FLASH芯片的读写时许,该芯片在整个读写操作过程中要求片选信号都为低,所以只能使用IO引脚控制之。使用AXD测试程序芯片ID终于读出来,数据也 能正常写入读出。

在U-BOOT中对NANDFLASH的支持还远没有NORFLASH那么完美,需要修改的地方较多:

首先,在配置文件at91rm9200dk.中增加如下配置:

#define CONFIG_CMD_NAND

#define CFG_NAND_BASE 0x40000000 /* wuyan add */
#define CFG_MAX_NAND_DEVICE 1 /* Max number of NAND devices  */
#define SECTORSIZE  2048  /*2048 for K9F2G08U, 512 for K9F2808 */

#define ADDR_COLUMN 2
#define ADDR_PAGE 3
#define ADDR_COLUMN_PAGE 5

#define NAND_ChipID_UNKNOWN 0x00
#define NAND_MAX_FLOORS 1
#define NAND_MAX_CHIPS 1

#define AT91_SMART_MEDIA_ALE (1 << 6) /* our ALE is AD6 */
#define AT91_SMART_MEDIA_CLE (1 << 7) /*our CLE is AD7*/

注意U-BOOT对NANDFLASH的操作有两种方法,一种是定义了CFG_NAND_LEGACY ,使用传统方法去进行读写;另一种是通过MTD层操作NANDFLASH,而U-BOOT中的MTD还有几个函数没有实现,所以还需要对 at91rm9200dk.c进行修改

其次,在board/atmel/at91rm9200dk.c中只实现nand_init (void)函数,在该函数中修改片选引脚

*AT91C_EBI_CSA |= AT91C_EBI_CS3A_SMC_SmartMedia;

 AT91C_BASE_SMC2->SMC2_CSR[3] = (SM_RWH | SM_RWS |
  AT91C_SMC2_ACSS_STANDARD | AT91C_SMC2_DBW_8 |
  SM_TDF | AT91C_SMC2_WSEN | SM_NWS);

 *AT91C_PIOC_ASR = AT91C_PC1_BFRDY_SMOE |AT91C_PC3_BFBAA_SMWE;
 *AT91C_PIOC_PDR = AT91C_PC1_BFRDY_SMOE |AT91C_PC3_BFBAA_SMWE;

 /* Configure PC14 as input (signal READY of the NAND FLASH) */
 *AT91C_PIOC_ODR = AT91C_PIO_PC14; /* disable output */
 *AT91C_PIOC_PER = AT91C_PIO_PC14; /* enable direct output enable */

 /* Configure PB25 as input (/cs for NAND FLASH) */
 *AT91C_PIOB_PER = AT91C_PIO_PB25; /* enable direct output enable */
 *AT91C_PIOB_ODR = AT91C_PIO_PB25; /* disable output */

 /* PIOB and PIOC clock enabling */
 *AT91C_PMC_PCER = 1 << AT91C_ID_PIOB;
 *AT91C_PMC_PCER = 1 << AT91C_ID_PIOC;
此外,还需要实现如下函数:

static void at91rm9200_nand_hwcontrol(struct mtd_info *mtd, int cmd)

static int at91rm9200_nand_ready(struct mtd_info *mtd)

int board_nand_init(struct nand_chip *nand)

完成后将使用mkimage工具压缩过的内核放在JFFS2文件系统中,烧写到NANDFLASH中去,而u-BOOT与环境变量依然放在 NORFLASH中。U-BOOT是支持JFFS2文件系统的,这样内核放在该文件系统的根目录下,U-BOOT能去读取内核,在系统启动后再反过来挂接 文件系统。使用buybox创建完ramdisk文件系统可以使用如下命令压缩成JFFS2文件格式:

mkfs.jffs2 -r rootfs -o rootfs.jffs2 -e 0x20000 -s 0x800 -n (-e表示擦除块大小,-s表示扇区大小,-r为输出文件名)

 

还要设置好如下环境变量:

bootdelay=3
baudrate=115200
ethaddr=08:00:3e:26:0a:5b
mtdids=nand0=nand0
mtdparts=mtdparts=nand0:4096k(kernel),12288k(rootfs),-(data)
bootargs=noinitrd root=/dev/mtdblock1 console=ttyS0,115200 mem=64M rootfstype=jffs2 rw
fileaddr=21000000
netmask=255.255.0.0
ipaddr=172.21.26.100

serverip=172.21.26.148
partition=nand0,1
mtddevnum=1
mtddevname=rootfs
loadaddr=20008000
filesize=135c9c
bootcmd=fsload aImage20008000;bootm 20008000
stdin=serial
stdout=serial
stderr=serial

使用如下命令将JFFS2文件系统烧写到NANDFLASH中去:

U-Boot> tftp 0x20000000 rootfs.jffs2
TFTP from server 172.21.26.148; our IP address is 172.21.26.1
Filename 'rootfs.jffs2'.
Load address: 0x20000000
Loading: #################################################################
         #################################################################
         #################################################################
         #################################################################
         #################################################################
         #################################################################
         #############################
done
Bytes transferred = 6150772 (5dda74 hex)
U-Boot> nand erase

NAND erase: device 0 whole chip
Skipping bad block at  0x08480000
Erasing at 0xffe0000 -- 100% complete.
OK
U-Boot> nand write.jffs2 0x20000000 0x400000 0x5dda74

NAND write: device 0 offset 0x400000, size 0x5dda74

Writing data at 0x9dd800 -- 100% complete.
 6150772 bytes written: OK

在板子上可以使用TFTP协议读取服务器上的文件,这样方便模块的调试:

tftp -gr uImage.bin  172.21.26.148 //在172.21.26.148上读取uImage.bin文件

(9) JFFS2文件系统

    JFFS2文件系统是基于NAND FLASH的MTD技术的日记文件系统,在嵌入式领域有广泛应用。在上面的应用中将内核bin文件放到根文件目录下面,让U-BOOT去读取。此种做法有 种弊端就是在修改了某些模块然后利用TFTP协议下载测试时会改写NAND FLASH导致CRC码与初始状态不一致,这样重新启动系统时将报CRC校验错误。因为内核修改并不多,常常修改的是模块代码,所以可以为内核单独辟出一 个分区,这样以后模块修改后无需每次都将内核重新烧写,在上电启动时JFFS2扫描会快很多。将内核烧写在0处,占4M空间;将文件系统烧写到 0x400000处,共计12M;其余240M左右的空间留给应用程序。烧写过程如下:

 

U-Boot> nand erase

NAND erase: device 0 whole chip
Skipping bad block at  0x08480000
Erasing at 0xffe0000 -- 100% complete.
OK
U-Boot> tftp 0x20000000 kernel.jffs2
TFTP from server 172.21.26.148; our IP address is 172.21.26.1
Filename 'kernel.jffs2'.
Load address: 0x20000000
Loading: #################################################################
         #############################################
done
Bytes transferred = 1604592 (187bf0 hex)

U-Boot> nand write.jffs2 0x20000000 0x00 187bf0

NAND write: device 0 offset 0x0, size 0x187bf0

Writing data at 0x187800 -- 100% complete.
 1604592 bytes written: OK
U-Boot> tftp 0x21000000 rootfs.jffs2
TFTP from server 172.21.26.148; our IP address is 172.21.26.1
Filename 'rootfs.jffs2'.
Load address: 0x21000000
Loading: #################################################################
         #################################################################
         #################################################################
         #################################################################
         #################################################################
         #################################################################
         #######################################
done
Bytes transferred = 6295500 (600fcc hex)
U-Boot> nand write.jffs2 0x21000000 0x400000 600fcc

NAND write: device 0 offset 0x400000, size 0x600fcc

Writing data at 0xa00800 -- 100% complete.
 6295500 bytes written: OK

相应环境变量做如下设置:

U-Boot> printenv
bootdelay=3
baudrate=115200
ethaddr=08:00:3e:26:0a:5b
mtdids=nand0=nand0
mtdparts=mtdparts=nand0:4096k(kernel),12288k(rootfs),-(data)  ---修改
bootargs=noinitrd root=/dev/mtdblock1 console=ttyS0,115200 mem=64M rootfstype=jf
fs2 rw
fileaddr=21000000
netmask=255.255.0.0
mtddevnum=1
mtddevname=rootfs
loadaddr=20008000
filesize=135c9c
bootcmd=fsload aImage20008000;bootm 20008000
ipaddr=172.21.26.1
serverip=172.21.26.148
partition=nand0,0----修改
stdin=serial
stdout=serial
stderr=serial

Environment size: 469/131068 bytes

在文件系统中,在超级用户下可以修改启动脚本/etc/init.d/rcS,在尾部添加:

insmod dram_driver
mknod /dev/dram_driver c 221 1
/dram_test

这样系统启动了以后自动加载模块,并创建设备文件,执行测试程序!

 

(10) USB挂载实验

     配置完内核后,使用fdisk -l命令后发现了U盘:

root@WK:fdisk -l

Disk /dev/sda: 131 MB, 131072000 bytes
255 heads, 63 sectors/track, 15 cylinders
Units = cylinders of 16065 * 512 = 8225280 bytes

   Device Boot      Start         End      Blocks  Id System
/dev/sda1   *           1          16      128504   b Win95 FAT32

但在此处直接挂载不成功:
root@WK:mount /dev/sda1 /tmp
FAT: codepage cp437 not found
FAT: codepage cp437 not found
yaffs: dev is 8388609 name is "sda1"
yaffs: passed flags ""
yaffs: Attempting MTD mount on 8.1, "sda1"
yaffs: dev is 8388609 name is "sda1"
yaffs: passed flags ""
yaffs: Attempting MTD mount on 8.1, "sda1"
mount: mounting /dev/sda1 on /tmp failed: Invalid argument
root@WK:

 

重新配置内核:
1、让内核支持热插拔
│ General setup --->
│ │
Support for hot-pluggable devices
2、USB驱动设置,可参考
http://www-128.ibm.com/developerworks/cn/linux/l-usb/index1.html
│ │ Device Drivers --->
│ │ Generic Driver Options --->
│<*> Hotplug firmware loading support
│ │ Block devices --->
│ │ <*> Low Performance USB Block driver
│ │ SCSI device support --->    //此处必选
│ │ <*> SCSI generic support  //此处必选
│ │
Probe all LUNs on each SCSI device
│ │ USB support --->
│ │<*> Support for Host-side USB  //此目录下所有必选,目录还有好几个懒得写了
│ │
USB device filesystem
│ │<*> OHCI HCD support
│ │<*> USB Mass Storage support  //此目录下所有必选,目录还有好几个懒得写了
│ │
USB Monitor
3、加入了MSDOS fs和VFAT fs的支持。 //必选,否则将看不到windows下的文件
│ │ File systems --->
│ │ DOS/FAT/NT Filesystems --->
  │ ┌──────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ │ 
  │ │                      <*> MSDOS fs support                                                                        │ │ 
  │ │                      <*> VFAT (Windows-95) fs support                                                            │ │ 
  │ │                      (437) Default codepage for FAT                                                              │ │ 
  │ │                      (iso8859-1) Default iocharset for FAT                                                       │ │ 
  │ │                      <*> NTFS file system support                                                                │ │ 
  │ │                      [*]   NTFS debugging support                                                                │ │ 
  │ │                      [*]   NTFS write support                                                                    │ │ 
  │ │                         

4 、加入分区支持
│ │ File systems --->
│ │ Partition Types --->
│ │ 
    Advance Partition Selection //选择它将自动出现若干选项,默认即可

5、加入中文语言支持
File Systems->Native Language Support->

  │ │                      --- Native language support                                                                 │ │ 
  │ │                      (iso8859-1) Default NLS Option                                                              │ │ 
  │ │                      <*>   Codepage 437 (United States, Canada)                                                  │ │ 
  │ │                      < >   Codepage 737 (Greek)                                                                  │ │ 
  │ │                      < >   Codepage 775 (Baltic Rim)                                                             │ │ 
  │ │                      < >   Codepage 850 (Europe)                                                                 │ │ 
  │ │                      < >   Codepage 852 (Central/Eastern Europe)                                                 │ │ 
  │ │                      < >   Codepage 855 (Cyrillic)                                                               │ │ 
  │ │                      < >   Codepage 857 (Turkish)                                                                │ │ 
  │ │                      < >   Codepage 860 (Portuguese)                                                             │ │ 
  │ │                      < >   Codepage 861 (Icelandic)                                                              │ │ 
  │ │                      < >   Codepage 862 (Hebrew)                                                                 │ │ 
  │ │                      < >   Codepage 863 (Canadian French)                                                        │ │ 
  │ │                      < >   Codepage 864 (Arabic)                                                                 │ │ 
  │ │                      < >   Codepage 865 (Norwegian, Danish)                                                      │ │ 
  │ │                      < >   Codepage 866 (Cyrillic/Russian)                                                       │ │ 
  │ │                      < >   Codepage 869 (Greek)                                                                  │ │ 
  │ │                      <*>   Simplified Chinese charset (CP936, GB2312)                                            │ │ 
  │ │                      < >   Traditional Chinese charset (Big5)                                                    │ │ 
  │ │                      < >   Japanese charsets (Shift-JIS, EUC-JP)                                                 │ │ 
  │ │                      < >   Korean charset (CP949, EUC-KR) 
6、重新make zImage,并使用u-boot的mkImage工具压缩之,放到JFFS2文件系统中,可以使用如下脚本重新生成内核的JFFS2文件系统,并将生成文件搬运到了所mount的远方电脑目录下面:
mkfs.jffs2 -r kernel -o kernel.jffs2 -e 0x20000 -s 0x800 -n
cp kernel.jffs2 /home/wfg/rmt

7、烧写到NAND FLASH的0分区中。重新启动,挂载:

root@WK:fdisk -l
Disk /dev/sda: 131 MB, 131072000 bytes
255 heads, 63 sectors/track, 15 cylinders
Units = cylinders of 16065 * 512 = 8225280 bytes

   Device Boot      Start         End      Blocks  Id System
/dev/sda1   *           1          16      128504   b Win95 FAT32
root@WK:mount -t vfat -o iocharset=cp936 /dev/sda1 /tmp
root@WK:cd tmp
root@WK:ls
20080511控制系列产品介绍.ppt
20080511控制系列产品介绍.rar
Makefile
Recycled
System Volume Information
Windows下通过XWindow远程登陆Linux.doc
Xmanager-v3.0Build0082
dram_driver.c
dram_test.c
makexample
tftpd32j.zip
u-boot-1.3.4
wxWaveRecord-wxwidgets-2.8.7.rar
装置本地实验结果.doc

 

退出usb挂载的tmp目录,然后卸载U盘
root@WK:cd ..
root@WK:ls
aImage_old  dev         hello.ko    mnt         sbin        usr
bin         dram_test   home        proc        sys         var
boot        etc         lib         root        tmp
root@WK:umount /tmp

 

OK,至此在AT91RM9200下挂载U盘成功!

(11)LCD调试过程

使用ncs7接S1D13505的片选,使用如下测试程序
  unsigned char * pRegs=0X80000000;
static unsigned short tmp=0x55;
//Step 1: Enable the host interface.
  *(pRegs + 0x1B) = 0x00;              /* 0000 0000 */
  while(1){
  tmp=*((unsigned char *)0x80000000);
  }
一直没有调试通,使用示波器测量结果发现接M/R的A21引脚竟然被拉高,我觉得很奇怪。甚至我去掉pRegs直接硬读0x80000000的版本寄存器内容A21还是被拉高,这是为什么呢?

今天终于解决了S1D13505的LCD显示问题,当初以为两者差不多,偷懒,没有把datasheet 从头到尾研究过,最终酿成苦果,花了2天时间才查出问题所在。原来它比S1D13506多了个SUSPEND引脚,用于控制LCD进入省电模式,当MD9 下拉时SUSPEND引脚=0时立即进入硬件休眠状态,所有内存与寄存器都不能读写。要读写寄存器必须将SUSPEND引脚拉高。没办法,我飞!飞完后液 晶测试正常,可惜没带数码相机。奇怪的是A21引脚依然在我不访问200000地址时还是被周期性拉高,看了一下时许,与CS配合感觉好像是对的。可能是 S1D13505内部造成的。
由于程序较多,决定另写一篇文章记录详细过程。
 
(12)驱动程序开发
    基于双口RAM的驱动程序开发已经完成。过程较为复杂,另一篇文章记录。另在调试过程中发现一个秘密,即如果某个模块不是放在压缩的文件系统中,而是在系 统启动成功才通过TFTP协议倒入到板子中运行,将会反复提示找不到指定的模块。此时只要将生成的模块放到JFFS2文件系统的/lib/modules /2.6.26.6文件夹中,再压缩之成JFFS2文件系统,重新下载即可运行该模块。所以在模块没有定义好时,可以先生成一个空的文件命名为与即将调试 的模块同名,这样以后调试时通过TFTP下载指定模块就可以正常加载。本人估计是系统在初始化时已经将modules文件夹下的模块按名称列表,如果是系 统启动后在倒入,这样模块名称列表可能不会更新,这可能是内核考虑不周的原因。调试驱动程序步骤较复杂,以GPIO驱动程序开发为例,决定将其所有步骤记 录下来:
1、保证U-BOOT已经烧写到nor flash中去,设置为外部启动
2、打开,笔记本的FTP服务器,按照本文第9项烧写内核及文件系统
3、打开服务器,利用XWINDOWS登录到服务器中(注意必须关闭windows的防火墙,否则无法建立通信),建立以下mountwfg别名:
alias mountwfg='mount -o username=wfg,passwd= //172.21.26.148/u-boot-1.3.4 /home/wfg/rmt'
这样,每次以超级用户等录,即可执行mountwfg别名以便mount到本地开发笔记本
4、在服务器下/home/wfg/driver下建立驱动程序及测试程序,makefile等文件,需要注意驱动程序必须指向内核源码的文件夹
5、切换到超级用户,以便有足够的权限压缩成JFFS2文件系统和拷贝文件。为了提高工作效率,所有工作过程可以用如下的脚本文件描述:
make clean
make  //编译驱动程序
/opt/crosstool/arm-unknown-linux-gnueabi/arm-unknown-linux-gnueabi/bin/gcc /home/wfg/driver/gpio/gpio_test.c -o gpio_test  //编译测试程序
cp gpio_driver.ko /home/wfg/rmt  //将驱动程序拷贝到本地电脑,以便通过FTP服务器下载到板子中测试
cp gpio_test /home/wfg/rmt    //将驱动程序测试拷贝到本地电脑,以便通过FTP服务器下载到板子中测试
cp gpio_driver.ko /home/wfg/fs/rootfs/lib/modules/2.6.26.6 //更新jffs2文件夹
cp gpio_test /home/wfg/fs/rootfs //更新jffs2文件夹
cd /home/wfg/fs
mkfs.jffs2 -r rootfs -o rootfs.jffs2 -e 0x20000 -s 0x800 -n  //重新生成JFFS2文件系统
cp rootfs.jffs2 /home/wfg/rmt  //更新本地JFFS2文件
这样,以后每次执行此脚本即可完成编译-拷贝-压缩生成JFFS2文件系统等一系列工作。
6、重新上电系统启动后进入主控画面,启动双口RAM驱动在启动时已经由引脚启动加载:
root@WK:ls
aImage_old  dev         gpio_test   lib         root        tmp
bin         dram_test   hello.ko    mnt         sbin        usr
boot        etc         home        proc        sys         var
root@WK:lsmod
dram_driver 2913 0 - Live 0xbf000000  
root@WK:insmod gpio_driver (必须保证gpio_driver .ko在JFFS2文件系统中的/lib/modules/2.6.26.6中)
root@WK:lsmod
gpio_driver 2369 0 - Live 0xbf002000 (模块加载成功)
dram_driver 2913 0 - Live 0xbf000000
root@WK:mknod /dev/gpio_driver c 220 1 (按照主设备号创建节点文件)
root@WK:./gpio_test  (开始执行测试程序)
open device success!
0:quit,1:DO test,2:DI test;1
please input DO Number(1-8) and value(0-1):6
0:quit,1:DO test,2:DI test;
7、如果模块修改过,将通过如下命令将模块传送到板子中重新调试(需要先卸载原模块)
root@WK:rmmod gpio_driver (切忌所有关于模块的命令都不能带后缀)
root@WK:lsmod
dram_driver 2913 0 - Live 0xbf000000
root@WK:tftp -gr gpio_driver.ko 172.21.26.148 (这里必须写后缀,否则找不到文件)
root@WK:insmod gpio_driver (重新加载模块)
root@WK:lsmod
gpio_driver 2369 0 - Live 0xbf002000 (模块加载成功)
dram_driver 2913 0 - Live 0xbf000000
root@WK:mknod /dev/gpio_driver c 220 1 (重新建立节点文件,在模块卸载后此节点文件也被相应卸载了)
root@WK:./gpio_test
  (重新开始执行测试程序,成功!)
open device success!

http://blog.csdn.net/warmshepherd/archive/2008/10/31/3194127.aspx

 

你可能感兴趣的:(linux,image,FTP服务器,Flash,嵌入式,平台)