You have to bypass the analogWrite
function in the abstraction layer
and talk directly to the hardware to do this. You will need to program
one of the timers, and one or more of the output compares to do this.
The Output Compare units in the PIC32 can work from either Timer2 or
Timer3. The analogWrite
code uses Timer2. If you don't
need analogWrite
to work, I would use Timer2. If you
need analogWrite
to work as well, use Timer3. The Output Compare sets
the pin when the timer resets. The timer then counts up from 0. The
Output Compare resets the pin when the the value in the timer matches
the value in the ouput compare register. The counter continues to count
up until the count value matches the value in the period register. The
timer then resets and it all starts over again. Also at the end of a
period the contents of the duty cycle buffer register(OCxRS) is loaded
into the duty cycle register(OCxR). The frequency of the resulting PWM
signal is determined by the clock speed of the timer, and the value in
the period register. The clock speed of the timer is determined by the
peripheral bus frequency and the prescaler selected. The peripheral bus
frequency is 80 MHz (at least this is the default set by the boot
loader). The prescaler can be selected to be 1:1, 1:2, 1:4, up to 1:256.
So for example, with a 1:8 prescaler selected, the 80 MHz would be
divided down to 10 MHz and that is the timer clock frequency (i.e. the
timer counts up 1 every 100ns). The value in the period register
determines when the counter resets. So, for example if you set the
period register to 10000, you would get a reset at 10000*100ns, or
every 1 ms. This is a frequency of 1 kHz. To get a 12-bit PWM, you could
load the period register with 4096 (2^12). With the 1:8 prescaler, this
would give a frequency of about 2.4 kHz.
The following code will initialize Timer2 with the 1:8 prescaler and a period value of 4096
T2CONCLR = T2_ON // Turn the timer off
T2CON = T2_PS_1_8; // Set prescaler
TMR2 = 0; // Clear the counter
PR2 = 4096; // Set the period
T2CONSET = T2_ON; // Turn the timer on
The following code will set output compare 1 to use Timer2 and a PWM value that would give a 50% duty cycle.
OC1R = 2048; // Load initial value into duty cycle register
OC1RS = 2048; // When a period finishes the contents of OC1RS is loaded to OC1R
OC1CON = OC_TIMER2_SRC | OC_PWM_FAULT_PIN_DISABLE; // Set Timer2 as source | enable pwm mode without fault protection
OC1CONSET = OC_ON;
This example code is taken (and slightly modified) from the code
for analogWrite
. This is in the file wiring_analog.c in the core
files. These statements are all writing directly to the peripheral
registers for Timer2 and Output Compare 1. For more complete details,
you should refer to the Timer and Output Compare sections of the PIC32
Family Reference Manual that can be downloaded from the Microchip web
site.