Hallo zusammen,
erstmal möchte ich loswerden wie oft mir dieses Forum schon bei
Problemen geholfen hat, vielen Dank dafür.
Zu meinem Problem:
Ich möchte regelmäßig ca. 25 Integer Werte von einem PIC16F707 an ein
Arduino Mega 2560 über I2C versenden.
Als Compiler verwende ich den Hi-tech C, dort ist auch eine Art i2c
Bibliothek mitgeliefert (Soft i2c).
der Code zum senden sieht folgendermaßen aus:
1
bitSendResults(char*data,charAddress)
2
{
3
4
for(unsignedchari=0;i<PinCount;i++){
5
i2c_WriteTo(Address);
6
i2c_PutByte(data[2*i]);
7
i2c_PutByte(data[2*i+1]);
8
i2c_Stop();
9
}
10
i2c_WriteTo(Address);
11
i2c_PutByte(SeparatorLine);
12
i2c_PutByte(SeparatorLine);
13
i2c_Stop();
14
//return Error;
15
}
Das Arduino wertet dies folgendermaßen aus:
1
voidreceiveEvent(inthowMany)
2
{
3
while(Wire.available())
4
{
5
b[0]=Wire.read();
6
b[1]=Wire.read();
7
p=b[1]*256+b[0];
8
if(p==0){Serial.println("CR");}
9
else{
10
Serial.print(p);
11
Serial.print("---");
12
}
13
}
14
}
Das ganze funktioniert auch ganz gut soweit, in dem angehängten Auszug
aus dem Serial Monitor sieht man schön strukturierte Werte. Allerdings
sieht man auch, das hin und wieder zwei Integer Werte (wenn dann Zwei
hintereinander) unterwegs verschütt gehen. Dies geschieht scheinbar
zufällig und ich bin mittlerweile echt ratlos. Habe auch schon
verschiedene Pullups verwendet, Oszi drangehängt etc.. die Pegel
scheinen in Ordnung.
Hat von euch schonmal jemand solche Erfahrungen gemacht oder weiß einen
Rat?
Vielen Dank schonmal.
Liebe Grüße,
Deniz
Hast du schon das Serial.print() überprüft?
Möglicherweise blockiert der PC den Arduino, I2C Eingabepuffer läuft
über und der Arduino wirft die korrekt eingelesenen Zeichen weg. Oder
umgekehrt - das receiveEvent() wird ausgeführt, aber bei überlaufendem
Ausgabepuffer wirft das Serial.print() die Ausgabe weg.
Bau den Empfänger so um, dass er nen Interrupt auslöst und das in nen
FIFO schreibt.
Da geht dann so schnell nix verlorn.
Achja und progg den AVR lieber in C und nicht diesem Failduino Müll ;)
Ansonsten hier ne I2C Slave lib, damit verhält sich der AVR wie nen
EEPROM und jeder Integer kommt an ne bestimmte Adresse:
http://www.jtronics.de/avr-projekte/library-i2c-twi-slave.html
Hi Denniz
Aus den Logs kann man natürlich nicht erkennen, ob der Sender oder der
Empfänger die Daten verbummelt. Da wirst Du etwas rumdebuggen müssen.
Kannst Du einen Pin am PIC als Output schalten (auf '0' initialisieren)
und als ersten Befehl in SendResults() den Pin auf '1' und als letzten
Befehl in SendResults() wieder auf '0' setzen ?
Am Scope kannst Du dann über die High-Time des Pins prüfen, ob immer die
gleiche Byteanzahl geschickt wurde.
Kein Name schrieb:> Hast du schon das Serial.print() überprüft?
Das hätte ich auch im Verdacht. Aber laut arduino.cc ist das nicht
blockend. Und ein Fifoüberlauf, wo ordentlich immer ASCII Ausgaben von
genau zwei Bytes fehlen ?
Wenn man das Serial.print() rausnimmt sieht man aber garnix mehr :/
Eine Möglichkeit wäre, vom PIC aus Pakete mit den Bytes 0x01 .. 0x19,
gefolgt von 0x00 zu schicken. Die Bytes addiert der Arduino zusammen und
gibt am Ende des Pakets die Summe aus.
Dann sind keine Serial.Print() mehr während eines Pakets am werkeln. Mit
einer hinreichend grossen Pause ZWISCHEN den Paketen sollte das zum
testen hinhauen.
Martin Wende schrieb:> Bau den Empfänger so um, dass er nen Interrupt auslöst und das in nen> FIFO schreibt.
Wenn es der Arduino ist, dann ist das eine sehr gute Idee.
>> Achja und progg den AVR lieber in C und nicht diesem Failduino Müll ;)
Solltest Du für diese Idee nicht erst mal wissen, warum er es so macht ?
Viele Grüße & Viel Erfolg beim Debuggen
Andreas
Deniz schrieb:> for(unsigned char i=0; i < PinCount; i++) {> i2c_WriteTo(Address);> i2c_PutByte(data[2*i]);> i2c_PutByte(data[2*i+1]);> i2c_Stop();
Du kannst nicht einfach so ins Blaue hinein schreiben. Nach jedem Byte
mußt Du erst prüfen, ob Du auch ein ACK empfangen hast.
Und der Master muß natürlich das Clock Stretching unterstützen, siehe:
http://www.i2c-bus.org/clock-generation-stretching-arbitration/
Peter
Peter Dannegger schrieb:> Und der Master muß natürlich das Clock Stretching unterstützen, siehe:>> http://www.i2c-bus.org/clock-generation-stretching...
Und der Peter muss natürlich noch lernen, die richtigen Dokumente zu
lesen (just kidding ;-)
Clock stretching ist ein optionales Feature.
"UM10204 - I2C-bus specification and user manual - Rev. 5 — 9 October
2012", Page 8, Table 2.
(Und die sollten es wissen - die haben I2C erfunden. Bzw. damals war es
ja noch Philips)
Und damit der Peter nicht lange suchen muss:
http://www.nxp.com/documents/user_manual/UM10204.pdf
Viele Grüße
Andreas
Andreas H. schrieb:> Und der Peter muss natürlich noch lernen, die richtigen Dokumente zu> lesen (just kidding ;-)
Nö.
Das richtige Dokument ist das AVR Datenblatt!
Als Slave zieht der AVR solange SCL auf low, bis der Interrupt behandelt
ist.
Und wenn der Master nicht darauf wartet, dann geht es eben gegen die
Wand.
Und das machen nicht nur die AVRs so, sondern auch andere MCs (z.B.
8051, ARM).
Nur bei den dummen I2C-Slaves (ADC, EEPROM, IO-Port usw.) ist der SCL
nur ein Eingang.
Peter
Vielen Dank für die Antworten.
Peter Dannegger schrieb:> Du kannst nicht einfach so ins Blaue hinein schreiben. Nach jedem Byte> mußt Du erst prüfen, ob Du auch ein ACK empfangen hast.
Hab ich mittlerweile umgesetzt, leider ohne erfolg:
1
for(unsignedchari=0;i<PinCount;i++){
2
i2c_WriteTo(Address);
3
while(-1==i2c_PutByte(data[2*i])){};
4
while(-1==i2c_PutByte(data[2*i+1])){};
5
//i2c_PutByte(SeparatorNumber);
6
i2c_Stop();
7
}
Peter schrieb:> Was sind denn das für Werte in Deinem Log? Wie korrespondieren die mit> den tatsächlichen übertragenen 9 Bit auf der Leitung?
Das sind Kapazitätsmesswerte eines Touchpanels (Anzahl Ladezyklen) in
Integer. Vor dem Senden werden sie in Highbyte und Lowbyte geteilt und
nach dem Empfang wieder zusammengesetzt - das sind die Werte im Log.
Andreas H. schrieb:> Und ein Fifoüberlauf, wo ordentlich immer ASCII Ausgaben von> genau zwei Bytes fehlen ?
Korrektur: Es fehlen immer genau zwei Integer Werte, sprich vier Bytes.
Andreas H. schrieb:> Wenn man das Serial.print() rausnimmt sieht man aber garnix mehr :/> Eine Möglichkeit wäre, vom PIC aus Pakete mit den Bytes 0x01 .. 0x19,> gefolgt von 0x00 zu schicken. Die Bytes addiert der Arduino zusammen und> gibt am Ende des Pakets die Summe aus.> Dann sind keine Serial.Print() mehr während eines Pakets am werkeln. Mit> einer hinreichend grossen Pause ZWISCHEN den Paketen sollte das zum> testen hinhauen.
Das werde ich als erstes ausprobieren.
Martin Wende schrieb:> Ansonsten hier ne I2C Slave lib, damit verhält sich der AVR wie nen> EEPROM und jeder Integer kommt an ne bestimmte Adresse:> http://www.jtronics.de/avr-projekte/library-i2c-tw...
Und das als zweites. Anschließend werde ich hier berichten wie es
ausgegangen ist. Vielen Dank!
So ich habs ausprobiert und es scheint nicht am Empfänger zu liegen:
Sendercode:
1
for(unsignedchari=1;i<PinCount;i=i+2){
2
i2c_WriteTo(Address);
3
while(-1==i2c_PutByte(i/*data[2*i]*/)){};
4
while(-1==i2c_PutByte(i+1/*data[2*i+1]*/)){};
5
//i2c_PutByte(SeparatorNumber);
6
i2c_Stop();
7
}
Empfängercode:
1
while(Wire.available())
2
{
3
MyByte=Wire.read();
4
if(MyByte==0){
5
Serial.println(i);
6
i=0;
7
}
8
else{i=i+Wire.read();}
Es ist wieder ein Auszug aus dem Serial Monitor angehängt. Hier kann man
schön sehen, dass wieder nach genau dem gleichen Schema Bytes verloren
gehen.
Auch das Trennzeichen (0x00) geht ab und zu verloren, daher die Werte
größer 156.
So langsam wird das ganze echt mysteriös. Einen Hardwarefehler kann man
auch fast ausschließen, da ein solcher Fehler (evtl. falsche Pull Ups)
keine so zufälligen aber doch gleichmäßigen Symptome erzeugen würde.
Liegt es evtl. an der Sender Software, sprich der Hi-tech c lib für i2c?
>Es ist wieder ein Auszug aus dem Serial Monitor angehängt. Hier kann man>schön sehen, dass wieder nach genau dem gleichen Schema Bytes verloren>gehen.
Irgendwann spielt Dein Slave nicht mit, warum kann man nur sagen, wenn
man die Pegel sieht.
Probier mal etwas langsamer zu senden - mach Warteschleifen dazwischen.
Was passiert dann?
Hallo,
Andreas H. schrieb:> Da ich den Fehler grade beim Basteln hatte: Deine Watchdogs hast Du> disabled ?
Ja habe ich, weiß noch nicht genau was ich damit anfangen soll. Soweit
ich weiß sind die zur Laufzeitüberwachung? Inwiefern können die Fehler
verursachen?
Peter schrieb:> Probier mal etwas langsamer zu senden - mach Warteschleifen dazwischen.> Was passiert dann?
Danke, werd ich gleich mal versuchen.
LG,
Deniz
Deniz schrieb:> Hab ich mittlerweile umgesetzt, leider ohne erfolg:for(unsigned char i=0; i <
PinCount; i++) {
> i2c_WriteTo(Address);> while (-1 == i2c_PutByte(data[2*i])){};> while (-1 == i2c_PutByte(data[2*i+1])){};> //i2c_PutByte(SeparatorNumber);> i2c_Stop();> }
Das ist kein Test auf ACK, sonst hängst Du ja in der While-Schleife
fest. Also wird -1 nie auftreten.
NACK heißt, niemand ist auf dem Bus. Nach dem NACK muß daher ein STOP
gesendet werden und dann wieder START, Adresse usw.
Das ACK muß auch nach der Adresse geprüft werden.
Lies Dir mal die Beschreibung des I2C in Ruhe durch.
Peter
Deniz schrieb:> Ja habe ich, weiß noch nicht genau was ich damit anfangen soll. Soweit>> ich weiß sind die zur Laufzeitüberwachung? Inwiefern können die Fehler>> verursachen?
Huhu
Watchdogs sind Counter, die von einem Resetwert bis 0 runterzählen. Wenn
sie bei 0 ankommen dann lösen sie einen Reset des Prozessors aus. Darum
muss man sie im Programm immer mal wieder auf ihren Resetwert
zurücksetzen.
Die Prozessoren haben dafür meist einen eigenen Befehl (wdt).
Sinn der Sache ist sicherzustellen, dass das Programm des Prozessors
immer ausgeführt wird und sich nicht, z.B. aufgrund einer externen
Störung, in einer Endlosschleife aufhängt (denn hier würde der WD ja
nicht mehr reseted werden).
Nachteil: Wenn der WD nicht reseted wird, dann reseted er den Chip, der
dann wieder das Programm NEU (!) ausführt. Das sieht man aber unter
Umständen nicht sofort.
Wenn z.B. bei einer seriellen Übertragung im Empfänger ein WDT auftritt,
dann geht der Receiver nach der Initialisierung innerhalb weniger us
wieder in die Empfangsschleife und es fehlen nur ein/zwei Byte. Würde
also evtl. zu Deinem Fehlerbild passen.
Evtl. kann man den WD auch nicht per Programm ausschalten, sondern nur
über Fuses. Damit soll verhindert werden, dass ein Nut-laufendes Program
den WD disabled, was ja die Idee ad absurdum führen würde.
Einfache Debugmaßnahme: Beim Programstart einen (freien) Outputpin 100us
auf '1' ziehen und danach permanent auf '0' halten. Siehst Du auf dem
Scope regelmäßig Pulse an diesem Pin, dann schlägt der WD zu.
Viele Grüße
Andreas
Während der Entwicklung bleibt der Watchdog grundsätzlich aus!
Er würde sonst die Fehler verstecken bzw. die Fehlersuche erschweren.
Wenn, dann wird der Watchdog immer als letztes implementiert, nachdem
alles einwandfrei funktioniert.
Peter
Der Watchdog Timer ist per fuses ausgestellt.
Eine zeitliche Pause zwischen den Übertragungen auch leider auch keine
Besserung gebracht!
Zurzeit beschäftige ich mich mit den ACKs, aber ich glaube das ganze ist
schon in den i2c Methoden implementiert.
Genau da ist das Problem beim Failduino, man weis ned was die Libs
machen ;)
Schreib die I2C Routinen doch mal selber, dann weiste zu 100% was da
abgeht.
Im Datenblatt steht alles nötige dazu.
Ich meinte eigentlich die i2c Methoden vom PIC C Compiler. Aber
grundsätzlich bin ich deiner Meinung. Aber man kann nicht immer das Rad
neu Erfinden, sonst kommt man nicht voran :)
Aber ich weiß mittlerweile woran es liegt:
Es liegt am Sender und zwar an der Übertragung der Adresse.
1
for(unsignedchari=0;i<PinCount;i++){
2
if(i2c_WriteTo(Address)){
3
i2c_WriteTo(Address);
4
i2c_PutByte(SeparatorLine);
5
i2c_PutByte(SeparatorLine);
6
i2c_Stop();}
7
i2c_PutByte(data[2*i]);
8
i2c_PutByte(data[2*i+1]);
9
//i2c_PutByte(SeparatorNumber);
10
i2c_Stop();
11
}
i2c_writeto liefert TRUE zurück wenn kein Ack zurückkommt. Der
Einfachheit halber lasse ich in diesem Falle zwei nullBytes schicken.
Und siehe da, nun erscheint jedes mal ein Zeilenumbruch (Empfänger ist
dementsprechend programmiert) wenn einer dieser Fehler auftritt. Ich
werde der Sache mal genauer nachgehen.
Vielen Dank schonmal für Eure Hilfe!
Peter Dannegger schrieb:> Während der Entwicklung bleibt der Watchdog grundsätzlich aus!>> Er würde sonst die Fehler verstecken bzw. die Fehlersuche erschweren.>>>> Wenn, dann wird der Watchdog immer als letztes implementiert, nachdem>> alles einwandfrei funktioniert.
Nette Theorie.
Ich hatte schon ASICs bei denen wir den WD auf expliziten Wunsch des
Kunden nicht abschaltbar implementiert haben.
Am Ende des Tages ist es auch egal. Die CFA musst Du sowieso immer
machen.
Grüße
Andreas
Andreas H. schrieb:> Ich hatte schon ASICs bei denen wir den WD auf expliziten Wunsch des> Kunden nicht abschaltbar implementiert haben.
Das schließt aber doch nicht aus, daß man es eben als letzten
Entwicklungsschritt macht.
Peter
Peter Dannegger schrieb:> Das schließt aber doch nicht aus, daß man es eben als letzten> Entwicklungsschritt macht.
Bei einem ASIC ? Wie soll das den gehen ?
Grüße
Andreas