硬件I2C

RT-Thread使用——I2C硬件驱动 RT-Thread实现硬件I2C 阅读详情

之前有抄过别人的IO模拟I2C,其实很多的芯片内部都有硬件I2C,这个的操作相对就比较简单。这里我们以Telechip8902 为例,在Wince系统下面如何构建I2C的驱动程序。

1:I2C的驱动是基于流驱动模式。

2:无非是显示一下接口函数:

LIBRARY TCC_I2C

EXPORTS
   I2C_Init
   I2C_Deinit
   I2C_Open
   I2C_Close
   I2C_IOControl
   I2C_PowerUp
   I2C_PowerDown
   I2C_Read
   I2C_Write
   I2C_Seek

 

3:首先是初始化,因为都是GPIO口复用,所以首先需要配置IO口,使之成为SDA,SCL接口模拟。

void I2C_GpioSetting(void)
{
    PGPIO pGPIO;
    pGPIO = (PGPIO)tcc_allocbaseaddress((unsigned int)&HwGPIO_BASE);

    //SCL0-GPIOA0, SDA0-GPIOA1
    BITCSET(pGPIO->GPAFN0, (Hw5-Hw0), Hw0); //GPIOA[0] function set 1
    BITCSET(pGPIO->GPAFN0, (Hw8-Hw4), Hw4); //GPIOA[1] function set 1

    //SCL1-GPIOA8, SDA1-GPIOA9
    BITCSET(pGPIO->GPAFN1, (Hw5-Hw0), Hw0); //GPIOA[8] function set 1
    BITCSET(pGPIO->GPAFN1, (Hw8-Hw4), Hw4); //GPIOA[9] function set 1
}

这个地方的许多的配置都是不一样的。这里说明有两个I2C接口

 

4:初始化完了就得实际配置下I2C,可以参加一下函数:

   void I2C_Initialize()

{

   pI2C = (PI2C)tcc_allocbaseaddress((unsigned int)&HwI2CMASTER0_BASE);
    //I2C Channel 0 setting 100kHz
      pI2C->PRES0 = 7; 

   //Enable I2C core and Enable I2C Core Interrupt bit

    pI2C->CTRL0 = HwI2CM_CMD_STA_EN | HwI2CM_CMD_STO_EN|HwI2CM_CTRL_MOD_8;
    BITSET( pI2C->CMD0, HwI2CM_CMD_IACK_CLR);
    //Sleep(1);
    BITSET( pI2C->CMD0,HwI2CM_CMD_IACK_CLR);
    //I2C Channel 1 setting 400kHz
    /* Required Frequency  */
    //pI2C->PRES1 = 2; // (400K)
    pI2C->PRES1 = 7; // (100K)
    pI2C->CTRL1 = HwI2CM_CMD_STA_EN | HwI2CM_CMD_STO_EN|HwI2CM_CTRL_MOD_8;
    BITSET( pI2C->CMD1, HwI2CM_CMD_IACK_CLR);
    //Sleep(1);
    BITSET( pI2C->CMD1, HwI2CM_CMD_IACK_CLR);

}

 

5:前面的步骤已经完成了配置工作,我们使用I2C最主要还是来通讯的。所以要写读写函数。我们一般定义一下结构体:

ypedef struct _I2C_Param{
    BYTE    DeviceAddr;
    BYTE    nPort;
    BYTE    nMode;
    BYTE    DUMMY;
    DWORD    nWriteByte;
    DWORD    nReadByte;
    BYTE    *pWriteBuffer;
    BYTE    *pReadBuffer;
    DWORD    nTimeout;
} I2C_Param;

typedef struct _RetParam{
    DWORD nReadByte;
    BYTE *pReadBuffer;
} RetParam;

第一个结构用来包装我们的传递的参数。第二个用来包装我们的返回值。

 

 

6:读写函数:

DWORD ReadChannel0(BYTE deviceAddr, DWORD writeBytes, BYTE* pWriteBuffer, DWORD readBytes, BYTE* pReadBuffer, BYTE nMode, DWORD nTimeout)
{
    DWORD nCount=0;
    if(writeBytes > 0)
    {
        pI2C->TXR0    = deviceAddr | I2C_WR;
        pI2C->CMD0    = HwI2CM_CMD_STA_EN | HwI2CM_CMD_WR_EN;
        while( !(pI2C->IRQSTR & Hw0) )   
        {
            nCount++;
            if(nCount > 100000)
            {
                RETAILMSG(TC_LOG_LEVEL(TC_DEBUG),(TEXT("[I2C         ]TIMEOUT /n")));
                return FALSE;
            }
        }
        BITSET( pI2C->CMD0, Hw0); //Clear a pending interrupt
        for(unsigned int i=0; i< writeBytes; i++) {
            RETAILMSG(TC_LOG_LEVEL(TC_DEBUG),(TEXT("[I2C         ]WriteData[%d]=[%x]/n"), i, pWriteBuffer[i]));
            pI2C->TXR0 = pWriteBuffer[i];
            pI2C->CMD0 = HwI2CM_CMD_WR_EN;
            nCount=0;
            while( !(pI2C->IRQSTR & Hw0) )   
            {
                nCount++;
                if(nCount > 100000)
                {
                    RETAILMSG(TC_LOG_LEVEL(TC_DEBUG),(TEXT("[I2C         ]TIMEOUT /n")));
                    return FALSE;
                }
            }
            BITSET( pI2C->CMD0, Hw0); //Clear a pending interrupt
        }
        if(!nMode || ((readBytes <= 0)&&(nMode != 2)&&(nMode != 4)))
        {   
            pI2C->CMD0 = HwI2CM_CMD_STO_EN;
            nCount=0;   
            while( !(pI2C->IRQSTR & Hw0) )   
            {
                nCount++;
                if(nCount > 100000)
                {
                    RETAILMSG(TC_LOG_LEVEL(TC_DEBUG),(TEXT("[I2C         ]TIMEOUT[STOP] /n")));
                    return FALSE;
                }
            }
            BITSET( pI2C->CMD0, Hw0); //Clear a pending interrupts
        }
    }// writeBytes
    if(readBytes > 0)
    {
        pI2C->TXR0    = deviceAddr | I2C_RD;
        pI2C->CMD0    = HwI2CM_CMD_STA_EN | HwI2CM_CMD_WR_EN;
        nCount=0;
        while( !(pI2C->IRQSTR & Hw0) )   
        {
            nCount++;
            if(nCount > 100000)
            {
                RETAILMSG(TC_LOG_LEVEL(TC_DEBUG),(TEXT("[I2C         ]TIMEOUT /n")));
                return FALSE;
            }
        }
        BITSET( pI2C->CMD0, Hw0); //Clear a pending interrupt
        for(unsigned int i=0; i< readBytes; i++) {
            if(nMode)
            {
                if(i==readBytes-1)
                    pI2C->CMD0 = HwI2CM_CMD_RD_EN |HwI2CM_CMD_ACK_EN;   
                else            
                    pI2C->CMD0 = HwI2CM_CMD_RD_EN ;
            }
            else
                pI2C->CMD0 = HwI2CM_CMD_RD_EN |HwI2CM_CMD_ACK_EN;
            nCount=0;
            while( !(pI2C->IRQSTR & Hw0) )   
            {
                nCount++;
                if(nCount > 100000)
                {
                    RETAILMSG(TC_LOG_LEVEL(TC_DEBUG),(TEXT("[I2C         ]TIMEOUT /n")));
                    return FALSE;
                }
            }
            BITSET( pI2C->CMD0, Hw0); //Clear a pending interrupt
            pReadBuffer[i] =(BYTE)pI2C->RXR0;
            RETAILMSG(TC_LOG_LEVEL(TC_DEBUG),(TEXT("[I2C         ]BUFFER[%d]:%x /n/r"),i,pReadBuffer[i]));
        }
        if(nMode != 4)
        pI2C->CMD0 = HwI2CM_CMD_STO_EN;
        nCount=0;
        while( !(pI2C->IRQSTR & Hw0) )   
        {
            nCount++;
            if(nCount > 100000)
            {
                RETAILMSG(TC_LOG_LEVEL(TC_DEBUG),(TEXT("[I2C         ]TIMEOUT /n")));
                return FALSE;
            }
        }
        BITSET( pI2C->CMD0, Hw0); //Clear a pending interrupt
    }//readBytes   
    return TRUE;
}

//这个函数是重点,在于如何告诉你读写操作。可以看的出来,以写为例:

//写

首先把要写数据导入到Transmit Data Register   也就是TX 里面。首先需要写入的是目标地址和控制位,这里是些,所以

pI2C->TXR0    = deviceAddr | I2C_WR;

这样需要发送的数据就准备好了,下次就可以直接发送这个信息。

pI2C->CMD0    = HwI2CM_CMD_STA_EN | HwI2CM_CMD_WR_EN;

上面的这句话是表示,允许写操作,并且开始Start Condition Generation

这样第一个语句就发送出去了,记住,这个只是类似于握手操作,我们真正需要的数据还没有开始传递。

当Master发送出去数据后,Salve需要有反应,如果没有反应,说明地址不对,或者线路不对。所以我们需要检查是否有反应。

while( !(pI2C->IRQSTR & Hw0) )   
        {
            nCount++;
            if(nCount > 100000)
            {
                RETAILMSG(TC_LOG_LEVEL(TC_DEBUG),(TEXT("[I2C         ]TIMEOUT /n")));
                return FALSE;
            }
        }

实际上就是不停得检查IRQSTR第一位死否为1,如果是,则说明已经有了反馈信号。下面的这段话是Telechips8902的DataSheet关于I2C寄存器的:

IRQ Status of I2C Master Controller Channel 0
0/1
IRQ Status Flag for I2C Master Controller of Channel 0.
This would be read as ‘1’ when the IRQ status of I2C master controller
channel 0 is activated.

当检查到这个标志后,说明完成,我们也需要手动清除这个标志:

BITSET( pI2C->CMD0, Hw0); //Clear a pending interrupt

那写其他数据就是同样的道理了,只是注意,已经Start 了,不用重新Start.

读也是一样的,发出读命令后,不停得检查ACK信息,当得到ACK信息后,就读取寄存器值RXR0即可。

记住,读写完成后需要STOP操作。

 

一般暴露给用户的是

BOOL I2C_IOControl( DWORD hOpenContext, DWORD dwCode, PBYTE pBufIn, DWORD dwLenIn, PBYTE pBufOut, DWORD dwLenOut, PDWORD pdwActualOut )
这个函数,这个参数就很明显。

stm32 I2C通信外设(硬件I2C读写MPU6050) TXE:用于指示发送数据寄存器是否准备好接收新的数据进行发送。RXNE:用于指示接收数据寄存器是否有新接收的数据可供读取。 阅读详情

相关推荐

ros_control硬件接口实战:从零构建机器人控制框架

本文详细介绍了ros_control硬件接口在机器人控制框架中的核心作用与实践方法。通过解析硬件接口类型、实现标准接口、构建主控制循环及自定义功能扩展,帮助开发者从零构建高效的机器人控制系统,提升硬件与ROS的协同效率。

lstm7chronicler的博客 500

STM32F103C8T6使用硬件IIC驱动OLED

开始配置 I2C1 ,/*!< 时钟频率.该参数必须设置小于 400kHz *//*!< I2C模式.该参数参考 @ref I2C_mode *//*!< I2C快速模式占空比.该参数参考 @ref I2C_duty_cycle_in_fast_mode *//*!< 指定自身I2C设备的地址.该参数可以是7位或10位地址 *//*!< 使能应答位.该参数参考 @ref I2C_acknowledgement *//*!< 7位或10位从地址设置.

qq_64284744的博客 7149

模型量化必知:Per-Tensor和Per-Channel到底怎么选?

本文深入解析了模型量化中Per-Tensor与Per-Channel两种核心策略的抉择。Per-Tensor量化实现简单、硬件兼容性极佳,适合激活值或分布均匀的权重;而Per-Channel量化精度更高,能更好地处理权重分布不均的卷积层,是现代CNN权重量化的主流。文章提供了从硬件平台、数值分布到精度需求的实战决策框架,并推荐了“权重Per-Channel,激活Per-Tensor”的混合量化最佳实践。

assembly8low的博客 983

基于STM32单片机编写的驱动与设备分离的IIC驱动(模拟IIC,可兼容其他32系列单片机)

基于STM32单片机编写的驱动与设备分离的IIC驱动(模拟IIC,可兼容其他32系列单片机)

weixin_52168390的博客 1272

Linux系统下Materials Studio 2020安装避坑指南:从依赖包到许可证配置全流程

本文提供了一份在Linux系统上安装Materials Studio 2020的深度避坑指南。详细解析了从系统依赖包检查、安装流程、许可证配置到Gateway服务部署的全过程,并分享了与Slurm作业调度系统集成的实战经验,旨在帮助用户高效、稳定地完成部署。

weixin_29313547的博客 385

【windows】【系统还原】亦是美kms执行一键关闭defender 之后,windows defender 被卸载了,无论如何都打不开

还是执行 都没有明显效果 那么,我最后是怎么解决得呢? 一、打开控制面板(任务栏搜索kzmb)

weixin_41899098的博客 6904

STM32—I2C软件模拟

I2C 通讯协议 (Inter - Integrated Circuit) 是由 Phiilps 公司开发的,由于它引脚少,硬件实现简单, 可扩展性强,不需要 USART、CAN 等通讯协议的外部收发设备,现在被广泛地使用在系统内多 个集成电路 (IC) 间的通讯。 。

自我升级中 2583

Android车载音频系统概览

官网有些部分的内容描述比较简单,对没有app、系统和底层开发经验,容易一眼扫过,没有留意到相关细节。 本节补充车载音频相关细节。

hwj的博客 785

单片机:IIC总线通信

一、IIC总线通信1、简介: IIC 即Inter-Integrated Circuit(集成电路总线),I2C总线是PHLIPS公司推出的一种串行总线, I2C总线只有两根双向信号线。一根是数据线SDA,另一根是时钟线SCL。 每个接到I2C总线上的器件都有唯一的地址。主机与其它器件间的数据传送可以是由主机发送数据到其它器件,这时主机即为发送器。由总线上接收数据的器件则为接收器。2、常用的串行扩...

iotflh的博客 3106

AUTOSAR从入门到精通-复杂设备驱动(CDD)

CDD是复杂设备驱动的首字母缩写主要为驱动程序或复杂驱动程序,但不限于驱动程序。复杂驱动程序是一种未被AUTOSAR标准化的软件实体,可以通过AUTOSAR接口和/或基本软件模块api访问。 CDD是位于基础软件复杂驱动层的特定模块,与标准BSW模块或Rte交互。 CDD可能需要与分层软件体系结构的模块连接 分层软件架构的模块可能需要连接到CDD CDD可能需要通过Rte连接swc。

getusushu的博客 4192

RK3568下GPIO模拟串口

在嵌入式开发中,硬件 UART 资源可能被其他外设占用。此时,通过 GPIO 模拟 UART(软串口)成为一种灵活的解决方案。本文基于 RK3568 平台,结合 Linux 内核模块,实现高精度软串口通信,并深入分析关键技术细节。可以看到已经接收到数据了,可以自己创建自定义的设备文件到/dev下,也可以按照串口设备的标准创建一个设备,后面有时间我写一篇和标准串口设备结合的gpio模拟串口文章。RK3568 GPIO 模拟串口(软串口)实现详解。将编译好的驱动放到板子上运行。再写个Makefile。

文石_2009的博客 364

【STM32】 硬件IIC 驱动SSD1306(0.96 OLED模块) -- 1/4 库函数 学习

经过了对于STM32的学习,但是大多数时候都还是以移植别人的历程然后修修改改为主。为了更好的巩固自己的学习能力。所以此篇文章将会以记录我个人学习为案例,学习驱动IIC总线设备的能力。

koko的博客 5056

【毕设实战】飞行器目标识别系统:基于YOLOv5的智能检测全流程教程,助你毕设脱颖而出

亲爱的同学,毕设是不是让你既期待创新又担心技术门槛?如果你的毕设方向是计算机视觉、智能检测,那这个绝对能成为你的“毕设王牌”。从数据准备到界面开发,我会把整个项目拆成“傻瓜式”步骤,让你能一步步做出属于自己的毕设成果。

know_F0727的博客 104

硬件I2C与模拟I2C

硬件I2C对应芯片上的I2C外设,有相应I2C驱动电路,其所使用的I2C管脚也是专用的,因而效率要远高于软件模拟的I2C;一般也较为稳定,但是程序较为繁琐。硬件(固件)I2C是直接调用内部寄存器进行配置;而软件I2C是没有寄存器这个概念的。 软件I2C一般是使用GPIO管脚,用软件控制SCL,SDA线输出高低电平,模拟i2c协议的时序。 例如下面这段I2C的开始和结束信号,我们使用GPI...

Hsy的博客 1万+

efm32 入门.pdf

本PDF共计22页,介绍的是操作驱动API,下载与否自己斟酌。

NTscan扫描工具

ntscan是一个扫描器,可以扫描没有密码和弱密码的共享,先到配置文件中填写猜测的用户名和密码,扫描过程中右侧出现的是扫描日志。

硬件I2C和软件I2C的区别

硬件I2C(Inter-Integrated Circuit)是STM32等微控制器内置的串行通信接口,采用**同步、半双工**方式,通过**SCL(时钟线)**和**SDA(数据线)**两根信号线与外部设备通信。- **主模式(Master Mode)**:在这种模式下,STM32充当总线主机,负责发起通信并生成时钟信号(SCL),可以作为发送端或接收端。- **从设备地址固定**:通常由硬件引脚(A0~A2)设置,例如AT24C02的默认地址为**0xA0**(写)/ **0xA1**(读);

weixin_63207510的博客 2666

数学建模模型总结

这是本人在两年内准备参加数学建模竞赛搜集到的模型资料,已经经过了本人的筛选和整理,希望能够对准备参加数学建模竞赛的学弟学妹们提供一些帮助!

STM32/软件I2C和硬件I2C

本文深入探讨了STM32微控制器中软件I2C和硬件I2C的实现方法。I2C协议是一种两线串行总线协议,适用于短距离低速设备间通信,具有主从设备结构和独特的仲裁机制。软件I2C通过GPIO模拟时序,灵活性高但速度慢,占用CPU资源多。硬件I2C则利用内置外设自动生成时序,速度快,时序精度稳定,但引脚固定,资源有限。文章提供了详细的初始化和操作示例,包括设置时钟速度、占空比、应答使能等参数,以及如何生成起始/停止信号、发送和接收数据。

2502_91794894的博客 1595

温度PID控制PLC程序

温度PID稳定控制程序,适用于欧姆龙PLC,对其他PLC也具有很大参考价值

I2C通信之硬件I2C

本文内容都是参考B站UP“铁头山羊”的视频所写,作为学习笔记使用。在上一篇文章介绍了I2C通信,以及I2C的初始化,本文围绕STM32F1单片机使用硬件I2C写数据和读数据展开,代码放在附录部分。本文对硬件I2C发送数据和接收数据的流程进行了介绍,并给出了示例代码。可以看出硬件I2C操作在标准库中非常繁琐,并且大量使用了while函数,易死锁。后续,我们会对软件I2C进行介绍。

2401_82807263的博客 1323

STM32F103硬件I2C

很多时候由于模拟I2C以及足够满足通信需求而且比较灵活,所以硬件I2C被很多人忽略。但硬件 IIC 的效率要高于软件模拟的,模拟 IIC 是通过 GPIO, 软件模拟寄存器的工作方式,而硬件 IIC 是直接调用内部寄存器进行配置,所以采用芯片自带的 硬件IIC 通信接口的读写速度较模拟的会快一些。 对于部分初学且不会使用硬件IIC的小伙伴,这里以正点原子的STM32F103ZET6精英板为例,初始化一个硬件I2C接口用于OLED的通信供大家参考学习。......

weixin_50874851的博客 7337

软件I2C与硬件I2C的区别

I2C(Inter-Integrated Circuit)是一种串行通信协议,用于在集成电路之间进行短距离的数据传输。

weixin_45615278的博客 3702

硬件I2C和软件I2C(模拟I2C)的区别

硬件I2C和软件I2C(模拟I2C)是两种不同的实现I2C(Inter-Integrated Circuit,集成电路间)通信协议的方式,它们在实现方式、性能特点以及应用场景上存在显著差异。

qq_65582400的博客 7349

STM32F103C8T6 硬件I2C OLED

都说stm32F1的硬件i2c有问题,小白我初生牛犊不怕虎,想着试一试,就是看模拟i2c不爽... 是基于野火家的硬件i2c的例程修改的,因为OLED只需要写,不需要读,所以可以精简很多。 实际测试发现硬件i2c真的比模拟的快得多!!! stm32硬件i2c驱动OLED对比 话不多说,上代码! OLED.C #include "oled.h" #include ...

q943413302的博客 8395

STM32的硬件I2C有BUG吗?

坊间一直流传着一个传说~STM32的硬件I2C设计有BUG,最好不要用,用软件I2C比较靠谱。长久以来,为了不必要的麻烦,我也一直没有用过硬件I2C,主要是软件I2C也比较...

zhang062061的专栏 4780

软件I2C与硬件I2C对比优劣:认知型解析

深入探讨软件i2c实现机制及其灵活性优势,对比硬件i2c在性能与资源占用上的差异,帮助开发者根据实际场景选择更合适的通信方案,掌握软件i2c的调试技巧与应用场景。

weixin_36289813的博客 974

IIC基础回顾——硬件I2C

文章目录前言I2C控制器设计思路源码分析main.ci2c.ceeprom.c运行结果源码 前言 使用硬件I2C是,不用编写协议时序细节,通过寄存器配置好MCU的I²C控制器,I²C控制器便可控制引脚自动输出I²C时序。这里还是基于STM32F103_MIN开发板,以读写EEPROM(ATC2402)为例,进行回顾和分析。 I2C控制器 STM32F103系列的I2C控制器,可作为通信主机或从机,因此有4中工作模式可选择:主机发送模式、主机接收模式,从机发送模式、从机接收模式。 传输速度上,支持标准模式

m0_56145255的博客 6257
上一篇: io模拟i2c程序
下一篇: Android 之 SQLite 数据库
dadahacker
博客等级 码龄20年 78粉丝 120原创
评论 2
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值