Jednoduchý DMX - RGB modul
Jeden môj priateľ, ktorý hráva rôzne akcie, ma požiadal, či by sme nedokázali vyrobiť svetlo, ovládane DMXom.
Tak som začal na túto tému hľadať na internete rôzne informácie.
Našiel som stránku, kde táto téma bola veľmi dobre vysvetlená [1]. Kedže AR čítam rád kvôli tomu, že
sa niečo naučím a "odkukám", pokúsím sa vysvetliť tento protokol DMX čo najlepšie, aby si každý prišiel na svoje. Či už ide len o ideu,
alebo princíp.
Zapojenie
Ako srdiečko zapojenia som použil ATMega8A, ktorý je nataktovaný na 16MHz. Zo vstupného konektoru putuje DMX signál cez
ochranné rezistory 10R do prevodníka rozhrania RS485/USART SN75176. Z neho putuje signál RxD do MCU. Prevodník je zapojený
tak, že dáta zo DMX zbernice sa iba prijímajú. Rozhranie RS485 má by byť zakončené rezistorom 120R. My sme to vyriešili tak,
že vo svetlách sme použili dva konektory JACK 6,3 so kontaktom. Obidva konektory sú priamo prepojené. Teda jeden ako Vstup a druhý ako Výstup.
Výstupný konektor má pripajkovaný rezistor 120R na svojich kontaktoch, ktoré sa odpoja pri zasunutí jacku.
Výstupný stupeň je v zapojení tranzistora ako spínač - (principiálne so spoločným "source"). Kvôli
kapacite medzi G a S som použil ochranný rezistor 470R medzi výstupom MCU a G tranzistora. Tranzistory sú typu IRLZ44,
no je ich možno nahradiť akýmkoľvek HEX-FETom, ktorý znesie požadovanú prúdovú zátaž a je určený pre spínanie napäťovou
úrovňou 5V (IRL540, IRLU7833...).
Pri projektovaní sme v napájaní ešte nemali veľmi jasno. Kvôli tomu sú na vstupe 3 diódy a stabilizátor na 5V.
Takto sa môže modul napájať buď vlastným zdrojom, alebo sa napája zo zdrojov pre žiarovky, LED pásiky, LED...
Adresa sa nastavuje veľmi jednoducho. Na DMX pulte sa všetky kanály nastavia na nulu. Potom sa na požadovanej
adrese zdvihne bežec nad polovicu (Teda nad hodnotu 128). A stlačí sa tlačítko "Uloženie". Ak sa rozsvieti Led D2, adresa bola
uložená do pamäte EEPROM.
Led D1 je dvojfarebná kontrolka, ktorá oznamuje zelenou - "prijatý paket dát" a červenou - "chybu v prijatých dátach".
Rozhranie
Protokol DMX komunikuje rýchlosťou 250Kb/s a používajú sa dva "stop" bity bez parity. Nič sa nestane, keď si USART nastavíme
iba na jeden "stop" bit. Funguje to jednoducho. Zbernica je stále na úrovni H (log.1). Akonáhle sa dostane do úrovne L
(log. 0), začne USART plniť register. Po poslednom dátovom bite musí nasledovať "stop" bit, ktorý je na úrovni H.
Ak sa stane, že na stop bite bude namiesto úrovne H úroveň L, vyhlási sa chyba FE (Frame error).
Viď obrázok 1.
Na spomínanej stránke [1] môžte nájsť celkový popis celého paketu. Dokonca aj pomenovanie jednotlivých
časti a ich dĺžky. Nás to až tak nemusí zaujímať.. (neskôr sa dozvieme prečo).
Zo začiatku paketu spadne úroveň na zbernici do L, ktorý trvá 88us. Potom sa zdvihne úroveň do H a vyšle sa prvý byte
s hodnotou 0. To je "Start byte". Po ňom nasledujú hodnoty (dáta) kanálov. Podľa typu protokolu, teda či ide o DMX256, alebo
DMX512, je vyslaný príslušný počet hodnôt jednotlivých kanálov (bajtov). Viď obrázok 2.
Najprv som sa zameral na ošetrenie 88us "Resetu". No zrejme nie všetky DMX ovládače dodržujú túto dĺžku, tak mi
to až tak dobre nefungovalo. Ale po dlhom hľadaní po internete som našiel jednu knižnicu ku DMX a v nej to vyriešili veľmi
zaujímavo.
Keďže pri vyslani signálu "Reset" spadne úroveň zbernice do L, spustí sa USART. Ten vyhlási chybu
FE (Frame Error), lebo USART na stop bitoch najde logickú 0, keďže je
ešte stále na zbernici úroveň L. (Signál "Reset" trvá dĺhšie, ako trvá načitanie jedneho bytu USARTom)
To je znamenie, že sme v "Resete" a nasleduje "Štart byte".
Celkový proces načítavania je odkrokovaný. V mojom programe je tento register označený písmenkom "F".
0 - Čakanie na chybu FE. Ak je vyhlásenia chyba, do F vloží 1.
1 - Načítanie prvého (Štart) byte a porovnanie. Ak načítaný byte je 0, do F vloží 2. Inač vynuluj F.
2 - Počkanie na byte podľa adresy. Teda, ak je adresa 10. Tak 9 byte sa ignorujú a desiaty byte sa načíta.
V našom prípade načitáme hodnotu farebnej zložky R (Red). Do F vloží 3.
3,4,5,6 - Načítanie G (Green), B (Blue), Y (Celkovy jas), Strobo. Po poslednom načítanom byte sa F
opäť vynuluje.
Softwate
Program je písaný pre ATMegu8 na 16MHz v assemblery AVRA [2]. Teda neviem zaručiť úplnú kompatibilitu s AVR
štúdiom. No každopádne sa to pokúsim vysvetliť tak, aby si to mohol „nakodiť“ každý vo svojom jazyku a prostredí.
Pre ATMegu mám napísanú knižnicu, ktorá je vlastne prepísaná knižnica „m8def.inc“ (teda jej základne časti. Ďalej
priraďuje vektory prerušenia, nastavuje „stack pointer“ a v poslednom rade makrá pre jednoduchšie písanie.
Začnem tabuľkou prerušení. Všetky vektory mám zapísané v takom tvare:
.equ URXCaddr = 0x000b ; USART, Rx Complete
.org URXCaddr
.ifdef Interupt_USART
.message "Event of URXC -> USART"
RJmp Interupt_USART
.else
RetI
.endif
Tento zápis mi zaručuje, že ak niekde v programe napíšem kód s adresou "Interupt_USART" :
Interupt_USART: ; Adresa obsluhy USART
...
...
RetI
Priradí k nej rutinu od USARTu. Teda ak USART prijme nový údaj, vyvolá sa v bežiacom programe prerušenie a skočí na
túto adresu. Vykoná sa obslužný podprogram a na inštrukcii „reti“ sa vráti na hlavný program, odkiaľ odbehol.
Počas podprogramu sa môžu zmeniť hodnoty v registroch, alebo príznaky v SREG. Preto sa pri prerušení všetky používané
registre a SREG uložia do zásobníka. Ošetril som si to makrom s názvom PushA a PopA. Názov je prevziatý z inštrukčnej sady
x86 (ta inštrukcia funguje až od 286ky).
; Makra
.Macro PushA
Push T ; Ulož register T (temp)
Push A ; Ulož register A (akumulátor)
Push B ; Ulož register B (pomocný akumulátor)
In T , SREG ; Ulož Status register
Push T ; - pomocou registra T
Cli ; Zakáž iné prerušenie
.EndMacro
.Macro PopA
Pop T ; Obnov Status register
Out SREG , T ; - pomocov registra T
Pop B ; Obnov register B
Pop A ; Obnov register A
Pop T ; Obnov register T
.EndMacro
;Rutina od USART
Interupt_USART:
PushA ; Zalohuj registre
..
..
PopA ; Obnov registre
RetI ; Koniec rutiny
Teraz si nastavíme USART. Prvým registrom pre obsluhu USART je UCSRA. Ide skôr o stavový register, ako by sa ním malo niečo nastavovať. Preto nás až tak nebude zaujímať. Druhým podstatnejším registrom je UCSRB. Viď obrázok 3.
RXCIE je povolenie vyvolať prerušenie, ak USART príjme bajt.
TXCIE je povolenie vyvolať prerušenie, ak USART odošle bajt.
UDRIE je povolenie vyvolať prerušenie, ak je dátový bajt nula.
RXEN je povolenie prijímania dát.
TXEN je povolenie odosielania dát.
UCSZ2 je v kombinácii s UCSZ0,1 nastavuje dĺžku dát. USART može odoslať aj 9 bitov.
RXB8 a TXB8 je práve tým deviatim bitom.
Tretím registrom je UCSRC. Tento register ma dve funkcie. Ak je bit URSEL v log.1, Správa sa tento register podľa
obrázku 4. Ak je bit URSEL v log. 0, predstavuje horný bajt baud-rate podľa
obrázku 5.
UMSEL Synchrónny \ Asynchrónny režim. ( 0 – Asynchrónny )
UPM1,0 Nastavenie paritného bitu. (0,0 – bez paritného bitu)
USBS Počet STOP bitov (0 – 1 stop bit)
USBS Počet STOP bitov (0 – 1 stop bit)
UCSZ1,0 Dĺžka dátového slova. (1,1 – dĺžka 8 bitov)
UCPOL Polarita ( 0 – bežaná )
Pre nastavenie rýchlosti baud-rate, slúži register UBRRL a UBRRH. UBRRH je, ako sme už spomínali, regiter UCSRC.
Viď obrázok 5.
Protokol DMX ma rýchlosť 250Kbps. Pri taktovacej frekvencii 16Mhz a vypnutom násobiči rýchlosti U2X, je hodnota
UBRRL=3. Do UBRRH zapíšeme nulu. Tu treba dať pozor na poradie zápisu horného a dolného bajtu. Totiž AVR si ukladá najprv
horný bajt do “bufra“ a pri zápise spodného bajtu, zapíše jedným taktom obidve hodnoty naraz. Týka sa to najme časovačov a
AD prevodníka. Treba mať na pamäti, že to isté platí aj pri čítaní, len naopak. Najprv sa načíta spodný bajt a následne horný.
Poďme sa pozrieť, ako bude vyzerať makro.
.Macro USART_Init;
; Nastavenie baud-rate
Ldi T , 0x00 ; Do UBRRH vlozime nulu
Out UCSRC , T ; - UCSRC je UBRRH
Ldi T , 0x03 ; Do UHRRL vlozime 3
Out UBRRL , T ; - pri 16Mhz -> 250Kbs
; Spustenie USARTu
Ldi T , 0b10011000 ; Povolenie vysielania/prijimania s prerušením
Out UCSRB , T ; - RXCIE, RXEN, TXEN
; Nastavenie rozhrania
Ldi T , 0b10000110 ; Nastavenie rozhrania
Out UCSRC , T ; - 8.bit dlzka, 1 stop bit, bez parity.
.EndMacro
Dáta sa vyberajú a vkladajú do registra UDR. Ak sa z registra číta, načítávame dáta „RXD“. Ak sa do registra UDR zapisuje,
dáta sa zapíšu do registra na odosielanie dát - "TXD".
Poznámka: Zásobníku, nastavenie portom, časovaču a eepromke sa nebudem v tomto článku venovať. Ak bude podnet, rád to niekedy
doplním. No teraz sa zameriame na dekódovanie DMX signálu. Priblížime si rutinu USARTu.
USART_Interupt:
PushA
; Nacitanie registrov USART
; - Nacitanie statusu
In B , UCSRA
; - Nacitanie prichadzajuceho bytu
In A , UDR
; Rozvetvenie podla statusu USART
; - vyhlasenie chyby FrameError (Pre nas signal, ze sme v BREAK pauze)
Sbrc B , FE
Rjmp USART_Interupt_FE
; - vyhlasenie chyby DataOverRun
Sbrc B , DOR
Rjmp USART_Interupt_DOR
; - Nacitanie prichadzajuceho bytu bolo bez chyby
; Rozvetvenie podla kroku F
; - Hladanie (cakanie na) BREAK pauzu
Cpi F , 0
Breq USART_Interupt_End
; - Overenie Start bytu
Cpi F , 1
Breq USART_Interupt_StartByte
; - Hladanie Adresy + Nacitanie prveho bytu farby R
Cpi F , 2
Breq USART_Interupt_FindAdres
; - Nacitanie 2. bytu platnych dat
Cpi F , 3
Breq USART_Interupt_LoadG
; - Nacitanie 3. bytu platnych dat
Cpi F , 4
Breq USART_Interupt_LoadB
; - Nacitanie 4. bytu platnych dat
Cpi F , 5
Breq USART_Interupt_LoadY
; - Nacitanie 5. bytu platnych dat
Cpi F , 6
Breq USART_Interupt_LoadStrobo
; Vynulovanie DMX pocitadla
Clr F
; Koniec prerusenia
USART_Interupt_End:
PopA
RetI
; Odskoky
; - Status FE
USART_Interupt_FE:
; Sme v BREAK pauze. Budeme cakat na START byte
Ldi F , 1
; Vynulujeme status USARTu
Cbi UCSRA , FE
RJmp USART_Interupt_End
; - Status DOR
USART_Interupt_DOR:
Clr F
; Vynulovanie statusu USARTu
Cbi UCSRA , DOR
; Zasvietenie LED Chyby + Zhasenie LED prijatia dat
:
RJmp USART_Interupt_End
; - Overenie StartBytu
USART_Interupt_StartByte:
Cpi A , 0
; Ak Start byte je iny ako 0, vyhlas chybu
Brne USART_Interupt_DOR
; Ak je Start byt v poriadku
; - Zhasenie LED Chyby + Zasvietenie LED prijatia dat :
; - Posunutie Kroku na hladanie adresy
Inc F
; Vynulovanie pocitadla prichadzajucich bytov
Clr ZH
Clr ZL
RJmp USART_Interupt_End
; - Hladanie adresy
USART_Interupt_FindAdres:
; Pripocitanie ku pocitadlu prijimanych bytov
Adiw Z , 1
; Kontrola stlacenia tlacidla
Sbis … ; od tlacidla..
Rjmp USART_Interupt_Button
; Zhasnutie Led store
:
; Porovnanie Adresy s pocitadlom prijatych bytov
Cp ZL , XL
Cpc ZH , ZH
; Adresa nenajdena
Brne USART_Interupt_End
; Adresa najdena
; - Hned nacitame prvy udaj
; - Cervena Farba
USART_Interupt_LoadR:
Mov cR , A
; Krok DMX prijimaca na dalsi byte
Inc F
RJmp USART_Interupt_End
:
:
Načítali sme si z USARTu do registra B status rozhrania a do registra A prijatý bajt. Najprv sa porovnáva status:
- Pri zdvihnutej vlajke (bite) FE (Frame Error) sme sa dostali na začiatok vysielania paketu. Ku počítadlu krokov F sa pripočíta jednotka.
Teda pôjdeme na ďalší krok.
- Pri zdvihnutej vlajke (bite) DOR (DataOverRun) sa vyhlási chyba, zasvieti červena signálka, zhasne zelená signálka a počítadlo krokov F sa
vynuluje. Budeme čakať opäť na FE.
Následne sa bude porovnávať počítadlo krokov F:
- Ak F = 0, koniec rutiny. Čakáme na FE.
- Ak F = 1, kontrola štart bajtu. Štart bajt ma byť „nula“. Ak nieje, vyhlás chybu, ako pri DOR. Ak je
načítaný bajt nulový, posuň krokovač F ďalej (na vyhľadanie adresy).
- Ak F = 2, kontroluje sa najprv stlačené tlačídlo.
a.)Ak je tlačídlo stlačené, ignoruje všetky dáta, kým nenarazí na
hodnotu väčšiu ako 128. Ak sa najde adresa, ktorá má hodnotu väčšiu ako 128, rozsvieti sa kontrolka „Uložené“ a
adresa (kde bola hodnota väščia ako 128) sa vloží do pamäte EEPROM.
b.)Ak tlačídlo nieje stlačené, ignorujú sa všetky dáta, pokiaľ nenájde požadovanú adresu.
Ak sa hľadaná adresa zhoduje s poradovým čislom prijatého bajtu, máme v registri A platný prvý dátový udaj. Preto
ho hneď uložíme do registra „červenej farby“. A samozrejme posunieme počítadlo krokov F na ďalší krok.
- Ak F = 3, načíta sa ďalší údaj, atď...
[1] projekt.cvut.org
[2] http://avra.sourceforge.net/