Question about signal generation
Reinhard
Posts: 489
Hello Forumists
I need 2 signals with 90 degree phase shift, generated by the Propeller.
I know the logic circuit with 2 JK-FF in feedback loop, but I do not want external components.
Further I do not like a software solution like this:
while(1)
{
high(PINA);
usleep(dt);
high(PINB);
usleep(dt);
low(PINA);
usleep(dt);
low(PINB);
usleep(dt);
}
So I can make two signals with maximal 250kHz.
But I need a cog for this job;
My question is, is it possible with tricky usage of counters, with set and forget ?
The range is 10 .. 20 kHz.
Thanks for advices ;-)
Reinhard
I need 2 signals with 90 degree phase shift, generated by the Propeller.
I know the logic circuit with 2 JK-FF in feedback loop, but I do not want external components.
Further I do not like a software solution like this:
while(1)
{
high(PINA);
usleep(dt);
high(PINB);
usleep(dt);
low(PINA);
usleep(dt);
low(PINB);
usleep(dt);
}
So I can make two signals with maximal 250kHz.
But I need a cog for this job;
My question is, is it possible with tricky usage of counters, with set and forget ?
The range is 10 .. 20 kHz.
Thanks for advices ;-)
Reinhard

Comments
It should be easy to generate two signals with the same frequency but 90° shifted with two Propeller counters.
Just set them to the same frequency and before you start the counters set PHSA to 0 and PHSB to 0x40000000.
(360° is the full 2^32 range of the counter, so 90° is 1/4 = 0x40000000).
If PropGCC allows to use the counter registers directly then a possible code can look like this: You will need to replace the values in < > with numbers or variables.
The FRQx calculation is simplified but the error is under 1% with this methode.
Andy
this is exact what I need.
Thank you
What I forget: You also need to set the pins to output in the DIRA register, otherwise the counters will not output the signals.
Andy
-Phil
Thank you for the hint
with a small C snippet I can determine this little
/** * This is the main TwoPhase90Degree program file. * produce 2 signals with 90 Degree Phase difference */ #include "simpletools.h" #define phase1 16 #define phase2 17 #define f 1 int main () { DIRA |= 1<<phase1; DIRA |= 1<<phase2; PHSA = 0; PHSB = 0x40000000 + 0x4020; FRQA = 54 * f; // for 80MHz Clock FRQB = FRQA; CTRA = (4<<26) + phase1; // NCO 0 degree CTRB = (4<<26) + phase2; // NCO 90 degree while(1) { printf("%8X : %8X : %8X\n",PHSA,PHSB,PHSB-PHSA); } }the diff is always 0x40000000 ;-))
@Andy
Thank's again for the code
Whatever you add to PHSB has to be multiplied by the value in FRQB to account for the overhead. Also, in your printf statement, PHSA and PHSB are not read simultaneously, so the result you see will be misleading.
The most reliable way to get true I and Q output is to do it in PASM, where the overheads are clearly defined and predictable.
-Phil
you are right.
for a certain frequency I adjust the value with an osci.
- be interesting to know what Prop-C 'fixup' offset is needed for PHSB, to give 90.00'
At 250KHz & 80MHz it is 320 clks per full period.
can you explain me the method with xor-gate and multimeter ?
phase1 xor phase2 give a signal with double frequency.
for example
...110011001100...
...011001100110...
...101010101010...
If the 90 degree shift exact, the duty cycle from new signal is 50%
with a multimeter I see Vcc/2
is it this what you mean ?
Thanks
Reinhard
Yes, and feed that thru a RC, just in case the AC disturbs the multimeter more sensitive ranges..
If you also wire other XOR gates as simple inv or non inv, and do the same RC they also should be 50.00%, and you can scale the meter to get an amplified zero with a differential reading.
180' span is Vcc sweep, so that gives ~ 20.625mV change per SysCLK step (12.5ns)
But my next <project> is (14 days Italy ;-)
Reinhard
Currently I have nether a multimeter nor an osci here.
So I use the stereo output from my DemoBoard, connect to the soundcard of my notebook
and write a short programm for display the two signals.
At moment this is very raw, but I go on to improve it.
CON _clkmode = xtal1 + pll16x _xinfreq = 5_000_000 IF_PIN = 24 QF_PIN = 25 TFRQ0 = $20c49b '40 kHz. VAR long testa, testb OBJ sio : "Parallax Serial Terminal" PUB start sio.start(115200) cognew(@quadrature, 0) cognew(@test_iq, @testa) repeat sio.dec(testa) sio.char(" ") sio.dec(testb) sio.char(13) waitcnt(cnt + clkfreq / 5) DAT '' Generate two square waves, 90 degrees out of phase (< 4 MHz). org 0 quadrature mov dira,q_dira0 mov frqa,q_freq mov frqb,q_freq mov phsa,#0 mov phsb,q_x40000000 add phsb,q_freq add phsb,q_freq add phsb,q_freq add phsb,q_freq mov ctra,q_ctra0 mov ctrb,q_ctrb0 :forever jmp #:forever '-----------[ Constants & Variables ]------------------------------------------ q_freq long TFRQ0 q_ctra0 long %00100 << 26 | IF_PIN q_ctrb0 long %00100 << 26 | QF_PIN q_dira0 long 1 << IF_PIN | 1 << QF_PIN q_x40000000 long $4000_0000 ''=================================================================== '' Test the 90-degree phase shift between I and Q: '' I:  '' Q:  '' A B C D A B C D '' CTRA counts times in states A and C. '' CTRB counts times in states B and D. '' With true quadrature output, the two counts will be equal. org 0 test_iq mov t_addra,par mov t_addrb,par add t_addrb,#4 mov ctra,t_ctra0 mov ctrb,t_ctrb0 waitpne t_imask,t_imask waitpeq t_imask,t_imask mov frqa,#1 mov frqb,#1 mov t_delay,cnt add t_delay,_80_000_000 test_lp waitcnt t_delay,_80_000_000 mov t_phsa,phsa mov t_phsb,phsb sub t_phsa,t_phsap add t_phsap,t_phsa sub t_phsb,t_phsbp add t_phsbp,t_phsb wrlong t_phsa,t_addra wrlong t_phsb,t_addrb jmp #test_lp t_ctra0 long %11001 << 26 | IF_PIN << 9 | QF_PIN t_ctrb0 long %10110 << 26 | IF_PIN << 9 | QF_PIN _80_000_000 long 80_000_000 t_phsap long 0 t_phsbp long 0 t_imask long 1 << QF_PIN t_addra res 1 t_addrb res 1 t_delay res 1 t_phsa res 1 t_phsb res 1If the phase shift is correct, the two numbers displayed will be approximately equal.
-Phil
And, would it be possible to generate more than 2 sync signals? I mean 3 or more signals with defined phase shifts using different cogs? I can create sync pairs using the same cog, but they are not synchronize with other pairs created using other cogs.
Many thanks in advance
You can not. The period of the waveform is 1/frequency, and to have a 90 degree phase shift the two signals have to be 1/4 of the period shifted from each other. For producing phase shifted signals in software I find it simpler to calculate the period from the frequency and use one fourth of that value for the timing.
Yes, that can be done if you synchronize the cogs when you start them.
When you modify & reload the frequency, in order to preserve phase you need to also reload the phase-offset
- ie that's 4 values updates for 2 counters running
There will always be some disturbance when you change values, but you could reduce that << 1us, with a pre-calculation of the 4 new values, then a simple 4 line copy.
If you want all COGs aligned on updates, then a shared trigger pin, or a global VAR for waitcnt can have all 'launch' at the same clock edge.
The trigger-step, should be done last, after any HUB reads.
I'm not sure if I understand the question properly? But, if you mean (as an example only) generate 3 signals on three different pins using 3 different cogs ... then, each one could wait for its linked cogs pin to change then apply a global 'wait' before toggling the next cogs output pin. Also, the duration of the pins 'active' state would have to be related to the wait time ... etc. Change the global 'delay' period and the freq changes ... but without disturbing the phase between them. This would need to be a PASM solution to reach 20KHz (I would think).
I/O pins ---> 7 8 9 │ │ │ ┌──┴───┐ ┌──┴───┐ ┌──┴───┐ │ │ │ │ │ │ │ 2 │ │ 3 │ │ 4 │ │ │ │ │ │ │ └──────┘ └──────┘ └──────┘ cog cog cog ┌────────────────────┐ │ Adjustable Delay │ └────────────────────┘ HUB Ram VariableThen, the only other issue would be if you want cog2 to retrigger at the end of cog4s' cycle ... or to trigger off another pin or event?
Anyway, you have plenty of suggestions now. And, if you don't mean what I described ... ignore post.
... Tim
DIRA |= 1<<phase3;
DIRA |= 1<<phase4;
PHSA = 0;
PHSB = 0x40000000 + (0x3620*f1);
FRQA = 54 * f1; // for 80MHz Clock
FRQB = FRQA;
waitcnt(t2); // t2= CNT + 1000;
CTRA = (4<<26) + phase3;
CTRB = (4<<26) + phase4;
In order to vary frequency I re-program FRQA, FRQB. Then, I have been trying to obtain the same difference between PSHB-PSHA that I get in the first programming. But I cant, I have tried using the same values, reading PSHA and adding 0x4000000 and some other combinations. Each update modifies a little bit the phase shift.
It can be accomplished by stopping the cog, modifying the freq and run the cog again, but I would like to modify it without stopping the cogs.
The following Assembler code does exactly the same as a counter in NCO mode, but three times and all 3 NCOs use the same FRQ register. So they update always to the same frequency at the same time (that is: in the same PASM loop). Therefore the phase shifts don't change when you change the frequency, and need to be set only once before the loop.
Here is the Spin+PASM code (just copy it into an empty Spin file):
'' Triple oscillator with adjustable phase offsets CON _clkmode = xtal1 + pll16x _xinfreq = 5_000_000 PINA = 16 'pin numbers PINB = 17 PINC = 18 VAR long freq PUB Main : i freq := 2577 * 100 '100 Hz cognew(@pasm,@freq) 'start oscillator cog repeat 'freq sweep repeat i from 100 to 1000 step 50 freq := 2577 * i waitcnt(clkfreq + cnt) DAT pasm mov dira,pin1 'set pins to output or dira,pin2 or dira,pin3 mov phs1,deg0 'set phase offsets mov phs2,deg1 mov phs3,deg2 loop rdlong frq,par 'read freq add phs1,frq '3 NCOs with same freq add phs2,frq add phs3,frq mov phs1,phs1 wc 'copy bit31 to pins muxc outa,pin1 mov phs2,phs2 wc muxc outa,pin2 mov phs3,phs3 wc muxc outa,pin3 jmp #loop '48cy = 1.67MHz fs pin1 long 1 << PINA pin2 long 1 << PINB pin3 long 1 << PINC deg0 long 11930464 * 0 'phase offsets in degree deg1 long 11930464 * 90 deg2 long 11930464 * 180 frq res 1 'variables phs1 res 1 phs2 res 1 phs3 res 1Andy
Thanks again
After several tries I might be missing something. I have set a piece code like I wrote here before.
DIRA |= 1<<pinA;
DIRA |= 1<<pinB;
PHSA = 0;
PHSB = 0x40000000 + (0x3620*freq);
FRQA = 54 * freq;
FRQB = FRQA;
waitcnt(t);
CTRA = (4<<26) + pinA; // NCO 0 degree
CTRB = (4<<26) + pinB; // NCO 90 degree
which give me 2 quadrature signals. However in order to modify the frequency I have added a pasm loop trying to follow your advice.
Well, I cannot keep the phase shift constant. If a use the following code I have 2 in-phase signals and the frequency varies wothout affecting the phase shift. However once I add something else to PSHB the phase shift varies in every frequency modification.
__asm__ __volatile__("mov PHSB, PHSA wc \n\t"
"mov FRQA, %0 wc \n\t"
"mov FRQB, FRQA wc \n\t"
: "=r" (out)
: "r" (fr_sent));
pause(2000);
freq=freq+50;
fr_sent=54 * freq;
Just an idea: If you do the frequency change in two equal steps, and change one time first FRQA and the other time first FRQB then the phase errors may be compensated. Something like that:
void setFreq(int freq) //freq in Hz { int mid; freq = 537 * freq / 10; //calc new FRQx value mid = (FRQA + freq) / 2; //middle between old and new FRQx value FRQA = mid; //set mid value A then B FRQB = mid; FRQB = freq; //set new value B then A FRQA = freq; }Andy
void setFreq(int freq) //freq in Hz
{
int mid; int out;
phs_b=0x40000000+ (0x1ec0*freq); //adjust phase
freq = 537 * freq / 10; //calc new FRQx value
mid = (FRQA + freq) / 2; //middle between old and new FRQx value
FRQA = mid; //set mid value A then B
FRQB = mid;
FRQB = freq; //set new value B then A
FRQA = freq;
//
Esto modifica la freq en ensamblador
__asm__ __volatile__("mov PHSB, PHSA wc \n\t"
"add PHSB, %0 wc \n\t"
: "=r" (out)
: "r" (phs_b));
}
A not that it matters as such - frqx being fn(freq) - it just seems more logical