IIC小结

一.IIC必知基本知识
1. 两根线SCL SDA,同步、串行、半双工
2. 多从机设备,每一个器件都可以既当主机,又当从机,每个器件都有一个7bit的地址标识
3.具有冲突检测和仲裁机制,当多主机同时启用总线时,可以防止错误产生
4.四大信号:起始信号、终止信号、应答信号和发送信号(SCL高电平SDA信号不可变化,为接收器接收;SCL低电平SDA可以变化,为发送器发送信号)
5. 发送器不同于串口(可以发5-8位数据位),iic必须每次发一个字节
6. 发送器每次发送完一个字节数据之后,接收器必须发送一位的应答位来回答发送器
7. 典型IIC时序:
接下来的8,9步被封装在iic_transfer、i2c_smbus_xfer等API函数中
8. IIC读流程:
主机发送起始信号(标志通信的开始) -> 发送I2C设备以及写(请求写入数据)-> 从机发送应答ACK信号 -> 重新发送开始信号(可有可没有) -> 主机发送要读取数据的寄存器地址 -> ACK ->主 机重新发送开始信号(标志接下来的操作是读取数据而不是写)->发送I2C设备以及读(请求读取数据)-> ACK ->从设备将数据字节发送给主机->主机发送ACK信号->主机发送停止信号
9. IIC写流程:
主机发送开始信号 -> 主机发送I2C设备地址及0写(表示要写数据) -> 从机发送应答ACK信号 ->
重新发送开始信号(可有可没有) -> 主机发送要写入数据的寄存器地址 -> 从机发送ACK信号 -> 主机发送要写入寄存器的地址 -> ACK信号 -> 停止信号
总结:
  • 写操作

    • 主设备发送寄存器地址和要写入的数据。
    • 从设备接收到寄存器地址后,准备接收数据。
  • 读操作

    • 主设备首先发送寄存器地址以指定要读取的寄存器。
    • 接着,主设备通过发送重复开始信号(Repeated START),切换到读取模式,并发送设备地址及读操作位(1)。
    • 从设备根据指定的寄存器地址将数据发送给主设备。

10.总线速度 五种模式

二.具体操作,驱动设备分离的思想,主控制器由I.MX的iic控制器,从设备这里设置为ap3216
  I.MX I2C 适配器驱动采用了 DMA 方式
I.MX适配器驱动(SOC.I2C控制器,主) + I.MX设备驱动(AP3216,从,外接设备)
①NXP官方已经撰写完成,包括中断号获取、linux虚拟内存映射获取I2C1控制器实际物理地址、初始化等工作
②设备树修改IO口,复用IO口,并创建相应的设备信息(ap3216),包括compatible和reg器件地址 →AP3216驱动编写
2.1 驱动注册:将ap3216注册到核心层,使内核开始监听匹配的I2C设备
   2.2 设备与驱动匹配:内核在I2C 总线上扫描设备并通过 ap3216c_idap3216c_of_match 进行设备与驱动的匹配。当匹配成功时,内核会调用驱动程序中的 probe 函数。
   2.3 初始化设备: ap3216c_probe():当 probe 函数被调用时,它会初始化 AP3216C 设备。具体步骤包括:
  1. 获取并解析设备树中的配置信息(如果使用设备树)。
  2. 为设备结构体(如 ap3216c_dev)分配内存并初始化相关成员变量,包括 private_data,用于存储 i2c_client 结构体。
  3. 注册字符设备,以便通过 /dev 接口与用户空间进行交互。
  4. 初始化设备所需的资源,如 GPIO、时钟等。

2.4 设备操作:在应用程序中,可以通过标准的字符设备接口(如 open, read, write)访问 AP3216C 传感器的数据。这些接口调用会触发驱动中的相应操作函数,例如:ap3216c_read_reg():读取单个寄存器的数据。

2.5 数据处理

  • 驱动会周期性地读取 AP3216C 的传感器数据(如 IR、ALS、PS)。这些数据通过合适的接口传递给用户空间的应用程序。
  • 数据处理的流程通常是通过定时器或中断触发的,例如每隔一段时间(如 0.3 秒)通过 QTimer 定时器调用相应的槽函数来读取数据并更新显示。

2.6 驱动卸载:当驱动需要被卸载的时候,会释放所有分配的资源

整个执行流程从驱动的注册开始,到设备的匹配与初始化,进而通过字符设备接口进行数据交互,最后在需要时卸载驱动并释放资源。这一流程确保了 AP3216C 传感器的正常工作,并通过内核驱动为用户空间提供稳定的访问接口。
③QT:在 Qt 中,定时器( QTimer)与槽函数之间的连接是通过信号和槽的机制来实现的。具体来说, QTimer 对象会发出一个 timeout() 信号,当定时器达到设定的时间间隔时,Qt 会自动触发这个信号,调用与之关联的槽函数。
connect连接槽函数以及信号:connect(ap3216c_tim, &QTimer::timeout, this, &MainWindow::ap3216_timeout);
三.LCD驱动 GT911
裸机:寄存器设置,配置LCD现存 VSYNC等 -> LCD IO口初始化 -> LCD像素时钟设置
驱动:IIC驱动+中断(监测到触摸信息后会触发中断,在中断函数里面读取触摸点信息)+input子系统触摸屏上报
LCD驱动 platform ——只需要修改设备树(电气属性、背光信息等)
多点触摸屏驱动编写与测试:
多点电容触摸的两大协议:TypeA(上报原始数据)以及 TypeB采用!(slot更新触摸点信息并硬件追踪上报)
1. 驱动主框架是 IIC 设备,会用到中断,在中断处理函数里面上报触摸点信息,要用到 input 子系统框架
2. 设备树 IO 修改, IIC 节点添加:,修改屏幕参数
INT- GPIO1_IO09 GPIO
RST-SNVS_TAMPER9 GPIO
I2C_SDA-UART5_RXD
I2C_SCL-UART5_RXD
1. 主体 I2C 框架准备好
2. 复位引脚和中断引脚,包括中断
3. input 子系统框架 这里通过触发ABS_MT事件上报
4. 初始化 ft5426
5. 在中断服务函数里面读取触摸坐标值,然后上报给系统
可以作为难点:注意:采用request_thread_irq(比request_irq多一个threaded函数)实现中断线程化
那么为什么要中断线程化呢?我们都知道硬件中断具有最高优先级,不论什么时候
只要硬件中断发生,那么内核都会终止当前正在执行的操作,转而去执行中断处理程序 ( 不考虑
关闭中断和中断优先级的情况 ) ,如果中断非常频繁的话那么内核将会频繁的执行中断处理程序,
导致任务得不到及时的处理。中断线程化以后中断将作为内核线程运行,而且也可以被赋予不
同的优先级,任务的优先级可能比中断线程的优先级高,这样做的目的就是保证高优先级的任
务能被优先处理。大家可能会疑问,前面不是说可以将比较耗时的中断放到下半部 (bottom half)
处理吗?虽然下半部可以被延迟处理,但是依旧先于线程执行,中断线程化可以让这些比较耗
时的下半部与进程进行公平竞争。
       要注意,并不是所有的中断都可以被线程化,重要的中断就不能这么操作。对于触摸屏而
言只要手指放到屏幕上,它可能就会一直产生中断 ( 视具体芯片而定, FT5426 是这样的 ) ,中断
处理程序里面需要通过 I2C 读取触摸信息并上报给内核, I2C 的速度最大只有 400KHz ,算是低
速外设。不断的产生中断、读取触摸信息、上报信息会导致处理器在触摸中断上花费大量的时
间,但是触摸相对来说不是那么重要的事件,因此可以将触摸中断线程化。
-> 思考: 在嵌入式软件开发中,线程化的需求通常由以下几种情况引发:

1. 并发任务处理

  • 需求:当系统需要同时处理多个任务或服务时,例如同时处理传感器数据采集、用户界面更新和通信任务。
  • 例子:同时读取传感器数据、处理用户输入、并进行通信时,将这些任务分配到不同的线程中可以提高响应性和效率。

2. 实时性要求

  • 需求:对于有实时性要求的任务,需要确保任务能够及时响应外部事件。
  • 例子:实时控制系统,如电机控制或传感器数据处理,可能需要单独的线程来确保响应时间符合要求。

3. 资源管理

  • 需求:当需要对共享资源进行保护,避免数据竞争或冲突时。
  • 例子:多个线程需要访问同一个硬件资源或数据结构时,使用互斥锁(mutex)来保护资源的访问,防止数据不一致性。

4. 异步操作

  • 需求:当需要执行一些耗时操作而不阻塞主线程。
  • 例子:在处理网络请求或文件读写时,使用线程来执行这些操作,从而避免主线程被阻塞,保持界面的响应性。

5. 提高系统吞吐量

  • 需求:提高系统的处理能力,通过并行化任务来提高吞吐量。
  • 例子:在图像处理、数据分析等高负载应用中,将不同的处理步骤分配到不同的线程中以提高整体处理速度。

6. 任务分离与组织

  • 需求:将复杂的任务分解成更简单的子任务,以提高代码的组织性和可维护性。
  • 例子:将用户界面处理、数据采集和数据处理分开到不同的线程中,使每个线程专注于一个任务,提高代码的清晰度。

7. 响应外部事件

  • 需求:处理外部事件时需要保证系统能够实时响应。
  • 例子:处理中断或接收来自外部设备的数据,通常会使用线程来处理这些事件,以确保系统能够及时响应。

总结

线程化通常用于提高系统的并发处理能力、确保实时性、保护共享资源、执行异步操作、提高系统吞吐量、分离任务以及响应外部事件。根据具体的需求和系统设计,可以选择合适的线程管理方式来实现这些目标。

补充:input子系统——管理比如按键输入、键盘、鼠标、触摸屏等的子系统
核心层:向Linux注册字符设备,input子系统所有设备的主设备号都是13,我们只需要注册一个input设备即可,即注册好input_dev设备,会在/dev/input目录下生成名为/dev/input/eventX的设备文件我们读取这个文件就可以获取到输入事件信息,比如按键值什么的。使用 read函数读取输入设备文件,也就是/dev/input/eventX,读取到的数据按照 input_event 结构体组织起来。获取到输入事件以后(input_event 结构体类型)使用 switch case 语句来判断事件类型,本章实验我们设置的事件类型为 EV_KEY,因此只需要处理 EV_KEY 事件即可。比如获取按键编号(KEY_0 的编号为 11)、获取按键状态,按下还是松开的?
上报输入事件:
input 设备都是具有输入功能的,但是具体是什么样的输入值 Linux 内核是不知道的,我们需要获取到具体的输入值,或者说是输入事件,然后将输入事件上报给 Linux 内核。不同的事件,其上报事件的 API 函数不同。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值