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
charbuf[]={'A','B','C','D','E'};
7
intcount=5,i=0;
8
9
inttemp=0;
10
voidi2c_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
inti2c_write()
44
{
45
while(count--)
46
{
47
I20DAT=buf[i++];// load data into I2DAT-Register
48
wait_for_SI();
49
if(I20STAT!=0x28)return0;// no acknowledge
50
}
51
return1;
52
}
53
54
voidwarte(unsignedintdauer)
55
{
56
while(dauer--);
57
}
58
59
60
voidi2c_start(intaddr)
61
{
62
VICIntEnable=(1<<IE_I2C);
63
I20CONSET|=(1<<STA);// set STA
64
}
65
66
67
voidwait_for_SI(void)
68
{
69
longtimeout=400000;
70
// clear SI starts action
71
while(timeout--&&!(I20CONSET&SI));// check SI with timeout
VPBDIV=0;//00 VPB bus clock is one fourth of the processor clock.
94
}
95
96
voidI2C_ISR(void)//__irq
97
{inttemp1=0;
98
temp1=I20STAT;
99
100
switch(temp1)
101
{
102
case0x08:
103
{
104
//I20DAT = 0x90; //addr
105
temp1=I20DAT;
106
I20CONCLR|=(1<<SIC)|(1<<STA);
107
break;
108
}
109
case0x10:
110
{
111
I20DAT=0x90;
112
I20CONCLR|=(1<<SIC);
113
break;
114
}
115
case0x18:
116
{
117
if(count==0)
118
i2c_stop();
119
else
120
count--;
121
I20DAT=*(buf);
122
I20CONCLR|=(1<<SIC);
123
break;
124
}
125
case0x20:
126
{
127
i2c_stop();
128
I20CONCLR|=(1<<SIC);
129
break;
130
}
131
case0x28:
132
{
133
if(count==0)
134
i2c_stop();
135
else
136
count--;
137
I20DAT=*buf;
138
I20CONCLR|=(1<<SIC);
139
break;
140
}
141
case0x30:
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?
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.
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.
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
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.
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
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
intmain(void)
6
{
7
i2c_init();
8
i2c_start(0x90);
9
10
return0;
11
12
}
13
14
voidi2c_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.
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
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.