三个要求:
1.建议安装纯linux系统
友情提示:备份重要的私人资料
ubuntu,fedora,kali
2.建议搭建嵌入式linux开发环境
tftp
nfs
linux串口终端工具:kermit/minicom
linux源码阅读工具:ctags/cscope
linux远程登录工具:openssh-server
linux编辑器vim
拷贝vim的配置文件和功能插件:
/home/tarena/.vimrc
/home/tarena/.vim
3.每天半小时笔试题
www.baidu.com
www.google.com + 英文
案例:给一个开发板,如何将系统部署起来?
面试题:谈谈对嵌入式的理解?
面试题:谈谈对嵌入式软件编程的理解?
面试题:谈谈对嵌入式linux系统的理解?
面试题:谈谈对linux系统启动的理解?
实施步骤:
1.了解开发板的硬件特性
1.1.宏观上掌握开发板具有的硬件接口
必要接口:
串口:搞清楚用的是哪个串口
搞清楚串口是并行还是交叉
网口:用于tftp和NFS网络调试
USB口:用于软件下载和调试
不必要接口:根据用户需求来添置
SD卡接口
TF卡接口
音频口
HDMI
按键:独立式按键和矩阵式按键
LED告警指示灯(呼吸灯)
...
1.2.微观上了解硬件特性
结合开发板原理图
重点关注开发板上的一些外围芯片跟CPU之间的通信接口, 例如,AT24C02存储器,采用I2C总线接口;外置的RTC实时
时钟芯片,采用SPI总线接口;外置DS18B20温度传感 器,采用1-wired(单总线)接口....
不同的接口,将来在软件上的操作方法不一致!
如果硬件上不太懂,不太明白,问硬件工程师!
2.部署软件内容
2.1.明确配套的软件一般都是由芯片厂家或者开发板的厂家提供,千万不要从头从零自己去所谓的"移植"
2.2.获取交叉编译器,部署交叉编译器的环境变量
从官方获取
从arm-linux官方获取编译器
利用crosstool-ng工具自己制作(自动)
单独下载gcc,glibc....自己制作(手动)
2.3.部署uboot
获取官员uboot源码
解压源码
进入源码
make distclean //获取最最干净的源码
make xxx_config //配置源码.xxx_config通过阅读Makefile文件来获取,一般来说xxx就是开发板的名称
make all //编译,结果生成u-boot.bin可执行文件
烧写
局部移植:现有的开发板有可能和官方提供的参考板有些外围接口不太一致,需要对官方的uboot源码进行局部的修改。
终点关注uboot的平台头文件:include/configs/xxx.h
如果在官方的uboot中添加额外的功能:logo显示或者组合按键功能一般都在main_loop函数中
面试题:谈谈对uboot的认识!
2.4.linux内核部署
获取官方的内核源码
make distclean //获取干净的源码,执行一次即可
make xxx_defconfig //配置源码,xxx_defconfig来源于
arch/arm/configs/xxx_defconfig
make zImage //编译内核,arch/arm/boot/zImage
多多看一个重要的平台代码文件:
arch/arm/mach-s5pv210/mach-cw210.c
此文件设计硬件相关的内容,跟移植和驱动开发相关
2.5.部署根文件系统rootfs
1.可以采用官方的根文件系统
又大,臃肿,很多内容用不着!
2.利用busybox,自己制作
体力活!
2.6.驱动开发
根据开发板的外设,完成外设的设备驱动
了解外设的硬件接口:GPIO,SPI,I2C,UART...
了解外设的硬件特性:看芯片手册
编写设备驱动
编写测试用例
3.设置启动参数
bootcmd:用于加载和引导内核
bootargs:用于给内核传递参数,告诉内核将来如何挂接根文件 系统
注意:给内核传递启动参数的方法有两种:
1.利用uboot的bootargs
2.内核自身来传递
进入内核源码
make menuconfig
Boot options->
() Default kernel command string (NEW)//内核默认的启动参数信息,将光标移动到此位置,按回车键进入,设置内核的启动参数,例如:
root=/dev/nfs nfsroot=...
[ ]Always use the default kernel command string
如果选择为*,使用内核自己的参数信息
如果不选择,默认使用uboot的参数信息
4.内核挂接NFS网络文件系统的注意事项:
1.安装nfs网络服务
2.sudo vim /etc/exports添加共享目录的支持
3.重启NFS网络服务
sudo /etc/init.d/nfs-kernel-server restart
4.内核要支持NFS网络文件系统
进入内核源码
make menuconfig
File systems --->
[*] Network File Systems --->
[*]Root file system on NFS
案例:将官方的内核在CW210开发板运行,并且采用NFS网络文件系统
实施步骤:
操作内核:
1.从ftp/drv下载官方内核源码:kernel.tar.bz2
2.修改/opt目录的用户和组
sudo chown tarena /opt -R
sudo chgrp tarena /opt -R
3.cp kernel.tar.bz2 /opt/
4.cd /opt/
5.tar -jxvf kernel.tar.bz2 //生成kernel目录(源码根目录)
6.cd kernel
7.make distclean //只执行一次
8.make cw210_defconfig //配置针对CW210开发板
9.make zImage //编译
10.cp arch/arm/boot/zImage /tftpboot
操作根文件系统
11.cp /home/tarena/workdir/rootfs/rootfs /opt/ -frd
12.sudo vim /etc/exports 添加/opt/rootfs的支持
13.sudo /etc/init.d/nfs-kernel-server restart 重启服务
设置启动参数:
14.进入uboot的命令行模式
15.setenv bootcmd tftp 20008000 zImage ; bootm 20008000
16.setenv bootargs root=/dev/nfs nfsroot=192.168.1.8:/opt/rootfs ip=192.168.1.110:192.168.1.8:192.168.1.1:255.255.255.0::eth0:on init=/linuxrc console=ttySAC0,115200
17.saveenv
内核自身来传递参数:
18.cd /opt/kernel
make menuconfig
Boot options->
() Default kernel command string (NEW)//内核默认的启动参数信息,将光标移动到此位置,按回车键进入,设置内核的启动参数,例如:
root=/dev/nfs nfsroot=192.168.1.8:/opt/rootfs
ip=192.168.1.110:192.168.1.8:192.168.1.1:255.255.255.0::eth0:on init=/linuxrc console=ttySAC0,115200
[*]Always use the default kernel command string
保存退出
make zImage
cp arch/arm/boot/zImage /tftpboot
19.进入uboot
setenv bootargs //清除uboot的bootargs
saveenv
20.重启开发板,看内核是否能挂接NFS网络文件系统
**********************************************************
2.linux内核基本编程框架
2.1.回顾应用程序的基本编程框架
#include
...
int main(int argc, char *argv[])
{
printf("hello,world
");
...
return 0;
}
特点:
1.头文件是标准C的头文件
2.printf函数是标准C的库函数,对应的库libc*
3.main函数是程序的入口函数
4.return表示程序的出口
5.argc,argv分别表示命令行传参的个数和参数信息
2.2.linux内核基本的编程框架
例子代码helloworld.c:
#include
#include
...
static int helloworld_init(void)
{
printk("hello,world
");
...
return 0; //执行成功返回0,执行失败返回负值
}
static void helloworld_exit(void)
{
printk("good bye!
");
...
}
module_init(helloworld_init);
module_exit(helloworld_exit);
MODULE_LICENSE("GPL");
内核程序特点:
1.使用的头文件都位于内核源码中
2.使用调用的函数的定义都位于内核源码中
3.module_init修饰的函数helloworld_init就是内核程序的入口函数,类似main函数,入口函数的返回值为int,参数为void
4.module_exit修饰的函数helloworld_exit就是内核程序的出口函数,类似return 0;返回值,形参都是void
5.任何一个内核程序(.c),都必须添加GPL许可声明,必须添加:
MODULE_LICENSE("GPL");
6.内核程序的入口函数执行完毕,并不代表内核程序结束,恰恰相反,内核程序而是刚刚开始,仅仅是存在于内存中,供应用程序来访问使用;
7.内核程序的出口函数执行完毕,这个内核程序将会从内存中剔除
2.3.问:如何编译内核程序(关键要指定内核源码)
答:编写Makefile即可
Makefile文件的模板:
obj-m += helloworld.o
#说明:将helloworld.c最终编译成对应的二进制可执行文件helloworld.ko
all:
make -C /opt/kernel SUBDIRS=$(PWD) modules
#说明:
make -C /opt/kernel:到/opt/kernel目录下执行make命令
SUBDIRS=$(PWD):$(PWD)代表helloworld.c所在的路径,把路径信息给SUBDIRS(表示内核的一个子目录)
modules:告诉内核,对于helloworld.c所在目录下的文件采用模块编译,就是将.c->.ko
clean:
make -C /opt/kernel SUBDIRS=$(PWD) clean
案例:编写第一个内核程序
实施步骤:
PC执行:
1.mkdir /opt/drivers/day01/1.0 -p
2.cd /opt/drivers/day01/1.0
3.vim helloworld.c 内容如下
#include
#include
static int helloworld_init(void) //入口函数
{
printk("hello,world
");
return 0; //执行成功返回0,执行失败返回负值
}
static void helloworld_exit(void) //出口函数
{
printk("good bye!
");
}
module_init(helloworld_init);
module_exit(helloworld_exit);
MODULE_LICENSE("GPL");
4.vim Makefile 内容如下:
obj-m += helloworld.o
all:
make -C /opt/kernel SUBDIRS=$(PWD) modules
clean:
make -C /opt/kernel SUBDIRS=$(PWD) clean
5.make 编译
6.结果是helloworld.c有了一个对应的helloworld.ko
7.cp helloworld.ko /opt/rootfs/ //将可执行文件拷贝到开发板
8.问:如何在开发板上运行内核程序呢?让他和zImage混呢?
答:
ARM板操作:
利用insmod,rmmod,lsmod进行对内核模块操作
insmod:加载内核程序到内核中(内存中)
加载内核程序时,如果内核程序有入口函数,内核调用此函数;如果没有入口函数,没关系,照样加载到内存中!
insmod helloworld.ko
lsmod:查看当前内核中加载了哪些内核模块,内核程序
lsmod
rmmod:删除内核模块,内核程序从内核(从内存中),如果内核程序有出口函数,此时调用出口函数,如果没有出口函数,没关系,照样删除!
rmmod helloworld
lsmod