EV3Basic: allgemeine Kommunikation mit I2C Geräten

NXC, C/C++, Lejos, pbLua, RobotC...

Moderator: Moderatoren

Benutzeravatar
c0pperdragon
Schreibt viel
Schreibt viel
Beiträge: 231
Registriert: 9. Feb 2015 00:29

Re: EV3Basic: allgemeine Kommunikation mit I2C Geräten

Beitragvon c0pperdragon » 28. Sep 2015 16:05

Das im I2C fix eingebaute Handshake wartet immer, bis die Antwort vom Slave komplett da ist.
In den Fällen, wo der Slave nicht da ist, wird die Kommunikation allerdings immer sofort beendet. Das müsste dann das Programm am Master erkennen und es nochmal versuchen.
Leider habe ich da in EV3Basic nichts vorgesehen, damit man die verschiedenen Fehlerszenarien (kein Slave, Slave bricht Kommunikation mitten drin ab) erkennen bzw. voneinander unterscheiden kann. Wahrscheinlich enthält das Rückgabe-Array dann nur Datenmüll, bzw. zuerst die noch empfangenen Daten und hinten dran den Datenmüll. Das müsste ich eventuell noch ein bisschen schöner gestalten.

Benutzeravatar
c0pperdragon
Schreibt viel
Schreibt viel
Beiträge: 231
Registriert: 9. Feb 2015 00:29

Re: EV3Basic: allgemeine Kommunikation mit I2C Geräten

Beitragvon c0pperdragon » 28. Sep 2015 16:08

Nochwas wegen dem Warten auf den Slave: Wenn ein Slave nicht mit dem vorgegebenen Übertragungstakt des Masters mithalten kann, weil z.B. die Daten noch nicht bereitliegen, dann kann er die Kommunikation verzögern ("Clock-Stretching"). Der Master muss dann eben so lange warten. Geht aber eben nur, wenn ein Slave mit der richtigen address da ist

Benutzeravatar
HaWe
Administrator
Administrator
Beiträge: 5399
Registriert: 11. Jan 2006 21:01
Wohnort: ein kleiner Planet in der Nähe von Beteigeuze

Re: EV3Basic: allgemeine Kommunikation mit I2C Geräten

Beitragvon HaWe » 28. Sep 2015 16:12

tatsächlich scheint genau so etwas zu passieren, denn er zeigt ja einen "Phantasie-Rüchgabe-Array" an:
beim Arduino ist der im Daten-Teil komplett auf Null,
und auch der EV3 initialisiert ihn vor dem Kontakt auf Null.
Von daher dürfte nach dem Befehl auch nichts anderes drinstehen, wenn kein Kontakt da war.
Trotzdem ist er gefüllt mit Werten, teilweise sogar chksum-"Bytes" die weit über 255 liegen /700, 800, 900...). Deshalb kann da was nicht stimmen.
Gruß,
HaWe
±·≠≈²³αβγδε∂ζλμνπξφωΔΦ≡ΠΣΨΩ∫√∀∃∈∉∧∨¬⊂⊄∩∪∅∞®
NXT NXC SCHACHROBOTER: https://www.youtube.com/watch?v=Cv-yzuebC7E

Benutzeravatar
HaWe
Administrator
Administrator
Beiträge: 5399
Registriert: 11. Jan 2006 21:01
Wohnort: ein kleiner Planet in der Nähe von Beteigeuze

Re: EV3Basic: allgemeine Kommunikation mit I2C Geräten

Beitragvon HaWe » 30. Sep 2015 13:54

@reinhard:
hast du denn jetzt einen Hinweis, wie der i2c master feststellen kann, ob er alle Daten gesendet und danach empfangen hat (Anzahl abgelieferte und wieder gelesene Bytes zählen) ?
Und solange warten und nichts tun, bis sie eingangen sind (ggf. mit time-out und Fehlermeldung)?
Gruß,
HaWe
±·≠≈²³αβγδε∂ζλμνπξφωΔΦ≡ΠΣΨΩ∫√∀∃∈∉∧∨¬⊂⊄∩∪∅∞®
NXT NXC SCHACHROBOTER: https://www.youtube.com/watch?v=Cv-yzuebC7E

Benutzeravatar
c0pperdragon
Schreibt viel
Schreibt viel
Beiträge: 231
Registriert: 9. Feb 2015 00:29

Re: EV3Basic: allgemeine Kommunikation mit I2C Geräten

Beitragvon c0pperdragon » 30. Sep 2015 21:32

Ich habe das jetzt etwas näher erforscht, und es ist schon arg unpraktisch, wie das von der Lego-Firmware gemacht wird. Es gibt keinen echten Weg zu unterscheiden, was genau bei der Übertragung passiert ist. Man kann höchstens versuchen, vom Inhalt des Lesepuffers darauf zu schließen was los war.
Anscheinend macht der Brick folgendes:
Er hat einen einzelnen internen Puffer in den er zuerst die Sendedaten hineinkopiert.
Dann adressiert er den Slave und versucht, ihm die Daten zu schicken.
Wenn das gut geht, dann löscht er den Puffer (setzt alles auf 255) und empfängt Daten von Slave.
Den Inhalt des Puffers bekomme ich dann am Ende ohne weitere Hinweise zurück.

Es gibt jetzt im Prinzip folgende Szenarien:
1. Slave existiert nicht : Puffer behält Sendedaten und die werden auch als Empfangsdaten zurückgegeben.
Falls weniger Daten gesendet werden sollten, als nachher empfangen, dann sind hinten sogar
noch ganz uralte Bytes drinnen, weil die nie überschrieben wurden
2. Slave existiert, antwortet aber mit zu wenigen Bytes:
Wo keine Bytes empfangen wurden, kriegt man 255 zurück
3. Alles OK:
Man erhält genau die Daten vom Slave

Wie kannst du jetzt eine vernünftige Erkennung der Probleme machen?
Erkennung von Szenario 1: Stelle sicher, dass bei korrektem Ablauf die Empfangsdaten ein einer bestimmten Stelle auf jeden Fall anders als die Sendedaten sein müssen. (z.B. 1.Byte gibt Richtung an, oder so was).
Erkennung von Szenario 2: Definiere das Protokoll so, dass die Empfangsdaten niemals ein 255 an der letzten Stelle haben dürfen.
Falls das für Szenario 2 zu aufwändig ist, kannst du ja auch deine Checksumme verwenden. Die sollte das auch halbwegs zuverlässig erkennen.

!!!
Noch ein zweites Problem existiert bei der derzeitigen Version (1.0.7) von EV3Basic: Im Brick-Modus (also wenn das Programm autonom auf dem Gerät läuft), dann erhält man als Empfangsdaten teilweise negative Zahlen für die Bytes, weil mein Compiler versehentlich die Bytes als vorzeichenbehaftete Zahlen interpretiert und dann in floats umwandelt. Ich repariere das und dann müsste sich das Programm genauso verhalten, wie derzeit auf dem PC.


Fürs Abwarten, dass die Kommunikation gelingt (und Timeout) habe ich nichts. Musst du im Programm selber machen.

Benutzeravatar
HaWe
Administrator
Administrator
Beiträge: 5399
Registriert: 11. Jan 2006 21:01
Wohnort: ein kleiner Planet in der Nähe von Beteigeuze

Re: EV3Basic: allgemeine Kommunikation mit I2C Geräten

Beitragvon HaWe » 30. Sep 2015 21:51

ich dachte an eine eher allgemeine I2C-Lösung EVV3Basic-seits.
Wenn er einen Sensor per i2c anspricht, kann ich ja Sensor-seitig nichts beeinflussen, der EV3 muss das alleine schaffen.

Für den Arduino als Slave kann ich ntl eingreifen:
man könnte das 3. Byte (sendarray[2]) dazu verwenden:
wenn der Master(EV3) sendet, schreibt er seinen adressierten Slave rein (hier: 0x04) ,
und wenn der Arduino sendet, schreibt er den Master als "0x00" rein.
So wären beide unterscheidbar.

das mit der letzten Stelle ist zwar lösbar, aber ärgerlich, denn ich wollte ja 48 Bytes, der EV3 schafft nur 32, davon werden nochmal 2 intern abgezwackt, das lässt nur 30, und jetzt noch das letzte weg, 29... -
das erinnert mich schon heftig an "10 kleine Negerlein"... :-/

Grundsätzlich hätte ich das Problem also eher auf EV3-Seite gelöst gehabt als vom Slave, der ja nur passiv ist und nur tut, was man ihm sagt (und das schon jetzt besser als der Master)

ps, (edit: hat sich überschnitten:)
der Arduino könnte aber sogar 32 Bytes zurückgeben, also 2 mehr als der EV3, denn er braucht ja die 2 Steuerbytes nicht.
Dann könnte ich 32 vom EV3 32 zurückverlangen, und die werden Arduino-seitig z.B. mit 127 aufgefüllt (nicht 0 und nicht 255).
Gruß,
HaWe
±·≠≈²³αβγδε∂ζλμνπξφωΔΦ≡ΠΣΨΩ∫√∀∃∈∉∧∨¬⊂⊄∩∪∅∞®
NXT NXC SCHACHROBOTER: https://www.youtube.com/watch?v=Cv-yzuebC7E

Benutzeravatar
c0pperdragon
Schreibt viel
Schreibt viel
Beiträge: 231
Registriert: 9. Feb 2015 00:29

Re: EV3Basic: allgemeine Kommunikation mit I2C Geräten

Beitragvon c0pperdragon » 30. Sep 2015 21:57

Tut mir leid. Ich kann nicht mehr anbieten, als mir die Firmware gibt.
Es sind aber schon 31 Byte beim Senden und 32 beim Empfangen.

Benutzeravatar
HaWe
Administrator
Administrator
Beiträge: 5399
Registriert: 11. Jan 2006 21:01
Wohnort: ein kleiner Planet in der Nähe von Beteigeuze

Re: EV3Basic: allgemeine Kommunikation mit I2C Geräten

Beitragvon HaWe » 30. Sep 2015 21:59

ps,
der Arduino könnte aber sogar 32 Bytes zurückgeben, also 2 mehr als der EV3, denn er braucht ja die 2 Steuerbytes nicht.
Dann könnte ich 32 vom EV3 32 zurückverlangen, und die werden Arduino-seitig z.B. mit 127 aufgefüllt (nicht 0 und nicht 255).

(Xander Soldaat hat sich so geäußert, dass der EV3 1 weiteres Byte belegt, neben der devaddr, ich meine für Register, kann aber auch für den Port sein - auf jeden Fall aber 2 insgesamt.
Er hat die Lego-Firmware umgeschrieben und verbessert für RobotC, auch den I2C-Teil, ich vermute eigentlich, er kennt sich damit aus. Aber wie auch immer, wenigstens zurück gibt es max. 32.)
Gruß,
HaWe
±·≠≈²³αβγδε∂ζλμνπξφωΔΦ≡ΠΣΨΩ∫√∀∃∈∉∧∨¬⊂⊄∩∪∅∞®
NXT NXC SCHACHROBOTER: https://www.youtube.com/watch?v=Cv-yzuebC7E

Benutzeravatar
c0pperdragon
Schreibt viel
Schreibt viel
Beiträge: 231
Registriert: 9. Feb 2015 00:29

Re: EV3Basic: allgemeine Kommunikation mit I2C Geräten

Beitragvon c0pperdragon » 30. Sep 2015 22:03

Weiß nicht genau, was Xander meint, aber ich habs ausprobiert, und es ging. 31 Byte Nutzdaten zum Slave und 32 Byte Nutzdaten zurück.
Ein Byte braucht der EV2 tatsächlich für die Slave-Addresse beim Senden und deswegen ist es auch eines weniger.

Benutzeravatar
HaWe
Administrator
Administrator
Beiträge: 5399
Registriert: 11. Jan 2006 21:01
Wohnort: ein kleiner Planet in der Nähe von Beteigeuze

Re: EV3Basic: allgemeine Kommunikation mit I2C Geräten

Beitragvon HaWe » 30. Sep 2015 22:04

ok, aber immerhin wie gesagt 32 zurück.
dann könnte man das 32. mit 127 besetzen.

Und darauf soll ich im Basic-Code testen?

und wenn das 32. jetzt 255 sein sollte oder das 3. nicht 0 - was dann genau, wie weiter?
Gruß,
HaWe
±·≠≈²³αβγδε∂ζλμνπξφωΔΦ≡ΠΣΨΩ∫√∀∃∈∉∧∨¬⊂⊄∩∪∅∞®
NXT NXC SCHACHROBOTER: https://www.youtube.com/watch?v=Cv-yzuebC7E

Benutzeravatar
c0pperdragon
Schreibt viel
Schreibt viel
Beiträge: 231
Registriert: 9. Feb 2015 00:29

Re: EV3Basic: allgemeine Kommunikation mit I2C Geräten

Beitragvon c0pperdragon » 30. Sep 2015 22:09

Dann hast du einen Übertragungsfehler erkannt. Dann versuchst du die Übertragung klarerweise nochmal.
Entweder so lange bis es geht, oder bis du es aufgeben willst.

Benutzeravatar
HaWe
Administrator
Administrator
Beiträge: 5399
Registriert: 11. Jan 2006 21:01
Wohnort: ein kleiner Planet in der Nähe von Beteigeuze

Re: EV3Basic: allgemeine Kommunikation mit I2C Geräten

Beitragvon HaWe » 30. Sep 2015 22:20

ok, also sofort neu senden, in einer Endlosschleife...
Aufgeben machrt dann ja keinen Sinn, denn ich brauche ja Daten vom Slave.
Die Gesamt-Performance leidet dadurch aber evtl schon etwas.
Gruß,
HaWe
±·≠≈²³αβγδε∂ζλμνπξφωΔΦ≡ΠΣΨΩ∫√∀∃∈∉∧∨¬⊂⊄∩∪∅∞®
NXT NXC SCHACHROBOTER: https://www.youtube.com/watch?v=Cv-yzuebC7E

Benutzeravatar
HaWe
Administrator
Administrator
Beiträge: 5399
Registriert: 11. Jan 2006 21:01
Wohnort: ein kleiner Planet in der Nähe von Beteigeuze

Re: EV3Basic: allgemeine Kommunikation mit I2C Geräten

Beitragvon HaWe » 30. Sep 2015 22:33

so in etwa...:

Code: Alles auswählen

MSGSZEV3 = 30
MSGSZSLV = 32
I2CPORT = 4          '// EV3 sensor port 4
I2CSLVADDR = 4       '// devaddr=0x04

sendarray = Vector.Init(MSGSZEV3, 0)
recvarray = Vector.Init(MSGSZSLV, 0)
'
'
'

   While ( (recvarray[MSGSZSLV-1]<>127) Or (recvarray[2]<>0) )
      recvarray= Sensor.CommunicateI2C( I2CPORT, I2CSLVADDR , MSGSZEV3 , MSGSZSLV,  sendarray )
   EndWhile
   '
   '
   '
   

?
Gruß,
HaWe
±·≠≈²³αβγδε∂ζλμνπξφωΔΦ≡ΠΣΨΩ∫√∀∃∈∉∧∨¬⊂⊄∩∪∅∞®
NXT NXC SCHACHROBOTER: https://www.youtube.com/watch?v=Cv-yzuebC7E

Benutzeravatar
c0pperdragon
Schreibt viel
Schreibt viel
Beiträge: 231
Registriert: 9. Feb 2015 00:29

Re: EV3Basic: allgemeine Kommunikation mit I2C Geräten

Beitragvon c0pperdragon » 1. Okt 2015 12:13

Das schaut vernünftig aus. Mit der Performance ist es bei I2C aber prinzipiell schlecht, weil der Aufruf die VM komplett blockiert, bis er fertig ist. Das dauert in deinem Fall bei erfolgreicher Kommunikation ca. 65ms. Wenn kein Slave da ist, geht es viel schneller. 4ms oder so. Wenn du mehrere Threads benutzt wäre also ein Delay in der Schleife gut.

Benutzeravatar
HaWe
Administrator
Administrator
Beiträge: 5399
Registriert: 11. Jan 2006 21:01
Wohnort: ein kleiner Planet in der Nähe von Beteigeuze

Re: EV3Basic: allgemeine Kommunikation mit I2C Geräten

Beitragvon HaWe » 1. Okt 2015 19:07

funktioniert aber leider nicht: kaum wird das Programm gestartet, erscheint der EV3-Startbildschirm statt Datenausgabe.
Nur wenn man die while-Schleife auskommentiert

Code: Alles auswählen

' While ( (recvarray[MSGSZSLV-1]<>127) Or (recvarray[2]<>0) )
       recvarray= Sensor.CommunicateI2C( I2CPORT, I2CSLVADDR , MSGSZEV3 , MSGSZSLV ,  sendarray )
' EndWhile


läuft es wieder wie vorher.

hier der Komplett-Code, übergangsweise noch mit gleich großen Sende-/Empfangs-arrays
:

Code: Alles auswählen

'//  EV3Basic code to interface an EV3 to an Arduino
'//  EV3 as an I2C master, Arduino as an I2C slave
'//  SmallBasic 1.0 or 1.5
'//  EV3Basic 1.07
'//  EV3 fw Lego 1.06
'//  ver. 0.003

MSGSZEV3 = 30
MSGSZSLV = 30
I2CPORT = 4          '// EV3 sensor port 4
I2CSLVADDR = 4       '// devaddr=0x04

sendarray = Vector.Init(MSGSZEV3, 0)
recvarray = Vector.Init(MSGSZSLV, 0)

datapacket = Vector.Init(MSGSZSLV, 0) '// global msg buffer to sub calculatechecksum
datasize   = MSGSZEV3                        '// global msg size to sub calculatechecksum
checksum = 0                                     '// global return value to sub calculatechecksum

sub calcchecksum
  checksum = 0
  For i=4 To datasize-1
     checksum = checksum + datapacket[i]   
  endfor
  checksum = Math.Remainder(checksum,256)
endsub


LCD.StopUpdate()
LCD.Clear()

While "True"
   LCD.Text(1,  0,  0,  1, "Send Array")
     'LCD.Text(1,   0, 10,  1, sendarray[0] )
     LCD.Text(1,   0, 10,  1, sendarray[1] )
     LCD.Text(1,  30, 10,  1, sendarray[2] )
     LCD.Text(1,  50, 10,  1, sendarray[3] )
     LCD.Text(1,  70, 10,  1, sendarray[4] )
     LCD.Text(1, 110, 10,  1, sendarray[5] )
     LCD.Text(1, 150, 10,  1, sendarray[6] )
   LCD.Text(1, 0,  40,  1, "Receive Array")
     'LCD.Text(1,   0, 50,  1, recvarray[0] )
     LCD.Text(1,   0, 50,  1, recvarray[1] )
     LCD.Text(1,  30, 50,  1, recvarray[2] )
     LCD.Text(1,  50, 50,  1, recvarray[3] )
     LCD.Text(1,  70, 50,  1, recvarray[4] )
     LCD.Text(1, 110, 50,  1, recvarray[5] )
     LCD.Text(1, 150, 50,  1, recvarray[6] )
   
   sendarray[0] = 255          '// start sync byte
   sendarray[2] = I2CSLVADDR   '// for receiver check
   sendarray[3] = 1            '// error flag: ok=1
   
   sendarray[4] = sendarray[4] +1 '// test increment in each loop
   
   datapacket = sendarray
   datasize    = MSGSZEV3
   calcchecksum()
   sendarray[1] = checksum
   
  ' While ( (recvarray[MSGSZSLV-1]<>127) Or (recvarray[2]<>0) )
       recvarray= Sensor.CommunicateI2C( I2CPORT, I2CSLVADDR , MSGSZEV3 , MSGSZSLV ,  sendarray )
   ' EndWhile
   datapacket = recvarray
   calcchecksum()
   If  recvarray[1]  <> checksum  Then   
      LCD.Text(1,  0, 100,  1, "CHKSUM ERROR" )
   Else
      LCD.Text(1,  0, 100,  1, "            " )
   EndIf
 
  Program.Delay(1)   '// yield()
 
EndWhile
Gruß,
HaWe
±·≠≈²³αβγδε∂ζλμνπξφωΔΦ≡ΠΣΨΩ∫√∀∃∈∉∧∨¬⊂⊄∩∪∅∞®
NXT NXC SCHACHROBOTER: https://www.youtube.com/watch?v=Cv-yzuebC7E


Zurück zu „textbasierte Programmiersoftware“

Wer ist online?

Mitglieder in diesem Forum: 0 Mitglieder und 15 Gäste

Lego Mindstorms EV3, NXT und RCX Forum : Haftungsauschluss