515 lines
16 KiB
Markdown
515 lines
16 KiB
Markdown
|
- [驱动](#驱动)
|
|||
|
- [驱动基础知识](#驱动基础知识)
|
|||
|
- [内核源码编译过程](#内核源码编译过程)
|
|||
|
- [第一步:配置Kconfig](#第一步配置kconfig)
|
|||
|
- [第二步:配置Makefile](#第二步配置makefile)
|
|||
|
- [第三步 配置上层目录的Makefile与Kconfig](#第三步-配置上层目录的makefile与kconfig)
|
|||
|
- [驱动程序分析过程](#驱动程序分析过程)
|
|||
|
- [插入驱动](#插入驱动)
|
|||
|
- [驱动加载进内核或以模块插入后会运行下面的初始化接口](#驱动加载进内核或以模块插入后会运行下面的初始化接口)
|
|||
|
- [初始化接口里进行设备驱动的注册](#初始化接口里进行设备驱动的注册)
|
|||
|
- [字符设备](#字符设备)
|
|||
|
- [字符设备框架](#字符设备框架)
|
|||
|
- [静态注册设备](#静态注册设备)
|
|||
|
- [新字符设备,引用了字符设备结构体](#新字符设备引用了字符设备结构体)
|
|||
|
- [platform驱动](#platform驱动)
|
|||
|
- [dts的platform驱动](#dts的platform驱动)
|
|||
|
- [驱动程序注册重要函数](#驱动程序注册重要函数)
|
|||
|
- [设备树](#设备树)
|
|||
|
- [系统](#系统)
|
|||
|
- [kernel、rootfs 和 uboot之间的关系](#kernelrootfs-和-uboot之间的关系)
|
|||
|
- [uboot代码结构](#uboot代码结构)
|
|||
|
- [uboot](#uboot)
|
|||
|
|
|||
|
# 驱动
|
|||
|
## 驱动基础知识
|
|||
|
### 内核源码编译过程
|
|||
|
1.遍历每个源码目录(或配置指定的源码目录)Makefile
|
|||
|
2.每个目录的Makefile 会根据Kconfig来定制要编译对象
|
|||
|
3.回到顶层目录的Makeifle执行编译
|
|||
|
|
|||
|
Kconfig ---> (每个源码目录下)提供选项 (决定哪些需要编译那些不需要)
|
|||
|
.config ---> (源码顶层目录下)保存选择结果 (默认配置)
|
|||
|
Makefile---> (每个源码目录下)根据.config中的内容来告知编译系统如何编译
|
|||
|
|
|||
|
|
|||
|
**举例**
|
|||
|
#### 第一步:配置Kconfig
|
|||
|
在driver目录下新建一个目录,
|
|||
|
mkdir driver/test
|
|||
|
进入test目录,创建Kconfig文件
|
|||
|

|
|||
|
|
|||
|
这里定义了一个TEST的句柄,Kconfig可以通过这个句柄来控制Makefile中是否编译,”Test driver”是显示在终端的名称
|
|||
|
#### 第二步:配置Makefile
|
|||
|

|
|||
|
|
|||
|
Obj-$(CONFIG_选项名) += xxx.o
|
|||
|
/*当CONFIG_选项名=y时,表示对应目录下的xxx.c将被编译进内核 当CONFIG_选项名=m时对应目录下的xxx.c将被编译成模块*/
|
|||
|
#### 第三步 配置上层目录的Makefile与Kconfig
|
|||
|
在上一层目录的Kconfig中
|
|||
|
|
|||
|

|
|||
|
|
|||
|
在上一层目录的Makefile中
|
|||
|
|
|||
|

|
|||
|
|
|||
|
结果,运行根目录的.config查看结果
|
|||
|
|
|||
|

|
|||
|
### 驱动程序分析过程
|
|||
|
#### 插入驱动
|
|||
|
1. insmod chrdevbase.ko
|
|||
|
2. 输入“lsmod”命令即可查看当前系统中存在的模块
|
|||
|
3. cat /proc/devices 查看当前系统中所有的设备
|
|||
|
4. 驱动加载成功需要在/dev 目录下创建一个与之对应的设备节点文件,应用程序就是通过操
|
|||
|
作这个设备节点文件来完成对具体设备的操作,使用旧接口注册的驱动需要用命令创建设备节点
|
|||
|
- mknod /dev/chrdevbase c 200 0
|
|||
|
#### 驱动加载进内核或以模块插入后会运行下面的初始化接口
|
|||
|
subsys_initcall(); //用于核心子系统的初始化,初始化时间早于module_init
|
|||
|
module_init(); //适用于以模块形式编译的代码,insmod加载驱动时会调用这个函数
|
|||
|
module_exit();
|
|||
|
#### 初始化接口里进行设备驱动的注册
|
|||
|
**注册函数**
|
|||
|
1. 对于字符设备驱动:
|
|||
|
- register_chrdev() - 注册字符设备号 //旧方法,需要手动创建设备节点
|
|||
|
- cdev_add() - 添加cdev结构到系统 //新方法, 会自动创建设备节点
|
|||
|
2. 对于平台驱动:
|
|||
|
- platform_driver_register() - 注册平台驱动
|
|||
|
3. 对于I2C和SPI总线驱动:
|
|||
|
- i2c_add_driver() - 注册I2C驱动
|
|||
|
- spi_register_driver() - 注册SPI驱动
|
|||
|
4. 对于USB驱动:
|
|||
|
- usb_register() - 注册USB驱动
|
|||
|
5. 对于网络设备驱动:
|
|||
|
- register_netdev() - 注册网络接口
|
|||
|
6. 通用设备驱动注册:
|
|||
|
- driver_register() - 注册设备驱动
|
|||
|
7. PCI设备驱动:
|
|||
|
- pci_register_driver() - 注册PCI设备驱动
|
|||
|
8. 输入设备驱动:
|
|||
|
- input_register_device() - 注册输入设备
|
|||
|
|
|||
|
## 字符设备
|
|||
|
|
|||
|

|
|||
|
|
|||
|
### 字符设备框架
|
|||
|
#### 静态注册设备
|
|||
|
```
|
|||
|
#include <linux/types.h>
|
|||
|
#include <linux/kernel.h>
|
|||
|
#include <linux/delay.h>
|
|||
|
#include <linux/ide.h>
|
|||
|
#include <linux/init.h>
|
|||
|
#include <linux/module.h>
|
|||
|
#include <linux/errno.h>
|
|||
|
#include <linux/gpio.h>
|
|||
|
#include <asm/mach/map.h>
|
|||
|
#include <asm/uaccess.h>
|
|||
|
#include <asm/io.h>
|
|||
|
|
|||
|
#define LED_MAJOR 200 /* 主设备号 */
|
|||
|
#define LED_NAME "led" /* 设备名字 */
|
|||
|
|
|||
|
static int led_open(struct inode *inode, struct file *filp)
|
|||
|
{
|
|||
|
return 0;
|
|||
|
}
|
|||
|
|
|||
|
static ssize_t led_read(struct file *filp, char __user *buf, size_t cnt, loff_t *offt)
|
|||
|
{
|
|||
|
return 0;
|
|||
|
}
|
|||
|
|
|||
|
static ssize_t led_write(struct file *filp, const char __user *buf, size_t cnt, loff_t *offt)
|
|||
|
{
|
|||
|
return 0;
|
|||
|
}
|
|||
|
|
|||
|
static int led_release(struct inode *inode, struct file *filp)
|
|||
|
{
|
|||
|
return 0;
|
|||
|
}
|
|||
|
|
|||
|
static struct file_operations led_fops = {
|
|||
|
.owner = THIS_MODULE,
|
|||
|
.open = led_open,
|
|||
|
.read = led_read,
|
|||
|
.write = led_write,
|
|||
|
.release = led_release,
|
|||
|
};
|
|||
|
|
|||
|
|
|||
|
static int __init led_init(void)
|
|||
|
{
|
|||
|
register_chrdev(LED_MAJOR, LED_NAME, &led_fops);
|
|||
|
return 0;
|
|||
|
}
|
|||
|
|
|||
|
static void __exit led_exit(void)
|
|||
|
{
|
|||
|
unregister_chrdev(LED_MAJOR, LED_NAME);
|
|||
|
}
|
|||
|
|
|||
|
module_init(led_init);
|
|||
|
module_exit(led_exit);
|
|||
|
MODULE_LICENSE("GPL");
|
|||
|
MODULE_AUTHOR("sakura");
|
|||
|
```
|
|||
|
static inline int register_chrdev(unsigned int major, const char *name,const struct file_operations *fops)
|
|||
|
>major:主设备号,Linux 下每个设备都有一个设备号,设备号分为主设备号和次设备号两部分
|
|||
|
>name:设备名字,指向一串字符串。
|
|||
|
>fops:结构体 file_operations 类型指针,指向设备的操作函数集合变量。
|
|||
|
#### 新字符设备,引用了字符设备结构体
|
|||
|
```
|
|||
|
#include <linux/types.h>
|
|||
|
#include <linux/kernel.h>
|
|||
|
#include <linux/delay.h>
|
|||
|
#include <linux/ide.h>
|
|||
|
#include <linux/init.h>
|
|||
|
#include <linux/module.h>
|
|||
|
#include <linux/errno.h>
|
|||
|
#include <linux/gpio.h>
|
|||
|
#include <linux/cdev.h>
|
|||
|
#include <linux/device.h>
|
|||
|
#include <asm/mach/map.h>
|
|||
|
#include <asm/uaccess.h>
|
|||
|
#include <asm/io.h>
|
|||
|
|
|||
|
/* newchrled设备结构体 */
|
|||
|
struct newchrled_dev{
|
|||
|
dev_t devid; /* 设备号 */
|
|||
|
struct cdev cdev; /* cdev */
|
|||
|
struct class *class; /* 类 */
|
|||
|
struct device *device; /* 设备 */
|
|||
|
int major; /* 主设备号 */
|
|||
|
int minor; /* 次设备号 */
|
|||
|
};
|
|||
|
|
|||
|
struct newchrled_dev newchrled; /* led设备 */
|
|||
|
|
|||
|
static int led_open(struct inode *inode, struct file *filp)
|
|||
|
{
|
|||
|
filp->private_data = &newchrled; /* 设置私有数据 */
|
|||
|
return 0;
|
|||
|
}
|
|||
|
|
|||
|
static ssize_t led_read(struct file *filp, char __user *buf, size_t cnt, loff_t *offt)
|
|||
|
{
|
|||
|
return 0;
|
|||
|
}
|
|||
|
|
|||
|
static ssize_t led_write(struct file *filp, const char __user *buf, size_t cnt, loff_t *offt)
|
|||
|
{
|
|||
|
return 0;
|
|||
|
}
|
|||
|
|
|||
|
static int led_release(struct inode *inode, struct file *filp)
|
|||
|
{
|
|||
|
return 0;
|
|||
|
}
|
|||
|
|
|||
|
/* 设备操作函数 */
|
|||
|
static struct file_operations newchrled_fops = {
|
|||
|
.owner = THIS_MODULE,
|
|||
|
.open = led_open,
|
|||
|
.read = led_read,
|
|||
|
.write = led_write,
|
|||
|
.release = led_release,
|
|||
|
};
|
|||
|
|
|||
|
static int __init led_init(void)
|
|||
|
{
|
|||
|
if (newchrled.major) { /* 定义了设备号 */
|
|||
|
newchrled.devid = MKDEV(newchrled.major, 0);
|
|||
|
register_chrdev_region(newchrled.devid, NEWCHRLED_CNT, NEWCHRLED_NAME);
|
|||
|
} else { /* 没有定义设备号 */
|
|||
|
alloc_chrdev_region(&newchrled.devid, 0, NEWCHRLED_CNT, NEWCHRLED_NAME); /* 申请设备号 */
|
|||
|
newchrled.major = MAJOR(newchrled.devid); /* 获取分配号的主设备号 */
|
|||
|
newchrled.minor = MINOR(newchrled.devid); /* 获取分配号的次设备号 */
|
|||
|
}
|
|||
|
newchrled.cdev.owner = THIS_MODULE;
|
|||
|
cdev_init(&newchrled.cdev, &newchrled_fops);
|
|||
|
cdev_add(&newchrled.cdev, newchrled.devid, NEWCHRLED_CNT);
|
|||
|
newchrled.class = class_create(THIS_MODULE, NEWCHRLED_NAME);
|
|||
|
newchrled.device = device_create(newchrled.class, NULL, newchrled.devid, NULL, NEWCHRLED_NAME);
|
|||
|
|
|||
|
return 0;
|
|||
|
}
|
|||
|
|
|||
|
static void __exit led_exit(void)
|
|||
|
{
|
|||
|
cdev_del(&newchrled.cdev);/* 删除cdev */
|
|||
|
unregister_chrdev_region(newchrled.devid, NEWCHRLED_CNT); /* 注销设备号 */
|
|||
|
device_destroy(newchrled.class, newchrled.devid);
|
|||
|
class_destroy(newchrled.class);
|
|||
|
}
|
|||
|
|
|||
|
module_init(led_init);
|
|||
|
module_exit(led_exit);
|
|||
|
MODULE_LICENSE("GPL");
|
|||
|
MODULE_AUTHOR("zuozhongkai");
|
|||
|
```
|
|||
|
#### platform驱动
|
|||
|
```
|
|||
|
#include <linux/types.h>
|
|||
|
#include <linux/kernel.h>
|
|||
|
#include <linux/delay.h>
|
|||
|
#include <linux/ide.h>
|
|||
|
#include <linux/init.h>
|
|||
|
#include <linux/module.h>
|
|||
|
#include <linux/errno.h>
|
|||
|
#include <linux/gpio.h>
|
|||
|
#include <linux/cdev.h>
|
|||
|
#include <linux/device.h>
|
|||
|
#include <linux/of_gpio.h>
|
|||
|
#include <linux/semaphore.h>
|
|||
|
#include <linux/timer.h>
|
|||
|
#include <linux/irq.h>
|
|||
|
#include <linux/wait.h>
|
|||
|
#include <linux/poll.h>
|
|||
|
#include <linux/fs.h>
|
|||
|
#include <linux/fcntl.h>
|
|||
|
#include <linux/platform_device.h>
|
|||
|
#include <asm/mach/map.h>
|
|||
|
#include <asm/uaccess.h>
|
|||
|
#include <asm/io.h>
|
|||
|
|
|||
|
struct leddev_dev{
|
|||
|
dev_t devid; /* 设备号 */
|
|||
|
struct cdev cdev; /* cdev */
|
|||
|
struct class *class; /* 类 */
|
|||
|
struct device *device; /* 设备 */
|
|||
|
int major; /* 主设备号 */
|
|||
|
};
|
|||
|
|
|||
|
struct leddev_dev leddev; /* led设备 */
|
|||
|
|
|||
|
static int led_open(struct inode *inode, struct file *filp)
|
|||
|
{
|
|||
|
filp->private_data = &leddev; /* 设置私有数据 */
|
|||
|
return 0;
|
|||
|
}
|
|||
|
|
|||
|
static ssize_t led_write(struct file *filp, const char __user *buf, size_t cnt, loff_t *offt)
|
|||
|
{
|
|||
|
return 0;
|
|||
|
}
|
|||
|
|
|||
|
static struct file_operations led_fops = {
|
|||
|
.owner = THIS_MODULE,
|
|||
|
.open = led_open,
|
|||
|
.write = led_write,
|
|||
|
};
|
|||
|
|
|||
|
static int led_probe(struct platform_device *dev)
|
|||
|
{
|
|||
|
if (leddev.major) { /* 定义了设备号 */
|
|||
|
leddev.devid = MKDEV(leddev.major, 0);
|
|||
|
register_chrdev_region(leddev.devid, LEDDEV_CNT, LEDDEV_NAME);
|
|||
|
} else { /* 没有定义设备号 */
|
|||
|
alloc_chrdev_region(&leddev.devid, 0, LEDDEV_CNT, LEDDEV_NAME); /* 申请设备号 */
|
|||
|
leddev.major = MAJOR(leddev.devid); /* 获取分配号的主设备号 */
|
|||
|
}
|
|||
|
leddev.cdev.owner = THIS_MODULE;
|
|||
|
cdev_init(&leddev.cdev, &led_fops);
|
|||
|
cdev_add(&leddev.cdev, leddev.devid, LEDDEV_CNT);
|
|||
|
leddev.class = class_create(THIS_MODULE, LEDDEV_NAME);
|
|||
|
leddev.device = device_create(leddev.class, NULL, leddev.devid, NULL, LEDDEV_NAME);
|
|||
|
return 0;
|
|||
|
}
|
|||
|
|
|||
|
static int led_remove(struct platform_device *dev)
|
|||
|
{
|
|||
|
cdev_del(&leddev.cdev);/* 删除cdev */
|
|||
|
unregister_chrdev_region(leddev.devid, LEDDEV_CNT); /* 注销设备号 */
|
|||
|
device_destroy(leddev.class, leddev.devid);
|
|||
|
class_destroy(leddev.class);
|
|||
|
return 0;
|
|||
|
}
|
|||
|
|
|||
|
static struct platform_driver led_driver = {
|
|||
|
.driver = {
|
|||
|
.name = "imx6ul-led", /* 驱动名字,用于和设备匹配 */
|
|||
|
},
|
|||
|
.probe = led_probe,
|
|||
|
.remove = led_remove,
|
|||
|
};
|
|||
|
|
|||
|
static int __init leddriver_init(void)
|
|||
|
{
|
|||
|
return platform_driver_register(&led_driver);
|
|||
|
}
|
|||
|
|
|||
|
static void __exit leddriver_exit(void)
|
|||
|
{
|
|||
|
platform_driver_unregister(&led_driver);
|
|||
|
}
|
|||
|
|
|||
|
module_init(leddriver_init);
|
|||
|
module_exit(leddriver_exit);
|
|||
|
MODULE_LICENSE("GPL");
|
|||
|
MODULE_AUTHOR("zuozhongkai");
|
|||
|
|
|||
|
```
|
|||
|
#### dts的platform驱动
|
|||
|
```
|
|||
|
#include <linux/types.h>
|
|||
|
#include <linux/kernel.h>
|
|||
|
#include <linux/delay.h>
|
|||
|
#include <linux/ide.h>
|
|||
|
#include <linux/init.h>
|
|||
|
#include <linux/module.h>
|
|||
|
#include <linux/errno.h>
|
|||
|
#include <linux/gpio.h>
|
|||
|
#include <linux/cdev.h>
|
|||
|
#include <linux/device.h>
|
|||
|
#include <linux/of_gpio.h>
|
|||
|
#include <linux/semaphore.h>
|
|||
|
#include <linux/timer.h>
|
|||
|
#include <linux/irq.h>
|
|||
|
#include <linux/wait.h>
|
|||
|
#include <linux/poll.h>
|
|||
|
#include <linux/fs.h>
|
|||
|
#include <linux/fcntl.h>
|
|||
|
#include <linux/platform_device.h>
|
|||
|
#include <asm/mach/map.h>
|
|||
|
#include <asm/uaccess.h>
|
|||
|
#include <asm/io.h>
|
|||
|
|
|||
|
struct leddev_dev{
|
|||
|
dev_t devid; /* 设备号 */
|
|||
|
struct cdev cdev; /* cdev */
|
|||
|
struct class *class; /* 类 */
|
|||
|
struct device *device; /* 设备 */
|
|||
|
int major; /* 主设备号 */
|
|||
|
struct device_node *node; /* LED设备节点 */
|
|||
|
int led0; /* LED灯GPIO标号 */
|
|||
|
};
|
|||
|
|
|||
|
struct leddev_dev leddev; /* led设备 */
|
|||
|
|
|||
|
static int led_open(struct inode *inode, struct file *filp)
|
|||
|
{
|
|||
|
filp->private_data = &leddev; /* 设置私有数据 */
|
|||
|
return 0;
|
|||
|
}
|
|||
|
|
|||
|
static struct file_operations led_fops = {
|
|||
|
.owner = THIS_MODULE,
|
|||
|
.open = led_open,
|
|||
|
.write = led_write,
|
|||
|
};
|
|||
|
|
|||
|
static int led_probe(struct platform_device *dev)
|
|||
|
{
|
|||
|
if (leddev.major) {
|
|||
|
leddev.devid = MKDEV(leddev.major, 0);
|
|||
|
register_chrdev_region(leddev.devid, LEDDEV_CNT, LEDDEV_NAME);
|
|||
|
} else {
|
|||
|
alloc_chrdev_region(&leddev.devid, 0, LEDDEV_CNT, LEDDEV_NAME);
|
|||
|
leddev.major = MAJOR(leddev.devid);
|
|||
|
}
|
|||
|
cdev_init(&leddev.cdev, &led_fops);
|
|||
|
cdev_add(&leddev.cdev, leddev.devid, LEDDEV_CNT);
|
|||
|
leddev.class = class_create(THIS_MODULE, LEDDEV_NAME);
|
|||
|
leddev.device = device_create(leddev.class, NULL, leddev.devid, NULL, LEDDEV_NAME);
|
|||
|
leddev.node = of_find_node_by_path("/gpioled");
|
|||
|
of_get_named_gpio(leddev.node, "led-gpio", 0);
|
|||
|
return 0;
|
|||
|
}
|
|||
|
|
|||
|
static int led_remove(struct platform_device *dev)
|
|||
|
{
|
|||
|
cdev_del(&leddev.cdev); /* 删除cdev */
|
|||
|
unregister_chrdev_region(leddev.devid, LEDDEV_CNT); /* 注销设备号 */
|
|||
|
device_destroy(leddev.class, leddev.devid);
|
|||
|
class_destroy(leddev.class);
|
|||
|
return 0;
|
|||
|
}
|
|||
|
|
|||
|
static const struct of_device_id led_of_match[] = {
|
|||
|
{ .compatible = "atkalpha-gpioled" },
|
|||
|
{ /* Sentinel */ }
|
|||
|
};
|
|||
|
|
|||
|
static struct platform_driver led_driver = {
|
|||
|
.driver = {
|
|||
|
.name = "imx6ul-led", /* 驱动名字,用于和设备匹配 */
|
|||
|
.of_match_table = led_of_match, /* 设备树匹配表 */
|
|||
|
},
|
|||
|
.probe = led_probe,
|
|||
|
.remove = led_remove,
|
|||
|
};
|
|||
|
|
|||
|
static int __init leddriver_init(void)
|
|||
|
{
|
|||
|
return platform_driver_register(&led_driver);
|
|||
|
}
|
|||
|
|
|||
|
static void __exit leddriver_exit(void)
|
|||
|
{
|
|||
|
platform_driver_unregister(&led_driver);
|
|||
|
}
|
|||
|
|
|||
|
module_init(leddriver_init);
|
|||
|
module_exit(leddriver_exit);
|
|||
|
MODULE_LICENSE("GPL");
|
|||
|
MODULE_AUTHOR("zuozhongkai");
|
|||
|
```
|
|||
|
|
|||
|
## 驱动程序注册重要函数
|
|||
|
|
|||
|
|
|||
|
## 设备树
|
|||
|
1. 设备树的作用:描述板级信息
|
|||
|
2. 设备树路径一般在arch目录下 例如:kernel_t41/kernel-4.4.94/arch/mips/boot/dts/ingenic
|
|||
|
|
|||
|
# 系统
|
|||
|
|
|||
|
## kernel、rootfs 和 uboot之间的关系
|
|||
|
|
|||
|
1. U-Boot 是引导加载程序,主要完成系统的初期引导工作。它会进行硬件初始化,然后从Flash、SD卡等外部存储中加载 Linux Kernel。
|
|||
|
2. Linux Kernel 是系统的内核,提供操作系统的核心功能。U-Boot会把内核映像加载到 RAM 中,并转交给内核控制权。
|
|||
|
3. Rootfs 是 root 文件系统,包含了 Linux 系统启动后需要的库、工具等文件。U-Boot同样会把 rootfs 从存储中加载到 RAM,以供内核挂载。
|
|||
|
4. 内核初始化完成后,会挂载 rootfs 为根文件系统,然后根据 rootfs 中的配置来启动系统服务,最终完成整个系统的启动。
|
|||
|
5. U-Boot主要在系统加电时执行,完成引导工作。内核和 rootfs 在系统运行时提供操作系统环境。
|
|||
|
6. U-Boot、内核和 rootfs 三者相互配合,将硬件系统引导起来,构成完整的 Linux 发行版。
|
|||
|
7. 开发时,会分别编译这三个组件,然后打包到存储介质中,实现可引导的嵌入式系统。
|
|||
|
所以 U-Boot、Kernel 和 Rootfs 在嵌入式系统中有明确的分工,相互配合实现从系统加电到启动完成的整个过程。
|
|||
|
|
|||
|
### uboot代码结构
|
|||
|
1. 启动代码(arch/arm/lib/crt0.S等):实现CPU和板级初始化,构建执行环境。
|
|||
|
2. 架构代码(arch/arm/):针对ARM等不同架构的底层支持代码。
|
|||
|
3. 公共库(lib/):提供字符串、内存相关的库函数。
|
|||
|
4. 驱动模型(drivers/):各种设备驱动,如串口、Ethernet、Flash等。
|
|||
|
5. 通用命令(cmd/):U-Boot命令行实现。
|
|||
|
6. 网络功能(net/):网络协议栈,如TFTP。
|
|||
|
7. 文件系统(fs/):文件系统驱动,如FAT。
|
|||
|
8. 加载Image(image/):镜像分析和加载。
|
|||
|
9. 板级支持(board/):针对特定开发板的定制代码。
|
|||
|
10. 通用核心(common/):初始化参数,环境变量,内存分配等。
|
|||
|
11. 入口点(main.c):主程序入口和命令行解析。
|
|||
|
|
|||
|
### uboot
|
|||
|
1. uboot作用启动内核,设置一些环境变量
|
|||
|
2. uboot添加命令#define U_BOOT_CMD(_name, _maxargs, _rep, _cmd, _usage, _help)
|
|||
|
3. uboot基本命令
|
|||
|
>- reset:重新启动嵌入式系统。
|
|||
|
>- printenv:打印当前环境变量。
|
|||
|
>- setenv:设置环境变量,格式:setenv name value。
|
|||
|
>- saveenv:保存环境变量到nand中。
|
|||
|
>- sleep:延迟执行,格式:sleep N,可以延迟N秒钟执行。
|
|||
|
>- bootm:可以引导启动存储在内存中的程序映像。
|
|||
|
>- nand erase:擦除NAND,格式:nand erase addr1 count。
|
|||
|
>- nand write:下载的内存数据写入NAND,格式:nand write addr offset count。
|
|||
|
>- sf0 probe
|
|||
|
>- sf0 erase
|
|||
|
>- sf0 write
|
|||
|
4. uboot加载内核
|
|||
|
5. uboot的重要配置文件,默认配置在路径uboot/configs下,板级头文件在uboot/include/configs下
|
|||
|
头文件由CONFIG_SYS_CONFIG_NAME宏配置。文件也可能没有默认配置文件,只需要头文件。
|
|||
|
6. uboot的nand的擦除,写入,读取命令在uboot/drivers/mtd/nand下实现
|