www.mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik I2C Problem beim LPC1768


Autor: Benny (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo liebe Leute,

ich sitz seit gestern Nacht an dem Problem bei meinem LPC1768 auf dem 
mbed die I2C-Schnittstelle zu aktivieren. Mit der LED-debug-Methode komm 
ich an einer Stelle nicht sonderlich weiter.

Der Controller bleibt immer in der Warteschleife bis er auf ein 
Interrupt-Flag der Start-Anweisung wartet. Vielleicht hilft der Code ein 
wenig:

// I²C aktivieren
LPC_SC->PCONP     |=  CLKPWR_PCONP_PCI2C0;
LPC_SC->PCLKSEL0  |= (CLKPWR_PCLKSEL_CCLK_DIV_2 << CLKPWR_PCLKSEL_I2C0);

// Clock
LPC_I2C0->I2SCLH = 225 / 2;
LPC_I2C0->I2SCLL = 225 / 2;

// Startzeichen
LPC_I2C0->I2CONSET   = I2C_I2CONSET_I2EN;
LPC_I2C0->I2CONCLR   = I2C_I2CONCLR_SIC;
LPC_I2C0->I2CONSET   = I2C_I2CONSET_STA;

// Warten
while (!(LPC_I2C0->I2CONSET & I2C_I2CONSET_SI));
LPC_I2C0->I2CONCLR = I2C_I2CONCLR_STAC;


Hab das aus dem CMSIS Funktionen heraus erstellt und auf die nötigsten 
Funktionen und Registerzugriffe reduziert. Ich würde gerne auf die API 
verzichten. Mit Initialisierung über die API Funktion klappt es aber 
auch nicht sonderlich.

Ich würde mich über kleine Hilfen sehr freuen.
Vielen Dank,
Benny

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

Bewertung
0 lesenswert
nicht lesenswert
Der Pegel an den I2C leitungen ist OK (vor beginn beide high)?

Siehst du an den Pins wie die Startbedinung ausgegeben wird?


Hab selber Probleme mit dem I2C am LPC. Bei mir kommt die Startbedingung 
raus und das SI Bit wird gesetzt, danach geht aber aus irgendeinem Grund 
das I2EN Bit auf low und der Rest der Funktion bleibt hängen.

Autor: Benny (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Also sollte meine Initialisierung stimmen?

Ist es nicht so gewollt, dass man das I2EN wieder setzen muss bevor die 
Daten gesendet werden? So kenne ichs jedenfalls.

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

Bewertung
0 lesenswert
nicht lesenswert
Benny schrieb:
> Also sollte meine Initialisierung stimmen?
Ich sehe keinen Fehler, aber bei mir funktioniert der I2C ja auch nicht 
richtig ;)

> Ist es nicht so gewollt, dass man das I2EN wieder setzen muss bevor die
> Daten gesendet werden? So kenne ichs jedenfalls.
So steht das aber nicht im Manual und auch in den Beispielen wird EN nur 
am Anfang gesetzt.

Hier mal mein Code:

Init:
void init_i2c (void)
{
  // I2C Disable
  I2C1CONCLR_bit.I2ENC = 1;

  // CPU Taktteiler fuer I2C1
//  PCLKSEL1_bit.PCLK_I2C1 = 0;   // CCLK/4
  PCLKSEL1_bit.PCLK_I2C1 = 1;   // CCLK/1
//  PCLKSEL1_bit.PCLK_I2C1 = 2;   // CCLK/2
//  PCLKSEL1_bit.PCLK_I2C1 = 3;   // CCLK/8

  // I2C Takt
  // I2C Frequenz = PCLK_I2C / (I2C_I2SCLH + I2C_I2SCLL)
  // Register Wert ist Anzahl von Taktzyklen fuer high- oder low-Time
  I2C2SCLH = 70;  // High-Time
  I2C2SCLL = 70;  // Low-Time

  // Werte muessen groesser gleich 4 sein
//  if (I2C1SCLH < 4 || I2C1SCLL < 4) return;

  // I2C Configuration Register
  I2C1CONCLR_bit.AAC = 1;   // ACK Flag Clear
  I2C1CONCLR_bit.SIC = 1;   // Interrupt Flag Clear
  I2C1CONCLR_bit.STAC = 1;  // Start Flag Clear
  I2C1CONSET_bit.I2EN = 1;  // I2C Enable
}

I2C write:
unsigned char write_i2c (unsigned char addr, unsigned char *data, unsigned char data_cnt)
{
  unsigned char i;

  // Start ausgeben
  I2C1CONSET_bit.STA = 1;

  // Auf Interrupt warten (Start fertig)
  while (!I2C1CONSET_bit.SI);
  if (I2C1STAT_bit.STATUS != 0x08) return 1;//FALSE;


  // Adresse ausgeben
  I2C1DAT = addr<<1;      // Write = 8. Bit low
  // Start ruecksetzen
  I2C1CONCLR = 0x20;  // Start ruecksetzen
  I2C1CONCLR_bit.SIC = 1; // Interrupt ruecksetzen


  // Auf Interrupt warten (ACK Adresse + Write)
  while (!I2C1CONSET_bit.SI);
  if (I2C1STAT_bit.STATUS != 0x18) return 2;//FALSE;


  for (i = 0; i < data_cnt; i++)
  {
    // Datenregister fuellen
    I2C1DAT = data[i];
    I2C1CONCLR_bit.SIC = 1; // Interrupt ruecksetzen

    // Auf Interrupt warten (TX fertig + ACK)
    while (!I2C1CONSET_bit.SI);
    if (I2C1STAT_bit.STATUS != 0x28) return 3;//FALSE;
  }

  // Stop ausgeben
  I2C1CONSET_bit.STO = 1;

  return TRUE;
}

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

Bewertung
0 lesenswert
nicht lesenswert
Oh, ich glaub ich habe einen Fehler bei mir entdeckt.
Hab 2 Register für I2C2 anstatt I2C1 benutzt:
 I2C2SCLH = 70;  // High-Time
 I2C2SCLL = 70;  // Low-Time

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

Bewertung
0 lesenswert
nicht lesenswert
Funktioniert jetzt bei mir. Lag irgendwie noch an den Compiler Defines. 
Setze einige Bits jetzt einfach erst mal direkt per HEX-Wert (siehe 
Code).
Muss ich mir dann noch mal anschauen. Jedenfalls lässt sich so schon mal 
ein LM75 Sensor auslesen.

Konfiguration:
- LPC1758
- Interner Oszil. (CPU ca. 14MHz)
- I2C1
- PINSEL auf 3 (I²C)
- PINMODE auf Open Drain und Pull-Up/Down aus
- Externe Pull-Ups 4,7kOhm

//////////////////////////////////////////////////////////////////////////
void init_i2c (void)
{
  // I2C Disable
  I2C1CONCLR_bit.I2ENC = 1;


  // CPU Taktteiler fuer I2C1
//  PCLKSEL1_bit.PCLK_I2C1 = 0;   // CCLK/4
  PCLKSEL1_bit.PCLK_I2C1 = 1;   // CCLK/1
//  PCLKSEL1_bit.PCLK_I2C1 = 2;   // CCLK/2
//  PCLKSEL1_bit.PCLK_I2C1 = 3;   // CCLK/8


  // I2C Takt
  // I2C Frequenz = PCLK_I2C / (I2C_I2SCLH + I2C_I2SCLL)
  // Register Wert ist Anzahl von Taktzyklen fuer high- oder low-Time
  I2C1SCLH = 70;  // High-Time
  I2C1SCLL = 70;  // Low-Time

  // Werte muessen groesser gleich 4 sein
//  if (I2C1SCLH < 4 || I2C1SCLL < 4) return;


  // I2C Configuration Register
  I2C1CONCLR_bit.AAC = 1;   // ACK Flag Clear
  I2C1CONCLR_bit.SIC = 1;   // Interrupt Flag Clear
  I2C1CONCLR_bit.STAC = 1;  // Start Flag Clear
  I2C1CONSET_bit.I2EN = 1;  // I2C Enable
}
///////////////////////////////////////////////////////////////////////////

///////////////////////////////////////////////////////////////////////////
unsigned char write_i2c (unsigned char addr, unsigned char *data, unsigned char data_cnt)
{
  unsigned char i;


  // Start ausgeben
  I2C1CONSET_bit.STA = 1;

  // Auf Interrupt warten (Start fertig)
  while (!I2C1CONSET_bit.SI);
  if (I2C1STAT_bit.STATUS != 0x08) return 11;//FALSE;

  // Adresse ausgeben
  I2C1DAT = addr<<1;        // Write = 8. Bit low
  // Start ruecksetzen
  //I2C1CONCLR_bit.STAC = 1;  // Start ruecksetzen
  //I2C1CONCLR_bit.SIC = 1;   // Interrupt ruecksetzen
  I2C1CONCLR = 0x20;
  I2C1CONCLR = 0x08;


  // Auf Interrupt warten (ACK Adresse + Write)
  while (!I2C1CONSET_bit.SI);
  if (I2C1STAT_bit.STATUS != 0x18) return 22;//FALSE;


  for (i = 0; i < data_cnt; i++)
  {
    // Daten ausgeben
    I2C1DAT = data[i];
    //I2C1CONCLR_bit.SIC = 1; // Interrupt ruecksetzen
    I2C1CONCLR = 0x08;

    // Auf Interrupt warten (TX fertig + ACK)
    while (!I2C1CONSET_bit.SI);
    if (I2C1STAT_bit.STATUS != 0x28) return 33;//FALSE;
  }

  //I2C1CONCLR_bit.SIC = 1; // Interrupt ruecksetzen
  I2C1CONCLR = 0x08;

  // Stop ausgeben
  I2C1CONSET_bit.STO = 1;


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

///////////////////////////////////////////////////////////////////////////
unsigned char read_i2c (unsigned char addr, unsigned char *data, unsigned char data_cnt)
{
  unsigned char i;


  // Start ausgeben
  I2C1CONSET_bit.STA = 1;

  // Auf Interrupt warten (Start fertig)
  while (!I2C1CONSET_bit.SI);
  if (I2C1STAT_bit.STATUS != 0x08) return 11;//FALSE;

  // Adresse ausgeben
  I2C1DAT = (addr<<1) + 1;  // Read = 8. Bit high
  // Start ruecksetzen
  //I2C1CONCLR_bit.STAC = 1;  // Start ruecksetzen
  //I2C1CONCLR_bit.SIC = 1; // Interrupt ruecksetzen
  I2C1CONCLR = 0x20;
  I2C1CONCLR = 0x08;


  // Auf Interrupt warten (ACK Adresse + Read)
  while (!I2C1CONSET_bit.SI);
  if (I2C1STAT_bit.STATUS != 0x40) return 22;//FALSE;
  //I2C1CONCLR_bit.SIC = 1; // Interrupt ruecksetzen
  //I2C1CONCLR = 0x08;


  for (i = 0; i < data_cnt; i++)
  {
    // Immer ACK bis auf letztes Byte
    if (i+1 < data_cnt)
    {
      // ACK ausgeben
      I2C1CONSET_bit.AA = 1;
      //I2C1CONCLR_bit.SIC = 1; // Interrupt ruecksetzen
      I2C1CONCLR = 0x08;

      // Auf Interrupt warten (RX & ACK fertig)
      while (!I2C1CONSET_bit.SI);
      if (I2C1STAT_bit.STATUS != 0x50) return (33+i);//FALSE;
    }
    else
    {
      // NACK ausgeben
      //I2C1CONCLR_bit.AAC = 1;
      I2C1CONCLR = 0x04;
      //I2C1CONCLR_bit.SIC = 1; // Interrupt ruecksetzen
      I2C1CONCLR = 0x08;

      // Auf Interrupt warten (RX & NACK fertig)
      while (!I2C1CONSET_bit.SI);
      if (I2C1STAT_bit.STATUS != 0x58) return (33+i);//FALSE;
    }


    // Daten einlesen
    data[i] = I2C1DAT;
  }

  //I2C1CONCLR_bit.SIC = 1; // Interrupt ruecksetzen
  I2C1CONCLR = 0x08;

  // Stop ausgeben
  I2C1CONSET_bit.STO = 1;


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

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

Bewertung
0 lesenswert
nicht lesenswert
Jörg S. schrieb:
> Lag irgendwie noch an den Compiler Defines.
Hat sich jetzt auch aufgeklärt.
Der
I2C1CONCLR_bit.SIC = 1;
Ausdruck macht ein read-modify-write Zugriff. Und da ein Read auf das 
I2C1CONCLR Register den Wert den Registers I2C1CONSET zurück gibt, wird 
das I2EN bit (was ja im I2C1CONCLR gesetzt ist) automatisch mit gesetzt 
und somit gelöscht. Somit bleibt der I2C dann stehen (I2EN = 0).

@Benny
Vielleicht ist das bei dir auch das Problem?

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

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

ich habe das Problem das der I2C stehen bleibt.
Wie kann ich das Problem beheben?

Gruß
msimmerl

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.