Forum: Mikrocontroller und Digitale Elektronik I2C Problem LPC1768


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


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:
1
#include "i2c.h"
2
#include "type.h"
3
4
//////////////////////////////////////////////////////////////////////////
5
void init_i2c (void)
6
{
7
    // I2C Disable
8
    LPC_I2C2->I2CONCLR |= (1<<6);
9
10
11
    // CPU Taktteiler fuer I2C1
12
    //PCLKSEL1_bit.PCLK_I2C1 = 0;   // CCLK/4
13
    LPC_SC->PCLKSEL1 |= (1<<20);   // CCLK/1
14
    //PCLKSEL1_bit.PCLK_I2C1 = 2;   // CCLK/2
15
    //PCLKSEL1_bit.PCLK_I2C1 = 3;   // CCLK/8
16
 
17
    LPC_SC->PCONP |= (1 << 26);
18
    
19
    LPC_PINCON->PINSEL0 |= (1 << 21) | (1 << 23);   //Select SDA2 and SCL2 on PIN P0.10 and P0.11
20
    
21
    LPC_PINCON->PINMODE0 |= (1 << 21) | (1 << 23);
22
    
23
    LPC_PINCON->PINMODE_OD0 |= (1 << 10);
24
    LPC_PINCON->PINMODE_OD0 |= (1 << 11);  
25
26
    // I2C Takt
27
    // I2C Frequenz = PCLK_I2C / (I2C_I2SCLH + I2C_I2SCLL)
28
    // Register Wert ist Anzahl von Taktzyklen fuer high- oder low-Time
29
    LPC_I2C2->I2SCLH = 255/2;  // High-Time
30
    LPC_I2C2->I2SCLL = 255/2;  // Low-Time
31
32
    // I2C Configuration Register
33
    LPC_I2C2->I2CONCLR |= (1<<2);   // ACK Flag Clear           AAC
34
    LPC_I2C2->I2CONCLR |= (1<<3);   // Interrupt Flag Clear     SIC
35
    LPC_I2C2->I2CONCLR |= (1<<5);  // Start Flag Clear         STAC
36
  
37
    LPC_I2C2->I2CONSET |= (1<<6);  // I2C Enable               I2EN
38
}
39
///////////////////////////////////////////////////////////////////////////
40
41
///////////////////////////////////////////////////////////////////////////
42
unsigned char write_i2c (unsigned char addr, unsigned char *data, unsigned char data_cnt)
43
{
44
    unsigned char i;
45
    // Start ausgeben
46
    LPC_I2C2->I2CONSET |= (1<<5);         //STA = 1
47
  
48
    // Auf Interrupt warten (Start fertig)
49
    while (!((LPC_I2C2->I2CONSET >> 3) & 0x01));
50
    if (LPC_I2C2->I2STAT != 0x08) return 11;//FALSE;
51
  
52
    // Adresse ausgeben
53
    LPC_I2C2->I2DAT = addr<<1;        // Write = 8. Bit low
54
    // Start ruecksetzen
55
    LPC_I2C2->I2CONCLR |= (1 << 5);   //Start zurücksetzen
56
    LPC_I2C2->I2CONCLR |= (1 << 3);   //Interrupt zurücksetzen
57
58
59
    // Auf Interrupt warten (ACK Adresse + Write)
60
    // Hier bleibt der Controller hängen!!!
61
    while (!((LPC_I2C2->I2CONSET >> 3) & 0x01));
62
    if (LPC_I2C2->I2STAT != 0x18) return 22;//FALSE;
63
64
    for (i = 0; i < data_cnt; i++)
65
    {
66
        // Daten ausgeben
67
        LPC_I2C2->I2DAT = data[i];
68
        // Interrupt ruecksetzen
69
        LPC_I2C2->I2CONCLR |= (1 << 3);
70
71
        // Auf Interrupt warten (TX fertig + ACK)
72
        while (!((LPC_I2C2->I2CONSET >> 3) & 0x01));
73
        if (((LPC_I2C2->I2STAT >> 2) & 0x1F) != 0x28) return 33;//FALSE;
74
    }
75
76
    //I2C1CONCLR_bit.SIC = 1; // Interrupt ruecksetzen
77
    LPC_I2C2->I2CONCLR |= (1 << 3);
78
79
    // Stop ausgeben
80
    LPC_I2C2->I2CONSET |= (1 << 4);
81
82
    return TRUE;
83
}
84
///////////////////////////////////////////////////////////////////////////

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:
1
    char retVal = 0;
2
    int i = 0;
3
    unsigned char cmd[4];
4
    for(i = 0; i < 4;i++){
5
        cmd[i] = 0;
6
    }
7
8
    init_i2c ();
9
    
10
    int addr = 0x90;
11
    cmd[0] = 0xAC;
12
    cmd[1] = 0x02;
13
    retVal = write_i2c (addr, cmd, 2);

Vielen Dank schon mal im vorraus.

Gruß
msimmerl

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


Lesenswert?

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

von T1050 (Gast)


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).

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


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.

von Jörg S. (joerg-s)


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.

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


Lesenswert?

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

von Jörg S. (joerg-s)


Lesenswert?

Kritisch ist das I2CONCLR Register das darfst du NICHT lesen!
1
LPC_I2C2->I2CONCLR |= (1 << 5);   //Start zurücksetzen
2
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:
1
LPC_I2C2->I2CONCLR = (1 << 5);   //Start zurücksetzen
2
LPC_I2C2->I2CONCLR = (1 << 3);   //Interrupt zurücksetzen
Damit wird nur geschreiben aber nicht gelesen.

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


Lesenswert?

Muss ich das dann überall ändern oder nur bei den beiden?

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


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?

von Jörg S. (joerg-s)


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?

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


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.

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.