2011-09-21 12 views
6

L'ho postato un paio di giorni fa sul forum Microchip (here) ma l'unica risposta è stata il cricket. Il codice I2C riportato di seguito funziona la maggior parte del tempo ma occasionalmente all'accensione si verifica una collisione del bus (BCLIF) e il modulo I2C non è in grado di eseguire il ripristino dopo il BCLIF. Le linee I2C sono sollevate di 3,3 K ohm. Utilizzo di REALICE e punti di interruzione Vedo che i2c_write() ripristina BCLIF e restituisce FALSE quando BCLIF è impostato. Ho usato uno scope per verificare che il bus I2C abbia una linea piatta. Re-inizializzazione del modulo I2C PIC18F25K20 (vedere init_i2c() di seguito) quando i2c_write() restituisce FALSE non aiuta. Il PIC18F25K20 I2C è collegato a un dispositivo slave singolo (MCP4018 I2C Digital POT). Ho usato questo stesso codice su precedenti progetti PIC18 senza problemi quindi ho sostituito il MCP4018 sospettando una parte errata ma non vedo differenze. C'è un modo per resettare il modulo I2C PIC18F25K20 quando è bloccato?Come ripristinare dalla collisione bus 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

Non riesco a vedere il codice in cui i pin SDA e SCL sono configurati come ingressi. –

+0

Puoi provare a scambiare l'avvio della condizione iniziando e prima controlla la collisione del bus in i2c_write() ed esegui questa funzione alcune volte di seguito con alcuni piccoli ritardi tra quando si verifica questo problema? Cosa succede allora? –

+0

Inoltre, potrebbe essere davvero utile se si dispone di oscilloscopio con trigger automatico, in modo da poter monitorare il comportamento della linea SDA dopo l'accensione. Gli stati del foglio dati: * Se all'inizio della condizione Start, i pin SDA e SCL sono già campionati in basso, o se durante la condizione Start, la linea SCL viene campionata bassa prima che la linea SDA venga scaricata, si verifichi una collisione del bus, Flag di interrupt di collisione bus, BCLIF, viene impostato, la condizione di avvio viene interrotta e il modulo I2C viene ripristinato nel suo stato di inattività *. –

risposta

7

This Errata deve essere aggiunto al PIC18F25K20 Errata.

PIC18F2455/2550/4455/4550 Rev. A3 Silicon Errata

17 Modulo: MSSP

E 'stato osservato che a seguito di un power-on reset, modalità I2C non può inizializza correttamente semplicemente configurando i pin SCL e SDA come ingressi o uscite . Questo è stato visto solo in alcuni ambienti unici del sistema .

Un test di un campione statisticamente significativo di sistemi pre-produzione, attraverso la tensione e corrente di alimentazione dell'applicazione , dovrebbe indicare se un sistema è suscettibile a questo problema.

Work around

Prima di configurare il modulo da utilizzare I2C :

  1. Configurare i pin SCL e SDA come uscite di compensazione loro corrispondenti bit TRIS.
  2. Forzare SCL e SDA in basso cancellando i bit LAT corrispondenti.
  3. Mantenendo i bit LAT liberi, configurare SCL e SDA come ingressi impostando i bit TRIS.

Una volta fatto questo, utilizzare lo SSPCON1 e SSPCON2 registri per configurare la modalità I2C corretta come prima.

+0

Quindi, questa sequenza ha funzionato per te? –

+0

@AndrejsCainikovs: Sì. Ha funzionato. Non posso accettare questa risposta fino a domani. – jacknad

2

Questo stesso errore sembra essere presente anche su PIC18F26K20/SS (Revisione B3), inoltre è necessario aggiungerlo all'errata.

2

Non conosco le tue specifiche, ma mi sono imbattuto in un problema in cui il microcontrollore stava uscendo dal modo di ripristino anticipato (molto prima che Vdd si stabilizzasse sul bus I2C). Quindi il controllore uController ha iniziato a leggere/scrivere i dati prima che l'obiettivo potesse funzionare correttamente causando tutti i tipi di problemi operativi I2C.