Forum: Mikrocontroller und Digitale Elektronik SPI - Daisy-Chain-Protokoll


von Peter M. (lctromnml)


Angehängte Dateien:

Lesenswert?

Hallo zusammen,

Ich versuche aktuell über einen STM32F4 mit mehreren, per Daisy Chain 
verbundenen Batterie-Management(BMS)-Chips zu kommunizieren.
Direkt kommunizieren muss ich dabei nur mit einem der Chips über SPI, 
dieser ist wiederum mit den anderen über eine Daisy Chain verbunden (Der 
Daisy-Chain-Standard ist ein proprietärer Standard).

Die Teilnehmer sind also:
STM32-Host-uC: SPI Master
BMS-Master-Chip: SPI Slave
Weitere BMS-Chips: Per Daisy-Chain mit BMS-Master-Chip verbunden

Die SPI-Kommunikation erfolgt über 5 Leitungen: MISO, MOSI, SCK und Chip
Select, sowie ein /DATA READY (GPIO IN am STM32-Host-uC), welches dem 
Host-STM32 mit fallender Flanke anzeigt, dass ein Byte vom 
BMS-Master-Chip empfangen werden kann (Dieses kann vom BMS-Master-Chip 
selbst, oder von einem der Weiteren BMS-Chips sein)
Ich muss dabei immer Befehle mit 4 Bytes bzw. 3 Bytes Länge senden und
empfange in der Regel dann 4 Bytes als Antwort.

Die 4 Bytes bestehen immer aus einer Adresse und Daten.

Zusätzlich gibt es Sonderfälle:

1. Auf bestimmte Kommandos kommt erst eine 4 Byte Antwort, direkt danach
allerdings noch eine definierte Anzahl weiterer 3 Byte Antworten.

2. Bei Fehlern wird automatisch eine 4 Byte Antwort gesendet durch den 
Batterie-Management-Chip.

Bei den empfangenen Daten gibt es keine Start-/Stopbytes, Anzahl noch zu 
empfangener Bytes im Frame oder ähnliches.  Erschwerend kommt noch 
hinzu, dass ich nach den Befehlen unterschiedliche Zeiten warten muss, 
bis ich den nächsten Befehl senden kann, und das relativ zügig empfangen 
werden muss, da der BMS-Master-Chip nur einen 4-Byte Buffer hat. 
Zusätzlich muss das Chip Select zwischen jedem Byte "gestrobed" werden 
(Direktes Auslesen von 4-bytes per DMA ist also beispielsweise auch 
nicht möglich).

Ich habe mittlerweile eine Lösung, die halbwegs stabil läuft, mit der 
ich aber nicht wirklich zufrieden bin. Jetzt würde mich interessieren, 
ob jemand Literatur/Code/Best practises kennt für Protokolle, die 
ähnlich aufgebaut sind, so dass man sich hier Anregungen holen kann.
Oder natürlich direkt Vorschläge, wie man das realisieren könnte, oder 
meine Lösung verbessern könnte.

Eine Beschreibung meiner bisherigen Lösung habe ich angehängt.
Bitte beachtet auch noch meinen Kommentar weiter unten.

: Bearbeitet durch User
von holger (Gast)


Lesenswert?

>und das relativ zügig empfangen
>werden muss, da der Master-Chip nur einen 4-Byte Buffer hat.

Wie bitte? Der Master gibt den Takt vor. Da muss gar nichts
zügig gehen. Ich glaube du machst da irgendwas falsch.

Deine Prosa oben kannst du dir übrigends an die Tapete
kleben. Damit kann niemand was anfangen.

von Peter M. (lctromnml)


Lesenswert?

Danke schnelle Antwort.

1. Nein, ich mache da nichts falsch, es war aber zu knapp beschrieben:

Die Teilnehmer sind:
STM32 Host-uC: SPI-Master
Master-Battery-Management(BMS)-Chip: SPI-Slave (Im ursprünglichen Text 
versehentlich nur als "Master-Chip" bezeichnet.
Weitere BMS-Chips: Per Daisy-Chain mit dem Master-BMS-Chip verbunden

Der STM32 Host-uC (SPI-Master) gibt den Takt vor, in meinem Fall 2MHz. 
Dieser ist mit dem BMS-Master-Chip per SPI verbunden. Dieser BMS-Chip 
ist über die Daisy-Chain mit allen anderen BMS-Chips verbunden und 
sendet neben seinen eignenen Daten auch die aller anderen BMS-Chips (Die 
er selbst über die Daisy-Chain empfängt) per SPI an den STM32 
Host-Microcontroller. Der Master BMS-Chip hat für diese Daten einen 
4-byte buffer.
Die Daten kommen über die Daisy-Chain mit 500kHz. Natürlich gebe ich mit 
dem STM32 Host-Microcontroller den Takt vor, aber wenn ich die Daten 
nicht schnell genug aus dem Buffer des Master-BMS-Chip lese, werden sie 
dort überschrieben (Mit neuen Daten von der Daisy-Chain).
Ich werde das oben im Text nochmal editieren, damit es klarer wird.

2. Ich hätte das Ganze gerne besser beschrieben, Auszüge aus dem 
Datenblatt gepostet etc. Leider ist das Datenblatt komplett als 
"Confidential" markiert und ich kann das nicht machen.
Mir geht es aber auch nicht darum, dass mir hier jemand Code postet. Das 
Coden schaffe ich dann selbst. Mir geht es darum, ob jemand ähnliche 
Protokolle und dafür frei verfügbare Lösungen kennt, Literatur wie man 
solche Probleme lösen kann, etc. Oder eben sich meine Lösung in Prosa 
mal durchlesen will, um mir zu sagen ob das 
scheisse/verbesserungswürdig/was auch immer ist.

Wenn du mir sagst, was genau an der Prosa unverständlich ist, kann ich 
mir gerne sehr viel Mühe geben, dass noch besser zu beschreiben. Ich 
habe hier leider keinen Drucker, kann es somit auch nicht "an die Tapete 
kleben".

von holger (Gast)


Lesenswert?

>aber wenn ich die Daten
>nicht schnell genug aus dem Buffer des Master-BMS-Chip lese, werden sie
>dort überschrieben (Mit neuen Daten von der Daisy-Chain).

In die Tonne treten diesen Schrott. Nicht vorhersehbare Timings
führen eigentlich zwangsläufig zu einem instabilen Programm.
Was ist wenn da mal ein Interrupt dazwischen funkt?

>Leider ist das Datenblatt komplett als
>"Confidential" markiert

Noch ein Grund mehr diesen Schrott in die Tonne zu treten.

von Peter M. (lctromnml)


Lesenswert?

Diese Wahl habe ich nicht.

Unvorhersehbar ist das Timing auch nicht. Der /Data Ready Pin zeigt an, 
wann ein Byte zur Verfügung steht. Die Daten kommen über die Daisy-Chain 
mit 500KHz, per SPI empfange ich mit 2 MHz. Somit ist es grundsätzlich 
kein Problem, alle Daten zuverlässig zu empfangen. Alle Timings werden 
im Datenblatt exakt beschrieben und von mir so auch eingehalten.

IRQs funken da zwangsläufig dazwischen (CAN, Timer, ADC-DMA, USART), das 
führt jedoch zu keinen relevanten Verzögerungen (Dem GPIO IRQ um die 
fallende Flanke an /DATA READY zu erkennen weise ich die höchste 
Priorität zu, per SPI empfangen kann ich dann unabhängig vom Prozessor 
per DMA, dem DMA IRQ kann ich wiederum eine hohe Priorität zuweisen).

von Joe F. (easylife)


Lesenswert?

Wenn eines mit Sicherheit nicht supergeheim ist, ist es wohl die 
Information, um welchen Chip es sich hier handelt.
Kann ja dann jeder selbst im chinesischen Internet auf die Suche nach 
einem Datenblatt gehen... ;-)

SPI dasy chaining stelle ich mir ganz anders vor, als du es beschreibst.
Üblicherweise bilden alle ge-dasy-chainten ICs ein entsprechend langes 
Schieberegister, das mit der vom Host kommenden Clock ausgelesen wird.
"Timing" spielt dabei überhaupt keine Rolle.

von Peter D. (peda)


Lesenswert?

Joe F. schrieb:
> SPI dasy chaining stelle ich mir ganz anders vor, als du es beschreibst.

Ich auch.
Bei SPI dasy chaining wird das MOSI des nächsten mit MISO des Vorgängers 
verbunden.
Will man z.B. aus 4 Chips mit dem 3. sprechen, schickt man an die 
anderen NOP-Befehle.
NOP heißt, leite alle Bytes nur durch und mache nichts.

von Oleg A. (oga)


Lesenswert?

Peter D. schrieb:
> NOP heißt, leite alle Bytes nur durch und mache nichts.

Alle vom Master kommenden Bits werden sowieso durchgeleitet.

von Peter M. (lctromnml)


Lesenswert?

Joe F. schrieb:
> Wenn eines mit Sicherheit nicht supergeheim ist, ist es wohl die
> Information, um welchen Chip es sich hier handelt.
> Kann ja dann jeder selbst im chinesischen Internet auf die Suche nach
> einem Datenblatt gehen... ;-)

Ich habe selbst nochmal nach Datenblättern geschaut. Zu meinem Chip wird 
man wohl nichts finden. Glücklicherweise gibt es einen sehr ähnlichen 
Chip, der, was die Daisy-Chain-Kommunikation betrifft, praktisch genauso 
funktioniert, den Intersil ISL94212.

Hier das Datenblatt:
http://www.intersil.com/content/dam/Intersil/documents/isl9/isl94212.pdf

Ich benutze SPI in "Half-Duplex-Operation" (Datenblatt Seite 32 für 
Daisy-Chain), die Daisy-Chain-Funktionalität inkl. Beispiel-Daten wird 
ab Seite 34 beschrieben.

> SPI dasy chaining stelle ich mir ganz anders vor, als du es beschreibst.
> Üblicherweise bilden alle ge-dasy-chainten ICs ein entsprechend langes
> Schieberegister, das mit der vom Host kommenden Clock ausgelesen wird.
> "Timing" spielt dabei überhaupt keine Rolle.

Dass die ge-dasy-chainten ICs ein entsprechend langes Schieberegister 
bilden ist grundsätzlich richtig. Wie bereits geschrieben handelt es 
sich bei dem Daisy-Chain-Protokoll um ein Proprietäres Protokoll, was 
exakt passiert lässt sich also nicht nachvollziehen. Jedenfalls ist 
diese Daisy-Chain gewissermaßen entkoppelt von der Host-uC/BMS-Master 
SPI Verbindung.

Konkret: Ich sende einen entsprechenden 4-byte Befehl an den BMS-Master. 
Dieser sendet ihn weiter auf die Daisy-Chain wo der Befehl bis zum 
entsprechenden BMS-Chip wandert. Am BMS-Master kommen daraufhin 40 Byte 
an Daten über die Daisy-Chain zurück und werden in einem 4-byte buffer 
gespeichert. Jedes mal wenn ein Byte ankommt gibt es eine fallende 
Flanke an /DATA READY und ich muss dieses Byte per Host-uC aus diesem 
Buffer "raustakten".

Das dies schnell genug passieren muss wird im Datenblatt auf Seite 32 
auch beschrieben:

"A 4 byte data buffer is provided for SPI communications. This
accommodates all single transaction responses. Multiple
responses, such as those that may be produced by a device
detecting an error would overflow this buffer. It is important
therefore that the host microcontroller reads the first byte of data
before a 5th byte arrives on the Master device’s daisy chain port
so as not to risk losing data."

von Peter D. (peda)


Lesenswert?

Peter M. schrieb:
> den Intersil ISL94212.

Achso, das ist ja gar keine SPI-Chain, sondern ein separater 
Erweiterungsbus.
Da hilft wohl nur, sich in das Protokoll gründlich einzulesen.

von Joe F. (easylife)


Lesenswert?

Tja, also einfach wird das nicht werden, den Ansprüchen dieses Chips 
gerecht zu werden.
a) dieses bi-direktionale SPI interface ist nicht wirklich Standard.
b) Zu verhindern, das der 4-byte Buffer überläuft ist eine 
Herausforderung.

Wie viele von diesen Battery-Managern hast du denn?
Ich denke mal, wenn die örtlich nicht besonders weit voneinander 
entfernt sind, wäre es einfacher, alle Battery-Mangager im 
Standalone-Mode zu betreiben.

Du würdest dafür alle an einen ganz normalen SPI Bus hängen (CLK, MOSI, 
MISO + entsprechend viele CS_N).

Alle timingkritischen Punkte, die mit diesem eigentümlichen Dasy-Chain 
Interface zusammen hängen, entfallen dann.

: Bearbeitet durch User
von c-hater (Gast)


Lesenswert?

Joe F. schrieb:

> Ich denke mal, wenn die örtlich nicht besonders weit voneinander
> entfernt sind, wäre es einfacher, alle Battery-Mangager im
> Standalone-Mode zu betreiben.
>
> Du würdest dafür alle an einen ganz normalen SPI Bus hängen (CLK, MOSI,
> MISO + entsprechend viele CS_N).
>
> Alle timingkritischen Punkte, die mit diesem eigentümlichen Dasy-Chain
> Interface zusammen hängen, entfallen dann.

Noch viel sinnvoller wäre, einfach selbst die daysy chain zu betreiben, 
denn dann blieben alle Vorteile der daysy chain Architektur erhalten.

Nur die Nachteile des Konstrukts mit dem zusätzlichen BMS master würden 
ausgemerzt. Und damit eindeutig nachgewiesen, dass der nicht nur völlig 
"über" ist, sondern sogar kontraproduktiv...

Ich frage mich ernsthaft, wie man überhaupt auf die Idee kommen kann, 
das Ding einsetzen zu wollen...

von Peter M. (lctromnml)


Lesenswert?

c-hater schrieb:
> Joe F. schrieb:
>
>> Ich denke mal, wenn die örtlich nicht besonders weit voneinander
>> entfernt sind, wäre es einfacher, alle Battery-Mangager im
>> Standalone-Mode zu betreiben.
>>
>> Du würdest dafür alle an einen ganz normalen SPI Bus hängen (CLK, MOSI,
>> MISO + entsprechend viele CS_N).
>>
>> Alle timingkritischen Punkte, die mit diesem eigentümlichen Dasy-Chain
>> Interface zusammen hängen, entfallen dann.
>
> Noch viel sinnvoller wäre, einfach selbst die daysy chain zu betreiben,
> denn dann blieben alle Vorteile der daysy chain Architektur erhalten.
>
> Nur die Nachteile des Konstrukts mit dem zusätzlichen BMS master würden
> ausgemerzt. Und damit eindeutig nachgewiesen, dass der nicht nur völlig
> "über" ist, sondern sogar kontraproduktiv...
>
> Ich frage mich ernsthaft, wie man überhaupt auf die Idee kommen kann,
> das Ding einsetzen zu wollen...

Die Platinen sind bereits beim Fertiger, dies sind also keine Optionen. 
Ich glaube auch nicht, dass einer von beiden Vorschlägen funktionieren 
würde:

Der Stack besteht aus 288 LiPo-Zellen (144s2p, 12 BMS-Chips, 
Pead-Entladestrom ca. 180 A, Peak-Ladestrom 80 A). Zusätzlich zu 
erheblichen EMV-Störungen ist auch eine gewisse räumliche Distanz 
zwischen den einzelnen Platinen zu überbrücken.

Die Daisy-Chain-Leitung dagegen ist eine differentielle 
Zweidraht-Leitung. Zusätzlich ist, wie im Datenblatt zu sehen, an jedem 
Frame eine CRC4-Checksum, um die Integrität der Daten festzustellen, und 
Kommunikations-Fehler werden von den BMS-Chips erkannt. All dies würde 
bei einer eigenen SPI-Daisy-Chain entfallen, und ich bezweifle dass 
diese EMV-resistent genug wäre (Getestet habe ich es nicht).

Der BMS-Master-Chip ist übrigens auch kein zusätzliches Konstrukt 
sondern überwacht seinerseite 12 Zellen. Siehe Datenblatt Seite 1.

von c-hater (Gast)


Lesenswert?

Peter M. schrieb:

> Die Platinen sind bereits beim Fertiger, dies sind also keine Optionen.

Keine Option? Statt des BMS-Master bestückt man einfach ein paar 
Drahtbrücken zwischen dessen Pads. Das kriegt jeder Fertiger recht 
problemlos hin...

> Die Daisy-Chain-Leitung dagegen ist eine differentielle
> Zweidraht-Leitung.

Aha. Dieses Detail hättest du vielleicht im allerersten Posting erwähnen 
sollen?
OK, ich gebe zu, dass da auch nirgendwo stand, dass es sich um eine 
SPI-daysy chain handelt, sondern nur, dass sie irgendwie proprietär 
wäre.

Aber OK. Dann sind's eben nicht nur ein paar Drahtbrücken, sondern ein 
Sub-PCB mit Diff-Treibern und Empfängern...

> Zusätzlich ist, wie im Datenblatt zu sehen, an jedem
> Frame eine CRC4-Checksum, um die Integrität der Daten festzustellen, und
> Kommunikations-Fehler werden von den BMS-Chips erkannt. All dies würde
> bei einer eigenen SPI-Daisy-Chain entfallen

Wieso? Seit wann kann ein ARM keine CRC's mehr berechnen? Ich meine: das 
können sogar die kleinen AVRs, mit denen ich normalerweise meist 
auskomme, völlig problemlos. Und bei CRC4 spielt die "Proprietärität" 
nicht mal mehr eine nennenswerte Rolle, die paar möglichen Varianten für 
das Generator-Polynom und Startwert hat man beim reverse engineering 
schneller ausgeklingelt, als dein Fertiger ein PCB-Exemplar herstellen 
kann...

> Der BMS-Master-Chip ist übrigens auch kein zusätzliches Konstrukt
> sondern überwacht seinerseite 12 Zellen.

So what? Einfach einen Slave mehr nehmen und alles ist gut. Ohne jede 
Änderung des Layouts der hochwichtigen und praktisch ja wohl bereits in 
100.000er Stückzahlen gelieferten Platine. Denn wären es wesentlich 
weniger, würde man das offensichtliche Fehldesign einfach abschreiben 
und von vorn beginnen...

von Joe F. (easylife)


Lesenswert?

Peter M. schrieb:
> Der BMS-Master-Chip ist übrigens auch kein zusätzliches Konstrukt
> sondern überwacht seinerseite 12 Zellen. Siehe Datenblatt Seite 1.

c-hater schrieb:
> Statt des BMS-Master bestückt man einfach ein paar
> Drahtbrücken zwischen dessen Pads.

;-)

c-haters Vorschlag macht die Sache nur wesentlich komplizierter.
Das Protokoll der Dasy-Chain ist ja komplett undokumentiert.
Das wird ebenfalls bidirektional sein, und die Clock muss im Protokoll 
auch noch eincodiert sein. Das möchte man nicht reverse-engineeren.

Die Aufgabe besteht jetzt halt darin, das zwar etwas ungewöhnliche, 
jedoch gut dokumentierte bidirektionale SPI Protokoll des BMS-Masters zu 
implementieren.

: Bearbeitet durch User
von Peter M. (lctromnml)


Lesenswert?

Joe F. schrieb:
> Die Aufgabe besteht jetzt halt darin, das zwar etwas ungewöhnliche,
> jedoch gut dokumentierte bidirektionale SPI Protokoll des BMS-Masters zu
> implementieren.

Exakt.

Danke für die vielen Vorschläge, aber das hardwaretechnisch zu ändern 
wird nicht funktionieren. Vielleicht hätte ich des von Anfan an 
ausführlicher schildern müssen, ich bin gar nicht auf die Idee gekommen, 
dass jemand die Hardware ändern will:

Die SPI-Verbindung vom Host-uC zum BMS-Master ist galvanisch getrennt. 
Das ist nötig, da die ISLs selbst von den Zellen versorgt werden, der 
Mikrocontoller hingegen vom galvanisch getrennten LV-System.
Sollte, wie von euch vorgeschlagen, der Mikrocontroller jetzt mit den 
anderen ISL Slaves direkt kommunizieren, bedarf es dazu einer 
gemeinsamen Masse.  Direkte Verbindung der negativsten Spannungen eines 
12s Stack in einem 144s (also 12x12s) System ist eher weniger 
zielführend. Man müsste daher also die galvanische Trennung des SPIs
weitere 11x ausführen.
Hinzu kommen die Probleme mit EMV bei einer reinen SPI-Daisy-Chain über 
mehrere Platinen und gewisse räumliche Abstände hinweg. Und dass es 
zeitlich für uns gar nicht möglich ist.

Meiner Meinung nach ist das auch kein Fehldesign sondern sind hier die 
Vorgaben des Herstellers hardware-technisch umgesetzt und müssen jetzt 
eben noch in Software implementiert werden. Grundsätzlich läuft es ja 
schon halbwegs.

Aktuell betreibe ich den SPI noch nicht Interrupt-gesteuert/über den 
DMA.
Ich denke über DMA macht auch nicht viel Sinn, ich könnte ja immer nur 
ein Byte auf einmal senden, da ich beim Befehle senden das Chip Select 
Signal "stroben" muss (High->Low nach jedem gesendeten Byte) und beim 
Empfangen mit /Data Ready synchronisieren muss?

Die Daten schreibe ich einfach in ein globales Array, welches dabei 
immer inkrementiert wird, bis die Anzahl der erwarteten Daten empfangen 
ist. Ist dies der Fall, wird der Index wieder auf 0 gesetzt und die 
Daten werden ausgewertet. Die ankommenden Daten takte ich aktuell noch 
direkt im GPIO Interrupt des /Data Ready Pins raus (immer ein Byte), der 
auf die fallende Flanke konfiguriert ist.

Wenn es hilft, könnte ich versuchen ein paar Code-Abschnitte zu posten, 
ist ziemlich viel, aber vllt. kriege ich es aufs Wesentliche reduziert? 
Hat sonst noch jemand Vorschläge, softwaretechnisch?

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.