Initializing asm pointers?
Peter Jakacki
Posts: 10,193
I just received my demoboard a couple of days ago and I have been busy modifying sample code etc.
What I want to do is to take microphone samples and store them in a buffer in main memory and playback from the oldest entry to achieve an audio delay.
Being very new at this the problem I am having at the moment is getting SPIN to pass the buffer address as a constant to init the assembly buffer pointer.
Just playing but I think that's right.
Can anyone give me a few pointers?
Thanks,
*Peter*
What I want to do is to take microphone samples and store them in a buffer in main memory and playback from the oldest entry to achieve an audio delay.
Being very new at this the problem I am having at the moment is getting SPIN to pass the buffer address as a constant to init the assembly buffer pointer.
Just playing but I think that's right.
Can anyone give me a few pointers?
Thanks,
*Peter*
CON
sndsz = 4000
attenuation = 0
sndbufcon = sndbuf '!!!!!!!!!!!!! how do i pass the address of sndbuf to assembler?
VAR
word sndbuf[noparse][[/noparse]sndsz]
DAT
'
'
' Assembly program
'
org
asm_entry mov dira,asm_dira 'make pins 8 (ADC) and 0 (DAC) outputs
'setup ADC
movs ctra,#8 'POS W/FEEDBACK mode for CTRA
movd ctra,#9
movi ctra,#%01001_000
mov frqa,#1
'setup DAC
movs ctrb,#10 'DUTY DIFFERENTIAL mode for CTRB
movd ctrb,#11
movi ctrb,#%00111_000
mov sndptr,sndptrvar
mov asm_cnt,cnt 'prepare for WAITCNT loop
add asm_cnt,asm_cycles
:loop waitcnt asm_cnt,asm_cycles 'wait for next CNT value (timing is determinant after WAITCNT)
mov asm_sample,phsa 'capture PHSA and get difference
sub asm_sample,asm_old
add asm_old,asm_sample
'delay buffer (Q&D)
wrword @sndptr,asm_sample 'buffer the current sample
add sndptr,#2 'bump ptr
cmp sndptr,sndszvar 'end of buffer?
if_ae mov sndptr,sndptrvar 'yep, reset ptr
rdword asm_sample,@sndptr 'read oldest sample
shl asm_sample,#32-bits-attenuation 'justify sample and output to FRQB
mov frqb,asm_sample
jmp #:loop 'wait for next sample period
'
'
' Data
'
asm_cycles long |< bits - 1 'sample time
asm_dira long $00000E00 'output mask
asm_cnt res 1
asm_old res 1
asm_sample res 1
sndptr res 1
sndszvar long sndbufcon+sndsz
sndptrvar long sndbufcon

Comments
cognew(@asm_entry, @sndbuf)
This will place the address of sndbuf[noparse][[/noparse]0] into the PAR register of the cog. To use the value (since·PAR is a read only register), copy it into sndptr with:
mov sndptr, par
You can also pass it by assigning sndptr via Spin before you run cognew, so you would do:
sndptr := @sndbuf
cognew(@asm_entry,0)
But in your case I would use the PAR method, this way you will keep a permanent read-only copy of the pointer to the buffer that you can reinitialize sndptr if needed.
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Paul Baker
Propeller Applications Engineer
Parallax, Inc.
Besides this I learned:
1. unlike the normal assembler words where the destination is to the left and source to the right instructions such as WRWORD must have the destination address on the right (doh!).
2. CMP instructions will happily compare but will keep it a secret unless you give them the WZ WC WR options (doh!)
I am sure I will say doh a few more times yet but this is what I have found. I have included the working code for anyone who is interested.
*Peter*
' This program uses the Propeller Demo Board, Rev C ' The microphone is digitized and the samples are played on the headphones. ' PBJ: ' As an exercise I have modified this program to use a buffer to delay samples ' and also to introduce some echo. ' CON _clkmode = xtal1 + pll16x _xinfreq = 5_000_000 ' At 80MHz the ADC/DAC sample resolutions and rates are as follows: ' ' sample sample ' bits rate ' ---------------- ' 5 2.5 MHz ' 6 1.25 MHz ' 7 625 KHz ' 8 313 KHz ' 9 156 KHz ' 10 78 KHz ' 11 39 KHz ' 12 19.5 KHz ' 13 9.77 KHz ' 14 4.88 KHz bits = 13 'try different values from table here PUB go cognew(@asm_entry, @sndbuf) 'launch assembly program into a COG CON sndsz = 16000 attenuation = 0 VAR word sndbuf[noparse][[/noparse]sndsz] DAT ' ' ' Assembly program ' org asm_entry mov sndptr, par mov sndend,par add sndend,sndszvar mov dira,asm_dira 'make pins 8 (ADC) and 0 (DAC) outputs 'setup ADC movs ctra,#8 'POS W/FEEDBACK mode for CTRA movd ctra,#9 movi ctra,#%01001_000 mov frqa,#1 'setup DAC movs ctrb,#10 'DUTY DIFFERENTIAL mode for CTRB movd ctrb,#11 movi ctrb,#%00111_000 mov asm_cnt,cnt 'prepare for WAITCNT loop add asm_cnt,asm_cycles :loop waitcnt asm_cnt,asm_cycles 'wait for next CNT value (timing is determinant after WAITCNT) mov asm_sample,phsa 'capture PHSA and get difference sub asm_sample,asm_old add asm_old,asm_sample 'delay buffer rdword buf,sndptr 'read oldest sample (for echo) shr buf,#2 'attenuate it add asm_sample,buf 'and mix it in with the latest wrword asm_sample,sndptr 'buffer the current sample add sndptr,#2 'bump ptr cmp sndptr,sndend wz 'end of buffer? if_e mov sndptr, par 'yep, reset ptr rdword asm_sample,sndptr 'read oldest sample shl asm_sample,#32-bits-attenuation 'justify sample and output to FRQB mov frqb,asm_sample jmp #:loop 'wait for next sample period ' ' ' Data ' asm_cycles long |< bits - 1 'sample time asm_dira long $00000E00 'output mask sndszvar long sndsz asm_cnt res 1 asm_old res 1 asm_sample res 1 buf res 1 sndptr res 1 sndend res 1wr is the only default enabled affect flag and this is for instructions that inherently want to write a result, probing instructions such as TEST and CMP have no default affects, wz and wc must always be specified for any instruction you want those flags affected. This may seem crazy to people use to the Intel or Motorola instruction sets, but the conditional affect coupled with the conditional execution is very powerful in reducing code bloat. Notice there are no 'skip if...' instructions as there are in the SX, conditional execution makes them obsolete along with the memory location required for the instruction.
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Paul Baker
Propeller Applications Engineer
Parallax, Inc.
Don't forget about using 'nr' as well... this is a way that you can do a non standard comparison without affecting the destination register. For example...
sub DataValueA, DataValueB wz, nr if_z jmp #DataEqualThe first line subtracts DataValueA from DataValueB ... If they are equal, then the Zero flag is set ...nr tells the compiler not to write the result back to DataValueA, so DataValueA and DataValueB remain intact.
The Second line branches to #DataEqual if the Zero flag has been set.
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Beau Schwabe
IC Layout Engineer
Parallax, Inc.
Post Edited (Beau Schwabe (Parallax)) : 9/15/2006 5:57:27 PM GMT
I missed that point that Mike made and found out fairly quickly anyway. The compile/download/execute cycle is extremely short so it is nothing at all to make a slight change, even without saving and then hitting F10, it works brilliantly, well done!
The idea of learning and using Spin was not immediately entertained but because the propeller ide is dealing with objects in source code form it makes it very easy to use, investigate, debug, and adapt. There are many many projects I have NOW lined-up for the propeller, I know it's new but why hasn't it taken off faster than this? It is true that there are many that find it hard to change processors and tools (taught on XYZ n C n I'll die XYZ n C [noparse]:)[/noparse] ), but really that's their loss.
*Peter*
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Paul Baker
Propeller Applications Engineer
Parallax, Inc.