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.