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
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.
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.
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
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.
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.
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 ...
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
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?
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.
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.
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);
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 | }
|
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?
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?
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?
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.