/* * softPwm.c: * Provide 2 channels of software driven PWM. * Copyright (c) 2012 Gordon Henderson *********************************************************************** * This file is part of wiringPi: * https://projects.drogon.net/raspberry-pi/wiringpi/ * * wiringPi is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * wiringPi is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with wiringPi. * If not, see . *********************************************************************** */ #include #include #include "wiringPi.h" #include "softPwm.h" #define MAX_PINS 64 // The PWM Frequency is derived from the "pulse time" below. Essentially, // the frequency is a function of the range and this pulse time. // The total period will be range * pulse time in uS, so a pulse time // of 100 and a range of 100 gives a period of 100 * 100 = 10,000 uS // which is a frequency of 100Hz. // // It's possible to get a higher frequency by lowering the pulse time, // however CPU uage will skyrocket as wiringPi uses a hard-loop to time // periods under 100uS - this is because the Linux timer calls are just // accurate at all, and have an overhead. // // Another way to increase the frequency is to reduce the range - however // that reduces the overall output accuracy... #define PULSE_TIME 100 static int marks [MAX_PINS] ; static int range [MAX_PINS] ; int newPin = -1 ; /* * softPwmThread: * Thread to do the actual PWM output ********************************************************************************* */ static PI_THREAD (softPwmThread) { int pin, mark, space ; pin = newPin ; newPin = -1 ; piHiPri (50) ; for (;;) { mark = marks [pin] ; space = range [pin] - mark ; if (mark != 0) digitalWrite (pin, HIGH) ; delayMicroseconds (mark * 100) ; if (space != 0) digitalWrite (pin, LOW) ; delayMicroseconds (space * 100) ; } return NULL ; } /* * softPwmWrite: * Write a PWM value to the given pin ********************************************************************************* */ void softPwmWrite (int pin, int value) { pin &= 63 ; /**/ if (value < 0) value = 0 ; else if (value > range [pin]) value = range [pin] ; marks [pin] = value ; } /* * softPwmCreate: * Create a new PWM thread. ********************************************************************************* */ int softPwmCreate (int pin, int initialValue, int pwmRange) { int res ; pinMode (pin, OUTPUT) ; digitalWrite (pin, LOW) ; marks [pin] = initialValue ; range [pin] = pwmRange ; newPin = pin ; res = piThreadCreate (softPwmThread) ; while (newPin != -1) delay (1) ; return res ; }