Basic Question about cog memory
So I have successfully generated a sin wave, output on 8 pins and sent to a DAC. I am trying to cycle through the wave once and store the values to COG memory so I can then spit them out faster because I won't be reading from hub memory every time. I cannot get this to work and would appreciate any direction/corrections.
CON
_clkmode = xtal1 + pll16x
_xinfreq = 5_000_000
VAR
long index
word angles[360]
PUB Get_samples
repeat index from 0 to 360
angles[index] := index*8192/360
cognew(@begin,@angles[0])
DAT
begin mov address, par
mov dira,#$FF
:loop rdword sin, address
add address, #2
call #getsin
mov time,cnt
add time,delay
waitcnt time,delay
sar sin, #9
add sin, #$80
mov cogmem, sin 'write sin cog memory rather than output pins
'mov outa,cogmem
add cogmem, #2 'increment memory location
djnz ctr,#:loop'decrement counter and restart loop
'mov ctr,#360 'Initialize counter.
'mov address,par
'jmp #:loop
mov :rdmem,start
mov ctr,#360
:rdmem mov cogmem,0-0
mov outa,cogmem
add cogmem, #2
djnz ctr,#:rdmem
mov :rdmem,start
mov ctr,#360
jmp #:rdmem
getsin test sin,sin_90 wc 'get quadrant 2|4 into c
test sin,sin_180 wz 'get quadrant 3|4 into nz
negc sin,sin 'if quadrant 2|4, negate offset
or sin,sin_table 'or in sin table address >> 1
shl sin,#1 'shift left to get final word address
rdword sin,sin 'read word sample from $E000 to $F000
negnz sin,sin 'if quadrant 3|4, negate sample
getsin_ret ret ' (this subroutine adapted from Prop manual)
sin_90 long $0800
sin_180 long $1000
sin_table long $E000 >>1
sin long 0
ptr long 0
ctr long 360
cntstart long 360
address long 0
cogmem long $03C0
start long $03C0
delay long 9
time res 1

Comments
Once read to COG Ram, no need for HUB calls.
It looks like you are only using 29 of the 492 memory locations available in cog ram, so the 360 values should fit.
mov cogmem, sin 'write sin cog memory rather than output pins 'mov outa,cogmem add cogmem, #2 'increment memory location djnz ctr,#:loop'decrement counter and restart loopdoes not do what the comments indicate. "cogmem" is just a single cog memory location. So while "mov cogmem, sin" will indeed move the sin value into cogmem, the subsequent "add cogmem, #2" will just corrupt the value you just put into cogmem by adding two to it.Also note that COG memory is always addressed in longs, not bytes.
So the code above should look roughly like (note that I give no guarantees, just giving a flavor!):
movd cogmem, :wrsin ' set up the indirection add cogmem,#1 ' go to next longword in cog memory (and wait a cycle so code at :wrsin will be fetched with proper modification) :wrsin mov 0-0, sin 'write sin cog memory rather than output pins djnz ctr,#:loop'decrement counter and restart loopThere's a similar problem in the loop:
mov :rdmem,start mov ctr,#360 :rdmem mov cogmem,0-0 mov outa,cogmem add cogmem, #2 djnz ctr,#:rdmemI gather your intention there is to copy the 360 sin values starting at "start" into outa. For that you would have to do something like:
mov cogmem,#start ' initialize COG memory pointer to start of 360 long array mov ctr,#360 :loop movs :rdmem,cogmem ' change the source of the instruction at :rdmem from 0-0 to whatever is stored in cogmem add cogmem,#1 ' there must be one instruction between when we modify :rdmem and :rdmem actually executes :rdmem mov outa,0-0 djnz ctr,#:loopYou can optimize this a bit by actually incrementing the instruction at :rdmem directly, since the source is in the low bits of the instruction, but that's an advanced topic :-).Finally note that you will need to reserve 360 long words, not 720 bytes, for the array, since in COG memory the smallest addressable unit is a long word (4 bytes). You could get fancy and do two samples at once by shifting and masking, but that's a bit more work.
Eric
I tried your code for the first loop and I no longer get a sinusoid on the scope when I uncomment mov outa,cogmem and the instructions at the end to keep the loop going. Rather I get a sawtooth wave much like the lower loop gives me. Any ideas?
Andy
CON _clkmode = XTAL1|PLL16X _xinfreq = 5_000_000 CON wcnt = 256 VAR word data[wcnt] PUB selftest : index repeat constant(wcnt/2) data[index++] := data[wcnt - 1 - index] := index cognew(@begin, @data{0}) DAT org 0 begin mov addr, par ' grab r/w copy of par mov dira, mask ' drive outputs movd :keep, #cogmem ' initialise start of local array ([COLOR="blue"]0-0[/COLOR]) mov ecnt, #wcnt ' adapt if > 511 :loop rdword temp, addr ' load array element add addr, #2 ' advance hub address call #process ' process array element (temp - temp) :keep mov [COLOR="blue"]0-0[/COLOR], temp ' cache processed value add $-1, dst1 ' advance move destination djnz ecnt, #:loop ' for all elements ' All values have been processed. Now send them to the LED bar. endless movs :loop, #cogmem ' start with first element ([COLOR="orange"]0-0[/COLOR]) mov ecnt, #wcnt ' adapt if > 511 :loop mov outa, [COLOR="orange"]0-0[/COLOR] ' send byte add $-1, #1 ' advance move source djnz ecnt, #:loop ' for all elements jmp #endless ' nothing else to do ... ' The value is stored in the LSB of the data word. For now simply ' shift it up 16 more bits to become visible on the LED bar (demoboard). process shl temp, #16 process_ret ret ' initialised data and/or presets mask long $00FF0000 dst1 long 1 << 9 ' dst +/-= 1 ' uninitialised data and/or temporaries addr res 1 ecnt res 1 temp res 1 cogmem res wcnt ' local cog array tail fit DATEric
I did try doing outa, sin and it worked but my goal is to get the sin data into the memory location cogmem so I can access it later (in the second loop). Essentially I want to read a full period into memory and then just spit out samples. So how do I get the DATA into "cogmem" rather than having it just be a pointer? Sorry if I'm being dense, I appreciate the help. I am also about to look at the other post from kuroneko about a different approach.
You can not store 360 values into a single cogmem location. You need to reserve 360 longs for cogmem, eighter with res as kuroneko has shown or with: Then these two loops can store and replay the sine values into/from this data-table:
movd :wrsin, #cogmem ' set up the indirection mov ctr, #360 :wrsin mov 0-0, sin 'write sin cog memory rather than output pins add :wrsin, incrDest djnz ctr,#:loop'decrement counter and restart loop sinout movs :rdmem,#cogmem 'mov startaddress to source field of :rdmem mov ctr,#360 :rdmem mov outa,0-0 'read indirect add :rdmem, #1 'increment source field to next address djnz ctr,#:rdmem 'for all sine values jmp #sinout 'start again for next periode incrDest long 1<<9 'constant for increment destination field cogmem long 0[360]AndyCON _clkmode = xtal1 + pll16x _xinfreq = 5_000_000 VAR long index word angles[360] 'set up a word array to hold angles PUB Get_samples repeat index from 0 to 360 angles[index] := index*8192/360 'fill angle array cognew(@begin,@angles[0]) 'launch cog DAT begin mov address, par 'point to angles array mov dira,#$FF 'set pins 0-7 as outputs mov ctr,#360 'initialize counter :loop rdword sin, address 'read angle into sin add address, #2 'increment to next array location call #getsin 'call getsin, which will return the sin in sin mov time,cnt 'delay add time,delay waitcnt time,delay sar sin, #9 'shift sin so it fits in 8 bits add sin, #$80 'offset movd :wrsin, #cogmem ' set up the indirection 'mov ctr, #360 'I think if this is here it resets on every loop iteration? nop 'time for self modifying code to complete :wrsin mov 0-0, sin 'write sin cog memory rather than output pins add :wrsin, incrDest 'increment memory location djnz ctr,#:loop 'decrement counter and restart loop sinout movs :rdmem,#cogmem 'mov start address to source field of :rdmem mov ctr,#360 :rdmem mov outa,0-0 'read indirect add :rdmem, #1 'increment source field to next address djnz ctr,#:rdmem 'for all sine values jmp #sinout 'start again for next periode getsin test sin,sin_90 wc 'get quadrant 2|4 into c test sin,sin_180 wz 'get quadrant 3|4 into nz negc sin,sin 'if quadrant 2|4, negate offset or sin,sin_table 'or in sin table address >> 1 shl sin,#1 'shift left to get final word address rdword sin,sin 'read word sample from $E000 to $F000 negnz sin,sin 'if quadrant 3|4, negate sample getsin_ret ret sin_90 long $0800 sin_180 long $1000 sin_table long $E000 >>1 sin long 0 incrDest long 1<<9 'constant for increment destination field delay long 9 ctr long 0 cogmem long 0[360] address long 0 time res 1Before I forget, your SPIN loop should stop at 359!