adc_oneshot.rst 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239
  1. 模数转换器 (ADC) 单次转换模式驱动
  2. ===================================
  3. :link_to_translation:`en:[English]`
  4. {IDF_TARGET_ADC_NUM:default="两", esp32c2="一", esp32c6="一", esp32h2="一"}
  5. 简介
  6. ----
  7. 模数转换器集成于芯片,支持测量特定模拟 IO 管脚的模拟信号。
  8. {IDF_TARGET_NAME} 有 {IDF_TARGET_ADC_NUM} 个 ADC 单元,可以在以下场景使用:
  9. - 生成 ADC 单次转换结果
  10. .. only:: SOC_ADC_DMA_SUPPORTED
  11. - 生成连续 ADC 转换结果
  12. 本指南介绍了 ADC 单次转换模式。
  13. 功能概述
  14. --------
  15. 下文将分节概述安装和运行 ADC 的基本步骤:
  16. - :ref:`adc-oneshot-resource-allocation` - 介绍获取 ADC 句柄所需设置的参数,以及如何在 ADC 完成工作后回收资源。
  17. - :ref:`adc-oneshot-unit-configuration` - 介绍配置 ADC 单元所需设置的参数,用于获取 ADC 转换的原始结果。
  18. - :ref:`adc-oneshot-read-conversion-result` - 介绍如何获取 ADC 转换的原始结果。
  19. - :ref:`hardware_limitations_adc_oneshot` - 介绍与 ADC 相关的硬件限制。
  20. - :ref:`adc-oneshot-power-management` - 介绍电源管理的相关内容。
  21. - :ref:`adc-oneshot-iram-safe` - 介绍在禁用 cache 时,如何读取 ADC 转换的原始结果。
  22. - :ref:`adc-oneshot-thread-safety` - 介绍由驱动程序认证为线程安全的 API。
  23. - :ref:`adc-oneshot-kconfig-options` - 介绍支持的 Kconfig 选项,不同选项对驱动程序的操作会产生不同影响。
  24. .. _adc-oneshot-resource-allocation:
  25. 资源分配
  26. ^^^^^^^^
  27. ADC 单次转换模式驱动基于 {IDF_TARGET_NAME} SAR ADC 模块实现,不同的 ESP 芯片可能拥有不同数量的独立 ADC。对于单次转换模式驱动而言,ADC 实例以 :cpp:type:`adc_oneshot_unit_handle_t` 表示。
  28. 请设置所需的初始配置结构体 :cpp:type:`adc_oneshot_unit_init_cfg_t` 安装 ADC 实例,具体如下:
  29. - :cpp:member:`adc_oneshot_unit_init_cfg_t::unit_id` 选择 ADC。请参阅 `技术规格书 <{IDF_TARGET_TRM_CN_URL}>`__,了解对应 ADC 的专用模拟 IO 管脚。
  30. - :cpp:member:`adc_oneshot_unit_init_cfg_t::clk_src` 选择 ADC 的时钟源。设置为 0 时,驱动程序将使用默认时钟源,详情请参阅 :cpp:type:`adc_oneshot_clk_src_t`。
  31. - :cpp:member:`adc_oneshot_unit_init_cfg_t::ulp_mode` 设置是否支持 ADC 在 ULP 模式下工作。
  32. .. todo::
  33. Add ULP ADC-related docs here.
  34. 完成 ADC 初始配置后,使用已设置的初始配置结构体 :cpp:type:`adc_oneshot_unit_init_cfg_t` 调用 :cpp:func:`adc_oneshot_new_unit`。如果分配成功,该函数将返回 ADC 单元实例句柄。
  35. 该函数可能因参数无效、内存不足等原因返回错误代码。比如,当要分配的 ADC 实例已经注册时,该函数会返回 :c:macro:`ESP_ERR_NOT_FOUND` 错误。可用 ADC 数量可通过 :c:macro:`SOC_ADC_PERIPH_NUM` 查看。
  36. 如果不再需要先前创建的 ADC 单元实例,请调用 :cpp:func:`adc_oneshot_del_unit` 回收该实例,相关的硬件和软件资源也会回收。
  37. 在普通单次转换模式下创建 ADC 单元实例句柄
  38. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  39. .. code:: c
  40. adc_oneshot_unit_handle_t adc1_handle;
  41. adc_oneshot_unit_init_cfg_t init_config1 = {
  42. .unit_id = ADC_UNIT_1,
  43. .ulp_mode = ADC_ULP_MODE_DISABLE,
  44. };
  45. ESP_ERROR_CHECK(adc_oneshot_new_unit(&init_config1, &adc1_handle));
  46. 回收 ADC 单元实例
  47. ~~~~~~~~~~~~~~~~~~~~
  48. .. code:: c
  49. ESP_ERROR_CHECK(adc_oneshot_del_unit(adc1_handle));
  50. .. _adc-oneshot-unit-configuration:
  51. 配置 ADC 单元实例
  52. ^^^^^^^^^^^^^^^^^^^^^^
  53. 创建 ADC 单元实例后,请设置 :cpp:type:`adc_oneshot_chan_cfg_t` 配置 ADC IO 以测量模拟信号,具体如下:
  54. - :cpp:member:`adc_oneshot_chan_cfg_t::atten`,ADC 衰减。请参阅 `技术参考手册 <{IDF_TARGET_TRM_CN_URL}>`__ > ``片上传感器与模拟信号处理``。
  55. - :cpp:member:`adc_oneshot_chan_cfg_t::bitwidth`,原始转换结果的位宽。
  56. .. note::
  57. ADC IO 及其对应的 ADC 通道编号,请参阅 `技术规格书 <{IDF_TARGET_TRM_CN_URL}>`__。
  58. 此外,可以使用 :cpp:func:`adc_continuous_io_to_channel` 和 :cpp:func:`adc_continuous_channel_to_io` 了解 ADC 通道和 ADC IO。
  59. 为使以上设置生效,请使用上述配置结构体调用 :cpp:func:`adc_oneshot_config_channel`,并指定要配置的 ADC 通道。函数 :cpp:func:`adc_oneshot_config_channel` 支持多次调用,以配置不同的 ADC 通道。驱动程序将在内部保存每个通道的配置。
  60. 配置两个 ADC 通道
  61. ~~~~~~~~~~~~~~~~~
  62. .. code:: c
  63. adc_oneshot_chan_cfg_t config = {
  64. .bitwidth = ADC_BITWIDTH_DEFAULT,
  65. .atten = ADC_ATTEN_DB_12,
  66. };
  67. ESP_ERROR_CHECK(adc_oneshot_config_channel(adc1_handle, EXAMPLE_ADC1_CHAN0, &config));
  68. ESP_ERROR_CHECK(adc_oneshot_config_channel(adc1_handle, EXAMPLE_ADC1_CHAN1, &config));
  69. .. _adc-oneshot-read-conversion-result:
  70. 读取转换结果
  71. ^^^^^^^^^^^^^^^^^^^^^^
  72. 完成上述配置后,ADC 即可测量来自配置好的 ADC 通道的模拟信号。调用 :cpp:func:`adc_oneshot_read` 可以获取 ADC 通道的原始转换结果。
  73. - :cpp:func:`adc_oneshot_read` 可安全使用。ADC 由其他驱动程序/外设共享,请参阅 :ref:`hardware_limitations_adc_oneshot`。函数 :cpp:func:`adc_oneshot_read` 使用互斥锁,避免与其他函数同时使用硬件,因此该函数不应在 ISR 上下文中使用。当 ADC 由其他驱动程序/外设占用时,该函数可能出错,并返回 :c:macro:`ESP_ERR_TIMEOUT` 错误。此时,ADC 原始结果无效。
  74. 该函数可能因参数无效而调用失败。
  75. 通过该函数获取的 ADC 转换结果为原始数据。可以使用以下公式,根据 ADC 原始结果计算电压:
  76. .. parsed-literal::
  77. Vout = Dout * Vmax / Dmax (1)
  78. 其中:
  79. .. list-table::
  80. :header-rows: 1
  81. :widths: 20 80
  82. :align: center
  83. * - Vout
  84. - 数字输出结果,代表电压。
  85. * - Dout
  86. - ADC 原始数字读取结果。
  87. * - Vmax
  88. - 可测量的最大模拟输入电压,与 ADC 衰减相关,请参考 `技术参考手册 <{IDF_TARGET_TRM_CN_URL}>`__ > ``片上传感器与模拟信号处理``。
  89. * - Dmax
  90. - 输出 ADC 原始数字读取结果的最大值,即 2^位宽,位宽即之前配置的 :cpp:member:`adc_digi_pattern_config_t::bit_width`。
  91. 若需进一步校准,将 ADC 原始结果转换为以 mV 为单位的电压数据,请参考校准文档 :doc:`adc_calibration`。
  92. 读取原始结果
  93. ~~~~~~~~~~~~~~~
  94. .. code:: c
  95. ESP_ERROR_CHECK(adc_oneshot_read(adc1_handle, EXAMPLE_ADC1_CHAN0, &adc_raw[0][0]));
  96. ESP_LOGI(TAG, "ADC%d Channel[%d] Raw Data: %d", ADC_UNIT_1 + 1, EXAMPLE_ADC1_CHAN0, adc_raw[0][0]);
  97. ESP_ERROR_CHECK(adc_oneshot_read(adc1_handle, EXAMPLE_ADC1_CHAN1, &adc_raw[0][1]));
  98. ESP_LOGI(TAG, "ADC%d Channel[%d] Raw Data: %d", ADC_UNIT_1 + 1, EXAMPLE_ADC1_CHAN1, adc_raw[0][1]);
  99. .. _hardware_limitations_adc_oneshot:
  100. 硬件限制
  101. ^^^^^^^^^^^^^^^^^^^^
  102. - 随机数生成器 (RNG) 以 ADC 为输入源。使用 ADC 单次转换模式驱动从 RNG 生成随机数时,随机性会减弱。
  103. .. only:: SOC_ADC_DMA_SUPPORTED
  104. - 一个 ADC 单元每次只能在一种操作模式下运行,可以是连续模式或单次模式。:cpp:func:`adc_oneshot_start` 提供了保护措施。
  105. .. only:: esp32 or esp32s2 or esp32s3
  106. - Wi-Fi 也使用 ADC2,:cpp:func:`adc_oneshot_read` 提供了 Wi-Fi 驱动与 ADC 单次转换模式驱动间的保护。
  107. .. only:: esp32c3
  108. - 由于硬件限制,现已不再支持使用 ADC2 DMA 功能获取 ADC 转换结果。使用 ADC2 单次转换的结果可能不稳定,具体可参考 `ESP32-C3 系列芯片勘误表 <https://www.espressif.com/sites/default/files/documentation/esp32-c3_errata_cn.pdf>`__。出于兼容性考虑,可以启用 :ref:`CONFIG_ADC_ONESHOT_FORCE_USE_ADC2_ON_C3`,强制使用 ADC2。
  109. .. only:: esp32
  110. - ESP32-DevKitC:GPIO0 已用于自动烧录功能,不能用于 ADC 单次转换模式。
  111. - ESP-WROVER-KIT:GPIO0、GPIO2、GPIO4 和 GPIO15 已有其他用途,不能用于 ADC 单次转换模式。
  112. .. _adc-oneshot-power-management:
  113. .. only:: not esp32
  114. .. _adc-oneshot-power-management:
  115. 电源管理
  116. ^^^^^^^^
  117. 启用电源管理,即启用 :ref:`CONFIG_PM_ENABLE` 时,系统在空闲状态下可能会调整系统时钟频率。然而,ADC 单次转换模式驱动以轮询例程运行,:cpp:func:`adc_oneshot_read` 会不断检查 CPU 是否完成读取,直到函数返回。在此期间,ADC 单次转换模式驱动程序所在的任务不会受阻塞。因此,在读取时时钟频率保持稳定。
  118. .. _adc-oneshot-iram-safe:
  119. IRAM 安全
  120. ^^^^^^^^^
  121. flash 写入/擦除、OTA 等原因都可能导致 cache 禁用,此时,默认不应运行任何 ADC 单次转换模式驱动 API。如果在禁用 cache 时执行了 ADC 单次转换模式驱动 API,可能会出现类似 ``Illegal Instruction`` 或 ``Load/Store Prohibited`` 的错误。
  122. .. _adc-oneshot-thread-safety:
  123. 线程安全
  124. ^^^^^^^^
  125. - :cpp:func:`adc_oneshot_new_unit`
  126. - :cpp:func:`adc_oneshot_config_channel`
  127. - :cpp:func:`adc_oneshot_read`
  128. 上述函数均为线程安全,使用时,可以直接从不同的 RTOS 任务中调用以上函数,无需额外锁保护。
  129. - :cpp:func:`adc_oneshot_del_unit` 非线程安全。此外,与上文中线程安全的函数一起调用该函数时,可能导致线程安全函数的调用出错。
  130. .. _adc-oneshot-kconfig-options:
  131. Kconfig 选项
  132. ^^^^^^^^^^^^
  133. - :ref:`CONFIG_ADC_ONESHOT_CTRL_FUNC_IN_IRAM` 决定了放置 ADC 快速读取函数的位置,即 IRAM 或 flash 中,详情请参阅 :ref:`adc-oneshot-iram-safe`。
  134. 应用示例
  135. --------------------
  136. * ADC 单次转换模式示例::example:`peripherals/adc/oneshot_read`。
  137. API 参考
  138. -------------
  139. .. include-build-file:: inc/adc_types.inc
  140. .. include-build-file:: inc/adc_oneshot.inc