Skip to content

Add ADC support on ESP32|S2|S3|C3|C6|H2 #16228

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged

Conversation

fdcavalcanti
Copy link
Contributor

Summary

  • documentation: update docs on ADC support for Espressif devices
  • boards/risc-v: ADC support on Espressif devices
  • boards/xtensa: ADC support on Espressif devices
  • arch/risc-v: ADC support for ESP32-C3|C6|H2
  • arch/xtensa: ADC support on ESP32|S2|S3

This PR adds support for ADC oneshot on Espressif devices.

It supports reading of all available ADC channels of the device. The user may use the adc defconfig which enables one ADC unit, usually with 3 or 4 channels by default.

The documentation has been updated for each SoC, describing the all GPIOs associated to a particular channel, some limitations and usage example.

On the usability side, all channels, ADC units and input voltage attenuation can be modified via menuconfig. Also, ADC calibration is enabled and applied by default (if the device supports it).

Special mention for ESP32S3: this device already had an ADC implementation. I have removed it but added some Kconfig entries to keep backwards compatibility, so the user should be able to compile but not use the same as before, since device registration has changed to keep up with ADC API.

Impact

Impact on user: Yes. Impacts users that use ADC on ESP32S3. Application should still compile, however the ADC character driver now represents an entire ADC unit instead of registering one character driver for each channel.

Impact on build: No.

Impact on hardware: Yes. This PR adds support for ADC on: ESP32|S2|S3|C3|C6|H2.

Impact on documentation: Yes. Updates documentation for ESP32|S2|S3|C3|C6|H2 regarding ADC peripheral support.

Impact on security: No.

Impact on compatibility: Only for ESP32S3. See "impact on user".

Testing

This procedure was done manually for all boards of this PR. All ADC channels were tested by setting 0 and 3.3 V and reading the ADC application output. A complementary test had a potentiometer to evaluate the voltage range.

A test application was developed to apply the internal pull-up and pull-down resistors of the GPIOs to automatically test the ADC (which will be running on Espressif's internal CI).

Building

The ADC defconfig enables the ADC unit 1 and 3 or 4 channels by default. For testing, we enable the ADC unit 2 and all possible channels.

  • ./tools/configure.sh esp32-devkitc:adc
  • CONFIG_DEBUG_FEATURES
  • CONFIG_DEBUG_ASSERTIONS
  • CONFIG_DEBUG_ANALOG
  • CONFIG_ESPRESSIF_ADC_2
  • CONFIG_ESPRESSIF_ADC_1_CH0 through CONFIG_ESPRESSIF_ADC_1_CH9
  • CONFIG_ESPRESSIF_ADC_2_CH0 through CONFIG_ESPRESSIF_ADC_2_CH9
  • CONFIG_EXAMPLES_ADC_GROUPSIZE=10
  • CONFIG_ADC_FIFOSIZE=11

Running

Connect the GPIO pins to a test voltage and run the ADC example for each unit:

  • adc -n 1 -p /dev/adc0
  • adc -n 1 -p /dev/adc1

Results

I'll summarize the results. OK means the voltage reading was good even though it might be off by some mV, which is expected on some SoCs.
I have some tables with the test results (SOC, channel, voltage max, min, etc) but I won't put it here since it is too long. I can upload somewhere if necessary.

  • ESP32 (ESP32_DevKitc_V4)

    • ADC1 channels 0-7: OK
    • ADC2 channels 0-9: OK with warning: channels 1, 2 and 3 are used as strapping pins and can present undefined behavior
  • ESP32S2 (ESP32-S2-Saola-1_V1.2)

    • ADC1 channels 0-9: OK
    • ADC2 channels 0-9: OK
  • ESP32S3 (ESP32-S3-DevKitC-1 v1.0)

    • ADC1 channels 0-9: OK
    • ADC2 channels 0-9: OK
  • ESP32C3 (ESP32-C3-DevKitC-02 V1.1)

    • ADC1 channels 0-4: OK
    • ADC2 not implemented since it only has 1 channel
  • ESP32C6 (ESP32-C6-DevKitC-1 V1.1)

    • ADC1 channels 0-6: OK
  • ESP32H2 (ESP32-H2-DevKitM-1 V1.2)

    • ADC1 channels 0-4: OK

Here's the log output for the ESP32S3, with verbosity high. All ADC channels are enabled on both ADC units (/dev/adc0 and /dev/adc1). We can see the ADC bringup, calibration and results. It is similar to all devices.

*** Booting NuttX ***
I (59) boot: chip revision: v0.1
I (59) boot.esp32s3: Boot SPI Speed : 40MHz
I (59) boot.esp32s3: SPI Mode       : DIO
I (63) boot.esp32s3: SPI Flash Size : 8MB
I (68) boot: Enabling RNG early entropy source...
dram: lma 0x00000020 vma 0x3fc8c800 len 0x2328   (9000)
iram: lma 0x00002350 vma 0x40374000 len 0x644c   (25676)
padd: lma 0x000087a8 vma 0x00000000 len 0x7850   (30800)
imap: lma 0x00010000 vma 0x42010000 len 0x17664  (95844)
padd: lma 0x0002766c vma 0x00000000 len 0x898c   (35212)
dmap: lma 0x00030000 vma 0x3c040000 len 0x8d20   (36128)
total segments stored 6
ABesp_adc_initialize: initialize SAR ADC 1
esp_adc_oneshot_new_unit: unit 0 freq 80000000
esp_adc_oneshot_config_channel: init adc unit 0, ch 0 (gpio 1), atten 3, bitwidth 0
esp_adc_oneshot_config_channel: init adc unit 0, ch 1 (gpio 2), atten 3, bitwidth 0
esp_adc_oneshot_config_channel: init adc unit 0, ch 2 (gpio 3), atten 3, bitwidth 0
esp_adc_oneshot_config_channel: init adc unit 0, ch 3 (gpio 4), atten 3, bitwidth 0
esp_adc_oneshot_config_channel: init adc unit 0, ch 4 (gpio 5), atten 3, bitwidth 0
esp_adc_oneshot_config_channel: init adc unit 0, ch 5 (gpio 6), atten 3, bitwidth 0
esp_adc_oneshot_config_channel: init adc unit 0, ch 6 (gpio 7), atten 3, bitwidth 0
esp_adc_oneshot_config_channel: init adc unit 0, ch 7 (gpio 8), atten 3, bitwidth 0
esp_adc_oneshot_config_channel: init adc unit 0, ch 8 (gpio 9), atten 3, bitwidth 0
esp_adc_oneshot_config_channel: init adc unit 0, ch 9 (gpio 10), atten 3, bitwidth 0
esp_adc_calibrate: curve fitting unit 0, chan 0, atten 3, bitwidth 0
esp_adc_calibrate: curve fitting unit 0, chan 1, atten 3, bitwidth 0
esp_adc_calibrate: curve fitting unit 0, chan 2, atten 3, bitwidth 0
esp_adc_calibrate: curve fitting unit 0, chan 3, atten 3, bitwidth 0
esp_adc_calibrate: curve fitting unit 0, chan 4, atten 3, bitwidth 0
esp_adc_calibrate: curve fitting unit 0, chan 5, atten 3, bitwidth 0
esp_adc_calibrate: curve fitting unit 0, chan 6, atten 3, bitwidth 0
esp_adc_calibrate: curve fitting unit 0, chan 7, atten 3, bitwidth 0
esp_adc_calibrate: curve fitting unit 0, chan 8, atten 3, bitwidth 0
esp_adc_calibrate: curve fitting unit 0, chan 9, atten 3, bitwidth 0
esp_adc_initialize: initialize SAR ADC 2
esp_adc_oneshot_new_unit: unit 1 freq 80000000
esp_adc_oneshot_config_channel: init adc unit 1, ch 0 (gpio 11), atten 3, bitwidth 0
esp_adc_oneshot_config_channel: init adc unit 1, ch 1 (gpio 12), atten 3, bitwidth 0
esp_adc_oneshot_config_channel: init adc unit 1, ch 2 (gpio 13), atten 3, bitwidth 0
esp_adc_oneshot_config_channel: init adc unit 1, ch 3 (gpio 14), atten 3, bitwidth 0
esp_adc_oneshot_config_channel: init adc unit 1, ch 4 (gpio 15), atten 3, bitwidth 0
esp_adc_oneshot_config_channel: init adc unit 1, ch 5 (gpio 16), atten 3, bitwidth 0
esp_adc_oneshot_config_channel: init adc unit 1, ch 6 (gpio 17), atten 3, bitwidth 0
esp_adc_oneshot_config_channel: init adc unit 1, ch 7 (gpio 18), atten 3, bitwidth 0
esp_adc_oneshot_config_channel: init adc unit 1, ch 8 (gpio 19), atten 3, bitwidth 0
esp_adc_oneshot_config_channel: init adc unit 1, ch 9 (gpio 20), atten 3, bitwidth 0
esp_adc_calibrate: curve fitting unit 1, chan 0, atten 3, bitwidth 0
esp_adc_calibrate: curve fitting unit 1, chan 1, atten 3, bitwidth 0
esp_adc_calibrate: curve fitting unit 1, chan 2, atten 3, bitwidth 0
esp_adc_calibrate: curve fitting unit 1, chan 3, atten 3, bitwidth 0
esp_adc_calibrate: curve fitting unit 1, chan 4, atten 3, bitwidth 0
esp_adc_calibrate: curve fitting unit 1, chan 5, atten 3, bitwidth 0
esp_adc_calibrate: curve fitting unit 1, chan 6, atten 3, bitwidth 0
esp_adc_calibrate: curve fitting unit 1, chan 7, atten 3, bitwidth 0
esp_adc_calibrate: curve fitting unit 1, chan 8, atten 3, bitwidth 0
esp_adc_calibrate: curve fitting unit 1, chan 9, atten 3, bitwidth 0

NuttShell (NSH) NuttX-10.4.0
nsh> 

Now reading the ADC unit 1. We expect values to be floating since nothing is connected to the pins.

nsh> adc -n 1 -p /dev/adc0
adc_main: g_adcstate.count: 1
esp_adc_oneshot_read: read adc 0 ch 0 (cali: 1): value 1042 (raw 1292)
adc_main: Hardware initialized. Opening the ADC device: /dev/adc0
esp_adc_oneshot_read: read adc 0 ch 1 (cali: 1): value 1039 (raw 1289)
esp_adc_oneshot_read: read adc 0 ch 2 (cali: 1): value 1039 (raw 1289)
esp_adc_oneshot_read: read adc 0 ch 3 (cali: 1): value 1039 (raw 1289)
esp_adc_oneshot_read: read adc 0 ch 4 (cali: 1): value 1039 (raw 1289)
esp_adc_oneshot_read: read adc 0 ch 5 (cali: 1): value 1039 (raw 1289)
esp_adc_oneshot_read: read adc 0 ch 6 (cali: 1): value 1039 (raw 1289)
esp_adc_oneshot_read: read adc 0 ch 7 (cali: 1): value 1039 (raw 1289)
esp_adc_oneshot_read: read adc 0 ch 8 (cali: 1): value 1039 (raw 1289)
esp_adc_oneshot_read: read adc 0 ch 9 (cali: 1): value 1039 (raw 1289)
adc_read: buflen: 50
adc_read: Returning: 50
Sample:
1: channel: 0 value: 1042
2: channel: 1 value: 1039
3: channel: 2 value: 1039
4: channel: 3 value: 1039
5: channel: 4 value: 1039
6: channel: 5 value: 1039
7: channel: 6 value: 1039
8: channel: 7 value: 1039
9: channel: 8 value: 1039
10: channel: 9 value: 1039

And finally ADC unit 2:

nsh> adc -n 1 -p /dev/adc1
adc_main: g_adcstate.count: 1
esp_adc_oneshot_read: read adc 1 ch 0 (cali: 1): value 183 (raw 213)
adc_main: Hardware initialized. Opening the ADC device: /dev/adc1
esp_adc_oneshot_read: read adc 1 ch 1 (cali: 1): value 441 (raw 524)
esp_adc_oneshot_read: read adc 1 ch 2 (cali: 1): value 610 (raw 734)
esp_adc_oneshot_read: read adc 1 ch 3 (cali: 1): value 160 (raw 186)
esp_adc_oneshot_read: read adc 1 ch 4 (cali: 1): value 505 (raw 604)
esp_adc_oneshot_read: read adc 1 ch 5 (cali: 1): value 502 (raw 599)
esp_adc_oneshot_read: read adc 1 ch 6 (cali: 1): value 485 (raw 579)
esp_adc_oneshot_read: read adc 1 ch 7 (cali: 1): value 517 (raw 619)
esp_adc_oneshot_read: read adc 1 ch 8 (cali: 1): value 695 (raw 840)
esp_adc_oneshot_read: read adc 1 ch 9 (cali: 1): value 685 (raw 828)
adc_read: buflen: 50
adc_read: Returning: 50
Sample:
1: channel: 0 value: 183
2: channel: 1 value: 441
3: channel: 2 value: 610
4: channel: 3 value: 160
5: channel: 4 value: 505
6: channel: 5 value: 502
7: channel: 6 value: 485
8: channel: 7 value: 517
9: channel: 8 value: 695
10: channel: 9 value: 685

@github-actions github-actions bot added Area: Documentation Improvements or additions to documentation Arch: risc-v Issues related to the RISC-V (32-bit or 64-bit) architecture Arch: xtensa Issues related to the Xtensa architecture Board: risc-v Board: xtensa Size: XL The size of the change in this PR is very large. Consider breaking down the PR into smaller pieces. labels Apr 16, 2025
@nuttxpr
Copy link

nuttxpr commented Apr 16, 2025

[Experimental Bot, please feedback here]

This PR appears to meet the NuttX requirements, although some minor improvements could be made.

Strengths:

  • Clear Summary: The summary clearly outlines the changes and their purpose.
  • Detailed Impact Assessment: The impact section addresses all the required points and provides specific details about the changes for ESP32S3.
  • Thorough Testing: The testing section describes the test setup, procedure, and results in detail, including example output. The mention of a separate automated test application is also a positive.

Areas for Improvement:

  • Conciseness: The testing section could be more concise. While detail is good, the extensive log output could be trimmed or moved to a separate file referenced in the PR. Summarizing the results across all boards is helpful, but the full tables aren't necessary in the PR description itself. Offer to provide the detailed data upon request.
  • Testing Logs Before Change: While you mention a testing procedure, you didn't include "before change" logs. These logs are essential to demonstrate the actual improvement or fix provided by the PR. Include a brief snippet of the output before the ADC changes were implemented, even if it simply shows a lack of functionality.
  • Related Issues: You mention updating the documentation, but it would be helpful to link any related NuttX or NuttX Apps issues that prompted this change, or that this change resolves. Even if there wasn't a specific issue, mentioning it ("No related issues") is good practice.

Verdict:

Overall, the PR seems well-structured and provides enough information to understand the changes. Addressing the minor points above, particularly including "before change" logs, would further strengthen the PR.

@fdcavalcanti fdcavalcanti changed the title ADC support on Espressif devices Add ADC support on ESP32|S2|S3|C3|C6|H2 Apr 16, 2025
Comment on lines +276 to +281
static void esp_adc_reset(struct adc_dev_s *dev)
{
struct esp_adc_dev_s *priv = (struct esp_adc_dev_s *)dev->ad_priv;

DEBUGASSERT(priv);
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why? 🙃

Copy link
Contributor Author

@fdcavalcanti fdcavalcanti Apr 16, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why what? Nothing inside? Future use could benefit, right now I didn't see a clear use case.
What do you think?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, I suggest include some comments just to make it clean

Add common ADC source for ESP32|S2|S3.
Remove legacy ADC from ESP32S3.

Signed-off-by: Filipe Cavalcanti <[email protected]>
Add common source for ADC that supports ESP32-C3|C6|H2.

Signed-off-by: Filipe Cavalcanti <[email protected]>
Adds adc defconfig and board support for: esp32-devkitc, esp32s2-saola-1 and esp32s3-devkit.

Signed-off-by: Filipe Cavalcanti <[email protected]>
Adds adc defconfig and board support for: esp32c3-generic, esp32c6-devkitc and esp32h2-devkit.

Signed-off-by: Filipe Cavalcanti <[email protected]>
Add documentation for ADC on RISC-V and Xtensa Espressif devices.

Signed-off-by: Filipe Cavalcanti <[email protected]>
@fdcavalcanti fdcavalcanti force-pushed the feature/adc-support-common branch from e0fd5b5 to f0e2dbd Compare April 16, 2025 14:25
@xiaoxiang781216 xiaoxiang781216 merged commit 2ff8199 into apache:master Apr 17, 2025
40 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Arch: risc-v Issues related to the RISC-V (32-bit or 64-bit) architecture Arch: xtensa Issues related to the Xtensa architecture Area: Documentation Improvements or additions to documentation Board: risc-v Board: xtensa Size: XL The size of the change in this PR is very large. Consider breaking down the PR into smaller pieces.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants