Forum: Mikrocontroller und Digitale Elektronik DMX senden & Bascom


von Jakob Gebel (Gast)


Angehängte Dateien:

Lesenswert?

Hi,

eigendlich ist meine Frage ganz einfach: Könnte sich jemand von euch
meinen Quelltext anschauen, und sagen, ob er so funktionieren würde?
Ich habe grade keine Möglichkeit ihn zu testen, daher meine bitte
(Meine Lötstation, Oszi, uCs, etc. befinden sich ca 2000km von mir
entfernt ;-). Ich hab mit Bascom noch nie etwas zeitkritisches gemacht,
daher weiß ich nicht, wo hier Probleme liegen könnten.

Zum Code selber:
Über eine serielle Schnittstelle werden DMX Daten vom PC oder einem
anderen Mikrocontroller an diesen hier gesendet. Das Ganze geschieht
bei 115200 Baud. Es werden immer nur die Änderungen übermittelt, also
nie komplette Frames wie bei DMX selber. Das hat den Vorteil gegenüber
z.B. MiniDMX, dass wenn der Datenstrom vom PC wegen Überlastung, ö.ä.
mal abreißen sollte, nicht alle Geräte direkt einen Reset dürchführen,
weil der uC ja trotzdem immer weiter DMX Frames generiert.

Was mir Sorgen bereitet:
Was passiert, wenn sich der uC dabei befindet ein Byte zu senden, und
daher die Interrupts abgeschaltet hat, aber genau in diesem Moment ein
Byte über die serielle Schnittstelle komplett empfangen wurde?
Wenn ich die Interrupts dann wieder einschalte, wird der Interrupt dann
sofort aausgelößt, oder muss ich dann manuell nach dem Byte suchen?
In dem Teil, der zum Interrupt gehört, steht eine Menge Code, den ich
nur reingeschrieben habe, damit ich ermitteln kann, ob 3 Nullen
hintereinander gesendet wurden (um ggf. einen Reset durchzuführen).
Könnte man das vielleicht irgendwie intelligenter lösen?
Wie groß wäre die Chance, dass ich ein Byte verpasse? Wenn ich nämlich
eins verpassen würde, dann würde ja das totale Chaos ausbrechen, weil
dann Kanalwerte als Kanäle interpretiert werden, usw.

Ich hoffe jemand von euch hat Zeit & Lust sich meinen Code mal
anzusehen, und ggf. auch zu verbessern.
Danke schon mal im vorraus!

von leo9 (Gast)


Lesenswert?

empfangene Bytes, sprich interrupts wirst du keine verpassen. Ein Int
kann frühestens alle 86us (1/115200*20) auftreten, dein Int ist
längstens 36us disablet.

Nicht funktionieren wird allerdings deine Senderoutine:
>>      For J = 1 To 8
>>         Portb = Bitwert(j)
>>         Waitus 4
>>      Next J
Falls Bascom sehr effektiv codet kommen pro Schleifendurchlauf 10
Maschinenbefehle dazu (1/16000000*10=625ns) womit jedes Bit statt 4us
4,63us lang wird. Daraus resultiert ein Fehler von etwa +15%, das
toleriert keine asynchrone Verbindung.

grüße leo

von AxelR. (Gast)


Lesenswert?


von Jakob Gebel (Gast)


Angehängte Dateien:

Lesenswert?

Hi,

ich habe das Timing jetzt an den kritischen Stellen mal umgeschrieben
und mit Timern gelößt. Ich Frage mich allerdings wieviele Takte ich
genau warten muss. Wenn ich bei DMX in der Tolleranz bleiben will, dann
muss 1 Bit 64 Takte +-1 Takt anliegen. Allerdings weiß ich im Moment
nicht, wie ich in Bascom eine bestimmt Anzahl von Takten warten kann.
Wenn ich dazu eine Lösung hätte, dann könnte ich mir die ganze Schleife
sparen.
Wenn ich Assembler könnte, würde ich versuchen es darüber zu lösen,
weil ich mir dann sicherer sein kann, wie viele Takte eine Operation
braucht :-( Aber leider kann ich kein Assembler, und ich weiß schon gar
nicht, wie ich es korrekt in Bascom einbinden kann, obwohl ich weiß,
dass es geht.

Naja, ich hab nochmal den Quelltext angehängt. Ich bin mir wie gesagt
beim Timing der Schleife zum senden noch nicht sicher, ob das so geht,
oder wie das Timing genau aussehen müsste.

von leo9 (Gast)


Lesenswert?

wird wieder nicht spielen

>>an den kritischen Stellen mal umgeschrieben
Das Startbit ist aber auch kritisch, weil das Gesamttiming mit der
fallenden Flanke beginnt.

>> dann muss 1 Bit 64 Takte +-1 Takt anliegen
Das Bit muß nicht anliegen, alle 64 Takte (=4us@16MHz) muß der neue
Wert gesetzt werden.

Könnte man zwar prinzipiell mit einem Timer lösen der alle 4us
überläuft und einen Interrupt auslöst. In der Int-Routine einfach
(255-64) zum aktuellen Zählerstand dazuaddieren und schon hast du ein
stabiles Zeitraster.

Ich fürchte aber dass das dann für BASCOM zu viel wird. Vermutlich
werden bei Interrupts alle möglichen Register "gerettet" und am
Schluß wieder restored und dann dauert die Int-Routine länger als die
maximal zur Verfügung stehenden 3,9us. Und das sind bei 16MHz halt
maximal 60 Maschinenbefehle.

Ich glaube du kannst das nur in assembler lösen und selbst da wird es
eng. Der Overhead für einen Interrupt braucht sicher 20Befehle
(Hinsprung, Status sichern, Timer inkrementieren, ..., Status restoren
und retourspringen). Fürs Byte ausgeben rechne ich nochmals 10 Befehle
und ein wenig Logik brauchts noch um die Start/Stop-Bits zu generieren
und den "Memory-Pointer" zu berechnen.

Damit sind wir bereits bei gut 50% CPU-Belastung, viel rechenintensives
sollte jetzt nicht mehr in kurzer Zeit verlangt werden.

Grüße leo

von AxelR. (Gast)


Lesenswert?

Hmm, sieh doch mal in den ersten Link, auf den ich verwies...
dort hat der Dirk /The_clown at web.de\ auch die assembler routinen
mit eingebunden. Die Firmware läuft perfekt! Sowohl an kommerziellen
DMX-Sendern, wie auch an selbstgebauten.
Axel

von Jakob Gebel (Gast)


Lesenswert?

Hi,

dann siehts für die zeitkritischen Sachen ja schon mal schlecht aus.
Ich hab mich mal grade schlau gemacht, wie man Assembler in Bascom
einbinden kann. Soweit so gut, wenn ich folgenden Code benutzen würde:


ldi r16,0b00000000
Out Portb , R16

ldi r16,{Bit1}
Out Portb , R16


Die ersten beiden Befehle würden mir ja dann auf Portb eine 0 ausgeben.
Damit hätte ich dann das Startbit geschrieben. Jetzt habe ich schon das
erste Problem: Wie bekomme ich es hin, dass ich jetzt in Assembler
genau die richtige Anzahl von Takten warten kann?
Dann beim dritten Befehl tut sich mir die Frage auf, ob ich das so
schreiben kann, und ob dann in das Register r16 die Adresse oder der
Wert von der Variable Bit1 reingeschrieben wird. (Zur Erklärung: Habe
mir jetzt Variablen mit den Namen von Bit1-Bit8 gemacht in die die
einzelenen Bitwerte reingeschrieben werden). Eigendlich habe ich damit
zwei generelle Fragen: Wie kann ich ein Byte von einer Bascom Variable
in ein Register laden, und wie erreiche ich eine Pause mit einer
bestimmten Anzahl von Takten?

von Jakob Gebel (Gast)


Lesenswert?

@AxelR: Den Thread hatte ich schon gesehen. Hab mir die Firmware auch
gleich mal gezogen, weil ich die auch ausprobieren wollte, wenn ich im
Sommer wieder zu Hause bin (bin grad auf Austauschjahr in Finnland). Da
wird aber leider nur der andere weg praktiziert: Von Assembler Daten
nach Bascom schicken, nicht umgekehrt. Wie man das ganz genau macht,
darüber schweigt sich die Bascom Hilfe irgendwie aus, oder ich bin nur
zu blöd, um an der richtigen Stelle zu suchen.

von AxelR. (Gast)


Lesenswert?

Stimmt ist blöd. Ich verwende seit einiger Zeit FastAVR. Da geht sowas
alles...

Ich dachte, Du kannst Dirk sein Kram gleich so nehmen, wie er ist?
(meinte ich mit "ableiten")

Gruß
Axel

von Jakob Gebel (Gast)


Lesenswert?

Hi,

das blöde an Dirks Kram ist ja, dass er nur die Daten empfängt und ich
hingegen ein DMX Signal senden möchte ;-). Daher muss ich irgendwie die
Variablen von Bascom nach Assembler bringen. Und eben diese Pause macht
mir noch Sorgen.

von Benjamin Munske (Gast)


Lesenswert?

@AxelR.: Hast du Dirks Code mal in FastAVR umcodiert oder läuft der auf
Anhieb so?

von Jakob Gebel (Gast)


Angehängte Dateien:

Lesenswert?

Hi,

jetzt habe ich inzwischen auch für die Variablen von Bascom nach
Assembler eine Lösung gefunden. Jetzt fehlt mir nur noch eine
Möglichkeit eine Anzahl von Takten zu warten. Weiß jemand von euch wie
das geht?

Ansonsten habe ich mal den aktuellen Code in den Anhang gelegt. Dazu
habe ich noch eine Frage: Kann man r24 einfach so benutzen, oder ist
das Register irgendwas spezielles?

von Benjamin Munske (Gast)


Lesenswert?

Hallo,

man wartet einen Taktzyklus mit dem Befehl nop (no operation)
R16 bis R30 kannst du benutzen.

von AxelR. (Gast)


Lesenswert?

Hi Ben,
nein, habe ich nicht umgeschrieben. Der Dimmer funktioniert doch...
Das Teil läuft, wie gesagt. Warum soll ich da noch was umschreiben, ist
doch durch das Projekt. Bisschen eng im Lichtrack isses zwar, aber
elektrisch alles bestens.
Axel

von Jakob Gebel (Gast)


Lesenswert?

Hi,

ich hab noch eine Frage (bin immernoch beim Timing): Ich verwende ja
folgenden Code, um die Bits aus einem Byte auszulesen:

         Bitwert = Rechner Mod 2
         Rechner = Rechner - Bitwert
         Rechner = Rechner / 2
         Loadadr Bitwert , Z
         ld r16,Z
         Bitwert = Rechner Mod 2
         Rechner = Rechner - Bitwert
         Rechner = Rechner / 2
         Loadadr Bitwert , Z
         ld r17,Z
         Bitwert = Rechner Mod 2
         Rechner = Rechner - Bitwert
         Rechner = Rechner / 2
         Loadadr Bitwert , Z
         ld r18,Z
         Bitwert = Rechner Mod 2
         Rechner = Rechner - Bitwert
         Rechner = Rechner / 2
         Loadadr Bitwert , Z
         ld r19,Z
         Bitwert = Rechner Mod 2
         Rechner = Rechner - Bitwert
         Rechner = Rechner / 2
         Loadadr Bitwert , Z
         ld r20,Z
         Bitwert = Rechner Mod 2
         Rechner = Rechner - Bitwert
         Rechner = Rechner / 2
         Loadadr Bitwert , Z
         ld r21,Z
         Bitwert = Rechner Mod 2
         Rechner = Rechner - Bitwert
         Rechner = Rechner / 2
         Loadadr Bitwert , Z
         ld r22,Z
         Bitwert = Rechner Mod 2
         Rechner = Rechner - Bitwert
         Rechner = Rechner / 2
         Loadadr Bitwert , Z
         ld r23,Z

Nur leider brauchen diese Schritte viel Zeit, sodass das MARK-Signal
zwischen den einzelnen Bytes alleine schon über 100uS lang wird, obwohl
laut Standart noch nicht mal eins da sein muss. Also frage ich mich, ob
es eine Möglichkeit gibt den Code irgendwie zu stuzen, sodass dort
nicht mehr soviel Zeit benötigt wird. Gibt es vielleicht einen Weg in
Bascom die einzelnen Bits aus einem Byte auszulesen, ohne selbiges
komplett zu zerlegen? Es gibt ja auch die Möglichkeit einzelne Pins
einzulesen, ohne erst den Kompletten Port zu lesen, und dann zu
zerteilen. Daher dachte ich, dass das vielleicht auch mit einem Byte im
Speicher möglich wäre.
Jetzt muss ich nur noch das nop richtig einbinden, dann sollte der Code
schonmal, bis auf ein paar kleine Änderungen (LEDs, etc. man will ja
auch was fürs Auge haben ;-) stehen. Bleibt nur noch dieses lange MARK
Signal was ich gerne kürzen würde.

von Benjamin Munske (Gast)


Lesenswert?

@AxelR: Sorry, das meinte ich nicht, ich dachte nur, dass der Bascom
Code nicht mit FastAVR arbeitet, da dort doch gewisse Unterschiede
bestehen, oder? Du meintest doch mal, dass du mit FastAVR arbeitest!?

von Dirk (Gast)


Angehängte Dateien:

Lesenswert?

Dirk's Kram kann auch Daten Senden.

Das ist ein Auszug aus meinem DMX-Lichtpult Projekt,
zusammengeschnitten und Lauffähig (habs ebend mal noch getestet).

MfG Dirk

von Jakob Gebel (Gast)


Angehängte Dateien:

Lesenswert?

Hi,

mittlerweile habe ich auch das Timing Problem beim auslesen der
einzelnen Bits beseitigt. Zwar auch wieder in Assembler, aber
wenigstens lerne ich damit das Zeug zu benutzen. Das Auslesen braucht
jetzt noch etwas über 8,6 uS, was ziemlich Ideal ist. Da ich mit dem
auslesen beginne, sobald die Stopbits gesetzt sind, ohne eine Pause zu
machen, dauert das Auslesen nur etwa 0,6 uS länger als die Stopbits
anliegen müssen. Damit bekomme ich ein Mark zwischen den Bytes, was
eben nur ca. 0,6 uS lang ist, und damit kaum noch kürzer zu kriegen
ist.

Der halbe Quelltext ist jetzt schon Assembler, aber das stört mich
inzwischen nicht mehr ;-)

Vielleicht kann ja von euch einer nochmal über den Code drüberschauen,
ob das alles so in Ordnung ist. Laut dem Bascom-Simulator sollten die
Timings alle stimmen.

von AxelR. (Gast)


Lesenswert?

Das immer alle das Fahhrad 2x erfinden müssen...

von leo9 (Gast)


Angehängte Dateien:

Lesenswert?

die Timings scheinen recht ok, aber die TX-Routine eckt. Zur Erklärung
schau in beiliegendes File (extrafile damit die Tabs erhalten
bleiben).

grüße leo

von Jakob Gebel (Gast)


Angehängte Dateien:

Lesenswert?

Hi,

den Fehler hab ich mittlerweile auch behoben ;-) Ich hätte wohl gestern
um 0:30 nicht mehr daran arbeiten sollen, dann wäre mir auch
aufgefallen, dass was falsch läuft. :) Bascom kenn allerdings btsc
leider nicht, daher musste ich es etwas anders lösen, so sollte es aber
jetzt auch gehen. Jetzt habe ich auf einmal so viel Luft bei den
Timings, dass ich sogar noch eine Pause einlegen muss, bevor das
nächste Byte gesendet wird, da sonst die Stopbits zu kurz werden. Ich
hab den Code nochmal angehängt, aber ich denke, dass jetzt alles
stimmen sollte. Daher werde ich dann mal dazu übergehen eine Platine zu
designen, und dann einen Mikrocontroller auszuwählen. Dann muss ich den
Code vielleicht noch was modifizieren, nen paar LEDs einbinden, o.ä.
Das dumme ist nur, dass ich so viel RAM brauche, sonst könnte ich einen
ziemlich kleinen Controller nehmen. Naja, ist aber nicht so schlimm.
Immerhin ist es ja ein DMX-Treiber, da darf der Controller ja ruhig
schon etwas größer sein.

Danke nochmal für eure Hilfe!

von philip (Gast)


Lesenswert?

könntest du eventull dann nen schalt plan veröffendlichen ?

und eventuell mir auch sagen wie man die einzelnen kanale dann
ansteuert? das habe ich noch nicht so ganz verstanden...

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.