I2C Problem LPC1768

OP (Firma: S+S) #2010218
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
#2012457
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.
OP (Firma: S+S) #2013943
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

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