Connecting A PWM Fan To A Raspberry Pi

A month or two ago I got a 40mm RGB fan with a cooler. In addition to the usual black and red power input leads, it had a third blue lead for PWM input. This seemed like quite a nice idea, slow down the fan when the Pi doesn’t need it and I’d have a much quieter setup.

RGB Fan With PWM Control

So I plugged the lead into the nominated GPIO pin, downloaded the supplier’s script and ran it, only it didn’t do what I thought it would. The script just turned the fan on at full speed above a certain temperature (I think this was 55°C) and turned it off completely below this temperature.

Pi Fan Connected To Raspberry Pi

A bit puzzled by this odd use of the PWM control pin, I then searched for some other scripts and all of the ones I found had some variant of turning the fan on or off at a certain temperature. Some did this through a python script and some used Raspberry Pi OS’s built-in fan control setting.

Suppliers Script With 0% ot 100% On

This solution obviously has some benefits as the fan is only running when it needs to be. But it isn’t really using PWM control. In fact with the 5-6mA current draw that these fans typically have, you could probably just plug the 5V supply lead into one of the GPIO pins and turn it off directly, you don’t even need a PWM fan. I wouldn’t suggest doing this permanently as there is a higher start-up current and you’ll probably run into issues if you add multiple fans.

So in this tutorial, we’ll fix that and write a script to make proper use of our fan’s PWM input.

Here’s my video trying out the scripts and testing the fan noise, read on for the written instructions:

What You Need For This Tutorial

  • Raspberry Pi 4B (This will work on any Raspberry Pi model) – Buy Here
  • 40mm 5V Noctua PWM Fan (Preferred) – Buy Here
    • or
  • 40mm 5V RGB Fan (Not as quiet) – Buy Here
  • Jumper Leads (For Noctua Fan) – Buy Here
  • Raspberry Pi SSD Desktop Case – Buy Here

Some of the above parts are affiliate links. By purchasing products through the above links, you’ll be supporting this channel, at no additional cost to you.

Testing The 40mm 5V RGB FAN

I started out by writing my own PWM script that actually uses a varying PWM output to control the speed of the fan, not just turn it on or off. The script fetches the CPU temperature, then scales the temperature from a range of between 25 and 80 degrees and turns it into a fan speed between 0 and 100, then sets this as the PWM fan speed.

Creating My Own PWM Fan Control Script

You can download the script from my Github repository. I’ve included instructions further along on installing this script and configuring it to automatically run on startup.

I plugged the fan into 5V, GND and GPIO pin 14.

Then I hit run to try it out.

Pi Fan Running PWM Script

This is when I figured out why these scripts all just use 100% on or off as their so-called PWM control. These fans sound horrible if you actually try varying their speed. Running at any level of reduced speed, they’re way louder than they are when running at full speed, so there really is no point in reducing their speed.

I thought that this might be related to the PWM frequency. I had this initially set at 100Hz, as this is what was in the other scripts, but I tried reducing it to 50Hz, and increasing it to 120Hz. This made very little difference, it just changed the frequency of the noise that the fan produced.

Changing Fan PWM Frequency

And this wasn’t just a bad fan, I literally tested this on over 10 different fans and from different suppliers. Some were a little better or worse than others but they were all noisy to the point where it was quieter to just run the fan at full speed all the time.

RGB 40mm Pi Fans Tested

Testing The 40mm 5V Noctua Fan

I then recalled buying a Noctua PWM fan for a build a while ago that I had never gotten around to using. This has a four-pin connector as it provides RPM feedback as well as PWM control, but we’ll just leave the RPM feedback disconnected for now.

Noctua NF-A4x10

You’ll need to replace the MOLEX connector or use some male-to-female jumpers to pick up on the pins to connect it to your Pi.

Connecting Pins To 4 Pin Connector

Like with the RGB fan, I plugged this fan into 5V, GND and GPIO pin 14 and tried out the same script.

Noctua Fan Connected To Raspberry POi

This time it ran perfectly. Noctua fans are known for being quiet, and being a small 40mm fan you can still hear some fan noise at full speed, but anything under 50% is practically silent. You can also actually slow the fan down to almost zero without any issues or weird noises coming from it – something the RGB fan struggled with.

Installing And Using The PWM Fan Control Script

When I was happy with the way in which the fan control worked, I then cleaned up the script. I actually landed up making two versions of it.

The first is the one that I used for my testing. It turns the fan on when a minimum temperature has been reached and then ramps the speed up sequentially to full speed at the Pi’s thermal throttling temperature of 80 degrees.

Proportional Temperature Script

This is fine for the Noctua fan, but if you use a fan that produces any noise or frequency hum then it gets annoying having the pitch of the sound constantly changing. So the second script addresses this.

The second script ramps up the fan speed in steps rather. So anything over 25 degrees is 25% on and this then increases in steps with each temperature band. This means that the fan operates at a fixed speed for a given temperature range, so the pitch of the sound it makes doesn’t change that often.

Stepped Temperature Script

To install the scripts from my Github repository and get them to run automatically on startup, use the following commands.

Update your Raspberry Pi’s software and reboot the Pi:

$ sudo apt-get update
$ sudo apt-get full-upgrade
$ sudo reboot

Download the fan script from Github:

$ git clone https://github.com/mklements/PWMFanControl.git
$ cd PWMFanControl
$ cp FanProportional.py ~/FanProportional.py
$ cp FanStepped.py ~/FanStepped.py

Set up crontab to run the script automatically on startup:

$ crontab -e

Add one of these lines to the end of the crontab file, depending on which script you’d like to use:

@reboot python3 /home/pi/FanProportional.py &

or

@reboot python3 /home/pi/FanStepped.py &

You can then remove the downloaded folder and reboot your Pi to test it:

$ sudo rm -rf PWMFanControl
$ sudo reboot

If a quieter fan is something you’d like to try, then I definitely recommend getting the 40mm 5V Noctua fan that you can actually PWM control without increasing the fan’s sound. It’s obviously a lot more expensive than the clear RGB ones shipped with most cases and coolers ($15 vs $5.50 at the time of writing), but it might be worth it if you value silence.

Noctua Fan In Raspberry Pi Desktop Case

I’m interested to see if anyone has had any luck with getting the clear RGB fans to run quietly under PWM control, if you have please let me know what you did in the comments section below.

Michael Klements
Michael Klements
Hi, my name is Michael and I started this blog in 2016 to share my DIY journey with you. I love tinkering with electronics, making, fixing, and building - I'm always looking for new projects and exciting DIY ideas. If you do too, grab a cup of coffee and settle in, I'm happy to have you here.

LEAVE A REPLY

Please enter your comment!
Please enter your name here

Latest posts

Taking My Workshop Offgrid Using EcoFlow Power Kits

EcoFlow are a popular name amongst campers and adventurers for their portable power stations and solar generators. These allow you to store power in...

Acrylic Pi Cases, Gweike Cloud Review – Can It Compete With The Glowforge?

If you've seen some of my other projects, I often use my K40 laser cutter to cut and engrave acrylic and plywood sheets to...

Raspberry Pi NAS vs. Asustor Drivestor 4, Is It Better to Buy or DIY?

My current file storage system is a bit of a mess. I save my current video editing libraries on an SSD, I dump the...

Related posts

This project is shared under the Creative Commons License: