Pulse Width Modulation (PWM) in dsPIC/PIC24 works from output compare section (OC). OC is simply a comparator. One input is from a timer and another from OC register where we set the value. The timer is used to set the frequency of the PWM and OC register for setting the duty cycle. There are actually 2 OC register. One where we set the value and another is a read only register that takes the copy of the value in the input register and update it in a glitch free manner. In order to know what timer can be used for PWM please refer the data sheet of the part you are using.
Select your part based on your application. Here I am using dsPIC33FJ32GP202. It is a General Purpose (GP) controller and does not have any special PWM ability. Wish I could have picked a MC series for Motor Control. May be next time.
Even with GP series you can control DC motor’s without a problem in one direction. But for bi-directional control it is better to use MC series. Available PWM options
- OC PWM (Using Output Compare)
- MC PWM (for motor control – control both H/L H-bridge)
- SMPS PWM (for SMPS design – Power electronics application)
- Here I’m using OC PWM.
- Note: For OC PWM use “outcompare.h” Similarly for other PWM’s you have pwm.h and pwm12.h. Select according to the documentations listed below.
Documents to read
- dsPIC33/PIC24 (DS70005157A) – http://ww1.microchip.com/downloads/en/DeviceDoc/70005157a.pdf
- C:\Program Files (x86)\Microchip\xc16\(version)\docs\periph_libs folder (assuming default location) For library documentation.
- Datasheet of the part being used.
PWM Sample
dsPIC33/PIC24 has ‘F’ series and ‘E’ series. ‘E’ series is relatively newer than ‘F’ series and has more features to it. So you have to read the library documentation to know how to use it. I don’t have any ‘E’ series with me.
Note: PWM function prototypes are located in outcompare.h |
Steps to setup PWM
- Setup Timer for required PWM frequency
- Use the function OpenOCx (x= 1,2…) to start your PWM.
That simple!
Here is another important boundary parameters you will see in the document 70005157a.pdf
Resolution of PWM
The resolution is hugely dependent on the Frequency and prescale used in the timer. The example code I’m going to put below is for generating a PWM of freqency 50Hz or say 20ms. 20ms is perfect for driving a servo motor or may be brushless motor controller. So I did end up using a prescale value 256 for the timer. So now my calculated value is 3125. How did I get that 3125? check https://singularengineer.com/timers-using-xc16-and-mplab-x/
PWM resolution (in bits) = log (3125)/ log(2)
= 11.60964 bits
So now the duty cycle of 0-100% = [ 0 – 3125 ]
dsPIC/PIC24 PWM Code
/* * File: dsPICtest.c * Author: Singular Engineer * * Created on January 19, 2015 */ #define FCY 40000000ULL //Fcy = (Fosc/2); Fosc = 80MHz #include <xc.h> #include "config.h" #include <libpic30.h> #include <pps.h> #include <timer.h> #include <outcompare.h> //for PWM unsigned int i = 0; unsigned int dutycycle = 0; void SetupClock(void); int main(int argc, char** argv) { SetupClock(); unsigned int pwmperiodval = 3125; //20ms (50Hz) //---------- Assigning PPS function------------------ PPSUnLock; PPSOutput(OUT_FN_PPS_OC1,OUT_PIN_PPS_RP9); //PWM 1 pin to RP 9 PPSLock; //----------------------------------------------------- OpenTimer2(T2_ON & //Timer2 ON T2_GATE_OFF & //Gated mode OFF T2_IDLE_STOP & //Stop when controller is in sleep T2_PS_1_256 & //Prescale 256 T2_SOURCE_INT, pwmperiodval); // Interal source unsigned int OC1Config1 = OC_IDLE_STOP & // Stop when controller sleeps OC_TIMER2_SRC & // Timer 2 as source OC_PWM_FAULT_PIN_DISABLE; // not using PWM fault OpenOC1(OC1Config1, 0x00, 0x00); while(1) { if(i == 0) { dutycycle++; SetDCOC1PWM(dutycycle); if(dutycycle > 3124) i = 1; } if(i == 1) { dutycycle--; SetDCOC1PWM(dutycycle); if(dutycycle < 1 ) i = 0; } __delay_ms(1); } return 0; } void SetupClock() { //Setting N1 to 4 (N1 = n+2); n = N1-2 CLKDIVbits.PLLPRE0 = 0; CLKDIVbits.PLLPRE1 = 1; CLKDIVbits.PLLPRE2 = 0; CLKDIVbits.PLLPRE3 = 0; CLKDIVbits.PLLPRE4 = 0; //Setting M to 32 (M = m+2); m = M-2 PLLFBDbits.PLLDIV0 = 0; PLLFBDbits.PLLDIV1 = 1; PLLFBDbits.PLLDIV2 = 1; PLLFBDbits.PLLDIV3 = 1; PLLFBDbits.PLLDIV4 = 1; PLLFBDbits.PLLDIV5 = 0; PLLFBDbits.PLLDIV6 = 0; PLLFBDbits.PLLDIV7 = 0; PLLFBDbits.PLLDIV8 = 0; //Setting N2 to 2 CLKDIVbits.PLLPOST0 = 0; CLKDIVbits.PLLPOST1 = 0; }
If i have copied the file and tryed in MPLAB X IDE V3.20, it shows an error of Recipe of target.. Please help me how to sort out the issue…
Please can i get the source file for the same, because i am the beginner of the MPLAB X IDE for Dspic33E
Please use Microchip’s MPLABX forum. You will get your questions answered promptly.
Plural of “motor” is “motors”, not “motor’s”.
@sam reeves
Dud, that’s your problem? A mistake in grammar? Man, get a life.
@singularengineer: Thank you for the example. Well written and concise.