;Dick Cappels' project pages ........You should be able to copy and paste this into an assembler file.
;email projects@cappels.org
;Use of information presented on this page is for personal, nonprofit educational

;and noncommercial use only. This material (including object files) is copyrighted
;by Richard Cappels and may not be republished or used directly for commercial 
;purposes without explicit permission For commercial license, click HERE.

;

;©2002 Richard Cappels All Rights Reserved

;HOME

;******************************************************
.include "1200def.inc"
;******************************************************
;
;8 channel PWM routine. All the actiion is during the interrupt time (nothing happens
;during non-interrupt time except waiting for interrupts). There is only
;one suroutine, and its called before the interrupt, so this only uses one
;level of the stack (and an AT90S1200 doesn''t have much stack space to start with).
;
;This can be made faster by changing the interrupt timer reload value. $ED looks safe.
;It can also go faster (have a higher minimum pulse fequency) if there are fewer
;PWM channels or less resolution on the pulse width
;.

.def tempcounter = r1 ;variable used to reverse order of bits
.def pwmvalue = r2 ;variable used to reverse order of bits
.def pwmvalue0 = r3 ;duty cycle
.def pwmvalue1 = r4 ;duty cycle
.def pwmvalue2 = r5 ;duty cycle
.def pwmvalue3 = r6 ;duty cycle
.def pwmvalue4 = r7 ;duty cycle
.def pwmvalue5 = r8 ;duty cycle
.def pwmvalue6 = r9 ;duty cycle
.def pwmvalue7 = r10 ;duty cycle
.def oldticks = r11 ;variable used to decide when to make a pulse
.def ticks = r12 ;relative interrupt number mod 8

.def bout = r19 ;temporary buffer for output port b
.def temp = r20 ;scratch register for non-interrupt times
.def itemp = r21 ;scratch register for interrupt times
;having separate scratch registers saves stack space and time.
.ORG $0000
rjmp start
.ORG $0002
rjmp timerservice
rjmp start
rjmp start
rjmp start


start:

ldi temp, $01 ; use temp to initaize prescaler to divide by 1
out TCCR0, temp
ldi temp,$E0 ; use temp to initialize counter
out TCNT0,temp
ldi temp, $02 ; use temp to initialize TIMSK
out TIMSK,temp

ldi temp, $FF ;set port B as output port
out DDRB,temp

ldi temp,$02 ;Enable timer interrupt
out TIMSK,temp

ldi temp,$00
mov ticks,temp


ldi temp,$00 ; test value for pwm value
mov pwmvalue,temp
rcall reversepwmvalue
mov pwmvalue0, pwmvalue


ldi temp,$01 ; test value for pwm value
mov pwmvalue,temp
rcall reversepwmvalue
mov pwmvalue1, pwmvalue


ldi temp,$02 ; test value for pwm value
mov pwmvalue,temp
rcall reversepwmvalue
mov pwmvalue2, pwmvalue

ldi temp,$0A ; test value for pwm value
mov pwmvalue,temp
rcall reversepwmvalue
mov pwmvalue3, pwmvalue

ldi temp,$80 ; test value for pwm value
mov pwmvalue,temp
rcall reversepwmvalue
mov pwmvalue4,pwmvalue

ldi temp,$A0 ; test value for pwm value
mov pwmvalue,temp
rcall reversepwmvalue
mov pwmvalue5, pwmvalue

ldi temp,$E0 ; test value for pwm value
mov pwmvalue,temp
rcall reversepwmvalue
mov pwmvalue6, pwmvalue

ldi temp,$FF ; test value for pwm value
mov pwmvalue,temp
rcall reversepwmvalue
mov pwmvalue7, pwmvalue

sei ; enable interrupts



loop: ;wait here for interrupt

rjmp loop


;REVERSE BIT ORDER OR PWMVALUE. Midifies pwmvalue, uses temp
reversepwmvalue: ; reverse bit order in pwmvale.
ldi temp,$08 ; 8 times through loop because there are 8 bits
mov tempcounter,temp
rotateagain:
rol pwmvalue
ror temp
dec tempcounter

brne rotateagain
mov pwmvalue,temp
ret




timerservice:
ldi itemp,$b4 ;set 75 clocks until next interrupt
out TCNT0,itemp
out portb,bout ;transfer portb buffer to port b
andi bout,$00 ;preset all PWM bits to zero
mov oldticks,ticks ;copy interrupt counter to temp
inc ticks ;increment interrupt timer
eor oldticks,ticks ;do X-OR and AND to find bits that changed to 1 (result in temp)
and oldticks,ticks ;do AND to find bits that just changes to a 1



; OUTPUT PWM COMB WAVEFORM TO PORTB BIT 0
mov itemp,oldticks
and itemp,pwmvalue0 ;AND to find if ones in data correspond to this interrupt count change
breq dontset0 ; if ones present, set lsb in portb buffer
ori bout,$01
dontset0:


; OUTPUT PWM COMB WAVEFORM TO PORTB BIT 1
mov itemp,oldticks
and itemp,pwmvalue1 ;AND to find if ones in data correspond to this interrupt count change
breq dontset1 ; if ones present, set lsb in portb buffer
ori bout,$02
dontset1:



; OUTPUT PWM COMB WAVEFORM TO PORTB BIT 2
mov itemp,oldticks
and itemp,pwmvalue2 ;AND to find if ones in data correspond to this interrupt count change
breq dontset2 ; if ones present, set lsb in portb buffer
ori bout,$04

dontset2:


; OUTPUT PWM COMB WAVEFORM TO PORTB BIT 3
mov itemp,oldticks
and itemp,pwmvalue3 ;AND to find if ones in data correspond to this interrupt count change
breq dontset3 ; if ones present, set lsb in portb buffer
ori bout,$08

dontset3:

; OUTPUT PWM COMB WAVEFORM TO PORTB BIT 3
mov itemp,oldticks
and itemp,pwmvalue4 ;AND to find if ones in data correspond to this interrupt count change
breq dontset4 ; if ones present, set lsb in portb buffer
ori bout,$10

dontset4:


; OUTPUT PWM COMB WAVEFORM TO PORTB BIT 3
mov itemp,oldticks
and itemp,pwmvalue5 ;AND to find if ones in data correspond to this interrupt count change
breq dontset5 ; if ones present, set lsb in portb buffer
ori bout,$20

dontset5:


; OUTPUT PWM COMB WAVEFORM TO PORTB BIT 3
mov itemp,oldticks
and itemp,pwmvalue6 ;AND to find if ones in data correspond to this interrupt count change
breq dontset6 ; if ones present, set lsb in portb buffer
ori bout,$40

dontset6:


; OUTPUT PWM COMB WAVEFORM TO PORTB BIT 3
mov itemp,oldticks
and itemp,pwmvalue7 ;AND to find if ones in data correspond to this interrupt count change
breq dontset7 ; if ones present, set lsb in portb buffer
ori bout,$80

dontset7:

reti ;finished with interrupt service



;http://projects.cappels.org/

HOME