i2c 使用
简介
face-rk3399 开发板上有 9 个片上 i2c 控制器,各个 i2c 的使用情况如下表:
本文主要描述如何在该开发板上配置 i2c。
配置 i2c 可分为两大步骤:
定义和注册 i2c 设备
定义和注册 i2c 驱动
下面以配置 gsl3680 为例。
定义和注册 i2c 设备
在注册i2c设备时,需要结构体 i2c_client 来描述 i2c 设备。然而在标准linux中,用户只需要提供相应的 i2c 设备信息,linux就会根据所提供的信息构造 i2c_client 结构体。
用户所提供的 i2c 设备信息以节点的形式写到 dts 文件中,如下所示:
kernel/arch/arm64/boot/dts/rockchip/rk3399-firefly-mini-edp.dts &i2c4 { status = “okay”; gsl3680: gsl3680@41 { compatible = “gslx680”; reg = 《0x41》; screen_max_x = 《1536》; screen_max_y = 《2048》; touch-gpio = 《&gpio1 20 irq_type_level_low》; reset-gpio = 《&gpio0 12 gpio_active_high》; }; };
定义和注册 i2c 驱动
定义 i2c 驱动
在定义 i2c 驱动之前,用户首先要定义变量 of_device_id 和 i2c_device_id 。
of_device_id 用于在驱动中调用dts文件中定义的设备信息,其定义如下所示:
static struct of_device_id gsl_ts_ids[] = { {.compatible = “gslx680”}, {} };
定义变量 i2c_device_id:
static const struct i2c_device_id gsl_ts_id[] = { {gslx680_i2c_name, 0}, {} }; module_device_table(i2c, gsl_ts_id);
i2c_driver 如下所示:
static struct i2c_driver gsl_ts_driver = { .driver = { .name = gslx680_i2c_name, .owner = this_module, .of_match_table = of_match_ptr(gsl_ts_ids), }, #ifndef config_has_earlysuspend //.suspend = gsl_ts_suspend, //.resume = gsl_ts_resume, #endif .probe = gsl_ts_probe, .remove = gsl_ts_remove, .id_table = gsl_ts_id, };
注:变量id_table指示该驱动所支持的设备。
注册 i2c 驱动
使用i2c_add_driver函数注册 i2c 驱动。
i2c_add_driver(&gsl_ts_driver);
在调用 i2c_add_driver 注册 i2c 驱动时,会遍历 i2c 设备,如果该驱动支持所遍历到的设备,则会调用该驱动的 probe 函数。
通过 i2c 收发数据
在注册好 i2c 驱动后,即可进行 i2c 通讯。
向从机发送信息:
int i2c_master_send(const struct i2c_client *client, const char *buf, int count) { int ret; struct i2c_adapter *adap = client-》adapter; struct i2c_msg msg; msg.addr = client-》addr; msg.flags = client-》flags & i2c_m_ten; msg.len = count; msg.buf = (char *)buf; ret = i2c_transfer(adap, &msg, 1); /* + if everything went ok (i.e. 1 msg transmitted), return #bytes + transmitted, else error code. */ return (ret == 1) ? count : ret; }
向从机读取信息:
int i2c_master_recv(const struct i2c_client *client, char *buf, int count) { struct i2c_adapter *adap = client-》adapter; struct i2c_msg msg; int ret; msg.addr = client-》addr; msg.flags = client-》flags & i2c_m_ten; msg.flags |= i2c_m_rd; msg.len = count; msg.buf = buf; ret = i2c_transfer(adap, &msg, 1); /* + if everything went ok (i.e. 1 msg received), return #bytes received, + else error code. */ return (ret == 1) ? count : ret; } export_symbol(i2c_master_recv);
faqs
q1: 通信失败,出现这种log:”timeout, ipd: 0x00, state: 1”该如何调试?
a1: 请检查硬件上拉是否给电。
q2: 调用i2c_transfer返回值为-6?
a2: 返回值为-6表示为nack错误,即对方设备无应答响应,这种情况一般为外设的问题,常见的有以下几种情况:
i2c地址错误,解决方法是测量i2c波形,确认是否i2c 设备地址错误;
i2c slave 设备不处于正常工作状态,比如未给电,错误的上电时序等;
时序不符合 i2c slave设备所要求也会产生nack信号。
q3: 当外设对于读时序要求中间是stop信号不是repeat start信号的时候,该如何处理?
a3: 这时需要调用两次i2c_transfer, i2c read 拆分成两次,修改如下:
static int i2c_read_bytes(struct i2c_client *client, u8 cmd, u8 *data, u8 data_len) { struct i2c_msg msgs[2]; int ret; u8 *buffer; buffer = kzalloc(data_len, gfp_kernel); if (!buffer) return -enomem;; msgs[0].addr = client-》addr; msgs[0].flags = client-》flags; msgs[0].len = 1; msgs[0].buf = &cmd; ret = i2c_transfer(client-》adapter, msgs, 1); if (ret 《 0) { dev_err(&client-》adapter-》dev, “i2c read failed\n”); kfree(buffer); return ret; } msgs[1].addr = client-》addr; msgs[1].flags = client-》flags | i2c_m_rd; msgs[1].len = data_len; msgs[1].buf = buffer; ret = i2c_transfer(client-》adapter, &msgs[1], 1); if (ret 《 0) dev_err(&client-》adapter-》dev, “i2c read failed\n”); else memcpy(data, buffer, data_len); kfree(buffer); return ret; }
目前思必驰已经有明确的上市计划,首选国内资本市场
应用机器视觉系统进行导航机器人的设计
YCR单向可控硅系列
物联网技术正在加速推动着零售行业转型升级
高侧电流传感器显示正负电源-High-Side Positi
fireflyFace-RK3399主板I2C控制器介绍
车载芯片的发展趋势是什么?GPU和ASIC的发展方向与应用的概述
预计爱立信年底全球5G用户数达1.9亿,到2025年底将达到28亿
高频/射频信号及视频压缩编码的基本概念
有毒有害气体检测仪在环保监测领域的应用
Cypress全新West Bridge控制器支持USB 3.0
当无人驾驶汽车闯了红灯 谁该买单?
脚本语言和编程语言的区别
VR将成为数字化工业重要环节
Overstock旗下区块链风投子公司Medic即将推出首个加密代币交易平台
业界要闻:奥士康上半年营收1亿元、和舰A股挂牌、印度通膨5月创新高
德媒:中国今年卫星发射已达20次打破历史纪录
信利光电在上市大考前夕突遇变数
51Talk获得新专利,虚拟现实外语学习即将到来
工程师电子制作故事:三轮智能遥控车(图文)