Arduino Nano PWM Fan Breadboard

Solving the DL180 G6 Fan Controller Problem

Some time ago I acquired a DL180-G6 rack mount server for very little money as these go for next to nothing on eBay in most configurations and one version has 12×3.5″ drive bays. Unfortunately there seems to be a bit of a problem with these systems where if you change any of the hardware (such as an unsupported raid card) or a whole variety of other things the on board fan controller defaults to high speed and it will sound like a jet engine. The fans are high flow high speed fans and so while they do work well they really scream at high speeds. Disconnecting the fans won’t help because if you do that the system will refuse to boot entirely.

The Fans

I decided that I needed to come up with a solution to this problem because well…how hard can it be?! Fundamentally these are standard 4 pin PWM type fans which have the following connections:

1 – GND
2 – +12V
3 – Tach
4 – PWM

Unfortunately the ones in the DL180G6 are a special case in that they have 6 pin connectors which follow a slightly different layout:

1 – +12V
2 – GND
3 – Blank
4 – Tach
5 – PWM
6 – Blank

The blank pins on the fan connector may seem a bit pointless at first but they’re like that because the motherboard support redundant pairs of fans in some configurations (I saw this on a Storageworks x1600g2 which shares the same main components). Due to this the motherboard needs a second tach (RPM) signal to monitor the second fan in the redundant pair and presumably due to the high power consumption of these fans a second +12V supply. This means you can either connect a single fan direct to the motherboard or a pair via the splitter which comes in the storage works (HP p/n  534358-001). The motherboard header looks like this:

1 – +12V-1
2 – GND
3 – +12V-2
4 – Tach – 1 (Inlet)
5 – PWM
6 – Tach – 2 (Outlet)

The good news is this means you only need one PWM per pair of fans in this configuration.

Arduino 25kHz PWM

At this point I decided I needed to build something I could fully control and so I decided to try to control it with an Arduino using the on board hardware PWM. This isn’t as easy as it sounds because PWM fans operate on a PWM control frequency of 25kHz which isn’t a standard configurable frequency on an Arduino IDE because it isn’t a direct division of the system clock. Thankfully there is a way round this. Timer 1 on the Arduino nano is a 16 bit timer and by directly manipulating the timer registers we can make the timer reset after a number of cycles so we can basically create a timer of any frequency we need. In this case  rather than being limited to prescalers (divide by 1,8,64,256,1024) from the main clock (16MHz) and 0-255 (0% – 100% duty) by using the 16 bit timer we can set a clock reset every 320 cycles which gives 25kHz at this clock frequency. I found some code which nicely did this on stack exchange and so just went with it.

https://arduino.stackexchange.com/questions/25609/set-pwm-frequency-to-25-khz

The clever bits are shown here:

    // Configure Timer 1 for PWM @ 25 kHz.
    TCCR1A = 0;           // undo the configuration done by...
    TCCR1B = 0;           // ...the Arduino core library
    TCNT1  = 0;           // reset timer
    TCCR1A = _BV(COM1A1)  // non-inverted PWM on ch. A
           | _BV(COM1B1)  // same on ch; B
           | _BV(WGM11);  // mode 10: ph. correct PWM, TOP = ICR1
    TCCR1B = _BV(WGM13)   // ditto
           | _BV(CS10);   // prescaler = 1
    ICR1   = 320;         // TOP = 320
void analogWrite25k(int pin, int value)
{
    switch (pin) {
        case 9:
            OCR1A = value;
            break;
        case 10:
            OCR1B = value;
            break;
        default:
            // no other pin will work
            break;
    }
}

The first bit sets up the timers to run at 25kHz as we need. The second bit is a special analogue write function to make sure we set the time right. We will use this function to update the timer value. We now have two PWM channels on pins 9 and 10 of our Arduino Nano.

Temperature Control

Next up I decided to add temperature control to these fans using a couple old DS18B20 temperature sensors I had lying about. These are good because multiple sensors can be daisy chained to a single data pin and the value doesn’t need scaling or anything unlike an analogue input pin and a thermistor. They cost a little more but for convenience they’re hard to argue with. They usually use +5V, Gnd and one signal pin. The signal pin needs a pullup resistor to work – this is normally specified as 4.7k. Technically these are a “1wire” device which can be run on parasitic power so the +5V isn’t actually required at the device end but if used in parasitic power mode you short it’s Vdd pin to ground. More information can be found here:

https://datasheets.maximintegrated.com/en/ds/DS18B20.pdf

There are specific Arduino libraries for using these devices so they’re really easy to use but they have one issue in this application. To do what I intended and have two separate fan zones we need to know which sensor is which. Thankfully included with the Onewire library is an example function called “DS18x20_Temperature” which will scan for devices on a specified pin. In the example this is called “ds” and it pin 10 by default but for my purposes this won’t work because we specifically need pin 9 and pin 10 for the two PWM outputs so this needs to be relocated somewhere else.

#include <OneWire.h>

// OneWire DS18S20, DS18B20, DS1822 Temperature Example
//
// http://www.pjrc.com/teensy/td_libs_OneWire.html
//
// The DallasTemperature library can do all this work for you!
// http://milesburton.com/Dallas_Temperature_Control_Library

OneWire ds(10); // on pin 10 (a 4.7K resistor is necessary)

void setup(void) {
Serial.begin(9600);
}

The code above isn’t the complete code for this example just an excerpt so you can see yours is the right one – use the one from the library.

Changing the pin to whatever you choose and running the example with serial monitor open you’ll get an output of the devices it finds. If you do this with one device connected at a time you can note down the device address for each. I marked them as #1 and #2 before hand to keep track of these later.

The Circuit

The next bit is bringing it all together electronically. We already looked at the Onewire sensors so these are really easy to connect up, I used two normal 3 pin PC fan connectors to allow these to be disconnectable for easy installation. The next bit is the fans. The PWM on fans are controlled using a pulse signal as described earlier but this isn’t a direct voltage control input. The fans need the PWM pin pulled to ground to control the signal but the output pins on the Arduino aren’t capable of absorbing the current required for direct connection so we need to add a transistor to do this for us. I went for a 2N7000 Mofset for each PWM channel because..well basically I had a bag full of them to hand and they’ll work at the output voltage of the Arduino. These will connect the fan PWM connection to ground when the Arduino output is driven high which unfortunately will reverse our PWM direction but that doesn’t matter because we can flip it back the right way in code. To correctly drive a a mosfet from an arduino you will need a gate drive resistor (to limit inrush to the Mosfet gate capacitance as this could damage the Arduino) and a gate pulldown resistor to make sure the mosfet fully turns off when the Arduino is no driving it. People will suggest all sorts of value for this but I went for a 220Ω for the gate drive and a 10kΩ for the pull down. The capacity of this Mosfet means we can use a single one for a large number of fans.

For simplicity I decided to use another of the eBay 6 pin fan connectors to connect up the cables for the fans. I intend to pass the power and tach signals directly to the motherboard so I’ll come up with a breakout cable to just isolate the PWM signal from the motherboard and allow us to feed in our own. Due to doing this we only actually need 4 pins (+12V, GND, PWM1 and PWM2) running up to the Arduino to control the fan but since I had them anyway why not!

Arduino Nano PWM Fan Breadboard

So this is the result the two connections for the DS18B20’s are on the right and the 6 pins for the fan/motherboard loom in the middle.

The Complete Code

This is where we start to bring everything together:

#include <DallasTemperature.h>
#include <OneWire.h>

// PWM output @ 25 kHz, only on pins 9 and 10.
// Output value should be between 0 and 320, inclusive.

int fanspeed1 = 25;
int fanspeed2 = 25;

float temp1;
float temp2;

#define onewirepin 3
OneWire oneWire(onewirepin);
DallasTemperature sensors(&oneWire);

DeviceAddress TempAdd1 = {0x28, 0x83, 0xC8, 0xE6, 0x3, 0x0, 0x0, 0x15};
DeviceAddress TempAdd2 = {0x28, 0x4A, 0xDE, 0xE6, 0x3, 0x0, 0x0, 0xFC};

void analogWrite25k(int pin, int value)
{
    switch (pin) {
        case 9:
            OCR1A = value;
            break;
        case 10:
            OCR1B = value;
            break;
        default:
            // no other pin will work
            break;
    }
}

void setup()
{

    Serial.begin(9600);    //Start diagnostic serial port
    
    // Configure Timer 1 for PWM @ 25 kHz.
    TCCR1A = 0;           // undo the configuration done by...
    TCCR1B = 0;           // ...the Arduino core library
    TCNT1  = 0;           // reset timer
    TCCR1A = _BV(COM1A1)  // non-inverted PWM on ch. A
           | _BV(COM1B1)  // same on ch; B
           | _BV(WGM11);  // mode 10: ph. correct PWM, TOP = ICR1
    TCCR1B = _BV(WGM13)   // ditto
           | _BV(CS10);   // prescaler = 1
    ICR1   = 320;         // TOP = 320

    // Set the PWM pins as output.
    pinMode( 9, OUTPUT);
    pinMode(10, OUTPUT);

    sensors.begin (); // Initialize the sensor and set resolution level
    sensors.setResolution(TempAdd1, 10);
    delay(1000);
    sensors.setResolution(TempAdd2, 10);
    delay(1000); 
}

void loop()
{

    sensors.requestTemperatures(); // Command all devices on bus to read temperature
    delay(1000);
    temp1 = sensors.getTempC(TempAdd1);             //Read Temp probe 1
    fanspeed1 = constrain(map((int)temp1,20,60,15,100),15,100);   
//Map fan speed for channel 1 to 25% at 30C to 100% at 60C and constrain the values to 25-100% range 
//(prevents fan from either going below 25% or trying to be set to above 100%)
    Serial.print ("Temp 1 is : ");
    Serial.print (temp1);
    Serial.print ("  Speed 1 is : ");
    Serial.println (fanspeed1);
    delay(1000);
    temp2 = sensors.getTempC(TempAdd2);            //Read Temp probe 2
    fanspeed2 = constrain(map((int)temp2,20,75,15,100),10,100);   
//Map fan speed to 25% at 30C to 100% at 75C and constrain the values to 25-100% range
    //(prevents fan from either going below 25% or trying to be set to above 100%)
    Serial.print ("Temp 2 is : ");
    Serial.print (temp2);
    Serial.print ("  Speed 2 is : ");
    Serial.println (fanspeed2);
    delay(1000);
  
    // Update Fan Speeds:
    analogWrite25k( 9, map(fanspeed1,0,100,320,0));         // Scale % fan speed from sensor one to actual PWM value for 25kHz output      
    analogWrite25k(10, map(fanspeed2,0,100,320,0));         // Scale % fan speed from sensor two to actual PWM value for 25kHz output   
    
   
}

Ok, it may not be perfect but it works.  The main bits to note are as follows:

1. The two “DeviceAddress” fields, these are the ID’s for our two DS18B20’s that we identified earlier.

2.  This line – fanspeed1 = constrain(map((int)temp1,20,60,15,100),15,100); which maps a temperature (converted to a float) between 20°C and 60°C to a fan speed of between 15% and 100% which is then constrained to this range so a temperature of 10°C doesn’t cause the fan to be given a 0% demand. You may want to change these constraints to minimise fan noise but I was being cautious and wanted to be sure the fans didn’t even slow down too far that anything overheated or triggered a BIOS warning. You can also tweak the temp vs speed mapping to optimise for a specific volume or temperature.

Map and ConstrainThere is another line like this for fanspeed2 so we can set different scaling ranges for the two sets of fans. You might only need a lower fan speed to maintain a temperature through the raid card area for example.

3. This line : analogWrite25k( 9, map(fanspeed1,0,100,320,0));
It maps our 0-100% fan speed to a value between 320-0 respectively so that we correct the signal inversion caused by using the N channel Mosfet.

The Wiring Loom

This bit is actually really simple but takes ages, buy or borrow a proper crimp tool for fan connectors a soldering iron and a good selection of heat shrink to cover everything up.

With this loom you can actually wire it up to a standard PWM fan controller off eBay or whatever if you just want a quick solution without all the soldering for the breadboard bit since it gives you power, ground and the PWM signals. Just be aware ONLY PWM fan controllers (the 4 pin ones). By doubling up the tach lines you could also take out several fans if that’s what you want so run the tach line from one fan to multiple motherboard headers if thats what you want. Here’s just how to intercept the right signal from the fan headers the way I did it:

DL180G6 Fan Wiring

Here’s what we end up with:

DL180g6 Fan Breakout

The Result

Finished Arduino DL180G6 Fan Controller
As mentioned earlier this will also work with the redundant fan systems because it passes through the tach signal of the second fan in the pair and a single PWM controls both. If doing this be careful, different servers seem to have different fan inputs configured depending on exactly what they are and you need to make sure you connect up to the right ones or the server will error on fan failure. This will probably work OK with other similar servers but can’t guarantee anything so  your mileage may vary. The other good news is that if PWM fans don’t get a PWM signal they default to 100%.

With the settings I have the fans will spin up to 100% briefly as the Arduino powers up but then spin down a few seconds later- this is normal behaviour for these fans. When the system is idling the fans seem to sit at the 15% most of the time occasionally going a little faster and now the power supply is by far the loudest part of the server so I probably wouldn’t bother setting a speed below 15% but the system is drastically quieter overall. You probably still won’t want it in your bedroom but you won’t be able to hear it everywhere in your building any more!

Other developments

When I get a bit more time I’m hoping to wire the Arduino USB connection up to an internal USB header so I can monitor the temperatures and even reprogram it when the server is running to fine tune the settings in operation. Technically its also possible to write a program to monitor CPU load and ramp the fan accordingly but this might just be too much effort.

Hopefully this will help those of you out there who have been having problems with these servers. Good luck

11 thoughts on “Solving the DL180 G6 Fan Controller Problem”

    1. Hi,
      Sorry no I didn’t create a proper PCB though probably should have. I didn’t think there would be enough interest in it to make it worth the effort. In fact so far you are the first person to comment on it! That said if enough people expressed an interest in buying something I’d consider designing and producing a batch and may even add some enhancements. Incidentally my initial prototype has been sat happily running in my server since I built it about 2 years ago – that’s the same server this blog now runs on.

      Jon

      1. I actually made a PCB (it’s quite simple, can post pictures/link later), but currently prototyping with arduino without the pcb. I am running D9 to fans 1&2 PWM (yellow wire) and D10 to fans 3&4 PWM (yellow wire again). It works, the fans are spinning at whatever default speed I set in the code.
        However the system shut downs and says “620-Non-Redundant Fan Failure or Missing”. I have verified they are all spinning, and I didn’t touch the tach wire (blue).

        Did you tie the incoming PWM from the motherboard to ground, does it have some sensing thingy on that?

        1. Never mind, I’m stupid. I was using the wrong fan headers (double-triple-quadruple checked it on multiple occasions). Now it works.

          I removed the PWM pin from the 6pin 2510 connector and wired it to a 3pin 2510 connector I had handy (read: dismantled old PC fans), and used fan extension cables from a 5.25″ bay fan controller to wire them to an arduino. Some pictures:
          https://i.imgur.com/5jq8Pq7.png
          https://i.imgur.com/OtPhNro.png
          https://i.imgur.com/Y0TdvRZ.png
          Here’s the PCB I designed and planned on using, but probably wont be doing that now as I have it working fine. (I also removed the 12V(pin1)VIN connection because it would be powered from USB)
          https://imgur.com/a/JS7zqkL

          1. Hi,

            Glad you got it all working in the end. Looks like a neat solution. I had always intended to build a PCB that sits on top of the motherboard fan headers so the fans can basically plug in in the same position which would be similar to the board you have but as ever now this works I’ve ignored it!

            You indeed don’t need the 12V hooked up if you plan to plug it in permanently on USB – mine is also currently on a USB cable which loops out the back of the case and into a spare port. The 12V is connected because my original intention was to get it all up and working adjusting the profiles as needed for best behaviour then remove the USB cable but basically it’s worked flawlessly on the initial ramp shown on the code. So as it is today I could do since it’s not been re-flashed for about 2 years and the USB really isn’t serving any purpose any more.

            The PWM’s from the motherboard were just left open because it’s basically a clock signal output from the motherboard which is intended to drive into a high impedance (I think usually into a mosfet gate via a few hundred ohms resistance) so current should be very low. Connecting these to ground may damage the PWM driver on the motherboard but I honestly don’t know for sure. I suggest leaving them open for safety.

            Glad the information helped!

  1. Thank you very much about this blog post.

    I have pretty much similar(?) Proliant DL380 G6 and it have totally 8 horribile loudly fans and now finally started building this. Last year tried https://www.reddit.com/r/homelab/comments/6xfscd/making_the_dl380_g7_quiet_for_good/ but had huge problems with it and later on noticed that here is better documented your version also.

    So far looking good, maybe tomorrow its fully working and running.

    Greetings from Finland.

    1. Hi,

      Glad to hear it’s useful to someone! Any problems let me know – I can conform it works reliably on my DL180 but sometimes what I write up isn’t entirely clear I can’t imagine the DL380 is far different. As I said to someone else recently my one has been controlling the fans on the server this blog is hosted on for about 2 years now and is still working perfectly. Obviously this version has temperature controlled fans which is quite nice but if you wanted simpler you can just put a fixed value for the fan speed and leave it but what that speed needs to be to keep you setup cool in all conditions is the problem. You could also just wire a potentiometer to one of the Arduino analogue inputs and pass that value to the PWM output (via the MAP function) and just have manual control. With mine setup with the profiles given in the code

      I never did get round to wiring the USB to an internal header, the lead just loops out the back of the case and plugs into a spare port so I could actually re-flash the Arduino while it’s running but I’ve never needed to!

      Good luck!

      Jon

  2. Well after much searching and snafu I stumbled across this.. and I have some 4500G2s here which are almost identical to the dl180g6 nut come with 8 fans aka the redundant fan kit is std. And despite them having a diff Bios and Ilo the same f’ing fan problem exists in spades. Dosnt matter what card It behaves the same. I have a Dell PERC flashed to LSI HBA and a 4 port usb3 card installed atm (had a 2 port lo but it was swapped)

    Anyhow ordered up a cpl audrino nanos after reading through here.. making a list of parts and oddly most are things I don’t have in hand and while I’m sure I can wire up something from the info here,

    However I would be quite interested in the idea of this being US reporting/monitoring/controllable and that’s way out of my skill set, I have never yet touched any audrino period.. Servers here are running unraid but I am thinking of tossing more ram and 2nd cpu into one and running win7 VM or something etc,, so in theory it might need to be a reporting signal/usb that could be understood by both (and since I have seen some others running winbloze on these as well it could be a bonus for multiple users)

    A suitable PCB design should be fairly easy to design and have built cheaply.. and if donr right Im guessing it could be doable for under $15 each inc parts and the audrino.,, and with 6 pin headers so stock fans would just plug straight in and leads/jumpers from the board would hook to the MB making it a plug and pray inline regardless of if the sys is 4 or 8 fans

    Anyone interested and that can do such coding?

    Also in theory one could get temps from onboard HP sensors that are “sea of” via a USB connection.. though the reality of that part I have zero digging done into so far,,

    then again if the tards at HP had a brain they would have released a fix for this common issued yrs ago and allowed end users to override fan speeds in the bios etc when I tried asking nearest HP they 1st wanted a CC before even asking my name.., and then when i got a tech (w/o paying) the tech laughed and said sales dept didnt want it fixed its an incentive to make upgrade sales argh)
    Anyhow if the author would please email me Id appreciate it since Ive no doubt going to have a few q’s

    Oh and if anyone is interested and also in canuckistan (and close to me I could order up more parts etc as a bundle to save on shipping etc)

    1. Hi,

      I’m the author of the DL180 fan controller blog post and all the other ones on this page. Long story short you probably could get temperatures from the motherboard somehow but there’s no particular standard as to how motherboards and I doubt HP would tell outsiders how theirs work so it’s well beyond the level of effort I’d want to bother with for hardware.

      you mention using 8 fan systems, this actually works with the wiring as shown using the standard HP fan splitters. You just put the Arduino controller wiring between the motherboard header and the HP splitter and the Arduino control and feedback to the MB still all work.

      In terms of reporting the code in the post includes sending the recorded temperatures and fan speeds back over USB serial link from the Arduino. Currently it’s done in a format that’s easy to read so looks nice if you just leave a terminal window open but with some basic software development a windows program with a display could be developed that just displays this data in a handy format but windows program development isn’t really something I do as I’m more an electronics person.

      There was another person who commented on this who designed a PCB but much like my approach got a basic setup working and as far as I’m aware never actually produced the PCB’s. If there’s genuinely enough interest I might be persuaded to have another look at designing one.

      Anyway, good luck if you do pursue developing it further and I’d be interested to see what you come up with. If you do have any questions on what I’ve done just message me back.

      Jon

  3. Hi Jon,

    I figured you were the author and many thanks for that alone since so far it is the best potential solution I’ve found yet for this issue. In response to your replyso it can e kept straight easier

    1) I know the hw could be done but no HP is a PITA even for old stuff like this so asking them for help esp w/o them demanding a CC before your name…. finding an honest politician will no doubt happen 1st lol (temps for hdds should be easy since they are build in so no HP needed for that)

    2) 8 fan systems I figure it would be just a matter of plugging i between the mb and the y adapter HP includes as the redundant kit. It wasn’t as much a q there as simply stating that such should work and there are many that are almost identical to the dl180 but that have dual fan by default (all p4500 g2 came with such afaik)

    3) Its good to know its in a std easy to use format. But I am also not as much the coder as hardware like you, Hence why I know even ignoring the adrino part I will bet this will need someone with far better coding skills than I have, (Not to mention I’m old school literally.. I am long before winbloze babies came along.. a ton of what coding I did do is way out of date now and it wasnt usually something I needed to do often)

    4) I read that post and pcb idea but they didnt really put up a full schematic. Initially I’m planning on a p2p wiring system using a 400 point breadboard. It should be just big enough to squeeze in the needed parts for 4 fan IOs 2 or more temp probe inputs using the same probe as you did..
    (they are cheap enough – but when finding suppliers care must be used to make sure they are the actual part and not the PN used as a reference only I found a half doz plus wannabes selling other probes with the listings looking almost like they were for the ds18b20 but on closer inspection were not but often looked similar)

    Then once that’s all done and working for the hardware aspect But once I have it worked out here I will look at the option for up a pcb design / layout and if there’s any interest a small batch could be done pf PCBs or maybe assembled units (I have sourced suppliers for the needed hardware)

    But even at a min a working design with layout on a small breadboard with detachable cables etc should be easy enough..

    The area beyond my skills are def going to be the coding for the idea of USB function etc,,

    My nano’s I ordered arrived yesterday btw.. so next spare time I get (w/o my youngest under my feet) to sort out the basic code to put into final form and flash it in etc.. while waiting for other parts to arrive, (another 2-3 weeks.. but since I ordered from Asia I got enough I should end up w/bits to be able to built 3+ of these to start easily)

    I will say the overall value of these older servers is VG esp used

    It will mean my main archive when this is done can actually stay on 24/7 without keeping the neighbors awake or murdering my hydro bill!

    So anyone reading.. it seems we will be needing a skilled coder to help bring this to its full potential any volunteers? lol

  4. Hi again Just waiting for more parts to arrive and free tome.. but was checking on other things and came across this (had forgotten about it) and this may possibly be helpful in some ways with the fans as well as accessing the onboard sensors etc.. so in case you havnt seen heres the LILO user manual online and downloadbale for thw DL180 g6 and others ver. p4500 g2 is of course very similar

    https://support.hpe.com/hpesc/public/docDisplay?docLocale=en_US&docId=c02521690

Leave a Reply

Your email address will not be published.