Due using the ADTRG for sampling

I'm looking for some help in getting the Due to sample on the ADTRG. I'm having trouble understanding what is needed to get the Due to sample with the ADTRG signal from an external source.

I've tried:

void adc_setup()
{
  
  
  PMC->PMC_PCER1 |= PMC_PCER1_PID37;                    // ADC power ON
  pinMode(A0, INPUT);
  digitalWrite(A0,HIGH);
 
  ADC->ADC_CR = ADC_CR_SWRST;                           // Reset ADC
  ADC->ADC_MR |=  ADC_MR_TRGEN_EN                       // Hardware trigger select
                  | ADC_MR_TRGSEL_ADC_TRIG0            // Trigger by ADTRG
                  | ADC_MR_LOWRES_BITS_12
                  | ADC_MR_PRESCAL(1);

  ADC->ADC_ACR = ADC_ACR_IBCTL(0b01);                   // For frequencies > 500 KHz

  ADC->ADC_IER = ADC_IER_EOC0;                          // End Of Conversion interrupt enable for channel 7
  NVIC_EnableIRQ(ADC_IRQn);                                  // Enable ADC interrupt
  ADC->ADC_CHER = ADC_CHER_CH0;                         // Enable Channel 0 = A7  
  //pio_ADTRG();
  PMC->PMC_PCER0 |= PMC_PCER0_PID11;
}
void pio_ADTRG()
{
  PMC->PMC_PCER0 |= PMC_PCER0_PID11;  // PIOA periph?
  PIOA->PIO_PDR   = PIO_PA11B_ADTRG;  //Disables PIO from controlling PIN
  PIOA->PIO_IDR   = PIO_PA11B_ADTRG;  //Disables Interrupt
  PIOA->PIO_ABSR   = PIO_PA11B_ADTRG;  //1-assigns to B peripheral
}
This code doesn't work.  I'm not sure how to configure the PIOA with the ADTRG being a peripheral B on the PIO.  I feel like I'm missing something simple.

Any help would be appreciated.

Thank you

You enable an interruption on End Of Conversion of Channel 0, but where is the interrupt handler in your code ?

BTW Post your full code.

Thanks for reading. I didn't include the interrupt handler or the rest of the code because I thought it would confuse the issue. The interrupt handler is never called. I think this is because the ADTRG signal is not triggering the ADC conversion. I think it is because I am not configuring it correctly.

Here is the code. I use TC0 to generate pulses to trigger the ADTRG signal. A jumper is set between PWM2 (TIOA0) and A7 (TIOA1). I can see the pulses are there at A7 (TIOA1), but the interrupt handler never gets called.

// a jumper needs to be installed between pin 2 (PWM2 output TC0 Channel 0- TIOA0) and pin TXD2 (ADTRG)


 #define BOARD_NAME "Arduino Due/X"
 #define STRING_EOL    "\r"
#define STRING_HEADER "-- PDC_UART Example --\r\n" \
"-- "BOARD_NAME" --\r\n" \
"-- Compiled: "__DATE__" "__TIME__" --"STRING_EOL

volatile uint32_t CaptureCount, CaptureCountB, TimerCount,ErrorStatus;
volatile boolean CaptureFlag,ErrorFlag;
uint32_t tStamps[1024];
uint32_t tStamps2[1024];
uint32_t Samples[1024];

char str[100];

void setup() {
  Serial.begin(115200);                                   // initilize Serial port to 250000 baud
  while(!Serial);
  CaptureCountB=0;
  CaptureFlag=0;

//Setup TC0 Ch0 for waveform output
// Output pulsing waveform on TIA0 (B) Pulse width 476ns at a period of 10us simulating pulses
  PMC->PMC_PCER0 |= PMC_PCER0_PID27;                      // Timer Counter 0 channel 0 IS TC0
  pio_TIOA0_B();
  TC0->TC_CHANNEL[0].TC_CCR = TC_CCR_CLKDIS ;                           // disable internal clocking while setup regs
  TC0->TC_CHANNEL[0].TC_CMR = TC_CMR_TCCLKS_TIMER_CLOCK1 // capture mode, MCK/2, clk on rising edge
                              |TC_CMR_ACPA_CLEAR
                              |TC_CMR_ACPC_SET                           
                              | TC_CMR_WAVSEL_UP_RC              // wave up reset @ RC value
                              | TC_CMR_WAVE;         // load RA on rising edge of trigger input
                              
   
    TC0->TC_CHANNEL[0].TC_RA = 200;
    TC0->TC_CHANNEL[0].TC_RC = 420;
    pio_TIOA0_B();
      
  TC0->TC_CHANNEL[0].TC_CCR = TC_CCR_SWTRG | TC_CCR_CLKEN; // Reset TC counter and enable
  // print the startup header
  adc_setup();
  Serial.println("Timer and ADC Capture");
  Serial.println(BOARD_NAME);
  Serial.println( "Compiled: " __DATE__ ", " __TIME__ ", " __VERSION__);
  Serial.println("Setup Complete");
  delay(3000);
  CaptureCountB=0;

}

void loop() {
  int i=0;
  ADC->ADC_CR = ADC_CR_START;
  if (CaptureFlag) {
     for(i=0;i<1024;i++)
     {
      sprintf(str,"Sample:\t%d\tTime:\t%x\tTime2:\t%x\tADC:\t%d",i,tStamps[i],tStamps2[i], Samples[i]);
      Serial.println(str);
     }
     delay(5000);
     CaptureFlag = 0;
     CaptureCountB=0;
     NVIC_EnableIRQ(ADC_IRQn); 
  }
  else{
    sprintf(str,"CCountB: %d, CR Reg: 0x%x, MR Reg: 0x%x, TC Val: 0x%x",CaptureCountB, ADC->ADC_CR, ADC->ADC_MR, TC0->TC_CHANNEL[1].TC_CV );
     Serial.println(str);
     delay(5000);
  }
}

void pio_TIOA0_B()
{
  PIOB->PIO_PDR   = PIO_PB25B_TIOA0;  //Disables PIO from controlling PIN
  PIOB->PIO_IDR   = PIO_PB25B_TIOA0;  //Disables Interrupt
  PIOB->PIO_ABSR |= PIO_PB25B_TIOA0;  //1-assigns to B peripheral
}
void pio_ADTRG()
{
  PMC->PMC_PCER0 |= PMC_PCER0_PID11;  // PIOA periph?
  PIOA->PIO_PDR   = PIO_PA11B_ADTRG;  //Disables PIO from controlling PIN
  PIOA->PIO_IDR   = PIO_PA11B_ADTRG;  //Disables Interrupt
  PIOA->PIO_ABSR   = PIO_PA11B_ADTRG;  //1-assigns to B peripheral
}
void adc_setup()
{
  PMC->PMC_PCER1 |= PMC_PCER1_PID37;                    // ADC power ON
  pinMode(A0, INPUT);
  digitalWrite(A0,HIGH);
 
  ADC->ADC_CR = ADC_CR_SWRST;                           // Reset ADC
  ADC->ADC_MR |=  ADC_MR_TRGEN_EN                       // Hardware trigger select
                  | ADC_MR_TRGSEL_ADC_TRIG0            // Trigger by ADTRG
                  | ADC_MR_LOWRES_BITS_12
                  | ADC_MR_PRESCAL(1);

  ADC->ADC_ACR = ADC_ACR_IBCTL(0b01);                   // For frequencies > 500 KHz

  ADC->ADC_IER = ADC_IER_EOC0;                          // End Of Conversion interrupt enable for channel 7
  NVIC_EnableIRQ(ADC_IRQn);                                  // Enable ADC interrupt
  ADC->ADC_CHER = ADC_CHER_CH0;                         // Enable Channel 0 = A7  
  //pio_ADTRG();
  PMC->PMC_PCER0 |= PMC_PCER0_PID11;
}

void ADC_Handler () {
  ADC->ADC_ISR;
  tStamps[CaptureCountB]= TC0->TC_CHANNEL[1].TC_CV;
  Samples[CaptureCountB] = ADC->ADC_CDR[0];
  tStamps2[CaptureCountB]=TC0->TC_CHANNEL[1].TC_CV;
  if(CaptureCountB++ >= 1024) {
    CaptureFlag=1;
    NVIC_DisableIRQ(ADC_IRQn);
  }
}

I tried an very simple sketch to trigger a one channel ADC conversion at 40 KHz with an external trigger and it seems to work. However, I suspect that the external trigger can't work above a relatively low frequency.

/*****************************************************************/
/*             ADC conversions at 40 KHz KHz                     */
/*    Hook a jumper between pin 12 and PA11(pin 18)              */
/*****************************************************************/

volatile uint32_t lastConversion;
volatile boolean Flag;
void setup()
{
  pinMode(12, OUTPUT);
  pinMode(LED_BUILTIN, OUTPUT);
  
  PMC->PMC_PCER0 |= PMC_PCER0_PID11;  // PIOA power ON
  PIOA->PIO_PDR   = PIO_PA11B_ADTRG;  //Disables PIO from controlling PIN
  PIOA->PIO_ABSR   = PIO_PA11B_ADTRG;  //1-assigns to B peripheral
  adc_setup();
}

void loop()
{
  if (Flag == true)
  {
    Flag = false;
    // A new conversion is available
  }
  digitalWrite(12, HIGH);
  delayMicroseconds(25);
  digitalWrite(12, LOW);
}

/*************  Configure ADC function  *******************/
void adc_setup() {

  PMC->PMC_PCER1 |= PMC_PCER1_PID37;                    // ADC power on
  ADC->ADC_CR = ADC_CR_SWRST;                           // Reset ADC
  ADC->ADC_MR |=  ADC_MR_TRGEN_EN                       // Hardware trigger select
                  | ADC_MR_TRGSEL_ADC_TRIG0             // Trigger by ADTRG
                  | ADC_MR_PRESCAL(1);
  //ADC->ADC_ACR = ADC_ACR_IBCTL(0b01);                   // For frequencies > 500 KHz

  ADC->ADC_CHER = ADC_CHER_CH7;                        // Enable ADC CH7 = A0
  ADC->ADC_IER = ADC_IER_EOC7;                         // Interrupt on End of conversion
  NVIC_EnableIRQ(ADC_IRQn);                            // Enable ADC interrupt

}
void ADC_Handler()
{
  static uint32_t Count;
  lastConversion = ADC->ADC_CDR[7];
  //lastConversion = ADC->ADC_LCDR;//Do NOT clear EOC7 bit !

  Flag = true;
  if (Count++ > 40000)
  {
    Count = 0;
    PIOB->PIO_ODSR ^= PIO_ODSR_P27;
  }
}

For higher frequencies, an input capture on an input pin and plus an ADC software trigger (START/STOP) should do the trick.

Turns out, my problem was in the hardware setup. I need better glasses/lighting. I had the external trigger hooked up to TXD1, not TXD2 which is the ADTRG. So my original code does work.

After some testing, it appears that the PIO doesn't need to be involved at all. Setting the ADC_MR_TRGSEL_ADC_TRIG0 bit seems to take care of the ADTRG, but this is not explicitly stated in the data sheet. You just have to wire it right! :slight_smile:

Also I don't think the frequency should matter, the rise time of the ADTRG could. But as long as the edge of the signal is there it should trigger.

Thanks for looking at this.