# Controlling a Servo with the HC12?

Started by November 20, 2009
defessler@g.. wrote:

> If only the answer was so simple. I've tried various methods. My bus runs
> at 2MHz.

Don't you think it is so simple to not reply and not help at all? One finds
a bug in your "I'll guess all my settings" -style code and the best you can
say is it doesn't help?
2MHz bus. 20ms period expressed in bus cycles = 2MHz/20ms8. 16bits PWM,
so you need to scale 1E8 down to fit 2^16. Least power of two divider is
2^(ceil(log2(1E8)) - 16) = 2^(ceil(ln(1E8)/ln(2)) - 16) = 2^11 = 2048.
Definitely scaled clock SA should be chosen, not A like in your work. 1/512
setting in PWMSCLA and 1/4 setting in PWMPRCLK could be fine. Then period
setting will be 1E8/2048 = 48828. Rest pulse width setting - 3662.

Edward

>
> I did try that for the duty cycle. I've tried various different prescaler
> settings. I can not get the motor to turn more than 1 way. I've also tried
> another motor with the same issues.
>
> I have the servo connected to 3 double A batteries, tied the ground with
> the microcontroller ground. The microcontroller is running off of USB
> power from my computer. I have PWM channel 1 connected to the pulse in of
> the servo.
>
> --Original Message--
>>Can't verify all your settings, you didn't specify bus frequency. But if
>>period setting is 5000 for 20ms, then duty cycle setting should be not
>>225,
>>but 1.5/20*5000 = 375 for rest, 325 for clockwise and 425 for ccw.
>>
>>Edward
>
I forgot that PWMSCLA isn't power of two divider. Doesn't mean previous
settings won't work, but duty cycle resolution can be improved a bit.
1E8 / 2^16 = ~1526 . Dividing that by 2 (scaled clock fixed divider) we get
763. This should be prescaled by 2^N to fit max possible PWMSCL/2 setting of
256. ceil(log2(763)) - log2(256) = 2 . Prescaler setting 1/(2^2)=1/4 .
PWMSCLA setting 4/ 1526 = ~ 1/382 . Period setting 1E8 / 4 / 382 = 65445.
Motor rest setting - 4908

Edward

----- Original Message -----

> defessler@g.. wrote:
>
>> If only the answer was so simple. I've tried various methods. My bus runs
>> at 2MHz.
>
> Don't you think it is so simple to not reply and not help at all? One
> finds
> a bug in your "I'll guess all my settings" -style code and the best you
> can
> say is it doesn't help?
> 2MHz bus. 20ms period expressed in bus cycles = 2MHz/20ms8. 16bits PWM,
> so you need to scale 1E8 down to fit 2^16. Least power of two divider is
> 2^(ceil(log2(1E8)) - 16) = 2^(ceil(ln(1E8)/ln(2)) - 16) = 2^11 = 2048.
> Definitely scaled clock SA should be chosen, not A like in your work.
> 1/512
> setting in PWMSCLA and 1/4 setting in PWMPRCLK could be fine. Then period
> setting will be 1E8/2048 = 48828. Rest pulse width setting - 3662.
>
> Edward
>
>>
>> I did try that for the duty cycle. I've tried various different prescaler
>> settings. I can not get the motor to turn more than 1 way. I've also
>> tried
>> another motor with the same issues.
>>
>> I have the servo connected to 3 double A batteries, tied the ground with
>> the microcontroller ground. The microcontroller is running off of USB
>> power from my computer. I have PWM channel 1 connected to the pulse in of
>> the servo.
>>
>> --Original Message--
>>>Can't verify all your settings, you didn't specify bus frequency. But if
>>>period setting is 5000 for 20ms, then duty cycle setting should be not
>>>225,
>>>but 1.5/20*5000 = 375 for rest, 325 for clockwise and 425 for ccw.
>>>
>>>Edward
>>
I'll give that a try. I did not mean to offend you. I was just being somewhat playful and I've spent a great deal of time on this. I admit I am very new to the concepts involved with a micro-controller. I did do all the calculations for the registers. I was doing some guess work when I created this. I knew the rest point was suppose to be 375 but that was not working and I tried to lower and raise the values randomly for quick tests and I didn't notice that I didn't change it back when I posted this. I had gotten my original values like this.

Right now I have:

2MHz/8 = 250KHz
1/250KHz = 4micros
20ms / 4micros = 5000 = PWMPER01
1.5ms/20ms = 7.5%
7.5% * 20ms = 375 = PWMDTY01

I was suspecting it had something to do with the PWMSCAL but the manual seemed to provide a foggy explanation of that register. I very much appreciate all the help so far. I'm going to try what you recommended, I'll post back on how it goes.

Hello,
>
>I am trying to control a Parallax Continuous Rotation Servo (#900-00008) using my MC9S12C128CFUE. I need to to use PWM to give a pulse 1.5ms(rest), 1.3ms (clockwise), and 1.7ms (counter-clockwise) every 20ms/50Hz. I can spin the motor, but it only ever spins in 1 direction and I can not make it stop spinning even if I try to calibrate it.
>
>Any help is appreciated. Here is my current code.
>
> PWMPOL = 0x01; // High at beginning, low at end (active high).
> PWMPRCLK = 0x03; // Prescaler.
> PWMCLK = 0x00; // Sets clock A to be ch 1 clock.
> PWMCAE = 0x00; // Sets left aligned PWM.
> PWMCTL = 0x10; // Sets up ch0+1 16bit.
> PWMPER01 = 5000;
> PWMDTY01 = 225;
> PWME = 0x02;
>
I am making progress with your advice, but I have to say my math skills are very lacking and I can not completely understand where you get getting your numbers.

Hello,
>
>I am trying to control a Parallax Continuous Rotation Servo (#900-00008) using my MC9S12C128CFUE. I need to to use PWM to give a pulse 1.5ms(rest), 1.3ms (clockwise), and 1.7ms (counter-clockwise) every 20ms/50Hz. I can spin the motor, but it only ever spins in 1 direction and I can not make it stop spinning even if I try to calibrate it.
>
>Any help is appreciated. Here is my current code.
>
> PWMPOL = 0x01; // High at beginning, low at end (active high).
> PWMPRCLK = 0x03; // Prescaler.
> PWMCLK = 0x00; // Sets clock A to be ch 1 clock.
> PWMCAE = 0x00; // Sets left aligned PWM.
> PWMCTL = 0x10; // Sets up ch0+1 16bit.
> PWMPER01 = 5000;
> PWMDTY01 = 225;
> PWME = 0x02;
>
Oh, I'm very sorry. I wasn't drunk but something went mad. Of course 20ms is
0.02*2000000 = 40000 bus clock periods, not 1E8 8-). Prescaler is not
required, because 40000 fits in 16bits. PER = 40000, DTY = 1.5/20 * 40000 3000. Clock source not scaled clock A.

But your settings with 1/8 prescaler and fixed DTY to 375 should be fine
indeed. Do you really run at 2MHz bus? It is 4MHz crystal and PLL not used,
right?
I see you have PWMPOL = 1. But in 16bits mode (concatenated two 8bit
channels) bit1 (not bit0) controls PWM01 output polarity. So please change
it to PWMPOL = 2. Also, do you expect PWM output on PTP1 pin, right?

Calculation is quite simple. log base 2 can be used to quickly find least
2^N divider without trial and error. For example let's consider the same but
for 8bit PWM. 40000 bus clocks period should be prescaled to fit 8bits.
log2(40000) = ln(40000)/ln(2) = 15.28. ceil(15.28) stands for round 15.28 up
to 16. So we need to divide 40000 by 2^(16 - 8) = 256. Period setting would
be 40000 / 256 = 156.25 then.

Prescaler divides by power of 2. PWMSCL setting divides by N and then by 2
(see Figure 12-34. PWM Clock Select Block Diagram). So to find both least
dividers, you divide 40000 by maximum period setting (256 in 8bits mode).
40000/256 = 156.25. Prescaler 2^N is not required, because 156 fits PWMSCL
max setting. Else you could use log2 to find least 2^N divider, then
calculate PWMSCL setting.

Edward

----- Original Message -----
From:
To: <6...>
Sent: Saturday, November 21, 2009 11:27 PM
Subject: [68HC12] Re: Controlling a Servo with the HC12?
>I am making progress with your advice, but I have to say my math skills are
>very lacking and I can not completely understand where you get getting your
>numbers.
>
> Hello,
>>
>>I am trying to control a Parallax Continuous Rotation Servo (#900-00008)
>>using my MC9S12C128CFUE. I need to to use PWM to give a pulse 1.5ms(rest),
>>1.3ms (clockwise), and 1.7ms (counter-clockwise) every 20ms/50Hz. I can
>>spin the motor, but it only ever spins in 1 direction and I can not make
>>it stop spinning even if I try to calibrate it.
>>
>>Any help is appreciated. Here is my current code.
>>
>> PWMPOL = 0x01; // High at beginning, low at end (active high).
>> PWMPRCLK = 0x03; // Prescaler.
>> PWMCLK = 0x00; // Sets clock A to be ch 1 clock.
>> PWMCAE = 0x00; // Sets left aligned PWM.
>> PWMCTL = 0x10; // Sets up ch0+1 16bit.
>> PWMPER01 = 5000;
>> PWMDTY01 = 225;
>> PWME = 0x02;
>>
>
I tried it with 40000 PWMPER and 3000 PWMDTY and it spins, but still only in 1 direction and doesn't rest at 3000. I think I need to track down an oscilloscope and make sure it's giving the pulses I am looking for, I can probably go to my college and use one.

I did manage to set the PWMPER to 2000 with no prescaler (test program I wrote to learn PWM originally) and if I set it to 0, it would stay at rest (no pulse) and every time I increase it by 100 it would move slightly faster until it was spinning full speed. Oddly, if I set it to about 1991 it would slowly turn in the other direction and speed up slowly as I increased the value by 1 (anything below 1991 spin the same direction as it did with 100).

I am pretty sure I am running a 4MHz crystal which is divided by 2 to get 2MHz. I am using PWM CH1 pin to read the pulse.

Thanks for the info on the math. I understand what log and ln are, but I've honestly never seen ceil before.

PWMPOL = 0x02; // High at beginning, low at end (active high).
PWMPRCLK = 0x00; // Prescaler.
PWMCLK = 0x00; // Sets clock A to be ch 1 clock.
PWMCAE = 0x00; // Sets left aligned PWM.
PWMCTL = 0x10; // Sets up ch0+1 16bit.
PWMPER01 = 40000;
PWMDTY01 = 3000;
PWME = 0x02;

Hello,
>
>I am trying to control a Parallax Continuous Rotation Servo (#900-00008) using my MC9S12C128CFUE. I need to to use PWM to give a pulse 1.5ms(rest), 1.3ms (clockwise), and 1.7ms (counter-clockwise) every 20ms/50Hz. I can spin the motor, but it only ever spins in 1 direction and I can not make it stop spinning even if I try to calibrate it.
>
>Any help is appreciated. Here is my current code.
>
> PWMPOL = 0x01; // High at beginning, low at end (active high).
> PWMPRCLK = 0x03; // Prescaler.
> PWMCLK = 0x00; // Sets clock A to be ch 1 clock.
> PWMCAE = 0x00; // Sets left aligned PWM.
> PWMCTL = 0x10; // Sets up ch0+1 16bit.
> PWMPER01 = 5000;
> PWMDTY01 = 225;
> PWME = 0x02;
>
OK, let's look into datasheet. Is this the right one ?:

>From previous mails I understood that PWM period is 20ms. But it seems 20ms
is not the period, but a pause between pulses! Looks like both, period and
pulse width should be adjusted every time.

1.5ms pulse, 20ms pause:
PER = 21.5ms *2MHz = 43000. DTY = PER * 1.5/(20+1.5) = 3000

1.3ms pulse, 20ms pause
PER = 42600, DTY = 2600

1.7ms pulse, 20ms pause:
PER = 43400, DTY = 3400

Edward

----- Original Message -----
From:
To: <6...>
Sent: Sunday, November 22, 2009 10:21 AM
Subject: [68HC12] Re: Controlling a Servo with the HC12?
>I tried it with 40000 PWMPER and 3000 PWMDTY and it spins, but still only
>in 1 direction and doesn't rest at 3000. I think I need to track down an
>oscilloscope and make sure it's giving the pulses I am looking for, I can
>probably go to my college and use one.
>
> I did manage to set the PWMPER to 2000 with no prescaler (test program I
> wrote to learn PWM originally) and if I set it to 0, it would stay at rest
> (no pulse) and every time I increase it by 100 it would move slightly
> faster until it was spinning full speed. Oddly, if I set it to about 1991
> it would slowly turn in the other direction and speed up slowly as I
> increased the value by 1 (anything below 1991 spin the same direction as
> it did with 100).
>
> I am pretty sure I am running a 4MHz crystal which is divided by 2 to get
> 2MHz. I am using PWM CH1 pin to read the pulse.
>
> Thanks for the info on the math. I understand what log and ln are, but
> I've honestly never seen ceil before.
>
> PWMPOL = 0x02; // High at beginning, low at end (active high).
> PWMPRCLK = 0x00; // Prescaler.
> PWMCLK = 0x00; // Sets clock A to be ch 1 clock.
> PWMCAE = 0x00; // Sets left aligned PWM.
> PWMCTL = 0x10; // Sets up ch0+1 16bit.
> PWMPER01 = 40000;
> PWMDTY01 = 3000;
> PWME = 0x02;
>
> Hello,
>>
>>I am trying to control a Parallax Continuous Rotation Servo (#900-00008)
>>using my MC9S12C128CFUE. I need to to use PWM to give a pulse 1.5ms(rest),
>>1.3ms (clockwise), and 1.7ms (counter-clockwise) every 20ms/50Hz. I can
>>spin the motor, but it only ever spins in 1 direction and I can not make
>>it stop spinning even if I try to calibrate it.
>>
>>Any help is appreciated. Here is my current code.
>>
>> PWMPOL = 0x01; // High at beginning, low at end (active high).
>> PWMPRCLK = 0x03; // Prescaler.
>> PWMCLK = 0x00; // Sets clock A to be ch 1 clock.
>> PWMCAE = 0x00; // Sets left aligned PWM.
>> PWMCTL = 0x10; // Sets up ch0+1 16bit.
>> PWMPER01 = 5000;
>> PWMDTY01 = 225;
>> PWME = 0x02;
>>
>
1.5ms pulse, 20ms pause:
PER = 21.5ms *2MHz = 43000. DTY = PER * 1.5/(20+1.5) = 3000

1.3ms pulse, 20ms pause
PER = 42600, DTY = 2600

1.7ms pulse, 20ms pause:
PER = 43400, DTY = 3400

I tried the settings above like you suggested, but it would still only rotate in 1 direction. I decided to mess around a bit and discovered that with PER at 43000 I could set DTY like this. I guess if it works, then I should use it like that, but it seems wrong.

DTY = 2200 at rest.
DTY = 2100 spins clockwise. (2000 full speed)
DTY = 2300 spins counter-clockwise. (2400 full speed)

Based on the data sheet this should work. The values the data sheet wants should work perfectly like you suggested. I had tried that before when I was using 5000 for the PER, except I did the calculation for the DTY wrong. I had 5375 for the PER and 403 for the DTY instead of 375.

Hello,
>
>I am trying to control a Parallax Continuous Rotation Servo (#900-00008) using my MC9S12C128CFUE. I need to to use PWM to give a pulse 1.5ms(rest), 1.3ms (clockwise), and 1.7ms (counter-clockwise) every 20ms/50Hz. I can spin the motor, but it only ever spins in 1 direction and I can not make it stop spinning even if I try to calibrate it.
>
>Any help is appreciated. Here is my current code.
>
> PWMPOL = 0x01; // High at beginning, low at end (active high).
> PWMPRCLK = 0x03; // Prescaler.
> PWMCLK = 0x00; // Sets clock A to be ch 1 clock.
> PWMCAE = 0x00; // Sets left aligned PWM.
> PWMCTL = 0x10; // Sets up ch0+1 16bit.
> PWMPER01 = 5000;
> PWMDTY01 = 225;
> PWME = 0x02;
>
Alright. I finally have it working properly. I had the wheels in a carriage and I was unable to get the proper leverage on the calibration screw and it wasn't turn past a certain point, I thought it was a limit of the screw. I took the motors out of the carriage and put some force into the screws.

The motors now rest at 3000 and turn proper if I increase it from 3000 to 3400 and 2600 respectively.

Hello,
>
>I am trying to control a Parallax Continuous Rotation Servo (#900-00008) using my MC9S12C128CFUE. I need to to use PWM to give a pulse 1.5ms(rest), 1.3ms (clockwise), and 1.7ms (counter-clockwise) every 20ms/50Hz. I can spin the motor, but it only ever spins in 1 direction and I can not make it stop spinning even if I try to calibrate it.
>
>Any help is appreciated. Here is my current code.
>
> PWMPOL = 0x01; // High at beginning, low at end (active high).
> PWMPRCLK = 0x03; // Prescaler.
> PWMCLK = 0x00; // Sets clock A to be ch 1 clock.
> PWMCAE = 0x00; // Sets left aligned PWM.
> PWMCTL = 0x10; // Sets up ch0+1 16bit.
> PWMPER01 = 5000;
> PWMDTY01 = 225;
> PWME = 0x02;
>