www.mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik I2C Problem LPC1768


Autor: Manuel Simmerl (Firma: S+S) (msimmerl)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

hab ein Problem mit einem LPC1768.
Ich will über den I2C-Bus einen DS1621 ansteuern. Nur leider 
funktioniert das ganze nicht.

Hab mir folgenden Beitrag durchgelesen und es versucht so zu machen:
Beitrag "I2C Problem beim LPC1768"

Hier mein Quellcode:
#include "i2c.h"
#include "type.h"

//////////////////////////////////////////////////////////////////////////
void init_i2c (void)
{
    // I2C Disable
    LPC_I2C2->I2CONCLR |= (1<<6);


    // CPU Taktteiler fuer I2C1
    //PCLKSEL1_bit.PCLK_I2C1 = 0;   // CCLK/4
    LPC_SC->PCLKSEL1 |= (1<<20);   // CCLK/1
    //PCLKSEL1_bit.PCLK_I2C1 = 2;   // CCLK/2
    //PCLKSEL1_bit.PCLK_I2C1 = 3;   // CCLK/8
 
    LPC_SC->PCONP |= (1 << 26);
    
    LPC_PINCON->PINSEL0 |= (1 << 21) | (1 << 23);   //Select SDA2 and SCL2 on PIN P0.10 and P0.11
    
    LPC_PINCON->PINMODE0 |= (1 << 21) | (1 << 23);
    
    LPC_PINCON->PINMODE_OD0 |= (1 << 10);
    LPC_PINCON->PINMODE_OD0 |= (1 << 11);  

    // I2C Takt
    // I2C Frequenz = PCLK_I2C / (I2C_I2SCLH + I2C_I2SCLL)
    // Register Wert ist Anzahl von Taktzyklen fuer high- oder low-Time
    LPC_I2C2->I2SCLH = 255/2;  // High-Time
    LPC_I2C2->I2SCLL = 255/2;  // Low-Time

    // I2C Configuration Register
    LPC_I2C2->I2CONCLR |= (1<<2);   // ACK Flag Clear           AAC
    LPC_I2C2->I2CONCLR |= (1<<3);   // Interrupt Flag Clear     SIC
    LPC_I2C2->I2CONCLR |= (1<<5);  // Start Flag Clear         STAC
  
    LPC_I2C2->I2CONSET |= (1<<6);  // I2C Enable               I2EN
}
///////////////////////////////////////////////////////////////////////////

///////////////////////////////////////////////////////////////////////////
unsigned char write_i2c (unsigned char addr, unsigned char *data, unsigned char data_cnt)
{
    unsigned char i;
    // Start ausgeben
    LPC_I2C2->I2CONSET |= (1<<5);         //STA = 1
  
    // Auf Interrupt warten (Start fertig)
    while (!((LPC_I2C2->I2CONSET >> 3) & 0x01));
    if (LPC_I2C2->I2STAT != 0x08) return 11;//FALSE;
  
    // Adresse ausgeben
    LPC_I2C2->I2DAT = addr<<1;        // Write = 8. Bit low
    // Start ruecksetzen
    LPC_I2C2->I2CONCLR |= (1 << 5);   //Start zurücksetzen
    LPC_I2C2->I2CONCLR |= (1 << 3);   //Interrupt zurücksetzen


    // Auf Interrupt warten (ACK Adresse + Write)
    // Hier bleibt der Controller hängen!!!
    while (!((LPC_I2C2->I2CONSET >> 3) & 0x01));
    if (LPC_I2C2->I2STAT != 0x18) return 22;//FALSE;

    for (i = 0; i < data_cnt; i++)
    {
        // Daten ausgeben
        LPC_I2C2->I2DAT = data[i];
        // Interrupt ruecksetzen
        LPC_I2C2->I2CONCLR |= (1 << 3);

        // Auf Interrupt warten (TX fertig + ACK)
        while (!((LPC_I2C2->I2CONSET >> 3) & 0x01));
        if (((LPC_I2C2->I2STAT >> 2) & 0x1F) != 0x28) return 33;//FALSE;
    }

    //I2C1CONCLR_bit.SIC = 1; // Interrupt ruecksetzen
    LPC_I2C2->I2CONCLR |= (1 << 3);

    // Stop ausgeben
    LPC_I2C2->I2CONSET |= (1 << 4);

    return TRUE;
}
///////////////////////////////////////////////////////////////////////////

Wie im Quellcode kommentiert bleibt der Controller in der zweiten 
while-Schleife hängen und wartet auf den Interrupt.

Kann mir jemand sagen was ich falsch gemacht habe, bzw an was das liegt?

Hier noch die main:
    char retVal = 0;
    int i = 0;
    unsigned char cmd[4];
    for(i = 0; i < 4;i++){
        cmd[i] = 0;
    }

    init_i2c ();
    
    int addr = 0x90;
    cmd[0] = 0xAC;
    cmd[1] = 0x02;
    retVal = write_i2c (addr, cmd, 2);

Vielen Dank schon mal im vorraus.

Gruß
msimmerl

Autor: Manuel Simmerl (Firma: S+S) (msimmerl)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Bitte hilft mir jemand ich muss morgen eine Arbeit darüber mit einem 
Programm abgeben und es läuft leider nicht.

Autor: T1050 (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo

ich glaube die Adresse sollte 0x48 sein. Bei 0x90 verlierst du in der 
Zeile "LPC_I2C2->I2DAT = addr<<1" sonst ein Bit (Annahme A0 bis A2 ist 
auf GND).

Autor: Manuel Simmerl (Firma: S+S) (msimmerl)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Danke für deine Antwort.
Deine Annahme ist richtig das A0 bis A2 auf GND liegen.

Hab die Adresse mal auf 0x48 geändert doch leider ändert sich nichts.
Bleibt immer noch in der Schleife hängen.

Autor: Jörg S. (joerg-s)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>Hab mir folgenden Beitrag durchgelesen und es versucht so zu machen:
Dann solltest du dir nochmal diesen Beitrag GENAU durchlesen:
Beitrag "Re: I2C Problem beim LPC1768"

Du verwendet auch read-modify-write, was wohl auch dein Problem ist.

Autor: Manuel Simmerl (Firma: S+S) (msimmerl)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Kannst du mir sagen was ich abändern muss? Steh jetzt komplett aufm 
Schlauch.

Autor: Jörg S. (joerg-s)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Kritisch ist das I2CONCLR Register das darfst du NICHT lesen!
LPC_I2C2->I2CONCLR |= (1 << 5);   //Start zurücksetzen
LPC_I2C2->I2CONCLR |= (1 << 3);   //Interrupt zurücksetzen
In dieser Anweisung liest du das I2C1CONSET Register (da ein lesender 
Zugriff auf das I2CONCLR Register auf dieses "umgeleitet" wird), fügst 
einzelne Bits hinzu und schreibst das ganze ins I2CONCLR Register.

Sollte also eher so aussehen:
LPC_I2C2->I2CONCLR = (1 << 5);   //Start zurücksetzen
LPC_I2C2->I2CONCLR = (1 << 3);   //Interrupt zurücksetzen
Damit wird nur geschreiben aber nicht gelesen.

Autor: Manuel Simmerl (Firma: S+S) (msimmerl)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Muss ich das dann überall ändern oder nur bei den beiden?

Autor: Manuel Simmerl (Firma: S+S) (msimmerl)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hab das jetzt mal abgeändert. Der Interrupt kommt wieder und das 
Programm bleibt nicht mehr in der Schleife hängen. Nur leider wird das 
Programm in der zweiten Schleife beendet da der Status 0xF8 und nicht 
0x18 ist.

Woran kann das noch liegen?

Autor: Jörg S. (joerg-s)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>Muss ich das dann überall ändern oder nur bei den beiden?
Da wo du ein read-modify-write Zugriff auf I2CONCLR machst.

>Nur leider wird das Programm in der zweiten Schleife beendet da der
>Status 0xF8 und nicht 0x18 ist.
Und was bedeutet 0xF8?

Autor: Manuel Simmerl (Firma: S+S) (msimmerl)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Folgendes steht in dem Usermanual:

This status code indicates that no relevant information is available 
because the serial interrupt flag, SI, is not yet set. This occurs 
between other states and when the I2C block
is not involved in a serial transfer.

0xF8 No relevant state
information available;
SI = 0.
No I2DAT action
No I2CON action
Wait or proceed current transfer.

Im ersten Teil steht ja das SI nicht gesetzt ist.
Das muss aber gesetzt sein, da sonst ja das Programm nicht an die Stelle 
kommen würde, da vorher das SI Flag abgefragt wird.

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.