Problema con I2C en PIC18F25K80

0

Estoy intentando configurar un protocolo I2C entre un PIC18F25k80 y un sensor de presión barométrica (el enlace para la hoja de datos se proporciona a continuación). No puedo averiguar cuál es el problema. Inicialmente estaba dando un error de colisión de escritura, que creo que logré manejar (corríjame si estoy equivocado). Sin embargo, las señales de salida del reloj y las líneas de datos no se parecen en nada a la secuencia esperada para una comunicación I2C (No hay señales de inicio o detención de secuencias en la salida del reloj).

Gracias

Enlace para la hoja de datos del sensor: enlace

METODO PRINCIPAL

/* 
 * File:   main.c
 * Author: b2049814
 *
 * Created on 19 March 2015, 11:27
 */

// PIC18F25K80 Configuration Bit Settings

// 'C' source line config statements

#include <xc.h>
#include <p18cxxx.h>
#include <stdio.h>
#include <plib/pconfig.h>
#include <stdlib.h>
#include <plib/adc.h>                       //include file for ADC library functions
#include "i2cFunctions.h"
#include <delays.h>

#define I2C_SLAVEW       0b11101110
#define I2C_SLAVER       0b11101111

#define RESET_CMD       0b00011110
#define PROM_READ_CMD   0b10100110
#define PRESS_CONV_CMD  0b01001000
#define READ_ADC_CMD    0b00000000

// #pragma config statements should precede project file includes.
// Use project enums instead of #define for ON and OFF.

// CONFIG1L
#pragma config RETEN = ON       // VREG Sleep Enable bit (Ultra low-power regulator is Enabled (Controlled by SRETEN bit))
#pragma config INTOSCSEL = HIGH // LF-INTOSC Low-power Enable bit (LF-INTOSC in High-power mode during Sleep)
#pragma config SOSCSEL = HIGH   // SOSC Power Selection and mode Configuration bits (High Power SOSC circuit selected)
#pragma config XINST = OFF      // Extended Instruction Set (Disabled)

// CONFIG1H
#pragma config FOSC = INTIO1    // Oscillator (Internal RC oscillator, CLKOUT function on OSC2)
#pragma config PLLCFG = OFF     // PLL x4 Enable bit (Disabled)
#pragma config FCMEN = OFF      // Fail-Safe Clock Monitor (Disabled)
#pragma config IESO = OFF       // Internal External Oscillator Switch Over Mode (Disabled)

// CONFIG2L
#pragma config PWRTEN = OFF     // Power Up Timer (Disabled)
#pragma config BOREN = OFF      // Brown Out Detect (Disabled in hardware, SBOREN disabled)
#pragma config BORV = 3         // Brown-out Reset Voltage bits (1.8V)
#pragma config BORPWR = ZPBORMV // BORMV Power level (ZPBORMV instead of BORMV is selected)

// CONFIG2H
#pragma config WDTEN = OFF      // Watchdog Timer (WDT disabled in hardware; SWDTEN bit disabled)
#pragma config WDTPS = 1048576  // Watchdog Postscaler (1:1048576)

// CONFIG3H
#pragma config CANMX = PORTB    // ECAN Mux bit (ECAN TX and RX pins are located on RB2 and RB3, respectively)
#pragma config MSSPMSK = MSK7   // MSSP address masking (7 Bit address masking mode)
#pragma config MCLRE = ON       // Master Clear Enable (MCLR Enabled, RE3 Disabled)

// CONFIG4L
#pragma config STVREN = ON      // Stack Overflow Reset (Enabled)
#pragma config BBSIZ = BB2K     // Boot Block Size (2K word Boot Block size)

// CONFIG5L
#pragma config CP0 = OFF        // Code Protect 00800-01FFF (Disabled)
#pragma config CP1 = OFF        // Code Protect 02000-03FFF (Disabled)
#pragma config CP2 = OFF        // Code Protect 04000-05FFF (Disabled)
#pragma config CP3 = OFF        // Code Protect 06000-07FFF (Disabled)

// CONFIG5H
#pragma config CPB = OFF        // Code Protect Boot (Disabled)
#pragma config CPD = OFF        // Data EE Read Protect (Disabled)

// CONFIG6L
#pragma config WRT0 = OFF       // Table Write Protect 00800-03FFF (Disabled)
#pragma config WRT1 = OFF       // Table Write Protect 04000-07FFF (Disabled)
#pragma config WRT2 = OFF       // Table Write Protect 08000-0BFFF (Disabled)
#pragma config WRT3 = OFF       // Table Write Protect 0C000-0FFFF (Disabled)

// CONFIG6H
#pragma config WRTC = OFF       // Config. Write Protect (Disabled)
#pragma config WRTB = OFF       // Table Write Protect Boot (Disabled)
#pragma config WRTD = OFF       // Data EE Write Protect (Disabled)

// CONFIG7L
#pragma config EBTR0 = OFF      // Table Read Protect 00800-03FFF (Disabled)
#pragma config EBTR1 = OFF      // Table Read Protect 04000-07FFF (Disabled)
#pragma config EBTR2 = OFF      // Table Read Protect 08000-0BFFF (Disabled)
#pragma config EBTR3 = OFF      // Table Read Protect 0C000-0FFFF (Disabled)

// CONFIG7H
#pragma config EBTRB = OFF      // Table Read Protect Boot (Disabled)

void initIO( void );

//**************************************************
// main function
//**************************************************

int main() 
{
    initIO();
    initI2C();

    while(1)
    {
        writeI2C( I2C_SLAVEW, PRESS_CONV_CMD );
    }

    return (0);
}

//**************************************************
// InitIO function (initialises ports  and oscillator)
//**************************************************
void initIO()
{
    OSCCON = 0x75;
    TRISAbits.TRISA1 = 1;
    TRISAbits.TRISA6 = 0;
    TRISAbits.TRISA5 = 0;
    TRISBbits.TRISB0 = 0;
    TRISCbits.TRISC3 = 1;                    // set SCL and SDA pins as inputs
    TRISCbits.TRISC4 = 1;
}

HEADER FILE (contiene las funciones utilizadas para configurar el protocolo I2C)

#ifndef i2cFunctions
#define i2cFunctions

void initI2C()
{
   // Master 100KHz
   SSPCON1 = 0b00101000;    // I2C enabled, Master mode
   SSPCON2 = 0x00;

   // I2C Master mode, clock = FOSC/(4 * (SSPADD + 1)) 
   SSPADD = 19;         // 100Khz @ 8Mhz Fosc

   SSPSTAT = 0b10000000;    // Slew rate disabled
}

void startI2C()
{
    SSPCON2bits.SEN = 1;            // initiate bus start condition
}

void stopI2C()
{
    SSPCON2bits.PEN = 1;            // initiate bus stop condition
}

void restartI2C()
{
    SSPCON2bits.RSEN = 1;           // initiate bus restart condition
}

void notAckI2C()
{
    SSPCON2bits.ACKDT = 1;           // set acknowledge bit state for ACK
    SSPCON2bits.ACKEN = 1;           // initiate bus acknowledge sequence
}

void ackI2C()
{
    SSPCON2bits.ACKDT = 0;           // set acknowledge bit state for ACK
    SSPCON2bits.ACKEN = 1;           // initiate bus acknowledge sequence
}

void idleI2C( void )
{
    while ( ( SSPCON2 & 0x1F ) || ( SSPSTATbits.R_W ) );
}

signed char writeByteI2C( unsigned char byte )
{
    SSPBUF = byte;

    if ( SSPCON1bits.WCOL )      // test if write collision occurred
    {
        return ( -2 );              // if WCOL bit is set return negative #
    }
    else
    {
        if ( ( ( SSPCON1&0x0F ) == 0x08 ) || ( ( SSPCON1&0x0F ) == 0x0B ) ) //master mode only
        { 
            while( SSPSTATbits.BF );   // wait until write cycle is complete   

            idleI2C();                 // ensure module is idle

            if ( SSPCON2bits.ACKSTAT ) // test for ACK condition received
            {
                return ( -1 );          // return NACK
            }
            else
            {
                return ( 0 );              //return ACK
            }          
        }
    }
    return ( -2 );
}

unsigned char readByteI2C( void )
{
    if( ((SSPCON1&0x0F)==0x08) || ((SSPCON1&0x0F)==0x0B) )  //master mode only
    SSPCON2bits.RCEN = 1;           // enable master for 1 byte reception
    while ( !SSPSTATbits.BF );      // wait until byte received  
    return ( SSPBUF );              // return with read byte 
}

void writeI2C( unsigned char slaveAddressW, unsigned char command )
{
    signed char writeResult;

    idleI2C();
    startI2C();
    while(SSPCON2bits.SEN);

    do
    {
        SSPBUF = 0x00;
        writeResult = writeByteI2C( slaveAddressW );

        if ( writeResult == -2 ) //write collision handler
        {
            SSPBUF = 0x00;        //Clearing buffer
            SSPCON1bits.WCOL = 0; //Clearing the write collision flag
        }
    }
    while ( writeResult != 0 ); //we're repeating transmission until ACK is received

    idleI2C();

    do
    {
        SSPBUF = 0x00;
        writeResult = writeByteI2C( command );

        if ( writeResult == -2 ) //write collision handler
        {
            SSPBUF = 0x00;        //Clearing the junk in buffer
            SSPCON1bits.WCOL = 0; //Clearing the write collision flag
        }
    }
    while ( writeResult != 0 ); //we're repeating transmission until ACK is received

    stopI2C();
}

void readI2C( unsigned char slaveAddressR )
{
    unsigned char readSensor[3];
    idleI2C();
    startI2C();
    writeByteI2C( slaveAddressR );

    readSensor[0] = readByteI2C();
    ackI2C();

    readSensor[1] = readByteI2C();
    ackI2C();

    readSensor[2] = readByteI2C();
    notAckI2C();
    stopI2C();
}
#endif

La captura de salida parece repetirse.

El número de pieza del sensor es MS5607-02BA03, pero la hoja de datos ya estaba incluida.

(Verde: Reloj, Púrpura: Datos)

Salida

Salidaampliada

  

Una forma de solucionar este problema sería modificar las funciones de I2C para esperar hasta que finalice su operación asociada antes de que regresen. Por ejemplo:

void startI2C()
{
    SSPCON2bits.SEN = 1;            // initiate bus start condition
    while (SSPCON2bits.SEN);        // wait for bus start condition to complete
}
  

y lo mismo para todas las demás funciones de I2C.

     

Otra alternativa sería hacer una llamada IdleI2C () entre cada operación única de I2C, como:

IdleI2C();
startI2C();
IdleI2C();
writeByteI2C( slaveAddressR );
IdleI2C();
etc ... 

Probé en ambos sentidos, pero la salida no parece cambiar en absoluto.

Intenté depurarlo de nuevo. Parece que la primera vez que intenta escribir algo en el registro del búfer falla y regresa con una colisión de escritura. Y sigue haciendo eso para siempre porque se atasca en el bucle do while que estoy usando para manejar una colisión de escritura.

pregunta user2344158

1 respuesta

1

Debe esperar a que todas y cada una de las operaciones de I2C se completen en un PIC antes de iniciar la siguiente. Esto es lo que está causando las colisiones en tu autobús.
Por ejemplo en tu código tienes:

startI2C();
writeByteI2C( slaveAddressR );

y el problema aquí es que no está esperando a que finalice la condición de inicio antes de iniciar la escritura de bytes.

Una forma de solucionar este problema sería modificar las funciones de I2C para esperar hasta que finalice su operación asociada antes de que regresen. Por ejemplo:

void startI2C()
{
    SSPCON2bits.SEN = 1;            // initiate bus start condition
    while (SSPCON2bits.SEN);        // wait for bus start condition to complete
}

y lo mismo para todas las demás funciones de I2C.

Otra alternativa sería hacer una llamada IdleI2C () entre cada operación única de I2C, como:

IdleI2C();
startI2C();
IdleI2C();
writeByteI2C( slaveAddressR );
IdleI2C();

etc ...

    
respondido por el brhans

Lea otras preguntas en las etiquetas