UpDownSweep

MICrODEC: Stock Functions

Up-Down Sweep

This function implements an up-down sweep. This means it plays forward at double speed until it hits the top of the buffer, and then plays in reverse until it hits the bottom. It takes in stereo data, and outputs stereo data. The pot (MOD1) varies the buffer size, within which the function reads back and forth.

Since the function just bounces back and forth inside the buffer, there is no buffer boundary problems, although the change in direction at the buffer ends can add a slight high frequency element. The buffer size is settable between and 3ms and 1.5s.

updown_sweep.asm


   1 ; program: up_downsweep-18b-pot.asm
   2 ; UID = 000035 - unique id to eliminate conflicts between variables
   3 ; 18b address space (3s sample time)
   4 ; stereo data
   5 ; pot (MOD1) controlled buffer size (3ms - 1.5s)
   6 
   7 ; program overview
   8 ;
   9 ; data is read in from memory and written out to the codec at the same time
  10 ; new data is written to the memory from the codec.  the write address
  11 ; increments until it reaches the top of the buffer and then starts at
  12 ; zero.  the read address increases at twice the rate until it reaches the
  13 ; write address, and then decreases until it reaches the write address.
  14 ; it continues this back and forth sample playback.  ADC0 (MOD1) is read
  15 ; and averaged over 256 samples to reduce jitter.  this value is subtracted
  16 ; from the write address to create the desired read address.  if the actual
  17 ; read address doesnt match the desired read address, it is either
  18 ; incremented or decremented by one sample each sample period until it
  19 ; matches.  this reduces noise during delay time transitions.
  20 
  21 ; register usage - may be redefined in other sections
  22 ;
  23 ; r0  desired buffer size fractional byte
  24 ; r1  
  25 ; r2  left lsb out
  26 ; r3  left msb out
  27 ; r4  right lsb out
  28 ; r5  right msb out
  29 ; r6  left lsb in
  30 ; r7  left msb in
  31 ; r8  right lsb in
  32 ; r9  right msb in
  33 ; r10 adc accumulation lsb
  34 ; r11 adc accumulation msb
  35 ; r12 read address offset lsb
  36 ; r13 read address offset msb
  37 ; r14 adc/switch sample counter
  38 ; r15 
  39 ; r16 temporary swap register
  40 ; r17 temporary swap register
  41 ; r18 null register
  42 ; r19 adc accumulation fractional byte
  43 ; r20 temporary swap regiser
  44 ; r21 read address offset high byte
  45 ; r22 write address high byte
  46 ; r23 read address high byte
  47 ; r24 write address lsb
  48 ; r25 write address msb
  49 ; r26 desired buffer size lsb
  50 ; r27 desired buffer size msb
  51 ; r28 read address lsb
  52 ; r29 read address msb
  53 ; r30 jump location for interrupt lsb
  54 ; r31 jump location for interrupt msb
  55 ; t   forward/reverse indicator
  56 
  57 ; program starts here first time
  58 ; initialze z pointer for correct jump
  59 ; this assumes a less than 256 word jump
  60 ldi r30,$29 ; set jump location to program start
  61 clr r24 ; clear write register
  62 clr r25
  63 ldi r22,$00 ; setup write address high byte
  64 clr r18 ; setup r18 as null register for carry addition and ddr setting
  65 ldi r17,$ff ; setup r17 for ddr setting
  66 
  67 clear_000035: ; clear delay buffer
  68 ; eliminates static when first switching to the delay setting
  69 
  70 adiw r25:r24,$01 ; increment write register
  71 adc r22,r18 ; increment write third byte
  72 cpi r22,$04 ; check if full memory space has been cleared
  73 breq cleardone_000035 ; continue until end of buffer reached
  74 out portd,r24 ; set address
  75 sts porth,r25
  76 out portg,r22 ; pull ce low,we low,and set high bits of address
  77 out ddra,r17 ; set porta as output for data write
  78 out ddrc,r17 ; set portc as output for data write
  79 out porta,r18 ; set data
  80 out portc,r18 ; r18 is cleared above
  81 sbi portg,portg2 ; pull we high to write
  82 out ddra,r18 ; set porta as input for data lines
  83 out ddrc,r18 ; set portc as input for data lines
  84 rjmp clear_000035 ; continue clearing
  85 
  86 cleardone_000035: ; reset registers
  87 
  88 ldi r24,$00 ; initialize write register
  89 ldi r25,$00
  90 ldi r22,$00 ; setup write address high byte
  91 ldi r28,$00 ; set read address to minimum delay
  92 ldi r29,$fe
  93 ldi r23,$07 ; setup read address high byte
  94 clr r0 ; set buffer size to minimum
  95 ldi r26,$01
  96 clr r27
  97 clr r12 ; set read address offset to minimum buffer size
  98 ldi r16,$01
  99 mov r13,r16
 100 clr r21
 101 clr r2 ; initialize data output registers
 102 clr r3
 103 clr r4
 104 clr r5
 105 clt ; clear t register to start with forward play
 106 reti ; finish with initialization and wait for next interrupt
 107 
 108 ; program starts here all but first time
 109 ; this is the point the z-pointer is incremented to
 110 ; initiate data transfer to codec
 111 sbi portb,portb0 ; toggle slave select pin
 112 out spdr,r3 ; send out left channel msb
 113 cbi portb,portb0
 114 
 115 wait1_000035: ; check if byte has been sent
 116 
 117 in r17,spsr
 118 sbrs r17,spif
 119 rjmp wait1_000035
 120 in r7,spdr ; recieve in left channel msb
 121 out spdr,r2 ; send out left channel lsb
 122 
 123 ;get left channel data from sram
 124 out portg,r23 ; pull ce low, we high, and set high bits of register
 125 out portd,r28 ; set address
 126 sts porth,r29
 127 adiw r29:r28,$01 ; increment read address
 128 adc r23,r18 ; placed here for efficient use of setup time
 129 andi r23,$03 ; mask off unsed bits
 130 ori r23,$04 ; set we/ bit in high byte register
 131 in r2,pina ; get data
 132 in r3,pinc ; get data
 133 
 134 wait2_000035: ; check if byte has been sent
 135 
 136 in r17,spsr
 137 sbrs r17,spif
 138 rjmp wait2_000035
 139 in r6,spdr ; recieve in left channel lsb
 140 out spdr,r5 ; send out right channel msb
 141 
 142 ;write left channel data to sram
 143 out portd,r24 ; set address
 144 sts porth,r25
 145 out portg,r22 ; pull ce low,we low,and set high bits of address
 146 ldi r17,$ff
 147 out ddra,r17 ; set porta as output for data write
 148 out ddrc,r17 ; set portc as output for data write
 149 out porta,r6 ; set data
 150 out portc,r7
 151 sbi portg,portg2 ; pull we high to write
 152 out ddra,r18 ; set porta as input for data lines
 153 out ddrc,r18 ; set portc as input for data lines
 154 
 155 wait3_000035: ; check if byte has been sent
 156 
 157 in r17,spsr
 158 sbrs r17,spif
 159 rjmp wait3_000035
 160 in r9,spdr ; recieve in right channel msb
 161 out spdr,r4 ; send out right channel lsb
 162 
 163 ;get right channel data from sram
 164 out portg,r23 ; pull ce low, we high, and set high bits of register
 165 out portd,r28 ; set address
 166 sts porth,r29
 167 adiw r25:r24,$01 ; increment write address
 168 adc r22,r18 ; placed here to use setup time efficiently
 169 andi r22,$03 ; mask off unsed bits
 170 in r4,pina ; get data
 171 in r5,pinc ; get data
 172 
 173 wait4_000035: ; check if byte has been sent
 174 
 175 in r17,spsr
 176 sbrs r17,spif
 177 rjmp wait4_000035
 178 in r8,spdr ; recieve in left channel lsb
 179 
 180 ;write right channel data to sram
 181 out portd,r24 ; set address
 182 sts porth,r25
 183 out portg,r22 ; pull ce low,we low,and set high bits of address
 184 ldi r17,$ff
 185 out ddra,r17 ; set porta as output for data write
 186 out ddrc,r17 ; set portc as output for data write
 187 out porta,r8 ; set data
 188 out portc,r9
 189 sbi portg,portg2 ; pull we high to write
 190 out ddra,r18 ; set porta as input for data lines
 191 out ddrc,r18 ; set portc as input for data lines
 192 
 193 ;increment write address to next sample position
 194 adiw r25:r24,$01 ; increment write address
 195 adc r22,r18 ; increment write third byte
 196 andi r22,$03 ; mask off unsed bits
 197 movw r29:r28,r25:r24 ; move write address to read address
 198 mov r23,r22
 199 
 200 ;calculate read offset
 201 brtc increment_000035 ; move read address forward if in foward mode
 202 ldi r16,$04 ; else move read address backwards by 2
 203 add r12,r16 ; this requires incrementing the read offset by 4
 204 adc r13,r18 ; r18 is cleared above
 205 adc r21,r18
 206 cp r12,r0 ; check if at bottom of buffer
 207 cpc r13,r26
 208 cpc r21,r27
 209 brlo readadd_000035 ; load read address if not at bottom of buffer
 210 clt ; else clear t register to indicate forward motion after next sample
 211 ; decrement offset by 2 - this halts playback for one sample
 212 ; to reduce spikes at transitions
 213 
 214 increment_000035: ; move read address forward by 4
 215 ; moving read address forward requires reducing the read offset by 2
 216 ldi r16,$02 ; subtract 2 from read offset
 217 sub r12,r16
 218 sbc r13,r18 ; r18 is cleared above
 219 sbc r21,r18
 220 brne readadd_000035 ; load read address if not at top of buffer
 221 ldi r16,$04 ; set to playback last played sample
 222 mov r12,r16 ; reduces spikes at transitions
 223 set ; else set t register to start reversing on next sample
 224 
 225 readadd_000035: ; add in read offset
 226 
 227 sub r28,r12 ; subtract offset from read address
 228 sbc r29,r13
 229 sbc r23,r21
 230 andi r23,$03 ; mask off unused bits
 231 ori r23,$04 ; set we/ bit for reading
 232 
 233 adcsample_000035: ; get buffer size from adc
 234 
 235 lds r17,adcsra ; get adc control register
 236 sbrs r17,adif ; check if adc conversion is complete
 237 rjmp done_000035 ; skip adc sampling if not
 238 lds r16,adcl ; get low byte adc value
 239 lds r17,adch ; get high byte adc value
 240 add r19,r16 ; accumulate adc samples
 241 adc r10,r17
 242 adc r11,r18 ; r18 is cleared above
 243 ldi r17,$f7
 244 sts adcsra,r17 ; clear interrupt flag
 245 dec r14 ; countdown adc sample clock
 246 brne done_000035 ; dont get buffer size till its been long enough
 247 lsr r11 ; divide adc sample by 2
 248 ror r10 ; as the max buffer size is only $020000
 249 ror r19 ; as the buffer is read backwards half of the time
 250 ldi r17,$01 ; check if adc value is less than $000100
 251 cp r10,r17
 252 cpc r11,r18 ; r18 cleared above
 253 brsh deadband_000035 ; check if adc value changed enough to update delay
 254 mov r10,r17 ; set minimum delay to $000100 = 3ms
 255 clr r19
 256 
 257 deadband_000035: ; check for change in adc value
 258 
 259 movw r17:r16,r11:r10 ; move adc sample to temporary register
 260 mov r20,r19
 261 sub r20,r0 ; find difference between adc sample and desired buffer size
 262 sbc r16,r26
 263 sbc r17,r27
 264 brsh check_000035 ; check for deadband if positive
 265 com r20 ; invert if negative
 266 com r16 ; using ones complement as it is faster, and only has 1 bit error
 267 com r17
 268 
 269 check_000035: ; check if difference is greater than deadband
 270 
 271 cpi r20,$80 ; check if difference is less than 1 lsb
 272 cpc r16,r18 ; r18 cleared above
 273 cpc r17,r18
 274 brlo empty_000035 ; do nothing if less than 1 lsb
 275 movw r27:r26,r11:r10 ; move adc sample to delay time if large enough change
 276 andi r19,$fc ; make sure buffer size is a multiple of 4
 277 mov r0,r19
 278 
 279 empty_000035: ; empty accumulation registers and finish off
 280 
 281 clr r10 ; empty accumulation registers
 282 clr r11
 283 clr r19
 284 
 285 switchsample_000035: ; check if at same function
 286 
 287 lds r16,pinj ; get switch data
 288 andi r16,$78 ; mask off rotary switch
 289 lsr r16 ; adjust switch position to program memory location
 290 lsr r16
 291 ldi r17,$02
 292 add r16,r17 ; move to jump register
 293 cpse r16,r31 ; check if location has changed
 294 clr r30 ; reset jump register to intial state
 295 mov r31,r16
 296 
 297 done_000035:
 298 
 299 reti ; return to waiting
 300 

UpDownSweep (last edited 2010-08-21 02:06:42 by guest)