ARM裸机 - I2C 通信和 ADC 转换

本节介绍I2C接口的物理特征、通信特征(串行、同步、非差分、低速率)、主从设备、通信时序,以及S5PV210的I2C控制器,然后还有x210自带的 gsensor 芯片

本节介绍I2C接口的物理特征、通信特征(串行、同步、非差分、低速率)、主从设备、通信时序,以及S5PV210的I2C控制器,然后还有x210自带的 gsensor 芯片

什么是I2C通信

物理接口:SCL + SDA

  • SCL(serial clock):
    • 时钟线,传输CLK信号,一般是I2C主设备向从设备提供时钟的通道。
  • SDA(serial data):
    • 数据线,通信数据都通过SDA线传输

通信特征:串行、同步、非差分、低速率

  • I2C属于串行通信,所有的数据以位为单位在SDA线上串行传输。
  • 同步通信就是通信双方工作在同一个时钟下,一般是通信的A方通过一根CLK信号线传输A自己的时钟给B,B工作在A传输的时钟下。所以同步通信的显著特征就是:通信线中有CLK
  • 非差分。因为I2C通信速率不高,而且通信双方距离很近,所以使用电平信号通信。
  • 低速率。I2C一般是用在同一个板子上的2个IC之间的通信,而且用来传输的数据量不大,所以本身通信速率很低(一般几百KHz,不同的I2C芯片的通信速率可能不同,具体在编程的时候要看自己所使用的设备允许的I2C通信最高速率,不能超过这个速率)

突出特征

主设备+从设备

I2C通信的时候,通信双方地位是不对等的,而是分主设备和从设备。通信由主设备发起,由主设备主导,从设备只是按照I2C协议被动的接受主设备的通信,并及时响应。谁是主设备、谁是从设备是由通信双方来定的(I2C协议并无规定),一般来说一个芯片可以只能做主设备、也可以只能做从设备、也可以既能当主设备又能当从设备(软件配置)。

可以多个设备挂在一条总线上

  • I2C通信可以一对一(1个主设备对1个从设备),也可以一对多(1个主设备对多个从设备)。
  • 主设备来负责调度总线,决定某一时间和哪个从设备通信。注意:同一时间内,I2C的总线上只能传输一对设备的通信信息,所以同一时间只能有一个从设备和主设备通信,其他从设备处于“冬眠”状态
  • 每一个I2C从设备在通信中都有一个I2C从设备地址,这个设备地址是从设备本身固有的属性,然后通信时主设备需要知道自己将要通信的那个从设备的地址,然后在通信中通过地址来甄别是不是自己要找的那个从设备。(这个地址是一个电路板上唯一的,不是全球唯一的)

主要用途

SoC和周边外设之间的通信(典型的如EEPROM、电容触摸IC、各种sensor等)

由I2C学通信时序

什么是时序

时序:字面意思,时序就是时间顺序,实际上在通信中时序就是通信线上按照时间顺序发生的电平变化,以及这些变化对通信的意义就叫时序。

I2C的总线空闲状态、起始位、结束位

condition

  • I2C总线上有1个主设备,n(n>=1)个从设备。
  • I2C总线上有2种状态:
    • 空闲态(所有从设备都未和主设备通信,此时总线空闲)
    • 忙态(其中一个从设备在和主设备通信,此时总线被这一对占用,其他从设备必须歇着)。
  • 整个通信分为一个周期一个周期的,两个相邻的通信周期是空闲态。每一个通信周期由一个起始位开始,一个结束位结束,中间是本周期的通信数据。
  • 起始位并不是一个时间点,起始位是一个时间段,在这段时间内总线状态变化情况是:SCL线维持高电平,同时SDA线发生一个从高到低的下降沿。
  • 与起始位相似,结束位也是一个时间段。在这段时间内总线状态变化情况是:SCL线维持高电平,同时SDA线发生一个从低到高的上升沿。

I2C数据传输格式(数据位&ACK)

format

  • 每一个通信周期的发起和结束都是由主设备来做的,从设备只有被动的响应主设备,没法自己自发的去做任何事情。
  • 主设备在每个通信周期会先发8位的从设备地址(其实8位中只有7位是从设备地址,还有1位表示主设备下面要写入还是读出)到总线(主设备是以广播的形式发送的,只要是总线上的所有从设备其实都能收到这个信息)。然后总线上的每个从设备都能收到这个地址,并且收到地址后和自己的设备地址比较看是否相等。如果相等说明主设备本次通信就是给我说话,如果不想等说明这次通信与我无关,不用听了不管了。
  • 发送方发送一段数据后,接收方需要回应一个ACK。这个响应本身只有1个bit位,不能携带有效信息,只能表示2个意思(要么表示收到数据,即有效响应;要么表示未收到数据,无效响应)
  • 在某一个通信时刻,主设备和从设备只能有一个在发(占用总线,也就是向总线写),另一个在收(从总线读)。如果在某个时间主设备和从设备都试图向总线写那就完蛋了,通信就乱套了。

数据在总线上的传输协议

transfer

  • I2C通信时的基本数据单位也是以字节为单位的,每次传输的有效数据都是1个字节(8位)。
  • 起始位及其后的8个 CLK 中都是主设备在发送(这设备掌控总线),此时从设备只能读取总线,通过读总线来得知主设备发给从设备的信息;然后到了第9周期,按照协议规定从设备需要发送ACK给主设备,所以此时主设备必须释放总线(主设备把总线置为高电平然后不要动,其实就类似于总线空闲状态),同时从设备试图拉低总线发出ACK。如果从设备拉低总线失败,或者从设备根本就没有拉低总线,则主设备看到的现象就是总线在第9周期仍然一直保持高,这对主设备来说,意味着我没收到ACK,主设备就认为刚才给从设备发送的8字节不对(接收失败)

S5PV210 的 I2C 控制器

S5PV210 RISC微处理器支持四个多主站I2C总线串行接口。为了在总线主站和连接到I2C总线的外围设备之间传输信息,使用了一条专用的串行数据线(SDA)和一条串行时钟线(SCL)。SDA和SCL线都是双向的。

为了控制多主站I2C总线操作,必须将值写入以下寄存器中:

  • 多主站I2C总线控制寄存器-I2CCON
  • 多主站I2C总线控制/状态寄存器-I2CSTAT
  • 多主站I2C总线Tx/Rx数据移位寄存器-I2CDS
  • 多主站I2C总线地址寄存器-I2CADD

如果I2C总线是空闲的,那么SDA和SCL线都应该是高电平。SDA从高电平到低电平的转换会触发一个开始条件。SDA的低电平到高电平的转换会触发一个停止条件,而SCL保持稳定在高电平。

主设备总是会产生启动和停止条件。启动条件启动后,通过SDA线传输的数据字节中的第一个7位地址值,可以确定总线主设备选择的从设备。第8位决定了传输的方向(读或写)。

每一个放到SDA线上的数据总共应该是8位。在总线传输操作中,发送或接收字节数没有限制。数据总是先从最高位(MSB)开始发送,每个字节后应紧随其后的是确认(ACK)位。

通信双方本质上是通过时序在工作,但是时序会比较复杂不利于SoC软件完成,于是乎解决方案是SoC内部内置了硬件的控制器来产生通信时序。这样我们写软件时只需要向控制器的寄存器中写入配置值即可,控制器会产生适当的时序在通信线上和对方通信。

结构框图

construct

  • 时钟部分
    • 时钟来源是PCLK_PSYS,经过内部分频最终得到I2C控制器的CLK,通信中这个CLK会通过SCL线传给从设备。
  • I2C总线控制逻辑(前台代表是I2CCON、I2CSTAT这两个寄存器)
    • 主要负责产生I2C通信时序。实际编程中要发送起始位、停止位、接收ACK等都是通过这两个寄存器(背后所代表的电路模块)实现的。
  • 移位寄存器(shift register)
    • 将代码中要发送的字节数据,通过移位寄存器变成1个位一个位的丢给SDA线上去发送/接收
  • 地址寄存器+比较器。本I2C控制器做从设备的时候用

系统分析I2C的时钟

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

主要寄存器I2CCON、I2CSTAT、I2CADD、I2CDS

  • I2CCON + I2CSTAT:主要用来产生通信时序和I2C接口配置。
  • I2CADD:用来写自己的slave address
  • I2CDS:发送/接收的数据都放在这里

X210板载 gsensor 介绍

原理图查阅

gsensor

  • gsensor的供电由PWMTOUT3引脚控制。当PWMTOUT3输出低电平时gsensor无电不工作;当输出高电平时gsensor才会工作。
  • gsensor的SDA和SCL接的是S5PV210的I2C端口0
  • 将来编程时在gsensor_init函数中要去初始化相关的GPIO。要把相应的GPIO设置为正确的模式和输入输出值。

I2C从设备的设备地址

  • KXTE9的I2C地址固定为0b0001111(0x0f)
  • I2C从设备地址本身是7位的,但是在I2C通信中发送I2C从设备地址时实际发送的是8位,这8位中高7位(bit7-bit1)对应I2C从设备的7位地址,最低一位(LSB)存放的是R/W信息(就是说下一个数据是主设备写从设备读(对应0),还是主设备读从设备写(对应1))
  • 基于上面讲的,对于KXTE9来说,主设备(SoC)发给gsensor信息时,SAD应该是:0b00011110(0x1E) 如果是主设备读取gsensor信息时,SAD应该是:0b00011111(0x1F)

I2C从设备的通信速率

  • I2C协议本身属于低速协议,通信速率不能太高。
  • 实际上通信的主设备和从设备本身都有最高的通信速率限制(属于各个芯片本身的参数),实际编程时怎么确定最终的通信速率?只要小于两个即可。
  • 一般来说只能做从设备的sensor芯片本身i2c通信速率偏低,像KXTE9最高支持400KHz的频率。

I2C总线的通信流程

S5PV210的主发送流程图

mtransfer

S5PV210的主接收流程图

master receiver

gsensor的写寄存器流程图

gsend

gsensor的读寄存器流程图

greceiver

I2C 相关寄存器

寄存器地址

rmap

I2C 控制寄存器

  • I2CCON0, R/W, Address = 0xE180_0000
  • I2CCON2, R/W, Address = 0xE1A0_0000

control

I2C 控制状态寄存器

  • I2CSTAT0, R/W, Address = 0xE180_0004
  • I2CSTAT2, R/W, Address = 0xE1A0_0004

status

I2C 从站地址寄存器

addr

I2C 移位寄存器

shift

I2C 线控寄存器

line

ADC的引入

什么是ADC

ADC:analog digital converter,AD转换,模数转换(也就是模拟转数字)。CPU本身是数字的,而外部世界变量(如电压、温度、高度、压力・・・)都是模拟的,所以需要用CPU来处理这些外部的模拟变量的时候就需要做AD转换。

ADC的主要相关概念

量程(模拟量输入范围)

  • AD转换器是一个电子器件,所以他只能输入电压信号。其他种类的模拟信号要先经过传感器(Sensor)的转换变成模拟的电压信号然后才能给AD。
  • AD输入端的模拟电压要求有一个范围,一般是0~3.3V或0~5V或者是0~12V等等。模拟电压的范围是AD芯片本身的一个参数。实际工作时给AD的电压信号不能超过这个电压范围。

精度(分辨率resolution)

  • AD转换输出的数字值是有一定的位数的(譬如说10位,意思就是输出的数字值是用10个二进制位来表示的,这种就叫10位AD)。这个位数就表示了转换精度。
  • 10位AD就相当于把整个范围分成了1024个格子,每个格子之间的间隔就是电压的表示精度。加入AD芯片的量程是0~3.3V,则每个格子代表的电压值是3.3V/1024=0.0032265V。如果此时AD转换后得到的数字量是447,则这个数字量代表的模拟值是:447×0.0032265V=1.44V。
  • AD的位数越多,则每个格子表示的电压值越小,将来算出来的模拟电压值就越精确。
  • AD的模拟量程一样的情况下,AD精度位数越多精度越高,测出来的值越准。但是如果AD的量程不一样。譬如2个AD,A的量程是0~50V,B的量程是0~0.5V,A是12位的,B是10位的,可能B的精度比A的还要高。(A的精度:50/1024=0.04883,B的精度:0.5/4096=0.000122)

转换速率(MSPS与 conventer clock的不同)

  • AD芯片进行AD转换是要耗费时间的。这个时间需要多久,不同的芯片是不一样的,同一颗芯片在配置不一样(譬如说精度配置为10位时时间比精度配置为12位时要小,譬如说有些AD可以配转换时钟,时钟频率高则转换时间短)时转换时间也不一样。
  • 详细的需要时间可以参考数据手册。一般数据手册中描述转换速率用的单位是MSPS(第一个M是兆,S是sample,就是采样;PS就是per second,总的意思就是兆样本每秒,每秒种转出来多少M个数字值)
  • AD工作都需要一个时钟,这个时钟有一个范围,我们实际给他配置时不要超出这个范围就可以了。AD转换是在这个时钟下进行的,时钟的频率控制着AD转换的速率。注意:时钟频率和MSPS不是一回事,只是成正比不是完全相等。譬如S5PV210中的AD转换器,MSPS = 时钟频率/5

S5PV210的ADC控制器

ADC和(电阻式)触摸屏的关系

adc_block

ADC在210的数据手册的Section10.7。电阻式触摸屏本身工作时依赖于AD转换,所以在210的SoC中电阻触摸屏接口本身和ADC接口是合二为一的。或者说电阻触摸屏接口使用了(复用了)ADC的接口。

ADC的工作时钟框图

adc_clock

ADCCLK 是ADC控制器工作的时钟,也就是1.13.2.3节中讲到的 converter clock。从时钟框图可以看出,它是PCLK(当然是PCLK_PSYS)经过了一次分频后得到的。所以将来初始化ADC控制器时一定有一个步骤是初始化这里的分频器。

210的10个ADC通道(注意ADC引脚和GPIO的区别)

  • 210一共支持10个ADC通道,分别叫AIN[0]~AIN[9]。理论上可以同时做10路AD转换。
  • SoC的引脚至少分2种:
    • digit数字引脚
    • analog模拟引脚。
    • 我们以前接触的GPIO都属于数字引脚,ADC channel通道引脚属于模拟引脚。数字引脚和模拟引脚一般是不能混用的。

ADC控制器的主要寄存器

reg

  • 等待触摸屏转换完毕的方法有2种:
    • 一种是检查标志位
      • 我们先开启一次转换然后循环不停检查标志位直到标志位为1表明已经转换完可以去读了
    • 第二种是中断
      • 设置好中断,写好中断isr来读取AD转换数据。
      • 然后开启中断后CPU就不用管了,等AD转换完成后会生成一个中断信号给CPU,就会进入中断处理流程。
    • 第一种方法是同步的,第二种方式是异步的。
  • AD转换都是需要反复进行的,那么转完一次一般要立即开启下一次转换,所以需要有一种机制能够在一次转完时自动开启下一次。这个机制就叫start by read,这个机制的工作方法是:当我们读取本次AD转换的AD值后,硬件自动开启下一次AD转换。

ADC Control Register (TSADCCONn)

  • TSADCCON0, R/W, Address = 0xE170_0000
  • TSADCCON1, R/W, Address = 0xE170_1000

adc_control

ADC Conversion Data X/Y Register (TSDATXn)

  • TSDATX0, R, Address = 0xE170_000C
  • TSDATX1, R, Address = 0xE170_100C

adc_conv

  • TSDATY0, R, Address = 0xE170_0010
  • TSDATY1, R, Address = 0xE170_1010

adc_convy

ADC Interrupt Clear Register (CLRINTADCn)

  • CLRINTADC0, W, Address = 0xE170_0018
  • CLRINTADC1, W, Address = 0xE170_1018

adc_int

这些寄存器是用来清除中断服务的。中断服务例程负责在中断服务完成后清除中断。在此寄存器中写入任何值,都会清除相关的中断断言。当它被读取时,将返回未定义的值。

ADC Channel Mux Register (ADCMUX, R/W, Address = 0xE170_001C)

adc_mux

  • 当不使用触摸屏时,可将触摸屏端口(AIN2~AIN9)作为ADC的模拟输入端口。
  • 当 TSADC 设置为 1) 独立的 X/Y 位置转换模式或 2) 自动(顺序)X/Y 位置转换模式时,SEL_MUX 值无效。

ADC 元件

adc_b

由主板原理图可知,外部的滑动变阻器接到了 ADCIN0 接口

adc_v

由核心板原理图可知,ADCIN0 接到了 S5PV210 的 XadcAIN_0 端口

io

最后,查 S5PV210 手册,可以看到 XadcAIN_0 是 AIN[0],使用的是模拟通道0