Synchronisieren Sie 12 Arduinos - I2C vs. seriell

Ich habe 12 Arduinos (Mega) und 12 Breakout-Boards (nach Kundenwunsch gebaut. Sie pumpen den Ausgang der digitalen Pins auf 12 V bei 120 mA) zur Steuerung von etwa 300 LEDs. Ich verwende eine Pseudo-PWM-Bibliothek, um die LEDs zu verblassen.

Dies hätte mit einem viel, viel billigeren Setup erreicht werden können. Offen für Vorschläge, aber die Zeit drängt.

Mein Dilemma besteht darin, all diese Mikrocontroller zu synchronisieren. Ich war noch nie an einem Projekt beteiligt, bei dem das Timing so wichtig war; Normalerweise würde ich die seriellen TX/RX-Pins verwenden, um nur Befehle weiterzuleiten, aber ich würde nachts besser schlafen, wenn es eine Art Herzschlag von einem Master zu 11 Slaves gäbe. Ist I2C in diesem Fall der richtige Weg, oder schaue ich nach Alternativen?

tl; dr Was ist der beste Weg, um 12 Arduinos synchron zu halten?

Die Frage ist, wie eng das Timing ist. Was sollen die LEDs bewirken? Welche Art von Zeitfehler können Sie tolerieren? Können Sie die Hierarchie des Systems näher erläutern? Ein Arduino könnte alle 12 Boards auf demselben I2C-Bus steuern, aber I2C ist ziemlich langsam. Ein einzelnes Arduino, das als Master fungiert und einen Impuls erzeugt, um den Rest zu synchronisieren, klingt ungefähr richtig (z. B. das Verriegeln eines Timers). Sie können sogar jedes Arduino dazu bringen, den Versatz von sich selbst mit dem Master zu finden, wenn dies auftritt, und sich so selbst "kalibrieren".
Müssen Sie sie nur synchronisieren oder Informationen vom Master zum Slave senden? Wenn Sie sie synchronisieren müssen, verwenden Sie den Interrupt-Pin auf Slaves und Master, um diesen Interrupt auszulösen.
Das Timing ist nicht so eng, ich kann mir wahrscheinlich eine Lücke von 50 ms zwischen den Controllern leisten, ohne eine Unterbrechung zu bemerken. Es gibt 3 Objekte, die eine Reihe von RGB-LED-Streifen halten, 4 Arduinos für ein Objekt. Die Objekte müssen zur gleichen Zeit dasselbe Programm abspielen. Die Programme sind einfache Kaskadeneffekte, bei denen die LEDs die Objekte auf- und abblenden. Was ich nicht möchte, ist, dass es beim Überqueren zum nächsten Arduino einen Zeitunterschied gibt. Mehr eine Frage der Zuverlässigkeit als der Geschwindigkeit.
Sie möchten also nur die gleiche Routine auf jedem Arduino gleichzeitig auslösen? Wie groß ist der Abstand zwischen jedem Arduino? Werden sie in einer Linie oder einer sternförmigen Konfiguration angeordnet?
Um dies weiterzuverfolgen, habe ich eine serielle Hierarchie erstellt. Der Master würde alle Controller gleichzeitig unterbrechen (ich nehme an, das war der 'Herzschlag', nach dem ich gesucht habe) und dann einen Befehl an 3 Anführer weitergeben, die diese an 2 andere Slaves weiterleiten würden. Die Geschwindigkeit war schnell genug, um nicht bemerkbar zu sein. Lächerlich, so viele Mikrocontroller zu verwenden, ich hätte LED-Treiber in einer I2C-Leitung verwendet, wenn ich mehr Zeit gehabt hätte.

Antworten (2)

Verwenden Sie zwei Pins pro Chip, einen Eingang und einen Ausgang, und verketten Sie sie seriell. Lassen Sie den "Master" -Chip den Pin bei jedem "Frame" umschalten und alle Slaves bei Pin-Änderung unterbrechen, das Heartbeat-Ereignis registrieren und "synchronisieren", dann den Pin-Status an den nächsten Chip weitergeben und so weiter ... wenn Wenn Sie Lust haben, wickeln Sie den Ausgang des letzten Chips in der Kette zurück zum Master, damit der Master feststellen kann, ob die Nachricht empfangen wurde und wie die Latenz dieser Antwort war.

Dies ist ein netter, einfacher Ansatz, der keine große Softwareentwicklung oder große Sorge um elektrische Eigenschaften und Signalintegrität erfordert. Es gibt offensichtlich andere, komplexere und funktionsreichere Ansätze zur Lösung des von Ihnen gestellten Problems.

Das AVR-TWI kann so konfiguriert werden, dass es eine "allgemeine Anruf"-Übertragung akzeptiert, die im Wesentlichen ein I²C-Schreibvorgang an Adresse 0 ist. Alle Slaves können eine individuelle Slave-Adresse haben und auch auf Adresse 0 antworten (was einfach SLA+W bestätigen kann , Zum Beispiel).

Dies kann verwendet werden, um die Slaves zu synchronisieren. Daten an alle Slaves senden, dann SLA+W an die allgemeine Rufadresse senden. Alle Slaves erhalten diesen „Befehl“ und können mehr oder weniger gleichzeitig mit der Datenverarbeitung beginnen.

Das AVR TWI generiert einen Interrupt, wenn ein Stopp oder wiederholter Start auf dem Bus generiert wurde. Dies kann nur geschehen, wenn alle Slaves SCL freigegeben haben, sodass Sie sicher sein können, dass alle Slaves, die SLA+W bestätigt haben, auch den Befehl verarbeitet und SCL freigegeben haben.

Bei diesem "Protokoll" können Sie nicht sicher sein, dass alle 11 Slaves den Befehl bestätigt haben.

Das Timing hängt von dem anderen Code ab, der auf Ihren Slaves ausgeführt wird. Wenn kein anderer Interrupt aktiv ist, läuft es auf die Interrupt-Latenz hinaus, die ein paar Taktzyklen beträgt (ich bin zu faul, das jetzt nachzuschlagen).

Ich bin mir nicht sicher, ob Folgendes mit dem Hardware-TWI funktioniert: Es ist möglicherweise möglich, den allgemeinen Anruf in einen Lesetransfer umzuwandeln. Alle Slaves liefern 2 Bytes zurück und jeder Slave gibt an einer individuellen Stelle eine Null aus. Die verdrahtete UND-Funktionalität des I²C-Busses führt zu einer kombinierten Antwort aller Slaves. So könnte das Ergebnis aussehen 1111 1000 0000 0000. Der Master kann nach allen erwarteten Nullen suchen und entsprechend handeln. Von hier aus könnte es kompliziert werden, wenn Sie eine "Abbruch"-Funktion hinzufügen möchten, die einsetzt, wenn nicht alle Slaves ihre Arbeit erledigt haben. Ich habe das nur einmal mit Bit-Banged I²C versucht.

Eine weitere Sache, die Sie anstelle eines allgemeinen Anruflesens versuchen sollten: Verwirren Sie mit dem Adressmaskenregister. Das TWI kann so konfiguriert werden, dass es eine einzelne Adresse akzeptiert, aber es kann auch eine Adressmaske anwenden, wenn es die Adresse prüft. Dies kann verwendet werden, um eine Nicht-Null-Adresse in eine benutzerdefinierte allgemeine Aufrufadresse umzuwandeln, die zum gleichzeitigen Lesen von Daten von allen Slaves verwendet werden kann.

Das auszuarbeiten, klingt nach einem coolen Projekt für sich ...


Und noch ein Edit: Ich habe mir das Datenblatt angesehen und bin zu dem Schluss gekommen, dass das Hardware-TWI nicht dazu gebracht werden kann, Adressen auf diese Weise zu akzeptieren. Sie können meinen ersten Vorschlag ausprobieren (einfach einen allgemeinen Anruf senden) oder einen etwas abgedroschenen I²C-Treiber schreiben, der alles tut, was Sie wollen. Oder versuchen Sie etwas ganz anderes, wie den Vorschlag von Vicatcu.

General Call funktioniert definitiv auf AVR ... Ich bin mir ziemlich sicher, dass ThingM / BlinkM es verwenden. Ich denke, es kann nur zum Schreiben von Daten auf Slaves verwendet werden, nicht zum Lesen von Daten von Slaves. Es ist realisierbar, aber ich denke, die Gesamtlänge des Busses wäre das größte Problem damit.
Mal sehen, ob rom die Fragen in Oli Glasers Kommentar beantwortet...