moar dmx?
authorTero Marttila <terom@fixme.fi>
Tue, 02 Aug 2011 09:27:19 +0300
changeset 46 ffb0c3ec9bc0
parent 45 7c684d241675
child 47 7f930a94ee1e
moar dmx?
delay.inc
dmx.s
--- a/delay.inc	Wed Jul 27 01:46:27 2011 +0300
+++ b/delay.inc	Tue Aug 02 09:27:19 2011 +0300
@@ -1,3 +1,4 @@
+;; vim: set ft=avr:
 ;;
 ;; Busy-loop delays
 ;;
--- a/dmx.s	Wed Jul 27 01:46:27 2011 +0300
+++ b/dmx.s	Tue Aug 02 09:27:19 2011 +0300
@@ -4,6 +4,7 @@
 .include "m168def.inc"      ; Same family as 328P
 .list
 
+.include "macros.inc"
 
 ;; Interrupt Vector
 .cseg
@@ -14,17 +15,46 @@
 ;; CPU cycles / second: 16 Mhz
 .set CPU_CYCLES = 16 * 1000 * 1000
 
+;; Delays
+.include "delay.inc"
+
 ;; DMX baud raite: 250k
 .set DMX_BAUD = 250 * 1000
 
 ;; CPU cycles / bit: 64
 .set DMX_CYCLES = CPU_CYCLES / DMX_BAUD
 
-;; DMX output por
+;; DMX output I/O
 .set DMX_DDR = DDRB
 .set DMX_PORT = PORTB
 .equ DMX_DATA = PORTB3
 
+;; DMX protocol timer
+; Registers
+.set DMX_TIMER_CRA = TCCR2A
+.set DMX_TIMER_CRB = TCCR2B
+.set DMX_TIMER_CNT = TCNT2
+.set DMX_TIMER_OCRA = OCR2A
+.set DMX_TIMER_OCRB = OCR2B
+.set DMX_TIMER_IMSK = TIMSK2
+.set DMX_TIMER_IFR = TIFR2
+
+; Compare output match isn't used
+.set DMX_TIMER_COMA = 0b00
+.set DMX_TIMER_COMB = 0b00
+
+; Control register, generation mode value
+.set DMX_TIMER_WGM_10 = 0b10        ; CTC
+.set DMX_TIMER_WGM_2 = 0b0
+
+; Clock select
+.set DMX_TIMER_CS_STOP = 0b000
+;.set DMX_TIMER_CS = 0b001      ; 1/1
+.set DMX_TIMER_CS = 0b111       ; 1/1024
+
+; Counted value
+.set DMX_TIMER_TOP = DMX_CYCLES     ; number of cycles for baud
+
 ;; Debug LED
 .set LED_DDR = DDRB
 .set LED_PORT = PORTB
@@ -40,79 +70,111 @@
         ; drive high
         sbi     DMX_PORT, DMX_DATA
 
+    ; Setup timer
+        ; setup CTC mode with no output pins
+        poke        [DMX_TIMER_CRA, r16, (DMX_TIMER_COMA << COM2A0) | (DMX_TIMER_COMB << COM2B0) | (DMX_TIMER_WGM_10 << WGM20)]
+        poke        [DMX_TIMER_CRB, r16, (DMX_TIMER_WGM_2 << WGM22) | (DMX_TIMER_CS_STOP << CS20)]
+
+        ; trigger threshold for CTC
+        poke        [DMX_TIMER_OCRA, r16, (DMX_TIMER_TOP)]
+		
     ; OK
-        ret
+    ret
+
+;; Start Break signal
+;;
+;; 22 bits - 1s long; then DMX_Break_Mark
+;;
+DMX_Break_Start:
+    ; Low
+        cbi         DMX_PORT, DMX_DATA
+
+    ret
+
+;; Start Mark-after-break signal
+;;
+;; 2 bits - 1s long; then DMX_Break_End
+;;
+DMX_Break_Mark:
+    ; High
+        sbi         DMX_PORT, DMX_DATA
+
+    ret
+
+;; End break; prepare for DMX_Frame
+DMX_Frame_Start:
+    ; Start timer
+        poke        [DMX_TIMER_CRB, r20, (DMX_TIMER_WGM_2 << WGM22) | (DMX_TIMER_CS << CS20)]
+    
+    ret
+
+;; Do a full DMX break, using some random length
+;;
+DMX_Break:
+    ; Break
+        ; start
+        rcall       DMX_Break_Start
+
+        ; wait; about 100ms?
+        ldi         r20, 82 / 10
+        rcall       VarDelay
+
+    ; MAB
+        ; mark
+        rcall       DMX_Break_Mark
+
+        ; short wait
+        ldi         r20, 1
+        rcall       VarDelay
+
+    ; Timed frames
+        ; start frame
+        rcall       DMX_Frame_Start
+
+    ; ok
+    ret
 
 ;; Bitbang one DMX bit out
 ;;  uses SREG/C to send
+;
+; Uses Timer2 as a bit sync clock, sending out the next bit once we've hit 64 cycles on the timer
 DMX_Bit:
-    ; Output bit: 4 cycles
+    ; Wait for bit sync clock
+_dmx_bit_wait:
+        ; test OCA hit
+        sbic    TIFR2, OCF2A     
+        rjmp    _dmx_bit_wait   
+
+sbi         LED_PIN, LED_BIT
+
+    ; Output bit
+        ; XXX: ugly bit-testing, can't we do this using something more nifty?
         brcs    _dmx_bit_1
         
+        ; bit 0
         cbi     DMX_PORT, DMX_DATA
-        rjmp    _dmx_bit_wait
+        rjmp    _dmx_bit_done
 
 _dmx_bit_1:
+        ; bit 1
         sbi     DMX_PORT, DMX_DATA
         nop
 
-_dmx_bit_wait:
-    ; Wait: 60 cycles
-        ; load: 1 cycle (offset by one less for brne)
-        ldi     r20, 6
-
-_dmx_bit_loop:
-        ; waste 8 cycles
-        nop
-        nop
-        nop
-        nop
-        nop
-        nop
-        nop
-        nop
-
-        ; loop: 1 + 2/1 cycles
-        ; 2/1 cycles
-        dec     r20
-        brne    _dmx_bit_loop
-       
-    ; OK
-        ret
+    ; Bit sent
+_dmx_bit_done:
+        ; reset OCA hit for next bit
+        cbi     TIFR2, OCF2A
 
-;; Break + MAB
-DMX_Break:
-    ; Break: 100 low bits
-        ldi         r21, 100
-
-_dmx_break_loop:
-        ; bitbang zero
-        clc
-        rcall       DMX_Bit
-        
-        ; count
-        dec         r21
-        brne        _dmx_break_loop
+    ; OK, bit sync clock keeps running for next bit
+    ret
 
-    ; MAB: 4 high bits
-        ldi         r21, 4
-
-_dmx_break_mab:
-        sec
-        rcall       DMX_Bit
-
-        ; loop
-        dec         r21
-        brne        _dmx_break_mab
-
-    ; OK
-        ret
-
-;; Byte
+;; Bitbang one DMX byte out, using DMX_Bit
 ;;  r16: byte value
+;
+; Uses Timer2 as a bit sync clock; must call DMX_Frame_Start before first DMX_Frame
 DMX_Frame:
     ; Start bit
-        sec
+        clc
         rcall       DMX_Bit
 
     ; Data bits: 8
@@ -128,17 +190,25 @@
         brne        _dmx_frame_loop
 
     ; Stop bits
-        clc
+        sec
         rcall       DMX_Bit
         rcall       DMX_Bit
     
     ; OK
-        ret
+    ret
 
-;; Send one value on all frames, continuously
+;; End of DMX frames
+DMX_Frame_End:
+    ; Keep mark from end of last frame; DMX_Break_Start starts the break
+    ; Stop the timer
+        poke        [DMX_TIMER_CRB, r20, (DMX_TIMER_WGM_2 << WGM22) | (DMX_TIMER_CS_STOP << CS20)]
+
+    ; OK
+    ret
+
+;; Send one value on all frames
 ;;  r17: byte value
 DMX_Flood:
-_dmx_flood:
     ; Break
         rcall       DMX_Break
 
@@ -161,24 +231,21 @@
         dec         r22
         brne        _dmx_flood_channels
 
-    ; OK; loop
-;sbi         LED_PIN, LED_BIT
-        rjmp        _dmx_flood
+    ; End packet
+        rcall       DMX_Frame_End
 
 
+    ret
+
 ;; Program main
 Main:
 ; Initialization
     ; Debug
         sbi         LED_DDR, LED_BIT
-cbi         LED_PORT, LED_BIT
+sbi         LED_PORT, LED_BIT
 
     ; Stack
-        ldi         r16, high(RAMEND)
-        ldi         r17, low(RAMEND)
-        out         SPH, r16
-        out         SPL, r17
-
+		poke		[SPL, r16:r17, RAMEND]
 
     ; Init
         rcall       DMX_Init
@@ -186,10 +253,12 @@
 sbi         LED_PORT, LED_BIT
 
     ; Send; value
+_main_loop:
         ldi         r17, 255
         rcall       DMX_Flood
 
-_main_loop:
+;sbi         LED_PORT, LED_BIT
+
         ; never returns..
         rjmp        _main_loop