softPwm.c 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166
  1. /*
  2. * softPwm.c:
  3. * Provide 2 channels of software driven PWM.
  4. * Copyright (c) 2012-2014 Gordon Henderson
  5. ***********************************************************************
  6. * This file is part of wiringPi:
  7. * https://projects.drogon.net/raspberry-pi/wiringpi/
  8. *
  9. * wiringPi is free software: you can redistribute it and/or modify
  10. * it under the terms of the GNU Lesser General Public License as
  11. * published by the Free Software Foundation, either version 3 of the
  12. * License, or (at your option) any later version.
  13. *
  14. * wiringPi is distributed in the hope that it will be useful,
  15. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  17. * GNU Lesser General Public License for more details.
  18. *
  19. * You should have received a copy of the GNU Lesser General Public
  20. * License along with wiringPi.
  21. * If not, see <http://www.gnu.org/licenses/>.
  22. ***********************************************************************
  23. */
  24. #include <stdio.h>
  25. #include <pthread.h>
  26. #include "wiringPi.h"
  27. #include "softPwm.h"
  28. // MAX_PINS:
  29. // This is more than the number of Pi pins because we can actually softPwm
  30. // pins that are on GPIO expanders. It's not that efficient and more than 1 or
  31. // 2 pins on e.g. (SPI) mcp23s17 won't really be that effective, however...
  32. #define MAX_PINS 1024
  33. // The PWM Frequency is derived from the "pulse time" below. Essentially,
  34. // the frequency is a function of the range and this pulse time.
  35. // The total period will be range * pulse time in µS, so a pulse time
  36. // of 100 and a range of 100 gives a period of 100 * 100 = 10,000 µS
  37. // which is a frequency of 100Hz.
  38. //
  39. // It's possible to get a higher frequency by lowering the pulse time,
  40. // however CPU uage will skyrocket as wiringPi uses a hard-loop to time
  41. // periods under 100µS - this is because the Linux timer calls are just
  42. // accurate at all, and have an overhead.
  43. //
  44. // Another way to increase the frequency is to reduce the range - however
  45. // that reduces the overall output accuracy...
  46. #define PULSE_TIME 100
  47. static volatile int marks [MAX_PINS] ;
  48. static volatile int range [MAX_PINS] ;
  49. static volatile pthread_t threads [MAX_PINS] ;
  50. static volatile int newPin = -1 ;
  51. /*
  52. * softPwmThread:
  53. * Thread to do the actual PWM output
  54. *********************************************************************************
  55. */
  56. static PI_THREAD (softPwmThread)
  57. {
  58. int pin, mark, space ;
  59. struct sched_param param ;
  60. param.sched_priority = sched_get_priority_max (SCHED_RR) ;
  61. pthread_setschedparam (pthread_self (), SCHED_RR, &param) ;
  62. pin = newPin ;
  63. newPin = -1 ;
  64. piHiPri (90) ;
  65. for (;;)
  66. {
  67. mark = marks [pin] ;
  68. space = range [pin] - mark ;
  69. if (mark != 0)
  70. digitalWrite (pin, HIGH) ;
  71. delayMicroseconds (mark * 100) ;
  72. if (space != 0)
  73. digitalWrite (pin, LOW) ;
  74. delayMicroseconds (space * 100) ;
  75. }
  76. return NULL ;
  77. }
  78. /*
  79. * softPwmWrite:
  80. * Write a PWM value to the given pin
  81. *********************************************************************************
  82. */
  83. void softPwmWrite (int pin, int value)
  84. {
  85. pin &= (MAX_PINS - 1) ;
  86. /**/ if (value < 0)
  87. value = 0 ;
  88. else if (value > range [pin])
  89. value = range [pin] ;
  90. marks [pin] = value ;
  91. }
  92. /*
  93. * softPwmCreate:
  94. * Create a new softPWM thread.
  95. *********************************************************************************
  96. */
  97. int softPwmCreate (int pin, int initialValue, int pwmRange)
  98. {
  99. int res ;
  100. pthread_t myThread ;
  101. if (range [pin] != 0) // Already running on this pin
  102. return -1 ;
  103. if (range <= 0)
  104. return -1 ;
  105. pinMode (pin, OUTPUT) ;
  106. digitalWrite (pin, LOW) ;
  107. marks [pin] = initialValue ;
  108. range [pin] = pwmRange ;
  109. newPin = pin ;
  110. res = pthread_create (&myThread, NULL, softPwmThread, NULL) ;
  111. while (newPin != -1)
  112. delay (1) ;
  113. threads [pin] = myThread ;
  114. return res ;
  115. }
  116. /*
  117. * softPwmStop:
  118. * Stop an existing softPWM thread
  119. *********************************************************************************
  120. */
  121. void softPwmStop (int pin)
  122. {
  123. if (range [pin] != 0)
  124. {
  125. pthread_cancel (threads [pin]) ;
  126. pthread_join (threads [pin], NULL) ;
  127. range [pin] = 0 ;
  128. digitalWrite (pin, LOW) ;
  129. }
  130. }