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
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!
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.