welcome: please sign in

Upload page content

You can upload content for the page named below. If you change the page name, you can also upload content for another page. If the page name is empty, we derive the page name from the file name.

File to load page content from
Page name
Comment
Enter the first 6 digits of Pi.

location: DelayShortAsm

DelayTutorial.asm

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

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

MICrODEC

Microdec Software