s5pv210嵌入式开发(三)之---IIC通信

news/2025/2/12 18:17:14/

1. 原理

(1)通信特征

串行、同步、非差分、低速率、半双工

(2) 同步

同步通信就是通信双方工作在同一个时钟下,一般是通信的A方通过一根CLK信号线传输A自己的时钟给B,B工作在A传输的时钟下。同步通信的显著特征就是:通信线中有CLK

(3)低速率

I2C一般是用在同一个板子上的2个IC之间的通信,而且用来传输的数据量不大,所以本身通信速率很低(一般几百KHz,不同的I2C芯片的通信速率可能不同。在编程的时候要看自己所使用的设备允许的I2C通信最高速率,不能超过这个速率

(4)非差分

因为I2C通信速率不高,而且通信双方距离很近,所以使用电平信号通信,其实还有一根GND线,用来构成电平信号,而不是差分信号。

半双工

因为I2C通信只有一个SDA数据线用来传输通信数据,所以一个通信周期只能是由一方发送给另一方,而不能双方同时发送,所以是半双工通信模式。

2. 主控图

在这里插入图片描述

(1) SDA:串行数据线
(2) SCL:串行时钟线
(3) 用于芯片芯片之间通信

3. 电路

在这里插入图片描述
在这里插入图片描述

4. 时序图

(1) 起始终止信号标志

在这里插入图片描述

开始通信:

SDA线由高位拉到低位,此时I2C bus接口还处于从节点状态,SCL一直为高位。
设置I2C bus接口为master mode,此时产生SCL时钟信号,SDA可以传输数据、命令。

结束通信:

I2C bus 接口为master mode,是SCL一直产生高电平;
SDA由低突然拉高,即结束通信;

(2)数据读取

在这里插入图片描述

(3)数据帧格式

放置在SDA行上的每个字节长度应为8位。对于每次传输没有传输字节的限制。
开始条件之后的第一个字节应该有地址字段。如果i2c总线在主模式下工作,主传送地址字段。每个字节后跟一个确认(ACK)位。串行数据和地址的数据首先传输最高有效位MSB首先被发送。

主设备向从设备中发送(写)数据

在这里插入图片描述

主设备向从设备中接收(读)数据

在这里插入图片描述

5. 寄存器介绍(芯片手册p895 )

在这里插入图片描述

(1) 控制寄存器I2CCON
(2) 状态寄存器I2CSTAT
(3) 地址寄存器I2CADD
(4) 线控寄存器I2CLC
(5) 数据移位寄存器I2CDS

6. SDA仲裁

(1) 仲裁发生在SDA线上,以防止两个主总线之间的争用。如果一个具有高级SDA的主服务器检测到其他具有低级SDA活动的主服务器,它不会启动数据传输,因为总线上的当前级别与它自己的级别不相对应。
(2)SDA线的仲裁也是建立在总线具有线“与”逻辑功能的原理上的。节点在发送1位数据后,比较总线上所呈现的数据与自己发送的是否一致。是,继续发送;否则,退出竞争。SDA线的仲裁可以保证I2C总线系统在多个主节点同时企图控制总线时通信正常进行并且数据不丢失。总线系统通过仲裁只允许一个主节点可以继续占据总线
(3假设主节点产生低电平作为第一个地址位,而另一个主节点保持高电平。在这种情况下,两个主节点都检测总线上的低电平,在功率上,因为低电平优于高电平。如果发生这种情况,低电平(作为地址的第1位)将获得领导权,而高电平(作为地址的第1位)生成将退出领导权。如果两个主人产生低电平作为第一个位地址,仲裁会从第二个地址位再次仲裁。此仲裁继续到最后一个地址位的末尾)

7. I2C时钟

(1)I2C时钟源头来源于PCLK(PCLK_PSYS,等于65MHz),经过了2级分频后得到的。
(2)第一级分频是I2CCON的bit6,可以得到一个中间时钟I2CCLK(等于PCLK/16或者PCLK/512)。
(3)第二级分频是得到最终I2C控制器工作的时钟,以I2CCLK这个中间时钟为来源,分频系数为[1,16]。
(4)最终要得到时钟是2级分频后的时钟,比如一个可用的设置是:65000KHz/512/4=31KHz

8.I2C控制器流程图

(1)主发送模式流程

在这里插入图片描述

(2) 主接收模式流程

在这里插入图片描述

(3) 从设备发送模式

在这里插入图片描述

(4) 从设备接收模式

在这里插入图片描述

9. 读写过程分析

(1)写的过程:

开始的8个CLK中进行写的操作,SDA由主机驱动,第9个CLK,SDA由从机驱动,发出应答信号;

(2) 读的过程:

开始的8个CLK中进行读的操作,SDA由从机驱动,第9个CLK,SDA由主机驱动,发出应答信号;

10.部分代码分析

#include "lib.h"
/*s5pv210 I2C相关寄存器配置*/
/* GPIO */
#define GPD1CON		(*(volatile unsigned int *)0xE02000C0)
#define GPD1PUD		(*(volatile unsigned int *)0xE02000C8)/* IIC */
#define IICCON		(*(volatile unsigned int *)0xE1800000)
#define IICSTAT    	(*(volatile unsigned int *)0xE1800004)
#define IICDS		(*(volatile unsigned int *)0xE180000C)#define VIC0ADDRESS  		(*(volatile unsigned int *)0xF2000F00)
#define VIC1ADDRESS  		(*(volatile unsigned int *)0xF2100F00)
#define VIC2ADDRESS  		(*(volatile unsigned int *)0xF2200F00)
#define VIC3ADDRESS  		(*(volatile unsigned int *)0xF2300F00)void Delay(int time);#define WRDATA      (1)
#define RDDATA      (2)typedef struct tI2C {unsigned char *pData;   /* 数据缓冲区 */volatile int DataCount; /* 等待传输的数据长度 */volatile int Status;    /* 状态 */volatile int Mode;      /* 模式:读/写 */volatile int Pt;        /* pData中待传输数据的位置 */
}t210_I2C, *pt210_I2C;static t210_I2C g_t210_I2C;void i2c_init(void)
{/* 选择引脚功能:GPE15:IICSDA, GPE14:IICSCL */GPD1CON |= 0x22;GPD1PUD |= 0x5;/* bit[7] = 1, 使能ACK* bit[6] = 0, IICCLK = PCLK/16* bit[5] = 1, 使能中断* bit[3:0] = 0xf, Tx clock = IICCLK/16* PCLK = 66.7MHz, IICCLK = 4.1MHz*/IICCON = (1<<7) | (0<<6) | (1<<5) | (0xf);  // 0xafIICSTAT = 0x10;     // I2C串行输出使能(Rx/Tx)
}/** 主机发送* slvAddr : 从机地址,buf : 数据存放的缓冲区,len : 数据长度 */
void i2c_write(unsigned int slvAddr, unsigned char *buf, int len)
{g_t210_I2C.Mode = WRDATA;   // 写操作g_t210_I2C.Pt   = 0;        // 索引值初始为0g_t210_I2C.pData = buf;     // 保存缓冲区地址g_t210_I2C.DataCount = len; // 传输长度IICDS   = slvAddr;IICSTAT = 0xf0;         // 主机发送,启动/* 等待直至数据传输完毕 */    while (g_t210_I2C.DataCount != -1);
}/** 主机接收* slvAddr : 从机地址,buf : 数据存放的缓冲区,len : 数据长度 */
void i2c_read(unsigned int slvAddr, unsigned char *buf, int len)
{g_t210_I2C.Mode = RDDATA;   // 读操作g_t210_I2C.Pt   = -1;       // 索引值初始化为-1,表示第1个中断时不接收数据(地址中断)g_t210_I2C.pData = buf;     // 保存缓冲区地址g_t210_I2C.DataCount = len; // 传输长度IICDS        = slvAddr;IICSTAT      = 0xb0;    // 主机接收,启动/* 等待直至数据传输完毕 */    while (g_t210_I2C.DataCount != 0);
}//----------IIC中断服务函数----------
void do_irq(void) 
{unsigned int iicSt,i;wy_printf("do_irq \n");iicSt  = IICSTAT; if(iicSt & 0x8){ wy_printf("Bus arbitration failed\n"); }switch (g_t210_I2C.Mode){    //模式为写时中断处理case WRDATA:{if((g_t210_I2C.DataCount--) == 0){// 下面两行用来恢复I2C操作,发出P信号IICSTAT = 0xd0;//主传输模式IICCON  = 0xaf;Delay(10000);  // 等待一段时间以便P信号已经发出break;    }IICDS = g_t210_I2C.pData[g_t210_I2C.Pt++];// 将数据写入IICDS后,需要一段时间才能出现在SDA线上for (i = 0; i < 10; i++);   IICCON = 0xaf;      // 恢复I2C传输break;}//模式为读时中断处理case RDDATA:{if (g_t210_I2C.Pt == -1){// 这次中断是发送I2C设备地址后发生的,没有数据// 只接收一个数据时,不要发出ACK信号g_t210_I2C.Pt = 0;if(g_t210_I2C.DataCount == 1)IICCON = 0x2f;   // 恢复I2C传输,开始接收数据,接收到数据时不发出ACKelse IICCON = 0xaf;   // 恢复I2C传输,开始接收数据break;}g_t210_I2C.pData[g_t210_I2C.Pt++] = IICDS;g_t210_I2C.DataCount--;if (g_t210_I2C.DataCount == 0){// 下面两行恢复I2C操作,发出P信号IICSTAT = 0x90;IICCON  = 0xaf;Delay(10000);  // 等待一段时间以便P信号已经发出break;    }      else{           // 接收最后一个数据时,不要发出ACK信号if(g_t210_I2C.DataCount == 1)IICCON = 0x2f;   // 恢复I2C传输,接收到下一数据时无ACKelse IICCON = 0xaf;   // 恢复I2C传输,接收到下一数据时发出ACK}break;}default:break;      }// 中断结束一定要清中断向量VIC0ADDRESS = 0x0;VIC1ADDRESS = 0x0;VIC2ADDRESS = 0x0;VIC3ADDRESS = 0x0;
} unsigned char s5pv210_read(unsigned char address)
{unsigned char val;wy_printf("at24cxx_read address = %d\r\n", address);i2c_write(0xA0, &address, 1);wy_printf("at24cxx_read send address ok\r\n");i2c_read(0xA0, (unsigned char *)&val, 1);wy_printf("at24cxx_read get data ok\r\n");return val;
}void s5pv210_write(unsigned char address, unsigned char data)
{unsigned char val[2];val[0] = address;val[1] = data;i2c_write(0xA0, val, 2);
}

http://www.ppmy.cn/news/157093.html

相关文章

Jetson Nano GPIO使用、四种模式以及串口解释

参考&#xff1a; http://www.waveshare.net/study/portal.php?modview&aid882https://www.jianshu.com/p/f98a69b94debhttps://blog.csdn.net/qq_26904271/article/details/79829363https://www.cnblogs.com/wangha/p/10475719.html Jetson Nano GPIO说明 1. 安装Jets…

S5PV210系列(裸机四)mkv210_image.c文件详解

分析启动过程可知&#xff1a; 210 启动后先执行内部iROM中的BL0&#xff0c;BL0执行完后会根据 OMpin 的配置选择一个外部设备来启动&#xff08;有很多&#xff0c;我们实际使用的有2个&#xff1a;usb 启动和 SD卡 启动&#xff09;。在 usb 启动时内部 BL0 读取到 BL1 …

Jetson Nano配置踩坑全记录

Jetson Nano配置踩坑全记录 Jetson Nano相关参数&#xff1a;JetPack 4.6&#xff0c;cuda 10.2&#xff0c; SD卡内存&#xff1a;512G 一、Jetson Nano系统镜像烧录 在Nvidia官网下载Jetson Nano的系统镜像&#xff1a; https://developer.nvidia.com/embedded/learn/get-s…

nVIDIA Jetson TX1 u-boot编译与烧写

1、官网下载源码&#xff1a; https://developer.nvidia.com/embedded/downloads#?tx$software,l4t-tx1 解压u-boot_src.tbz2到本地&#xff1a; $ tar -xvjf u-boot_src.tbz2 $ cd u-boot/ 2、u-boot修改与编译 设置环境变量&#xff1a; $ export ARCHarm $ export CR…

在Jetson Nano中安装Tensorflow与PyTorch,解决arm架构h5py、sklearn、TLS block等问题

Setup Jetson Nano 因为Nano是Arm架构&#xff0c;所以相比x86_64架构的配置流程有所区别。 解决BUG部分请直接跳到本文最后。 1. Notification Arm的许多源是与x86_64源不同的&#xff0c;所以除非很有把握&#xff0c;最好保持Nvidia出厂配置的源不变&#xff0c;轻易不改…

Nvidia内核设备树driver编译

一、环境准备 下载同一个SDK的开源code以及编译好的对应镜像&#xff0c;链接&#xff1a; https://developer.nvidia.com/embedded/linux-tegra-r3271一般选择最新的即可&#xff0c;然后主要需要以下工具 public source code &#xff1a;设备树以及linux源码x86 cross co…

Linux学习——I2C-MPU6050驱动移植记录

开发板&#xff1a;Nvidia Jetson Nano b01 模块&#xff1a;MPU6050 I2C设备 接线 vcc — 3.3v(17) gnd — GND(25) scl — I2C0_SCL(28) -> pJ1 sda — I2C0_SDA(27) //AD0:从机地址设置引脚 :1.接地或悬空时, 地址为0x68&#xff1b;2.接VCC时&#xff0c;地址为0x69 /…

当刷机工具遇到SetupConnection时的解决方法

当刷机工具遇到SetupConnection时&#xff0c;解决方法 首先&#xff0c;在此贴上原文地址&#xff0c;已表感激之情。 http://blog.sina.com.cn/s/blog_636fd7d90101drak.html http://bbs.gfan.com/android-4032375-1-1.html 据说程序员是比较挑剔的&#xff0c;骨子里难…