libxr  1.0
Want to be the best embedded framework
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 ASSERT(read_err == ESP_OK);
52 if (read_err != ESP_OK)
53 {
54 if (read_err == ESP_ERR_INVALID_STATE)
55 {
56 (void)adc_continuous_flush_pool(continuous_handle_);
57 }
58 break;
59 }
60
61 if (out_length == 0U)
62 {
63 break;
64 }
65
66 uint32_t parsed_count = 0U;
67 const esp_err_t parse_err =
68 adc_continuous_parse_data(continuous_handle_, continuous_read_buf_, out_length,
69 continuous_parsed_buf_, &parsed_count);
70 ASSERT(parse_err == ESP_OK);
71 if (parse_err != ESP_OK)
72 {
73 break;
74 }
75
76 for (uint32_t i = 0; i < parsed_count; ++i)
77 {
78 const adc_continuous_data_t& sample = continuous_parsed_buf_[i];
79 if (!sample.valid || (sample.unit != unit_))
80 {
81 continue;
82 }
83
84 const uint8_t sample_channel = static_cast<uint8_t>(sample.channel);
85 if (sample_channel >= SOC_ADC_MAX_CHANNEL_NUM)
86 {
87 continue;
88 }
89
90 const uint8_t sample_idx = channel_idx_map_[sample_channel];
91 if ((sample_idx == INVALID_CHANNEL_IDX) || (sample_idx >= num_channels_))
92 {
93 continue;
94 }
95
96 sums[sample_idx] += sample.raw_data;
97 counts[sample_idx] += 1U;
98 any_sample = true;
99 }
100 }
101
102 if (!any_sample)
103 {
104 return;
105 }
106
107 for (uint8_t i = 0; i < num_channels_; ++i)
108 {
109 if (counts[i] == 0U)
110 {
111 continue;
112 }
113
114 const uint16_t raw = static_cast<uint16_t>(sums[i] / counts[i]);
115 latest_raw_[i] = raw;
116 latest_values_[i] = RawToVoltage(i, raw);
117 channel_ready_[i] = true;
118 }
119}
120
121ESP32ADC::ContinuousInitResult ESP32ADC::InitContinuous(uint32_t freq,
122 size_t dma_buf_size)
123{
124 if (!IsDigiUnitSupported(unit_))
125 {
126 return ContinuousInitResult::UNSUPPORTED;
127 }
128
129 const uint32_t sample_freq = ClampSampleFreq(freq);
130 const uint32_t min_frame =
131 static_cast<uint32_t>(num_channels_) * SOC_ADC_DIGI_RESULT_BYTES;
132 const uint32_t frame_size = AlignUp(min_frame, SOC_ADC_DIGI_DATA_BYTES_PER_CONV);
133 const uint32_t store_size =
134 AlignUp(static_cast<uint32_t>((dma_buf_size > static_cast<size_t>(frame_size))
135 ? dma_buf_size
136 : frame_size * 5U),
137 SOC_ADC_DIGI_DATA_BYTES_PER_CONV);
138 const uint32_t parsed_capacity = frame_size / SOC_ADC_DIGI_RESULT_BYTES;
139
140 continuous_read_buf_ = new uint8_t[frame_size];
141 continuous_parsed_buf_ = new adc_continuous_data_t[parsed_capacity];
142
143 adc_continuous_handle_cfg_t handle_cfg = {};
144 handle_cfg.max_store_buf_size = store_size;
145 handle_cfg.conv_frame_size = frame_size;
146 handle_cfg.flags.flush_pool = 1U;
147 if (adc_continuous_new_handle(&handle_cfg, &continuous_handle_) != ESP_OK)
148 {
149 return ContinuousInitResult::FAILED;
150 }
151
152 std::array<adc_digi_pattern_config_t, SOC_ADC_PATT_LEN_MAX> patterns = {};
153 ASSERT(num_channels_ <= patterns.size());
154 if (num_channels_ > patterns.size())
155 {
156 return ContinuousInitResult::FAILED;
157 }
158
159 for (uint8_t i = 0; i < num_channels_; ++i)
160 {
161 patterns[i].atten = static_cast<uint8_t>(attenuation_);
162 patterns[i].channel = static_cast<uint8_t>(channel_ids_[i]);
163 patterns[i].unit = static_cast<uint8_t>(unit_);
164 patterns[i].bit_width = static_cast<uint8_t>(bitwidth_);
165 ConfigureAnalogPad(channel_ids_[i]);
166 channel_ready_[i] = false;
167 latest_values_[i] = 0.0f;
168 latest_raw_[i] = 0U;
169 }
170
171 adc_continuous_config_t config = {};
172 config.pattern_num = num_channels_;
173 config.adc_pattern = patterns.data();
174 config.sample_freq_hz = sample_freq;
175 config.conv_mode =
176 (unit_ == ADC_UNIT_2) ? ADC_CONV_SINGLE_UNIT_2 : ADC_CONV_SINGLE_UNIT_1;
177 config.format = ResolveContinuousFormat();
178 if (adc_continuous_config(continuous_handle_, &config) != ESP_OK)
179 {
180 return ContinuousInitResult::FAILED;
181 }
182
183 if (adc_continuous_start(continuous_handle_) != ESP_OK)
184 {
185 return ContinuousInitResult::FAILED;
186 }
187
188 continuous_frame_size_ = frame_size;
189 continuous_prime_timeout_ms_ =
190 ((1000U * static_cast<uint32_t>(num_channels_) * 2U) / sample_freq) + 5U;
191 if (continuous_prime_timeout_ms_ < 5U)
192 {
193 continuous_prime_timeout_ms_ = 5U;
194 }
195 if (continuous_prime_timeout_ms_ > 50U)
196 {
197 continuous_prime_timeout_ms_ = 50U;
198 }
199
200 backend_ = Backend::CONTINUOUS_DMA;
201 DrainContinuousFrames(continuous_prime_timeout_ms_);
202 return ContinuousInitResult::STARTED;
203}
204
205#else
206
207ESP32ADC::ContinuousInitResult ESP32ADC::InitContinuous(uint32_t, size_t)
208{
209 return ContinuousInitResult::UNSUPPORTED;
210}
211
212#endif
213
214} // namespace LibXR
LibXR 命名空间
Definition ch32_can.hpp:14