LoopBack
该示例演示使用 I2C 进行自发自收的通信。
将I2C0作为主机读取I2C1传递的数据长度和数据信息,I2C1作为从机接收I2C0发送数据长度和数据信息,实现I2C的通信功能。
环境需求
该示例支持以下开发套件:
Hardware Platforms |
Board Name |
---|---|
RTL87x2G HDK |
RTL87x2G EVB |
更多信息请参考快速入门。
硬件连线
连接P4_0(I2C0的SCL)和P4_2(I2C1的SCL),P4_1(I2C0的SDA)和P4_3(I2C1的SDA),接线时需要接2.2k上拉电阻。
上拉电阻的连接示意图如下图所示:

I2C上拉电阻连接示意图
配置选项
该示例可配置的宏如下:
I2C_MASTER_SEND_SLAVE_RECEIVE
:开启该宏可配置示例为主机发送从机接收。I2C_MASTER_RECEIVE_SLAVE_SEND
:开启该宏可配置示例为主机接收从机发送。I2C_MASTER_REPEAT_READ
:开启该宏可配置示例为主机连续发送和接收数据。
编译和下载
该示例的工程路径如下:
Project file: samples\peripheral\i2c\trx_loopback\proj\rtl87x2g\mdk
Project file: samples\peripheral\i2c\trx_loopback\proj\rtl87x2g\gcc
请按照以下步骤操作构建并运行该示例:
打开工程文件。
按照 快速入门 中 编译APP Image 给出的步骤构建目标文件。
编译成功后,在路径
mdk\bin
或gcc\bin
下会生成 app binapp_MP_xxx.bin
文件。按下复位按键,开始运行。
测试验证
开启I2C主机发送从机接收 I2C_MASTER_SEND_SLAVE_RECEIVE
时:
当SLAVE端接收的数据达到设定的threshold level时,触发
I2C_INT_RX_FULL
中断,打印log。I2C1 Rx Full detected
当MASTER端数据发送完毕时,SLAVE端也检测到停止信号,MASTER端和SLAVE端触发
I2C_INT_STOP_DET
中断,打印log。I2C0 Stop signal detected I2C1 Stop signal detected
在SLAVE端中断函数内,打印收到的数据长度和数据内容。
Slave Recv Date Lenth = 24 I2C1_Slave_ReceiveData=0 ... I2C1_Slave_ReceiveData=23
开启I2C主机接收从机发送 I2C_MASTER_RECEIVE_SLAVE_SEND
时:
SLAVE端收到MASTER端发来的读请求,触发
I2C_INT_RD_REQ
中断,打印log 。Enter I2C1 interrupt I2C1_INT_RD_REQ!
打印MASTER端接收到的数据。
Master Read data = 10 ... Master Read data = 33
开启I2C主机连续发送和接收数据 I2C_MASTER_REPEAT_READ
时:
SLAVE端收到MASTER端发来的读请求,触发
I2C_INT_RD_REQ
中断,打印log。Enter I2C1 interrupt I2C1_INT_RD_REQ!
SLAVE端收到MASTER端发来的数据,在SLAVE端中断函数内,打印收到的数据长度和数据内容。
Slave Recv Date Lenth = 4 I2C1_Slave_ReceiveData=1 I2C1_Slave_ReceiveData=2 I2C1_Slave_ReceiveData=3 I2C1_Slave_ReceiveData=4
SLAVE端接收完毕数据,打印log。
I2C1 RX_DONE detected
SLAVE端给MASTER端回数据。MASTER端收数据完成后,打印log。
I2C0 Stop signal detected
打印MASTER端收到的数据。
Master Repeat Read data = 10 ... Master Repeat Read data = 33
代码介绍
该章节分为以下几个部分:
源码路径
工程路径:
sdk\samples\peripheral\i2c\trx_loopback\proj
源码路径:
sdk\samples\peripheral\i2c\trx_loopback\src
该工程的工程文件代码结构如下:
└── Project: trx_loopback
└── secure_only_app
└── Device includes startup code
├── startup_rtl.c
└── system_rtl.c
├── CMSIS includes CMSIS header files
├── CMSE Library Non-secure callable lib
├── Lib includes all binary symbol files that user application is built on
└── rtl87x2g_io.lib
├── Peripheral includes all peripheral drivers and module code used by the application
├── rtl_rcc.c
├── rtl_pinmux.c
├── rtl_nvic.c
├── rtl_gdma.c
└── rtl_i2c.c
└── APP includes the ble_peripheral user application implementation
├── main_ns.c
└── io_i2c.c
初始化
初始化流程包括了 board_i2c_master_init
, board_i2c_slave_init
,
driver_i2c_master_init
、 driver_i2c_slave_init
和 nvic_i2c_config
board_i2c_master_init
和 board_i2c_slave_init
中包含了对I2C0和I2C1的PAD与PINMUX设置:
配置PAD:设置引脚、PINMUX模式、PowerOn、内部上拉、输出使能、输出高
配置PINMUX:分配引脚分别为I2C0_CLK、I2C0_DAT、I2C1_CLK、I2C1_DAT功能。
driver_i2c_master_init
包含了对I2C0外设的初始化:
使能PCC时钟源。
设置I2C时钟频率为100k。
设置设备模式为主机模式。
设置I2C地址为7位地址模式。
设置从机地址位0x50。
使能ACK功能。
使能I2C0。
RCC_PeriphClockCmd(APBPeriph_I2C0, APBPeriph_I2C0_CLOCK, ENABLE);
...
I2C_InitStruct.I2C_ClockSpeed = 100000;
I2C_InitStruct.I2C_DeviveMode = I2C_DeviveMode_Master;
I2C_InitStruct.I2C_AddressMode = I2C_AddressMode_7BIT;
I2C_InitStruct.I2C_SlaveAddress = 0x50;
I2C_InitStruct.I2C_RxThresholdLevel = 8;
I2C_InitStruct.I2C_Ack = ENABLE;
driver_i2c_slave_init
包含了对I2C1外设的初始化:
使能PCC时钟。
设置I2C时钟频率为100k。
设置设备模式为从机模式。
设置I2C地址为7位地址模式。
设置从机地址位0x50。
使能ACK功能。
使能I2C1。
RCC_PeriphClockCmd(APBPeriph_I2C1, APBPeriph_I2C1_CLOCK, ENABLE);
...
I2C_InitStruct.I2C_ClockSpeed = 100000;
I2C_InitStruct.I2C_DeviveMode = I2C_DeviveMode_Slave;
I2C_InitStruct.I2C_AddressMode = I2C_AddressMode_7BIT;
I2C_InitStruct.I2C_SlaveAddress = 0x50;
I2C_InitStruct.I2C_RxThresholdLevel = 8;
I2C_InitStruct.I2C_Ack = ENABLE;
nvic_i2c_config
包含了对中断的配置
清除中断挂起位
根据程序中具体发送或接收设定使能I2C0和I2C1相关中断。
I2C_ClearINTPendingBit(I2C0, I2C_INT_STOP_DET);
...
#if I2C_MASTER_SEND_SLAVE_RECEIVE
I2C_INTConfig(I2C0, I2C_INT_STOP_DET, ENABLE);
I2C_INTConfig(I2C1, I2C_INT_RX_FULL, ENABLE);
I2C_INTConfig(I2C1, I2C_INT_STOP_DET, ENABLE);
I2C_INTConfig(I2C1, I2C_INT_RX_DONE, ENABLE);
#endif
#if I2C_MASTER_RECEIVE_SLAVE_SEND
I2C_INTConfig(I2C1, I2C_INT_RD_REQ, ENABLE);
#endif
#if I2C_MASTER_REPEAT_READ
I2C_INTConfig(I2C0, I2C_INT_STOP_DET, ENABLE);
I2C_INTConfig(I2C1, I2C_INT_RX_FULL, ENABLE);
I2C_INTConfig(I2C1, I2C_INT_STOP_DET, ENABLE);
I2C_INTConfig(I2C1, I2C_INT_RX_DONE, ENABLE);
I2C_INTConfig(I2C1, I2C_INT_RD_REQ, ENABLE);
#endif
...
功能实现
开启I2C主机发送从机接收 I2C_MASTER_SEND_SLAVE_RECEIVE
时:
执行
I2C_MasterWrite()
,主机发送write_data数组中的数据给从机。从机接收主机发送的数据,当从机接收达到threshold时触发
I2C_INT_RX_FULL
,或者检测到停止信号时触发I2C_INT_STOP_DET
中断,进入中断处理函数I2C1_Handler
判断检测到接收满状态为SET时:
获取RX FIFO中接收数据的长度以及保存接收数据。
清除
I2C_INT_RX_FULL
中断挂起位。
判断从机检测到停止信号状态为SET时:
获取RX FIFO中接收数据的长度以及保存接收数据。
打印接收数据总长度以及接收数据信息。
清除
I2C_INT_STOP_DET
中断挂起位。
if (I2C_GetINTStatus(I2C1, I2C_INT_STOP_DET) == SET)
{
DBG_DIRECT("I2C1 Stop signal detected");
/*read I2C receive data*/
lenth = I2C_GetRxFIFOLen(I2C1);
for (uint32_t i = 0; i < lenth; i++)
{
I2C_Rev_Data[I2C_Rev_Index++] = I2C_ReceiveData(I2C1);
}
I2C_Rev_Data_Lenth += lenth;
I2C_ClearINTPendingBit(I2C1, I2C_INT_STOP_DET);
...
}
...
if (I2C_GetINTStatus(I2C1, I2C_INT_RX_FULL) == SET)
{
DBG_DIRECT("I2C1 Rx Full detected");
lenth = I2C_GetRxFIFOLen(I2C1);
/*read I2C data*/
for (uint32_t i = 0; i < lenth; i++)
{
I2C_Rev_Data[I2C_Rev_Index++] = I2C_ReceiveData(I2C1);
}
I2C_Rev_Data_Lenth += lenth;
I2C_ClearINTPendingBit(I2C1, I2C_INT_RX_FULL);
}
开启I2C主机接收从机发送 I2C_MASTER_RECEIVE_SLAVE_SEND
时:
主机通过
I2C_MasterRead()
发送命令给从机。从机检测到RD_REQ申请时触发
I2C_INT_RD_REQ
中断,进入中断处理函数I2C1_Handler
。执行
I2C_SendCmd()
命令发送数据给主机。发送数据完成后,清除
I2C_INT_RD_REQ
中断挂起位。
for (uint32_t i = 0; i < TransferLength; i++)
{
I2C_SendCmd(I2C1, I2C_WRITE_CMD, send_data_buffer[i], DISABLE);
}
I2C_ClearINTPendingBit(I2C1, I2C_INT_RD_REQ);
打印主机收到的数据。
开启I2C主机连续发送和接收数据 I2C_MASTER_REPEAT_READ
时:
主机发送
I2C_RepeatRead()
命令给从机,发送tx_data中的数据,接收数据存储在rx_data中。
uint8_t tx_data[10] = {01, 02, 03, 04};
uint8_t rx_data[TransferLength] = {0};
I2C_RepeatRead(I2C0, tx_data, 4, rx_data, TransferLength);
从机接收主机发送的数据,当从机接收FIFO满时触发I2C_INT_RX_FULL,或者检测到停止信号时触发
I2C_INT_STOP_DET
中断;从机检测到RD_REQ申请时触发I2C_INT_RD_REQ
中断,进入中断处理函数I2C1_Handler
(同上)。