I2C简单实验之LT6911UXC读取ChipID

原创 二月半 2023-06-09 15:12

 近期有点全身心投入到了嵌入式驱动的开发意思了,起早贪黑的学习。不过也是,人生的路都是在不断地学习中度过的。对于干了几年的硬件工程师而言,不说硬件是不是很牛了,就是想换换脑子,整天三极管、电阻、电容的,确实让人乏味。思来想去,硬件是软件的基座,驱动是软件沟通硬件的桥梁。倒不如自己整点知识,也方便自己以后调试硬件不是,再说了从软件角度去理解硬件思维,会有很多不同的收获不是。

 奋战了一个月,倒是把驱动的基本框架了解七七八八了,兴致使然,图像采集感觉还不错,公司有产品当开发板,也是省下了大部分的学习成本。

 硬件基本结构就是:SOC平台为瑞芯微,视频桥接芯片是LT6911UXC,千兆网络接口和基本的电源电路,还有的最小核心板组成就不多说了。

 总归是要初始化和调试LT6911UXC的,那么最基础的当然是通过固定的总线去访问和配置其寄存器了,而大多这类芯片都是用的I2C,LT6911UXC也不例外。于是重点看了下I2C总线的驱动实现框架。那么就在已有的基本驱动框架下实验下了

一、基本的驱动框架


#include <linux/init.h>
#include <linux/module.h>
static int lt6911_driver_init(void)
{
    return 0;
}

static void lt6911_driver_exit(void)
{
}

module_init(lt6911_driver_init);
module_exit(lt6911_driver_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("LY");
MODULE_VERSION("V1.0");


二、 增加I2C的框架

1. 添加一个I2C设备

这一步是通过i2c_add_driver(driver)这个API函数实现的,那么就在驱动加载的时候使用这个函数


static int lt6911_driver_init(void)
{
    int ret;
    printk("==>this is lt6911_driver_init\n");
    ret= i2c_add_driver(&lt6911_driver);
    if(ret<0){
        printk("==>lt6911 i2c driver add error\n");
        return 0;
    }

    return 0;
}


那么要按照以上的实现方式,必须要先实现一个I2C设备,这个设备是通过i2c_driver这个结构体实现的


struct i2c_driver lt6911_driver={
    .probe=lt6911_driver_probe,
    .remove=lt6911_driver_remove,
    .driver={
        .owner=THIS_MODULE,
        .name="lt6911uxc",          //没有设备树使用的匹配名
        .of_match_table=lt6911_id   //使用设备树匹配的设备列表
    },
.id_table=lt6911_id_table       //无论使不使用设备树,这里必须实现
};


2. 实现两个函数

从上一步的i2c_driver设备结构体可以看出,需要实现probe和remove函数。probe函数是当I2C设备正确挂载后所执行的函数,remove函数是I2C设备卸载时所执行的函数。

probe函数


int lt6911_driver_probe(struct i2c_client *client, const struct i2c_device_id *id)
{
    printk("==>this is lt6911_driver_probe\n");
    return 0;
}


remove函数


int lt6911_driver_remove(struct i2c_client *client)
{
    printk("==>this is lt6911_driver_remove\n");
    return 0;
}


3. 在设备树中对应的I2C下添加此设备信息

上面两步完成后,编译驱动为KO文件,通过insmod是可以加载此驱动的,但是会发现加载后只会执行到init这一步。那是因为我们没有在设备树中添加相应设备信息。我的板卡是挂在了I2C2上的,于是就进行下面操作


&i2c2{
status = "okay";
clock-frequency = <100000>;
lt6911uxc:lt6911uxc@56{
        compatible = "lt6911uxc";
status = "okay";
        reg = <0x56>;      //设备的芯片地址,手册都会说明             
interrupt-parent = <&gpio3>;
interrupts = <RK_PA5 IRQ_TYPE_LEVEL_LOW>;
rst-gpio =  <&gpio4 RK_PA1 GPIO_ACTIVE_LOW>;

pinctrl-names="default";
pinctrl-0=<&lt6911_rstn_gpio>;
};

};


然后重新编译内核,烧录开发板。再此进行加载KO文件,发现可以打印probe函数中设置的打印语句了

4. 实现最简单的读取Chip ID

框架都搭建完成,接下来当然是与芯片交流一下了,阅读了下LT6911UXC相关手册,要想读取寄存器的数据还得改变它的I2C工作模式和切换bank.原因是其内部集成了MCU,而这个MCU也是通过这个I2C在内部已经连接了LT6911UXC处理核心。

 

 

那么就要实现i2c的write和read函数了。驱动程序中I2C的读写都是以包的形式发送和接收的,所以我们先封包。封包使用的结构体是struct i2c_msg,最终的读写函数实现如下

static void lt6911_i2c_write( u16 reg, u8 *values, u32 n)
{
    struct i2c_msg msgs[2];
    int err, i;
    u8 data[8];
    u8 bank = reg >> 8;
    u8 reg_addr = reg & 0xFF;
    u8 buf[2] = {0xFF, bank};

    data[0] = reg_addr;
    for (i = 0; i < n; i++)
    data[i + 1] = values[i];

    /* write bank */
    msgs[0].addr = lt6911_client->addr;
    msgs[0].flags = 0;
    msgs[0].len = 2;
    msgs[0].buf = buf;

    /* write reg data */
    msgs[1].addr = lt6911_client->addr;
    msgs[1].flags = 0;
    msgs[1].len = 1 + n;
    msgs[1].buf = data;

    err = i2c_transfer(lt6911_client->adapter, msgs, ARRAY_SIZE(msgs));
    if(err < 0){
         printk("==>transfer error %d\n",err);
    }
}

static int lt6911_i2c_read(u16 reg,u8 *values, u32 n)
{
    
    int ret;
    u8 bank = reg >> 8;
    u8 reg_addr = reg & 0xFF;
    u8 bank_buff[2]={0xff,bank};
    struct i2c_msg msgs[]={
        [0]={
            .addr=lt6911_client->addr,
            .flags=0,
            .len=2,
            .buf=bank_buff,
        
        },
        [1]={
            .addr=lt6911_client->addr,
            .flags=0,
            .len=sizeof(reg_addr),
            .buf=&reg_addr,
        
        },
        [2]={
            .addr=lt6911_client->addr,
            .flags=1,
            .len=sizeof(values),
            .buf=values,           
        }
    };
    ret = i2c_transfer(lt6911_client->adapter, msgs, ARRAY_SIZE(msgs));
    if(ret < 0){
         printk("==>transfer error %d\n",ret);
         return ret;
    }
    return 0;
}

读写函数实现没问题了,那么就在init函数中添加调用就可以了

    lt6911_i2c_write( 0x80ee, &i2c_enable, 1);
    lt6911_i2c_read(0x8100,&rdata,1);
    printk("==>lt6911_id is %#x\n",rdata);

编译后,再次加载KO文件,发现在写函数中i2c_transfer函数返回值为-6,意思是NO ACK。怎么回事呢,经过询问最近比较火热的Chatgpt,它告诉我了个答案

 

 

也就是我们给了设备地址,但是这个函数会将设备地址左移后然后增加读写位,才是真正的发送的地址。而通过开发板命令行中使用I2C工具(命令:i2cdump -y -f 2 0x56)来读取设备寄存器,通过逻辑分析仪抓取后得到

 

 

0x56左移一位再加上写标志位,确实是0xAC啊,经过资料的一番查找,对于I2C设备地址,都是七位。而资料给的发送格式0x56是带有读写位的。那么去掉读写位,也就是将0x56右移一位,在最高位加一个零,就得到了0x2B,再次使用I2C工具试下

 

 

就这样成功了,翻阅了大量资料。对于一个初学者而言都是在不断地怀疑和比较中找到了答案。还是挺兴奋的。所以我们就要把设备树中的配置更改下

&i2c2{
status = "okay";
clock-frequency = <100000>;
    lt6911uxc:lt6911uxc@56{
        compatible = "lt6911uxc";
        status = "okay";
        reg = <0x2b>;      //设备的芯片地址,手册都会说明             
        interrupt-parent = <&gpio3>;
        interrupts = <RK_PA5 IRQ_TYPE_LEVEL_LOW>;
        rst-gpio =  <&gpio4 RK_PA1 GPIO_ACTIVE_LOW>;

        pinctrl-names="default";
        pinctrl-0=<&lt6911_rstn_gpio>;
    };

};

编译内核,烧录。读chipID成功

 

 

总结

i2c的读写最关键的就是设备地址了,驱动的框架是固定的。

学习就应该在怀疑中调试,在调试中比较,在比较中得到答案。我们都是站在巨人的肩膀上的,当自己出现问题时,最好是看看巨人都是怎么做的。

二月半 在自学的道路不断前行着,【公众号】自学者的博客园
评论
  • By Toradex 秦海1). 简介嵌入式平台设备基于Yocto Linux 在开发后期量产前期,为了安全以及提高启动速度等考虑,希望将 ARM 处理器平台的 Debug Console 输出关闭,本文就基于 NXP i.MX8MP ARM 处理器平台来演示相关流程。 本文所示例的平台来自于 Toradex Verdin i.MX8MP 嵌入式平台。  2. 准备a). Verdin i.MX8MP ARM核心版配合Dahlia载板并
    hai.qin_651820742 2025-01-07 14:52 48浏览
  • 这篇内容主要讨论三个基本问题,硅电容是什么,为什么要使用硅电容,如何正确使用硅电容?1.  硅电容是什么首先我们需要了解电容是什么?物理学上电容的概念指的是给定电位差下自由电荷的储藏量,记为C,单位是F,指的是容纳电荷的能力,C=εS/d=ε0εrS/4πkd(真空)=Q/U。百度百科上电容器的概念指的是两个相互靠近的导体,中间夹一层不导电的绝缘介质。通过观察电容本身的定义公式中可以看到,在各个变量中比较能够改变的就是εr,S和d,也就是介质的介电常数,金属板有效相对面积以及距离。当前
    知白 2025-01-06 12:04 173浏览
  • 彼得·德鲁克被誉为“现代管理学之父”,他的管理思想影响了无数企业和管理者。然而,关于他的书籍分类,一种流行的说法令人感到困惑:德鲁克一生写了39本书,其中15本是关于管理的,而其中“专门写工商企业或为企业管理者写的”只有两本——《为成果而管理》和《创新与企业家精神》。这样的表述广为流传,但深入探讨后却发现并不完全准确。让我们一起重新审视这一说法,解析其中的矛盾与根源,进而重新认识德鲁克的管理思想及其著作的真正价值。从《创新与企业家精神》看德鲁克的视角《创新与企业家精神》通常被认为是一本专为企业管
    优思学院 2025-01-06 12:03 124浏览
  • 本文介绍Linux系统更换开机logo方法教程,通用RK3566、RK3568、RK3588、RK3576等开发板,触觉智能RK3562开发板演示,搭载4核A53处理器,主频高达2.0GHz;内置独立1Tops算力NPU,可应用于物联网网关、平板电脑、智能家居、教育电子、工业显示与控制等行业。制作图片开机logo图片制作注意事项(1)图片必须为bmp格式;(2)图片大小不能大于4MB;(3)BMP位深最大是32,建议设置为8;(4)图片名称为logo.bmp和logo_kernel.bmp;开机
    Industio_触觉智能 2025-01-06 10:43 87浏览
  • 村田是目前全球量产硅电容的领先企业,其在2016年收购了法国IPDiA头部硅电容器公司,并于2023年6月宣布投资约100亿日元将硅电容产能提升两倍。以下内容主要来自村田官网信息整理,村田高密度硅电容器采用半导体MOS工艺开发,并使用3D结构来大幅增加电极表面,因此在给定的占位面积内增加了静电容量。村田的硅技术以嵌入非结晶基板的单片结构为基础(单层MIM和多层MIM—MIM是指金属 / 绝缘体/ 金属) 村田硅电容采用先进3D拓扑结构在100um内,使开发的有效静电容量面积相当于80个
    知白 2025-01-07 15:02 76浏览
  • 根据Global Info Research项目团队最新调研,预计2030年全球封闭式电机产值达到1425百万美元,2024-2030年期间年复合增长率CAGR为3.4%。 封闭式电机是一种电动机,其外壳设计为密闭结构,通常用于要求较高的防护等级的应用场合。封闭式电机可以有效防止外部灰尘、水分和其他污染物进入内部,从而保护电机的内部组件,延长其使用寿命。 环洋市场咨询机构出版的调研分析报告【全球封闭式电机行业总体规模、主要厂商及IPO上市调研报告,2025-2031】研究全球封闭式电机总体规
    GIRtina 2025-01-06 11:10 104浏览
  • 在智能家居领域中,Wi-Fi、蓝牙、Zigbee、Thread与Z-Wave等无线通信协议是构建短距物联局域网的关键手段,它们常在实际应用中交叉运用,以满足智能家居生态系统多样化的功能需求。然而,这些协议之间并未遵循统一的互通标准,缺乏直接的互操作性,在进行组网时需要引入额外的网关作为“翻译桥梁”,极大地增加了系统的复杂性。 同时,Apple HomeKit、SamSung SmartThings、Amazon Alexa、Google Home等主流智能家居平台为了提升市占率与消费者
    华普微HOPERF 2025-01-06 17:23 146浏览
  • 大模型的赋能是指利用大型机器学习模型(如深度学习模型)来增强或改进各种应用和服务。这种技术在许多领域都显示出了巨大的潜力,包括但不限于以下几个方面: 1. 企业服务:大模型可以用于构建智能客服系统、知识库问答系统等,提升企业的服务质量和运营效率。 2. 教育服务:在教育领域,大模型被应用于个性化学习、智能辅导、作业批改等,帮助教师减轻工作负担,提高教学质量。 3. 工业智能化:大模型有助于解决工业领域的复杂性和不确定性问题,尽管在认知能力方面尚未完全具备专家级的复杂决策能力。 4. 消费
    丙丁先生 2025-01-07 09:25 83浏览
  • 根据环洋市场咨询(Global Info Research)项目团队最新调研,预计2030年全球无人机锂电池产值达到2457百万美元,2024-2030年期间年复合增长率CAGR为9.6%。 无人机锂电池是无人机动力系统中存储并释放能量的部分。无人机使用的动力电池,大多数是锂聚合物电池,相较其他电池,锂聚合物电池具有较高的能量密度,较长寿命,同时也具有良好的放电特性和安全性。 全球无人机锂电池核心厂商有宁德新能源科技、欣旺达、鹏辉能源、深圳格瑞普和EaglePicher等,前五大厂商占有全球
    GIRtina 2025-01-07 11:02 74浏览
  • 每日可见的315MHz和433MHz遥控模块,你能分清楚吗?众所周知,一套遥控设备主要由发射部分和接收部分组成,发射器可以将控制者的控制按键经过编码,调制到射频信号上面,然后经天线发射出无线信号。而接收器是将天线接收到的无线信号进行解码,从而得到与控制按键相对应的信号,然后再去控制相应的设备工作。当前,常见的遥控设备主要分为红外遥控与无线电遥控两大类,其主要区别为所采用的载波频率及其应用场景不一致。红外遥控设备所采用的射频信号频率一般为38kHz,通常应用在电视、投影仪等设备中;而无线电遥控设备
    华普微HOPERF 2025-01-06 15:29 131浏览
我要评论
0
点击右上角,分享到朋友圈 我知道啦
请使用浏览器分享功能 我知道啦