Sorry if there is a better way to include code. This is what I’m trying to compile. It’s not my code but a program from Nuts and Volts January '08. It compiles with only the one Linker error and I didn’t find an obvious point to change the code suggested. Thanks for looking at this for me.
;*******************************************************************************
; Digital Domain Color Organ Program for the MSP430F2012
;
; The ADC10 is used to digitize audio samples at ~16000 samples/second. The
; samples are processed by a noise gate and an AGC (automatic gain control)
; function to keep the sampled data in a range suitable for filtering.
; The agc'ed samples are then sent to four 3rd order digital
; filters for the four bands: low, low mid, high mid and high. The outputs
; of the filters are processed and used to PWM the brightness of the output
; LEDs.
;
; Most of the color organ functions performed in the "old days" with analog
; circuitry are performed in this design.
;
; Written and Copyright by: Craig A. Lindley
; Version: 1.0
; Last update: 06/26/2007
;
;*******************************************************************************
;
#include "msp430x20x2.h"
;
; Register aliases used in this program
;
#define in R4
#define out R5
#define acc R6
#define p R7
#define in1 R8
#define in2 R9
#define out1 R10
#define out2 R11
;
;-------------------------------------------------------------------------------
; Program Equates
;-------------------------------------------------------------------------------
;
; Noise gate and decay processor equates
;
MIN_SAMPLE EQU 10 ; Any sample less than this becomes 0
MIN_PWM_SAMPLE EQU 17 ; Any sample less than this becomes 0
DECAY_COUNT EQU 2000 ; Clear filter histories after this
;
; AGC equates
;
MAX_SAMPLE EQU 8192 ; Max value for max light output
PEAK_THRESHOLD EQU MAX_SAMPLE / 10 ;Threshold for gain adjustments
PEAKS_MAX EQU 30 ; Number of peaks before gain lowered
PEAKS_MIN EQU 5 ; Number of peaks before gain raised
COUNTED_SAMPLES EQU 1000 ; Samples in 1/16th of a second
GAIN_MAX EQU 15
;
; AGC state machine equates
;
STATE_0 EQU 0
STATE_1 EQU 1
STATE_2 EQU 2
STATE_3 EQU 3
STATE_4 EQU 4
;
; ADC equates
;
ADCIN EQU INCH_3 ; External ADC input is A3 on P1.3
;
; PWM equates
;
PWM_BIT EQU 4
PWM_PERIOD EQU 500
PWM_OFF EQU PWM_PERIOD + 1
;
; Output slot equates
;
NO_SLOT EQU 4
LP_SLOT EQU 0
LM_SLOT EQU 1
HM_SLOT EQU 2
HP_SLOT EQU 3
;
BLUE_MUX_BITS EQU 0
GREEN_MUX_BITS EQU 1
YELLOW_MUX_BITS EQU 2
RED_MUX_BITS EQU 3
;
; Do output channel assignment
;
; LP=red,LM=yellow,HM=green,HP=blue
;
;LP_MUX_BITS EQU RED_MUX_BITS
;LM_MUX_BITS EQU YELLOW_MUX_BITS
;HM_MUX_BITS EQU GREEN_MUX_BITS
;HP_MUX_BITS EQU BLUE_MUX_BITS
;
; LP=blue,LM=green,HM=yellow,HP=red
;
LP_MUX_BITS EQU BLUE_MUX_BITS
LM_MUX_BITS EQU GREEN_MUX_BITS
HM_MUX_BITS EQU YELLOW_MUX_BITS
HP_MUX_BITS EQU RED_MUX_BITS
;
;-------------------------------------------------------------------------------
; Data segment
;-------------------------------------------------------------------------------
;
ASEGN DATA16_N
;
LowLPDelay0 DS 2
LowLPDelay1 DS 2
LowLPDelay2 DS 2
LowMidLPDelay0 DS 2
LowMidLPDelay1 DS 2
LowMidLPDelay2 DS 2
LowMidHPDelay0 DS 2
LowMidHPDelay1 DS 2
LowMidHPDelay2 DS 2
HighMidLPDelay0 DS 2
HighMidLPDelay1 DS 2
HighMidLPDelay2 DS 2
HighMidHPDelay0 DS 2
HighMidHPDelay1 DS 2
HighMidHPDelay2 DS 2
HighHPDelay0 DS 2
HighHPDelay1 DS 2
HighHPDelay2 DS 2
LowOutput DS 2
LowMidOutput DS 2
HighMidOutput DS 2
HighOutput DS 2
Gain DS 2
Slot DS 2
DecayCount DS 2
SampleCount DS 2
PeakCount DS 2
State DS 2
;
;-------------------------------------------------------------------------------
; Code segment
;-------------------------------------------------------------------------------
ASEGN CODE ; Start of FLASH
;
; Do processor initialization
;
main mov #0280h,SP ; Initialize stackpointer
mov #WDTPW+WDTHOLD,&WDTCTL ; Stop WDT for now
;
; Set DCO to 16 MHz
;
mov.b &CALDCO_16MHZ,&DCOCTL ; Load calibration data for
mov.b &CALBC1_16MHZ,&BCSCTL1 ; 16MHZ DCO
;
; Set SMCK to DCO/8 or 2MHZ. SMCLK used by ADC10, TimerA and WDT
;
mov.b #DIVS0+DIVS1,&BCSCTL2
;
; Do application initialization
;
call #appInit
;
; Loop forever
;
l1 nop
nop
jmp l1
;
;-------------------------------------------------------------------------------
; ADC10 interrupt service routine
; Called for each new sample ~ 16000 times/second
;-------------------------------------------------------------------------------
;
adc10_isr
mov &ADC10MEM,in ; Get new sample
sub #0x1FF,in ; Remove DC component
;
;-------------------------------------------------------------------------------
; Noise gate function
;
; This function monitors the value of the input sample and if it is less
; than the threshold it is set equal to zero.
;
; in in "in" register
; out in "out" register
;-------------------------------------------------------------------------------
;
; Do absolute value on in -> out
;
mov in,out ; Move in to out
tst out ; Test out against 0
jge ng0 ; if out >= 0, jmp to done
inv out ; out < 0 so do 2's comp
inc out
ng0 cmp #MIN_SAMPLE,out ; Is sample above threshold ?
jge ng1 ; Jmp if it is
clr in ; Otherwise set sample to 0
ng1
;
;-------------------------------------------------------------------------------
; Decay processor function
;
; This processor looks for long runs of zero samples and if DecayCount number
; are found the filter histories are reset so filter outputs go to zero.
;
; in in the "in" register
; no output from this function other than filters reset when appropriate
;-------------------------------------------------------------------------------
;
tst in ; Do we have a non zero sample ?
jnz d1 ; Jmp if so
tst &DecayCount ; Have we fully decayed ?
jnz d2 ; Jmp if not
call #initFilters ; Fully decayed so reinit filters
clr &Gain ; Also set gain to unity
d1 mov #DECAY_COUNT,&DecayCount; Reset decay count
jmp d3
d2 dec &DecayCount ; Decrement decay count
d3
;
;-------------------------------------------------------------------------------
; AGC gain element
; Provides gain to a sample depending upon the value of
; the Gain variable. If Gain = 0, sample is returned
; unchanged. If Gain > 0, the sample is amplified. Gain attentuation
; is never needed.
;
; in in the "in" register
; out in the "in" register
;-------------------------------------------------------------------------------
;
tst in ; Is input sample zero ?
jz ge1 ; If yes no gain correction is possible
tst &Gain ; Unity gain ?
jz ge1 ; Jmp if so as there is nothing to do
;
; Gain is to be adjusted
;
mov &Gain,R14 ; Get the Gain
rla R14 ; Convert to index
mov #gainTbl,R15 ; Pt at end of gainTbl
sub R14,R15 ; R15 is ptr to code
call R15 ; Execute proper number of rla's
ge1
;
;-------------------------------------------------------------------------------
; AGC state machine
; This state machine is executed every sample and the complete state machine
; is executed every 1/16th of a second. Gain can be modified only once each
; state machine execution. This state machine sets the Gain variable. The
; code above manipulates the actual samples.
;-------------------------------------------------------------------------------
;
; Dispatch to current state
; States are ordered for efficiency
;
cmp #STATE_2,&State
jeq state2
cmp #STATE_1,&State
jeq state1
cmp #STATE_3,&State
jeq state3
cmp #STATE_4,&State
jeq state4
;
; STATE 0 - Set gain to unity and transistion to STATE 1
; This state is only entered once.
;
state0 clr &Gain ; Set unity gain
mov #STATE_1,&State ; Go to STATE 1
jmp smExit
;
; STATE 1 - Clear counts and transistion to STATE 2
; This state is entered at least every 1/16 of a second or
; every 1000 samples. Everytime the state machines restarts it starts in
; this state.
;
state1 clr &SampleCount ; Clear count of samples
clr &PeakCount ; Clear count of peaks
mov #STATE_2,&State ; Go to STATE 2
jmp smExit
;
; STATE 2 - Count samples and peaks
; State machine will remain in this state until either the time interval
; has been exceeded or the maximum number of peaks have been detected.
; Transition to STATE 3 occurs if maximum peaks have been exceeded.
; Transition to STATE 4 occurs if time interval exceeded.
;
state2 inc &SampleCount ; Increment sample count
;
; Take absolute value of in -> out
;
mov in,out ; Move in to out
tst out ; Test out against 0
jge state20 ; if out >= 0, jmp to done
inv out ; out < 0 so do 2's comp
inc out
state20 cmp #PEAK_THRESHOLD,out ; Is sample above max ?
jl state21 ; Jmp if not
inc &PeakCount ; Count the peak
cmp #PEAKS_MAX,&PeakCount ; Has peak count been exceeded ?
jl state21 ; Jmp if not
mov #STATE_3,&State ; Go to STATE 3
jmp smExit
state21 cmp #COUNTED_SAMPLES,&SampleCount ; Has time interval exceeded ?
jne smExit ; Jmp if not
mov #STATE_4,&State ; Time exceeded, go to STATE4
jmp smExit
;
; STATE 3 - Maximum peaks have been exceeded so gain is reduced and a transition
; to STATE 1 occurs to restart state machine.
;
state3 dec &Gain ; Decrease the gain
mov #STATE_1,&State ; Go to STATE 1
jmp smExit
;
; STATE 4 - Counted samples have expired so a transition to STATE 1 occurs. If
; to few peaks were detected in this interval, gain is increased.
;
state4 cmp #PEAKS_MIN,&PeakCount ; Were minimum peaks detected ?
jge state41 ; If not go to STATE 1
cmp #GAIN_MAX,&Gain ; Limit how high the gain can go
jge state41
inc &Gain ; Increase gain
state41 mov #STATE_1,&State ; Go to STATE 1
smExit
;
push in ; Place gain adjusted sample on stack
;
;-------------------------------------------------------------------------------
; Low Frequency Low Pass Lattice Wave Digital Filter
;
; Third order Chebyshev with fc ~ 115 Hz
; Horner equations generated with horner.java.
;
; Adaptor 0 Type 1
; Adaptor 1 Type 4
; Adaptor 2 Type 1
;
; Alpha0 = 0.029038268420706226
; Alpha1 = 0.029021120245024568
; Alpha2 = 0.0011984646525969866
;
; Adapter implementation order: 0,2,1
;
;-------------------------------------------------------------------------------
;
; Adaptor 0 - Type 1
;
mov in,in1 ; sample into in1
mov &LowLPDelay0,in2 ; delay int in2
mov in1,p ; p = in1
sub in2,p ; p = in1 - in2
;Horner equations:
;T1 = X * 2^-4 - X
;T2 = T1 * 2^-3 - X
;T3 = T2 * 2^-4 + X
;Fraction result = T3 * 2^-5
mov p,acc
rra acc
rra acc
rra acc
rra acc
sub p,acc
rra acc
rra acc
rra acc
sub p,acc
rra acc
rra acc
rra acc
rra acc
add p,acc
rra acc
rra acc
rra acc
rra acc
rra acc
add in2,acc ; acc = out2
mov acc,&LowLPDelay0 ; store delay for next time
sub p,acc ; out1 = out2 - p
mov acc,out1 ; Save top output
;
; Adaptor 2 - Type 1
;
mov &LowLPDelay1,in1 ; in1 = delay1
mov &LowLPDelay2,in2 ; in2 = delay2
mov in1,p ; p = in1
sub in2,p ; p = in1 - in2
;Horner equations:
;T1 = X * 2^-3 + X
;T2 = T1 * 2^-2 + X
;Fraction result = T2 * 2^-10
mov p,acc
rra acc
rra acc
rra acc
add p,acc
rra acc
rra acc
add p,acc
rra acc
rra acc
rra acc
rra acc
rra acc
rra acc
rra acc
rra acc
rra acc
rra acc
add in2,acc ; acc = out2
mov acc,&LowLPDelay2 ; store delay for next time
sub p,acc ; acc = out1
;
; Adaptor 1 - Type 4
;
mov in,in1 ; sample into in1
mov acc,in2 ; out from previous stage
mov in2,p ; p = in2
sub in1,p ; p = in2 - in1
;Horner equations:
;T1 = X * 2^-2 - X
;T2 = T1 * 2^-2 - X
;T3 = T2 * 2^-3 - X
;7T4 = T3 * 2^-4 + X
;Fraction result = T4 * 2^-5
mov p,acc
rra acc
rra acc
sub p,acc
rra acc
rra acc
sub p,acc
rra acc
rra acc
rra acc
sub p,acc
rra acc
rra acc
rra acc
rra acc
add p,acc
rra acc
rra acc
rra acc
rra acc
rra acc
sub in2,acc ; acc is out2
mov acc,&LowLPDelay1 ; store delay for next time
sub p,acc ; acc is out1
;
; Combine outputs
;
add out1,acc ; sum of output1 + output2
rra acc ; divide by two
mov acc,in
;
call #processForPWM ; Process result for PWM usage
mov out,&LowOutput ; Result in LowOutput
pop in ; Get input sample again
push in
;
;-------------------------------------------------------------------------------
; Low/Mid Frequency Band Pass Lattice Wave Digital Filter
; Made with third order CauerEllipic HP and LP filter sections
; fc ~ 600 Hz
; Horner equations generated with horner.java.
;
; High Pass Filter Specs
;
; Adaptor 0 Type 1
; Adaptor 1 Type 4
; Adaptor 2 Type 1
;
; Alpha = 0.1506240867800397
; Alpha = 0.1226961162560467
; Alpha = 0.015895377584976056
;
; Low Pass Filter Specs
;
; Adaptor 0 Type 1
; Adaptor 1 Type 4
; Adaptor 2 Type 1
;
; Alpha = 0.2554927751405798
; Alpha = 0.17297510883210843
; Alpha = 0.048924617642919443
;
; Adapter implementation order: HP0,HP2,HP1,LP0,LP2,LP1
;-------------------------------------------------------------------------------
;
; Adaptor 0 of HP section - Type 1
;
mov in,in1 ; sample into in1
mov &LowMidHPDelay0,in2 ; delay into in2
mov in1,p ; p = in1
sub in2,p ; p = in1 - in2
;Horner equations:
;T1 = X * 2^-4 + X
;T2 = T1 * 2^-3 + X
;T3 = T2 * 2^-2 - X
;T4 = T3 * 2^-2 + X
;T5 = T4 * 2^-2 + X
;Fraction result = T5 * 2^-3
mov p,acc
rra acc
rra acc
rra acc
rra acc
add p,acc
rra acc
rra acc
rra acc
add p,acc
rra acc
rra acc
sub p,acc
rra acc
rra acc
add p,acc
rra acc
rra acc
add p,acc
rra acc
rra acc
rra acc
add in2,acc ; acc = out2
mov acc,&LowMidHPDelay0 ; store delay for next time
sub p,acc ; out1 = out2 - p
mov acc,out1 ; acc is out1
; Adaptor 2 of HP section - Type 1
;
mov &LowMidHPDelay1,in1 ; in1 = delay1
mov &LowMidHPDelay2,in2 ; in2 = delay2
mov in1,p ; p = in1
sub in2,p ; p = in1 - in2
;Horner equations:
;T1 = X * 2^-4 + X
;T2 = T1 * 2^-6 + X
;Fraction result = T2 * 2^-6
mov p,acc
rra acc
rra acc
rra acc
rra acc
add p,acc
rra acc
rra acc
rra acc
rra acc
rra acc
rra acc
add p,acc
rra acc
rra acc
rra acc
rra acc
rra acc
rra acc
add in2,acc ; acc = out2
mov acc,&LowMidHPDelay2 ; store delay for next time
sub p,acc ; acc = out1
;
; Adaptor 1 of HP section - Type 4
;
mov in,in1 ; sample into in1
mov acc,in2 ; out1 from previous stage
mov in2,p ; p = in2
sub in1,p ; p = in2 - in1
;Horner equations:
;T1 = X * 2^-3 + X
;T2 = T1 * 2^-2 - X
;T3 = T2 * 2^-2 - X
;T4 = T3 * 2^-6 + X
;Fraction result = T4 * 2^-3
mov p,acc
rra acc
rra acc
rra acc
add p,acc
rra acc
rra acc
sub p,acc
rra acc
rra acc
sub p,acc
rra acc
rra acc
rra acc
rra acc
rra acc
rra acc
add p,acc
rra acc
rra acc
rra acc
sub in2,acc ; acc = out2
mov acc,&LowMidHPDelay1 ; store delay for next time
sub p,acc ; acc = out1
;
; Combine outputs for high pass function
;
sub acc,out1
rra out1
mov out1,out2
;
; Adapter 0 of LP section - Type 1
;
mov out2,in1 ; out2 has high pass output
mov &LowMidLPDelay0,in2 ; delay into in2
mov in1,p ; p = in1
sub in2,p ; p = in1 - in2
;Horner equations:
;T1 = X * 2^-3 + X
;T2 = T1 * 2^-2 - X
;T3 = T2 * 2^-2 - X
;T4 = T3 * 2^-2 + X
;T5 = T4 * 2^-5 + X
;Fraction result = T5 * 2^-2
mov p,acc
rra acc
rra acc
rra acc
add p,acc
rra acc
rra acc
sub p,acc
rra acc
rra acc
sub p,acc
rra acc
rra acc
add p,acc
rra acc
rra acc
rra acc
rra acc
rra acc
add p,acc
rra acc
rra acc
add in2,acc ; acc = out2
mov acc,&LowMidLPDelay0 ; store delay for next time
sub p,acc ; out1 = out2 - p
mov acc,out1 ; Save top output
;
; Adaptor 2 of LP section - Type 1
;
mov &LowMidLPDelay1,in1 ; in1 = delay1
mov &LowMidLPDelay2,in2 ; in2 = delay2
mov in1,p ; p = in1
sub in2,p ; p = in1 - in2
;Horner equations:
;T1 = X * 2^-2 + X
;T2 = T1 * 2^-4 + X
;T3 = T2 * 2^-3 - X
;T4 = T3 * 2^-2 + X
;Fraction result = T4 * 2^-4
mov p,acc
rra acc
rra acc
add p,acc
rra acc
rra acc
rra acc
rra acc
add p,acc
rra acc
rra acc
rra acc
sub p,acc
rra acc
rra acc
add p,acc
rra acc
rra acc
rra acc
rra acc
add in2,acc ; acc = out2
mov acc,&LowMidLPDelay2 ; store delay for next time
sub p,acc ; acc = out1
;
; Adaptor 1 of LP section - Type 4
;
mov out2,in1
mov acc,in2
mov in2,p ; p = in2
sub in1,p ; p = in2 - in1
;Horner equations:
;T1 = X * 2^-3 + X
;T2 = T1 * 2^-4 - X
;T3 = T2 * 2^-2 - X
;T4 = T3 * 2^-2 + X
;Fraction result = T4 * 2^-2
mov p,acc
rra acc
rra acc
rra acc
add p,acc
rra acc
rra acc
rra acc
rra acc
sub p,acc
rra acc
rra acc
sub p,acc
rra acc
rra acc
add p,acc
rra acc
rra acc
sub in2,acc ; acc = out2
mov acc,&LowMidLPDelay1 ; store delay for next time
sub p,acc ; acc = out2
;
; Combine outputs
;
add out1,acc
rra acc
mov acc,in
;
call #processForPWM ; Process result for PWM usage
mov out,&LowMidOutput ; Result in LowMidOutput
pop in ; Get input sample
push in
;
;-------------------------------------------------------------------------------
; High/Mid Frequency Band Pass Lattice Wave Digital Filter
; Made with third order CauerElliptic HP and LP filter sections
; fc ~ 2.4 KHz
; Horner equations generated with horner.java.
;
; High Pass Filter Specs
;
; Adaptor 0 Type 2
; Adaptor 1 Type 4
; Adaptor 2 Type 1
;
; Alpha = 0.3525975077291272
; Alpha = 0.4536651886901931
; Alpha = 0.3789313695495832
;
; Low Pass Filter Specs
;
; Adaptor 0 Type 2
; Adaptor 1 Type 4
; Adaptor 2 Type 2
;
; Alpha = 0.21581589315641658
; Alpha = 0.4739679570641818
; Alpha = 0.41328688498417915
;
; Adapter implementation order: HP0,HP2,HP1,LP0,LP2,LP1
;-------------------------------------------------------------------------------
;
; Adaptor 0 of HP section - Type 2
;
mov in,in1 ; sample into in1
mov &HighMidHPDelay0,in2 ; delay int in2
mov in2,p ; p = in2
sub in1,p ; p = in2 - in1
;Horner equations:
;T1 = X * 2^-2 + X
;T2 = T1 * 2^-4 + X
;T3 = T2 * 2^-3 + X
;T4 = T3 * 2^-2 - X
;T5 = T4 * 2^-2 - X
;T6 = T5 * 2^-2 + X
;Fraction result = T6 * 2^-1
mov p,acc
rra acc
rra acc
add p,acc
rra acc
rra acc
rra acc
rra acc
add p,acc
rra acc
rra acc
rra acc
add p,acc
rra acc
rra acc
sub p,acc
rra acc
rra acc
sub p,acc
rra acc
rra acc
add p,acc
rra acc
push acc
add in1,acc ; acc = out2
mov acc,&HighMidHPDelay0 ; store delay for next time
pop acc
add in2,acc ; out1 = out2 - p
mov acc,out1 ; acc is out1
;
; Adaptor 2 of HP section - Type 1
;
mov &HighMidHPDelay1,in1 ; in1 = delay1
mov &HighMidHPDelay2,in2 ; in2 = delay2
mov in1,p ; p = in1
sub in2,p ; p = in1 - in2
;Horner equations:
;T1 = X * 2^-8 + X
;T2 = T1 * 2^-5 - X
;T3 = T2 * 2^-2 + X
;Fraction result = T3 * 2^-1
mov p,acc
rra acc
rra acc
rra acc
rra acc
rra acc
rra acc
rra acc
rra acc
add p,acc
rra acc
rra acc
rra acc
rra acc
rra acc
sub p,acc
rra acc
rra acc
add p,acc
rra acc
add in2,acc ; acc = out2
mov acc,&HighMidHPDelay2 ; store delay for next time
sub p,acc ; acc = out1
;
; Adaptor 1 of HP section - Type 4
;
mov in,in1 ; sample into in1
mov acc,in2 ; out1 from previous stage
mov in2,p ; p = in2
sub in1,p ; p = in2 - in1
;Horner equations:
;T1 = X * 2^-2 + X
;T2 = T1 * 2^-3 + X
;T3 = T2 * 2^-5 + X
;T4 = T3 * 2^-2 - X
;T5 = T4 * 2^-3 + X
;Fraction result = T5 * 2^-1
mov p,acc
rra acc
rra acc
add p,acc
rra acc
rra acc
rra acc
add p,acc
rra acc
rra acc
rra acc
rra acc
rra acc
add p,acc
rra acc
rra acc
sub p,acc
rra acc
rra acc
rra acc
add p,acc
rra acc
sub in2,acc ; acc = out2
mov acc,&HighMidHPDelay1 ; store delay for next time
sub p,acc ; acc = out1
;
; Combine outputs for high pass function
;
sub acc,out1
rra out1
mov out1,out2
;
; Adapter 0 of LP section - Type 2
;
mov out2,in1 ; out2 has high pass output
mov &HighMidLPDelay0,in2 ; delay int in2
mov in2,p ; p = in2
sub in1,p ; p = in2 - in1
;Horner equations:
;T1 = X * 2^-6 + X
;T2 = T1 * 2^-2 - X
;T3 = T2 * 2^-3 - X
;T4 = T3 * 2^-3 + X
;Fraction result = T4 * 2^-2
mov p,acc
rra acc
rra acc
rra acc
rra acc
rra acc
rra acc
add p,acc
rra acc
rra acc
sub p,acc
rra acc
rra acc
rra acc
sub p,acc
rra acc
rra acc
rra acc
add p,acc
rra acc
rra acc
push acc
add in1,acc ; acc = out2
mov acc,&HighMidLPDelay0 ; store delay for next time
pop acc
add in2,acc
mov acc,out1 ; Save top output
;
; Adaptor 2 of LP section - Type 2
;
mov &HighMidLPDelay1,in1 ; in1 = delay1
mov &HighMidLPDelay2,in2 ; in2 = delay2
mov in2,p ; p = in2
sub in1,p ; p = in2 - in1
;Horner equations:
;T1 = X * 2^-2 - X
;T2 = T1 * 2^-2 + X
;T3 = T2 * 2^-2 - X
;T4 = T3 * 2^-3 + X
;T5 = T4 * 2^-2 + X
;T6 = T5 * 2^-2 - X
;T7 = T6 * 2^-2 + X
;Fraction result = T7 * 2^-1
mov p,acc
rra acc
rra acc
sub p,acc
rra acc
rra acc
add p,acc
rra acc
rra acc
sub p,acc
rra acc
rra acc
rra acc
add p,acc
rra acc
rra acc
add p,acc
rra acc
rra acc
sub p,acc
rra acc
rra acc
add p,acc
rra acc
push acc
add in1,acc ; acc = out2
mov acc,&HighMidLPDelay2 ; store delay for next time
pop acc
add in2,acc ; acc = out1
;
; Adaptor 1 of LP section - Type 4
;
mov out2,in1
mov acc,in2
mov in2,p ; p = in2
sub in1,p ; p = in2 - in1
;Horner equations:
;T1 = X * 2^-2 + X
;T2 = T1 * 2^-2 + X
;T3 = T2 * 2^-2 + X
;T4 = T3 * 2^-2 + X
;T5 = T4 * 2^-3 - X
;T6 = T5 * 2^-4 + X
;Fraction result = T6 * 2^-1
mov p,acc
rra acc
rra acc
add p,acc
rra acc
rra acc
add p,acc
rra acc
rra acc
add p,acc
rra acc
rra acc
add p,acc
rra acc
rra acc
rra acc
sub p,acc
rra acc
rra acc
rra acc
rra acc
add p,acc
rra acc
sub in2,acc ; acc = out2
mov acc,&HighMidLPDelay1 ; store delay for next time
sub p,acc ; acc = out1
;
; Combine outputs
;
add out1,acc
rra acc
mov acc,in
;
call #processForPWM ; Process result for PWM usage
mov out,&HighMidOutput ; Result in HighMidOutput
pop in ; Get input sample, clear stack
;
;-------------------------------------------------------------------------------
; High Frequency High Pass Lattice Wave Digital Filter
; Third order Chebyshev with fc ~ 6.2 KHz
; Horner equations generated with horner.java.
;
; Adaptor 0 Type 3
; Adaptor 1 Type 4
; Adaptor 2 Type 4
;
; Alpha = 0.35290166046448673
; Alpha = 0.4823641184368461
; Alpha = 0.30404751604718305
;
; Adapter implementation order: 0,2,1
;
;-------------------------------------------------------------------------------
;
; Adaptor 0 - Type 3
;
mov in,in1 ; sample into in1
mov &HighHPDelay0,in2 ; delay int in2
mov in1,p ; p = in1
sub in2,p ; p = in1 - in2
;Horner equations:
;T1 = X * 2^-3 - X
;T2 = T1 * 2^-2 - X
;T3 = T2 * 2^-2 + X
;T4 = T3 * 2^-2 + X
;T5 = T4 * 2^-2 - X
;T6 = T5 * 2^-2 - X
;T7 = T6 * 2^-2 + X
;Fraction result = T7 * 2^-1
mov p,acc
rra acc
rra acc
rra acc
sub p,acc
rra acc
rra acc
sub p,acc
rra acc
rra acc
add p,acc
rra acc
rra acc
add p,acc
rra acc
rra acc
sub p,acc
rra acc
rra acc
sub p,acc
rra acc
rra acc
add p,acc
rra acc
push acc
sub in1,acc ; acc = out2
mov acc,&HighHPDelay0 ; store delay for next time
pop acc
sub in2,acc ; acc = out1
mov acc,out1 ; Save top output
;
; Adaptor 2 - Type 4
;
mov &HighHPDelay1,in1 ; in1 = delay1
mov &HighHPDelay2,in2 ; in2 = delay2
mov in2,p ; p = in2
sub in1,p ; p = in2 - in1
;Horner equations:
;T1 = X * 2^-2 - X
;T2 = T1 * 2^-2 - X
;T3 = T2 * 2^-4 - X
;T4 = T3 * 2^-3 + X
;T5 = T4 * 2^-2 + X
;Fraction result = T5 * 2^-2
mov p,acc
rra acc
rra acc
sub p,acc
rra acc
rra acc
sub p,acc
rra acc
rra acc
rra acc
rra acc
sub p,acc
rra acc
rra acc
rra acc
add p,acc
rra acc
rra acc
add p,acc
rra acc
rra acc
sub in2,acc ; acc = out2
mov acc,&HighHPDelay2 ; store delay for next time
sub p,acc ; acc = out1
;
; Adaptor 1 - Type 4
;
mov in,in1 ; sample into in1
mov acc,in2 ; out from previous stage
mov in2,p ; p = in2
sub in1,p ; p = in2 - in1
;Horner equations:
;T1 = X * 2^-5 - X
;T2 = T1 * 2^-3 - X
;T3 = T2 * 2^-5 + X
;Fraction result = T3 * 2^-1
mov p,acc
rra acc
rra acc
rra acc
rra acc
rra acc
sub p,acc
rra acc
rra acc
rra acc
sub p,acc
rra acc
rra acc
rra acc
rra acc
rra acc
add p,acc
rra acc
sub in2,acc ; acc = out2
mov acc,&HighHPDelay1 ; store delay for next time
sub p,acc ; acc = out1 of stage or output2 of filter
;
; Combine outputs for HP output
;
sub acc,out1 ; sum of output1 - output2
rra out1 ; divide by two
mov out1,in
;
call #processForPWM ; Process result for PWM usage
mov out,&HighOutput ; Result in HighOutput
reti
;
;
;-------------------------------------------------------------------------------
; Process the filter outputs into form suitable for driving PWM circuitry
;
; in in the "in" register.
; out in the "out" register
;-------------------------------------------------------------------------------
;
processForPWM
;
; Take the absolute value of the filtered sample because we only want
; positive sample values for PWM calculations.
;
mov in,out ; Move in to out
tst out ; Test out against 0
jge p0 ; if out >= 0, jmp to done
inv out ; out < 0 so do 2's comp
inc out
;
p0 cmp #MIN_PWM_SAMPLE,out ; Is sample below min ?
jge p1
mov #PWM_OFF,out ; Turn output off
ret
p1 cmp #MAX_SAMPLE,out ; Is sample above max ?
jl p2 ; Jmp if not
mov #MAX_SAMPLE,out ; Clip if it is
;
; Multiply sample value by 0.059814
; This converts the range of sample values from 0..8192 to the range of
; PWM values, 0..490. This is done because above 490
; there are known crosstalk problems.
;
p2 mov out,acc
rra acc
rra acc
rra acc
rra acc
add out,acc
rra acc
rra acc
add out,acc
rra acc
rra acc
sub out,acc
rra acc
rra acc
rra acc
rra acc
add out,acc
rra acc
rra acc
rra acc
rra acc
;
; Substract processed sample value from 500. Sample range of 0..490
; becomes 500..10. This conversion is necessary because the larger
; the sample value the smaller PWM count it has because this causes the
; widest possible PWM pulse for maximum LED brightness.
;
mov #PWM_PERIOD,out ; Load PWM period value
sub acc,out ; Convert calculated PWM value
ret
;
;-------------------------------------------------------------------------------
; AGC gain tables
;-------------------------------------------------------------------------------
;
rla in ; Indexed gain table
rla in
rla in
rla in
rla in
rla in
rla in
rla in
rla in
rla in
rla in
rla in
rla in
rla in
rla in
rla in
rla in
rla in
rla in
rla in
gainTbl ret
;
;-------------------------------------------------------------------------------
; Initialize filter histories and filter outputs to zero
;-------------------------------------------------------------------------------
;
initFilters
mov #22,R14
mov #LowLPDelay0,R15
if1 clr 0(R15)
inc R15
inc R15
dec R14
tst R14
jnz if1
ret
;
;-------------------------------------------------------------------------------
; Application initialization
;-------------------------------------------------------------------------------
;
appInit
;
; Port initialization for color organ
; P1.0 and P1.1 will be the demux outputs
; P1.2 will be the PWM pulse output
; P1.3 will be the analog input to the ADC10
;
mov.b #PWM_BIT,&P1OUT ; All bits except P1.2 set off
bis.b #0x07,&P1DIR ; Set P1.0, P1.1 and P1.2 to outputs
bis.b #PWM_BIT,&P1SEL ; P1.2/TA1 set for PWM out
;
; ADC10 initialization
;
; For ADC10CTL0
; Select reference: VR+ = VREF+ and VR- = VSS
; Sample and hold time: 4 ADC10CLKs
; Sampling rate: up to ~50 ksps
; Reference output: off
; Reference burst: reference buffer on continuously
; Multiple sample and conversion: Automatic conversions as fast as possible
; Reference generator voltage: 2.5V
; Reference generator on: on
; ADC10on: adc10 on
; ADC10 interrupt enable: interrupt enabled
; Enable conversion: ADC10 disabled (until later)
; Start conversion: no sample and conversion start (until later)
;
mov #SREF0+ADC10SR+MSC+REF2_5V+REFON+ADC10ON+ADC10IE,&ADC10CTL0
;
; For ADC10CTL1
; Input channel select: ADCIN
; Sample and hold source select: ADC10SC
; ADC10 data format: not two compliment
; Invert signal sample and hold: not inverted
; ADC10 clock divider: divide by 7
; ADC10 clock source: SMCLK
; Conversion sequence mode select: repeat single channel
;
mov #ADCIN+ADC10DIV2+ADC10DIV1+ADC10SSEL1+ADC10SSEL0+CONSEQ1,&ADC10CTL1
;
; For ADC10AE0
; ADC10 analog enable: A3
;
bis.b 0x08,&ADC10AE0
;
; Watch dog timer initialization
; Set to interval mode with SM clock/512
; This should cause an interval interrupt every 256 microseconds
;
mov #WDTPW+WDTCNTCL+WDTTMSEL+WDTIS1,&WDTCTL
;
; Timer A initialization
; Timer is set for PWM mode. We want the timer to be a one shot
; When enabled it should count up and output a PWM pulse. After the
; pulse is produced the next WDT interrupt stops TA. It will be restarted
; when output is needed again.
;
mov #PWM_PERIOD,&TACCR0 ; Set period
mov #PWM_PERIOD,&TACCR1 ; Initial PWM value for no output
mov #TASSEL1,&TACTL ; Set Timer A up mode, SMCLK as clock
mov #OUTMOD_7,&TACCTL1 ; Set output mode 7 for TA1
;
; Variable initialization
;
clr &Gain ; Set initial gain to unity
clr &State ; Set agc state to zero
clr &Slot ; Determines which channnel to output
mov #DECAY_COUNT,&DecayCount; Initialize decay processor count
call #initFilters ; Set all filter delay elements to zero
;
; Setup for servicing interrupts
;
bis.b #GIE,SR ; Get general interrupt enable
bis.b #WDTIE,IE1 ; Enable the watch dog interrupt
;
; Put the ADC into automatic single channel sample mode
;
bis #ENC+ADC10SC,&ADC10CTL0
ret
;
;-------------------------------------------------------------------------------
; Watch dog timer interrupt service routine
; This isr is executed every 256 micro seconds. Each time it is executed
; output is performed for a different slot/channel. Output for each
; slot/channel is performed for a maximum of 250 microseconds every
; 1.024 milliseconds. PWM is used to control the brightness of output.
;
; Timer A is used to generate a PWM pulse with a duty cycle proportional to
; the value to be output. Timer A is disabled at the start of each interrupt
; and then turned back on to time the output pulse for a given slot/channel.
;
; Note: no registers are used in this isr so none need to be saved/restored
;
wdt_isr bic #MC0,&TACTL ; Disable TA
;
; Is it time for Low output ?
;
cmp #LP_SLOT,&Slot ; Time for Low output ?
jne wd1 ; No check next slot/channel
;
; Yes, time for Low output.
;
mov.b #LP_MUX_BITS,&P1OUT ; Set mux bits
mov &LowOutput,&TACCR1 ; Set the duty cycle
jmp wd4
;
; Is it time for LowMid output ?
;
wd1 cmp #LM_SLOT,&Slot ; Time for LowMid output ?
jne wd2 ; No check next slot/channel
;
; Yes, time for LowMid output.
;
mov.b #LM_MUX_BITS,&P1OUT ; Set mux bits
mov &LowMidOutput,&TACCR1 ; Set the duty cycle
jmp wd4
;
; Is it time for HighMid output ?
;
wd2 cmp #HM_SLOT,&Slot ; Time for HighMid output ?
jne wd3 ; No check next slot/channel
;
; Yes, time for HighMid output.
;
mov.b #HM_MUX_BITS,&P1OUT ; Set mux bits
mov &HighMidOutput,&TACCR1 ; Set the duty cycle
jmp wd4
;
; By default it is time for Highs output.
;
wd3 mov.b #HP_MUX_BITS,&P1OUT ; Set mux bits
mov &HighOutput,&TACCR1 ; Set the duty cycle
;
; Turn TA on to time the PWM pulse
;
wd4 clr &TAR ; Reset TA counter to zero
bis #MC0,&TACTL ; Enable TA for PWM pulse
;
inc &Slot ; Set up for next time
cmp #NO_SLOT,&Slot
jne wd5
clr &Slot
wd5 reti
;
;-------------------------------------------------------------------------------
; Vector segment
;
ASEGN INTVEC
;
; Assign the various vectors
;
ORG ADC10_VECTOR ; ADC10 vector
DW adc10_isr
ORG WDT_VECTOR ; Watch dog timer vector
DW wdt_isr
;
ORG RESET_VECTOR
DW main ; POR vector
;
; End of program
;
END