Forum: Mikrocontroller und Digitale Elektronik I2C Problem beim LPC1768


von Benny (Gast)


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:
1
// I²C aktivieren
2
LPC_SC->PCONP     |=  CLKPWR_PCONP_PCI2C0;
3
LPC_SC->PCLKSEL0  |= (CLKPWR_PCLKSEL_CCLK_DIV_2 << CLKPWR_PCLKSEL_I2C0);
4
5
// Clock
6
LPC_I2C0->I2SCLH = 225 / 2;
7
LPC_I2C0->I2SCLL = 225 / 2;
8
9
// Startzeichen
10
LPC_I2C0->I2CONSET   = I2C_I2CONSET_I2EN;
11
LPC_I2C0->I2CONCLR   = I2C_I2CONCLR_SIC;
12
LPC_I2C0->I2CONSET   = I2C_I2CONSET_STA;
13
14
// Warten
15
while (!(LPC_I2C0->I2CONSET & I2C_I2CONSET_SI));
16
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

von Jörg S. (joerg-s)


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.

von Benny (Gast)


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.

von Jörg S. (joerg-s)


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:
1
void init_i2c (void)
2
{
3
  // I2C Disable
4
  I2C1CONCLR_bit.I2ENC = 1;
5
6
  // CPU Taktteiler fuer I2C1
7
//  PCLKSEL1_bit.PCLK_I2C1 = 0;   // CCLK/4
8
  PCLKSEL1_bit.PCLK_I2C1 = 1;   // CCLK/1
9
//  PCLKSEL1_bit.PCLK_I2C1 = 2;   // CCLK/2
10
//  PCLKSEL1_bit.PCLK_I2C1 = 3;   // CCLK/8
11
12
  // I2C Takt
13
  // I2C Frequenz = PCLK_I2C / (I2C_I2SCLH + I2C_I2SCLL)
14
  // Register Wert ist Anzahl von Taktzyklen fuer high- oder low-Time
15
  I2C2SCLH = 70;  // High-Time
16
  I2C2SCLL = 70;  // Low-Time
17
18
  // Werte muessen groesser gleich 4 sein
19
//  if (I2C1SCLH < 4 || I2C1SCLL < 4) return;
20
21
  // I2C Configuration Register
22
  I2C1CONCLR_bit.AAC = 1;   // ACK Flag Clear
23
  I2C1CONCLR_bit.SIC = 1;   // Interrupt Flag Clear
24
  I2C1CONCLR_bit.STAC = 1;  // Start Flag Clear
25
  I2C1CONSET_bit.I2EN = 1;  // I2C Enable
26
}

I2C write:
1
unsigned char write_i2c (unsigned char addr, unsigned char *data, unsigned char data_cnt)
2
{
3
  unsigned char i;
4
5
  // Start ausgeben
6
  I2C1CONSET_bit.STA = 1;
7
8
  // Auf Interrupt warten (Start fertig)
9
  while (!I2C1CONSET_bit.SI);
10
  if (I2C1STAT_bit.STATUS != 0x08) return 1;//FALSE;
11
12
13
  // Adresse ausgeben
14
  I2C1DAT = addr<<1;      // Write = 8. Bit low
15
  // Start ruecksetzen
16
  I2C1CONCLR = 0x20;  // Start ruecksetzen
17
  I2C1CONCLR_bit.SIC = 1; // Interrupt ruecksetzen
18
19
20
  // Auf Interrupt warten (ACK Adresse + Write)
21
  while (!I2C1CONSET_bit.SI);
22
  if (I2C1STAT_bit.STATUS != 0x18) return 2;//FALSE;
23
24
25
  for (i = 0; i < data_cnt; i++)
26
  {
27
    // Datenregister fuellen
28
    I2C1DAT = data[i];
29
    I2C1CONCLR_bit.SIC = 1; // Interrupt ruecksetzen
30
31
    // Auf Interrupt warten (TX fertig + ACK)
32
    while (!I2C1CONSET_bit.SI);
33
    if (I2C1STAT_bit.STATUS != 0x28) return 3;//FALSE;
34
  }
35
36
  // Stop ausgeben
37
  I2C1CONSET_bit.STO = 1;
38
39
  return TRUE;
40
}

von Jörg S. (joerg-s)


Lesenswert?

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

von Jörg S. (joerg-s)


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

1
//////////////////////////////////////////////////////////////////////////
2
void init_i2c (void)
3
{
4
  // I2C Disable
5
  I2C1CONCLR_bit.I2ENC = 1;
6
7
8
  // CPU Taktteiler fuer I2C1
9
//  PCLKSEL1_bit.PCLK_I2C1 = 0;   // CCLK/4
10
  PCLKSEL1_bit.PCLK_I2C1 = 1;   // CCLK/1
11
//  PCLKSEL1_bit.PCLK_I2C1 = 2;   // CCLK/2
12
//  PCLKSEL1_bit.PCLK_I2C1 = 3;   // CCLK/8
13
14
15
  // I2C Takt
16
  // I2C Frequenz = PCLK_I2C / (I2C_I2SCLH + I2C_I2SCLL)
17
  // Register Wert ist Anzahl von Taktzyklen fuer high- oder low-Time
18
  I2C1SCLH = 70;  // High-Time
19
  I2C1SCLL = 70;  // Low-Time
20
21
  // Werte muessen groesser gleich 4 sein
22
//  if (I2C1SCLH < 4 || I2C1SCLL < 4) return;
23
24
25
  // I2C Configuration Register
26
  I2C1CONCLR_bit.AAC = 1;   // ACK Flag Clear
27
  I2C1CONCLR_bit.SIC = 1;   // Interrupt Flag Clear
28
  I2C1CONCLR_bit.STAC = 1;  // Start Flag Clear
29
  I2C1CONSET_bit.I2EN = 1;  // I2C Enable
30
}
31
///////////////////////////////////////////////////////////////////////////
32
33
///////////////////////////////////////////////////////////////////////////
34
unsigned char write_i2c (unsigned char addr, unsigned char *data, unsigned char data_cnt)
35
{
36
  unsigned char i;
37
38
39
  // Start ausgeben
40
  I2C1CONSET_bit.STA = 1;
41
42
  // Auf Interrupt warten (Start fertig)
43
  while (!I2C1CONSET_bit.SI);
44
  if (I2C1STAT_bit.STATUS != 0x08) return 11;//FALSE;
45
46
  // Adresse ausgeben
47
  I2C1DAT = addr<<1;        // Write = 8. Bit low
48
  // Start ruecksetzen
49
  //I2C1CONCLR_bit.STAC = 1;  // Start ruecksetzen
50
  //I2C1CONCLR_bit.SIC = 1;   // Interrupt ruecksetzen
51
  I2C1CONCLR = 0x20;
52
  I2C1CONCLR = 0x08;
53
54
55
  // Auf Interrupt warten (ACK Adresse + Write)
56
  while (!I2C1CONSET_bit.SI);
57
  if (I2C1STAT_bit.STATUS != 0x18) return 22;//FALSE;
58
59
60
  for (i = 0; i < data_cnt; i++)
61
  {
62
    // Daten ausgeben
63
    I2C1DAT = data[i];
64
    //I2C1CONCLR_bit.SIC = 1; // Interrupt ruecksetzen
65
    I2C1CONCLR = 0x08;
66
67
    // Auf Interrupt warten (TX fertig + ACK)
68
    while (!I2C1CONSET_bit.SI);
69
    if (I2C1STAT_bit.STATUS != 0x28) return 33;//FALSE;
70
  }
71
72
  //I2C1CONCLR_bit.SIC = 1; // Interrupt ruecksetzen
73
  I2C1CONCLR = 0x08;
74
75
  // Stop ausgeben
76
  I2C1CONSET_bit.STO = 1;
77
78
79
  return TRUE;
80
}
81
///////////////////////////////////////////////////////////////////////////
82
83
///////////////////////////////////////////////////////////////////////////
84
unsigned char read_i2c (unsigned char addr, unsigned char *data, unsigned char data_cnt)
85
{
86
  unsigned char i;
87
88
89
  // Start ausgeben
90
  I2C1CONSET_bit.STA = 1;
91
92
  // Auf Interrupt warten (Start fertig)
93
  while (!I2C1CONSET_bit.SI);
94
  if (I2C1STAT_bit.STATUS != 0x08) return 11;//FALSE;
95
96
  // Adresse ausgeben
97
  I2C1DAT = (addr<<1) + 1;  // Read = 8. Bit high
98
  // Start ruecksetzen
99
  //I2C1CONCLR_bit.STAC = 1;  // Start ruecksetzen
100
  //I2C1CONCLR_bit.SIC = 1; // Interrupt ruecksetzen
101
  I2C1CONCLR = 0x20;
102
  I2C1CONCLR = 0x08;
103
104
105
  // Auf Interrupt warten (ACK Adresse + Read)
106
  while (!I2C1CONSET_bit.SI);
107
  if (I2C1STAT_bit.STATUS != 0x40) return 22;//FALSE;
108
  //I2C1CONCLR_bit.SIC = 1; // Interrupt ruecksetzen
109
  //I2C1CONCLR = 0x08;
110
111
112
  for (i = 0; i < data_cnt; i++)
113
  {
114
    // Immer ACK bis auf letztes Byte
115
    if (i+1 < data_cnt)
116
    {
117
      // ACK ausgeben
118
      I2C1CONSET_bit.AA = 1;
119
      //I2C1CONCLR_bit.SIC = 1; // Interrupt ruecksetzen
120
      I2C1CONCLR = 0x08;
121
122
      // Auf Interrupt warten (RX & ACK fertig)
123
      while (!I2C1CONSET_bit.SI);
124
      if (I2C1STAT_bit.STATUS != 0x50) return (33+i);//FALSE;
125
    }
126
    else
127
    {
128
      // NACK ausgeben
129
      //I2C1CONCLR_bit.AAC = 1;
130
      I2C1CONCLR = 0x04;
131
      //I2C1CONCLR_bit.SIC = 1; // Interrupt ruecksetzen
132
      I2C1CONCLR = 0x08;
133
134
      // Auf Interrupt warten (RX & NACK fertig)
135
      while (!I2C1CONSET_bit.SI);
136
      if (I2C1STAT_bit.STATUS != 0x58) return (33+i);//FALSE;
137
    }
138
139
140
    // Daten einlesen
141
    data[i] = I2C1DAT;
142
  }
143
144
  //I2C1CONCLR_bit.SIC = 1; // Interrupt ruecksetzen
145
  I2C1CONCLR = 0x08;
146
147
  // Stop ausgeben
148
  I2C1CONSET_bit.STO = 1;
149
150
151
  return TRUE;
152
}
153
///////////////////////////////////////////////////////////////////////////

von Jörg S. (joerg-s)


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?

von Manuel S. (Firma: S+S) (msimmerl)


Lesenswert?

Hallo,

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

Gruß
msimmerl

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.