{{
*****************************************
* *
* Author: Ian Mitchell *
*****************************************
}}
{
Revision History:
Version 1.0 - original file created
}
con
_CLKMODE = XTAL1 + PLL16X
_XINFREQ = 5_000_000
var
long frequency
obj
' DDS : "DDS1_0.1"
' DDS : "DDS4_0.1"
DDS : "DDS7_0.2"
ss : "Simple_Serial"
' pst : "Parallax Serial Terminal" ' Serial communication object
pub main
'dira[16..23]~~ 'Set pins to outputs
'outa[16] := 1
' pst.start(9600) '' Initialize serial communication to the PC through the USB connector
' repeat 100
' pst.Str(String("Testing one two three, one two three..."))
' pst.NewLine
' waitcnt(clkfreq*5+cnt)
' repeat 2
' ss.init(31,30,9600)
' ss.str(String("Testing one two three, one two three..."))
' ss.tx($0d)
' ss.dec(clkfreq)
' ss.tx($0d)
DDS.start(3_999_000)
' DDS.start(3_123_000)
waitcnt(clkfreq*3+cnt)
repeat
repeat
waitcnt(clkfreq*3+cnt)
DDS.setfrequency(4_123_000)
waitcnt(clkfreq*3+cnt)
DDS.setfrequency(2_123_000)
waitcnt(clkfreq*3+cnt)
DDS.setfrequency(2_000_100)
waitcnt(clkfreq*3+cnt)
DDS.setfrequency(1_123_000)
repeat 'loop forever to keep cog alive
dat
{{
┌──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐│ TERMS OF USE: MIT License │├──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤│Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation ││files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, ││modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software││is furnished to do so, subject to the following conditions: ││││The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.││││THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE ││WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR ││COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ││ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. │└──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
}}
DDS7_0.2.spin
{{
1 0 (init to base_phase*0)
2 1000 (init to base_phase*1)
3 2000 (init to base_phase*2)
4 3000 (init to base_phase*3)
5 4000 (init to base_phase*4)
6 5000 (init to base_phase*5)
7 6000 (init to base_phase*6)
1 7000 (add base_phase*7)
2 8000 (add base_phase*7)
3 9000 (add base_phase*7)
4 10000 (add base_phase*7)
5 11000 (add base_phase*7)
6 12000 (add base_phase*7)
7 13000 (add base_phase*7)
1 14000 (add base_phase*7)
2 15000 (add base_phase*7)
3 16000 (add base_phase*7)
4 17000 (add base_phase*7)
5
6
7
1
2
3
4
5
6
7
}}
con
dds_clock = 20_000_000varlong phase_init_1 'initial phase valuelong phase_chan_1 'new phase change valuelong phase_sync_1 'clock sync valuelong phase_accu_1 'phase accumulator value (passed back)long phase_init_2 'initial phase valuelong phase_chan_2 'new phase valuelong phase_sync_2 'clock sync valuelong phase_accu_2 'phase accumulator value (passed back)long phase_init_3 'initial phase valuelong phase_chan_3 'new phase valuelong phase_sync_3 'clock sync valuelong phase_accu_3 'phase accumulator value (passed back)long phase_init_4 'initial phase valuelong phase_chan_4 'new phase valuelong phase_sync_4 'clock sync valuelong phase_accu_4 'phase accumulator value (passed back)long phase_init_5 'initial phase valuelong phase_chan_5 'new phase valuelong phase_sync_5 'clock sync valuelong phase_accu_5 'phase accumulator value (passed back)long phase_init_6 'initial phase valuelong phase_chan_6 'new phase valuelong phase_sync_6 'clock sync valuelong phase_accu_6 'phase accumulator value (passed back)long phase_init_7 'initial phase valuelong phase_chan_7 'new phase valuelong phase_sync_7 'clock sync valuelong phase_accu_7 'phase accumulator value (passed back)obj
ss : "Simple_Serial"pubstart(frequency) | phase,syncvaldira[24]~~
outa[24] := 0
phase := fraction(frequency,dds_clock)
{{
ss.init(31,30,9600)
ss.dec(phase)
ss.tx($0d)
}}
phase_init_1 := phase*1
phase_init_2 := phase*2
phase_init_3 := phase*3
phase_init_4 := phase*4
phase_init_5 := phase*5
phase_init_6 := phase*6
phase_init_7 := phase*7
phase *= 7
phase_chan_1 := phase
phase_chan_2 := phase
phase_chan_3 := phase
phase_chan_4 := phase
phase_chan_5 := phase
phase_chan_6 := phase
phase_chan_7 := phase
{{
ss.str(String("phase_init_1: "))
ss.dec(phase_init_1)
ss.tx($0d)
ss.str(String("phase_init_2: "))
ss.dec(phase_init_2)
ss.tx($0d)
ss.str(String("phase_init_3: "))
ss.dec(phase_init_3)
ss.tx($0d)
ss.str(String("phase_init_4: "))
ss.dec(phase_init_4)
ss.tx($0d)
ss.str(String("phase_init_5: "))
ss.dec(phase_init_5)
ss.tx($0d)
ss.str(String("phase_init_6: "))
ss.dec(phase_init_6)
ss.tx($0d)
ss.str(String("phase_init_7: "))
ss.dec(phase_init_7)
ss.tx($0d)
}}
syncval := 800_000+cnt'10ms into the future
phase_sync_1 := syncval+4*0
phase_sync_2 := syncval+4*1
phase_sync_3 := syncval+4*2
phase_sync_4 := syncval+4*3
phase_sync_5 := syncval+4*4
phase_sync_6 := syncval+4*5
phase_sync_7 := syncval+4*6cognew(@ddsload,@phase_init_1)
cognew(@ddsload,@phase_init_2)
cognew(@ddsload,@phase_init_3)
cognew(@ddsload,@phase_init_4)
cognew(@ddsload,@phase_init_5)
cognew(@ddsload,@phase_init_6)
cognew(@ddsload,@phase_init_7)
pubsetfrequency(frequency) | newphase,syncval,t1,t2
newphase := fraction(frequency,dds_clock)
'flag new frequencyouta[24] := 1'wait for notification from each cogrepeatuntil phase_chan_1==0repeatuntil phase_chan_2==0repeatuntil phase_chan_3==0repeatuntil phase_chan_4==0repeatuntil phase_chan_5==0repeatuntil phase_chan_6==0repeatuntil phase_chan_7==0'reset the flagouta[24] := 0'find the largest accumulator value'set initial phase
phase_init_1 := newphase*1
phase_init_2 := newphase*2
phase_init_3 := newphase*3
phase_init_4 := newphase*4
phase_init_5 := newphase*5
phase_init_6 := newphase*6
phase_init_7 := newphase*7
t1 := cnt'sync the cogs
syncval := 80_000+cnt'1ms into the future
phase_sync_1 := syncval+4*0
phase_sync_2 := syncval+4*1
phase_sync_3 := syncval+4*2
phase_sync_4 := syncval+4*3
phase_sync_5 := syncval+4*4
phase_sync_6 := syncval+4*5
phase_sync_7 := syncval+4*6'set the new phase change
newphase *= 7
phase_chan_1 := newphase
phase_chan_2 := newphase
phase_chan_3 := newphase
phase_chan_4 := newphase
phase_chan_5 := newphase
phase_chan_6 := newphase
phase_chan_7 := newphase
t2 := cnt
ss.dec(t2-t1)
ss.tx($0d)
prifraction(a,b) : f'division of (a/b)*2^32
a <<= 1repeat32
f <<= 1if a => b
a -= b
f++
a <<= 1datorg0
ddsload
jmp #ddsstart
' mov dira,testdir' mov outa,testout'stop jmp #stop 'long $00_ff_00_80long$00_ff_00_83long$00_ff_00_86long$00_ff_00_89long$00_ff_00_8clong$00_fe_00_8flong$00_fe_00_92long$00_fd_00_95long$00_fd_00_99long$00_fc_00_9clong$00_fb_00_9flong$00_fb_00_a2long$00_fa_00_a5long$00_f9_00_a8long$00_f8_00_ablong$00_f7_00_aelong$00_f5_00_b1long$00_f4_00_b4long$00_f3_00_b6long$00_f1_00_b9long$00_f0_00_bclong$00_ee_00_bflong$00_ed_00_c2long$00_eb_00_c4long$00_e9_00_c7long$00_e8_00_c9long$00_e6_00_cclong$00_e4_00_cflong$00_e2_00_d1long$00_e0_00_d3long$00_de_00_d6long$00_db_00_d8long$00_d9_00_dalong$00_d7_00_dclong$00_d5_00_dflong$00_d2_00_e1long$00_d0_00_e3long$00_cd_00_e5long$00_cb_00_e7long$00_c8_00_e8long$00_c6_00_ealong$00_c3_00_eclong$00_c0_00_eelong$00_bd_00_eflong$00_bb_00_f1long$00_b8_00_f2long$00_b5_00_f3long$00_b2_00_f5long$00_af_00_f6long$00_ac_00_f7long$00_a9_00_f8long$00_a6_00_f9long$00_a3_00_falong$00_a0_00_fblong$00_9d_00_fclong$00_9a_00_fdlong$00_97_00_fdlong$00_94_00_felong$00_91_00_felong$00_8e_00_fflong$00_8b_00_fflong$00_87_00_fflong$00_84_00_fflong$00_81_00_fflong$00_7e_00_fflong$00_7b_00_fflong$00_78_00_fflong$00_74_00_fflong$00_71_00_fflong$00_6e_00_felong$00_6b_00_felong$00_68_00_fdlong$00_65_00_fdlong$00_62_00_fclong$00_5f_00_fblong$00_5c_00_fblong$00_59_00_falong$00_56_00_f9long$00_53_00_f8long$00_50_00_f7long$00_4d_00_f5long$00_4a_00_f4long$00_47_00_f3long$00_44_00_f1long$00_42_00_f0long$00_3f_00_eelong$00_3c_00_edlong$00_39_00_eblong$00_37_00_e9long$00_34_00_e8long$00_32_00_e6long$00_2f_00_e4long$00_2d_00_e2long$00_2a_00_e0long$00_28_00_delong$00_26_00_dblong$00_24_00_d9long$00_21_00_d7long$00_1f_00_d5long$00_1d_00_d2long$00_1b_00_d0long$00_19_00_cdlong$00_17_00_cblong$00_16_00_c8long$00_14_00_c6long$00_12_00_c3long$00_11_00_c0long$00_0f_00_bdlong$00_0e_00_bblong$00_0c_00_b8long$00_0b_00_b5long$00_0a_00_b2long$00_08_00_aflong$00_07_00_aclong$00_06_00_a9long$00_05_00_a6long$00_04_00_a3long$00_04_00_a0long$00_03_00_9dlong$00_02_00_9along$00_02_00_97long$00_01_00_94long$00_01_00_91long$00_00_00_8elong$00_00_00_8blong$00_00_00_87long$00_00_00_84long$00_00_00_81long$00_00_00_7elong$00_00_00_7blong$00_00_00_78long$00_00_00_74long$00_00_00_71long$00_01_00_6elong$00_01_00_6blong$00_02_00_68long$00_02_00_65long$00_03_00_62long$00_04_00_5flong$00_05_00_5clong$00_06_00_59long$00_07_00_56long$00_08_00_53long$00_09_00_50long$00_0a_00_4dlong$00_0c_00_4along$00_0d_00_47long$00_0e_00_44long$00_10_00_42long$00_11_00_3flong$00_13_00_3clong$00_15_00_39long$00_17_00_37long$00_18_00_34long$00_1a_00_32long$00_1c_00_2flong$00_1e_00_2dlong$00_20_00_2along$00_23_00_28long$00_25_00_26long$00_27_00_24long$00_29_00_21long$00_2c_00_1flong$00_2e_00_1dlong$00_30_00_1blong$00_33_00_19long$00_36_00_17long$00_38_00_16long$00_3b_00_14long$00_3d_00_12long$00_40_00_11long$00_43_00_0flong$00_46_00_0elong$00_49_00_0clong$00_4b_00_0blong$00_4e_00_0along$00_51_00_08long$00_54_00_07long$00_57_00_06long$00_5a_00_05long$00_5d_00_04long$00_60_00_04long$00_63_00_03long$00_66_00_02long$00_6a_00_02long$00_6d_00_01long$00_70_00_01long$00_73_00_00long$00_76_00_00long$00_79_00_00long$00_7c_00_00long$00_7f_00_00long$00_80_00_00long$00_83_00_00long$00_86_00_00long$00_89_00_00long$00_8c_00_00long$00_8f_00_01long$00_92_00_01long$00_95_00_02long$00_99_00_02long$00_9c_00_03long$00_9f_00_04long$00_a2_00_05long$00_a5_00_06long$00_a8_00_07long$00_ab_00_08long$00_ae_00_09long$00_b1_00_0along$00_b4_00_0clong$00_b6_00_0dlong$00_b9_00_0elong$00_bc_00_10long$00_bf_00_11long$00_c2_00_13long$00_c4_00_15long$00_c7_00_17long$00_c9_00_18long$00_cc_00_1along$00_cf_00_1clong$00_d1_00_1elong$00_d3_00_20long$00_d6_00_23long$00_d8_00_25long$00_da_00_27long$00_dc_00_29long$00_df_00_2clong$00_e1_00_2elong$00_e3_00_30long$00_e5_00_33long$00_e7_00_36long$00_e8_00_38long$00_ea_00_3blong$00_ec_00_3dlong$00_ee_00_40long$00_ef_00_43long$00_f1_00_46long$00_f2_00_49long$00_f3_00_4blong$00_f5_00_4elong$00_f6_00_51long$00_f7_00_54long$00_f8_00_57long$00_f9_00_5along$00_fa_00_5dlong$00_fb_00_60long$00_fc_00_63long$00_fd_00_66long$00_fd_00_6along$00_fe_00_6dlong$00_fe_00_70long$00_ff_00_73long$00_ff_00_76long$00_ff_00_79long$00_ff_00_7clong$00_ff_00_7f
ddsstart ordira,dirmask 'set group of 8 pins to outputmov0,sin0 'restore first element of sine tablemov p_phase_init,par'set pointer to phase init parametermov p_phase_chan,par'set pointer to phase chan parameter -4mov p_phase_sync,par'set pointer to phase sync parameter -8mov p_phase_accu,par'set pointer to phase accu parameter -12add p_phase_chan,#4'adjust to correct location add p_phase_sync,#8'adjust to correct location add p_phase_accu,#12'adjust to correct location
sync rdlong acc,p_phase_init 'set accumulator to initial phase valuerdlong pha,p_phase_chan 'set the phase valuerdlong syn,p_phase_sync 'set the sync valuewaitcnt syn,#0'sync with other cogs
loop mov tmp,acc 'need to change acc so copy itshr tmp,#24'get the high order bytemovs sin1,tmp 'index into sine tableadd acc,pha 'add phase to accumulator
sin1 movouta,0-0'output sine valuemovouta,#0'clear for next cogtestn exitmask,inawz'test for new frequencymov tmp,acc 'need to change acc so copy itshr tmp,#24'get the high order bytemovs sin2,tmp 'index into sine tableadd acc,pha 'add phase to accumulator
sin2 movouta,0-0'output sine valuemovouta,#0'clear for next cogif_nzjmp #loop 'carry on, unless frequency changedwrlong zero,p_phase_chan 'indicated stopped
wait rdlong pha,p_phase_chan wz'get the new phase valueif_zjmp #wait 'wait for a valid phase valuejmp #sync 'sync with other cogs
p_phase_init long$0'pointer to initial phase value parameter
p_phase_chan long$0'pointer to new phase change value parameter
p_phase_sync long$0'pointer to clock sync value parameter
p_phase_accu long$0'pointer to phase accumulator value (passed back) parameter
zero long$0
dirmask long$00_ff_00_ff
sin0 long$00_ff_00_80
exitmask long$01_00_00_00
syn long$0
pha long$0
acc long$0
tmp long$0
teststopped long$00_aa_00_00
testpha long30006
testout long$00_72_00_00
Note: this code is experimental. I've only done a bit of testing but it seems to work!
The -con- part of the op code of all the table entrys in 0000 the whole table is a bunch of nop's.
Correct. That was the intended message
As for your rdlong aversion, your loop will lock nicely to a 3 hub window grid (48 cycles, 8+7*4 aligned to 16n). Only the first rdlong will suffer from jitter depending on where you've been. That said, if you change your code like this (table omitted):
movdira, PinMsk 'LSB to PA0, LSB to PA7
:loop rdlong M_,par'Get Freq Control Valueadd Acc, M_ 'M $1FF max if literal with #$xxxror Acc, #16'Postion indexmovs :inline, Acc 'Store 9-bit indexandn :inline, #%1_00000000'Clamp to 8-bitsrol Acc, #16'Restore accumulator
:inline movouta, 0-0'Get long value from tablejmp #:loop 'Loop again
even the first rdlong is properly aligned. The first instruction of a cog is -4 cycles away from its hub-window, the table consists of 256 nops which can be ignored in terms of hub-window lock (256*4 = 16*64). Which means that the mov dira, PinMsk is also at -4 placing the rdlong at +0. So no jitter involved here. FWIW, it's 8..23 (8 + 0..15) cycles.
@Tom: FWIW, here is a 2 hub window version (table omitted). The original code just missed it by 4 cycles which demanded closer inspection. As the accumulator update is placed in the blind slot it requires a separate setup sequence before the loop (similar to my [post=896415]counter version[/post], phsx sampling).
Cool DDS. It is amazing to me the way things on this forum always improve themselves just by existing. Are we back in the 80s (figuring out the best way to do everything, and pushing the limits)? It sure feels like it and I really enjoy this.
I haven't actually built the circuit yet but am just drawing the schematic.
Wow, I have always figured out the theory, done the math, wrote a connection+components list, built the test circuit, and then (once it is working) drawn the schematic for my circuits.
@ Kuroneko
Thank's for the ideas. I was busy this weekend with Taxes but I tried your 3-hub version and
had good results. With and without testing for pin 8 as a sync signal.
When I tried your latest 2 hub version today my output frequency dropped from in the 10Khz range all the way down to 100Hz range.
I also was contemplating how you figure out what and where things are happening in the hub timing.
Still thinking on that , a good learning exercise.
I attached both 3hub and 2hub versions , the main spin code calls ChangeFreq in a loop I atached
the 3hub version for reference. The filename is incrementing as I experiment.
@David
Glad you liked the thread, this thread and the one on the AD9833 DDS chip were going good last year around this time.
When I tried your latest 2 hub version today my output frequency dropped from in the 10Khz range all the way down to 100Hz range.
Note that the tuning word is affected by loop length and accumulator size. So for the 3 hub window version you need $18937 (10kHz). The 2 hub window version uses a 32bit accumulator, i.e. tuning value for 10kHz is $10624DD. If you're happy with a 24bit accumulator then multiply the (24bit) tuning word by 256 before passing it to the DDS cog. HTH
Also, the start method should pass M instead of a hard-wired constant to the DDS cog (affects both implementations).
@ Kuroneko
I should have answered back sooner, sorry.
Your values work, I missed the switch to a 32 bit accumulator in your last version. I just copyed the code in and tested it.
My hard coded constants are just me playing around with values as I try things.
Other than watching it sweep back and forth I have been working on a Delphi App to send it values and do the tuning value
calculation. Not on the fly for sweep values but start, stop freq and fixed freq etc.
Comments
dds.spin:
{{ ***************************************** * * * Author: Ian Mitchell * ***************************************** }} { Revision History: Version 1.0 - original file created } con _CLKMODE = XTAL1 + PLL16X _XINFREQ = 5_000_000 var long frequency obj ' DDS : "DDS1_0.1" ' DDS : "DDS4_0.1" DDS : "DDS7_0.2" ss : "Simple_Serial" ' pst : "Parallax Serial Terminal" ' Serial communication object pub main 'dira[16..23]~~ 'Set pins to outputs 'outa[16] := 1 ' pst.start(9600) '' Initialize serial communication to the PC through the USB connector ' repeat 100 ' pst.Str(String("Testing one two three, one two three...")) ' pst.NewLine ' waitcnt(clkfreq*5+cnt) ' repeat 2 ' ss.init(31,30,9600) ' ss.str(String("Testing one two three, one two three...")) ' ss.tx($0d) ' ss.dec(clkfreq) ' ss.tx($0d) DDS.start(3_999_000) ' DDS.start(3_123_000) waitcnt(clkfreq*3+cnt) repeat repeat waitcnt(clkfreq*3+cnt) DDS.setfrequency(4_123_000) waitcnt(clkfreq*3+cnt) DDS.setfrequency(2_123_000) waitcnt(clkfreq*3+cnt) DDS.setfrequency(2_000_100) waitcnt(clkfreq*3+cnt) DDS.setfrequency(1_123_000) repeat 'loop forever to keep cog alive dat {{ ┌──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ │ TERMS OF USE: MIT License │ ├──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤ │Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation │ │files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, │ │modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software│ │is furnished to do so, subject to the following conditions: │ │ │ │The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.│ │ │ │THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE │ │WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR │ │COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, │ │ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. │ └──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ }}
DDS7_0.2.spin
{{ 1 0 (init to base_phase*0) 2 1000 (init to base_phase*1) 3 2000 (init to base_phase*2) 4 3000 (init to base_phase*3) 5 4000 (init to base_phase*4) 6 5000 (init to base_phase*5) 7 6000 (init to base_phase*6) 1 7000 (add base_phase*7) 2 8000 (add base_phase*7) 3 9000 (add base_phase*7) 4 10000 (add base_phase*7) 5 11000 (add base_phase*7) 6 12000 (add base_phase*7) 7 13000 (add base_phase*7) 1 14000 (add base_phase*7) 2 15000 (add base_phase*7) 3 16000 (add base_phase*7) 4 17000 (add base_phase*7) 5 6 7 1 2 3 4 5 6 7 }} con dds_clock = 20_000_000 var long phase_init_1 'initial phase value long phase_chan_1 'new phase change value long phase_sync_1 'clock sync value long phase_accu_1 'phase accumulator value (passed back) long phase_init_2 'initial phase value long phase_chan_2 'new phase value long phase_sync_2 'clock sync value long phase_accu_2 'phase accumulator value (passed back) long phase_init_3 'initial phase value long phase_chan_3 'new phase value long phase_sync_3 'clock sync value long phase_accu_3 'phase accumulator value (passed back) long phase_init_4 'initial phase value long phase_chan_4 'new phase value long phase_sync_4 'clock sync value long phase_accu_4 'phase accumulator value (passed back) long phase_init_5 'initial phase value long phase_chan_5 'new phase value long phase_sync_5 'clock sync value long phase_accu_5 'phase accumulator value (passed back) long phase_init_6 'initial phase value long phase_chan_6 'new phase value long phase_sync_6 'clock sync value long phase_accu_6 'phase accumulator value (passed back) long phase_init_7 'initial phase value long phase_chan_7 'new phase value long phase_sync_7 'clock sync value long phase_accu_7 'phase accumulator value (passed back) obj ss : "Simple_Serial" pub start(frequency) | phase,syncval dira[24]~~ outa[24] := 0 phase := fraction(frequency,dds_clock) {{ ss.init(31,30,9600) ss.dec(phase) ss.tx($0d) }} phase_init_1 := phase*1 phase_init_2 := phase*2 phase_init_3 := phase*3 phase_init_4 := phase*4 phase_init_5 := phase*5 phase_init_6 := phase*6 phase_init_7 := phase*7 phase *= 7 phase_chan_1 := phase phase_chan_2 := phase phase_chan_3 := phase phase_chan_4 := phase phase_chan_5 := phase phase_chan_6 := phase phase_chan_7 := phase {{ ss.str(String("phase_init_1: ")) ss.dec(phase_init_1) ss.tx($0d) ss.str(String("phase_init_2: ")) ss.dec(phase_init_2) ss.tx($0d) ss.str(String("phase_init_3: ")) ss.dec(phase_init_3) ss.tx($0d) ss.str(String("phase_init_4: ")) ss.dec(phase_init_4) ss.tx($0d) ss.str(String("phase_init_5: ")) ss.dec(phase_init_5) ss.tx($0d) ss.str(String("phase_init_6: ")) ss.dec(phase_init_6) ss.tx($0d) ss.str(String("phase_init_7: ")) ss.dec(phase_init_7) ss.tx($0d) }} syncval := 800_000+cnt '10ms into the future phase_sync_1 := syncval+4*0 phase_sync_2 := syncval+4*1 phase_sync_3 := syncval+4*2 phase_sync_4 := syncval+4*3 phase_sync_5 := syncval+4*4 phase_sync_6 := syncval+4*5 phase_sync_7 := syncval+4*6 cognew(@ddsload,@phase_init_1) cognew(@ddsload,@phase_init_2) cognew(@ddsload,@phase_init_3) cognew(@ddsload,@phase_init_4) cognew(@ddsload,@phase_init_5) cognew(@ddsload,@phase_init_6) cognew(@ddsload,@phase_init_7) pub setfrequency(frequency) | newphase,syncval,t1,t2 newphase := fraction(frequency,dds_clock) 'flag new frequency outa[24] := 1 'wait for notification from each cog repeat until phase_chan_1==0 repeat until phase_chan_2==0 repeat until phase_chan_3==0 repeat until phase_chan_4==0 repeat until phase_chan_5==0 repeat until phase_chan_6==0 repeat until phase_chan_7==0 'reset the flag outa[24] := 0 'find the largest accumulator value 'set initial phase phase_init_1 := newphase*1 phase_init_2 := newphase*2 phase_init_3 := newphase*3 phase_init_4 := newphase*4 phase_init_5 := newphase*5 phase_init_6 := newphase*6 phase_init_7 := newphase*7 t1 := cnt 'sync the cogs syncval := 80_000+cnt '1ms into the future phase_sync_1 := syncval+4*0 phase_sync_2 := syncval+4*1 phase_sync_3 := syncval+4*2 phase_sync_4 := syncval+4*3 phase_sync_5 := syncval+4*4 phase_sync_6 := syncval+4*5 phase_sync_7 := syncval+4*6 'set the new phase change newphase *= 7 phase_chan_1 := newphase phase_chan_2 := newphase phase_chan_3 := newphase phase_chan_4 := newphase phase_chan_5 := newphase phase_chan_6 := newphase phase_chan_7 := newphase t2 := cnt ss.dec(t2-t1) ss.tx($0d) pri fraction(a,b) : f 'division of (a/b)*2^32 a <<= 1 repeat 32 f <<= 1 if a => b a -= b f++ a <<= 1 dat org 0 ddsload jmp #ddsstart ' mov dira,testdir ' mov outa,testout 'stop jmp #stop 'long $00_ff_00_80 long $00_ff_00_83 long $00_ff_00_86 long $00_ff_00_89 long $00_ff_00_8c long $00_fe_00_8f long $00_fe_00_92 long $00_fd_00_95 long $00_fd_00_99 long $00_fc_00_9c long $00_fb_00_9f long $00_fb_00_a2 long $00_fa_00_a5 long $00_f9_00_a8 long $00_f8_00_ab long $00_f7_00_ae long $00_f5_00_b1 long $00_f4_00_b4 long $00_f3_00_b6 long $00_f1_00_b9 long $00_f0_00_bc long $00_ee_00_bf long $00_ed_00_c2 long $00_eb_00_c4 long $00_e9_00_c7 long $00_e8_00_c9 long $00_e6_00_cc long $00_e4_00_cf long $00_e2_00_d1 long $00_e0_00_d3 long $00_de_00_d6 long $00_db_00_d8 long $00_d9_00_da long $00_d7_00_dc long $00_d5_00_df long $00_d2_00_e1 long $00_d0_00_e3 long $00_cd_00_e5 long $00_cb_00_e7 long $00_c8_00_e8 long $00_c6_00_ea long $00_c3_00_ec long $00_c0_00_ee long $00_bd_00_ef long $00_bb_00_f1 long $00_b8_00_f2 long $00_b5_00_f3 long $00_b2_00_f5 long $00_af_00_f6 long $00_ac_00_f7 long $00_a9_00_f8 long $00_a6_00_f9 long $00_a3_00_fa long $00_a0_00_fb long $00_9d_00_fc long $00_9a_00_fd long $00_97_00_fd long $00_94_00_fe long $00_91_00_fe long $00_8e_00_ff long $00_8b_00_ff long $00_87_00_ff long $00_84_00_ff long $00_81_00_ff long $00_7e_00_ff long $00_7b_00_ff long $00_78_00_ff long $00_74_00_ff long $00_71_00_ff long $00_6e_00_fe long $00_6b_00_fe long $00_68_00_fd long $00_65_00_fd long $00_62_00_fc long $00_5f_00_fb long $00_5c_00_fb long $00_59_00_fa long $00_56_00_f9 long $00_53_00_f8 long $00_50_00_f7 long $00_4d_00_f5 long $00_4a_00_f4 long $00_47_00_f3 long $00_44_00_f1 long $00_42_00_f0 long $00_3f_00_ee long $00_3c_00_ed long $00_39_00_eb long $00_37_00_e9 long $00_34_00_e8 long $00_32_00_e6 long $00_2f_00_e4 long $00_2d_00_e2 long $00_2a_00_e0 long $00_28_00_de long $00_26_00_db long $00_24_00_d9 long $00_21_00_d7 long $00_1f_00_d5 long $00_1d_00_d2 long $00_1b_00_d0 long $00_19_00_cd long $00_17_00_cb long $00_16_00_c8 long $00_14_00_c6 long $00_12_00_c3 long $00_11_00_c0 long $00_0f_00_bd long $00_0e_00_bb long $00_0c_00_b8 long $00_0b_00_b5 long $00_0a_00_b2 long $00_08_00_af long $00_07_00_ac long $00_06_00_a9 long $00_05_00_a6 long $00_04_00_a3 long $00_04_00_a0 long $00_03_00_9d long $00_02_00_9a long $00_02_00_97 long $00_01_00_94 long $00_01_00_91 long $00_00_00_8e long $00_00_00_8b long $00_00_00_87 long $00_00_00_84 long $00_00_00_81 long $00_00_00_7e long $00_00_00_7b long $00_00_00_78 long $00_00_00_74 long $00_00_00_71 long $00_01_00_6e long $00_01_00_6b long $00_02_00_68 long $00_02_00_65 long $00_03_00_62 long $00_04_00_5f long $00_05_00_5c long $00_06_00_59 long $00_07_00_56 long $00_08_00_53 long $00_09_00_50 long $00_0a_00_4d long $00_0c_00_4a long $00_0d_00_47 long $00_0e_00_44 long $00_10_00_42 long $00_11_00_3f long $00_13_00_3c long $00_15_00_39 long $00_17_00_37 long $00_18_00_34 long $00_1a_00_32 long $00_1c_00_2f long $00_1e_00_2d long $00_20_00_2a long $00_23_00_28 long $00_25_00_26 long $00_27_00_24 long $00_29_00_21 long $00_2c_00_1f long $00_2e_00_1d long $00_30_00_1b long $00_33_00_19 long $00_36_00_17 long $00_38_00_16 long $00_3b_00_14 long $00_3d_00_12 long $00_40_00_11 long $00_43_00_0f long $00_46_00_0e long $00_49_00_0c long $00_4b_00_0b long $00_4e_00_0a long $00_51_00_08 long $00_54_00_07 long $00_57_00_06 long $00_5a_00_05 long $00_5d_00_04 long $00_60_00_04 long $00_63_00_03 long $00_66_00_02 long $00_6a_00_02 long $00_6d_00_01 long $00_70_00_01 long $00_73_00_00 long $00_76_00_00 long $00_79_00_00 long $00_7c_00_00 long $00_7f_00_00 long $00_80_00_00 long $00_83_00_00 long $00_86_00_00 long $00_89_00_00 long $00_8c_00_00 long $00_8f_00_01 long $00_92_00_01 long $00_95_00_02 long $00_99_00_02 long $00_9c_00_03 long $00_9f_00_04 long $00_a2_00_05 long $00_a5_00_06 long $00_a8_00_07 long $00_ab_00_08 long $00_ae_00_09 long $00_b1_00_0a long $00_b4_00_0c long $00_b6_00_0d long $00_b9_00_0e long $00_bc_00_10 long $00_bf_00_11 long $00_c2_00_13 long $00_c4_00_15 long $00_c7_00_17 long $00_c9_00_18 long $00_cc_00_1a long $00_cf_00_1c long $00_d1_00_1e long $00_d3_00_20 long $00_d6_00_23 long $00_d8_00_25 long $00_da_00_27 long $00_dc_00_29 long $00_df_00_2c long $00_e1_00_2e long $00_e3_00_30 long $00_e5_00_33 long $00_e7_00_36 long $00_e8_00_38 long $00_ea_00_3b long $00_ec_00_3d long $00_ee_00_40 long $00_ef_00_43 long $00_f1_00_46 long $00_f2_00_49 long $00_f3_00_4b long $00_f5_00_4e long $00_f6_00_51 long $00_f7_00_54 long $00_f8_00_57 long $00_f9_00_5a long $00_fa_00_5d long $00_fb_00_60 long $00_fc_00_63 long $00_fd_00_66 long $00_fd_00_6a long $00_fe_00_6d long $00_fe_00_70 long $00_ff_00_73 long $00_ff_00_76 long $00_ff_00_79 long $00_ff_00_7c long $00_ff_00_7f ddsstart or dira,dirmask 'set group of 8 pins to output mov 0,sin0 'restore first element of sine table mov p_phase_init,par 'set pointer to phase init parameter mov p_phase_chan,par 'set pointer to phase chan parameter -4 mov p_phase_sync,par 'set pointer to phase sync parameter -8 mov p_phase_accu,par 'set pointer to phase accu parameter -12 add p_phase_chan,#4 'adjust to correct location add p_phase_sync,#8 'adjust to correct location add p_phase_accu,#12 'adjust to correct location sync rdlong acc,p_phase_init 'set accumulator to initial phase value rdlong pha,p_phase_chan 'set the phase value rdlong syn,p_phase_sync 'set the sync value waitcnt syn,#0 'sync with other cogs loop mov tmp,acc 'need to change acc so copy it shr tmp,#24 'get the high order byte movs sin1,tmp 'index into sine table add acc,pha 'add phase to accumulator sin1 mov outa,0-0 'output sine value mov outa,#0 'clear for next cog testn exitmask,ina wz 'test for new frequency mov tmp,acc 'need to change acc so copy it shr tmp,#24 'get the high order byte movs sin2,tmp 'index into sine table add acc,pha 'add phase to accumulator sin2 mov outa,0-0 'output sine value mov outa,#0 'clear for next cog if_nz jmp #loop 'carry on, unless frequency changed wrlong zero,p_phase_chan 'indicated stopped wait rdlong pha,p_phase_chan wz 'get the new phase value if_z jmp #wait 'wait for a valid phase value jmp #sync 'sync with other cogs p_phase_init long $0 'pointer to initial phase value parameter p_phase_chan long $0 'pointer to new phase change value parameter p_phase_sync long $0 'pointer to clock sync value parameter p_phase_accu long $0 'pointer to phase accumulator value (passed back) parameter zero long $0 dirmask long $00_ff_00_ff sin0 long $00_ff_00_80 exitmask long $01_00_00_00 syn long $0 pha long $0 acc long $0 tmp long $0 teststopped long $00_aa_00_00 testpha long 30006 testout long $00_72_00_00
Note: this code is experimental. I've only done a bit of testing but it seems to work!
:-)
As for your rdlong aversion, your loop will lock nicely to a 3 hub window grid (48 cycles, 8+7*4 aligned to 16n). Only the first rdlong will suffer from jitter depending on where you've been. That said, if you change your code like this (table omitted):
mov dira, PinMsk 'LSB to PA0, LSB to PA7 :loop rdlong M_,par 'Get Freq Control Value add Acc, M_ 'M $1FF max if literal with #$xxx ror Acc, #16 'Postion index movs :inline, Acc 'Store 9-bit index andn :inline, #%1_00000000 'Clamp to 8-bits rol Acc, #16 'Restore accumulator :inline mov outa, 0-0 'Get long value from table jmp #:loop 'Loop again
even the first rdlong is properly aligned. The first instruction of a cog is -4 cycles away from its hub-window, the table consists of 256 nops which can be ignored in terms of hub-window lock (256*4 = 16*64). Which means that the mov dira, PinMsk is also at -4 placing the rdlong at +0. So no jitter involved here. FWIW, it's 8..23 (8 + 0..15) cycles.Thank's for the info, I will give it a try.
A learning lesson here also
Thank's
Tom
mov dira, mask ' -4 rdlong tuning, par ' +0 = initial read [COLOR="blue"]add accu, tuning[/COLOR] ' +8 prime accumulator :loop mov temp, accu ' -4 get private copy rdlong tuning, par ' +0 = update tuning word shr temp, #24 ' +8 extract index movs :inline, temp ' -4 implant index [COLOR="blue"]add accu, tuning[/COLOR] ' +0 = update accumulator :inline mov outa, 0-0 ' +4 jmp #:loop ' +8 mask long $FF accu long 0 tuning res 1 temp res 1
Wow, I have always figured out the theory, done the math, wrote a connection+components list, built the test circuit, and then (once it is working) drawn the schematic for my circuits.
Thank's for the ideas. I was busy this weekend with Taxes but I tried your 3-hub version and
had good results. With and without testing for pin 8 as a sync signal.
When I tried your latest 2 hub version today my output frequency dropped from in the 10Khz range all the way down to 100Hz range.
I also was contemplating how you figure out what and where things are happening in the hub timing.
Still thinking on that , a good learning exercise.
I attached both 3hub and 2hub versions , the main spin code calls ChangeFreq in a loop I atached
the 3hub version for reference. The filename is incrementing as I experiment.
@David
Glad you liked the thread, this thread and the one on the AD9833 DDS chip were going good last year around this time.
Tom
Also, the start method should pass M instead of a hard-wired constant to the DDS cog (affects both implementations).
I should have answered back sooner, sorry.
Your values work, I missed the switch to a 32 bit accumulator in your last version. I just copyed the code in and tested it.
My hard coded constants are just me playing around with values as I try things.
Other than watching it sweep back and forth I have been working on a Delphi App to send it values and do the tuning value
calculation. Not on the fly for sweep values but start, stop freq and fixed freq etc.
Thank's
Tom