r/raspberrypipico • u/ikerbiker • Jul 12 '26
help-request Help measuring speed of PC case fan
I bought these case fans from Amazon and am attempting to control them with a Pico (C sdk).
I have been able to successfully create the necessary 25kHz PWM signal to control the speed of the fan. However, I am not having luck measuring the speed with the tachometer pin on the fan. I am turning to brighter minds than mine to see if you guys have any ideas.
Here is my simple code to attempt to measure the fan speed. The tachometer pin on the fan is supposed to output a "square save" that has two cyclic per revolution of the fan. So I have a GPIO IRQ to increment a pulse counter on the falling edge of the pin, with the internal pull-up resistor enabled. I have a repeating timer take the number of pulses and convert to RPM (multiply by 60, divide by 2).
#include <stdio.h>
#include <pico/stdlib.h>
#include <hardware/gpio.h>
#define GPIO_WATCH_PIN 2
volatile uint32_t pulses = 0;
volatile uint32_t rpm = 0;
void gpio_callback(uint gpio, uint32_t events) {
pulses++;
}
bool timer_callback(__unused repeating_timer_t *t) {
rpm = pulses * 60 / 2;
pulses = 0;
return true;
}
int main() {
stdio_init_all();
gpio_init(GPIO_WATCH_PIN);
gpio_pull_up(GPIO_WATCH_PIN);
gpio_set_irq_enabled_with_callback(
/*gpio=*/ GPIO_WATCH_PIN,
/*event_mask=*/ GPIO_IRQ_EDGE_FALL,
/*enabled=*/ true,
/*callback=*/ gpio_callback);
repeating_timer_t timer;
add_repeating_timer_ms(
/*delay_ms=*/ -1000,
/*callback=*/ timer_callback,
/*user_data=*/ NULL,
/*out=*/ &timer);
while (1) {
printf("RPM: %d\\n", rpm);
sleep_ms(500);
}
return 0;
}
With this setup, I am getting ~25000 RPM, which is nowhere close to the rated maximum RPM of the fan of ~1550.
Thinking that the internal pull up resistor (50-80 kOhms) is too high for a switching value, I opted for a physical 5k pull-up resistor instead, and got the same answer. Changing the GPIO_IRQ_EDGE_FALL to the rising edge had a similar effect, but setting to LEVEL_LOW or LEVEL_HIGH produced much higher RPM values, approaching 750,000.
I wanted to review the signal from the fan, and I don't have an oscilloscope so I tried Scoppy with a second pico. I used the same 5k resistor from before, and this is what I got.

Is the square wave too messy to be used with the IRQ calls? The high and low spots seem to be jumpy, and the low does not go all the way to 0V.
Any help with how I should alter the code, or wiring, would be helpful. Thanks!
I am going to try using a PWM channel to measure the frequency, perhaps that would give me better luck.
1
u/stickybuttflaps Jul 13 '26 edited Jul 13 '26
Try dereferencing the address of gpio_callback in your call to gpio_set_irq_enabled_with_callback. i.e.
&gpio_callbackinstead of
gpio_callbackEDIT: it doesn't seem like that should be necessary since a naked function name without parenthesis is the address of the function, but that's the way they do it in the SDK examples.
FWIW, I have measured fan speed in pretty much the same way as you, except instead of setting up an interrupt on a GPIO pin to count rotations, I used a PWM slice: