mirror of
https://github.com/espressif/esp-idf.git
synced 2025-12-10 09:55:47 +00:00
system: reset dma when soft reset
This commit is contained in:
committed by
bot
parent
d35173c147
commit
d7d1dee208
@@ -31,6 +31,7 @@
|
||||
#include "hal/adc_types.h"
|
||||
#include "hal/adc_hal.h"
|
||||
#include "hal/dma_types.h"
|
||||
#include "esp32c3/esp_efuse_rtc_calib.h"
|
||||
|
||||
#define ADC_CHECK_RET(fun_ret) ({ \
|
||||
if (fun_ret != ESP_OK) { \
|
||||
@@ -89,13 +90,17 @@ typedef struct adc_digi_context_t {
|
||||
RingbufHandle_t ringbuf_hdl; //RX ringbuffer handler
|
||||
bool ringbuf_overflow_flag; //1: ringbuffer overflow
|
||||
bool driver_start_flag; //1: driver is started; 0: driver is stoped
|
||||
bool use_adc1; //1: ADC unit1 will be used; 0: ADC unit1 won't be used.
|
||||
bool use_adc2; //1: ADC unit2 will be used; 0: ADC unit2 won't be used. This determines whether to acquire sar_adc2_mutex lock or not.
|
||||
adc_atten_t adc1_atten; //Attenuation for ADC1. On this chip each ADC can only support one attenuation.
|
||||
adc_atten_t adc2_atten; //Attenuation for ADC2. On this chip each ADC can only support one attenuation.
|
||||
adc_digi_config_t digi_controller_config; //Digital Controller Configuration
|
||||
} adc_digi_context_t;
|
||||
|
||||
static const char* ADC_DMA_TAG = "ADC_DMA:";
|
||||
static adc_digi_context_t *s_adc_digi_ctx = NULL;
|
||||
|
||||
static uint32_t adc_get_calibration_offset(adc_ll_num_t adc_n, adc_channel_t chan, adc_atten_t atten);
|
||||
|
||||
/*---------------------------------------------------------------
|
||||
ADC Continuous Read Mode (via DMA)
|
||||
@@ -265,6 +270,16 @@ esp_err_t adc_digi_start(void)
|
||||
|
||||
adc_arbiter_t config = ADC_ARBITER_CONFIG_DEFAULT();
|
||||
adc_hal_init();
|
||||
|
||||
if (s_adc_digi_ctx->use_adc1) {
|
||||
uint32_t cal_val = adc_get_calibration_offset(ADC_NUM_1, ADC_CHANNEL_MAX, s_adc_digi_ctx->adc1_atten);
|
||||
adc_hal_set_calibration_param(ADC_NUM_1, cal_val);
|
||||
}
|
||||
if (s_adc_digi_ctx->use_adc2) {
|
||||
uint32_t cal_val = adc_get_calibration_offset(ADC_NUM_2, ADC_CHANNEL_MAX, s_adc_digi_ctx->adc2_atten);
|
||||
adc_hal_set_calibration_param(ADC_NUM_2, cal_val);
|
||||
}
|
||||
|
||||
adc_hal_arbiter_config(&config);
|
||||
adc_hal_digi_init(&s_adc_digi_ctx->hal_dma, &s_adc_digi_ctx->hal_dma_config);
|
||||
adc_hal_digi_controller_config(&s_adc_digi_ctx->digi_controller_config);
|
||||
@@ -365,6 +380,7 @@ esp_err_t adc_digi_deinitialize(void)
|
||||
s_adc_digi_ctx->ringbuf_hdl = NULL;
|
||||
}
|
||||
|
||||
free(s_adc_digi_ctx->rx_dma_buf);
|
||||
free(s_adc_digi_ctx->hal_dma_config.rx_desc);
|
||||
free(s_adc_digi_ctx->digi_controller_config.adc_pattern);
|
||||
free(s_adc_digi_ctx);
|
||||
@@ -420,11 +436,16 @@ int adc1_get_raw(adc1_channel_t channel)
|
||||
ADC_DIGI_LOCK_ACQUIRE();
|
||||
|
||||
periph_module_enable(PERIPH_SARADC_MODULE);
|
||||
|
||||
adc_atten_t atten = s_atten1_single[channel];
|
||||
uint32_t cal_val = adc_get_calibration_offset(ADC_NUM_1, channel, atten);
|
||||
adc_hal_set_calibration_param(ADC_NUM_1, cal_val);
|
||||
|
||||
adc_hal_digi_controller_config(&dig_cfg);
|
||||
|
||||
adc_hal_intr_clear(ADC_EVENT_ADC1_DONE);
|
||||
adc_hal_onetime_channel(ADC_NUM_1, channel);
|
||||
adc_hal_set_onetime_atten(s_atten1_single[channel]);
|
||||
adc_hal_set_onetime_atten(atten);
|
||||
|
||||
//Trigger single read.
|
||||
adc_hal_adc1_onetime_sample_enable(true);
|
||||
@@ -475,13 +496,17 @@ esp_err_t adc2_get_raw(adc2_channel_t channel, adc_bits_width_t width_bit, int *
|
||||
|
||||
SAC_ADC2_LOCK_ACQUIRE();
|
||||
ADC_DIGI_LOCK_ACQUIRE();
|
||||
|
||||
periph_module_enable(PERIPH_SARADC_MODULE);
|
||||
|
||||
adc_atten_t atten = s_atten2_single[channel];
|
||||
uint32_t cal_val = adc_get_calibration_offset(ADC_NUM_2, channel, atten);
|
||||
adc_hal_set_calibration_param(ADC_NUM_2, cal_val);
|
||||
|
||||
adc_hal_digi_controller_config(&dig_cfg);
|
||||
|
||||
adc_hal_intr_clear(ADC_EVENT_ADC2_DONE);
|
||||
adc_hal_onetime_channel(ADC_NUM_2, channel);
|
||||
adc_hal_set_onetime_atten(s_atten2_single[channel]);
|
||||
adc_hal_set_onetime_atten(atten);
|
||||
|
||||
//Trigger single read.
|
||||
adc_hal_adc2_onetime_sample_enable(true);
|
||||
@@ -523,10 +548,26 @@ esp_err_t adc_digi_controller_config(const adc_digi_config_t *config)
|
||||
memcpy(s_adc_digi_ctx->digi_controller_config.adc_pattern, config->adc_pattern, config->adc_pattern_len * sizeof(adc_digi_pattern_table_t));
|
||||
|
||||
//See whether ADC2 will be used or not. If yes, the ``sar_adc2_mutex`` should be acquired in the continuous read driver
|
||||
s_adc_digi_ctx->adc1_atten = ADC_ATTEN_MAX;
|
||||
s_adc_digi_ctx->adc2_atten = ADC_ATTEN_MAX;
|
||||
s_adc_digi_ctx->use_adc1 = 0;
|
||||
s_adc_digi_ctx->use_adc2 = 0;
|
||||
for (int i = 0; i < config->adc_pattern_len; i++) {
|
||||
if (config->adc_pattern->unit == ADC_NUM_2) {
|
||||
const adc_digi_pattern_table_t* pat = &config->adc_pattern[i];
|
||||
if (pat->unit == ADC_NUM_1) {
|
||||
s_adc_digi_ctx->use_adc1 = 1;
|
||||
if (s_adc_digi_ctx->adc1_atten == ADC_ATTEN_MAX) {
|
||||
s_adc_digi_ctx->adc1_atten = pat->atten;
|
||||
} else if (s_adc_digi_ctx->adc1_atten != pat->atten) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
} else if (pat->unit == ADC_NUM_2) {
|
||||
s_adc_digi_ctx->use_adc2 = 1;
|
||||
if (s_adc_digi_ctx->adc2_atten == ADC_ATTEN_MAX) {
|
||||
s_adc_digi_ctx->adc2_atten = pat->atten;
|
||||
} else if (s_adc_digi_ctx->adc2_atten != pat->atten) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -802,3 +843,40 @@ esp_err_t adc_digi_isr_deregister(void)
|
||||
/*---------------------------------------------------------------
|
||||
RTC controller setting
|
||||
---------------------------------------------------------------*/
|
||||
|
||||
static uint16_t s_adc_cali_param[ADC_ATTEN_MAX] = {};
|
||||
|
||||
//NOTE: according to calibration version, different types of lock may be taken during the process:
|
||||
// 1. Semaphore when reading efuse
|
||||
// 2. Lock (Spinlock, or Mutex) if we actually do ADC calibration in the future
|
||||
//This function shoudn't be called inside critical section or ISR
|
||||
static uint32_t adc_get_calibration_offset(adc_ll_num_t adc_n, adc_channel_t channel, adc_atten_t atten)
|
||||
{
|
||||
const bool no_cal = false;
|
||||
if (s_adc_cali_param[atten]) {
|
||||
return (uint32_t)s_adc_cali_param[atten];
|
||||
}
|
||||
|
||||
if (no_cal) {
|
||||
return 0; //indicating failure
|
||||
}
|
||||
|
||||
// check if we can fetch the values from eFuse.
|
||||
int version = esp_efuse_rtc_calib_get_ver();
|
||||
assert(version == 1);
|
||||
uint32_t init_code = esp_efuse_rtc_calib_get_init_code(version, atten);
|
||||
|
||||
ESP_LOGD(ADC_TAG, "Calib(V%d) ADC%d atten=%d: %04X", version, adc_n, atten, init_code);
|
||||
s_adc_cali_param[atten] = init_code;
|
||||
return init_code;
|
||||
}
|
||||
|
||||
// Internal function to calibrate PWDET for WiFi
|
||||
esp_err_t adc_cal_offset(adc_ll_num_t adc_n, adc_channel_t channel, adc_atten_t atten)
|
||||
{
|
||||
uint32_t cal_val = adc_get_calibration_offset(adc_n, channel, atten);
|
||||
ADC_ENTER_CRITICAL();
|
||||
adc_hal_set_calibration_param(adc_n, cal_val);
|
||||
ADC_EXIT_CRITICAL();
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
39
components/driver/esp32c3/adc2_init_cal.c
Normal file
39
components/driver/esp32c3/adc2_init_cal.c
Normal file
@@ -0,0 +1,39 @@
|
||||
// Copyright 2016-2018 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
/* This file is used to get `adc2_init_code_calibration` executed before the APP when the ADC2 is used by Wi-Fi or other drivers.
|
||||
The linker will link constructor (adc2_init_code_calibration) only when any sections inside the same file (adc2_cal_include) is used.
|
||||
Don't put any other code into this file. */
|
||||
|
||||
#include "adc2_wifi_private.h"
|
||||
#include "hal/adc_hal.h"
|
||||
#include "adc_cali.h"
|
||||
|
||||
/**
|
||||
* @brief Set initial code to ADC2 after calibration. ADC2 RTC and ADC2 PWDET controller share the initial code.
|
||||
* This API be called in before `app_main()`.
|
||||
*/
|
||||
static __attribute__((constructor)) void adc2_init_code_calibration(void)
|
||||
{
|
||||
const adc_ll_num_t adc_n = ADC_NUM_2;
|
||||
const adc_atten_t atten = ADC_ATTEN_DB_11;
|
||||
const adc_channel_t channel = 0;
|
||||
adc_cal_offset(adc_n, channel, atten);
|
||||
}
|
||||
|
||||
/** Don't call `adc2_cal_include` in user code. */
|
||||
void adc2_cal_include(void)
|
||||
{
|
||||
/* When this empty function is called, the `adc2_init_code_calibration` constructor will be linked and executed before the app.*/
|
||||
}
|
||||
157
components/driver/esp32c3/rtc_tempsensor.c
Normal file
157
components/driver/esp32c3/rtc_tempsensor.c
Normal file
@@ -0,0 +1,157 @@
|
||||
// Copyright 2016-2018 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include <esp_types.h>
|
||||
#include <stdlib.h>
|
||||
#include <ctype.h>
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/semphr.h"
|
||||
#include "esp_log.h"
|
||||
#include "soc/rtc_cntl_reg.h"
|
||||
#include "driver/temp_sensor.h"
|
||||
#include "esp32c3/rom/ets_sys.h"
|
||||
|
||||
static const char *TAG = "tsens";
|
||||
|
||||
#define TSENS_CHECK(res, ret_val) ({ \
|
||||
if (!(res)) { \
|
||||
ESP_LOGE(TAG, "%s:%d (%s)", __FILE__, __LINE__, __FUNCTION__); \
|
||||
return (ret_val); \
|
||||
} \
|
||||
})
|
||||
#define TSENS_XPD_WAIT_DEFAULT 0xFF /* Set wait cycle time(8MHz) from power up to reset enable. */
|
||||
#define TSENS_ADC_FACTOR (0.4386)
|
||||
#define TSENS_DAC_FACTOR (27.88)
|
||||
#define TSENS_SYS_OFFSET (20.52)
|
||||
|
||||
#include "regi2c_ctrl.h"
|
||||
|
||||
#define ANA_CONFIG2_REG 0x6000E048
|
||||
#define ANA_CONFIG2_M (BIT(18))
|
||||
|
||||
#define I2C_ADC 0X69
|
||||
#define I2C_ADC_HOSTID 1
|
||||
|
||||
typedef struct {
|
||||
int index;
|
||||
int offset;
|
||||
int set_val;
|
||||
int range_min;
|
||||
int range_max;
|
||||
int error_max;
|
||||
} tsens_dac_offset_t;
|
||||
|
||||
static const tsens_dac_offset_t dac_offset[TSENS_DAC_MAX] = {
|
||||
/* DAC Offset reg_val min max error */
|
||||
{TSENS_DAC_L0, -2, 5, 50, 125, 3},
|
||||
{TSENS_DAC_L1, -1, 7, 20, 100, 2},
|
||||
{TSENS_DAC_L2, 0, 15, -10, 80, 1},
|
||||
{TSENS_DAC_L3, 1, 11, -30, 50, 2},
|
||||
{TSENS_DAC_L4, 2, 10, -40, 20, 3},
|
||||
};
|
||||
|
||||
static SemaphoreHandle_t rtc_tsens_mux = NULL;
|
||||
|
||||
esp_err_t temp_sensor_set_config(temp_sensor_config_t tsens)
|
||||
{
|
||||
//CLEAR_PERI_REG_MASK(RTC_CNTL_ANA_CONF_REG, RTC_CNTL_SAR_I2C_FORCE_PD_M);
|
||||
//SET_PERI_REG_MASK(RTC_CNTL_ANA_CONF_REG, RTC_CNTL_SAR_I2C_FORCE_PU_M);
|
||||
CLEAR_PERI_REG_MASK(ANA_CONFIG_REG, BIT(18));
|
||||
SET_PERI_REG_MASK(ANA_CONFIG2_REG, BIT(16));
|
||||
REGI2C_WRITE_MASK(I2C_ADC, I2C_SARADC_TSENS_DAC, dac_offset[tsens.dac_offset].set_val);
|
||||
SENS.sar_tctrl.tsens_clk_div = tsens.clk_div;
|
||||
SENS.sar_tctrl.tsens_power_up_force = 1;
|
||||
SENS.sar_tctrl2.tsens_xpd_wait = TSENS_XPD_WAIT_DEFAULT;
|
||||
SENS.sar_tctrl2.tsens_xpd_force = 1;
|
||||
// SENS.sar_tctrl2.tsens_reset = 1;// Reset the temp sensor.
|
||||
// SENS.sar_tctrl2.tsens_reset = 0;// Clear the reset status.
|
||||
ESP_LOGI(TAG, "Config temperature range [%d°C ~ %d°C], error < %d°C",
|
||||
dac_offset[tsens.dac_offset].range_min,
|
||||
dac_offset[tsens.dac_offset].range_max,
|
||||
dac_offset[tsens.dac_offset].error_max);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t temp_sensor_get_config(temp_sensor_config_t *tsens)
|
||||
{
|
||||
TSENS_CHECK(tsens != NULL, ESP_ERR_INVALID_ARG);
|
||||
//CLEAR_PERI_REG_MASK(RTC_CNTL_ANA_CONF_REG, RTC_CNTL_SAR_I2C_FORCE_PD_M);
|
||||
//SET_PERI_REG_MASK(RTC_CNTL_ANA_CONF_REG, RTC_CNTL_SAR_I2C_FORCE_PU_M);
|
||||
CLEAR_PERI_REG_MASK(ANA_CONFIG_REG, BIT(18));
|
||||
SET_PERI_REG_MASK(ANA_CONFIG2_REG, BIT(16));
|
||||
tsens->dac_offset = REGI2C_READ_MASK(I2C_ADC, I2C_SARADC_TSENS_DAC);
|
||||
for (int i = TSENS_DAC_L0; i < TSENS_DAC_MAX; i++) {
|
||||
if (tsens->dac_offset == dac_offset[i].set_val) {
|
||||
tsens->dac_offset = dac_offset[i].index;
|
||||
break;
|
||||
}
|
||||
}
|
||||
tsens->clk_div = SENS.sar_tctrl.tsens_clk_div;
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t temp_sensor_start(void)
|
||||
{
|
||||
if (rtc_tsens_mux == NULL) {
|
||||
rtc_tsens_mux = xSemaphoreCreateMutex();
|
||||
}
|
||||
TSENS_CHECK(rtc_tsens_mux != NULL, ESP_ERR_NO_MEM);
|
||||
// SENS.sar_tctrl.tsens_dump_out = 0;
|
||||
// SENS.sar_tctrl2.tsens_clkgate_en = 1;
|
||||
// SENS.sar_tctrl.tsens_power_up = 1;
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t temp_sensor_stop(void)
|
||||
{
|
||||
SENS.sar_tctrl.tsens_power_up = 0;
|
||||
// SENS.sar_tctrl2.tsens_clkgate_en = 0;
|
||||
if (rtc_tsens_mux != NULL) {
|
||||
vSemaphoreDelete(rtc_tsens_mux);
|
||||
rtc_tsens_mux = NULL;
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t temp_sensor_read_raw(uint32_t *tsens_out)
|
||||
{
|
||||
TSENS_CHECK(tsens_out != NULL, ESP_ERR_INVALID_ARG);
|
||||
TSENS_CHECK(rtc_tsens_mux != NULL, ESP_ERR_INVALID_STATE);
|
||||
xSemaphoreTake(rtc_tsens_mux, portMAX_DELAY);
|
||||
SENS.sar_tctrl.tsens_dump_out = 1;
|
||||
while (!SENS.sar_tctrl.tsens_ready);
|
||||
*tsens_out = SENS.sar_tctrl.tsens_out;
|
||||
SENS.sar_tctrl.tsens_dump_out = 0;
|
||||
xSemaphoreGive(rtc_tsens_mux);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t temp_sensor_read_celsius(float *celsius)
|
||||
{
|
||||
TSENS_CHECK(celsius != NULL, ESP_ERR_INVALID_ARG);
|
||||
temp_sensor_config_t tsens;
|
||||
uint32_t tsens_out = 0;
|
||||
esp_err_t ret = temp_sensor_get_config(&tsens);
|
||||
if (ret == ESP_OK) {
|
||||
ret = temp_sensor_read_raw(&tsens_out);
|
||||
TSENS_CHECK(ret == ESP_OK, ret);
|
||||
const tsens_dac_offset_t *dac = &dac_offset[tsens.dac_offset];
|
||||
*celsius = (TSENS_ADC_FACTOR * (float)tsens_out - TSENS_DAC_FACTOR * dac->offset - TSENS_SYS_OFFSET);
|
||||
if (*celsius < dac->range_min || *celsius > dac->range_max) {
|
||||
ESP_LOGW(TAG, "Exceeding the temperature range!");
|
||||
ret = ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
Reference in New Issue
Block a user