adc_oneshot.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297
  1. /*
  2. * SPDX-FileCopyrightText: 2019-2023 Espressif Systems (Shanghai) CO LTD
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. */
  6. #include <esp_types.h>
  7. #include <sys/lock.h>
  8. #include "sdkconfig.h"
  9. #if CONFIG_ADC_ENABLE_DEBUG_LOG
  10. // The local log level must be defined before including esp_log.h
  11. // Set the maximum log level for this source file
  12. #define LOG_LOCAL_LEVEL ESP_LOG_DEBUG
  13. #endif
  14. #include "stdatomic.h"
  15. #include "esp_log.h"
  16. #include "esp_check.h"
  17. #include "esp_heap_caps.h"
  18. #include "freertos/FreeRTOS.h"
  19. #include "driver/gpio.h"
  20. #include "driver/rtc_io.h"
  21. #include "esp_adc/adc_oneshot.h"
  22. #include "esp_clk_tree.h"
  23. #include "esp_private/adc_private.h"
  24. #include "esp_private/adc_share_hw_ctrl.h"
  25. #include "esp_private/sar_periph_ctrl.h"
  26. #include "esp_private/esp_sleep_internal.h"
  27. #include "hal/adc_types.h"
  28. #include "hal/adc_oneshot_hal.h"
  29. #include "hal/adc_ll.h"
  30. #include "soc/adc_periph.h"
  31. #if CONFIG_ADC_ONESHOT_CTRL_FUNC_IN_IRAM
  32. #define ADC_MEM_ALLOC_CAPS (MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT)
  33. #else
  34. #define ADC_MEM_ALLOC_CAPS MALLOC_CAP_DEFAULT
  35. #endif
  36. extern portMUX_TYPE rtc_spinlock;
  37. static const char *TAG = "adc_oneshot";
  38. typedef struct adc_oneshot_unit_ctx_t {
  39. adc_oneshot_hal_ctx_t hal;
  40. uint32_t unit_id;
  41. adc_ulp_mode_t ulp_mode;
  42. } adc_oneshot_unit_ctx_t;
  43. typedef struct adc_oneshot_ctx_t {
  44. _lock_t mutex;
  45. adc_oneshot_unit_ctx_t *units[SOC_ADC_PERIPH_NUM];
  46. int apb_periph_ref_cnts; //For the chips that ADC oneshot mode using APB_SARADC periph
  47. } adc_oneshot_ctx_t;
  48. static adc_oneshot_ctx_t s_ctx; //ADC oneshot mode context
  49. static atomic_bool s_adc_unit_claimed[SOC_ADC_PERIPH_NUM] = {ATOMIC_VAR_INIT(false),
  50. #if (SOC_ADC_PERIPH_NUM >= 2)
  51. ATOMIC_VAR_INIT(false)
  52. #endif
  53. };
  54. static bool s_adc_unit_claim(adc_unit_t unit);
  55. static bool s_adc_unit_free(adc_unit_t unit);
  56. static esp_err_t s_adc_io_init(adc_unit_t unit, adc_channel_t channel);
  57. esp_err_t adc_oneshot_io_to_channel(int io_num, adc_unit_t * const unit_id, adc_channel_t * const channel)
  58. {
  59. return adc_io_to_channel(io_num, unit_id, channel);
  60. }
  61. esp_err_t adc_oneshot_channel_to_io(adc_unit_t unit_id, adc_channel_t channel, int * const io_num)
  62. {
  63. return adc_channel_to_io(unit_id, channel, io_num);
  64. }
  65. esp_err_t adc_oneshot_new_unit(const adc_oneshot_unit_init_cfg_t *init_config, adc_oneshot_unit_handle_t *ret_unit)
  66. {
  67. #if CONFIG_ADC_ENABLE_DEBUG_LOG
  68. esp_log_level_set(TAG, ESP_LOG_DEBUG);
  69. #endif
  70. esp_err_t ret = ESP_OK;
  71. adc_oneshot_unit_ctx_t *unit = NULL;
  72. ESP_GOTO_ON_FALSE(init_config && ret_unit, ESP_ERR_INVALID_ARG, err, TAG, "invalid argument: null pointer");
  73. ESP_GOTO_ON_FALSE(init_config->unit_id < SOC_ADC_PERIPH_NUM, ESP_ERR_INVALID_ARG, err, TAG, "invalid unit");
  74. #if CONFIG_IDF_TARGET_ESP32C3 && !CONFIG_ADC_ONESHOT_FORCE_USE_ADC2_ON_C3
  75. /**
  76. * We only check this on ESP32C3, because other adc units are no longer supported on later chips
  77. * If CONFIG_ADC_ONESHOT_FORCE_USE_ADC2_ON_C3 is enabled, we jump this check
  78. */
  79. ESP_GOTO_ON_FALSE(SOC_ADC_DIG_SUPPORTED_UNIT(init_config->unit_id), ESP_ERR_INVALID_ARG, err, TAG, "adc unit not supported");
  80. #endif
  81. unit = heap_caps_calloc(1, sizeof(adc_oneshot_unit_ctx_t), ADC_MEM_ALLOC_CAPS);
  82. ESP_GOTO_ON_FALSE(unit, ESP_ERR_NO_MEM, err, TAG, "no mem for unit");
  83. bool success_claim = s_adc_unit_claim(init_config->unit_id);
  84. ESP_GOTO_ON_FALSE(success_claim, ESP_ERR_NOT_FOUND, err, TAG, "adc%d is already in use", init_config->unit_id + 1);
  85. _lock_acquire(&s_ctx.mutex);
  86. s_ctx.units[init_config->unit_id] = unit;
  87. _lock_release(&s_ctx.mutex);
  88. unit->unit_id = init_config->unit_id;
  89. unit->ulp_mode = init_config->ulp_mode;
  90. adc_oneshot_clk_src_t clk_src = ADC_DIGI_CLK_SRC_DEFAULT;
  91. if (init_config->clk_src) {
  92. clk_src = init_config->clk_src;
  93. }
  94. uint32_t clk_src_freq_hz = 0;
  95. ESP_GOTO_ON_ERROR(esp_clk_tree_src_get_freq_hz(clk_src, ESP_CLK_TREE_SRC_FREQ_PRECISION_CACHED, &clk_src_freq_hz), err, TAG, "clock source not supported");
  96. adc_oneshot_hal_cfg_t config = {
  97. .unit = init_config->unit_id,
  98. .work_mode = (init_config->ulp_mode == ADC_ULP_MODE_FSM) ? ADC_HAL_ULP_FSM_MODE : ADC_HAL_SINGLE_READ_MODE,
  99. .clk_src = clk_src,
  100. .clk_src_freq_hz = clk_src_freq_hz,
  101. };
  102. adc_oneshot_hal_init(&(unit->hal), &config);
  103. #if SOC_ADC_DIG_CTRL_SUPPORTED && !SOC_ADC_RTC_CTRL_SUPPORTED
  104. //To enable the APB_SARADC periph if needed
  105. _lock_acquire(&s_ctx.mutex);
  106. s_ctx.apb_periph_ref_cnts++;
  107. if (s_ctx.apb_periph_ref_cnts == 1) {
  108. adc_apb_periph_claim();
  109. }
  110. _lock_release(&s_ctx.mutex);
  111. #endif
  112. if (init_config->ulp_mode == ADC_ULP_MODE_DISABLE) {
  113. sar_periph_ctrl_adc_oneshot_power_acquire();
  114. } else {
  115. esp_sleep_enable_adc_tsens_monitor(true);
  116. }
  117. ESP_LOGD(TAG, "new adc unit%"PRId32" is created", unit->unit_id);
  118. *ret_unit = unit;
  119. return ESP_OK;
  120. err:
  121. if (unit) {
  122. free(unit);
  123. }
  124. return ret;
  125. }
  126. esp_err_t adc_oneshot_config_channel(adc_oneshot_unit_handle_t handle, adc_channel_t channel, const adc_oneshot_chan_cfg_t *config)
  127. {
  128. ESP_RETURN_ON_FALSE(handle && config, ESP_ERR_INVALID_ARG, TAG, "invalid argument: null pointer");
  129. ESP_RETURN_ON_FALSE(config->atten < SOC_ADC_ATTEN_NUM, ESP_ERR_INVALID_ARG, TAG, "invalid attenuation");
  130. ESP_RETURN_ON_FALSE(((config->bitwidth >= SOC_ADC_RTC_MIN_BITWIDTH && config->bitwidth <= SOC_ADC_RTC_MAX_BITWIDTH) || config->bitwidth == ADC_BITWIDTH_DEFAULT), ESP_ERR_INVALID_ARG, TAG, "invalid bitwidth");
  131. ESP_RETURN_ON_FALSE(channel < SOC_ADC_CHANNEL_NUM(handle->unit_id), ESP_ERR_INVALID_ARG, TAG, "invalid channel");
  132. s_adc_io_init(handle->unit_id, channel);
  133. adc_oneshot_hal_ctx_t *hal = &(handle->hal);
  134. adc_oneshot_hal_chan_cfg_t cfg = {
  135. .atten = config->atten,
  136. .bitwidth = (config->bitwidth == ADC_BITWIDTH_DEFAULT) ? SOC_ADC_RTC_MAX_BITWIDTH : config->bitwidth,
  137. };
  138. portENTER_CRITICAL(&rtc_spinlock);
  139. adc_oneshot_hal_channel_config(hal, &cfg, channel);
  140. if (handle->ulp_mode) {
  141. adc_oneshot_hal_setup(hal, channel);
  142. }
  143. portEXIT_CRITICAL(&rtc_spinlock);
  144. return ESP_OK;
  145. }
  146. esp_err_t adc_oneshot_read(adc_oneshot_unit_handle_t handle, adc_channel_t chan, int *out_raw)
  147. {
  148. ESP_RETURN_ON_FALSE(handle && out_raw, ESP_ERR_INVALID_ARG, TAG, "invalid argument: null pointer");
  149. ESP_RETURN_ON_FALSE(chan < SOC_ADC_CHANNEL_NUM(handle->unit_id), ESP_ERR_INVALID_ARG, TAG, "invalid channel");
  150. if (adc_lock_try_acquire(handle->unit_id) != ESP_OK) {
  151. return ESP_ERR_TIMEOUT;
  152. }
  153. portENTER_CRITICAL(&rtc_spinlock);
  154. adc_oneshot_hal_setup(&(handle->hal), chan);
  155. #if SOC_ADC_CALIBRATION_V1_SUPPORTED
  156. adc_atten_t atten = adc_ll_get_atten(handle->unit_id, chan);
  157. adc_hal_calibration_init(handle->unit_id);
  158. adc_set_hw_calibration_code(handle->unit_id, atten);
  159. #endif // SOC_ADC_CALIBRATION_V1_SUPPORTED
  160. bool valid = false;
  161. valid = adc_oneshot_hal_convert(&(handle->hal), out_raw);
  162. portEXIT_CRITICAL(&rtc_spinlock);
  163. adc_lock_release(handle->unit_id);
  164. return valid ? ESP_OK : ESP_ERR_TIMEOUT;
  165. }
  166. esp_err_t adc_oneshot_read_isr(adc_oneshot_unit_handle_t handle, adc_channel_t chan, int *out_raw)
  167. {
  168. ESP_RETURN_ON_FALSE_ISR(handle && out_raw, ESP_ERR_INVALID_ARG, TAG, "invalid argument: null pointer");
  169. ESP_RETURN_ON_FALSE_ISR(out_raw, ESP_ERR_INVALID_ARG, TAG, "invalid argument: null pointer");
  170. ESP_RETURN_ON_FALSE_ISR(chan < SOC_ADC_CHANNEL_NUM(handle->unit_id), ESP_ERR_INVALID_ARG, TAG, "invalid channel");
  171. portENTER_CRITICAL_SAFE(&rtc_spinlock);
  172. adc_oneshot_hal_setup(&(handle->hal), chan);
  173. #if SOC_ADC_CALIBRATION_V1_SUPPORTED
  174. adc_atten_t atten = adc_ll_get_atten(handle->unit_id, chan);
  175. adc_hal_calibration_init(handle->unit_id);
  176. adc_set_hw_calibration_code(handle->unit_id, atten);
  177. #endif
  178. adc_oneshot_hal_convert(&(handle->hal), out_raw);
  179. portEXIT_CRITICAL_SAFE(&rtc_spinlock);
  180. return ESP_OK;
  181. }
  182. esp_err_t adc_oneshot_del_unit(adc_oneshot_unit_handle_t handle)
  183. {
  184. ESP_RETURN_ON_FALSE(handle, ESP_ERR_INVALID_ARG, TAG, "invalid argument: null pointer");
  185. adc_ulp_mode_t ulp_mode = handle->ulp_mode;
  186. bool success_free = s_adc_unit_free(handle->unit_id);
  187. ESP_RETURN_ON_FALSE(success_free, ESP_ERR_NOT_FOUND, TAG, "adc%"PRId32" isn't in use", handle->unit_id + 1);
  188. _lock_acquire(&s_ctx.mutex);
  189. s_ctx.units[handle->unit_id] = NULL;
  190. _lock_release(&s_ctx.mutex);
  191. ESP_LOGD(TAG, "adc unit%"PRId32" is deleted", handle->unit_id);
  192. free(handle);
  193. if (ulp_mode == ADC_ULP_MODE_DISABLE) {
  194. sar_periph_ctrl_adc_oneshot_power_release();
  195. } else {
  196. esp_sleep_enable_adc_tsens_monitor(false);
  197. }
  198. #if SOC_ADC_DIG_CTRL_SUPPORTED && !SOC_ADC_RTC_CTRL_SUPPORTED
  199. //To free the APB_SARADC periph if needed
  200. _lock_acquire(&s_ctx.mutex);
  201. s_ctx.apb_periph_ref_cnts--;
  202. assert(s_ctx.apb_periph_ref_cnts >= 0);
  203. if (s_ctx.apb_periph_ref_cnts == 0) {
  204. adc_apb_periph_free();
  205. }
  206. _lock_release(&s_ctx.mutex);
  207. #endif
  208. return ESP_OK;
  209. }
  210. esp_err_t adc_oneshot_get_calibrated_result(adc_oneshot_unit_handle_t handle, adc_cali_handle_t cali_handle, adc_channel_t chan, int *cali_result)
  211. {
  212. int raw = 0;
  213. ESP_RETURN_ON_ERROR(adc_oneshot_read(handle, chan, &raw), TAG, "adc oneshot read fail");
  214. ESP_LOGD(TAG, "raw: 0d%d", raw);
  215. ESP_RETURN_ON_ERROR(adc_cali_raw_to_voltage(cali_handle, raw, cali_result), TAG, "adc calibration fail");
  216. return ESP_OK;
  217. }
  218. #define ADC_GET_IO_NUM(unit, channel) (adc_channel_io_map[unit][channel])
  219. static esp_err_t s_adc_io_init(adc_unit_t unit, adc_channel_t channel)
  220. {
  221. ESP_RETURN_ON_FALSE(channel < SOC_ADC_CHANNEL_NUM(unit), ESP_ERR_INVALID_ARG, TAG, "invalid channel");
  222. #if SOC_ADC_DIG_CTRL_SUPPORTED && !SOC_ADC_RTC_CTRL_SUPPORTED
  223. uint32_t io_num = ADC_GET_IO_NUM(unit, channel);
  224. gpio_config_t cfg = {
  225. .pin_bit_mask = BIT64(io_num),
  226. .mode = GPIO_MODE_DISABLE,
  227. .pull_up_en = GPIO_PULLUP_DISABLE,
  228. .pull_down_en = GPIO_PULLDOWN_DISABLE,
  229. .intr_type = GPIO_INTR_DISABLE,
  230. };
  231. ESP_RETURN_ON_ERROR(gpio_config(&cfg), TAG, "IO config fail");
  232. #else
  233. gpio_num_t io_num = ADC_GET_IO_NUM(unit, channel);
  234. ESP_RETURN_ON_ERROR(rtc_gpio_init(io_num), TAG, "IO config fail");
  235. ESP_RETURN_ON_ERROR(rtc_gpio_set_direction(io_num, RTC_GPIO_MODE_DISABLED), TAG, "IO config fail");
  236. ESP_RETURN_ON_ERROR(rtc_gpio_pulldown_dis(io_num), TAG, "IO config fail");
  237. ESP_RETURN_ON_ERROR(rtc_gpio_pullup_dis(io_num), TAG, "IO config fail");
  238. #endif
  239. return ESP_OK;
  240. }
  241. static bool s_adc_unit_claim(adc_unit_t unit)
  242. {
  243. bool false_var = false;
  244. return atomic_compare_exchange_strong(&s_adc_unit_claimed[unit], &false_var, true);
  245. }
  246. static bool s_adc_unit_free(adc_unit_t unit)
  247. {
  248. bool true_var = true;
  249. return atomic_compare_exchange_strong(&s_adc_unit_claimed[unit], &true_var, false);
  250. }