NUCLEO-F411RE RT-Thread 体验 (6) - GCC环境 I2C驱动移植以及i2c-tool的编写

news2024/9/9 3:59:15

NUCLEO-F411RE RT-Thread 体验 (6) - GCC环境 I2C驱动移植以及i2c-tool的编写

1、I2C驱动移植

RT-Rhread这里用的是软件模拟i2c,stm32的驱动里并没有找到硬件i2c的驱动,但是在GD32里面却有硬件i2c的驱动,有兴趣的小伙伴可以根据gd32的代码写一份stm32硬件I2c的驱动。
rtconfig.h里添加i2c的配置
在这里插入图片描述
Makefile里添加i2c的编译
在这里插入图片描述
这样修改后,输入list_device,会列出i2c1设备。
在这里插入图片描述

2、应用层的使用

在PB6 PB7 上挂了一颗at24c02,我们用msh cmd写几个数据进去,然后读出来。
在这里插入图片描述
在这里插入图片描述

应用层最重要的是发送函数的封装,如果在kernel下搞过i2c的设备驱动,rt_i2c_transfer函数这个形式并不陌生。我这里封装了读函数,写函数,多寄存器,多数据的读写方式。
在这里插入图片描述
在这里插入图片描述

3 、完整测试代码

#include <rtthread.h>
#include <rtdevice.h>
#include <string.h>

#define I2C_BUS_NAME                    "i2c1"  /* EEPROM连接的I2C总线设备名称 */
#define I2C_TEST_ADDR                   0x50    /* 从机地址 */
#define I2C_MAX_DATA_LENGTH             128

static struct rt_i2c_bus_device *i2c_bus = RT_NULL;     /* I2C总线设备句柄 */

/* I2C 写寄存器 */
static rt_err_t write_reg(struct rt_i2c_bus_device *bus, rt_uint16_t reg_len,rt_uint8_t *reg, 
                                            rt_uint16_t len, rt_uint8_t *data)
{
    rt_uint8_t buf[I2C_MAX_DATA_LENGTH] = {0};
    rt_uint8_t *p = buf;
    struct rt_i2c_msg msgs;

    memcpy(p,reg,reg_len);
    p += reg_len;
    memcpy(p,data,len);

    msgs.addr = I2C_TEST_ADDR;
    msgs.flags = RT_I2C_WR;
    msgs.buf = buf;
    msgs.len = reg_len + len;
    /* 调用I2C设备接口传输数据 */
    if (rt_i2c_transfer(bus, &msgs, 1) == 1)
    {
        return RT_EOK;
    }
    else
    {
        return -RT_ERROR;
    }
}

/* 读I2C寄存器数据 */
static rt_err_t read_regs(struct rt_i2c_bus_device *bus, rt_uint16_t reg_len,
                                        rt_uint8_t *reg, rt_uint16_t len, rt_uint8_t *buf)
{
    struct rt_i2c_msg msgs[2];

    msgs[0].addr = I2C_TEST_ADDR;
    msgs[0].flags = RT_I2C_WR;
    msgs[0].buf = reg;
    msgs[0].len = reg_len;

    msgs[1].addr = I2C_TEST_ADDR;
    msgs[1].flags = RT_I2C_RD;
    msgs[1].buf = buf;
    msgs[1].len = len;
    /* 调用I2C设备接口传输数据 */
    if (rt_i2c_transfer(bus, msgs, 2) == 1)
    {
        return RT_EOK;
    }
    else
    {
        return -RT_ERROR;
    }
}

static void i2c_sample(int argc, char *argv[])
{  
    rt_uint8_t reg = 0x00;
    rt_uint8_t r_value[5] = {0};
    rt_uint8_t w_value[5] = {0x98,0x97,0x99,0xA0,0x45};
    char name[RT_NAME_MAX];
    if (argc == 2)
    {
        rt_strncpy(name, argv[1], RT_NAME_MAX);
    }
    else
    {
        rt_strncpy(name, I2C_BUS_NAME, RT_NAME_MAX);
    }

    /* 查找I2C总线设备,获取I2C总线设备句柄 */
    i2c_bus = (struct rt_i2c_bus_device *)rt_device_find(name);
    if (i2c_bus == RT_NULL)
    {
        rt_kprintf("can't find %s device!\n", name);
    }

    write_reg(i2c_bus,1,&reg,5,w_value);
    rt_thread_delay(10);
    read_regs(i2c_bus,1,&reg,5,r_value);

    for(int i=0;i<5;i++)
    {
        rt_kprintf("get data[%d] == 0x%02x\n",i,r_value[i]);
    }
}
/* 导出到 msh 命令列表中 */
MSH_CMD_EXPORT(i2c_sample, i2c test sample);

4、i2cdetect 工具

封装i2cdetect工具,用来查找总线的设备,比如总线上挂载一颗at24c02,那么使用i2cdetect后现象如图:
在这里插入图片描述
i2cdetect代码

void i2c_detect_show_usage(void)
{
    rt_kprintf("Usage:\r\n");
    rt_kprintf("  i2cdetect (-h | --help)\r\n");
    rt_kprintf("  i2cdetect (-f | --find      )   find devices in i2c bus \r\n");
}

static int i2c_send_detect_msg(struct rt_i2c_bus_device *bus,rt_uint8_t device_addr)
{
    struct rt_i2c_msg msgs;

    msgs.addr = device_addr;
    msgs.flags = RT_I2C_WR;
    msgs.buf = NULL;
    msgs.len = 0;
    /* 调用I2C设备接口传输数据 */
    if (rt_i2c_transfer(bus, &msgs, 1) == 1)
    {
        return RT_EOK;
    }
    else
    {
        return -RT_ERROR;
    }
}

rt_uint8_t show_i2c_detect_result(rt_uint8_t value)
{
    rt_int8_t result = 0;
	rt_uint8_t j = 0;
    rt_int8_t name[8] = {0};

    rt_sprintf(name,"%s%d","i2c",value);
     /* 查找I2C总线设备,获取I2C总线设备句柄 */
    i2c_bus = (struct rt_i2c_bus_device *)rt_device_find(name);
    if (i2c_bus == RT_NULL)
    {
        rt_kprintf("can't find %s device!\n", name);
        return -1;
    }

    for(j = 0;j < 128; j++)
	{
		if((j % 16) == 0)
		{
			rt_kprintf("\r\n");
		}
		result = i2c_send_detect_msg(i2c_bus,j);
		if(result == 0)
		{
			rt_kprintf(" %X ",j);//%X 十六进制输出,大写;%x 小写
		}
		else
		{
			rt_kprintf(" -- ");
		}
	}
    rt_kprintf("\r\n");
    return 0;
}

int i2cdetect(int argc ,char *argv[])
{
    rt_uint8_t bus_index;
    int c;
    int longindex = 0;

    const char short_options[] = "hf:";
    const struct option long_options[] =
    {
        {"help",        0,  NULL,     'h'},
        {"find",        1,  NULL,     'f'},
        {NULL,          0,  NULL,      0},
    };

    if (argc == 1)
    {
        /* goto the help */
        i2c_detect_show_usage();
        return 0;
    }
    /* init 0 */
    optind = 0;
    do
    {
        /* parse the args */
        c = getopt_long(argc, argv, short_options, long_options, &longindex);
        if (c == 0x3f)
        {
            i2c_detect_show_usage();
            return -1;
        }
        switch (c)
        {
        case 'h':
            i2c_detect_show_usage();
            break;
        case 'f':
            bus_index = strtol(optarg,NULL,10);
            if (bus_index >= 0)
            {
                show_i2c_detect_result(bus_index);
            }
            else
            {
                i2c_detect_show_usage();
            }
            break;    
        default:break;
        }
    }while (c != -1);

    return 0;
}

/* 导出到 msh 命令列表中 */
MSH_CMD_EXPORT(i2cdetect, i2c device detect);

5、i2cset 命令

比如 往0x50 设备的0x00地址写一个字节数据 0x08,那么命令如下:
i2cset -f 1 0x50 0x00 0x08 b
比如 往0x50 设备的0x00地址写一个half word 数据 0x08,0x07,那么命令如下:
i2cset -f 1 0x50 0x00 0x08 0x07 w
在这里插入图片描述
i2cset命令代码:

void i2c_set_show_usage(void)
{
    rt_kprintf("Usage:\r\n");
    rt_kprintf("  i2cset (-h | --help)\r\n");
    rt_kprintf("  i2cset (-f | --find      )    i2cset -f busNUM deviceaddr regaddr data\n");
    rt_kprintf("  i2cset (-f | --find      )    write a byte : i2cset -f 1 0x50 0x00 0x01 b \n"); 
    rt_kprintf("  i2cset (-f | --find      )    write a word : i2cset -f 1 0x50 0x00 0x01 0x02 w\n");                                            
}

int i2cset(int argc,char *argv[])
{
    char *end;
    int value;
    int find = 0,version = 0;
    int opt;
    int longindex = 0;
    int address,daddress;
    rt_int8_t name[8] = {0};
    rt_uint8_t data[128] = {0};
    rt_uint8_t wite_num = 1;

    const char short_options[] = "hf:";
    const struct option long_options[] =
    {
        {"help",        0,  NULL,     'h'},
        {"find",        1,  NULL,     'f'},
        {NULL,          0,  NULL,      0},
    };

    /* init 0 */
    optind = 0;
    do
    {
        /* parse the args */
        opt = getopt_long(argc, argv, short_options, long_options, &longindex);
        if (opt == 0x3f)
        {
            i2c_set_show_usage();
            return -1;
        }
        switch (opt)
        {
        case 'h':
            i2c_set_show_usage();
            return 0;
        case 'f':
            find = strtol(optarg,NULL,10);
            if (find <= 0)
            {
                i2c_set_show_usage();
                return -1;
            }
            break;    
        default:break;
        }
    }while (opt != -1);

    if (argc < optind + 3)
    {
        /* goto the help */
        i2c_set_show_usage();
        return 0;
    }

    rt_sprintf(name,"%s%d","i2c",find);
    /* 查找I2C总线设备,获取I2C总线设备句柄 */
    i2c_bus = (struct rt_i2c_bus_device *)rt_device_find(name);
    if (i2c_bus == RT_NULL)
    {
        rt_kprintf("can't find %s device!\n", name);
        return -1;
    }

    address = strtol(argv[optind],&end,0);
    if (*end || address < 0 || address > 0xff) 
    {
		rt_kprintf("Error: Data address invalid!\n");
		i2c_set_show_usage();
        return -1;
	}

    daddress = strtol(argv[optind+1],NULL,0);
    if (daddress <0 || address > 0xff)
    {
        rt_kprintf("Error: Data address invalid!\n");
		i2c_set_show_usage();
        return -1;
    } 

    int data_num = argc - optind - 2 - 1;
    for (int i=0;i<data_num;i++)
    {
        data[i] = strtol(argv[optind + 2 + i],NULL,0);
        if (data[i] > 0xff) 
        {
            rt_kprintf("Error: Data address invalid!\n");
		    i2c_set_show_usage();
            return -1;
        }
    }

    if (!strncmp(argv[argc-1],"b",1))
    {
        wite_num = 1;
    }
    else if (!strncmp(argv[argc-1],"w",1))
    {
        wite_num = 2;
    }
    else
    {
        wite_num = 1;
    }

    if (data_num != wite_num)
    {
        rt_kprintf("Error: Data Number Wrong\n");
        i2c_set_show_usage();
        return -1;
    }

    value = write_reg(i2c_bus,address,1,&daddress,wite_num,data);
    if (value == RT_EOK)
    {
        if (wite_num == 1)
        {
            rt_kprintf("Write Device: 0x%02x Reg: 0x%02x Data: 0x%02x Success\n",address,daddress,data[0]);
        }
        else
        {
            rt_kprintf("Write Device: 0x%02x Reg: 0x%02x Data: 0x%02x 0x%02x  Success\n",address,daddress,data[0],data[1]);
        }
    }

    return 0;
}

/* 导出到 msh 命令列表中 */
MSH_CMD_EXPORT(i2cset, i2c set value to device);

6、i2cget命令

从设备中读取数据,
比如从i2c1总线上的0x50设备中的0x00地址读取一个字节数据
i2cget -f 1 0x50 0x00 b
比如从i2c1总线上的0x50设备中的0x00地址读取half-word数据
i2cget -f 1 0x50 0x00 w

在这里插入图片描述
i2cget 命令代码

void i2c_get_show_usage(void)
{
    rt_kprintf("Usage:\r\n");
    rt_kprintf("  i2cget (-h | --help)\r\n");
    rt_kprintf("  i2cget (-f | --find      )    i2cset -f busNUM deviceaddr regaddr \n");
    rt_kprintf("  i2cget (-f | --find      )    read a byte : i2cget -f 1 0x50 0x00  b \n"); 
    rt_kprintf("  i2cget (-f | --find      )    read a word : i2cget -f 1 0x50 0x00  w \n");                                            
}

int i2cget(int argc ,char *argv[])
{
    char *end;
    int value;
    int find = 0,version = 0;
    int opt;
    int longindex = 0;
    rt_uint8_t address,daddress;
    rt_int8_t name[8] = {0};
    rt_uint8_t data[2] = {0};
    rt_uint8_t wite_num = 1;

    const char short_options[] = "hf:";
    const struct option long_options[] =
    {
        {"help",        0,  NULL,     'h'},
        {"find",        1,  NULL,     'f'},
        {NULL,          0,  NULL,      0},
    };

    /* init 0 */
    optind = 0;
    do
    {
        /* parse the args */
        opt = getopt_long(argc, argv, short_options, long_options, &longindex);
        if (opt == 0x3f)
        {
            i2c_get_show_usage();
            return -1;
        }
        switch (opt)
        {
        case 'h':
            i2c_get_show_usage();
            return 0;
        case 'f':
            find = strtol(optarg,NULL,10);
            if (find <= 0)
            {
                i2c_get_show_usage();
                return -1;
            }
            break;    
        default:break;
        }
    }while (opt != -1);

    if (argc < optind + 3)
    {
        /* goto the help */
        i2c_get_show_usage();
        return 0;
    }

    rt_sprintf(name,"%s%d","i2c",find);
    /* 查找I2C总线设备,获取I2C总线设备句柄 */
    i2c_bus = (struct rt_i2c_bus_device *)rt_device_find(name);
    if (i2c_bus == RT_NULL)
    {
        rt_kprintf("can't find %s device!\n", name);
        return -1;
    }

    address = strtol(argv[optind],&end,0);
    if (*end || address < 0 || address > 0xff) 
    {
		rt_kprintf("Error: Data address invalid!\n");
		i2c_get_show_usage();
        return -1;
	}

    daddress = strtol(argv[optind+1],NULL,0);
    if (daddress <0 || address > 0xff)
    {
        rt_kprintf("Error: Data address invalid!\n");
		i2c_get_show_usage();
        return -1;
    } 

    if (!strncmp(argv[argc-1],"b",1))
    {
        wite_num = 1;
    }
    else if (!strncmp(argv[argc-1],"w",1))
    {
        wite_num = 2;
    }
    else
    {
        wite_num = 1;
    }
    value = read_regs(i2c_bus,address,1,&daddress,wite_num,data);

    if (value == RT_EOK)
    {
        if (wite_num == 1)
        {
            rt_kprintf("Write Device: 0x%02x Reg: 0x%02x Data: 0x%02x Success\n",address,daddress,data[0]);
        }
        else
        {
            rt_kprintf("Write Device: 0x%02x Reg: 0x%02x Data: 0x%02x 0x%02x  Success\n",address,daddress,data[0],data[1]);
        }
    }
    return 0;
}



/* 导出到 msh 命令列表中 */
MSH_CMD_EXPORT(i2cget, i2c get value from device);

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/676380.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Ubutun开机黑屏解决方法

开机黑屏解决方法 临时性解决方法永久性解决方法补充说明 在项目支持过程中发现Ubuntu 16 在新终端上开机黑屏&#xff0c;没有显示图形界面&#xff0c;这个可能是因为系统版本太低&#xff0c;对新显卡不兼容导致的&#xff0c;后通过查资料有如下解决方法。 临时性解决方法 …

腾讯云+PicGo+Typora图床,生成专属图片链接

腾讯云PicGoTypora搭建自己的图床 原创声明&#xff0c;转载请注明文章链接来源、作者信息 TyporaPicGogitHub搭建自己的图床&#xff0c;写作效率大大提升 索奇问答 问&#xff1a;图床是什么&#xff1f; 答&#xff1a;用户可以将图片上传到图床&#xff0c;然后将生成的…

代码随想录算法训练营第四十一天 |

01背包&#xff1a;n种物品&#xff0c;每种物品只有1个&#xff0c;有相应的重量和价值 最多只能装m的重量&#xff0c;最多价值为多少&#xff1f; dp[i][j] : [0, i]物品任取放进容量为j的背包里 不放物品i&#xff1a;dp[i-1][j] 放物品i&#xff1a;dp[i-1][j-weight[…

递归的浅浅应用

首先&#xff0c;这里是一道简单题目&#xff0c;浅浅地验证了我之前发过的这篇文章 写递归题目的思路 &#xff0c;我结合它来讲解一下这道题的思路&#xff1a; 剑指 Offer 27 和 method 226.翻转二叉树 给你一棵二叉树的根节点 root &#xff0c;翻转这棵二叉树&#xff0c;…

python数据清洗 —— re.split()划分字符串

需求 对于一行字符串&#xff1a; route-views6.routeviews.org 141694 2a0c:b641:24f:fffe::7 184891 | CN | apnic | OTAKUJAPAN-AS Otaku Limited, CN要将其划分成如下7个部分&#xff0c; [route-views6.routeviews.org, 141694…

【C++篇】OOP下部分:友元、运算符重载与多态

友情链接&#xff1a;C/C系列系统学习目录 知识总结顺序参考C Primer Plus&#xff08;第六版&#xff09;和谭浩强老师的C程序设计&#xff08;第五版&#xff09;等&#xff0c;内容以书中为标准&#xff0c;同时参考其它各类书籍以及优质文章&#xff0c;以至减少知识点上的…

精选MyBatis面试题

什么是MyBatis&#xff1f; MyBatis是一个半ORM&#xff08;对象关系映射&#xff09;框架&#xff0c;它内部封装了JDBC&#xff0c;加载驱动、创建连接、创建statement等繁杂的过程&#xff0c;开发者开发时只需要关注如何编写SQL语句&#xff0c;可以严格控制sql执行性能&a…

Python高级语法--迭代器和生成器的区别

迭代器 在 Python 中&#xff0c;迭代器&#xff08;iterator&#xff09;是访问集合元素的一种方式&#xff0c;它可以遍历一个序列中的元素&#xff0c;而无需事先确定序列的大小&#xff08;即无需全部载入到内存中&#xff09;&#xff0c;且支持惰性求值。使用迭代器可以…

程序员 35 岁以后就真的要返乡种田了么?如果家里没田怎么办?

前言 在科技互联网高速发展的当下&#xff0c;程序员这个职业无疑是备受关注的。然而&#xff0c;这个行业似乎总是被一种说法所笼罩&#xff1a;程序员年龄一旦超过35岁&#xff0c;就会面临职业生涯的下坡路&#xff0c;甚至需要考虑“返乡种田”。这种说法是否真实呢&#x…

【Software Testing】【期末习题库】【2023年春】【仅供参考】

文章目录 ①单选②多选③填空④判断⑤大题 类型总分占比平时成绩40%考试/考查60% 题型题量分值备注单选201’多选103’全对3’&#xff0c;错1个0’&#xff0c;少选-1’填空102’判断52’大题210’ 平时习题&#xff08;3次&#xff09;&#xff1a; ①软件测试概述 ②黑盒测…

【五子棋实战】第5章 开发五子棋前端页面

【五子棋实战】第5章 开发五子棋前端页面 页面设计原则 开发页面 ## 基础HTML骨架 ## 添加页面响应式功能 编写JS ## 获取画布对象与DOM对象 ## 定义棋子、棋盘对象 ## 定义绘画对象&#xff08;重要&#xff01;&#xff01;&#xff09; ## 初始化绘制棋盘 ## 添加点…

Network 之十三 NC-SI 原理、拓扑结构、RBT 接口及仲裁、协议格式

最近&#xff0c;正在学习 NC-SI 的使用方法&#xff0c;于是开始各种 Google 查找 NC-SI 的资料进行学习。最详细还是得直接看 NC-SI 规范文档 DSP0222&#xff0c;以下就是记录的一些感觉 NC-SI 规范中比较重要的点以及我的一些理解&#xff0c;以备后续查阅。 有任何疑问&am…

OpenGL之模板测试

文章目录 模板测试模板函数物体轮廓源代码 模板测试 当片段着色器处理完一个片段之后&#xff0c;模板测试(Stencil Test)会开始执行&#xff0c;和深度测试一样&#xff0c;它也可能会丢弃片段。接下来&#xff0c;被保留的片段会进入深度测试&#xff0c;它可能会丢弃更多的片…

Git下:Git命令使用-详细解读

目录 一、Git 安装 二、Git 配置 三、Git 工作流程 四、Git 工作区、暂存区和版本库 五、常用 Git 命令清单 1. 创建仓库 2. 增加/删除文件 3. 代码提交 4. 分支管理 5. 标签 6. 查看历史提交 7. 远程仓库同步 8. 撤销操作 六、Git 常用命令速查表 七、Git 电子…

时序预测的深度学习算法全面盘点

1.概述 深度学习方法是一种利用神经网络模型进行高级模式识别和自动特征提取的机器学习方法&#xff0c;近年来在时序预测领域取得了很好的成果。常用的深度学习模型包括循环神经网络&#xff08;RNN&#xff09;、长短时记忆网络&#xff08;LSTM&#xff09;、门控循环单元&…

第五十一章 协助调查

眼前一个红彤彤的东西缓缓升起。 旭日东升&#xff1f;可现在才升未免太晚了些&#xff0c;升起的速度也未免太快了些&#xff0c;这红日么&#xff0c;也未免太小了些&#xff0c;而且&#xff0c;刚升起的朝阳&#xff0c;也未免显得太红太亮了些。 “是谁呀&#xff0c;水烧…

C语言数据存储 —— 浮点型篇

C语言数据存储 —— 浮点型篇 前言1. 一个常见问题2. 浮点数存储规则2.1 有效数字M一些特别的规定2.2 有效数字E一些特别的规定2.2.1 E如何存入内存2.2.2 E如何从内存中取出 3. 前面问题的解释。4. 结尾 前言 浮点数在内存中的存储方式对程序员来说非常重要。理解浮点数的存储…

数据结构:二叉树经典例题(单选题)-->你真的掌握二叉树了吗?(第一弹)

朋友们、伙计们&#xff0c;我们又见面了&#xff0c;本期来给大家解读一下有关二叉树的经典例题&#xff0c;如果看完之后对你有一定的启发&#xff0c;那么请留下你的三连&#xff0c;祝大家心想事成&#xff01; C 语 言 专 栏&#xff1a;C语言&#xff1a;从入门到精通 数…

消防通道堵塞识别 opencv

消防通道堵塞识别系统通过opencvpython网络模型技术&#xff0c;消防通道堵塞识别对消防通道的状态进行实时监测&#xff0c;检测到消防通道被堵塞时&#xff0c;将自动发出警报提示相关人员及时采取措施。OpenCV的全称是Open Source Computer Vision Library&#xff0c;是一个…

linux-centOS7.9通过docker安装cwmp server:drumsergio/genieacs

一、安装环境 #查看centOS版本 [rootMiWiFi-R4CM-srv network-scripts]# cat /etc/redhat-release CentOS Linux release 7.9.2009 (Core) #自动查找最新安装包并升级 [rootMiWiFi-R4CM-srv ~]# sudo yum upgrade 二、关闭firewalld、NetworkManager、selinux 关闭防火墙、…