MSP430 I2C Ansteuerung - Veratändnis Probleme

Gast #5106635
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
Angehängte Dateien:
#5106639
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.
Persönliche Seite #5106649
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.
#5106858
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.
Gast #5106988
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.
Gast #5107081
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.
Angehängte Dateien:
#5107600
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 ...
Gast #5107997
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
Angehängte Dateien:
Gast #5108025
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.
Angehängte Dateien:
Gast #5108159
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);
#5108268
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
}
Gast #5108317
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?
#5108392
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?
Gast #5108641
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?

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren