驱动开发

确定主设备号 定义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

异常与中断的概念以及处理流程