Forum: Mikrocontroller und Digitale Elektronik I2C Startcondition und dann nix mehr


von A. C. (michael1988)


Lesenswert?

Hallo,
ich bin bald am verzweifeln.
Ich versuche einen I2C BUs zum laufen zu bringen, aber das einzige was 
funktionniert ist, dass die Startcondition gesendet wird.
Ich verwende den LPC2148 auf dem MBC2140 EvaluatuonBorad von Keil und 
debugge das Ganze mit Hitop5.

Pull-Ups habe ich bereits zwischen 1k und 10k variert.
Hier mein Source Code:
1
#include "LPC214x.h"                        /* LPC21xx definitions */
2
#include "type.h"
3
#include "I2C.h"
4
#include "irq.h"
5
6
char buf[]={'A','B','C','D','E'};
7
int count = 5, i = 0;
8
9
int temp = 0;
10
void i2c_init(void)
11
{
12
  PINSEL0 = 0;
13
  PINSEL1 = 0;
14
  PCONP |= (1 << I2C_POWER);
15
16
  PINSEL0 |=(1 << SCL0_PINSEL) | (1 << SDA0_PINSEL); //SDA und SCL Pins auf I2C-MOdus
17
18
  I20CONCLR |= (1 << STO) | (1 << AA) | (1 << STA) | (1 << SI);
19
  temp =   I20CONCLR;
20
21
  I20CONSET |= (1 << I2EN) ;//| (1 << STA);  //enable the I2C function.
22
  //temp = I20CONSET;
23
24
  I20SCLH = 100;
25
  temp = I20SCLH;
26
  I20SCLL = 50;
27
  temp = I20SCLL;
28
29
  VICIntSelect = 0;
30
  temp = VICIntSelect;
31
        //VICIntEnable = (1 << IE_I2C);
32
  temp = VICIntEnable;
33
  
34
  VICVectCntl0 = (DWORD)(IRQ_SLOT_EN | IE_I2C);
35
  temp = VICVectCntl0;
36
  VICVectAddr0 = (DWORD) I2C_ISR;
37
  temp = VICVectAddr0;  
38
39
  IOSET0 = 0x00000000;                // clear the ZEROs output
40
    IODIR0 = 0x00000000;               // set the output bit direction
41
}
42
43
int i2c_write()
44
{
45
  while (count--)
46
  {
47
    I20DAT = buf[i++];            //  load data into I2DAT-Register
48
    wait_for_SI();
49
    if (I20STAT != 0x28) return 0;    //  no acknowledge
50
  }
51
  return 1;
52
}
53
54
void warte(unsigned int dauer)
55
{
56
  while(dauer--);
57
}
58
59
60
void i2c_start(int addr)
61
{    
62
  VICIntEnable = (1 << IE_I2C);  
63
  I20CONSET |= (1 << STA) ;      //  set STA  
64
}
65
66
67
void wait_for_SI(void)
68
{
69
  long timeout = 400000;
70
            //  clear SI starts action
71
  while (timeout-- && !(I20CONSET & SI));    //  check SI with timeout
72
}
73
74
75
void i2c_stop(void)
76
{
77
  I20CONSET |= (1 << STO);    //  set STO
78
  I20CONCLR |=(1 << SI);      //  clear SI
79
}
80
81
void CCLK_set(void)
82
{ 
83
  PLLCFG |= (4 << MSEL); 
84
  PLLCFG |= (1 << PSEL);  //Fosc*5 =CCLK
85
  PLLFEED = 0xAA;
86
  PLLFEED = 0x55;
87
88
  PLLCON |= (1 << PLLE) | (1 << PLLC); //PLL Enable.//PLL Connect.
89
  PLLFEED = 0xAA;
90
  PLLFEED = 0x55;
91
  
92
93
  VPBDIV = 0;//00 VPB bus clock is one fourth of the processor clock.  
94
}
95
96
void I2C_ISR(void) //__irq
97
{  int temp1 = 0;
98
  temp1 = I20STAT;
99
100
  switch(temp1)
101
  {
102
    case 0x08:
103
    {  
104
      //I20DAT = 0x90; //addr
105
      temp1 = I20DAT;
106
      I20CONCLR |= (1 << SIC) | (1 << STA);
107
      break;
108
    }
109
    case 0x10:
110
    {
111
      I20DAT = 0x90;
112
      I20CONCLR |= (1 << SIC);
113
      break;
114
    }
115
    case 0x18:
116
    {
117
      if(count==0)
118
        i2c_stop();
119
      else
120
        count--;
121
      I20DAT = *(buf);
122
      I20CONCLR |= (1 << SIC);
123
      break;
124
    }
125
    case 0x20:
126
    {
127
      i2c_stop();
128
      I20CONCLR |= (1 << SIC);
129
      break;  
130
    }
131
    case 0x28:
132
    {
133
      if(count==0)
134
        i2c_stop();
135
      else
136
        count--;
137
      I20DAT = *buf;
138
      I20CONCLR |= (1 << SIC);
139
      break;
140
    }
141
    case 0x30:
142
    {
143
      i2c_stop();  
144
      I20CONCLR |= (1 << SIC);
145
      break;  
146
    }
147
  }
148
149
  VICVectAddr = 0;
150
    
151
}

Wie gesagt, Startcondition wird gesendet( erst SDA auf LOW gezogen und 
dann SCL), im I2CStatusregister ist der Wert 0x08, dann bleibt beides 
auf LOW, bis in der ISR das SI-Flag gelöscht wird.

Was komisch ist, ich hatte einmal den Jumper7(für die, die des 
MCB2140Schematics zufällig vor sich haben) noch an, als ich den I2C1 
verwendete, und dann bekamm ich ein CLocksignal auf SCL, das nicht mehr 
aufhörte, aber das SI-Flag wurde nicht merh gesetzt. Über den Jumper 7 
wird SDA über einen Kondensator mit 100nF auf Ground gezogen und über 
einen 22k Wiederstand auf HIGH. Als ich den Jumper entfernte war es 
genauso, wie als ich den I2c0 verwendet habe.

Wie bekomme ich es jetzt hin, dass nicht nur die Startcondition sondern 
auch die Slaveaddresse gesendet wird? Und dann vielleicht auch mal Daten 
gesendet werden können?

von (prx) A. K. (prx)


Lesenswert?

Sind die obligatorischen Pullups dran?

von A. C. (michael1988)


Lesenswert?

Pull-Ups habe ich bereits zwischen 1k und 10k variert.
Da aber 3mA fließen müssen,  werde ich eher die kleineren Widerstände 
verweden, wenn die Pullups nicht dran wären, könnte der IC ja nichts auf 
LOW ziehen.
Ich hatte schon den Verdacht dass ich vielleicht Bus-Arbitration 
verliere, aber gegen wen?
Ich hatte berits einen IC(den DS1624) angeschlossen ,habe jetzt aber, um 
Fehler beim DS1624 aus zu schließen, nur SDA und SCL über einen Pullup 
an High(3,3V) abgeschlossen.
Das komische ist ja, dass er die Startconidition macht und in der ISR 
die Slaveaddresse in I2DAT lädt, aber dann nichts passiert, nicht mal 
ein Clock genertiert wird. Ich schau das ganz natürlich mit dem Oszi an.

von (prx) A. K. (prx)


Lesenswert?

Unabhängig vom I2C Code kommt mir die Initialisierung vom Takt etwas 
seltsam vor. Du schaltest dich beispielsweise auf den PLL-Takt bevor die 
PLL sich überhaupt stabilisert hat (locked), wenn ich mal meinen Code 
für LPC2106 und LPC2129 als Massstab nehme.

von (prx) A. K. (prx)


Lesenswert?

In deinem Code fehlt das Hautprogramm. Aufruf von i2c_init, usw.

von (prx) A. K. (prx)


Lesenswert?

Kennst du die NXP Application Notes AN10331 (PLL) und AN10369 (u.A.I2C)?

von A. C. (michael1988)


Lesenswert?

Hallo,
ja ich habe den Teil mit der Main-Schleife in einer anderen Datei 
gehabt.
Ja die Application Notes kenne ich, habe mich so weit auch daran 
gehalten.
A.K. könnsest du deinen Code vom 2106 und 2129 eventuell mal hier rein 
stellen, würde mich mal interessieren.
Danke schon mal. Gruß Markus
1
int main (void)
2
{
3
4
  i2c_init();
5
  i2c_start(0x90);
6
  
7
  while(1)
8
  {
9
    i2c_write();    
10
  }
11
  return 0;
12
13
}

von (prx) A. K. (prx)


Angehängte Dateien:

Lesenswert?

Viel Vergnügen ;-).

Fehlt natürlich ein bischen was drum herum und ist für anderen Compiler, 
als nix für "einfach übersetzen und läuft".

Ich weiss nicht mehr wieviel ich davon getestet hatte. Ist nicht 
produktiv im Einsatz. Einfachen Basistest gab es aber.

von (prx) A. K. (prx)


Angehängte Dateien:

Lesenswert?

Für die PLL. Dieser Code ist produktiv im Einsatz.

von A. C. (michael1988)


Lesenswert?

Ok, Vielen Dank für den Code. Mir ist aber aufgefallen, dass ich den PLL 
garnicht verwende, da ich CCLK_set() garnicht aufrufe. Dann sollte der 
PLL ja defaultmäßig abgschaltet sein und CCLK = Fosc.
Habe jetzt I20SCLH auf 20 und I20SCLL auf 10 gesetzt, dann sollte mit 
einer Quarzfrequenz von 12MHZ die Bitrate 100kB betragen.
Was mir noch auffällt. Wenn ich an SCL messe erhalte ich 800ns bevor 
dieser abfällt einen kleinen Spannungseinbruch von 650mV. Könnte dass 
der Zeitpunkt sein, an dem SDA auf LOW geht?

Leider ändert sich bisher nichts daran, dass SDA und SCL auf LOW gehen 
und dann nichts mehr passiert, bis ich das SI Flag in der ISR lösche und 
dann beide wieder auf HIGH gehen.

Wäre für jeden Rat dankbar.
Gruß Markus

von A. C. (michael1988)


Lesenswert?

Ich habe jetzt mal alle für diese Problem irrelavnten Codeteile raus 
gestrichen.

Die Slaveaddresse ist erstmal irrelavant, da ich keinen Slave angehängt 
habe, sindern SDA und SCl über Pullups auf HIGH gezogen habe.

Ich hoffe jemand kann mit diesem Problem was Anfangen.
Gruß Markus
1
#include "LPC214x.h"                        /* LPC21xx definitions */
2
#include "type.h"
3
#include "I2C.h"
4
5
int main (void)
6
{
7
  i2c_init();
8
  i2c_start(0x90);
9
      
10
  return 0;
11
12
}
13
14
void i2c_init(void)
15
{
16
  PINSEL0 = 0;
17
  PINSEL1 = 0;
18
  PCONP |= (1 << I2C_POWER);
19
20
  PINSEL0 |=(1 << SCL0_PINSEL) | (1 << SDA0_PINSEL); //SDA und SCL Pins auf I2C-MOdus
21
22
  I20CONCLR |= (1 << STO) | (1 << AA) | (1 << STA) | (1 << SI);
23
  I20CONSET |= (1 << I2EN) ;//| (1 << STA);  //enable the I2C function.
24
25
  I20SCLH = 100;
26
  I20SCLL = 50;
27
28
  VICIntSelect = 0;
29
  //VICIntEnable = (1 << IE_I2C);
30
   
31
  VICVectCntl0 = (DWORD)(IRQ_SLOT_EN | IE_I2C);
32
  VICVectAddr0 = (DWORD) I2C_ISR;
33
 
34
}
35
36
void i2c_start(int addr)
37
{    
38
  VICIntEnable = (1 << IE_I2C);  
39
  I20CONSET |= (1 << STA) ;      //  set STA  
40
}
41
42
void I2C_ISR(void) 
43
{  int temp1 = 0;
44
  temp1 = I20STAT;
45
46
  switch(temp1)
47
  {
48
    case 0x08:
49
    {  
50
      I20DAT = 0x90; //addr
51
      I20CONCLR |= (1 << SIC) | (1 << STA);
52
      break;
53
    }
54
  }
55
56
  VICVectAddr = 0;
57
    
58
}

von (prx) A. K. (prx)


Lesenswert?

In
  I20CONSET |= (1 << STA);
  I20CONCLR |= (1 << SIC) | (1 << STA);
ergibt |= keinen Sinn, ganz besonders nicht bei ICONCLR.

von A. C. (michael1988)


Lesenswert?

Warum macht |= keinen Sinn?

von Mike (Gast)


Lesenswert?

Verhaspelt sich der LPC vielleicht irgendwo beim Interrupt? Wird die ISR 
angesprungen (evtl. zum Test  dort LED setzen)? Vielleicht ist es für 
den Anfang besser, erst einmal ohne Interrupt, nur mit Polling zu 
arbeiten.

Gruss
Mike

von (prx) A. K. (prx)


Lesenswert?

Markus D. schrieb:

> Warum macht |= keinen Sinn?

Erstens weil CONCLR als WO definiert ist. Als nicht lesbar.

Zweitens weil der tiefere Sinn dieser beiden Sichtweisen auf das gleiche 
Register genau darin besteht, den Lesevorgang der |= Operation 
überflüssig zu machen.

Lies nochmal nach wie die funktionieren.

von A. C. (michael1988)


Lesenswert?

Alles klar, des |= war es.
Das hatte ich nciht gewusst.
Naja wieder wa gelernt.
Vielen dank für die Hilfe!

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.