Is it possible to change the PWM Frequency to 20 kHz?

Hello,

there are 5 PWM Pins there. I measured 1.836 kHz PWM Frequency on them.
Is it possible to change the PWM Frequency to 20 kHz?

with kind regards
Erik

@Erik01 what about use this function ?
https://www.arduino.cc/reference/en/language/functions/advanced-io/tone/

Hello @Baozhu, thank you, but this is not what i’m searching for.
I don’t want a 20 kHz tone.
I want to pulse the signal on the PWM pin in a specific waveform in pulse width modulation in a lower frequency (for example 10 Hz). But the frequency of the pulse width modulation should be in an area where it can not be heard (20 kHz).

with kind regards
Erik

Hello @WioTerminalGeeks
how is it about a library for PWM? (Like for example PWM.h for Arduino or the function analogwritefrequency for Teensy)

with kind regards
Erik

Hi @Erik01

For you demand, you may need to use the timer. Please check this library for reference: https://github.com/adafruit/Adafruit_ZeroTimer

Hello @ansonhe97

thank you for the link.
There is an example: timers_pwmout.ino


#include <Arduino.h>
#include “Adafruit_ZeroTimer.h”

// timer tester
Adafruit_ZeroTimer zt3 = Adafruit_ZeroTimer(3);
Adafruit_ZeroTimer zt4 = Adafruit_ZeroTimer(4);
Adafruit_ZeroTimer zt5 = Adafruit_ZeroTimer(5);

/* Valid PWM outs:
FOR SAMD21:
Timer3: channel 0 on D2 or D10, channel 1 on D5 or D12
Timer4: channel 0 on SDA or A1, channel 2 on SCL or A2
Timer5: channel 0 on MOSI, channel 1 on SCK
FOR SAMD51:
Timer3: channel 0 on D10 or MISO, channel 1 on D11
Timer4: channel 0 on A4, D7, or D1, channel 2 on A5, D4, or D0
Timer5: channel 0 on D5, channel 1 on D6
*/

#if defined(SAMD51)
#define TIMER3_OUT0 10
#define TIMER3_OUT1 11

#define TIMER4_OUT0 A4
#define TIMER4_OUT1 A5

#define TIMER5_OUT1 6
#else
#define TIMER3_OUT0 10
#define TIMER3_OUT1 12

#define TIMER4_OUT0 A1
#define TIMER4_OUT1 A2

#define TIMER5_OUT1 SCK
#endif

void setup() {
Serial.begin(115200);
//while(!Serial);
Serial.println(“Timer PWM tester”);

/********************* Timer #3, 16 bit, two PWM outs, period = 65535 */
zt3.configure(TC_CLOCK_PRESCALER_DIV1, // prescaler
TC_COUNTER_SIZE_16BIT, // bit width of timer/counter
TC_WAVE_GENERATION_NORMAL_PWM // frequency or PWM mode
);
if (! zt3.PWMout(true, 0, TIMER3_OUT0)) {
Serial.println(“Failed to configure PWM output”);
}

if (! zt3.PWMout(true, 1, TIMER3_OUT1)) {
Serial.println(“Failed to configure PWM output”);
}

zt3.setCompare(0, 0xFFFF/4);
zt3.setCompare(1, 0xFFFF/2);
zt3.enable(true);

/********************* Timer #4, 8 bit, two PWM outs, period = 100 */
zt4.configure(TC_CLOCK_PRESCALER_DIV1, // prescaler
TC_COUNTER_SIZE_8BIT, // bit width of timer/counter
TC_WAVE_GENERATION_NORMAL_PWM // frequency or PWM mode
);
zt4.setPeriodMatch(100, 20, 0); // channel 0, 20/100 count
zt4.setPeriodMatch(100, 75, 1); // channel 1, 75/100 count
if (! zt4.PWMout(true, 1, TIMER4_OUT1)) {
Serial.println(“Failed to configure PWM output”);
}
if (! zt4.PWMout(true, 0, TIMER4_OUT0)) {
Serial.println(“Failed to configure PWM output”);
}
zt4.enable(true);

/********************* Timer #5, 16 bit, one PWM out, period = 1000 */
zt5.configure(TC_CLOCK_PRESCALER_DIV1, // prescaler
TC_COUNTER_SIZE_16BIT, // bit width of timer/counter
TC_WAVE_GENERATION_MATCH_PWM // frequency or PWM mode
);
zt5.setPeriodMatch(1000, 200); // channel 1 only, 200/1000 count
if (! zt5.PWMout(true, 1, TIMER5_OUT1)) {
Serial.println(“Failed to configure PWM output”);
}
zt5.enable(true);

/*********************/
// some other simple tests
delay(500);
zt3.enable(false);
delay(500);
zt3.enable(true);
}

uint16_t c = 0;

void loop() {
zt3.setCompare(0, c);
zt3.setCompare(1, 0xFFFF-c);

c++;
delayMicroseconds(100);
}


Can you help me here.
How should it look like for example that all 3 Timers are set for a PWM frequency for around 20 kHz?
Which pin of the Wio Terminal GPIO refers to which Timer?
Pin 13, BCM27, A0 (PWM0) = Timer ?
Pin 16, BCM23, A2 (PWM1) = Timer ?
Pin 23, BCM11 (PWM2) = Timer?
Pin 33, BCM13, A6 (PWM3) = Timer?
Pin 37, BCM26, A8 (PWM4) = Timer?

with kind regards
Erik

Hello,
Is there a documentation about the timers and the GPIO pins of Wio Terminal?

Which pin of the Wio Terminal GPIO refers to which Timer?
Pin 13, BCM27, A0 (PWM0) = Timer ?
Pin 16, BCM23, A2 (PWM1) = Timer ?
Pin 23, BCM11 (PWM2) = Timer?
Pin 33, BCM13, A6 (PWM3) = Timer?
Pin 37, BCM26, A8 (PWM4) = Timer?

with kind regards
Erik

It would seem no one has shared a successful demonstration of any of these things. I’m going to be setting up an output signal for driving a test bench I am rebuilding. 20 kHz has a period of 50 microseconds. From previous projects, I know that you can literally bit bang a signal in your code. Either in loop() or using a pulse() function you call on occasion (meaning every 50 microseconds).

Looking at the schematic page 2, it seems TCC3 is used for I2S, GPCLK1 and 2. TCC4 is on

  • GPCLK0. Page 5 shows the breakout of the signals on the RPi 40 pin connector:
  • GPCLK0 looks like pin# 7 on the connector, “GPIO4/GCKL”, which in user manual is BCM4
  • GPCLK1 looks like pin# 29 on the connector, “GPIO5” —> BCM5
  • GPCLK0 looks like pin# 31 on the connector, “GPIO6” —> BCM6

For my testing application, precision isn’t exactly required, so long as whatever I do set up is consistent from test to test. I mistakenly thought the Wio Terminal was ESP32 based, which is a shame since their libraries have a trivial signal generation ability. You call it, set the frequency you want, pick the resolution of the duty cycle, set the duty cycle, and go.

I dug through a few things in the Examples and seems there is not explanation of how to set up a clock, timer, PWM, or anything useful to my case. I am determined to use this Wio Terminal and will reply with the means to which I attain my own “PWM”.

I have working sample code, and results are tested with an oscilloscope. Using google, I found a SAMD51_InterruptTimer library on Github.

This is the pre-setup:

// I chose BCM27 by finding variant.h & compared to drawing 
// and just "picked a pin"
#define SIG_OUT BCM27
#include "SAMD51_InterruptTimer.h"
volatile uint pw = 2480;
volatile uint32_t period = 14120;
void myISR() {
	digitalWrite(SIG_OUT, 1);
	delayMicroseconds( pw );
	digitalWrite(SIG_OUT, 0);
}

Notice that I made changes from the provided example code. The sample code with the github ends up making a square wave with a period of twice what the “period” is. They employed a volatile bool which toggled in the ISR.

I did not implement duty cycle, though anyone could make the necessary changes. The original question was regarding 20kHz, which has a period of 50 microseconds, so it would be easy enough to implement with my sample code.

Then in my setup():

void setup() {
	pinMode(SIG_OUT, OUTPUT);
	TC.startTimer(period, myISR); // 100000 usec
}	

There is no mention of loop() because it i irrelevant for the purpose of setting up a signal on a pin.

The github library I used has these member functions that could be useful:

restartTimer()
setPeriod()
startTimer()
stoptTimer()

I then studied the RPi pins with an o’scope. Note the magic numbers I chose for the constants… the pulse width of 2480 used in software came to 2.50 microseconds on my o’scope. The 14120 microseconds programmed into the period measured as 14.10 microseconds on the o’scope. If accuracy is needed, best to confirm results with test equipment. The output was 3.3V at “high” state.

I was curious if this library’s use of TCC3 would affect BCM5. It does not. Without any better research, I am assuming the output multiplexer has TCC3 not attached to the output pin which it otherwise could be attached to. And then pinMode() set the output of my software timer to BCM5. I chose BCM5 for no other reason than the pin seemed it would be not otherwise popular.

Worthy of note:
BCM0 and BCM1 are both high / 3.3V, even though I did nothing with those pins.

Summary:
The documentation is leaving much to be desired. The samples and tutorials are focused on more exciting applications while skipping over more pedestrian functions. variant.h is a key file for how to access “pins” on the output… there should be more explanation on how to access I/O from within a sketch. How many people know to dig through %USER%/App Data/Local/Arduinox.x to eventually find variant.h?

As an engineer deploying this for a production part, I had to make the choice to research how to implement my needs. In the ESP32, documentation is present which had me immediately using the ESP32 in production. This extra work on the engineer’s part due to lack of documentation and software implementation surely will limit the Wio Terminal adoption to less than it should be.

As the testing and production engineer, having a case with buttons and display are a bonus. What makes the Wio Terminal so exciting to me is the easily accessible 40 pin RPi connector. The Wio Terminal has all the functionality I could ever need, a mature user interface (in the physical sense), and easy & reliable interconnection to equipment.

The direct competition to the Wio Terminal is the M5 Stack realm. Sadly, I found their means to connect to external equipment rather awkward. I am not sure we will ever implement an M5 in our test benches.