内核移植开发文档
1.内核版本
平台从cirrus 9307芯片转移到atmel AT91RM9200后,嵌入式系统linux版本也从原来的2.6.8过渡到2.6.16。2.6.16版本是完全重新移植,后来由于串口驱动DMA工作方式的原因,从原来的2.6.16,过渡到2.6.21,因为2.6.21的串口驱动支持DMA功能,还有很多其它新增功能。
2.内核的配置
在内核源代码所在根目录下键入:make menuconfig 命令后回车,出现下图所示的文本
配置界面。
Code maturity level options ---> General setup --->
2.6.21版本linux内核配置项共有19个大类,如下:
Loadable module support ---> Block layer ---> System Type --->
Bus support ---> Kernel Features ---> Boot options ---> Floating point emulation ---> Userspace binary formats ---> Power management options ---> Networking ---> Device Drivers ---> File systems ---> Profiling support ---> Kernel hacking ---> Security options ---> Cryptographic options ---> Library routines --->
Code maturity level options
[*] Prompt for development and/or incomplete code/drivers 译内核时提示开发与未完成代码位置)
(必选,软件成熟度选项,编General setup
系统相关的一些配置,如支持ram disk;make menuconfig的配置保存到.config文件中。 [*] Automatically append version information to the version string (编译时,自动将版本信息附加到版本字符串中)
[*] System V IPC (system V版本第进程间通信协议)
<*> Kernel .config support (内核配置信息保存到.config文件中) [*] Create deprecated sysfs files (自动备份旧版本内核配置信息)
[*] Initial RAM filesystem and RAM disk (initramfs/initrd) support (支持ram disk机制)
[*] Optimize for size (Look out for broken compilers!) (对编译链接生成对uImage的大小进行优化)
Loadable module support
内核模式驱动,要么集成到linux内核uImage中,或者以ko文件的形式存在,ko形式
的驱动,本质就是module,使用之前需要insert module。对于嵌入式的linux系统,为了缩小体积,可以将内核的装载,卸载module功能去掉,“Loadable module support”配置就是实现这个功能。内核支持“Enable loadable module support” 还不够,ramdisk必须提供insmod等相关命令。
Block layer
块设备,单个大文件的相关支持。
System Type
系统配置,即目标板 芯片相关配置,如MCU,dataflash,时钟的支持。所有的内核源代
码编译之前必须设置好这些选项。
ARM system type (Atmel AT91) (我们用的AT91系列芯片) [*] Support ARM920T processor (ARM9核的类型)
Bus support
PC卡,CF卡等总线的支持配置。我们3G监控的系统可以不用选。
Kernel Features
内核扩展特点的支持,升级的功能但是不稳定,放入这个大类中。如内核支持板上LED,
64位总线存储接口。
Boot options
配置Uboot所在的基地址,配置uboot引导uImage时传入参数没有设置的情况下使用
一般不需要设置,在uboot中指定好传入参数即可。
的缺省传入参数。
Floating point emulation
因为ARM没有浮点数计算器,必须用软件来模拟,软件模拟浮点运算有不同的算法,
用这个配置指定其中一种软件浮点运算。
[*] NWFPE math emulation (采用NWFPE数学库进行软件浮点计算)
Userspace binary formats
用户空间支持的二进制格式,即嵌入式linux运行环境下支持的可执行二进制格式。我
们选的是通用的elf文件,ECOFF一般用于ARM7的环境中。
Power management options
类似windows系统中的电源管理,我们没有用到。
Networking
网络支持配置,包括有线IP网络和无线网络。Tftp,ping 等网络程序的正确运行,必
须配置好其中的“TCP/IP networking”部分:
Device Drivers
Generic Driver Options --->
驱动编译时的环境设置
Connector - unified userspace <-> kernelspace linker --->
内核空间与用户空间的一个连接器驱动
Memory Technology Devices (MTD) --->
MTD驱动支持,NAND,NOR flash 驱动,MTD分区支持在这里配置
Parallel port support --->
并口驱动支持
Plug and Play support --->
设备pnp 性能支持
Block devices --->
块设备驱动支持,包括ram disk驱动设置
ATA/ATAPI/MFM/RLL support --->
老硬盘的ATA驱动支持 SCSI device support --->
SCSI驱动支持,注意如果板子上要插U盘,其中的“SCSI disk support”项必须选上。
Serial ATA (prod) and Parallel ATA (experimental) drivers --->
串行ATA,与并行ATA驱动支持
Multi-device support (RAID and LVM) --->
RAID驱动支持
Fusion MPT device support --->
“Fusion MPT”设备驱动的支持
IEEE 1394 (FireWire) support --->
火线1394驱动支持
I2O device support --->
IO设备驱动支持
Network device support --->
网络设备驱动支持,包括一些虚拟协议驱动,如网卡EMAC驱动,PHY芯片驱动,PPP
驱动等等。
ISDN subsystem --->
ISDN设备驱动支持
Input device support --->
输入设备驱动支持,包括键盘,鼠标,游戏手柄,触摸屏等等。
Character devices --->
字符设备驱动的支持,包括看门狗驱动,console驱动等。
I2C support --->
硬I2C控制器的驱动支持,我们都是用软件模拟的I2C接口没有使用硬SPI控制器
SPI support --->
硬SPI控制器的驱动支持,我们都是用软件模拟的SPI接口没有使用硬SPI控制器
Dallas's 1-wire bus --->
“Dallas's 1-wire”驱动支持
Hardware Monitoring support --->
硬件监控芯片支持
Misc devices --->
空,更高版本中可能用到。
Multifunction device drivers --->
多功能设备驱动支持,即一些手持终端的驱动支持
LED devices --->
板上LED驱动支持
Multimedia devices --->
多媒体视频方面驱动支持,视频编解码的支持,需要这些驱动才能播放视频格式文件。
Graphics support --->
图形驱动支持,如LCD,VGA控制器驱动 Sound --->
音频芯片驱动支持 HID Devices ---> 鼠标键盘驱动支持 USB support --->
USB 驱动支持,包括host和device驱动 MMC/SD Card support ---> MMC/SD卡驱动支持 Real Time Clock --->
实时时钟驱动支持
File systems
文件系统的配置,即linux下支持的文件格式系统,如EXT2,EXT3,JFFS2。类似windows下的FAT32,NTFS文件系统的选择,不同的是linux同时可以支持多种文件系统,windows一个分区只能支持一种。任意一个普通文件与相应的文件系统相对应,在linux系统中要浏览该文件,必须配置有相应文件系统。
如果要用U盘,必须将“VFAT (Windows-95) fs support”项选上。
Kernel hacking
内核调试用的一些配置,对于直接修改内核源代码的情况,这些配置比较有用。
Security options
网络传输中的安全配置和密钥配置。
Cryptographic options
加密相关的函数库配置,如MD4,MD5的库函数。
Library routines
其它一些函数库的配置,包括“CRC-CCITT functions”,后面新版本将会有更多选项。
3.内核编译说明
首先将源代码根目录下Makefile中的“CROSS_COMPILE”变量修改为:
CROSS_COMPILE ?= /home/usr/crosstc/arm-linux-gcc-3.4.3/bin/arm-linux-
然后运行命令:make uImage,即可将内核源代码编译生成需要的uImage文件。
4.内核源代码修改
下载到源代码以后,要将内核在我们的监控盘上正常运行,必须进行必要的修改,以适
应监控盘硬件。修改包括:晶体频率,网口驱动相关,串口驱动,MTD驱动。
晶体频率
为了利用公司现有库存晶体,同时保证分频倍频后得到的MCU工作频率精确,监控盘
采用了12M晶体。下载的内核源代码是根据ATMEL原厂评估板上的18.432M晶体设置,因此需要修改源代码中相应部分,此为移植的第一步。具体步骤是修改源代码中文件: linux-2.6.21\\arch\\arm\\mach-at91\\board-dk.c,该文件有一个函数dk_map_io,定义如下:
static void __init dk_map_io(void) { }
/* Setup the serial ports and console */ at91_init_serial(&dk_uart_config);
/* Initialize processor: 18.432 MHz crystal */
at91rm9200_initialize(18432000, AT91RM9200_BGA); /* Setup the LEDs */
at91_init_leds(AT91_PIN_PB2, AT91_PIN_PB2);
该函数调用at91rm9200_initialize时指定的参数为板上晶体频率,和AT91RM9200
芯片的封装类型,因为AT91RM9200有PQFP,BGA两种封装,两种封装IO的bank个数不同,因此这两个参数都要正确指定,根据我们监控盘的具体情况,修改为:
at91rm9200_initialize(12000000, AT91RM9200_PQFP);
网口驱动
修改目的是使网口相关驱动(PHY驱动,MAC驱动)正常工作,满足我们监控盘的硬
件,包括网线插上与拔出的中断正常响应。
修改源代码文件linux-2.6.21\\arch\\arm\\mach-at91\\board-dk.c 中下面网络相关结构:
static struct at91_eth_data __initdata dk_eth_data = {
.phy_irq_pin = AT91_PIN_PC4, .is_rmii = 1, };
ATMEL原厂DK 评估板,用的RMII接口,PHY中断(即插上网线到网口时产生的中
断)用的AT91_PIN_PC4引脚。因我们监控盘KS8721s芯片使用的接口为MII接口,同时PHY中断接AT91RM9200的AT91_PIN_PA25引脚。因此该结构必须修改为:
static struct at91_eth_data __initdata dk_eth_data = {
.phy_irq_pin = AT91_PIN_PA25, .is_rmii = 0, };
串口驱动
串口修改包括:各串口的编号排序,FSK数据的过滤和封包处理,添加485串口的收
发切换。
(1)串口编号的修改在源代码文件linux-2.6.21\\arch\\arm\\mach-at91\\board-dk.c 中的下
面结构:
static struct at91_uart_config __initdata dk_uart_config = { .console_tty = -1,
.nr_tty
= 2,
};
.tty_map = { 4, 1, -1,-1,-1 } /* ttyS0, ..., ttyS4 */
上面的结构只定义了2个串口设备,nr_tty指串口设备个数,定义的2个串口设
备ttyS0,ttyS1分别对应AT91RM9200的串口4和串口1。AT91RM9200总共5个串口,编号从0,到4。
因为我们的监控盘用到了所有5个串口,因此需要进行修改,修改后的结构如下:
static struct at91_uart_config __initdata dk_uart_config = { };
.console_tty = 4/, .nr_tty .tty_map
= 5,
= { 0, 1, 2, 3, 4 } /* ttyS0, ..., ttyS4 */
nr_tty指定总共5个串口,缺省时console使用ttyS4,串口设备ttyS0…ttyS4
分别对应AT91RM9200的0…4号串口。
(2)FSK数据的过滤和封包处理
因为FSK通信用的CC1000芯片数据传输使用的是串口,同时需要有收发切换的控制
功能,通过3个IO引脚控制CC1000的控制引脚。通过实验发现在应用层做FSK的数据切换,然后调用串口的write,read函数来传输数据,切换延时不好控制。另外,由于FSK数据传输的特殊性,数据包含了若干前导码,导致应用层处理起来有些烦琐。为了使整个逻辑更清晰,使用户层操作FSK,与普通串口一样,不需要额外处理,故将FSK的收发切换,前导码过滤等功能移到串口驱动中。为了传输方便,从应用层收到要发送的数据后,对其进行封包发送。修改源代码\\linux-2.6.21\\drivers\\serial\\atmel_serial.c文件如下:
在atmel_tx_chars函数中添加FSK封包和切换到发方式功能:
static void atmel_tx_chars(struct uart_port *port) {
struct circ_buf *xmit = &port->info->xmit; int i;
static unsigned char bHadCap;// 头部已经封的标志位
bHadCap = 0;
if (port->x_char) { }
if (uart_circ_empty(xmit) || uart_tx_stopped(port)) { }
atmel_stop_tx(port); return;
UART_PUT_CHAR(port, port->x_char); port->icount.tx++; port->x_char = 0; return;
if((port->line == 3) && (port485flag == 0)) set_cc1000_tx_mode(); // 循环发送收到的若干直接
while (UART_GET_CSR(port) & ATMEL_US_TXRDY) {
if((port->line != 3) || ((port->line == 3)&&(port485flag == 1))) {
// 将buf中某个直接发送出去,port参数提供一个地址而已 UART_PUT_CHAR(port, xmit->buf[xmit->tail]);
if(port->line == 3)
while (!(UART_GET_CSR(port) & ATMEL_US_TXRDY)); }
else if((port->line == 3) && (port485flag == 0))// ttyS3 的FSK方式才单独处理 {
if (bHadCap==0) {
// 根据数据手册和实践这3个0xff必须加 HX_PUT_CHAR(port, 0xff); HX_PUT_CHAR(port, 0xff); HX_PUT_CHAR(port, 0xff);
}
// 转义判断
// 头部添加12个0x55,一个0x7e for(i=0;i<12;i++) { }
// 根据数据手册和实践这2个0xff必须加 HX_PUT_CHAR(port, 0xff); HX_PUT_CHAR(port, 0xff); HX_PUT_CHAR(port, 0x7e);
bHadCap=1; // 置标志位,下次不进入
HX_PUT_CHAR(port, 0x55);
if (xmit->buf[xmit->tail]==FRAM_HEAD/*0x7e*/) // 收到0x7e,发0x5e,0x7c两个
{
HX_PUT_CHAR(port, 0x5e); HX_PUT_CHAR(port, 0x7d);
}else if (xmit->buf[xmit->tail]==FRAM_TAIL) // 收到0x7f,发0x5e,0x7b两个 {
HX_PUT_CHAR(port, 0x5e); HX_PUT_CHAR(port, 0x7b);
}else
if (xmit->buf[xmit->tail]==0x5e) // 收到0x5e,发0x5e,0x5c两个 {
HX_PUT_CHAR(port, 0x5e); HX_PUT_CHAR(port, 0x5d);
}
}
}else { }
HX_PUT_CHAR(port, xmit->buf[xmit->tail]);
xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
port->icount.tx++; // 因为是透明传输,这里不需要动 if (uart_circ_empty(xmit)) { }
if((port->line == 3)&&(port485flag == 0)) { } break;
// 完成并退出这批数据发送之前,尾部添加一个0x7f,2个0xff HX_PUT_CHAR(port, FRAM_TAIL); HX_PUT_CHAR(port, 0xff);
if((port->line == 3) && (port485flag == 0)) set_cc1000_rx_mode(); if((port->line == 3) && (port485flag == 1)) {
set_ab485_rx();
}
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
if (uart_circ_empty(xmit))
uart_write_wakeup(port);
pl2303_set_termios中添加波特率支持:
case B460800: baud = 460800; break;// lxd case B921600: baud = 921600; break;// lxd
这两个波特率配置必须添加,否则modem无法相应AT命令,拨号失败。
其它修改
(1)启动linux完成后,Ctrl+C在控制台失效,并出现下面错误的解决方法
-sh: can't access tty; job control turned off
Ctrl+C 在控制台不起作用是因为ramdisk的initab脚本的最后一句在console或者ttyS4上起动一个shell,这样做会有问题,不能在console上起动shell,否则运行不正常!initab上不起动脚本,busybox就不会在那个串口上运行,所以只有把内核的console 去掉。
将源代码drivers/char/tty_io.c 文件中所有的 noctty = 1; 修改成noctty = 0;就能解决上面两个问题。