Forum: Mikrocontroller und Digitale Elektronik MSP430G2553 USCI mit I2C geht nicht


von Stephan M. (swissman)


Lesenswert?

Ich komme mit dem USCI einfach nicht klar.
Habe mir die "USCI communication library without DMA" von TI geholt und 
benutze diese um über I2C zu kommunizieren. Der Code wird auf den 
Mikrokontroller geladen und läuft auch durch. Nur leider wird auf dem 
I2C nicht kommuniziert.

Was ich bereits versucht habe:
1. #include "msp430G2553.h" ersetzt durch den korrekten controller
2. SDA und SCL Pins richtig setzen
   #define SDA_PIN 0x80 // msp430G2553 UCB0SDA pin
   #define SCL_PIN 0x40 // msp430G2553 UCB0SCL pin
3. Pins auswählen in receive init und transmit init
   P1SEL |= SDA_PIN + SCL_PIN;  // Assign I2C pins to USCI_B0
4. Debugger anwerfen
   Mein Programm läuft komplett durch. Bleibt also auch bei der
   while Schlaufe nicht hängen

   while ( TI_USCI_I2C_notready() );       // wait for bus to be free
   Trotzdem werden auch vom nachfolgenden Code keine Daten übertragen
   TI_USCI_I2C_transmit(0x20,InitDisplayUSCI); // transmit Init Display 
Command
4. Oszilloskop anschliessen
   SCL und SDA Pin gehen beide auf high, sobald ich den pin aktiviere, 
der die beiden 4.5 kOhm Widerstände als pull up ansteuert.
   Danach ändert sich der Zustand der beiden Pins nicht mehr! Es wird 
also nichts kommuniziert. Ich verstehe nicht, wo mein Denkfehler liegt. 
Habt Ihr Ansätze für mich? Ich wäre euch wirklich sehr dankbar.

von Jörg S. (joerg-s)


Lesenswert?

Stell deinen Code mal rein.

von Stephan M. (swissman)


Lesenswert?

Danke für die rasche Antwort.
Mein main code sieht folgendermassen aus:

int main(void)
{
  WDTCTL = WDTPW + WDTHOLD;             // Stop watchdog timer

  // Beschleunigungssensor und I2C Stromversorgung
  P3DIR |= 0x20;      // Setzte P3.5 in Output Richtung
  P3OUT |= 0x20;      // I2C Stromversorgung einschalten auf P3.5

  // Display Stromversorgung
  P3DIR |= 0x80;         // Set P3.7 to output direction
  P3OUT |= 0x80;         // Turn on Display on P3.7

  BCSCTL1 = CALBC1_1MHZ;                // Set DCO
  DCOCTL = CALDCO_1MHZ;

  _EINT();
  //__enable_interrupt();

  TI_USCI_I2C_transmitinit(0x7C,0x08);    // init transmitting with USCI

  while ( TI_USCI_I2C_notready() );       // wait for bus to be free

  TI_USCI_I2C_transmit(0x20,InitDisplayUSCI); // transmit Init Display

  // The code here is executed but no communication on SDA and SCL pins.

  // If I set the breakpoint here it is triggered.
  // Therefore the hole code is executed...

  LPM3;
}

von Stephan M. (swissman)


Lesenswert?

Inhalt der TI_USCI_I2C_master.h

#define SDA_PIN 0x80         // msp430G2553 UCB0SDA pin
#define SCL_PIN 0x40         // msp430G2553 UCB0SCL pin

void TI_USCI_I2C_receiveinit(unsigned char slave_address, unsigned char 
prescale);
void TI_USCI_I2C_transmitinit(unsigned char slave_address, unsigned char 
prescale);

void TI_USCI_I2C_receive(unsigned char byteCount, unsigned char *field);
void TI_USCI_I2C_transmit(unsigned char byteCount, unsigned char 
*field);

unsigned char TI_USCI_I2C_slave_present(unsigned char slave_address);
unsigned char TI_USCI_I2C_notready();

von Tobias K. (kurzschluss81)


Lesenswert?

Das entschiedene fehlt noch. Den I2C Code bräuchten wird auch noch sonst 
sieht ja keiner was du evtl. falsch machst

von Stephan M. (swissman)


Lesenswert?

Danke Tobias. Ja, da hast du natürlich recht. Es handelt sich um den 
Standard Code von TI. Meine einzigen Änderungen sind im ersten Post 
beschrieben.
Das sieht dann in der "TI_USCI_I2C_master.c" folgendermassen aus:

//*******************************************************************
//   MSP430 USCI I2C Transmitter and Receiver
//*******************************************************************
#include "msp430G2553.h"                    // device specific header

#include "TI_USCI_I2C_master.h"

signed char byteCtr;
unsigned char *TI_receive_field;
unsigned char *TI_transmit_field;

//----------------------------------------------------------------------
// void TI_USCI_I2C_receiveinit(unsigned char slave_address,
//                              unsigned char prescale)
//
// This function initializes the USCI module for master-receive
// operation.
//
// IN:   unsigned char slave_address   =>  Slave Address
//       unsigned char prescale        =>  SCL clock adjustment
//----------------------------------------------------------------------
void TI_USCI_I2C_receiveinit(unsigned char slave_address,
                             unsigned char prescale){
  P1SEL |= SDA_PIN + SCL_PIN;           // Assign I2C pins to USCI_B0

  UCB0CTL1 = UCSWRST;                      // Enable SW reset
  UCB0CTL0 = UCMST + UCMODE_3 + UCSYNC; // I2C Master, synchronous mode
  UCB0CTL1 = UCSSEL_2 + UCSWRST;            // Use SMCLK, keep SW reset
  UCB0BR0 = prescale;                       // set prescaler
  UCB0BR1 = 0;
  UCB0I2CSA = slave_address;                // set slave address
  UCB0CTL1 &= ~UCSWRST;             // Clear SW reset, resume operation
  UCB0I2CIE = UCNACKIE;
  IE2 = UCB0RXIE;                            // Enable RX interrupt
}

//---------------------------------------------------------------------
// void TI_USCI_I2C_transmitinit(unsigned char slave_address,
//                               unsigned char prescale)
//
// This function initializes the USCI module for master-transmit
// operation.
// IN:   unsigned char slave_address   =>  Slave Address
//       unsigned char prescale        =>  SCL clock adjustment
//---------------------------------------------------------------------
void TI_USCI_I2C_transmitinit(unsigned char slave_address,
                          unsigned char prescale){
  P1SEL |= SDA_PIN + SCL_PIN;           // Assign I2C pins to USCI_B0
  UCB0CTL1 = UCSWRST;                         // Enable SW reset
  UCB0CTL0 = UCMST + UCMODE_3 + UCSYNC; // I2C Master, synchronous mode
  UCB0CTL1 = UCSSEL_2 + UCSWRST;            // Use SMCLK, keep SW reset
  UCB0BR0 = prescale;                         // set prescaler
  UCB0BR1 = 0;
  UCB0I2CSA = slave_address;                // Set slave address
  UCB0CTL1 &= ~UCSWRST;             // Clear SW reset, resume operation
  UCB0I2CIE = UCNACKIE;
  IE2 = UCB0TXIE;                          // Enable TX ready interrupt
}

//---------------------------------------------------------------------
//void TI_USCI_I2C_receive(unsigned char byteCount,
//                         unsigned char *field)
// This function is used to start an I2C commuincation in
// master-receiver mode.
// IN:   unsigned char byteCount  =>  number of bytes that
// should be read
//       unsigned char *field     =>  array variable used to store
//                                    received data
//----------------------------------------------------------------------
void TI_USCI_I2C_receive(unsigned char byteCount, unsigned char *field)
{
  TI_receive_field = field;
  if ( byteCount == 1 ){
    byteCtr = 0 ;
    __disable_interrupt();
    UCB0CTL1 |= UCTXSTT;                    // I2C start condition
    while (UCB0CTL1 & UCTXSTT);             // Start condition sent?
    UCB0CTL1 |= UCTXSTP;                    // I2C stop condition
    __enable_interrupt();
  } else if ( byteCount > 1 ) {
    byteCtr = byteCount - 2 ;
    UCB0CTL1 |= UCTXSTT;                      // I2C start condition
  } else
    while (1);                                // illegal parameter
}

//---------------------------------------------------------------------
//void TI_USCI_I2C_transmit(unsigned char byteCount,
//                          unsigned char *field)
// This function is used to start an I2C commuincation in
// master-transmit mode.
//
// IN:   unsigned char byteCount  =>  number of bytes that should be
// transmitted
//       unsigned char *field     =>  array variable. Its content
//                                    will be sent.
//----------------------------------------------------------------------
void TI_USCI_I2C_transmit(unsigned char byteCount, unsigned char *field)
{
  TI_transmit_field = field;
  byteCtr = byteCount;
  UCB0CTL1 |= UCTR + UCTXSTT;               // I2C TX, start condition
}

//--------------------------------------------------------------------
// unsigned char TI_USCI_I2C_slave_present(unsigned char slave_address)
//
// This function is used to look for a slave address on the I2C bus.
//
// IN:   unsigned char slave_address  =>  Slave Address
// OUT:  unsigned char                =>  0: address was not found,
//                                        1: address found
//---------------------------------------------------------------------
unsigned char TI_USCI_I2C_slave_present(unsigned char slave_address){
  unsigned char ie2_bak, slaveadr_bak, ucb0i2cie, returnValue;
  ucb0i2cie = UCB0I2CIE;                    // restore old UCB0I2CIE
  ie2_bak = IE2;                            // store IE2 register
  slaveadr_bak = UCB0I2CSA;                 // store old slave address
  UCB0I2CIE &= ~ UCNACKIE;                  // no NACK interrupt
  UCB0I2CSA = slave_address;                // set slave address
  IE2 &= ~(UCB0TXIE + UCB0RXIE);            // no RX or TX interrupts
  __disable_interrupt();
  UCB0CTL1 |= UCTR + UCTXSTT + UCTXSTP;     // I2C TX, start condition
  while (UCB0CTL1 & UCTXSTP);               // wait for STOP condition

  returnValue = !(UCB0STAT & UCNACKIFG);
  __enable_interrupt();
  IE2 = ie2_bak;                            // restore IE2
  UCB0I2CSA = slaveadr_bak;                 // restore old slave address
  UCB0I2CIE = ucb0i2cie;                    // restore old UCB0CTL1
  return returnValue;                       // return whether or not
                                            // a NACK occured
}

//---------------------------------------------------------------------
// unsigned char TI_USCI_I2C_notready()
//
// This function is used to check if there is commuincation in progress.
// OUT:  unsigned char  =>  0: I2C bus is idle,
//                          1: communication is in progress
//---------------------------------------------------------------------- 
---
unsigned char TI_USCI_I2C_notready(){
  return (UCB0STAT & UCBBUSY);
}


#pragma vector = USCIAB0RX_VECTOR
__interrupt void USCIAB0RX_ISR(void)
{
  if (UCB0STAT & UCNACKIFG){          // send STOP if slave sends NACK
    UCB0CTL1 |= UCTXSTP;
    UCB0STAT &= ~UCNACKIFG;
  }
}


#pragma vector = USCIAB0TX_VECTOR
__interrupt void USCIAB0TX_ISR(void)
{
  if (IFG2 & UCB0RXIFG){
    if ( byteCtr == 0 ){
      UCB0CTL1 |= UCTXSTP;                    // I2C stop condition
      *TI_receive_field = UCB0RXBUF;
      TI_receive_field++;
    }
    else {
      *TI_receive_field = UCB0RXBUF;
      TI_receive_field++;
      byteCtr--;
    }
  }
  else {
    if (byteCtr == 0){
      UCB0CTL1 |= UCTXSTP;                  // I2C stop condition
      IFG2 &= ~UCB0TXIFG;                   // Clear USCI_B0 TX int flag
    }
    else {
      UCB0TXBUF = *TI_transmit_field;
      TI_transmit_field++;
      byteCtr--;
    }
  }
}

von Tobias K. (kurzschluss81)


Lesenswert?

Warum hast du die Initialisierung eigentlich doppelt drin?

Du musst zu mindestens bei der Aktivierung der Interrupte aufpassen weil 
du durch die Doppelte Ausführung der Initialisierung die einen Interrupt 
wieder weg haust

von Jörg S. (joerg-s)


Lesenswert?

Du kannst deinen C-Code übrigens auch hier im Forum als C-Code 
darstellen lassen. Dafür gibt es die C Klammern ([c]). Siehe 
Formatierung.

von Stephan M. (swissman)


Lesenswert?

@Tobias
Unter anderem hatte ich auch probiert, ob es was bringt, wenn ich das 
EINT() ausschreibe. Macht aber erwartungsgemäss keinen Unterschied. Ist 
deshalb auch auskommentiert. Es waren aber nie beide Zeilen aktiv.

von Tobias K. (kurzschluss81)


Lesenswert?

Das meinte ich nicht.
Ich meine die Initialisierung der I2C Schnittstelle.
Einmal mit
1
void TI_USCI_I2C_transmitinit(unsigned char slave_address,
2
                          unsigned char prescale)
3
und ein zweites mal mit 
4
void TI_USCI_I2C_receiveinit(unsigned char slave_address,
5
                          unsigned char prescale)

von Stephan M. (swissman)


Lesenswert?

Ok, das heisst dann, ich soll nicht diese TI Library verwenden, wenn ich 
sowohl senden als auch empfangen möchte?
Ich versteh zwar immer noch nicht, wieso der code nicht läuft, weil ich 
ja eigentlich nur sende und die andere initialisierung gar nicht zur 
Anwendung kommt. Aber so oder so werde ich mich mal auf die Suche nach 
anderem Code machen, der dieses Problem nicht hat, da ich eigentlich 
beides machen möchte.
Danke für den Hinweis.

von Tobias K. (kurzschluss81)


Lesenswert?

Nun nach dieser Aussage habe ich den Eindruck das du gar nicht weißt was 
dein Code überhaupt macht. Denn mit 2-3 Änderungen wäre das Problem mit 
der doppelten Initialisierung behoben. Kann es sein das du hier einfach 
2 Code Examples zusammenkopiert hast ohne zu verstehen was der Code 
macht.

von Stephan M. (swissman)


Lesenswert?

:-(

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.