1

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;
}
8
  • I think the wiringPi site on-line documentation for hardware PWM is accurate. I have never had a reason to doubt it.
    – joan
    Commented Dec 2, 2017 at 21:11
  • @joan with the difference in the behavior of the 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 testing pwmWrite() 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. Commented Dec 2, 2017 at 21:43
  • You are probably right, I have never studied the documentation in great detail. I don't like the way wiringPi provides control over hardware PWM, I believe (my) pigpio uses a better model.
    – joan
    Commented Dec 2, 2017 at 21:50
  • 1
    I don't understand why people model PWM on the Pi in this way. To me there are two characteristics of PWM, i.e. the frequency and the duty cycle. Nothing else is relevant to the user. It seems that people are slavishly following the method the hardware uses to set up PWM. They should really conceal those details from the end user. You'll need to look at the code and see what it actually does with the numbers and how the hardware uses them.
    – joan
    Commented Dec 3, 2017 at 3:41
  • 1
    @joan I took a look at the wirePi library code. It looks like there will need to be an investment in developing an understanding of the Broadcom GPIO interface and the code I read looks to be doing a bit of esoteric pointer stuff that is not well commented so I am going to have to pull it down into an IDE for an investigation into the memory model used. I am not sure as to the reason behind the hardware architectural choices which is reflected in the source code. The Broadcom doc I found does not go into much detail. Commented Dec 3, 2017 at 4:22

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Browse other questions tagged or ask your own question.