Wie erholen Sie sich von I2C-bus-Kollision BCLIF?

Ich gepostet vor ein paar Tagen auf dem Microchip Forum ( hier ), aber die einzige Reaktion war Grillen.
Der I2C code unten funktioniert die meiste Zeit, aber gelegentlich einschalten, es gibt eine bus-Kollision (BCLIF) und das I2C-Modul ist nicht in der Lage sich zu erholen, nachdem die BCLIF.
Die I2C Leitungen sind gezogen, bis von 3,3 K OHM.
Mit REALICE und Haltepunkte kann ich sehen, dass i2c_write() setzt BCLIF und gibt FALSE zurück, wenn BCLIF eingestellt ist.
Ich habe verwendet, einen Bereich, um zu überprüfen, dass der I2C-bus ist Platt.
Re-Initialisierung der PIC18F25K20 I2C-Modul (siehe init_i2c() unten), wenn i2c_write() gibt FALSE zurück, nicht helfen.
Die PIC18F25K20 I2C angeschlossen ist, um ein Einzel-slave-Gerät (MCP4018 I2C Digital-TOPF).
Ich habe diesen gleichen code auf der vorherigen PIC18 Projekte ohne Problem, also ersetzte ich die MCP4018 Verdacht, einem schlechten Teil, sehe aber keinen Unterschied.
Gibt es eine Möglichkeit zum zurücksetzen der PIC18F25K20 I2C Modul, wenn es gesperrt ist?

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); 
} 
  • Ich kann nicht sehen, den code, wo SDA und SCL-pins sind als Eingang konfiguriert.
  • Können Sie versuchen, den Austausch von start-Bedingung einleiten und prüfen Sie, ob bus-Kollision in i2c_write() und führen Sie diese Funktion einige Male in einer Reihe mit einigen kleinen Verzögerungen dazwischen, wenn dieses problem Auftritt? Was passiert dann?
  • Außerdem könnte es wirklich praktisch, wenn Sie das Oszilloskop mit auto-trigger, so können Sie überwachen, was das Verhalten der SDA-Leitung nach power-up. Datenblatt besagt: Wenn man am Anfang der Start-Bedingung, die SDA-und SCL-pins sind bereits gesampelte niedrig ist, oder wenn während der Start-Bedingung, die SCL-Leitung abgetastet wird niedrig, bevor die SDA-Leitung getrieben wird, niedrig ist, wird eine bus-Kollision Auftritt, wird die Bus-Kollision Interrupt-Flag, BCLIF, gesetzt ist, wird die Start-Bedingung abgebrochen wird und das I2C-Modul wird zurückgesetzt in den Wartezustand.
  • SDA-und SCL-pins sind als Eingang konfiguriert, oder sonst der I2C nicht funktionieren würde überhaupt.
  • Aussieht gilt dies auch für die dsPICs, da sehe ich die gleiche Sache.
InformationsquelleAutor jacknad | 2011-09-21
Schreibe einen Kommentar