【简介】
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节点信息。

33


