Nano Every ADC pins vs. MUXPOS value

Hello,

I'm using a Nano Every and (for good reassons, please trust me) I'm using the ADC by direct register programming. The code I have is working and input voltages agree well with returned ADC data ... except they seem to be on the wrong ADC channel.

I've selected the 2.5V internal reference and done some testing:

(the details below use the Nano Every schematics to map from module pins to ATMEGA4809 pins and the datasheet (48-pin package) then takes us from 4809 pins to AINx channels ... I thought AINx was the MUSPOS value needed to select that input but ...)

1.2V on Arduino Nano Every module pin 4 = A0 net = pin 23 (AIN3) >> 0x1DE on MUXPOS 4
1.2V on Arduino Nano Every module pin 5 = A1 net = pin 22 (AIN2) >> 0x1DE on MUXPOS 3
1.2V on Arduino Nano Every module pin 6 = A2 net = pin 21 (AIN1) >> 0x1DE on MUXPOS 2
1.2V on Arduino Nano Every module pin 7 = A3 net = pin 20 (AIN0) >> 0x1DE on MUXPOS 1
1.2V on Arduino Nano Every module pin 10 = A6 net = pin 24 (AIN4) >> 0x1DE on MUXPOS 5
1.2V on Arduino Nano Every module pin 11 = A7 net = pin 25 (AIN5) >> 0x1DE on MUXPOS 0

I've carefully set up the control registers, made sure the clock tree is giving the ADC a clock of around 100kHz and each sample is manually triggered (i.e. set MUXPOS, wait a few ms for settling, start a convserion, wait until the resultReady flag is set, read ADC result). Does anyone know why AINx does not correspond to the MUXPOS value? This mapping seems to be the only problem. I suspect I'm missing something obvious.

Nano Every schematics: https://docs.arduino.cc/resources/schematics/ABX00028-schematics.pdf

Thanks.

Hi,

Your table or its assignment is incorrect. For example, ADC0 is pin 21 on PD5.
ADC0.MUXPOS = ADC_MUXPOS_AIN5_gc; // select A7 input channel -->> Pin 21 / PD5

For example, you want to measure pin name 'A2" on Arduino, which is real pin PD1, then this is the ADC channel AN1. You write:
ADC0.MUXPOS = ADC_MUXPOS_AIN1_gc; // Pin 16 / PD1

Table
 Arduino Nano Every PinOut (ATmega4809)
                           _
                        __|_|__    
                       |       |  
      (SCK)(D13)  PE2  +       +  PE1  (D12)(MISO)  
                 3.3V  +       +  PE0  (D11)(MOSI)  
           (AREF) PD7  +       +  PB1  (D10)(~)(TCA0 Channel 1)
       (A0)(D14)  PD3  +       +  PB0  (D 9)(~)(TCA0 Channel 0)
       (A1)(D15)  PD2  +       +  PE3  (D 8)(SS)
       (A2)(D16)  PD1  +       +  PA1  (D 7) 
       (A3)(D17)  PD0  +       +  PF4  (D 6)(~)(TCB0)
  (SDA)(A4)(D18)  PF2  +       +  PB2  (D 5)(~)(TCA0 Channel 2)
  (SDL)(A5)(D19)  PF3  +       +  PC6  (D 4)  
       (A6)(D20)  PD4  +       +  PF5  (D 3)(~)(TCB1)  
       (A7)(D21)  PD5  +       +  PA0  (D 2) 
                 5.0V  +       +  GND
                RESET  +       +  RESET
                  GND  +       +  PC5  (D 0) RX1
                  VIN  +       +  PC4  (D 1) TX1      
                       |_______|  

//----------------------------------------------------------------------------------------------------------------------------------------------

 With 'default' in the table the view from the µC is meant. Not the one of the Arduino framework. 
 If you don't change anything at the portmux registers, the setting according to the board label above is valid.

 Ardu      |    Event       | EVSYS  |      CCL-LUTn     |       TCA0        |       TCBn        |  ADC0   |
  Pin Port | Port | Channel |        | default | PortMux | default | PortMux | default | PortMux | default |
   0  PC5  |  0     2 or 3  |  ----  |   ---       ---   |   ---      0-WO5  |   ---       ---   |         |
   1  PC4  |  0     2 or 3  |  ----  |   ---       ---   |   ---      0-WO4  |   ---       ---   |         |
   2  PA0  |  0     0 or 1  |  ----  |  0-IN0      ---   |  0-WO0      ---   |   ---       ---   |         |
   3  PF5  |  1     4 or 5  |  ----  |   ---       ---   |   ---      0-WO5  |   ---      1-WO   |  AIN15  |
   4  PC6  |  0     2 or 3  |  ----  |   ---      1-OUT  |   ---       ---   |   ---       ---   |         |
   5  PB2  |  1     0 or 1  | EVOUTB |   ---       ---   |   ---      0-WO2  |   ---       ---   |         |
   6  PF4  |  1     4 or 5  |  ----  |   ---       ---   |   ---      0-WO4  |   ---      0-WO   |  AIN14  |
   7  PA1  |  0     0 or 1  |  ----  |  0-IN1      ---   |  0-WO1      ---   |   ---       ---   |         |
   8  PE3  |  0     4 or 5  |  ----  |   ---       ---   |   ---      0-WO3  |   ---       ---   |  AIN11  |
   9  PB0  |  1     0 or 1  |  ----  |   ---       ---   |   ---      0-WO0  |   ---       ---   |         |
  10  PB1  |  1     0 or 1  |  ----  |   ---       ---   |   ---      0-WO1  |   ---       ---   |         |
  11  PE0  |  0     4 or 5  |  ----  |   ---       ---   |   ---      0-WO0  |   ---       ---   |  AIN8   |
  12  PE1  |  0     4 or 5  |  ----  |   ---       ---   |   ---      0-WO1  |   ---       ---   |  AIN9   |
  13  PE2  |  0     4 or 5  | EVOUTE |   ---       ---   |   ---      0-WO2  |   ---       ---   |  AIN10  |
  14  PD3  |  1     2 or 3  |  ----  |  2-OUT      ---   |   ---      0-WO3  |   ---       ---   |  AIN3   |
  15  PD2  |  1     2 or 3  | EVOUTD |  2-IN2      ---   |   ---      0-WO2  |   ---       ---   |  AIN2   |
  16  PD1  |  1     2 or 3  |  ----  |  2-IN1      ---   |   ---      0-WO1  |   ---       ---   |  AIN1   |
  17  PD0  |  1     2 or 3  |  ----  |  2-IN0      ---   |   ---      0-WO0  |   ---       ---   |  AIN0   |
  18  PF2  |  1     4 or 5  | EVOUTF |  3-IN2      ---   |   ---      0-WO2  |   ---       ---   |  AIN12  |  board internal double assignment with PA2 observe !!! (EVOUTA)
  19  PF3  |  1     4 or 5  |  ----  |  3-OUT      ---   |   ---      0-WO3  |   ---       ---   |  AIN13  |  board internal double assignment with PA3 observe !!!
  20  PD4  |  1     2 or 3  |  ----  |   ---       ---   |   ---      0-WO4  |   ---       ---   |  AIN4   |
  21  PD5  |  1     2 or 3  |  ----  |   ---       ---   |   ---      0-WO5  |   ---       ---   |  AIN5   |

Hey Doc_Arduino,

Genuinely many thanks for your reply. I completely agree, I have to be doing something wrong but I'm still struggling to see what it is. I'm an electronic engineer so my favourite (perhaps more difficult) route is to go via datasheets and schematics. If I can beg for a little more time from you, perhaps I can explain the process I used and maybe you can spot the error?

As an example I have a voltage (1.2V) applied to Nano Every pin 5. Using the official Arduino schematics for the Nano Every (https://docs.arduino.cc/resources/schematics/ABX00028-schematics.pdf) I see the following:

JP2 pin 5 connects to the A1 schematic signal which connects to the ATMEGA4809 pin 22 (PD02).

From the ATMEGA4809 datasheet (https://ww1.microchip.com/downloads/en/DeviceDoc/ATmega4808-4809-Data-Sheet-DS40002173A.pdf) in section 4.1 we have the 48-pin pinout:

This shows ATMEGA4809 pin 22 is AIN2.

The ATMEGA4809 datasheet's MUXPOS entry shows:

So, I think, AIN2 is measured by setting MUXPOS = 0x02.

... but ... (just repeating for ease of reading) ... my actual physical tests showed:

1.2V on Arduino Nano Every module pin 4 = A0 net = pin 23 (AIN3) >> 0x1DE on MUXPOS 4
1.2V on Arduino Nano Every module pin 5 = A1 net = pin 22 (AIN2) >> 0x1DE on MUXPOS 3
1.2V on Arduino Nano Every module pin 6 = A2 net = pin 21 (AIN1) >> 0x1DE on MUXPOS 2
1.2V on Arduino Nano Every module pin 7 = A3 net = pin 20 (AIN0) >> 0x1DE on MUXPOS 1
1.2V on Arduino Nano Every module pin 10 = A6 net = pin 24 (AIN4) >> 0x1DE on MUXPOS 5
1.2V on Arduino Nano Every module pin 11 = A7 net = pin 25 (AIN5) >> 0x1DE on MUXPOS 0

For AIN0/1/2/3 the MUXPOS value seems to be "AINx + 1" but this breaks for AIN4/5.

The code I'm using to read each ADC channel is:

uint16_t getADCreading(uint8_t MUXPOS) {
// Assumes ADC hardware setup is already complete and ADC is NOT in free-running mode
// Set MUXPOS, wait for current conversion to complete, then wait for next converion to complete and return that
  HWREG8(ATMEGA_IO_ADC0_MUXPOS) = MUXPOS;
  delay(DELAY_AFTER_SETTING_MUXPOS_ms);                             // Mux settling time
  for (uint8_t discardADCvaluesToGiveSettlingTime = 0; discardADCvaluesToGiveSettlingTime < DISCARD_THIS_MANY_ADC_READINGS; discardADCvaluesToGiveSettlingTime ++) {
    HWREG8(ATMEGA_IO_ADC0_INTFLAGS)           = 0b00000001;         // Clear previous result ready flag
    HWREG8(ATMEGA_IO_ADC0_COMMAND)            = 0b00000001;         // Start conversion
    while ((HWREG8(ATMEGA_IO_ADC0_INTFLAGS)   & 0b00000001) == 0);  // Wait for next ADC result to be ready
  }
  HWREG8(ATMEGA_IO_ADC0_INTFLAGS)             = 0b00000001;         // Clear previous result ready flag
  HWREG8(ATMEGA_IO_ADC0_COMMAND)              = 0b00000001;         // Start conversion
  while ((HWREG8(ATMEGA_IO_ADC0_INTFLAGS)     & 0b00000001) == 0);  // Wait for next ADC result to be ready
  return HWREG16(ATMEGA_IO_ADC0_RES16);
}

For completeness, the function above is being called from a simple test loop:

void TEST_displayADCresults(uint8_t screenX, uint8_t screenY) {
    for (uint8_t channelCount = 0; channelCount < 6; channelCount ++) {
      positionalPRINTF(screenX, screenY++ , "Channel " + (String)channelCount +": 0x" + String(getADCreading(channelCount), HEX) + "   ");
    };
}

positionalPRINTF() is just a VT00 function that prints the given string at the specified VT100 terminal row/col.

HWREG8 and HWREG16 are macros used many times elsewhere (for both read and write) which seem to work OK:

// Macros for memory addressed (e.g. all registers) device read/write
#define  HWREG8(x) *(uint8_t*)(x)
#define HWREG16(x) *(uint16_t*)(x)

... and the ADC-related macros are:

#define ATMEGA_IO_ADC0_base                 ATMEGA_IO_base            + 0x0600
#define ATMEGA_IO_ADC0_CTRLA                ATMEGA_IO_ADC0_base       + 0x0000
#define ATMEGA_IO_ADC0_CTRLB                ATMEGA_IO_ADC0_base       + 0x0001
#define ATMEGA_IO_ADC0_CTRLC                ATMEGA_IO_ADC0_base       + 0x0002
#define ATMEGA_IO_ADC0_CTRLD                ATMEGA_IO_ADC0_base       + 0x0003
#define ATMEGA_IO_ADC0_CTRLE                ATMEGA_IO_ADC0_base       + 0x0004
#define ATMEGA_IO_ADC0_SAMPCTRL             ATMEGA_IO_ADC0_base       + 0x0005
#define ATMEGA_IO_ADC0_MUXPOS               ATMEGA_IO_ADC0_base       + 0x0006
#define ATMEGA_IO_ADC0_COMMAND              ATMEGA_IO_ADC0_base       + 0x0008
#define ATMEGA_IO_ADC0_EVCTRL               ATMEGA_IO_ADC0_base       + 0x0009
#define ATMEGA_IO_ADC0_INTCTRL              ATMEGA_IO_ADC0_base       + 0x000A
#define ATMEGA_IO_ADC0_INTFLAGS             ATMEGA_IO_ADC0_base       + 0x000B
#define ATMEGA_IO_ADC0_DBGCTRL              ATMEGA_IO_ADC0_base       + 0x000C
#define ATMEGA_IO_ADC0_TEMP                 ATMEGA_IO_ADC0_base       + 0x000D
#define ATMEGA_IO_ADC0_RES16                ATMEGA_IO_ADC0_base       + 0x0010  // 16 bit
#define ATMEGA_IO_ADC0_WINLT16              ATMEGA_IO_ADC0_base       + 0x0012  // 16 bit
#define ATMEGA_IO_ADC0_WINHT16              ATMEGA_IO_ADC0_base       + 0x0014  // 16 bit
#define ATMEGA_IO_ADC0_CALIB                ATMEGA_IO_ADC0_base       + 0x0016

That's the logic I was using. I've probably been looking at this for too long now and am overlooking something obvious - can you see the error in the logic I used?

Thanks again for the help!

Why did you delete your answer?

Could it be that you are confusing the Arduino numbering with the controller housing numbering?

For example, Arduino 'A2' is not controller 'AIN2'.
Arduino pin 'A2' is controller pin PD1 and PD1 is 'AIN1'.

Hi, I didn't - it was eaten by the forum spam filter - hopefully back again soon.

Thanks.

Hi, I don't think I'm doing that although there is the potential for confusion. On the schematics the Nano Every wire "A1" is just a track connecting JP2 pin 5 to U1 pin 22 (PD02 which I think the datasheet table says is AIN2). I'm still failing to see my error, annoyingly :slight_smile:

HWREG8 and HWREG16 are macros used many times elsewhere (for both read and write) which seem to work OK:

I would be questioning your Macros.

What do you see when you use the recommended syntax where X is the channel to read.

ADC0.MUXPOS = ADC_MUXPOS_AINX_gc;

I'm fairly confident the macros are OK. e.g. when used for assignment they set up the correct VREF voltage and return the expected values when used for reading. As mentioned, they also read the expected ADC results for the voltage I'm applying - all that's wong is the physical Nano Every pin to ADC0 result channel mapping. In other test functions I used them to read back CLKCTRL and the ADC register values themselves and all results are OK.

I'll try ADC_MUXPOS_AINX_gc and post back; good suggestion.

Just a little extra test info: with +1.2V applied to module pin 5 the code loop above is reporting:

                                Datasheet
                                =========
Channel 0: 0x0		(AIN0 = ATMEGA pin 20 = schematic wire "A3" = JP2/Nano Every pin  7)
Channel 1: 0x0		(AIN1 = ATMEGA pin 21 = schematic wire "A2" = JP2/Nano Every pin  6)
Channel 2: 0x0		(AIN2 = ATMEGA pin 22 = schematic wire "A1" = JP2/Nano Every pin  5)
Channel 3: 0x1dd	(AIN3 = ATMEGA pin 23 = schematic wire "A0" = JP2/Nano Every pin  4)
Channel 4: 0x0		(AIN4 = ATMEGA pin 24 = schematic wire "A6" = JP2/Nano Every pin 10)
Channel 5: 0x0		(AIN5 = ATMEGA pin 25 = schematic wire "A7" = JP2/Nano Every pin 11)

Hi,

I took another look at one of the lines of the assignments I wrote first. The MUX bits are shifted by one.

wrong MUXPOS Bits, every + 1

Arduino Nano Every pin A0 = µC pin 23 (AIN3) = PD3 >> MUXPOS 4
Arduino Nano Every pin A1 = µC pin 22 (AIN2) = PD2 >> MUXPOS 3
Arduino Nano Every pin A2 = µC pin 21 (AIN1) = PD1 >> MUXPOS 2
Arduino Nano Every pin A3 = µC pin 20 (AIN0) = PD0 >> MUXPOS 1
Arduino Nano Every pin A6 = µC pin 24 (AIN4) = PD4 >> MUXPOS 5
Arduino Nano Every pin A7 = µC pin 25 (AIN5) = PD5 >> MUXPOS 0

correct is (more clearly formatted)

Arduino Nano Every pin A0 = PD3 = AIN3 = MUXPOS 3
Arduino Nano Every pin A1 = PD2 = AIN2 = MUXPOS 2
Arduino Nano Every pin A2 = PD1 = AIN1 = MUXPOS 1
Arduino Nano Every pin A3 = PD0 = AIN0 = MUXPOS 0
Arduino Nano Every pin A6 = PD4 = AIN4 = MUXPOS 4
Arduino Nano Every pin A7 = PD5 = AIN5 = MUXPOS 5

AINx = MUXPOSx

Edit:
And leave your module numbering alone for once. It might be confusing. There are only Arduino pin numbers according to their pinout and the controller housing pin numbers. You should not jump back and forth between other numbers.

This is what I mean. These are not Arduino Every Board pin numbers. This is just the pin of one of the pin headers. They have absolutely no meaning.

 JP2/Nano Every pin  7)
 JP2/Nano Every pin  6)
 JP2/Nano Every pin  5)
 JP2/Nano Every pin  4)
 JP2/Nano Every pin 10)
 JP2/Nano Every pin 11)

Please forget that, it's just confusing.

Hi again,

The electronic hardware engineer in me just won't let this go (I'm not ignoring your advice although it might look like it :wink: ). Honestly on the schematics the JP2 and JP3 headers really are the module pin strips. This is exactly how a hardware engineer would represent them. You'll see all the signals are on the expected JP2 pins. The schematics also say that pin 2 has +3V3, pin 3 has VREF (measured as +2.5V, the inended ADC ref voltage), pin 15 has the USB VBUS etc and these all agree with the Nano's datasheet - JP2 pins 1-15 are module pins 1-15 for sure.

To add to that I've just buzzed between Nano Every pins 7/6/5/4/10/11 and pins 20-25 on the ATMEGA4809 chip itself and each connection agrees with the schematics. I've also tried reading back and printing each MUXPOS value after the ADC result value is printed and they're correct.

Just thought I'd give an update. Thanks again and all the best - Paul.

Don't worry, I can understand the love affair. Show us your complete code. Maybe there is a mistake in the implementation. When to switch to which channel.

Your macros are missing “volatile”. Who knows what the code looks like once the optimizer fiddles with it.

Hi, good idea, thanks. I’ll try that and see if there’s a difference.

Best regards - Paul.

I think this is better readable:

ADC0.MUXPOS = 1; // or 0b0000001 or 0x01
ADC0.COMMAND = 1;
while (ADC0.COMMAND) {};
myVar = ADC0.RES;

You’ll need to read the datasheet or iom4809.h anyway to get the names of the registers and the bit positions.

The ADC in the 4809 is better than in the 328, delays are not necessary when the impedance of the signal source < 10kΩ.

Here is some ADC example code from Tom Almy's book on the Nano Every
"Far Inside the Nano Every"
https://almy.us/arduinoeverybook.html

Indeed when I test input to A1 in position 5 on the header JP2 with other analog input pins grounded I see the input on ADC_MUXPOS_AIN2_gc which is has a value equal to 2.

I wonder if the order of your reading and index incrementing is not right.

/*
  adc_3 -- Continously read A0 through A5 and report values every
  second. Uses an interrupt routine to direct the multiplexer
  and start operation.
  Copyright (C) 2020  Thomas Almy

  This program is free software; you can redistribute it and/or
  modify it under the terms of the GNU General Public License
  as published by the Free Software Foundation; either version 2
  of the License, or (at your option) any later version.

  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.

  You should have received a copy of the GNU General Public License
  along with this program; if not, write to the Free Software
  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.

  Contact the author at tom@almy.us */


// Table of pins to read, expressed as values for ADC0.MUXPOS
#define NUMBER_INPUTS (6)
const uint8_t muxValues[NUMBER_INPUTS] = {ADC_MUXPOS_AIN3_gc,
                                          ADC_MUXPOS_AIN2_gc,
                                          ADC_MUXPOS_AIN1_gc,
                                          ADC_MUXPOS_AIN0_gc,
                                          ADC_MUXPOS_AIN12_gc,
                                          ADC_MUXPOS_AIN13_gc
                                         };

volatile uint16_t adcvalues[NUMBER_INPUTS]; // Room for reading all desired ADC values.
uint8_t muxIndex = 0; // Index of next value to read

void setup() {
  Serial.begin(9600);
  // Turn of digital input for all used analog pins
  PORTD.PIN3CTRL = PORT_ISC_INPUT_DISABLE_gc; // A0
  PORTD.PIN2CTRL = PORT_ISC_INPUT_DISABLE_gc; // A1
  PORTD.PIN1CTRL = PORT_ISC_INPUT_DISABLE_gc; // A2
  PORTD.PIN0CTRL = PORT_ISC_INPUT_DISABLE_gc; // A3
  PORTF.PIN4CTRL = PORT_ISC_INPUT_DISABLE_gc; // A4
  PORTF.PIN5CTRL = PORT_ISC_INPUT_DISABLE_gc; // A5
  PORTA.PIN4CTRL = PORT_ISC_INPUT_DISABLE_gc; // A4 tied to this pin
  PORTA.PIN5CTRL = PORT_ISC_INPUT_DISABLE_gc; // A5 tied to this pin
  ADC0.CTRLA = 1; // Enable ADC
  ADC0.CTRLC = ADC_SAMPCAP_bm + 1 * (1 << ADC_REFSEL_gp) + 3;
  // VDD reference, correct clock divisor (16)
  ADC0.MUXPOS = muxValues[muxIndex]; // This is input from pin A0
  ADC0.INTCTRL = 1; // Enable RESRDY interrupt
  ADC0.COMMAND = 1; // Start the conversion
  delay(700);
}


void loop() {
  int value;
  uint8_t index;
  for (index = 0; index < NUMBER_INPUTS; index++) {
    cli(); // Atomic access
    value = adcvalues[index];
    sei();
    Serial.print(value);
    Serial.print(" ");
  }
  Serial.println("");
  delay(1000);
}

ISR(ADC0_RESRDY_vect) { // A conversion has completed. Get result and start next conversion
  adcvalues[muxIndex] = ADC0.RES;
  muxIndex++;
  if (muxIndex >= NUMBER_INPUTS) {
    muxIndex = 0;
  }
  ADC0.MUXPOS = muxValues[muxIndex]; // This is input from next pin
  ADC0.COMMAND = 1; // Start the conversion
}

Thanks everyone for your help. Time pressures mean I have to park this for now. The main reason I switched to direct register manipulation was because the built in libraries’ ADC reference didn’t leave the external VREF pin driven when (built in library) analogRead() function calls weren’t executing … but I’ve found out how to fix that now so can use analogRead() again. Even with analogRead() I found there’s another gotcha; the ADC channel specifier (A0, A3 etc) needs to be type pinsize_t, uint8_t doesn’t work. Is that documented somewhere that I’m not aware of?

Thanks again. If I get further with the MUXPOS puzzle I’ll post updates.

Please explain more.

First, I don't see a channel specifier parameter in analogRead( ).

This is the code for analogRead() in the megaavr core where the channel is determined from a uint8_t pin number.

int analogRead(uint8_t pin)
{
	pin = digitalPinToAnalogInput(pin);
	if(pin > NUM_ANALOG_INPUTS) return NOT_A_PIN;
	
	/* Check if TWI is operating on double bonded pin (Master Enable is high 
		in both Master and Slave mode for bus error detection, so this can 
		indicate an active state for Wire) */
	if(isDoubleBondedActive(pin)) return 0;

	uint8_t low, high;

#if defined(analogPinToChannel)
	/* If analog pin number != adc0 channel */
#endif

#if defined(ADC0)
	/* Reference should be already set up */
	/* Select channel */
	ADC0.MUXPOS = (pin << ADC_MUXPOS_gp);

	/* Start conversion */
	ADC0.COMMAND = ADC_STCONV_bm;

	/* Wait for result ready */
	while(!(ADC0.INTFLAGS & ADC_RESRDY_bm));

	/* Save state */
	uint8_t status = SREG;
	cli();

	/* Read result */
	low = ADC0.RESL;
	high = ADC0.RESH;

	/* Restore state */
	SREG = status;

#else	/* No ADC, return 0 */
	low = 0;
	high = 0;
#endif

	/* Combine two bytes */
	return (high << 8) | low;
}

Hi Cattledog,

Thanks for your reply. My problem turned out to be that I was using

Serial.print(analogRead( (uint8_t)0xA0));

... which I thought was reasonable ... but the "0x" breaks it (in this case the returned ADC "result" is always 255(decimal)). [BTW, I'm casting here just for simplicity and to shorten this demo code].

The following works OK (but still seems like a syntax crime to me):

Serial.print(analogRead(   (uint8_t)A0));

Surely it's OK (better) to explicitly specify the hex radix when assigning this sort of value to a uint8_t type? If isn't a hex number then what is it in this case?

The first fix I found was to use pin_size_t which also works:

Serial.print(analogRead((pin_size_t)A0));

Complete mini-demo:

#include <HardwareSerial.h>
#define USE_VT100               // Comment this out to use serial monitor

void setup() {
  // Running on a Nano Every with TeraTerm serial window in VT100 mode
  Serial.begin(115200);
  analogReference(INTERNAL2V5);
  
  #ifdef USE_VT100
    Serial.print("\033[2J");    // CLS
    Serial.print("\033[H");     // HOME
    Serial.print("\033[92m");   // green text
    Serial.print("\033[?25l");  // cursor off
  #endif
  Serial.println("Reading from Nano Every pin 4/A0");
  Serial.println("================================");
  Serial.println();
  Serial.println("Left = uint8_t 0xA0, middle = uint8_t A0, right = pinsize_t A0");
  Serial.println("--------------------------------------------------------------");
}

void loop() {
  Serial.print(analogRead( (uint8_t)0xA0));    Serial.print(" (always 255)     "); // left   >> gives wrong result
  Serial.print(analogRead(   (uint8_t)A0));    Serial.print(" (correct)        "); // middle >> gives correct result
  Serial.print(analogRead((pin_size_t)A0));    Serial.print(" (correct)        "); // right  >> gives correct result
  #ifdef USE_VT100
    Serial.print("\r");
  #else
    Serial.println();
    Serial.println("Left = uint8_t 0xA0, middle = uint8_t A0, right = pinsize_t A0");
    Serial.println("--------------------------------------------------------------");
  #endif
}

// What is A0 when assigned to a uint8_t?  Why is not 0xA0 not correct?
// Does anyone know how to make serial monitor execute a CR (without LF)?

As a side question, how do you get a genuine CR on the IDE Serial Monitor (as opposed to CRLF)?

Thanks again - Paul.

MCUdude gives a more extensive view of the ADC-inputs (and other uses of the Nano Evvery pins).