12v 4 Wire PWM Fan, Error Reading RPM from Tacho Wire.

Background

I'm posting out of desperation in the hope that someone can shed some light on my PWM / RPM issue using an UNO

I'm writing a rather mammoth sketch in pieces to start with and at some point in the future ill piece it all together. Below is some code to PWM a 4 Pin 12v DC fan at 25khz and at the same time read back the RPM of the fan over the Tachometer wire.

Most of the cleverness is hidden inside the PWM.h code which can be found here PWM frequency library - Libraries - Arduino Forum

Everything works as expected when the PWM value is at 255, The RPM value returned to the console is correct

Problem

My issues seem to occur when I PWM at anything other than 0 or 255. Say I PWM at 250 I get RPM readings which are in the thousands and massively wrong.

Ground wires are connected.

I cant find anyone else but this post to help me out Problem reading RPM when using PWM on 4-pin fan - Project Guidance - Arduino Forum that said the solution they found, A didnt work in my case and B Im not sure anyone can explain the reason its works at all...

Any help 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, 150); // 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 
 }

What I see is a program that starts and immediately starts counting rising edge inputs for ten seconds.

Don't you think you should let the fan reach a final speed before attempting to measure said speed? Otherwise, you're just measuring the average speed for 10 seconds, beginning at zero.

FWIW, I had to edit the library to get it to compile without redefinition warnings...

Thanks for the reply. To be honest I'm new to electronics and coding. So attempting to piece bits from other projects together. You are right on its usage and probably its draw backs, that said what I don't understand is the crazy reading I get from the code when i provide a PWM signal other than 0 or 100%

I mean it goes from 1400RPM (which is correct) to 12000RPM when i lower the PWM by even a few points.

Re: Library

The code for the library isn't mine, and yes your right i had to modify it also to get it to compile. I think its quite old.

I haven't been able to find any examples of someone who has driven a PWM fan at 25khz using any other code... Any other libraries or suggestions that could do this more efficiently if you think this is the cause of the problem would be most welcome.

How do you have things wired? I’m no expert on cpu fans but I’m fairly certain you need a pullup resistor on the tach line and then a voltage divider to get the proper voltage input signal.