Msp430g2553 biblioteca de comunicación i2c con el giroscopio itg3200

6

He estado creando una biblioteca I2C para comunicarme con el giroscopio ITG3200 para el launchpad experimental MSP430g2553. Todavía tengo problemas leves con la lectura secuencial y los valores firmados, pero estoy casi completo. ¿Puedes ayudarme con los últimos problemas con los que estoy lidiando? Parece que estoy atascado en un punto. Aquí está la biblioteca enlace

guía de usuario familiar: enlace

guía de usuario de Gyro: enlace

Si no desea descargar esos 3 archivos de origen, aquí está la explicación de las funciones requeridas:

Principal:

WDTCTL = WDTPW + WDTHOLD; // Stop WDT
BCSCTL1 = CALBC1_1MHZ; // Set DCO to 1Mhz
DCOCTL = CALDCO_1MHZ;
P1SEL |= BIT1 + BIT2 + BIT6 + BIT7; // Assign I2C pins to USCI_B0 // Assign Uart pins to USCI_A0
P1SEL2 |= BIT1 + BIT2 + BIT6 + BIT7; // Assign I2C pins to USCI_B0 // Assign Uart pins to USCI_A0
init_I2C(); // initialize i2c
initUart(); // initialize uart

..

..

I2C init:

void init_I2C(void) {
    UCB0CTL1 |= UCSWRST; // Enable SW reset
    UCB0CTL0 = UCMST + UCMODE_3 + UCSYNC; // I2C Master, synchronous mode
    UCB0CTL1 = UCSSEL_2 + UCSWRST; // Use SMCLK, keep SW reset
    UCB0BR0 = 10; // fSCL = 1Mhz/10 = ~100kHz
    UCB0BR1 = 0;
    UCB0I2CSA = itgAddress; // Slave Address is 069h
    UCB0CTL1 &= ~UCSWRST; // **Initialize USCI state machine**
    IE2 |= UCB0RXIE + UCB0TXIE; // Enable RX and TX interrupt
}

Función de recepción:

uint8_t Receive(char registerAddr){
    uint8_t receivedByte;
    while (UCB0CTL1 & UCTXSTP); // Ensure stop condition got sent
    UCB0CTL1 |= UCTR + UCTXSTT; // I2C start condition with UCTR flag for transmit
    while((IFG2 & UCB0TXIFG) == 0); //UCB0TXIFG is set immidiately
    UCB0TXBUF = registerAddr; //write registerAddr in TX buffer
    while((IFG2 & UCB0TXIFG) == 0); // wait until TX buffer is empty and transmitted
    UCB0CTL1 &= ~UCTR ; // Clear I2C TX flag for receive
    UCB0CTL1 |= UCTXSTT + UCTXNACK; // I2C start condition with NACK for single byte reading
    while (UCB0CTL1 & UCTXSTT); // Start condition sent? RXBuffer full?
    receivedByte = UCB0RXBUF;
    UCB0CTL1 |= UCTXSTP; // I2C stop condition
    return receivedByte;
}

Uart init:

void initUart(void) {
    UCA0CTL1 |= UCSSEL_2; // Use SMCLK
    UCA0BR0 = 104; // 1MHz 9600
    UCA0BR1 = 0; // 1MHz 9600
    UCA0MCTL = UCBRS0; // Modulation UCBRSx = 1
    UCA0CTL1 &= ~UCSWRST; // **Initialize USCI state machine**
}

impresión entera:

void serialPrintInteger(uint16_t num) {
    int i;
    uint16_t num_send[5];
    uint16_t numTemp;
    num_send[0] = num/10000; // extract 5th digit
    numTemp = num % 10000; // get remaining 4
    num_send[1] = numTemp/1000; // extract 4th digit
    numTemp = numTemp % 1000; // get remamining 3
    num_send[2] = numTemp/100; // extract 3th digit
    numTemp = numTemp % 100; // get remaining 2
    num_send[3] = numTemp/10; // extract 2th digit
    num_send[4] = numTemp % 10; // extract 1th digit

    if(num_send[0] > 0) { // if num is 5 digit
        for(i = 0 ; i <= 4 ; i++)
            serialWrite(num_send[i]); // send each digit as one byte
    }
    else if(num_send[1] > 0) { // if num is 4 digit
        for(i = 1 ; i <= 4 ; i++)
            serialWrite(num_send[i]);
    }
    else if(num_send[2] > 0) { // if num is 3 digit
        for(i = 2 ; i <= 4 ; i++)
            serialWrite(num_send[i]);
    }
    else if(num_send[3] > 0) { // if num is 2 digit
        for(i = 3 ; i <= 4 ; i++)
            serialWrite(num_send[i]);
    }
    else { // if num is 1 digit
        serialWrite(num_send[4]);
    }
}

void serialPrintAscii(uint8_t ascii) {
    UCA0TXBUF = ascii;
    while (!(IFG2&UCA0TXIFG)); // USCI_A0 TX buffer ready?
}

Y aquí está mi problema. Cuando pruebo estas lecturas en mi bucle principal, obtengo los resultados que debería tener.

serialPrintInteger(Receive(0x00));

o

serialPrintInteger(Receive(0x15));

o

serialPrintInteger(Receive(0x16));

y las salidas de estos son 0x69 de Receive (0x00) que lee el registro de dirección del esclavo del giroscopio, 9 de Receive (0x15) donde escribí 9 en el registro de 0x15 para la configuración y 25 de Receive (0x16) donde escribí también .

No creo que mis funciones serialPrint estén dañadas también, lo he intentado con muchas combinaciones en el rango de 16 bits donde debería estar. Esta secuencia funciona bien:

serialPrintInteger(5);
serialPrintAscii(Ascii_Comma);
serialPrintInteger(10);
serialPrintAscii(Ascii_And);
serialPrintInteger(15);
serialPrintAscii(Ascii_Dot);

Veo una salida como esta en mi consola serie: 5,10 & 15.5,10 & 15.5 ...

La parte divertida comienza cuando intento esta lógica en mi función Recibir. Aquí está la secuencia que utilizo

serialPrintInteger(Receive(0x00)); // result 105
serialPrintAscii(Ascii_Comma);
serialPrintInteger(Receive(0x15)); // result 9
serialPrintAscii(Ascii_And);
serialPrintInteger(Receive(0x00)); // result 105
serialPrintAscii(Ascii_Dot);

La secuencia en mi consola es la siguiente: 105,105 & 9.105,105 & 9.105 ...

Primero pensé que no estaba enviando NACK correctamente al esclavo para un solo byte y pensé que seguía incrementando la dirección de registro por su cuenta, pero están funcionando bien por separado y Gyro tiene x, y, z registra también y están no corromper mi secuencia

Estuve luchando con los registros de movimiento de giroscopios por un tiempo, pero me di cuenta de que todavía no tengo el control total de mi I2C. Entonces, ¿puedes señalar lo que estoy haciendo mal aquí?

    

1 respuesta

2

Esta pregunta se resolvió en el sitio web de Ti y la siguiente es la solución que agregó:

  

Al observar la Operación USCI, sección de modo I2C en MSP430x2xx > Guía del usuario familiar SLAU144I Creo que el bit UCTXSTT se borrará después de que > el esclavo haya ACKed su dirección de recepción, y antes de que se hayan leído y gt; del esclavo. Por lo tanto, lo siguiente en la función Recibir podría leer > UCB0RXBUF antes de que se hayan recibido los datos:

  while (UCB0CTL1 & UCTXSTT); // Start condition sent? RXBuffer full?
  receivedByte = UCB0RXBUF;
     

Intenta cambiar a:

 while((IFG2 & UCB0RXIFG) == 0); // Wait until data read

 receivedByte = UCB0RXBUF;
     

publicación de Chester Gillon

     

Solucioné mi problema cambiando algunas partes en la función Recibir. Gracias > a la publicación de Chester Gillon, me hizo darme cuenta de que ocurre una interrupción de STT > justo después de que el esclavo ACK el maestro. Después de revisar la guía del usuario > cuidadosamente, encontré esto:

     

Si un maestro solo quiere recibir un solo byte, el bit UCTXSTP debe establecerse > mientras se está ejecutando el byte   recibido. Para este caso, se puede sondear UCTXSTT para determinar cuándo se > se borra:

     

Por lo tanto, esta condición de DETENCIÓN debe ocurrir después del ACK pero antes del segundo dato > ACK. Así que cambié mi función de recepción en esto y resolví todos mis problemas >

uint8_t Receive(char registerAddr){
uint8_t receivedByte = 0;
while (UCB0CTL1 & UCTXSTP); // Ensure stop condition got sent
UCB0CTL1 |= UCTR + UCTXSTT; // I2C start condition with UCTR flag for >     transmit
while((IFG2 & UCB0TXIFG) == 0); //UCB0TXIFG is set immidiately
UCB0TXBUF = registerAddr; //write registerAddr in TX buffer
while((IFG2 & UCB0TXIFG) == 0); // wait until TX buffer is empty and >     transmitted
UCB0CTL1 &= ~UCTR ; // Clear I2C TX flag for receive
UCB0CTL1 |= UCTXSTT; // I2C start condition with NACK for single byte >     reading
while (UCB0CTL1 & UCTXSTT); // Start condition sent? RXBuffer full?
UCB0CTL1 |= UCTXSTP;
while((IFG2 & UCB0RXIFG) == 0); // wait until TX buffer is empty and >     transmitted
receivedByte = UCB0RXBUF; // I2C stop condition
return receivedByte;
}
     

publicación de Barışcan Kayaoğlu

enlace

    
respondido por el Catch.Me

Lea otras preguntas en las etiquetas