My name is Mike Marzalek, and I have lurked in this usenet group for a
couple
years while I did hearing aid research in my spare time. I presented two
papers at the 1995 "Hearing Aid Research and Development Conference".
I no longer have the time to pursue this interest, have documented my work
and am making it public domain. If anyone in the group can use this work,
or know of anyone who can, then great.
As audiologists, you may find it interesting to see the direction that
hearing aids may be going in the future.
My name is Mike Marzalek and I am a Research and Development
engineer at Hewlett Packard, and have been for twenty nine
years. I have a BSEE from UC Berkeley, an MSEE from Stanford,
and have nine patents in the electronics field.
I have built a hearing aid that achieves infinite compression
yet it does not reduce intelligibility because it uses slow gain
time constants which do not distort the temporal envelope. This
would greatly benefit those with little residual hearing dynamic
range.
It is able to do this because it is a digital hearing aid, and
it keeps a 53 mSec circular buffer of the input speech signal
which it analyzes before outputting the processed speech to the
user.
I have ported the code from my hearing aid, to the Texas
Instruments TMS320C50 DSK development kit to make it easy to
evaluate the processing algorithms. It is available for $99
>From most electronics distributors such as Wiley.
This aid could be self fitting. It has the ability to create
arbitrary frequency and amplitude sine waves for hearing
threshold testing. During a fitting, the microphone is not
needed, so the user could clap their hands to signify hearing a
tone and to go to the next frequency. By doing hearing testing
in place with the aid, the value of real ear measurements
becomes diminished.
Another feature is limiting the max gain so that the quietest
speech intervals stay 6 dB below the target sound level.
If you have any questions, or if anyone you pass this along to
would like any assistance, please feel free to contact me.
A listing of the code follows.
Mike Marzalek
mikem at sr.hp.com
****************************************************************
* MODULE NAME: HEAR.ASM 1/27/97 Marzalek
*
* Any ideas or code in this document are public domain and
* may be used freely. Mike Marzalek 2/8/98
*
* DESCRIPTION: Hearing aid processing code. It can either run
* on a stock Texas Instruments TMS320C50 DSK development board
* available for $99 from most electronics distributors eg Wiley
* or on a highly modified DSK that has been converted to a
* hearing aid. Setting the compile option "STOCK" determines
* which.
*
* OVERVIEW: The C50 DSP has a 20 MHz clock, the adc interrupts at
* 12 kHz, so 6 kHz max frequency without aliasing.
* 640 samples (53 mSec) are kept in a circular buffer and
* "processed" before output. This allows processing the output
* data knowing what the next 53 mSec of input is. As opposed to
* reacting to the input after it has arrived, I can see the input
* up to 53 mSec into the "future". This permits interesting
* processing.
*
* As data is put into the circular buffer, the max value over
* each group of 20 samples is determined and this is kept in a
* peaks circular buffer. At the conclusion of each 20 samples, the
* peaks array is analyzed to determine at what rate to modify
* the gain while the next 20 samples are being taken and 53 mSec
* old data is being output.
*
* The current implementation utilizes infinite compression. All
* input (averaged over 53 mSec) will be heard at the same level.
* High compression is difficult to implement because of the
* distortion it causes in the temporal envelope. This design
* does not have that problem because the gain changes slowly
* over the 53 mSec it has before the current adc samples are output.
* Lesser compression would be easy to implement.
*
* The following example shows how the new algorithm compares to
* the AGC/compression in current hearing aids. Note that the
* envelope on the AGC waveform exceeds the target a lot and
* the gain then changes rapidly to recover, causing large distortion.
*
* You'll probably need to insert spaces & tabs to line up what was
* fixed pitch font graphics.
*
*
* ____________ ____
* | | |
* __| |_______________________|
* Input
* __ _______________________
* | | |
* |____________| |____
*
*
*
*
* |\ |\
* __| \__________ ____| \__
* | ____-----
* |_____-----
* Standard AGC
* _____
* | -----____
* __ __________| -----____ __
* | / | /
* |/ |/
*
*
*
* ____________ _______ __
* | | __-- --__ |
* __| |__-- --__|
* This design
* __ __ __
* | | --__ __-- |
* |____________| --_______--\ |__
* \
* \gain drops in
anticipation
*
*
* I keep track of the quietest sound input and limit the gain to
* keep this level 6 dB below the target level.
*
* An external anti-alias filter should be used to limit max input
* frequency to 6 kHz. Though things work pretty well without it.
*
* I apologize for the readabllity of the code. It wasn't intended
* to be seen in this unfinished state.
*
* There are various debugging tools built into the code. They
* work well with a code developer from GO DSP in Canada. I think
* TI now sells it for them. It was $69.
*
* If compile option BIGDEBUG is set, I keep a half second circular
* buffer where I track one variable as positive only in even
* locations, and a different variable as negative only in odd
* locations. I can display this graphically to monitor opertaion.
*
* I can generate an arbitrary frequency and amplitude sine wave
* and inject it at the input for processing testing, or at the
* output for an in patient hearing threshold test. For the
* hearing test, the input is unused, and so the patient could
* clap their hands to indicate hearing the tone and to go to
* the next frequency. Since the hearing test is administered
* by the hearing aid, the value of real ear measurements is
* diminished. It is left as an exercise for the student how
* to handle requests such as reducing high frequency energy.
*
* I can also square wave modulate the sine wave for testing
* the processing. Noise could be added if desired.
*
* There is currently no patient dependent frequency shaping,
* this is easy to add.
*
* Load/Run:
* To run the code using the TI tools:
* from DOS
* >DSK5D
* >M
* >R
* >ST1=1BC
* >L
* >D
* >HEAR.DSK
* >X
* >G
*
* To assemble the code
* >DSK5A HEAR
*
* Conventions:
* coeff & pgm must be in different blocks, Dn are in DARAM
* leave PM shift bits at reset value of zero
* overflow saturation mode on - no wrap
* sign extension mode on
* ldp set to 2 always - 100h thru 17Fh
*
* TLC2543 ADC (not stock):
* must be given a hi_reset pulse initially
* outputs a 12 bit word as a 12 bit word is entered
* the 12 bit input word is a 16 bit word hardware truncated
* during the truncation, the 12 MSB's are kept (+-32752)
* output and input are MSB first
* adc output is binary 2's complement (+- 2047 << 4=+-32752)
* run at 12 kHz (max spec 100 kHz)
* max data clock rate 4.1 MHz, I have to run 5 MHz - works!
*
* To go mobile, set the MOBILE define, 1st yank AC, then RS232
*
*
* Memory map:
* 00h - 60h memory mapped reg's
* 60h - 80h reserved by kernal
* 100h - 17Fh daram - ldp #2 default
* 180h - 19Fh peak array (different ldp)
* 1A0h - 4FFh available daram (different ldp)
* 500h - 800h reserved by kernal
* 800h - 980h interrupt vectors & reserved by kernal
* A00h -20FFh user space
* if BIGDEBUG, user A00-CFF, debug ring buf D00-23FF (size 16FF, 5887)
* 2100h -23FFh debug ring buffer
* 2400h -2BFFh input ring buffer
*
*
* AR's:
* AR0 used for "only process every nth sample" (AR0=0)
* AR1 used for ADC in circular buffer
* AR2 used for sine gen
* AR2 used for digital filter
* AR2 used as flag to process ADC input
* AR2 used to get max of peak array
* AR3 used for debug circular buffer
* AR4 used for peak array
*
* Time constants:
* peak determined real time
* everything else done @ skip rate set by AR0
*
* Labels 8 char max - will crash if not heeded
*
* There are 1667 total clocks (20 MHz/12 kHz)
****************************************************************
.mmregs
CWMIC .set 0
CWRCVR .set 0
DISPVAR .set 1
BIGDEBUG .set 1
SAFETY .set 1
SQMOD .set 1 ; square wave AM modulate sin gen
BGLIMIT .set 1 ; limit gain for background level
MOBILE .set 0
STOCK .set 1 ; stock DSK development board with AIC
FIXDGAIN .set 0
CBUFSIZE .set 640 ; 53 mSec @ 12 kHz
SKIP_CNT .set 20 ; 1.67 mSec (300 Hz has pos or neg peak)
MIN_PKS .set 15 ; new min pk only after num peak intvls
MIN_SHFT .set 1 ; max gain @ minInPk << MIN_SHFT
OUTLIMT .set 32700 ; positive limit if SAFETY set
OUTLIMTN .set -32700 ; negative limit if SAFETY set
GAINSHFT .set 10 ; sets max gain allowed (16 max)
; 0x7FFF is max outMult
; outTgt/0x7FFF << 16-GAIN_SHIFT is min input
.ds 0100h ; DARAM
DO_lp .word 0 ; input 1750 lowpass
D1_lp .word 0
D2_lp .word 0
D3_lp .word 0
D4_lp .word 0
dummy1 .word 0 ; gets zapped by MACD
spareCnt .word 0 ; # of spare clocks per cycle
minSpare .word 0 ; min # of spare clocks per cycle
outRight .word 01800h
outLeft .word 0E800h
adcData .word 0
inReg .word 0FFFFh
inMux .word 2200h
phase .word 0 ; for sin gen
dPhase .word 7 ; for sin gen 1 -> 47 Hz, 7 -> 328 Hz
amShift .word 0 ; for square AM modulation of sin gen
LTavgInh .word 0 ; DC term 32 bits
LTavgInl .word 0
LTavgIn .word 0 ; DC term 16 bits
peakIn .word 1
outTgt .word 20000
outMult .word 0
dOutMult .word 0
minInPk .word 0
inTgt .word 7FFFh
minCtr .word 0
newMinPk .word 0
pkSave .word 0
lastPk .word 0
noInptLP .word 0
deBounce .word 0
debugOut .word 0
****************************************************************
* Set up the ISR vector
****************************************************************
.if STOCK
.ps 080Ah
rint: B TIMERSTK ; 0x80A rcvr interrupt - stock
xint: B XMITINT ; 0x80C xmit interrupt - stock
.else
.ps 0808h
tint: B TIMER ; 0x808 timer interrupt - !stock
.endif
*
******************************************************************
* TMS32C05X INITIALIZATION
*
******************************************************************
.ps 0a00h
.entry
START: SETC INTM ; Disable interrupts
LDP #0 ; Set data page pointer
OPL #08B7h,PMST ;
B CONT1
NC4 .word 4096 ; numerator 1750 lowpass
NC3 .word 16384
NC2 .word 24576
NC1 .word 16384
NC0 .word 4096
DC4 .word -3402 ; denominator 1750 lowpass
DC3 .word 13311
DC2 .word -22616
DC1 .word 19704
SINTAB0 .word 402 ; sin table - stores 64 values over 90 deg
SINTAB1 .word 1206
SINTAB2 .word 2009
SINTAB3 .word 2811
SINTAB4 .word 3612
SINTAB5 .word 4410
SINTAB6 .word 5205
SINTAB7 .word 5998
SINTAB8 .word 6786
SINTAB9 .word 7571
SINTAB10 .word 8351
SINTAB11 .word 9126
SINTAB12 .word 9896
SINTAB13 .word 10659
SINTAB14 .word 11417
SINTAB15 .word 12167
SINTAB16 .word 12910
SINTAB17 .word 13645
SINTAB18 .word 14372
SINTAB19 .word 15090
SINTAB20 .word 15800
SINTAB21 .word 16499
SINTAB22 .word 17189
SINTAB23 .word 17869
SINTAB24 .word 18537
SINTAB25 .word 19195
SINTAB26 .word 19841
SINTAB27 .word 20475
SINTAB28 .word 21096
SINTAB29 .word 21705
SINTAB30 .word 22301
SINTAB31 .word 22884
SINTAB32 .word 23452
SINTAB33 .word 24007
SINTAB34 .word 24547
SINTAB35 .word 25072
SINTAB36 .word 25582
SINTAB37 .word 26077
SINTAB38 .word 26556
SINTAB39 .word 27019
SINTAB40 .word 27466
SINTAB41 .word 27896
SINTAB42 .word 28310
SINTAB43 .word 28706
SINTAB44 .word 29085
SINTAB45 .word 29447
SINTAB46 .word 29791
SINTAB47 .word 30117
SINTAB48 .word 30424
SINTAB49 .word 30714
SINTAB50 .word 30985
SINTAB51 .word 31237
SINTAB52 .word 31470
SINTAB53 .word 31685
SINTAB54 .word 31880
SINTAB55 .word 32057
SINTAB56 .word 32213
SINTAB57 .word 32351
SINTAB58 .word 32469
SINTAB59 .word 32567
SINTAB60 .word 32646
SINTAB61 .word 32705
SINTAB62 .word 32745
SINTAB63 .word 32765
***************** Timer Interrupt Service Routine ***************
.if STOCK
.else
TIMER:
SACL spareCnt,0
SUB minSpare
LACC spareCnt
XC 1,LT
SACL minSpare,0
LACC outLeft
SAMM 50h
LAMM 50h ; read switches - takes 2 reads to settle
LAMM 50h
SACL inReg
LACC outRight
SAMM 50h
LAMM DRR ; get last adc conversion
SACL adcData
LACC inMux ; select user's mux choice
* LACC inMux ; select user's mux choice
* LACC #0200h ; select A0 (8 bit value << 9 - loses msb)
* LACC #2200h ; select A1 (8 bit value << 9 - loses msb)
* LACC #4200h ; select A2 (8 bit value << 9 - loses msb)
* LACC #6200h ; select A3 (8 bit value << 9 - loses msb)
* LACC #8200h ; select A4 (8 bit value << 9 - loses msb)
SAMM DXR ; start next ADC conversion
LAR AR2,#1 ; flag to process ADC input
RETE
*
******************************************************************
* DESCRIPTION: This routine initializes the ADC
******************************************************************
*
ADCINIT:
SPLK #20h,TCR ; To generate 12 kHz for
SPLK #1667,PRD ; sample clock
MAR *,AR0
LACC #0038h ; Non continuous mode
SACL SPC ; FSX as input
LACC #00F8h ; 16 bit words
SACL SPC
OPL #0837h,PMST ; make address lines visible
LDP #1FFh ; set adc reset hi by writing to big adrs
RPT #10000 ; and taking it low after 10000 cycles
LACC dummy1 ; (.5ms at 50ns)
OPL #08B7h,PMST ; make address lines invisible
RET ;
.endif
******************* continue setup **********************************
CONT1:
SETC OVM ; overflow saturation set - no wrap
SETC SXM ; sign extension mode on
ZAP ; set up 7 I/O wait states for DAC's
SAMM PDWSR
LACC #0FFFFh
SAMM IOWSR
LACC #4
SAMM CWSR
LACC #2400h ; setup input circ buffer
SAMM CBSR1
SAMM AR1
SAMM ARCR
ADD #CBUFSIZE,0
SAMM CBER1
SPLK #9,CBCR ; circ #1, AR1 - circ2 off
.if BIGDEBUG
LACC #0D00h
.else
LACC #2100h ; setup test circ buffer
.endif
SAMM CBSR2
SAMM AR3
.if BIGDEBUG
ADD #16FFh,0
.else
ADD #CBUFSIZE,0
.endif
SAMM CBER2
SPLK #0B9h,CBCR ; circ #1, AR1 - circ2 on, AR3
SPLK #180h,AR4 ; peak array pointer
.if STOCK
LACC #22h
SAMM IMR ; need xmit int + rs232 intrpt
CALL ADCINSTK ; initialize ADC and enable interrupts
.else
LACC #2
SAMM IMR ; only rs232 intrpt
CALL ADCINIT ; initialize ADC and enable interrupts
.endif
LAR AR0,#0
CLRC OVM ; OVM = 0
SPM 0 ; PM = 0
LACC #0Ah ; timer & rs232 ints only
.if STOCK
LACC #12h ; rcvr & rs232 ints only
.endif
SAMM IMR
LDP #spareCnt ; Set data page pointer
MAR *,AR2
.if MOBILE
LACC #8h
SAMM IMR ; timer intrpt only - kill the kernal
CLRC XF
.endif
CLRC INTM ; enable intrpts
B WAIT
;------- end of setup ----------;
;
; PROCESS ADC INPUT ********************************************
;
PROCESS:
LACC adcData ; get ADC data
.if CWMIC
CALL sinGen
BSAR 4
SACL adcData
.endif
B NOLP
LACC noInptLP ; locks up at 4 kHz
BCNDD NOLP,NEQ
LACC adcData
SACL dummy1
LACC dummy1,10
MAR *,AR2
ZPR ; 1750 lowpass**************************
LAR AR2,#D4_lp
RPT #3 ; do denom
MAC DC4,*-
APAC ; final accum
SACH *,3 ; save D[0], denom coeff are mult by 8192
; so divide D[0] by 8192(=acc*8/2^16)
ADRK #4 ; now do the numerator
RPTZ 4 ; assembler bug, no # allowed
MACD NC4,*-
LTA *,AR1
BSAR 15 ; divide by 65536
BSAR 1
SACL adcData ; end low pass****************************
NOLP:
SUB LTavgIn ; subtract off DC
SACB
LACC #7FFFh
CRLT
LACC #8001h
CRGT
MAR *,AR1 ; store ADC to circ buf
SACL *+,0,AR0
.if DISPVAR ;***********************************************************
SACL dummy1 ; save off ADC
MAR *,AR3
LAMM AR3 ; odd or even?
AND #1
BCND EVEN,EQ
LACC dummy1
SACL pkSave
LACC outMult
B CONT3
EVEN: LACC debugOut
ABS
NEG
CONT3:
SACL *+,0,AR0
LACC dummy1
.endif ;************************************************************
ABS ; test for new peak
SACB
LACC peakIn
CRGT
SACL peakIn
BANZ DOOUTPUT,*-,AR1 ; skip counter > 0?
NORMSKP:;******************begin skip = 0******************************
LACC LTavgInh,16 ; compute DC
; compute 64 * long term avg (defined as LTav)
; = LTav+#-LTav/64
; approx by LTav+# - (LTav+#)/64
; get 32 bit long term average
OR LTavgInl
ADD adcData
SACB
BSAR 6
EXAR
SBB
SACH LTavgInh
SACL LTavgInl
BSAR 6
SACL LTavgIn
LAR AR0,#SKIP_CNT ; load skip counter
LACL inReg ; handle buttons
AND #0C000h,0
XOR #0C000h,0
SACB
LACC deBounce
SUB #1
XC 1,GT
SACL deBounce
BCND CONT2,GT
LACB
BCND CONT2,EQ ; is a switch down?
AND #4000h,0 ; which switch?
BCND SWITCH2,NEQ
LACC #500
SACL deBounce
LACC inMux
ADD #2000h,0
SACL inMux
SUB #6200h,0 ; max allowed
LACC #200h
XC 1,C
SACL inMux
LACC #10000
SACL peakIn
B CONT2
SWITCH2:
LACC #500
SACL deBounce
LACC noInptLP
XOR #1
SACL noInptLP
CONT2:
SKIPZN:;***********begin skip ctr = 0, peak<hiTgt**********************
; make slow tweak to inTgt
LACC minInPk ; take care of min peak stuff
ADD #1
SACL minInPk
SACB
LACC peakIn
CRLT
BCND NONEWMIN,NC
LACC newMinPk
CRGT
SACL newMinPk
LACC minCtr
SUB #1
SACL minCtr
BCND SKIPZN1,GT
LACC newMinPk
SACL minInPk
NONEWMIN:;***********************no new min**************************
ZAP
SACL newMinPk
LACL #MIN_PKS
SACL minCtr
SKIPZN1:
LACC peakIn
MAR *,AR4 ; store peak to peak array
SACL *+,0,AR2
LAMM AR4
AND #19Fh ; 180H + 31 (enforce circular buf)
SAMM AR4
LACC #180h ; get max of peak array
SAMM AR2
NOP
NOP
LACC *+
SACB ; got 1st point
LACC #30 ; loop 31 times
SAMM BRCR
RPTB ENDBLOCK -1
LACC *+
CRGT
NOP ; need a 3 instruction loop
ENDBLOCK:
SUB inTgt ; determine amount to modify inTgt
BSAR 5 ; change by 1/32 (32 mini blocks)
ADD inTgt
SACB ; take max of inTgt, minInPk << MIN_SHFT
.if BGLIMIT
LACC minInPk,MIN_SHFT
CRGT
.endif
LACC #07FFFh ; limit to max
CRLT
; min inTgt is 0x272(or outMult o'flo)
LACC #0x272
CRGT
SACL inTgt
ZAP ; zero out the peak
SACL peakIn
; calc new outMult
; acc_lo = (outTgt << GAIN_SHIFT)/inTgt
LACC outTgt,GAINSHFT
RPT #15
SUBC inTgt
SACL dummy1 ; clean off MS bits
LACC dummy1
SUB outMult ; calc delta outMult (dOutMult)
; = (newOutMult-outMult)/20
; = (newOutMult-outMult)/16 -
; (newOutMult-outMult)/64
BSAR 4
SACB
BSAR 2
EXAR
SBB
SACL dOutMult
* B DOOUTPUT
DOOUTPUT:;****************do output**************************************
MAR *,AR1
.if FIXDGAIN
LACC #750
SACL outMult
.else
LACC outMult ; update outMult
ADD dOutMult
SACL outMult
.endif
LACC *,0 ; get oldest value
LT * ; mult by outMult
MPY outMult
PAC
BSAR GAINSHFT
SACL debugOut
.if SAFETY
SACL dummy1
SACB
LACC #OUTLIMT,0 ; limit positive numbers to max
CRLT
BCND LOCKUP,C
LACC #OUTLIMTN,0
CRGT
BCND LOCKUP,C
.endif
UNLOCK:
.if CWRCVR
CALL sinGen
BSAR 1
.endif
SACL dummy1 ; save in a temp for right output
*************************** process left output ********************
.if STOCK
AND #0FFFCh ; mask off DAC lsb's or else lockup
SAMM DXR
.else
BSAR 4 ; max of +-2k for full width pulse
ADD #2048,0 ; unipolar dac
AND #0FFFh
OR #0E000h ; switch precharge & chip select
SACL outLeft
*************************** process right output ********************
LACC dummy1 ; get oldest value for output
BSAR 4 ; max of +-2k for full width pulse
ADD #2048,0 ; unipolar dac
AND #0FFFh
OR #01000h ; chip select
SACL outRight
.endif
ZAC ; zero acc - counts idle time
LAR AR2,#0 ; done processing flag
MAR *,AR2 ; can eliminate later?
WAIT:
.if MOBILE
IDLE
BANZ PROCESS ; AR2 is flag
B WAIT
.else
BANZD PROCESS ; AR2 is flag
ADD #2
ADD #2
BD WAIT
ADD #2
ADD #2
.endif
LOCKUP: B UNLOCK
*****************************************************************
* gen a sin wave, 90 deg stored in SINTAB - saves MAR
sinGen:
SST #0,BMAR ; save MAR (bits of ST0) in BMAR
LACL phase
ADD dPhase ; add delta phase
AND #255 ; max phase is 255
SACL phase
AND #127 ; confine to 180 degrees
SACB
SUB #64 ; if phase > 90 deg, C=1
LACB
XC 2,C ; if phase > 90 deg, phase = 127 - phase
NEG
ADD #127
ADD #SINTAB0,0 ; get the correct value from SINTAB
SAMM AR2
MAR *,AR2
NOP ; need 2 cycles after SAMM AR2 before LACL
LACL *
SACB ; if phase > 180 deg, value = - value
LACL phase
SUB #128
LACB
XC 1,C
NEG
.if SQMOD ; square wave AM modulate
SACB
LACL phase ; on phase = 0, increment amShift
BCND AMOK,NEQ
LACL amShift
ADD #1
SACL amShift
AMOK:
LACL amShift
AND #8
BCND FULLAMP,NEQ
EXAR
BSAR 1
EXAR
FULLAMP:
EXAR
.endif
LDP #0 ; restore MAR
LST #0,BMAR
RET
.if STOCK
******************************************************************
* DESCRIPTION: This routine initializes the TLC320C40 for *
* a 12 kHz sample rate with a gain setting of 1 *
******************************************************************
* aic initialization data
*
ADCINSTK: SPLK #20h,TCR ; To generate 10 MHz from Tout
SPLK #01h,PRD ; for AIC master clock
MAR *,AR0
LACC #0008h ; Non continuous mode
SACL SPC ; FSX as input
LACC #00c8h ; 16 bit words
SACL SPC
OPL #0837h,PMST ; make address lines visible
LACC #080h ; Pulse AIC reset by setting it low
SACH DXR
SACL GREG
LAR AR0,#0FFFFh
RPT #10000 ; and taking it high after 10000 cycles
LACC *,0,AR0 ; (.5ms at 50ns)
SACH GREG
;------------------------ dig filter clock = 10 MHz/(2*TA)
SETC SXM ; = 416.7 kHz
LACC #12,9 ; TA
ADD #24,2 ; RA - unused
CALL AIC_2ND ;
;------------------------ ADC rate = dig filter clock / TB
; = 11905 kHz
LACC #35,9 ; TB
ADD #18,2 ; RB - unused
ADD #02h ;
CALL AIC_2ND ;
;------------------------
LACC #28h,2 ; AIC control, max gain(4), synchronous
ADD #03h ;
CALL AIC_2ND ;
OPL #08B7h,PMST ; make address lines invisible
RET ;
AIC_2ND:
LDP #0
SACH DXR ;
CLRC INTM
IDLE
ADD #6h,15 ; 0000 0000 0000 0011 XXXX XXXX XXXX XXXX
b
SACH DXR ;
IDLE
SACL DXR ;
IDLE
LACL #0 ;
SACL DXR ; make sure the word got sent
IDLE
SETC INTM
RET ;
XMITINT:
RETE
TIMERSTK:
SACL spareCnt,0
SUB minSpare
LACC spareCnt
XC 1,LT
SACL minSpare,0
LAMM DRR
SACL adcData
LAR AR2,#1 ; flag to process ADC input
ENDO:;******************end of program*****************************
RETE
.endif
.end