PWM Valve Controller

Hi All,

Looking at controlling an exhaust valve with a Seeed Studio Xiao-RP2040. I can control the valve using a PWM signal generator, so I know what frequency I need (about 130Hz) and what duty cycle (10% is closed, ~90% is open). I found a PWM library that allows you to change the pre-scaler of the on board timers effectively changing the frequency of the PWM output. I don't quite understand the error messages, but my fear is the Xiao-RP2040 being a Raspberry Pi based board doesn't use the same timers as other Arduino boards.

I chose the Xiao-RP2040 for its size and the fact it wasn't really that expensive, its also very likely more powerful than I need for this application so it wouldn't have made sense to go for a more expensive Arduino based board.

Just would like to know if it is possible to use this library as I think I should be able to or if I'm going to have to go back to the drawing board. Everything else in the code works the way I want it to, it's just case of getting the correct signal out out to the valve.

My Code:

#include <PWM.h>

const int buttonIN = 26;
const int ledOUT = 27;
const int valveOUT = 28;

int buttonState = 0;
int lastButtonState = 0;
int buttonCount = 0;

int32_t frequency = 130;

void setup() {

  InitTimersSafe();

  SetPinFrequencySafe(valveOUT, 130);

  pinMode(buttonIN, INPUT);
  pinMode(ledOUT, OUTPUT);

  Serial.begin(9600);

}

void loop() {

  buttonState = digitalRead(buttonIN);

  if (buttonState != lastButtonState) {

    if (buttonState == HIGH) {

      buttonCount ++;
      Serial.print("Button Pressed ");

    }

    else {

      Serial.print("Button not Pressed ");

    }

    delay(50);

  }

  Serial.println(buttonCount);

  if (buttonCount % 2 == 0) {

    open();

  }

  else {

    close();

  }

}

void open() {

  Serial.print("Valve Open ");
  digitalWrite(ledOUT, HIGH);
  pwmWrite(valveOUT, 127);
  delay(100);

}

void close() {

  Serial.print("Valve Closed ");
  digitalWrite(ledOUT, LOW);
  pwmWrite(valveOUT, 0);
  delay(100);

}

The Errors:

C:/Users/warehouse/AppData/Local/Arduino15/packages/rp2040/tools/pqt-gcc/4.0.1-8ec9d6f/bin/../lib/gcc/arm-none-eabi/14.2.0/../../../../arm-none-eabi/bin/ld.exe: C:\Users\warehouse\AppData\Local\arduino\sketches\B2AF0C3E4FBB155740337B4B80187E33\sketch\PWM_Controller.ino.cpp.o: in function `_Z4openv':
C:\Users\warehouse\Documents\Arduino\PWM_Controller/PWM_Controller.ino:72:(.text._Z4openv+0x16): undefined reference to `_Z8pwmWritehh'
C:/Users/warehouse/AppData/Local/Arduino15/packages/rp2040/tools/pqt-gcc/4.0.1-8ec9d6f/bin/../lib/gcc/arm-none-eabi/14.2.0/../../../../arm-none-eabi/bin/ld.exe: C:\Users\warehouse\AppData\Local\arduino\sketches\B2AF0C3E4FBB155740337B4B80187E33\sketch\PWM_Controller.ino.cpp.o: in function `_Z5closev':
C:\Users\warehouse\Documents\Arduino\PWM_Controller/PWM_Controller.ino:81:(.text._Z5closev+0x16): undefined reference to `_Z8pwmWritehh'
C:/Users/warehouse/AppData/Local/Arduino15/packages/rp2040/tools/pqt-gcc/4.0.1-8ec9d6f/bin/../lib/gcc/arm-none-eabi/14.2.0/../../../../arm-none-eabi/bin/ld.exe: C:\Users\warehouse\AppData\Local\arduino\sketches\B2AF0C3E4FBB155740337B4B80187E33\sketch\PWM_Controller.ino.cpp.o: in function `setup':
C:\Users\warehouse\Documents\Arduino\PWM_Controller/PWM_Controller.ino:18:(.text.setup+0x2): undefined reference to `_Z14InitTimersSafev'
C:/Users/warehouse/AppData/Local/Arduino15/packages/rp2040/tools/pqt-gcc/4.0.1-8ec9d6f/bin/../lib/gcc/arm-none-eabi/14.2.0/../../../../arm-none-eabi/bin/ld.exe: C:\Users\warehouse\Documents\Arduino\PWM_Controller/PWM_Controller.ino:20:(.text.setup+0xa): undefined reference to `_Z19SetPinFrequencySafeam'
collect2.exe: error: ld returned 1 exit status
exit status 1

Compilation error: exit status 1

Any help much appreciated!

1 Like

Showing ALL the verbose error messages is normal debugging procedure. If you had read the pinned post 'How to get the most from the Forum' you would know that. I do congratulate you on using code tags on your code however.
Does the library you are using say it is valid for that board (btw, there are other small, cheap boards available, maybe even some Arduino boards as well as the Espressif type board you chose)
What library is that (PWM.h) I can't find it.

Have you tried turning it off then on again? That's usually the best fix if you believe you did everything right.

1 Like

This library was used in this video. They have very basic code just to show the library working.

I believe it is the same library in this forum post. It's a little on the older side so it may not support some of the newer boards.

Try this library

1 Like

After a few hours figuring out this library I am now able to compile and upload to the xiao-rp2040. However the valve doesn't actuate which seems more likely to be a hardware problem. Looks like I'm going to need to get an oscilloscope to see if we are emitting the correct signal.

Definitely some more figuring out to do, thanks for the help so far!

Code:

//This is a very simple PWM Valve controller that opens or closes a valve fully at the push of a button.

#include <RP2040_PWM.h>

RP2040_PWM* PWM_Instance;

const int buttonIN = 26;
const int ledOUT = 27;
const int valveOUT = 28;
const int frequency = 130;

int buttonState = 0;
int lastButtonState = 0;
int buttonCount = 0;
int dutyCycle = 0;

void setup() {

  pinMode(buttonIN, INPUT);
  pinMode(ledOUT, OUTPUT);

  PWM_Instance = new RP2040_PWM(valveOUT, frequency, dutyCycle);

  if (PWM_Instance) {

    PWM_Instance->setPWM();

  }

  Serial.begin(9600);

}

void loop() {

  buttonState = digitalRead(buttonIN);

  if (buttonState != lastButtonState) {

    if (buttonState == HIGH) {

      buttonCount++;
      Serial.print("Button Pressed ");

    }

    else {

      Serial.print("Button not Pressed ");
    }

    delay(50);
  }

  Serial.println(buttonCount);

  if (buttonCount % 2 == 0) {

    open();

  }

  else {

    close();

  }

}

void open() {

  Serial.print("Valve Open ");
  digitalWrite(ledOUT, HIGH);

  dutyCycle = 10;

  Serial.print(dutyCycle);

  PWM_Instance->setPWM(valveOUT, frequency, dutyCycle);

  delay(100);

}

void close() {

  Serial.print("Valve Closed ");
  digitalWrite(ledOUT, LOW);

  dutyCycle = 90;

  Serial.print(dutyCycle);

  PWM_Instance->setPWM(valveOUT, frequency, dutyCycle);

  delay(100);

}