# Hardware PWM on PIC

#### camerart

##### Active Member
Hi,
I'm trying to write a program (Oshonsoft BASIC) on an18F4431 PIC, specifically 4x HW PWM Channels.

Registers need to be set, and counters count to match 2x registers, PINs and BITS are set when something happens, then the CODE should act accordingly etc.

When trawling through a D/S, which I think is very difficult, where many of the registers look similar, and remembering which does what is difficult.

Can anyone give me their idea of how they go about starting to figure it all out, and perhaps make a procedure chart or similar, to help with the actual programming, please?
C

#### Pommie

##### Well-Known Member
Use the code configurator in MPLABX to generate the C source code and convert it to basic.

Mike.

#### Nigel Goodwin

##### Super Moderator
Use the code configurator in MPLABX to generate the C source code and convert it to basic.

Mike.
I agree, it's often far easier to use the MCC rather than try and sort out what the datasheet says.

But bear in mind the MCC creates code in a number of different files, and also a LOT of code (functions) that you probably don't need - so he only needs to convert a fairly small amount of code - this is the code I cut & pasted from the MCC, I ignored the rest.

C:
void PWM5_Initialize(void)
{
// Set the PWM to the options selected in the PIC10 / PIC12 / PIC16 / PIC18 MCUs.
// PWM5POL active_hi; PWM5EN enabled;
PWM5CON = 0x80;

// DCH 0; - initialise at zero
PWM5DCH = 0x00; //0x00;

// DCL 0;
PWM5DCL = 0x00; //0x00;

// Select timer
CCPTMRS1bits.P5TSEL = 2;            // PW5 using TMR4
}

// Writing to 8 MSBs of PWM duty cycle in PWMDCH register
PWM5DCH = (dutyValue & 0x03FC)>>2;

// Writing to 2 LSBs of PWM duty cycle in PWMDCL register
PWM5DCL = (dutyValue & 0x0003)<<6;
}

Bear in mind you also have to configure the timer (TMR4 in my example), so you do that in the MCC as well.

C:
// timer for PWM5
void TMR4_Initialize(void)
{
// Set TMR4 to the options selected in the User Interface

// T4CS FOSC/4;
T4CLKCON = 0x01;

// TPSYNC Not Synchronized; T4MODE Software control; T4CKPOL Rising Edge; T4CKSYNC Not Synchronized;
T4HLT = 0x00;

// T4RSEL T4CKIPPS pin;
T4RST = 0x00;

// PR2 63;
T4PR = 0x3F;

// TMR2 0;
T4TMR = 0x00;

// Clearing IF flag.
PIR7bits.TMR4IF = 0;

// T4CKPS 1:1; T4OUTPS 1:1; TMR4ON on;
T4CON = 0x80;
// set prescaler for PWM frequency
//T4CONbits.CKPS=0;       // 122KHz PWM at 8 bits resolution 32MHz clock
//T4CONbits.CKPS=1;       // 61KHz PWM (or 122KHz with 64MHz clock)
//T4CONbits.CKPS=2;       // 30.5KHz PWM (or 61KHz with 64MHz clock)
//T4CONbits.CKPS=3;       // 15.25KHz PWM (or 30.5KHz with 64MHz clock)
//T4CONbits.CKPS=4;       // 7.625KHz PWM (or 15.25KHz with 64MHz clock)
T4CONbits.CKPS=5;       // 3.812KHz PWM (or 7.625KHz with 64MHz clock)
//T4CONbits.CKPS=6;       // 1.96KHz PWM (or3.812KHz with 64MHz clock)
}

void TMR4_Start(void)
{
// Start the Timer by writing to TMRxON bit
T4CONbits.TMR4ON = 1;
}

As you can see from the commented out parts, I've been experimenting with different PWM frequencies

Last edited:

#### camerart

##### Active Member
Hi M and N,
Ok, I'll have a go, thanks for the CODE 'N'.

Next thing find out what MCC is
I did a search and found this:
-------------------------------------------------------
MCC Modified Continuous Cooking Computing
2
MCC Motor Control Center Mechanics
,
HVAC Construction
1
MCC Master Command Center

MCC Motion Control Chart

Automotive Systems
,
Motion
,
Industry
-----------------------------------------
Any of these

So what is MCC?
C

#### camerart

##### Active Member
Hi,
Of course now I remember. It's a bit complicated for me, so I use Oshonsoft and Pickit-3

For this case though it may be easier, so I'll re-install it.
C

#### Nigel Goodwin

##### Super Moderator
Hi,
Of course now I remember. It's a bit complicated for me, so I use Oshonsoft and Pickit-3

For this case though it may be easier, so I'll re-install it.
C
As you can see from the C code, it's very, very simple - just writing to a handful of registers - so should be trivial to convert to BASIC.

#### camerart

##### Active Member
As you can see from the C code, it's very, very simple - just writing to a handful of registers - so should be trivial to convert to BASIC.
Hi N,
Well I tried!
I used an old laptop, and had a good try, but MPLAB is too difficult, and sadly you're program is too far removed from my skills that I can't understand nearly all of it.

Here's where I've got to so far (In Oshonsoft): (All I've done is look at examples, written in BASIC, then working through the D/S for register words.)
Thanks for trying.

C.

#### Attachments

• 18f4431 32mhz XTL REMOTE PWM 060522 2000.bas
2.2 KB · Views: 14
Last edited:

##### Well-Known Member
Have you checked out the calculator/code generator?

#### camerart

##### Active Member
Have you checked out the calculator/code generator?
Hi M,

I see se see you've you yo you youv'e ch ch changed your AvAva avaaaa tar

Yes, I looked at the calculator, which will come in handy, when I get to that point, thanks for posting.

My original question, is: When starting a project, while looking throught the relevant D/S, how are all of the registers, matches, SET PINS/BITs counts, and timers planned? How I imagine a flow diagram, although I've never used one.
I hope you understand.
C

#### Pommie

##### Well-Known Member
That chip doesn't have PPS so setting up is simply going to the relevant section and setting up the peripheral you need.
All PWM modules use Timer2 so set that up first.
What speed are you running the PWMs at?

Mike.

#### camerart

##### Active Member
That chip doesn't have PPS so setting up is simply going to the relevant section and setting up the peripheral you need.
All PWM modules use Timer2 so set that up first.
What speed are you running the PWMs at?

Mike.
Hi M,
Good!
1/ 4 of 6 Channels.

2/ PERIPHERAL: The joystick DATA is received in PIC 18F4431 from PIC18F46K20, which then does all of the calculation to control MOTORS/SERVO.

3/ The clock speed is Crystal 8mHz x 4 PLL = 32mHz

4/ I don't know what speed to run the PWMs at. All I know is each CH is 1-2ms-ON subtracted from 20ms envelope.

Thanks, C.

#### camerart

##### Active Member
As you can see from the C code, it's very, very simple - just writing to a handful of registers - so should be trivial to convert to BASIC.
Hi N,
I posted my program so far! when you look at is does it seem trivial to you to convert it to 'C' ? (genuine question)
------------------------------------------------------------

I can try your method in MPLAB too.

I don't want to learn MPLAB, but I will watch a video about is sometime, and play at pressing all of the button which sometimes gives results. (More of a puzzle)

So far I've copied and pasted the CODE you posted into MPLAB.

C.

#### Pommie

##### Well-Known Member
4/ I don't know what speed to run the PWMs at. All I know is each CH is 1-2ms-ON subtracted from 20ms envelope.
That is not PWM but servo control which the standard PWM can't do. You can use the compare function to generate these signals but it'll be slightly glitchy.

Mike.

#### camerart

##### Active Member
That is not PWM but servo control which the standard PWM can't do. You can use the compare function to generate these signals but it'll be slightly glitchy.

Mike.
Hi M,
I want to use the Hardware PWM0-7, which are in pairs, so only 4Channels. Is this not the same as what I outlined above?

Can you give me clarification please? What are the differences?
C

#### Pommie

##### Well-Known Member
I wrote an article for Bill's (blueroomelectronics) newsletter. I've attached it here and the article is on page 4.

Mike.
Edit, it could be done cycle accurate but would require some complex interrupt code, can your Basic (and you) do that?
Edit2, no it can't as that chip only has two CCP modules.

#### Attachments

• JPUG_02.pdf
658.4 KB · Views: 18
Last edited:

#### rjenkinsgb

##### Well-Known Member
To run multiple servos, use a timer and capture/compare as in Mike's article, but instead of turning the output off and starting over, shift a single "1" bit across the PIC output port and update the next capture time with each servo position in sequence.

So, like
Start - set the servo number to 1
this_servo = servotime(number) // the time for servo 1.
put 0x01 on the port and set the capture to (timer + this_servo)

loop:
servo number = servo number + 1 // Increment the servo counter
this_servo = servotime(number) // And get the time for the next servo

On capture event, shift left the port data // (so 0x02, 0x04, 0x08, 0x10 etc. at each pass through the loop).
// That turns off the pulse to the last servo and starts the pulse for the next one.
Set capture to (timer + this_servo) // And set the capture to suit the present servo

if(servo number < maximum) go to loop // Just repeat through how ever many servos - up to eight on an eight bit port.

#### Pommie

##### Well-Known Member
Shifting sounds like a good idea but it stops you using the rest of the port except as inputs. When I've done multiple servos I use 2.5mS slots so I can easily work out the time remaining to keep a 20mS time frame - some servos don't like the time frame to not be constant!!!

If the chip had PPS then a single (hardware) channel could be steered to different pins but it doesn't so you end up with jitter due to the (variable) latency of the ISR. It could be done by steering with AND gates and 5 pins.

Mike.

#### Nigel Goodwin

##### Super Moderator
Hi N,
Well I tried!
I used an old laptop, and had a good try, but MPLAB is too difficult, and sadly you're program is too far removed from my skills that I can't understand nearly all of it.

Here's where I've got to so far (In Oshonsoft): (All I've done is look at examples, written in BASIC, then working through the D/S for register words.)
Thanks for trying.

C.

You're doing the right thing, just writing values to registers - such as this clip of yours and mine:

Code:
// Set the PWM to the options selected in the PIC10 / PIC12 / PIC16 / PIC18 MCUs.
// PWM5POL active_hi; PWM5EN enabled;
PWM5CON = 0x80;

PWMCON0 = %01010100  'PWM[5:0] outputs enabled

Yours writes in binary, mine (from the MCC) writes in HEX

Many of the other lines (those with 'bits' in the name) write to a specific bit in a register, and makes it easier to understand rather than writing to 8 bits, just to change 1.

As others have said, generally the PWM hardware isn't suitable for servos, and while it can be used it requires a lot of 'messing about' to get it to work - basically it's far too low a resolution 'as is' - as it's PWM, not servo signals.

#### camerart

##### Active Member
I wrote an article for Bill's (blueroomelectronics) newsletter. I've attached it here and the article is on page 4.

Mike.
Edit, it could be done cycle accurate but would require some complex interrupt code, can your Basic (and you) do that?
Edit2, no it can't as that chip only has two CCP modules.
Hi M,
EDIT 1: I think my BASIC can do it, and possibly with time, I could. I have previous examples, as long as I know what the plan is.
EDIT 2: I'm hoping for 4x CH using PWM0-7 /2 and 2x using the CCP section.
C

#### camerart

##### Active Member
You're doing the right thing, just writing values to registers - such as this clip of yours and mine:

Code:
// Set the PWM to the options selected in the PIC10 / PIC12 / PIC16 / PIC18 MCUs.
// PWM5POL active_hi; PWM5EN enabled;
PWM5CON = 0x80;

PWMCON0 = %01010100  'PWM[5:0] outputs enabled

Yours writes in binary, mine (from the MCC) writes in HEX

Many of the other lines (those with 'bits' in the name) write to a specific bit in a register, and makes it easier to understand rather than writing to 8 bits, just to change 1.

As others have said, generally the PWM hardware isn't suitable for servos, and while it can be used it requires a lot of 'messing about' to get it to work - basically it's far too low a resolution 'as is' - as it's PWM, not servo signals.
Hi N,
I thought that PWM was the same however you look at it, and using a PIC HW was best.
I understood that the PIC HW PWMs are in pairs, for use as PUSH PULL, with allowance for a NULL POINT, but set as individual, only 4xCH they are simple PWM, but it appears not.

I will give it a bit more time, then revert to a previous program where 1-2ms is used.
Thanks.

Replies
7
Views
6K
Replies
1
Views
2K
Replies
19
Views
3K
Replies
15
Views
10K
Replies
2
Views
2K