Reading Fan RPM with PWM

I’m brand new to the Arduino and I have an UNO. I’m trying to control a 4-pin CPU fan using PWM at 25khz and then read back the fan speed using a 10kohm pullup resistor. However, the fan speed I’m reading back is not exactly what I’d expect based on the fan specs.

At 20% duty cycle the fan is supposed to run at 2,600rpm and at 100% duty cycle the fan is supposed to run at 11,500rpm. At 20% duty cycle I’m reading about 3360rpm and at 100% duty cycle I’m reading about 11,900rpm.

I’m trying to decide if the difference between the rated speeds and the speeds I’m reading back is reasonable and can be attributed to variations from fan to fan and/or somewhat unstable PWM control using the PWM.h library or if my code has some problems. Since this is my first project with the arduino I was hoping someone could take a look at my code and give me some feedback, any help would be greatly appreciated.

//fan speed sensor wire attached to digital pin 2 with a 10kohm pullup resistor
//fan PWM control wire attached directly to digital pin 9

#include <PWM.h> //include PWM library http://forum.arduino.cc/index.php?topic=117425.0

volatile int half_revolutions; //allow half_revolutioins to be accesed in intterupt
int rpm; //set rpm as an integer

void setup() 
{
  InitTimersSafe(); //not sure what this is for, but I think i need it for PWM control?
  bool success = SetPinFrequencySafe(9, 25000); //set frequency to 25kHz
  pwmWrite(9, 51); // 51=20% duty cycle, 255=100% duty cycle
  
  pinMode(2,INPUT); //set RPM pin to digital input
  half_revolutions = 0;
  rpm = 0;
  
  Serial.begin(9600);
}



void loop()
{
  sei(); //enable intterupts
  attachInterrupt(digitalPinToInterrupt(2), fan_rpm, RISING); //record pulses as they rise
  delay(10000);
  detachInterrupt(digitalPinToInterrupt(2));
  cli(); //disable intterupts
  
  rpm = (half_revolutions/2)*6; 

  Serial.print("SPEED: ");
  Serial.print(rpm);
  Serial.println("rpm");
  Serial.println();

  rpm = 0;
  half_revolutions = 0;

}

void fan_rpm()
{
   ++half_revolutions; //increment before returning value 
 }

The following image is basically how I’ve connected everything, with the addition of a brown PWM control wire coming out of the fan and going straight into digital pin 9.

I would think that the fan speed specification is approximate. That is to say, you are reading the exact RPM, but the PWM settings do not generate exactly the specified RPM.

aarg: I would think that the fan speed specification is approximate. That is to say, you are reading the exact RPM, but the PWM settings do not generate exactly the specified RPM.

Awesome! I figured this was a reasonable variation, but I've got almost not background in any kind of coding so I just wanted double check myself.

I would expect the fan speed to vary a little under load as well. Would I be guessing correctly that you are testing it in open air?

aarg: I would expect the fan speed to vary a little under load as well. Would I be guessing correctly that you are testing it in open air?

I am. Which brings up a good point. I hadn't considered that maybe the spec ratings included some amount of static pressure.