libxr
Embedded C++ framework for bare-metal, RTOS and Linux
Loading...
Searching...
No Matches
esp_adc_continuous.cpp
1#include <array>
2
3#include "esp_adc.hpp"
4
5namespace LibXR
6{
7
8#if SOC_ADC_DIG_CTRL_SUPPORTED && SOC_ADC_DMA_SUPPORTED
9
10bool ESP32ADC::IsDigiUnitSupported(adc_unit_t unit)
11{
12 return SOC_ADC_DIG_SUPPORTED_UNIT(static_cast<int>(unit)) != 0;
13}
14
15adc_digi_output_format_t ESP32ADC::ResolveContinuousFormat()
16{
17#if SOC_ADC_DIGI_RESULT_BYTES == 2
18 return ADC_DIGI_OUTPUT_FORMAT_TYPE1;
19#else
20 return ADC_DIGI_OUTPUT_FORMAT_TYPE2;
21#endif
22}
23
24void ESP32ADC::DrainContinuousFrames(uint32_t timeout_ms)
25{
26 if ((backend_ != Backend::CONTINUOUS_DMA) || (continuous_handle_ == nullptr) ||
27 (continuous_read_buf_ == nullptr) || (continuous_parsed_buf_ == nullptr) ||
28 (continuous_frame_size_ == 0U))
29 {
30 return;
31 }
32
33 std::array<uint32_t, SOC_ADC_MAX_CHANNEL_NUM> sums = {};
34 std::array<uint32_t, SOC_ADC_MAX_CHANNEL_NUM> counts = {};
35 bool first_read = true;
36 bool any_sample = false;
37
38 while (true)
39 {
40 uint32_t out_length = 0U;
41 const esp_err_t read_err = adc_continuous_read(
42 continuous_handle_, continuous_read_buf_, continuous_frame_size_, &out_length,
43 first_read ? timeout_ms : 0U);
44 first_read = false;
45
46 if (read_err == ESP_ERR_TIMEOUT)
47 {
48 break;
49 }
50
51 if (read_err != ESP_OK)
52 {
53 if (read_err == ESP_ERR_INVALID_STATE)
54 {
55 (void)adc_continuous_flush_pool(continuous_handle_);
56 }
57 break;
58 }
59
60 if (out_length == 0U)
61 {
62 break;
63 }
64
65 uint32_t parsed_count = 0U;
66 const esp_err_t parse_err =
67 adc_continuous_parse_data(continuous_handle_, continuous_read_buf_, out_length,
68 continuous_parsed_buf_, &parsed_count);
69
70 if (parse_err != ESP_OK)
71 {
72 break;
73 }
74
75 for (uint32_t i = 0; i < parsed_count; ++i)
76 {
77 const adc_continuous_data_t& sample = continuous_parsed_buf_[i];
78 if (!sample.valid || (sample.unit != unit_))
79 {
80 continue;
81 }
82
83 const uint8_t sample_channel = static_cast<uint8_t>(sample.channel);
84 if (sample_channel >= SOC_ADC_MAX_CHANNEL_NUM)
85 {
86 continue;
87 }
88
89 const uint8_t sample_idx = channel_idx_map_[sample_channel];
90 if ((sample_idx == INVALID_CHANNEL_IDX) || (sample_idx >= num_channels_))
91 {
92 continue;
93 }
94
95 sums[sample_idx] += sample.raw_data;
96 counts[sample_idx] += 1U;
97 any_sample = true;
98 }
99 }
100
101 if (!any_sample)
102 {
103 return;
104 }
105
106 for (uint8_t i = 0; i < num_channels_; ++i)
107 {
108 if (counts[i] == 0U)
109 {
110 continue;
111 }
112
113 const uint16_t raw = static_cast<uint16_t>(sums[i] / counts[i]);
114 latest_raw_[i] = raw;
115 latest_values_[i] = RawToVoltage(i, raw);
116 channel_ready_[i] = true;
117 }
118}
119
120ESP32ADC::ContinuousInitResult ESP32ADC::InitContinuous(uint32_t freq,
121 size_t dma_buf_size)
122{
123 if (!IsDigiUnitSupported(unit_))
124 {
125 return ContinuousInitResult::UNSUPPORTED;
126 }
127
128 const uint32_t sample_freq = ClampSampleFreq(freq);
129 const uint32_t min_frame =
130 static_cast<uint32_t>(num_channels_) * SOC_ADC_DIGI_RESULT_BYTES;
131 const uint32_t frame_size = AlignUp(min_frame, SOC_ADC_DIGI_DATA_BYTES_PER_CONV);
132 const uint32_t store_size =
133 AlignUp(static_cast<uint32_t>((dma_buf_size > static_cast<size_t>(frame_size))
134 ? dma_buf_size
135 : frame_size * 5U),
136 SOC_ADC_DIGI_DATA_BYTES_PER_CONV);
137 const uint32_t parsed_capacity = frame_size / SOC_ADC_DIGI_RESULT_BYTES;
138
139 continuous_read_buf_ = new uint8_t[frame_size];
140 continuous_parsed_buf_ = new adc_continuous_data_t[parsed_capacity];
141
142 adc_continuous_handle_cfg_t handle_cfg = {};
143 handle_cfg.max_store_buf_size = store_size;
144 handle_cfg.conv_frame_size = frame_size;
145 handle_cfg.flags.flush_pool = 1U;
146 if (adc_continuous_new_handle(&handle_cfg, &continuous_handle_) != ESP_OK)
147 {
148 return ContinuousInitResult::FAILED;
149 }
150
151 std::array<adc_digi_pattern_config_t, SOC_ADC_PATT_LEN_MAX> patterns = {};
152 ASSERT(num_channels_ <= patterns.size());
153 if (num_channels_ > patterns.size())
154 {
155 return ContinuousInitResult::FAILED;
156 }
157
158 for (uint8_t i = 0; i < num_channels_; ++i)
159 {
160 patterns[i].atten = static_cast<uint8_t>(attenuation_);
161 patterns[i].channel = static_cast<uint8_t>(channel_ids_[i]);
162 patterns[i].unit = static_cast<uint8_t>(unit_);
163 patterns[i].bit_width = static_cast<uint8_t>(bitwidth_);
164 ConfigureAnalogPad(channel_ids_[i]);
165 channel_ready_[i] = false;
166 latest_values_[i] = 0.0f;
167 latest_raw_[i] = 0U;
168 }
169
170 adc_continuous_config_t config = {};
171 config.pattern_num = num_channels_;
172 config.adc_pattern = patterns.data();
173 config.sample_freq_hz = sample_freq;
174 config.conv_mode =
175 (unit_ == ADC_UNIT_2) ? ADC_CONV_SINGLE_UNIT_2 : ADC_CONV_SINGLE_UNIT_1;
176 config.format = ResolveContinuousFormat();
177 if (adc_continuous_config(continuous_handle_, &config) != ESP_OK)
178 {
179 return ContinuousInitResult::FAILED;
180 }
181
182 if (adc_continuous_start(continuous_handle_) != ESP_OK)
183 {
184 return ContinuousInitResult::FAILED;
185 }
186
187 continuous_frame_size_ = frame_size;
188 continuous_prime_timeout_ms_ =
189 ((1000U * static_cast<uint32_t>(num_channels_) * 2U) / sample_freq) + 5U;
190 if (continuous_prime_timeout_ms_ < 5U)
191 {
192 continuous_prime_timeout_ms_ = 5U;
193 }
194 if (continuous_prime_timeout_ms_ > 50U)
195 {
196 continuous_prime_timeout_ms_ = 50U;
197 }
198
199 backend_ = Backend::CONTINUOUS_DMA;
200 DrainContinuousFrames(continuous_prime_timeout_ms_);
201 return ContinuousInitResult::STARTED;
202}
203
204#else
205
206ESP32ADC::ContinuousInitResult ESP32ADC::InitContinuous(uint32_t, size_t)
207{
208 return ContinuousInitResult::UNSUPPORTED;
209}
210
211#endif
212
213} // namespace LibXR
LibXR 命名空间 / LibXR namespace.
Definition ch32_can.hpp:14