NU32v2: Output Compare, PWM, and Analog Output
*** UNDER CONSTRUCTION ***
"Output compare" refers to the fact that the count of a timer is compared against one or two fixed values, and when they are equal, a digital output is set high or low. This can be used to generate a single pulse of specified duration or a continuous train of pulses.
Like most microcontrollers, our PIC does not come with analog output (DAC). Instead, one way to transmit an analog value is by using the timing of a fixed period pulse train from a single digital output: the analog value is proportional to the duty cycle of the pulse train, where the duty cycle is the percentage of the period that the signal is high. This is sometimes called "pulse width modulation" (PWM). This high-frequency switching signal can be low-pass filtered to create an analog output.
Overview
The output compare peripheral can be configured to operate in a number of different modes. In all modes, the module uses either the count of the 16-bit timer Timer 2 or Timer 3, or the count of the 32-bit timer Timer 23, depending on the Output Compare Control register OCxCON (where x=1..5 is the particular module). The timer must be set up with its own prescaler and period register, which will influence the behavior of the OC peripheral.
The OC peripheral supports 7 different operating modes: 3 "single match" modes, 2 "dual match" modes, and 2 PWM modes, as chosen by three bits in OCxCON. In the single match modes, the count is compared to a single value (in OCxR). When they match, the OC output is either set high, cleared low, or toggled, depending on the mode. Thus the last mode generates a continuous pulse train, with the period determined by the period of the Timer base.
In the dual match modes, the count is compared to two values, OCxR and OCxRS. On the first match, the output is driven high, and on the second the output is driven low. Depending on a bit in OCxCON, either a single pulse is generated or a continuous pulse train is produced.
The 2 PWM modes also create a continuous pulse train. Each pulse begins (is set high) at roll-over of the timer base. The output is then set low when the timer count reaches OCxR. To change the value of OCxR, the user's program may set the value in OCxRS at any time. This value will then be transferred to OCxR at the beginning of the new time period. If the time base of the OC peripheral is the 16-bit Timer 2, then the duty cycle of the pulse train is (OCxR/PR2)x100%.
The 2 PWM modes also offer the use of a fault protection input. If this is chosen, then the OCFA pin (corresponding to OC1 through OC4) or the OCFB pin (corresponding to OC5) must be high for PWM to operate. If the pin is logic low, then the PWM output will be high impedance.
Details
Single match: interrupt flag is set on match event.
Dual match: interrupt flag is set on the falling edge of the pulse (match to OCxRS).
PWM: interrupt flag is set each time the base timer resets.
Library Functions
Library functions can be found in pic32-libs/include/peripheral/outcompare.h.
- OpenOCx(config, value1, value2): Sets OCxCON to config (turns OC peripheral x on, sets the mode, and chooses the timer source), OCxR to value1, and OCxRS to value2. In PWM mode, OCxR is the initial duty cycle and OCxRS is what the duty cycle will be set to be on the next period.
- SetDCOCxPWM(dutycycle): Sets OCxRS equal to dutycycle.
Sample Code
Sample code for PWM:
OpenTimer2(T2_ON | T2_PS_1_4, 1000); // 20kHz PWM: 80000000Hz / 4ps / 1000 = 20 kHz OpenOC1(OC_ON | OC_TIMER2_SRC | OC_PWM_FAULT_PIN_DISABLE, 0, 0); // PWM output on Pin D1, 0 duty cycle SetDCOC1PWM(duty); // unsigned int duty from 0-1000
More Information
To get an analog output from a PWM signal, you can use a passive RC low-pass filter to "average" the PWM signal. Attach one end of a resistor R to the OC output, and attach the other end to a capacitor C. Attach the other end of the capacitor C to ground. You can measure the voltage across the capacitor. This RC circuit will low-pass filter the OC output, with a cutoff frequency of Hz. You should choose the RC values so your cutoff frequency is sufficiently below the PWM frequency, so you don't see significant high-frequency ripples in the output. For example, if your PWM is at 20 kHz, you might choose an RC cutoff of around 200 Hz. For R = 1 k, we get C = 0.8 uF (approximate as 1 uF), and for R = 10 k, we get C = 0.1 uF.