Description
Hardware:
Board: Adafruit ESP32 Feather
Core Installation version: 1.0.6
IDE name: Arduino IDE
Flash Frequency: 80Mhz
PSRAM enabled: no
Upload Speed: 921600
Computer OS: Fedora 33 5.11.17-200.fc33.x86_64
Description:
AnalogReadResolution was implemented, but testing shows that the full range was not. The code comments say the range is 1 to 16.
arduino-esp32/cores/esp32/esp32-hal-adc.h
Lines 41 to 48 in eb46978
However, only bit counts in the range of 9 to 12 give the expected results. Values less than 9 act as if 9 was set, and values greater than 12 act as if 12 was set. What is supposed to happen, is that values between 1 and 32 should work. Values outside of the 9 to 12 directly supported by the hardware should cause analogRead()
results to be "shifted" left or right to match the range for the specified number of bits. So a full range value would return 1 for a resolution of 1 bit, and a little less than 2 ** 32 for 32 bits. The "little less" because the shifting zero fills. With the 12 bits available from the hardware adc, with a real value of 0xfff, being turned into 0xfff00000. Implementing that is also going to need analogRead() to return a uint32_t
, instead a uint16_t
. Without that, the resolution could still be implement for up to 16 bits.
It is not sufficent to "force" the resolution bits into the 9 to 12 range. The actual specified resolution needs to be use by analogRead()
(all return paths) to shift the hardware result into the correct range.
arduino-esp32/cores/esp32/esp32-hal-adc.c
Lines 136 to 144 in 7856de7
arduino-esp32/cores/esp32/esp32-hal-adc.c
Lines 67 to 77 in 7856de7
The logic needed is similar to how the debug sketch generates the expected values.
- when bits < 9
return value >> (9 - bits);
- when bits > 12
return value << (bits - 12);
- otherwise
return value';
#define MIN_HARDWARE_BITS 9
#define MAX_HARDWARE_BITS 12
uinit16_t __scaleToResolution(uinit16_t raw, uint8_t bits)
{
uint16_t value = raw;
if(bits < MIN_HARDWARE_BITS) {
return value >> (MIN_HARDWARE_BITS - bits);
}
if(bits > MAX_HARDWARE_BITS) {
return value << (bits - MAX_HARDWARE_BITS);
}
return value;
}
where the bits value needs to be carried over from when analogReadResolution()
was called, or defaulted (I assume) to 12. Not the adjusted value calculated in __analogSetWidth()
Sketch: esp32_analog_resolution
/* Analog read «adc» testing for ESP32
*
* Reference:
* https://www.arduino.cc/reference/en/language/functions/zero-due-mkr-family/analogreadresolution/
* "If you set the analogReadResolution() value to a value higher than your
* board’s capabilities, the Arduino will only report back at its highest
* resolution, padding the extra bits with zeros."
* "If you set the analogReadResolution() value to a value lower than your
* board’s capabilities, the extra least significant bits read from the ADC
* will be discarded."
*/
const unsigned long SERIAL_BAUD = 115200;
const unsigned long READING_INTERVAL = 10;
const unsigned long REPEAT_INTERVAL = 1000;
const size_t INPUT_PIN = A2; // gpio 34 for analogRead()
void setup() {
Serial.begin(SERIAL_BAUD);
delay(200);
Serial.println("starting test sketch");
}
void loop() {
uint16_t rawADC[16];
uint16_t max12 = 0xfff;
// With input set to VDD to get range maximum value
for (size_t i = 0; i <16; i++) {
analogReadResolution(i + 1);
rawADC[i] = analogRead(INPUT_PIN);
delay(READING_INTERVAL);
}
Serial.print("bits: ");
for (size_t i = 1; i <= 16; i++) {
Serial.printf("%7d", i);
}
Serial.print("\nreading: ");
for (size_t i = 0; i < 16; i++) {
Serial.printf(" %#6x", rawADC[i]);
}
Serial.print("\nexpected:");
for (size_t i = 1; i <= 12; i++) {
Serial.printf(" %#6x", max12 >> (12 - i));
}
for (size_t i = 13; i <= 16; i++) {
Serial.printf(" %#6x", max12 << (i - 12));
}
Serial.println("\n"); // add blank line
delay(REPEAT_INTERVAL);
}
Debug Messages:
output from test sketch
bits: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
reading: 0x1ff 0x1ff 0x1ff 0x1ff 0x1ff 0x1ff 0x1ff 0x1ff 0x1ff 0x3ff 0x7ff 0xfff 0xfff 0xfff 0xfff 0xfff
expected: 0x1 0x3 0x7 0xf 0x1f 0x3f 0x7f 0xff 0x1ff 0x3ff 0x7ff 0xfff 0x1ffe 0x3ffc 0x7ff8 0xfff0