I2C Problem beim LPC1768

Gast #1953380
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
#1953962
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.
#1955729
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
}
#1956676
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
///////////////////////////////////////////////////////////////////////////
#1956838
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?

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren