Notifications
Clear all

Pico strange RPM calculation

1 Posts
1 Users
0 Reactions
461 Views
(@gorek)
Member
Joined: 4 years ago
Posts: 11
Topic starter  

Hi, I try to make very similar experiment as Bill with PWM controlled fan  but I use Pico instead ESP32.
My fan is Delta AUB0912VH (tacho: 2 pulses per revolution, max 3800 RPM).

On fan datasheet I can read that optimal PWM control frequency is 25kHz so I set my Pico to generate such PWM frequecy and my (not verry expensive but working 😎) osciloscope confirm exactly this frequency.

Based of fan datasheet setting PWM duty to 0% should give minimal fan speed.
Pico show this is 870 RPM, my osciloscope shows tacho pulses frequency is 29Hz (with 2 pulses per revolition gives exactly 870 RPM). Datasheet says is should be about 500RPM so 870RMP is quie higher but acceptable in my opinion.

When PWM duty is 100% fan should spin on maximal speed.
Based on fan datasheet is should be about 3800 (with 10% tolerance) but my pico shows absurd value: about 22560 RPM. Osciloscope shows frequency 114Hz (that give about 3420 RPM what is within tolerance).

What I'm dong wrong??

Here is the code that runs on the Pico:

#include <stdio.h>

#include "hardware/adc.h"
#include "hardware/pwm.h"
#include "pico/stdlib.h"

#define PWM_PIN 2
#define TACHO_PIN 16

volatile uint32_t pulses = 0;
uint32_t lastTachTime = 0;

long map(long x, long in_min, long in_max, long out_min, long out_max) {
  return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
}

void tacho_irq(uint gpio, uint32_t events) {
  pulses++;
}

int main() {
  uint32_t wrap;
  const uint32_t TACH_SAMPLE_TIME = 1000;  // Sample period in milliseconds
  uint32_t rpm = 0;
  uint16_t result;

  stdio_init_all();
  gpio_init(PWM_PIN);  // initialization and setting of pin mode
  gpio_set_function(PWM_PIN, GPIO_FUNC_PWM);
  gpio_init(PICO_DEFAULT_LED_PIN);
  gpio_set_dir(PICO_DEFAULT_LED_PIN, GPIO_OUT);
  gpio_put(PICO_DEFAULT_LED_PIN, 1);


  adc_init();           // ADC initialization
  adc_gpio_init(26);    // assignment to ADC pin 26 (ADC0)
  adc_select_input(0);  // Select ADC input 0 (GPIO26)

  const float conversion_factor = 3.3f / (1 << 12);

  lastTachTime = to_ms_since_boot(get_absolute_time());

  // interrupt initialization
  gpio_set_irq_enabled_with_callback(TACHO_PIN, GPIO_IRQ_EDGE_FALL, true, tacho_irq);

  uint8_t slice_num = pwm_gpio_to_slice_num(PWM_PIN);  // assignment of values to variables slice_num and channel
  uint8_t channel = pwm_gpio_to_channel(PWM_PIN);
  wrap = 4999; //PWM 25kHz
  pwm_set_wrap(slice_num, wrap);
  pwm_set_chan_level(slice_num, chan, 0); // 0% duty

  pwm_set_enabled(slice_num, true);  // PWM signal activation

  while (true) {

    result = adc_read();
    uint16_t duty = map(result, 0, 4095, 0, 100);
    uint16_t level = wrap * duty / 100;
    pwm_set_chan_level(slice_num, channel, wrap * duty / 100);

    uint32_t currentTime = to_ms_since_boot(get_absolute_time());
    if (currentTime - lastTachTime >= TACH_SAMPLE_TIME) {
      gpio_set_irq_enabled(TACHO_PIN, GPIO_IRQ_EDGE_FALL, false);
      rpm = (pulses * 60000) / (TACH_SAMPLE_TIME * 2);
      printf("Raw value: %d, voltage: %4.2f V duty: %d%%, level: %d RPM: %d\n", result, result * conversion_factor, duty, level, rpm);

      // Reset counters
      pulses = 0;
      lastTachTime = currentTime;
      gpio_set_irq_enabled(TACHO_PIN, GPIO_IRQ_EDGE_FALL, true);
    }

    sleep_ms(50);
  }
}

This topic was modified 7 months ago by gorek

   
Quote