1
6
7
13
14
15
18
19
20
21
22
23
24
28
29
30
31
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
71
72
73
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
148
149
150
151
152
153
154
/* ... */
#include <string.h>
#include "soc/soc_caps.h"
#include "driver/dac_cosine.h"
#include "hal/clk_tree_ll.h"
#include "dac_priv_common.h"
#include "clk_ctrl_os.h"6 includes
#if CONFIG_DAC_ENABLE_DEBUG_LOG
#define LOG_LOCAL_LEVEL ESP_LOG_DEBUG/* ... */
#endif
#include "esp_check.h"
#if CONFIG_PM_ENABLE
#include "esp_pm.h"
#endif
struct dac_cosine_s {
dac_cosine_config_t cfg;
bool is_started;
}{ ... };
static const char *TAG = "dac_cosine";
/* ... */
static uint32_t s_cwg_refer_cnt = 0;
static uint32_t s_cwg_freq = 0;
esp_err_t dac_cosine_new_channel(const dac_cosine_config_t *cos_cfg, dac_cosine_handle_t *ret_handle)
{
#if CONFIG_DAC_ENABLE_DEBUG_LOG
esp_log_level_set(TAG, ESP_LOG_DEBUG);
#endif
DAC_NULL_POINTER_CHECK(cos_cfg);
DAC_NULL_POINTER_CHECK(ret_handle);
ESP_RETURN_ON_FALSE(cos_cfg->chan_id < SOC_DAC_CHAN_NUM, ESP_ERR_INVALID_ARG, TAG, "invalid dac channel id");
ESP_RETURN_ON_FALSE(cos_cfg->freq_hz >= (130 / clk_ll_rc_fast_get_divider()), ESP_ERR_NOT_SUPPORTED, TAG, "The cosine wave frequency is too low");
ESP_RETURN_ON_FALSE((!s_cwg_freq) || cos_cfg->flags.force_set_freq || (cos_cfg->freq_hz == s_cwg_freq),
ESP_ERR_INVALID_STATE, TAG, "The cosine wave frequency has set already, not allowed to update unless `force_set_freq` is set");
esp_err_t ret = ESP_OK;
dac_cosine_handle_t handle = heap_caps_calloc(1, sizeof(struct dac_cosine_s), MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT);
ESP_RETURN_ON_FALSE(handle, ESP_ERR_NO_MEM, TAG, "no memory for the dac cosine handle");
memcpy(&handle->cfg, cos_cfg, sizeof(dac_cosine_config_t));
ESP_GOTO_ON_ERROR(dac_priv_register_channel(cos_cfg->chan_id, "dac cosine"), err1, TAG, "register dac channel %d failed", cos_cfg->chan_id);
periph_rtc_dig_clk8m_enable();
uint32_t rtc_clk_freq = periph_rtc_dig_clk8m_get_freq() / clk_ll_rc_fast_get_divider();
periph_rtc_dig_clk8m_disable();
if (rtc_clk_freq == 0) {
ESP_LOGW(TAG, "RTC clock calibration failed, using the approximate value as default");
rtc_clk_freq = SOC_CLK_RC_FAST_FREQ_APPROX;
}{...}
DAC_RTC_ENTER_CRITICAL();
if ((!s_cwg_freq) || cos_cfg->flags.force_set_freq) {
dac_ll_cw_set_freq(cos_cfg->freq_hz, rtc_clk_freq);
s_cwg_freq = cos_cfg->freq_hz;
}{...}
dac_ll_cw_set_atten(cos_cfg->chan_id, cos_cfg->atten);
dac_ll_cw_set_phase(cos_cfg->chan_id, cos_cfg->phase);
dac_ll_cw_set_dc_offset(cos_cfg->chan_id, cos_cfg->offset);
DAC_RTC_EXIT_CRITICAL();
*ret_handle = handle;
return ret;
err1:
free(handle);
return ret;
}{ ... }
esp_err_t dac_cosine_del_channel(dac_cosine_handle_t handle)
{
DAC_NULL_POINTER_CHECK(handle);
ESP_RETURN_ON_FALSE(!handle->is_started, ESP_ERR_INVALID_STATE, TAG,
"the dac cosine generator is not stopped yet");
ESP_RETURN_ON_ERROR(dac_priv_deregister_channel(handle->cfg.chan_id), TAG,
"deregister dac channel %d failed", handle->cfg.chan_id);
if (!s_cwg_refer_cnt) {
s_cwg_freq = 0;
}{...}
free(handle);
return ESP_OK;
}{ ... }
esp_err_t dac_cosine_start(dac_cosine_handle_t handle)
{
DAC_NULL_POINTER_CHECK(handle);
ESP_RETURN_ON_FALSE(!handle->is_started, ESP_ERR_INVALID_STATE, TAG,
"the dac channel has already started");
periph_rtc_dig_clk8m_enable();
ESP_RETURN_ON_ERROR(dac_priv_enable_channel(handle->cfg.chan_id), TAG,
"enable dac channel %d failed", handle->cfg.chan_id);
DAC_RTC_ENTER_CRITICAL();
if (s_cwg_refer_cnt == 0) {
dac_ll_cw_generator_enable();
}{...}
dac_ll_cw_enable_channel(handle->cfg.chan_id, true);
s_cwg_refer_cnt++;
handle->is_started = true;
DAC_RTC_EXIT_CRITICAL();
return ESP_OK;
}{ ... }
esp_err_t dac_cosine_stop(dac_cosine_handle_t handle)
{
DAC_NULL_POINTER_CHECK(handle);
ESP_RETURN_ON_FALSE(handle->is_started, ESP_ERR_INVALID_STATE, TAG,
"the dac channel has already stopped");
ESP_RETURN_ON_ERROR(dac_priv_disable_channel(handle->cfg.chan_id), TAG,
"disable dac channel %d failed", handle->cfg.chan_id);
DAC_RTC_ENTER_CRITICAL();
dac_ll_cw_enable_channel(handle->cfg.chan_id, false);
s_cwg_refer_cnt--;
if (s_cwg_refer_cnt == 0) {
dac_ll_cw_generator_disable();
}{...}
handle->is_started = false;
DAC_RTC_EXIT_CRITICAL();
periph_rtc_dig_clk8m_disable();
return ESP_OK;
}{ ... }