Hot Raspberry Pi

I have a Raspberry Pi 3 that takes care of some IOT odds and ends around here. The other day I noticed it was running a bit warmer than I’d like, so I threw together this quick hack using a 20 mm fan I’d parted out of an old junk laptop a while ago, a 2N2222 transistor, 1N4001 diode, and 1K resistor.

The circuit required looks like this (click on image to see instructables.com article).

Circuit diagram from instructables.com article

First, I bread-boarded a circuit to drive the fan via one of the Pi’s PWM outputs. The Raspberry Pi PWM pins can’t source enough current to drive the fan (and the 3.3V output wouldn’t drive the 5V fan to full speed anyway), so I used a 2N2222 to control the 5V supply. A 10K resistor between the PWM output and the base, emitter to ground, and the collector connected to the fan. The other fan lead goes to the 5V supply. You need a diode across the motor so inductive voltage spikes don’t damage the transistor.

With that tested I fit the parts on a bit of protoboard.

Layout parts

Soldered parts, power, ground, PWM input, fan leads to the board.

Then hacked a hole into the plastic case, mounted the fan, and installed standoffs to hold the board.

Next the protoboard was mounted to the standoffs.

Snapped on the cover and we’re ready to roll.

The code to drive it is fairly trivial. While the fan will run at 30%, it won’t start, so in the function that controls the fan I give it a short kick at 100% to get it going if it was previously off.

/*
Temperature controlled Raspberry Pi cpu fan via hardware PWM
Wiring diagram available here:
https://www.instructables.com/id/PWM-Regulated-Fan-Based-on-CPU-Temperature-for-Ras/
*/

#include <wiringPi.h>

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdbool.h>
#include <string.h>

const int PWM_pin = 1;   /* GPIO 1 as per WiringPi, GPIO18 as per BCM */
bool debug = false;

int main (int argc, char *argv[])
{
	FILE *tempFile;
	int temp;
	double T;
	void setFan(int);

	if ((argc == 2) && (strcmp("-d", argv[1]) == 0))
		debug = true;

	// can't do anything if setup fails
	if (wiringPiSetup () == -1) {
		fprintf(stderr, "wiringPi setup failed");
		exit (1) ;
	}

	// setup output
	pinMode (PWM_pin, PWM_OUTPUT) ; /* set PWM pin as output */

	while (1) {
		// get temperature
		tempFile = fopen("/sys/class/thermal/thermal_zone0/temp", "r");
		if (tempFile == NULL) {
			fprintf(stderr, "File open failed\n");
			exit(1);
		}

		fscanf(tempFile, "%lf", &T);
		T /= 1000;
		if (debug)
			printf("CPU temperature is %6.3f C\n", T);
		fclose(tempFile);
		temp = (int) T;		// don't care about details, so just truncate it

		setFan(temp);
		sleep(10);
	}

	exit(0);
}

// set fan speed based on CPU temperature
void setFan(int temp) {
	long map(long, long, long, long, long);
	int speed;
	static int last_speed = 0;

	if (temp < 50)			// under 50C don't run fan
		speed = 0;
	else if (temp > 80)		// anything over 80 run 100%
		speed = 100;
	else {					// vary speed as temp increases
		speed = map(temp, 50, 80, 30, 100);
	}

	if (speed != last_speed) {
		if (debug)
			printf("Setting fan to %d\n", speed);

		if (last_speed == 0) {
			pwmWrite(PWM_pin, 100);		// give it a kick start
			delay(100);					// let fan start
		}
		pwmWrite(PWM_pin, speed);
		last_speed = speed;
	}
}

long map(long x, long in_min, long in_max, long out_min, long out_max)
{
	return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
}

I installed the compiled program in /usr/local/bin and added a line in rc.local to run it when the Raspberry Pi boots. Where I’ve set the temperature threshold, the fan kicks on occasionally while the Pi is idle. As soon as any sort of load is added, the fan starts almost immediately and speeds until the temperature levels off. The fan provides more air than is actually needed to keep the Pi cool, as even under full load the fan doesn’t come up to full speed.

Leave a Reply

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