Start ADC-conversion with PWM-Interrupt

Hi,

i have a small problem, i try to fix it, and can't find a solution.
I want to use a PWM-Interrupt to start the ADC-conversion. After the conversion is finished i want to start the adc_handler to get the values.

I get an pwm-interrupt in the pwm-handler but the adc_handler is not triggered.

any idea what i'm doing wrong?

void vCFG_PWM_setup () {

  PMC->PMC_WPMR &= 0xFFFFFFFE;   
  PMC->PMC_PCER1 |= PMC_PCER1_PID36;                  // activate PWM
  PIOC->PIO_ABSR |= PIO_ABSR_P22 | PIO_ABSR_P23;      // wähle Peripheral Option B (PWM5 UND PWM6)
  PIOC->PIO_PDR  |= PIO_PDR_P22 | PIO_PDR_P23;        // PWM Pins as output (PWM5 UND PWM6 )

  PWM->PWM_CLK = PWM_CLK_PREA(0) | PWM_CLK_DIVA(1);   // PWM clock A- Fequenz zu 84MHz/1

  PWM->PWM_CH_NUM[5].PWM_CMR = PWM_CMR_CPRE_CLKA;     // Aktivierung einer einzel PWM mit Clock A
  PWM->PWM_CH_NUM[5].PWM_CMR |= PWM_CMR_CALG;         // Ausrichtung symmetrisch
  PWM->PWM_CH_NUM[5].PWM_CPRD = PWM_MAX_INK;          // PWM Frequenz (84MHz/INK)
  PWM->PWM_CH_NUM[5].PWM_CMR |= PWM_CMR_CPOL;         // Polarität invertiert 

  PWM->PWM_CH_NUM[6].PWM_CMR = PWM_CMR_CPRE_CLKA;     // Aktivierung einer einzel PWM mit Clock A
  PWM->PWM_CH_NUM[6].PWM_CMR |= PWM_CMR_CALG;        
  PWM->PWM_CH_NUM[6].PWM_CPRD = PWM_MAX_INK;          
  PWM->PWM_CH_NUM[6].PWM_CMR |= PWM_CMR_CPOL;      

  PWM->PWM_IER1 = PWM_ENA_CHID5;//| PWM_ENA_CHID6;      // ISR1 Interrupt bei Channel 5
  PWM->PWM_IER2 = PWM_IER2_CMPM5;                       // ISR2 Interrupt bei Channel 5 (Match)
  PWM->PWM_IER2 |= PWM_ENA_CHID5;//| PWM_ENA_CHID6;     //
  
  //Eventline
  PWM->PWM_ELMR[1] = PWM_ELMR_CSEL5;

  NVIC_SetPriority(PWM_IRQn, 2);
  NVIC_EnableIRQ(PWM_IRQn);
  PWM->PWM_ENA = PWM_ENA_CHID5 | PWM_ENA_CHID6;   // PWM Channel aktivieren

}

void vCFG_ADC_Init(int iFrequenz) {

  int iPrescal = (ADC_FREQUENZ / iFrequenz) - 1 ;   // f= 2Mhz / (1+prescal)

  PMC->PMC_PCER1 |= PMC_PCER1_PID37;                // ADC power on
  ADC->ADC_CR = ADC_CR_SWRST;   
  
  ADC->ADC_WPMR &= 0xFFFFFFFE;                  // disable write protect
  
  ADC->ADC_IER    = ADC_CHER_CH7;                 // enable interrupt triggered by End of Conversion on channel 7


  //ADC->ADC_MR     = ADC_MR_FREERUN | ADC_MR_PRESCAL(2000);
  ADC->ADC_MR     =  ADC_MR_TRGEN_EN | ADC_MR_TRGSEL_ADC_TRIG5 | ADC_MR_PRESCAL(1);
  ADC->ADC_MR     |=  ADC_12_BITS;
  ADC->ADC_CHER   =   ADC_CHER_CH7;              // enable channel 7
  ADC->ADC_CHER   |=  ADC_CHER_CH6;              // enable channel 6
  ADC->ADC_CHER   |=  ADC_CHER_CH4;              // enable channel 5
//change gain 
  adc_enable_anch(ADC);
  adc_set_channel_input_gain(ADC, ADC_CHANNEL_7, ADC_GAINVALUE_1);
  adc_set_channel_input_gain(ADC, ADC_CHANNEL_6, ADC_GAINVALUE_1);
  adc_set_channel_input_gain(ADC, ADC_CHANNEL_5, ADC_GAINVALUE_1);
  
  NVIC_SetPriority(ADC_IRQn, 1);
  NVIC_EnableIRQ(ADC_IRQn);
}
void ADC_Handler() {  // ADC Interupt Service Routine
  int dummy = ADC->ADC_LCDR;
  static bool boTest = false;
  stEA.iUi_Raw = ADC->ADC_CDR[PIN_A0];           
  stEA.iLageRaw   = ADC->ADC_CDR[PIN_A2];  
  stEA.iInputRaw  = ADC->ADC_CDR[PIN_A1]; 

  boTest = !boTest;
}

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
   //alternative start of adc-trigger (also not working
//  ADC->ADC_CR |= ADC_CR_START;
}

From the code you provided, it looks like you have set up the ADC and PWM interrupts correctly. However, you are not starting the ADC conversion in the PWM interrupt handler.

In the PWM_Handler function, you should add a line of code to start the ADC conversion. This can be done by setting the START bit in the ADC_CR register.

Here's an example of how you could modify the PWM_Handler function:

javaCopy code

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
   
   // start ADC conversion
   ADC->ADC_CR |= ADC_CR_START;
}

This will trigger the ADC conversion and the ADC interrupt handler should be called when the conversion is complete.

as i have limited replies from Arduino i would like to help for further assistance feel free to visit me on any account attact to my profile

sorry my mistake.
That way you describe is working for that i have to deactivate the hardware-trigger and write the pwm_handler like you posted. but i dont want to use the pwm handler i want to start the adc-conversion directly with the pwm-eventline mechanism.

1 Like

I see, if you want to start the ADC conversion directly with the PWM event line mechanism, you can use the following approach:

  1. Configure the PWM timer to generate an event when the pulse starts. You can do this by setting the PWM timer's event generation register (EGR) to trigger on the update event, like this:

rustCopy code

TIM1->EGR |= TIM_EGR_UG; // Generate an update event to start the PWM timer
TIM1->CR2 |= TIM_CR2_MMS_1; // Set the PWM timer to generate an update event on the TRGO line when a new PWM period starts
  1. Configure the ADC to start a conversion when it receives a trigger from the PWM timer's event line. You can do this by setting the ADC's external trigger conversion mode (EXTEN) to trigger on the rising edge of the PWM timer's event line, like this:

lessCopy code

ADC1->CR2 |= ADC_CR2_EXTEN_0; // Set the ADC to trigger on a rising edge
ADC1->CR2 |= ADC_CR2_EXTSEL_0 | ADC_CR2_EXTSEL_2; // Set the ADC trigger source to the TRGO line of TIM1
  1. Start the PWM timer, which will trigger the ADC to start a conversion at the beginning of each PWM period.

lessCopy code

TIM1->CR1 |= TIM_CR1_CEN; // Start the PWM timer

I hope this helps! Let me know if you have any further questions.

hi hiibraahmad,

thanks for your support. but i don't understand what you want to do with the TIM1.
It looks more complicated than i read in the datasheet of the controller.

normally i just want to fire an eventline interrupt using the the pwm register.
what i read in the datasheet is that the eventline is called when the comparator is working. And the comparator is just working with the sync channels.

so what i try i to snyc my channels in the pwm and configure the comparator.
the code

void vCFG_PWM_setup () {
  // Initialisierung PWM-Steuerung
  PMC->PMC_WPMR &= 0xFFFFFFFE;   
  PMC->PMC_PCER1 |= PMC_PCER1_PID36;                  // aktiviert PWM
  PIOC->PIO_ABSR |= PIO_ABSR_P22 | PIO_ABSR_P23;      // wähle Peripheral Option B (PWM5 UND PWM6)
  PIOC->PIO_PDR  |= PIO_PDR_P22 | PIO_PDR_P23;        // PWM Pins als Ausgang (PWM5 UND PWM6 )

  PWM->PWM_CLK = PWM_CLK_PREA(0) | PWM_CLK_DIVA(1);   // PWM clock A- Fequenz zu 84MHz/1

  PWM->PWM_CH_NUM[5].PWM_CMR = PWM_CMR_CPRE_CLKA;     // Aktivierung einer einzel PWM mit Clock A
  PWM->PWM_CH_NUM[5].PWM_CMR |= PWM_CMR_CALG;         // Ausrichtung symmetrisch
  PWM->PWM_CH_NUM[5].PWM_CPRD = PWM_MAX_INK;          // PWM Frequenz (84MHz/INK)
  //PWM->PWM_CH_NUM[5].PWM_CMR |= PWM_CMR_CPOL;         // Polarität invertiert 

  PWM->PWM_CH_NUM[6].PWM_CMR = PWM_CMR_CPRE_CLKA;     // Aktivierung einer einzel PWM mit Clock A
  PWM->PWM_CH_NUM[6].PWM_CMR |= PWM_CMR_CALG;         // Ausrichtung symmetrisch
  PWM->PWM_CH_NUM[6].PWM_CPRD = PWM_MAX_INK;          // PWM Frequenz (84MHz/INK)
  //PWM->PWM_CH_NUM[6].PWM_CMR |= PWM_CMR_CPOL;         // Polarität invertiert 
  
  //PWM-Sync-Channel konfigurieren
  PWM->PWM_SCM |= PWM_SCM_SYNC0 | PWM_SCM_SYNC5 | PWM_SCM_SYNC6;
  PWM->PWM_SCM |= PWM_SCM_UPDM_MODE1;
  PWM->PWM_CH_NUM[0].PWM_CMR = PWM_CMR_CPRE_CLKA;
  PWM->PWM_CH_NUM[0].PWM_CMR |= PWM_CMR_CALG;         // Ausrichtung symmetrisch
  //PWM->PWM_CH_NUM[0].PWM_CMR |= PWM_CMR_CPOL;         // Polarität invertiert 
  PWM->PWM_CH_NUM[0].PWM_CPRD = PWM_MAX_INK;          // PWM Frequenz (84MHz/INK)
  PWM->PWM_CH_NUM[0].PWM_CDTYUPD = PWM_MAX_INK;          // PWM Frequenz (84MHz/INK)

  PWM->PWM_CMP[0].PWM_CMPV = PWM_CMPV_CV(PWM_MAX_INK/2);
  PWM->PWM_CMP[0].PWM_CMPM = PWM_CMPM_CEN;
  PWM->PWM_IER2 |= PWM_IER2_CMPM0;
  PWM->PWM_ELMR[1] = PWM_ELMR_CSEL0;
  
  //PWM->PWM_IER1 = PWM_ENA_CHID5;//| PWM_ENA_CHID6;      // ISR1 Interrupt bei Channel 5
  //PWM->PWM_IER2 = PWM_IER2_CMPM5;                       // ISR2 Interrupt bei Channel 5 (Match)
  //PWM->PWM_IER2 |= PWM_ENA_CHID5;//| PWM_ENA_CHID6;     //

  NVIC_SetPriority(PWM_IRQn, 0);
  NVIC_EnableIRQ(PWM_IRQn);
  PWM->PWM_ENA = PWM_ENA_CHID5 | PWM_ENA_CHID6 | PWM_ENA_CHID0;   // PWM Channel aktivieren
}

void vCFG_ADC_Init(int iFrequenz) {

  int iPrescal = (ADC_FREQUENZ / iFrequenz) - 1 ;   // f= 2Mhz / (1+prescal)

  PMC->PMC_PCER1 |= PMC_PCER1_PID37;                // ADC power on
  ADC->ADC_CR = ADC_CR_SWRST;   
  
  ADC->ADC_WPMR &= 0xFFFFFFFE;                  // disable write protect
  //alle Analogkanäle lösen Interrupt aus bei fertiger Konvertierung
  ADC->ADC_IER    = ADC_CHER_CH7;                 // enable interrupt triggered by End of Conversion on channel 7
  //ADC->ADC_IER    |=(1 << PIN_A1);              // enable interrupt triggered by End of Conversion on channel 6
  //ADC->ADC_IER    |=(1 << PIN_A2);              // enable interrupt triggered by End of Conversion on channel 5


  //ADC->ADC_MR     = ADC_MR_FREERUN | ADC_MR_PRESCAL(2000);
   ADC->ADC_MR     =  ADC_MR_TRGEN_EN | ADC_MR_TRGSEL_ADC_TRIG4 | ADC_MR_TRGSEL_ADC_TRIG5 | ADC_MR_PRESCAL(1);
  ADC->ADC_MR      =  ADC_MR_PRESCAL(1);
  ADC->ADC_MR     |=  ADC_12_BITS;
  ADC->ADC_CHER    =  ADC_CHER_CH7;              // enable channel 7
  ADC->ADC_CHER   |=  ADC_CHER_CH6;              // enable channel 6
  ADC->ADC_CHER   |=  ADC_CHER_CH5;              // enable channel 5
  //Auflösung anpassen
  
  //ADC->ADC_CGR = ADC_CGR_GAIN0(ADC_GAINVALUE_1);
  adc_enable_anch(ADC);
  adc_set_channel_input_gain(ADC, ADC_CHANNEL_7, ADC_GAINVALUE_1);
  adc_set_channel_input_gain(ADC, ADC_CHANNEL_6, ADC_GAINVALUE_1);
  adc_set_channel_input_gain(ADC, ADC_CHANNEL_5, ADC_GAINVALUE_1);
  
  NVIC_SetPriority(ADC_IRQn, 1);
  NVIC_EnableIRQ(ADC_IRQn);
}

In my debugger i see that ier2 is fired with the Value of 263. So all looks correct from the PWM-side. But the ADC-Handler is not working.

got it running.

in the last code example the line "ADC->ADC_MR = ADC_MR_PRESCAL(1);" is wrong.
if i delete this it work like expected

1 Like

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.