I am working with the wiringPi library with C on a Raspberry Pi 3 Model B and attempting to understand and develop a model so that I can predict the blinking behavior of an LED connected to GPIO #18, a pin with the Pulse Width Modulating hardware.
However thus far I can not seem to predict with a comfortable degree of accuracy the behavior I should see. I need someone to provide the basic outline of how the wiringPi library functions are used to specify a particular rate of blinking.
What is a general mathematical model and procedure to use the following PWM related functions of the wiringPi library (practically every posted question seems to have an answer using a different library, pigpio) to figure out the following specific calculations as well as other blinking rates and behaviors?
determine the necessary values and calls to specify a blinking rate of 1 second on and 1 second off?
determine the necessary values and calls to specify a blinking rate of 1 second on and 2 seconds off?
determine the necessary values and calls to specify a blinking rate of 1 second on and a half second off?
I thought that to make the LED turn on for a second and then turn off for one second I could set the PWM clock frequency to 60 hertz and the range to 2 seconds and the Duty Cycle to 50%.
However the pwmSetClock()
does not appear to allow a value large enough to get the PWM clock frequency much below about 4.8 Khz. How can I do this?
I am using Mark Space mode with the PWM pin so that I will have a clear indication of the LED being turned on and then being turned off.
From what I can glean from various postings and questions and answers in this and other stackexchange as well as the wiringPi.org web site is that I need to do the following:
- set the clock divisor using
pwmSetClock()
, range 2 to 4095 - set the range counter using
pwmSetRange()
, range 2 to 4096 - set the Duty Cycle using
pwmWrite()
, range 0 to 1024
The GPIO board will take the clock frequency of 19.2 Mhz and divide it by the clock divisor specified in the pwmSetClock()
call to derive a calculated PWM clock frequency which is then used to decrement the range counter value specified in the pwmSetRange()
call until it reaches zero. Once the range counter reaches zero, the range counter is set back to the value specified in the pwmSetRange()
call and the decrementing is done again.
The Duty Cycle specified with the pwmWrite()
function is used to determine how much of the range is the GPIO pin held HIGH. The accepted range is 0 to 1024, according to the documentation I can find, with 0 meaning a Duty Cycle of 0% and 1024 meaning a Duty Cycle of 100%.
However I am not seeing the LED illumination behavior I expect.
The pwmWrite()
function actually seems to need a value between 0 and the value specified in the pwmSetRange()
call. When I specify a range value of 2,500 and a Duty Cycle value of 1024 expecting the LED to always be on, I instead see blinking. When I use a value of 2,500 then I see the always on behavior I expect.
The default for pwmSetRange()
is 1024 according to the wiringPi documentation so I suppose that is why the wiringPi web site documentation also says the range for the pwmWrite()
function is 0 to 1024?
This then brings into the question the values for the pwmSetClock()
and the pwmSetRange()
calls that I have found. See for instance Control Hardware PWM frequency as well as Driving PWM output frequency
The actual C program I am using to test the LED behavior is as follows. This program sets up the clock and range for the PWM pin and then tries several different Duty Cycle values, each time using delay()
to allow the LED blinking from the PWM to work for 10 seconds, as I observe the LED on my breadboard.
#include <wiringPi.h>
#include <stdio.h>
int main ()
{
// LEDPIN is wiringPi Pin #1 or GPIO #18
// we choose this pin since it supports PWM as
// PWM is not supported by any other GPIO pins.
const int LEDPIN = 1;
if (wiringPiSetup() == -1) {
printf ("Setup wiringPi Failed!\n");
return -1;
}
printf ("Reminder: this program must be run with sudo. Delay 5 seconds.\n");
delay (5000);
printf (" starting now.\n");
pinMode (LEDPIN, PWM_OUTPUT);
// set the PWM mode to Mark Space
pwmSetMode(PWM_MODE_MS);
// set the clock divisor to reduce the 19.2 Mhz clock
// to something slower, 5 Khz.
// Range of pwmSetClock() is 2 to 4095.
pwmSetClock (3840); // 19.2 Mhz divided by 3840 is 5 Khz.
// set the PWM range which is the value for the range counter
// which is decremented at the modified clock frequency.
// in this case we are decrementing the range counter 5,000
// times per second since the clock at 19.2 Mhz is being
// divided by 3840 to give us 5 Khz.
pwmSetRange (2500); // range is 2500 counts to give us half second.
delay (1); // delay a moment to let hardware settings settle.
{
int i;
int list[] = {50, 500, 1024, 2500, -1};
for (i = 0; list[i] > 0; i++) {
// range for the value written is 0 to 1024.
pwmWrite (LEDPIN, list[i]); // set the Duty Cycle for this range.
// delay 10 seconds to watch the LED flash due to the PWM hardware.
printf (" PWM Duty Cycle %d\n", list[i]);
delay (10000);
}
}
// cleanup the environment. set each pin to low
// and set the mode to INPUT. These steps make sure
// the equipment is safe to manipulate and prevents
// possible short and equipment damage from energized pin.
pinMode(LEDPIN, INPUT);
digitalWrite (LEDPIN, LOW);
return 0;
}
pwmWrite()
function I am under the impression that the documentation may have a few assumptions or ambiguities in it here and there. Since what I am seeing with testingpwmWrite()
is showing different from expected behavior than I had from reading the documentation I am wondering what else I may be misunderstanding or is not well documented.