i.MX6驱动开发学习日志
Day 1 【了解常识】
基本概念了解
环境熟悉
1.1 MCIMX6U8DVM10AB 芯片概述
- 32位MPU
- 双核ARM - Cortex-A9
- 1GHz主频
- 芯片命名方式:
1.2 关于Linux内核的一些基础概念
-
eMMC: embedded Multi Media Card,嵌入式存储器标准规格
-
gzip压缩: Linux常见压缩工具,压缩为*.gz格式文件
-
常见内核文件:
- vmlinux: 编译出来的原始内核文件
- zImage: 经过gzip压缩的vmlinux
- bzImage: big zImage,内核较大需要用bzImage,占用内存1M以上
- uImage: U-boot专用映像文件
- vmlinuz: zImage/bzImage的拷贝或链接
- initrd: initial ramdisk,引导硬件可被实际内核vmlinuz接管
-
内核源码结构:
- arch: 硬件架构
- block: 块设备驱动程序I/O调度
- crypto: 常用加密、散列、压缩、校验算法
- crypto-【英文前缀】保密的
- crypto-community,地下党
- cryptography,密码学
- Documentation: 内核各部分的注释
- drivers: 设备驱动程序
- fs: file system,文件系统
- include: 头文件
- init: 内核初始化代码
- ipc: 进程间通信代码
- kernel: 内核核心部分,包括进程调度、定时器
- lib: 库文件
- mm: memory manage,内存管理
- net: 网络代码
- scripts: 用于配置内核的脚本
- security: SELinux模块
- sound: 音频设备驱动代码
- usr: 用于打包和压缩的cpio
- cpio: copy input output,用来建立、还原备份档的工具程序
-
内核组成部分:
- 进程调度 - SCHED
- 内存管理 - MM
- 虚拟文件系统 - VFS
- 网络接口 - NET
- 进程间通信 - IPC
1.3 Linux嵌入式开发基本概念
- 单片机简单的操作系统:
- UCOS,FreeRTOS
- 只具备Kernel
- 网络、文件系统、GUI等需要移植
- 可移植操作系统的嵌入式开发:
- 底层驱动开发:
- 裸机开发:
- 不具备IDE - 安装交叉编译环境
- Linux操作系统开发:
- 系统移植:
- 移植Uboot(一种bootloader代码,用于启动Linux内核)
- 移植Linux内核
- 移植根文件系统(rootfs),包含常用命令和文件
- 系统移植:
- 裸机开发:
- 底层驱动开发:
-
-
-
- 三大驱动:
- 字符设备驱动
- 块设备驱动
- 网络设备驱动
- 三大驱动:
-
- 应用开发
(待)
-
1.4 关于交叉编译器
- Ubuntu 自带的gcc编译器是针对x86架构的
- 在x86架构的PC上安装的、可以编译ARM架构代码的、GCC编译器 - 交叉编译器
1.5 MfgTool系统烧入工具
-
运行在Windows下
-
可烧写uboot.imx,zImage,dtb,rootfs
-
问题1: litialize operation failed, please refer to “MfgTool.log” for detailed information, error code: 4.
-
- 我出现这个问题的原因是我将mfgtools解压在移动硬盘里,可能系统需要获取管理员权限才能执行脚本,将mfgtools文件夹改到其他硬盘里问题就解决了
-
问题2: Unassigned
尚未解决
1.6 Linux 文件系统
- 文件系统:
- 将二进制数据翻译为人类语言的文件格式
- 不同的物理结构需要不同的文件系统管理
Day 2 【熟悉环境】
Xshell通信
代码编译与运行
点灯
2.1 查看原理图
- 点灯用的是开发板P8的4个引脚
2.2 设备树文件
- 设备树文件 imx6qdl-sabresd.dtsi
- 路径
/home/uptech/fsl-6dl-source/kernel-3.14.28/arch/arm/boot/dts/imx6qdl-sabresd.dtsi
- 路径
2.3 运行代码
- i.MX6 开发板
-
内部有之前编译好的执行文件和驱动,可以直接使用
-
若没有,可以通过NFS共享将Ubuntu虚拟机的
/imx6
文件夹挂载到开发板的/mnt
目录下
-
在Xshell里对开发板运行指令
-
用网线接好开发板与电脑,确保主机、虚拟机、开发板处于同一网段下
-
通过Xshell使用命令
ifconfig eth0 192.168.1.130
可改变开发板的地址 -
通过Xshell使用命令
mount -t nfs 192.168.1.120:/imx6 /mnt/
可将虚拟机下的 /imx6 文件夹 挂载到开发板的 /mnt/ 文件夹 下
-
-
insmod ./driver/LEDBuzzer.ko
加载驱动 -
./LEDBuzzer
运行执行文件,效果:
-
Day 3 【裸机开发了解】
Cortex-A7 MPCore架构(Multi-Processor)
关于IO和GPIO
启动方式
3.1 Cortex-A处理器运行模式(9种)
模式 | 描述 |
---|---|
USR | 用户模式,大部分程序运行模式,【非特权模式】 |
FIQ | Fast Interrupt rQuest, 快速中断模式 |
IRQ | Interrupt ReQuest,一般中断模式 |
SVC | SupVisor, 超级管理员模式,操作系统使用 |
MON | MONitor, 监视模式,用于安全拓展模式 |
ABT | ABorT,数据访问终止模式,用于虚拟存储、存储保护 |
HYP | HPYe-supervisor, 超级监视,用于虚拟化拓展r |
UNDef | 未定义指令终止模式 |
SYStem | 系统模式 |
3.2 关于 I/O
-
IOMUX Controller,IO复用控制
-
32位软件复用控制寄存器,32-bit software mux control registers
-
IO命名: IOMUXC_SW_MUC_CTL_PAD_XX_XX, XX_XX为IO口功能,例如UART1_TX_DATA
-
IO复用功能查询:
IMX6SDLRM.pdf
手册Charpter4 - External Signals and Pin Multiplexing
-
IO和GPIO的差别:
- IO是宏观的
- GPIO是IO的一种工作方式,比如说点亮LED、按键输入等操作
-
IO参数配置:
-
两个寄存器:
- IOMUXC_SW_MUX_CTL_PAD_XX_XX,配置复用功能
- IOMUXC_SW_PAD_CTL_PAD_XX_XX,配置IO参数:
- HYS: Hysteresis comparator,施密特触发器使能,施密特触发器的迟滞现象
- PUS: Pull Up/down Set,上下拉电阻
- PUE: Pull Up/down Enable,上下拉/状态保持器
- PKE: 使能/失能上下拉/状态保持器
- ODE: 使能/使能IO开路输出
- SPEED: IO速度
- DSE: IO驱动能力
- SRE: Slew Rate,压摆率
-
IO口功能配置:
-
-
GPIO时钟使能
- 时钟系统
Clock Control Module(CCM)
- 门控寄存器 - CCM Clock Gating Register
- CCM_CCGRx [0, 6]
- 时钟系统
-
GPIO使能方式:
- 使能时钟
- 设置复用功能
- 设置IO参数
- 配置GPIO参数
3.3 启动方式
BOOT_MODE | 描述 |
---|---|
00 | FUSE启动 |
01 | 串行下载 |
10 | 内部BOOT模式 |
11 | 保留 |
Day 4 字符设备
ARM Linux驱动开发概述
字符设备驱动简介
字符设备驱动开发
4.1 ARM Linux驱动开发概述
- 三大类驱动:`
- 字符设备驱动:
- GPIO
- I2C
- SPI 等
- 块设备驱动:
- 存储器设备的驱动
- EMMC
- NAND
- SD
- U盘等
- 网络设备驱动:
- USB WIFI
- 字符设备驱动:
4.2 字符设备驱动简介
-
字符设备:
- 通过字节流进行读写操作的设备
-
Linux的应用程序如何调用驱动程序:
-
Linux一切皆文件,驱动操作文件位于
/dev/device_name
-
应用程序运行在用户空间,驱动属于内核空间,用户必须系统调用才能调用内核空间实现对底层驱动的操作
- 应用程序使用的函数,在具体驱动中都有与之对应的函数
- 应用程序调用open,驱动程序也要有open
- 内核驱动操作函数集合
include/linux/fs.h: struct file_operations
- 应用程序使用的函数,在具体驱动中都有与之对应的函数
-
常用内核驱动操作函数
操作函数 | 函数功能 |
---|---|
owner | 该结构体的指针 |
llseek | 修改文件当前读写位置 |
read | 读取设备文件 |
write | 向设备文件写入数据 |
poll | 查询设备是否可以进行非阻塞读写 |
unlocked_ioctl | 提供对设备的控制功能,与应用程序ioctl 对应 |
mmap | 将设备的内存映射到进程空间(用户空间),帧缓冲设备会使用此函数,例如LCD显存 |
open | 打开设备文件 |
release | 释放(关闭)设备文件,与应用程序close 对应 |
fasvnc | 刷新待处理的数据,将缓冲区数据刷新到磁盘中 |
aio_fsync | 异步刷新待处理的数据 |
4.3 字符设备驱动开发
- 加载和卸载:
- Linux驱动两种运行方式:
- 编译进内核,开机自启
- 编译成模块(
.ko
文件),insmod xxx.ko
加载模块,调试阶段使用
- 模块加载
module_init(xxxx_init)
insmod
时调用xxxx_init
- 模块卸载
module_exit(xxxx_exit)
rmmod
时调用xxxx_exit
- 模块加载
- Linux驱动两种运行方式:
// 字符设备驱动模块加载和卸载函数模板
/* 驱动入口函数 */
static int __init xxx_init(void){
return 0;
}
/* 驱动出口函数 */
static void __exit xxx_exit(void){
}
/* 将上面两个函数指定为驱动的入口和出口函数 */
module_init(xxx_init);
module_exit(xxx_exit);
-
insmod 与 modprobe 指令比较
insmod
- 简单
- 但不能决定模块的依赖关系
- dvc_1.ko 依赖于 dvc_2.ko
- 先
insmod dvc_2.ko
- 再
insmod dvc_1.ko
- 先
- 卸载驱动
insmod dvc_1.ko
modprobe
- 智能化加载驱动
- 卸载驱动
modprove -r dvc_1.ko
- 会卸载掉驱动的依赖
- 需要防止依赖项有多个驱动在使用
-
字符设备注册与注销
- 注册字符设备:
cat/proc/devices
查看已注册的设备号,不可重复register_chrdev(_*_)
,参数:
- 主设备号
- 设备名称
- 操作函数合集结构体的拷贝
- 注册字符设备:
// 字符设备注册和注销
// 操作函数集合结构体变量 test_fops
// 尚未定义open release等成员函数
static struct file_operations test_fops;
/* 驱动入口函数 */
static int __init xxx_init(void){
int retvalue = 0;
// 注册字符设备驱动
// 主设备号200
// 设备名称 chrtest
// 结构体拷贝 &test_fops
retvalue = register_chrdev(200, "chrtest", &test_fops);
if(retvalue < 0){
// 字符设备注册失败,自行处理
}
return 0;
}
/* 驱动出口函数 */
static void __exit xxx_exit(void){
// 注销字符设备驱动
unregister_chrdev(200, "chrtest");
}
/* 将上面两个函数指定为驱动的入口和出口函数 */
module_init(xxx_init);
module_exit(xxx_exit);
-
设备具体操作函数
-
设备打开
chrtest_open()
/* 打开设备 */
static int chrtest_open(struct inode *inode, struct file *filp){
return 0;
}
- 从设备读取
chrtest_read()
/* 从设备读取 */
static ssize_t chrtest_read(struct file *filp, char __user *buf,
size_t cnt, loff_t *offt){
return 0;
}
- 向设备写数据
chrtest_write()
/* 向设备写数据 */
static ssize_t chrtest_write(struct file *filp,
const char __user *buf,
size_t cnt, loff_t *offt){
return 0;
}
- 释放设备
chrtest_release()
/* 关闭 /释放设备 */
static int chrtest_release(struct inode *inode, struct file *filp){
return 0;
}
- 用以上定义好的函数来初始化结构体
struct file_operations test_fops
static struct file_operations test_fops = {
.owner = THIS_MODULE,
.open = chrtest_open,
.read = chrtest_read,
.write = chrtest_write,
.release = chrtest_release,
};
- 驱动入口
xxx_init()
/* 驱动入口函数 */
static int __init xxx_init(void){
int retvalue = 0;
/* 注册字符设备驱动 */
retvalue = register_chrdev(200, "chrtest", &test_fops);
if(retvalue < 0){
/* 字符设备注册失败,自行处理 */
}
return 0;
}
- 驱动出口
xxx_exit()
/* 驱动出口函数 */
static void __exit xxx_exit(void){
/* 注销字符设备驱动 */
unregister_chrdev(200, "chrtest");
}
- 入口/出口指定
module_init(xxx_init);
module_exit(xxx_exit);
- 添加LICENSE(必须加)
// LICENSE 采用GPL协议
MODULE_LICENSE('GPL');
// 作者 不必须加
MODULE_AUTHOR('***');
- Linux设备号
- 主设备号
- 具体的驱动
12 位
0 - 4095
- 次设备号
- 驱动的各个设备
20位
- 定义位置
include/linux/types.h
- 分配方式
- 静态分配
cat/proc/devices
查看已分配的设备号
- 动态分配
int alloc_chrdev_region(dev_t _dev, unsigned baseminor, unsigned count, const char _name)
dev
保存32位设备号baseminor
alloc_chrdev_region可申请一段连续的,主设备号相同,次设备号不同的设备,此变量设置次设备号起始地址,一般为0count
要申请的设备号数量name
设备名称from
要释放的设备号count
从from开始,释放的设备号数量
- 静态分配
- 主设备号
Day 5 设备树
.dts
: 描述板级信息,开发板有哪些设备.dtsi
:描述SOC级信息,有几个CPU,主频、控制器信息DTB
:编译后的DTSDTC
:DTS编译器
评论(0)
您还未登录,请登录后发表或查看评论