Hallo zusammen,
Da mein DMX-Krempel auf mehr Interesse als erwartet stieß, habe ich vor
kurzem auf RDM (s.u.) aufgerüstet.
Leider schluckt der Code beinahe 2kB, was ein Viertel vom
Programmspeicher eines mega8 oder mega8515 ist.
Da etliche Geräte sogar nur den TINY2313 verwenden, ist dies wohl
letztlich einfach zu viel...
Ich habe bereits ziemlich in die Trickkiste gegriffen und am Code
gefeilt - hoffe aber, dass Ihr noch ein paar Einfälle habt.
(Als angehender Maschi habe ich programmiertechnisch ja auch nicht die
Weisheit mit Löffeln gefressen...)
Die ISRs sollten neben der geringen Codegröße natürlich auch möglichst
flott sein.
Bei den anderen Funktionen spielt Geschwindigkeit keine derart
wesentliche Rolle.
Erläuterungen zu dem Code:
http://www.hoelscher-hi.de/hendrik/light/ressources/AN017.pdf
Der Code selbst:
http://www.hoelscher-hi.de/hendrik/light/ressources/rdm_in.zip
(Ansich ist nur die lib_rdm_in.c und der Header interessant...)
Tausend Dank im Voraus!
Hendrik
Hier noch etwas Hintergrund, was aber nicht unmittelbar wichtig ist:
RDM (remote device management) ist eine Erweiterung des DMX512
Lichtsteuerprotokolls und durch die ANSI E1.20 spezifiziert.
(Ich darf sie aber wohl aus Copyright-Gründen nicht hochladen...)
Durch RDM können angeschlossene Geräte konfiguriert werden und auch
Status- und Fehlerinformationen können ausgelesen werden.
RDM ist paketbasiert: Der Controller sendet ein Paket via RS485 an einen
Responder und der antwortet.
Der Ablauf geschieht folgendermaßen:
Der Controller ermittelt die angeschlossenen Geräte über eine
Discovery-Prozedur, bei der an alle Geräte eine Nachricht mit einem
MAC-Adressbereich (Untergrenze, Obergrenze) gebroadcastet wird.
Liegt die MAC eines Empfängers im Bereich antwortet er mit seiner
encodierten Mac. (Da mehrere Empfänger antworten, bekommt der Controller
also einen üblen Datensalat...)
Nun engt er den Adressbereich immer weiter ein, bis nur noch ein
Empfänger antwortet, der dann gemuted wird. (Treesearch)
Sind alle Empfänger identifiziert, kann der Controller ein Paket gezielt
verschicken:
RDM start code (0xCC)
RDM sub start code (0x01)
Paketlänge
Zieladresse
Quelladresse
Typ des Paketes (Discovery, Ändern eines Parameters, Auslesen eines
Parameters)
ID des Parameters
Länge der Daten des Parameters
Datenfeld
additive Checksumme
Es gilt dabei MSB first.
Leute, die mir bei der Optimierung helfen, werde ich gern mit als Autor
aufführen (wenn gewünscht).
Viel Kleinkram...
Um zu beurteilen, wo Potential liegt, ist eigentlich ein Blick in den
erzeugten Assembler notwendig. Weil die Software auf unterschiedlichen
µC und auch verschiedenen Compiler-Versionen laufen soll (auch ältere
gcc-Versionen sowie kommende), die Teilweise anderes Verhalten zeigen
werden, sind allgemeint Tipps sehr schwer zu geben.
Immerhin will man ja in C proggen, weil das halbwegs unabhängig ist von
der Hardware, anstatt C als portierbaren Assembler zu verwenden.
Ok, genug Prosa.
-- Winz-Funktionen wie swapInt fühlen sich sehr warscheinlich wohler als
static inline, bzw. der Aufrufer hat ne deutlich bequemere
RegisterlAllokierung.
-- isHigher ist als isLower doppelt vorhanden. Eine Vergleichs-Func, die
je nach Gemengelage -1, 0 oder 1 liefert, ist evtl. praktikabler.
-- getMsgP gibt's als memcpy_P, was wehlt ist nur Rumgecaste
-- RxState ist volatile und Du machst 1000 Zugriffe, zB in einer ISR.
Das ist sau teuer! --> Auf lokaler, temporärer Kopie arbeiten! Dito
für den Mini-Zoo an anderen Globals -- dazu gehören evtl. auch
Komposit-Elemente von Globals.
Siehe auch
Beitrag "Bitte um Hilfe bei Code-Optimierung"
-- Indirekter Zugriff in C wird nicht unbedingt zu (möglicherweise
platzsparenderem als direktem Zugriff) indirektem Zugriff in Assembler.
Erkläuterungen dazu gibt's ebenfalls hinter obigem Link.
Zum Code:
Die ISRs sollen flott sein? delay-Zeug hat nix in einer ISR zu suchen,
zumindest nicht bei deaktivierten IRQs und wenns schnell sein soll. In
einer ISR IRQs zuzulassen und damit eine Prioritäts-Zwischenschicht
einzuziehen ist möglich (hab ich in fast all meinen AVR-Anwendungen),
das will aber genau überlegt sein.
Es soll ja vermutlich noch ne Anwendung laufen, die Dein Zeug benutzt.
Wenn die härtere Echtzeit-Anforderungen hat, kann sie diese wegen der
erhöhten IRQ-Latenz uU nicht erfüllen.
Zunächst einmal Vielen Dank, Johann!
Die Tipps der static inline Deklaration und memcpy_P werde ich später
mal einbauen.
Die Vergleichsfunktionen könnten etwas frickelig werden. Ich hatte dies
schon mal versucht und wahrscheinlich einen Denkfehler bei den
Abbruchbedingungen...
Bei der Verwendung von RxState hast Du Dich wahrscheinlich verguckt:
Bei jedem Durchlauf lese ich ein Mal den Wert ein und schreibe ein Mal
einen Wert zurück. Der Compiler lädt dazu direkt den Wert in ein gerade
freies Register und kopiert es direkt ins RAM. Der Compiler arbeitet da,
meine ich, optimal...
In allen anderen Fällen (echte Mehrfachzugriffe) hast Du vollkommen
Recht und ich lege lokale Kopieen an. (Falls nicht, ist das ein Fehler
von mir.)
Zum indirekten Zugriff:
Ich hatte zuvor mit Pointern gearbeitet, der GCC scheint den jetzigen
Zugriff aber lieber zu mögen... (Es sei denn, ich habe Denkfehler
gemacht und dadurch Overhead verzapft.)
Deinen Link habe ich vor meinem Thread schon durchgearbeitet - er war
eigentlich der Anlass, so einen Thread auch einmal zu versuchen...
Zur TxISR:
Ich bin eigentlich über Delays (besonders in ISRs) genauso verärgert wie
Du. Der Hintergrund hier ist:
Ich muss den Bus noch 20us IDLE halten, damit der Controller keine EMV
als weitere Daten interpretiert. Warte ich kürzer, bekommt der
Controller evtl Probleme - warte ich deutlich länger, verpasse ich evtl.
ein folgendes Paket, falls der Controller zu schnell sendet.
Ich kann also nicht einfach sofort wieder auf Empfang schalten.
Ich kann auch nicht einen Counter für das Hauptprogramm starten, da ich
dort keinen wirklichen Einfluss auf das Zeitverhalten habe.
Ich möchte eigentlich auch keinen Timer opfern.
Was bleibt mir dann noch??
(Als Entschuldigung sei gesagt, dass das Delay nur ein Mal pro zu
beantwortendem Paket stört - also fast nie...)
Nochmals Danke!
Hendrik
Das ursprüngliche Projekt brauchte 1712 Bytes.
Die Deklaration der Winz-Funktionen als static inline führte zu 1630
Bytes.
Die Nutzung von memcpy_P anstatt meine eigenen Funktion führte zu 1628
Bytes.
Das ist jetzt noch kein gewaltiger Sprung - aber doch ganz nett :-)
Viele Grüße,
Hendrik
Der Compare-Vergleich nach chris führt zu 1628 Bytes (identische Größe).
(Entweder gibt es automatisches Inlining oder die Funktion ist
aufwendiger als mein Konstrukt - müsste ich mir noch einmal im
Disassembler anschauen.)
Ich befürchte langsam, dass ich an genau der Stelle wohl nicht Hunderte
von Bytes einsparen kann...
Oder kennt jemand eine Alternative zu den delays in den ISRs für
konstante inter byte gaps und den Senderichtungswechsel?
Vielen Dank für Eure Mühe bislang,
Hendrik
Bin ich richtig in der Annahme, daß dein Code ge-Inlined wird, und
compare nicht. Bei den Switch Anweisungen lassen sich ca 100-200 bytes
einsparen, aber das ist zu wenig.
@chris:
so ist es. Deinen Code brauche ich zwei Mal; bei mir jeden Vergleich ein
Mal. Deshalb wird compare wohl nicht ge-inlined...
Der Ersatz von switch (Sprungtabelle) durch einzelne Bedingungen machte
die RxISR ein Stück langsamer und der switch in der Auswertung wird in
einzelne Bedingungen aufgelöst.
@Henne
Habe gerade bemerkt, daß du compare nur 2x aufrufst, wobei es 3x sein
sollte, ich glaube forUs fehlt dir. Weiters könnte man die Konstante in
compare laden, so spart man sich ein paar bytes. Auch eventuell
mitgeben,
auf was getestet werden muß, muß man sich anschauen, ob das was bringt,
aber du hast recht, es bringt weniger als ich vermutete.
Achso, habe einen fehler drin, res muß signed und nicht unsigned sein.
@chris:
In "forUs" teste ich gleichzeitig auf einen broadcast - Da würde ich
nicht viel raus holen können...
Mit der Konstanten hast Du natürlich Recht - verbessert aber nichts, wie
ich gerade gesehen habe.
Viele Grüße,
Hendrik
--swapInt ist überflüssig, weil nur gegen Compilezeit-Konstanten
verglichen wird. Man kann den swap also vom Compiler auf den Konstanten
machen lassen.
-- isLower und isHigher werden nur 1x verwendet. Wenn die auserhalb
nicht gebraucht werden, reicht ne Deklaration als static zum Inlinen.
-- RxCount_16 in der einen ISR fühlt sich wohler als lokale Auto.
Moin Johann,
swapInt wertet die Bedeutung eines eintreffenden Paketes (also die PID)
aus. Ich kenne die einzelnen Pakete, die später bei meinem Gerät
eintreffen, nicht zur Compilezeit...
Man könnte allerdings die PID-Definitionen im Header umdrehen.
Allerdings würde ich dann gegen die Norm verstoßen, weil ich für mich
die PIDs geswappt haben möchte. Das dürfte dann bei PID-Erweiterungen
von Dritten für ordentlich Verwirrung sorgen, oder?
In RxCount_16 werden im DMX-Betrieb die eintreffenden Bytes bis zum
Erreichen der Startadresse runtergezählt. Im RDM-Betrieb wird darin die
additive Checksumme gebildet. Sie muss also im RAM gehalten werden.
Bislang dachte ich, es mache keinen Unterschied, ob ich solche Variablen
global in der Datei angebe oder innerhalb der Funktion als statisch
markiere. Da werde ich noch einmal schauen...
Vielen Dank,
Hendrik
Der Unterschied zwischen den Deklarationen ist, dass ich bei lokal und
static nicht außerhalb der Funktion auf die Variable zugreifen kann. Ich
meine, dies wäre im Sinne der Data Encapsulation - ich seh da allerdings
keinen Vorteil für mich. Bei größeren Dateien sieht das bestimmt anders
aus...
@Michael,@Henne:
Ich kenne jetzt nicht die gesamte Anwendung aber durch das
Auskommentieren verändert sich das Verhalten der Funktion und unter
Umständen das Ergebnis.
DevID[] = {0,1,1}
buf[] = {1,0,1}
isHiger()_original liefert 0
isHigher()_modifiziert liefert 1
Falls ich mich jetzt nicht gerade vertue...
Hallo,
einiges scheinen Manchestercodiert zu sein, andere nicht.
ev. schick mir die RDM pdf auf scoxo3511514@yahoo.com, wobei
die o und der 5 wegzulassen sind, vor dem domain.
Habe ein paar optimierungideen bez. Messages, aber ohne Hintergrundinfo,
ist es ein heikles thema.
Henne wrote:
> swapInt wertet die Bedeutung eines eintreffenden Paketes (also die PID)> aus. Ich kenne die einzelnen Pakete, die später bei meinem Gerät> eintreffen, nicht zur Compilezeit...
Brauchst auch nicht.
Anstatt
1
switch(SWAP(var))
2
caseA:
3
caseB:
geht doch
1
switch(var)
2
caseSWAP(A):
3
caseSWAP(B):
wobei in der zweiten Skizze SWAP zur Compilezeit auswertbar sein muss
und dann auch zur CZ ausgewertet wird. Das spart also Laufzeit und
Platz.
> Man könnte allerdings die PID-Definitionen im Header umdrehen.
Könnte man muss man aber nicht wie eben skizziert.
> In RxCount_16 werden im DMX-Betrieb die eintreffenden Bytes bis zum> Erreichen der Startadresse runtergezählt. Im RDM-Betrieb wird darin die> additive Checksumme gebildet. Sie muss also im RAM gehalten werden.> Bislang dachte ich, es mache keinen Unterschied, ob ich solche Variablen> global in der Datei angebe oder innerhalb der Funktion als statisch> markiere. Da werde ich noch einmal schauen...
Das macht auch keinen Unterschied. Zumindest, was Resourcen-Verbrauch
angeht.
Gemeint ist's so wie im Anhang in der einen ISR: Man operiert auf einer
lokalen auto Variablen (nicht auf einem Static!). Gelesen und
Geschrieben wird nur 1x, am Anfang und am Ende. Das typeof() ist
Faulheit, würd ich in der Endversion nicht verwenden.
Bei vielen Zugriffen auf das gleiche Ding spart man so Zugriffe, die der
Compiler nicht immer wegoptimiert (oder nicht wegoptimieren darf wenn
das Ding volatile ist). Um abzuwägen, ob sich das lohnt, schaut man das
Listfile durch. "Nester" mit den 4-Byte-Zugriffen ins RAM sind beim
Drüberscrollen schnell zu erkennen, weil sie aus den normalen
2-Byte-Zugriffen vorstechen. Wird in einer Funktion oft auf die selbe
Adresse gegriffen, ist's ein potentieller Kandidat.
Kosten für die lokale Variante sind die Regs, in denen man das Datum
halten muss. In einer ISR muss das Reg zudem immer gesichert werden im
Gegensatz zu einer normalen Funktion, wo nicht alle Regs gesichert
werden mussen, und ein Umbau sich eigentlich immer lohnt, wenn noch
call-used-Regs frei sind und die Funktion ein Blatt im Call-Baum ist.
Johann
@chris:
Es gibt nirgendwo eine Manchestercodierung...
@Gast:
Das Original ist richtig. Ich brauche die Abbruchbedingung, da ich
andernfalls die Vergleichsergebnisse der höher wertigen Bytes nicht
berücksichtige.
@Johann:
Die Idee mit der Swapumstellung ist vielversprechend. Mal schaun...
Die "Nester" räucher ich eigentlich immer wie du es beschrieben hast aus
- von daher wird es mich wundern, wenn ich da viel hohle.
Was mir derzeit keine Ruhe lässt sind die delays:
Mit 5us könnte ich noch leben - aber die 20 sind wirklich etwas viel.
Wäre ein Sperren des TxC-IRQs, danach ein sei und dann die Schleife
vertretbar?
- halbwegs definierte Umschaltzeit des Ports
- keine ungewollten rekursiven Aufrufe der TxISR
- andere Interrupts freigegeben
Henne schrieb:
> Was mir derzeit keine Ruhe lässt sind die delays:> Mit 5us könnte ich noch leben - aber die 20 sind wirklich etwas viel.> Wäre ein Sperren des TxC-IRQs, danach ein sei und dann die Schleife> vertretbar?
Seh ich kein Problem. Vor Verlassen der ISR muss der IRQ aber wieder
aktiviert werden, davor ein CLI.
Auch möglich, ist am Ende der ISR abzudesten, ob das IRQ-Flag schon
wieder gesetzt ist. Gegebenenfalls wird das Flag gelöscht in der ISR
geschleift. Weil bei gesetztem IRQ-Flag die ISR eh nach Verlassen wieder
angesprungen würde, spart diese Technik Zeit, nämlich einen ISR-Epilog
und -Prolog.
In Deinem Fall braucht man diese Technik aber kaum. CLI und
IRQ-reaktivieren sollte vollauf genügen.
Bei der Methode steigt die ISR-Tiefe um Eins, was bei der ISR, um die es
geht, aber kaum was ausmacht. Die braucht ja nur ne handvoll Bytes aufm
Stack, das sollte auch bei 128 Bytes RAM unkritisch sein.
Hallo Henne,
ich greif das Thema nach langer Zeit mal wieder auf. Bin auch grad dabei
eine RDM Implementation für einen Mega 162 controller zu schreiben.
Deswegen habe ich mir deinen Code mal angesehen. Hab das auch soweit
umgeschrieben bekommen das ich es auf dem Mega 162 ans laufen bekomme.
DMX empfang läuft. RDM geht leider noch nicht.
Kann es sein das du die Checksumme für die "discover unique branch"
respond Message nicht richtig berechnet wird. Laut Ansi 1.20 steht da
drin "Checksum is the sum of the previous 12 EUID slots. The checksum is
an unsigned additive sum of the 8-bit fields into a 16-bit response
value."
In deinem code adierst du aber den preamble auch mit hinzu. und jede
EUID auch nur einmal.
Hast du das ganze schon mal mit einer echten RDM Anwendung getestet?
Ich habe im Moment das Enttec RDM USB Pro Interface zum probieren hier.
Mein controller Empfängt die RDM Pakete und sendet auch was zurück. Aber
der Enttec RDM Controller findet das Device nicht.
Und beim DMX Empfang würde ich auch noch nen kleinen schönheitsfehler
ausbügeln. In Zeile 427 würde ich >= schreiben weil es sonst seihen kann
das wenn du den letzten DMX Kanal abgreifen kannst der Status nicht
gewechselt wird.
case STARTADR_DMX:
DmxField[RxCount_8++]= DmxByte; //get channel
if (RxCount_8 > sizeof(DmxField))
{
Flags |= (1<<EVAL_DMX); //reception finished
RxState = IDLE; //all ch received -> wait for
break
}
break;
Wenn Du die Lib mit dem Enttec-Controller zum Laufen gebracht hast,
würden mich die Änderungen interessieren.
Die Discovery und die Adressvergabe hatten bei mir damals funktioniert -
das Auslesen der Device-Eigenschaften wollte jedoch nicht.
Also ich schau mir das mit der Checksumme noch mal an. Habs gestern dann
auch noch soweit geschafft das mein RDM Device schon mal erkannt wird.
Die ID wird im Enntec Tool angezeigt. Und dann meldet er die meiste Zeit
"Selected Device did not respond to the DEVICE_INFO, No Information to
display, Refer to the Manual for more info"
Aber ich habs auch schon gehapt das er alle Parameter richtig ausgelesen
hat. Ist aber mehr sporadisch. Das blöde ist ich kann nicht gleichzeitig
RDM senden und mit dem Interface den Datenstrom mitsniffen. Aber
irgendwie wird das wohl auch noch zum laufen zu bringen sein. :-)
Wenn ich was rausfinde sag ich auf jeden Fall bescheid. Muss den Code
dann auch noch etwas aufräumen. Wollte das eigentlich auch dann noch so
machen das man das ganze noch etwas leichter für andere Prozessoren der
AVR Reihe anpassen kann.
@Christian:
Jetzt sind wir mit dem Enttec-Teil genau auf demselben Stand.
Ich hatte deswegen auch schon bei rdmprotocol.org gepostet, wo mir
empfohlen wurde, die Daten mit einem Oszi anzuschauen und die Pakete
nachzurechnen.
(Was anderes ist ja auch schlecht möglich...)
Selbstverständlich habe ich auch als erstes die Response-Pakete nochmal
durchgesehen (Oszi bringt mir dabei nicht viel): Es wird gesendet, was
ich nach meiner Interpretation der E1.20 glaube, senden zu müssen.
Abgesehen davon, sollte sonst nie irgendein Paket korrekt behandelt
werden...
Evtl. ist es sinnvoll, mit einem zweiten Rechner und meinem
"OpenRDM"-Dongle den Bus mal abzuhorchen und vielleicht doch mal mit
einem Oszi nachprüfen, wie sich der Bus während der Port-Turn-Arounds
verhält. (Eigentlich müsste er über einen Pullup im ENTTEC-IF auf IDLE -
also HI - gehalten werden.)
Ich bin auf jeden Fall für alles dankbar - ich kann zwar mit meinen
eigenen Systemen RDM fahren, möchte aber natürlich zum offiziellen
Standard kompatibel sein.
VG,
Hendrik
Ich hab auch noch mal deine Paketreihenfolge mit dem Protokoll
verglichen. Sieht eigentlich gut aus was du da rauschickst. Hab auch
schon nen bißchen mit dem AVR simulator rumprobiert. Aber ich denke auch
mal das es nen Timing Problem oder sowas ist. Weil er mir halt auch
gestern zeitweise auch schon mal sämtliche Daten im enttec Programm
dargestellt hat.
Aber ich werd mir jetzt wohl erstmal noch dein OpenRDM-Dongel bauen
damit ich das vernüftig Sniffen kann. Ich kann mit dem Enntec Interface
ja leider nicht gleichzeitg RDM senden und die Pakete Analysieren. Aber
werd dann mal mit deiner Software RDM Daten schicken und schauen was der
Enttec RDM Sniffer dazu sagt. Ozzi hab ich auch da. Muss ich mal auf den
Pin triggern der die Sendeumschaltung macht und gleichzeitig die Daten
anschauen. Vielleicht krieg ich dann auch schon was raus.
Meistens ist es ja immer nur ne Kleinigkeit die einem Kopfschmerzen
bereitet.
Gruß
Christian
@Christian:
Ich glaube, ich habe noch ein fertiges Modul bei mir liegen. Wenn Du mir
Deine Adresse mailst, kann ich es Dir für die nächsten Monate gegen
Erstattung der Versandkosten leihen.
Meine eMail-Adresse findest Du auf meiner Seite.
VG,
Hendrik
@ Hendrik
Danke für das Angebot und fürs rausuchen des Moduls. Aber ich denk mal
ich werd mir das heute mal Anhand deines Schaltplans zusammen basteln.
Der Materialwert liegt ja doch etwas unter 33 Euro. Und so hab ich noch
nen bißchen was zu löten. Hab mir schon die passenden ICs besorgt. Von
daher muss ich mir nur noch die Platine basteln. Aber Layout hab ich
gestern schon gemacht.
Hab gestern auch noch mal vorm Ozilloskop gesessen und gemessen. Aber so
richtig nen Fehler erkennen konnte ich bisher nocht. Ist halt auch nicht
so einfach damit nen Datenstrom zu analysieren. Aber ich denk mal wenn
ich den RS485 umsetzer fertig hab sieht man weiter. Hab zwar hier
haufenweise normale DMX Interfaces zum Testen. Aber das hilft einem bei
RDM leider auch nicht wiklich weiter. (Arbeite für meine Lichtsteurungen
unter anderem mit Martin Lightjockey, Ecue und seit neustem Cuelux. Ecue
hat zwar angekündigt im laufe des Jahres auch RDM zu unterstüzen. Aber
bisher ist mir da noch keine Version bekannt die das unterstüzt.
Meinen Schaltplan würde ich mittlerweile etwas erweitern:
In der E1.20 ist in einem Anhang die Bus-Termination dargestellt, so
dass er während der Port Turn-Arounds hochohmig auf IDLE hängt. Diese
Widerstandsanordnung sollte übernommen werden.
Tx und Rx LEDs würde ich auch noch spendieren.
Falls es hakeln sollte: mein Angebot steht noch.
VG,
Hendrik
So, USB --> RS485 Umsetzer hab ich aufgebaut und fertig am Laufen. Inkl.
LEDs und Widerstandskette.
Hab dann also den neuen Dongel mit deiner Software zum discovern und
Datenabfragen verwendet. Funktioniert soweit auch wunderbar. Dann hab
ich das Enttec interface als Sniffer geflasht und die Daten mit der
Enntec Sniffer Software mitgelockt.
Die gute Nachricht ist, die Daten die übertragen werden sind soweit ok.
Also die Pakete passen von den Anzahl und Cheksumme.
Aber er meckert bei mir jedes Paket mit nem Timing fehler an. (Sowohl
die gesendeeten vom PC wie auch die Response Nachrichten)
Jetzt muss ich der Sache mal noch weiter auf den Grund gehen. Die
Leitung floatet auf jeden Fall nicht. Haben jetzt immer nen definierten
Zustand drauf.
Ich werd mal noch nen bißchen experementieren. Sollte wohl in den Griff
zu bekommen sein.
MfG
Christian
Auf der FTDI-Seite wirst Du nicht viel machen können:
Der Port Turn-Around erfolgt automatisch.
Interbyte Gaps sind nicht möglich.
Der Break dauert mind. 1,X ms, da die Frequenz, mit der die USB-Pakete
verschickt werden, wohl nicht mehr hergibt.
Laut E1.20 dürfte ich aber eigentlich keine Grenzwerte verletzen.
Auf der AVR-Seite haben wir freie Hand.
Danke schonmal für das bisherige Feedback!
Hendrik
So, komme jetzt auch langsam mit den ganzen Features der Enttec Sniffer
Software klar. Also auf der FTDI Senderseite macht er folgende
Fehlermeldung:
RDM Paket: Timing Error
Recorded Breakt Time: 2973 usek
Allowed Break Time: Controller (176 usek --- 352 usek)
Refer: Page 8, Table 3-1, Line 1&2 (RMD Spec)
Timestamp(us) Count Event Data
0 - Start Break -
2973 - End Of Break -
5061 1 Data CC
5105 2 Data 01
5149 3 Data 18
5193 4 Data FF
5237 5 Data FF
5281 6 Data FF
5325 7 Data FF
5369 8 Data FF
5413 9 Data FF
5457 10 Data 41
5501 11 Data 64
5545 12 Data FF
5589 13 Data 00
5633 14 Data 00
5677 15 Data 01
5721 16 Data 01
5765 17 Data 01
5809 18 Data 00
5853 19 Data 00
5897 20 Data 00
5941 21 Data 10
5985 22 Data 00
6029 23 Data 03
6074 24 Data 00
6116 25 Data 08
6160 26 Data 99
Wobei die Zeit über nen ganzen Datensatz auf Senderseite zwischen 2000
und 3000 usek liegt.
Wenn du sagst der Break liegt da immer bei mindestens 1,xx ms. Dann
überschreitet man natürlich immer die Zeit. (Die Angabe aus der Ansi
1.20 stimmen) Aber ist ja auch erstmal nicht so tragisch. Zu Testzwecken
reicht einem das natürlich erstmal.
Auf AVR Seite habe ich derzeit erstmal die Delayzeiten rausgenommen die
du eingepglegt hast. Dann hab ich mal mit der Baudrate für den Break
gespielt. (90,9k)
Mit deiner Einstellung produziert er folgenden Fehler:
RDM Paket: Timing Error
Recorded Breakt Time: 110 usek
Allowed Break Time: Controller (176 usek --- 352 usek)
Refer: Page 10, Table 3-3, Line 1&2 (RMD Spec)
Hab das dann mal angepasst auf z.B. (voher UBRR0L = 0x05;) auf UBRR0L =
0x11;
Dann meldet er keine Fehler auf AVR Seite im Sniffer:
Timestamp(us) Count Event Data
0 - Start Break -
326 - End Of Break -
402 - Start Code CC
452 1 Data 01
501 2 Data 1A
551 3 Data 41
601 4 Data 64
651 5 Data FF
703 6 Data 00
752 7 Data 00
801 8 Data 01
851 9 Data 12
901 10 Data 34
951 11 Data 56
1005 12 Data 78
1054 13 Data 9A
1103 14 Data BC
1151 15 Data A8
1201 16 Data 00
1251 17 Data 00
1301 18 Data 00
1351 19 Data 00
1405 20 Data 11
1453 21 Data 00
1502 22 Data 03
1551 23 Data 02
1601 24 Data 00
1651 25 Data 00
1701 26 Data 05
1755 27 Data B4
Dann hab ich mit der Firmware im AVR mal wieder den RDM Controller
gestartet und nen Discovery gemacht. Immer noch Fehler:
"Selected Device did not respond to the DEVICE_INFO, No Information to
display, Refer to the Manual for more info"
Das ist dann allerdings merkwürdig. Wenn der Sniffer sagt das jetzt das
Timing im grünen Bereich liegt, sollte es ja eigentlich sauber laufen.
Muss ich wohl noch etwas weiter tüffteln.
Erst einmal vielen Dank für das Timing des Response Break! Das werde ich
heute anpassen.
Mögliche Fehlerquelle bei device info request:
Wenn ich nach der Discovery gemuted werde, antworte ich nicht auf eine
Device Info Request (oder irgendetwas anderes)
Darf ich also zum Zeitpunkt der Anfrage überhaupt antworten oder bin ich
gemuted?
VG,
Hendrik
(Es gibt zum Muting die Interpretationen, dass es sich nur auf die
Discovery oder auf alles außer Mute/Umute bezieht. Ich schließe mich der
letzteren an, um sicherzustellen, dass meine Geräte nie aus Versehen
dazwischenquaken...)
Also das Muting bezieht sich meiner Meinung nach nur auf Discovery
Messages. Der Trick an der Sache ist ja das ein Device normal nur
Antwortet wenn es angesprochen wird.
Wenn man aber nicht die IDs der Geräte kennt werden alle Geräte unmuted
per Broadcast. Dann spricht man einen bestimmten Adressbereich an und
schaut ob jemand Antwortet. Wenn man ein vernüftiges Paket bekommt mit
gültiger Checksumme dann hat man auch eine gültige ID. Man spricht also
das erkannte Device an und schickt ihm eine Mute Message. Wenn das
Device dieser erhält, reagiert es ab sofort nicht mehr auf Discovery
Messages und sendet eine Respond das es den Mute Befehl verstanden hat.
Jetzt ist dieses Device in dem Adressbereich Still wenn man ihn noch mal
anspricht. Sollten jetzt noch andere Devices in dem Bereich seihen
werden diese Antworten.
Bekommt man bei der Abfrage keine gültige Nachricht zurück weil zwei
Geräte gleichzeitig Antworten, muss man den Adressraum einschränken.
Solange bis man ein gültiges Paket bekommt. Wenn niemand antwortet geht
man davon aus das der Adressbereich in dem man sucht frei ist.
Generell muss jedes Device immer Auf eine geziehlte Anfrage mit der
passenden ID reagieren. Damit man testen kann ob es noch da ist. Das
Muten gibts meiner meinung nach nur damit man halt bei der Erkennung
erkannte Geräte ausblenden kann. Aber man möchte natürlich nach der
Erkennung der "Seriennummern" anschliessend die Gerätedaten auslesen.
Von daher macht es ja keinen Sinn Geräte dann auszuschalten.
Generell Antwortet ein RDM Gerät ja nur dann wenn es danach gefragt
wird. Somit besteht im Normalbetrieb eigentlich keine Gefahr das zwei
Geräte durcheinader funken. (Außer der Hersteller pennt und liefert zwei
Geräte mit der gleichen ID aus)
Ich werd mir das gleich noch mal anschauen in deinem Code. Aber so wie
ich das sehe ist es dann natürlich klar das sich das Device auf die Info
Message nicht mehr meldet.
Jau, daran lags, hab grad deine IF Abfrage der Mute Flags bei der
void respondMsg(void)
rausgenommen. Jetzt funktioniert das wie es soll. Erklärung siehe oben
:-)
Dann kann ich jetzt mich ja dran machen die anderen RDM Funktionen ans
laufen zu bekommen.
MfG
Christian
So, zu den verbessungen die noch gmacht werden sollten:
SOFTWARE_VERSION_LABEL ist laut Norm auch ein Pflichtfeld, sollte also
bei dir auch noch eingebaut werden:
//*********** Deklaration als Beispiel
const unsigned char Software_V_Label_Msg[] =
{ //Software Version Label msg (ASCII text up to 32 character)
'A','B'
};
Dann musste deine Switch Case Funktion noch um nen Punkt erweitern:
case SOFTWARE_VERSION_LABEL:
getMsgP(Software_V_Label_Msg, sizeof(Software_V_Label_Msg));
rdm->PDLen= sizeof(Software_V_Label_Msg);
rdm->PortID= RESPONSE_TYPE_ACK; //Acknolege
respondMsg();
break;
Und was mir in deinem Code auch noch aufgefallen ist. Es sind einige
Variablen sind mitten in den Funktionen deklariert. Normal gehören die
Deklarationen an den Anfang der Funktion. Hab das bei mir bereits
geändert. Der WinAVR Compiler stört das scheinabr nicht. Aber andere
Compiler meckern das schon an.
Ich werde das Muting und Break-Timing ändern.
Zu dem SW-Version Label:
Ist Pflicht, ich sehe darin keinen Nutzen, es raubt mir Flash (der mir
an allen Ecken und Enden fehlt).
-> Ich lass es weg.
Zu Parametern in Funktionen:
Meine WinAVR-Version ist nicht so schlau sich anzugucken, wann ich
welche Variable in der Funktion brauche. Dadurch gibt es mehr
SRAM-Zugriffe zum Puffern lok. Variablen als notwendig und der Code wird
größer.
Grundsätzlich hast Du natürlich Recht.
Vielen Dank,
Hendrik
Ok, ich geize halt normal nichzt so mit den Recourcen. Man kann sich ja
aussuchen welchen Controller man nimmt. Und in nen Mega 128 passt schon
ne Menge Code. Die kleinen Controller haben meistens auch zu wenig
Hardware PWS mit 16 Bit. Da nutzt man dann doch eher das Teil ne Numer
größer. Werd das ganze in nen LED Netzteil einbauen. Und da möchte ich
dann schon alles was von der Norm vorgegebn wird auch drin zu haben.
Dann kann man das Teil auch für drausen vergießen und alels schön übern
Bus steuern.
Das mit dem SOFTWARE_VERSION_LABEL hat aber schon nen Sinn. Weil es
viele Geräte am Markt gibt die im laufe der Zeit neue Versionen
bekommen. Und da die sich dann nicht gleich verhalten macht es auch Sinn
das ganze zu Kennzeichnen. Damit man dann auch sehen kann wenn man
unterschiedliche Geräte im Strang hat.
IDENTYFY_DEVICE ist übrigens auch noch ein Pflichtfeld. Wenn du willst
kannst du ja zumindest nen Komentar im Quelltext hinterlegen. Damit dann
andere Leute das bei Bedarf mit aufnehmen können.
Ist ja durch die Struktur sehr schön nen Befehl dazu zu bauen.
Ansonsten muss man mal schauen ob sich RDM in der Lichtechnik weiter
durchsetzt. Die neuen Robe Scheinwerfer habens zumindest auch mit drin.
Ansonsten kommen die anderen großen Hersteller ja auch auf den Trichter
ihre Geräte damit auszurüsten. Würd mich freuen wenn ich demnächt keine
Dippschalter mehr adressieren muss g
Identify haben meine fertigen Geräte. Ist haber gerätespezifisch -
deswegen habe ich es aus meiner GPL-Lib erst einmal rausgelassen.
Zu den Kosten:
Wenn die FW für eine Funzel ist, von der 10k Stäck/a gefertigt werden,
bekommst Du ziemlich klare Kostenvorgaben. Und schon wird die jedes Byte
lieb und teuer ;-)
zur Durchsetzung:
In einigen FWs läuft es versteckt schon mit, wenn der Platz da ist. Ich
bin in einigen Mailverteilern zu dem Thema und konnte mal eine halbwegs
akteuelle UID-Liste der ESTA sehen: RDM wird kommen.
Identify ist schon Gerätespezifisch, gibt sicherlich auch Geräte wo mans
nicht so toll einbauen kann. Bei Lampen ist das ja nicht das Problem...
lass es leuchten oder blinken.
Also die Geräte die ich bisher gebaut habe gehen normal nie in 10k
Stückzahlen. Von daher hat man den Vorteil das man nicht um jeden Cent
sparen muss. Wenn man in Deutschland was produziert ist das Material
meistens auch eher ein kleiner Faktor. Da versauen dann eher die
Personal und Handlingskosten den Schnitt. Genrell kann man aber wenns
wiklich mal was in größeren Stückzahlen läuft man bei fast jedem
Hersteller auch was am preis drehen.
Offtopic an
Bei mir ist es halt so, ich toure schon seit 10 jahren als DJ und LJ
durch die gegend. Habe Radio und Fernsehtechniker gelernt. Und nach der
Ausbildung bei meiner jetzigen Firma in der Produktion angefangen. Dann
nebenbei meinen Techniker gemacht. Technikerarbeit war dann ne
Metallkernleiterplatte mit 4 stromgeregelten Luxeon 1 LEDs und DMX
Eingang drauf. Nach dem Techniker bin ich dann in die Entwicklung
gewechselt. Die Firma macht aber normal halt Motoren und Steuerungen für
RWA (Rauch- und Wärmeabzug). Wir produzieren aber im Elektronikbereich
auch viel OEM als Bestückung. Seit nen paar Jahren bestücken wir halt
auch viel Hochleistungsleds für diverse Kunden (Lampenhersteller und
Industriekunden). Dadurch kommen dann halt auch mal Anfragen für
Kundenspezifische Lösungen. Das LED Netzteil ist halt auch ne
Entwicklung für nen Lampenhersteller. Der bekommt das aber nur mit 1-10V
Eingang. Da das aber Modular aufgebaut ist hab ich mir jetzt halt mal ne
Controllerplatine gebaut mit RS485 Schnittstelle. DMX drauf ist ja kein
Thema... Aber wollte mich jetzt halt auch mal mit RDM beschäftigen. Hat
man halt schon ne Menge möglichkeiten auch wenns leider im Moment noch
nicht so toll unterstüzt wird. Aber ich denk auch das es kommen wird.
Weil der mehraufwand an der Hardware halt sehr gering ist.
Die Aktuellen Hersteller IDs sind übrigens online veröffentlich:
http://www.esta.org/tsp/working_groups/CP/mfctrIDs.php
Sind eigentlich alle Namenhaften Hersteller dabei. Da die Registrierung
auch nichts kostet steht der Sache auch nichts entgegen.
Muss jetzt mal schauen ob ich für mich privat jetzt mal nen Satz
Controllerplatine für die Netzteile bauen lasse. Das dumme ist halt das
die Firma halt immer nur Zulieferteile herstellt und man leider nie ne
komplette Leuchte hat. Muss man sich dann schon selbst was basteln.
Bis jetzt hat auch bei uns noch niemand nach RDM gefragt. Aber wird
vielleicht dann auch mal kommen das es ein Lampenhersteller haben will.
aktuell baue ich grad erstmal an ner Motorsteuerung. Von daher ist
nichts mit hell und bunt.
Deine Libary werd ich dann auch noch mal ausprobieren. Hab mir
spasseshalber auch mal eine von deinen Controllerplatinen bestellt. Dann
kann ichs auch mal auf deiner Hardwarebasis den Code für dich testen.
Ich selbst baue ja fast nur noch SMD. Obwohl ich auch schon ne DMX
Platine mit nem Solid State Relais in bedratet gebaut habe. War auch für
nen Kundenprojekt. Die brauchten da einmal 100 Stück von. Da lohnt das
dann nicht extra nen Bestückungsautomat für anzuwerfen.
Wenn du noch was wissen willst schreib einfach an dj AT turnthetable DOT
de
Vielleicht kannst mir dann auch mal nen paar Infos geben was du noch so
treibst und was du so mit Lichtechnik zu tun hast. Würd mich auch mal
intressieren.
Und wenn du mal was produzieren lassen willst kann ich da vielleicht
auch mal was für dich tun. Ist zwar mehr Aufgabe unseres Vertriebs. Aber
die sitzen ja im Büro um die Ecke.
Ansonsten hab ich halt ganz gute Kontakte im Bereich Hochleistungs LEDs.
Wenn du da Infos brauchst oder Material brauchst kannst dich auch gerne
melden.
Offtopic aus