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
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.
If 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).
Then, 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):
Andy
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:
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