Trigger/Configure Interrupt with Hardware PWM using Arduino Due

Hi everyone,

I am trying to make a MIDI synthesizer using the Arduino Due. I want to use a sampling rate of 192kHz to generate pulse-modulated waveforms. Using the hardware PWM on the Sam3x/Due, I'm able to output a 192kHz PWM waveform on a pin, and I'm also able to change the pulse width.

However, I want to use the hardware PWM to trigger an interrupt at the sampling rate (~ every 5.2us) that will call a function to calculate the next pulse width value based on the desired waveform and frequency (say, a sine wave at Middle A/440Hz). Looking through the documentation for the Sam3x and the pwmc.h/.c (among other Arduino source files), there seems to be a function called "PWM_Handler()" that I might need to call. However, I don't know how to configure it, and sticking it in my code as-is does not do anything.

I have been searching around a lot and haven't found any information on how to configure the interrupt on the Due/Sam3x. I have experimented a bit with the hardware timers (the TC_ library), but they don't seem to be as reliable on outputing a square wave consistently at the 192kHz frequency.

Thank you for your help, and please let me know if you need additional information.

In general you write an ISR for a timer interrupt, that does an analogWrite with the next duty cycle. Then configure the timer to interrupt at the desired sample rate. Details are controller specific, dunno how to accomplish that on a Due :frowning:

I figured it out. Here is my code for anyone who stumbles across this. it sets up a hardware PWM to output at . The key for the interrupt is to add the NVIC code and also read the interrupt status register in the interrupt service routine:

uint32_t totalTime = 0; // total elapsed time

uint32_t pwmPin = 8; // PWM output pin
uint32_t channel = g_APinDescription[pwmPin].ulPWMChannel; // set channel for PWM out
uint32_t sampFreq = 192000ul; // sampling frequency (Hz)
uint16_t maxDutyCount = 255;
uint32_t clkAFreq = 42000000ul; // clock frequency (Hz)
uint32_t pwmFreq = (clkAFreq * 2)/sampFreq; // calculate PWM frequency
uint16_t dutyPercent = 128; // starting duty percent
uint16_t dutyAct = pwmFreq * (maxDutyCount-dutyPercent) / maxDutyCount; // 

void setup() {
   // put your setup code here, to run once:

   pmc_enable_periph_clk(PWM_INTERFACE_ID);
   PWMC_ConfigureClocks(clkAFreq, 0, VARIANT_MCK);
 
   PIO_Configure(
    g_APinDescription[pwmPin].pPort,
    g_APinDescription[pwmPin].ulPinType,
    g_APinDescription[pwmPin].ulPin,
    g_APinDescription[pwmPin].ulPinConfiguration);
 
   //uint32_t
   channel = g_APinDescription[pwmPin].ulPWMChannel; // channel 5
   PWMC_ConfigureChannel(PWM_INTERFACE, channel, clkAFreq, 0, 0);
   PWMC_SetPeriod(PWM_INTERFACE, channel, pwmFreq);
   PWMC_EnableChannel(PWM_INTERFACE, channel);
   PWMC_SetDutyCycle(PWM_INTERFACE, channel, dutyAct);
   PWM_INTERFACE->PWM_IER1 = 0x20; //enable interrupt on channel 5
   PWM_INTERFACE->PWM_IDR1 = 0xFFFFFFDF; //enable interrupt on channel 5
   PWM_INTERFACE->PWM_IER2 = 0x00002001; //enable interrupt on channel 5
   PWM_INTERFACE->PWM_IDR2 = 0xFFFFDFFE; //enable interrupt on channel 5

   NVIC_DisableIRQ(PWM_IRQn); // set up interrupt
   NVIC_ClearPendingIRQ(PWM_IRQn);
   NVIC_SetPriority(PWM_IRQn, 0);
   NVIC_EnableIRQ((IRQn_Type)36); //NVIC_EnableIRQ(PWM_IRQn);
   PWMC_EnableChannel(PWM_INTERFACE, channel);
   //Enable of the Interrupts (writing CHIDx and FCHIDx
   //in PWM_IER1 register, and writing WRDYE, ENDTXE,
   //TXBUFE, UNRE, CMPMx and CMPUx in PWM_IER2 register)
}

void loop() {
}

void PWM_Handler(void) // PWM interrupt handler
{
   volatile long dummy = PWM_INTERFACE->PWM_ISR1; // clear interrupt flag
   dummy = PWM_INTERFACE->PWM_ISR2; // clear interrupt flag
   //your code here
}

Hello,

Can you explain why you use the name "PWM_Handler" for the interrupt. I'm trying to get a solid understanding of setting up different interrupts for arduino due.
And if you can explain where this information is found, it would greatly help!

Thank you and i appreciate your help,
-Mark

I will guess you have a PC.

Open an arduino Ide window,

  • Select File>Préferences
  • Click in the URL at the bottom of the pop up window: C:\Users...\AddData\Local\Arduino15\preferences.txt
  • Follow this path: packages>arduino>hardware>sam>1.6.x>cores>arduino and open the cortex_handlers file.

As you will see, any interrupt Handler is named: peripheralname(Uppercase)_Handler(void).