So konfigurieren Sie den I2C des MSP430

Ich habe ein MSP430FR6989- Entwicklungsboard ( MSP-EXP430FR6989 ).

Ich möchte es so programmieren, dass es mit einem MAX30102- Pulsoximeter und einem Herzfrequenz-IC kommuniziert. Die Schnittstelle erfolgt über das I2C-Protokoll.

Ich habe nur einen Master (MSP430) und einen Slave (MAX30102).

Geben Sie hier die Bildbeschreibung ein

Aus dem Lesen des MSP430-Benutzerhandbuchs (Seite 821, Kapitel 32, eUSCI-I2C-Modus) und des MAX30102-Datenblatts (Seite 16/32) geht Folgendes hervor:

  • Wir schreiben die Slave-Adresse in das Master-Adressregister UCB0I2CSA = 0x57, setzen sie UCTRfür einen Schreibvorgang und setzen sie UCTXSTTfür eine START-Bedingung.
  • MSP430 überträgt die Adresse des Slaves zusammen mit dem Schreibbit (8 Bits, die von der SCL umgeschaltet werden)
  • MAX30102 sendet ein ACK-Signal (LOW), das UCTXSTTBit wird gelöscht und das UCB0TXIFG0Bit gesetzt
  • Wenn UCB0TXIFG0das Bit gesetzt ist, geht MSP430 zu einem ISR, das Interrupt-Flag wird gelöscht, und wir schreiben das Adressregister von MAX30102 FIFO_WR_PTR in den Übertragungspuffer UCB0TXBUF.
  • MSP430 überträgt die Daten (FIFO_WR_PTR-Registeradresse) und wartet auf ein ACK vom MAX30102.
  • Wenn eine ACK empfangen wird (zweite ACK), UCBOTXIFG0wird das Bit gesetzt, geht zur ISR, wir löschen das UCTRBit für einen Lesemodus und setzen es UCTXSTTfür eine REPEATED START-Bedingung.
  • Die Slave-Adresse bleibt gleich und wird zusammen mit dem gelesenen Bit an den Slave übertragen.
  • Der Slave bestätigt dies (ACK) und wird UCRXIFG0gesetzt, MSP430 geht zu eUSCI_B0 ISR (diesmal entspricht der Wert am Interrupt-Vektor den empfangenen Daten).
  • Ein ISR-Wert bei UCB0RXBUF(FIFO_WR_PTR) wird in einer globalen Variablen gespeichert WritePointer = UCB0RXBUF.

Ich habe entsprechend einen MSP430-Code geschrieben.

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

Wenn ich jedoch den Code baue und ausführe, habe ich den SCL (P1.7) mit einem Oszilloskop geprüft und ich bekomme nur eine hohe Spannung (3,3 V). Selbst wenn meine I2C-Softwarekonfiguration falsch ist, sollte ich immer noch mindestens 9 Impulse (7-Bit-Adresse, 1-Bit-Write, 1-Bit-ACK/NACK) vom SCL mit dem Oszilloskop erhalten.

Als ich den Code debuggte und der MSP430 in die While-Schleife wechselt, wenn UCTXSTTgesetzt ist, wird kein Interrupt-Flag gesetzt.

PS: Der HW-Anschluss ist ein Open-Drain mit 4,7-kOhm-Widerständen, die als Pullup-Widerstände fungieren.

Ich weiß nicht, wo mein Fehler liegt, bitte helfen Sie mir bei diesem Problem.

Antworten (1)

    #define ENABLE_PINS 0xFFFE
    PM5CTL0 = ENABLE_PINS;

Dadurch werden alle anderen Bits als 1 geschrieben. Um ein einzelnes Bit zu löschen, verwenden Sie PM5CTL0 &= ~LOCKLPM5;.

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

Wie in Tabelle 6-21 des Datenblatts gezeigt, müssen Sie das Bit in P1SEL0 setzen und das Bit in P1SEL1 löschen.

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

Dadurch wird fortlaufend eine neue Transaktion gestartet. Sie möchten zumindest warten, bis der vorherige fertig ist.

Vielen Dank für den Kommentar, ich werde PM5CTL0 ändern, P1SEL0 und P1SEL1 korrekt konfigurieren, einen Timer-Interrupt von einer Sekunde hinzufügen, der die Übertragung startet, die Variable wird jedoch counterzurückgesetzt, wenn MSP430 die Else-Anweisung in die ISR eingibt
Ihre Kommentare haben CL geholfen, ich habe die Pins korrekt neu konfiguriert und eine gewisse Zeit gesetzt, bevor ich erneut eine START-Bedingung gesetzt habe.