PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Datenaustausch per I2C



Rabenauge
06.11.2021, 08:55
Hallöle.
Angeregt durch eine Unterhaltung mit @inka hab ich meinem Freddie II mal einen Pi ZeroW spendiert.
Für den möchte ich mir ein grafisches Interface bauen, damit ich Freddie per VNC fern steuern kann.

Das Problem dabei: ausser meiner IR/Cut-Kamera hängt eigentlich nix wirklich am Pi, die gesamte Fahrwerkskontrolle macht ein Arduino Nano.
Deshalb hab ich den Pi an I2C gehängt (mit Levelshifter natürlich), und das funktioniert auch. Ich kann das kleine Display, was Freddie auf dem Schutzblech hat, sowohl vom Nano, als auch vom Raspi aus füttern.
Auch der verbaute Kompass wird problemlos vom Pi erkannt.

Motorsteuerung, Hinderniserkennung (Freddie hat vier IR-Wand-Sensoren ringsum), Akkuüberwachung, Odometrie, an die ganzen Sachen kommt der Pi gar nicht ran.

Der Plan ist, dass der Pi dem Nano sagt, was zu tun ist (in Form von "fahre mal 5m vor" oder "drehe um 30° nach rechts").
Nebenbei sollte der Nano auch gelegentlich Daten zurücksenden, wie z.B. die Spannung des Akkus, oder eben einfach "ausgeführt".
Ich frage mich gerade, wie man das sinnvoll umsetzen kann...so dass es später auch erweiterbar ist (ich hab nicht die geringste Ahnung, was ich mit Freddie in Zukunft vor habe).

Es müssen ja vollkommen unterschiedliche Daten hin-und hergeschickt werden.
Wie geht ihr bei sowas vor?

Holomino
06.11.2021, 12:57
Telegramme über I2C geht fast genau wie bei UART, wenn man die UART-typischen Fifos weiter verwendet. Das spart die bei I2C übliche Registeradressierung. Statt
Slaveadresse, Registeradresse, Registerinhalt,...
muss man dann nur noch
Slaveadresse, Fifoinhalt,...
schreiben. Beim Lesen geht's ebenso.

Ich habe so was letztens für ATXMega und 1er Tiny-Controller gebaut. Wie immer der Hauptteil (teuflisches Gestocher) in der I2C-Hardware mit den ganzen I2C-Stati, aber im Ergebnis recht zufriedenstellend.

Was man in die Fifos schreibt (Json, XML, Ascii oder binäre Strukturen), kann man sich ja selber erfinden.
Ich schreibe mir in der Regel Strukturtypen, deren erstes Byte grundsätzlich eine CommandID als eindeutigen Identifier beinhalten. Das frisst nicht viel Platz.

rolber
08.11.2021, 18:56
Hallo !

Das hört sich nach Multi Master Betrieb an.
Ich habe das gleiche mal mit meinem Sensobot 3 versucht, mit 2 ATmega32 Boards. Ich muss sagen, ich bin kläglich gescheitert.
Ich habe das Ganze aber auch mit Bascom AVR programmiert, hat aber nicht funktioniert. Vielleicht war ich aber auch zu blöd. bin ja nur Hobby Programmierer.
Dann habe habe ich umgestellt auf Master - Slave Betrieb, was funktionierte.
Da mein Problem aber immer nur der Speicherplatz war, habe ich einfach einen anderen Prozessor genommen. Den ATmega1284p.
Den habe ich auch beim Sensobot4 genommen. Er fungiert auch hier als Master.
Als Slave habe ich noch den SD 21 Servocontroller und den Evensense 6050 Gyro / Accelerometer dran. Also 1 Master, 2 Slave.
Funktioniert tadellos. Ich schwöre auf Master / Slave Betrieb. Kann aber auch mit meinen eingeschränkten Programmierfähigkeite zu tun haben.

MfG

Rabenauge
09.11.2021, 07:27
Du hast recht- bei mir läuft es tatsächlich auf Multi-Master hinaus.
Und teilweise (mehr hab ich schlichtweg noch nicht versucht, momentan frisst das grafische Interface meine Zeit) funktioniert es auch.

Ich hab ein kleines OLED-Display drauf, was sowohl der Nano als auch der Pi beschreiben können.
Das hatte ich zum testen versucht: klappt.
Nötig ist das nicht, da der Pi ein grafisches Interface bekommt, auf das ich per VNC zugreifen kann.
Inzwischen hab ich, zum testen, dem Nano auch mal ne feste Adresse verpasst, nun erkennt der Pi ihn, den Kompass, und das Display auch als I2C-Gerät.

Rabenauge
12.11.2021, 00:00
Es geht...noch etwas holprig (der Nano antwortet momentan auf alle Anfragen mit der Spannung des Akkus, der kanns schlichtweg noch nicht anders), aber der Wert hinter "Akku" kommt direkt vom Nano, der den Akku ab und zu prüft (ich glaube, alle 10 Sekunden).
Die Anzeige ist das grafische Interface, was auf dem Pi läuft (ich hol mir das per VNC auf den Laptop, da am Pi gar kein Display dran ist, würde aber auch gehen).
35636

Die Sache fängt an, mir zu gefallen.

rolber
12.11.2021, 22:18
Hallo !

Hoert sich so an , als ob der Pi mit den Daten vom Nano noch nichts anfangen kann (zumindest alles was nach der Akku Spannung kommt).
Oder der Pi weiss einfach noch nicht, was er mit den nachfolgenden Daten anfangen soll.

Du bist auf einem guten Weg.
Ich kenne das Problem!
Es ist so, dass es nicht reicht, am Nano etwas umzuschreiben, du musst dann auch den Pi so umprogrammieren, das er mit den neuen Daten etwas anfangen kann.
Multi Master ist eben kompliziert, aber ich wuerde mich freuen , wenn Du es hin bekommst.

MfG
Roland

Rabenauge
13.11.2021, 10:36
Nein, da liegt das Problem nicht.
Das kann man nämlich ganz easy lösen: man fragt einfach jeden Wert separat an....
Du löst das aus, indem der Master einfach sowas mach:


wire.write(adresse,wert)

Der Slave weiss nun anhand des Wertes, der kommt, was der Master will.
Ich hab nur schlichtweg im Slave (also im Nano) noch keine Tabelle mit den Kommandos, die kommen könnten.
Auch muss ich noch rausfinden, wie ich als Wert mehr als nur ein Byte senden kann (das hab ich schlichtweg noch nicht versucht), weil z.B der Kompasskurs (Freddie hat im Unterdeck nen Kompass) nicht wirklich in ein Byte passt.
Zwar könnte ich den Kompass auch direkt vom Raspberry auslesen (der hängt ja auch am I2C-Bus), müsste dann aber auch die ganze Kalibrierung im Pi machen- da der Nano das aber sowieso macht, kann er auch den Kurs direkt rausrücken.

Rabenauge
17.11.2021, 00:32
Die Sache fängt an, _richtig_ zu funktionieren.
Im Screenshot sieht man die Akkuspannung (so weit war ich ja neulich schon), etwas drunter der stilisierte Freddie mit seinen Hindernis-Sensoren.
Etwa alle 50ms wird der Status der Sensoren vom Raspberry per I2C angefordert- und auch aktualisiert.
Vor den rot leuchtenden halte ich grade die Hand...nehm ich sie weg, wechselt er auf grün, wie der andere.

35640

Allerdings gibt es noch Probleme: der linke funktioniert einwandfrei, aber der rechte "friert" nach einer Weile meistens ein.
In Python gibts dann einen I/O-Fehler.
Da muss ich mich wohl noch mal ans Timing der Sache setzen...möglicherweise schaffts der Arduino nicht immer, schnell genug zu antworten?

Das Ganze funktioniert jetzt so, dass der Pi "von Zeit zu Zeit" einfach eine Zahl (als Byte, das reicht für 256 Kommandos) an den Nano sendet.
Der schaut sie sich an und sendet dann die dazu passende Antwort zurück, eigentlich ganz einfach.
Das "von Zeit zu Zeit" ist unterschiedlich: es gibt keinen Grund, den Akku andauernd abzufragen, das wird nur alle Weile mal gemacht (ich glaube, alle 2 Sekunden), die Sensoren aber möchte ich möglichst schnell aktualisiert haben, bei 100ms sieht man die Verzögerung dann schon.
Bei 50 _nicht_ (ich jedenfalls nicht).

Macht Spass, hehe.

rolber
17.11.2021, 20:59
Hallo!

Das kommt mir bekannt vor.
Die gleichen Probleme hatte ich damals auch.
Eine Weile hat alles gut funktioniert, aber dann kam ein "Error" , ohne ersichtlichen Grund.
Ich hoffe es gelingt Dir noch , alles so hin zu bekommen wie Du es willst.
Habe für Dich noch einen "Chat" zum Thema rausgesucht, der mir damals in einigen Sachen geholfen hat.

https://www.mikrocontroller.net/topic/489801#new

Viel Erfolg

Rabenauge
18.11.2021, 09:07
Eine Fehlerquelle konnte ich inzwischen lokalisieren, hier war es tatsächlich ein Multi-Master-Problem: jedes Mal, wenn der Nano den Akku überprüft hat, blieb _eine_ Abfrage auf I2C stecken.
Das war der ausfallende Sensor...
Grund war offenbar, dass der Nano nach dem auslesen der Akku-Spannung den Wert zum OLED-Display geschickt hatte.
In dem Moment ist er selber Master...
Merkwürdig daran war, dass dabei _immer_ nur der eine der Sensoren hängen blieb, der zweite lief einwandfrei weiter.
Nachdem ich den Teil auskommentiert hatte (darauf kann ich verzichten, weil Freddie ja sowieso fern gesteuert werden soll, es gibt also keinen Grund, irgendwas auf das montierte Display zu schreiben, im VNC-Panel sehe ich ja die Spannung auch), lief es.
Bis ich den dritten Sensor vom Pi aus abfrage...nun bleibt der ganze Bus relativ häufig komplett stecken.
Da hilft nur noch ein Reset des Nano...seltsam.
Das ist erstmal unerklärlich, denn der Nano wird nun gar nicht mehr zum Master (es sei denn, eine der Librarys spuckt in diese Suppe).

Den Trick mit der zusätzlichen Busy-Leitung hatte ich irgendwo schonmal angewendet, weiss aber nicht mehr, wo das war. Falls am Nano noch was frei ist (der ist pinmässig ziemlich ausgereizt), wäre das ne Option.
Der Levelshifter hätte noch zwei freie Leitungen, wäre also recht unkompliziert machbar.

oberallgeier
18.11.2021, 10:55
Eine Fehlerquelle .. blieb _eine_ Abfrage auf I2C stecken .. unerklärlich .. (es sei denn, eine der Librarys spuckt in diese Suppe) ..Bei der I²C-Kommunikation in meinem archie hatte ich ebenfalls Probleme. Zuerst mit dem Multi-Master-Konzept. Als die in sinnvoller Zeit nicht gelöst werden (konnten) hatte ich umgestellt auf Ein-Master-mehrere Slaves (http://dl.dropbox.com/s/4pzc61yk56ug9ej/Archie-Topo.jpg?dl=0) (Anm.: Topo ist veraltet). Der zentrale Master "pollt" bei Bedarf (auf Anforderung) Werte von den Slaves. Ansonsten bin ich zu I²C der übliche Anfänger/Noncompos.

Bei diesen Arbeiten hatte ich mal die I²C-Bibliothek von Peter Fleury <pfleury@gmx.ch> http://jump.to/fleury durchgeforstet - und die I²C-Gebetbücher wie Philips Semiconductors: THE I 2C-BUS SPECIFICATION (https://www.csd.uoc.gr/~hy428/reading/i2c_spec.pdf), VERSION 2.1, JANUARY 2000, document order number: 9398 393 40011 sowie die ATMEL APPLICATION NOTE Atmel-2565E-Using-the-TWI-Module-as-I2C-Slave_AVR311_Application Note-03/2016. Auffällig war dabei (siehe rot - evtl. scrollen):


/************************************************** ***********************
* Title: I2C master library using hardware TWI interface
* Author: Peter Fleury <pfleury@gmx.ch> http://jump.to/fleury
* File: $Id: twimaster.c,v 1.3 2005/07/02 11:14:21 Peter Exp $
* Software: AVR-GCC 3.4.3 / avr-libc 1.2.3
* Target: any AVR device with hardware TWI
..
************************************************** ************************/
. . .

/************************************************** ***********************
Issues a start condition and sends address and transfer direction.
return 0 = device accessible, 1= failed to access device
************************************************** ***********************/
unsigned char i2c_start(unsigned char address)
{
uint8_t twst;

// send START condition
TWCR = (1<<TWINT) | (1<<TWSTA) | (1<<TWEN);

// wait until transmission completed
while(!(TWCR & (1<<TWINT)));

// check value of TWI Status Register. Mask prescaler bits.
twst = TW_STATUS & 0xF8;
if ( (twst != TW_START) && (twst != TW_REP_START)) return 1;

// send device address
TWDR = address;
TWCR = (1<<TWINT) | (1<<TWEN);

// wail until transmission completed and ACK/NACK has been received
while(!(TWCR & (1<<TWINT)));

// check value of TWI Status Register. Mask prescaler bits.
twst = TW_STATUS & 0xF8;
if ( (twst != TW_MT_SLA_ACK) && (twst != TW_MR_SLA_ACK) ) return 1;

return 0;

}/* i2c_start */
/************************************************** ***********************

Entsprechend der Philips-Bibel zum I²C wird hier vorschriftsgemäß gewartet bis eine Antwort kommt. Und wenn keine kommt hängt sich das Zeugs auf. Das Stretching ist aber sowieso nicht unkompliziert (https://www.i2c-bus.org/clock-stretching/).

Meine Änderung war nun ein Counter der ne Weile zum runterzählen braucht und alternativ zum NICHT eintrudelnden Signal die Routine beendet (teils mit Fehlerflag). Das löste einerseits die Häng-ihn-auf-Probleme, andererseits klappte es nicht immer mit ner alternativen Lösung. Egal - mittlerweile läufts, siehe Link auf das Topo (http://dl.dropbox.com/s/4pzc61yk56ug9ej/Archie-Topo.jpg?dl=0) oben. Allerdings habe ich mittlerweile meinen I²C-Bus über ein ca. 2 m langes, nicht abgeschirmtes Flachbandkabel im archie mit 800 kHz in Betrieb. Anm.: Hab leider kein aktuell geltendes Topo in meiner "Bilderbibliothek".
/* I2C clock in Hz */
#define SCL_CLOCK 800000L
// ... hier 800 kHz, TWBR = 4 (komma 5)

Fazit: möglicherweise könntest Du Dein Problem durch ne vergleichbare Änderung lösen?

Rabenauge
18.11.2021, 16:06
Auf dem Arduino laufen eigentlich drei Bibliotheken, die I2C nutzen: wire (das ist die Standard-Lib für das TWI-Interface), die Adafruit fürs Display und eine für den Kompass.
Um das umzusetzen, müsste ich die letzteren beiden zerlegen und sehen,was die genau treiben. Dass die wire "nach Vorschrift" arbeitet, davon geh ich mal aus.
Und das in Python zu realisieren, ganz ehrlich..da fehlt mir noch ne genze Menge an Verständnis.
Python ist in vielem so....seltsam.

Im Grunde hab ich drei Möglichkeiten:

-entweder ich ernenne den Nano kurzerhand zum Busmeister
oder
-ich realisiere eine Busy-Leitung zusätzlich
oder
ich ernenne den Raspberry zum alleinigen Meister.

Letzteres erscheint mir weniger sinnvoll denn dann müsste der Raspi sich z.B. auch um den Kompass kümmern- samt Software-Kalibrierung.
Das alles läuft auf dem Nano schon- und ist gar nicht ganz ohne.
Und da es aber "nur" ein Raspi Zero(W) ist, und der mir später auch noch nen Livestream der Kamera liefern soll, dürfte er genug zu tun haben.

Die Busy-Leitung ist ne machbare Option, allerdings müsste ich da noch zwei Strippen ziehen.
Das ist also erstmal Plan B.
Plan A ist die erste Option: den Nano zum Meister über alles ernennen.
Hat den Nachteil, dass ich später die Fahrsignale, die ja im Pi (über den hübschen "Joystick" im Panel) erzeugt werden,dauernd abfragen muss, ist aber ohne jegliche Hardware-Änderung machbar.
Daher probier ich das erstmal aus.
Dazu werd ich im Python-Interface allerdings _einiges_ umbauen müssen, mal rausfinden, wie _das nun wieder_ geht...