这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界 » 论坛首页 » 活动中心 » 板卡试用 » 【分享开发笔记,赚取电动螺丝刀】s32k146适配zephyr(五)添加设备树节

共9条 1/1 1 跳转至

【分享开发笔记,赚取电动螺丝刀】s32k146适配zephyr(五)添加设备树节点

高工
2025-04-14 20:30:42   被打赏 33 分(兑奖)     打赏

【简介】

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;
}

运行上述测试代码,系统中的设备节点信息如下:

image.png

zephyr  的 DTS 处理过程流程说明如下

image.png

对应的yaml文件如下,生成DTS 的文件时会根据ymal的属性信息进行检查,如果如下的需要配置的配置项缺失会编译报错。

image.png


zephyr 下gpio 模拟的I2C 算法通过“compatible = "gpio-i2c"” 来配置,对应的配置信息说明如下:

image.png

按照上述的的信息参照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 说明示例如下

image.png

在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已经添加到系统中。

image.png

【功能验证】

在之前的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节点信息。

image.png


专家
2025-04-14 20:46:26     打赏
2楼

感谢分享


专家
2025-04-14 20:47:48     打赏
3楼

感谢分享


高工
2025-04-25 21:54:48     打赏
4楼

看起来这个配置方法在其他支持zepyhr的方案上也能用


专家
2025-04-26 06:59:03     打赏
5楼

这个gpio模拟iic的代码,他们是开源的吗?


专家
2025-04-28 13:59:17     打赏
6楼

看得出,楼主写代码不喜欢加注释。

不学习的话,跟不上大佬的节奏。



专家
2025-04-28 14:10:19     打赏
7楼

这种模拟I2C的设备,会不会受到中断的影响,导致I2C通讯异常?


院士
2025-04-28 16:44:37     打赏
8楼

楼主的分享真棒。

这给正在学习或练习的网友们提供了最直接的帮助。


助工
2025-05-09 16:12:33     打赏
9楼

楼主对zephyr的研究较深,  文章内容详细且每一项步骤都条理清晰. 特别是给用户说明的时候还能针对原理性的配置流程进行解释. 期待后续zephyr的更新


共9条 1/1 1 跳转至

回复

匿名不能发帖!请先 [ 登陆 注册 ]