system: reset dma when soft reset

This commit is contained in:
Michael (XIAO Xufeng)
2020-12-23 12:29:57 +08:00
committed by bot
parent d35173c147
commit d7d1dee208
44 changed files with 1325 additions and 2772 deletions

View File

@@ -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;
}

View 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.*/
}

View 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;
}