Picking appropriate transistor/mosfet/optocoupler

I am trying to control many (20) PWM computer fans. I have successfully managed to make the Arduino output PWM at 25kHz but I face a problem.

Reading up on spec sheets, it seems that computer PWM fans can draw 5mA on the PWM pin. However, Arduino's IO pins are rated only for 40mA (I don't want to go over 30mA). This is a problem because I am trying to control 20 fans (20×5=100mA).

I have used transistors and mosfets before but I don't think they are appropriate for this high frequency PWM. I have looked at some optocouplers but the max collector current is usually quite low (50mA etc).

Any suggestions on what I could do here?

25kHz is not a high frequency.

AWOL:
25kHz is not a high frequency.

Okay I should reword that, the frequency is too high for my TIP120 to work with.

Post wiring diagram.

Here's the circuit diagram. I've omitted everything that isn't relevant. PB1/pin 15 on the atmega328p is pin 9 on the arduino uno which is where I am outputting the PWM signal.

If you put a steady HIGH on PB1 (not PWM), what voltage do you get from ground to TIP120 emitter?

JCA79B:
If you put a steady HIGH on PB1 (not PWM), what voltage do you get from ground to TIP120 emitter?

Just tested it, I got 5v.

chairr:
Reading up on spec sheets, it seems that computer PWM fans can draw 5mA on the PWM pin.

You can find lower than that, check individual datasheets.

Circuit won't work; that NPN transistor should switch low side, you switch high side. You'd need a PNP type at that position. Next you miss a pull-down resistor to get the signal back low again.

The problem is indeed you have to drive 20 fans - that's bound to be significant stray capacitance to overcome. You're better off with a push/pull buffer instead of a transistor. Maybe a 74HC04 hex inverter, inputs all connected to your Arduino output, each output driving 3-4 fans. Just remember to reverse the analogWrite values (255 is off, 0 is on).

wvmarle:
Circuit won't work; that NPN transistor should switch low side, you switch high side. You'd need a PNP type at that position. Next you miss a pull-down resistor to get the signal back low again.

The problem is indeed you have to drive 20 fans - that's bound to be significant stray capacitance to overcome. You're better off with a push/pull buffer instead of a transistor. Maybe a 74HC04 hex inverter, inputs all connected to your Arduino output, each output driving 3-4 fans. Just remember to reverse the analogWrite values (255 is off, 0 is on).

I swapped the fan pin with an led/resistor and it worked perfectly, I could see the led dim/brighten as designed. I've added a pull down resistor (10k) but it still doesn't work with the fan pwm pin. I'm pretty certain the PWM pin on the fan is load that requires high side as well. I don't understand why it isn't working.

I tried with a BC547 instead of a TIP120 (both NPN) but they both display the same behaviour; works with an LED but not with the PWM fan pin. I have plugged the PWM pin directly into the Arduino and confirmed that it does work as intended, but just not when I connect it to the transistor connected to the Arduino.

The hex inverter does seem promising but the max continuous current through the 74HC04 (VCC pin) is 50mA, which isn't enough. I've look at other buffers too but they all seem to have the same max continuous current.

The buffer is of course to drive the PWM signal, not the fan. It should be more than enough for a simple signal. It only needs sufficient current to overcome the capacitance of the wires and the fan input fast enough to produce a nice signal.

No surprise the LED works. It's current driven, and you do switch the current on and off. When you switch on the transistor the current flows and the LED is on, when you switch off the transistor the current stops and the LED is off.

Very different to a signal, which is a voltage. Switch on the transistor and a high level voltage is supplied to the fan's input, when the transistor is off no voltage is supplied (no, as in: not high, not low. It's floating).

I see, wouldn't something like a 10k pull down resistor get rid of the floating pin problem?

In your case that'd have to be a pull-up. Transistor between resistor and GND. And a current limiting resistor on the base (1-10k).

For faster response (you will need that) use a stronger pull-up. 1k or so sounds a good starting point. And note that the output will be inverted.

I managed to get it working with a pull up and it was inverted like you said but the range seemed very limited (seemed to be between 30-60%). Is this due to the slew rate of the transistor/mosfet being too slow? Or is it something else?

wvmarle:
Circuit won't work; that NPN transistor should switch low side, you switch high side. You'd need a PNP type at that position. Next you miss a pull-down resistor to get the signal back low again.

The problem is indeed you have to drive 20 fans - that's bound to be significant stray capacitance to overcome. You're better off with a push/pull buffer instead of a transistor. Maybe a 74HC04 hex inverter, inputs all connected to your Arduino output, each output driving 3-4 fans. Just remember to reverse the analogWrite values (255 is off, 0 is on).

A low-side MOSFET driver chip would be much more capable, many amps available with some of them, designed to drive large capacitances at very fast rise-times.

Even better.

Use two 74HC14s (or 74HC04s). Drive one inverter with your PWM pin. Drive the other 11 from the first inverter. Two or three fans each.