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;
}
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
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
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.
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).
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'
}
Hey there, I'm a bit of a beginner to this and I've been having trouble finding the field you're describing in the documentation of the atmega4809. Would you mind telling me how I could change the PRESC field to get a 1MHz ADC clock? Maybe a one-line of code? Thanks in advance!
Thanks Pieter. So as I understand, if I am running a 20MHz clock, and the 4809 datasheet specifies a max ADC clock speed of 2MHz, I should set my prescaler divider at 10, correct?
Dividers can be set only at powers of 2 and for maximum resolution you cannot go beyond 1.5MHz. Since 20MHz/1.5MHz is ~13 you need to set a /16 clock, ADC_PRESC_DIV16_gc. This gives you a 1.25MHz ADC clock.