[Tutorial] DMX Empfang mit AVRs / Strobe Interface

  • Hallo zusammen,


    hier wie versprochen der offizielle Thread, in dem ich versuche, mit Euch ein DMX-Interface für analoge Stroboskope zu entwickeln. Nebenbei gibt es hoffentlich ein paar Anregungen, wie Ihr selbst kleinere DMX-Projekte realisieren könnt.


    Zunächst ein paar Hinweise zum Thread:
    - Bitte möglichst wenig off-topic / Kartoffelsalat posten. Das wird Euch später nur stören.
    - Ich werde nicht auf grundsätzliche Probleme mit dem Beschreiben von AVRs (z.B. Verbindungsfehler mit PonyProg) eingehen. Dazu existieren unzählige Threads und es bestand seit der Ankündigung zwei Wochen Zeit, den Fehler zu finden.
    - Dasselbe geht für HW-Fehler am Transceiver.
    - Es gibt viele Möglichkeiten und IDEs AVRs zu programmieren. Es gibt viele Controllerfamilien, die sich für DMX eignen. Es gibt viele Typen in der AVR-Familie, die alle ihre Vor- und Nachteile haben. Viele programmieren AVRs in AVR-Assembler (AVRASM), C, C++, Pascal oder Bascom - Alle diese Sprachen haben ihre Daseinsberechtigung. Also bitte keine Grundsatzdiskussionen über Glaubensfragen!!



    Die in diesem Tutorial genutzte Hardware ist mein DMX-Transceiver:
    http://www.hoelscher-hi.de/hen…ht/dmxled.htm#Transceiver


    Als Entwicklungsumgebung (integrated development environment, IDE) nutzen wir das AVR-Studio. Wer sich nicht offiziell bei ATMEL (mit Phantasieangaben) registrieren will, kann hier die Software beziehen:
    http://www.atmel.no/beta_ware/
    Ich selbst nutze Version 4.13 mit SP1&2, da ich das alte Paneldesign komfortabler finde. Evtl. werden bei Euch deshalb ein paar Panels leicht abweichend aussehen.


    Da wir den AVR in C programmieren wollen, benötigen wir die GCC-Toolchain für Windows. Sie wird nahtlos in das AVR-Studio integriert. (Programmer's notepad wird nicht benötigt.)
    http://sourceforge.net/project/showfiles.php?group_id=68108
    Ich selbst verwende noch version 20071221, da sie bei mir einen effizienteren Maschinencode als die neueren produziert. (Ich habe verschiedene Projekte kompiliert und im Disassembler verglichen...)


    Zu guter Letzt wird noch ein Pogramm zur Übertragung der Firmware auf den AVR benötigt:
    http://www.lancos.com/prog.html

  • Für den DMX-Empfang nehmen wir als Grundgerüst meine C-Lib zu AN012:
    http://www.hoelscher-hi.de/hendrik/light/ressources.htm


    Allgemeine Informationen zur Programmierung von AVRs mit der GCC (gnu compiler collection) findet Ihr hier - auch das Forum ist sehr empfehlenswert:
    http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial


    Wenn es um spezifische Fragen zum Mikrocontroller geht (also: Kann Dein Transceiver XYZ machen?), hilft ein Blick in das Datenblatt. Wir verwenden den ATmega8515:
    http://www.atmel.com/dyn/resou…rod_documents/doc2512.pdf


    =====
    Ich geh jetzt erst mal noch 'ne Runde raus und bereite hier dann alles für 14.30h vor.
    Falls es schon Fragen, Hinweise, etc. gibt: Ich schau bis dahin öfters mal hier vorbei...


    Bis dann,
    Hendrik

  • Na - dann fangen wir mal langsam an :D


    Zuerst das WinAVR (also die GCC-Toolchain) intallieren.
    Dann das AVR-Studio nachschicken, damit es bei der Installation schon die Pfade von WinAvr kennt.


    Dann fehlt noch PonyProg für die Programmierung.


    Die Sourcen von WinAVR brauchen wir erst einmal nicht - schaden tun sie aber auch nicht...

  • Als nächstes beginnen wir mir dem neuen Projekt:


    Bevor wir gleich mit DMX und Strobos anfangen, lassen wir erst einmal die rote LED blinken.


    Das Blinken einer LED ist bei den meisten embedded-Entwicklungen das erste Ziel und entspricht dem berüchtigten "Hallo Welt" gewohnten Informatik :wink:

  • Startet dazu das AVR-Studio.


    Es öffnet sich der Startup-Wizard (Welcome to AVR Studio 4).
    Beginnt ein neues Projekt mit "New Project".


    Wählt dann unter Project type "AVR GCC", da wir unsere Firmware in C schreiben wollen.
    Gebt nun den Pfad unter Location an, wo der Ordner mit allen zu dem Projekt gehörenden Daten abgelegt werden soll. (Bei mir lautet er bspw.: C:\eigene Programme\Rev3_0\)
    Als Projektnamen wähle ich AnaStrobe, da wir ein Interface für analoge Strobes schreiben wollen.
    Das initial file nenne ich wie üblich main.c
    (create folder und create initial file bleiben gewählt)

  • Durch Klicken auf "Next" kommen wir zu den Degugger-Einstellungen:
    Wählt als Debug Platform den "AVR Simulator" und als Device den "ATmega8515"


    Beendet den Wizard mit "Finish".

  • Nun öffnet sich die eigentliche Entwicklungsumgebung:


    In der Mitte befindet sich die jeweils aktive Datei mit dem Quellcode.


    Links findet Ihr ein Panel mit verschiedenen Funktionen:
    Durch Klicken auf den unteren Reiter "AVR GCC" könnt Ihr verschiedene Dateien in das Proekt einbauen bzw. entfernen.
    Es gibt dabei verschiedene Dateiarten:
    "Source Files" haben die Endung .c, .cpp oder .s und beinhalten die eigentlichen Funktionen.
    In "Header Files" (Endung .h) stehen Vereinbahrungen, die in mehreren Source Files bekannt sein müssen. Beispiele dafür sind gemeinsame Variablen oder Pinbelegungen und andere Konstanten.


    Der Reiter "I/O View" wird später bei der Simulation des Codes interessant, da wir hier sehen, wie sich der AVR später durch das Programm verhalten wird.


    Unten befindet sich schließlich noch ein Panel mit verschiedenen Logs und Compiler-Ausgaben. Falls es beim Kompilieren der Quelltexte Probleme gibt, werden hier Hinweise dazu gegeben.

  • Nun beginnen wir mal mit dem ersten Programm:


    Zunächst ein paar Kommentare, damit man in ein paar Jahren noch durchsteigt:


    /* DMX Stroboskop Interface
    Version: 0.1
    Datum: 21.06.09
    Autor: H.Hölscher (http://www.hoelscher-hi.de)
    Target: DMX Transceiver @8MHz
    Lizenz: GPLv2
    */


    Dann binden wir ein paar Definitionen ein, mit denen wir später arbeiten wollen:


    #include <avr/io.h>
    #include <stdint.h>
    #include <avr/wdt.h>


    Die "io.h" sagt dem Kompiler, was wir mit typischen Peripherienamen, etc. meinen und übersetzt sie in die physikalische Adresse. So können wir zum Beispiel schreiben:
    "PORTA= 0xFF;" und nicht "0x23= 0xFF"
    Natürlich sind die physikalischen Adressen bei jedem AVR-Typ anders - aber deshalb haben wir ja bereits festgelegt, dass wir mit einem mega8515 arbeiten.


    Die "stdint.h" erklärt dem Compiler was wir mit verschiedenen Variablentypen meinen. Andernfalls kann der GCC nichts mit "char", "integer" oder "short" anfangen und wirft Fehlermeldungen.


    Die "wdt.h" läst uns auf den Watchdog zugreifen.
    Wenn dieser Wachhund nicht alle paar ms von uns zurückgerufen wird, startet er den AVR neu. Somit stehen wir bei einem Absturz des AVRs nicht im Dunkeln sondern sind nach <1s wieder dabei ;)
    Da ich ihn sicherheitshalber gern schon mit den fuses aktiviere, rufen wir ihn einfach sicherheitshalber einfach zurück - auch wenn wir ihn zunächst gar nicht initialisieren...

  • Dann deklarieren wir unsere erste Variable:


    uint16_t count;


    Dies ist eine nicht-negative (unsigned) Variable mit 16bit, die wir "count" nennen.
    Count kann also einen Wert von 0 bis 2^16, also 65535, annehmen.


    Jetzt fehlt eigentlich nur noch der erste spektakuläre Code:





    Das Hauptprogramme lautet immer:
    int main(void)
    {
    }
    Es heißt also main, bekommt beim Aufruf keine Werte mit und gibt einen Integer (beim Absturz...) zurück.


    Zunächst initialisieren wir PortA sicherheitshalber als Ausgang, indem wir das Datenregister auf 0b11111111 (also 0xFF) setzen und machen alle Pins LOW.


    Dann initialisieren wir PortD in ähnlicher Weise. (Schaut mal in den Schaltplan auf meiner Seite - dann seht Ihr den Sinn der Werte ;)


    Nun kommt eine for-Endlosschleife, damit wir nicht den Code ein Mal abarbeiten und dann abstürzen.
    Darin setzen wir zunächst den Watchdog zurück.
    Dann ziehen wir 1 von count ab (count= count -1 und schauen anschließend, ob wir 0 erreicht haben.
    Wenn ja, läuft count über und wir wechseln den Status der LED an PortD, Pin7. (Wer mit dem Exklusiv-Oder Probleme hat, sollte noch mal in das C-Tut auf mikrocontroller.net linsen...)


    EDIT: Gibt es hier eigentlich eine Möglichkeit, Dateien anzuhängen?

  • Nach dem Abspeichern drückt Ihr Strg+F7 und kompiliert damit das Programm und startet den Simulator.


    Das Nachrichtenfenster sollte nun zeigen, dass die Geschichte erfolgreich war und 180byte Programmcode erzeugt wurde.


    Das ist ziemlich viel für die paar Zeilen - deshalb klicken wir auf das Zahnrad-Icon (von mir aus auch Schnecke - auf jeden Fall neben dem blauen X) und wählen als Optimization "-0s" und kompilieren noch mal.


    Siehe da: 130bytes


    BTW:
    -0o: keine Optimierung
    -01..-03: Optimierung der Geschwindigkeit
    -0s: Optimierung der Codegröße. (Wenig Code geht auch schneller ;)



    Nun klickt Ihr bei "Debug" auf "AVR Simulator Options" und wählt 8MHz als Frequenz.


    Nochmal kompilieren.


    Nun kann mit Tippen von F11 Schritt für Schritt der Code durchlaufen werden.


    Das Ergebnis seht Ihr links, wenn Ihr den I/O-View Reiter anwählt.
    Variablen (wie count) können Ihr durch Eingabe von Alt+4 beobachten. (Wenn der Compiler schlau ist, merkt er, dass wir count nur in der Funktion main einsetzen und sonst keine globalen Variablen haben. In diesem Fall findet Ihr count in den Registern...)


    Das Hex-File findet Ihr in dem default-Ordner innerhalb Eures Projekt-Ordners. Wenn Ihr es mit PonyProg auf den Transceiver überspielt, flackert die rote LED mit 16-20Hz.


    ===


    Ich schlage vor, wir warten bis 15.30h und beginnen dann mit dem DMX-Empfang.
    Vielleicht ist bis dann mehr los...

  • <ich habe in dem vorigen Post noch etwas zum Beobachten von Variablen editiert>


    Zunächst fügt Ihr meine "lib_dmx_in.c" und die "lib_dmx_in.h" aus dem Archiv "rxd.zip" in Euer Projektverzeichnis (bei mir: AnaStrobe ) ein.


    Dann geht Ihr links im AVR-Studio auf den Reiter "AVR GCC" und fügt die lib_dmx_in.c zu den source files und die lib_dmx_in.h zu den Header Files.


    Nun möchten wir ja mit unserem Hauptprogramm Funktionen aus der Lib nutzen können. Dazu müssen wir die Header Datei oben in Eurem Code bekannt machen:


    #include "lib_dmx_in.h"


    (Die io.h und stdint.h können wieder entfernt werden, da ich sie in der Header Datei der Lib einbinde...)


    Damit die Initialisierung etwas strukturierter aussieht, bekommt sie eine eigene Prozedur:





    Über init_DMX () rufe ich den Initialisierungscode aus der Lib auf und muss mich nicht weiter darum kümmern.


    Nun zum Hauptprogramm:




    Mit cli sperre ich zunächst die Interrupts, damit mir kein Ereignis dazwischenfunkt. Dann initialisiere ich den Transceiver und gebe die Interrupts wieder frei.
    Mit get_dips() lese ich die Startadresse ein.
    Und danach schau ich nur noch, ob mein erster Kanal >50% ist. Falls ja, knipse ich die rote LED an.


    ========


    Bis hierhin laufen alle Projekte gleich. Deshalb konnte ich einen Großteil der anfänglichen Posts der alten DMXC-Tuts wiederverwenden :D


    Wenn Ihr bis hierhin gekommen seid, wird es auch für mich spannend :)

  • @PMN: Hast Du die Header-Datei eingebunden? Wird in der Header-Datei DmxField oder etwas anderes deklariert?



    Wenn Ihr soweit seid, brauchen wir zunächst eine wichtige Angabe für das Projekt:


    Welcher Frequenzbereich soll für das Stroboskop einstellbar sein? (25Hz-100Hz wären wahrscheinlich suboptimal :D )


    ...und haltet schon mal das Datenblatt für den mega8515 bereit. Tipp: ab S.97 wird es spannend

  • @all:
    In der letzten Version der Lib habe ich folgendes geändert:
    DmxField -> DmxRxField
    init_DMX -> init_DMX_RX


    In einem Projekt benötigte ich sowohl Tx und Rx Lib, was die Änderung notwendig mache.


    Also einfach die Namen in main.c anpassen...


    EDIT:
    Wenn Euch sowas mal bei einem Update eines größeren Projektes passieren sollte, kann man das Ersetzen einfach über Cntrl+H automatisieren.



    ====
    Vorschläge zum Frequenzbereich?

  • Als Blitzraten wären ja 1-15 Hz und Einzelauslösung eines Blitzes Sinnvoll, wie ich finde.


    Also z.B.
    DMX 0-10 -> off
    DMX 11-210 -> Steigerung der Blitzrate
    DMX 211-255 -> Einzelblitz


    Edit:
    Fehler ist weg... defekter Dip-Switch geliefert worden :(

  • *auch mal zu Wort meldet*


    Hab auch noch ein DMX-Modul von Henne rumliegen, bin allerdings blutiger Anfänger was das programmiern angeht. Werde trotzdem den Thread mal mitverfolgen und versuchen es nachzumachen. :)


    edit: Okay, das ist mir deutlich zu hoch... :D

    Einmal editiert, zuletzt von Daniel23 ()