www.mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik MSP430F4250 I2C Slave


Autor: Nobbie (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Tippgeber (Gast)
Datum:

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

Autor: Michael (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi,

schau dir auch mal die Application Note SLAA330 an.

Viele Grüße
Michael

Autor: Nobbie (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

danke für eure Antworten. Werde es durcharbeiten

Gruss Nobbie

Autor: Tippgeber (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert

Autor: Nobbie (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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)
void init_I2C(void)
{
  unsigned char adr;
  adr = 0x0048;
  
    
  P3SEL &= ~0x30;                           // P3.4,5 = USART0 TXD/RXD, UART0 NOT SELECT
  P3SEL |= 0x0A;                            // P3.1,3 = I2C, Assign I2C pins to module

  U0CTL |= SWRST;

  U0CTL |= I2C + SYNC;                      // Switch USART0 to I2C mode
  U0CTL &= ~I2CEN;                          // clear I2CEN bit => necessary to re-configure I2C module

  U0CTL &= ~XA;
  U0CTL &= ~LISTEN;
  U0CTL &= ~RXDMAEN;
  U0CTL &= ~TXDMAEN;

  I2CTCTL = 0X00;
  I2CTCTL = I2CSSEL_2 ;                     // smclk = mclk = 8 Mhz


  I2CIE   = TXRDYIE + NACKIE+ RXRDYIE + ARDYIE + STTIE + OAIE; // Enable I2C interrupts
  I2CIFG  =0x00;                            // clear I2C interrupt flags

  I2CSA = adr;

  I2COA = 0x0049;

  I2CNDAT = 0x01;                          // one byte

  SetI2cSpeed();                            // set i2c speed

  U0CTL |= I2CEN;                           // Enable I2C

  IFG1 &= ~UTXIFG0;
  IFG1 &= ~URXIFG0;
}


Setzen der I2C SCL F1611 (Master)
void SetI2cSpeed(void)
{
  I2CPSC = 0x03;
  I2CSCLL = 0x0a;                  
  I2CSCLH = 0x0a;
}



ISR I2C F1611 (Master)
void I2C_ISR (void) __interrupt  [USART0TX_VECTOR]
{
 switch( I2CIV )
 {
   case  2: 
            break;                          // Arbitration lost
   case  4:                      // clear I2CEN bit => necessary to re-configure I2C module
            
            break;                          // No Acknowledge
            
   case  6: break;                          // Own Address
   case  8: 
            break;                          // Register Access Ready
   case 10:
            RXData = I2CDRB;
            
            break;                          // Receive Ready
   case 12:                                 // Transmit Ready
            I2CDRB = TXData;              // Load I2CDRB and increment
            
            break;
   case 14: break;                          // General Call
   case 16: 
            break;                          // Start Condition
 }



main F1611 (Master)
void main(void)
{
  volatile unsigned int i;
  WDTCTL = WDTPW + WDTHOLD;                         
  BCSCTL1 = 0x07;                                    
  BCSCTL2 |= SELS;             // SMCLK = XT2 (8 MHz)

  //Port3 I2C und USARTs
  P3SEL = 0xFF;                // UART and I2C pin option select
  P3DIR = 0xFF;                // set port 3 to output direction
  init_I2C();

  U0CTL |= MST;                             // Master mode
  I2CTCTL |= I2CSTT + I2CSTP + I2CTRX;      // Initiate  TX
  while (I2CBB & I2CDCTL);


  U0CTL |= MST;
  I2CTCTL &= ~I2CTRX;            // Clear transmit bit
  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

Autor: szimmi (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: szimmi (Gast)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
btw., im Anhang mal Master-Code des TI-Examples.

Autor: szimmi (Gast)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Und hier der zugehörige Slave-Code. Vielleicht hilfts...

Autor: Nobbie (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: szimmi (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Nochmal die Bitte, schicke mal die restliche main-Funktionalität

Autor: Nobbie (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

na, kannst du auch nicht von der Arbeit lassen??? ;-)

also hier jetz moch einmal die komplette main
void main(void)
{
  
  volatile unsigned int i;
  WDTCTL = WDTPW + WDTHOLD;      
  BCSCTL1 = 0x07;                // XT2on, max RSEL (8 MHz)
  BCSCTL2 = SELS;                // SMCLK = XT2 (8 MHz)

  //Port3 I2C und USARTs
  P3SEL = 0xFF;                  // UART and I2C pin option select
  P3DIR = 0xFF;                  // set port 3 to output direction
  init_I2C();
  

  _EINT();                       // enable interrupts


  //I2CNDAT = 0x01;
  TXData = 0x00;
  for (i=0; i<2 ; i++)
  {
    
    U0CTL |= MST;                             // Master mode
    I2CTCTL |= I2CSTT + I2CTRX + I2CSTP;      // Initiate  TX
    while ((I2CTCTL & I2CSTP) == I2CSTP);     // wait until the STOP   
                                              // condition bit is reset
    //while (I2CBB & I2CDCTL);
    TXData++;
  }

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

Autor: szimmi (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Nobbie (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.