驱动第三周

📅 发布时间:2026/8/15 11:07:22
驱动第三周 一.iio子系统IIOIndustrial I/O是 Linux 内核中专门用于模数转换器ADC、数模转换器DAC以及各类传感器加速度计、陀螺仪、温度、光照等的子系统。ADC底板硬件原理图在核心板上搜索XadcAIN3得可知我们使用的是adc的通道三内核源码的exynos-adc.c代码中查阅芯片手册可得基地址为0x126C_0000最大偏移 0x001C 4字节 0x0020 → 总大小 0x20 (32字节)基地址0x1002_0000 偏移量0x0718 大小0x1只有ADC_PHY_CONTROL使能之后才可以通过在系统寄存器 SFR 中设置 ADC_CFG[16] 位来选择其中一个 ADC 模块。获取中断ADC的中断的父设备为combiner通过查找可得ADC中断需要的2个32位数字表示第一个为组号第二个组内的中断号通过芯片手册可以得到获取时钟在通过查找在未使用vdd-supply属性时,驱动和设备正常匹配且adc正常输出.并且出现supply vdd的提示信息,并提示使用dummy regulator通过查阅芯片原理图可得1.8V由3.3V压降得来发现pmic管理的电源中并没有VDD1V8_EXT,得到pmic未对VDD1V8_EXT进行管理所以vdd-supply属性可写也可不写如果编写就需要在regulator子系统下创建节点再来编写我们adc的设备树节点在这里填充 了indio_dev 字段并将注册到 IIO 。上层调用read_raw函数就会回调到exynos_read_raw函数参数含义indio_devIIO 设备通过iio_priv()可取出私有数据infochan当前被读取的通道chan-address存的是通道编号0~7val输出参数存放读到的整数值val2输出参数存放小数部分本驱动不用只用整数mask请求的信息类型IIO_CHAN_INFO_RAW表示读原始值只读原始数据并加锁mlock是 IIO 框架内建的互斥锁。ADC 是共享资源多个进程可能同时cat in_voltageX_raw。进程A: 选择通道3 → 启动转换 → 等待中断...进程B: 选择通道5 → 启动转换 ← 如果没锁通道选择会互相覆盖在这里等待中断并解锁。实验现象二.i2c子系统1.底层为芯片厂家提供的IIC控制器驱动负责直接控制IIC总线硬件但不同厂家的控制器驱动接口不统一且无法预知要对接的IIC从设备信息。2.中间层为IIC核心层i2c_core承上启下制定统一标准要求底层控制器驱动按标准实现接口要求上层从设备驱动按标准调用接口提供统一的i2c_transfer通信接口屏蔽底层控制器差异上层无需关心底层具体是哪款控制器。3.上层为IIC从设备驱动只需将要操作的从设备信息通过i2c_transfer传递给核心层由核心层调用对应控制器驱动完成通信从设备驱动还可向应用层提供操作接口。硬件信息通过查阅芯片手册可得芯片从地址0x68再查阅芯片厂商写的I2C_5设备树我们需要修改status状态。怎么确定我们status是否为okay呢就可以查看当前设备树信息查看报错对比i2c13860000和i2c138B0000可以看到缺乏的设备树属性。这样我们就可以写自己的设备树节点了重要的结构体查看通讯时序实验现象列出注册了哪些控制器扫描I2C 总线看看有哪些设备响应。三.并发与竞态并发通过算法将CPU使用权合理分配给多个任务并行多核处理器的每个核心都可以独立执行任务竞态并发可能造成多个程序同时访问一个共享资源同时访问一个共享资源产生的问题就是竞争。1.互斥锁互斥锁 Mutual Exclusion Lock 是多线程编程中用于保护共享资源的一种机制确保同一时间只有一个线程进 入临界区 访问临界资源。它是阻塞的。void mutex_init(struct mutex *lock)初始化互斥锁void mutex_lock(struct mutex *lock)获取锁void mutex_unlock(struct mutex *lock)解锁2.自旋锁自旋锁 spin lock 也是为了保护共享资源的一种锁机制 是一种非阻塞锁如果线程获取自旋锁但锁已经被其他线程占用该线程不会挂起而是消耗 CPU 的时间不停尝试获取锁。spin_lock_init(spinlock_t *lock)初始化自旋锁void spin_lock(spinlock_t *lock)获取锁void mutex_unlock(struct mutex *lock)解锁3.信号量本质上是一个全局变量信号量的值表示控制访问资源的线程数当线程访问共享资源时信号量执行“减一”操作访问完成后再执行“加一”操作。void sema_init(struct semaphore *sem, int val)信号量初始化int down_interruptible(struct semaphore *sem)获取信号量获取不到则睡眠等待等待可被信号打断void up(struct semaphore *sem)释放信号量并唤醒一个等待者4.原子操作只能做一些简单的增减将操作变为一个整体中间不会有上下文切换无法被打断。四.spi子系统硬件信息查询厂商写的spi_2设备树查看spi核心层代码得到从设备reg0的原因spi不像i2c一样使用从设备地址而在这里使用reg来给从设备做标识。这个地方会对我们spi控制器的子节点做解析如果没有cs-gpio属性就会匹配不上所以有两种做法第一就是是将这两行代码屏蔽掉第二就是在我们自己写设备树的spi控制器添加cs-gpio属性。解析从设备核心层cs的拉低过程spi控制器代码S3C64XX_SPI_SLAVE_SEL为Slave Select 寄存器NSS这行代码就是把 bit0 写 0激活硬件 Slave Select 信号。硬件 SS 信号激活可得寄存器的地址寄存器地址作用CANSTAT0x0E状态寄存器反映 CAN 控制器的当前状态如工作模式、错误状态等CANCTRL0x0F控制寄存器配置 CAN 控制器的工作模式如正常模式、监听模式、睡眠模式等#define INSTRUCTION_RESET 0xC0#define INSTRUCTION_WRITE 0x02#define INSTRUCTION_READ 0x03spi 子系统数据传输在 spi 子系统中在进行数据传输时,会将数据封装成 spi_message 结构体,形成消息队列在 进行发送spi_message 结构体定义如下一个 spi_message 对象可以由多个 spi_transfer 来构成,spi_transfer 的定义如下spi 子系统传输方式在 spi 传输过程中,可以使用 同步方式 与 异步方式 :同步方式 是指数据传输的发起者必须等待本次传输的结束期间不能做其它事情用代码来解释就是调用传输的函数后直到数据传输完成函数才会返回。异步方式则正好相反数据传输的发起者无需等待传输的结束数据传输期间还可以做其 它事情用代码来解释就是调用传输的函数后函数会立刻返回而不用等待数据传输完成我们只需设置一个回调函数传输完成后该回调函数会被调用以通知发起者数据传送已经完成在 Linux 内核 spi 子系统,可以调用 spi_sync() 函数用于 spi 同步传输。设备树实验现象回环测试在spidev.c里设备树