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.