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!