Software PWM

I was hoping to avoid wrighting my own software pwm for the pic but it looks like i've arrived there. the motors and tracks I hot glued toghther don't drive straigh so the only way I can think of fixing it is to use PWM to slow down one motor. I know I could use the one hardware pwm to slow down just one motor but thats going to be used in the future for somthing else so I have to create the pwm myself in software.

I like how you can set the hardware and it will continue to work while the pic is doing other things. I'd like to have the same sort of functionallity with the software pwm. this leads me to think that I should use the timers and interrupts to create the PWM. I've been looking for some examples that are simple to follow but I haven't come across a good one yet. I guess what I'm looking for are the basic steps (psuedocode) to creating the PWM on a Pic18XXXX microcontroller.

Writing a Soft-PWm is a lot

Writing a Soft-PWm is a lot easyer than it seems at first really. The best thing is to work with a timer-interrupt, that overflows every 20ms (prescaler) . That way your processor only has to work when you are switching from hight to low, the rest of the time, it can continue doing other stuff.

If you are just controlling a few servos, you won’t even tell the difference in your cpu-power, just as if it was a hard-pwm^^

How would that work?

That seems very slow. 20ms with 8 unique speeds is a PWM frequency of only 6.25Hz. Too slow to be useful unless your motor has a big flywheel. What operation would you perform every 20ms?

One strategy

1) Decide on the resolution (the number of steps between off and 100% on. Go with 16. That’s plenty.

2) Decide on a PWM frequency. Go with 30Hz. It sounds odd, but the reason becomes apparent next.

3) Set a 1:8 prescaler on an 8-bit timer.

4) Create a label “Count” and set it to the resolution (16).

5) Create a label "Demand"

6) In the interrupt service routine for the timer interrupt:

6.1) Decrement Count

6.2) When Count becomes zero, set it back to the resolution value again (16).

6.3) If Demand > Count, set the PWM output bit. Otherwise, clear it.

There you have a single PWM output. Put a value from 0 to 16 into “Demand” and the PWM output will perform accordingly. If you want two outputs, you create two Demands and perform two comparisons. (You only need one Count.)

What happens is that (assuming a 4MHz clock), this will interrupt every 2568=2048us. Each time, the counter decrements by one. This happens 16 times meaning that each of your unique mark to space ratios is 2048us apart and that your PWM time is 2048 * 16 = 32768us, or 30.51Hz.

If your demanded PWM value is less that the PWM counter, then your PWM should be marking, otherwise, you should be spacing.

Of course 30Hz might be a bit lumpy. Swap your 4MHz crystal for a 20MHz one and suddenly you’re at 150Hz. Irritatingly audiable. Your options are to reduce your resolution (half the resolution = double the frequency) or reduce your total pulse time (half the pulse time = double the frequency).

The disadvantage of reducing the resolution is obvious. The disadvantage or reducing the pulse time is that it leaves you fewer free processor cycles for your “main” program. In the example above, your interrupt is only called every 2048 cycles. Assuming it costs 200 cycles (that’s generous) to process the interrupt, that leaves your main program 1948 cycles between interrupts.

You could come down to a 2:1 prescaler with a PWM resolution of 8 and a clock of 20MHz. that gives you a PWM frequency of 20/4/(2256*8)*1000000 = 1.22kHz. BUT there are only 512 operations between interrupts then and 200(ish) of hem are taken up servicing the interrupt itself.

 

I don’t know what you are

I don’t know what you are using, but normal servos get a pwm signal every 20 ms. The signal itsself is between 1 and 2 ms long and determines the position in wich the servo goes ( 1.5 ms being the middle position)

Of course you have overflows way more often, but you just increment a register each time your timer overflows. Then you can time pretty exact 20 ms. That way, you set your signal every 20 ms, and reset it a number X of timeroverflows later.

X would be your parameter that controlls the servo position.

If you choose the right prescaler you can get it exact enough. That’s the way I did it and it is working (so don’t try to tell me it can’t work.^^)

 

PS: sorry, i just realised my first comment was really unprecise

Servos?

Indeed they do. I didn’t think wolfc mentioned servos in this thread, though. He does mention them briefly elsewhere. How were we to know?

I know it can work (now that we’ve got past the “it’s easy, just switch stuff on and off every 20ms” solution) which is why I detailled it in the next thread.

Servos

OKay, there’s the possibility that you’re talking about servos.

The above strategy still works, but you can use a much lower refresh rate (as low as 5ms, but 20ms is more typical).

The 8-bit timer with x8 postscaler will only give you a refresh rate of 2.048ms. User timer1 (or whatever your 16-bit counter is) with NO postscaler. Each time the interrupt occurs, reset the TMR1 value to 20000. (The best approach is to stop the counter while you’re setting it, so it doesn’t partially overflow during the process.)

You’ll probably want a resolution higher than 16. Maybe go for 64 unique positions (they would then be around 2.8 degrees apart, which is pretty good).

If you have multiple servos, you can also save clock cycles with this approach. Check to see if the TMR1 is greater than about 3000 and if it is, skip the rest of the checks by exiting the interrupt. 2500 is the maximum width of the pulse, so there’s no point checking to see if it should be longer…!

Yes I was really nof

Yes I was really not precise the first time around but all i really wanted to du was give the pointer about timer-interrupts.

Of course, if it’s for dc-motors, i agree that a faster rate is better, because it makes the motor run more “smooth”. Just forget the first comment and it’s all good again alright?^^

On servos speeds

Details in the next thread.

In fact, he explicitly mentions “speed” in his post. One doesn’t control the “speed” of a servo. Assuming the servo has been modified for continuous rotation, as mentioned here, fine control of the speed is quite impossible. You can do it roughly, but nowhere near accurately enough to obtain a straight line.

Yes, you’re right again,

Yes, you’re right again, he’s propably talking about dc-motors

I hope so

I wanted to make my tri wheel bot as cheap as possible, hoping I could make a little kit for folk who don’t have a mechanical workshop. It’s just doubled in price, because the guys at MIT and CMU can’t do accurate speed control.

Bummer.

Does my schema (below) make sense? Could you help wolfc on it? Are you using assembler for your strategy?

Thanks, for all the info

It appears that I wasn’t all that clear about what I wanted to do with the pwm. for now I need it for the dc motors. later, onece i get a servo i’ll need it for that too.

 

my clock is currently the internal 8Mhz soruce so that gets divided by 4 to become 2Mhz. Do you know if there is a way to use the 8Mhz directly?

 

thanks for all the info on the PWM

Explain?
What do you mean "directly"? All the info given still applies except it runs twice as fast, so you can either double your resolution or half your PWM time. in order to achieve the same effect.

my previous question was a
my previous question was a little off the topic but still related. when i set up the internal oscillator on the pic it appears to get divided by 4 just like an external one does. when I said directly I ment I want to use the 8Mhz internal osscilator without having it divided by 4. Is that possible?

No
It’s not really divided by four. Each instruction in the pic takes four clock cycles to execute except for jumps which take 8 cycles.

My lab instructor told me
My lab instructor told me that the osscilator gets divided by 4 and then each instruction takes 1 clock cycle and jumps take 2 cycles. what you said makes more sense (most everything takes 4 cycles). thanks.

Semantics

OKay. You want the full story? It’s always really hard to guage what people’s background knowledge is. If you make it too simple, they fall asleep. You make it too complex, they fall asleep.

Strictly speaking, the clock (internal or external) is divided by four to give you four Q-clocks (quadrature clocks). I could simplify at this point and say that’s one cycle each for PC increment, fetch, decode, execute. But it’s not even that simple. The instructions are 2-stage pipelined so that PC increment and fetch are done in 4 Q-cycles, and the decode and execute happen in the next four cycles with the fetch of the next instruction happening in parallel with the execute of the previous one.

You really didn’t want to know that, did you?

All this is in the Microchip midrange MCU family data sheet. It’s 688 pages long, and I’ve read it. I used to be a professor (US) / lecturer (UK) of Computer Architecture 101, so go easy on your lab guy: I wish I’d had someone like him to feed me a distilled version when I was a student!!

yes, your strategy makes
yes, your strategy makes perfect sense, i use assembler for it, and I am looking at it right now^^

ok, looks like everything is

ok, looks like everything is clear now, if you run into any more problems, feel free to ask

PS: on my atmel, if your clock is set to 8 Mhz, your timer increases 8 million times per second, but on pic itshould be the same^^

Why?
It’s a completely different architecture. There’s no reason why the two should execute at the same rate for the same clock.