More code. This is the A/D routine and the 16 bit median filter. Together with the timer 2 interrupt these make up the high speed part of the detector code. The timer 2 interrupt occurs 26,400 times per second. It calls the A/D routine 8800 times per second, and it in turn calls the median filter 4400 times per second. The timer 2 interrupt also calls count2200 2200 times per second, but the only thing it does at that rate is update a counter. Count2200 does other things at 60 or 30 times per second.
Robert Hoolko
AD: ; Read A/D converter, filter, and accumulate data.
; Enter with address of data struct in Z
; Flag T determines whether this sample is added to or
; subtracted from the accumulator
; r16 r17 r18 are free
sbi portd,4 ; debug, scope strobe
in r16,ADCL ; get previous A/D results
in r17,ADCH
sbi ADCSR,4 ;Clear ADC INT SAFE
sbi ADCSR,4 ;Clear ADC INT
sbi ADCSR,6 ; start next conversion
andi r17,00000011b ; mask off unused bits
brtc ADaccum ; add or sub?
st Z+,r16 ; save this sample for next time
st Z,r17
rjmp ADexit
ADaccum:
ld r18,Z+ ; sub saved sample from this one
sub r16,r18
ld r18,Z+
sbc r17,r18
lds r18,debug ; debug flags
sbrc r18,0 ; debug, skip if no flag
rcall putcirc ; debug,
lds r18,fflag ; filter flag
sbrc r18,1 ; skip if flag clear
adiw ZL,4 ; mfilt does this
sbrs r18,1 ; skip if flag set
rcall mfilt16 ; median filter
ld r18,Z ; accumulate data as 24 bits
add r18,r16 ; low byte
st Z+,r18
ld r18,Z
adc r18,r17 ; middle byte
st Z+,r18
clr r16 ; extend sign
sbrc r17,7 ; test sign
ser r16
ld r18,Z
adc r18,r16 ; high byte
st Z+,r18 ;
ADexit:
cbi portd,4 ; debug, scope strobe
ret
;************************************************* **********************
;*
;* "mfilt16"
;* 3 point median filter for 16 bit signed data
;*
;* Number of words :
;* Number of cycles : 72 + 12 in modified version
;* Low registers used :0
;* High registers used :7 (r16-r22)
;* Pointers used :Y,Z
;*
;************************************************* **********************
;***** Subroutine Register Variables
#define al r16
#define ah r17
#define bl r18
#define bh r19
#define cl r20
#define ch r21
#define temp r22
#define mflag r28
mfilt16:
;***** Enter with new data in A (r16,r17)
; and address of filter data in Z
; Exit with filtered data in r16,r17
; and Z incremented by 4
; Instructions marked with * are a modification
; that allows 1 bit of noise through
push YH
push YL
push r22
push r21
push r20
push r19
push r18
clr mflag ; clear flags
clr YH
ld bl,Z ; get filter data b
ldd bh,Z+1
ldd cl,Z+2 ; get filter data c
ldd ch,Z+3
cp bl,al ; compare a and b
cpc bh,ah
brge bgea ;
ori mflag,4 ; set if b is less than a
bgea:
cp al,cl
cpc ah,ch ; compare c and a
brge agec ;
ori mflag,2 ; set if a is less than c
agec:
cp cl,bl
cpc ch,bh ; compare b and c
brge cgeb ;
ori mflag,1 ; set if c is less than b
cgeb:
ldi temp,7 ;
sbrc mflag,2 ; test msb of flag bits
eor mflag,temp ; fold around 3
breq alleq ; if 0, all were equal
dec mflag ; else reduce 1,2,3 to 0,1,2
alleq: add mflag,mflag ; compute offset to median, mflag is YL
ori mflag,16 ; address of r16
; We do not need c any more
; Shift a and b to b and c
; We will need these the next time the filter is called
st Z+,al ; store filter data b
st Z+,ah
st Z+,bl ; store filter data c
st Z+,bh ;
ld temp,Y ;*was there any noise?
cp temp,al ;*
ldd temp,Y+1 ;*
cpc temp,ah ;*
ld r16,Y+ ; get median
ld r17,Y
breq nonoise ;*no noise
brlt posnoise ;*
subi r16,1 ;*if neg noise, subtract 1 from median
sbci r17,0 ;*
rjmp nonoise ;*
posnoise: ;*
subi r16,-1 ;*if pos noise, add 1 to median
sbci r17,-1 ;*
nonoise: ;*
pop r18
pop r19
pop r20
pop r21
pop r22
pop YL
pop YH
ret
;************************************************* **************************
; Data
#dseg
;struct
Itemp: ds 2
Imfilt: ds 4 ;must follow Itemp
Iaccum: ds 3 ;must follow Imfilt
;struct
Qtemp: ds 2
Qmfilt: ds 4 ;must follow Qtemp
Qaccum: ds 3 ;must follow Qmfilt
#define IQhold 6
#define IQair 9
#define IQchan 12
;struct
Idcmfilt: ds 6
Ihold: ds 3
Iair: ds 3
Ichan: ds 1
;struct
Qdcmfilt: ds 6
Qhold: ds 3
Qair: ds 3
Qchan: ds 1
; struct
; The following data must be in pairs I,Q or cos,sin or x,y
Idc: ds 3
Qdc: ds 3
calcos: ds 2
calsin: ds 2
#define NDELAY 11
Xcal: ds 3 ;12 most recient samples
Ycal: ds 3 ;12 most recient samples
ds 6*NDELAY; x,y delay line
XF: ds 3 ; filterd
YF: ds 3
Xcap: ds 3 ; captured
Ycap: ds 3
; end of pairs
c2200: ds 1
c60: ds 1
csec: ds 1
flag60: ds 1
fflag: ds 1
debug: ds 1
pw2: ds 1
gndcos: ds 2
gndsin: ds 2
fthreshuf: ds 1
fthresh: ds 3
fthreshtc: ds 1
coilon: ds 1
coiloff: ds 1
drvangle: ds 1
Robert Hoolko
AD: ; Read A/D converter, filter, and accumulate data.
; Enter with address of data struct in Z
; Flag T determines whether this sample is added to or
; subtracted from the accumulator
; r16 r17 r18 are free
sbi portd,4 ; debug, scope strobe
in r16,ADCL ; get previous A/D results
in r17,ADCH
sbi ADCSR,4 ;Clear ADC INT SAFE
sbi ADCSR,4 ;Clear ADC INT
sbi ADCSR,6 ; start next conversion
andi r17,00000011b ; mask off unused bits
brtc ADaccum ; add or sub?
st Z+,r16 ; save this sample for next time
st Z,r17
rjmp ADexit
ADaccum:
ld r18,Z+ ; sub saved sample from this one
sub r16,r18
ld r18,Z+
sbc r17,r18
lds r18,debug ; debug flags
sbrc r18,0 ; debug, skip if no flag
rcall putcirc ; debug,
lds r18,fflag ; filter flag
sbrc r18,1 ; skip if flag clear
adiw ZL,4 ; mfilt does this
sbrs r18,1 ; skip if flag set
rcall mfilt16 ; median filter
ld r18,Z ; accumulate data as 24 bits
add r18,r16 ; low byte
st Z+,r18
ld r18,Z
adc r18,r17 ; middle byte
st Z+,r18
clr r16 ; extend sign
sbrc r17,7 ; test sign
ser r16
ld r18,Z
adc r18,r16 ; high byte
st Z+,r18 ;
ADexit:
cbi portd,4 ; debug, scope strobe
ret
;************************************************* **********************
;*
;* "mfilt16"
;* 3 point median filter for 16 bit signed data
;*
;* Number of words :
;* Number of cycles : 72 + 12 in modified version
;* Low registers used :0
;* High registers used :7 (r16-r22)
;* Pointers used :Y,Z
;*
;************************************************* **********************
;***** Subroutine Register Variables
#define al r16
#define ah r17
#define bl r18
#define bh r19
#define cl r20
#define ch r21
#define temp r22
#define mflag r28
mfilt16:
;***** Enter with new data in A (r16,r17)
; and address of filter data in Z
; Exit with filtered data in r16,r17
; and Z incremented by 4
; Instructions marked with * are a modification
; that allows 1 bit of noise through
push YH
push YL
push r22
push r21
push r20
push r19
push r18
clr mflag ; clear flags
clr YH
ld bl,Z ; get filter data b
ldd bh,Z+1
ldd cl,Z+2 ; get filter data c
ldd ch,Z+3
cp bl,al ; compare a and b
cpc bh,ah
brge bgea ;
ori mflag,4 ; set if b is less than a
bgea:
cp al,cl
cpc ah,ch ; compare c and a
brge agec ;
ori mflag,2 ; set if a is less than c
agec:
cp cl,bl
cpc ch,bh ; compare b and c
brge cgeb ;
ori mflag,1 ; set if c is less than b
cgeb:
ldi temp,7 ;
sbrc mflag,2 ; test msb of flag bits
eor mflag,temp ; fold around 3
breq alleq ; if 0, all were equal
dec mflag ; else reduce 1,2,3 to 0,1,2
alleq: add mflag,mflag ; compute offset to median, mflag is YL
ori mflag,16 ; address of r16
; We do not need c any more
; Shift a and b to b and c
; We will need these the next time the filter is called
st Z+,al ; store filter data b
st Z+,ah
st Z+,bl ; store filter data c
st Z+,bh ;
ld temp,Y ;*was there any noise?
cp temp,al ;*
ldd temp,Y+1 ;*
cpc temp,ah ;*
ld r16,Y+ ; get median
ld r17,Y
breq nonoise ;*no noise
brlt posnoise ;*
subi r16,1 ;*if neg noise, subtract 1 from median
sbci r17,0 ;*
rjmp nonoise ;*
posnoise: ;*
subi r16,-1 ;*if pos noise, add 1 to median
sbci r17,-1 ;*
nonoise: ;*
pop r18
pop r19
pop r20
pop r21
pop r22
pop YL
pop YH
ret
;************************************************* **************************
; Data
#dseg
;struct
Itemp: ds 2
Imfilt: ds 4 ;must follow Itemp
Iaccum: ds 3 ;must follow Imfilt
;struct
Qtemp: ds 2
Qmfilt: ds 4 ;must follow Qtemp
Qaccum: ds 3 ;must follow Qmfilt
#define IQhold 6
#define IQair 9
#define IQchan 12
;struct
Idcmfilt: ds 6
Ihold: ds 3
Iair: ds 3
Ichan: ds 1
;struct
Qdcmfilt: ds 6
Qhold: ds 3
Qair: ds 3
Qchan: ds 1
; struct
; The following data must be in pairs I,Q or cos,sin or x,y
Idc: ds 3
Qdc: ds 3
calcos: ds 2
calsin: ds 2
#define NDELAY 11
Xcal: ds 3 ;12 most recient samples
Ycal: ds 3 ;12 most recient samples
ds 6*NDELAY; x,y delay line
XF: ds 3 ; filterd
YF: ds 3
Xcap: ds 3 ; captured
Ycap: ds 3
; end of pairs
c2200: ds 1
c60: ds 1
csec: ds 1
flag60: ds 1
fflag: ds 1
debug: ds 1
pw2: ds 1
gndcos: ds 2
gndsin: ds 2
fthreshuf: ds 1
fthresh: ds 3
fthreshtc: ds 1
coilon: ds 1
coiloff: ds 1
drvangle: ds 1