热门关键字:  ubuntu  分区  函数  Fedora  linux系统进程

华恒ColdFire系列嵌入式Linux开发板常见问题解答

来源: 作者: 时间:2007-08-06 Tag: 点击:


22、关于管道的使用
下面是一个例子,在一个进程中通过管道启动另一个进程test。
#include <sys/wait.h>
#include <stdio.h>
int main(void)
{
FILE *fd;
int waitstat;
char buf[20];
if((fd=popen("/bin/test","r"))==NULL)
printf("popen error! \n");
wait(&waitstat);
//pclose(fd);
if(fgets(buf,15,fd)==NULL)
printf("fgets error! \n");
printf("%s",buf);
return 0;
}
代码移植到uC下时应在popen后加入,pclose(fd)或wait(&waitstat)。因为uClibc中popen的实现与X86下的不同,它使用了vfork(PC上是用fork)必须等子进程可靠结束关闭文件后才执行对文件的下一步读写。

23. 关于ColdFire系列开发板的uClinux内核版本
华恒ColdFire系列开发板提供的嵌入式uClinux内核版本目前主要有两种:2.0.38和2.4.x,
其中只有HHCF5272-R1还保留了2.0.38的内核版本,其它套件全部为2.4内核。目前HHCF5272-R1也可以提供2.4的内核。
华恒版本的uClinux和从网上uClinux.org down下来的版本的区别在于:
1)网上开源的版本只提供了RAM版内核,不提供ROM版本,呵呵,这样做我想可能就是为了限制商业化用户吧,因为RAM版本还需要bootloader来引导(但行业内,bootloader基本上大家都不提供源代码),不能直接启动,根本无法作为商业产品使用,因此也就只能给爱好者折腾着玩玩而已。华恒替客户完成了这部分ROM化的工作。
2)华恒以本地化器件提供的硬件板卡,因此要针对自己的硬件修改系统启动代码、硬件设备驱动BSP,并相应的提供下载、烧写等工具软件,这些都要自己移植,修改或者完全自己定制。没有这些辅助工具,空有uClinux的tar包,是根本无法进行开发调试的。
3)本地化全中文技术手册及相关的技术支持(论坛)。

24. 关于不同内核版本间应用程序移植的问题
应用程序的移植一般的和内核版本是没有任何关系的,当然有的应用程序是需要内核支持的,例如pppd等。在2.0.38内核和2.4内核之间互移应用程序,唯一要注意的就是Makefile的写法:
其实区别就一句话,就是2.4下面,它把elf2flt作为gcc的一个参数一步完成了,而2.0.38还要分为两步完成,体现在Makefile上就如下:
对于2.0.38:
$(LD) $(LDFLAGS) -o $@.elf $(OBJS) $(LDLIBS)
$(CONVERT)
对于2.4.x:
$(CC) $(LDFLAGS) -o $@ $(OBJS) $(LDLIBS)

25、关于外设中断的问题
MCF5272处理器提供了6路外部中断以供外设控制芯片使用。在MCF5272的启动代码中(sysinit.c代码中)屏蔽了所有的内部和外部中断,因为用户在扩展使用自己的中断源设备时,在该设备的驱动初始化代码(如open函数中)中就必须手工打开允许这个外部中断源。屏蔽和允许一个中断源都是通过设置ICRn寄存器来实现的。
在对应的PI位写1,而后面的三位IPL位都为0就表示屏蔽该中断源。
在对应的PI位写1,后面的三位IPL位写001~111就表明打开运行该中断源,并设置其中断优先级为1到7级,级别越高,优先级越高。
switch(irq)
{
case 1:
*(volatile unsigned long *)(0x10000020) |= 0xb0000000;
break;
case 3:
*(volatile unsigned long *)(0x10000020) |= 0x00b00000;
break;
case 4:
*(volatile unsigned long *)(0x10000020) |= 0x000b0000;
break;
case 5:
*(volatile unsigned long *)(0x1000002c) |= 0x0b000000;
break;
}

26、关于中断的问题
在每个使用中断的设备的驱动初始化代码中,都首先要打开中断,因为启动代码把所有中断都禁止(mask)了,根据CPU手册,在ICRn对应的PI位写1,而后面的三位IPL位都为0就表示屏蔽该中断源。即将对应ICR中对应的字节设置为8。例如启动时,ICR1就被设置为:0x88888888。
打开中断时,则在ICRn对应的PI位写1,后面的三位IPL位写001~111就表明打开运行该中断源,并设置其中断优先级为1到7级,级别越高,优先级越高。例如MCF5272的几个内部模块所使用的内部中断:
1)TIMER:在ICR1对应位设置0xd,即priority == 5(2.0.38用的是TMR1,2.4内核用的是TMR4)
2)FEC:在ICR3对应位设置0xd,即priority == 5
3)FEC要工作的同时还要使用MII(占用INT2),在ICR1对应位设置0xd,即priority == 5
4)UART:在ICR2对应位设置0xe,即priority == 6
样例代码如下:
FEC:fec.c中int __init fec_enet_init(struct net_device *dev)
volatile unsigned long *icrp;
icrp = (volatile unsigned long *) (MCF_MBAR + MCFSIM_ICR3);//FEC
*icrp = 0x00000ddd;
icrp = (volatile unsigned long *) (MCF_MBAR + MCFSIM_ICR1);//MII
*icrp = (*icrp & 0x70777777) | 0x0d000000;
TMR4:在uClinux/linux-2.4.x/arch/m68knommu/platform/5272/config.c中对TIMER的初始化如下:
void coldfire_timer_init(void (*handler)(int, void *, struct pt_regs *))函数中有如下代码:
icrp = (volatile unsigned long *) (MCF_MBAR + MCFSIM_ICR1);
*icrp = 0x0000000d; /* TMR4 with priority 5 */
request_irq(72, handler, SA_INTERRUPT, "ColdFire Timer", NULL);
UART1/UART2:在uClinux/linux-2.4.x/drivers/char/mcfserial.c中,有如下代码对UART进行中断初始化:
static void mcfrs_irqinit(struct mcf_serial *info)
volatile unsigned long *icrp;
volatile unsigned long *portp;
icrp = (volatile unsigned long *) (MCF_MBAR + MCFSIM_ICR2);
switch (info->line) {
case 0:
*icrp = 0xe0000000;
break;
case 1:
*icrp = 0x0e000000;
break;
此外,MCF5272相应外部中断后,并不会自动的清楚该中断的pending位,这样用户就必须在自己的中断处理函数的末尾自己来替处理器完成这一工作。例如:对于外部中断3
*(volatile unsigned long*)(MCF_MBAR+0x20) |= 0x00800000;

27、应用程序中如何定时产生信号?
这个问题就相当于实现WINDOWS下的WM_TIMER功能,定时给应用程序发送消息
例如:要求每一秒产生一个信号,去打印一句test。本来signal/alarm只能一次性工作,现在要让它循环起来,每一秒都产生信号,就要再其信号处理函数中对其进行重置。
void test()
{
signal(SIGALRM,test);//重置
alarm(1);
printf("test\n");
}
main()
{
signal(SIGALRM,test);
alarm(1);
for(;;)
{/*主函数处理部分*/
}
}

28、应用程序的编译参数观察
用户在编译自己的应用程序时,也是要在uClinux下执行make,屏幕一滚就过去了,SHIFT+PAGEUP也翻不了那末多,其实自己的应用怎么编译的也不清楚。
在uClinux下执行make >&t,则自动生成临时文件t,它记录了整个编译过程及每步编译的详细参数,对于理解编译工具的使用及其参数非常有帮助。(整个的编译过程详细分析请参见手册2.1.3节),举例而言,以应用程序uClinux/user/inetd和ping为例:
对于uClinux-2.0.38下的写法如下:
/HHCF5272-R1/uClinux/tools/m68k-elf-gcc -m5200 -Wa,-m5200 -DCONFIG_COLDFIRE -Dl
inux -D__linux__ -Dunix -DEMBED -O2 -msoft-float
-I/HHCF5272-R1/uClinux/tools/gcc-include -I/HHCF5272-R1/uClinux/lib/libc/include
-I/HHCF5272-R1/uClinux/lib/libm
-I/HHCF5272-R1/uClinux/vendors/include -fno-builtin -DSERVICES=\"/etc/services
\" -DINETD_CONF=\"/etc/inetd.conf\" -c -o inetd.o inetd.c
对于uClinux-2.4.17下的编译全部以gcc为前台,连ld也被隐藏到后台了:
m68k-elf-gcc -m5307 -DCONFIG_COLDFIRE -Os -g -fomit-frame-pointer -Dlinux
-D__linux__ -Dunix -D__uClinux__ -DEMBED
-I/HHCF5272-R1/uClinux/lib/libc/include -I/HHCF5272-R1/uClinux/lib/libm
-I/HHCF5272-R1/uClinux -I/HHCF5272-R1/uClinux/linux-2.4.x/include
-fno-builtin -msep-data -c -o ping.o ping.c
m68k-elf-gcc -m5307 -DCONFIG_COLDFIRE -Os -g -fomit-frame-pointer
-Dlinux -D__linux__ -Dunix -D__uClinux__ -DEMBED
-I/HHCF5272-R1/uClinux/lib/libc/include -I/HHCF5272-R1/uClinux/lib/libm
-I/HHCF5272-R1/uClinux -I/HHCF5272-R1/uClinux/linux-2.4.x/include
-fno-builtin -msep-data -Wl,-elf2flt -o ping ping.o
-L/HHCF5272-R1/uClinux/lib/libc/. -L/HHCF5272-R1/uClinux/lib/libc/lib
-L/HHCF5272-R1/uClinux/lib/libm -L/HHCF5272-R1/uClinux/lib/libnet
-L/HHCF5272-R1/uClinux/lib/libdes -L/HHCF5272-R1/uClinux/lib/libpcap
-L/HHCF5272-R1/uClinux/lib/libssl -lc
-L表明后面为所要链接的libc库的路径。库路径可以有多个(对于一个应用程序而言,很多库并没有用),因此可以看到有多个-L参数;
-I参数表明后面所跟的为C语言INCLUDE头文件的路径,这个路径可以有多个,因此可以看到有多个-I参数;
-m5200(-m5307)为处理器相关编译参数,2.4下采用了-m5307,这其实对于应用程序而言没有任何区别;
-c后面为所要编译的C文件;
-o后面为这行编译操作的目的,即这行编译完毕后要生成的文件;
-Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -fno-strength-reduce:这些都是编译参数;

29、FLASH上数据保存
鉴于目前发行的开发板中的uClinux均采用ROMFS作为其根文件系统,因此其目录大多是不可写的。只有/var,/tmp是RAM盘可写,但板子一掉电里面的内容就丢失了,因此只能作临时文件保存,无法永久的保存数据,例如配置文件等。下面大概介绍一下几种FLASH上保存配置的方法:
1、对于简单的数据,小的配置文件等,而且不是非常频繁的(例如一分钟写10次)写入的,可以直接自己在FLASH的空余处(例如第二片FLASH上)划出一块区域,以自己定义的方式写入,并在板子启动时自动读出。华恒提供了这样的样例代码,即user/memtools/,其详细介绍在手册第二章“FLASH扇区保存IP地址”一节。这样作最大的好处是用户的控制程度最大,形式最灵活,保存的可以是自定义的数据,可以不是文件的形式。而下面的几种方式都是要求文件的形式保存,无法处理自定义的数据保存。
2、对于比较多的配置文件,一般的都先写在RAM盘中,然后选择保存,一次性写入FLASH的某几个扇区。这时就可使用flatfsd软件,它的使用需要内核的配合支持,即要在blkmem.c中为其指定保存数据的几个扇区的起始/结束地址。这中方式也不能适应非常频繁的写入。
使用说明:将要保存的文件放在板子的RAM盘目录/etc/config目录下,因为uClinux的根目录/是建于FLASH上的romfs文件系统,是不可写的,只有几个RAM盘才可写,可用mount命令查看:
/etc> mount
rootfs on / type rootfs (rw)
/dev/rom0 on / type romfs (ro)
/proc on /proc type proc (rw)
/dev/ram0 on /var type ext2 (rw)
/dev/ram1 on /etc/config type ext2 (rw)
/dev/mtdblock0 on /sbin type jffs2 (rw)
要保存的时候,就在minicom里面执行
killall -10 flatfsd
或者在C程序代码里面用vfork+execlp执行这句命令行即可.
这样就会自动将RAM盘中/etc/config目录里面的文件全部保存写入到板子FLASH的扇区里面(具体哪几个扇区是由linux-2.4.x/drivers/block/blkmem.c中指定的,可在板子启动信息里面看到:)
Blkmem copyright 1998 Kenneth Albanowski
Blkmem 2 disk images:
0: FFC77362-FFCCE761 [VIRTUAL FFC77362-FFCCE761] (RO) /*romfs*/
1: FFFC0000-FFFFFFFF [VIRTUAL FFFC0000-FFFFFFFF] (RW) /*flatfsd*/
能够保存的机制是由如下文件的一行保证的:
/etc> cat inittab
inet:unknown:/bin/inetd
flt:unknown:/bin/flatfsd
这样就保证系统启动后系统进程里面有flatfsd进程永远在运行,才能保证接收兵处理用户发来的数值为10的信号SIGNAL:
/etc> ps
PID PORT STAT SIZE SHARED %CPU COMMAND
1 S 37K 0K 0.0 init
2 S 0K 0K 0.0 keventd
3 R 0K 0K 0.2 ksoftirqd_CPU0
4 R 0K 0K 22.7 kswapd
5 S 0K 0K 0.0 bdflush
6 S 0K 0K 0.0 kupdated
7 S 0K 0K 0.0 mtdblockd
16 S 0K 0K 0.0 jffs2_gcd_mtd0
30 S0 S 85K 0K 0.0 /bin/sh
31 S 38K 0K 0.0 /bin/inetd
32 S 53K 0K 0.0 /bin/flatfsd
33 S 190K 0K 2.2 /bin/diald -f /etc/config/diald.pppoe1
34 S 207K 0K 0.0 /bin/dhcpd -d -cf /etc/config/dhcpd.conf eth0
1220 S 149K 0K 0.0 /bin/pppd -detach mtu 1454 mru 1454 file /etc/config/pppoe1
1221 S 69K 0K 7.4 /bin/pppoe -I eth0 -T 3000 -m 1412 -p /var/log/pppoe.pid
1241 S 49K 0K 0.0 /bin/telnetd
1242 p2 R 88K 0K 0.0 sh
而板子启动时通过执行/etc/rc里面的flatfsd –r就可以将FLASH上的保存的文件恢复到RAM盘目录/etc/config/下。
/> cd /etc/
/etc> cat rc
hostname mp3server
/bin/expand /etc/ramfs.img /dev/ram0
/bin/expand /etc/ramfs.img /dev/ram1
mount -t proc proc /proc
mount -t ext2 /dev/ram0 /var
mount -t ext2 /dev/ram1 /etc/config
mount -t jffs2 /dev/mtdblock0 /sbin
mkdir /var/tmp
mkdir /var/log
mkdir /var/run
mkdir /var/lock
/bin/flatfsd -r
touch /etc/config/dhcpd.leases
ifconfig lo 127.0.0.1
ifconfig eth0 192.168.2.254 netmask 255.255.255.0
ifconfig eth0:1 192.168.1.2 netmask 255.255.255.0
/bin/ena -e
iptables -t nat -A POSTROUTING -o ppp0 -j MASQUERADE
注意:若想修改板子启动后/etc/config里面的文件的内容,例如 板子启动后的IP地址设置文件/etc/config/start文件,需要如下操作:
修改uClinux源代码uClinux-dist/romfs/etc/default/start文件内容,然后重新编译生成image.bin,烧写板子,板子启动后,在minicom里面执行
cp /etc/default/start /etc/config
killall -10 flatfsd
这样下次启动就会自动生效。
3、对于比较频繁的数据保存,就要在板子上建立额外的日志型文件系统JFFS/JFFS2,或者干脆就用JFFS/JFFS2取代ROMFS作根文件系统。这样板子的目录就是可写的,就像硬盘一样,不需要额外的工具来负责将数据写入FLASH。JFFS为2.0.38内核所支持,它不支持JFFS2,JFFS2到2.4内核才被支持,它采用了成熟稳定的MTD技术,因此要比JFFS稳定。这两种文件系统要在uClinux上实现支持并不复杂,但它的实用还需要一些额外的工作,例如烧写工具的配合,新型image.bin编译生成,因为真正产品化的软件是不能允许每次启动后都还要进行许多的手工操作,例如加载文件系统等,板子出厂烧写也要一次完成,而不能还要分多次烧写等等,这些工作都是比较繁杂的,而且没有烧写工具的源代码是无法完成的。华恒提供JFFS/JFFS2整套软件技术。

30、关于2.4内核版本下的RAM版内核的编译
对于2.0.38内核,华恒提供了完备的ram.ld和crt0_ram.S,它们和华恒提供的bootloader可配合使用。 对于2.4.17的内核,从网上直接DOWN的uClinux-Coldfire版本(例如最新版本:uClinux-dist-20020701.tar.gz)是可以直接在华恒bootloader提示符HHCN>下执行readàgo 100000跑起来的。而若客户要从华恒2.4系列开发套件软件系统的基础上改动跑RAM版则需要做一些改动才可以的,例如HHCF5272-LCD-IDE-R1、HHCF5272-2ETH-R2等都是采用的2.4内核。因为华恒板子烧在FLASH上的就是一个RAM版本的内核,经由华恒的bootloader解压复制到RAM中才激活执行的,它的执行方式和readàgo的方式是完全不同的,虽然都是RAM版。要做到这一点,华恒是做了一些改动的,而现在实际上就是要恢复成从网上直接DOWN下来的状态。
1、首先是crt0_ram.S和直接下载的uClinux-Coldfire版本的crt0_ram.S有区别,是经过华恒修改的代码,若直接使用必然无法通过bootloaderàreadàgo 100000而跑起来。因此这时就必须使用网上下载的原始未经改动的crt0_ram.S,其实两个文件的区别很小,仅在于华恒的版本注释了复制romfs的部分代码:
只要把uClinux/linux-2.4.x/arch/m68knommu/platform/5272/HHTECH/crt0_ram.S中的一个#if 0 改为#if 1
下面贴出华恒代码:
_start:
nop /* Filler */
move.w #0x2700, %sr /* No interrupts */
/*
* Setup VBR here, otherwise buserror remap will not work.
* if dBug was active before (on my SBC with dBug 1.1 of Dec 16 1996)
*
* bkr@cut.de 19990306
*
* Note: this is because dBUG points VBR to ROM, making vectors read
* only, so the bus trap can't be changed. (RS)
*/
move.l #VBR_BASE, %a7 /* Note VBR can't be read */
movec %a7, %VBR
move.l %a7, _ramvec /* Set up vector addr */
move.l %a7, _rambase /* Set up base RAM addr */
/*
* Set to 4 meg for the Cadre III board (m5206e).
*/
move.l #MEM_SIZE, %a0
move.l %a0, %d0 /* Mem end addr is in a0 */
move.l %d0, %sp /* Set up initial stack ptr */
move.l %d0, _ramend /* Set end ram addr */
#if 1
/*
* Enable CPU internal cache.
*/
move.l #0x01000000, %d0 /* Invalidate cache cmd */
movec %d0, %CACR /* Invalidate cache */
move.l #0x80000100, %d0 /* Setup cache mask */
movec %d0, %CACR /* Enable cache */
#endif
/*
* Move ROM filesystem above bss :-)
*/
lea.l _ebss, %a1 /* Set up destination */
move.l %a1, _ramstart /* Set start of ram */
#if 1【这里原来是#if 0,即在华恒版本中被注释掉了】
lea.l _sbss, %a0 /* Get start of bss */
lea.l _ebss, %a1 /* Set up destination */
move.l %a0, %a2 /* Copy of bss start */
move.l 8(%a0), %d0 /* Get size of ROMFS */
addq.l #8, %d0 /* Allow for rounding */
and.l #0xfffffffc, %d0 /* Whole words */
add.l %d0, %a0 /* Copy from end */
add.l %d0, %a1 /* Copy from end */
move.l %a1, _ramstart /* Set start of ram */
_copy_romfs:
move.l -(%a0), %d0 /* Copy dword */
move.l %d0, -(%a1)
cmp.l %a0, %a2 /* Check if at end */
bne _copy_romfs
#endif
/*
* Zero out the bss region.
*/
lea.l _sbss, %a0 /* Get start of bss */
lea.l _ebss, %a1 /* Get end of bss */
clr.l %d0 /* Set value */
_clear_bss:
move.l %d0, (%a0)+ /* Clear each word */
cmp.l %a0, %a1 /* Check if at end */
bne _clear_bss
/*
* load the current task pointer and stack
*/
lea init_task_union, %a0
movel %a0, _current_task
lea 0x2000(%a0), %sp
/*
* Assember start up done, start code proper.
*/
jsr start_kernel /* Start Linux kernel */
_exit:
jmp _exit /* Should never get here */
2、ram.ld也要有修改,
MEMORY {
ram : ORIGIN = 0x100000, LENGTH = 0x6e0000
}
从网上直接DOWN下来默认的ORIGIN = 0x20000,这样用我们的bootloader下载下去当然是跑不起来的。以下的SECTIONS 节不需要任何改动。
3、修改vendors/HHTECH/M5272/Makefile
image:
[ -d $(IMAGEDIR) ] || mkdir -p $(IMAGEDIR)
/usr/local/bin/genromfs -v -V "ROMdisk" -f $(ROMFSIMG) -d $(ROMFSDIR)
m68k-elf-objcopy -O binary $(ROOTDIR)/$(LINUXDIR)/linux \
$(IMAGEDIR)/linux.bin
#gzip -f $(IMAGEDIR)/linux.bin 【注释掉】
#cat $(IMAGEDIR)/linux.bin.gz $(ROMFSIMG) > $(IMAGE) 【注释掉】
cat $(IMAGEDIR)/linux.bin $(ROMFSIMG) > $(IMAGE)
$(ROOTDIR)/tools/cksum -b -o 2 $(IMAGE) >> $(IMAGE)
[ -n "$(NO_BUILD_INTO_TFTPBOOT)" ] || cp $(IMAGE) /tftpboot
#$(MAKE) -C ../../../colilo 【注释掉】
BSS=`m68k-elf-objdump --headers $(ROOTDIR)/$(LINUXDIR)/linux | \
grep .bss` ; \
ADDR=`set -- $${BSS} ; echo 0x$${4}` ; \
m68k-elf-objcopy --add-section=.romfs=$(ROMFSIMG) \
--adjust-section-vma=.romfs=$${ADDR} --no-adjust-warnings \
--set-section-flags=.romfs=alloc,load,data \
$(ROOTDIR)/$(LINUXDIR)/linux $(ELFIMAGE) 2> /dev/null
4、修改linux-2.4.x/drivers/block/blkmem.c的第125行开始的几句,注释掉defined(CONFIG_HHTECH),修改后代码如下:
#ifdef CONFIG_COLDFIRE
#ifdef CONFIG_TELOS
#undef CONFIG_CARDE3
#define CAT_ROMARRAY
......
其实关键就是去掉CAT_ROMARRAY的定义。

31、2.4 Linux内核大小
uClinux/linux-2.4.x/目录下编译出来的linux文件有5M多,这是ELF格式的文件,它转换成image.bin时还要用m68k-elf-objcopy工具转换成binary格式的linux.bin,这时它就只有800k了,再压缩一下就变成300k了。这个工作具体可参见uClinux/vendors/HHTECH/M5272/Makefile。
最新评论共有 4 位网友发表了评论
发表评论
评论内容:不能超过250字,需审核,请自觉遵守互联网相关政策法规。
用户名: 密码:
匿名?
注册