Hallo, ich muss zwischen den F1611 und den F4250 eine I2C Kommunikation realisieren. Bedingt durch die Architektur soll der F4250 als I2C Slave agieren. Da der F4250 aber keine hardwareseitige Implementierung hat, muss es also durch Software realisiert werden. Jetzt die Frage, hat jemand von euch schon mal einen I2C Slave durch Software realisiert? Ich denke, dass dies nicht so einfach ist. In einem anderen Thread habe ich schon mal dieselbe Frage gefunden. Hier wurde vorgeschlagen, die SCL Leitung am Slave mit Interrupt zu handeln und dann den Portpin entsprechen zu lesen oder zu setzen. Mich interresiert aber, ob dies so sinnvoll ist und ob es wirklich schon jemand in der Praxis zum Laufen gebracht hat. (Vielleicht mit ein paar Codezeilen) Danke Nobbie
Hi, schau dir auch mal die Application Note SLAA330 an. Viele Grüße Michael
Hallo, ich habe den I2C Slave jetzt softwareseitig implementiert und das Lesen und Schreiben funktioniert beim ersten Byte sauber. Ich habe das mit dem Osziloskop getestet. Jetzt habe ich das Problem, wenn ich mehr als 1 Datenbyte senden/lesen möchte, geht garnichts mehr. Interressant ist, dass sich der SCL Clock nachdem senden/lesen des ersten Datenbytes ändert (von 30kHz auf 80kHz). Ich habe keine Ahnung warum. Wie gesagt, das Timing zwischen dem F1611(Master) und dem F4250(Slave) funktioniert beim ersten Datenbyte einwandfrei. Ich poste mal kurz meinen Code. Ich bin völlig ratlos und verzweifelt, warum sich auf einmal der SCL ändert. Initialisierung I2C F1611 (Master)
1 | void init_I2C(void) |
2 | {
|
3 | unsigned char adr; |
4 | adr = 0x0048; |
5 | |
6 | |
7 | P3SEL &= ~0x30; // P3.4,5 = USART0 TXD/RXD, UART0 NOT SELECT |
8 | P3SEL |= 0x0A; // P3.1,3 = I2C, Assign I2C pins to module |
9 | |
10 | U0CTL |= SWRST; |
11 | |
12 | U0CTL |= I2C + SYNC; // Switch USART0 to I2C mode |
13 | U0CTL &= ~I2CEN; // clear I2CEN bit => necessary to re-configure I2C module |
14 | |
15 | U0CTL &= ~XA; |
16 | U0CTL &= ~LISTEN; |
17 | U0CTL &= ~RXDMAEN; |
18 | U0CTL &= ~TXDMAEN; |
19 | |
20 | I2CTCTL = 0X00; |
21 | I2CTCTL = I2CSSEL_2 ; // smclk = mclk = 8 Mhz |
22 | |
23 | |
24 | I2CIE = TXRDYIE + NACKIE+ RXRDYIE + ARDYIE + STTIE + OAIE; // Enable I2C interrupts |
25 | I2CIFG =0x00; // clear I2C interrupt flags |
26 | |
27 | I2CSA = adr; |
28 | |
29 | I2COA = 0x0049; |
30 | |
31 | I2CNDAT = 0x01; // one byte |
32 | |
33 | SetI2cSpeed(); // set i2c speed |
34 | |
35 | U0CTL |= I2CEN; // Enable I2C |
36 | |
37 | IFG1 &= ~UTXIFG0; |
38 | IFG1 &= ~URXIFG0; |
39 | }
|
Setzen der I2C SCL F1611 (Master)
1 | void SetI2cSpeed(void) |
2 | {
|
3 | I2CPSC = 0x03; |
4 | I2CSCLL = 0x0a; |
5 | I2CSCLH = 0x0a; |
6 | }
|
ISR I2C F1611 (Master)
1 | void I2C_ISR (void) __interrupt [USART0TX_VECTOR] |
2 | {
|
3 | switch( I2CIV ) |
4 | {
|
5 | case 2: |
6 | break; // Arbitration lost |
7 | case 4: // clear I2CEN bit => necessary to re-configure I2C module |
8 | |
9 | break; // No Acknowledge |
10 | |
11 | case 6: break; // Own Address |
12 | case 8: |
13 | break; // Register Access Ready |
14 | case 10: |
15 | RXData = I2CDRB; |
16 | |
17 | break; // Receive Ready |
18 | case 12: // Transmit Ready |
19 | I2CDRB = TXData; // Load I2CDRB and increment |
20 | |
21 | break; |
22 | case 14: break; // General Call |
23 | case 16: |
24 | break; // Start Condition |
25 | }
|
main F1611 (Master)
1 | void main(void) |
2 | {
|
3 | volatile unsigned int i; |
4 | WDTCTL = WDTPW + WDTHOLD; |
5 | BCSCTL1 = 0x07; |
6 | BCSCTL2 |= SELS; // SMCLK = XT2 (8 MHz) |
7 | |
8 | //Port3 I2C und USARTs
|
9 | P3SEL = 0xFF; // UART and I2C pin option select |
10 | P3DIR = 0xFF; // set port 3 to output direction |
11 | init_I2C(); |
12 | |
13 | U0CTL |= MST; // Master mode |
14 | I2CTCTL |= I2CSTT + I2CSTP + I2CTRX; // Initiate TX |
15 | while (I2CBB & I2CDCTL); |
16 | |
17 | |
18 | U0CTL |= MST; |
19 | I2CTCTL &= ~I2CTRX; // Clear transmit bit |
20 | I2CTCTL |= I2CSTT + I2CSTP; // Restart - read from slave |
Ich glaube, dass es mit dem Master zusammenhängt. Sobald ich diesem nähmlich wieder resete, antwortet der Softwareslave(F4250) ohne Probleme. Was kann ich machen?????? Danke
Mal ne Frage, was kommt denn in Deinem Programm im main nach der letzten Zeile: I2CTCTL |= I2CSTT + I2CSTP; // Restart - read from slave ??? Poste mal bitte die komplette main-Funktion
Hallo, erst mal danke für die Antworten. Wie bereits gesagt, ist der Slave als softwareseitig implementiert. Am Port sind P1.0 und P1.1 beim F4250 als I2C konfiguriert. Da der F4250 keine hardwaresetige Unterstützung für I2C hat, muss ich also eine Softwarelösung realisieren. Die Pins beim F4250 habe ich über Interrupts getriggert, um so die Start, Stopcondition zu erkennen und die jeweiligen Daten- oder Adressbits zu lesen oder zu schreiben. Das funktioniert soweit auch alles, solange ich vom Master aus nur ein Datenbyte lesen/schreiben möchte. Das habe ich mit dem Oszi nachgeprüft. Das Handling funktioniert sauber. Die ACKs werden mit den entsprechenden Taktzyklen sauber gesetzt und nach der erfolgreichen Übertragung (19. SCL Takt) wird die StOP Condition sauber erkannt. Wenn ich jetzt aber mehrere Datenbytes lesen oder schreiben möchte, "bricht alles zusammen". Der SCL Takt, der ja vom Master vorgegeben wird, verändert sich auf einmal(wird schneller). Wie bereits im vorherigen Beitrag beschrieben, will ich statisch in der main ein Byte schreiben und ein Byte lesen. Ich habe das Gefühl, dass das hardwareseitige I2C handling im master nach dem ersten Datenbyte völlig zusammenbricht. Ich weiß aber nicht warum. Ich suche und suche und komme nicht zur Lösung. Bin echt am verzweifeln. Sobald ich den Master resete, kann ich wieder ordnungsgemäß ein Datenbyte übertragen, bevor die Kommunikation wieder zusammenbricht. Danke Nobbie
Hallo, na, kannst du auch nicht von der Arbeit lassen??? ;-) also hier jetz moch einmal die komplette main
1 | void main(void) |
2 | {
|
3 | |
4 | volatile unsigned int i; |
5 | WDTCTL = WDTPW + WDTHOLD; |
6 | BCSCTL1 = 0x07; // XT2on, max RSEL (8 MHz) |
7 | BCSCTL2 = SELS; // SMCLK = XT2 (8 MHz) |
8 | |
9 | //Port3 I2C und USARTs
|
10 | P3SEL = 0xFF; // UART and I2C pin option select |
11 | P3DIR = 0xFF; // set port 3 to output direction |
12 | init_I2C(); |
13 | |
14 | |
15 | _EINT(); // enable interrupts |
16 | |
17 | |
18 | //I2CNDAT = 0x01;
|
19 | TXData = 0x00; |
20 | for (i=0; i<2 ; i++) |
21 | {
|
22 | |
23 | U0CTL |= MST; // Master mode |
24 | I2CTCTL |= I2CSTT + I2CTRX + I2CSTP; // Initiate TX |
25 | while ((I2CTCTL & I2CSTP) == I2CSTP); // wait until the STOP |
26 | // condition bit is reset
|
27 | //while (I2CBB & I2CDCTL);
|
28 | TXData++; |
29 | }
|
Innerhalb der main will ich zweimal ein Datenbate zum Slave senden. Da im Slave momentan nur die 1 Byte Variante mit START/STOP Bedingung implementiert ist, muss ich jedes einzelne Datenbyte mit START/STOP Bedingung übertragen. Ich habe das Gefühl, dass es auf Masterseite Schwierigkeiten beim hardwareseitigen Handling(Stopbedingung) des I2C workflowes gibt. Ich kann mir aber nicht erklären, warum. Das Zusammenspiel aus SCL/SDA zwischen Master/Slave ist absolut konform mit der I2C-Spec von Phillips. Ich könnte mir es höchstens mit einem Timingproblem auf Seiten des Masters vorstellen. _ _ _ _ _ SDA || | ... _ _ _ _ _ _ _ _ _ _||_ _ _ _ _ | _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ SCL | | | | | | | ... _| |_ _ _| |_ _ _| |_| Oben habe ich dir mal die letzten Signalverläufe dargestellt. Der eine Spike auf der SDA Leitung ist von der Busübergabe für das ACK. Interessant ist, dass nach dem ACK der Zeitzyklus wo SCL LOW ist, viel geringer ist. Nichts desto trotz, ist aber die STOP condition sauber zu erkennen. Hast du noch eine Idee? Werde morgen mal die Masterplatine tauschen und sehen was dann passiert. Zum jetzigen Zeitpunkt bin ich jedenfalls absolut wissenslos, was es noch sein könnte. Gruss Nobbie
Hiho, erstmal eine einfache Idee. Nachdem bei Dir i==2 geworden ist, verschwindet Dein Programm im Nirvana (while (1) im main hat manchmal seinen Sinn...). Es sei denn, in Deinem main kommt noch irgendwas, was ich noch nicht kenne. Zum zweiten,probier doch einmal den TI-Code aus (siehe auch früher genanntes Beispiel): U0CTL |= MST; // Master mode I2CTCTL |= I2CSTT; // Initiate transfer while (1) { if (i == 6) { i = 0; TestData++; I2CTCTL |= I2CSTP; while (I2CTCTL & I2CSTP); // Check Stop Condition U0CTL |= MST; I2CTCTL |= I2CSTT; } i++; _BIS_SR(CPUOFF); // Enter LPM0 P1OUT |= 0x01; // Set P1.0 if (TestData++ != RXData) break; // Test received data P1OUT &= ~0x01; // Clear P1.0 } while (1); // Trap CPU } Bevor Du am MSP und Deiner Hardware zweifelst.
Hallo allerseits, es scheint jetzt doch an der Masterhardware zu liegen. Habe mitr noch einmal die Eratasheets des 1611 angeschaut und die relevanten Bugs durchgelesen. Anschließend habe ich den MSP mit einem Atmel ausgetauscht und siehe da, der F4250 Software Slave "schnurt wie ein Kätzchen". Es lag anscheinend wirklich daran, dass die Statemachine im master nicht sauber funktioniert hat und nach dem ersten Datenbyte resetet hat. Schade um das Wochenende ;-( gruss
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.