Hallo,
Ich arbeite an einer Uhr, dabei muss ich Daten von einem RTC IC
(RV3029C2) über I2C auf den PIC18F26K22 holen und umgekehrt.
Das Problem ist, der PIC bleibt irgendwo in meiner Read Funktion hängen,
ich kann mir aber nicht erklären, warum.
Mit einem Logic Analyzer habe ich den Datenstrom ausgelesen und
festgestellt, dass die Antwort vom RTC kommt, trotzdem hängt sich der
PIC auf.
Ich kann Daten z.B. ins Minutenregister schreiben und mit der Read
Funktion bekomme ich den gleichen Wert zurück (Mit Logic Analyzer
festgestellt).
Nach dieser Codezeile werden jedoch keine Anweisungen mehr ausgeführt.
Hier mal die betreffenden Codezeilen:
1
voidmain(void)
2
{
3
...
4
RTC_SetTime(10,27);//Wird ausgeführt
5
unsignedshortminutes=RTC_ReadMinutes();//FEHLER IRGENDWO HIER
6
Display_ClearBuffer();//Wird nicht mehr ausgeführt
7
Display_Update();
8
}
9
10
charRTC_ReadMinutes(void)
11
{
12
I2C_Master_Start();//Send Start condition
13
I2C_Master_WriteByte(0b10101100);//Write RTC 7-Bit address + Write bit
14
I2C_Master_WriteByte(0x09);//Write address of Minutes Register
15
I2C_Master_Stop();
16
I2C_Master_Start();//Re-establish connection
17
I2C_Master_WriteByte(0b10101101);//Write RTC 7-Bit address + Read bit
18
charminBCD=I2C_Master_Read(0);//Read the Minute register
19
I2C_Master_Stop();//Convert BCD to DEC format
20
charminDEC=(minBCD&0x0F)+((minBCD>>4)*10);
21
returnminDEC;
22
}
23
24
unsignedshortI2C_Master_Read(unsignedshorta)
25
{
26
unsignedshorttemp;
27
I2C_Wait_for_Idle();
28
SSP1CON2bits.RCEN=1;
29
I2C_Wait_for_Idle();
30
temp=SSPBUF;//Read data from SSPBUF
31
I2C_Wait_for_Idle();
32
SSP1CON2bits.ACKDT=(a)?0:1;//Acknowledge bit, a = 1: ACK, a = 0: NACK
Luca schrieb:> Das Problem ist, der PIC bleibt irgendwo in meiner Read Funktion hängen,> ich kann mir aber nicht erklären, warum.
Wo genau? Setze dir doch mal Flags rein sodass zumindest entsprechende
Portpins geschaltet werden, dann könntest du sehen wo genau es hängen
bleibt (mit simplen MM den entsprechenden Portpin überwachen).
Möglicherweise kommt kein NACK/ACK beim Lesen vom Device und dein PIC
bleibt deshalb hängen eben weil er auf NACK/ACK vom Slave wartet.
Ich hab mir in meinem I2C-Lib für den AVR eine 8 Bit Status-Variable
generiert und meine I2C-Funktionen haben nur ein gewisses Zeitfenster
(in meinem Fall die dopplte Zeit die es eigentlich brauchen sollte) bis
sie abgearbeitet sein müssen. Wenn da also bei mir dann was nicht klappt
brauche ich nur die Status-Variable auslesen und sehe so, wo es hängen
geblieben ist.
Du hast vermutlich ein PICkit und MPLABX?
Setz einen Breakpoint zu Beginn deiner Read-Fuktion, und step das durch.
Dann siehst du schnell, an welcher Codezeile es klemmt.
Wahrscheinlich wartet der PIC auf irgendein Bit in einem Register das
nicht kommt.
Den Wert des Flags kannst du im Watch anschauen. Das Flag kannst du im
Datenblatt nachkucken. Oder du schreibst es uns hier.
Wenn du kein PICkit hast, kannst du dir mit GPIOs helfen. Du setzt
bestimmte GPIOs zu bestimmten Zeiten, dann kannst du sogar nur mit einer
LED + Vorwiderstand genau kucken, wo es hängt.
Eine Mögliche Stelle wäre eine Codezeile wie diese:
I2C_Wait_for_Idle();
M. K. schrieb:> mit simplen MM den entsprechenden Portpin überwachen
Danke fuer die Antwort.
Was meinst du mit MM?
Du setzt also dann nach und nach in der I2C Funktion diese 8 Bits, damit
du weisst, in welchem Teil sie haengen geblieben ist?
Genau, PicKit3 und MPLABX. Habe ich eben gestern auch versucht, aber
irgendwie hats nicht geklappt mit den Breakpoints, heisst dann einfach
Running.. Aber es haelt nicht an.
Liegt vielleicht daran, dass es ein China PicKit ist ;).
Das mit I/Os klingt aber auch gut, werd ich mal probieren. Habe zwar den
Fehler gemacht, dass ich kein einziges Status LED an meiner Leiterplatte
eingeplant habe, mach ich nie mehr.
Muss ich halt irgendwo eines dranfriemeln ^^.
Melde mich dann wieder.
Habe das Problem gefunden, den Grund zwar nicht wirklich, aber zumindest
funktioniert es jetzt.
Habe per Zufall nur bei einer Funktion (ReadMinutes())) ein NACK
gesendet vor der Stop Condition.
Bei den anderen wie ReadHours, ReadDay etc. habe ich jeweils ein ACK
gesendet.
Wenn ich nach diesen die Funktion TimeIsValid() aufgerufen habe, blieb
die Funktion nach dem Senden der Stop Condition hängen. (??).
Ich weiss zwar aus dem Datenblatt, dass das ACK eigentlich dafür
vorgesehen ist, das Register zu inkrementieren, wenn man mehrere Bytes
lesen will. Aber warum das System beim nächsten Leseversuch nach der
Stop Condition hängen bleibt wenn zuvor ein ACK gesendet wurde, ist mir
trotzdem schleierhaft.
Habe nirgens gelesen, dass ein Acknowledge nicht erlaubt wäre, obwohl
man nur ein Byte lesen will.
Hier noch ein Ausschnitt der betreffenden Funktionen, falls es jemanden
interessiert:
1
charRTC_ReadMinutes(void)
2
{
3
I2C_Master_Start();//Send Start condition
4
I2C_Master_WriteByte(0b10101100);//Write RTC 7-Bit address + Write bit
5
I2C_Master_WriteByte(0x09);//Write address of Minutes Register
6
I2C_Master_Stop();
7
I2C_Master_Start();//Re-establish connection
8
I2C_Master_WriteByte(0b10101101);//Write RTC 7-Bit address + Read bit
9
charminBCD=I2C_Master_Read(0);//Read the Minute register
10
I2C_Master_Stop();//Convert BCD to DEC format
11
charminDEC=(minBCD&0x0F)+((minBCD>>4)*10);
12
returnminDEC;
13
}
14
15
unsignedshortI2C_Master_Read(unsignedshorta)
16
{
17
unsignedshorttemp;
18
I2C_Wait_for_Idle();
19
SSP1CON2bits.RCEN=1;
20
I2C_Wait_for_Idle();
21
temp=SSPBUF;//Read data from SSPBUF
22
I2C_Wait_for_Idle();
23
SSP1CON2bits.ACKDT=(a)?0:1;//Acknowledge bit, a = 1: ACK, a = 0: NACK
24
SSP1CON2bits.ACKEN=1;//Acknowledge sequence
25
returntemp;
26
}
27
28
charRTC_TimeIsValid(void)
29
{
30
I2C_Master_Start();
31
I2C_Master_WriteByte(0b10101100);//Write RTC 7-Bit address + Write bit
32
I2C_Master_WriteByte(0x03);//Write address of Control Status Register
33
I2C_Master_Stop();
34
I2C_Master_Start();//Re-establish the Connection
35
I2C_Master_WriteByte(0b10101101);//Write RTC 7-Bit address + Read bit
36
charcontrolStatus=I2C_Master_Read(0);//Read Control Status Register, Send ACK
37
I2C_Master_Stop();
38
chari=(controlStatus&0b00111000)>0?0:1;//Time is invalid when PON, SR or VLOW2 bits are set
39
40
//PON: Power on
41
returni;//SR: System Reset or Self Recovery Reset //VLOW2: Voltage drop below 1.3V detected
42
}
Jedenfalls geht es jetzt. Bis jetzt :P
Danke für alle Inputs!
Luca schrieb:> Habe per Zufall nur bei einer Funktion (ReadMinutes())) ein NACK> gesendet vor der Stop Condition.
Das ist korrekt und entspricht der I2C-Spezifikation.
Beim Lesen muß nach dem letzten Byte ein NACK erfolgen, um dem Slave zu
sagen, daß er nicht weiter senden darf. Ansonsten kollidiert das nächste
Bit mit dem STOP. Je nach Wert des nächsten Bits schlägt das STOP dann
fehl oder nicht.
In der Regel taktet ein I2C-Master alle 9 Bits am Stück, d.h. man muß
bereits vor dem letzen Byte einstellen, daß es mit einem NACK
abgeschlossen wird.
Hier mal ein Auszug aus meiner Lesefunktion:
Luca schrieb:> Was meinst du mit MM?
Multimeter.
Luca schrieb:> Du setzt also dann nach und nach in der I2C Funktion diese 8 Bits, damit> du weisst, in welchem Teil sie haengen geblieben ist?
Richtig.
Luca schrieb:> Genau, PicKit3 und MPLABX. Habe ich eben gestern auch versucht,> aber> irgendwie hats nicht geklappt mit den Breakpoints, heisst dann einfach> Running.. Aber es haelt nicht an.
Ich würde es mal probieren. Auch ein China-PICkit muss debuggen können.
Das Problem wird sein, dass du den PIC anhalten musst, damit er den
Breakpoint akzeptiert. Das ist eine Beschränkung des PICkits.
Du kannst dazu den Breakpoint reintun, dann auf "Pause" (eventuell
"Reset") und dann wieder weiter.
Du kannst noch viele andere nützliche Sachen mit deinem PICkit
anstellen:
- Codelaufzeiten zwischen zwei Breakpoints mit der "Stopwatch" messen
- Variablen manipulieren, wenn du im Breakpoint stehst
- IOs umschalten oder Ports umkonfigurieren
- Speicher auslesen und manipulieren
Und so weiter.
Ich kann nur empfehlen, dass sich die Beschäftigung damit lohnt. Sobald
du damit Übung hast, ist es extrem nützlich, den Code Zeile für Zeile
abarbeiten und dabei die Variablen anschauen zu können.
Das ist DER Killervorteil des PICkits gegenüber den billigen
AVR-Programmern.