《嵌入式程序设计》第三、四周学习总结
这两周主要学习了Linux交叉开发环境的搭建和bootloader的配置移植及编译,以及Linux的内核
教材学习内容总结
一.交叉开发环境的搭建
1.交叉编译器的完整安装需要多个软件,包括binutils、gcc、glibc等软件。其中,gcc用来生成交叉编译器的,主要生成arm-linux-gcc交叉编译工具,生成此工具后已经搭建起了交叉编译环境,可以编译linux内核,但由于没有提供标准用户函数库,用户程序还无法编译;glibc主要是提供用户程序所使用的一些基本的函数库。这样交叉环境就搭建起来了。
二、编译嵌入式Linux内核
(1)内核配置
内核配置中的选项主要是用户用来为目标选择处理器架构的选项,不同的处理器架构会有不同的处理器选项,ARM必须确保在根目录中makefile里“ARCH”的值已设定了目标版的类型。
如:ARCH :=arm
(2)内核支持的4种不同的配置方法
这几种方法只是与用户交互界面不同,其实现的功能一样。每种方法都会通过读入一个默认的配置文件--根目录下“.config”隐藏文件
①make config
基于文本的最为传统的配置界面
②make menuconfig
基于文本选单的配置界面,字符终端下推荐使用
③make xconfig
基于图形窗口模式的配置界面,Xwindow下推荐使用。
④make oldconfig
自动读入".config"配置文件,并且只要求用户设定前次没有设定过的选项
注意:2.4和2.6内核在串口命令上的一个重要区别,在2.4内核中"COM1"对应的是"ttyS0",而在2.6内核中"COM1"对应"ttySAC0",因此在启动参数的子项要格外注意。
(3)建立依赖关系通常在第一次编译内核的时候进行,它会在内核源码树中每个子目录产生一个".depend"文件。运行"make dep"即可,在编译2.6版本直接输入"make"即可。
(4)Linux内核源码目录结构
①/include:子目录包含了建立内核代码时所需的大部分包含文件,这个模板利用其它模板重建内核。
②/init:子目录包含了内核的初始化代码,这里的代码是内核工作的起始入口。
③/arch:子目录包含了所有处理器体系结构特定的内核代码
④/drivers:子目录包含了内核中所有的设备驱动程序,如块设备和SCSI设备
⑤/fs:子目录包含了所有的文件系统的代码
⑥/net子目录包含了内核的网络相关代码
⑦/mm子目录包含了所有内存管理代码
⑧/ipc子目录包含了进程间通信代码
⑨/kernel子目录包含了内核核心代码
(5)将工具链加入到PATH中:
\(PATH,查看/usr/bin 第一种:\)export PATH=\(PATH:/usr/local/arm/gcc-3.4.6-glibc-2.3.6/bin 这种方法关掉客户端就没了 第二种:添加到下面三个文件其一均可 /etc/profile是系统启动过程执行的一个脚本,对所有用户都生效。 /.bash_profile是用户的脚本,在用户登录时生效。 ~/.bashrc也是用户的脚本,在~/.bash_profile中调用生效。 三.U-Boot移植配置 (1)U-Boot源码结构 ①board:和一些已有开发板有关的代码,如makefile和U-Boot.lds ②common:与体系结构无关的代码,用来实现各种命令的C程序 ③cpu:包含CPU相关代码,其中的子目录都是以U-BOOT所支持的CPU为名,如子目录arm926ejs等 ④disk:disk驱动的分区相关代码 ⑤doc:文档 ⑥drivers:通用设备驱动程序,比如各种网卡、支持CFI的Flash ⑦fs:支持文件系统的文件 ⑧include:头文件,还有对各种硬件平台支持的汇编文件 ⑨net:与网络有关的代码 ⑩lib_arm:与ARM体系结构相关的代码 ⑪tools:创建S-Rccord格式文件和U-BOOT image的工具 (2)U-Boot移植主要步骤 ①建立自己的开发版类型 在Makefile文件中添加两行 ```eduk2410_config: unconfig @\)(MKCONFIG) $(@:_config=) arm arm920t eduk2410 NULL s3c24x0其中"arm"为表示处理器体系结构的种类,"arm920t"表示处理器体系结构的名称 eduk2410为主板名 ②在board目录中建立eduk2410目录,将smdk目录中的内容复制到该目录中 ③修改GPIO配置 修改0x00044555改为0x0004455A: (3)编译U-Boot ①首先运行如下命令配置U-Boot:
# make eduk2410_config```
Configuring for edul2410 board...
②然后运行make命令编译:
make
四.基本文件操作
①open()函数用于打开或创建文件
②close()函数用于关闭一个被打开的文件
③read()函数用于将从指定的文件描述符中读出的数据放到缓冲区中,并返回实际读入的字符数。
④write()函数用于向打开的文件写数据,写操作从文件的当前指针位置开始。
⑤lseek()函数用于在指定的文件描述符中将文件指针定位到相应的位置。它只能用在可定位(可随机访问)文件操作中。
课后作业总结
(1)创建src_file文件
(2)创建copy_file.c文件
(3)进行编译
(4)运行
(5)dest_file文件内容跟src_file一致
(6)代码注释
/* copy_file.c */
// 加入头文件
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <stdio.h>
// 每次读写缓存大小,影响运行效率
#define BUFFER_SIZE 1024
// 源文件名
#define SRC_FILE_NAME "src_file"
// 目标文件名
#define DEST_FILE_NAME "dest_file"
// 复制的数据大小
#define OFFSET 10240
int main()
{
// 定义源文件和目标文件
int src_file, dest_file;
// 定义数据的缓存区
unsigned char buff[BUFFER_SIZE];
// 定义数据长度
int real_read_len;
// 以只读方式打开源文件
src_file = open(SRC_FILE_NAME, O_RDONLY);
// 以只写方式打开目标文件,若此文件不存在则创建该文件,访问权限值为644
dest_file = open(DEST_FILE_NAME, O_WRONLY | O_CREAT,
S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
// 如果源文件或目标文件没有,输出“ Open file error ”
if(src_file < 0 || dest_file < 0)
{
printf("Open file error\n");
exit(1);
}
// 将源文件的读写指针移到最后10KB的起始位置
lseek(src_file, -OFFSET, SEEK_END);
// 读取源文件的最后10KB数据并写到目标文件中,每次读写1KB
while((real_read_len = read(src_file, buff, sizeof(buff))) > 0)
{
//将数据写到dest_file文件里
write(dest_file, buff, real_read_len);
}
// 关闭目标文件
close(dest_file);
// 关闭源文件
close(src_file);
return 0;
}
实验楼
学习进度条
代码行数(新增/累积) | 博客量(新增/累积) | 学习时间(新增/累积) | 重要成长 | |
---|---|---|---|---|
目标 | 5000行 | 15 | 20/20 | |
第一周 | 200/200 | 2/2 | 1/1 | vi的使用 |
第二周 | 1000/1200 | 3/7 | 7/8 | gcc,gdb,makefile |
第三周 | 500/1700 | 1/8 | 4/12 | U-Boot |
第四周 | 1500/3200 | 1/9 | 6/18 | Linux的内核 |
参考资料
- 《交叉环境编译PPT》
- 《嵌入式Linux应用程序开发标准教程》