IIC
一、IIC介绍
I2C(Inter-Integrated Circuit)总线是80年代PHILIPS公司开发的两线式串行总线,如今已经成为芯片间低速串行通信的事实标准,被广泛使用在消费、控制类电子设备场合。这里的两个关键词两线和低速:
两线意味着结构简单,低速意味着好实现,做电路的都知道速度越慢电路实现起来就越容易,而且协议方式也很优雅。所以这是一个简单、优雅、好实现、应用又广泛的电路协议。
二、TM4C123GH6PM的I2C模块的特征
内部集成电路(I2C)总线通过一个两线设计(串行数据线 SDA 和串行时钟线 SCL)来提供双向数据传输,并且与外部 I2C 器件诸如串行存储器(RAM 和 ROM),网络设备,LCD,音频发生器等联系。I2C 总线也可用于产品开发和制造的系统测试和诊断的目的。TM4C123GH6PM 微控制器提供与其他 I2C 总线上的设备交互(发送和接收)的能力。TM4C123GH6PM 控制器的 I2C 模块具有以下特点:
- 可以用作master也可以用作slave
- 两种情况下都支持发送和接受数据
- 同时支持主机和从机操作
- 四个I2C模式
- 主机发送模式
- 主机接收模式
- 从机发送模式
- 从机接收模式
- 四个发送速率
- 标准模式(100Kbps)
- 快速模式(400Kbps)
- 超快速模式(1bm’s)
- 高速模式(3.33bm’s)
- 时钟低超时中断
- 双从地址能力
- 抗干扰
- 主机和从机中断的产生
- 当主机发送或接收操作完成时(或因为错误终止时),产生中断
- 当从机发送数据或主机需要数据或检测到起始停止条件时,产生中断
- 主机由仲裁和时钟同步,支持多主机,以及7位寻址模式
三、结构图
四、操作介绍
1、主机操作
- 当使用那些API操作I2C主机模块时,用户必须首先调用
I2CMasterInitExpClk()
函数,这个函数可以设置总线速率、使能主机模块。 - 首先设置从机地址
I2CMasterSlaveAddrSet()
,这个函数还可以用于设置定义是发送(向从机写)还是接收(从从机读)。 - 然后如果当前总线是一个多主机主线的话,我们这个主机要先调用
l I2CMasterBusBusy()
函数。这个函数可以确定这个主线忙不忙。 - 最后,如果是想发送数据,就调用
I2CMasterDataPut()
函数,可以将要传送的数据存入I2C主机数据寄存器中。I2CMasterControl()
控制I2C主机的状态(也就是发送一个指令),这样的指令就能操纵总线,发送开始序列,发送从机地址和方向。剩余部分的传送可以通过轮询或者中断的方法来进行。下面是指令的内容关于轮询模式和中断模式的介绍
- For the single send and receive cases, the polling method involves looping on the return fromI2CMasterBusy(). Once that function indicates that the I2C master is no longer busy, the bus transaction has been completed and can be checked for errors using I2CMasterErr(). If there are no errors, then the data has been sent or is ready to be read using I2CMasterDataGet().
- For the burst send and receive cases, the polling method also involves calling the I2CMasterControl() function for each byte transmitted or received (using either the I2C_MASTER_CMD_BURST_SEND_CONT or I2C_MASTER_CMD_BURST_RECEIVE_CONT commands), and for the last byte sent or received (using either the I2C_MASTER_CMD_BURST_SEND_FINISH or I2C_MASTER_CMD_BURST_RECEIVE_FINISH commands). If any error is detected during the burst transfer, the I2CMasterControl() function should be called using the appropriate stop command (I2C_MASTER_CMD_BURST_SEND_ERROR_STOP or I2C_MASTER_CMD_BURST_RECEIVE_ERROR_STOP).
- For the interrupt-driven transaction, the user must register an interrupt handler for the I2C devices and enable the I2C master interrupt; the interrupt occurs when the master is no longer busy.
具体功能需结合数据手册的相应位查看
I2C_MASTER_CMD_BURST_SEND_START
起始信号+从机地址+应答+从机寄存器+应答
I2C_MASTER_CMD_BURST_SEND_CONT
数据+应答
I2C_MASTER_CMD_BURST_SEND_FINISH
I2C_MASTER_CMD_BURST_SEND_STOP
停止信号
I2C_MASTER_CMD_BURST_RECEIVE_START
起始信号+从机地址+应答+从机寄存器+应答
I2C_MASTER_CMD_BURST_RECEIVE_CONT
接收数据+应答
I2C_MASTER_CMD_BURST_RECEIVE_FINISH
停止信号
注意
I2C_MASTER_CMD_SINGLE_SEND
起始信号+从机地址+应答+数据+应答
与I2C_MASTER_CMD_BURST_SEND_CONT区别:多了起始信号+从机地址+应答
I2C_MASTER_CMD_SINGLE_RECEIVE
起始信号+从机地址+应答+接收数据+应答
同上!2.从机模式
当使用I2C从机模式时,用户需要调用
I2CSlaveInit()
函数。这个函数可以使能I2C从机模块,初始化从机地址。然后,根据操作的不同,用户可以调用I2CSlaveDataPut()
或者I2CSlaveDataGet()
来完成传输。或者可以通过中断来完成传输操作。中断用I2CIntRegister()
来注册五、驱动包含在 driverlib/i2c.c 和 driverlib/i2c.h 里
六、例程
这里先给出一个loopback的程序(无需连接外置I2C设备,自发自收)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39uint32_t pui32DataTx[NUM_I2C_DATA];
uint32_t pui32DataRx[NUM_I2C_DATA];
uint32_t ui32Index;
SysCtlPeripheralEnable(SYSCTL_PERIPH_I2C0);
SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOB);
GPIOPinConfigure(GPIO_PB2_I2C0SCL);
GPIOPinConfigure(GPIO_PB3_I2C0SDA);
GPIOPinTypeI2CSCL(GPIO_PORTB_BASE, GPIO_PIN_2);
GPIOPinTypeI2C(GPIO_PORTB_BASE, GPIO_PIN_3);
I2CLoopbackEnable(I2C0_BASE);
I2CMasterInitExpClk(I2C0_BASE, SysCtlClockGet(), false);
I2CSlaveEnable(I2C0_BASE);
I2CSlaveInit(I2C0_BASE, SLAVE_ADDRESS);
I2CMasterSlaveAddrSet(I2C0_BASE, SLAVE_ADDRESS, false);
pui32DataTx[0] = 'I';
pui32DataTx[1] = '2';
pui32DataTx[2] = 'C';
for(ui32Index = 0; ui32Index < NUM_I2C_DATA; ui32Index++){
pui32DataRx[ui32Index] = 0;
}
for(ui32Index = 0; ui32Index < NUM_I2C_DATA; ui32Index++){
I2CMasterDataPut(I2C0_BASE, pui32DataTx[ui32Index]);
I2CMasterControl(I2C0_BASE, I2C_MASTER_CMD_SINGLE_SEND);
while(!(I2CSlaveStatus(I2C0_BASE) & I2C_SLAVE_ACT_RREQ)){}
pui32DataRx[ui32Index] = I2CSlaveDataGet(I2C0_BASE);
while(I2CMasterBusy(I2C0_BASE)){}
}
for(ui32Index = 0; ui32Index < NUM_I2C_DATA; ui32Index++){
pui32DataRx[ui32Index] = 0;
}
I2CMasterSlaveAddrSet(I2C0_BASE, SLAVE_ADDRESS, true);
I2CMasterControl(I2C0_BASE, I2C_MASTER_CMD_SINGLE_RECEIVE);
while(!(I2CSlaveStatus(I2C0_BASE) & I2C_SLAVE_ACT_TREQ)){}
for(ui32Index = 0; ui32Index < NUM_I2C_DATA; ui32Index++){
I2CSlaveDataPut(I2C0_BASE, pui32DataTx[ui32Index]);
I2CMasterControl(I2C0_BASE, I2C_MASTER_CMD_SINGLE_RECEIVE);
while(!(I2CSlaveStatus(I2C0_BASE) & I2C_SLAVE_ACT_TREQ)){}
pui32DataRx[ui32Index] = I2CMasterDataGet(I2C0_BASE);
}