Jump to content


dsPIC30F Motor Control PWM Module

Pulse Width Modulation, commonly referred to as PWM, is a common technique used for supplying power and motor control. Using it to power an LED, for example, means that by varying the duty cycle (which affects the average voltage) you can adjust the brightness of the LED. In this tutorial, you will learn how to configure the Motor Control PWM module (MCPWM) on a dsPIC30F and how to drive a hobby servo motor with it.

Here's some information we might find useful (calculations based on my 10MHz crystal):
  • Fosc = 10*10^6 (10MHz)
  • This is just the frequency of your crystal/oscillator
  • Fcy = 2.5*10^6 (2.5MIPS)
  • The frequency of the instruction clock is "Fosc / 4"
  • Tcy = 4*10^-7 (400ns)
  • The time of one instruction cycle is "1 / Fcy" which is equal to "4 / Fosc"
  • Fpwm = 55.555 (1/0.018)
  • The period of the PWM signal is 18ms, so the frequency is "1 / 18ms"
  • Prescaler = 4
  • Valid prescaler options are 1:1, 1:4, 1:16, 1:64
Calculating the period and duty cycle:
Most hobby motors with electronic speed controllers, like the Vex motors I'm using, and servos need to receive ~1ms-2ms of high time over a period of ~18ms to run full speed in either direction, with ~1.5ms being neutral. You could also think of it as a 1ms-2ms "pulse" every 18ms.

PTPER is the PWM time base period register. It holds the entire period of the PWM signal (the low time + the high time). The family reference manual states that "The user must write a 15-bit value to PTPER<14:0>." So if your PTPER value (calculated using the equation below) is greater than 32767 (the maximum value that 15 bits can hold) you will need to use a higher prescaler. I ended up using a prescaler of 1:4. The faster your system clock, the higher your prescaler will need to be.

Here is the equation we use to calculate the correct value for the period register:





Duty cycle is the ratio of the high-time divided by the period. For example: If we had a period of 18ms and 9ms of high-time, then we would have a 0.5 (9/18) or 50% duty cycle.

Using equation 15-4 in 70062E.pdf, we can calculate the correct values to put in the duty cycle register:






We now know to have a 100% duty cycle (the output would continuously be high) PDCx needs to be "22502." But we don't want a 100% duty cycle! Remember, we only need a 1ms-2ms pulse every 18ms, meaning that we only need 1/18th of the 100% duty cycle for full reverse, 1.5/18th for neutral and finally, only 2/18th for full forward. Multiplying these fractions into the 100% duty cycle value, we get:

Full reverse: 1250 (1/18 * 22,502)
Neutral: 1875 (1.5/18 * 22,502)
Full Forward: 2500 (2/18 * 22,502)

Every motor runs a little differently, so you may have to "tweak" these numbers to use the motor or servo at it's full potential. Just be careful not to turn a servo too far, that could cause the plastic stop inside it to break.

The code:

The comments should make the code fairly easy to understand:
/**** PTCON: PWM Time Base Control Register ****/
PTCONbits.PTEN   = 0;  // Timer Enable bit: DISABLE MCPWM
PWMCON1bits.PEN1H = 1; // PWM1H (pin 37) is enabled for PWM output
PWMCON1bits.PEN2H = 1; // PWM2H (pin 35) is enabled for PWM output
PTCONbits.PTCKPS = 1;  // Input Clock Prescale bits: 1:4
PTCONbits.PTOPS  = 0;  // Output Clock Postscale bits: 1:1
PTCONbits.PTSIDL = 1;  // Stop in Idle Mode: YES
PTCONbits.PTMOD  = 0;  // Mode Select bits: Free Running Mode
PTCONbits.PTEN   = 1;  // Timer Enable bit: ENABLE MCPWM
 
/**** PTPER: PWM Time Base Period Register ****/
PTPERbits.PTPER = 11250; // Period Value bits 

Download the dsPIC30F Motor Control PWM Module sample program.