1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275
|
;; Written by Jan Kansky, 5/15/2001.
;;
;; Copyright (C) 2001 Jan Edward Kansky - kansky@jeklink.net
;;
;; This program is free software; you can redistribute it and/or
;; modify it under the terms of the GNU General Public License as
;; published by the Free Software Foundation; either version 2 of the
;; License, or (at your option) any later version.
;;
;; This program is distributed in the hope that it will be useful, but
;; WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
;; General Public License for more details.
;;
;; You should have received a copy of the GNU General Public License
;; along with this program; if not, write to the Free Software
;; Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
;; .device AT90S1200
.include "1200def.inc"
;; ***** Global Register Variables
.def ch1_lsb=r0
.def ch1_msb=r1
.def ch2_lsb=r2
.def ch2_msb=r3
.def ch3_lsb=r4
.def ch3_msb=r5
.def ch4_lsb=r6
.def ch4_msb=r7
.def ch5_lsb=r8
.def ch5_msb=r9
.def ch6_lsb=r10
.def ch6_msb=r11
.def ch7_lsb=r12
.def ch7_msb=r13
.def ch8_lsb=r14
.def ch8_msb=r15
.def ch9_lsb=r16
.def ch9_msb=r17
.def ch10_lsb=r18
.def ch10_msb=r19
.def temp=r20
.def save_state=r21
.def current_ppm=r22 ; Current input channel for PPM decoding
.def current_out=r23 ; Current output nibblet for LPT interface*2
.def timer_val=r24 ; Timer value at PPM irq
.def overflows=r25 ; Number of timer overflows since last PPM irq
.def num_channels=r26
.def temp2=r27
.def y_low_byte=r28
.def temp5=r29
.def temp3=r30
.def temp4=r31
;; ***** Code
.cseg
.org 0
rjmp RESET ; Reset interrupt handler
rjmp PPM_INTERRUPT
rjmp TIMER_OVERFLOW
rjmp RESET
RESET: ldi temp,$1f ; PB4 is the PtrClk output, lsn out
out DDRB,temp
ldi temp,$F0 ; PtrClk high, enable pullups on top 3 bits
out PORTB,temp ; No wait signal, msn pullups on
ldi temp,$00
out DDRD,temp ; Port D are all not used, so set to inputs
ldi temp,$FB
out PORTD,temp ; activate all pullups on PORTD, except irq
ldi temp,$00
mov ch1_lsb,temp ; Set all channel values to zero initially
mov ch1_msb,temp
mov ch2_lsb,temp
mov ch2_msb,temp
mov ch3_lsb,temp
mov ch3_msb,temp
mov ch4_lsb,temp
mov ch4_msb,temp
mov ch5_lsb,temp
mov ch5_msb,temp
mov ch6_lsb,temp
mov ch6_msb,temp
mov ch7_lsb,temp
mov ch7_msb,temp
mov ch8_lsb,temp
mov ch8_msb,temp
mov ch9_lsb,temp
mov ch9_msb,temp
mov ch10_lsb,temp
mov ch10_msb,temp
mov num_channels,temp ; Number of detected channels initialized to 0
mov current_ppm,temp ; Current channel is 0, indicating not synched
ldi current_out,0 ; Nibble 0 is to be output on LPT
mov overflows,temp ; No 8 bit timer overflows have occured.
clr y_low_byte ; Starting outputting channel 1 lsn
mov num_channels,temp ; No channels have been detected.
ldi temp,$02 ; Set falling edge interrupts.
out MCUCR,temp
ldi temp,$40
out GIMSK,temp ; Enable external interrupt
ldi temp,$02
out TIFR,temp
out TIMSK,temp ; Enable timer overflow irqs
sei ; Enable interrupts
ldi temp,1
out TCCR0,temp ; Timer running with no prescaling
ldi temp,$00
out TCNT0,temp
ldi temp2,$00
START: mov temp3,y_low_byte ; Copy current byte address to Z register
ld temp,Z ; Load data to prepare for output
ldi temp2,$F0 ; Keep pullups on, and PtrClk high for now
sbrc current_out,0 ; See if we are on an odd nibble
swap temp ; if so then swap nibbles
andi temp,$0F ; Mask of least significant nibble
or temp2,temp ; Or that nibble into the output byte
ldi temp,$F0 ; Set PtrClk, maintain pullups
cpi y_low_byte,0 ; See if we should output a sync pulse
brne sync_it_up ; Current output channel is zero
cpi current_out,0 ; Current nibble output is zero
brne sync_it_up
ldi temp,$F1 ; Set PtrClk, maintain pullups, set sync
sync_it_up:
out PORTB,temp
POLL: sbic PINB,5 ; Wait for host to ask for data
rjmp POLL
out PORTB,temp2 ; Output data to host
andi temp2,$EF ; Set Ptr Clock low, indicating data ready
out PORTB,temp2 ; Output data to host
inc current_out ; Add one to prepare for next nibble output
cpi current_out,$02 ; If we just finished outputting second nibble
brne dont_update_y
inc y_low_byte ; increment the byte address
dont_update_y:
cpi current_out,$03 ; If we finished the third nibble, start over
brlo channel_not_done
ldi current_out,0 ; Back to starting nibble
inc y_low_byte ; Switch to next channel
channel_not_done:
REPLY: sbis PINB,5 ; Wait for host to finish reading data
rjmp REPLY
cpi y_low_byte,$14 ; If done with 20 bytes, (9 channels+1 sync)*2
brne cycle_not_done
inc y_low_byte ; Increment address so irqs still registers
no_new_data_yet:
cpi temp4,$FF ; Wait for new frame of data to complete
brne no_new_data_yet
ldi temp4,$00
ldi temp,$F1 ; Tell host we are ready to transfer new frame
out PORTB,temp
dont_go_back_to_zero_yet:
sbic PINB,5 ; Wait for host to ask for new frame
rjmp dont_go_back_to_zero_yet
clr y_low_byte ; Reset address to zero
cycle_not_done:
rjmp START
TIMER_OVERFLOW:
in save_state,SREG
inc overflows
out SREG,save_state
reti
PPM_INTERRUPT:
in save_state,SREG
ldi temp4,0
out TCCR0,temp4 ; Stop timer
mov temp5,temp3 ; Backup Z register
in timer_val,TCNT0 ; Read timer value
in temp4,TIFR ; Read in Timer interrupt flag register
ldi temp3,$00 ; Reset counter to zero, prepare for next irq
out TCNT0,temp3
ldi temp3,1
out TCCR0,temp3 ; Timer running with no prescaling
sbrs temp4,1
rjmp no_overflow ; If not set, continue
inc overflows ; Increment overflow counter
ldi temp3,$02
out TIFR,temp3 ; Clear the overflow
no_overflow:
cpi overflows,$0E ; Check if this is a sync pulse
brlo check_sync ; If not, put data into appropriate channel
ldi current_ppm,1 ; if it is reset channel counter to first chanl
mov temp4,y_low_byte ; Check to make sure we aren't currently
lsr temp4 ; sending this data to the LPT
ldi temp3,$09
cp temp3,temp4
breq dont_change_now
mov temp3,timer_val
lsr temp3
lsr temp3
lsr temp3
mov temp4,overflows
sbrc temp4,0
sbr temp3,$20
sbrc temp4,1
sbr temp3,$40
sbrc temp4,2
sbr temp3,$80
lsr temp4
lsr temp4
lsr temp4
mov ch10_lsb,temp3 ; Store the sync pulse width in ch10
mov ch10_msb,temp4 ; this will allow for total cycle time comp.
mov temp3,num_channels ; Clear unused channels
ldi num_channels,$00
lsl temp3
continue_clearing:
cpi temp3,$12 ; See if we've cleared up to and including 9
breq done_clearing
st Z,num_channels ; Clear low byte
inc temp3
st Z,num_channels ; Clear high byte
inc temp3
rjmp continue_clearing
done_clearing:
ldi temp4,$FF
dont_change_now:
rjmp exit_ppm ; and exit to await next irq
check_sync:
cpi current_ppm,0 ; If not a sync pulse, check to see if we
brne save_data ; have achieved sync. If not, exit, else
rjmp exit_ppm ; see which channel the irq belongs to.
save_data:
cp current_ppm,num_channels; Determine how many channels are
brlo not_new_max ; being output by the radio transmitter
mov num_channels,current_ppm
not_new_max:
mov temp4,y_low_byte ; Check to make sure we aren't currently
lsr temp4 ; sending this data to the LPT
mov temp3,current_ppm ; Prepare Z register for Immediate with offset
dec temp3
cp temp3,temp4
breq dont_save
lsl temp3
ldi temp4,0
st Z,timer_val
inc temp3
st Z,overflows
dont_save:
ldi temp3,0
ldi temp4,9
cp current_ppm,temp4
brlo done_ppm
dec current_ppm ; Decrement current_ppm so ch 10 or higher go into 9
done_ppm:
inc current_ppm ; Increment for the next channel
exit_ppm:
ldi overflows,0
mov temp3,temp5 ; Restore Z register
out SREG,save_state
reti
|