Today I am going to introduce a peripheral. So far we have interacted with the I/O pins on the micro controller. This can get you pretty far and if you can manipulate the pins quickly enough you can produce nearly any signal. However, there are times when the signal must be generated continuously and your MCU must perform other tasks.
Today we will be generating a PWM signal. PWM stands for Pulse Width Modulation. The purpose of PWM is to produce a fixed frequency square wave but the width of the high and low pulses can be adjusted. By adjusting the percentage of the time the signal is high versus low, you can change the amount of energy in a system. In a motor control application, changing the energy will change the speed. In an LED application, changing the energy will change the brightness. We will use the PWM to change the brightness of the LED on our demo board.
Here is a sample of a PWM signal. The PWM frequency is 467.3hz and the duty cycle is 35%.
One way to produce such a signal is to execute a bit of code such as this one.
This code does not help you if you are writing in C but it will serve to show the challenges of this technique. This is a simple macro that must be executed numerous times to produce the entire PWM cycle. The PWM frequency is determined by how often this macro can be called. So one option is quite simply this:
But if you do this the MCU will not be able to perform any other functions.
Here is one that updates the PWM duty cycle every time the reload variable overflows. This is not a lot of additional work but the MCU is still 100% consumed toggling a pin and deciding when to update the duty cycle. Surely there is a better way.
Enter a Peripheral
MCU Peripherals are special hardware functions that can be controlled by the software but do some tasks automatically. One common peripheral is the PWM peripheral. Different MCU have different peripherals that can produce a PWM signal. For instance, older PICmicrocontrollers have the CCP (Capture, Compare, PWM) peripheral and newer PICmicrocontrollers have dedicated PWM's. To demonstrate the use of this simple peripheral I will switch to C and give some code.
The good side to using a peripheral is the work it takes on. The down side is the additional effort required to setup the additional hardware. Microchip provides a tool call MCC to do this work but in this example, we will do the work ourselves. Fortunately, Microchip provided a section in the data sheet that provides an 8 step checklist for configuring the PWM.
Time for doing the steps
// Steps from Chapter 30.9 of the datasheet
// Step 1
TRISAbits.TRISA2 = 1;
// Step 2
PWM6CON = 0;
// Step 3
T2PR = 0xFF;
// Step 4
PWM6DC = 358 << 6;
// Step 5
T2CLKCONbits.CS = 1;
T2CONbits.CKPS = 0;
T2CONbits.ON = 1;
// Step 6
// Step 7
TRISAbits.TRISA2 = 0;
RA2PPS = 0x0D;
// Step 8
PWM6CONbits.EN = 1;
And here is 35% just like before, except last time the period of the entire wave was 2.14ms and now it is 0.254ms. That is about 10x faster than before.
This time the main loop is doing absolutely nothing making it possible to do all kinds of neat things like implement a flicker to make the LED look like a candle.
PWM6DC = rand() % 1024 << 6;
So here is a candle. Through honestly it is not the best looking candle. Perhaps you can do a better job.
Peripherals can be a huge time saver and can certainly provide more CPU in your application for the real "secret sauce". Most of the data sheet covers peripherals so we will go through a few of them in the next few weeks.