ADC register Nano every

Hello,

I just got some Nano Every, thinking it would be kinda plug and play with my previous code but, as always, something is going wrong, and I’m afraid that I don’t have the level to get this working by myself,

So, I was using the ADC from the UNO in freemode to get faster readings and do some FFT
The problem is that Every doesnt know what I’m talking about with ADCSRA
The chips works totally differently

Here’s the part of the code that involves this register

for(int i=0; i<SAMPLES; i++)
    {
      while(!(ADCSRA & 0x10));        // wait for ADC to complete current conversion ie ADIF bit set
      ADCSRA = 0b11110101 ;               // clear ADIF bit so that ADC can do next operation (0xf5)
      int value = ADC - 512 ;                 // Read from ADC and subtract DC offset caused value
      vReal[i]= (value/8);                      // Copy to bins after compressing
      vImag[i] = 0;                         
    }

I found this topic talks about it but I can’t figure it out, and neither how to get it on the arduino IDE

I did find some instructions on the Atmel start website but arduino IDE doesn’t know them (atmel_start_init & ADC_0_start_conversion)

atmel_start_init();
  //FREE RUNNING
  ADC0.CTRLA |= 1 << ADC_FREERUN_bp;
  ADC_0_start_conversion(6);  //Ch A4

Help pleease ^^

Did you go through the ATmega4809 datasheet? The ATmega4809 uses a different set of registers to control the ADC than the ATmega328P. You can find the correct register names in the datasheet, to use them in your code, add the ADC0. prefix, e.g. ADC0.CTRLA. Constants are prefixed with ADC_.
Also see this application note: http://ww1.microchip.com/downloads/en/AppNotes/TB3209-Getting-Started-with-ADC-90003209A.pdf
And the corresponding code examples: TB3209_Getting_Started_with_ADC/main.c at master · MicrochipTech/TB3209_Getting_Started_with_ADC · GitHub

Thanks ! The 2 last links were very helpful !
So I kinda got it working, I can start the ADC, switch between the analog pins and get the results, that’s nice

Now it’s still not going right, getting the reading is way too slow, I’m trying to get enough samples for the FFT, 64, and it doesn’t seems to be faster with those instructions than by using the analogRead one.
With the code I had for the UNO it was much faster, I could get some “real time” display of the FFT analysis

So my samples loop looks like this now

   for(int i=0; i<SAMPLES; i++)
    {
      while(!ADC0_conversionDone());        // wait for ADC to complete current conversion ie ADIF bit set
      int value = ADC0_read() - 512 ;                 // Read from ADC and subtract DC offset caused value
      vReal[i]= (value/8);                      // Copy to bins after compressing
      vImag[i] = 0;                         
    }

With the 2 functions here :

uint16_t ADC0_read(void){
    /* Clear the interrupt flag by writing 1: */
    ADC0.INTFLAGS = ADC_RESRDY_bm;
    return ADC0.RES;
}
bool ADC0_conversionDone(void){
    return (ADC0.INTFLAGS & ADC_RESRDY_bm);
}

Am i missing something or is it just the way Every works and I won’t be able to get it doing this right ?

Edit/ I just remember something else that could slow down my program,maybe it has nothing to see with the adc

Ok, so the whole ADC part is going good,
I’m using some led matrix with the MD_MAX72XX library, I can’t understand why but if I use this instruction everything works perfectly

MD_MAX72XX mx = MD_MAX72XX(HARDWARE_TYPE, CS_PIN, MAX_DEVICES);

But if I want to use different pins for the clock and data, as in this one

MD_MAX72XX mx = MD_MAX72XX(HARDWARE_TYPE, DATA_PIN, CLK_PIN, CS_PIN, MAX_DEVICES);

Then everything slows down , maybe 10 times slower… I can’t figure it out, so instead of going mad I prefered to change my wiring even though it’s a little more messy now

Thank you again

If you use the SPI interface, sending data to the display is done by the SPI hardware, which is very fast.
If you specify specific pins, data is clocked out in software, using digitalWrite to drive the clock and data pins, which is much slower.

Alright, good to know ! I should really dive into the hardware stuff a bit more but it takes so long to get it all !

In case you haven't discovered this, the ADC in the Nano Every is capable of doing conversions 8 times faster than the UNO does. It is "throttled down" to be compatible with the UNO. Look at the PRESC field of ADC0.CTRLC. It can be set to a value of 3, which gives a 1MHz ADC clock rather than the 125kHz ADC clock the part is set to by the Arduino library code. This excludes running with the 0.55v reference.

Since you have performance concerns, you might also want to increase the system clock from 16 to 20MHz for a 25% increase (including to the ADC conversion speed, making it 10x faster). If you dig around here you can find instructions on how to make the change (it involves modifying the boards.txt file).

Hi,

another example with RTC and event system. The RTC cyclically starts an ADC measurement. Without MCU load! In the loop a finished measurement is polled. With the CTRLA register there is a bug to consider.

/*
  Doc_Arduino - from the german part of the https://forum.arduino.cc forum.
  IDE 1.8.15
  Arduino Nano Every
  23.05.2021
  License: GNU GPLv3
*/
  
#include <avr/interrupt.h>
#include <util/atomic.h>

const byte messPin {21};  // PD5

volatile unsigned int adcVal;
volatile bool newResult;

void setup()
{
  Serial.begin(250000);
  Serial.println(F("\nµC Reset ### ### ###"));
  
  pinMode(messPin, INPUT);

  initRTC();
  initADC0();
  initEventSystem();
}

void loop()
{
  if (newResult)
  {
    uint16_t var {0};
    ATOMIC_BLOCK (ATOMIC_RESTORESTATE)
    {
      var = adcVal;
    }
    Serial.print("ADC0 "); Serial.print(var); Serial.print(" Digits");
    Serial.println();
    newResult = false;
  }
}

void initADC0(void)
{
  /* IDE default
    ADC0.CTRLA, true);    // 0b0000'0001 -->> enable
    ADC0.CTRLC, true);    // 0b0001'0110 -->> DIV128 und Vref = Vdd
  */

  ADC0.MUXPOS = ADC_MUXPOS_AIN5_gc;     // Select ADC channel, Pin 21
  ADC0.INTCTRL = ADC_RESRDY_bm;         // Enable interrupts
  ADC0.EVCTRL = ADC_STARTEI_bm;         // Enable event triggered conversion
}

ISR(ADC0_RESRDY_vect)
{
  adcVal = ADC0.RES;
  newResult = true;
  ADC0.INTFLAGS = ADC_RESRDY_bm;        // clear result ready interrup flag
}

void initRTC (void)
{  
  // Initialize RTC //   
  while (RTC.STATUS > 0) { ; }              // wait for all register to be synchronized
  RTC.CLKSEL = RTC_CLKSEL_INT32K_gc;        // Periodendauer 30,518µs
  RTC.PER = 64;                             // set period = 1000ms / 15,625ms
  
  // RTC.CTRLA Bug, siehe Errata, CTRLA
  uint8_t temp {0};
  //temp |= RTC_PRESCALER_DIV128_gc;    // Prescaler  128 -->> 30,518µs * 128  =  3,906ms
  temp |= RTC_PRESCALER_DIV512_gc;      // Prescaler  512 -->> 30,518µs * 512  = 15,625ms
  //temp |= RTC_PRESCALER_DIV1024_gc;   // Prescaler 1024 -->> 30,518µs * 1024 = 31,250ms
  temp |= RTC_RUNSTDBY_bm;
  temp |= RTC_RTCEN_bm;                 // enabled  
  RTC.CTRLA = temp;
}

void initEventSystem(void)
{
  EVSYS.CHANNEL0 = EVSYS_GENERATOR_RTC_OVF_gc;      // connect generator 'RTC OVF' with 'channel 0'
  EVSYS.USERADC0 = EVSYS_CHANNEL_CHANNEL0_gc;       // connect 'channel 0' with user 'ADC0'
}