【简介】
zephyr 的设备管理使用的设备树的管理方式,在之前的帖子也有修改过设备树的配置来跟本地的硬件匹配,之前都是基于既有的设备节点进行修改,本次我们添加设备树节点至系统来熟悉设备树的管理方式,本地的硬件配置有两路I2C,S32K146芯片内部只有一个LPI2C模块,多路I2C的使用场景要使用FLEXIO或者GPIO 来模拟I2C,zephyr 的I2C驱动已经支持了GPIO模拟I2C的驱动算法。
【添加GPIO模拟I2C设备树节点】
zephyr 会将设备树配置中“okay” 的节点和对应的驱动匹配,如果匹配成功则会在系统中静态的创建设备驱动,在开始添加gpio模拟i2c之前我们先添加如下测试代码输出当前系统的设备信息。
static const char *get_device_name(const struct device *dev, char *buf, size_t len) { const char *name = dev->name; if ((name == NULL) || (name[0] == 0)) { snprintf(buf, len, "[%p]", dev); name = buf; } return name; } unsigned int device_list(char argc,char ** argv) { const struct device *devlist; size_t devcnt = z_device_get_all_static(&devlist); const struct device *devlist_end = devlist + devcnt; const struct device *dev; printf("devices:\r\n"); for (dev = devlist; dev < devlist_end; dev++) { char buf[20]; const char *name = get_device_name(dev, buf, sizeof(buf)); printf("- %s (%s)\r\n", name,(!device_is_ready(dev) ? "DISABLED": "READY")); } return 1; }
运行上述测试代码,系统中的设备节点信息如下:
zephyr 的 DTS 处理过程流程说明如下
对应的yaml文件如下,生成DTS 的文件时会根据ymal的属性信息进行检查,如果如下的需要配置的配置项缺失会编译报错。
zephyr 下gpio 模拟的I2C 算法通过“compatible = "gpio-i2c"” 来配置,对应的配置信息说明如下:
按照上述的的信息参照lpi2c0 信息在,\zephyr\dts\arm\nxp\nxp_s32k1xx.dtsi 添加以下gpioi2c0 节点信息,默认“disable”
gpioi2c0: gpioi2c0 { compatible = "gpio-i2c"; clock-frequency = <I2C_BITRATE_STANDARD>; #address-cells = <1>; #size-cells = <0>; status = "disabled"; };
设备树的属性信息overlay 说明示例如下
在board 对应的dts 中引用该节点并使能配置,并按照硬件信息配置GPIO信息,对应配置如下:
&gpioi2c0{ scl-gpios = <&gpiob 9 GPIO_ACTIVE_HIGH>; sda-gpios = <&gpiob 10 GPIO_ACTIVE_HIGH>; status = "okay"; };
最终的gpioi2c0 设备树配置如下:
gpioi2c0: gpioi2c0 { compatible = "gpio-i2c"; clock-frequency = < 0x186a0 >; #address-cells = < 0x1 >; #size-cells = < 0x0 >; status = "okay"; scl-gpios = < &gpiob 0x9 0x0 >; sda-gpios = < &gpiob 0xa 0x0 >; };
更新上述设备树配置信息后,再次查看系统内的设备信息发现gpioi2c0已经添加到系统中。
【功能验证】
在之前的lpi2c 代码基础上添加gpio模拟I2C 总线节点扫描验证,
#include <stdio.h> #include "littleshell.h" #include <zephyr/kernel.h> #include <zephyr/device.h> #include <zephyr/drivers/i2c.h> #include <ringbuffer.h> #include <zephyr/drivers/gpio.h> #include <string.h> #include <zephyr/logging/log.h> #include <zephyr/device.h> /******************************************************************************************************** * Private Function Declarations * *******************************************************************************************************/ static int i2c_probe(const struct device *dev,char addr) { uint8_t data = 0; static struct i2c_msg msg; int ret = -1; msg.len = 1; msg.buf = &data; msg.flags = I2C_MSG_WRITE; ret = i2c_transfer(dev,&msg,1,addr); if(ret == 0) { msg.len = 1; msg.buf = &data; msg.flags = I2C_MSG_READ | I2C_MSG_STOP; ret = i2c_transfer(dev,&msg,1,addr); } return ret == 0 ? 1 : 0; } static void i2c_scan(const struct device *dev,uint8_t start_addr, uint8_t stop_addr) { printf(" 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F"); uint8_t pos = start_addr <= 0xF? 0x00: start_addr & 0xF; for(; pos < stop_addr; pos++) { if((pos & 0xF) == 0) { printf("\r\n%02X: ", pos); } if(pos < start_addr) { printf(" "); continue; } if( i2c_probe(dev,pos) == 1) { printf("%02X", pos); } else { printf("--"); } printf(" "); } printf("\r\n"); } unsigned int i2c(char argc,char *argv[]) { static const struct device * dev; if(strcmp(argv[1],"scan") == 0) { if(strcmp(argv[2],"lpi2c") == 0 ) { dev = device_get_binding("i2c@40066000"); if(dev == NULL) { printf("lpi2c0 init failed.\r\n"); goto out; } } if(strcmp(argv[2],"gpioi2c") == 0 ) { dev = device_get_binding("gpioi2c0"); if(dev == NULL) { printf("gpio i2c0 init failed.\r\n"); goto out; } } i2c_scan(dev,0x00,0x7f); } out: return 0; } LTSH_FUNCTION_EXPORT(i2c,"i2c test command");
扫描gpio 模拟的i2c总线上已经扫描到对应的slave节点信息。