; 8 channel PWM test program.
;
; Board: SX Demo/Proto Board
;
; 8 LEDs are fed with PWM signal. Each channel starts from a different value
; (0, 32, 64, 96, 128, 160, 192, 224) and goes slowly up and down.
;
; PWM code is based on Scott Dattalo's code.
DEVICE SX28L, OSC4MHZ, TURBO, STACKX, OPTIONX
RESET start
ORG $08 ;global bank
temp DS 1 ;short term temp
dir DS 1 ;direction of PWM inputs change (inverted on reaching
;maximum (255) or minimum (1)). each bit is related to a PWM channel
pwm_state DS 1 ;pwm outputs state (0 - off, 1 - on)
pwm_period DS 1 ;pwm period counter
ORG $10 ;bank0
pwm_bank EQU $
pwm0 DS 1 ;PWM counters
pwm1 DS 1
pwm2 DS 1
pwm3 DS 1
pwm4 DS 1
pwm5 DS 1
pwm6 DS 1
pwm7 DS 1
ORG $30 ;bank1
ORG $50 ;bank2
ORG $70 ;bank3
ORG $90 ;bank4
ORG $B0 ;bank5
ORG $E0 ;bank6
ORG $F0 ;bank7
RA_DIR EQU %00000000
RB_DIR EQU %00000000
;RB.0 .. RB.7 - LED outputs
RC_DIR EQU %00000000
ORG $000
start
;init ports
clr RA
clr RB
clr RC
mov w, #RA_DIR
mov !RA, w
mov w, #RB_DIR
mov !RB, w
mov w, #RC_DIR
mov !RC, w
;init vars
call init_pwms
;****************************************************************************
;pwm loop:
;****************************************************************************
bank pwm_bank
pwm_loop
clr w ;clear w, and then set bits of those
;channels that don't need to be reset
decsz pwm0 ;don't set bit on reaching the end of a pwm pulse
or w, #$01
decsz pwm1
or w, #$02
decsz pwm2
or w, #$04
decsz pwm3
or w, #$08
decsz pwm4
or w, #$10
decsz pwm5
or w, #$20
decsz pwm6
or w, #$40
decsz pwm7
or w, #$80
and w, pwm_state ;clear those bits that are zero already
dec pwm_period ;decrement master pwm counter
snz ;on reaching 0, set all outputs
xor w, #$FF
mov pwm_state, w ;update state
; and w, #$7F ;mask beeper on RB.7
mov RB, w ;update outputs
;on zero pwm_period counter update pwm counters
;
;Note: for a completely stable step size, a delay
; equal to update_pwms routine should be added
; on non-zero pwm_period. Can also be done using RTC.
test pwm_period
snz
call update_pwms
jmp pwm_loop
;****************************************************************************
;Load PWM counters and inputs with 0, 32, 64, 96, 128, 160, 192, 224
init_pwms
mov w, #pwm_bank ;use FSR as pointer
mov FSR, w
clr temp ;temp holds value and also is used as a counter
inc temp
init_pwms_loop
mov w, temp ;load value
mov IND, w ;save to pwm counter
inc FSR ;next pwm channel
mov w, #32 ;next value
add temp, w
sc ;loop until overflow
jmp init_pwms_loop
clr pwm_state ;initially all outputs are OFF
clr pwm_period ;reset pwm counter
clr dir ;init direction (all up)
retp
;****************************************************************************
;To each pwm channel counter:
;1) if direction=0, add 1. On reaching 255, change direction
;2) if direction=1, subtract 1. On reaching 1, change direction
update_pwms
mov w, #pwm_bank ;use FSR as pointer
mov FSR, w
mov w, #$80 ;temp holds direction value and also is used as a counter
mov temp, w
update_pwms_loop
;update pwm input according to direction
mov w, #$01 ;w = dir == 0? 1 : 255
snb dir.0
mov w, #$FF
add IND, w
;check limits
add w, IND ;zero if the limit is reached
mov w, #$01 ;invert the direction bit on borrow
snz
xor dir, w
;select next channel
inc FSR
rr dir ;shift new dir bit in temp
rr temp ;and temp to carry (carry is set after 8 shifts)
sc ;loop until overflow
jmp update_pwms_loop
;update direction
mov w, temp
mov dir, w
retp
;****************************************************************************
ORG $200
ORG $400
ORG $600