ECL-Bus-Decoder: Unterschied zwischen den Versionen

Aus Hobbyelektronik.org
(Paketinformationen hinzugefügt)
Zeile 105: Zeile 105:
 
000000
 
000000
 
000000
 
000000
 
 
</pre>
 
</pre>
  
Zeile 112: Zeile 111:
 
Erwähnenswert ist an dieser Stelle vielleicht noch, dass das LSB (Least Significant Bit) zuerst übertragen wird, was in der AVR-Software bereits berücksichtigt wird.
 
Erwähnenswert ist an dieser Stelle vielleicht noch, dass das LSB (Least Significant Bit) zuerst übertragen wird, was in der AVR-Software bereits berücksichtigt wird.
  
Wie man aus dem Auszug oben erahnen kann, bestehen die Pakete aus 5 Teilpaketen. Aus der blinden Annahme heraus, dass das erste wohl in irgendeiner Form einer Adresse entsprechen muss, habe ich das erste Teilpaket mehrerer Pakete genommen und in einem deutlich längeren (29000 Zeilen) Auszug suchen lassen. Ergebnis: diese Teilpakete wiederholen sich und stehen immer am Anfang eines Pakets - größtenteils sogar periodisch!
+
Wie man aus dem Auszug oben erahnen kann, bestehen die Pakete aus 5 Teilpaketen. Aus der blinden Annahme heraus, dass das erste wohl in irgendeiner Form einer Adresse entsprechen muss, habe ich das erste Teilpaket mehrerer Pakete genommen und in einem deutlich längeren (29000 Zeilen) Auszug suchen lassen. Ergebnis: diese Teilpakete wiederholen sich und stehen immer am Anfang eines Pakets - größtenteils periodisch.
  
Beim weiteren Durchsuchen finden sich folgende Paketköpfe: AF0400, AF0500, AF0600, AF0900, AF1100, EF6000, F00101, F00201, FA0501, FA0601, FA0901, FE6201 und FF0501.
+
Beim weiteren Durchsuchen finden sich folgende Paketköpfe: AF0400, AF0500, AF0900, EF6000, F00101, F00201, FA0501, FA0601, FA0901 und FE6201.
  
 
Auffällig ist hier bereits, dass die ersten beiden Zeichen (Nibbles) nur A, E, F und 0 sind, was schon fast nach Adressen schreit. Zudem ist das letzte empfangene Bit (dargestellt durch ein volles Byte, an der niedrigsten Stelle, da das LSB zuerst übertragen wird) 1, wenn das erste Nibble F ist. Allgemein lässt die Häufigkeit des F vermuten, dass es sich um die Adresse des Reglers handelt.
 
Auffällig ist hier bereits, dass die ersten beiden Zeichen (Nibbles) nur A, E, F und 0 sind, was schon fast nach Adressen schreit. Zudem ist das letzte empfangene Bit (dargestellt durch ein volles Byte, an der niedrigsten Stelle, da das LSB zuerst übertragen wird) 1, wenn das erste Nibble F ist. Allgemein lässt die Häufigkeit des F vermuten, dass es sich um die Adresse des Reglers handelt.
Zeile 121: Zeile 120:
  
 
<pre>
 
<pre>
(vorübergehend leer)
+
AF0500 FF2800 2A0000 000100 060D00
 +
FA0601 002801 2AFF01 FF0101 510D01
 +
AF0500 FF2A00 2A0000 000100 080D00
 +
FA0601 002A01 2AFF01 FF0101 530D01
 +
AF0500 FF2C00 2A0000 000100 0A0D00
 +
FA0601 002C01 2AFF01 FF0101 550D01
 +
AF0500 FF2E00 2A0000 000100 0C0D00
 +
FA0601 002E01 2AFF01 FF0101 570D01
 
</pre>
 
</pre>
  
In dieser Sequenz wurde die Temperatur zuerst auf ..., dann auf ..., ... und ...°C angehoben.
+
In dieser Sequenz wurde die Temperatur zuerst auf 20, dann auf 21, 22 und 23°C angehoben.
Passend hierzu gibt es die Pakete mit den Adressen ... und ... . Betrachtet man die Pakete einzeln, sieht man, dass sich (ungeachtet dem letzten Teilpaket) immer nur das zweite Byte im zweiten Paket ändert.
+
Passend hierzu gibt es die Pakete mit den Adressen AF0500 und AF0601. Betrachtet man die Pakete einzeln, sieht man, dass sich (ungeachtet dem letzten Teilpaket) immer nur das zweite Byte im zweiten Paket ändert.
  
 
Wie der Zufall will, entspricht dieser Wert im Dezimalsystem auch exakt dem, was auf dem Display steht. Durch den Paketverkehr kann man nun auch darauf schließen, dass das Raumleitgerät zuerst an den Regler sendet und dieser dann den gesetzten Wert bestätigt.
 
Wie der Zufall will, entspricht dieser Wert im Dezimalsystem auch exakt dem, was auf dem Display steht. Durch den Paketverkehr kann man nun auch darauf schließen, dass das Raumleitgerät zuerst an den Regler sendet und dieser dann den gesetzten Wert bestätigt.
  
Der Adresskopf folgt also dem Muster <Absender (1 Nibble)><Empfänger (1 Nibble)><Befehl (1 Byte)><Befehl vom Master (1 Bit)>
+
Der Adresskopf folgt also dem Muster <Absender (4 Bit)><Empfänger (4 Bit)><Befehl (8 Bit)><Befehl vom Master (1 Bit)>. Warum im letzten Bit jedes Teilpakets immer übertragen wird, ob das aktuelle Paket vom Master stammt, habe ich bis jetzt noch nicht herausgefunden. Da die Information redundant ist, lasse ich sie im Folgenden außenvor.
  
Nach näherer Analyse der Daten ergab sich folgende Geräteliste
+
Nach näherer Analyse der Daten ergab sich folgende Geräteliste:
  
 
{| class="wikitable"
 
{| class="wikitable"
Zeile 145: Zeile 151:
 
| F || Regler '''ECL 300'''
 
| F || Regler '''ECL 300'''
 
|}
 
|}
 +
 +
== Pakete ==
 +
 +
{| class="wikitable"
 +
|-
 +
! Sender/Empfänger !! Typ !!  Bezeichnung
 +
|-
 +
| AF || 04 || Innentemperatur (ECA 60)
 +
|-
 +
| AF || 05 || Solltemperatur am ECA 60 setzen, Vorübergehende Wechsel (Freie Tage, Urlaub, Entspannen, Abwesenheit)
 +
|-
 +
| AF || 09 || Abfrage Tagesprogramm
 +
|-
 +
| EF || 60 || Temperaturfühler ECA 86
 +
|-
 +
| F0 || 01 || Außentemperatur|-| F0 || 02 || Aktuelle Zeit
 +
|-
 +
| FA || 05 || Solltemperatur am ECL 300 setzen
 +
|-
 +
| FA || 06 || Bestätigung Setzen Solltemperatur (Antwort auf AF05)
 +
|-
 +
| FA || 09 || Tagesprogramm (Antwort auf AF06)
 +
|-
 +
| FE || 62 || Setzen Relais an ECA 86
 +
|}
 +
== AF04 (Innentemperatur) ==
 +
Die Innentemperatur wird nur übertragen, wenn ein ECA 60 angeschlossen ist.
 +
 +
<pre>
 +
AF04  10101011 00001011  00000000 00000000  00000000 00000000
 +
      !!!!!!!! ?!!!!!!!  00000000 00000000  00000000 00000000
 +
</pre>
 +
 +
Im zweiten Byte wird der ganzzahlige Anteil der Temperatur um 1 Bit nach rechts verschoben ausgegeben. Das "fehlende" Bit befindet sich im ersten Byte an höchstwertiger Stelle.
 +
 +
Die Temperatur kann mit der Formel b[1] + b[0]/128 berechnet

Version vom 12. April 2011, 19:27 Uhr

Da mir die Betriebsdatenerfassung unserer Wärmepumpe nicht ganz koscher war, hab ich diese Sache relativ schnell auf die Seite gelegt. Trotzdem hat es mir immer wieder in den Fingerspitzen gekribbelt, dem Gerät doch ein paar Kennwerte zu entlocken.

Wie im Blog erwähnt bin ich durch einen (un)glücklichen Zufall an ein ECA60 von Danfoss gekommen.

In der Bedienungsanleitung der Wärmepumpe entdeckte ich ein paar Schaltpläne, in denen ein externes Sensor-/Alarmmodul samt Busanbindung befindet, die auch an externe Klemmen geführt werden. Die Recherche nach dem mit ECL betitelte Bus lieferte bis auf ein paar kommerzielle Datenwandler keine Ergebnisse. Auch der Support von Danfoss selbst konnte/wollte keine Hilfestellung geben.

Interface

Um die Entwicklung eines Businterfaces zu vereinfachen, habe ich die Platine des Geräts fotografiert und per Bildbearbeitung übereinandergelegt:

Mit etwas Buntstift und Überlegen entstand in EAGLE folgender Stromlaufplan:

Oben wird das Bussignal eingefüttert, an der mittleren CPU-Leitung liegt das auf Vcc + ~0,7V begrenzte Signal, das vom Bus empfangen wird. Die obere und untere Leitung zur CPU dienen offensichtlich dem Senden auf dem Bus. Zuerst (siehe Historie des obigen Bildes) war ich etwas irritiert, warum T1 und T2 den Bus gegen sich selbst kurzschloss. Bis ich gesehen habe, dass dort ein Elko zur Spannungsglättung vorhanden ist. Das machte die Sache deutlich klarer: "Jeder" Teilnehmer im Bus sendet in den Low-Phasen des Trägersignals, indem er die "Restenergie" im Elko zum Senden verwendet. Über T3 kann der Bus (der übrigens mit knapp 27V getrieben wird) gegen GND gezogen werden. Zwar ergibt sich durch den Widerstand von 48kOhm nur ein Strom von 550µA, der dürfte aber reichen, Störeinflüsse bis zu einem gewissen Maß einzudämmen.

Messungen

Der Stromlaufplan lässt aufgrund fehlender Komperatoren/Filter/etc. vermuten, dass - anders als der VBus er mit den Pegeln 0V/Busspannung arbeitet.

Das Oszilloskop ist hier gleicher Meinung:

Das Signal besteht aus einem 50Hz Rechtecksignal, wobei der Duty-Cycle etwa 36/64 ist.

Die Nutzinformationen werden in der Low-Phase des (ich nenne es einfach mal) Trägersignals übermittelt. Hier werden die Daten mit einer Bitlänge von ca. 428µs übertragen. Mit den gemessenen Werten kann man auf 16.8 Bit pro Teilpaket schließen.

Da ich mit meinem Oszilloskop leider keinen vollständigen Datensatz einfangen konnte und die Messversuche mit einer Soundkarte auch nicht besser waren, wurde ein wirklich einfaches Interface - bestehend aus Widerständen und Optokoppler - gestrickt und an den Logic Analyzer angeschlossen.

Nach einer Woche gespannter Leitung quer durchs Haus habe ich selbige durch Leerrohre gelegt. Aus der Toleranz der Familie wird Akzeptanz und der weiteren Bastelei steht nichts mehr im Weg ;-)

Invertiert durch den Optokoppler kommen die Signale wie folgt am LA an:

Ecl la1.png

Zu sehen ist ein komplettes Datenpaket - bestehend aus 5 Paketteilen.

Ecl la2.png

Mit der Hilfe von ein paar Zeitmarken lassen sich die Parameter des PHY etwas genauer bestimmen:

Bitdauer (T2-T1) 0,415ms
Teilpaketlänge (T3-T1) 7,26ms
Inaktiv-Phase (T4-T3) 12,75ms
Periode (T4-T1) 20,01ms

Mit der Bit- und Teilpaketlänge kann nun wieder die Anzahl der Bits im Teilpaket berechnet werden. Unter Berücksichtigung von Jitter kommt man dabei auf 18 Bit, wobei das erste Bit zur Synchronisation immer 0 ist.

Protokollanalyse

Hardware

Da mein Logic Analyzer nicht allzu viel Speicher hat und auch nicht auf den PC streamen kann, half ein AVR (Atmega8 mit 12MHz und Datei:Ecl protokollyse.c) etwas nach:

INT0 löst bei einer steigenden Flanke auf dem Bus aus, deaktiviert sich selbst, löscht das zuletzt empfangene Teilpaket und aktiviert den Timer mit anderdhalb Bit Wartezeit, um ab dem zweiten empfangenen Bit (Sampling in der Mitte) zu lesen.

Im ersten Versuch habe ich die Daten ab dem ersten Bit einlesen lassen, was im Nachhinein ein dummer Fehler war. Zwar konnte ich die Daten korrekt dekodieren, alle Daten waren natürlich um ein Bit verschoben, was aufgrund des stellenweise merkwürdigen Datenaufbau nicht aufgefallen ist.

Im Timer0-Interrupt wird nun insgesamt 17 mal ausgelöst und schiebt jedes empfangene Bit in den Puffer. Beim 17. Bit wird der Timer deaktiviert und INT0 wieder aktiviert, sodass das nächste (Teil-)Paket empfangen werden kann.

Im Main-Loop wird stetig geprüft, ob ein vollständiges Teilpaket empfangen wurde. Wenn dies der Fall ist, werden im Groben die empfangenen Daten hexadezimal ausgegeben. Genauer: da prinzipiell immer leere Datenpakete empfangen werden, wird geprüft, ob die ersten 8 Bit ungleich 0 ist. Ist dies der Fall, werden die nächsten 5 Teilpakete an auf dem UART ausgegeben. Damit wird die Ausgabe deutlich übersichtlicher und die Gefahr, Daten zu verlieren bleibt relativ gering.

Software

Auf der PC-Seite werkelt zunächst Hterm, das die Daten entgegennimmt.

Der Ausgabe sieht in etwa wie folgt aus:

000000
000000
F00201
2C2001
141301
6F6301
370D01
000000
000000
000000
000000
AF0400
2F0A00
000000
000000
EC0D00
000000
000000

die 000000-Blöcke sind in Wahrheit meist deutlich länger, werden aber - wie oben beschrieben - von der Software im AVR gekürzt.

Erwähnenswert ist an dieser Stelle vielleicht noch, dass das LSB (Least Significant Bit) zuerst übertragen wird, was in der AVR-Software bereits berücksichtigt wird.

Wie man aus dem Auszug oben erahnen kann, bestehen die Pakete aus 5 Teilpaketen. Aus der blinden Annahme heraus, dass das erste wohl in irgendeiner Form einer Adresse entsprechen muss, habe ich das erste Teilpaket mehrerer Pakete genommen und in einem deutlich längeren (29000 Zeilen) Auszug suchen lassen. Ergebnis: diese Teilpakete wiederholen sich und stehen immer am Anfang eines Pakets - größtenteils periodisch.

Beim weiteren Durchsuchen finden sich folgende Paketköpfe: AF0400, AF0500, AF0900, EF6000, F00101, F00201, FA0501, FA0601, FA0901 und FE6201.

Auffällig ist hier bereits, dass die ersten beiden Zeichen (Nibbles) nur A, E, F und 0 sind, was schon fast nach Adressen schreit. Zudem ist das letzte empfangene Bit (dargestellt durch ein volles Byte, an der niedrigsten Stelle, da das LSB zuerst übertragen wird) 1, wenn das erste Nibble F ist. Allgemein lässt die Häufigkeit des F vermuten, dass es sich um die Adresse des Reglers handelt.

Da eine blinde Analyse eher mühselig ist, galt es bekannte Werte zu verwenden oder diese einfach zu erzeugen. Über den ECA 60 kann man u. a. die Soll-Raum-Temperatur einstellen. Was liegt also näher, diese zu verändern und auf dem Bus zu lauschen:

AF0500 FF2800 2A0000 000100 060D00
FA0601 002801 2AFF01 FF0101 510D01
AF0500 FF2A00 2A0000 000100 080D00
FA0601 002A01 2AFF01 FF0101 530D01
AF0500 FF2C00 2A0000 000100 0A0D00
FA0601 002C01 2AFF01 FF0101 550D01
AF0500 FF2E00 2A0000 000100 0C0D00
FA0601 002E01 2AFF01 FF0101 570D01

In dieser Sequenz wurde die Temperatur zuerst auf 20, dann auf 21, 22 und 23°C angehoben. Passend hierzu gibt es die Pakete mit den Adressen AF0500 und AF0601. Betrachtet man die Pakete einzeln, sieht man, dass sich (ungeachtet dem letzten Teilpaket) immer nur das zweite Byte im zweiten Paket ändert.

Wie der Zufall will, entspricht dieser Wert im Dezimalsystem auch exakt dem, was auf dem Display steht. Durch den Paketverkehr kann man nun auch darauf schließen, dass das Raumleitgerät zuerst an den Regler sendet und dieser dann den gesetzten Wert bestätigt.

Der Adresskopf folgt also dem Muster <Absender (4 Bit)><Empfänger (4 Bit)><Befehl (8 Bit)><Befehl vom Master (1 Bit)>. Warum im letzten Bit jedes Teilpakets immer übertragen wird, ob das aktuelle Paket vom Master stammt, habe ich bis jetzt noch nicht herausgefunden. Da die Information redundant ist, lasse ich sie im Folgenden außenvor.

Nach näherer Analyse der Daten ergab sich folgende Geräteliste:

Adresse Überschrift
0 Broadcast
A Raumleitgerät ECA 60
E Alarm- und Temperaturüberwachungsmodul ECA 86
F Regler ECL 300

Pakete

Sender/Empfänger Typ Bezeichnung
AF 04 Innentemperatur (ECA 60)
AF 05 Solltemperatur am ECA 60 setzen, Vorübergehende Wechsel (Freie Tage, Urlaub, Entspannen, Abwesenheit)
AF 09 Abfrage Tagesprogramm
EF 60 Temperaturfühler ECA 86
F0 01 -| F0 02 Aktuelle Zeit
FA 05 Solltemperatur am ECL 300 setzen
FA 06 Bestätigung Setzen Solltemperatur (Antwort auf AF05)
FA 09 Tagesprogramm (Antwort auf AF06)
FE 62 Setzen Relais an ECA 86

AF04 (Innentemperatur)

Die Innentemperatur wird nur übertragen, wenn ein ECA 60 angeschlossen ist.

AF04  10101011 00001011  00000000 00000000  00000000 00000000
      !!!!!!!! ?!!!!!!!  00000000 00000000  00000000 00000000

Im zweiten Byte wird der ganzzahlige Anteil der Temperatur um 1 Bit nach rechts verschoben ausgegeben. Das "fehlende" Bit befindet sich im ersten Byte an höchstwertiger Stelle.

Die Temperatur kann mit der Formel b[1] + b[0]/128 berechnet