Introduction: CPU & GPU Driven Fan Controller

About: I like designing useful devices. Also, I’m a vegatarian.

I recently upgraded my graphics card. New GPU model has higher TDP than my CPU and an old GPU, so I also wanted to install additional case fans. Unfortunately, my MOBO has only 3 fan connectors with speed control, and they can only be linked to the CPU or chipset temperature. I decided to remedy this, by designing my very own PC fan controller that reads RPM speeds of already installed fans (both those connected to the MOBO and driven by CPU temp and the ones that cool GPU) and has two output channels. Channel A uses speed of both CPU & GPU temperature linked fans to drive 3-pin output fans with variable speed. Channel B senses only GPU fans speed and its output circuit uses additional transistor that allows to achieve lower speeds of fans driven by it (it works well with semi-passive graphics card).

Reading other fans speed in my opinion is easier and cheaper than installing additional temperature probes right next to processors covered in heatsinks (it basically requires connecting fans tachometers wire directly to a microcontroller pin).

Some of the methods of controlling fan speeds are described here. I decided to use low-frequency PWM, but with few modifications to the method described in the article. Firstly, each channel has 6 diodes connected in series, that can be used to reduce voltage that powers a fan by 4-5V. In this setup, PWM voltage levels are ~8V – 12V and 0V - ~8V (not available in Channel A) instead of 0V – 12V. This greatly reduces noise produced be the fan. Another trick that I used to make fan controlled in this fashion more silent is described here. This trick requires installing RC circuit between microcontroller’s output and a gate of a MOSFET that I used to switch fan’s voltage levels. This reduces slew rate of a signal that controls the MOSFET, in turn making fan’s angular jerk during voltage level change less prominent, cutting vibration and voltage spikes.


Parts and materials:

  • ATtiny13 or ATtiny13A in a 8-PDIP case
  • 8 Pin DIP Socket
  • 3x IRF530 transistor
  • 12x 1N4007 diode (any other 1A diode with voltage drop of around 0.7V should work)
  • 220uF/25V radial electrolytic capacitor
  • 10uF/16V radial electrolytic capacitor
  • 5x 100nF ceramic disc capacitor
  • 10k 0.25W resistor
  • 4x 22k 0.25W resistor
  • 2x 1k 0.25W resistor
  • 6x6mm tactile switch button
  • 2x 2 pin 2.54mm straight male pin header
  • 4x 3-pin male fan connector (Molex 2510), alternatively, you can use regular pin headers if you want to (I did it), but then you have to be extra careful when connecting fans, and female connectors of those fans will be attached less securely
  • 4-pin Molex connector, female housing/male pins (AMP MATE-N-LOK 1-480424-0 power connector), I used one that was part of Molex male to 2x SATA female adapter bundled with some old MOBO
  • 2x jumper cables with 2.54mm female connectors (or connector housings + pins + wires), they will be soldered to input fans tachometer wires (or directly to their connectors on PCBs)
  • prefboard (50mm x 70mm, min 18 x 24 hole array), alternatively, you can etch copper clad board yourself and drill holes
  • few pieces of wire
  • insulating tape
  • aluminum foil tape (if you are going to attach connector to the GPU backplate, see Step 5)
  • paper


  • diagonal cutter
  • pliers
  • flat-bladed screwdriver
  • utility knife
  • multimeter
  • soldering station
  • solder
  • AVR programmer (standalone programmer like USBasp or you can use ArduinoISP
  • breadboard and jumper cables that will be used to program microcontroller outside of PCB (or any other tool that can achieve this goal)

Step 1: Disclaimer

Construction of this a device requires use of moderately dangerous tools and may cause harm or damage to property. Some of the required steps may void a warranty of your hardware or even damage it when improperly conducted. You build and use described device at your own risk.

Step 2: How Fan Control Works

Channel A uses two inputs. Each of those Channel A inputs has a level associated with it, lets call those levels A0 and A1. By default both of those levels are 0. Both inputs have threshold RPM values associated with them (3 thresholds per input). When first threshold is achieved, A0 or A1 increases to 1, when second it increases to 2, and the third threshold sets one of the input levels to 3. Later A0 and A1 are combined (simply added together and prevented from achieving a value higher than 3), making main output Channel A level number in 0-3 range. This number is used to control output fans speed, 0 means that they are powered by 7-8V (duty cycle of 0%). Higher output levels mean that fan is powered from full 12V for 33%, 66% or 100% of a 100ms or 33ms cycle (it depends on selected frequency).

Channel B has only one input (B1, physically it is shared with Channel A [PB1 pin]). There are six possible B1 levels (1-6), default level is 1. Five threshold values exist, which are able to increase B1. B1 is used as main output Channel B level. When it is 1, 7-8V powers output fans for 33% of cycle time in one cycle, in the other one for 66%, for the rest of the time power is disconnected. Level 2 means 66% of every cycle is 7-8V, rest 0V. Level 3 means that 7-8V is constantly applied. Levels 4-6 mean that fan is powered from full 12V for 33%, 66% or 100% of the cycle, for the rest of the time voltage is 7-8V.

Frequency of this PWM control by default is 10Hz. It can be increased to 30Hz by closing J7 jumper pins.

When higher threshold is reached, A0, A1 and B1 levels increase instantaneously. When RPMs fall however, level is held for 200ms and may only decrease by 1 per 200ms. It is to prevent rapid changes of those levels when input fan RPM is very close to the threshold.

Step 3: Soldering Electronic Components

Solder all electronic components to the prefboard (except Attiny13, it will be later put inside a socket). Use copper wires (0.5 mm diameter ones from UTP cable should be perfect) to make electrical connections between components. If you have trouble with pushing large wires coming out of Molex(AMP MATE-N-LOK) connector, you can drill larger holes for them. If you don’t want to use a drill you can always turn a screw few times inside small prefboard holes. Make sure that wires do not cause any short-circuits.

If you prefer to make your own PCB I also provide .svg (board dimensions are 53.34x63.50mm) and .pdf (A4 page size, inside .zip archive) files. Single sided copper clad board should suffice, as there is just one connection on the front side (it can be made with a wire), so files for the front side are provided main so that this connection can be identified.

I strongly recommend that you cover back of PCB with some insulating material that will prevent any accidental short circuits. I used few layers of regular paper that are held to the PCB’s edges by few strips of insulating tape.

Step 4: Programming ATtiny Microcontroller

Program that is running on the MCU has hard-coded several thresholds of input fans RPM speeds. Those thresholds are located at the beginning of fan_controller.c file. Line that contains first threshold, which is responsible for slightly increasing Channel A output level in response to input_0 fan exceeding 450 RPM, looks like this:

#define A0_SPEED_0 3 // 450 RPM

If you want to change threshold RPM value, then you need to replace number 3 with something else. Incrementing this number by 1 will change threshold by 150 RPM.

Other thing that you may want to change is decrease of output level delay. This delay prevents output level rapid changes when input fan RPM is very close to the threshold. There are 3 lines that control this (as Channel A use 2 inputs and Channel B uses 1) and first of them looks like this:

    if(channel_A0_lower_rpm_cycles > 2) {

Increasing number 2 will increase this delay. Delay is counted in 100ms cycles.

To compile source code and then program chip you will need some software. On a Debian-based Linux distribution it can be installed by executing following command:

sudo apt-get install avr-libc gcc-avr avrdude

If you are using Windows you may try installing WinAVR suite, which also contains required software.

To compile source code you need to execute this:

avr-gcc -mmcu=attiny13 -Os -Wall fan_controller.c -o fan_controller.out -lm

To create .hex file you need to copy this line into terminal:

avr-objcopy -O ihex -R .eeprom fan_controller.out fan_controller.hex

This command allows to check how much memory will program use (text is Flash, data are variables that will be stored in Flash and then copied into RAM, and bss are variables initialized with a value of 0 in RAM) :

avr-size fan_controller.out

When your .hex file is ready you need to insert ATtiny13 into breadboard and connect it to the programmer with jumper cables. It is best to disconnect power from the programmer when you are connecting it to the MCU. Keep default fuse bits (H:FF, L:6A). If your programmer is USBasp this command will program MCU’s flash memory:

avrdude -c usbasp -p t13 -B 8 -U flash:w:fan_controller.hex

-B 8 changes speed of transmission between programmer and MCU (bitclock). You may need to change it to a higher value if you have problems with connecting to the microcontroller.

When MCU us ready, put it inside DIP 8 socket. To remove MCU from breadboard I usually pry it with flat-bladed screwdriver.

Step 5: Connecting Fans to the Device

As a Input 0 fan (the one connected to the PB0) I selected one of the case fans plugged into MOBO, which speed varied with CPU temperature. I removed insulation from the part of fan’s tachometer wire and soldered one end of jumper cable to it. The other end (with 2.54mm female connector attached to it) will be connected to the fan controller. If jumper cable is too short, extend it by soldering another cable between the ones previously mentioned. Then cover all exposed conductors with insulation tape.

Input 1 reads speed of GPU fans (in my case there are actually 3 of them, but there is only one fan connector on the graphics card PCB). I soldered Input 1 jumper cable directly to one of the leads of 4-pin mini GPU fan connector located on the PCB. As this lead was located between PCB and backplate, I insulated backplate with a piece of paper first (especially because backplate’s material was quite solderable) and then firmly attached female connector of the cable to the other side of backplate with the use of aluminum foil tape. Then GPU fan(s) could be connected to PB1 pin with the use of another (extended) jumper cable. If you don’t want to solder anything on your graphics card PCB you can attach jumper cable to the fan’s wires or make adapter that will be placed between fan(s) and connector on PCB, the decision is yours.

Fan transmits its current speed through tachometer wire by the means of connecting this wire to the ground via open drain/collector two times per rotation (fan’s rotor usually has 4-poles[NSNS] which are detected by Hall sensor, fan’s output goes low when on type of pole is detected). On the other side, this wire is usually pulled to the 3.3V voltage level. If you are not sure if you got the right wire you may use oscilloscope or build one of the detection circuits that are draw on the last picture in this step. First of them allows you to check maximum voltage that appears in measured location, the second to check if low frequency pulses appear there.

3.3V should be read by ATtiny’s input pins as HIGH state, but if you have problems with this, you may try to reduce voltage that powers MCU (it will increase resistance of MOSFETs as well!). I didn’t have any problems, nevertheless, I decided that I should include this thought here.

When input fans are ready, you may place fan controller inside your PC case, in a place of your choosing. I mounted it to the side of two of my empty 5.25” drive bays, by pushing it between metal parts of the bay, placing some paper behind it and locking it in place with the use of a zip tie pushed through one of the large holes in prefboard and some other holes in the 5.25” bay. Make sure that no metal parts of the PC case can touch any of the fan controller’s exposed conductors.

Now you can connect 3-pin output fans to the controller. Output fans connected to the Channel A will be linked to both CPU and GPU fans, and minimum voltage that will power them will be about 7-8V. Fans plugged into the Channel’s B output connectors will be driven only by the GPU cooler fan(s) and their voltage may drop to 0V (but only for 66ms every second 100ms cycle at the lowest output drive level). Fans should not draw more than 1A per output channel.

Step 6: Other Changes That I Made to My PC

Channel A drives two fans located on the top of my case. They are the same model and they are powered by the same voltage, which makes them spin at very similar speeds. Some audible beat (interference pattern between two sounds of slightly different frequencies) appeared as a result of that. To remedy this I installed 2 diodes (one regular one and one Schottky) in series with one of the fans. This reduced that fan voltage and speed, making beat go away.

Another change, which is related to one of those to fans that I made, is installation of a paper wall bellow top fan located more to the front. Its purpose is to prevent this fan from sucking air that haven’t passed through any of the heatsinks yet. I also tried make other paper walls that prevented GPU exhaust air from being sucked into CPU cooler. They actually reduced CPU temp, but at the cost of GPU heating up more, so in the end I removed them.

Other unusual modification that I made is removal of dust filter at the exhaust of those two top fans (most of the time air is being pushed out of the case anyway, and when my PC is off, drawer located slightly above the PC case shields it from dust). I also installed 92mm fan in front of two empty 5.25” drive bays (fan controller is located just behind it). This fan is not held by any screws, just fits nicely between 120mm fan bellow it and optical drive above (surfaces of both of them are covered with insulation tape to provide some vibration dampening).