Linux驱动开发基础知识
驱动开发
确定主设备号 定义file_operations结构体 实现对应的open/read/write函数
在内核里注册程序register_chrdev 入口函数 出口函数 提供设备信息、自动创建设备节点(module_init、module_exit) MODULE_LICENSE(“GPL”)必须遵守GPL协议
chrdevs类似数组,其实不是数组
misc内核经典 字符驱动程序
copy_from_user函数copy数据至内核、用户空间
init中注册驱动、创建class、创建device
insmod 开发板上装驱动程序。驱动程序是xxx.ko
lsmod 查看已经装载的驱动程序
rmmod 卸载驱动程序
dmeg查看内核打印的东西 printk内核打印 printf是app打印的
普通GPIO操作方法
使能GPIO模块
设置引脚模式选择
方向设置
设置数据
读写寄存器,不要影响其他位 所以要先读出来,设置后再写回去。如果直接写入,会影响其他位
imx6uL GPIO操作方法
CCM(18章):时钟控制单元 使能端口
设计IOMUXC(32章) io控制器 mux control pad setting
设置DR GDIR PSR 5组GPIO
loopback 回环模式
LED操作方法
LED驱动程序
file operations register_chrdev
入口函数
出口函数
class_creat
drive_creat
ioremap虚拟映射后才能访问底层驱动
先写框架
volatile 禁止优化变量
先设置虚拟地址,再映射到实际地址。不能够直接访问实际地址,ioremap函数
*a 取值 int* a
就是指针
strcmp
dmesg|grep xxx
打开内核打印信息 echo “7 4 1 7” > /proc/sys/kernel/printk
LED驱动程序框架
驱动程序分层
app层
driver led_open led_write
#ifndef 防止多次定义同一个宏
先写框架,再写代码
需要映射到虚拟地址才能使用ioremap
MMU 内存管理功能、权限保护功能
static volatile unsigned
驱动程序思想:面向对象(用结构体表现某一对象)、分层、分离
分离:资源、硬件通用代码
优化写法
linux驱动 = 驱动框架 +硬件操作
主要在驱动框架的阅读上
platform_drive结构体
dts(设备树) -> dtb(二进制)
分配、设置、注册结构体 bus
设备树:只是配置信息而已
bus连通 dev、drv
比较driver_override和platform_driver的driver
记录、创建
export_symbol导出函数
设备树的引入 DTS
/f 根节点
xxx{
} xxx节点
chosen 虚拟节点
#address_cells、#size_cells 数据大小
compatible 兼容xxx驱动,寻找对应的driver的
model 具体是哪个驱动
status 使能
编译设备树文件 make dtbs V=1
按空格进入bootloard fdtfile
启动后查看设备树
内核处理设备树
compatile属性
device_node 在根节点里
设备树实践 设备树(资源)和驱动分离
修改dtb文件
APP读取按键值。 中断、休眠、唤醒、poll
按键驱动程序
面向对象 file_operations register_chrdev 入口 出口unregister
驱动在open除了配置pin外,还会注册中断服务程序 按键 触发中断
poll:有数据,直接返回。无数据,休眠一段时间(类似定时中断)
异步通知(外部中断):发SIGIO信号 谁发? 发什么? 发给谁? 怎么处理? 一定要有这四步
GPIO和Pinctrl子系统使用:
IOMUX配置pin为不同功能
IOMUX(Pinctrl)Pinctrl软件概念,起引脚复用、配置作用(BSP工程师写的)驱动工程师用就行。 client客户
generic pin multiplexing node Pinctrl中可以配置程某个功能或者复用状态,没有通用格式。但是概念是通用的
GPIO子系统概念
static
主设备号、次设备号
设备树里重复指定GPIO 原因: pinctrol-gpio写好,顺序约定好 直接用princtrol就行。为了避免pinctrol没写好,因此重复指定GPIO
异常与中断的概念以及处理流程