terom@45: ;;; vim: set ft=avr: terom@45: terom@45: .nolist terom@45: .include "m168def.inc" ; Same family as 328P terom@45: .list terom@45: terom@46: .include "macros.inc" terom@45: terom@45: ;; Interrupt Vector terom@45: .cseg terom@45: .org 0x0000 terom@45: rjmp Main terom@45: terom@45: terom@45: ;; CPU cycles / second: 16 Mhz terom@45: .set CPU_CYCLES = 16 * 1000 * 1000 terom@45: terom@46: ;; Delays terom@46: .include "delay.inc" terom@46: terom@45: ;; DMX baud raite: 250k terom@45: .set DMX_BAUD = 250 * 1000 terom@45: terom@45: ;; CPU cycles / bit: 64 terom@45: .set DMX_CYCLES = CPU_CYCLES / DMX_BAUD terom@45: terom@46: ;; DMX output I/O terom@45: .set DMX_DDR = DDRB terom@45: .set DMX_PORT = PORTB terom@45: .equ DMX_DATA = PORTB3 terom@45: terom@46: ;; DMX protocol timer terom@46: ; Registers terom@46: .set DMX_TIMER_CRA = TCCR2A terom@46: .set DMX_TIMER_CRB = TCCR2B terom@46: .set DMX_TIMER_CNT = TCNT2 terom@46: .set DMX_TIMER_OCRA = OCR2A terom@46: .set DMX_TIMER_OCRB = OCR2B terom@46: .set DMX_TIMER_IMSK = TIMSK2 terom@46: .set DMX_TIMER_IFR = TIFR2 terom@46: terom@46: ; Compare output match isn't used terom@46: .set DMX_TIMER_COMA = 0b00 terom@46: .set DMX_TIMER_COMB = 0b00 terom@46: terom@46: ; Control register, generation mode value terom@46: .set DMX_TIMER_WGM_10 = 0b10 ; CTC terom@46: .set DMX_TIMER_WGM_2 = 0b0 terom@46: terom@46: ; Clock select terom@46: .set DMX_TIMER_CS_STOP = 0b000 terom@62: .set DMX_TIMER_CS = 0b001 ; 1/1 terom@62: ;.set DMX_TIMER_CS = 0b111 ; 1/1024 terom@46: terom@46: ; Counted value terom@46: .set DMX_TIMER_TOP = DMX_CYCLES ; number of cycles for baud terom@46: terom@45: ;; Debug LED terom@45: .set LED_DDR = DDRB terom@45: .set LED_PORT = PORTB terom@45: .set LED_PIN = PINB terom@62: .set LED_BIT = PORTB0 terom@45: terom@45: ;; Set up DMX output terom@45: DMX_Init: terom@45: ; Setup output port terom@45: ; out terom@45: sbi DMX_DDR, DMX_DATA terom@45: terom@45: ; drive high terom@45: sbi DMX_PORT, DMX_DATA terom@45: terom@46: ; Setup timer terom@46: ; setup CTC mode with no output pins terom@46: poke [DMX_TIMER_CRA, r16, (DMX_TIMER_COMA << COM2A0) | (DMX_TIMER_COMB << COM2B0) | (DMX_TIMER_WGM_10 << WGM20)] terom@46: poke [DMX_TIMER_CRB, r16, (DMX_TIMER_WGM_2 << WGM22) | (DMX_TIMER_CS_STOP << CS20)] terom@46: terom@46: ; trigger threshold for CTC terom@46: poke [DMX_TIMER_OCRA, r16, (DMX_TIMER_TOP)] terom@46: terom@45: ; OK terom@46: ret terom@46: terom@46: ;; Start Break signal terom@46: ;; terom@46: ;; 22 bits - 1s long; then DMX_Break_Mark terom@46: ;; terom@46: DMX_Break_Start: terom@46: ; Low terom@46: cbi DMX_PORT, DMX_DATA terom@46: terom@46: ret terom@46: terom@46: ;; Start Mark-after-break signal terom@46: ;; terom@46: ;; 2 bits - 1s long; then DMX_Break_End terom@46: ;; terom@46: DMX_Break_Mark: terom@46: ; High terom@46: sbi DMX_PORT, DMX_DATA terom@46: terom@46: ret terom@46: terom@46: ;; End break; prepare for DMX_Frame terom@46: DMX_Frame_Start: terom@46: ; Start timer terom@46: poke [DMX_TIMER_CRB, r20, (DMX_TIMER_WGM_2 << WGM22) | (DMX_TIMER_CS << CS20)] terom@46: terom@46: ret terom@46: terom@46: ;; Do a full DMX break, using some random length terom@46: ;; terom@46: DMX_Break: terom@46: ; Break terom@46: ; start terom@46: rcall DMX_Break_Start terom@46: terom@46: ; wait; about 100ms? terom@46: ldi r20, 82 / 10 terom@46: rcall VarDelay terom@46: terom@46: ; MAB terom@46: ; mark terom@46: rcall DMX_Break_Mark terom@46: terom@46: ; short wait terom@46: ldi r20, 1 terom@46: rcall VarDelay terom@46: terom@46: ; Timed frames terom@46: ; start frame terom@46: rcall DMX_Frame_Start terom@46: terom@46: ; ok terom@46: ret terom@45: terom@45: ;; Bitbang one DMX bit out terom@45: ;; uses SREG/C to send terom@46: ; terom@46: ; Uses Timer2 as a bit sync clock, sending out the next bit once we've hit 64 cycles on the timer terom@45: DMX_Bit: terom@46: ; Wait for bit sync clock terom@46: _dmx_bit_wait: terom@46: ; test OCA hit terom@46: sbic TIFR2, OCF2A terom@46: rjmp _dmx_bit_wait terom@46: terom@62: ;sbi LED_PORT, LED_BIT terom@46: terom@46: ; Output bit terom@46: ; XXX: ugly bit-testing, can't we do this using something more nifty? terom@45: brcs _dmx_bit_1 terom@45: terom@46: ; bit 0 terom@45: cbi DMX_PORT, DMX_DATA terom@46: rjmp _dmx_bit_done terom@45: terom@45: _dmx_bit_1: terom@46: ; bit 1 terom@45: sbi DMX_PORT, DMX_DATA terom@45: nop terom@45: terom@46: ; Bit sent terom@46: _dmx_bit_done: terom@46: ; reset OCA hit for next bit terom@46: cbi TIFR2, OCF2A terom@45: terom@46: ; OK, bit sync clock keeps running for next bit terom@46: ret terom@45: terom@46: ;; Bitbang one DMX byte out, using DMX_Bit terom@45: ;; r16: byte value terom@46: ; terom@46: ; Uses Timer2 as a bit sync clock; must call DMX_Frame_Start before first DMX_Frame terom@45: DMX_Frame: terom@45: ; Start bit terom@46: clc terom@45: rcall DMX_Bit terom@45: terom@45: ; Data bits: 8 terom@45: ldi r21, 8 terom@45: terom@45: _dmx_frame_loop: terom@45: ; shift + send bit terom@45: lsl r16 terom@45: rcall DMX_Bit terom@45: terom@45: ; loop terom@45: dec r21 terom@45: brne _dmx_frame_loop terom@45: terom@45: ; Stop bits terom@46: sec terom@45: rcall DMX_Bit terom@45: rcall DMX_Bit terom@45: terom@45: ; OK terom@46: ret terom@45: terom@46: ;; End of DMX frames terom@46: DMX_Frame_End: terom@46: ; Keep mark from end of last frame; DMX_Break_Start starts the break terom@46: ; Stop the timer terom@46: poke [DMX_TIMER_CRB, r20, (DMX_TIMER_WGM_2 << WGM22) | (DMX_TIMER_CS_STOP << CS20)] terom@46: terom@46: ; OK terom@46: ret terom@46: terom@46: ;; Send one value on all frames terom@45: ;; r17: byte value terom@45: DMX_Flood: terom@45: ; Break terom@45: rcall DMX_Break terom@45: terom@45: ; Start code terom@45: ldi r16, 0 terom@45: rcall DMX_Frame terom@45: terom@45: ; Channels terom@45: ; number of channels to send terom@45: ldi r22, 100 terom@45: terom@45: _dmx_flood_channels: terom@45: ; restore channel value terom@45: mov r16, r17 terom@45: terom@45: ; send channel value terom@45: rcall DMX_Frame terom@45: terom@45: ; loop terom@45: dec r22 terom@45: brne _dmx_flood_channels terom@45: terom@46: ; End packet terom@46: rcall DMX_Frame_End terom@45: terom@45: terom@46: ret terom@46: terom@45: ;; Program main terom@45: Main: terom@45: ; Initialization terom@45: ; Debug terom@45: sbi LED_DDR, LED_BIT terom@46: sbi LED_PORT, LED_BIT terom@45: terom@45: ; Stack terom@46: poke [SPL, r16:r17, RAMEND] terom@45: terom@45: ; Init terom@45: rcall DMX_Init terom@45: terom@62: cbi LED_PORT, LED_BIT terom@45: terom@45: ; Send; value terom@46: _main_loop: terom@45: ldi r17, 255 terom@45: rcall DMX_Flood terom@45: terom@62: cbi LED_PORT, LED_BIT terom@46: terom@45: ; never returns.. terom@45: rjmp _main_loop terom@45: