Fast Quadrature Encoder
Carlos D. Lopez
Posts: 9
Hi,
I'm trying to create a Quadrature signal for a A pulse frequency of 83.565 kHz.
Here is the code for what I'm trying to do. I have a pulse signal on the Pin 20, for each pulse, I modify the pins[noparse][[/noparse]16..19] to look like a quadrate signal, where Pin[noparse][[/noparse]16]= A, Pin[noparse][[/noparse]17]= -A, Pin[noparse][[/noparse]18] = B (phased 90 degrees), and Pin[noparse][[/noparse]19] = -B.
My problem is that the waitcnt command has a limit for the "Delay" value of 381. Is there away around this so that I can generate a pulse signal of 334 Khz?
thanks
Carlos Lopez
I'm trying to create a Quadrature signal for a A pulse frequency of 83.565 kHz.
Here is the code for what I'm trying to do. I have a pulse signal on the Pin 20, for each pulse, I modify the pins[noparse][[/noparse]16..19] to look like a quadrate signal, where Pin[noparse][[/noparse]16]= A, Pin[noparse][[/noparse]17]= -A, Pin[noparse][[/noparse]18] = B (phased 90 degrees), and Pin[noparse][[/noparse]19] = -B.
{{Output.spin Toggles two pins, one after another.}} VAR byte myCounter byte myPulse PUB Main Toggle(clkfreq/31_100) 'Toggle P16 ten times, 1/4 s each PUB Toggle(Delay)| Time {{Toggle Pin, Count times with Delay clock cycles in between.}} dira[noparse][[/noparse]16..20]~~ 'Set I/O pin to output direction Time:=cnt repeat 'Repeat for Count iterations waitcnt(Delay + cnt) ' Wait for Delay cycles !myPulse outa[noparse][[/noparse]20]:=myPulse if myPulse <> 0 case myCounter 0:outa[noparse][[/noparse]16..19] := %1001 ' Toggle I/O Pin 1:outa[noparse][[/noparse]16..19] := %0101 ' Toggle I/O Pin 2:outa[noparse][[/noparse]16..19] := %0110 ' Toggle I/O Pin 3:outa[noparse][[/noparse]16..19] := %1010 ' Toggle I/O Pin myCounter++ if myCounter>3 myCounter:=0
My problem is that the waitcnt command has a limit for the "Delay" value of 381. Is there away around this so that I can generate a pulse signal of 334 Khz?
thanks
Carlos Lopez
Comments
I'm not an expert on spin timing, but I don't think that loop (in SPIN at least) is going to go around fast enough for you to generate 334 kHz. Just try running without your delay and see what frequency you get out
The good news, however is that two counters can be set up to do quadrature in the background for you. They can also do the inverted -A and -B signals if you want them. It works best (no jitter) with dividing by powers of two, so if you have a 5Mhz crystal and your prop is running at 80 Mhz, you can easily derive 78.125 khz (divide by 80 Mhz by 1024).
Let us know how you decide to proceed and I'm sure we can give you a little help, if needed.
Jonathan
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
lonesock
Piranha are people too.
the higher bit, which you save before doing the XOR and output both at the same time.
Getting the last 2 phases should be obvious.
This is another code that I tried just to see how fast I could make it go.
I'm creating a delay by adding the add counter command. Also with this code, for some reason I'm not getting pin 18 to respond to change, it is copying from pin 19, which does not happen with the original spin code I had.
The Period of the signal that I'm getting is around 3us (micro), around 333kHz.
How can I change this code so that I can get the desired frequency, 83.565kHz, and I need this to be programmable in the sense that I need to change the frequency, this being the fastest.
83.565 kHz - 80 ft/min
73.119 kHz - 70 ft/min
62.673 kHz - 60 ft/min
- 50 ft/min
- 40 ft/min
- 30 ft/min
- 20 ft/min
- 10 ft/min
Is it possible to interface this with another programming language, VBA or C++ or something external to the Propeller tool?
Thanks.
Rather than mov into outa you should or with outa, so
Would set bits 0 and 3 high but that is not quite what you want. You could put the 1001 in a variable and shift it left:
This would set the bit defined by pin high as well as the bit three above it. This can be done before the loop.
To change the frequency you would need to add one or many waitcnts in the loop, there delay would be set by getting a variable from hub ram (using rdlong). Alternatively your main program could set one of the pins oscillating at the required frequency using a counter module. Then this cog could use the waitpne type instructions changing state when the pin pulsed. The main program could then easy change the frequency simply by changing FRQA.
You can communicate to a PC through serial via the same lead you program the device through.
Graham
You can update the frequency by calling the set_Hz function, once you've called start. This works since it's running in its own cog, you have your own outa register, so you can store all the patterns you want, and just rotate them "through" the window of output bits set in dira.
Jonathan
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
lonesock
Piranha are people too.
Why is the initial timestamp = #511?
And what about specifying the frequency parameter from another external program? using VBA or C++?
Thanks for your help.
The initial 511 is added to the current cnt value, so I'm just making sure it starts some time in the future (it should be at least 27, 22 max for the rdlong, and 5 for the waitcnt, but 511 is extra safe, and really doesn't take much time (511/80e6 seconds) once at cog-load. I do it in the order set offset, then add cnt because that way the cnt value is the least stale possible.
You could use another program on the PC to specify the frequency. I would send down the frequency over a serial port (look into Full Duplex Serial, a.k.a. FDS). This would require you parsing the serial data, then calling the set_Hz function. Serial communication under unextended C++ may be a bit difficult. I've never tried under VBA. You can do it fairly easily under VB.net 2008, and there's a free Express Edition available.
Finally, this method will not give you the _exact_ frequency you need...if you end up needing more precision, we could use counters, but those are a bit harder to explain...I'd save that for rev 2, if this works for you.
Jonathan
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
lonesock
Piranha are people too.
1. He puts two copies of the set of quads into the outa register and then uses rol to scroll through them.
outa:
1001_0101_0110_1010____1001_0101_0110_1010
rol outa,#4
outa now:
0101_0110_1010____1001_0101_0110_1010_1001_
So the next set of values will be on your output pins.
2. Initial time stamp of 511 to provide some time in which to read the actual delay time from hub memory the very first time.
3. I suggested using serial via the USB programming link, you can get serial objects for VBA and C++
If this were the program that called the code posted previously:
Would these need to be loaded the EEPROM instead of RAM?
I have Visual Studio.NET 2005, so I could use vb.net or c#. But how would you send the frequency parameter?