1
\$\begingroup\$

I have an MSP430FR6989 development board (MSP-EXP430FR6989).

I would like to program it to communicate with a MAX30102 Pulse Oximeter and Heart Rate IC, the interface is done through I2C protocol.

I have only one master (MSP430) and one slave (MAX30102).

enter image description here

From reading the MSP430 user guide (pg821 Chapter 32 eUSCI I2C Mode) and the MAX30102 datasheet (pg16/32), this is my understanding:

  • we write slave address in master address register UCB0I2CSA = 0x57, set UCTR for a write, and set UCTXSTT for a START condition.
  • MSP430 transmits the slave's address along with the write bit, (8 bits toggled from the SCL)
  • MAX30102 sends an ACK signal (LOW), the UCTXSTT bit is cleared, and the UCB0TXIFG0 bit is set
  • when UCB0TXIFG0 bit is set, MSP430 goes to an ISR, interrupt flag gets cleared, and we write the address register of MAX30102 FIFO_WR_PTR into the Transmit Buffer UCB0TXBUF.
  • MSP430 transmits the data (FIFO_WR_PTR register address) and waits for an ACK from the MAX30102.
  • When an ACK is received (second ACK), UCBOTXIFG0 bit is set, goes to the ISR, we clear the UCTR bit for a read mode and set UCTXSTT for a REPEATED START condition.
  • The slave address remains the same and gets transmitted to the slave along with the read bit.
  • Slave acknowledges it (ACK), and the UCRXIFG0 is set, MSP430 goes to eUSCI_B0 ISR (this time, value at interrupt vector corresponds to Received Data).
  • at ISR value at UCB0RXBUF (FIFO_WR_PTR) is stored in a global variable WritePointer = UCB0RXBUF.

I have written an MSP430 code accordingly.

#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;
    }
}

However when I build and to run the code, I probed the SCL (P1.7) with an oscilloscope and I only get a high voltage (3.3V). Even if my I2C software configuration is wrong, I should still get at least 9 pulses (7 bits address, 1 bit Write, 1 bit ACK/NACK) from the SCL with the oscilloscope.

When I debugged the code and the MSP430 goes inside the while loop, when UCTXSTT is set, no interrupt flag is set.

PS: the HW connection is an open drain, with 4.7K ohm resistors acting as pullup resistors.

I don't know where is my error, kindly help me with this issue.

\$\endgroup\$

1 Answer 1

1
\$\begingroup\$
    #define ENABLE_PINS 0xFFFE
    PM5CTL0 = ENABLE_PINS;

This writes all the other bits as 1. To clear a single bit, use PM5CTL0 &= ~LOCKLPM5;.

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

As shown in table 6-21 of the datasheet, you need to set the bit in P1SEL0 and clear the bit in P1SEL1.

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

This contionuously starts a new transaction. You want at least to wait until the previous one has finished.

\$\endgroup\$
2
  • \$\begingroup\$ Thank you for the comment, I will change PM5CTL0, configure the P1SEL0 and P1SEL1 correctly, add a one second timer interrupt that will start transmission, however variable counter is reset, when MSP430 enters the else statement inside the ISR \$\endgroup\$ Nov 24, 2020 at 11:02
  • \$\begingroup\$ Your comments did help CL, I reconfigured the pins correctly and put a period of time before setting a START condition again. \$\endgroup\$ Nov 25, 2020 at 3:20

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.