GPIO模拟I2C学习任务——实战

序言

任务:
用rk3328-evb中的两个gpio模拟I2C,slave模式是基本,master作为拓展。

目标:

  1. 功能成功
  2. 速率可设
  3. 主从模式
  4. 挂在设备树上

平台:
RK3328-evb,arm64,ddr4,硬件信息可以从开源网站中获取
rock-chip开源官网

固件烧录

烧录也是通过开源网的教程中慢慢琢磨,固件烧录过程遇到挺多的问题,把遇到一些问题贴出来,如果大家遇到了有好的解决方法,希望告知。
RK3328烧录过程遇到问题

内核模块动态加载

内核驱动调试过程最好做成模块,然后通过动态加载也就是单独编译出来然后insert进内核,我总结了三种便捷的交叉编译方式,我主要使用V2.0,编译过程是在虚拟机中,而内核模块加载是加载在目标机上,所以注意交叉编译相关内容。
V1.0:整个kernel 编译模块

Makefile:
make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- rockchip_linux_defconfig

kernel/:
make modules ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu-

rk3328-evb:
insmod(rmmod)
mknod /dev/i2c_ldq c 225 0

V2.0:编译指定模块

Makefile:
ifneq ($(KERNELRELEASE),)
       obj-m:= led.o
else
KDIR := /home/ldq/kernel
PWD := $(shell pwd)
CROSS_COMPILE=/opt/prebuilts/gcc/linux-x86/aarch64/aarch64-linux-android-5.3-linaro/bin/aarch64-linux-android-
ARCH =arm64
default:
    make -C $(KDIR) M=$(PWD) modules CROSS_COMPILE=$(CROSS_COMPILE) ARCH=$(ARCH)
    rm -rf *.o *.cmd *.mod.c *.order *.symvers
endif
clean:
    rm -rf *.o *.cmd *.mod.c *.ko *.order *.symvers

V3.0:代码行直接使用

make -C /home/ldq/kernel M=/home/ldq/kernel/drivers/char/hello modules CROSS_COMPILE=/opt/prebuilts/gcc/linux-x86/aarch64/aarch64-linux-android-5.3-linaro/bin/aarch64-linux-android- ARCH=arm64

手册阅读

  • GRF:pin复用,尤其是我们要用到的GPIO口是否被其他驱动复用到其他设备上,导致GPIO寄存器无法配置有效
  • GPIO寄存器:通过配置GPIO的direction和data来完成GPIO配置

I2C协议

外围设备都具有一个七位的“从器件专用码”,高四位厂家信息,由厂家定义。低三位地址信息,由使用者自己定义。所以不需要外部的片选。多种slc频率,但是保持在100k或以下,不过这个都是比较旧的资料,不知道现在是什么速率。

  • 空闲状态:SCL和SDA保持高电平
  • 起始位:SCL高 SDA高转低跳变
  • 终止位:SCL高 SDA低转高跳
  • 发送端发送一个字节后,由接收端反馈一个应答信号,低电平为有效应答(ACK),高电平位无效电平(NACK),要求在第九个SCL时钟信号低电平期间,拉低,并且在第九个SCL时钟高电平期间,保持低。
    GPIO模拟I2C学习任务——实战_第1张图片

  • 如果接收器是主控器,则在它收到最后一个字节后,发送一个NACK信号,以通知被控发送器结束数据发送,并释放SDA线,以便主控接收器发送一个停止信号P。

  • 在SCL低电平期间SDA做变化,SCL高电平期间SDA保持电平,这样的数据才有效
  • 同步——每一位数据都有一个时钟脉冲相对应

工作流程

  1. 主设备发出起始电平
  2. 主设备发出设备地址、读写位,然后释放总线等待从设备拉低应答
  3. 发送所要读取的slave的内部寄存器,等待应答
  4. 发送数据
  5. 发送停止位

    ● 写入从设备

    1. 主设备发出起始电平 start
    2. 主设备发出设备地址、写位,然后释放总线等待从设备拉低应答 write
    3. 发送所要写的slave的内部寄存器,等待应答 read ack
    4. 发送数据 write read ack
    5. 发送停止位,从设备进入内部写入周期,所以两次写之间需要一个大概10ms的延迟。
      GPIO模拟I2C学习任务——实战_第2张图片
      GPIO模拟I2C学习任务——实战_第3张图片

● 读从设备

  1. 主设备发出起始电平 start
  2. 主设备发出设备地址、读位 bit[0:7]
  3. 发送所要读取的slave的内部寄存器 bit[0:7]
  4. 重新发送起始电平,即restart start
  5. 重新发送slave地址+read bit set;
  6. 读取数据
    主机接收器在接收到最后一个字节后,也不会发出ACK信号。于是,从机发送器释放SDA线,以允许主机发出P信号结束传输。
  7. 发送停止位
    GPIO模拟I2C学习任务——实战_第4张图片
    GPIO模拟I2C学习任务——实战_第5张图片

设备树

作用:

  • 板级的信息获取抽象到驱动中,而具体信息在设备树上,通过修改设备树节点的信息,来使得驱动支持普通信息发生改变的不同开发板(比如管教的物理地址),但是如果驱动逻辑发生改变,还是要重写驱动
  • 设备树就是为驱动服务的

    GPIO模拟I2C学习任务——实战_第6张图片
    GPIO模拟I2C学习任务——实战_第7张图片

注释

  • 节点名可以引用 &pinctrl,pinctrl:
  • KEY

未完待续……

你可能感兴趣的:(内核驱动研究)