Author:DriverMonkey
Mail:boowkorepeng@hotmail.com
QQ:196568501
欢迎交流(承接各类嵌入式外包项目-wince,linux,单片机,上位机开发)
进入u-boot
file: start.s
b reset // 跳转到复位执行函数
...
reset:
//1.set the cpu to SVC32 mode
....
bl cpu_init_crit
.....
cpu_init_crit:
...
bl lowlevel_init @ go setup pll,mux,memory
...
file:lowlevel_init.s
lowlevel_init:
...
bl s_init //从这里调到c语言初始化代码
..
evm.c
void s_init(void)
{
/* Can be removed as A8 comes up with L2 enabled */
l2_cache_enable();
/* WDT1 is already running when the bootloader gets control
* Disable it to avoid "random" resets
*/
__raw_writel(0xAAAA, WDT_WSPR);
while(__raw_readl(WDT_WWPS) != 0x0);
__raw_writel(0x5555, WDT_WSPR);
while(__raw_readl(WDT_WWPS) != 0x0);
#ifdef CONFIG_SPL_BUILD
/* Setup the PLLs and the clocks for the peripherals */
pll_init();
/* Enable RTC32K clock */
//rtc32k_enable(); //masked by DriverMonkey
/* UART softreset */
u32 regVal;
u32 uart_base = DEFAULT_UART_BASE;
enable_uart0_pin_mux();
/* IA Motor Control Board has default console on UART3*/
/* XXX: This is before we've probed / set board_id */
if (board_id == IA_BOARD) {
uart_base = UART3_BASE;
}
regVal = __raw_readl(uart_base + UART_SYSCFG_OFFSET);
regVal |= UART_RESET;
__raw_writel(regVal, (uart_base + UART_SYSCFG_OFFSET) );
while ((__raw_readl(uart_base + UART_SYSSTS_OFFSET) &
UART_CLK_RUNNING_MASK) != UART_CLK_RUNNING_MASK);
/* Disable smart idle */
regVal = __raw_readl((uart_base + UART_SYSCFG_OFFSET));
regVal |= UART_SMART_IDLE_EN;
__raw_writel(regVal, (uart_base + UART_SYSCFG_OFFSET));
/* Initialize the Timer */
init_timer();
preloader_console_init();
config_am335x_ddr3();//added by DriverMonkey
//config_am335x_ddr();
#endif
}
Start.s
call_board_init_f:
ldr sp, =(CONFIG_SYS_INIT_SP_ADDR)
bic sp, sp, #7 /* 8-byte alignment for ABI compliance */
ldr r0,=0x00000000
bl board_init_f
spl.c
void board_init_f(ulong dummy)
{
/*
* We call relocate_code() with relocation target same as the
* CONFIG_SYS_SPL_TEXT_BASE. This will result in relocation getting
* skipped. Instead, only .bss initialization will happen. That's
* all we need
*/
debug(">>board_init_f()++\n");
printf("board_init_f\n");
relocate_code(CONFIG_SPL_STACK, &gdata, CONFIG_SPL_TEXT_BASE);
}
Start.s
relocate_code:
mov r4, r0 /* save addr_sp */
mov r5, r1 /* save addr of gd */
mov r6, r2 /* save addr of destination */
/* Set up the stack
原问题来自于CSDN问答频道,更多见:http://ask.csdn.net/questions/1840
问题描述:
有一个多行文本的textView,如果文本不超过显示空间,就设置重力向上
tv.setGravity(Gravity.TOP);
如果文本过多超出范围,我需要显示文本的结尾部分。
tv.setGravity(Gravity.BOTTOM);
布局:
<RelativeLayout android:id="@+id/textLayout" android:layout_marginTop="16dp" android:layout_width="fill_parent" android:layout_height="110dp" android:orientation="vertical" android:visibility="visible" > <TextView android:id="@+id/tv" android:layout_width="match_parent" android:layout_height="fill_parent" android:layout_alignParentLeft="true" android:layout_alignParentTop="true" android:gravity="top" android:text="Long text bla bla." android:textColor="@android:color/black" android:textColorHint="@android:color/black" android:textSize="37sp" /> ... </RelativeLayout>
不知道应该怎么让应用能判断文本有多长?有没有超出范围。每个屏幕尺寸不同所以不能通过硬编码设定行数判断。
:
在LinearLayout中加入TextVew,然后比较TextVew 和linearlayout 的高度
<RelativeLayout android:id="@+id/textLayout" android:layout_marginTop="16dp" android:layout_width="fill_parent" android:layout_height="110dp" android:orientation="vertical" android:visibility="visible" > <LinearLayout android:id ="@+id/linear" android:layout_width="match_parent" android:layout_height="fill_parent" android:orientation="horizontal"> <TextView android:id="@+id/text" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_alignParentLeft="true" android:layout_alignParentTop="true" android:gravity="top" android:text="Long text bla bla." android:textColor="@android:color/black" android:textColorHint="@android:color/black" android:textSize="37sp" />
比较高度:
if(text.getHeight()>linear.getHeight()){ //Here TextView longer than available space }
由于之前做过2440和6410,鉴于时间原因,这里暂时跨过其他模块的裸机驱动和uboot移植,直接进入内核移植及驱动开发方面的学习。
内核移植其实很简单,因为内核是linus率领的linux内核开发团队开发并维护的,我们只需要跟我们的平台交叉编译一下即可使用,但是,内核移植也不简单,因为内核移植起见出现任何问题都可能会被卡住,因为内核代码非常庞大,我们无法通读内核代码,下面是我移植期间遇到的各种悲催的问题和,首先是必备的开发环境:
a) Linux内核代码,版本3.8.3
b) S5PV210开发板(我的是TQ210)
c) HOST环境是WIN7(64位)下安装的Ubuntu虚拟机(12.10)
一 内核编译
从Linux内核网站(kernel.org)下载内核代码、解压并进入内核目录
(1)修改Makefile,将195行和196行改为:
ARCH = arm CROSS_COMPILE ?= arm-linux-(2)进行默认配置,进入arch/arm/configs目录,可以发现最接近我们开发板的配置文件是s5pv210_defconfig,故
make s5pv210_defconfig(3)编译内核,如果需要生成zImage则执行
make zImage如果需要生成uImage则执行
make uImage(4)用uboot下载并尝试运行,结果是悲剧的,在uboot打印”Starting kernel...“之后就看不到任何输出了,显然,有两种原因:
a. 编译的内核类型错误,比如您的uboot使用的是uImage,而您编译的是zImage。
b. 移植的uboot存在问题,没能正确的拷贝内核到正确的内存地址并启动。
c. 内核存在某些配置,我们没有配置。
经过查看内核配置项知道,内核默认采用的UART1打印调试信息,因此,执行:
make menuconfig在出来的对话中依次选择System type => (1) S3C UART to use for low-level messages,在编辑框中将1改为0,然后保存配置并再次编译内核,直接执行make即可,无需make clean。如果是首次执行make menuconfig会遇到错误,这是因为make menuconfig依赖一个库,这里我忘记名字了,如果是ubuntu可以直接用指令安装的,网上搜一下就可以搞定。
编译完内核之后再次下载并尝试运行,这时,可以看到内核打印的信息了,如果您不幸只看到“Uncompressing Linux... done, booting the kernel.”就没有任何输出了,那么请检查uboot传入的机器码跟内核机器码是否匹配,如果不匹配请修正,然后重新编译运行内核或者uboot,如果修正之后仍然看不到其他输出,那么请检查uboot的bootargs参数,bootargs中必须配置console=ttySAC0,否则也看不到打印信息。
如果没有出现上面的错误,那么您的内核已经可以打印出很多信息,但是由于内核默认没有提供对Nand或网卡的支持,无法挂接文件系统,所以仍然无法正常运行。为了能使内核进入控制台,为后面的驱动开发提供环境,我们先制作文件系统,然后来移植网卡驱动,让内核NFS方式挂接文件系统,然后我们就可以开发其他驱动了,如Nand、LCD、声卡等等。
二 构建文件系统
其实构建文件系统还是比较简单的,注意几个地方,然后按部就班的来就可以了。
(1)创建根文件系统目录结构,可以使用如下脚本:
#!/bin/sh echo "------Create rootfs directons start...--------" mkdir rootfs cd rootfs echo "--------Create root,dev....----------" mkdir root dev etc boot tmp var sys proc lib mnt home usr mkdir etc/init.d etc/rc.d etc/sysconfig mkdir usr/sbin usr/bin usr/lib usr/modules echo "make node in dev/console dev/null" sudo mknod -m 600 dev/console c 5 1 sudo mknod -m 600 dev/null c 1 3 mkdir mnt/etc mnt/jffs2 mnt/yaffs mnt/data mnt/temp mkdir var/lib var/lock var/run var/tmp chmod 1777 tmp chmod 1777 var/tmp echo "-------make direction done---------"
在这里我将脚本命名为mkrootfs.sh,接下来给脚本加可执行权限(即chmod a+x mkrootfs)并运行脚本。我的脚本是在/nfsroot目录下运行的,所以我的根文件系统的根目录为/nfsroot/rootfs,后面均以该目录为例阐述。
(2)编译Busybox
到Busybox下载最新版的Busybox源码,我是用的是1.21.0版本,下载完后解压并进入busybox目录,首先是配置busybox
make menuconfig
配置菜单跟配置内核时的差不多,依次进入Busybox Settings => Build Options => Cross Compiler prefix (NEW),设置为编译器的前缀,我的是arm-linux-。网上有些朋友还推荐选择Busybox Settings => Build Options => Build BusyBox as a static binary (no shared libs),但是如果我们正确拷贝编译器了运行库的话,不设置也可以。现在可以编译Busybox了,执行
make
编译过程很顺利,我这里没有遇到任何错误,接下来将编译好的Busybox安装到/nfsroot/rootfs就可以了,执行
make CONFIG_PREFIX=/nfsroot/rootfs install
(3)拷贝编译器运行库
我的编译器是4.5.1版本的,拷贝arm-none-linux-gnueabi/sys-root/lib的所有动态库到/nfsroot/rootfs/lib下,为了不拷贝连接,应该加上”-d"选项,执行
cp *so* /nfsroot/rootfs/lib -d
同样拷贝arm-none-linux-gnueabi/sys-root/usr/lib下的所有动态库到/nfsroot/rootfs/usr/lib下,执行
cp *so* /nfsroot/rootfs/usr/lib -d
(4)构建etc目录
在etc目录下创建Inittab文件,内容如下
::sysinit:/etc/init.d/rcS console::askfirst:-/bin/sh ::restart:/sbin/init ::ctrlaltdel:/sbin/reboot ::shutdown:/bin/umount -a -r ::shutdown:/sbin/swapoff -a
在etc/init.d/目录下创建rcS文件,内容如下
echo "----------mount all.........." mount -a echo "----------Starting mdev......" echo /sbin/mdev > /proc/sys/kernel/hotplug mdev -s /bin/hostname -F /etc/sysconfig/HOSTNAME
为inittab和rcS文件添加可执行权限
chmod a+x inittab chmod a+x rcS
在etc目录下创建fstab文件,内容如下
#evice mount-point type option dump fsck order proc /proc proc defaults 0 0 none /tmp ramfs defaults 0 0 mdev /dev ramfs defaults 0 0 sysfs /sys sysfs defaults 0 0
在etc目录下创建profile文件,内容如下
PATH=/bin:/sbin:/usr/bin:/usr/sbin export PATH #set hostname HOSTNAME='/bin/hostname' export HOSTNAME # Set PS1 PS1='[\u@\h \W]\$' export PS1
拷贝主机/etc目录下的passwd和group文件到etc目录下。
(5) 设置HOSTNAME文件
在etc/sysconfig目录下创建HOSTNAME文件,在文件中写入主机名,我这里写的是bruce。
(6) 安装内核modules
进入内核源码目录,执行
make modules
待编译完成后安装modules,执行指令
make modules_install INSTALL_MOD_PATH=/nfsroot/rootfs
到这,根文件系统就构建完成了.
三 设置uboot启动参数
我的nfs根目录为/nfsroot,我的根文件系统目录是在该目录之下的,即/nfsroot/rootfs目录,故uboot启动参数设置如下
noinitrd console=ttySAC0 root=<主机IP>:/nfsroot/rootfs rw ip=<开发板IP>:<主机IP>:<网关>:<子网掩码>::eth0:off init=/linuxrc
需要注意的是,所有的冒号":"都不可省略。
四 网卡驱动移植(DM9000)
选择网卡移植是因为网卡驱动相对较为简单,对于DM9000就更加简单了,因为内核本身提供了DM9000的驱动程序,但是没有针对开发板进行管教配置,因此,我们配置下开发板相关的东西即可完成网卡驱动的移植。打开arch/arm/mach-s5pv210/mach-smdkv210.c文件,并作以下修改:
(1) 修改smdkv210_dm9000_resources定义如下
static struct resource smdkv210_dm9000_resources[] = { [0] = { .start = 0x88000000, .end = 0x88000000 + 3, .flags = IORESOURCE_MEM, }, [1] = { .start = 0x88000000 + 4, .end = 0x88000000 + 4 + 3, .flags = IORESOURCE_MEM, }, [2] = { .start = IRQ_EINT(10), .end = IRQ_EINT(10), .flags = IORESOURCE_IRQ|IORESOURCE_IRQ_HIGHLEVEL, } };
(2) 修改smdkv210_dm9000_init函数如下
static void __init smdkv210_dm9000_init(void) { unsigned long* srom_bw = ioremap(0xE8000000, 4); unsigned long* srom_bc1 = ioremap(0xE8000004, 4); *srom_bc1 = ((0<<28)|(0<<24)|(5<<16)|(0<<12)|(0<<8)|(0<<4)|(0<<0)); *srom_bw &= ~(0xf << 4); *srom_bw |= (1<<4)|(1<<5); gpio_request(S5PV210_MP01(1), "nCS1"); s3c_gpio_cfgpin(S5PV210_MP01(1), S3C_GPIO_SFN(2)); gpio_free(S5PV210_MP01(1)); iounmap(srom_bw); iounmap(srom_bc1); }
这样,就完成了DM9000网卡驱动的移植,其实这样修改是有逻辑的,根据TQ210的原理图可知DM9000连接的片选时nCS1,也就是网卡是接在来ROM控制器的BANK1上。
根据S5PV210的内存映射表可以看出,SROMC的BANK1地址空间为0x88000000~0x8FFFFFFF,故当CPU寻址该范围内的地址空间时才会使能片选nCS1。所以,我们采用的是0x88000000地址。
另外,从TQ210原理图的DM9000部分还可以看到,DM9000使用的是外部中断10,故将中断号修改为10号。
最后需要说明的是smdkv210_dm9000_init函数的修改,这是因为DM9000的数据访问、命令发送等是按照一定时序工作的,而DM9000接再SROMC上,因此需要配置SROMC时序,使其可以正确驱动DM9000,关于时序的详细配置我还没研究,不过韦东山老师的第二期视频中讲述了DM9000的驱动移植,也讲了时序配置,需要的话可以参考。
五 挂接文件系统
我们现在配置好了网卡驱动,还需要对内核稍作配置才能使内核支持网络文件系统挂载,具体的可以参考以下配置。
(1) 配置网络支持
[*] Networking support ---> Networking options ---> <*> Packet socket <*> Unix domain sockets [*] TCP/IP networking [*] IP: multicasting [*] IP: kernel level autoconfiguration [*] IP: DHCP support [*] IP: BOOTP support [*] IP: RARP support [*] IP: multicast routing
(2) 配置网卡设备支持
Device Drivers ---> [*] Network device support ---> [*] Ethernet driver support ---> <*> DM9000 support
File systems ---> [*] Network File Systems ---> <*> NFS client support <*> NFS client support for NFS version 2 <*> NFS client support for NFS version 3 [*] NFS client support for the NFSv3 ACL protocol extension <*> NFS client support for NFS version 4 [*] Root file system on NFS
配置完以上三项后保存配置,然后再次编译内核,直接执行make指令即可。
这时,重新下载内核测试运行,没有意外的话现在内核已经可以正常工作了,如果不幸的遇到了问题,那么问题应该是NFS服务器配置的问题,ubuntu下配置NFS服务器很简单
sudo apt-get install nfs-kernel-server
然后以根权限打开/etc/exports文件,我的NFS根目录为/nfsroot,故,我设置export为
/nfsroot/ *(rw,sync,no_root_squash)
设置完成之后需要重启NFS服务,ubuntu下执行
sudo service nfs-kernel-server restart
重启的时候会看到一些警告,如下图
但是上述警告不影响使用。反之,如果设置为no_subtree_check,虽然系统可以正常挂载,但是无法进行创建文件等写操作,也就是说,挂载的文件系统是只读的。最后还要修改下/nfsroot的权限,为了以后使用方便。
chmod a+x /nfsroot -R
到这里,基于TQ210的内核移植已经初步完成了,接下来我们就可以进行驱动开发了。
六 问题总结
我在配置过程中遇到了很多问题,现在稍作总结
(1) 串口中断打印完Starting kernel...之后就没有任何输出了
配置内核,指定调试信息输出端口为UART0,文中讲到了详细配置。
(2) 解压完内核之后没有任何输出了
a.检查bootargs环境变量设置是否正确,必须设置console=ttySAC0
b.检查uboot传递的机器码根内核是否对应
c.检查uboot传给内核的taglist是否正确
(3) 内核无法挂接到NFS文件系统
a. 正确移植DM9000网卡驱动
b. 配置内核的网络部分、网卡设备和文件系统中的网络文件系统
c. 确认NFS服务器的配置是否正确,用另外其他linux或已经移植好系统的linux进行测试(mount -o nolock xx.xx.xx.xx:/nfsroot/rootfs)。
(4) 文件系统挂接成功,无法执行/linuxrc
a. 检查NFS配置文件,最好以NFSv2方式配置,内核不支持的话会出现问题。
b. 最好以文中推荐的方式进行NFS服务器配置。
c. 配置完成之后需要重启NFS服务或者是重启系统。
七 其它问题
如果您在移植过程中出现了其他问题欢迎留言讨论。