DIY ArtNet Device – Wenn Energia, dann kompatibel

… mit diesem Vorsatz hat sich mein kleines Wochenendprojekt bis in die Woche hineingezogen.

Das Arduino-Universum hat sich schon lange ziemlich ausgebreitet und sehr umfangreiche Cortex-M4 Boards wollen/müssen mit den netten Arduino-Funktionen kompatibel sein.

Dass das in der Praxis weniger gut funktionieren, musste ich bei meinem DIY ArtNet Device erfahren.

Der Plan

Beim wühlen in den Bastelkisten habe ich nicht nur meine Sammelbox herunter geschmissen, sondern es ist auch wieder Zubehör aufgetaucht, das sich wunderbar für eine anstehende Silvesterparty verwenden lässt:

IMG_3048

 

Zubehör:

  • EK-TM4C1294XL TI Connected LaunchPad
  • Ein kleiner Servomotor (180 °, 5 V)
  • Kühlkörper mit Lüfter (12 V) (Bild)
  • 12 Volt Schaltnetzteil (12 V, 1,5 A)
  • Kaltweiße 10 W LED (~ 10V, 1 A) (Bild)
  • Ein Glaskristall mir „Brilliantschliff“ (Bild)

Herauskommen soll eine Art kompakte Discokugel für Partys. Die Helligkeit soll veränderbar sein, eine Stroboskopeffekt mit verschiedenen Frequenzen muss zuschaltbar sein und der Servo soll sich drehen lassen. Das alles natürlich passend zur Musik. Da die Musik vom Laptop kommt und es hier einige Lichtprogramme gibt, ist die Steuerzentrale schnell gefunden. DMX Control als Software bietet viele Ausgabe-Interface an, dass bekanntest für solche Anwendungen ist wohl ArtNet und es ist wirklich sehr praktisch das über ein LAN zu erledigen.

Da ich mit dem TI LaunchPad und Energia schon erfolgreich einen tpm2.net zu WS2801 Umsetzer programmiert habe, um beliebige Matrizen anzusteuern, kann doch ein ArtNet Empfänger nicht so schwer sein?!

Die Umsetzung – Hardware

Die LED habe ich mit zwei 1 W Vorwiderständen versehen, denn auf den Wirkungsgrad kommt es hier nicht an. Da die 10 W LED aber schon ein günstiges Spannungslevel von 10 V benötigt, ist man nur gezwungen 2 V also 2 W zu verheizen.

Um die Helligkeit steuern zu können, habe ich einen Logic-N-Kanal MOSFET in die Masse der LED gelötet. Das Gate habe ich mit 100 kOhm gegen Ground gezogen.

Die 100 kOhm waren etwas groß gewählt, man konnte die LED weiterhin durch berühren des Gates einschalten. Nach ein paar mal war der FET auch durch Überspannung am Gate dahin. Also noch mal neu. Diesmal 10 kOhm und eine Z-Diode zum Schutz vor Überspannung am Gate. Eine Z-Diode ist meist etwas langsamer als eine ESD Diode, aber war in der Bastelkiste greifbar.

Beim Löten habe ich alles nur sehr funktional und quick and dirty zusammengelötet. Ich habe auch einen Draht nicht abgeschnitten und diesen über die Anode der LED gebogen. Damit kann ich auch ohne µC die LED einschalten, indem ich den FET kurzerhand mit dem Draht überbrücke.

Den Kristall habe ich mit Zweikomponentenkleber auf den Servo geklebt und anschließend mit einem Kabelbinder am Kühlkörper fixiert.

IMG_3069

 

Ein Pappkarton dient als vorläufiges Gehäuse. Dazu habe ich oben ein Loch für den Lüfter hinein geschnitten und den Lüfter mit zwei seiner Schrauben an der Pappe fixiert. Damit die Luft auch aus dem Karton wieder heraus kann, gibt es ein weiteres Loch. Das wird auch gleichzeitig zum Anschluss des Netzwerkkabels und der USB-Versorgungsspannung verwendet. Das Dev-Board ist ebenfalls an der Pappe fixiert. Dazu habe ich wieder einen Kabelverbinder verwendet und musste die vorgesehenen Schraubenlöcher der Platine noch etwas aufbohren. Da um die Löcher herum keine Leiterbahnen verlaufen, ist das überhaupt kein Problem.

Ein Versuch die 5 Volt für das Board aus den schon vorhandenen 12 Volt mit einem schnöden 7805 zu genieren schlug leider fehl. Trotz kleinen und großen Pufferkondensatoren führte das Anlaufen des Servos zum Reset des Mikrocontrollers. Eine USB-Versorgung bringt bei mir keine Probleme. Mit diesem einen externen Anschluss mehr kann ich aber durchaus leben. Ihr solltet aber den Jumper J1 auf OTG stellen, nachdem das Board programmiert ist. Damit kann der USB-Port neben dem Netzwerkanschluss zur Versorgung verwendet werden und man kommt durch das oben gezeigte Loch im Pappkarton an beide Anschlüsse heran.

Damit der Servo auf die vorhandenen Stiftleisten passt (5 V, GND, Signal – PB4), musste ich die Polung des Steckers drehen. Das stellte sich als sehr problemlos heraus. Das MOSFET-Gate habe ich wegen dem danebenliegendem Ground auf PF1 gelegt. Warum ich es nicht auf PM3 gelegt habe folgt im Software-Teil.

Mit Alu-Folie verkleidet sieht die Pappe auch viel ansprechender aus. 🙂

IMG_3076

 

Die Umsetzung – Software

Um möglichst schnell einen UDP-Stack auf dem Board zum laufen zu bekommen, entschied ich mich für die „Energie programmierung“. Der UDP-Stack lief auch nach wenigen Minute.

Nun musste eine ArtNet Vorlage her. Für ein kommerzielles Projekt habe ich schon eine Bibliothek in C geschrieben. Natürlich verbietet es sich den Quellcode zu verwenden, wenn das fertige „Produkt“ OpenSource werden soll. Da ein ArtNet Device auf ein ArtNet Poll (Broadcast-Nachricht) mit einem Reply antworten soll und so sehr einfach in bestehende Programme eingelesen werden kann, musste die Funktion unbedingt enthalten sein. Gefunden habe ich es nur in der lib von: www.deskontrol.net/blog. Leider musste ich noch ältere UDP-Funktionen durch neue Ersetzen und etwas aufräumen, da das Projekt als ArtNet zu 4x DMX ausgelegt war.

Leider habe ich es nicht geschafft, dass das der gefundene Stack auf ein Poll antwortet. Ich hatte aber keine Lust auf Fehlersuche und habe es erst einmal ohne diese nette Funktion probiert.

Für die Servo-Ansteuerung hab ich die vorhandene Servo-lib verwendet. Die funktionierte auf Anhieb gut. Ich musste nur den maximalen Winkel von 180 ° etwas einschränken, da hier schon der Anschlag meines Servos war.

Für den Strobo-Kanal brauchte ich einen Timer-Interrupt, um ohne Verzögerung ein gleichmäßiges Flackern zu erzeugen. Leider scheint es keine Arduino-Energia kompatible Funktion dafür zu geben und so habe ich es nach einiger Zeit aufgegeben etwas zu finden und erledige es nun mit den HAL-Funktionen von TI:

//setup timer to handle strob effect
#define MY_TIMER_BASE TIMER1_BASE
void initTimer()
{
    //SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER0);
    SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER1);
    TimerConfigure(MY_TIMER_BASE, TIMER_CFG_PERIODIC);
    unsigned long ulPeriod = (SysCtlClockGet() / 1);
    TimerLoadSet(MY_TIMER_BASE, TIMER_A, ulPeriod -1);
    IntEnable(INT_TIMER1A);
    TimerIntEnable(MY_TIMER_BASE, TIMER_TIMA_TIMEOUT);
    TimerIntRegister(MY_TIMER_BASE, TIMER_A, TimerIntHandler);
    TimerEnable(MY_TIMER_BASE, TIMER_A);
}

//with this function the timer could change his frequency
void ChangeFrequencyTimer(unsigned int rate) 
{
    unsigned long ulPeriod = (SysCtlClockGet() / (long)rate * 64);
    TimerLoadSet(MY_TIMER_BASE, TIMER_A, ulPeriod -1);
}
//interrupt for strobe handling
void TimerIntHandler() 
{
    static uint8_t j = 0;
    TimerIntClear(MY_TIMER_BASE, TIMER_TIMA_TIMEOUT);
    digitalWrite(RED_LED, j&0x01);
    j++;
    if(strobe != 0) {
         if(j&0x01) {
             PWMWrite(gamma_cor[dim_level]);
         }
         else {
             PWMWrite(0);
         }
    }
}

Damit ist dieser Quellcode schon mal nicht mehr auf Arduino anwendbar oder überhaupt außerhalb eines TI-Cortexes. Ich bin zwar kein Energia- oder Arduino-Fanboy, aber wenn ich programmiere versuche ich immer die Coding-Guidelines einzuhalten und bei Arduino sollte der Quellcode möglichst wenig von der Hardware abhängig sein!

Es wird also der Timer1 gestartet und ein Interrupt-Callback festgelegt. Mit einer weiteren Funktion ist es möglich die Frequenz des Timers anzupassen. Das habe ich so gestaltet, dass im Interrupt selbst kein Zähler/Verzögerung mehr nötig ist.

Wenn strobe ( != 0 ) nun aktiviert ist, wird im Wechsel die LED abgeschalten oder die vorgegebene Helligkeit eingestellt. „j“ ist nur ein Merker ob die LED gerade an oder aus ist.

Damit die LED in der vorgegebene Helligkeit leuchtet musste noch eine PWM eingebaut werden. Diese sollte um einiges schneller geschalten werden als die schnellste Strobostufe, um Veränderungen bei der Helligkeit zu vermeiden. Praktisch das es bei Arduino die Funktion analogWrite gibt. Diese läuft gerade so ausreichend mit 490 Hz.

Siegessicher spielte ich mit DMXControl herum und teste alle Kanäle durch. Beim verstellen des Dim-Levels musste ich immer wieder ein unschönes Flackern entdecken. Ich schaute mir die Implementierung des Befehls an und stellte fest, dass es wohl dadurch kommen musste, dass nicht nur das Match-Register geupdatet wird sondern auch der Endwert und der Teiler des Timers. Ich habe leider sehr viel Zeit damit verbracht die Funktion verbessern zu wollen. Problem ist einfach, dass ein digitalWrite sich nichts merken darf, da es zu jeder Zeit mit einem anderen Pin aufgerufen werden kann. Nach einigen frustrierten Minuten oder Stunden(?) habe ich den Ansatz aufgegeben und mir eine eigene Funktion geschrieben. Diese benutzt das PWM-Modul. Dazu musste ich PF1 statt PM3 verwenden, was sich mit einem drehen des vorbereiteten Steckers realisieren lies.

void PWMWrite(uint32_t duty)
{
    // tune to about 1,8 kHz
    // energia source analog write cause flicker, so I have to wrote my     one pwm handling
    // all the reinitialisation cause no flicker... so don't care
    SysCtlPWMClockSet(SYSCTL_PWMDIV_4);
    SysCtlPeripheralEnable(SYSCTL_PERIPH_PWM0);
    SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOF);
    GPIOPinConfigure(GPIO_PF1_M0PWM1);
    GPIOPinTypePWM(GPIO_PORTF_BASE, GPIO_PIN_1);
    PWMGenConfigure(PWM0_BASE, PWM_GEN_0,     PWM_GEN_MODE_UP_DOWN | PWM_GEN_MODE_NO_SYNC);
    PWMGenPeriodSet(PWM0_BASE, PWM_GEN_0, 0xFFFF);
    PWMPulseWidthSet(PWM0_BASE, PWM_OUT_0, duty * 256);
    PWMOutputState(PWM0_BASE, PWM_OUT_0_BIT, true);
    PWMGenEnable(PWM0_BASE, PWM_GEN_0);
    PWMGenConfigure(PWM0_BASE, PWM_GEN_1,     PWM_GEN_MODE_UP_DOWN | PWM_GEN_MODE_NO_SYNC);
    PWMGenPeriodSet(PWM0_BASE, PWM_GEN_1, 0xFFFF);
    PWMPulseWidthSet(PWM0_BASE, PWM_OUT_1, duty * 256);
    PWMOutputState(PWM0_BASE, PWM_OUT_1_BIT, true);
    PWMGenEnable(PWM0_BASE, PWM_GEN_1);
}

Nun arbeitet das Programm fast wie erwartet, aber ein Programmieren mit dem Code Composer Studio wäre wohl im Nachhinein zielführender gewesen.

Ich wünsche viel Spaß beim nachbauen. Die Silvesterparty sollte damit definitiv rocken.

Advertisements
Dieser Beitrag wurde unter Allgemein abgelegt und mit , , , , , , , , , verschlagwortet. Setze ein Lesezeichen auf den Permalink.

Kommentar verfassen

Trage deine Daten unten ein oder klicke ein Icon um dich einzuloggen:

WordPress.com-Logo

Du kommentierst mit Deinem WordPress.com-Konto. Abmelden / Ändern )

Twitter-Bild

Du kommentierst mit Deinem Twitter-Konto. Abmelden / Ändern )

Facebook-Foto

Du kommentierst mit Deinem Facebook-Konto. Abmelden / Ändern )

Google+ Foto

Du kommentierst mit Deinem Google+-Konto. Abmelden / Ändern )

Verbinde mit %s