…could be used for cooling the Raspberry Pi as well.
A fan controlled by a PWM signal depending on temperature. I implemented 8 ‘on’ stages of fan speed but the routine can be set up to use 1 on-stage (on /off) as well.
The speed of a fan can be controlled by turning it on for some time and turning it off for another period of time. On average there will be a certain rpm (rounds per minute) rate depending on the relation between the on and the off times (the “duty cycle”). The frequency is of secondary importance. I have implemented the PWM signal with 50 Hz which works great with the fan that I am using. There is certainly a upper limit to it as the fan would not start to turn at all with a 50Hz / 10% PWM signal. It certainly would work at approximately 10% if we let it work for 2 seconds and turn it off for 18 seconds (i.e. a frequency of 0.05 Hz). I haven’t tested the PWM signal for such low frequencies however.
The actual software driver of the fan is a python script using the hardware PWM of the Raspberry Pi (GPIO 18). For this purpose I use the Python library wiringpi . The script sets up the GPIO in PWM_OUTPUT mode (2), adjusts range (1200) and clock (320) so that we get a 50Hz output frequency and then writes the duty cycle value according to a command line option, a number between 0 and 100. A value of 10 represents a duty cycle of 10%, that is a 2ms on-pulse followed by 18ms off time. A value of 60 would represent a 12ms on pulse followed by 8ms off time. The good news about the hardware PWM is that the pulsed signal continues on the PWM pin after the script has finished, and no software in the background has to take care that increases CPU load. The resulting script looks simple, although it took me quite some time to get there. The documentation of wiringpi is really bad.
On the hardware side, we have to consider the fact that a fan consumes between 50 to 100mA at a voltage at 5V or even 12V. The Raspberry Pi’s GPIO pins cannot deliver more than 2mA at 3.3V, as everybody knows (hopefully). A NPN transistor as current amplifier will do the switching. My fan operates at 5V, supplied by the Raspberry Pi’s power supply.
Some details about the PWM setup: The base frequency of the PWM generator is 19.2 Mhz. The frequency is determined by pwmSetClock(divider1) and pwmSetRange(divider2). pwmSetClock sets a divider to the base frequency. Its default value is 32. In my example it is 320, so the base frequency gets 19.2MHz / 320 = 600 kHz. The range is not only a second divider, but sets the resolution of the duty cycle as well. Its default value is 1024, the maximum possible value is 4096. In my case, the range is set to 1200, so the PWM frequency gets finally
19.2MHz / 320 / 1200 = 50 Hz
Theoretically I have a duty cycle resolution of 1200, where 0 would be no duty cycle at all (GND), 600 represents a perfect square wave and 1200 would be DC. However I just need 8 stages of it.
The pwmSetMode() function is a bit mysterious; mode 0 is called “mark/space”, which is the known way “usual” PWM works. The other possible mode (1) is called “balanced”. What ever I tried and studied, I cannot make sense of this mode.