(clkfreq/1_000_000 + cnt) and system clock frequency setting
Scott2Hot
Posts: 10
CON '_clkmode = xtal1 + pll2x 'Clock mode set for 10Mz. '_xinfreq = 5_000_000 'External oscillator frequency for precision timing. PB1 = 0 'Push button pin. Servo = 11 'Servo pin. Servo_C = 1500 'Servo center of 1.5ms. uS = (1_000_000) 'Value used to divide clock frequency into micro seconds. Period = 20_000 'Servo PWM offtime in uS. VAR long Servo_P 'Servo pulse. long Stack[noparse][[/noparse]50] 'Cog stack space. PUB Main Servo_P := Servo_C 'Make servo pulse equal to servo center position. COGNEW (Servo_Cog, @Stack[noparse][[/noparse]0]) 'Launch new cog to drive servo. dira[noparse][[/noparse]8] := 1 'Bi-color led output. dira[noparse][[/noparse]9] := 1 'Bi-color led output. Repeat outa[noparse][[/noparse]8] := 0 'Bi-color led is green. outa[noparse][[/noparse]9] := 1 Repeat until ina[noparse][[/noparse]PB1] == 1 'Wait until push button is pressed. outa[noparse][[/noparse]8] := 1 'Bi-Color led is red while running routine. outa[noparse][[/noparse]9] := 0 WAITCNT (clkfreq*1 + cnt) 'Wait one second after button pressed. Servo_P := 1000 'Send 1ms pulse to servo. WAITCNT (clkfreq*5 + cnt) 'Wait 5 seconds. Servo_P := 2000 'Send 2ms pulse to servo. WAITCNT (clkfreq*5 + cnt) 'Wait 5 seconds. Servo_P := Servo_C 'Set pulse for center position. PUB Servo_Cog 'New cog to refresh servo. dira[noparse][[/noparse]Servo] := 1 'Set servo pin to output. repeat outa[noparse][[/noparse]Servo] := 1 'Turn pulse on. waitcnt((clkfreq/1_000_000) * Servo_P + cnt) 'Servo pulse on time outa[noparse][[/noparse]Servo] := 0 'Turn pulse off. waitcnt((clkfreq/1_000_000) * Period + cnt) 'Servo pulse off time.
Okay so I finally pulled my PELabs kit out and started to try to learn how to use the prop in a project. I am trying to drive a servo motor and ran into a problem·I cannot solve. My program works good dividing the clkfreq by 1meg to create a 1 microsecond unit and then multiple it by the servo pulse I want in·microseconds plus the clock count with the standard internal 12Mhz clock. So 1_500 will equal 1.5 miliseconds to center a servo. This worked pretty good·until I tried to change the clock from internal to external for better resolution of time. I have commented·the clock frequency settings out in the code above in the constant block (10Mhz in this case). After changing the clock frequency, the timing of my variable "Servo_P"·has changed. My thought is that clkfreq divided by 1_000_000 should remain in microseconds no matter what the actual·frequency·is that·I use. This is not the case. Can somebody please·point me in the right direction to my mistake with clkfreq timing?·
Comments
If you are indeed interested in working on PWM in Spin, Andy Lindsay has a good section on timing techniques in the counters module in the Propeller Education Kit Fundamentals PDF which is also available for free download from Parallax.
One additional note: be careful of the current requirements of your servo when using the propeller education kit. If your servo draws too much current, it will brown out the propeller, which will then reset, which will then start the servo again, which will brown out... Don't ask me how I know this... If you have a large servo, use a separate power source for it, and tie the ground of it to the prop board. The signal itself draws very little current.
Good luck with your project
Dave
In your repeat loop you do a lot of stuff:
1. repeat instruction
2. you set the output
3. you calculate for which cnt to wait for with 1 division, 1 multiplication and one addition
4. do the same as in 2./3. for the pause and go back to step 1
So, when you decrease the clock frequency all this needs longer. Decreasing clock frequency by ~2% means the code will be ~2% slower. You should do the calculation of (clkfreq/1_000_000)*servo_P outside of the Servo_Cog. And use a cntwait-variable instead of adding cnt everytime. This will increase accuracy. (This is described in the Education Lab)
This way the runtime of instructions between the out-instructions are not added to the wait-time.
Maybe this helps.
I wanted to use the Servo32V7 object but could not figure out how to use it to control my servo. If you know where to find a simple·example of how to use Servo32V7,·please let me know.
Thank you!
This is an adaptation of one of the programs in the counters app note (AN001) -- you can extend it to two servos if you need. I've attached a screen cap of the output; you can see that it refreshes right on 20ms using a synchronized waitcnt in the repeat loop. The position pulse is precise because the counter is doing the hard work setting the output.
Going beyond two servos, you'll need to do it differently. Since you're already launching a another cog, you could use one of the servo objects in ObEx. Dare I say... this one's pretty good:
-- obex.parallax.com/objects/445/
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Jon McPhalen
Hollywood, CA
Post Edited (JonnyMac) : 2/3/2010 4:53:23 PM GMT
If you work with a variable like I did and you did, the time difference comeing from instruction overhead is zero! Only the first time I clear the output the time may vary, but that's why I've choosen to have the first outa being a clear-bit instruction.
Let's say we are in the middle of generation:
the first waitcnt waits for 20ms. The output will be set to·1 at t1 = 20ms + dt1 (some runtime for returning from waitcnt and outa instruction)
the second waitcnt waits for 1.5ms. The output will be set to·0 at t2 = 20ms + 1.5ms + dt2 (some runtime for return&outa)
Where is dt1? It dissappeared because we calculate t (in your case and cntwait in my case) continuously adding either 20ms or 1.5ms.
Now let's have a look at the instructions - and remember, the propeller is totally deterministic. So, the return time from waitcnt and the out instructions will definitely need the same time in both cases. (dt1 = dt2)
So, let's calculate how long the impulse was:
t2 - t1 = (20ms + 1.5ms + dt2) - (20ms +dt1) = 1.5ms (as dt2=dt1)
So, the timing is as exact as the clock-frequency - either in spin and using waitcnt. You only need to take care that both parts (set and clear pin) are symmetrical (waitcnt directly followed by outa).
Post Edited (MagIO2) : 2/3/2010 7:50:50 PM GMT