Forum: Mikrocontroller und Digitale Elektronik MSP430F4250 I2C Slave


von Nobbie (Gast)


Lesenswert?

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

von Tippgeber (Gast)


Lesenswert?

TI ist da immer die erste und beste Quelle:
Software I2C Slave Using the MSP430 (slaa330.htm, 0 KB)

von Michael (Gast)


Lesenswert?

Hi,

schau dir auch mal die Application Note SLAA330 an.

Viele Grüße
Michael

von Nobbie (Gast)


Lesenswert?

Hallo,

danke für eure Antworten. Werde es durcharbeiten

Gruss Nobbie

von Tippgeber (Gast)


Lesenswert?


von Nobbie (Gast)


Lesenswert?

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

von szimmi (Gast)


Lesenswert?

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

von szimmi (Gast)


Angehängte Dateien:

Lesenswert?

btw., im Anhang mal Master-Code des TI-Examples.

von szimmi (Gast)


Angehängte Dateien:

Lesenswert?

Und hier der zugehörige Slave-Code. Vielleicht hilfts...

von Nobbie (Gast)


Lesenswert?

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

von szimmi (Gast)


Lesenswert?

Nochmal die Bitte, schicke mal die restliche main-Funktionalität

von Nobbie (Gast)


Lesenswert?

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

von szimmi (Gast)


Lesenswert?

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.

von Nobbie (Gast)


Lesenswert?

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
Noch kein Account? Hier anmelden.