ftdi_sio应用学习笔记 4 - I2C
目录
1. 查找设备
2. 打开设备
3. 写数据
4. 读数据
5. 设置频率
6 验证
6.1 遍历设备
6.2 开关设备
6.3 读写测试
I2C设备最多有6个(FT232H),其他为2个。和之前的设备一样,定义个I2C结构体记录找到的设备。
#define FTDI_DEVICE_MAX_INTEFACE_I2C 2
#define FTDI_DEVICE_MAX_I2C 6
struct ftdi_i2c_info {struct ftdi_i2c_info *next;int i2c_num[FTDI_DEVICE_MAX_INTEFACE_I2C][FTDI_DEVICE_MAX_I2C]; int pid;int vid;char serial_number[64];
};
FTDI设备和I2C设备对应的关系,可以在/sys/bus/usb下找到ttyUSBn(串口的那个文件夹内),在这个文件夹内可以看到i2c设备的信息,例如:
:/sys/bus/usb/devices/2-1/2-1:1.0/ttyUSB0$ ls
driver i2c-1 latency_timer power subsystem uevent
event_char i2c-2 port_number spi_master tty
可以看到该设备(FT4232H)的接口0有2个i2c设备。
1. 查找设备
和串口类似,先找到ttyUSB字符串,然后在这个文件夹内找"i2c-"字符串。
DIR *i2c_dir;
struct dirent *i2c_entry;
int i2c_index = 0;
sprintf(name_path, "/sys/bus/usb/devices/%s:1.%d/%s", entry->d_name, interface, tty_entry->d_name);
i2c_dir = opendir(name_path);
while ((i2c_entry = readdir(i2c_dir)) != NULL) {if (strstr(i2c_entry->d_name, "i2c-") != NULL) { printf("Found:%s\n", i2c_entry->d_name);sscanf(i2c_entry->d_name, "i2c-%d", &dev_list->i2c_num[interface][i2c_index]);i2c_index++;}
}
closedir(i2c_dir);
2. 打开设备
分2种情况,通过pid或通过串口号打开
int ftdi_sio_i2c::open_i2c(int pid, int n, int num)
int ftdi_sio_i2c::open_i2c(char *serial_number, int interface, int num)
参数:
pid - FTDI设备的PID号
n - 需要打开的同PID号的第n个设备
num - 该设备的第num个i2c设备
返回i2c设备的设备句柄。
找到设备的方式和之前的方式一样。
char i2c_path[PATH_MAX];
int fd;
sprintf(i2c_path, "/dev/i2c-%d", dev_list->i2c_num[interface][num]);
printf("open:%s\n", i2c_path);
if ((fd = open(i2c_path, O_RDWR)) < 0) {perror("Failed to open the i2c bus\n");
}
3. 写数据
int ftdi_sio_i2c::write_bytes(int fd, char slave_addr, char reg_addr_width, int reg_addr, unsigned char *pdat, int len)
参数:
fd - open设备时返回的设备句柄
slave_addr - 从设备的地址
reg_addr_width - 从设备内部寄存器地址宽度,有效参数为0/8/16
reg_addr - 从设备内部寄存器地址
pdat - 写入从设备的数据
len - 写入数据长度
写数据需要将地址和数据一起打包到i2c_msg类型的数据中,一个信息就可以写入设备。
if(reg_addr_width == 16) {outbuf[offset++] = (unsigned char)(reg_addr >> 8);outbuf[offset++] = (unsigned char)reg_addr;
} else if(reg_addr_width == 8)outbuf[offset++] = (unsigned char)reg_addr;
memcpy(outbuf + offset, pdat, len);
messages[0].addr = slave_addr;
messages[0].flags = 0;
messages[0].len = total;
messages[0].buf = outbuf;
packets.nmsgs = 1;
packets.msgs = messages; if(ioctl(fd, I2C_RDWR, &packets) < 0) {perror("i2cWrite ioctl fail");free(outbuf);return -1;
}
4. 读数据
int ftdi_sio_i2c::read_bytes(int fd, char slave_addr, char reg_addr_width, int reg_addr, unsigned char *pdat, int len)
参数意义与写数据一样的。
当需要写寄存器地址时,需要2个msg写入设备,第一个msg是写地址,第二个msg是读数据。
messages[0].addr = slave_addr;
messages[0].flags = 0;
messages[0].len = offset;
messages[0].buf = outbuf;
/* The data will get returned in this structure */
messages[1].addr = slave_addr;
messages[1].flags = I2C_M_RD/* | I2C_M_NOSTART*/;
messages[1].len = len;
messages[1].buf = pdat;
/* Send the request to the kernel and get the result back */
packets.msgs = messages;
packets.nmsgs = 2;
如果没有寄存器的地址,只需要1个msg写入设备。
messages[0].addr = slave_addr;
messages[0].flags = I2C_M_RD/* | I2C_M_NOSTART*/;
messages[0].len = len;
messages[0].buf = pdat;
/* Send the request to the kernel and get the result back */
packets.msgs = messages;
packets.nmsgs = 1;
5. 设置频率(失败)
一般的I2C设备并不能支持直接修改i2c的频率,这里在内核驱动中添加频率的属性参数。由于之前是一个设备共用一个i2c_clk的参数,所以只在ttyUSB设备里面增加i2c_clk属性。
static ssize_t ftdi_mpsse_show_i2c_clk(struct device *dev,struct device_attribute *attr, char *buf)
{struct usb_serial_port *port = to_usb_serial_port(dev);struct ftdi_private *priv = usb_get_serial_port_data(port);return sprintf(buf, "%d\n", priv->i2c_clk - 1);
}static ssize_t ftdi_mpsse_set_i2c_clk(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{struct usb_serial_port *port = to_usb_serial_port(dev);struct ftdi_private *priv = usb_get_serial_port_data(port);priv->i2c_clk = simple_strtoul(buf, NULL, 10) + 1;return count;
}
static DEVICE_ATTR(i2c_clk, S_IWUSR | S_IRUSR, ftdi_mpsse_show_i2c_clk, ftdi_mpsse_set_i2c_clk);
注意,i2c_clk的值要减一,即i2c_clk的值为0时最快,但是在驱动中的值是1。
在初始化中添加初始化这个属性:
device_create_file(&port->dev, &dev_attr_i2c_clk);
在释放设备中删掉这个属性:
device_remove_file(&port->dev, &dev_attr_i2c_clk);
这样就可以在ttyUSBn的文件夹中找到这个属性(i2c_clk):
:/sys/bus/usb/devices/1-2/1-2:1.0/ttyUSB0$ ls
driver i2c-1 i2c_clk port_number spi_master tty
event_char i2c-2 latency_timer power subsystem uevent
在/sys/class/tty/里面也可以看到这个属性
:/sys/class/tty/ttyUSB0/device$ ls
driver i2c-1 i2c_clk port_number spi_master tty
event_char i2c-2 latency_timer power subsystem uevent
只要写这个文件就可以改变设备的i2c频率,和打开设备一样,提供2个函数设置频率,由于整个设备都是一个频率,所以这里不区分interface(如果需要区分interface或者每个i2c独立设置频率,则需要修改ftdi_sio_i2c.c里面频率部分)
int ftdi_sio_i2c::set_freq(int pid, int n, int freq)
int ftdi_sio_i2c::set_freq(char *serial_number, int freq)
这里有一个问题,如果改动过频率,读写就会提示错误,ACK错误,不知道原因,所以这个设置频率的方式有问题。
6 验证
使用FT4232H模块验证。
6.1 遍历设备
ftdi_sio_i2c i2c;
i2c.find_devices();i2c.free_devices();
打印结果:
$ sudo ./ftdi_sio_app
serial number:FT9PQ9R2
Found:i2c-1
Found:i2c-2
Found:i2c-3
Found:i2c-4
6.2 开关设备
打开FT4232H的第一个I2C。
fd = i2c.open_i2c((char *)"FT9PQ9R2", 0, 0);i2c.close_i2c(fd);
打印结果:
$ sudo ./ftdi_sio_app
serial number:FT9PQ9R2
Found:i2c-1
Found:i2c-2
Found:i2c-3
Found:i2c-4
open:/dev/i2c-1
6.3 读写测试
将FT4232H的AD4和AD5分别接到EEPROM的SCL和SDA脚上。定义EEPROM的地址和数据长度
#define EEPROM_ADDR_WIDTH 16
#define I2C_LEN 16
写入数据随机产生,然后再写入EEPROM
printf("i2c write data:\n");
srand(time(NULL));
for(int i = 0; i < (int)sizeof(wr_buf); i++) {wr_buf[i] = (unsigned char)rand();
}
printf(" 0 1 2 3 4 5 6 7 8 9 a b c d e f");
for(int i = 0; i < I2C_LEN; i++) {if((i % 16) == 0) {printf("\n%2x: ", i);}printf(" %2x ", wr_buf[i]);
}
printf("\n");ret = i2c->write_bytes(fd, 0x50, EEPROM_ADDR_WIDTH, 0, wr_buf, sizeof(wr_buf));
if(ret < 0) {printf("write eeprom fail\n");return;
}
再从EEPROM读出这笔数据,并比较判断
for(int i = 0; i < I2C_LEN; i++) {rd_buf[i] = 0;
}
ret = i2c->read_bytes(fd, 0x50, EEPROM_ADDR_WIDTH, 0, rd_buf, sizeof(rd_buf));
if(ret < 0) {printf("read eeprom fail\n");return;
}
printf("Read value from register\n");
printf(" 0 1 2 3 4 5 6 7 8 9 a b c d e f");
for(int i = 0; i < I2C_LEN; i++) {if((i % 16) == 0) {printf("\n%2x: ", i);}printf(" %2x ", rd_buf[i]);
}
printf("\n");
测试速度可以看到速度大约是400KHz以下。
相关文章:
ftdi_sio应用学习笔记 4 - I2C
目录 1. 查找设备 2. 打开设备 3. 写数据 4. 读数据 5. 设置频率 6 验证 6.1 遍历设备 6.2 开关设备 6.3 读写测试 I2C设备最多有6个(FT232H),其他为2个。和之前的设备一样,定义个I2C结构体记录找到的设备。 #define FT…...
如何更好的把控软件测试质量
如何更好的把控软件测试质量 在软件开发过程中,测试是确保软件质量、稳定性和用户体验的重要环节。随着需求的不断变化以及技术的不断进步,如何更好的把控软件测试质量已成为一个不可忽视的话题。本文将从几个维度探讨确保软件质量的方法和方案…...
“漫步北京”小程序及“气象景观数字化服务平台”上线啦
随着科技的飞速发展,智慧旅游已成为现代旅游业的重要趋势。近日,北京万云科技有限公司联合北京市气象服务中心,打造的“气象景观数字化服务平台“和“漫步北京“小程序已经上线,作为智慧旅游的典型代表,以其丰富的功能…...
SOL链上的 Meme 生态发展:从文化到创新的融合#dapp开发#
一、引言 随着区块链技术的不断发展,Meme 文化在去中心化领域逐渐崭露头角。从 Dogecoin 到 Shiba Inu,再到更多细分的 Meme 项目,这类基于网络文化的加密货币因其幽默和社区驱动力吸引了广泛关注。作为近年来备受瞩目的区块链平台之一&…...
身份证实名认证API接口助力电商购物安全
亲爱的网购达人们,你们是否曾经因为网络上的虚假信息和诈骗而感到困扰?在享受便捷的网购乐趣时,如何确保交易安全成为了我们共同关注的话题。今天,一起来了解一下翔云身份证实名认证接口如何为电子商务保驾护航,让您的…...
【过程控制系统】第6章 串级控制系统
目录 6. l 串级控制系统的概念 6.1.2 串级控制系统的组成 6.l.3 串级控制系统的工作过程 6.2 串级控制系统的分析 6.2.1 增强系统的抗干扰能力 6.2.2 改善对象的动态特性 6.2.3 对负荷变化有一定的自适应能力 6.3 串级控制系统的设计 6.3.1 副回路的选择 2.串级系…...
YOLOv11融合针对小目标FFCA-YOPLO中的FEM模块及相关改进思路
YOLOv11v10v8使用教程: YOLOv11入门到入土使用教程 YOLOv11改进汇总贴:YOLOv11及自研模型更新汇总 《FFCA-YOLO for Small Object Detection in Remote Sensing Images》 一、 模块介绍 论文链接:https://ieeexplore.ieee.org/document/10…...
qt+opengl 三维物体加入摄像机
1 在前几期的文章中,我们已经实现了三维正方体的显示了,那我们来实现让物体的由远及近,和由近及远。这里我们需要了解一个概念摄像机。 1.1 摄像机定义:在世界空间中位置、观察方向、指向右侧向量、指向上方的向量。如下图所示: …...
day05(单片机高级)PCB基础
目录 PCB基础 什么是PCB?PCB的作用? PCB的制作过程 PCB板的层数 PCB设计软件 安装立创EDA PCB基础 什么是PCB?PCB的作用? PCB(Printed Circuit Board),中文名称为印制电路板,又称印刷…...
全球天气预报5天-经纬度版免费API接口教程
接口简介: 获取全球任意地区未来5天天气预报,必须传经纬度参数。可先调用【位置坐标】分类下相关接口获取地区经纬度坐标。 请求地址: https://cn.apihz.cn/api/tianqi/tqybjw5.php 请求方式: POST或GET。 请求参数:…...
Shell编程8
声明! 学习视频来自B站up主 **泷羽sec** 有兴趣的师傅可以关注一下,如涉及侵权马上删除文章,笔记只是方便各位师傅的学习和探讨,文章所提到的网站以及内容,只做学习交流,其他均与本人以及泷羽sec团队无关&a…...
python语言基础-5 进阶语法-5.5 上下文管理协议(with语句)
声明:本内容非盈利性质,也不支持任何组织或个人将其用作盈利用途。本内容来源于参考书或网站,会尽量附上原文链接,并鼓励大家看原文。侵删。 5.5 上下文管理协议(with语句)(参考链接࿱…...
自动驾驶3D目标检测综述(三)
前两篇综述阅读理解放在这啦,有需要自行前往观看: 第一篇:自动驾驶3D目标检测综述(一)_3d 目标检测-CSDN博客 第二篇:自动驾驶3D目标检测综述(二)_子流行稀疏卷积 gpu实现-CSDN博客…...
【GESP】C++三级练习 luogu-B3661, [语言月赛202209] 排排
三级知识点一维数组练习,除了应用了数组以外,其余逻辑比较简单,适合初学者。 题目题解详见:https://www.coderli.com/gesp-3-luogu-b3661/ 【GESP】C三级练习 luogu-B3661, [语言月赛202209] 排排队 | OneCoder三级知识点一维数…...
【PPTist】添加PPT模版
前言:这篇文章来探索一下如何应用其他的PPT模版,给一个下拉菜单,列出几个项目中内置的模版 PPT模版数据 (一)增加菜单项 首先在下面这个菜单中增加一个“切换模版”的菜单项,点击之后在弹出框中显示所有的…...
大疆上云api开发
目前很多公司希望使用上云api开发自己的无人机平台,但是官网资料不是特别全,下面浅谈一下本人开发过程中遇到的一系列问题。 本人使用机场为大疆机场2,飞机为M3TD,纯内网使用 部署 链接: 上云api代码. 首先从github上面拉去代码 上云api代码github. 后…...
IDEA2023 SpringBoot整合MyBatis(三)
一、数据库表 CREATE TABLE students (id INT AUTO_INCREMENT PRIMARY KEY,name VARCHAR(100) NOT NULL,age INT,gender ENUM(Male, Female, Other),email VARCHAR(100) UNIQUE,phone_number VARCHAR(20),address VARCHAR(255),date_of_birth DATE,enrollment_date DATE,cours…...
【Apache Paimon】-- 6 -- 清理过期数据
目录 1、简要介绍 2、操作方式和步骤 2.1、调整快照文件过期时间 2.2、设置分区过期时间 2.2.1、举例1 2.2.2、举例2 2.3、清理废弃文件 3、参考 1、简要介绍 清理 paimon (表)过期数据可以释放存储空间,优化资源利用并提升系统运行效率等。本文将介绍如何清理 Paim…...
C语言数据结构——详细讲解 双链表
从单链表到双链表:数据结构的演进与优化 前言一、单链表回顾二、单链表的局限性三、什么是双链表四、双链表的优势1.双向遍历2.不带头双链表的用途3.带头双链表的用途 五、双链表的操作双链表的插入操作(一)双链表的尾插操作(二&a…...
Shell脚本基础(4):条件判断
内容预览 ≧∀≦ゞ Shell脚本基础(4):条件判断声明导语基本的if语句结构数值比较运算符文件测试运算符扩展:使用elif和else使用&&和||结合条件判断小结 Shell脚本基础(4):条件判断 声明…...
springboot 百货中心供应链管理系统小程序
一、前言 随着我国经济迅速发展,人们对手机的需求越来越大,各种手机软件也都在被广泛应用,但是对于手机进行数据信息管理,对于手机的各种软件也是备受用户的喜爱,百货中心供应链管理系统被用户普遍使用,为方…...
屋顶变身“发电站” ,中天合创屋面分布式光伏发电项目顺利并网!
5月28日,中天合创屋面分布式光伏发电项目顺利并网发电,该项目位于内蒙古自治区鄂尔多斯市乌审旗,项目利用中天合创聚乙烯、聚丙烯仓库屋面作为场地建设光伏电站,总装机容量为9.96MWp。 项目投运后,每年可节约标煤3670…...
12.找到字符串中所有字母异位词
🧠 题目解析 题目描述: 给定两个字符串 s 和 p,找出 s 中所有 p 的字母异位词的起始索引。 返回的答案以数组形式表示。 字母异位词定义: 若两个字符串包含的字符种类和出现次数完全相同,顺序无所谓,则互为…...
tree 树组件大数据卡顿问题优化
问题背景 项目中有用到树组件用来做文件目录,但是由于这个树组件的节点越来越多,导致页面在滚动这个树组件的时候浏览器就很容易卡死。这种问题基本上都是因为dom节点太多,导致的浏览器卡顿,这里很明显就需要用到虚拟列表的技术&…...
3-11单元格区域边界定位(End属性)学习笔记
返回一个Range 对象,只读。该对象代表包含源区域的区域上端下端左端右端的最后一个单元格。等同于按键 End 向上键(End(xlUp))、End向下键(End(xlDown))、End向左键(End(xlToLeft)End向右键(End(xlToRight)) 注意:它移动的位置必须是相连的有内容的单元格…...
零基础在实践中学习网络安全-皮卡丘靶场(第九期-Unsafe Fileupload模块)(yakit方式)
本期内容并不是很难,相信大家会学的很愉快,当然对于有后端基础的朋友来说,本期内容更加容易了解,当然没有基础的也别担心,本期内容会详细解释有关内容 本期用到的软件:yakit(因为经过之前好多期…...
视频行为标注工具BehaviLabel(源码+使用介绍+Windows.Exe版本)
前言: 最近在做行为检测相关的模型,用的是时空图卷积网络(STGCN),但原有kinetic-400数据集数据质量较低,需要进行细粒度的标注,同时粗略搜了下已有开源工具基本都集中于图像分割这块,…...
LLMs 系列实操科普(1)
写在前面: 本期内容我们继续 Andrej Karpathy 的《How I use LLMs》讲座内容,原视频时长 ~130 分钟,以实操演示主流的一些 LLMs 的使用,由于涉及到实操,实际上并不适合以文字整理,但还是决定尽量整理一份笔…...
6个月Python学习计划 Day 16 - 面向对象编程(OOP)基础
第三周 Day 3 🎯 今日目标 理解类(class)和对象(object)的关系学会定义类的属性、方法和构造函数(init)掌握对象的创建与使用初识封装、继承和多态的基本概念(预告) &a…...
鸿蒙(HarmonyOS5)实现跳一跳小游戏
下面我将介绍如何使用鸿蒙的ArkUI框架,实现一个简单的跳一跳小游戏。 1. 项目结构 src/main/ets/ ├── MainAbility │ ├── pages │ │ ├── Index.ets // 主页面 │ │ └── GamePage.ets // 游戏页面 │ └── model │ …...
