welcome: please sign in
location: Diff for "DelayTutorialAsm"
Differences between revisions 4 and 5
Revision 4 as of 2010-07-18 03:19:10
Size: 16649
Comment:
Revision 5 as of 2010-07-18 03:24:14
Size: 16653
Comment:
Deletions are marked like this. Additions are marked like this.
Line 357: Line 357:
    ; oh wait, what? I'm going to have to do it again? from the beginning?
    ; but I still need to get my pointers all lined up!
    ; oh wait, what? We're going to have to do it again? from the beginning?
    ; but we still need to get our pointers all lined up!

DelayTutorial.asm

[Discussion of code elements, needed revision etc, can go here]

   1 ; ****************************************************************************
   2 ; * program: delay-16b-rotary.asm                                            *
   3 ; * UID = Tutorial - unique id to eliminate conflicts between variables,     *
   4 ; *       replace each instance of UID in the code with this unique id.      *
   5 ; * 16b address space (.7s delay time)                                       *
   6 ; * stereo data                                                              *
   7 ; * pot controlled delay time (0s - .7s)                                     *
   8 ; ****************************************************************************
   9 ; *                                                                          *
  10 ; * PROGRAM OVERVIEW                                                         *
  11 ; *                                                                          *
  12 ; * data is read in from memory and written to the codec at the same time    *
  13 ; * new data is written to the memory from the codec.  the rotary encoder    *
  14 ; * increments or decrements the read address, adjusting the delay time.     *
  15 ; *                                                                          *
  16 ; * register usage - may be redefined in other sections                      *
  17 ; *                                                                          *
  18 ; * r0                                                                       *
  19 ; * r1                                                                       *
  20 ; * r2  left lsb out                                                         *
  21 ; * r3  left msb out                                                         *
  22 ; * r4  right lsb out                                                        *
  23 ; * r5  right msb out                                                        *
  24 ; * r6  left lsb in                                                          *
  25 ; * r7  left msb in                                                          *
  26 ; * r8  right lsb in                                                         *
  27 ; * r9  right msb in                                                         *
  28 ; * r10                                                                      *
  29 ; * r11                                                                      *
  30 ; * r12 desired delay lsb                                                    *
  31 ; * r13 desired delay msb                                                    *
  32 ; * r14                                                                      *
  33 ; * r15 switch sample counter                                                *
  34 ; * r16 temporary swap register                                              *
  35 ; * r17 temporary swap register                                              *
  36 ; * r18                                                                      *
  37 ; * r19                                                                      *
  38 ; * r20                                                                      *
  39 ; * r21                                                                      *
  40 ; * r22 write address third byte/null register                               *
  41 ; * r23                                                                      *
  42 ; * r24 write address lsb                                                    *
  43 ; * r25 write address msb                                                    *
  44 ; * r26 actual delay lsb                                                     *
  45 ; * r27 actual delay msb                                                     *
  46 ; * r28 read address lsb                                                     *
  47 ; * r29 read address msb                                                     *
  48 ; * r30 jump location for interrupt lsb                                      *
  49 ; * r31 jump location for interrupt msb                                      *
  50 ; ****************************************************************************
  51 
  52 
  53 ; * NOTES: - all unprocessed (dry) raw data  comes in off of the SPI port, via spdr
  54 ;          - all processed (wet) data goes out over the SPI port, also via spdr
  55 ;          - all external memory addressing happens over ports D and H 
  56 ;          - all data we are saving and reading back (like our delay audio) travels over ports A and C
  57 
  58 
  59 
  60 
  61 
  62 ; **********************
  63 ; **** PROGRAM START
  64 ; **********************
  65 
  66 ; initiate data transfer to codec
  67 
  68 sbi portb, portb0           ; set bit portb0  (aka DACLRC aka DAC sample rate left/right clock)
  69                             ;  
  70                             ; **NOTE: from WM8731 data sheet, page 36: 
  71                             ;                   "DACLRC is an alignment clock that controls whether Left or Right channel 
  72                             ;                            data is present on DACTAT" 
  73 
  74 ; (now on SPI - LEFT MSB)  *********************************************************************************************
  75 
  76 out spdr, r3            ; send out processed left channel msb (or whatever's currently in r3) to SPI data register
  77 cbi portb, portb0       ; clear DACLRC
  78 
  79 adiw r25:r24, 0x01      ; increment write address pointer by 0x01
  80 adiw r29:r28, 0x01      ; increment  read address pointer by 0x01
  81 ldi  r22, 0x00          ; setup write high byte with null
  82 
  83 
  84 ; **********************
  85 ; **** wait1 
  86 ; **********************
  87 
  88 wait1_UID:                 ; wait to see if processed left channel msb has been sent
  89 
  90 in   r17, spsr             ; move spi status register to r17 so we can look at it
  91 sbrs r17, spif             ; skip next instruction if the SPIF (spi interrupt flag) bit is set
  92                            ; **NOTE: from atmega3250P data sheet, page 162:
  93                            ;                    "When a serial transfer is complete, the SPIF flag is set" 
  94 rjmp wait1_UID             ; aka: loop until SPIF is set
  95                            ; and then...
  96 
  97 ; ### after wait1, new spi data ready
  98 
  99 in r7, spdr                ; move spi data register into r7  (remember spdr is read/write, page 162)
 100                            ; this moves the incoming (dry) left channel msb to r7
 101 
 102 ; (end of wet/dry left msb transfer) ***********************************************************************************
 103 
 104 ; (now on SPI - LEFT LSB)            ***********************************************************************************
 105 
 106 out spdr, r2               ; send the processed (wet) left lsb out
 107 
 108 ; ### retrieve stored left channel data from SRAM: 
 109 
 110 out portd, r28             ; move read address lsb pointer to portd (see schematic) 
 111 sts porth, r29             ; move read address msb pointer to portH
 112                            ; **NOTE: - this is a special instruction because the I/O portH register is wayyy up there in the sram
 113                            ;             - 'out' completes in one cycle, 'sts' completes in two
 114 
 115 nop                        ; read address msb hits the port, now wait for  (1)  
 116 nop                        ; a latch time of two cycles...                 (2)
 117 
 118                            ; DING!  your data is ready, please pick it up! 
 119 in r2, pina                ; (see schematic) D0-7,  aka lsb, is on port A, now stored in r2
 120 in r3, pinc                ;             and D8-15, aka msb, is on port C, now stored in r3
 121 
 122 ; ###  left channel SRAM retrieve completed
 123 
 124                            ; now we've got a little time to kill, so...
 125 adiw r29:r28, 0x01         ; increment read address pointer by 1
 126 
 127 
 128 ; **********************
 129 ; **** wait2 
 130 ; **********************
 131 
 132 wait2_UID:                 ; wait to see if wet left channel lsb has been sent
 133  
 134 in   r17, spsr             ; spi status reg. to r17 (looking familiar?)
 135 sbrs r17, spif             ; skip next if SPIF bit not set...
 136 rjmp wait2_UID             ; loop until SPIF set
 137 
 138                            ; **NOTE: and now a couple of words about rjmp:
 139                            ;            - it can only move within 2k of memory (ie, can't jump all the way to the start, or end, of a long program) 
 140                            ;            - it doesn't do anything to the stack  (so if it loops a thousand times, the stack isn't going to overflow)
 141                            ;            - it takes two cycles
 142 
 143 ; ### after wait2 is finished, new spi data ready
 144 
 145 in r6, spdr                ; receive in dry left channel lsb 
 146                            ; **NOTE: that gives us both bytes of the incoming left channel, and both wet bytes have been sent
 147                            ;         we can now move on to the right channel
 148 
 149 ; (end of wet/dry left lsb transfer) ************************************************************************************
 150 
 151 ; (now on SPI - RIGHT MSB)           ************************************************************************************
 152 
 153 out spdr, r5               ; send out (wet) right msb
 154 
 155 ; ### writing (dry) left channel to SRAM:
 156 out portd, r24             ; update data address ports to reflect where we want to write
 157 sts porth, r25             ; remember 'out' and 'sts'?
 158 
 159 out portg, r22             ; woah, portG? what's this?  Check out the SRAM data sheet and the schematic:
 160                            ;    r22 is currently 0x00, so we are pulling CE and WE low, and writing our high address bits to zero
 161                            ;    CE (chip enable) and WE (write enable) are asserted low
 162                            
 163                            ; **NOTE:  from AS7C4098 data sheet, page 2:
 164                            ;                     "Data on input pins io1-io16 is written on the rising edge of WE..." 
 165                            ;                     "To avoid bus contention, external devices should drio i/o pins only after 
 166                            ;                            outputs have been disabled with OE (output enable) or WE"
 167                            ;                     "A read cycle is accomplished by asserting OE and CE, with WE high."  
 168 
 169 ldi r17, 0xFF        ; prepare a salad of ones 
 170 out ddra, r17        ; send them to the portA direction register
 171 out ddrC, r17        ; and to the portC direction register       
 172                      ; (see ATmega3250P data sheet, page 65, 'Switching Between Input and Output')
 173 
 174 out porta, r6        ; with these two 'out' instructions 
 175 out portc, r7        ; we send left channel dry data directly to the sram
 176                                 
 177 
 178 sbi portg, portg2    ; and as soon as we pull WE (write enable) on portG_2 high,
 179                      ; zzztt!  a single audio sample is written into memory, just like that.
 180                                    
 181                   
 182 
 183 ; ### left channel SRAM write completed
 184 
 185 
 186 out ddra, r22       ; now, we happen to know that r22 contains a bunch of zeros 
 187 out ddrc, r22       ; so we can use that register to set ports A and C back to an input state. 
 188 
 189 
 190 
 191 
 192 ; **********************
 193 ; **** wait3
 194 ; **********************
 195 
 196 wait3_UID:              ; meanwhile, back at the codec, we are still transferring the right channel lsb
 197 
 198 in   r17, spsr          ; check out the spsr, check out the spif,
 199 sbrs r17, spif          ; we know what we're doing here now, right?  
 200 rjmp wait3_UID          ; loop until transfer completed
 201 
 202 ; ### end of wait3, new data ready!
 203 
 204 in r9, spdr             ; recieve in (dry) right channel msb
 205 
 206 ; (end of wet/dry right msb transfer) ***********************************************************************************
 207 
 208 ; (now on SPI - RIGHT LSB)            ***********************************************************************************
 209 
 210 out spdr, r4            ; send out (wet) right channel lsb
 211 
 212 ; ### retrieve stored right channel data from SRAM
 213 out portd, r28          ; set up the address we want to read from
 214 sts porth, r29          ; on ports d and h
 215 
 216 nop                     ; killing time again... 
 217 nop                     ; two cycles, while the SRAM latches the address
 218 
 219                         ; and once more, ding!  our data is now waiting on the SRAM data lines
 220 in r4, pina             ; right lsb
 221 in r5, pinc             ; right msb    (this is audio data we saved in the past)
 222 
 223 ; ### right channel SRAM data retrieval completed
 224 
 225 adiw r25:r24, 0x01      ; increment the write address (we're going to be using that pointer next)
 226 
 227 
 228 ; **********************
 229 ; **** wait4
 230 ; **********************
 231 
 232 wait4_UID:                      ; checking up on that SPI transfer
 233 
 234 in r17, spsr
 235 sbrs r17, spif
 236 rjmp wait4_UID                  ; loop until SPIF is set
 237 
 238 ; ### end of wait4, more new data!
 239 in r8, spdr                     ; bring in right channel lsb
 240 
 241 ; (end of wet/dry right lsb transfer) ***********************************************************************************
 242 ; now that we have both bytes of the right channel dry audio, we can store it in the SRAM
 243 
 244 ; ### writing (dry) right channel to SRAM
 245 
 246 out portd, r24          ; give the sram the write address, lsb
 247 sts porth, r25          ; now msb
 248 
 249 out portg, r22          ; pull WE low, (CE is already low, WE was high for read operations)
 250 ldi r17, 0xFF           ; prepare a bevy of ones
 251 out ddra, r17           ; set porta as output
 252 out ddrc, r17           ; set portc as output
 253 out porta, r8           ; put the data on the ports, lsb
 254 out portc, r9           ; msb
 255 sbi portg, portg2       ; zzzt!  pull WE high and write the data
 256 
 257 out ddra, r22           ; reconfigure porta as input
 258 out ddrc, r22           ; reconfigure portc as input
 259 
 260 
 261 ; **********************************************************************************
 262 ; **** check rotary encoder and adjust delay time
 263 ; **********************************************************************************
 264 ; * The rotary encoder is externally debounced, so we don't have to do that here.
 265 ; * You'll see it in the schematic labeled MOD2 on portJ0, portJ1, and portJ2.
 266 ; * 
 267 ; * The encoder's pin1 is sampled on a transition from high to low on pin0.  
 268 ; * if pin1 is high, a left turn occured, if pin1 is low, a right turn occured.
 269 ; **********************************************************************************
 270 
 271 dec r15                 ; well, let's do a little debouncing anyway
 272 brne adjust_UID         ; brne checks the Z register,
 273                         ; if r15 was not zero after the last operation, it will branch us to adjust_UID
 274 
 275 ldi r17, 0x40           ; prepare a constant in r17                                     
 276 mov r15, r17            ; put 0x40 in the sample freq bin to catch all rising edges (results in 1.5ms sampletime)
 277 lds r17, pinj           ; move port J data into r17
 278 sbrs r17, PINJ0         ; skip next if PINJ0 is set
 279 rjmp edgecheck_UID      ; if it's not set, is it a falling edge?
 280 
 281 clt                     ; clear T reg (in SREG)
 282 rjmp switchsample_UID   ; done looking at mod2, look at the program selector
 283 
 284 ; **********************
 285 ; **** edgecheck 
 286 ; **********************
 287 
 288 edgecheck_UID:                  ; checks for falling edge
 289 brts switchsample_UID           ; if the T flag in SREG is set, assume the edge was already detected
 290 set                             ; otherwise set the T flag
 291 sbrs r17, PINJ1                 ; check if PINJ1 is high
 292 rjmp upcount_UID                ; if PINJ0 has just gone low and PINJ1 is low, a right turn has transpired
 293                                 ; upcount will therefore increase the delay
 294                                 ; otherwise, PINJ1 is high and a left turn has transpired, so we should decrease the delay
 295 ; **** downcount
 296 ldi r17, 0x01                   ; load our decrement amount into r17  (0x01 = 256 samples = 0.006s)
 297 sub r13, r17                    ; decrement delay MSB 
 298 
 299 rjmp switchsample_UID           ; done looking at mod2, look at the program selector
 300 
 301 ; **** upcount
 302 upcount_UID:                    ; increment delay register
 303 ldi r17, 0x01                   ; load increment amount into r17
 304 add r13, r17                    ; increment MSB
 305 
 306 
 307 ; **********************
 308 ; **** switchsample
 309 ; **********************
 310 
 311 switchsample_UID:               ; sample the program select dial
 312 
 313 lds  r31, pinj                  ; put switch data into jump location MSB reg
 314 andi r31, 0x78                  ; mask off rotary encoder 0b01111000
 315 ldi  r17, 0x02                  ; 0x02 into r17
 316 lsr  r31                        ; shift r31 to the right
 317 lsr  r31                        ; shift again
 318 add r31, r17                    ; convert switch position data to program memory location
 319 
 320 
 321 ; **********************
 322 ; **** adjust
 323 ; **********************
 324 
 325 adjust_UID:                     ; since we've only changed the desired delay in the previous section, we need to implement that delay
 326                                 ; this checks to see if the delay time is correct,
 327                                 ; and if it's not it makes an effort to move slightly closer to the correct delay 
 328 
 329 andi r26, 0xFE                  ; is the delay time even?
 330 cp r26, r22                     ; compare actual delay lsb to zero
 331 cpc r27, r13                    ; compare with carry actual delay msb with desired delay msb
 332 breq done_UID                   ; If equal, head to done, yay!  
 333 brsh indexdown_UID              ; If the same or higher, branch to indexdown
 334                                 ; otherwise, we can assume it is too low
 335 ; **** indexup
 336 adiw r27:r26, 0x04              ; so increment delay register by 0x04
 337 rjmp done_UID                   ; and head to the end
 338 
 339 ; **** indexdown
 340 indexdown_UID:
 341 sbiw r27:r26, 0x02              ; decrement delay reg by 0x02
 342 
 343 
 344 
 345 ; **********************
 346 ; **** done
 347 ; **********************
 348 
 349 done_UID:                       ; It's been a long hard row to hoe, but we did it!  
 350                                 ; oh wait, what?  We're going to have to do it again?  from the beginning?  
 351                                 ; but we still need to get our pointers all lined up!    
 352 
 353 movw r29:r28, r25:r24           ; sync write destination and read address
 354 sub r28, r26                    ; now subtract by the delay in samples (first lsb)
 355 sbc r29, r27                    ; subtract msb with carry from previous
 356 
 357 reti                            ; return from interrupt so we can get back to our idling 
 358 

MICrODEC

Microdec Software

DelayTutorialAsm (last edited 2010-08-21 01:53:49 by guest)