Go Down

Topic: PWM triggered ADC with Event line (Read 731 times) previous topic - next topic


Jun 29, 2015, 06:37 am Last Edit: Jun 29, 2015, 06:51 am by eugenio412
Hi guys,

I'm trying to achieve an ADC sampling triggered by then PWM. The circuit is very simple, I have an RC filter on the PWM (pin 34 and 35,  PWM ch0), and i'm reading the voltage on the capacitor trough the ADC, on pin A7 (ADC ch0).

As you can see in the image I would like to read the value at half of the transitory, because it's the average voltage.

Reading in the Arduino due ARM chip datasheet at page 1318 you can see that the Arduino due is equipped with a PWM event line, created for this purpose.

I'm pretty good with the registers so I used this way to implement the code. The problem is that the trigger is not reaching the ADC converter, and i don't know why, it's two weeks that I'm trying to figure out why. Meanwhile i wrote a code that uses another PWM (ch4, pin 9),synchronized with the ch0, that is doing the same job wired to the hardware trigger on pin 18. But I need a better solution, an external wire it's not enough for my project. In this case it's working, but I need something better. I also tried to ask to the Atmel support, but the path to reach their engineers is long and nobody gave me the right hint.

On the page 995 of the datasheet you can find how the event line works, it shouldn't be hard to do but for some reason I'm not able to deliver it.

Here my code, the register ADC_MR it's available in three modes, FREERUN (Never wait for a trigger, it's working), External trigger (it's working if you wire the Pin 18 to PWM on pin 9) and event line, that it's not working.

I hope someone of you can help me to deliver this event line trigger.

Have a good day.

Code: [Select]
unsigned int start_time;
unsigned int stop_time;
unsigned long values[1000];
void setup() {
  //PWM configuration
  REG_PIOC_PDR = PIO_PDR_P2 | PIO_PDR_P3 | PIO_PDR_P21; //PIO disable register of PC2, PC3 and PC23(pin34, pin35, pin9)
  REG_PIOC_ABSR = REG_PIOC_ABSR | PIO_ABSR_P2 | PIO_ABSR_P3 | PIO_ABSR_P21; //periphal AB select register for PC2,3 and 21
  REG_PMC_PCER1 = REG_PMC_PCER1 | PMC_PCER1_PID36 | PMC_PCER1_PID37; //Peripheral Clock Enable Register 1 (activate clock for PWM, id36 on PMC_PCSR1)
  REG_PWM_ENA = REG_PWM_SR | PWM_ENA_CHID0 | PWM_ENA_CHID4; //PWM Enable Register | PWM Status Register (activate channel 0 and 4)
  REG_PWM_IER1 = PWM_ISR1_CHID0; //Counter Event on Channel x Interrupt Enable on ch0
  REG_PWM_IER2 = PWM_IER2_CMPM0 | PWM_IER2_CMPU0; //enabling the update and match interrupt on channel 0
  PWM->PWM_ELMR[0] = PWM_ELMR_CSEL0; //PWM_ELMR0 register,PWM event line 0, on PWM ch4
  REG_PWM_CMR0 = PWM_CMR_DTE | PWM_CMR_CALG | PWM_CMR_CES | PWM_CMR_CPRE_MCK; //Channel 0 Mode Register: Dead Time Enable DTE=0;Counter event selection(CES) for up and down position and center allignment(CALG)
  REG_PWM_SCM = PWM_SCM_SYNC0 | PWM_SCM_SYNC4; //sync channel 0 and 4
  REG_PWM_DT0 = PWM_DT_DTH(9) | PWM_DT_DTL(9); //Channel 0 Dead Time Register (100ns * 84MHz = 8.4 ~ 9 step for outputs PWML0,PWMH0)
  REG_PWM_CPRD0 = 210; //Channel 0 Period Register (84mhz/(84 steps)=1Mhz) or half with CALG enabled on CMRx
  REG_PWM_CDTY0 = 105; //duty ratio of pin 35(direct) and 34(inverted), it's the ch0 on pin 34 and 35
  REG_PWM_CDTY4 = 1; //duty ratio of pin 35(direct) and 34(inverted), it's the ch4 on pin
  //ADC configuration
  //REG_ADC_MR = ADC_MR_FREERUN_ON; //enable freerun(never wait for trigger)
  //REG_ADC_MR = ADC_TRIG_EXT; //use an external trigger, on pin 18, connecting the pwm to pin 18 i obtain 1 MSample/s
  REG_ADC_MR = ADC_TRIG_PWM_EVENT_LINE_0;  //enable hardware trigger, select the trigger PWM event line 0 and keep 12 bits
  REG_ADC_CHER = ADC_CHER_CH0; //enable ADC on pin A7, ch0
  Serial.println("start conversion");

void loop() {
  unsigned int i;

  start_time = micros();
  for (i = 0; i < 1000; i++) {
    while ((REG_ADC_ISR & ADC_ISR_EOC0) == 0); // wait for conversion flag on ch0
    values[i] = ADC->ADC_CDR[0]; //get values
  stop_time = micros();

  Serial.print("Total time: ");
  Serial.println(stop_time - start_time);
  Serial.print("Average time per conversion: ");
  Serial.println((float)(stop_time - start_time) / 1000);

  Serial.println("Values: ");
  for (i = 0; i < 1000; i++) {

and here the PWM that drives the external trigger in external trigger mode


This post is more than one year old. I am having the same problem. Has anyone found a solution?

Best regards



Oct 23, 2016, 02:59 pm Last Edit: Oct 23, 2016, 03:58 pm by ard_newbie
In the code above, 2 handlers are triggered by :

PWM->PWM_IER1  = ....  // PWM Interrupt enable 1
PWM->PWM_IER2 = ....

So if you expect these handlers to be triggered several times, you should read their status registers to clear some bits:

void PWM_Handler () {


/*Reading PWM_ISR1 automatically clears flags WRDY, UNRE and CMPSx.
  and PWM_ISR1_Handler() can be triggered again (see Sam3X datasheet
  38.7.17  page 1022) */

Idem for ISR2

Go Up