软件模拟IIC的全面笔记(已调通)

@[toc] lib_i2c_simulation

/** @Author: Haiyichen* @Date: 2023-09-21 16:16:16* @LastEditors: Haiyichen* @LastEditTime: 2023-10-31 18:01:10* @Description: Personal notes of i2c-simulation*/

i2c基础

通讯流程

协议

除了文字解释,有用wavedrom简单画了一些各种信号的电平变化过程,但需要支持MPE才能看到,虽然CSDN上的在线编辑器无法渲染出图,但还是放出来了,如果有条件可以在自己的VSCode中配置MPE(markdown preview enhenced)

  1. 开始:SCL为高电平时,SDA从高电平状态切换到低电平状态。
    {signal:[{       name:'SCL',   wave:'p.Pp'},{       name:'data',  wave:"x.=x", data:["Start" ]},{       name:'SDA',   wave:"1.0"}
    ]}
  2. 停止:SCL为高电平时,SDA从低电平状态切换到高电平状态。
    {signal:[{       name:'SCL',   wave:'p.PPp'},{       name:'data',  wave:"x.=x", data:["Stop" ]},{       name:'SDA',   wave:"0.10"}
    ]}
  3. 应答:发送侧发送完8bit数据后,接收侧需要回复一个信号,即第9个SCL时,接收侧将SDA拉低,称作ACK。
    {signal:[{       name:'SCL',   wave:'p.Pp..|Pp'},{       name:'data',  wave:"x.==..|=x", data:["Start", "SlaveAddress","Ack"]},{       name:'SDA',   wave:"0.10.1|0."}
    ]}
  4. 无应答:发送侧发送完8bit数据后,接收侧需要回复一个信号,即第9个SCL时,接收侧将SDA拉高(或叫释放SDA),称作NACK。NACK时同时会引起Master发生RESTART或STOP流程。
    {signal:[
    {       name:'SCL',   wave:'p.Pp..|Pp'},
    {       name:'data',  wave:"x.==..|=x", data:["Start", "SlaveAddress","Nack"]},
    {       name:'SDA',   wave:"0.10.0|1."}
    ]}
  5. 地址命令:i2c的地址是7bit,第8bit是方向位。1代表Read、0代表Write

写流程

  1. Master发起START
  2. Master发送Slave地址(7bit)和W(0:写动作),等待Slave发动应答ACK
  3. Slave发送应答ACK
  4. Master发送寄存器地址(8bit),等待Slave发送应答ACK
  5. Slave发送应答ACK
  6. Master发送写入寄存器的数据(8bit),等待Slave发送应答ACK
  7. Slave发送应答ACK
  8. 6~7可以循环多次,即按顺序写多个寄存器
  9. Master发起STOP

读流程

  1. Master发起START
  2. Master发送Slave地址(7bit)和W(0:写动作),等待Slave发送应答ACK
  3. Slave发送应答ACK
  4. Master发送寄存器地址(8bit),等待Slave发送应答ACK
  5. Slave发送应答ACK
  6. Master发起START
  7. Master发送Slave地址(7bit)和R(1:读动作),等待Slave发送应答ACK
  8. Slave发送应答ACK
  9. Slave发送寄存器里数据(8bit),等待Master发送ACK
  10. Master发送ACK或NACK(出现NACK,后面直接就是STOP流程)
  11. 9~10可以循环多次,即顺序读多个寄存器
  12. Master发起STOP

i2c模拟驱动函数

相关硬件配置

/* IO definition of i2c simulation */
#define I2C_SIMULATION_GPIO_PORT             GPIOA
#define I2C_SIMULATION_SCL_PIN               GPIO_PINS_0
#define I2C_SIMULATION_SDA_PIN               GPIO_PINS_1/* driver definition of i2c simulation for M1 */
#define I2C_SDA_H()        I2C_SIMULATION_GPIO_PORT->scr = I2C_SIMULATION_SDA_PIN;
#define I2C_SDA_L()        I2C_SIMULATION_GPIO_PORT->clr = I2C_SIMULATION_SDA_PIN; 
#define I2C_SCL_H()        I2C_SIMULATION_GPIO_PORT->scr = I2C_SIMULATION_SCL_PIN;
#define I2C_SCL_L()        I2C_SIMULATION_GPIO_PORT->clr = I2C_SIMULATION_SCL_PIN;

关于模拟i2c的IO配置细节

关于SDA引脚是配置成开漏还是推挽,

  • 推挽输出对应->需要切换输入输出模式;
  • 开漏输出对应->不需要切换输入输出模式.
    参考链接已验证

i2c_Delay()

//需要根据主控MCU频率和i的取值,调整i2c_Delay的时长,进而调整SCL的脉宽。(也受编译器“优化等级”影响)
/*** @name   i2c_Delay* @brief  soft delay for i2c clock* @param  none* @retval none*/
static void i2c_Delay(void)
{uint8_t i;/**AT32F425F6P7,*i = 100,SCL = 163.4KHZ,6.1us*i = 75, SCL = 243.9KHZ,4.1us*i = 50, SCL = 312.5kHZ,3.2us*/for(i=0;i<100;i++);
}

hw_i2c_START()

/*** @name   hw_i2c_START* @brief  start signal for i2c simulation* @param  none* @retval none*/void hw_i2c_START(void){I2C_SDA_H();I2C_SCL_H();i2c_Delay();I2C_SDA_L();i2c_Delay();I2C_SCL_L();i2c_Delay();}

hw_i2c_ACK()

/*** @name   hw_i2c_ACK* @brief  ACK signal for i2c simulation* @param  none* @retval none*/
void hw_i2c_ACK(void)
{I2C_SDA_L();i2c_Delay();I2C_SCL_H();i2c_Delay();I2C_SCL_L();i2c_Delay();I2C_SDA_H();}

hw_i2c_WaitAck()

/*** @name   hw_i2c_WaitAck* @brief  Wait ACK signal for i2c simulation* @param  none* @retval uint8_t tempRe:Get slave ack signal or not*/uint8_t hw_i2c_WaitAck(void)
{uint8_t tempRe;I2C_SDA_H();                //MCU(master) set SDA Highi2c_Delay();I2C_SCL_H();                //MCU(master) send a new SCL signal, slave device should return an Ack signali2c_Delay();tempRe = I2C_SDA_READ();    //MCU(master) read SDA state(1 or 0)I2C_SCL_L();i2c_Delay();return tempRe;
}

hw_i2c_NACK()

/*** @name   hw_i2c_NACK* @brief  Send NACK signal to slave for i2c simulation* @param  none* @retval none*/
void hw_i2c_NACK(void)
{I2C_SDA_L();I2C_SCL_H();i2c_Delay();I2C_SDA_H();
}

hw_i2c_STOP()

/*** @name   hw_i2c_STOP* @brief  Send STOP signal to slave for i2c simulation* @param  none* @retval none*/
void hw_i2c_STOP(void)
{I2C_SDA_L();I2C_SCL_H();i2c_Delay();I2C_SDA_H();i2c_Delay();
}

lib_i2c_SendByte()

/*** @name   lib_i2c_SendByte* @brief  Send Byte from master by simulation of i2c* @param  DataByte:data* @retval none*/
void lib_i2c_SendByte(uint8_t DataByte)
{uint8_t i;for ( i = 0; i < 8; i++){if (DataByte & 0x80){I2C_SDA_H();}else{I2C_SDA_L();}i2c_Delay();I2C_SCL_H();i2c_Delay();I2C_SCL_L();if (i == 7){I2C_SDA_H();      //MCU(master) set SDA high}DataByte <<= 1;i2c_Delay();        }
}

lib_i2c_ReadByte()

/*** @name   lib_i2c_ReadByte* @brief  Read Byte from slave device by simulation of i2c* @param  none * @retval tempData:data*/
uint8_t lib_i2c_ReadByte(void)
{uint8_t i;uint8_t	tempData = 0;uint8_t	tempRe = 0;for(i = 0; i < 8; i++){tempData <<=1;I2C_SCL_H();i2c_Delay();tempRe = I2C_SDA_READ();if(tempRe){tempData++;}I2C_SCL_L();i2c_Delay();}return tempData;
}

lib_i2c_ReadMutiBytes()

/*** @name   lib_i2c_ReadMutiBytes* @brief  Read Muti Bytes data from slave device* @param  slave_address* @param  reg_address* @param  pdatabuf* @param  len* @retval tempRe:whether read data successfully or not*/
uint8_t lib_i2c_ReadMutiBytes(uint8_t slave_address, uint8_t reg_address, uint8_t* pdatabuf, uint8_t len)
{uint8_t tempData;		uint8_t tempRe = 0;uint8_t cnt = 0;uint8_t tempaddr_W = slave_address<<1;uint8_t tempaddr_R = tempaddr_W + 1;do{/* 1st:i2c start signal */hw_i2c_START();/* 2nd:write slave device address, bit0 is a read-write control bit, 0 for write, and 1 for read */lib_i2c_SendByte(tempaddr_W);/* 3rd:wait ack from slave device */tempRe = hw_i2c_WaitAck();if (tempRe){							// the return value is 1 ,that is to say SDA is not lowwed. the target ist8310 doesn't Ackbreak;}/* 4th:send target register address */lib_i2c_SendByte(reg_address);/* 5th:wait Ack from slave device */stempRe = hw_i2c_WaitAck();if (tempRe){							// the return value is 1 ,that is to say SDA is not lowwed. the target ist8310 doesn't Ackbreak;}/* 6th:send a start signal to reset i2c bus, and then start to read data from slave device */hw_i2c_START();/* 7th:Send a read command(bit0) for the slave address */lib_i2c_SendByte(tempaddr_R);/* 8th:wait Ack from slave device */tempRe = hw_i2c_WaitAck();if (tempRe){							// the return value is 1 ,that is to say SDA is not lowwed. the target ist8310 doesn't Ackbreak;}			//9th:read data by loopfor(cnt = 0; cnt < len; cnt++){pdatabuf[cnt] = lib_i2c_ReadByte();    //read 1 byte/* After reading each byte, an Ack needs to be sent, except for the last byte, which requires a Nack */if(cnt != len - 1){/* After the middle byte is read, the CPU generates the ACK signal (Drive SDA = 0) */hw_i2c_ACK();}else{/* After reading the last byte, the CPU generates the NACK signal (drive SDA = 1) */hw_i2c_NACK();}}}while(0);/* Send I2C bus stop signal */hw_i2c_STOP();if(tempRe){tempRe = 0;}else{tempRe = 1;}return tempRe;
}

lib_i2c_WriteSingleByte()

/*** @brief  write single byte through the i2c1(For M1) by sofyware simulation.* @param  slave_address: address of tagert slave device* @param  reg_address: address of tagert register* @param  pdata: pointer to the data* @retval tempRe: Write data successfully or not*/
uint8_t lib_i2c_WriteSingleByte(uint16_t slave_address, uint16_t reg_address, uint8_t pdata)
{uint8_t tempRe = 0;uint8_t tempData = pdata;uint16_t tempaddr = slave_address<<1;do{hw_i2c_START();lib_i2c_SendByte(tempaddr);tempRe = hw_i2c_WaitAck();if (tempRe){							// the return value is 1 ,that is to say SDA is not lowwed. the target ist8310 doesn't Ackbreak;}lib_i2c_SendByte(reg_address);tempRe = hw_i2c_WaitAck();if (tempRe){							// the return value is 1 ,that is to say SDA is not lowwed. the target ist8310 doesn't Ackbreak;}lib_i2c_SendByte(tempData);tempRe = hw_i2c_WaitAck();if (tempRe){							// the return value is 1 ,that is to say SDA is not lowwed. the target ist8310 doesn't Ackbreak;}hw_i2c_STOP();} while (0);return tempRe;
}

小结

因为用的芯片硬件IIC的底层官方函数一直卡死跑不通,于是干脆自己整理了一套软件模拟IIC的相关流程和函数,已经在项目中顺利调通了,项目换芯片也经历过不同芯片的移植,也很方便。

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

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

相关文章

C++设计模式_24_Visitor 访问器

Visitor 访问器也是属于“行为变化”模式。 文章目录 1. 动机( Motivation)2. 代码演示Visitor 访问器3. 模式定义4. 结构(Structure)5. 要点总结6. 其他参考1. 动机( Motivation) 在软件构建过程中,由于需求的改变,某些类层次结构中常常需要增加新的行为(方法),如果直接在基…

【Linux】开发工具——vim多模式编辑器的入土设置sudoers白名单

个人主页点击直达&#xff1a;小白不是程序媛 Linux系列专栏&#xff1a;Linux被操作记 目录 前言&#xff1a; 基本概念 vim基本操作 [正常模式]切换至[插入模式] [插入模式]切换至[正常模式] [正常模式]切换至[末行模式] 三种模式的切换关系图 vim命令模式命令集 进…

微信小程序-授权登录(手机号码)

1、WXBizDataCrypt.js-下载地址 2、UNIAPP代码 <template> <view class"work-container"> <view class"login"> <view class"content"> <button class"button_wx&q…

数据结构之栈的实现

&#x1d649;&#x1d65e;&#x1d658;&#x1d65a;!!&#x1f44f;&#x1f3fb;‧✧̣̥̇‧✦&#x1f44f;&#x1f3fb;‧✧̣̥̇‧✦ &#x1f44f;&#x1f3fb;‧✧̣̥̇: Solitary-walk ⸝⋆ ━━━┓ - 个性标签 - &#xff1a;来于“云”的“羽球人”…

J2EE项目部署与发布(Linux版本)->jdktomcat安装,MySQL安装,后端接口部署,linux单体项目前端部署

jdk&tomcat安装MySQL安装后端接口部署linux单体项目前端部署 1.jdk&tomcat安装 上传jdk、tomcat安装包 解压两个工具包 #解压tomcat tar -zxvf apache-tomcat-8.5.20.tar.gz #解压jdk tar -zxvf jdk-8u151-linux-x64.tar.gz 配置并且测试jdk安装 #配置环境变量 vim /e…

文件夹批量重命名:如何利用上级目录给多个文件夹进行高效重命名

在文件管理中&#xff0c;我们经常需要处理大量的文件和文件夹。其中&#xff0c;文件名过长或混乱的问题经常让我们感到困扰。这不仅影响了我们的工作效率&#xff0c;还可能导致一些错误。为了解决这个问题&#xff0c;我们可以用云炫文件管理器将“上级目录”批量重命名文件…

模拟select通信过程

文章目录 模拟select通信过程 但有客户端正在处理数据,新增一台客户端请求建立连接当N台服务器都处于通信状态,其中有一台由于客户端断开处在G处,如果它立即重新请求连接,请分析它的过程当N台服务器都处于通信状态,其中有一台由于客户端断开处在G处,如果它立即重新请求连接, 并…

网络安全中的渗透测试主要有几个方面

渗透测试中主要有软件测试和渗透测试。 1、测试对象不同   软件测试&#xff1a;主要测试的是程序、数据、文档。 渗透测试&#xff1a;对象主要为网络设备、主机操作系统、数据库系统和应用系统。 2、测试内容不同   软件测试&#xff1a;主要工作内容是验证和确认&#x…

如何将word格式的文档转换成markdown格式的文档

如何将word格式的文档转换成markdown格式的文档 前言 A. 介绍Markdown和Word格式文档 什么是Markdown&#xff1f; Markdown是一种轻量级标记语言&#xff0c;旨在简化文本格式化和排版的过程。它以纯文本形式编写&#xff0c;通过使用简单的标记语法&#xff0c;使文档更具…

使用Objective-C和ASIHTTPRequest库进行Douban电影分析

概述 Douban是一个提供图书、音乐、电影等文化内容的社交网站&#xff0c;它的电影频道包含了大量的电影信息和用户评价。本文将介绍如何使用Objective-C语言和ASIHTTPRequest库进行Douban电影分析&#xff0c;包括如何获取电影数据、如何解析JSON格式的数据、如何使用代理IP技…

学习Python的NumPy、pandas、matplotlib笔记

关于Numpy、Pandas、matplotlib笔记 关于Numpy的学习Numpy的代码练习 关于Pandas的学习Pandas代码的练习 关于Matplotlib的学习Matplotlib代码练习 关于Numpy的学习 Numpy的代码练习 import numpy as np anp.array([[1,2],[3,4]]) print(a) print(a.dtype) a.astype(np.float1…

响应式设计疑难问题全解析!一篇读懂,立即上手

在我们当前的技术环境中&#xff0c;响应式设计已经成为前端开发的重要部分。其目标是让网站能够以最优的方式在任何设备上工作——不论是大屏电脑、笔记本、平板还是智能手机。这就要求网页能够自适应不同设备的屏幕大小。下面就让我们深入浅出地探讨响应式设计的精髓&#xf…

AI:50-基于深度学习的柑橘类水果分类

🚀 本文选自专栏:AI领域专栏 从基础到实践,深入了解算法、案例和最新趋势。无论你是初学者还是经验丰富的数据科学家,通过案例和项目实践,掌握核心概念和实用技能。每篇案例都包含代码实例,详细讲解供大家学习。 📌📌📌本专栏包含以下学习方向: 机器学习、深度学…

Qt 使用QtXlsx操作Excel表

1.环境搭建 QtXlsx是一个用于读写Microsoft Excel文件&#xff08;.xlsx&#xff09;的Qt库。它提供了一组简单易用的API&#xff0c;可以方便地处理电子表格数据。 Github下载&#xff1a;GitHub - dbzhang800/QtXlsxWriter: .xlsx file reader and writer for Qt5 官方文档…

虚拟机防火墙关闭教程

虚拟机防火墙关闭教程 连接数据库请求超时 教程

主机ping、ssh连接不通本地虚拟机

一、问题描述 在使用vscode remote ssh时&#xff0c;连接timeout&#xff0c;而且主机无论如何也ping不通虚拟机&#xff0c;但是虚拟机可以ping通主机。通过vagrant也可以连接虚拟机。 二、解决方案 试了网上包括设置remote ssh在内的许多方法都不行。重新查看主机和虚拟机…

15种稳定扩散模型的技术示例

推荐Stable Diffusion自动纹理工具&#xff1a; DreamTexture.js自动纹理化开发包 什么是稳定扩散模型&#xff1f; 潜在扩散模型 &#xff08;LDM&#xff09; 是一种图像生成技术&#xff0c;其工作原理是在潜在表示空间中迭代“去噪”数据&#xff0c;然后将表示解码为完整…

自己动手实现一个深度学习算法——二、神经网络的实现

文章目录 1. 神经网络概述1&#xff09;表示2&#xff09;激活函数3&#xff09;sigmoid函数4&#xff09;阶跃函数的实现5&#xff09;sigmoid函数的实现6)sigmoid函数和阶跃函数的比较7&#xff09;非线性函数8&#xff09;ReLU函数 2.三层神经网络的实现1&#xff09;结构2&…

设置防火墙

1.RHEL7中的防火墙类型 防火墙只能同时使用一张,firewall底层调用的还是lptables的服务: firewalld:默认 &#xff0c;基于不同的区域做规则 iptables: RHEL6使用&#xff0c;基于链表 Ip6tables Ebtables 2.防火墙的配置方式 查看防火墙状态: rootlinuxidc -]#systemct…