Unfortunately, the analogRead() function doesn't work because digital pin D9 is listed as "No_ADC_Channel" in the "variants.cpp" file and analogRead() uses this entry to reference the correct pin.
Here's how to read 12-bit analog values from digital pin D9 using register manipulation:
// Set-up the ADC to read analog input on A7 (D9) with 12-bit resolution
void setup() {
Serial.begin(115200); // Set-up the native serial port at 115200 bit/s
while(!SerialUSB);
ADC->CTRLB.reg = ADC_CTRLB_PRESCALER_DIV512 | // Divide Clock ADC GCLK by 512 (48MHz/512 = 93.7kHz)
ADC_CTRLB_RESSEL_12BIT; // Set ADC resolution to 12 bits
while(ADC->STATUS.bit.SYNCBUSY); // Wait for synchronization
ADC->SAMPCTRL.reg = 0x00; // Set max Sampling Time Length to half divided ADC clock pulse (5.33us)
ADC->INPUTCTRL.bit.MUXPOS = ADC_INPUTCTRL_MUXNEG_PIN7_Val; // Set the analog input to A7
while(ADC->STATUS.bit.SYNCBUSY); // Wait for synchronization
ADC->CTRLA.bit.ENABLE = 1; // Enable the ADC
while(ADC->STATUS.bit.SYNCBUSY); // Wait for synchronization
}
void loop() {
ADC->SWTRIG.bit.START = 1; // Initiate a software trigger to start an ADC conversion
while(ADC->STATUS.bit.SYNCBUSY); // Wait for write synchronization
while(!ADC->INTFLAG.bit.RESRDY); // Wait for the conversion to complete
ADC->INTFLAG.bit.RESRDY = 1; // Clear the result ready (RESRDY) interrupt flag
while(ADC->STATUS.bit.SYNCBUSY); // Wait for read synchronization
int result = ADC->RESULT.reg; // Read the ADC result
SerialUSB.println(result); // Output the result
delay(500); // Wait for 500ms
}
What should I do when I would like to read 3 channels (A1, A2 and D9)? I'm thinking in this direction, but the readings are wrong:
void ADC_Handler()
{
static uint16_t counter = 0; // Results counter
if (ADC->INTFLAG.bit.RESRDY) // Check if the result ready (RESRDY) flag has been set
{
ADC->INTFLAG.bit.RESRDY = 1; // Clear the RESRDY flag
while(ADC->STATUS.bit.SYNCBUSY); // Wait for read synchronization
if(counter == 0) adc_val_a = ADC->RESULT.reg;
if(counter == 1) adc_val_b = ADC->RESULT.reg;
if(counter == 2) adc_val_c = ADC->RESULT.reg;
//Change MUX to next input
ADC->INPUTCTRL.bit.MUXPOS = inputCtrl[counter+1];
while(ADC->STATUS.bit.SYNCBUSY); // Wait for synchronization
if(counter == ADC_CHANNELS-1) // Once the required number of samples have been made
{
ADC->INPUTCTRL.bit.MUXPOS = inputCtrl[0]; // Prepare for next cycle
while(ADC->STATUS.bit.SYNCBUSY); // Wait for synchronization
ADC->CTRLA.bit.ENABLE = 0; // Disable the ADC
while(ADC->STATUS.bit.SYNCBUSY); // Wait for synchronization
counter = 0; // Reset the counter
resultsReady = true; // Set the resultsReady flag
}
else
counter++;
}
}
The ADC will be started each 100us, it seems to work OK, except for the readings, I think it has somehing to do with the MUX registers (MUXPOS and MUXNEG), I'm not sure how these are related to the right ADC pins.
Ok, found out myself, just don't use the freerun, since it seems you are not allowed to change mux setting during freerun mode. I simply start adc conversion and in the adc handler I change mux register to next channel and retrigger a adc read, if all 3 channels are read, I disable the adc. This takes around 70us in total.
void ADC_Handler()
{
static uint16_t counter = 0; // Results counter
if (ADC->INTFLAG.bit.RESRDY) // Check if the result ready (RESRDY) flag has been set
{
ADC->INTFLAG.bit.RESRDY = 1; // Clear the RESRDY flag
while(ADC->STATUS.bit.SYNCBUSY); // Wait for read synchronization
if(counter == 0) adc_val_a= ADC->RESULT.reg;
if(counter == 1) adc_val_b = ADC->RESULT.reg;
if(counter == 2) adc_val_c = ADC->RESULT.reg;
if(counter < ADC_CHANNELS-1) // Once the required number of samples have been made
{
counter++;
//Change MUX to next input
ADC->INPUTCTRL.bit.MUXPOS = inputCtrl[counter];
while(ADC->STATUS.bit.SYNCBUSY); // Wait for synchronization
ADC->SWTRIG.bit.START = 1; // Initiate a software trigger to start an ADC conversion
while(ADC->STATUS.bit.SYNCBUSY); // Wait for synchronization
}
else
{
ADC->INPUTCTRL.bit.MUXPOS = inputCtrl[0]; // Prepare for next cycle
while(ADC->STATUS.bit.SYNCBUSY); // Wait for synchronization
ADC->CTRLA.bit.ENABLE = 0; // Disable the ADC
while(ADC->STATUS.bit.SYNCBUSY); // Wait for synchronization
counter = 0; // Reset the counter
resultsReady = true; // Set the resultsReady flag
}
}
}