welcome: please sign in
location: attachment:fullwave_delay_lowpass.asm of FullwaveDelayLowpass

Attachment 'fullwave_delay_lowpass.asm'

Download

   1 ; program: fullwave-delay-lowpass.asm
   2 ; UID = 000055 - unique id to eliminate conflicts between variables
   3 ; mono data (left in only, delayed output on left, direct out on right)
   4 ; pot (MOD1) controls the delay time (0s - 1.5s)
   5 ; rotary encoder (MOD2) controls the cutoff frequency
   6 
   7 ; program overview
   8 ;
   9 ; data is read in from the codec, and negative values are inverted to
  10 ; positive values.  all values are then shifted down to mid-rail and
  11 ; multiplied by 2 to normalize the output.  these values are then written
  12 ; to memory, and read back out and accumulated.  this creates a simple
  13 ; moving average low pass filter.  the delay time (and corresponding cutoff
  14 ; frequency) is set with the rotary encoder (MOD2).  there are 7 different
  15 ; cutoff frequencies, with rotations to the right increasing the cutoff
  16 ; frequnecy.  changing the cutoff frequency restarts the program to blank
  17 ; the accumulation buffer.  the delay time is set with the pot (MOD1).  the
  18 ; adc is oversampled 256 times and deadbanded to reduce jitter.  turning the
  19 ; pot all the way to the right overlaps the delay and lowpass buffers,
  20 ; causing some distortions.
  21 
  22 ; register usage - may be redefined in other sections
  23 ;
  24 ; r0  adc accumulation fractional byte
  25 ; r1  adc accumulation lsb
  26 ; r2  adc accumulation msb
  27 ; r3  
  28 ; r4  left lsb out
  29 ; r5  left msb out
  30 ; r6  left lsb in
  31 ; r7  left msb in
  32 ; r8  right output lsb
  33 ; r9  right output msb
  34 ; r10 accumulation lsb
  35 ; r11 accumulation mlb
  36 ; r12 accumulation mhb
  37 ; r13 accumulation msb
  38 ; r14 rotary encoder counter
  39 ; r15 adc/switch sample counter
  40 ; r16 temporary swap register
  41 ; r17 temporary swap register
  42 ; r18 null register 
  43 ; r19 cutoff frequency
  44 ; r20 temporary register
  45 ; r21 
  46 ; r22 actual delay lsb
  47 ; r23 actual delay msb
  48 ; r24 write address lsb
  49 ; r25 write address msb
  50 ; r26 desired delay lsb
  51 ; r27 desired delay msb
  52 ; r28 read address lsb
  53 ; r29 read address msb
  54 ; r30 jump location for interrupt lsb
  55 ; r31 jump location for interrupt msb
  56 ; t   rotary encoder state bit
  57 
  58 ;program starts here first time and after buffer changes
  59 ldi r30,$1c ; set jump location to program start
  60 ldi r16,$08 ; set lowpass buffer size to mid range
  61 ldi r19,$03 ; initialize cutoff frequency to midrange
  62 
  63 restart_000055: ; restart location for clearing memory
  64 
  65 clr r24 ; clear write register
  66 clr r25
  67 clr r18 ; setup r18 as null register for carry addition and ddr setting
  68 ldi r17,$ff ; setup r17 for ddr setting
  69 
  70 clear_000055: ; clear lowpass buffer
  71 ; required to ensure an accurate accumulation
  72 out portd,r24 ; set address
  73 sts porth,r25
  74 out portg,r18 ; pull ce low,we low,and set high bits of address
  75 out ddra,r17 ; set porta as output for data write
  76 out ddrc,r17 ; set portc as output for data write
  77 out porta,r18 ; set data
  78 out portc,r18 ; r18 is cleared above
  79 sbi portg,portg2 ; pull we high to write
  80 out ddra,r18 ; set porta as input for data lines
  81 out ddrc,r18 ; set portc as input for data lines
  82 inc r24 ; increment write register - only clears first 256 bytes
  83 brne clear_000055 ; continue until end of buffer reached
  84 
  85 cleardone_000055: ; reset registers
  86 
  87 mov r24,r16 ; set buffer size for lowpass
  88 clr r28 ; set read address
  89 clr r29
  90 clr r10 ; initialize accumulation registers
  91 clr r11
  92 clr r12
  93 clr r13
  94 reti ; finish with initialization and wait for next interrupt
  95 
  96 ; program starts here every time but first
  97 ; initiate data transfer to codec
  98 sbi portb,portb0 ; toggle slave select pin
  99 out spdr,r5 ; send out left channel msb
 100 cbi portb,portb0
 101 
 102 ;increment sram addreses
 103 adiw r25:r24,$01 ; increment write address
 104 adiw r29:r28,$01 ; increment read address
 105 
 106 wait1_000055: ; check if byte has been sent
 107 
 108 in r17,spsr
 109 sbrs r17,spif
 110 rjmp wait1_000055
 111 in r7,spdr ; recieve in left channel msb
 112 out spdr,r4 ; send out left channel lsb
 113 
 114 wait2_000055: ; check if byte has been sent
 115 
 116 in r17,spsr
 117 sbrs r17,spif
 118 rjmp wait2_000055
 119 in r6,spdr ; recieve in left channel lsb
 120 out spdr,r9 ; send out right channel msb
 121 
 122 ;fullwave rectify left data
 123 sbrs r7,$07 ; check if negative
 124 rjmp normalize_000055
 125 com r6 ; invert data if negative (using ones complement to avoid problem at $8000)
 126 com r7
 127 
 128 normalize_000055: ; normalize data since its all positive values now
 129 
 130 lsl r6 ; multiply data by two
 131 rol r7 ; data is unsigned integer at this point
 132 ldi r16,$80 ; convert to signed integer
 133 add r7,r16
 134 
 135 wait3_000055: ; check if byte has been sent
 136 
 137 in r17,spsr
 138 sbrs r17,spif
 139 rjmp wait3_000055
 140 in r17,spdr ; recieve in right channel msb
 141 out spdr,r8 ; send out right channel lsb
 142 
 143 ;write rectified left channel data to sram
 144 out portd,r24 ; set address
 145 sts porth,r25
 146 out portg,r18 ; pull ce low,we low,and set high bits of address
 147 ldi r17,$ff
 148 out ddra,r17 ; set porta as output for data write
 149 out ddrc,r17 ; set portc as output for data write
 150 out porta,r6 ; set data
 151 out portc,r7
 152 sbi portg,portg2 ; pull we high to write
 153 out ddra,r18 ; set porta as input for data lines
 154 out ddrc,r18 ; set portc as input for data lines
 155 
 156 wait4_000055: ; check if byte has been sent
 157 
 158 in r17,spsr
 159 sbrs r17,spif
 160 rjmp wait4_000055
 161 in r17,spdr ; recieve in left channel lsb
 162 
 163 ;get left channel data from sram
 164 out portd,r28 ; set address
 165 sts porth,r29
 166 nop ; wait input latch time of 2 clock cycles
 167 nop
 168 in r4,pina ; get data
 169 in r5,pinc ; get data
 170 
 171 ;accumulate samples for lowpass
 172 add r10,r6 ; add in current sample
 173 adc r11,r7
 174 sbrc r7,$07 ; check if data is negative
 175 ldi r18,$ff ; set high bits if it is
 176 adc r12,r18 ; r18 is cleared above
 177 adc r13,r18
 178 clr r18 ; reset null register
 179 sub r10,r4 ; remove last sample in buffer
 180 sbc r11,r5
 181 sbrc r5,$07 ; check if data is negative
 182 ldi r18,$ff ; set high bits if it is
 183 sbc r12,r18 ; r18 is cleared above
 184 sbc r13,r18
 185 clr r18 ; reset null register
 186 
 187 mov r4,r10 ; divide by 256 and move to ouptput register
 188 mov r5,r11
 189 mov r17,r12
 190 tst r19 ; check if no dividing necessary
 191 breq store_000055 ; keep dividing till the right size
 192 mov r16,r19 ; move cutoff to temporary register
 193 
 194 divide_000055: ; divide accumulation for proper scaling
 195 
 196 asr r17 ; divide accumulation
 197 ror r5
 198 ror r4
 199 dec r16 ; check if done
 200 brne divide_000055 ; keep dividing till the right size
 201 
 202 store_000055: ; store lowpassed data to memory
 203 
 204 movw r9:r8,r5:r4 ; move immediate data to right output
 205 movw r17:r16,r25:r24 ; move write address to temporary register
 206 subi r17,$01 ; move to delay buffer location
 207 out portd,r16 ; set address
 208 sts porth,r17
 209 out portg,r18 ; pull ce low,we low,and set high bits of address
 210 ldi r20,$ff
 211 out ddra,r20 ; set porta as output for data write
 212 out ddrc,r20 ; set portc as output for data write
 213 out porta,r4 ; set data
 214 out portc,r5
 215 sbi portg,portg2 ; pull we high to write
 216 out ddra,r18 ; set porta as input for data lines
 217 out ddrc,r18 ; set portc as input for data lines
 218 
 219 ;fetch delayed data from memory
 220 sub r16,r22 ; subtract delay time
 221 sbc r17,r23
 222 out portd,r16 ; set address
 223 sts porth,r17
 224 nop ; wait input latch time of 2 clock cycles
 225 nop
 226 in r4,pina ; get data
 227 in r5,pinc ; put delayed data to left output
 228 
 229 rotary_000055: ; check rotary encoder and adjust cutoff frequency
 230 ; although rotary encoder is externally debounced, it is done here again.
 231 ; pin1 is sampled on a transition from high to low on pin0.  if pin1 is
 232 ; high, a left turn occured, if pin1 is low, a right turn occured.
 233 dec r14 ; check if time to sample rotary encoder
 234 brne shift_000055 ; continue if not
 235 ldi r17,$40 ; adjust sample frequency to catch all rising edges (1.5ms)
 236 mov r14,r17
 237 lds r17,pinj ; get switch data
 238 sbrs r17,$00 ; check if pin0 is low
 239 rjmp edge_000055 ; check if pin0 was low on previous sample
 240 clt ;  clear state register if back high
 241 rjmp shift_000055 ; finish off
 242 
 243 edge_000055: ; check for falling edge
 244 
 245 brts shift_000055 ; do nothing if edge was already detected
 246 set ; set t register to indicate edge detected
 247 sbrs r17,$01 ; check if pin1 is high
 248 rjmp increment_000055 ; increase cutoff frequency if right rotation
 249 cpi r19,$06 ; else check if at max value
 250 brsh shift_000055 ; finish off if at max
 251 inc r19 ; incrementing cutoff value decreases cutoff frequency
 252 rjmp buffer_000055 ; reset accumulation buffer
 253 
 254 increment_000055: ; increase cutoff frequency
 255 
 256 cpi r19,$01 ; check if cutoff at min value
 257 brlo shift_000055 ; finish off if at min
 258 dec r19 ; decrementing cutoff value increases cutoff frequency
 259 
 260 buffer_000055: ; adjust buffer size
 261 
 262 movw r29:r28,r25:r24 ; move write address to read address
 263 ldi r16,$01 ; initialize the offset register
 264 tst r19 ; check if any shifting is required
 265 breq bufferload_000055
 266 mov r17,r19 ; move cutoff to temporary register
 267 
 268 shift1_000055: ; shift in zeros to make correct buffer size
 269 
 270 lsl r16 ; increment buffer size
 271 dec r17
 272 brne shift1_000055 ; keep shifting until done
 273 
 274 bufferload_000055: ; load buffer size
 275 
 276 rjmp restart_000055 ; clear accumulation buffer
 277 
 278 shift_000055: ; check if delay time is correct
 279 
 280 cp r26,r22 ; compare desired delay to actual delay
 281 cpc r27,r23
 282 breq adcsample_000055 ; do nothing if the same
 283 brlo indexdown_000055
 284 ldi r17,$02 ; increment delay register
 285 add r22,r17
 286 adc r23,r18 ; r18 is cleared above
 287 rjmp adcsample_000055
 288 
 289 indexdown_000055:
 290 
 291 ldi r17,$01 ; decrement delay register
 292 sub r22,r17
 293 sbc r23,r18 ; r18 is cleared above
 294 
 295 adcsample_000055: ; get delay settings
 296 
 297 lds r17,adcsra ; get adc control register
 298 sbrs r17,adif ; check if adc conversion is complete
 299 rjmp done_000055 ; skip adc sampling
 300 lds r16,adcl ; get low byte adc value
 301 lds r17,adch ; get high byte adc value
 302 add r0,r16 ; accumulate adc samples
 303 adc r1,r17
 304 adc r2,r18 ; r18 is cleared above
 305 ldi r17,$f7
 306 sts adcsra,r17 ; clear interrupt flag
 307 dec r15 ; countdown adc sample clock
 308 brne done_000055 ; get delay time if its been long enough
 309 lsr r2 ; divide adc sample by 4 to make 16b value
 310 ror r1
 311 ror r0
 312 lsr r2
 313 ror r1
 314 ror r0
 315 
 316 deadband_000055: ; check if adc has changed enough to warrant update
 317 
 318 movw r17:r16,r1:r0 ; move adc sample to temporary register
 319 sub r16,r26 ; find difference between adc sample and desired delay time
 320 sbc r17,r27
 321 brsh check_000055 ; check for deadband if positive
 322 neg r16 ; invert if negative
 323 adc r17,r18 ; r18 is cleared above
 324 neg r17
 325 
 326 check_000055: ; check if difference is greater than deadband
 327 
 328 cpi r16,$40 ; check if difference is less than 1 lsb
 329 cpc r17,r18 ; r18 cleared above
 330 brlo empty_000055 ; do nothing if less than 1 lsb
 331 movw r27:r26,r1:r0 ; move adc sample to delay time if large enough change
 332 andi r26,$fe ; make sure delay time is a multiple of 2
 333 
 334 empty_000055: ; empty accumulation registers and finish off
 335 
 336 clr r0 ; empty adc accumulation registers
 337 clr r1
 338 clr r2
 339 
 340 switchsample_000055: ; check rotary switch
 341 
 342 lds r16,pinj ; get switch data
 343 andi r16,$78 ; mask off rotary switch
 344 lsr r16 ; adjust switch position to program memory location
 345 lsr r16
 346 ldi r17,$02
 347 add r16,r17
 348 cp r16,r31 ; check if location has changed
 349 breq done_000055 ; finish off if no change
 350 clr r30 ; reset jump register to new location
 351 mov r31,r16
 352 
 353 done_000055: ; normalize data and move to read buffer
 354 
 355 reti ; return to waiting
 356 

Attached Files

To refer to attachments on a page, use attachment:filename, as shown below in the list of files. Do NOT use the URL of the [get] link, since this is subject to change and can break easily.

You are not allowed to attach a file to this page.