Fast Quadrature Encoder
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.
PUB Main {Launch cog to toggle P16 endlessly} dira[noparse][[/noparse]16..18]~ 'Set I/O pin to output direction cognew(@Toggle, 0) 'Launch new cog DAT {Toggle P16} org 0 'Begin at Cog RAM addr 0 Toggle mov dira, Pin18 'Set Pin to output :loop mov outa, %1001 add Counter, #1 mov outa, %0101 add Counter, #1 mov outa, %0110 add Counter, #1 mov outa, %1010 jmp #:loop 'Loop endlessly Pin18 long %11110000000000000000'|< 18 'Pin number Time res 1 'System Counter Workspace Counter long 0I'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
VAR long pause_counts byte quad_cog PUB start stop set_Hz( 83_565 ) quad_cog := cognew( @quad_entry, @pause_counts ) + 1 PUB stop if quad_cog cogstop( quad_cog~ - 1 ) PUB set_Hz( Hz ) ' the update rate is 4x faster than the frequency pause_counts := ((clkfreq >> 2) + (Hz >> 1)) / Hz DAT ORG 0 'Begin at Cog RAM addr 0 {{ This will be run in its own cog, meaning: - we need our own copy of dira - we get our own copy of outa - I need to get the frequency info from the Hub RAM (address is in the PAR register) }} quad_entry mov outa,all_quad_vals_twice mov dira,pin_mask mov timestamp,#511 add timestamp,cnt loop_forever rdlong delay_counts,par waitcnt timestamp,delay_counts rol outa,#4 jmp loop_forever {===== PASM constants and parameters =====} pin_mask long %1111 << 16 all_quad_vals_twice long %1001_0101_0110_1010____1001_0101_0110_1010 {===== PASM scratch variables =====} ' Remember, all RES variables _MUST_ come after all LONG variables delay_counts res 1 timestamp res 1 ' make sure this whole thing fits inside a single cog FIT 496You 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?