I2C通信——S5PV210的I2C通信简单案例

以下内容源于朱有鹏嵌入式课程的学习与整理,如有侵权请告知删除。

参考内容

I2C子系统详解3——I2C总线驱动层代码分析_天糊土的博客-CSDN博客

一、S5PV210的I2C控制器 

1、为什么需要控制器?

通信双方通过时序协调工作,但是时序比较复杂,不利于SoC软件完成。于是在SoC内部设置了硬件的控制器来产生通信时序,这样我们写软件时只需要向控制器的寄存器中写入配置值即可。

2、I2C控制器结构框图

S5PV210的I2C控制器的相关内容,见用户手册第883页。

(1)时钟部分

时钟来源是PCLK_PSYS,经过内部分频最终得到I2C控制器的CLK,通信中这个CLK会通过SCL线传给从设备。

(2)I2C总线控制逻辑

这部分负责产生I2C通信时序,主要体现在I2CCON、I2CSTAT这两个寄存器。实际编程中要发送起始位、停止位、接收ACK等都是通过这两个寄存器(背后所代表的电路模块)来实现的。

(3)移位寄存器

将要发送的字节数据,通过移位寄存器变成连续的位,一个个位地丢给SDA线。

(4)地址寄存器 + 比较器

本I2C控制器做从设备的时候用。

3、I2C控制器的工作时钟

S5PV210——S5PV210的时钟系统中“三个时钟域”可知,PSYS时钟域为I2C模块提供时钟。时钟源头是PCLK_PSYS,经过2级分频后得到I2C控制器的工作时钟:第一级分频系数,在I2CCON的bit[6]进行设置,分频后得到一个中间时钟I2CCLK;第二级分频系数为[1,16],分频器的输入是I2CCLK,输出是I2C控制器的工作时钟。比如一个可用的配置是:65000KHz/512/4=31KHz。

4、I2C控制器有关的寄存器

(1)控制寄存器:I2CCON、I2CSTAT

主要用来产生通信时序和I2C接口配置。

(2)地址寄存器:I2CADD

当某个设备作为从设备时,可以往该寄存器的bit1~bit7写入这个从设备的 slave address。

换句话说,该寄存器的bit1~bit7存储着从设备在I2C总线上的地址。

(3)数据移位寄存器:I2CDS

将要发送的数据,或者接收到的数据,都存放在这个寄存器中。

二、X210板载gsensor简介

1、重力加速度传感器的简介

重力加速度传感器,这里简称为“gsensor”。

gsensor一般用在手机、平板、智能手表等设备上,用来感受物体的移动,以获取一些与运动方向性有关的信息,并作为输入参量传给系统。比如可以用来设计智能手表的计步器功能。

重力加速度传感器、地磁传感器、陀螺仪这三个传感器,都是用来感测运动的速度、方位等信息的,所以现在的9轴传感器,就是把这三个传感器结合起来,使用一定的算法得出结论,这样的结论比较精准。

传感器的接口一般有2种:模拟接口和数字接口。

模拟接口,是指使用接口电平变化来作为输出。比如使用模拟接口的压力传感器,在压力不同时输出电平在0~3.3V范围内变化,每个电压对应一个压力。SoC需要用使用AD对这些数据进行转换,得到数字化的电压值,再用数字电压值去校准得到压力值。

采用数字接口的传感器,是在采用模拟接口的传感器的基础上,内部集成了AD,通过一定的总线接口协议(一般是I2C)来输出数字化的参数。这样SoC直接通过总线接口初始化传感器、读取传感器输出的参数即可。比如gsensor、电容触摸屏IC就采用数字接口。

换言之,gsensor是I2C通信中的从设备,S5PV210中的I2C控制器是主设备。

2、gsensor原理图分析

由X210开发板的原理图可知:

(1)gsensor的供电由PWMTOUT3引脚控制。当PWMTOUT3输出低电平时,gsensor无电不工作,输出高电平时gsensor才会工作。PWMTOUT3对应着引脚GPD20_3。

(2)gsensor的SDA和SCL接在S5PV210的I2C端口0,对应着引脚GPD1_0、GPD1_1。将来编程时要初始化相关的GPIO,即把相关GPIO设置为正确的模式和输入输出值,这需要通过设置寄存器GPD1CON的来实现。该寄存器的内容如下:

3、I2C从设备的设备地址

这款重力加速度传感器的型号叫KXTE9,它作为I2C通信中的从设备,与S5PV210这个SoC中的I2C控制器(主设备)进行通信。KXTE9的I2C地址固定为 0b0001111(0x0f)。

I2C从设备地址本身是7位的,但是在I2C通信中发送I2C从设备地址时实际发送的是8位。高7位(bit7-bit1)对应I2C从设备的7位地址,最低一位(LSB)存放R/W信息(即下一个数据是主设备写从设备读(对应0),还是主设备读从设备写(对应1))。

主设备发信息给gsensor时,SAD应该是0b00011110(0x1E);如果是主设备读取gsensor信息时,则SAD应该是0b00011111(0x1F)。

4、I2C从设备的通信速率

I2C协议本身属于低速协议,通信速率不能太高。

另外主设备和从设备本身都有最高通信速率限制(属于各个芯片本身的参数),实际编程时只要小于两个即可。

作为只能做从设备的sensor,其本身I2C通信速率偏低,像KXTE9最高支持400KHz的频率。


三、I2C总线通信流程

这部分的内容位于用户手册第889页。

1、S5PV210的主发送流程图

2、S5PV210的主接收流程图

3、gsensor的写寄存器流程图

待写。

4、gsensor的读寄存器流程图

待写。

四、I2C通信代码

相关函数在文件drivers\i2c\busses\i2c-s3c2410.c中。

1、I2C控制器初始化:s3c24xx_i2c_init()

此函数完成I2C控制器的初始化:初始化GPIO,设置IRQEN和ACKEN,初始化I2C时钟。


/* s3c24xx_i2c_init
 *
 * initialise the controller, set the IO lines and frequency
*/

static int s3c24xx_i2c_init(struct s3c24xx_i2c *i2c)
{
	unsigned long iicon = S3C2410_IICCON_IRQEN | S3C2410_IICCON_ACKEN;
	struct s3c2410_platform_i2c *pdata;
	unsigned int freq;

	/* get the plafrom data */

	pdata = i2c->dev->platform_data;

	/* inititalise the gpio */

	if (pdata->cfg_gpio)
		pdata->cfg_gpio(to_platform_device(i2c->dev));

	/* write slave address */

	writeb(pdata->slave_addr, i2c->regs + S3C2410_IICADD);

	dev_dbg(i2c->dev, "slave address 0x%02x\n", pdata->slave_addr);

	writel(iicon, i2c->regs + S3C2410_IICCON);

	/* we need to work out the divisors for the clock... */

	if (s3c24xx_i2c_clockrate(i2c, &freq) != 0) {
		writel(0, i2c->regs + S3C2410_IICCON);
		dev_err(i2c->dev, "cannot meet bus frequency required\n");
		return -EINVAL;
	}

	/* todo - check that the i2c lines aren't being dragged anywhere */

	dev_dbg(i2c->dev, "bus frequency set to %d KHz\n", freq);
	dev_dbg(i2c->dev, "S3C2410_IICCON=0x%02lx\n", iicon);

	dev_dbg(i2c->dev, "S3C2440_IICLC=%08x\n", pdata->sda_delay);
	writel(pdata->sda_delay, i2c->regs + S3C2440_IICLC);

	return 0;
}

2、I2C控制器主模式开始一次读写:s3c24xx_i2c_message_start


/* s3c24xx_i2c_message_start
 *
 * put the start of a message onto the bus
*/

static void s3c24xx_i2c_message_start(struct s3c24xx_i2c *i2c,
				      struct i2c_msg *msg)
{
	unsigned int addr = (msg->addr & 0x7f) << 1;
	unsigned long stat;
	unsigned long iiccon;

	stat = 0;
	stat |=  S3C2410_IICSTAT_TXRXEN;

	if (msg->flags & I2C_M_RD) {
		stat |= S3C2410_IICSTAT_MASTER_RX;
		addr |= 1;
	} else
		stat |= S3C2410_IICSTAT_MASTER_TX;

	if (msg->flags & I2C_M_REV_DIR_ADDR)
		addr ^= 1;

	/* todo - check for wether ack wanted or not */
	s3c24xx_i2c_enable_ack(i2c);

	iiccon = readl(i2c->regs + S3C2410_IICCON);
	writel(stat, i2c->regs + S3C2410_IICSTAT);

	dev_dbg(i2c->dev, "START: %08lx to IICSTAT, %02x to DS\n", stat, addr);
	writeb(addr, i2c->regs + S3C2410_IICDS);

	/* delay here to ensure the data byte has gotten onto the bus
	 * before the transaction is started */

	ndelay(i2c->tx_setup);

	dev_dbg(i2c->dev, "iiccon, %08lx\n", iiccon);
	writel(iiccon, i2c->regs + S3C2410_IICCON);

	stat |= S3C2410_IICSTAT_START;
	writel(stat, i2c->regs + S3C2410_IICSTAT);
}

3、I2C控制器主模式结束一次读写:s3c24xx_i2c_stop

static inline void s3c24xx_i2c_stop(struct s3c24xx_i2c *i2c, int ret)
{
	unsigned long iicstat = readl(i2c->regs + S3C2410_IICSTAT);

	dev_dbg(i2c->dev, "STOP\n");

	/* stop the transfer */
	iicstat &= ~S3C2410_IICSTAT_START;
	writel(iicstat, i2c->regs + S3C2410_IICSTAT);

	i2c->state = STATE_STOP;

	s3c24xx_i2c_master_complete(i2c, ret);
	s3c24xx_i2c_disable_irq(i2c);
}

4、框架分析

我们最终目的是通过读写gsensor芯片的内部寄存器来得到一些信息。

为了完成这个目的,我们需要能够读写gsensor的寄存器。而根据gsensor的规定,我们需要按照一定的操作流程来读写gsensor的内部寄存器,这是一个层次(姑且叫做传输层、协议层、应用层)。协议层的代码主要取决于gsensor芯片。

我们要按照操作流程去读写寄存器,就需要考虑I2C接口协议。这就是所谓的物理层,本质就是那些时序。此时要看主机SoC有没有控制器,有控制器时考虑控制器的寄存器,没控制器时要自己软件模拟时序。物理层代码主要取决于主机SoC。

相关的操作函数

gsensor写寄存器:gsensor_i2c_write_reg

gsensor读寄存器:gsensor_i2c_read_reg

gsensor编程:gsensor_initial等

  • 3
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

天糊土

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值