Controling 5V fan with RaspberryPi (poor man’s PWM)

My 5V RaspberryPi fan was very loud and annoying, so I wanted a solution to regulate the fan depending on the Pi temperature.

To achieve that, I used a mosfet switch, pulled out from an old computer motherboard, followed by some easy bash scripting.

Almost any mosfet from an old computer motherboard should work.

motherboard_mosfet

Wiring:

mosfet_fan_schematics

You can use any not used GPIO to connect the gate pin, in the picture above it’s #23.

mosfet_fan_schematics2

I connected the mosfet pin to GPIO 19 in my case. You can choose  your own.

Software:

sudo apt-get update
sudo apt-get install bc

Enable selected GPIO pin, In my case, GPIO 19

echo "19" > /sys/class/gpio/export
echo "out" > /sys/class/gpio/gpio19/direction

If you wan’t to select another GPIO and you already exported one GPIO, you need to unexport previous GPIO.

echo "19" > /sys/class/gpio/unexport

Bash script for controlling fan “speed”:

pico rpipwm.sh

Paste the script bellow, edit your GPIO pin and save:

#!/bin/bash
#Poor man's PWM
#16.11.2015 by S55MA
#Quick and dirty script for controlling fan speed on RaspberryPI
#No rights reserved

#Define GPIO pin
pin="19"

while true; do

#Read temp
temp=$(cat /sys/class/thermal/thermal_zone0/temp | awk 'NR == 1 { print $1 / 1000}' | cut -c -4)

#If temperature is equal or lower than 39.99, the fan will stop spinning
if [[ $(bc <<< "$temp <= 39.99") == 1 ]] ;
then
$(echo "0" > /sys/class/gpio/gpio$pin/value)
fi

#If temperature is between 40 and 42.99, the fan will start with 1 second burst and 1 second sleep
if [[ $(bc <<< "$temp >= 40 && $temp <= 42.99") == 1 ]] ;
then
$(echo "1" > /sys/class/gpio/gpio$pin/value; sleep 1; echo "0" > /sys/class/gpio/gpio$pin/value; sleep 1)
fi

#If temperature is between 43 and 47.99, the fan will start with 1 second burst and 0.5 second sleep
if [[ $(bc <<< "$temp > 43 && $temp <= 47.99") == 1 ]] ;
then
$(echo "1" > /sys/class/gpio/gpio$pin/value; sleep 1; echo "0" > /sys/class/gpio/gpio$pin/value; sleep 0.5)
fi

#If temperature is equal or higher than 48, the fan will start spinning constantly
if [[ $(bc <<< "$temp >= 48") == 1 ]] ;
then
$(echo "1" > /sys/class/gpio/gpio$pin/value)
fi
sleep 0.1
done
chmod +x rpipwm.sh
./rpipwm.sh

Enable auto start at boot:

sudo cp rpipwm.sh /etc/init.d/rpipwm.sh
sudo chmod +x /etc/init.d/rpipwm.sh
sudo update-rc.d /etc/init.d/rpipwm.sh defaults

or you can use crontab:

crontab -e

Add and save:

@reboot /path/to/script/rpipwm.sh
sudo update-rc.d cron defaults

5 comments

  1. Good, but you doesn’t explain too much about the mosfet. I don’t know a lot about eletronics, so it’s kind hard to understand. For example, it’s a p-channel or n-channel mosfet? If I would by one, which one should fit?

  2. Hi, I recently went through your tutorial and got it to work, so thank you for posting it!

    The only issue i’m having is that I have to go into the terminal and enter the following commands:

    echo “23” > /sys/class/gpio/export
    echo “out” > /sys/class/gpio/gpio23/direction

    Otherwise the fan will not come on in accordance with the rpipwm.sh script.

    Once I’ve run the commands, everything works fine, but I’d prefer to not have to run it every time I reboot.

    Thanks in advance!

    1. Open /etc/rc.local add this two lines, save and it should work at reboot:
      echo “19” > /sys/class/gpio/export
      echo “out” > /sys/class/gpio/gpio19/direction

        1. Now that it is working, it seems to be coming on and off at temperatures different than what I measure via ‘vcgencmd measure_temp’. Is there another way of measuring that the software is using to give it different readings?

Leave a Reply

Your email address will not be published. Required fields are marked *