i2c子系统及eeprom驱动--Apple的学习笔记

一,前言

爽11选东东花费了我一周的业余时间,趁着周末又调整回了常规的学习状态。之前做的applepaper是虚拟的platform设备,最近把10年前配合单片机以前买的电子元器件都翻出来看看能否资源利用。接着就找到了eeprom和电阻,最适合的就是先研究i2c子系统了。
设备驱动开发详解中的i2c子系统看完后,5.4内核i2c源码看了下。基本上了解了i2c自系统的框架。就是包括i2c总线驱动(adapter+algorithm)和i2c设备驱动(client,driver)。另外,我一开始理解框架的时候最大的疑惑就是at24.c中为什么没有file_operate的read,write等,只有probe和release。原因是read,write都在i2c-dev.c文件中,它实现的client是虚拟的,它的主体是i2c_driver成员函数+字符设备驱动。
APP测试工程路径在我的gitee,可参考10_i2c_eeprom文件夹。

二,配置eeprom驱动

在Document中我看到了i2c-tools,所以我理解只要i2c的eeprom驱动完成后,我不写用户程序也可以操控eeprom了。而对于eeprom驱动及i2c总线驱动只要简单修改下设备树即可实现。
1,先设计原理图
因为i2c0已经被bb black用了连接at24c32,并且写保护。所以bb black开发板引出的是i2c1和i2c2,由于已经定于了i2c2的功能脚,所以我直接用i2c2来设计电路,地址为0x51

image.png

2. 编译dts
am335x-bone-common.dtsi删除原来的i2c2修改为如下

&i2c2 {
    pinctrl-names = "default";
    pinctrl-0 = <&i2c2_pins>;

    status = "okay";
    clock-frequency = <100000>;

    apple_eeprom0: apple_eeprom0@51 {
        compatible = "atmel,24c02";
        reg = <0x51>;
        #address-cells = <1>;
        #size-cells = <1>;
        apple_eeprom0_data: apple_eeprom0_data@0 {
            reg = <0 0x100>;
        };
    };
};

3.遇到的问题
a, 由于万用表的9v电池失效了,所以电阻不能测量,只能看色环来辨别。找了个4.7k的。
b,由于万用表没有电,面包板我忘记了哪些是连通哪些是断开的,只能拿示波器来测量。
c,一开始modprobe at24.ko后没有识别出eeprom,在at24.c中添加printk发现是read timeout导致的,接着我就检查引脚,怕杜邦线断掉,用示波器测试sda的波形居然没有。接着突然发现at24c02的引脚我全部都连反了。重新连线后解决。
4. 驱动成功
能在i2c总线设备下找到2-0051设备,modprobe at24.ko后能绑定到at24驱动。并且通过i2c-tools能像eeprom写值和读值。

# cd /sys/bus/i2c/devices/
# ls
0-0024  0-0050  0-0070  2-0051  i2c-0   i2c-2
# cd 2-0051
# ls -al
total 0
drwxr-xr-x    3 root     root             0 Jan  1 00:00 .
drwxr-xr-x    5 root     root             0 Jan  1 00:00 ..
-r--r--r--    1 root     root          4096 Jan  1 00:00 modalias
-r--r--r--    1 root     root          4096 Jan  1 00:00 name
lrwxrwxrwx    1 root     root             0 Jan  1 00:00 of_node -> ../../../../../../../../../firmware/devicetree/base/ocp/interconnect@48000000/segment@100000/target-module@9c000/i2c@0/apple_eeprom0@51
drwxr-xr-x    2 root     root             0 Jan  1 00:00 power
lrwxrwxrwx    1 root     root             0 Jan  1 00:00 subsystem -> ../../../../../../../../../bus/i2c
-rw-r--r--    1 root     root          4096 Jan  1 00:00 uevent
# modprobe at24.ko
[   38.083623] at24 0-0050: GPIO lookup for consumer wp
[   38.088645] at24 0-0050: using device tree for GPIO lookup
[   38.094306] of_get_named_gpiod_flags: can't parse 'wp-gpios' property of node '/ocp/interconnect@44c00000/segment@200000/target-module@b000/i2c@0/baseboard_eeprom@50[0]'
[   38.109556] of_get_named_gpiod_flags: can't parse 'wp-gpio' property of node '/ocp/interconnect@44c00000/segment@200000/target-module@b000/i2c@0/baseboard_eeprom@50[0]'
[   38.124702] at24 0-0050: using lookup tables for GPIO lookup
[   38.130395] at24 0-0050: No GPIO consumer wp found
[   38.137966] at24 0-0050: 4096 byte 24c32 EEPROM, writable, 1 bytes/write
[   38.145393] at24 2-0051: GPIO lookup for consumer wp
[   38.150399] at24 2-0051: using device tree for GPIO lookup
[   38.156028] of_get_named_gpiod_flags: can't parse 'wp-gpios' property of node '/ocp/interconnect@48000000/segment@100000/target-module@9c000/i2c@0/apple_eeprom0@51[0]'
[   38.171101] of_get_named_gpiod_flags: can't parse 'wp-gpio' property of node '/ocp/interconnect@48000000/segment@100000/target-module@9c000/i2c@0/apple_eeprom0@51[0]'
[   38.186069] at24 2-0051: using lookup tables for GPIO lookup
[   38.191761] at24 2-0051: No GPIO consumer wp found
[   38.223103] at24 2-0051: 256 byte 24c02 EEPROM, writable, 1 bytes/write
# ls -al
total 0
drwxr-xr-x    4 root     root             0 Jan  1 00:00 .
drwxr-xr-x    5 root     root             0 Jan  1 00:00 ..
drwxr-xr-x    3 root     root             0 Jan  1 00:00 2-00510
lrwxrwxrwx    1 root     root             0 Jan  1 00:00 driver -> ../../../../../../../../../bus/i2c/drivers/at24
-rw-------    1 root     root           256 Jan  1 00:00 eeprom
-r--r--r--    1 root     root          4096 Jan  1 00:00 modalias
-r--r--r--    1 root     root          4096 Jan  1 00:00 name
lrwxrwxrwx    1 root     root             0 Jan  1 00:00 of_node -> ../../../../../../../../../firmware/devicetree/base/ocp/interconnect@48000000/segment@100000/target-module@9c000/i2c@0/apple_eeprom0@51
drwxr-xr-x    2 root     root             0 Jan  1 00:00 power
lrwxrwxrwx    1 root     root             0 Jan  1 00:00 subsystem -> ../../../../../../../../../bus/i2c
-rw-r--r--    1 root     root          4096 Jan  1 00:00 uevent
# i2cdetect -r -y 2
     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
00:          -- -- -- -- -- -- -- -- -- -- -- -- -- 
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
50: -- UU -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
70: -- -- -- -- -- -- -- --                         
# i2cdump -f -y 2 0x51
     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f    0123456789abcdef
00: ff ab ff ff ff ff ff ff ff ff ff ff ff ff ff ff    .?..............
10: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff    ................
20: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff    ................
30: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff    ................
40: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff    ................
50: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff    ................
60: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff    ................
70: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff    ................
80: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff    ................
90: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff    ................
a0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff    ................
b0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff    ................
c0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff    ................
d0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff    ................
e0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff    ................
f0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff    ................
# i2cset -f -y 2 0x51 0x01 0x12
# i2cget -f -y 2 0x51 0x01
0x12

二,eeprom读写用户程序

为eeprom的0地址写值4,读取值也为4。读写一致。

# ./i2c w 4
wrdata:0x4
# ./i2c r
writeaddress return: 1
readdata return:1
rddata:0x4
# i2cdump -f -y 2 0x51
     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f    0123456789abcdef
00: 04 12 ff ff ff ff ff ff ff ff ff ff ff ff ff ff    ??..............
10: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff    ................
20: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff    ................
30: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff    ................
40: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff    ................
50: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff    ................
60: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff    ................
70: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff    ................
80: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff    ................
90: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff    ................
a0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff    ................
b0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff    ................
c0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff    ................
d0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff    ................
e0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff    ................
f0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff    ................

1. 遇到的问题
用自己写的app测试的代码,能正常读取,但是写入错误。原因是看了datasheet读取的时候要发2次设备地址,写入的时候只要发一次设备地址。如下是at24c32的。at24c02的地址是8byte的。

image.png

所以参考了网址linux下eeprom的读写改成了iotrl方式来写eeprom后成功写入。
2. 关于驱动和app的分工的设计
上面的网址中eeprom相关的处理都写到了用户程序,其实也可以写到驱动中,这样用户程序就会比较简单。我参考了其它传感器设备也是用i2c总线的,他们的设备驱动就是自己写的和我之前的applepaper一样,只不过不是注册到平台虚拟总线,而是将驱动注册到i2c总线。也就是说我也可以自己写一个i2c eeprom设备驱动,而不用默认的at24.c及i2c-dev.c。
另外,eeprom可以当做二进制文件,通过sysfs文件系统访问I2C设备,这样的话,app写起来就比较简单了,等于是在操作二进制文件,参考网址i2c子系统-eeprom实例分析

#define EEPROM_DEVICE "/sys/devices/platform/ocp/48000000.interconnect/48000000.interconnect:segment@100000/4819c000.target-module/4819c000.i2c/i2c-2/2-0051"

三,i2c子系统理论学习

设备驱动第15章节描述了i2c子系统还是很清晰的。关于总线就是适配器用来选择设备,并且适配器会绑定总线协议,因为i2c和SMbus协议不同。网上有很多i2c子系统的详细说明。
i2c_client和i2c_driver就是i2c设备驱动。他们的关系如下。


image.png

另外,关于master_xfer是比较重要的函数,所以我看了下它的调用关系,里面的函数都是cpu芯片级别控制i2c。

# cat trace | head -30
# tracer: function
#
# entries-in-buffer/entries-written: 32/32   #P:1
#
#                              _-----=> irqs-off
#                             / _----=> need-resched
#                            | / _---=> hardirq/softirq
#                            || / _--=> preempt-depth
#                            ||| /     delay
#           TASK-PID   CPU#  ||||    TIMESTAMP  FUNCTION
#              | |       |   ||||       |         |
             i2c-126   [000] ....   372.888227: omap_i2c_xfer_common <-omap_i2c_xfer_irq
             i2c-126   [000] ....   372.888245: 
 => omap_i2c_xfer_irq
 => __i2c_transfer
 => i2c_transfer
 => i2c_transfer_buffer_flags
 => i2cdev_read
 => __vfs_read
 => vfs_read
 => ksys_read
 => sys_read
 => ret_fast_syscall
 => 0xbee3ecd0

另外也监控了at24probe的过程

# cat trace | head -40
# tracer: function
#
# entries-in-buffer/entries-written: 30/30   #P:1
#
#                              _-----=> irqs-off
#                             / _----=> need-resched
#                            | / _---=> hardirq/softirq
#                            || / _--=> preempt-depth
#                            ||| /     delay
#           TASK-PID   CPU#  ||||    TIMESTAMP  FUNCTION
#              | |       |   ||||       |         |
        modprobe-123   [000] ....   614.268663: device_property_present <-at24_probe
        modprobe-123   [000] ....   614.268682: 
 => at24_probe
 => i2c_device_probe
 => really_probe
 => driver_probe_device
 => device_driver_attach
 => __driver_attach
 => bus_for_each_dev
 => driver_attach
 => bus_add_driver
 => driver_register
 => i2c_register_driver
 => at24_init
 => do_one_initcall
 => do_init_module
 => load_module
 => sys_finit_module
 => ret_fast_syscall
 => 0xbed48b20

at24_read函数在app读取的时候不会被调用的

# mount -t debugfs nodev /sys/kernel/debug
# cd /sys/kernel/debug/tracing
# echo 0 > tracing_on
# echo at24_read > set_ftrace_filter
# echo function > current_tracer
# echo func_stack_trace > trace_options
# echo 1 > tracing_on
# cd /usr/study/
# ./i2c r
writeaddress return: 1
readdata return:1
rddata:0x4
# cd /sys/kernel/debug/tracing
# echo 0 > tracing_on
# cat trace | head -40
# tracer: function
#
# entries-in-buffer/entries-written: 0/0   #P:1
#
#                              _-----=> irqs-off
#                             / _----=> need-resched
#                            | / _---=> hardirq/softirq
#                            || / _--=> preempt-depth
#                            ||| /     delay
#           TASK-PID   CPU#  ||||    TIMESTAMP  FUNCTION
#              | |       |   ||||       |         |

你可能感兴趣的:(i2c子系统及eeprom驱动--Apple的学习笔记)