counting PWM pulses with Arduino Due

Hi,

I generate a 500kHz PWM 50% duty-cycle signal with my ArduinoDue. After x periods of the PWM signal I want to generate a short output pulse on any digital output. I don't want to use my CPU (no ISR, polling, etc.) to count the pulses. I read about "PWM event lines" in the datasheet of the SAM3X but i am not sure whether they are useful for me... I also read something similar in the Arduino Zero (SAMD21) datasheet it is called "Event system"... Has anybody a good idea how to realize my plan?

regards,
Manuel

1 Like

Pulses generated on event lines are mostly used as hardware triggers for ADC conversions, but comparisons are also used for other purposes:

In Sam3x datasheet:

38.6.3 PWM Comparison Units

These comparisons are intended ….()…to generate software interrupts (thru PWM_ISR2).

Each time a comparison matches, PWM_Handler() is triggered provided CMPMx bit has been previously set in PWM_IER2 in setup(). Then inside the exception handler, read status register to clear it and, e.g. toggle a PIO pin previously selected as output PIO in setup().

Note that Sam3x and Sam4 share the same PWM controller, but documentation for Sam4 is slightly more detailed. Look at figure 39-17 page 974 of Sam4 datasheet (Atmel-11100K-ATARM-SAM4S-Datasheet_09-Jun-15) to see an example of PWM comparison.

Hi,
Welcome to the forum.

Please read the first post in any forum entitled how to use this forum.
http://forum.arduino.cc/index.php/topic,148850.0.html

What is generating the 500kHz 50% PWM?

Tom... :slight_smile:

You can use an external clock to trigger the count in a timer. Then set up the rest of the timer to generate an interrupt on a specific count. Then the only CPU time that is used is when you count is reached ad you do something.
See the data sheet of the specific processor you want to use for details.

@TomGeorge: you're right , i generate the PWM signal with my ArduinoDue, sry

@ard_newbie: thank you that is what i was looking for. do you know any example code?

regards,
Manuel

I don't have a ready-made code for that, but I suggest that you follow up step by step chap. 38.6.5 PWM Controller Operations page 996 (only the steps you need of course).

Personally I found more handy to use direct register programming with the help of datasheet rather than ASF functions when it comes to debugging….

Then, if any issue occurs, post your code (between code tags), describe the issue. You can eventually post in the sub-forum of this forum dedicated to the DUE here

I generate a 500kHz PWM 50% duty-cycle signal with my ArduinoDue. After x periods of the PWM signal I want to generate a short output pulse on any digital output. I don’t want to use my CPU (no ISR, polling, etc.) to count the pulses.

I second Grumpy_Mike’s approach.

Split your output pulse, and use one branch as an external clock source to a timer. No CPU resources are used in counting. You can certainly set a compare match interrupt for the count you want.

I’m not familiar with the Due, but it may be possible to use some timer hardware output pin to generate your output on compare match, and no interrupts will be involved.

After x periods of the PWM signal I want to generate a short output pulse on any digital output. I don't want to use my CPU (no ISR, polling, etc.) to count the pulses.

CPLD.

i like the more elegant way to work with PWM comparison matches, because i can use the signal internally. I am still trying to register the comparison match interrupt, but it does not work... If i want to debug the register settings stepwise, do i need a debugger tool (Atmel ICE)?

You can also use second counter properly prescaled and started at the same time to generate the short pulses. Possibly no need for physical connection to the PWM.

i try to implement a interrupt handler for a PMW comparison match, maybe it is bullshit code but i just want to understand how to set up an interrupt for a PWM comparison match, but it doesn't work, can anyone help me?

long ctr = 0;

void setup() {
  REG_PIOC_PDR = 0x3FC;  
  REG_PIOC_ABSR |= 0x3FCu; 
  REG_PMC_PCER1 |= 16; 
  REG_PWM_WPCR = 0;
  REG_PWM_CLK |= PWM_CLK_DIVA(1)| PWM_CLK_PREA(1) | PWM_CLK_DIVB(1) | PWM_CLK_PREB(1);                
  REG_PWM_CMR0 |= PWM_CMR_CPRE_MCK; 
  REG_PWM_CPRD0 |= PWM_CPRD_CPRD(15);
  REG_PWM_CDTY0 |= PWM_CDTY_CDTY(8);
  REG_PWM_CMPV0 |= PWM_CMPV_CV(0);
  REG_PWM_CMPM0 |= PWM_CMPM_CEN | PWM_CMPM_CTR(0) | PWM_CMPM_CPR(0); 
  REG_PWM_IER1 |= 0;
  REG_PWM_IER2 |= PWM_IER2_CMPM0;
  REG_PWM_ENA |= PWM_IER2_CMPM0;
  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);
}
 
void loop() 
{
}

void PWM_Handler()         
{
  ctr+=1;
  PWM->PWM_ISR1; 
}

A few thoughts about this snippet :

I suppose you decided to use PWM channel 0 (PWMH0).

2 main documents will drive your code writing: the pinout diagram (the one from Greynomad is overkill) and Sam3x datasheet.

Since header files are included in your IDE, it's much easier to use them rather than magic numbers that (nearly) nobody can decipher. E.g. at the beginning of your setup(), you have to tell the uc that a PIO will be driven by a peripheral instead of the GPIO :

Page 973 of datasheet: PWMH0 => Instance PWM, I/O line PC3 (Arduino pin 35), Peripheral B

PIOC->PIO_PDR |=PIO _PDR_P3; // PC3 is driven by the Peripheral
PIOC->PIO_ABSR|= PIO_ABSR_P3; // Peripheral B is selected
// Alternately, you could write PIOC->PIO_ABSR |= PIO_PC3B_PWMH0;

And so on….

In PWM_Handler(), since you previously enabled an interruption in PWM_IER2 register (CMPM0), you need to clear the corresponding status register because you want it to fire again, i.e. PWM_ISR2, and maybe do something in your interrupt function.

If you want a counter in your interrupt function, declare a : uint32_t ctr=0;

Then in your loop(), you will be doing a Serial.print(ctr); every x ms. Note that Serial.print should not be used inside an interrupt function which needs to be as short as possible.

I did recently a PWM snippet in this thread, reply #16 :

I don't understand why, but i don't get my PWM comparison match interrupt running. Ideas???

#include "arduino.h"

//
//
void PWM_Handler();
uint32_t ctr = 0;

void setup() {
	NVIC_DisableIRQ(PWM_IRQn); 
	NVIC_ClearPendingIRQ(PWM_IRQn);
	REG_PMC_PCER1 |= PMC_PCER1_PID36;   
	REG_PWM_WPCR = 0;                   
	REG_PIOC_PDR |= PIO_PDR_P3;        
	REG_PIOC_ABSR |= PIO_ABSR_P3;       
	REG_PWM_CLK |= PWM_CLK_DIVA(1)| PWM_CLK_PREA(1) | PWM_CLK_DIVB(1) | PWM_CLK_PREB(1);
	REG_PWM_CMR0 |= PWM_CMR_CPRE_MCK;
	REG_PWM_CPRD0 |= PWM_CPRD_CPRD(15);
	REG_PWM_CDTY0 |= PWM_CDTY_CDTY(8);
	REG_PWM_CMPV0 |= PWM_CMPV_CV(0);
	REG_PWM_CMPM0 |= PWM_CMPM_CEN | PWM_CMPM_CTR(1) | PWM_CMPM_CPR(1);
	//REG_PWM_IER1 |= PWM_IER1_CHID0;
	REG_PWM_IER2 |= PWM_IER2_CMPM0;
	REG_PWM_ENA |= PWM_ENA_CHID0;
	NVIC_SetPriority(PWM_IRQn, 0);
	NVIC_EnableIRQ((IRQn_Type)36);
	NVIC_EnableIRQ(PWM_IRQn);
}

void loop()
{
}

void PWM_Handler()
{
	ctr+=1;
	REG_PWM_ISR2;
}