Direct Accessing of ADC Registers

Hello all,

Since I am new to Arduino, my question might seem very basic, so please excuse me.
I am trying to use ADC in my Arduino Due. I am trying to directly access the ADC mode register which is ADC_MR. But in the code, lets say I can't just write ADC_MR = 0xXXXXXXXX, because it will give an error "Unknown variable ADC_MR". Can any of you tell me the Header file I must include or is there any other way to directly access the registers.

Thanks in Advance.

Header files are already included in your IDE. To update ADC_MR register use the ADC instance:

ADC->ADC_MR = .....;

Here is an example code to trigger ADC conversions with a 3 KHz frequency:

void setup()
{

  adc_setup();
  tc_setup();
}

void loop()
{

}

/*************  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_TRIG3;            // Trigger by TIOA2

  ADC->ADC_CHER = ADC_CHER_CH7;                        // Enable ADC CH7 = A0

}

/*************  Timer Counter 0 Channel 2 to generate PWM pulses thru TIOA2  ************/
void tc_setup() {

  PMC->PMC_PCER0 |= PMC_PCER0_PID29;                      // TC2 power ON : Timer Counter 0 channel 2 IS TC2
  TC0->TC_CHANNEL[2].TC_CMR = TC_CMR_TCCLKS_TIMER_CLOCK3  // MCK/32, clk on rising edge
                              | TC_CMR_WAVE               // Waveform mode
                              | TC_CMR_WAVSEL_UP_RC        // UP mode with automatic trigger on RC Compare
                              | TC_CMR_ACPA_CLEAR          // Clear TIOA2 on RA compare match
                              | TC_CMR_ACPC_SET;           // Set TIOA2 on RC compare match


  TC0->TC_CHANNEL[2].TC_RC = 875;  //<*********************  Frequency = (Mck/32)/TC_RC  Hz = 3 KHz
  TC0->TC_CHANNEL[2].TC_RA = 400;  //<********************   Any Duty cycle in between 1 and 874

  TC0->TC_CHANNEL[2].TC_CCR = TC_CCR_SWTRG | TC_CCR_CLKEN; // Software trigger TC2 counter and enable

}

Thank you ard_newbie. I will try this code.

Hello,
I allow myself to mingle with your post,
To read A0 and A1 through the registers, I use a code of this style but I do not know how often the ADC works
How to know the frequency of this piece of code?
Can it be improved to increase frequency performance?
Thanks for all your information

void setup() 
{
  ADC->ADC_MR |= 0x80; // Mode FREERUN
  ADC->ADC_CR=2;       // Start converter                         - Demarrage convertisseur
  ADC->ADC_CHER=0xC0; // Enabling channels 6 and 7 (A0 and A1)  - Activation voies 6 et 7 (A0 et A1)
  Serial.begin(115200);
}

void loop() 
{
Serial.print("A0--> ");
  Serial.print(ADC->ADC_CDR[7]);    //AD7
 Serial.print("     A1--> "); 
  Serial.println(ADC->ADC_CDR[6]);  //AD6
}

Bonjour,
Je me permets de me mêler à votre post,
Pour lire A0 et A1 par les registres , j'utilise un code de ce style mais je ne sais pas à quelle fréquence l'ADC fonctionne
Comment connaître la fréquence de ce bout de code ?
Peut-t-on l'améliorer pour augmenter ces performances de fréquence ?
Merci pour toutes vos informations

Hello Tfou57...

I think it is already fast since you have configured your ADC to free running mode. Any ways there might be a better answer to your question. Hopefully someone would answer.

Hi,

I'm also trying to get the adc to work but can't seem to get into the adc interrupt handler. Can someone point me in the right direction? Thanks

I'm setting up TC0 to start the conversion at a fixed interval

#include <Arduino.h>

// setup tc0 channel 0
void setup_adc_timer() {

	PMC -> PMC_PCER0 |= PMC_PCER0_PID27;

	PIOB -> PIO_PDR |= PIO_PDR_P25;					// enable tioa0 output pin
	PIOB -> PIO_ABSR |= PIO_ABSR_P25;

	TC0 -> TC_CHANNEL[0].TC_CMR = TC_CMR_TCCLKS_TIMER_CLOCK4	//MCK/128
								| TC_CMR_WAVE					//waveform mode
								| TC_CMR_WAVSEL_UP_RC					//clk increments and resets itself on RC match
								| TC_CMR_EEVT_XC0        // enable external event
						       |TC_CMR_ENETRG
                                                       | TC_CMR_ACPC_TOGGLE;		// toggle tioa0 on compare match

	// interrupt register		
	TC0 -> TC_CHANNEL[0].TC_IER = TC_IER_CPCS;				// enable interrupt on RC match
	
	TC0 -> TC_CHANNEL[0].TC_RC = 65620;          // 10Hz
	NVIC_EnableIRQ(TC0_IRQn);

}

// enable TC0
void enable_adc_timer() {

	TC0 -> TC_CHANNEL[0].TC_CCR |= TC_CCR_SWTRG | TC_CCR_CLKEN;

}

// setup adc
void setup_adc() {

	PMC -> PMC_PCER1 |= PMC_PCER1_PID37;
	
	ADC -> ADC_CR = ADC_CR_SWRST;      // software reset

	ADC -> ADC_MR |= ADC_MR_TRGSEL_ADC_TRIG1              // select tioa0 as trigger source
					| ADC_MR_STARTUP_SUT96;         // startup period

	ADC -> ADC_CHER |= ADC_CHER_CH7;                            // select ch7 -> A0
	ADC->ADC_IDR= ~(1<<7);                                            // enable interrupt
	ADC -> ADC_IER = ADC_IER_EOC7;

	NVIC_EnableIRQ(ADC_IRQn);

}

void enable_adc() {

	ADC -> ADC_MR |= ADC_MR_TRGEN_EN;

}

void setup(){

	delay(2000);
	Serial.begin(9600);
	Serial.println("Starting serial comms");

        // debug pin
	PIOC -> PIO_OER = (1ul << 1);
	PIOC -> PIO_OWER = (1ul << 1);
	PIOC -> PIO_SODR = (1ul << 1);


	setup_adc_timer();
	setup_adc();

	enable_adc();
	enable_adc_timer();

}

void loop() {}

void TC0_Handler() {

 	TC0->TC_CHANNEL[0].TC_SR;

}

void ADC_handler() {

	ADC -> ADC_ISR;
	PIOC -> PIO_ODSR ^= 1ul << 1;    // toggle pin to see adc working
	
}

The toggle pin doesn't change. My code never goes into ADC_handler(); My oscilloscope does show my tioa0 signal, so no problems with the timer.

Here is an example sketch to trigger ADC conversion at a 3 KHz frequency:

/********************************************************************************/
/*     ADC conversions triggered by a Timer Counter at a 3 KHz frequency        */
/********************************************************************************/

volatile uint16_t LastConversion;
volatile boolean FlagSomethingToRead;
void setup()
{

  adc_setup();
  tc_setup();
}

void loop()
{
  if (FlagSomethingToRead == true) {
    FlagSomethingToRead = false;
    // Do something with the last conversion
  }
}

/*************  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_TRIG3;            // Trigger by TIOA2

  ADC->ADC_IER = ADC_IER_EOC7;                         // Interrupt on End Of Conversion for channel 7 = A0
  NVIC_EnableIRQ(ADC_IRQn);                            // Enable ADC interrupts

  ADC->ADC_CHER = ADC_CHER_CH7;                        // Enable ADC CH7 = A0

}

void ADC_Handler() {

  LastConversion = ADC->ADC_CDR[7]; // Read the last conversion and
                                    //clear status register ADC->ADC_SR bit EOC7
  FlagSomethingToRead = true;
}

/*************  Timer Counter 0 Channel 2 to generate PWM pulses thru TIOA2  ************/
void tc_setup() {

  PMC->PMC_PCER0 |= PMC_PCER0_PID29;                      // TC2 power ON : Timer Counter 0 channel 2 IS TC2
  TC0->TC_CHANNEL[2].TC_CMR = TC_CMR_TCCLKS_TIMER_CLOCK3  // MCK/32, clk on rising edge
                              | TC_CMR_WAVE               // Waveform mode
                              | TC_CMR_WAVSEL_UP_RC        // UP mode with automatic trigger on RC Compare
                              | TC_CMR_ACPA_CLEAR          // Clear TIOA2 on RA compare match
                              | TC_CMR_ACPC_SET;           // Set TIOA2 on RC compare match


  TC0->TC_CHANNEL[2].TC_RC = 875;  //<*********************  Frequency = (Mck/32)/TC_RC  Hz = 3 KHz
  TC0->TC_CHANNEL[2].TC_RA = 400;  //<********************   Any Duty cycle in between 1 and 874

  TC0->TC_CHANNEL[2].TC_CCR = TC_CCR_SWTRG | TC_CCR_CLKEN; // Software trigger TC2 counter and enable

}

Note that TIOA2 triggers ADC conversions internally (in fact TIOA2 pin is not broken out).

Thanks for your code. I recognize it from somewhere as I googled lots to find a good solution haha. But I don't think I was able to run it correctly. I'll test your code somewhere this week and dissect it to use it for my application.
A quick run now gave me errors, idk why you declare variables and function as last. Fixing that, the toggle pin isn't that clean.