I am new to the arduino community. I have some experience working with ARM, bare metal microcontrollers.
I bought an Arduino Nano 33 IoT for the ease of the WiFiNINA library. For my project, I would like to set up a 38kHz PWM output to control IR emitters. Unfortunately, the IRremote library is not compatible with this board currently.
It is my understanding, based on looking in the variant header file for the board, that the oscillator frequency is 32kHz. Without using any other external hardware, is it possible to configure a 38kHz PWM signal, and if so, how?
I found the blog post below and got it to run on an Adafruit Feather M0 which is also a SAMD21. It will need some tweaking to get it to a pin on the Arduino Nano 33. Just running it on the Arduino Nano 33 did not work. The pins are different.
I did not want you to wait to long. Maybe we can figure this out together.
It is my understanding, based on looking in the variant header file for the board, that the oscillator frequency is 32kHz. Without using any other external hardware, is it possible to configure a 38kHz PWM signal, and if so, how?
The SAMD21 microcontroller on the Nano33 runs crystalless, so it instead uses its standard, internal, on-chip 32.768kHz oscillator (OSC32K). This clock is then ramped (multiplied) up to 48MHz internally using an on-chip Digtal Frequency Locked Loop (DFLL48M). The 48MHz clock source is allocated to generic clock GCLK0 (in the Arduino core's "startup.c" file). The initial lines in the code below connect the 48MHz GCLK0 to the TCC0 and TCC1 timers.
Here's some example code that outputs 38kHz PWM on the Nano 33's D7 pin:
// Output 38kHz PWM on digital pin D7 on Nano33
void setup()
{
// Feed GCLK0 at 48MHz to TCC0 and TCC1
GCLK->CLKCTRL.reg = GCLK_CLKCTRL_CLKEN | // Enable GCLK0 as a clock source
GCLK_CLKCTRL_GEN_GCLK0 | // Select GCLK0 at 48MHz
GCLK_CLKCTRL_ID_TCC0_TCC1; // Feed GCLK0 to TCC0 and TCC1
while (GCLK->STATUS.bit.SYNCBUSY); // Wait for synchronization
// Enable the port multiplexer for pins D7
PORT->Group[g_APinDescription[7].ulPort].PINCFG[g_APinDescription[7].ulPin].bit.PMUXEN = 1;
// D7 is on EVEN port pin PA06 and TCC1/WO[0] channel 0 is on peripheral E
PORT->Group[g_APinDescription[7].ulPort].PMUX[g_APinDescription[7].ulPin >> 1].reg = /*PORT_PMUX_PMUXO_E |*/ PORT_PMUX_PMUXE_E;
// Normal (single slope) PWM operation: timer countinuouslys count up to PER register value and then is reset to 0
TCC1->WAVE.reg |= TCC_WAVE_WAVEGEN_NPWM; // Setup single slope PWM on TCC1
while (TCC1->SYNCBUSY.bit.WAVE); // Wait for synchronization
TCC1->PER.reg = 1262; // Set the frequency of the PWM on TCC1 to 38kHz: 48MHz / (1262 + 1) = 38kHz
while (TCC1->SYNCBUSY.bit.PER); // Wait for synchronization
TCC1->CC[0].reg = 630; // TCC1 CC0 - 50% duty cycle on D7
while (TCC1->SYNCBUSY.bit.CC0); // Wait for synchronization
TCC1->CTRLA.bit.ENABLE = 1; // Enable the TCC1 counter
while (TCC1->SYNCBUSY.bit.ENABLE); // Wait for synchronization
}
void loop()
{
// Using buffered counter compare registers (CCBx)
TCC1->CCB[0].reg = 315; // TCC1 CCB1 - 25% duty cycle on D7
while (TCC1->SYNCBUSY.bit.CCB0); // Wait for synchronization
delay(1000); // Wait for 1 second
TCC1->CCB[0].reg = 945; // TCC1 CCB1 - 75% duty cycle on D7
while (TCC1->SYNCBUSY.bit.CCB0); // Wait for synchronization
delay(1000); // Wait for 1 second
}