I2C子系统驱动框架及应用

I2C驱动原理 APP访问硬件肯定是需要驱动程序的, 对于I2C设备,内核提供了驱动程序,通过它可以直接使用下面的I2C控制器驱动程序来访问I2C设备。框架如下:i2c-tools是一套好用的工具,也是一套示例代码。使用一句话概括I2C传输:APP通过I2C Controller与I2C Device传输数据。所以使用I2C-Tools时也需要指定:哪个I2C控制器(或称为I2C BUS、I2C Adapter)哪个I2C设备(设备地址)数据:读还是写、数据本身。 阅读详情

I2C子系统驱动框架:
应用程序层(app层)
——————————————————————————————————–
i2c driver层: 从设备驱动层(TS Sensor等)
1. 需要和应用层交互(fops cdev)
2. 封装数据,但是不知道数据如何写入到硬件,需要调用adapter层的相关函数去写
——————————————————————————————————–
i2c core:维护i2c bus, 包括i2c driver和i2c client链表
1. 实现i2c client和i2c driver的匹配
——————————————————————————————————–
i2c adapter层: i2c控制器层,初始化i2c控制器,实现i2c时序
1. 将数据写入或读取从设备
2. 不知道具体数据(i2c driver提供的数据)是什么,但知道具体如何操作(读/写)从设备
这一层是具体的厂商实现的,比如三星:driver/i2c/busser/i2c-s3c2410.c

框架中,i2c core是由Linux内核实现的(i2c-core.c),i2c adapter是由具体的芯片厂商实现的,比如三星的芯片adapter实现都在driver/i2c/busser/i2c-s3c2410.c。所以这连个部分需要编译到uImage中(make menuconfig -> device driver -> <*> i2c support -> i2c hardware Bus support -> S3C2410 I2C driver)。
如果在/sys/bus/i2c/devices/i2c-0/1/2 表示有i2c-adapter 存在

在总结的时候看到有其他博友整理的框图非常好,我就借过来给大家分享!
i2c子系统框架

重要结构体之间的关系

从i2c驱动架构图中可以看出,linux内核对i2c架构抽象了一个叫核心层core的中间件,它分离了设备驱动device driver和硬件控制的实现细节(如操作i2c的寄存器),core层不但为上面的设备驱动提供封装后的内核注册函数,而且还为下面的硬件事件提供注册接口(也就是i2c总线注册接口i2c_add_register),可以说core层起到了承上启下的作用。

相关的重要结构体和函数:
1. i2c_client
每一个i2c从设备都需要用一个i2c_client结构体来描述,i2c_client对应真实的i2c物理设备device,但是i2c_client不是我们自己写程序去创建的,而是通过以下常用的方式自动创建的(这个地方不做详细说明,以介绍总体框架为主):
platform创建:
1. 注册i2c_board_info
2. 获取对应的adapter,然后i2c_new_device
devicetree创建:
3. 通过设备树的一个节点去描述一个从设备,设备树在解析的时候会自动创建client

struct i2c_client {
    unsigned short flags;        //标志位 (读写)
    unsigned short addr;         //7位的设备地址(低7位)
    char name[I2C_NAME_SIZE];    //设备的名字,用来和i2c_driver匹配
    struct i2c_adapter *adapter; //依附的适配器(adapter),适配器指明所属的总线(i2c0/1/2_bus)
    struct device dev;           //继承的设备结构体
    int irq;                     //设备申请的中断号
    struct list_head detected;   //已经被发现的设备链表
};

2. i2c_driver
driver是指向从设备的驱动程序,由我们自己去实现并通过i2c_add_register注册到i2c的bus中,和i2c clinet进行匹配,匹配成功则调用probe函数。

struct i2c_driver {
    int (*probe)(struct i2c_client *, const struct i2c_device_id *); //设备匹配成功调用的函数
    int (*remove)(struct i2c_client *);                              //设备移除之后调用的函数
    struct device_driver driver;                                     //设备驱动结构体
    const struct i2c_device_id *id_table;   //设备的ID表,匹配用platform创建的client
};

3. i2c_adapter
i2c总线适配器其实就是一个i2c总线控制器,本质上是一个物理设备,主要用来完成i2c总线控制器相关的数据通信
由芯片厂商去实现的。

struct i2c_adapter {
    struct module *owner;
    unsigned int class;               //允许匹配的设备的类型
    const struct i2c_algorithm *algo; //指向适配器的驱动程序,实现发送数据的算法
    struct device dev;                //指向适配器的设备结构体
    char name[48];                    //适配器的名字
};

4. i2c_algorithm
i2c算法,适配器对应的驱动程序,每一个适配器对应一个驱动程序,用来描述适配器和设备之间的通信方法
由芯片厂商去实现的。

struct i2c_algorithm {
    //传输函数指针,指向实现IIC总线通信协议的函数
    int (*master_xfer)(struct i2c_adapter *adap, struct i2c_msg *msgs, int num);        
};

5. i2c_msg
把要发送的数据封装成msg结构体(比如16个字节进行拆分)

struct i2c_msg {
    __u16 addr;     /* slave address  */
    __u16 flags;    /* 1 - 读  0 - 写 */
    __u16 len;      /* msg length     */
    __u8 *buf;      /* 要发送的数据   */
};

6. i2c_add_register
注册一个i2c_driver结构体,通过name或者id_tables或者of_match_table去匹配一个i2c_client,如果匹配成功,则会调用i2c_driver结构体里面的probe函数,并将对应的i2c_client结构体传过来。
#define i2c_add_driver(driver) i2c_register_driver(THIS_MODULE, driver)
int i2c_register_driver(struct module *owner, struct i2c_driver *driver)

7. i2c_transfer
负责通过对应的i2c总线对依附于这个adapter的从机设备(i2c_client)进行读写数据(双向的)。其中要读写的数据要封装成为一个i2c_msg结构体,根据msg的flags标志位是0还是1来决定是读还是写。其实i2c_transfer是对master_xfer的封装。

/**
 * i2c_transfer - execute a single or combined I2C message
 * @adap: Handle to I2C bus
 * @msgs: One or more messages to execute before STOP is issued to
 *  terminate the operation; each message begins with a START.
 * @num: Number of messages to be executed.
 *
 * Returns negative errno, else the number of messages executed.
 *
 * Note that there is no requirement that each message be sent to
 * the same slave address, although that is the most common model.
 */
int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
eg.
/* i2c_msg指明要操作的从机地址,方向,缓冲区 */
struct i2c_msg msg[] = {
    {client->addr, 0, 1, &txbuf},    //0表示写,向往从机写要操作的寄存器的地址
    {client->addr, 1, 1, &rxbuf},    //读数据
};

/* 通过i2c_transfer函数操作msg */
ret = i2c_transfer(client->adapter, msg, 2);    //执行2条msg

这几个重要结构体之间的关系:
a – i2c_adapter与i2c_algorithm
i2c_adapter对应与物理上的一个适配器,而i2c_algorithm对应一套通信方法,一个i2c适配器需要i2c_algorithm中提供的(i2c_algorithm中的又是更下层与硬件相关的代码提供)通信函数来控制适配器上产生特定的访问周期。缺少i2c_algorithm的i2c_adapter什么也做不了,因此i2c_adapter中包含其使用i2c_algorithm的指针。
i2c_algorithm中的关键函数master_xfer()用于产生i2c访问周期需要的start、stop、ack信号,以i2c_msg为单位发送和接收通信数据。
i2c_msg也非常关键,调用驱动中的发送接收函数需要填充该结构体

b –i2c_driver和i2c_client
i2c_driver对应一套驱动方法
i2c_client对应真实的i2c物理设备device,每个i2c设备都需要一个i2c_client来描述
i2c_driver与i2c_client的关系是一对多。一个i2c_driver上可以支持多个同等类型的i2c_client.

c – i2c_adapter和i2c_client
i2c_adapter和i2c_client的关系与i2c硬件体系中适配器和设备的关系一致,即i2c_client依附于i2c_adapter,由于一个适配器上可以连接多个i2c设备,所以i2c_adapter中包含依附于它的i2c_client的链表

下面给出一个i2c子系统实例代码(用设备树实现):
主机 - 三星的某款cpu
从机 - mpu6050三轴加速度传感器

设备树描述:
当设备树被内核解析后会生成一个依附于i2c-0这个adapter的i2c_client

@i2c-0 {//表示这个i2c_client所依附的adapter是i2c-0
    //对应i2c_client的name = "invensense,mpu6050"
    compatible = "invensense,mpu6050";
    //对应i2c_client的addr = 0x69  -- 从机设备的地址
    reg = <0x69>;
    //对应i2c_client的irq
    interrupts = <70>;
};

driver代码:

#include <linux/module.h>
#include <linux/init.h>
#include <linux/i2c.h>
#include <linux/cdev.h>
#include <linux/fs.h>
#include <asm/uaccess.h>
#include "mpu6050.h"

MODULE_LICENSE("GPL");

#define SMPLRT_DIV      0x19
#define CONFIG          0x1A
#define GYRO_CONFIG     0x1B
#define ACCEL_CONFIG    0x1C
#define TEMP_OUT_H      0x41
#define TEMP_OUT_L      0x42
#define PWR_MGMT_1      0x6B

int MAJOR = 255;
int MINOR = 0;

struct mpu6050_device {
    struct cdev cdev;
    dev_t devno;
    struct i2c_client * client;
}mpu6050_dev;

/* 读取mpu6050中一个字节的数据,将读取的数据的地址返回 */
static int mpu6050_read_byte(struct i2c_client * client, unsigned char reg_add)
{
    int ret;

    /* 要读取的那个寄存器的地址 */
    char txbuf = reg_add;

    /* 用来接收读到的数据 */
    char rxbuf[1];

    /* i2c_msg指明要操作的从机地址,方向,缓冲区 */
    struct i2c_msg msg[] = {
        {client->addr, 0, 1, &txbuf},       //0表示写,向往从机写要操作的寄存器的地址
        {client->addr, I2C_M_RD, 1, rxbuf}, //读数据
    };

    /* 通过i2c_transfer函数操作msg */
    ret = i2c_transfer(client->adapter, msg, 2);    //执行2条msg
    if (ret < 0)
    {
        printk("i2c_transfer read err\n");
        return -1;
    }

    return rxbuf[0];
}

static int mpu6050_write_byte(struct i2c_client * client, unsigned char reg_addr, unsigned char data)
{
    int ret;

    /* 要写的那个寄存器的地址和要写的数据 */
    char txbuf[] = {reg_addr, data};

    /* 1个msg,写两次 */
    struct i2c_msg msg[] = {
        {client->addr, 0, 2, txbuf}
    };

    ret = i2c_transfer(client->adapter, msg, 1);
    if (ret < 0)
    {
        printk("i2c_transfer write err\n");
        return -1;
    }

    return 0;
}

static int mpu6050_open(struct inode * inodep, struct file * filep)
{
    printk("%s called\n", __func__);

    mpu6050_write_byte(mpu6050_dev.client, PWR_MGMT_1, 0x00);
    mpu6050_write_byte(mpu6050_dev.client, SMPLRT_DIV, 0x07);
    mpu6050_write_byte(mpu6050_dev.client, CONFIG, 0x06);
    mpu6050_write_byte(mpu6050_dev.client, GYRO_CONFIG, 0xF8);
    mpu6050_write_byte(mpu6050_dev.client, ACCEL_CONFIG, 0x19);

    return 0;
}

static int mpu6050_release(struct inode * inodep, struct file * filep)
{
    printk("%s called\n", __func__);

    return 0;
}

void get_temp(union mpu6050_data * data)
{
    data->temp = mpu6050_read_byte(mpu6050_dev.client, TEMP_OUT_L);
    data->temp |= mpu6050_read_byte(mpu6050_dev.client, TEMP_OUT_H) << 8;
}

static long mpu6050_ioctl(struct file * filep, unsigned int cmd, unsigned long arg)
{
    union mpu6050_data data;

    switch (cmd)
    {
        case GET_TEMP:
            get_temp(&data);
            break;
        default:
            break;
    }

    if (copy_to_user((unsigned int *)arg, &data, sizeof(data)))
        return -1;

    return 0;
}

struct file_operations mpu6050_fops = {
    .owner = THIS_MODULE,
    .open  = mpu6050_open,
    .release = mpu6050_release,
    .unlocked_ioctl = mpu6050_ioctl,
};

/* 匹配函数,设备树中的mpu6050结点对应转换为一个client结构体 */
static int mpu6050_probe(struct i2c_client * client, const struct i2c_device_id * id)
{
    int ret;
    printk("mpu6050 match ok!\n");

    mpu6050_dev.client = client;

    /* 注册设备号 */
    mpu6050_dev.devno = MKDEV(MAJOR, MINOR);
    ret = register_chrdev_region(mpu6050_dev.devno, 1, "mpu6050");  
    if (ret < 0)
        goto err1;

    cdev_init(&mpu6050_dev.cdev, &mpu6050_fops);
    mpu6050_dev.cdev.owner = THIS_MODULE;
    ret = cdev_add(&mpu6050_dev.cdev, mpu6050_dev.devno, 1);
    if (ret < 0)
        goto err2;

    return 0;

err2:
    unregister_chrdev_region(mpu6050_dev.devno, 1);
err1:
    return -1;
}

static int mpu6050_remove(struct i2c_client * client)
{
    printk("mpu6050 removed!\n");

    cdev_del(&mpu6050_dev.cdev);
    unregister_chrdev_region(mpu6050_dev.devno, 1);

    return 0;
}

/* 用来匹配mpu6050的设备树 */
static struct of_device_id mpu6050_of_match[] = {
    {.compatible = "invensense,mpu6050"},
    {},
};

struct i2c_driver mpu6050_driver = {
    .driver = {
        .name = "mpu6050",
        .owner = THIS_MODULE,
        .of_match_table = of_match_ptr(mpu6050_of_match),
    },
    .probe = mpu6050_probe,
    .remove = mpu6050_remove,
};

static int mpu6050_init(void)
{
    printk("%s called\n", __func__);

    i2c_add_driver(&mpu6050_driver);

    return 0;
}

static void mpu6050_exit(void)
{
    printk("%s called\n", __func__);

    i2c_del_driver(&mpu6050_driver);

    return ;
}

module_init(mpu6050_init);
module_exit(mpu6050_exit);
linux下i2c开发与框架源码分析 从分层角度上看,i2c子系统大致分为设备驱动层client、i2c核心层和i2c适配器层,如下图大致描述了整个i2c应用和内核框架的关系逻辑,从上到下,用户可通过底层提供的总线设备或者外设设备来访问挂载在总线上的i2c设备。以上便是一个i2c adapter的注册过程,比较简单,需要注意的是,在设备树定义了多个i2c节点是,这个driver将被调用多次,即将申请多个adapter,这里一个硬件i2c就申请一个adapter。来看此时i2c子系统是如何解析这个层级关系,以及client如何生成。 阅读详情

相关推荐

Linux 驱动 | 高级驱动 | I2C子系统

Linux 驱动 | 高级驱动 | I2C子系统

I_feige的博客 1291

I2C子系统框架入门—i2c驱动示例

在这个流程中,驱动程序(即你的代码)负责发起I²C命令请求,而实际的数据传输和命令执行由I²C控制器完成。I²C控制器是硬件层面的存在,它通过I²C总线执行读写操作,将驱动程序的请求发送到物理设备上。

weixin_46999174的博客 1755

Linux下的I2C通信

linux下的i2c通信。

zxz_Fine的博客 1916

【Linux驱动】I2C驱动框架总结

I2C(Inter-Integrated Circuit)是一种串行通信总线,主要用于连接集成电路。

weixin_45298012的博客 1435

I2C_dev.c设备驱动实现EEPROM读写操作指南

本文还有配套的精品资源,点击获取 简介:本文深入探讨了如何在Linux系统下使用I2C_dev.c设备驱动来读写EEPROM。首先介绍了I2C总线的基本原理,然后详细说明了使用I2C_dev.c框架进行EEPROM读写操作的步骤,包括设备注册、初始化、数据传输和错误处理等。通过具体的应用程序示例,提供了实际操作指导。最终目的是让开发者能够方便地控制EEPROM,同时理解I2...

weixin_42576804的博客 1196

从Datasheet到可用的Verilog模块:手把手教你为N25Q128 SPI Flash写状态机驱动

本文详细介绍了如何从Datasheet到实现可用的Verilog模块,手把手教你为N25Q128 SPI Flash编写状态机驱动。文章涵盖SPI Flash的核心工作机制、数据手册解析方法、Verilog状态机设计实践以及调试与性能优化技巧,特别适合FPGA开发者和硬件设计工程师参考。

weixin_30596023的博客 177

I2C子系统---(4)I2C驱动模型框架

I2C子系统驱动框架前言基本数据结构busdriverapideviceapiadapter 注册client的注册数据收发api总结 前言 在上一篇文章中,我们已经知道设备树中描述的节点是如何联系进系统中去的,本编文章我们来介绍写I2C系统框架有哪些组成部分,以及I2C设备驱动的注册是指什么,以及常用的I2C通用访问接口具体干了啥,主要围绕驱动框架来熟悉这块的模型。 我们了解,I2C驱动模型是基于设备驱动模型,相关的就直接得出结论不展开,其相关见Linux内核驱动模型—设备总线驱动 Linux内核驱动模型

weixin_41884251的博客 2124

Abaqus复合材料层合板仿真

由于复合材料的损伤失效问题过于复杂,解析方法受到数学工具的限制难以实现,而实验也需要高昂的费用和时间成本难以广泛应用,Abaqus针对复合材料提供了专业的建模工具和损伤分析理论来模拟复合材料层合板在各种工况下的失效行为。

JXHXHL的博客 2542

linux内核I2C驱动编程框架简析(一)

文章目录linux内核I2C驱动编程机制struct i2c_client定义如下struct i2c_board_infostruct i2c_driver I2C驱动跟前面介绍的linux内核驱动的platform机制一样,也是总线-设备-驱动模型。同样是使用内核的bus_type结构体定义了一个虚拟总线i2c_bus_type。 bus_type结构体定义如下 /** * struct bus_type - The bus type of the device * * @name: The na

AuvKaixin的博客 649

Cursor+Playwright MCP实战:如何用自然语言一键生成UI自动化测试脚本

本文探讨了如何利用Cursor与Playwright MCP实现自然语言驱动的UI自动化测试脚本生成。通过智能IDE与浏览器自动化协议的结合,开发者可以高效创建稳定的测试脚本,显著提升测试效率与维护性。重点介绍了MCP架构的优势、项目结构最佳实践及团队协作规范,为自动化测试带来革命性改进。

k8l9m0n的博客 442

企业数字化转型的 4A 架构指南:从概念解读到 TOGAF 阶段对应

4A企业架构是中国数字化转型实践中总结的简化框架,包含业务、应用、数据和技术四个架构层。它自上而下形成业务驱动应用的指导关系,自下而上构建技术支撑数据的实现路径,与国际标准TOGAF核心内容高度对应。该模型通过统一语言、战略对齐和系统梳理,有效连接业务需求与IT实施,已成为企业架构规划的实用工具。其分层结构清晰展示了从业务目标到技术落地的完整推导链,特别适合中国企业的数字化转型场景。

友莘居士的博客 2177

[Linux 驱动] -- I2C子系统驱动框架及应用

I2C子系统驱动框架: 应用程序层(app层) i2c driver 层:从设备驱动层(TS Sensor等) 需要和应用层交互(fops cdev); 封装数据,但是不知道数据如何写入到硬件,需要调用adapter层的相关函数去写 i2c core:维护i2c bus,包括i2c driver 和i2c client链表 实现i2c client 和 i2c driver的匹配; 这一...

u014674293的博客 261

Zephyr、FreeRTOS 和 RT-Thread

你是…更适合用嵌入式新手,刚接触 RTOSFreeRTOS(入门简单)IoT 项目开发,需要 BLE/WiFi/MQTTZephyr(协议全)想快速构建可部署的产品Zephyr(模块统一)只做单个任务或简单状态机控制FreeRTOS(轻量)做平台化、持续集成、自动测试Zephyr(CI 支持强)

is0815的博客 2248

I2C子系统驱动框架及应用 (转)

I2C子系统驱动框架: 应用程序层(app层) ——————————————————————————————————– i2c driver层: 从设备驱动层(TS Sensor等) 1. 需要和应用层交互(fops cdev) 2. 封装数据,但是不知道数据如何写入到硬件,需要调用adapter层的相关函数去写 ——————————————————————————————————– ...

weixin_30376509的博客 124

OpenCV图像去畸变实战指南:从原理到参数调优(附完整代码与效果对比)

本文深入解析了OpenCV图像去畸变的原理与实战技巧,详细对比了标准透视、鱼眼及全能型omnidir三种校正函数的核心参数调优方法。通过分析alpha、balance、centerX/Y及focalScale四大参数对输出效果的影响,并结合完整代码与效果对比图,帮助开发者精准校正镜头畸变,提升计算机视觉任务精度。

weixin_29046611的博客 341

基于YOLOv5的仪表读数识别系统:从检测到识别的完整解决方案

随着工业自动化水平的不断提高,仪表读数识别技术在电力系统、石油化工、智能制造等领域发挥着越来越重要的作用。本文提出了一种基于YOLOv5的仪表自动读数识别系统,该系统能够有效区分指针式和数字式仪表,并实现高精度的读数识别。我们详细介绍了系统的整体架构、数据集构建、模型训练策略以及用户界面设计,并提供了完整的代码实现。实验结果表明,本系统在仪表检测和读数识别任务上均取得了优异的表现,为工业现场的自动化监控提供了可靠的技术支持。关键词:仪表读数识别;YOLOv5;目标检测;深度学习;工业自动化。

YOLO 680

linux驱动-i2c子系统框架学习(1)

初识linuxi2c子系统

weixin_49529507的博客 521

【人工智能】RAG如何根据实际需求选择和进行文档解析(如 PDF、Word、TXT、网页等)?

文档解析的核心在于根据解析目标、文档类型和处理量选择合适工具。PDF、Word、TXT和网页各有特性:PDF需区分可编辑与扫描版,Word需处理结构化内容,TXT简单但需注意编码,网页需应对动态内容。解析场景包括提取纯文本、结构化数据、保留格式和批量处理。非技术用户可借助工具如Adobe Acrobat、WPS和在线OCR,技术用户可通过编程实现自动化。通用流程为:明确目标、分析文档属性、选择工具并测试优化。核心是“工具适配需求”,无需追求万能方案。

奶爸的编程之路,也就一周冷个三天 506

linux驱动-i2c子系统框架学习(2)

理解i2c子系统框架

weixin_49529507的博客 776

汉书HE8,好用的汇编代码编写工具

汉书HE8,好用的汇编代码编写工具早期编写汇编代码所用功能强大

大中型超市收银系统(可直接运行)

光步前台收银系统系统功能:商品销售、商品退货、挂单、收银员权限、会员销售、单品取消、整单取消、商品查询、脱机销售、脱机数据上传,基本资料下载,开钱箱、小票打印、收款结算,支持多币种付款方式(现金、储值卡、礼券、微信等),支持多种促销。运行环境:.net 4.0登陆信息用户名:1001 密码:123456内置商品信息,商品编码可输入00001000 - 00010000,测试效果相关功能键F5 结算 F9挂单 F11商品查询 F8退货 Insert单品取消 Del整单取消 F12开钱箱F2 会员 Ctrl+Z退出系统 Home 锁屏 相关源码待公开

Linux驱动第九章:I²C总线驱动子系统

摘要:本文系统介绍了I2C总线通信协议及其在Linux驱动开发中的应用。首先讲解了I2C的基本原理,包括其双线制设计(SCL时钟线和SDA数据线)和主从通信机制。接着分析了Linux内核中的I2C驱动框架,详细说明了i2c_driver、i2c_client等核心数据结构及其操作方法(i2c_master_send/i2c_master_recv)。然后通过具体案例展示了如何编写I2C设备驱动,包括设备树配置、驱动注册、数据收发等关键步骤。最后以温度传感器SI7006为例,实现了基于按键触发的温度和湿度采集

a2123827797的博客 1019

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

高级驱动——三、i2c子系统(与e2prom通信)

一,I2C子系统作用和框架 1,作用: 为I2c从设备驱动的编写提供编程的规范 统一管理i2c总线上的从设备驱动 2,i2c从设备 HDIM ts camera e2prom gsensor 等 3,i2c子系统框架 应用层: app.c ------------------------------------------------ 驱动框架-----i2c子系统 i2c-driver层:i2c从设备驱动层 -----//自己写 作用: 1,与用户层交互 2,知道如何把数据传给用户,但

weixin_49551849的博客 546

SIMATIC S7-1200, S7-1500 PID 控制[手册]

SIMATIC S7-1200, S7-1500 PID 控制[手册]

I2C 子系统与驱动开发入门

在 RK3588 等瑞芯微平台及各类嵌入式 Linux 系统中,I2C 是最常见的低速通信总线。无论是温湿度传感器、陀螺仪、电源管理芯片 (PMIC),还是触控 IC、显示接口转换芯片,绝大多数外设都依赖 I2C 进行控制。 本文将从零开始,构建一个完整的 I2C 设备驱动,掌握从设备树描述到驱动代码实现的全流程,并介绍工业级驱动开发常用的 regmap 框架。

专注Linux内核驱动开发15年+,致力于让天下没有难写的驱动。 788

从零构建:手把手教你编写Linux I2C设备驱动

本文手把手教你从零编写Linux I2C设备驱动,详细讲解I2C子系统架构、设备树配置、驱动框架搭建及通信实现。通过实战案例和代码示例,帮助开发者掌握传感器、存储器等外设的驱动开发技巧,避开常见陷阱,提升嵌入式开发能力。

alice7model的博客 638

Linux驱动——MMC/SPI/I2C

Linux驱动——MMC/SPI/I2C

Hello Mr.Z的博客 493

硬件IIC(I2C子系统)与软件IIC

IIC主要特点就是同步,半双工,多主多从机制,同一时刻只能有一个主机与一个从机通信,设备间的通信是通过开漏进行的,IIC又分为模拟IIC和硬件IIC,模拟IIC就是将俩个GPIO引脚分别当作SDA和SCL,通过高低电平模拟出起始,结束,ACK,NACK信号,硬件IIC依赖于I2C子系统,通过编写驱动层IIC_deriver,通过adapter与硬件进行交互。硬件IIC和模拟IIC的区别?

2301_80371156的博客 496
上一篇: Linux内核中的pinctrl子系统应用实例
下一篇: Ubuntu各个版本的镜像下载地址
hanp_linux
博客等级 码龄10年 139粉丝 22原创
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值