20170220

Raspberry Pi 3 CPU Fan Control

PI / GOLANG: Finally got my Raspberry Pi 3 working the way I wanted. It's been on my list of todo-projects for a while. I got it about half a year ago or so - and it was my first foray into Linux. It did not go too well, so that install got to be a real mess.

Since then I've been using Ubuntu more or less daily on my laptops, so I got the urge the other week to try out Ubuntu MATE on the Pi. Got it up and running well enough - but it did not take to updates all that well. It froze dead twice during that process actually. So waited a bit until Ubuntu MATE 16.04.02 got released last week and tried that. This worked fine but for one major niggle - no matter what I did, my Norwegian keyboard layout would not stick between reboots.

So, back to Raspbian. And since last, it's been rebranded PIXEL. Fine. Gave it a go. Worked very well straight out of the box. Though, it would not recognize my WiFi card in the GUI. Some bash-magic fixed that, so got connected to my home network.

Plenty of updates, tweaks and twiddling about later, it is now working like a charm. It's a pretty decent little setup as it happens. Very pleased with it.



Even better, with a bit of investigation I found someone that had been so kind as to compile Visual Studio Code for the Pi. Tried doing this myself, but ran into all kinds of problems with out of date this, missing that and misconfigured other thing. So having it already compiled and available was quite the boon to my efforts.



Most other IDEs (on the Pi anyway) require all kinds of esoteric configurations and fiddling with settings to work flawlessly with my language of choice - Go. Not so with VS Code. Everything is in place after mere minutes, and by and large automagically. It's just wonderful.

With all things performing well and to my taste, I thought it a good idea to give it a proper spin. Do a little project to enhance my Pi. I got this enclosure for my Pi that included heatsinks and a CPU fan. Though I never used the fan after first testing it, as it makes for a rather noisy rattling annoyance when going full tilt. Which is all it would do, as it is a simple two-wire job with no speed control.

Though to protect from overheat having a fan available is always a good idea. The Pi will throttle down the CPU at I think 80'C. However running such temperatures may significantly reduce the lifespan of the CPU. I've even read about people measuring upwards of 100'C on a Pi 3. Obviously, that won't do.

A little fan-control circuitry and code was in order. The circuitry itself is simple enough. A S8050 NPN transistor, a 10 ohm resistor, a tiny bit of proto-typing board and some wires, headers and plugs.



Soldered it up and tested with +5V and +3.3V from a lab PSU - worked as intended.



Next I taped it up with some electrical-tape and crammed it into the Pi enclosure. It fit snuggly between the case and fan.



Hardware done, on with the software. I know plenty of others have done similar - if not identical - projects to this. Though from what I've seen, the software have been done in Python or even as a Bash-script.

That just rubs me the wrong way. Just the interpreter for JIT languages like Python gobbles up a ton of resources before you've even executed a single line of code. Then there is the compatibility issues, the distribution issues, the slowness of the execution. And so on and so forth.

Native binaries for the win! If resources are at a premium, nothing beats C/C++. Well, assembler do, but who got time for that?! Luckily, a Pi3 got reasonable amounts of resources, so Go is a very viable option for writing native apps in. It will be a bit bigger and hungrier than C/C++ due to the inner workings of the concurrency model and garbage collector. But it'll be nearly as fast and lean in execution - and also got all the other advantages of a static native binary.

Anyhow, the full code and binary can be found on my github;

rDybing/PiFanControl

Just download, and move the binary to a location of your choosing. Then to have it start automatically at boot, edit your /etc/rc.local file to include the pifc binary. Remember to put an ampersand at the end to make it run on a thread of its own. My edit look like this:

/etc/fancontrol/pifc &

Pin connections are easy enough;

+5VCC   (red wire)
GND     (black wire)
GPIO-18 (green wire)

Another little note - my application relies on the command '$ vcgencmd measure_temp' not needing sudo. This won't be a problem if running the default user - but if logged in as another user, it may. The solution is to add your user account to root Video-group for some reason. Yeah, don't ask why - you just have to. Here is the command to do that:

>$ sudo usermod -a -G video yourUserNameHere

Nothing too complicated in the code. Fairly straight forward. Anyone who's been fiddling around with Arduino for instance, should be comfortable with both structure and syntax of how to operate the GPIO pins on the Pi using Go.

The one thing worth noting in the code is how the temperature limits are implemented. In most others code I've seen (yes, those dreaded Python and Bash scripts), it's a simple threshold. Above it, turn on, below it turn off.

Which sounds nice and dandy in theory. In practice though, you can get some heavy trashing between the two states as the temperature may fluctuate right on the threshold. So I got a 'deadzone' implemented.


---

func setFan(s *state_t) {
  if s.fanOn {
    if s.tempC < s.limitOff {
      // turn off fan
      s.fanOn = false
      embd.DigitalWrite(fanPin, embd.Low)
    }
  } else {
    if s.tempC > s.limitOn {
      // turn on fan
      s.fanOn = true
      embd.DigitalWrite(fanPin, embd.High)
    }
  }
}


---

As you can see, I use a flag to check if fan is on or off, and then check the limits. The limit for turning on is set to above 65'C and turning off is set to below 63'C.

I check the temperature every other second. In between the app sleeps. At first I tried using a timer rather than sleep - but all that resulted in was one core running at 100%. So even-though I am not a fan of sleep commands in code, here was one of those few times where it was warranted.

It works very well. During testing, running sysbench pushing all four cores to 100%, it will intermittently hit 70'C - but usually hovers around 68-69'C. During normal use, the fan is off naturally as it won't even be close to the threshold to trigger it. But now I got the added safety of having a fan kick in should it be needed.

Now I just need think up another project for my Pi. Probably something server/backend related for an Arduino project I am contemplating :)

4 comments:

  1. I put all the files from your github in my pi/home directory and tried running with 'sudo pifc' and nothing. What am I doing wrong?

    ReplyDelete
  2. Need to install golang via apt-get then 'go get github.com/kidoman/embd' and then set 'export GOPATH=$PWD' now it works.

    ReplyDelete
  3. Adding this to rc.local worked to auto start the fan:

    #!/bin/bash
    export GOPATH=$PWD
    export PATH=$PATH:$(go env GOPATH)/bin
    go get github.com/kidoman/embd
    go run /home/pi/pifc.go

    ReplyDelete
  4. Ah, I see. I assumed Go already being installed on the Pi and properly set up - and having the embd library already downloaded. Anyway, this is only necessary if compiling yourself.

    If just running the binary, being statically linked and all, that should not matter.

    To launch it, just go to wherever you copied the binary to, and type './pifc' or if running on another account than the default one - and added your user to the video-group as explained in the post, launch by 'sudo ./pifc'

    What you are doing there is essentially scripting to set the Go env variables, dl the embd library and compile and run the app.

    You can build your own static binary by using 'go build pifc.go' from where the source file is - assuming you got all the go env paths and working directory set up properly.

    ReplyDelete