Difference between revisions of "PIC32MX: PWM Motor Control"

From Mech
Jump to navigationJump to search
Line 143: Line 143:
This code is based off the NU32 board and hardware profile. If a button called swUser is not defined, the button should be set up. When the button is pushed, the motor will turn off
This code is based off the NU32 board and hardware profile. If a button called swUser is not defined, the button should be set up. When the button is pushed, the motor will turn off
#include "HardwareProfile.h"
#include "HardwareProfile.h"

int main(void)
int main(void)
{
{
// Configure the proper PB frequency and the number of wait states
// Configure the proper PB frequency and the number of wait states
SYSTEMConfigPerformance(SYS_FREQ);
SYSTEMConfigPerformance(SYS_FREQ);
// init OC1 module
// init OC1 module
OpenOC1( OC_ON | OC_TIMER2_SRC | OC_PWM_FAULT_PIN_DISABLE, 0, 0);
OpenOC1( OC_ON | OC_TIMER2_SRC | OC_PWM_FAULT_PIN_DISABLE, 0, 0);
// init Timer2 mode and period (PR2)
// init Timer2 mode and period (PR2)
OpenTimer2( T2_ON | T2_PS_1_1 | T2_SOURCE_INT, 0xFFFF);
OpenTimer2( T2_ON | T2_PS_1_1 | T2_SOURCE_INT, 0xFFFF);
while(1)
while(1)
{
{
if (swUser == 0)
if (swUser == 0)
{
{
SetDCOC1PWM(PR2 / 2); // Turns on the motor with 50% duty cycle
SetDCOC1PWM(PR2 / 2); // Turns on the motor with 50% duty cycle
}
}
else
else
{
{
SetDCOC1PWM(0); // Turns off the motor
SetDCOC1PWM(0); // Turns off the motor
}
}
}
}

CloseOC1();
CloseOC1();

} //end main
} //end main


===Timer Interrupt Code===
===Timer Interrupt Code===

Revision as of 14:03, 14 January 2010

Pulse Width Modulation, or PWM, is a technique used to vary the average magnitude of a signal by changing its duty cycle (the proportion of time that a signal is active or "high"). For a more in-depth introduction to PWM motor control click here.

PWM for PIC32 is discussed in more detail in the Microchip Output Compare documention.

Available Pins

The pins available for PWM are 5 input pins (OC1, OC2, OC3, OC4, and OC5) and 2 output pins (OCFA and OCFB). The output pins are for fault pin protection.

General Approach

PWM can be set up by either changing directly the special function registers or using the functions in outcompare.h (a header file included in the peripheral library (plib.h). The latter case is more straightforward and easier. This wiki describes how to use the outcompare functions. The register bits approach is described in detail in theMicrochip Output Compare documention.

There are four main functions that are used for PWM.

  void OpenOCX( config, value1, value2)
  void OpenTimerX(config, period)
  unsigned int SetDCOCXPWM(dutycycle)
  void CloseOCX();


where X is the module (1-5) or timer(2-3) that you want to use. Each of these functions are described below.

OpenOCX configures the OCX module and loads the R(value2) and RS (value1) registers with default values. The OCxR register is a read only slave duty cycle register. OCxRS is a buffer register that is written by the user to update the PWM duty cycle. At the end of a PWM period, OCxR is loaded with the contents of OCxRS. An example is shown below:

  OpenOC1( OC_ON | OC_TIMER2_SRC | OC_PWM_FAULT_PIN_DISABLE, 0, 0);

The different configuration constants are shown below. If not specified, the default configuration is used. These constants are mutually exclusive for each category (ie you can only use one of them).

Config Constant Description
OC_ON Turns the Module ON
OC_OFF Default - Turns the Module Off
Stop-in-idle control
OC_IDLE_STOP stop in idle mode
OC_IDLE_CON Default - continue operation in idle mode
16/32 bit mode
OC_TIMER_MODE32 Use 32 bit Mode
OC_TIMER_MODE16 Default - Use 16 bit Mode
Timer select
OC_TIMER3_SRC Timer 3 is clock source
OC_TIMER2_SRC Default - Timer 2 is clock source
Operation mode select
OC_PWM_FAULT_PIN_ENABLE PWM Mode on OCx, fault pin enabled
OC_PWM_FAULT_PIN_DISABLE PWM Mode on OCx, fault pin disabled
OC_CONTINUE_PULSE Generates Continuous Output pulse on OCx Pin
OC_SINGLE_PULSE Generates Single Output pulse on OCx Pin
OC_TOGGLE_PULSE Compare toggles OCx pin
OC_HIGH_LOW Compare1 forces OCx pin Low
OC_LOW_HIGH Compare1 forces OCx pin High
OC_MODE_OFF Default - OutputCompare x Off

For the operation mode, to use PWM one of the first two constants must be used.

The output compare modules use either Timer 2 (default) or Timer 3. These must be set up using OpenTimerX function, where X is either 2 or 3. The period can be between 0 and 0xFFFF inclusive. The OC can be configured to use a 32 bit timer in which both Timer 2 and Timer 3 are used. An example is shown below:

  OpenTimer2( T2_ON | T2_PS_1_1 | T2_SOURCE_INT, 0xFFFF);

The configuration constants are shown below for Timer 2. Replace the 2 with a 3 for Timer 3.

Config Constant Description
T2_ON Turns the Timer ON
T2_OFF Default - Turns the Timer Off
Stop-in-idle control
T2_IDLE_STOP stop in idle mode
T2_IDLE_CON Default - continue operation in idle mode
Timer gate control
T2_GATE_ON Timer Gate accumulation mode ON
T2_GATE_OFF Default - Timer Gate accumulation mode OFF
Prescale values
T2_PS_1_256 Prescaler 1:256
T2_PS_1_64 1:64
T2_PS_1_32 1:32
T2_PS_1_16 1:16
T2_PS_1_8 1:8
T2_PS_1_4 1:4
T2_PS_1_2 1:2
T2_PS_1_1 Default - 1:1
32-bit or 16-bit
T2_32BIT_MODE_ON Enable 32-bit mode
T2_32BIT_MODE_OFF Default
Sync external clock option
T2_SOURCE_EXT External clock source
T2_SOURCE_INT Internal Clock source

The duty cycle can be updated by using SetDCOCXPWM(dutycycle) where X is the module. The duty cycle gets updated on the next cycle. The duty cycle must be less than or equal to the period register defined in Timer 2 or Timer 3. An example is shown below:

   SetDCOC1PWM(PR2 / 2);

The Output Compare module can be closed as shown below:

   CloseOC1();

Calculation Equations 1. PWM Period 2. PWM Frequency 3. Maximum PWM Resolution (bits) 4. Example

Unidirectional Motor Control

This section will detail how to set up 2 simple programs and circuit to control a motor using a PIC microcontroller and PWM. The first program shows how to use a button to switch between 2 duty cycles and the second program shows how to use a timer interrupt to change the duty cycle.

Button Code

This code is based off the NU32 board and hardware profile. If a button called swUser is not defined, the button should be set up. When the button is pushed, the motor will turn off

#include "HardwareProfile.h"

int main(void)
{
	// Configure the proper PB frequency and the number of wait states
	SYSTEMConfigPerformance(SYS_FREQ);
	
	// init OC1 module
	OpenOC1( OC_ON | OC_TIMER2_SRC | OC_PWM_FAULT_PIN_DISABLE, 0, 0);
	
	// init Timer2 mode and period (PR2)
	OpenTimer2( T2_ON | T2_PS_1_1 | T2_SOURCE_INT, 0xFFFF);
	
	while(1)
	{
		if (swUser == 0)
		{
			SetDCOC1PWM(PR2 / 2); // Turns on the motor with 50% duty cycle
		}
		else
		{
			SetDCOC1PWM(0); // Turns off the motor
		}
	}

	CloseOC1();

} //end main

Timer Interrupt Code

This code uses an interrupt with Timer 2 to update the duty cycle. The motor ramps up and down.

First add the usual includes

  #include "GenericTypeDefs.h"
  #include "Compiler.h"
  #include <plib.h>
  #include "HardwareProfile.h"

Define the system frequency (80MHz)

  #define SYS_FREQ				80000000L

Define some variables

  unsigned int Pwm; // variable to store calculated PWM value
  unsigned int Mode = 0; // variable to determine ramp up or ramp down

Begin main body of program

  int main(void)
  {

Configure the proper PB frequency and the number of wait states

  SYSTEMConfigPerformance(SYS_FREQ);

Allow vector interrupts

  INTEnableSystemMultiVectoredInt();

Initialize Output Compare module 1 and Timer 2.

  OpenOC1( OC_ON | OC_TIMER2_SRC | OC_PWM_FAULT_PIN_DISABLE, 0, 0);
  OpenTimer2( T2_ON | T2_PS_1_1 | T2_SOURCE_INT, 0xFFFF);

Set up the Interrupt

  mT2SetIntPriority( 7); 	// set Timer2 Interrupt Priority
  mT2ClearIntFlag(); 		// clear interrupt flag
  mT2IntEnable( 1);		// enable timer2 interrupts

Main Loop

  while(1)
  {}

Close the Output Compare Module

  CloseOC1();

End Main Function

  }

Interrupt Function

  void __ISR( _TIMER_2_VECTOR, ipl7) T2Interrupt( void)
  {
     if ( Mode )
     {
         if ( Pwm <= 0xFFFF ) // ramp up mode
         {
            Pwm ++; // If the duty cycle is not at max, increase
            SetDCOC1PWM(Pwm); // Write new duty cycle
         }
         else
         {
             Mode = 0; // PWM is at max, change mode to ramp down

}

      } // end of ramp up
      else
      {
         if ( Pwm > 0 ) // ramp down mode
         {
             Pwm --; // If the duty cycle is not at min, increase
             SetDCOC1PWM(Pwm); // Write new duty cycle
         }
         else
         {
             Mode = 1; // PWM is at min, change mode to ramp up
         }
      } // end of ramp down
     // clear interrupt flag and exit
     mT2ClearIntFlag();
  } // T2 Interrupt

Associated Circuitry

The Uni-Directional PWM circuit is described in Driving using a single MOSFET . The PIC32 can not supply enough current to open the gate of the MOSFET. Add a buffer between the PIC32 output compare pin and the gate of the MOSFET. A non-inverting chip works well.