主题中讨论的其他器件:C2000WARE
驱动程序库:C2000Ware 4.02.00
参考的示例:I2C_Ex5_MASTER_SLAVE_INTERRUPT
I2C 规范:100kHz、7位地址、8位数据格式。 使用 FIFO 和 FIFO 中断。
简介:
- 0025C 作为从 站、使用 Microchip PICkit 串行分析器测试正常且稳定、也可以使用另一个 F280025C 控制卡实现 I2C 主站、这意味着 I2C 总线设置正确。
- 使用 Linux 系统作为主系统并运行"i2cget"命令、有机会让0025将 SCL 保持在低电平、猜它会进入延时模式。 Linux 系统还没有超时机制。
- 需要知道的是、代码不够快、无法处理 I2C 请求、或者一些中断被抢占的问题导致了这个问题。
- 这个问题有点复杂...
尊敬的 TI 专家:
正如我 之前在 I2C 上所做的工作、我将构建一 个中断主/从设备进行通信。
感谢 gurus 作为您、我知道 I2C 中断可以触发主器件/从器件来更改数据方向、并将角色从接收器更改为发送器。
考虑将 Linux 系统用作主系统、0025C 与 EEPROM 一样、 应 通过"i2cget"命令读取/写入寄存器(命令)。
问题是、当我使用数据分析器和另一个0025作为主器件来测试代码时、它非常稳定、快速且正确。
但是、当我将平台更改为自定义平台时、通过数据格式、电子特性是相同的、因此有机会让从器件保持 SCL 为低电平。
发生错误时对波形执行堆叠:

虽然逻辑分析仪显示 SCL 恢复为高电平、但出于某种原因、我使用示波器检查 SCL 是否为低电平(可能是它超出范围)。
我还检查总线上是否有其他器件导致了此问题、但 SCL 仅在我的器件连接到总线时拉低。
此时、我在 while 循环中设置了一个断点(不执行任何循环)、并按如下所示检查寄存器:

BB 位 为高电平、这会导致 I2C 模块的状态错误、从而中断有限状态机。
正如我所知、I2C 模块检测 到 STARTcondition 后、BB=1、直到检测到另一个停止条件。
因此、不可预测的 BB=1意味着两个感官:意外发生了开始或意外发生了停止、或者我错过了什么?
但 I2C 模块具有内置滤波器、我认为这不是噪声问题。
为了将这个死端作为从器件来解决、我不能通过发送启动/停止条件来将其复位、而是复位整个 I2C 模块。
下面是一些参考波形:
数据重新发送失败 、但 I2C 获得了正确的停止条件以复位 BB 位。
数据传输成功、它包含两个字节、并完美地停止位。
通过自定义 Linux 系统获得成功

使用串行数据分析器成功

代码如下所示
I2C FIFO ISR
我知道,当器件处于从站传输模式时,I2CCNT 值无关,要传输数据,只需使用 I2C_Put ()即可。
我希望只使用 I2C_FFTX_INT 一次、将两个字节的数据放入 FIFO 中进行循环。
I2C 模块应自动向外发送数据。
/* @brief Process I2C FIFO interrupt source
* @param none
* @return none
* @disc FIFO ISR need to process RX data and send data back to master
*/
__interrupt void i2c_FIFO_isr(void)
{
uint32_t intSource_FIFO = (uint32_t)I2C_getInterruptStatus(I2CA_BASE);
// If RX FIFO interrupt flag is set, read command
if((intSource_FIFO & I2C_INT_RXFF) != 0)
{
I2c_cmd = I2C_getData(I2CA_BASE);
I2C_clearInterruptStatus(I2CA_BASE, I2C_INT_RXFF);
}
// Slave transmitter mode, send back data asked by master
if(((intSource_FIFO & I2C_INT_TXFF) && I2c_cmd) != 0 )
{
i2c_cmd_process(I2c_cmd); // process the i2c command
I2c_cmd = 0;
I2C_clearInterruptStatus(I2CA_BASE, I2C_INT_TXFF);
/* After sending data back to master, stop condition detected
* Then FIFOINT will be disabled,
* so the process should not go back to TXFFINT again.
*/
}
PieCtrlRegs.PIEACK.bit.ACK8 = 1;
}
I2C_cmd_process
此函数切换到不同的命令、发送不同的数据。
我认为这可能会减慢整个过程、因为它处于中断中?
void i2c_cmd_process(uint16_t cmd){
uint16_t i;
switch(cmd){
case(Vin1_cmd):
sData[0] = (Vin1_adc_val >> 8) & 0x00ff;
sData[1] = (Vin1_adc_val) & 0x00ff;
for(i = 0; i < 2; i ++)
I2C_putData(I2CA_BASE, sData[i]);
break;
default:
// Unrecognize command, send 0x87 twice
for(i = 0; i < 2; i ++)
I2C_putData(I2CA_BASE, 0x87);
break;
}
}
I2C INT ISR
只需调整数据方向、并在检测到停止条件时复位 FIFO。
另外、发生在其他器件通信上的停止位也会导致该中断、只需保持 FIFO 清零即可。
/* @brief Process I2C interrupt source
* @param none
* @return none
* @disc As I2C slave, ISR happened when master call it, this will trigger AASINT.
* Also, when master stop communication, STPINT triggered, slave reset I2C FFINT.
*/
__interrupt void i2c_isr(void){
I2C_InterruptSource intSource = I2C_getInterruptSource(I2CA_BASE);
// Go into different interrupt case
switch (intSource)
{
case I2C_INTSRC_ARB_LOST:
break;
case I2C_INTSRC_NO_ACK:
break;
case I2C_INTSRC_REG_ACCESS_RDY:
break;
case I2C_INTSRC_RX_DATA_RDY:
break;
case I2C_INTSRC_TX_DATA_RDY:
break;
case I2C_INTSRC_STOP_CONDITION:
// Disable I2C interrupt when I2C communication stop
I2C_disableInterrupt(I2CA_BASE, (I2C_INT_TXFF | I2C_INT_RXFF));
// Reset FIFO
I2C_disableFIFO(I2CA_BASE);
I2C_enableFIFO(I2CA_BASE);
break;
case I2C_INTSRC_ADDR_SLAVE:
// Slave called by master
I2C_setFIFOInterruptLevel(I2CA_BASE, I2C_FIFO_TX2, I2C_FIFO_RX1); // Prepare the FIFO level
// When master call the salve in read mode
if((I2C_getStatus(I2CA_BASE) & I2C_STS_SLAVE_DIR))
{
// Slave Transmitter (SDIR = 1)
I2C_setConfig(I2CA_BASE, I2C_SLAVE_SEND_MODE);
// Enable TX FIFO interrupt to send back data
// Disable RXFF interrupt
I2C_disableInterrupt(I2CA_BASE, I2C_INT_RXFF);
I2C_enableInterrupt(I2CA_BASE, I2C_INT_TXFF);
I2C_clearInterruptStatus(I2CA_BASE, (I2C_INT_TXFF|I2C_INT_RXFF));
}
// When master call the slave in write mode
else
{
// Slave Receiver (SDIR = 0)
I2C_setConfig(I2CA_BASE, I2C_SLAVE_RECEIVE_MODE);
// Enable RX FIFO interrupt waiting command
// Disable TXFF interrupt
I2C_disableInterrupt(I2CA_BASE, I2C_INT_TXFF);
I2C_enableInterrupt(I2CA_BASE, I2C_INT_RXFF);
I2C_clearInterruptStatus(I2CA_BASE, (I2C_INT_TXFF|I2C_INT_RXFF));
}
break;
default:
ESTOP0;
break;
}
PieCtrlRegs.PIEACK.bit.ACK8 = 1;
}
INIT_I2C
GPIO 设置和 I2C 模块设置
void Init_I2C(void)
{
// Enable I2C-A on GPIO32 - GPIO33
EALLOW;
GpioCtrlRegs.GPBPUD.bit.GPIO32 = 0; // Enable pull-up for GPIO32 (SDAA)
GpioCtrlRegs.GPBPUD.bit.GPIO33 = 0; // Enable pull-up for GPIO33 (SCLA)
GpioCtrlRegs.GPBQSEL1.bit.GPIO32 = 3; // Asynch input GPIO32 (SDAA)
GpioCtrlRegs.GPBQSEL1.bit.GPIO33 = 3; // Asynch input GPIO33 (SCLA)
GpioCtrlRegs.GPBGMUX1.bit.GPIO32 = 0; // Configure GPIO32 for SDAA operation
GpioCtrlRegs.GPBGMUX1.bit.GPIO33 = 0; // Configure GPIO33 for SCLA operation
GpioCtrlRegs.GPBMUX1.bit.GPIO32 = 1; // Configure GPIO32 for SDAA operation
GpioCtrlRegs.GPBMUX1.bit.GPIO33 = 1; // Configure GPIO33 for SCLA operation
GpioCtrlRegs.GPBODR.bit.GPIO32 = 0;
GpioCtrlRegs.GPBODR.bit.GPIO33 = 0;
EDIS;
// Initialize I2C (Slave receiver mode)
I2caRegs.I2CMDR.bit.IRS = 0; // Reset I2C module
I2caRegs.I2COAR.all = 0x60; // Configure I2C own address
I2caRegs.I2CSAR.all = 0x0; // Configure I2C slave address
I2caRegs.I2CMDR.bit.MST = 0; // Configure I2C as slave
I2caRegs.I2CMDR.bit.TRX = 0; // Configure I2C as receive mode
I2caRegs.I2CMDR.bit.BC = 0; // Set the bit count to 8 bits per data byte
I2caRegs.I2CCNT = 1; // Set data count = 1 bytes
// Setup TX FIFO
I2caRegs.I2CFFTX.bit.TXFFRST = 0; // Reset and hold TX FIFO
I2caRegs.I2CFFTX.bit.I2CFFEN = 1; // Enable I2C FIFO
I2caRegs.I2CFFTX.bit.TXFFIENA = 0; // Disable TXFF interrupt
I2caRegs.I2CFFTX.bit.TXFFIL = 0; // TX FIFO level = 0 bytes
I2caRegs.I2CFFTX.bit.TXFFINTCLR = 1; // Clear TXFF INT
I2caRegs.I2CFFTX.bit.TXFFRST = 1; // Enable TX FIFO
// Setup RX FIFO
I2caRegs.I2CFFRX.bit.RXFFRST = 0; // Reset and hold RX FIFO
I2caRegs.I2CFFRX.bit.RXFFIENA = 1; // Enable RXFIFO interrupt
I2caRegs.I2CFFRX.bit.RXFFIL = 1; // RX FIFO level = 1 byte
I2caRegs.I2CFFRX.bit.RXFFINTCLR = 1; // Clear RXFF INT
I2caRegs.I2CFFRX.bit.RXFFRST = 1; // Enable RX FIFO
// Setup interrupt source
I2caRegs.I2CIER.bit.AAS = 1; // Enable Address as slave interrupt
I2caRegs.I2CIER.bit.SCD = 1; // Enable Stop condition detected interrupt
I2caRegs.I2CIER.bit.XRDY = 0; // Enable Transmit-data-ready interrupt
I2caRegs.I2CIER.bit.RRDY = 0; // Enable Receive-data-ready interrupt
I2caRegs.I2CIER.bit.ARDY = 0; // Enable Register-access-ready interrupt
I2caRegs.I2CIER.bit.NACK = 0; // Enable Non-ack interrupt
I2caRegs.I2CIER.bit.ARBL = 0; // Enable Arbitration-lost interrupt
I2caRegs.I2CEMDR.bit.BC = 0;
// Clear interrupt flags
I2caRegs.I2CSTR.all = 0xFFFF; // Clear other I2C flags
I2caRegs.I2CMDR.bit.IRS = 1; // Release I2C module
DELAY_US(100);
}
结论:
- 我想知道我的 TTXFFINT 使用是否良好、或者这个中断设计为逐字节传输数据?
- 我错过了什么会导致 I2C 总线冻结(BB =1)吗?
- 如果中断被其他更高优先级的 ISR (如 ADCA1)抢占、它会导致 I2C 中断?
- 这种问题很可能会导致 Linux 系统的问题很小、因为它可以正确读取其他设备。
感谢您的帮助!!










