# HG changeset patch # User Tero Marttila # Date 1312266439 -10800 # Node ID ffb0c3ec9bc034980f319bf599cce298db29eeb9 # Parent 7c684d2416751eaa95905f598143a6e3f7d57620 moar dmx? diff -r 7c684d241675 -r ffb0c3ec9bc0 delay.inc --- 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 ;; diff -r 7c684d241675 -r ffb0c3ec9bc0 dmx.s --- 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