No se puede hacer que I2C funcione en PIC32 ("omite" bytes / bloqueos)

3

Estoy trabajando en una placa de desarrollo PIC32-MAXI-WEB de Olimex que me gustaría comunicarme con un acelerómetro / giroscopio Invensense MPU-6050 6DOF. Al modificar una demo de Olimex, logré que la imagen se comunicara.

Comencé a trabajar en un proyecto para el que creé un nuevo proyecto (en IDE), ya que no necesitaba / quería el kernel FreeRTOS en el que se basa la demostración. Sin embargo, no puedo hacer que el mismo código I2C funcione allí. Obtengo algunos resultados, pero no lo que debería obtener.

Funciones de ayuda de la DEMO de Olimex:

BOOL StartTransfer( BOOL restart )
{
    I2C_STATUS  status;

    // Send the Start (or Restart) signal
    if(restart)
    {
        I2CRepeatStart(I2C2);
    }
    else
    {
        // Wait for the bus to be idle, then start the transfer
        while( !I2CBusIsIdle(I2C2) );

        if(I2CStart(I2C2) != I2C2)
        {
            DBPRINTF("Error: Bus collision during transfer Start\n");
            return FALSE;
        }
    }

    // Wait for the signal to complete
    do
    {

        status = I2CGetStatus(I2C2);

    } while ( !(status & I2C_START) );

    return TRUE;
}


BOOL TransmitOneByte( UINT8 data )
{
    // Wait for the transmitter to be ready
    while(!I2CTransmitterIsReady(I2C2));

    // Transmit the byte
    if(I2CSendByte(I2C2, data) == I2C_MASTER_BUS_COLLISION)
    {
        DBPRINTF("Error: I2C Master Bus Collision\n");
        return FALSE;
    }

    // Wait for the transmission to finish
    while(!I2CTransmissionHasCompleted(I2C2));

    return TRUE;
}

void StopTransfer( void )
{
    I2C_STATUS  status;

    // Send the Stop signal
    I2CStop(I2C2);


    // Wait for the signal to complete
    do
    {
        status = I2CGetStatus(I2C2);

    } while ( !(status & I2C_STOP) );
}

Mi código:

int I2C_CLOCK_SPEED = 400000;

int actualClock;

// Configure Various I2C Options
I2CConfigure(I2C2, 0);

// Set Desired Operation Frequency
actualClock = I2CSetFrequency(I2C2, GetPeripheralClock(), I2C_CLOCK_SPEED);
if ( abs(actualClock-I2C_CLOCK_SPEED) > I2C_CLOCK_SPEED/10 ) {
    return -1;
}

// Enable the module
I2CEnable(I2C2, TRUE);

BYTE ADDR = 0x68<<1;

BIT WRITE = 0;
BIT READ = 1;

BYTE tmp;

StartTransfer(FALSE); // Read power management register

TransmitOneByte(ADDR|WRITE);
TransmitOneByte(0x75);

StartTransfer(TRUE);

TransmitOneByte(ADDR |READ);
I2CReceiverEnable(I2C2, TRUE);
while(!I2CReceivedDataIsAvailable(I2C2));
I2CAcknowledgeByte(I2C2, FALSE);
tmp = I2CGetByte(I2C2);

StopTransfer();

Con un analizador lógico puedo ver que parece eliminar la dirección y enviar solo el segundo byte de los tres. También falla al enviar el bit de parada / devolver el bus a inactivo:

No debería ser un problema de hardware, ya que la demostración original funciona. Estoy usando el compilador xc32 y MPLAB X IDE.

    
pregunta varesa

1 respuesta

3

Algunas observaciones:

1) Está llamando ciegamente a StartTransfer (FALSO) sin verificar si la condición de inicio fue exitosa (debería ser VERDADERO si lo fue; si es falso, no debe enviar nada hasta que el bus esté despejado y el inicio) es válido.)

2) Después de enviar la dirección, no está comprobando si se confirmó antes de enviar el byte de datos. Debe asegurarse de que se reconozca la dirección antes de tomar cualquier otra acción; si no lo es, debe enviar una parada.

3) Reemplace las llamadas de la biblioteca enlatadas por la manipulación directa de SFR (es decir, escriba y lea directamente a los SFR periféricos I2C): el código de la biblioteca a menudo tiene matices que no son evidentes de inmediato y, como la fuente no está disponible, no los tiene. t tiene una manera fácil de solucionar el problema.

    
respondido por el Adam Lawrence

Lea otras preguntas en las etiquetas