Forum: Mikrocontroller und Digitale Elektronik MSP430 I2C Ansteuerung - Veratändnis Probleme


von Teddy (Gast)


Angehängte Dateien:

Lesenswert?

Hallo Leute,
nachdem ich mit dem Atmega328P und I2C anfreunden konnte, klappt der 
Übergang von Atmega I2C zu MSP430 (Launchspad v1.5) I2C nicht so 
sonderlich.

Der I2C von dem MSP430 scheint auf dem ersten Blick doch komplizierter 
zu sein.
Bisher habe ich mich mit dem Datasheet, Code Beispielen von TI und hier 
aus dem Forum auseinandergesetzt und entstanden ist der Code, den ich im 
Anhang angehängt habe.

Angesteuert wird wieder der MCP23017, der mit dem Atmega328P ohne 
Probleme läuft.

Folgende Probleme habe ich bisher erkennen aber nicht lösen können.
1) Ich habe keinen externen Takt. Ich weiß nicht und konnte bisher nicht 
herausfinden wie groß der interne Takt ist. 8MHz, kann das stimmen?

2) Bei der Initialisierung habe ich folgendes übernommen, die ich nicht 
verstanden habe.

P1SEL |= BIT6 + BIT7;                     // Assign I2C pins to USCI_B0
P1SEL2|= BIT6 + BIT7;                     // Assign I2C pins to USCI_B0

Die Selektion Register sind ja dafür zuständig, in welchem Modus die I/O 
Ports arbeiten sollen. Ich habe bisher nicht herausfinden können, warum 
diese Zeile für I2C sein soll.
Beim Atmega328P wurde dies automatisch vom Controller gemacht, hier 
nicht?

3) Man schreibt die Slave Adresse in einen Register Namens "UCB0I2CSA", 
d.h. der MSP430, also der USCI Controller schickt die Adresse 
automatisch zum Slave, nachdem der Startbit gesendet wurde? Und ob Read 
oder Write mitgesendet wird, hängt vom dem Wert UCTR ab? UCTR = 1 ist 
Transmit und UCTR = 0 ist Read.

4) Beim Debuggen hängt das Programm bereits in der Zeile
    //Warten bis das Startbit gesendet wurde
    while(UCB0CTL1 & UCTXSTT);

Laut Datenblatt wird nach dem Startbit, das UCTXSTT Bit gecleared. Da 
das Programm dort hängen bleibt, wurde dementsprechend kein Startbit 
gesendet, warum auch immer.

5) Im Idle Modus, also nach dem Initialisieren des I2C messe ich am SDA 
Pin eine Spannung von ca. 3,5V aber beim SCL Pin eine Spannung von ca. 
2V.
Irgendwo scheint beim SCL Pin der Wurm zu liegen. Der müsste doch auch 
3,5V  betragen oder?

Das waren zunächst alle Fragen, die mich beschäftigen und ich ohne 
weiteres nicht lösen konnte.

Lg

von Stefan S. (mexakin)


Lesenswert?

Pull ups an den Leitungen hast du? Texas I2C benötigt das mMn immer, 
Atmel denke ich auch, weil I2C sich ja nciht selber auf high setzen 
kann.

Die PxSEL Befehle sagen dem MSP430 dass er diese Pins explusiv und 
speziell für I2C benutzen soll, ich hab nciht ind ein Datenblatt 
geschaut, ich schreib heir nur generell.

Hast du den entsprechenden IRQ auch atkiv udn gefüllt, ich kann mir 
vorstellen, dass der MSP den I2C IRQ Flag nur im IRQ rücksetzen kann, 
daher könnte es sein das er hier hängt , für immer.

Grüße.

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Teddy schrieb:
> 1) Ich habe keinen externen Takt. Ich weiß nicht und konnte bisher nicht
> herausfinden wie groß der interne Takt ist. 8MHz, kann das stimmen?

Der MSP430 enthält üblicherweise einen programmierbaren RC-Oszillator 
als Taktquelle. Das Ding wird im "Family User's Guide" und im Datenblatt 
DCO genannt.

Die resultierende Taktfrequenz kannst Du zur Laufzeit recht freizügig 
einstellen.

Die Codebeispiele von TI behandeln das, auch steht in den Kommentaren 
des Initialisierungscodes üblicherweise drin, welche Taktfrequenz 
verwendet wird.

> Ich habe bisher nicht herausfinden können, warum diese Zeile für I2C
> sein soll.

Du solltest Dir den "Family User's Guide" ansehen. Da wird in den 
entsprechenden Abschnitten, die die verschiedenen Betriebsarten der 
verschiedenen Peripherieelemente beschreiben, auch solcherlei Dinge 
erwähnt.

von Clemens L. (c_l)


Lesenswert?

Teddy schrieb:
> Ich weiß nicht und konnte bisher nicht
> herausfinden wie groß der interne Takt ist. 8MHz, kann das stimmen?

Es gibt Kalibrierungswerte für 1/8/12/16 MHz, mit denen du das 
Clock-Modul programmieren kannst. Das sähe ungefähr so aus:
1
  BCSCTL1 = CALBC1_1MHZ;
2
  DCOCTL = CALDCO_1MHZ;

> Die Selektion Register sind ja dafür zuständig, in welchem Modus die I/O
> Ports arbeiten sollen. Ich habe bisher nicht herausfinden können, warum
> diese Zeile für I2C sein soll.

Dann wirf mal einen Blick in Tabelle 19 des MSP430G2553-Datenblatts.

> entstanden ist der Code, den ich im Anhang angehängt habe.

Abschnitt 17.3.2 des User's Guide sagt:
>  The bus busy bit, UCBBUSY, is set after a START and cleared after a STOP.

Diese ganzen Schleifen sind falsch.

> 4) Beim Debuggen hängt das Programm bereits in der Zeile
>     //Warten bis das Startbit gesendet wurde
>     while(UCB0CTL1 & UCTXSTT);

Bild 17-12 zeigt, dass die Hardware darauf wartet, dass du das erste 
Byte in TXBUF schreibst.

: Bearbeitet durch User
von Teddy (Gast)


Lesenswert?

Pull Ups etc sind dran.
Ich will zunächst den I2C ohne Interrupt zum laufen kriegen.

Clemens L. schrieb:
>> Die Selektion Register sind ja dafür zuständig, in welchem Modus die I/O
>> Ports arbeiten sollen. Ich habe bisher nicht herausfinden können, warum
>> diese Zeile für I2C sein soll.
>
> Dann wirf mal einen Blick in Tabelle 19 des MSP430G2553-Datenblatts.
>
>> entstanden ist der Code, den ich im Anhang angehängt habe.
>
> Abschnitt 17.3.2 des User's Guide sagt:
>>  The bus busy bit, UCBBUSY, is set after a START and cleared after a STOP.
>
> Diese ganzen Schleifen sind falsch.
>
>> 4) Beim Debuggen hängt das Programm bereits in der Zeile
>>     //Warten bis das Startbit gesendet wurde
>>     while(UCB0CTL1 & UCTXSTT);
>
> Bild 17-12 zeigt, dass die Hardware darauf wartet, dass du das erste
> Byte in TXBUF schreibst.

Soweit erstmal danke.
Ich habe mich zu sehr auf die USER Guide konzentriert.
Mit dem UCBBUSY habe ich wohl überlesen. Ok das korrigiere ich gleich.

Das die Hardware darauf wartet, steht dort mit "Reception of own adress 
etc...."?. Englisch >.<

Danke erstmal soweit.

von Teddy (Gast)


Angehängte Dateien:

Lesenswert?

Habe mir das Datenblatt und das User Guide nochmal genau angeschaut.
Gemäß Bild 17-12 kann ich die Daten sogar später in den Buffer legen wie 
ich es bereits so implementiert habe.

Der Startbitflag soll nach dem Empfangen des ACK Bit des Slaves gelöscht 
werden. Das tut bei mir nicht. Der hängt wieder an der gleichen While 
Schleife.

Den neuen Code habe ich wieder angehängt.

von Clemens L. (c_l)


Lesenswert?

Auf UCTXSTT=0 zu warten ist nur beim ersten Byte sinnvoll.

UCTXSTT wird gelöscht, nachdem das ACK des Slave empfangen wurde.

Du solltest einfach vor dem Schreiben von TXBUF auf TXIFG warten, und 
vor dem Lesen von RXBUF auf RXIFG.

Und wenn I2C_Startbit() immer UCTR setzt, wird das mit dem Lesen 
schwierig ...

von Teddy (Gast)


Angehängte Dateien:

Lesenswert?

Ich kapiere das nicht.
Habe es genauso gemacht wie du es beschrieben hast, hat aber nichts 
gebracht.

Ich habe den Code wieder etwas geändert, aber das bringt auch nichts.
Irgendwo ist der Fehler :(
Der Debugger hängt wieder an der While Schleife mit der Abfrage ob das 
Bit UCTXSTT gecleared wurde.

Ich hänge mal wieder meinen Atmega dran, um einen Schaltungsfehler 
auszuschließen

von Teddy (Gast)


Lesenswert?

Also die Schaltung ist korrekt.

von Clemens L. (c_l)


Lesenswert?

Teddy schrieb:
> Also die Schaltung ist korrekt.

Und das sollen wir dir einfach so glauben?

> Der Debugger hängt wieder an der While Schleife mit der Abfrage ob das
> Bit UCTXSTT gecleared wurde.

Offensichtlich kein ACK. Was sagen Oszilloskop oder Logic-Analyzer?

von Teddy (Gast)


Angehängte Dateien:

Lesenswert?

Clemens L. schrieb:
> Teddy schrieb:
>> Also die Schaltung ist korrekt.
>
> Und das sollen wir dir einfach so glauben?

Ja bitte. Ich kann aber auch gerne einen Schaltplan zeichen, wenn ihr 
mögt.

>> Der Debugger hängt wieder an der While Schleife mit der Abfrage ob das
>> Bit UCTXSTT gecleared wurde.
>
> Offensichtlich kein ACK. Was sagen Oszilloskop oder Logic-Analyzer?

Ein Bild ist im Anhang.

von Teddy (Gast)


Angehängte Dateien:

Lesenswert?

Die Schaltung

von Clemens L. (c_l)


Lesenswert?

Teddy schrieb:
> Der Debugger hängt wieder an der While Schleife

Da hängt nichts.

Das Problem ist anscheinend, dass UCTXSTP zu früh gesetzt wird.

Zeig mal, wie du diesen Funktionen aufrufst.

von Teddy (Gast)


Lesenswert?

1
//I2C Datenbyte senden
2
void I2C_Send_Data(unsigned char Daten)
3
{
4
    //Startbit senden
5
    UCB0CTL1 |= UCTXSTT;
6
7
    //UCB0TXIFG is set, when start condition is generated and the first data to be transmitted can be written into UCB0TXBUF
8
    while(!(IFG2 & UCB0TXIFG));
9
10
    //Daten ins Senderegister legen
11
    UCB0TXBUF = Daten;
12
13
    //When the slaves acknowledges the address, the UCTXSTT bit is cleared
14
    while(UCB0CTL1 & UCTXSTT);
15
16
    //Stopbit senden
17
    UCB0CTL1 |= UCTXSTP;
18
}

Aufgerufen wird sie in der Main() so:
z.B. für die Port Richtungen - MCP23017_DDRA(0x00);
Und diese Funktion enthält das hier:

I2C_Send_Data(IODIRA);
I2C_Send_Data(DDR_A);

von Clemens L. (c_l)


Lesenswert?

Wenn du sowohl die Register-Adresse als auch das Datenbyte senden 
willst, dann darfst du zwischendurch die Transaktion nicht mit einem 
Stop abbrechen.
1
void I2C_Send_2(byte reg, byte data)
2
{
3
    while (UCB0CTL1 & UCTXSTP); // warte, bis vorherige Transaktion beendet
4
5
    UCB0CTL1 |= UCTR | UCTXSTT;
6
7
    while (!(IFG2 & UCB0TXIFG));
8
    UCB0TXBUF = reg;
9
10
    while (!(IFG2 & UCB0TXIFG));
11
    UCB0TXBUF = data;
12
13
    while (!(IFG2 & UCB0TXIFG));
14
    UCB0CTL1 |= UCTXSTP;
15
}

von Teddy (Gast)


Lesenswert?

Clemens L. schrieb:
> Wenn du sowohl die Register-Adresse als auch das Datenbyte senden
> willst, dann darfst du zwischendurch die Transaktion nicht mit einem
> Stop abbrechen.

Laut Datenblatt soll man das aber tun. Siehe Seite 459 Abschnitt 4.
Ansonsten sende man nur die Adresse.

>     while (!(IFG2 & UCB0TXIFG));
>     UCB0TXBUF = reg;

Was ist das hier? Soll hier die Adresse eigegeben werden?
Wofür ist dann das UCB0I2CSA Register?

Und habe den Code so übernommen, aber klappt auch nicht.wa
Klappt es bei dir etwa?

von Clemens L. (c_l)


Lesenswert?

Teddy schrieb:
> Clemens L. schrieb:
>> Wenn du sowohl die Register-Adresse als auch das Datenbyte senden
>> willst, dann darfst du zwischendurch die Transaktion nicht mit einem
>> Stop abbrechen.
>
> Laut Datenblatt soll man das aber tun. Siehe Seite 459 Abschnitt 4.

Keiner der beiden beteiligten Chips hat ein Datenblatt mit 459 Seiten. 
Falls du das User's Guide meinst: ich sehe keinen Abschnitt 4 auf dieser 
Seite, sondern 17.3.4.2.1. Wo genau siehst du dort diese Aussage über 
Stop?

>>     while (!(IFG2 & UCB0TXIFG));
>>     UCB0TXBUF = reg;
>
> Was ist das hier? Soll hier die Adresse eigegeben werden?

Ja, die Adresse des Registers.

> Wofür ist dann das UCB0I2CSA Register?

Für die Adresse des Slaves.

> klappt auch nicht

Hängt er? Wo? Rauch?

von Teddy (Gast)


Lesenswert?

Die Funktion oben habe ich übernommen. In der Main steht nun das hier

void main(void)
{
  WDTCTL = WDTPW | WDTHOLD;  // stop watchdog timer

  BCSCTL1 = CALBC1_1MHZ;
  DCOCTL = CALDCO_1MHZ;
I2C_Init(1);

I2C_Send_2(0x00,0x00);   //0x00 = IODIRA, 0x00 Alle Ports von A auf 
Ausgänge
I2C_Send_2(0x12,0xFF);   //0x12 = GPIPOA, 0xFF Alle Ports auf HIGH
while(1)
{}
}

Es hängt in dieser While Schleife
    while (!(IFG2 & UCB0TXIFG));
    UCB0TXBUF = data;

Funktioniert das denn bei dir?

von Teddy (Gast)


Lesenswert?

Soo jetzt läufts es mit meinem Code.
Das Lösung brachte mich dieser Thread.

https://e2e.ti.com/support/microcontrollers/msp430/f/166/t/185591

Ergo, habe einfach mal die USB Verbindung getrennt, wieder verbunden, 
Code abgespielt et voila es läuft.

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.