Check out my first novel, midnight's simulacra!

PC Fans

From dankwiki
Revision as of 22:07, 21 November 2022 by Dank (talk | contribs) (→‎External links)

Fans for personal computers are governed by specifications from Intel and Noctua:

Almost all available fans are either 5V, 12V, or 24V, with 12V dominating personal computers (there is no readily-available 24V source from an ATX power supply). Fans operating at higher voltages will require less current for the same work. Two-pin fans offer neither feedback nor PWM control. Three-pin fans typically offer a tachometer signal on the third wire. Four-pin fans add a PWM control on the fourth wire (some fans without PWM control can still be controlled via varying voltage; voltage ought be kept constant for a PWM fan). PWM is a 5V logical control that does not modify supplied power.

Fans can be run at less than their maximum duty to reduce acoustic noise and consume less power.

Power draw

Intel's spec mandates 12V±5% (11.4–12.6V). A fan in its steady state operating in freestream (V) conditions ought not draw more than 1.5A (this would be a maximum of 18.9W; most consumer fans draw far less). During startup, 2.2A of inrush current may be drawn for a period of no more than 1s (27.72W).

Note that the powerful (and bracingly loud) Noctua iPPC-3000 is speced at 3.6W, i.e. 0.3 amps, just 20% of the allowed draw. On the other hand, truly industrial fans exist: Delta's PFC1212DE 5500RPM behemoth draws 4A for an out-of-spec 48W. At this point, system designers really must begin considering heat added to the system by the fan:

If the supply fan is downstream of the cooling coil in a draw-through configuration, the fan heat increases the supply air temperature, increasing the supply air volume required to meet a given space load. If the fan is upstream of the coil in a blow-through configuration, the fan heat is absorbed directly by the coil. In either case, the fan heat adds to the cooling coil load. —James S. Elleson, Cold Air Distribution (1996)

Most motherboard fan headers are rated for between one and two amps. More current than this can be drawn from independently-powered fan controllers. One hears a rule of thumb that more than three consumer fans ought not be hooked up to a single header, but just add the damn amps and check the manual.

PWM

Pulse width modulation controls the power delivered by dividing time up into quanta, and supplying current only during part of each quantum. The signal is characterized by the quantum length (∝ 1/frequency); the level can then be varied from none to the entirety of the quantum. 100% PWM is equivalent to constant current supply, while 0% PWM is equivalent to no supply.

PC fans are ideally controlled via 25KHz PWM, though the range 21KHz to 28KHz is deemed acceptable. The PWM high signal ought be 5V with an absolute maximum of 5.25V. The absolute max current drawn is 5mA. The maximum value of logic low is 0.8V. In the absence of a valid signal, the fan ought run at maximum speed. Intel's document puts fairly strict requirements on the PWM-RPM relationship: the fan speed shall be a "continuous and monotonic function of the duty cycle" (a reasonable requirement), and furthermore that the effected speed, as a percentage of maximum speed, should match the PWM duty cycle to within ±10%. If the PWM duty cycle is e.g. 50%, and the fan's max speed is 1900 RPM, conformance requires fan speed of 760–1140 RPM. The response curve must thus be more-or-less linear in the large.

Fans have a minimum rotation speed, corresponding to some minimum PWM duty cycle; duty cycles below this minimum result in the the fan running at less than or equal to the minimum speed (perhaps not running at all). The fan will never *start* spinning at less than the minimum rotation speed. The minimum rotation speed must not be more than 30% of the maximum speed.

(an aside about Intel terminology: a "Type A" fan never shuts down, a "Type B" fan shuts down at 0% PWM, and a "Type C" fan shuts down at all PWM duty cycles below some threshold; one would think it sufficient to specify a "maximum PWM for shutdown" and simply specify -1 for "Type A" fans, but who knows?)

Controlling PWM

Controlling fans using a microcontroller has some complexity. The first difficulty is generating a 25KHz PWM signal. On Arduino UNOs and MEGAs, this is not available via the standard libraries, and the hardware must be programmed directly. Here's a sample implementation for the MEGA, using timer 5 for a PWM signal:

#define PWM_FREQ_HZ 25000

static void setup_timers(void){                                                                                                     
  TCCR5A = 0;                                                                                                                       
  TCCR5B = 0;                                                                                                                       
  TCNT5  = 0;                                                                                                                       
  // Mode 10: phase correct PWM with ICR4 as Top (phase-correct needs a                                                             
  // factor of 2 in division below). OC4C as Non-Inverted PWM output.                                                               
  // 16MHz / (25KHz * 2) == 320 cycles per interrupt.                                                                               
  ICR5 = (F_CPU / PWM_FREQ_HZ) / 2;                                                                                                 
  TCCR5A = _BV(COM5C1) | _BV(WGM51);                                                                                                
  TCCR5B = _BV(WGM53) | _BV(CS50);                                                                                                  
}

static void set_pwm(unsigned pwm){
  OCR5C = ICR5 * (pwm + 1) / 256;
}

The relevant pin ought be placed into OUTPUT mode, and must be associated with timer 5 (say, Pin 44). No direct manipulation of the pins is necessary, and the PWM is handled in hardware.

The ESP32's ledc library can be harnessed to do this at a higher level, using hardware PWM. Supply a chosen channel (of 8) and an OUTPUT pin, together with a freq of 25000, to e.g.:

static int initialize_pwm(ledc_channel_t channel, int pin, int freq){                                                                      
  ledc_channel_config_t conf;                                                                                                       
  memset(&conf, 0, sizeof(conf));                                                                                                   
  conf.gpio_num = pin;                                                                                                              
  conf.speed_mode = LEDC_HIGH_SPEED_MODE;                                                                                           
  conf.intr_type = LEDC_INTR_DISABLE;                                                                                               
  conf.timer_sel = FANPWM_TIMER;                                                                                                    
  conf.duty = FANPWM_BIT_NUM;                                                                                                       
  conf.channel = channel;                                                                                                           
  if(ledc_channel_config(&conf) != ESP_OK){                                                                                         
    return -1;                                                                                                                      
  }                                                                                                                                 
  ledc_timer_config_t ledc_timer;                                                                                                   
  memset(&ledc_timer, 0, sizeof(ledc_timer));                                                                                       
  ledc_timer.speed_mode = LEDC_HIGH_SPEED_MODE;                                                                                     
  ledc_timer.bit_num = FANPWM_BIT_NUM;                                                                                              
  ledc_timer.timer_num = FANPWM_TIMER;                                                                                              
  ledc_timer.freq_hz = freq;
  if(ledc_timer_config(&ledc_timer) != ESP_OK){                                                                                     
    return -1;                                                                                                                      
  }                                                                                                                                 
  return 0;                                                                                                                         
}

and then set the PWM duty cycle by calling on that same channel:

static int set_pwm(ledc_channel_t channel, unsigned p){                                                                                                     
  if(ledc_set_duty(LEDC_HIGH_SPEED_MODE, channel, p) != ESP_OK){                                                                 
    return -1;                                                                                                                      
  }
  if(ledc_update_duty(LEDC_HIGH_SPEED_MODE, channel) != ESP_OK){                                                           
    return -1;                                                                                                                      
  }                                                                                                                                 
  return 0;                                                                                                                         
}

The ESP8266 requires a call to analogWriteFreq(25000); before using analogWrite() to set an 8-bit duty cycle. This is a global setting, and will affect any other analogWrite()s in your program. If you don't like it, you can always bitbang.

Tachometer

Two pulses per revolution on an open collector. Maximum current is 5mA for 5V and 12V fans, and 2mA for 24V fans.

A junction must propagate only one tachometer signal, i.e. if three fans are connected to a splitter, only one tach value is reported. Whether this is a maximum, or an average, or something else is undefined, but every junction I've ever seen, from passive splitters to active controllers, simply connects only one tachometer to the wire (controllers using a side channel in addition to the fan connector might of course report multiple tach signals, as does the Aquacomputer OCTO via USB).

Connector and wiring

Pinout (GND, power, tach, PWM).

Intel specifies UL1430 wire with a minimum AWG26, 300V capacity, with rating of at least 105℃.

The fan wire ought be terminated with a four-pin housing (Wieson 2510C888-001, Molex 47054-1000, or equivalent).

The intended mating header ought be housed in Wieson 2366C888-007, Molex 47053-1000, Foxconn HF27040-M1, Tyco 1470947-1, or equivalent.

Pinout: GND (black), Power (yellow), Tach (green), PWM (blue)

Both connectors ought employ a polarizing rib between the third and fourth pin to ensure correct connection. The absence of such does not preclude mating with a ribbed connector; an offset connection is almost certain to blow the tachometer circuit if the device is externally powered.

External links

See also