Reading ADC register on Leonardo/Micro/ATmega32u4

I am trying to do some fast data acquisition with the code shown below, but am having some problems.

The code will run on a Genuine UNO (value of sensorValue drops to zero when ADC0 pin is grounded, otherwise is around 400 when the pin is floating.

The code does NOT work correctly when loaded on a Leonardo or Micro (value of sensorValue is always around 400 with ADC0 pin is grounded or floating.

The hardware seems to be fine as both boards behave as expected when using the analogRead() function.

I have been through the datasheet for the ATmega32U4, but couldn't see anything obvious wrong (but the ADMUX register description left me confused)

The 'Arduino AVR Boards' has been updated to version 1.6.23 using the Boards Manager

Excuse the code, I have stripped it down to the bare minimum to try and isolate the problem.

const byte adcPin = 0;  
int sensorValue;
  
void setup() 
{
  Serial.begin (115200);

  ADCSRA =  bit (ADEN);                                // turn ADC on
  ADCSRA |= bit (ADPS0) |  bit (ADPS1) | bit (ADPS2);  // Prescaler of 128
  ADMUX =   bit (REFS0) | (adcPin & 0x07);             //Vcc reference, select channel  
  bitSet (ADCSRA, ADSC);  // start first conversion
}  

void loop() 
{
  delay(1000);              // delay between reads for ADC to finish
  
  //sensorValue = analogRead(A0);        //use this for checking that hardware works
  
  sensorValue = ADC;      // read result (after delay of 1 second assume that conversion is complete
  bitSet (ADCSRA, ADSC);  // start next conversion
  
  Serial.println (sensorValue);
}

Any comments appreciated, I am out of ideas.

charlierw:
The code does NOT work correctly when loaded on a Leonardo or Micro (value of sensorValue is always around 400 with ADC0 pin is grounded or floating.

Which Leonardo Analog Input Pin do you believe is connected to ADC0?

I had assumed it was the one marked "A0", but after doing some research it seems that there can be a mapping between the Arduino channels and the AVR channels. Selecting a wrong ADC channel would explain what I am seeing.

https://www.arduino.cc/en/Hacking/PinMapping32u4

This (and the associated links) make for some interesting reading as well

darrob:
Arduino - PinMapping32u4

This (and the associated links) make for some interesting reading as well

That clears up a few things. I also found this link which helped.

I used the function analogPinToChannel() to map the Arduino analog input to the correct hardware channel and it seems to be working fine. I assume that is the correct way to handle this?

New code below:

const byte arduinoAnalogPin = 0;  //arduino analog input we want to use
int sensorValue;
  
void setup() 
{
  Serial.begin (115200);

  ADCSRA =  bit (ADEN);                                // turn ADC on
  ADCSRA |= bit (ADPS0) |  bit (ADPS1) | bit (ADPS2);  // Prescaler of 128
  ADMUX =   bit (REFS0) | (analogPinToChannel(arduinoAnalogPin) & 0x07);     //Vcc reference, hardware analog channel. Use analogPinToChannel() to map Arduino analog input to correct hardware channel
  bitSet (ADCSRA, ADSC);  // start first conversion
}  

void loop() 
{
  delay(1000);              // delay between reads for ADC to finish
  
  //sensorValue = analogRead(A0);        //use this for checking that hardware works
  
  sensorValue = ADC;      // read result (after delay of 1 second assume that conversion is complete
  bitSet (ADCSRA, ADSC);  // start next conversion
  
  Serial.println (sensorValue);
}

Many thanks.