4 wire fan speed control

edrummer

Well-known member
I want to control the speed of a 4 wire CPU fan with a potentiometer, I was told these require high frequency PWM, 25kHz.
I have an old Teensy 3.6 I was wondering if it could work. There is a guy on YouTube that changed the frequency of an Arduino
I
As usual this is looking way more complex than I thought but I have need for a ultra quiet variable speed fan. Any help greatly appreciated.
 
Searching with "pc fan control arduino", you will find you need a PWM signal and could read the fan speed.
But these two signals are 5V (if I am not wrong). And the Teensy is 3.3V, inputs beeing not 5V tolerant.
The FAN PWM signal could probably accept the 3.3V signal comming from the Teensy. But don't connect the speed signal directly to the Teensy. You could insert a resistor divider.

Or use this https://www.amazon.com/Control-Temperature-3-3V-5V-EMC2101-Controller/dp/B0DGLJC5C9
 
Last edited:
Judging by that video the tacho signal is open drain - it has no "high" voltage and requires a pullup. So you could connect it directly to a Teensy pin configured for INPUT_PULLUP mode.
 
Adding a diode could protect the teensy. If the "fan" goes above 3.3v the diode will protect it against more voltage.
 
The PWM signal is open drain/collector; I recommend using a BSS138 or NX138AKR N-channel enhancement mode logic level MOSFET, with source to ground, drain to the fourth pin of the 4-pin fan connector (MOLEX 47053-1000), and gate to a 100Ω – 220Ω current limiting resistor which is connected to a Teensy GPIO pin. The standard frequency is 25 kHz, but anything between 21 kHz and 29 kHz will work the same.

The tachometer signal (third pin) is also an open drain/collector signal, which the fan controller side should pull to 12V via a pull-up resistor. The circuit I recommend uses a 10kΩ pull-up to 12V, then to the gate of another BSS138 or NX138AKR. The source is connected to ground, and the drain both to a GPIO pin, as well as a a 10kΩ pull-up resistor to 3.3V. You will get two pulses per rotation; at 1200 RPM (typical for quiet 120mm and 140mm fans) it will be 20 pulses per second. You can use an interrupt for this, and the ARM DWT cycle counter to determine the interval between pulses. There will be jitter, so apply a low-pass filter (for example, a box-averaging or an exponential filter).

I prefer NX138AKR in SOT23-3, because it is small, but hand-solderable (two pins at 1.8mm distance, with the third pin on the opposite side centered), and quite cheap at e.g. Mouser and elsewhere; it is also slightly faster than BSS138 to switch because its total gate capacitance is lower.

Connecting the PWM and tach signals this way is quite safe, because these logic-level MOSFETs can handle gate-source voltages between -20V and +20V. MOSFET gates act like capacitors, and the voltage between gate and source (Vgs) determines the resistance between drain and source; NX138AKR works fine down to 2.5V gate voltage (with respect to source - here, ground). It is very rare for MOSFETs to short gate to drain, which is the only way Teensy GPIO pins could be damaged by this.

Except for the wire colors, basically all 4-pin 12V PWM fans follow the Intel 4-wire PWM fan specification (PDF).
 
(I did create my own single and dual 12V PWM fan controllers using ATtiny85 AVR MCUs (ATTINY85-20PU). Both the schematics and the board files are in Public Domain / CC0-1.0, but I haven't written the firmware yet; I'll use the dual one for my DIY soldering fume hood with 2/3/4 120-140mm 12V PWM fans. The single one also exports I²C for use with a small display, either OLED or LED digits; the dual one supports two fans. The idea here is that the potentiometer does NOT control the PWM duty cycle directly; it sets the desired RPM instead, between build-time configured minimum and maximum (which can be different for the two fans on the dual model). The microcontroller then adjusts the PWM duty cycle to achieve that RPM. This way, as the fans age, you don't need to continuously adjust the potentiometer to get the same airflow.)
 
Searching with "pc fan control arduino", you will find you need a PWM signal and could read the fan speed.
But these two signals are 5V (if I am not wrong). And the Teensy is 3.3V, inputs beeing not 5V tolerant.
The FAN PWM signal could probably accept the 3.3V signal comming from the Teensy. But don't connect the speed signal directly to the Teensy. You could insert a resistor divider.

Or use this https://www.amazon.com/Control-Temperature-3-3V-5V-EMC2101-Controller/dp/B0DGLJC5C9
Thanks, I also have a 3.2 which is 5v tolerant I believe, I seen the temp controlled ones I need a pot though.
 
You can control the fan power with a relay. And with that you can control the on and off of the fan. You can isolate the PWM control pin of your MCU with a 1N4148 diode


Implemented the control on a teensy 4.1 and a 5" 800x480 FT813 TFT
MFVOAMBl.jpg
 
Last edited:
(I did create my own single and dual 12V PWM fan controllers using ATtiny85 AVR MCUs (ATTINY85-20PU). Both the schematics and the board files are in Public Domain / CC0-1.0, but I haven't written the firmware yet; I'll use the dual one for my DIY soldering fume hood with 2/3/4 120-140mm 12V PWM fans. The single one also exports I²C for use with a small display, either OLED or LED digits; the dual one supports two fans. The idea here is that the potentiometer does NOT control the PWM duty cycle directly; it sets the desired RPM instead, between build-time configured minimum and maximum (which can be different for the two fans on the dual model). The microcontroller then adjusts the PWM duty cycle to achieve that RPM. This way, as the fans age, you don't need to continuously adjust the potentiometer to get the same airflow.)
You can control the fan power with a relay. And with that you can control the on and off of the fan. You can isolate the PWM control pin of your MCU with a 1N4148 diode


Implemented the control on a teensy 4.1 and a 5" 800x480 FT813 TFT
MFVOAMBl.jpg
You can control the fan power with a relay. And with that you can control the on and off of the fan. You can isolate the PWM control pin of your MCU with a 1N4148 diode


Implemented the control on a teensy 4.1 and a 5" 800x480 FT813 TFT
MFVOAMBl.jpg
Thanks, I wanted to try this code but it won't compile what am I missing?
Screenshot 2024-12-13 193312.png
 
This program directly accesses the timers from old 8 bit AVR chips.

The usage is pretty simple to replace with analogWriteFrequency() and analogWrite(). I can help, but please post the whole program as text. I want to help you, but retyping it all from this screenshot isn't something I'm going to do only to show how to use analogWriteFrequency() and analogWrite().
 
This program directly accesses the timers from old 8 bit AVR chips.

The usage is pretty simple to replace with analogWriteFrequency() and analogWrite(). I can help, but please post the whole program as text. I want to help you, but retyping it all from this screenshot isn't something I'm going to do only to show how to use analogWriteFrequency() and analogWrite().
Thankyou, I didn't realize this would be this hard. I have a 3.2 if that would work better. I'm most interested in the sound level which is why I want to use a pot rather than temp control.
Code:
[code]
const int fan_control_pin = 9;  // Blue Wire on fan (about 25kHz PWM)
int count = 0;
unsigned long start_time;
int rpm;

void setup() {
  TCCR1A = 0; // undo the configuration done by...
  TCCR1B = 0; // the Arduino core library
  TCNT1 = 0; // reset timer
  TCCR1A = _BV(COM1A1) | _BV(COM1B1) | _BV(WGM11);  // Undo default timers
  TCCR1B = _BV(WGM13) | _BV(CS10); // for pins 9 & 10
  ICR1 = 320; // PWM will be 0 to 320 instead of 0 to 255
  pinMode(fan_control_pin, OUTPUT);
  OCR1A = 0; //set pin to 0 out of 320 on pin 9
  OCR1B = 0; //set pin to 0 out of 320 on pin 10
  Serial.begin(9600);
  attachInterrupt(digitalPinToInterrupt(2), counter, RISING);  // Yelloww Wier

}

void loop() {

  for (int pwm = 0; pwm <= 320; pwm += 64) {
    OCR1A = pwm;
    delay(5000);
    start_time = millis();
    count = 0;
    while ((millis() - start_time) < 1000) {
    }
    rpm = count * 30;  //60/2
    Serial.print("PWM = ");
    Serial.print(map(pwm, 0, 320, 0, 100));
    Serial.print(" % , speed = ");
    Serial.print(rpm);
    Serial.println(" rpm");
  }
}
void counter() {
  count++;
}
[/CODE]
 
Give this a try.

I checked the waveform with my oscilloscope, but didn't have a 4 wire fan handy for testing. Please let me know if it really works with your 4 wire fan?

Code:
const int fan_control_pin = 9;  // Blue Wire on fan (about 25kHz PWM)
volatile int count = 0;
unsigned long start_time;
int rpm;

void setup() {
  analogWriteFrequency(fan_control_pin, 25000);
  analogWrite(fan_control_pin, 0);
  Serial.begin(9600);
  pinMode(2, INPUT_PULLUP);
  attachInterrupt(digitalPinToInterrupt(2), counter, RISING);  // Yellow Wire
}

void loop() {
  for (int pwm = 0; pwm <= 255; pwm += 51) {
    analogWrite(fan_control_pin, pwm);
    delay(2000); // ?? time for fan to change speed ??
    start_time = millis();
    count = 0;
    while ((millis() - start_time) < 1000) {
    }
    rpm = count * 30;  //60/2
    Serial.print("PWM = ");
    Serial.print(map(pwm, 0, 255, 0, 100));
    Serial.print(" % , speed = ");
    Serial.print(rpm);
    Serial.println(" rpm");
  }
}
void counter() {
  count++;
}
 
Before you start I would run a couple of tests. If you have a different 4 wire fan plug it in and start the computer. You can hold the fan in your hand while it boots but you NEED to keep the CPU COOL. I used a small fan that plugs into a 120volt outlet and blow it into the case If it starts normal and gives no alarm then you are good to go... Also try unplugging the fan and see if it boots. If it does boot and only gives an alarm then If it errors out or will not turn on the the mother board is checking for a specific fan to be there and a specific RPM. Remember to keep the CPU COOL. I bought a used Dell workstation at the beginning of the year that has 10 fans (Very Loud) although there are temp sensors throughout, the fan speeds would not adjust to the load and temp of the components. It would also NOT accept a different fan and when a different fan was installed or no fan at all the PC would give a diagnostic screen during post and not boot to the OS. I was my first real microcontroller project and I used 1 Teensy 4.1 with 7 temp sensors in zones to control the 10 fans. I used a second Teensy 4.1 to "trick" the mother board into believing the 10 factory fans were still present. Occasionally it runs a test that I have not figured how to simulate and I just restart and it boots to the OS. MOST computers do NOT have this problem however, I found out that it looks for a specific fan with a specific rpm WAY late into the project so I just kept going.

One other suggestion... MOST computers have a setting in the bios to control the CPU fan thermally or just have a set speed. Not to dissuade your from the Teensy project but you may find your solution there or just install a larger cooler with a quieter fan. You should also monitor the CPU temp to make sure it does NOT get too hot.
 
Before you start I would run a couple of tests. If you have a different 4 wire fan plug it in and start the computer. You can hold the fan in your hand while it boots but you NEED to keep the CPU COOL. I used a small fan that plugs into a 120volt outlet and blow it into the case If it starts normal and gives no alarm then you are good to go... Also try unplugging the fan and see if it boots. If it does boot and only gives an alarm then If it errors out or will not turn on the the mother board is checking for a specific fan to be there and a specific RPM. Remember to keep the CPU COOL. I bought a used Dell workstation at the beginning of the year that has 10 fans (Very Loud) although there are temp sensors throughout, the fan speeds would not adjust to the load and temp of the components. It would also NOT accept a different fan and when a different fan was installed or no fan at all the PC would give a diagnostic screen during post and not boot to the OS. I was my first real microcontroller project and I used 1 Teensy 4.1 with 7 temp sensors in zones to control the 10 fans. I used a second Teensy 4.1 to "trick" the mother board into believing the 10 factory fans were still present. Occasionally it runs a test that I have not figured how to simulate and I just restart and it boots to the OS. MOST computers do NOT have this problem however, I found out that it looks for a specific fan with a specific rpm WAY late into the project so I just kept going.

One other suggestion... MOST computers have a setting in the bios to control the CPU fan thermally or just have a set speed. Not to dissuade your from the Teensy project but you may find your solution there or just install a larger cooler with a quieter fan. You should also monitor the CPU temp to make sure it does NOT get too hot.
I'm not using this for a computer, These will be in a recording studio.
 
Is there a difference between using a PWM pin with default frequency?
Code:
  analogWrite(fan_control_pin, 50);
  Serial.begin(9600);
  pinMode(2, INPUT_PULLUP);
  attachInterrupt(digitalPinToInterrupt(2), counter, RISING);  // Yellow Wire

And with modified frequency?
Code:
  analogWriteFrequency(fan_control_pin, 25000);
  analogWrite(fan_control_pin, 50);
  Serial.begin(9600);
  pinMode(2, INPUT_PULLUP);
  attachInterrupt(digitalPinToInterrupt(2), counter, RISING);  // Yellow Wire

Is there any effect on the final behavior of the fan in each case?
 
Click Tools > Board to check which board you have selected. It's probably not Teensy, because the analogWriteFrequency() function isn't displayed with orange test. When you select any Teensy board, the color of analogWriteFrequency() will be orange, and the code should compile without any error.
 
I have a PC with windows 10 and one with 11 , the 2.3.4 IDE doesn't work on the windows 10 PC so I went back to 1.8 IDE on that one. The windows 11 PC has the 2.3.4 IDE which works but doesn't acknowledge Teensy. I tried to install Teensyduino on both as the screenshot shows, it says no driver needed The teensy doesn't show up on either PC. It is an old 3.2 but the little led comes on. Suggestions?
 

Attachments

  • Screenshot 2024-12-14 210623.png
    Screenshot 2024-12-14 210623.png
    62.5 KB · Views: 19
  • Screenshot 2024-12-14 210930.png
    Screenshot 2024-12-14 210930.png
    28.8 KB · Views: 14
  • Screenshot 2024-12-14 212812.png
    Screenshot 2024-12-14 212812.png
    24.2 KB · Views: 15
Maybe this helps? Can't tell from screen shots:

For IDE 2.x: use the Board Manager installer

For IDE 1.8.x use only TeensyDuino after pointing it to the Arduino 1.8.x install location - it does the work of the Board Mgr install.
 
I tried both those things, the Board Manager installer for IDE 2.x has no knowledge of a Teensy and the !.8 shows it but says only works with 2.0 or later.
 

Attachments

  • Screenshot 2024-12-14 225632.png
    Screenshot 2024-12-14 225632.png
    29.1 KB · Views: 19
Two important points.

First, the most common problem is power-only USB cables. If Teensy powers up (orange LED blinks, stops blinking when you press the pushbutton), but your PC never detects any USB device, you almost certainly have a power only cable. Most Windows computers make a chime sound when any new USB device connects. If yours does not, search for how to configure the chime sound (sorry, I mostly use Linux so I don't know Windows config stuff). Test by plugging in some other USB device. If you hear the chime with other devices but not with Teensy, you need a proper USB cable. No amount of installing software can make Teensy communicate if you use a cable that has only wires for power and lacks the wires for data!

Second, by default Teensy uses HID protocol, not Serial. If you only look for COM ports on Windows, you will miss finding Teensy when it is using HID communication.

the Board Manager installer for IDE 2.x has no knowledge of a Teensy

You need to add the Teensy URL using File > Preferences. Details here:


But again, if you have a power only cable, which you can test using only the Windows chime sound for connecting USB devices, nothing you install can solve the missing wires problem. Those power only cables are sold with very cheap products that have USB for power only. They are made with the 2 wires for power, but lack wires for data. Those power only cables are by far the most common problem and have been discussed over and over on this forum. Check that you get the Windows chime sound before wasting a lot of time installing software!
 
Back
Top