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

共2条 1/1 1 跳转至

【分享开发笔记,赚取电动螺丝刀】s32k146适配zephyr(三)添加I2C总线设备驱动

高工
2025-04-11 21:17:24     打赏

【简介】

  在前两篇(s32k146适配zephyr(一)添加board  )(s32k146适配zephyr(二)适配板级别差异),我们已经将本地的S32K146 的开发板添加到zephyr 系统,我们基于此基础上继续使用I2C设备驱动。zephyr  的驱动开发有点像linux 下驱动开发,因为驱动中已经支持了S32K 的I2C总线驱动,我们需要做的是配置DTS 中的I2C节点,开启I2C总线的驱动就可以使用zephyr  的I2C驱动。对S32K146 LPI2C的说明可以查看之前的该帖子使用S32DS适配I2C接口),在此就不重复赘述。

【I2C总线设备树配置】

S32K146 芯片内部有集成了一个LPI2C的硬件I2C模块,对应的设备节点在\zephyr\dts\arm\nxp\nxp_s32k1xx.dtsi 通用的dtsi文件中描述如下:

		lpi2c0: i2c@40066000 {
			compatible = "nxp,lpi2c";
			clock-frequency = <I2C_BITRATE_STANDARD>;
			#address-cells = <1>;
			#size-cells = <0>;
			reg = <0x40066000 0x1000>;
			interrupts = <24 0>;
			clocks = <&clock NXP_S32_LPI2C0_CLK>;
			status = "disabled";
		};


再次配置中status 属性是关闭的,我们需要在我们的board 对应的DTS 配置中重写该属性开启I2C设备树节点,对应我们的board下的DTS中引用 lpi2c0 设备并更新对应的属性信息。

&lpi2c0 {
	pinctrl-0 = <&lpi2c0_default>;
	pinctrl-names = "default";
	scl-gpios = <&gpioa 3 GPIO_ACTIVE_HIGH>;
	sda-gpios = <&gpioa 2 GPIO_ACTIVE_HIGH>;
	status = "okay";
};


大家看到这不知是否有个疑问?这里面的配置项目代表的含义是什么,我看到这的时候是有这个疑问的,带着这个疑问查看了官方的nxp,lpi2c 的节点说明,官方的链接(https://docs.zephyrproject.org/latest/build/dts/api/bindings/i2c/nxp%2Clpi2c.html#dtbinding-nxp-lpi2c)有对应的属性描述,我们截取了部分的属性说明如下:

image.png

除了上述I2C的节点配置外,我们还需要在PIN_CTRL节点中配置GPIO为I2C功能,对应PIN_CTRL配置如下

&pinctrl {

	lpuart1_default: lpuart1_default {
		group0 {
			pinmux = <LPUART1_RX_PTC8>, <LPUART1_TX_PTC9>;
			drive-strength = "low";
		};
	};

	lpi2c0_default: lpi2c0_default {
		group1 {
			pinmux = <LPI2C0_SDA_PTA2>, <LPI2C0_SCL_PTA3>;
			drive-strength = "low";
		};
	};

};

【I2C驱动配置】

我们在上面更新了DTS相关的I2C配置,我们只需要在zephyr 的工程config 中开启I2C驱动就可以将I2C驱动编译到系统中,在应用\zephyr\samples\drivers\uart\shell\prj.conf 文件中添加I2C总线驱动配置。

image.png

【测试代码】

更新好上述配置后,我们可以就可以在代码中添加如下测试代码验证I2C总线驱动,在zephyr 中i2c设备驱动通过i2c_msg结构来对总线进行读写访问。

image.png

i2c_transfer() 函数将上述的i2c_msg结构信息发送到总线。

image.png

我们编写测试代码对总线的地址范围进行扫描遍历,对应的节点是否有应答来确认总线上的节点数目信息,该测试在之前使用S32DS配置I2C总线时使用过(使用S32DS适配I2C接口),只要修改底层I2C驱动访问接口即可。我们使用zephyr I2C驱动函数访问I2C对应修改如下。

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)
    {
        i2c_scan(dev,0x00,0x7f);
    }

    if(strcmp(argv[1],"init") == 0)
    {
	    dev = device_get_binding("i2c@40066000");
        if(dev == NULL)
        {
            printf("i2c init failed.\r\n");
        }
    }

    return 0;
}


【实机验证】

上述测试代码,扫描总线的地址信息输出如下,跟之前验证的结果一致。

image.png

上述结果已经能说明I2C 总线驱动已经按照预期工作,我们通过逻辑分析仪查看I2C总线的读写访问功能的波形也是很规整的。

以下是扫描到的0x32地址的设备的完整波形,从结果看是有接收到ACK应答。

image.png

以下是扫描0x33地址,没有接收到ACK应答的波形。

image.png

适配好总线驱动后,后续我们就可以使用I2C总线设备来驱动板子上的I2C外设了。



专家
2025-04-15 08:55:49     打赏
2楼

谢谢分享!楼主不习惯给代码加注释吗?

有注释更方便理解程序。


共2条 1/1 1 跳转至

回复

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