2011-09-21 1680 views
6

几天前我在Microchip论坛发布了这个消息(here),但唯一的回应是蟋蟀。 下面的I2C代码大部分时间工作,但偶尔在上电时会出现总线冲突(BCLIF),I2C模块无法在BCLIF后恢复。 I2C线上拉3.3K欧姆。 使用REALICE和断点我可以看到i2c_write()重置BCLIF并在BCLIF置位时返回FALSE。 我已经使用示波器来验证I2C总线是否平整。 当i2c_write()返回FALSE时,重新初始化PIC18F25K20 I2C模块(请参阅下面的init_i2c())不会有帮助。 PIC18F25K20 I2C连接到单个从器件(MCP4018 I2C数字POT)。 我在以前的PIC18项目中使用了相同的代码而没有问题,所以我更换了MCP4018怀疑坏的部分,但没有看到任何区别。 PIC18F25K20 I2C模块在锁定时是否有复位的方法?如何恢复I2C总线冲突BCLIF?

void init_i2c(I2C_BAUD_RATE baud_rate, float freq_mhz) 
{ 
    UINT32 freq_cycle; 
    /* Reset i2c */ 
    SSPCON1 = 0; 
    SSPCON2 = 0; 
    PIR2bits.BCLIF = 0; 
    /* Set baud rate */ 
    /* SSPADD = ((Fosc/4)/Fscl) - 1 */ 
    freq_cycle = (UINT32) ((freq_mhz * 1e6)/4.0); 
    if (baud_rate == I2C_1_MHZ) 
    { 
     SSPADD = (UINT8) ((freq_cycle/1000000L) - 1); 
     SSPSTATbits.SMP = 1;  /* disable slew rate for 1MHz operation */ 
    } 
    else if (baud_rate == I2C_400_KHZ) 
    { 
     SSPADD = (UINT8) ((freq_cycle/400000L) - 1); 
     SSPSTATbits.SMP = 0;  /* enable slew rate for 400kHz operation */ 
    } 
    else /* default to 100 kHz case */ 
    { 
     SSPADD = (UINT8) ((freq_cycle/100000L) - 1); 
     SSPSTATbits.SMP = 1;  /* disable slew rate for 1MHz operation */ 
    } 
    /* Set to Master Mode */ 
    SSPCON1bits.SSPM3 = 1; 
    SSPCON1bits.SSPM2 = 0; 
    SSPCON1bits.SSPM1 = 0; 
    SSPCON1bits.SSPM0 = 0; 
    /* Enable i2c */ 
    SSPCON1bits.SSPEN = 1; 
} 
BOOL i2c_write(UINT8 addr, const void *reg, UINT16 reg_size, const void *data, UINT16 data_size) 
{ 
    UINT16 i; 
    const UINT8 *data_ptr, *reg_ptr; 

    /* convert void ptr to UINT8 ptr */ 
    reg_ptr = (const UINT8 *) reg; 
    data_ptr = (const UINT8 *) data; 
    /* check to make sure i2c bus is idle */ 
    while ((SSPCON2 & 0x1F) | (SSPSTATbits.R_W)) 
     ; 
    /* initiate Start condition and wait until it's done */ 
    SSPCON2bits.SEN = 1; 
    while (SSPCON2bits.SEN) 
     ; 
    /* check for bus collision */ 
    if (PIR2bits.BCLIF) 
    { 
     PIR2bits.BCLIF = 0; 
     return(FALSE); 
    } 
    /* format address with write bit (clear last bit to indicate write) */ 
    addr <<= 1; 
    addr &= 0xFE; 
    /* send out address */ 
    if (!write_byte(addr)) 
     return(FALSE); 
    /* send out register/cmd bytes */ 
    for (i = 0; i < reg_size; i++) 
    { 
     if (!write_byte(reg_ptr)) 
      return(FALSE); 
    } 
    /* send out data bytes */ 
    for (i = 0; i < data_size; i++) 
    { 
     if (!write_byte(data_ptr)) 
      return(FALSE); 
    } 
    /* initiate Stop condition and wait until it's done */ 
    SSPCON2bits.PEN = 1; 
    while(SSPCON2bits.PEN) 
     ; 
    /* check for bus collision */ 
    if (PIR2bits.BCLIF) 
    { 
     PIR2bits.BCLIF = 0; 
     return(FALSE); 
    } 
    return(TRUE); 
} 
BOOL write_byte(UINT8 byte) 
{ 
    /* send out byte */ 
    SSPBUF = byte; 
    if (SSPCON1bits.WCOL)  /* check for collision */ 
    { 
     return(FALSE); 
    } 
    else 
    { 
     while(SSPSTATbits.BF) /* wait for byte to be shifted out */ 
      ; 
    } 
    /* check to make sure i2c bus is idle before continuing */ 
    while ((SSPCON2 & 0x1F) | (SSPSTATbits.R_W)) 
     ; 
    /* check to make sure received ACK */ 
    if (SSPCON2bits.ACKSTAT) 
     return(FALSE); 
    return(TRUE); 
} 
+1

我看不到将SDA和SCL引脚配置为输入的代码。 –

+0

您是否可以尝试交换启动条件启动并首先检查i2c_write()中的总线冲突,并在出现此问题之间连续几次执行此功能,并且有一些小的延迟时间?然后会发生什么? –

+0

另外,如果您的示波器带有自动触发器,它可能非常方便,因此您可以监视上电后SDA线的行为。数据表说明:*如果在开始条件开始时,SDA和SCL引脚已经采样为低电平,或者如果在启动条件期间,SCL线在SDA线驱动为低电平之前被采样为低电平,则会发生总线冲突总线冲突中断标志BCLIF置1,中断启动条件并将I2C模块复位到空闲状态*。 –

回答

7

This Errata需要添加到PIC18F25K20勘误表。

PIC18F2455/2550 /四千五百五十零分之四千四百五十五启A3芯片勘误表

17模块:MSSP

已经观察到的是以下一个上电复位,I2C模式可能无法正确 通过初始化只需将SCL和SDA引脚配置为 输入或输出即可。这只能在几个独特的系统环境中看到。

试生产系统的统计显著样品的测试,在整个电压和电流范围 应用的电源的,应说明如果一个系统是易受 这个问题。

周围

工作在配置模块,用于I2C 操作:

  1. 配置SCL和SDA引脚为输出通过清除其 对应TRIS位。
  2. 通过清零相应的LAT位强制SCL和SDA为低电平。
  3. 在保持LAT位清零的同时,通过设置它们的TRIS位将SCL和SDA配置为输入 。

完成此操作后,使用SSPCON1和 SSPCON2寄存器像以前一样配置正确的I2C模式。

+0

那么,这个序列对你有用吗? –

+0

@AndrejsCainikovs:是的。有效。直到明天才能接受这个答案。 – jacknad

2

PIC18F26K20/SS(版本B3)也出现同样的错误,也需要添加到它的勘误表中。

2

我不知道你的具体情况,但我遇到了一个问题,一旦其中微控制器被出来的方式早(VDD稳定I2C总线上多之前)复位。因此,uController开始在目标可以正常工作之前读取/写入数据,导致各种I2C操作问题。