author | Tero Marttila <terom@paivola.fi> |
Sun, 20 Apr 2014 22:47:56 +0300 | |
changeset 79 | 076657910c0a |
parent 62 | 2d68a76322cb |
permissions | -rw-r--r-- |
45 | 1 |
;;; vim: set ft=avr: |
2 |
||
3 |
.nolist |
|
4 |
.include "m168def.inc" ; Same family as 328P |
|
5 |
.list |
|
6 |
||
46 | 7 |
.include "macros.inc" |
45 | 8 |
|
9 |
;; Interrupt Vector |
|
10 |
.cseg |
|
11 |
.org 0x0000 |
|
12 |
rjmp Main |
|
13 |
||
14 |
||
15 |
;; CPU cycles / second: 16 Mhz |
|
16 |
.set CPU_CYCLES = 16 * 1000 * 1000 |
|
17 |
||
46 | 18 |
;; Delays |
19 |
.include "delay.inc" |
|
20 |
||
45 | 21 |
;; DMX baud raite: 250k |
22 |
.set DMX_BAUD = 250 * 1000 |
|
23 |
||
24 |
;; CPU cycles / bit: 64 |
|
25 |
.set DMX_CYCLES = CPU_CYCLES / DMX_BAUD |
|
26 |
||
46 | 27 |
;; DMX output I/O |
45 | 28 |
.set DMX_DDR = DDRB |
29 |
.set DMX_PORT = PORTB |
|
30 |
.equ DMX_DATA = PORTB3 |
|
31 |
||
46 | 32 |
;; DMX protocol timer |
33 |
; Registers |
|
34 |
.set DMX_TIMER_CRA = TCCR2A |
|
35 |
.set DMX_TIMER_CRB = TCCR2B |
|
36 |
.set DMX_TIMER_CNT = TCNT2 |
|
37 |
.set DMX_TIMER_OCRA = OCR2A |
|
38 |
.set DMX_TIMER_OCRB = OCR2B |
|
39 |
.set DMX_TIMER_IMSK = TIMSK2 |
|
40 |
.set DMX_TIMER_IFR = TIFR2 |
|
41 |
||
42 |
; Compare output match isn't used |
|
43 |
.set DMX_TIMER_COMA = 0b00 |
|
44 |
.set DMX_TIMER_COMB = 0b00 |
|
45 |
||
46 |
; Control register, generation mode value |
|
47 |
.set DMX_TIMER_WGM_10 = 0b10 ; CTC |
|
48 |
.set DMX_TIMER_WGM_2 = 0b0 |
|
49 |
||
50 |
; Clock select |
|
51 |
.set DMX_TIMER_CS_STOP = 0b000 |
|
62
2d68a76322cb
hello-dmx: working basic dmx output using DmxSimple's frame-timing inline assembler code
Tero Marttila <terom@paivola.fi>
parents:
46
diff
changeset
|
52 |
.set DMX_TIMER_CS = 0b001 ; 1/1 |
2d68a76322cb
hello-dmx: working basic dmx output using DmxSimple's frame-timing inline assembler code
Tero Marttila <terom@paivola.fi>
parents:
46
diff
changeset
|
53 |
;.set DMX_TIMER_CS = 0b111 ; 1/1024 |
46 | 54 |
|
55 |
; Counted value |
|
56 |
.set DMX_TIMER_TOP = DMX_CYCLES ; number of cycles for baud |
|
57 |
||
45 | 58 |
;; Debug LED |
59 |
.set LED_DDR = DDRB |
|
60 |
.set LED_PORT = PORTB |
|
61 |
.set LED_PIN = PINB |
|
62
2d68a76322cb
hello-dmx: working basic dmx output using DmxSimple's frame-timing inline assembler code
Tero Marttila <terom@paivola.fi>
parents:
46
diff
changeset
|
62 |
.set LED_BIT = PORTB0 |
45 | 63 |
|
64 |
;; Set up DMX output |
|
65 |
DMX_Init: |
|
66 |
; Setup output port |
|
67 |
; out |
|
68 |
sbi DMX_DDR, DMX_DATA |
|
69 |
||
70 |
; drive high |
|
71 |
sbi DMX_PORT, DMX_DATA |
|
72 |
||
46 | 73 |
; Setup timer |
74 |
; setup CTC mode with no output pins |
|
75 |
poke [DMX_TIMER_CRA, r16, (DMX_TIMER_COMA << COM2A0) | (DMX_TIMER_COMB << COM2B0) | (DMX_TIMER_WGM_10 << WGM20)] |
|
76 |
poke [DMX_TIMER_CRB, r16, (DMX_TIMER_WGM_2 << WGM22) | (DMX_TIMER_CS_STOP << CS20)] |
|
77 |
||
78 |
; trigger threshold for CTC |
|
79 |
poke [DMX_TIMER_OCRA, r16, (DMX_TIMER_TOP)] |
|
80 |
||
45 | 81 |
; OK |
46 | 82 |
ret |
83 |
||
84 |
;; Start Break signal |
|
85 |
;; |
|
86 |
;; 22 bits - 1s long; then DMX_Break_Mark |
|
87 |
;; |
|
88 |
DMX_Break_Start: |
|
89 |
; Low |
|
90 |
cbi DMX_PORT, DMX_DATA |
|
91 |
||
92 |
ret |
|
93 |
||
94 |
;; Start Mark-after-break signal |
|
95 |
;; |
|
96 |
;; 2 bits - 1s long; then DMX_Break_End |
|
97 |
;; |
|
98 |
DMX_Break_Mark: |
|
99 |
; High |
|
100 |
sbi DMX_PORT, DMX_DATA |
|
101 |
||
102 |
ret |
|
103 |
||
104 |
;; End break; prepare for DMX_Frame |
|
105 |
DMX_Frame_Start: |
|
106 |
; Start timer |
|
107 |
poke [DMX_TIMER_CRB, r20, (DMX_TIMER_WGM_2 << WGM22) | (DMX_TIMER_CS << CS20)] |
|
108 |
||
109 |
ret |
|
110 |
||
111 |
;; Do a full DMX break, using some random length |
|
112 |
;; |
|
113 |
DMX_Break: |
|
114 |
; Break |
|
115 |
; start |
|
116 |
rcall DMX_Break_Start |
|
117 |
||
118 |
; wait; about 100ms? |
|
119 |
ldi r20, 82 / 10 |
|
120 |
rcall VarDelay |
|
121 |
||
122 |
; MAB |
|
123 |
; mark |
|
124 |
rcall DMX_Break_Mark |
|
125 |
||
126 |
; short wait |
|
127 |
ldi r20, 1 |
|
128 |
rcall VarDelay |
|
129 |
||
130 |
; Timed frames |
|
131 |
; start frame |
|
132 |
rcall DMX_Frame_Start |
|
133 |
||
134 |
; ok |
|
135 |
ret |
|
45 | 136 |
|
137 |
;; Bitbang one DMX bit out |
|
138 |
;; uses SREG/C to send |
|
46 | 139 |
; |
140 |
; Uses Timer2 as a bit sync clock, sending out the next bit once we've hit 64 cycles on the timer |
|
45 | 141 |
DMX_Bit: |
46 | 142 |
; Wait for bit sync clock |
143 |
_dmx_bit_wait: |
|
144 |
; test OCA hit |
|
145 |
sbic TIFR2, OCF2A |
|
146 |
rjmp _dmx_bit_wait |
|
147 |
||
62
2d68a76322cb
hello-dmx: working basic dmx output using DmxSimple's frame-timing inline assembler code
Tero Marttila <terom@paivola.fi>
parents:
46
diff
changeset
|
148 |
;sbi LED_PORT, LED_BIT |
46 | 149 |
|
150 |
; Output bit |
|
151 |
; XXX: ugly bit-testing, can't we do this using something more nifty? |
|
45 | 152 |
brcs _dmx_bit_1 |
153 |
||
46 | 154 |
; bit 0 |
45 | 155 |
cbi DMX_PORT, DMX_DATA |
46 | 156 |
rjmp _dmx_bit_done |
45 | 157 |
|
158 |
_dmx_bit_1: |
|
46 | 159 |
; bit 1 |
45 | 160 |
sbi DMX_PORT, DMX_DATA |
161 |
nop |
|
162 |
||
46 | 163 |
; Bit sent |
164 |
_dmx_bit_done: |
|
165 |
; reset OCA hit for next bit |
|
166 |
cbi TIFR2, OCF2A |
|
45 | 167 |
|
46 | 168 |
; OK, bit sync clock keeps running for next bit |
169 |
ret |
|
45 | 170 |
|
46 | 171 |
;; Bitbang one DMX byte out, using DMX_Bit |
45 | 172 |
;; r16: byte value |
46 | 173 |
; |
174 |
; Uses Timer2 as a bit sync clock; must call DMX_Frame_Start before first DMX_Frame |
|
45 | 175 |
DMX_Frame: |
176 |
; Start bit |
|
46 | 177 |
clc |
45 | 178 |
rcall DMX_Bit |
179 |
||
180 |
; Data bits: 8 |
|
181 |
ldi r21, 8 |
|
182 |
||
183 |
_dmx_frame_loop: |
|
184 |
; shift + send bit |
|
185 |
lsl r16 |
|
186 |
rcall DMX_Bit |
|
187 |
||
188 |
; loop |
|
189 |
dec r21 |
|
190 |
brne _dmx_frame_loop |
|
191 |
||
192 |
; Stop bits |
|
46 | 193 |
sec |
45 | 194 |
rcall DMX_Bit |
195 |
rcall DMX_Bit |
|
196 |
||
197 |
; OK |
|
46 | 198 |
ret |
45 | 199 |
|
46 | 200 |
;; End of DMX frames |
201 |
DMX_Frame_End: |
|
202 |
; Keep mark from end of last frame; DMX_Break_Start starts the break |
|
203 |
; Stop the timer |
|
204 |
poke [DMX_TIMER_CRB, r20, (DMX_TIMER_WGM_2 << WGM22) | (DMX_TIMER_CS_STOP << CS20)] |
|
205 |
||
206 |
; OK |
|
207 |
ret |
|
208 |
||
209 |
;; Send one value on all frames |
|
45 | 210 |
;; r17: byte value |
211 |
DMX_Flood: |
|
212 |
; Break |
|
213 |
rcall DMX_Break |
|
214 |
||
215 |
; Start code |
|
216 |
ldi r16, 0 |
|
217 |
rcall DMX_Frame |
|
218 |
||
219 |
; Channels |
|
220 |
; number of channels to send |
|
221 |
ldi r22, 100 |
|
222 |
||
223 |
_dmx_flood_channels: |
|
224 |
; restore channel value |
|
225 |
mov r16, r17 |
|
226 |
||
227 |
; send channel value |
|
228 |
rcall DMX_Frame |
|
229 |
||
230 |
; loop |
|
231 |
dec r22 |
|
232 |
brne _dmx_flood_channels |
|
233 |
||
46 | 234 |
; End packet |
235 |
rcall DMX_Frame_End |
|
45 | 236 |
|
237 |
||
46 | 238 |
ret |
239 |
||
45 | 240 |
;; Program main |
241 |
Main: |
|
242 |
; Initialization |
|
243 |
; Debug |
|
244 |
sbi LED_DDR, LED_BIT |
|
46 | 245 |
sbi LED_PORT, LED_BIT |
45 | 246 |
|
247 |
; Stack |
|
46 | 248 |
poke [SPL, r16:r17, RAMEND] |
45 | 249 |
|
250 |
; Init |
|
251 |
rcall DMX_Init |
|
252 |
||
62
2d68a76322cb
hello-dmx: working basic dmx output using DmxSimple's frame-timing inline assembler code
Tero Marttila <terom@paivola.fi>
parents:
46
diff
changeset
|
253 |
cbi LED_PORT, LED_BIT |
45 | 254 |
|
255 |
; Send; value |
|
46 | 256 |
_main_loop: |
45 | 257 |
ldi r17, 255 |
258 |
rcall DMX_Flood |
|
259 |
||
62
2d68a76322cb
hello-dmx: working basic dmx output using DmxSimple's frame-timing inline assembler code
Tero Marttila <terom@paivola.fi>
parents:
46
diff
changeset
|
260 |
cbi LED_PORT, LED_BIT |
46 | 261 |
|
45 | 262 |
; never returns.. |
263 |
rjmp _main_loop |
|
264 |