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!
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
http://www.mikrocontroller.net/attachment.php/135103/DMX_Dimmer8_V1_doc.bas http://www.mikrocontroller.net/forum/read-1-118845.html sieh mal hier nach... Vielleicht kannste hier was "ableiten" Gruß AxelR.
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.
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
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
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?
@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.
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
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.
@AxelR.: Hast du Dirks Code mal in FastAVR umcodiert oder läuft der auf Anhieb so?
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?
Hallo, man wartet einen Taktzyklus mit dem Befehl nop (no operation) R16 bis R30 kannst du benutzen.
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
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.
@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!?
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
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.
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
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!
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.