Cómo configurar el I2C del MSP430

Tengo una placa de desarrollo MSP430FR6989 ( MSP-EXP430FR6989 ).

Me gustaría programarlo para que se comunique con un oxímetro de pulso y frecuencia cardíaca MAX30102 IC, la interfaz se realiza a través del protocolo I2C.

Solo tengo un maestro (MSP430) y un esclavo (MAX30102).

ingrese la descripción de la imagen aquí

Al leer la guía del usuario de MSP430 (pg821 Capítulo 32 Modo eUSCI I2C) y la hoja de datos MAX30102 (pg16/32) , esto es lo que entiendo:

  • escribimos la dirección esclava en el registro de direcciones maestras UCB0I2CSA = 0x57, configuramos UCTRpara una escritura y configuramos UCTXSTTpara una condición de INICIO.
  • MSP430 transmite la dirección del esclavo junto con el bit de escritura (8 bits alternados desde el SCL)
  • MAX30102 envía una señal ACK (BAJO), el UCTXSTTbit se borra y el UCB0TXIFG0bit se establece
  • cuando UCB0TXIFG0se establece el bit, MSP430 va a un ISR, se borra el indicador de interrupción y escribimos el registro de dirección de MAX30102 FIFO_WR_PTR en el búfer de transmisión UCB0TXBUF.
  • MSP430 transmite los datos (dirección de registro FIFO_WR_PTR) y espera un ACK del MAX30102.
  • Cuando se recibe un ACK (segundo ACK), UCBOTXIFG0el bit se establece, va al ISR, borramos el UCTRbit para un modo de lectura y lo configuramos UCTXSTTpara una condición de INICIO REPETIDO.
  • La dirección del esclavo sigue siendo la misma y se transmite al esclavo junto con el bit de lectura.
  • El esclavo lo reconoce (ACK) y se UCRXIFG0establece, MSP430 va a eUSCI_B0 ISR (esta vez, el valor en el vector de interrupción corresponde a los datos recibidos).
  • El valor de ISR en UCB0RXBUF(FIFO_WR_PTR) se almacena en una variable global WritePointer = UCB0RXBUF.

He escrito un código MSP430 en consecuencia.

#include <msp430.h> 
#include <stdint.h>

uint8_t WritePointer = 0;//to store the value inside the FIFO_WR_PTR

#define ENABLE_PINS 0xFFFE

#define MAX30102_SLAVE_ADDR         0x57
#define MAX30102_FIFO_WR_PTR_ADDR   0x04
//other address definitions

// S SLA/W (A) FIFO_WR_PTR_ADDR (A) SR SLA/R (A) (FIFO_WR_PTR) NACK P  1st interaction


/*
 * Private Variables
 */


void configClock(void);

int main(void)
{
    WDTCTL = WDTPW | WDTHOLD;   // stop watchdog timer
    PM5CTL0 = ENABLE_PINS;
    
    configClock ();

    //config pins P1.6 SDA P1.7 SCL
    P1SEL0 &= ~(BIT6 | BIT7);
    P1SEL1 |= (BIT6 | BIT7);

    UCB0CTLW0 |= UCSWRST;//put it on a restart mode to config
    UCB0CTLW0 |= (UCMST | UCMODE_3 | UCSSEL__SMCLK);// i2c master cs smclk
    UCB0BRW = 10;//100kbps fSCL = fSMCLK / 10 = 100 KHz
    UCB0IFG &= ~UCTXIFG0;//set eUSCI_B0 for operation
    UCB0I2CSA = MAX30102_SLAVE_ADDR;//from datasheet address is 0x57
    UCB0CTLW0 &= ~UCSWRST;//release for operation

    UCB0IE |= (UCTXIE0 | UCRXIE0);//enable RX and TX isr
    //when and ACK is received a tx or rx isr is serviced

    _BIS_SR (GIE);//enable global interrupt

    while(1)
    {
        UCB0CTLW0 |= (UCTR | UCTXSTT);//W and START
    }

    return 0;
}

void configClock (void)
{
    CSCTL0 = CSKEY;
    CSCTL1 = 0x0000;//DCO 1MHz
    CSCTL2 |= (SELA__LFXTCLK | SELS__DCOCLK | SELM__DCOCLK);
}

#pragma vector = USCI_B0_VECTOR
__interrupt void eUSCI_B0_I2C_ISR (void)
{
    static int counter = 0;
    //this is a byte counter, after the Slave ACK Address and W
    //Master is expected to transmit data (register address of FIFO_WR_PTR)
    //then set a REPEATED START, along with the slave address (the same) and change the mode to read

    switch(UCB0IV)
    {
    case USCI_I2C_UCTXIFG0:
        if(counter == 0)
        {
            UCB0TXBUF = MAX30102_FIFO_WR_PTR_ADDR;
            counter++;
        }

        else
        {
            UCB0CTLW0 &= ~UCTR;//R
            UCB0CTLW0 |= UCTXSTT;//repeated start
            counter = 0;
        }
        break;
    case USCI_I2C_UCRXIFG0:
        WritePointer = UCB0RXBUF;
        //WritePointer is a global variable
        //FIFO_WR_PTR is assigned to WritePointer

        UCB0CTLW0 |= UCTXSTP;
        //MSP430 to initiate STOP condition
        break;
    default:
        break;
    }
}

Sin embargo, cuando construyo y ejecuto el código, probé el SCL (P1.7) con un osciloscopio y solo obtengo un alto voltaje (3.3V). Incluso si la configuración de mi software I2C es incorrecta, debería obtener al menos 9 pulsos (dirección de 7 bits, escritura de 1 bit, ACK/NACK de 1 bit) del SCL con el osciloscopio.

Cuando depuré el código y el MSP430 entra en el ciclo while, cuando UCTXSTTestá configurado, no se configura ningún indicador de interrupción.

PD: la conexión HW es un drenaje abierto, con resistencias de 4,7 K ohmios que actúan como resistencias pull-up.

No sé dónde está mi error, por favor ayúdenme con este problema.

Respuestas (1)

    #define ENABLE_PINS 0xFFFE
    PM5CTL0 = ENABLE_PINS;

Esto escribe todos los demás bits como 1. Para borrar un solo bit, use PM5CTL0 &= ~LOCKLPM5;.

    //config pins P1.6 SDA P1.7 SCL
    P1SEL0 &= ~(BIT6 | BIT7);
    P1SEL1 |= (BIT6 | BIT7);

Como se muestra en la tabla 6-21 de la hoja de datos, debe configurar el bit en P1SEL0 y borrar el bit en P1SEL1.

    while(1)
    {
        UCB0CTLW0 |= (UCTR | UCTXSTT);//W and START
    }

Esto inicia continuamente una nueva transacción. Desea al menos esperar hasta que el anterior haya terminado.

Gracias por el comentario, cambiaré PM5CTL0, configuraré P1SEL0 y P1SEL1 correctamente, agregaré una interrupción de temporizador de un segundo que iniciará la transmisión, sin embargo, la variable se restablecerá, cuando MSP430 ingrese counterla declaración else dentro del ISR
Sus comentarios ayudaron a CL, reconfiguré los pines correctamente y puse un período de tiempo antes de establecer una condición de INICIO nuevamente.