1 /***************************************************************************/ /**
2 * \file cyhal_adc_sar.c
3 *
4 * \brief
5 * Provides a high level interface for interacting with the Cypress Analog/Digital
6 * converter. This interface abstracts out the chip specific details. If any chip
7 * specific functionality is necessary, or performance is critical the low level
8 * functions can be used directly.
9 *
10 ********************************************************************************
11 * \copyright
12 * Copyright 2018-2022 Cypress Semiconductor Corporation (an Infineon company) or
13 * an affiliate of Cypress Semiconductor Corporation
14 *
15 * SPDX-License-Identifier: Apache-2.0
16 *
17 * Licensed under the Apache License, Version 2.0 (the "License");
18 * you may not use this file except in compliance with the License.
19 * You may obtain a copy of the License at
20 *
21 * http://www.apache.org/licenses/LICENSE-2.0
22 *
23 * Unless required by applicable law or agreed to in writing, software
24 * distributed under the License is distributed on an "AS IS" BASIS,
25 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
26 * See the License for the specific language governing permissions and
27 * limitations under the License.
28 *******************************************************************************/
29
30 /**
31 * \addtogroup group_hal_impl_adc ADC (Analog Digital Converter)
32 * \ingroup group_hal_impl
33 * \{
34 * \section cyhal_adc_impl_features Features
35 * The CAT1A/CAT2 (PMG/PSoC™ 4/PSoC™ 6/XMC7™) ADC supports the following features:
36 * * Resolution: 12 bit
37 * * Only @ref CYHAL_POWER_LEVEL_DEFAULT and CYHAL_POWER_LEVEL_OFF are defined. The default power
38 * level will automatically adjust based on smple rate.
39 * * Average counts: 2, 4, 8, 16, 32, 64, 128, 256
40 *
41 * CAT1A supports DMA-based transfer when using @ref cyhal_adc_read_async. When using @ref
42 * cyhal_adc_read_async_uv, only interrupt-driven software copy is supported.
43 *
44 * CAT1A/CAT2 support the following features:
45 * * Up to four unique acquisition times
46 *
47 * CAT1C supports the following features:
48 * * Unique acquisition time per channel
49 * * Single-ended channels only, referenced to VREF
50 * * Internal VREF only
51 * * No external bypass
52 *
53 * After initializing the ADC or changing the reference or bypass selection, it may be necessary to wait up to
54 * 210 us for the reference buffer to settle. See the architecture TRM (Analog Subsystem -> SAR ADC ->
55 * Architecture -> SARREF) for device specific guidance.
56 *
57 * \note On CAT1C devices, the \ref cyhal_source_t object populated by \ref cyhal_adc_enable_output is only valid
58 * as long as the last channel initialized is not disabled, and no new channels are added. If it necessary to
59 * make any of these changes, disable the output using \ref cyhal_adc_disable_output, then re-enable
60 * \} group_hal_impl_adc
61 */
62
63 #include <cmsis_compiler.h>
64
65 #include "cyhal_adc.h"
66 #include "cyhal_analog_common.h"
67 #include "cyhal_clock.h"
68 #include "cyhal_dma.h"
69 #include "cyhal_gpio.h"
70 #include "cyhal_hwmgr.h"
71 #include "cyhal_utils.h"
72 #include "cyhal_irq_impl.h"
73 #include "cyhal_interconnect.h"
74 #include "cyhal_syspm.h"
75 #include "cyhal_system.h"
76 #include <string.h>
77
78 #if (_CYHAL_DRIVER_AVAILABLE_ADC_SAR)
79
80 #if defined(CY_IP_MXS40PASS_SAR_INSTANCES)
81 #define _CYHAL_ADC_SAR_INSTANCES CY_IP_MXS40PASS_SAR_INSTANCES
82 #elif defined(CY_IP_MXS40EPASS_ESAR_INSTANCES)
83 #define _CYHAL_ADC_SAR_INSTANCES CY_IP_MXS40EPASS_ESAR_INSTANCES
84 #elif defined(CY_IP_M0S8PASS4A_SAR_INSTANCES)
85 #define _CYHAL_ADC_SAR_INSTANCES CY_IP_M0S8PASS4A_SAR_INSTANCES
86 #endif
87
88 /* ESAR only sign extends to 16 bits, but we return 32-bit signed values. This means that
89 * while we can technically read the ADC results using DMA, doing so doesn't bring any
90 * real value because still have to post-process the results using the CPU to achieve
91 * proper sign extension. We do this on existing CAT1A and CAT2 devices because we had
92 * already released DMA support before the issue was realized and we can't remove it
93 * without breaking BWC, but extending this behavior to new devices would just be misleading */
94 #if (CYHAL_DRIVER_AVAILABLE_DMA && !defined(CY_IP_MXS40EPASS_ESAR_INSTANCES))
95 #define _CYHAL_ADC_DMA_SUPPORTED (1u)
96 #else
97 #define _CYHAL_ADC_DMA_SUPPORTED (0u)
98 #endif
99
100 #if defined(__cplusplus)
101 extern "C"
102 {
103 #endif
104
105 // The PDL for M0S8 PASS doesn't take the register as an argument; it always writes to MUX_SWITCH0
106 #if defined(CY_IP_M0S8PASS4A_SAR_INSTANCES)
107 #define CY_SAR_MAX_NUM_CHANNELS CY_SAR_SEQ_NUM_CHANNELS
108 #define _CYHAL_ADC_SARSEQ_STATE(state) (state)
109 #define _CYHAL_ADC_SWITCH_STATE(state) (state)
110 #define _CYHAL_ADC_SET_SWITCH(base, mask, state) Cy_SAR_SetAnalogSwitch((base), (mask), (state))
111 #else
112 #define _CYHAL_ADC_SWITCH_STATE(state) ((state) ? CY_SAR_SWITCH_CLOSE : CY_SAR_SWITCH_OPEN)
113 #define _CYHAL_ADC_SARSEQ_STATE(state) ((state) ? CY_SAR_SWITCH_SEQ_CTRL_ENABLE : CY_SAR_SWITCH_SEQ_CTRL_DISABLE)
114 #define _CYHAL_ADC_SET_SWITCH(base, mask, state) Cy_SAR_SetAnalogSwitch((base), CY_SAR_MUX_SWITCH0, (mask), _CYHAL_ADC_SWITCH_STATE((state)))
115 #endif
116
117 #if defined(CY_IP_MXS40EPASS_ESAR)
118 const uint32_t _CYHAL_ADC_MIN_ACQUISITION_TIME_NS = 300u;
119 #else
120 const uint32_t _CYHAL_ADC_MIN_ACQUISITION_TIME_NS = 167;
121 #endif
122
123 #if (CY_IP_MXS40PASS_SAR_INSTANCES == 1) && !defined(CY_DEVICE_PSOC6A256K)
124 #define _CYHAL_ADC_SINGLE_UNSUFFIXED
125 #endif
126
127 #if defined(CY_IP_MXS40EPASS_ESAR_INSTANCES)
128 static PASS_SAR_Type *const _cyhal_adc_base[] =
129 #else
130 static SAR_Type *const _cyhal_adc_base[] =
131 #endif
132 {
133 #if defined(_CYHAL_ADC_SINGLE_UNSUFFIXED)
134 SAR,
135 #else
136 #if (_CYHAL_ADC_SAR_INSTANCES >= 1)
137 #if defined(CY_IP_MXS40EPASS_ESAR_INSTANCES)
138 PASS0_SAR0,
139 #else
140 SAR0,
141 #endif
142 #endif
143 #if (_CYHAL_ADC_SAR_INSTANCES >= 2)
144 #if defined(CY_IP_MXS40EPASS_ESAR_INSTANCES)
145 PASS0_SAR1,
146 #else
147 SAR1,
148 #endif
149 #endif
150 #if (_CYHAL_ADC_SAR_INSTANCES >= 3)
151 #if defined(CY_IP_MXS40EPASS_ESAR_INSTANCES)
152 PASS0_SAR2,
153 #else
154 SAR2,
155 #endif
156 #endif
157 #if (_CYHAL_ADC_SAR_INSTANCES >= 4)
158 #warning Unhandled SAR instance count
159 #endif
160 #endif
161 };
162
163 static const en_clk_dst_t _cyhal_adc_clock[] =
164 {
165 #if defined(_CYHAL_ADC_SINGLE_UNSUFFIXED)
166 PCLK_PASS_CLOCK_SAR,
167 #elif (CY_IP_M0S8PASS4A_SAR_INSTANCES == 1)
168 PCLK_PASS0_CLOCK_SAR,
169 #elif (CY_IP_M0S8PASS4A_SAR_INSTANCES == 2)
170 PCLK_PASS0_CLOCK_SAR,
171 PCLK_PASS1_CLOCK_SAR,
172 #else
173 #if (_CYHAL_ADC_SAR_INSTANCES >= 1)
174 #if defined(CY_IP_MXS40EPASS_ESAR_INSTANCES)
175 PCLK_PASS0_CLOCK_SAR0,
176 #else
177 PCLK_PASS_CLOCK_SAR0,
178 #endif
179 #endif /* (_CYHAL_ADC_SAR_INSTANCES >= 1) */
180 #if (_CYHAL_ADC_SAR_INSTANCES >= 2)
181 #if defined(CY_IP_MXS40EPASS_ESAR_INSTANCES)
182 PCLK_PASS0_CLOCK_SAR1,
183 #else
184 PCLK_PASS_CLOCK_SAR1,
185 #endif
186 #endif /* (_CYHAL_ADC_SAR_INSTANCES >= 2) */
187 #if (_CYHAL_ADC_SAR_INSTANCES >= 3)
188 #if defined(CY_IP_MXS40EPASS_ESAR_INSTANCES)
189 PCLK_PASS0_CLOCK_SAR2,
190 #else
191 PCLK_PASS_CLOCK_SAR2,
192 #endif
193 #endif /* (_CYHAL_ADC_SAR_INSTANCES >= 3) */
194 #if (_CYHAL_ADC_SAR_INSTANCES >= 4)
195 #warning Unhandled SAR instance count
196 #endif
197 #endif
198 };
199
200 static const cyhal_source_t _cyhal_adc_tr_out[] =
201 {
202 #if defined(_CYHAL_ADC_SINGLE_UNSUFFIXED)
203 CYHAL_TRIGGER_PASS_TR_SAR_OUT,
204 #elif (CY_IP_M0S8PASS4A_SAR_INSTANCES == 1)
205 CYHAL_TRIGGER_PASS0_TR_SAR_OUT,
206 #elif (CY_IP_MXS40PASS_SAR_INSTANCES == 1)
207 CYHAL_TRIGGER_PASS_TR_SAR_OUT0,
208 #elif (CY_IP_MXS40PASS_SAR_INSTANCES == 2)
209 CYHAL_TRIGGER_PASS_TR_SAR_OUT0,
210 CYHAL_TRIGGER_PASS_TR_SAR_OUT1,
211 #elif (CY_IP_M0S8PASS4A_SAR_INSTANCES == 2)
212 CYHAL_TRIGGER_PASS0_TR_SAR_OUT,
213 CYHAL_TRIGGER_PASS1_TR_SAR_OUT,
214 #elif defined(CY_IP_MXS40EPASS_ESAR_INSTANCES)
215 /* There are two "tr_gen" outputs per SAR, but we only expose one type of trigger
216 * so we simplify and only use the first trigger per SAR */
217 #if (CY_IP_MXS40EPASS_ESAR_INSTANCES > 0)
218 CYHAL_TRIGGER_PASS0_TR_SAR_GEN_OUT0_EDGE,
219 #endif
220 #if (CY_IP_MXS40EPASS_ESAR_INSTANCES > 1)
221 CYHAL_TRIGGER_PASS0_TR_SAR_GEN_OUT2_EDGE,
222 #endif
223 #if (CY_IP_MXS40EPASS_ESAR_INSTANCES > 2)
224 CYHAL_TRIGGER_PASS0_TR_SAR_GEN_OUT4_EDGE,
225 #endif
226 #if (CY_IP_MXS40EPASS_ESAR_INSTANCES > 3)
227 #error "Unhandled EPASS_ESAR count"
228 #endif
229 #else
230 #warning Unhandled SAR instance count
231 #endif
232 };
233
234 #if defined(CY_IP_MXS40EPASS_ESAR_INSTANCES)
235 static uint8_t _cyhal_adc_last_enabled(const cyhal_adc_t* obj); /* Or last channel, if no channel is enabled */
236 #endif
237
238 static const cyhal_dest_t _cyhal_adc_tr_in[] =
239 {
240 #if defined(_CYHAL_ADC_SINGLE_UNSUFFIXED)
241 CYHAL_TRIGGER_PASS_TR_SAR_IN,
242 #elif (CY_IP_M0S8PASS4A_SAR_INSTANCES == 1)
243 CYHAL_TRIGGER_PASS0_TR_SAR_IN,
244 #elif (CY_IP_MXS40PASS_SAR_INSTANCES == 1)
245 CYHAL_TRIGGER_PASS_TR_SAR_IN0,
246 #elif (CY_IP_MXS40PASS_SAR_INSTANCES == 2)
247 CYHAL_TRIGGER_PASS_TR_SAR_IN0,
248 CYHAL_TRIGGER_PASS_TR_SAR_IN1,
249 #elif (CY_IP_M0S8PASS4A_SAR_INSTANCES == 2)
250 CYHAL_TRIGGER_PASS0_TR_SAR_IN,
251 CYHAL_TRIGGER_PASS1_TR_SAR_IN,
252 #elif defined(CY_IP_MXS40EPASS_ESAR_INSTANCES)
253 /* We don't use groups, so we always trigger the SAR starting from channel 0 */
254 #if (CY_IP_MXS40EPASS_ESAR_INSTANCES > 0)
255 CYHAL_TRIGGER_PASS0_TR_SAR_CH_IN0,
256 #endif
257 #if (CY_IP_MXS40EPASS_ESAR_INSTANCES > 1)
258 (cyhal_dest_t)(CYHAL_TRIGGER_PASS0_TR_SAR_CH_IN0 + PASS_SAR_SLICE_NR0_SAR_SAR_CHAN_NR),
259 #endif
260 #if (CY_IP_MXS40EPASS_ESAR_INSTANCES > 2)
261 (cyhal_dest_t)(CYHAL_TRIGGER_PASS0_TR_SAR_CH_IN0
262 + PASS_SAR_SLICE_NR0_SAR_SAR_CHAN_NR + PASS_SAR_SLICE_NR1_SAR_SAR_CHAN_NR),
263 #endif
264 #if (CY_IP_MXS40EPASS_ESAR_INSTANCES > 3)
265 #error "Unhandled EPASS_ESAR count"
266 #endif
267 #else
268 #warning Unhandled SAR instance count
269 #endif
270 };
271
272 static cyhal_adc_t* _cyhal_adc_config_structs[_CYHAL_ADC_SAR_INSTANCES];
273
274 #if defined(CY_IP_MXS40EPASS_ESAR_INSTANCES)
_cyhal_adc_calc_channel_irq(uint8_t adc_num,uint8_t channel_num)275 static _cyhal_system_irq_t _cyhal_adc_calc_channel_irq(uint8_t adc_num, uint8_t channel_num)
276 {
277 _cyhal_system_irq_t base = pass_0_interrupts_sar_0_IRQn;
278 #if (CY_IP_MXS40EPASS_ESAR_INSTANCES > 1)
279 if(adc_num > 0u)
280 {
281 base = (_cyhal_system_irq_t)(base + PASS_SAR_SLICE_NR0_SAR_SAR_CHAN_NR);
282 }
283 #endif
284 #if (CY_IP_MXS40EPASS_ESAR_INSTANCES > 2)
285 if(adc_num > 1u)
286 {
287 base = (_cyhal_system_irq_t)(base + PASS_SAR_SLICE_NR1_SAR_SAR_CHAN_NR);
288 }
289 #endif
290 #if (CY_IP_MXS40EPASS_ESAR_INSTANCES > 3)
291 #error "Unhandled ADC instance count"
292 #endif
293
294 _cyhal_system_irq_t irq = (_cyhal_system_irq_t)(base + channel_num);
295 return irq;
296 }
297 #else
298 static const _cyhal_system_irq_t _cyhal_adc_irq_n[] =
299 {
300 #if defined(_CYHAL_ADC_SINGLE_UNSUFFIXED)
301 pass_interrupt_sar_IRQn,
302 #elif (CY_IP_M0S8PASS4A_SAR_INSTANCES == 1)
303 pass_0_interrupt_sar_IRQn,
304 #elif (CY_IP_MXS40PASS_SAR_INSTANCES == 1)
305 pass_interrupt_sar_0_IRQn,
306 #elif (CY_IP_MXS40PASS_SAR_INSTANCES == 2)
307 pass_interrupt_sar_0_IRQn,
308 pass_interrupt_sar_1_IRQn,
309 #elif (CY_IP_M0S8PASS4A_SAR_INSTANCES == 2)
310 pass_0_interrupt_sar_IRQn,
311 pass_0_interrupt_sar_IRQn,
312 #else
313 #warning Unhandled SAR instance count
314 #endif
315 };
316 #endif
317
318 #if defined(CY_IP_MXS40EPASS_ESAR)
319 // Expected to be lowest value possible
320 #define _CYHAL_ADC_VBG_CHANNEL_IDX (0)
321 static cyhal_adc_channel_t _cyhal_adc_vbg_channels[CY_IP_MXS40EPASS_ESAR_INSTANCES];
322 #endif /* defined(CY_IP_MXS40EPASS_ESAR) */
323
_cyhal_adc_get_block_from_irqn(_cyhal_system_irq_t irqn)324 static uint8_t _cyhal_adc_get_block_from_irqn(_cyhal_system_irq_t irqn)
325 {
326 #if defined(CY_IP_MXS40EPASS_ESAR_INSTANCES)
327 uint8_t channel_offset = (uint8_t)(irqn - pass_0_interrupts_sar_0_IRQn);
328 #if (CY_IP_MXS40EPASS_ESAR_INSTANCES > 3u)
329 #error "Unhandled ADC instance count"
330 #endif
331 #if (CY_IP_MXS40EPASS_ESAR_INSTANCES > 2u)
332 if(channel_offset >= PASS_SAR_SLICE_NR1_SAR_SAR_CHAN_NR + PASS_SAR_SLICE_NR0_SAR_SAR_CHAN_NR)
333 {
334 return 2u;
335 }
336 #endif
337 #if (CY_IP_MXS40EPASS_ESAR_INSTANCES > 1u)
338 if(channel_offset >= PASS_SAR_SLICE_NR0_SAR_SAR_CHAN_NR)
339 {
340 return 1u;
341 }
342 #endif
343 return 0u;
344 #else
345 switch (irqn)
346 {
347 #if defined(_CYHAL_ADC_SINGLE_UNSUFFIXED)
348 case pass_interrupt_sar_IRQn:
349 return 0;
350 #elif (CY_IP_M0S8PASS4A_SAR_INSTANCES == 1)
351 case pass_0_interrupt_sar_IRQn:
352 return 0;
353 #elif (CY_IP_MXS40PASS_SAR_INSTANCES == 1)
354 case pass_interrupt_sar_0_IRQn:
355 return 0;
356 #elif (CY_IP_MXS40PASS_SAR_INSTANCES == 2)
357 case pass_interrupt_sar_0_IRQn:
358 return 0;
359 case pass_interrupt_sar_1_IRQn:
360 return 1;
361 #elif (CY_IP_M0S8PASS4A_SAR_INSTANCES == 2)
362 case pass_0_interrupt_sar_IRQn:
363 return 0;
364 case pass_1_interrupt_sar_IRQn:
365 return 1;
366 #else
367 #warning Unhandled SAR instance count
368 #endif
369 default:
370 CY_ASSERT(false); // Should never be called with a non-SAR IRQn
371 return 0;
372 }
373 #endif
374 }
375
376 #if defined(CY_IP_MXS40EPASS_ESAR_INSTANCES)
377 static const cy_stc_sar2_config_t _CYHAL_ADC_DEFAULT_PDL_CONFIG =
378 {
379 .preconditionTime = 1u,
380 .powerupTime = 0u,
381 .enableIdlePowerDown = 0u,
382 .msbStretchMode = CY_SAR2_MSB_STRETCH_MODE_1CYCLE, /* Give similar behavior to MXS40PASS */
383 .enableHalfLsbConv = true,
384 .sarMuxEnable = true,
385 .adcEnable = true,
386 .sarIpEnable = true,
387 .channelConfig = { NULL } /* Channels will be individually configured */
388 };
389
390 static const cy_stc_sar2_channel_config_t _CYHAL_ADC_DEFAULT_PDL_CHAN_CONFIG =
391 {
392 /* channelHwEnable will be populated from the user's configuration */
393 /* triggerSelection will be populated based on continous scanning configuration */
394 .preenptionType = CY_SAR2_PREEMPTION_FINISH_RESUME,
395 /* isGroupEnd is populated from the position relative to other enabled channels */
396 .doneLevel = CY_SAR2_DONE_LEVEL_PULSE,
397 .portAddress = CY_SAR2_PORT_ADDRESS_SARMUX0, /* Despite what the name implies, this means use our own SarMux */
398 /* pinAddress will be populated based on user's configuration */
399 .extMuxSelect = 0u, /* We don't support the external mux features in the HAL */
400 .extMuxEnable = false,
401 .preconditionMode = CY_SAR2_PRECONDITION_MODE_OFF, /* Consistent with MXS40PASS */
402 .overlapDiagMode = CY_SAR2_OVERLAP_DIAG_MODE_OFF, /* Other settings are for debugging */
403 /* sampleTime will be computed based on channel configuration */
404 .calibrationValueSelect = CY_SAR2_CALIBRATION_VALUE_REGULAR,
405 /* postProcessingMode will be populated based on whether averaging is enabled */
406 .resultAlignment = CY_SAR2_RESULT_ALIGNMENT_RIGHT,
407 .signExtention = CY_SAR2_SIGN_EXTENTION_UNSIGNED,
408 /* averageCount is populated based on global adc configuration. rightShift is populated based on average vs. accumulate */
409 .rangeDetectionMode = CY_SAR2_RANGE_DETECTION_MODE_BELOW_LO, /* Placeholder value, range detection is not exposed */
410 .rangeDetectionLoThreshold = 0u,
411 .rangeDetectionHiThreshold = 0u,
412 .interruptMask = 0u, /* interruptMask will be updated if this is the last channel */
413 };
414
415 #elif defined(CY_IP_MXS40PASS_SAR_INSTANCES)
416 /* OR in the following user-configurable values: vref, bypass, vneg, */
417 #define _CYHAL_ADC_DEFAULT_CTRL ((uint32_t)CY_SAR_VREF_PWR_100 | (uint32_t)CY_SAR_VREF_SEL_BGR \
418 | (uint32_t)CY_SAR_BYPASS_CAP_DISABLE | (uint32_t)CY_SAR_CTRL_NEGVREF_HW \
419 | (uint32_t)CY_SAR_CTRL_COMP_DLY_12 | (uint32_t)CY_SAR_COMP_PWR_100 \
420 | (uint32_t)CY_SAR_DEEPSLEEP_SARMUX_OFF | (uint32_t)CY_SAR_SARSEQ_SWITCH_ENABLE)
421
422 /* Default configuration. OR in the average count, and average mode */
423 #define _CYHAL_ADC_DEFAULT_SAMPLE ((uint32_t)CY_SAR_RIGHT_ALIGN | (uint32_t)CY_SAR_TRIGGER_MODE_FW_ONLY \
424 | (uint32_t)CY_SAR_SINGLE_ENDED_SIGNED | (uint32_t)CY_SAR_DIFFERENTIAL_SIGNED \
425 | (uint32_t)CY_SAR_TRIGGER_MODE_FW_ONLY)
426
427 static const cy_stc_sar_config_t _CYHAL_ADC_DEFAULT_PDL_CONFIG =
428 {
429 /* .ctrl is populated from _CYHAL_ADC_DEFAULT_CTRL plus the user's configuration */
430 /* .sampleCtrl is puopulated from _CYHAL_ADC_DEFAULT_SAMPLE plus the user's configuration */
431 .sampleTime01 = (10UL << SAR_SAMPLE_TIME01_SAMPLE_TIME0_Pos), // Sample times 1, 2, and 3 are not used
432 .sampleTime23 = 0UL,
433 .rangeThres = (0UL << CY_SAR_RANGE_HIGH_SHIFT) | (0UL << CY_SAR_RANGE_LOW_SHIFT),
434 .rangeCond = CY_SAR_RANGE_COND_BELOW,
435 .chanEn = 0UL,
436 .chanConfig = { 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL},
437 .intrMask = (uint32_t) CY_SAR_INTR_EOS,
438 .satIntrMask = 0UL,
439 .rangeIntrMask = 0UL,
440 .muxSwitch = 0UL,
441 .muxSwitchSqCtrl = 0UL,
442 .configRouting = true,
443 /* .vrefMvValue is populated from the user's configuration */
444 };
445
446 #endif
447
448 #define _CYHAL_ADC_RESOLUTION 12u
449 #define _CYHAL_ADC_INTERNAL_VREF_MV 1200UL
450 #define _CYHAL_ADC_CONVERSION_CYCLES (_CYHAL_ADC_RESOLUTION + 2)
451
452 static const cyhal_adc_config_t _CYHAL_ADC_DEFAULT_CONFIG =
453 {
454 .resolution = _CYHAL_ADC_RESOLUTION,
455 .average_count = 1,
456 .average_mode_flags = CYHAL_ADC_AVG_MODE_AVERAGE,
457 .continuous_scanning = true,
458 #if defined(CY_IP_MXS40EPASS_ESAR_INSTANCES)
459 .vneg = CYHAL_ADC_VNEG_VSSA,
460 #else
461 .vneg = CYHAL_ADC_VNEG_VREF,
462 #endif
463 .vref = CYHAL_ADC_REF_INTERNAL,
464 .ext_vref = NC,
465 .ext_vref_mv = 0u,
466 .is_bypassed = false,
467 .bypass_pin = NC,
468 };
469
470 /*******************************************************************************
471 * Internal helper functions
472 *******************************************************************************/
473 #if defined(CY_IP_MXS40EPASS_ESAR_INSTANCES) /* Not specific to this IP, but no other IP needs these */
_cyhal_adc_first_enabled(const cyhal_adc_t * obj)474 static uint8_t _cyhal_adc_first_enabled(const cyhal_adc_t* obj) /* Or first channel, if no channel is enabled */
475 {
476 uint8_t first_enabled = 0u;
477 for(uint8_t i = 0; i < CY_SAR_MAX_NUM_CHANNELS; ++i)
478 {
479 if(NULL != obj->channel_config[i] && obj->base->CH[i].ENABLE)
480 {
481 first_enabled = i;
482 break;
483 }
484 }
485
486 return first_enabled;
487 }
488
_cyhal_adc_last_enabled(const cyhal_adc_t * obj)489 static uint8_t _cyhal_adc_last_enabled(const cyhal_adc_t* obj) /* Or last channel, if no channel is enabled */
490 {
491 uint8_t last_enabled = CY_SAR_MAX_NUM_CHANNELS - 1u;
492 /* NOT uint, or the loop will never terminate */
493 for(int i = CY_SAR_MAX_NUM_CHANNELS - 1; i >= 0; --i)
494 {
495 if(NULL != obj->channel_config[i] && obj->base->CH[i].ENABLE)
496 {
497 last_enabled = i;
498 break;
499 }
500 }
501
502 return last_enabled;
503 }
504
_cyhal_adc_counts_to_uvolts(cyhal_adc_t * obj,uint8_t channel,uint32_t counts)505 static int32_t _cyhal_adc_counts_to_uvolts(cyhal_adc_t* obj, uint8_t channel, uint32_t counts)
506 {
507 CY_UNUSED_PARAMETER(obj); /* We're always single-ended with vneg set to vssa */
508 CY_UNUSED_PARAMETER(channel); /* We're always single-ended with vneg set to vssa */
509
510 /* 900000 uV (0.9V) is value from SAR2 ADC PDL driver documentation and stands for voltage on VBG diode.
511 * It always remains stable and it is recommended to be used as reference in ADC counts to Voltage calculations */
512 return (int32_t)((counts * 900000.0f) / obj->vbg_last_value);
513 }
514
_cyhal_adc_extract_channel_conf(cyhal_adc_t * adc,cy_stc_sar2_channel_config_t * channel_configs)515 static void _cyhal_adc_extract_channel_conf(cyhal_adc_t* adc, cy_stc_sar2_channel_config_t* channel_configs)
516 {
517 for(uint8_t i = 0; i < CY_SAR_MAX_NUM_CHANNELS; ++i)
518 {
519 /* The ADC channel configuration structs do not come up with determistic values, so force to 0 any channel
520 which we have not explicitly configured */
521 if(NULL == adc->channel_config[i])
522 {
523 memset(&channel_configs[i], 0u, sizeof(cy_stc_sar2_channel_config_t));;
524 }
525 else
526 {
527 channel_configs[i].triggerSelection = (cy_en_sar2_trigger_selection_t)_FLD2VAL(PASS_SAR_CH_TR_CTL_SEL, adc->base->CH[i].TR_CTL);
528 channel_configs[i].channelPriority = (uint8_t)_FLD2VAL(PASS_SAR_CH_TR_CTL_PRIO, adc->base->CH[i].TR_CTL);
529 channel_configs[i].preenptionType = (cy_en_sar2_preemption_type_t)_FLD2VAL(PASS_SAR_CH_TR_CTL_PREEMPT_TYPE, adc->base->CH[i].TR_CTL);
530 channel_configs[i].isGroupEnd = (bool)_FLD2BOOL(PASS_SAR_CH_TR_CTL_GROUP_END, adc->base->CH[i].TR_CTL);
531 channel_configs[i].doneLevel = (cy_en_sar2_done_level_t)_FLD2BOOL(PASS_SAR_CH_TR_CTL_DONE_LEVEL, adc->base->CH[i].TR_CTL);
532
533 channel_configs[i].pinAddress = (cy_en_sar2_pin_address_t)_FLD2VAL(PASS_SAR_CH_SAMPLE_CTL_PIN_ADDR, adc->base->CH[i].SAMPLE_CTL);
534 channel_configs[i].portAddress = (cy_en_sar2_port_address_t)_FLD2VAL(PASS_SAR_CH_SAMPLE_CTL_PORT_ADDR, adc->base->CH[i].SAMPLE_CTL);
535 channel_configs[i].extMuxSelect = (uint8_t)_FLD2VAL(PASS_SAR_CH_SAMPLE_CTL_EXT_MUX_SEL, adc->base->CH[i].SAMPLE_CTL);
536 channel_configs[i].extMuxEnable = (bool)_FLD2BOOL(PASS_SAR_CH_SAMPLE_CTL_EXT_MUX_EN, adc->base->CH[i].SAMPLE_CTL);
537 channel_configs[i].preconditionMode = (cy_en_sar2_precondition_mode_t)_FLD2VAL(PASS_SAR_CH_SAMPLE_CTL_PRECOND_MODE, adc->base->CH[i].SAMPLE_CTL);
538 channel_configs[i].overlapDiagMode = (cy_en_sar2_overlap_diag_mode_t)_FLD2VAL(PASS_SAR_CH_SAMPLE_CTL_OVERLAP_DIAG, adc->base->CH[i].SAMPLE_CTL);
539 channel_configs[i].sampleTime = (uint16_t)_FLD2VAL(PASS_SAR_CH_SAMPLE_CTL_SAMPLE_TIME, adc->base->CH[i].SAMPLE_CTL);
540 channel_configs[i].calibrationValueSelect = (cy_en_sar2_calibration_value_select_t)_FLD2VAL(PASS_SAR_CH_SAMPLE_CTL_ALT_CAL, adc->base->CH[i].SAMPLE_CTL);
541
542 channel_configs[i].postProcessingMode = (cy_en_sar2_post_processing_mode_t)_FLD2VAL(PASS_SAR_CH_POST_CTL_POST_PROC, adc->base->CH[i].POST_CTL);
543 channel_configs[i].resultAlignment = (cy_en_sar2_result_alignment_t)_FLD2VAL(PASS_SAR_CH_POST_CTL_LEFT_ALIGN, adc->base->CH[i].POST_CTL);
544 channel_configs[i].signExtention = (cy_en_sar2_sign_extention_t)_FLD2VAL(PASS_SAR_CH_POST_CTL_SIGN_EXT, adc->base->CH[i].POST_CTL);
545 channel_configs[i].averageCount = (uint8_t)_FLD2VAL(PASS_SAR_CH_POST_CTL_AVG_CNT, adc->base->CH[i].POST_CTL);
546 channel_configs[i].rightShift = (uint8_t)_FLD2VAL(PASS_SAR_CH_POST_CTL_SHIFT_R, adc->base->CH[i].POST_CTL);
547 channel_configs[i].rangeDetectionMode = (cy_en_sar2_range_detection_mode_t)_FLD2VAL(PASS_SAR_CH_POST_CTL_RANGE_MODE, adc->base->CH[i].POST_CTL);
548
549 channel_configs[i].rangeDetectionLoThreshold = (uint16_t)_FLD2VAL(PASS_SAR_CH_RANGE_CTL_RANGE_LO, adc->base->CH[i].RANGE_CTL);
550 channel_configs[i].rangeDetectionHiThreshold = (uint16_t)_FLD2VAL(PASS_SAR_CH_RANGE_CTL_RANGE_HI, adc->base->CH[i].RANGE_CTL);
551
552 channel_configs[i].channelHwEnable = (bool)(adc->base->CH[i].ENABLE);
553 channel_configs[i].interruptMask = Cy_SAR2_Channel_GetInterruptMask(adc->base, i);
554 }
555 }
556 }
557 #endif
558
_cyhal_adc_update_intr_mask(const cyhal_adc_t * obj)559 static void _cyhal_adc_update_intr_mask(const cyhal_adc_t* obj)
560 {
561 bool needs_eos = (obj->async_scans_remaining > 0) /* Async transfer in progress */
562 || (false == obj->conversion_complete) /* ISR needs to flag that a conversion finished */
563 #if !defined(CY_IP_MXS40EPASS_ESAR)
564 || obj->stop_after_scan /* ISR needs to stop the conversion after the scan finishes */
565 #endif
566 || (0u != (CYHAL_ADC_EOS & obj->user_enabled_events)); /* User requested EOS event */
567
568 #if defined(CY_IP_MXS40EPASS_ESAR_INSTANCES)
569 uint8_t last_channel = _cyhal_adc_last_enabled(obj);
570 uint32_t current_mask = Cy_SAR2_Channel_GetInterruptMask(obj->base, last_channel);
571 uint32_t new_mask;
572 if(needs_eos)
573 {
574 new_mask = current_mask | CY_SAR2_INT_GRP_DONE;
575 }
576 else
577 {
578 new_mask = current_mask & ~CY_SAR2_INT_GRP_DONE;
579 }
580
581 Cy_SAR2_Channel_ClearInterrupt(obj->base, last_channel, new_mask & (~current_mask));
582 Cy_SAR2_Channel_SetInterruptMask(obj->base, last_channel, new_mask);
583 #else
584 uint32_t current_mask = Cy_SAR_GetInterruptMask(obj->base);
585 uint32_t new_mask;
586 if(needs_eos)
587 {
588 new_mask = current_mask | CY_SAR_INTR_EOS;
589 }
590 else
591 {
592 new_mask = current_mask & ~CY_SAR_INTR_EOS;
593 }
594
595 Cy_SAR_ClearInterrupt(obj->base, new_mask & (~current_mask));
596 Cy_SAR_SetInterruptMask(obj->base, new_mask);
597 #endif
598 }
599
_cyhal_adc_max_configured_channel(const cyhal_adc_t * obj)600 static uint8_t _cyhal_adc_max_configured_channel(const cyhal_adc_t* obj)
601 {
602 uint8_t max = 0;
603 for(uint8_t i = 0; i < CY_SAR_MAX_NUM_CHANNELS; ++i)
604 {
605 if(NULL != obj->channel_config[i])
606 {
607 max = i;
608 }
609 }
610 return max;
611 }
612
_cyhal_adc_calculate_source(cyhal_adc_t * obj)613 static cyhal_source_t _cyhal_adc_calculate_source(cyhal_adc_t *obj)
614 {
615 CY_ASSERT(obj->resource.block_num < _CYHAL_ADC_SAR_INSTANCES);
616 return _cyhal_adc_tr_out[obj->resource.block_num];
617 }
618
619 #if !defined(CY_IP_MXS40EPASS_ESAR_INSTANCES)
_cyhal_adc_get_mux_switch_control(cyhal_gpio_t gpio)620 static uint32_t _cyhal_adc_get_mux_switch_control(cyhal_gpio_t gpio)
621 {
622 static const uint32_t mux_lookup[] =
623 {
624 #if defined(CY_IP_M0S8PASS4A_SAR_INSTANCES)
625 SAR_MUX_SWITCH_HW_CTRL_MUX_HW_CTRL_P0_Msk,
626 SAR_MUX_SWITCH_HW_CTRL_MUX_HW_CTRL_P1_Msk,
627 SAR_MUX_SWITCH_HW_CTRL_MUX_HW_CTRL_P2_Msk,
628 SAR_MUX_SWITCH_HW_CTRL_MUX_HW_CTRL_P3_Msk,
629 SAR_MUX_SWITCH_HW_CTRL_MUX_HW_CTRL_P4_Msk,
630 SAR_MUX_SWITCH_HW_CTRL_MUX_HW_CTRL_P5_Msk,
631 SAR_MUX_SWITCH_HW_CTRL_MUX_HW_CTRL_P6_Msk,
632 SAR_MUX_SWITCH_HW_CTRL_MUX_HW_CTRL_P7_Msk,
633 #else
634 (uint32_t)CY_SAR_MUX_SQ_CTRL_P0,
635 (uint32_t)CY_SAR_MUX_SQ_CTRL_P1,
636 (uint32_t)CY_SAR_MUX_SQ_CTRL_P2,
637 (uint32_t)CY_SAR_MUX_SQ_CTRL_P3,
638 (uint32_t)CY_SAR_MUX_SQ_CTRL_P4,
639 (uint32_t)CY_SAR_MUX_SQ_CTRL_P5,
640 (uint32_t)CY_SAR_MUX_SQ_CTRL_P6,
641 (uint32_t)CY_SAR_MUX_SQ_CTRL_P7
642 #endif
643 };
644 uint8_t pin = CYHAL_GET_PIN(gpio);
645 CY_ASSERT(pin < sizeof(mux_lookup)/sizeof(mux_lookup[0]));
646 return mux_lookup[pin];
647 }
648
_cyhal_adc_get_fw_switch_control(cyhal_gpio_t gpio,bool is_vplus)649 static uint32_t _cyhal_adc_get_fw_switch_control(cyhal_gpio_t gpio, bool is_vplus)
650 {
651 static const uint32_t vplus_lookup[] =
652 {
653 (uint32_t)CY_SAR_MUX_FW_P0_VPLUS,
654 (uint32_t)CY_SAR_MUX_FW_P1_VPLUS,
655 (uint32_t)CY_SAR_MUX_FW_P2_VPLUS,
656 (uint32_t)CY_SAR_MUX_FW_P3_VPLUS,
657 (uint32_t)CY_SAR_MUX_FW_P4_VPLUS,
658 (uint32_t)CY_SAR_MUX_FW_P5_VPLUS,
659 (uint32_t)CY_SAR_MUX_FW_P6_VPLUS,
660 (uint32_t)CY_SAR_MUX_FW_P7_VPLUS
661 };
662
663 static const uint32_t vminus_lookup[] =
664 {
665 (uint32_t)CY_SAR_MUX_FW_P0_VMINUS,
666 (uint32_t)CY_SAR_MUX_FW_P1_VMINUS,
667 (uint32_t)CY_SAR_MUX_FW_P2_VMINUS,
668 (uint32_t)CY_SAR_MUX_FW_P3_VMINUS,
669 (uint32_t)CY_SAR_MUX_FW_P4_VMINUS,
670 (uint32_t)CY_SAR_MUX_FW_P5_VMINUS,
671 (uint32_t)CY_SAR_MUX_FW_P6_VMINUS,
672 (uint32_t)CY_SAR_MUX_FW_P7_VMINUS
673 };
674
675 uint8_t pin = CYHAL_GET_PIN(gpio);
676 CY_ASSERT(pin < sizeof(vplus_lookup)/sizeof(vplus_lookup[0]));
677 return (uint32_t)(is_vplus ? vplus_lookup[pin] : vminus_lookup[pin]);
678 }
679
680 #if defined(CY_IP_M0S8PASS4A_SAR_INSTANCES)
_cyhal_adc_get_pin_addr(cyhal_gpio_t gpio)681 static uint32_t _cyhal_adc_get_pin_addr(cyhal_gpio_t gpio)
682 {
683 // On this version of the PASS, there is no explicit vminus address; it is implied by vplus
684 static const cy_en_sar_chan_config_port_pin_addr_t vplus_lookup[] =
685 {
686 CY_SAR_ADDR_SARMUX_0,
687 CY_SAR_ADDR_SARMUX_1,
688 CY_SAR_ADDR_SARMUX_2,
689 CY_SAR_ADDR_SARMUX_3,
690 CY_SAR_ADDR_SARMUX_4,
691 CY_SAR_ADDR_SARMUX_5,
692 CY_SAR_ADDR_SARMUX_6,
693 CY_SAR_ADDR_SARMUX_7
694 };
695 uint8_t pin = CYHAL_GET_PIN(gpio);
696 CY_ASSERT(pin < sizeof(vplus_lookup)/sizeof(vplus_lookup[0]));
697 return (uint32_t)vplus_lookup[pin];
698 }
699 #else
_cyhal_adc_get_pin_addr(cyhal_gpio_t gpio,bool is_vplus)700 static uint32_t _cyhal_adc_get_pin_addr(cyhal_gpio_t gpio, bool is_vplus)
701 {
702 static const cy_en_sar_chan_config_pos_pin_addr_t vplus_lookup[] =
703 {
704 CY_SAR_CHAN_POS_PIN_ADDR_0,
705 CY_SAR_CHAN_POS_PIN_ADDR_1,
706 CY_SAR_CHAN_POS_PIN_ADDR_2,
707 CY_SAR_CHAN_POS_PIN_ADDR_3,
708 CY_SAR_CHAN_POS_PIN_ADDR_4,
709 CY_SAR_CHAN_POS_PIN_ADDR_5,
710 CY_SAR_CHAN_POS_PIN_ADDR_6,
711 CY_SAR_CHAN_POS_PIN_ADDR_7
712 };
713
714 static const cy_en_sar_chan_config_neg_pin_addr_t vminus_lookup[] =
715 {
716 CY_SAR_CHAN_NEG_PIN_ADDR_0,
717 CY_SAR_CHAN_NEG_PIN_ADDR_1,
718 CY_SAR_CHAN_NEG_PIN_ADDR_2,
719 CY_SAR_CHAN_NEG_PIN_ADDR_3,
720 CY_SAR_CHAN_NEG_PIN_ADDR_4,
721 CY_SAR_CHAN_NEG_PIN_ADDR_5,
722 CY_SAR_CHAN_NEG_PIN_ADDR_6,
723 CY_SAR_CHAN_NEG_PIN_ADDR_7
724 };
725 uint8_t pin = CYHAL_GET_PIN(gpio);
726 CY_ASSERT(pin < sizeof(vplus_lookup)/sizeof(vplus_lookup[0]));
727 uint32_t pin_addr = is_vplus ? (uint32_t)vplus_lookup[pin] : (uint32_t)vminus_lookup[pin];
728 return is_vplus ? (pin_addr | CY_SAR_POS_PORT_ADDR_SARMUX) : (pin_addr | CY_SAR_NEG_PORT_ADDR_SARMUX);
729 }
730 #endif
731
_cyhal_adc_convert_vref(cyhal_adc_vref_t vref)732 static cy_en_sar_ctrl_vref_sel_t _cyhal_adc_convert_vref(cyhal_adc_vref_t vref)
733 {
734 switch(vref)
735 {
736 case CYHAL_ADC_REF_INTERNAL:
737 return CY_SAR_VREF_SEL_BGR;
738 case CYHAL_ADC_REF_EXTERNAL:
739 return CY_SAR_VREF_SEL_EXT;
740 case CYHAL_ADC_REF_VDDA:
741 return CY_SAR_VREF_SEL_VDDA;
742 case CYHAL_ADC_REF_VDDA_DIV_2:
743 return CY_SAR_VREF_SEL_VDDA_DIV_2;
744 default:
745 CY_ASSERT(false);
746 return CY_SAR_VREF_SEL_BGR;
747 }
748 }
749
_cyhal_adc_convert_average_count(uint32_t hal_count,cy_en_sar_sample_ctrl_avg_cnt_t * pdl_count)750 static cy_rslt_t _cyhal_adc_convert_average_count(uint32_t hal_count, cy_en_sar_sample_ctrl_avg_cnt_t* pdl_count)
751 {
752 switch(hal_count)
753 {
754 case 1: /* Average count of 1 is achieved by disabling averaging for all channels */
755 case 2:
756 *pdl_count = CY_SAR_AVG_CNT_2;
757 return CY_RSLT_SUCCESS;
758 case 4:
759 *pdl_count = CY_SAR_AVG_CNT_4;
760 return CY_RSLT_SUCCESS;
761 case 8:
762 *pdl_count = CY_SAR_AVG_CNT_8;
763 return CY_RSLT_SUCCESS;
764 case 16:
765 *pdl_count = CY_SAR_AVG_CNT_16;
766 return CY_RSLT_SUCCESS;
767 case 32:
768 *pdl_count = CY_SAR_AVG_CNT_32;
769 return CY_RSLT_SUCCESS;
770 case 64:
771 *pdl_count = CY_SAR_AVG_CNT_64;
772 return CY_RSLT_SUCCESS;
773 case 128:
774 *pdl_count = CY_SAR_AVG_CNT_128;
775 return CY_RSLT_SUCCESS;
776 case 256:
777 *pdl_count = CY_SAR_AVG_CNT_256;
778 return CY_RSLT_SUCCESS;
779 default:
780 return CYHAL_ADC_RSLT_BAD_ARGUMENT;
781 }
782 }
783
_cyhal_adc_get_vref_mv(const cyhal_adc_config_t * hal_config)784 static uint32_t _cyhal_adc_get_vref_mv(const cyhal_adc_config_t* hal_config)
785 {
786 switch(hal_config->vref)
787 {
788 case CYHAL_ADC_REF_INTERNAL:
789 return _CYHAL_ADC_INTERNAL_VREF_MV;
790 case CYHAL_ADC_REF_EXTERNAL:
791 CY_ASSERT(hal_config->ext_vref_mv > 0); // Should have been error checked already
792 return hal_config->ext_vref_mv;
793 case CYHAL_ADC_REF_VDDA_DIV_2:
794 return cyhal_syspm_get_supply_voltage(CYHAL_VOLTAGE_SUPPLY_VDDA) / 2;
795 default:
796 CY_ASSERT(CYHAL_ADC_REF_VDDA == hal_config->vref);
797 return cyhal_syspm_get_supply_voltage(CYHAL_VOLTAGE_SUPPLY_VDDA);
798 }
799 }
800
801 #if defined(CY_IP_M0S8PASS4A_SAR_INSTANCES)
_cyhal_adc_convert_resolution(uint8_t hal_resolution,cy_en_sar_sample_ctrl_sub_resolution_t * pdl_resolution)802 static cy_rslt_t _cyhal_adc_convert_resolution(uint8_t hal_resolution, cy_en_sar_sample_ctrl_sub_resolution_t *pdl_resolution)
803 {
804 switch(hal_resolution)
805 {
806 case 10:
807 *pdl_resolution = CY_SAR_SUB_RESOLUTION_10B;
808 break;
809 case 8:
810 *pdl_resolution = CY_SAR_SUB_RESOLUTION_8B;
811 break;
812 default:
813 return CYHAL_ADC_RSLT_BAD_ARGUMENT;
814 }
815
816 return CY_RSLT_SUCCESS;
817 }
818
_cyhal_adc_extract_channel_conf(cyhal_adc_t * adc,cy_stc_sar_channel_config_t * channel_configs)819 static void _cyhal_adc_extract_channel_conf(cyhal_adc_t* adc, cy_stc_sar_channel_config_t* channel_configs)
820 {
821 for(uint8_t i = 0; i < CY_SAR_SEQ_NUM_CHANNELS; ++i)
822 {
823 channel_configs[i].addr = (cy_en_sar_chan_config_port_pin_addr_t)_FLD2VAL(SAR_CHAN_CONFIG_PIN_ADDR, adc->base->CHAN_CONFIG[i]);
824 channel_configs[i].addr |= (cy_en_sar_chan_config_port_pin_addr_t)_FLD2VAL(SAR_CHAN_CONFIG_PORT_ADDR, adc->base->CHAN_CONFIG[i]);
825
826 channel_configs[i].avgEn = _FLD2BOOL(SAR_CHAN_CONFIG_AVG_EN, adc->base->CHAN_CONFIG[i]);
827 channel_configs[i].sampleTimeSel = (cy_en_sar_channel_sampletime_t)_FLD2VAL(SAR_CHAN_CONFIG_SAMPLE_TIME_SEL, adc->base->CHAN_CONFIG[i]);
828 channel_configs[i].differential = _FLD2BOOL(SAR_CHAN_CONFIG_DIFFERENTIAL_EN, adc->base->CHAN_CONFIG[i]);
829 channel_configs[i].resolution = (cy_en_sar_channel_ctrl_resolution_t)_FLD2VAL(SAR_CHAN_CONFIG_RESOLUTION, adc->base->CHAN_CONFIG[i]);
830 // Range and Saturate interrupt masks have an enable bit per channel
831 channel_configs[i].rangeIntrEn = (0u != (Cy_SAR_GetRangeInterruptMask(adc->base) & 1uL << i));
832 channel_configs[i].satIntrEn = (0u != (Cy_SAR_GetSatInterruptMask(adc->base) & 1uL << i));
833 }
834 }
835
_cyhal_adc_populate_pdl_config(const cyhal_adc_config_t * hal_config,cy_stc_sar_config_t * pdl_config,cy_stc_sar_channel_config_t * channel_configs)836 static cy_rslt_t _cyhal_adc_populate_pdl_config(const cyhal_adc_config_t* hal_config, cy_stc_sar_config_t* pdl_config,
837 cy_stc_sar_channel_config_t* channel_configs /* Array, length CY_SAR_SEQ_NUM_CHANNELS */)
838 {
839 memset(pdl_config, 0, sizeof(cy_stc_sar_config_t));
840
841 cy_rslt_t result = CY_RSLT_SUCCESS;
842 pdl_config->vrefSel = _cyhal_adc_convert_vref(hal_config->vref);
843 pdl_config->vrefBypCapEn = hal_config->is_bypassed;
844 pdl_config->negSel = (hal_config->vneg == CYHAL_ADC_VNEG_VSSA) ? CY_SAR_NEG_SEL_VSSA_KELVIN : CY_SAR_NEG_SEL_VREF;
845 pdl_config->negVref = CY_SAR_NEGVREF_HW;
846 pdl_config->boostPump = true;
847 pdl_config->power = CY_SAR_NORMAL_PWR;
848 pdl_config->sarMuxDsEn = false; // This only enables the routing in deepsleep, not the SAR. And we only use the routing with the SAR
849 pdl_config->switchDisable = false; // We are using the SARSEQ
850 if(hal_config->resolution != _CYHAL_ADC_RESOLUTION)
851 {
852 result = _cyhal_adc_convert_resolution(hal_config->resolution, &pdl_config->subResolution);
853 }
854 if(CY_RSLT_SUCCESS == result)
855 {
856 pdl_config->leftAlign = false;
857 pdl_config->singleEndedSigned = true;
858 pdl_config->differentialSigned = true;
859 pdl_config->avgShift = true;
860 result = _cyhal_adc_convert_average_count(hal_config->average_count, &pdl_config->avgCnt);
861 }
862 if(CY_RSLT_SUCCESS == result)
863 {
864 pdl_config->trigMode = CY_SAR_TRIGGER_MODE_FW_ONLY;
865 pdl_config->eosEn = false;
866 // Will be updated after configuration when we populate sample times after adding channels
867 pdl_config->sampleTime0 = pdl_config->sampleTime1 = pdl_config->sampleTime2 = pdl_config->sampleTime3 = 10u;
868 // Skipping range thresholds because we don't expose the range detect feature.
869 // We always need to populate channel configuration structs here because otherwise the PDL will not
870 // initialize the default gain value that the channels will need when and if we add them later.
871 for(uint8_t i = 0; i < CY_SAR_SEQ_NUM_CHANNELS; ++i)
872 {
873 pdl_config->channelConfig[i] = &channel_configs[i];
874 }
875 // Routing will be configured and channels will be enabled as channels are added
876 pdl_config->vrefMvValue = _cyhal_adc_get_vref_mv(hal_config);
877 }
878 return result;
879 }
880
881 #else /* defined(CY_IP_M0S8PASS4A_SAR_INSTANCES) */
882
_cyhal_adc_convert_average_mode(uint32_t average_mode_flags)883 static uint32_t _cyhal_adc_convert_average_mode(uint32_t average_mode_flags)
884 {
885 uint32_t result = 0;
886 if(0u != (average_mode_flags & CYHAL_ADC_AVG_MODE_ACCUMULATE))
887 {
888 result |= CY_SAR_AVG_MODE_SEQUENTIAL_ACCUM;
889 }
890 else if(0u != (average_mode_flags & CYHAL_ADC_AVG_MODE_INTERLEAVED))
891 {
892 /* INTERLEAVED on its own does not divide the result back down */
893 result |= (CY_SAR_AVG_MODE_INTERLEAVED | SAR_SAMPLE_CTRL_AVG_SHIFT_Msk);
894 }
895 else
896 {
897 result |= CY_SAR_AVG_MODE_SEQUENTIAL_FIXED;
898 }
899 return result;
900 }
901
902 /* Populates the PDL config struct with settings from the ADC config struct */
_cyhal_adc_populate_pdl_config(const cyhal_adc_config_t * hal_config,cy_stc_sar_config_t * pdl_config)903 static cy_rslt_t _cyhal_adc_populate_pdl_config(const cyhal_adc_config_t* hal_config, cy_stc_sar_config_t* pdl_config)
904 {
905 memset(pdl_config, 0, sizeof(cy_stc_sar_config_t));
906 if(hal_config->resolution != _CYHAL_ADC_RESOLUTION) /* SAR does not support configurable resolution */
907 {
908 return CYHAL_ADC_RSLT_BAD_ARGUMENT;
909 }
910
911 if (((hal_config->average_mode_flags & CYHAL_ADC_AVG_MODE_ACCUMULATE) > 0) &&
912 ((hal_config->average_mode_flags & CYHAL_ADC_AVG_MODE_INTERLEAVED) > 0))
913 {
914 /* Accumulate mode is not compatible with interleaved averaging */
915 return CYHAL_ADC_RSLT_BAD_ARGUMENT;
916 }
917
918 *pdl_config = _CYHAL_ADC_DEFAULT_PDL_CONFIG;
919 uint32_t ctrl = _CYHAL_ADC_DEFAULT_CTRL;
920 ctrl |= (uint32_t)_cyhal_adc_convert_vref(hal_config->vref);
921 ctrl |= (hal_config->is_bypassed) ? CY_SAR_BYPASS_CAP_ENABLE : CY_SAR_BYPASS_CAP_DISABLE;
922 ctrl |= (hal_config->vneg == CYHAL_ADC_VNEG_VSSA) ? CY_SAR_NEG_SEL_VSSA_KELVIN : CY_SAR_NEG_SEL_VREF;
923
924 uint32_t sample_ctrl = _CYHAL_ADC_DEFAULT_SAMPLE;
925 cy_en_sar_sample_ctrl_avg_cnt_t pdl_avg;
926 cy_rslt_t result = _cyhal_adc_convert_average_count(hal_config->average_count, &pdl_avg);
927 if(CY_RSLT_SUCCESS == result)
928 {
929 sample_ctrl |= (uint32_t)pdl_avg;
930 sample_ctrl |= _cyhal_adc_convert_average_mode(hal_config->average_mode_flags);
931
932 pdl_config->ctrl = ctrl;
933 pdl_config->sampleCtrl = sample_ctrl;
934 pdl_config->vrefMvValue = _cyhal_adc_get_vref_mv(hal_config);
935 }
936 return result;
937 }
938 #endif /* defined(CY_IP_M0S8PASS4A_SAR_INSTANCES) */
_cyhal_adc_counts_to_uvolts(cyhal_adc_t * obj,uint8_t channel,int32_t counts)939 static int32_t _cyhal_adc_counts_to_uvolts(cyhal_adc_t* obj, uint8_t channel, int32_t counts)
940 {
941 return Cy_SAR_CountsTo_uVolts(obj->base, channel, counts);
942 }
943 #endif /* defined(CY_IP_MXS40EPASS_ESAR_INSTANCES) */
944
_cyhal_adc_start_convert(cyhal_adc_t * obj)945 static void _cyhal_adc_start_convert(cyhal_adc_t* obj)
946 {
947 #if defined(CY_IP_MXS40EPASS_ESAR_INSTANCES)
948 /* Continuous vs. single-shot is handled via the trigger configuration */
949 Cy_SAR2_Channel_SoftwareTrigger(obj->base, _cyhal_adc_first_enabled(obj));
950 #else
951 Cy_SAR_StartConvert(obj->base, obj->continuous_scanning ? CY_SAR_START_CONVERT_CONTINUOUS : CY_SAR_START_CONVERT_SINGLE_SHOT);
952 #endif
953 }
_cyhal_adc_irq_handler(void)954 static void _cyhal_adc_irq_handler(void)
955 {
956 /* The only enabled event is scan finished */
957 cyhal_adc_event_t hal_event = CYHAL_ADC_EOS;
958
959 _cyhal_system_irq_t irqn = _cyhal_irq_get_active();
960 uint8_t block = _cyhal_adc_get_block_from_irqn(irqn);
961 cyhal_adc_t* obj = _cyhal_adc_config_structs[block];
962 #if defined(CY_IP_MXS40EPASS_ESAR_INSTANCES)
963 uint8_t channel_idx = _cyhal_adc_last_enabled(obj);
964 Cy_SAR2_Channel_ClearInterrupt(obj->base, channel_idx, CY_SAR2_INT_GRP_DONE);
965 #else
966 Cy_SAR_ClearInterrupt(obj->base, CY_SAR_INTR_EOS);
967 #endif
968 obj->conversion_complete = true;
969 #if !defined(CY_IP_MXS40EPASS_ESAR_INSTANCES)
970 if(obj->stop_after_scan)
971 {
972 Cy_SAR_StopConvert(obj->base);
973 }
974 #endif
975
976 if(obj->async_scans_remaining > 0)
977 {
978 uint8_t num_channels = _cyhal_adc_max_configured_channel(obj) + 1;
979 /* Can't read millivolts out via DMA */
980 if(CYHAL_ASYNC_SW == obj->async_mode || obj->async_transfer_in_uv)
981 {
982 for(uint8_t i = 0; i < num_channels; ++i)
983 {
984 int32_t counts = 0;
985 #if defined(CY_IP_MXS40EPASS_ESAR_INSTANCES)
986 if (_CYHAL_ADC_VBG_CHANNEL_IDX == i)
987 {
988 obj->vbg_last_value = Cy_SAR2_Channel_GetResult(obj->base, _CYHAL_ADC_VBG_CHANNEL_IDX, NULL);
989 continue;
990 }
991 else
992 {
993 counts = Cy_SAR2_Channel_GetResult(obj->base, i, NULL);
994 }
995 #else
996 counts = Cy_SAR_GetResult32(obj->base, i);
997 #endif
998 *obj->async_buff_next = obj->async_transfer_in_uv ? _cyhal_adc_counts_to_uvolts(obj, i, counts) : counts;
999 ++obj->async_buff_next;
1000 }
1001 --(obj->async_scans_remaining);
1002 if(0 == obj->async_scans_remaining)
1003 {
1004 obj->async_buff_next = obj->async_buff_orig = NULL;
1005 hal_event |= CYHAL_ADC_ASYNC_READ_COMPLETE;
1006 }
1007 else if(false == obj->continuous_scanning)
1008 {
1009 _cyhal_adc_start_convert(obj);
1010 }
1011 /* If we're continously scanning, another scan will be kicked off automatically
1012 * so we don't need to do anything */
1013 }
1014 else
1015 {
1016 CY_ASSERT(CYHAL_ASYNC_DMA == obj->async_mode);
1017
1018 #if _CYHAL_ADC_DMA_SUPPORTED
1019 cyhal_dma_cfg_t dma_config =
1020 {
1021 .src_addr = (uint32_t)obj->base->CHAN_RESULT,
1022 .src_increment = 1u,
1023 .dst_addr = (uint32_t)obj->async_buff_next,
1024 .dst_increment = 1u,
1025 .transfer_width = 32u,
1026 .length = num_channels,
1027 .burst_size = 0u,
1028 .action = CYHAL_DMA_TRANSFER_FULL
1029 };
1030
1031 // Configure needs to happen after we've manipulated the descriptor config
1032 cy_rslt_t result = cyhal_dma_configure(&(obj->dma), &dma_config);
1033 if(CY_RSLT_SUCCESS == result)
1034 {
1035 result = cyhal_dma_enable(&(obj->dma));
1036 }
1037 if(CY_RSLT_SUCCESS == result)
1038 {
1039 result = cyhal_dma_start_transfer(&(obj->dma));
1040 }
1041 CY_ASSERT(CY_RSLT_SUCCESS == result);
1042
1043 /* Don't increment the buffer here - do that when the DMA completes */
1044 if(false == obj->continuous_scanning)
1045 {
1046 _cyhal_adc_start_convert(obj);
1047 }
1048 #else
1049 CY_ASSERT(false); // DMA not supported on the current device
1050 #endif //_CYHAL_ADC_DMA_SUPPORTED
1051 }
1052 }
1053
1054 _cyhal_adc_update_intr_mask(obj);
1055
1056 if(0 != (hal_event & ((cyhal_adc_event_t)obj->user_enabled_events)))
1057 {
1058 cyhal_adc_event_callback_t callback = (cyhal_adc_event_callback_t)obj->callback_data.callback;
1059 if(NULL != callback)
1060 {
1061 callback(obj->callback_data.callback_arg, (cyhal_adc_event_t)(hal_event & obj->user_enabled_events));
1062 }
1063 }
1064
1065 }
1066
1067 #if _CYHAL_ADC_DMA_SUPPORTED
_cyhal_adc_dma_handler(void * arg,cyhal_dma_event_t event)1068 static void _cyhal_adc_dma_handler(void* arg, cyhal_dma_event_t event)
1069 {
1070 CY_ASSERT(CYHAL_DMA_TRANSFER_COMPLETE == event);
1071 CY_UNUSED_PARAMETER(event);
1072 cyhal_adc_t* obj = (cyhal_adc_t*)arg;
1073 CY_ASSERT(CYHAL_ASYNC_DMA == obj->async_mode);
1074
1075 uint8_t num_channels = _cyhal_adc_max_configured_channel(obj) + 1;
1076 CY_ASSERT(false == obj->async_transfer_in_uv);
1077 obj->async_buff_next += num_channels;
1078 --(obj->async_scans_remaining);
1079 _cyhal_adc_update_intr_mask(obj);
1080
1081 if(0 == obj->async_scans_remaining)
1082 {
1083 // DMA doesn't sign extend when we copy from 16 to 32 bits, so do the sign extension
1084 // ourselves once all channel scans are complete.
1085 while(obj->async_buff_orig != obj->async_buff_next)
1086 {
1087 // Mask off the upper two bytes because those contain mirrored status bits which
1088 // are not part of the ADC counts
1089 int16_t sar_result = (int16_t)(0xFFFF & *(obj->async_buff_orig));
1090 *(obj->async_buff_orig) = sar_result;
1091 ++(obj->async_buff_orig);
1092 }
1093 obj->async_buff_next = obj->async_buff_orig = NULL;
1094 if(0 != (CYHAL_ADC_ASYNC_READ_COMPLETE & ((cyhal_adc_event_t)obj->user_enabled_events)))
1095 {
1096 cyhal_adc_event_callback_t callback = (cyhal_adc_event_callback_t)obj->callback_data.callback;
1097 if(NULL != callback)
1098 {
1099 callback(obj->callback_data.callback_arg, CYHAL_ADC_ASYNC_READ_COMPLETE);
1100 }
1101 }
1102 }
1103 }
1104 #endif
1105
1106 /*******************************************************************************
1107 * ADC HAL Functions
1108 *******************************************************************************/
1109
_cyhal_adc_config_hw(cyhal_adc_t * obj,const cyhal_adc_configurator_t * cfg,cyhal_gpio_t pin,bool owned_by_configurator)1110 cy_rslt_t _cyhal_adc_config_hw(cyhal_adc_t *obj, const cyhal_adc_configurator_t* cfg, cyhal_gpio_t pin, bool owned_by_configurator)
1111 {
1112 const uint32_t DESIRED_DIVIDER = 8000000u; // 8 MHz. Required range is 1.7 - 18
1113
1114 CY_ASSERT(NULL != obj);
1115
1116 cy_rslt_t result = CY_RSLT_SUCCESS;
1117
1118 memset(obj, 0, sizeof(cyhal_adc_t));
1119 obj->clock.reserved = false;
1120 obj->resource.type = CYHAL_RSC_INVALID;
1121 obj->async_mode = CYHAL_ASYNC_SW;
1122 obj->source = CYHAL_TRIGGER_CPUSS_ZERO;
1123 #if defined(CY_IP_M0S8PASS4A_SAR_INSTANCES)
1124 obj->resolution = _CYHAL_ADC_RESOLUTION;
1125 obj->ext_vref = NC;
1126 obj->bypass_pin = NC;
1127 #endif
1128
1129 obj->owned_by_configurator = owned_by_configurator;
1130
1131 if(NULL == cfg->resource && (NC != pin))
1132 {
1133 const cyhal_resource_pin_mapping_t* map = _CYHAL_UTILS_TRY_ALLOC(pin, CYHAL_RSC_ADC, cyhal_pin_map_pass_sarmux_pads);
1134
1135 if (NULL == map)
1136 {
1137 result = CYHAL_ADC_RSLT_BAD_ARGUMENT;
1138 }
1139 else
1140 {
1141 /* No need to reserve - try_alloc did so for us already */
1142 obj->resource.type = CYHAL_RSC_ADC;
1143 obj->resource.block_num = map->block_num;
1144 obj->resource.channel_num = 0; // Force channel to 0, since we don't use channels and the sarmux_pads overload that item
1145 }
1146 }
1147 else if(NULL != cfg->resource)
1148 {
1149 obj->resource = *cfg->resource;
1150 }
1151 else
1152 {
1153 result = CYHAL_ADC_RSLT_BAD_ARGUMENT;
1154 }
1155
1156 en_clk_dst_t pclk = (en_clk_dst_t)0;
1157 if (CY_RSLT_SUCCESS == result)
1158 {
1159 obj->base = _cyhal_adc_base[obj->resource.block_num];
1160 pclk = _cyhal_adc_clock[obj->resource.block_num];
1161 if (NULL != cfg->clock)
1162 {
1163 obj->clock = *cfg->clock;
1164 obj->dedicated_clock = false;
1165 }
1166 else if (CY_RSLT_SUCCESS ==
1167 (result = _cyhal_utils_allocate_clock(&(obj->clock), &(obj->resource), CYHAL_CLOCK_BLOCK_PERIPHERAL_16BIT, true)))
1168 {
1169 obj->dedicated_clock = true;
1170 }
1171 }
1172
1173 if (CY_RSLT_SUCCESS == result)
1174 {
1175 if (CY_SYSCLK_SUCCESS != _cyhal_utils_peri_pclk_assign_divider(pclk, &(obj->clock)))
1176 result = CYHAL_ADC_RSLT_FAILED_CLOCK;
1177 }
1178
1179 if (CY_RSLT_SUCCESS == result)
1180 {
1181 if(obj->dedicated_clock)
1182 {
1183 uint32_t source_hz = _cyhal_utils_get_peripheral_clock_frequency(&(obj->resource));
1184 uint32_t div = source_hz / DESIRED_DIVIDER;
1185 if (0 == div ||
1186 (CY_SYSCLK_SUCCESS != _cyhal_utils_peri_pclk_set_divider(pclk, &(obj->clock), div - 1)) ||
1187 (CY_SYSCLK_SUCCESS != _cyhal_utils_peri_pclk_enable_divider(pclk, &(obj->clock))))
1188 {
1189 result = CYHAL_ADC_RSLT_FAILED_CLOCK;
1190 }
1191 }
1192 }
1193
1194 if (result == CY_RSLT_SUCCESS)
1195 {
1196 #if defined(CY_IP_MXS40EPASS_ESAR)
1197 result = (cy_rslt_t)Cy_SAR2_Init(obj->base, cfg->config);
1198 Cy_SAR2_SetReferenceBufferMode(PASS0_EPASS_MMIO, CY_SAR2_REF_BUF_MODE_ON);
1199 #else
1200 result = (cy_rslt_t)Cy_SAR_Init(obj->base, cfg->config);
1201 #endif
1202 }
1203
1204 if (result == CY_RSLT_SUCCESS)
1205 {
1206 #if !defined(CY_IP_MXS40EPASS_ESAR)
1207 Cy_SAR_SetVssaSarSeqCtrl(obj->base, _CYHAL_ADC_SARSEQ_STATE(true));
1208 Cy_SAR_SetVssaVminusSwitch(obj->base, _CYHAL_ADC_SWITCH_STATE(true));
1209 #endif
1210
1211 _cyhal_analog_init();
1212
1213 _cyhal_adc_update_intr_mask(obj);
1214 _cyhal_adc_config_structs[obj->resource.block_num] = obj;
1215 #if defined(CY_IP_MXS40EPASS_ESAR)
1216 /* Register every channel to the same handler; only the current last one in the group will fire
1217 * but this avoids us having to unregister and reregister interrupts every time we enable/disable a channel */
1218 for(uint8_t i = 0; i < CY_SAR_MAX_NUM_CHANNELS; ++i)
1219 {
1220 _cyhal_irq_register(_cyhal_adc_calc_channel_irq(obj->resource.block_num, i),
1221 CYHAL_ISR_PRIORITY_DEFAULT, _cyhal_adc_irq_handler);
1222 _cyhal_irq_enable(_cyhal_adc_calc_channel_irq(obj->resource.block_num, i));
1223 }
1224
1225 Cy_SAR2_Enable(obj->base);
1226 #else
1227 _cyhal_irq_register(_cyhal_adc_irq_n[obj->resource.block_num], CYHAL_ISR_PRIORITY_DEFAULT, _cyhal_adc_irq_handler);
1228 _cyhal_irq_enable(_cyhal_adc_irq_n[obj->resource.block_num]);
1229 Cy_SAR_Enable(obj->base);
1230 #endif
1231 }
1232 else
1233 {
1234 cyhal_adc_free(obj);
1235 }
1236 return result;
1237 }
1238
cyhal_adc_init_cfg(cyhal_adc_t * adc,cyhal_adc_channel_t ** channels,uint8_t * num_channels,const cyhal_adc_configurator_t * cfg)1239 cy_rslt_t cyhal_adc_init_cfg(cyhal_adc_t *adc, cyhal_adc_channel_t** channels, uint8_t* num_channels,
1240 const cyhal_adc_configurator_t *cfg)
1241 {
1242 cy_rslt_t result = CY_RSLT_SUCCESS;
1243 if(*num_channels < cfg->num_channels)
1244 {
1245 result = CYHAL_ADC_RSLT_BAD_ARGUMENT;
1246 }
1247
1248 if(CY_RSLT_SUCCESS == result)
1249 {
1250 *num_channels = cfg->num_channels;
1251 result = _cyhal_adc_config_hw(adc, cfg, NC, true);
1252 }
1253
1254 if(CY_RSLT_SUCCESS == result)
1255 {
1256 /* config_hw will have initialized the channels in the ADC HW and the configurator will
1257 * have set up the routing, but we need to initialize the channel structs */
1258 for(int i = 0; i < *num_channels; ++i)
1259 {
1260 cyhal_adc_channel_t* channel = channels[i];
1261 memset(channel, 0, sizeof(cyhal_adc_channel_t));
1262 channel->adc = adc;
1263 channel->channel_idx = i;
1264 /* Nothing in this flow needs to know what the pins are - and the inputs aren't even
1265 * necesssarily pins. The configurator takes care of resource reservation and routing for us */
1266 channel->vplus = NC;
1267 #if !defined(CY_IP_MXS40EPASS_ESAR_INSTANCES)
1268 channel->vminus = NC;
1269 #endif
1270 /* The configurator takes care of initial solving, but store this so that we behave properly
1271 * if the user changes any of the configuration at runtime */
1272 channel->minimum_acquisition_ns = cfg->achieved_acquisition_time[i];
1273 }
1274 }
1275 return result;
1276 }
1277
cyhal_adc_init(cyhal_adc_t * obj,cyhal_gpio_t pin,const cyhal_clock_t * clk)1278 cy_rslt_t cyhal_adc_init(cyhal_adc_t *obj, cyhal_gpio_t pin, const cyhal_clock_t *clk)
1279 {
1280 cy_rslt_t result = CY_RSLT_SUCCESS;
1281 #if !defined(CY_IP_MXS40EPASS_ESAR_INSTANCES)
1282 /* On EPASS, there are no non-default values that we need to set on the ADC-wide PDL config */
1283 cy_stc_sar_config_t pdl_config;
1284
1285 #if defined(CY_IP_M0S8PASS4A_INSTANCES)
1286 cy_stc_sar_channel_config_t chan_configs[CY_SAR_SEQ_NUM_CHANNELS];
1287 memset(chan_configs, 0, sizeof(chan_configs));
1288 // No channels have actually been configured yet, so an empty set of config structs is fine here
1289 result = _cyhal_adc_populate_pdl_config(&_CYHAL_ADC_DEFAULT_CONFIG, &pdl_config, chan_configs);
1290 #else
1291 result = _cyhal_adc_populate_pdl_config(&_CYHAL_ADC_DEFAULT_CONFIG, &pdl_config);
1292 #endif
1293 #endif
1294
1295 if (CY_RSLT_SUCCESS == result)
1296 {
1297 cyhal_adc_configurator_t config;
1298 config.resource = NULL;
1299 #if defined(CY_IP_MXS40EPASS_ESAR_INSTANCES)
1300 config.config = &_CYHAL_ADC_DEFAULT_PDL_CONFIG;
1301 #else
1302 config.config = &pdl_config;
1303 #endif
1304 config.clock = clk;
1305 config.num_channels = 0u;
1306
1307 result = _cyhal_adc_config_hw(obj, &config, pin, false);
1308 }
1309 #if defined(CY_IP_MXS40EPASS_ESAR_INSTANCES)
1310 /* Some of the default configuration options are per-channel in the hardware and therefore
1311 * need to be stored on the hal object, call into configure() to take care of that */
1312 if(CY_RSLT_SUCCESS == result)
1313 {
1314 result = cyhal_adc_configure(obj, &_CYHAL_ADC_DEFAULT_CONFIG);
1315 }
1316 if (CY_RSLT_SUCCESS == result)
1317 {
1318 obj->vbg_chan_inited = false;
1319 }
1320 #endif
1321 return result;
1322 }
1323
cyhal_adc_free(cyhal_adc_t * obj)1324 void cyhal_adc_free(cyhal_adc_t *obj)
1325 {
1326 if (NULL != obj && NULL != obj->base)
1327 {
1328 #if defined(CY_IP_MXS40EPASS_ESAR)
1329 for(uint8_t i = 0; i < CY_SAR_MAX_NUM_CHANNELS; ++i)
1330 {
1331 _cyhal_irq_free(_cyhal_adc_calc_channel_irq(obj->resource.block_num, i));
1332 }
1333 #else
1334 _cyhal_system_irq_t irqn = _cyhal_adc_irq_n[obj->resource.block_num];
1335 _cyhal_irq_free(irqn);
1336 #endif
1337 _cyhal_adc_config_structs[obj->resource.block_num] = NULL;
1338
1339 cy_rslt_t rslt;
1340 rslt = cyhal_adc_disable_output(obj, CYHAL_ADC_OUTPUT_SCAN_COMPLETE);
1341 CY_ASSERT(CY_RSLT_SUCCESS == rslt);
1342 if (CYHAL_TRIGGER_CPUSS_ZERO != obj->source)
1343 {
1344 rslt = cyhal_adc_disconnect_digital(obj, obj->source, CYHAL_ADC_INPUT_START_SCAN);
1345 CY_ASSERT(CY_RSLT_SUCCESS == rslt);
1346 }
1347 (void)rslt; // Disable compiler warning in release build
1348
1349 #if !defined(CY_IP_MXS40EPASS_ESAR)
1350 Cy_SAR_SetVssaSarSeqCtrl(obj->base, _CYHAL_ADC_SARSEQ_STATE(false));
1351 Cy_SAR_SetVssaVminusSwitch(obj->base, _CYHAL_ADC_SWITCH_STATE(false));
1352
1353 Cy_SAR_StopConvert(obj->base);
1354 #endif
1355
1356 if(false == obj->owned_by_configurator)
1357 {
1358 #if !defined(CY_IP_MXS40EPASS_ESAR)
1359 Cy_SAR_Disable(obj->base);
1360 #else
1361 Cy_SAR2_Disable(obj->base);
1362 #endif
1363
1364 if(obj->dedicated_clock)
1365 {
1366 _cyhal_utils_peri_pclk_disable_divider(_cyhal_adc_clock[obj->resource.block_num], &(obj->clock));
1367 cyhal_clock_free(&obj->clock);
1368 }
1369
1370 _cyhal_analog_free();
1371 #if defined(CY_IP_M0S8PASS4A_SAR_INSTANCES)
1372 _cyhal_utils_release_if_used(&(obj->ext_vref));
1373 _cyhal_utils_release_if_used(&(obj->bypass_pin));
1374 #endif
1375 cyhal_hwmgr_free(&obj->resource);
1376 }
1377 obj->base = NULL;
1378 }
1379 }
1380
1381 #if defined(CY_IP_MXS40EPASS_ESAR)
_cyhal_adc_populate_acquisition_timers(cyhal_adc_t * obj)1382 cy_rslt_t _cyhal_adc_populate_acquisition_timers(cyhal_adc_t* obj)
1383 {
1384 /* EPASS has dedicated acquisition timer per channel. To avoid
1385 * having to ifdef the numerous callsiteas, implement this as a no-op */
1386 CY_UNUSED_PARAMETER(obj);
1387 return CY_RSLT_SUCCESS;
1388 }
1389
_cyhal_adc_apply_channel_configs(cyhal_adc_t * obj,cy_stc_sar2_channel_config_t * channel_configs)1390 cy_rslt_t _cyhal_adc_apply_channel_configs(cyhal_adc_t* obj, cy_stc_sar2_channel_config_t* channel_configs)
1391 {
1392 cy_rslt_t result = CY_RSLT_SUCCESS;
1393 uint32_t clock_frequency_hz = cyhal_clock_get_frequency(&(obj->clock));
1394 uint32_t clock_period_ns = (clock_frequency_hz > 0u)
1395 ? (_CYHAL_UTILS_NS_PER_SECOND / clock_frequency_hz)
1396 : 0u;
1397
1398 if (0u == clock_period_ns)
1399 {
1400 CY_ASSERT(false);
1401 result = CYHAL_ADC_RSLT_BAD_ARGUMENT;
1402 }
1403 else
1404 {
1405 bool found_enabled = false;
1406 uint8_t last_enabled = 0u;
1407 for(size_t i = 0; i < CY_SAR_MAX_NUM_CHANNELS; ++i)
1408 {
1409 Cy_SAR2_Channel_DeInit(obj->base, i);
1410 if (channel_configs[i].channelHwEnable)
1411 {
1412 last_enabled = i;
1413 if(false == found_enabled) /* Set trigger on the start of the group */
1414 {
1415 found_enabled = true;
1416 channel_configs[i].triggerSelection = obj->continuous_scanning ?
1417 CY_SAR2_TRIGGER_CONTINUOUS : CY_SAR2_TRIGGER_GENERIC0;
1418 }
1419
1420 if(obj->channel_config[i]->avg_enabled)
1421 {
1422 /* Value stored is 1 less than the desired count, but decrement is done by Cy_SAR2_Channel_Init */
1423 channel_configs[i].averageCount = obj->average_count;
1424 /* postProcessingMode=AVG triggers the repeated acquisition of samples.
1425 * The difference between accumulate and average is whether we do a right shift afterwards
1426 */
1427 uint8_t rightShift;
1428 channel_configs[i].postProcessingMode = CY_SAR2_POST_PROCESSING_MODE_AVG;
1429 if(obj->average_is_accumulate)
1430 {
1431 rightShift = 0u;
1432 }
1433 else
1434 {
1435 for(rightShift = 31u; (0u == (obj->average_count & 1u << rightShift)); --rightShift) { }
1436 }
1437 channel_configs[i].rightShift = rightShift;
1438 }
1439 else
1440 {
1441 channel_configs[i].averageCount = 0u;
1442 channel_configs[i].postProcessingMode = CY_SAR2_POST_PROCESSING_MODE_NONE;
1443 channel_configs[i].rightShift = 0u;
1444 }
1445
1446 uint16_t sample_clock_cycles =
1447 (uint16_t)((obj->channel_config[i]->minimum_acquisition_ns + (clock_period_ns - 1)) / clock_period_ns);
1448 channel_configs[i].sampleTime = sample_clock_cycles;
1449 }
1450 channel_configs[i].isGroupEnd = false;
1451 channel_configs[i].interruptMask = 0u;
1452 }
1453
1454 channel_configs[last_enabled].isGroupEnd = true;
1455 channel_configs[last_enabled].interruptMask = CY_SAR2_INT_GRP_DONE;
1456
1457 /* We need to do a 2 pass because we don't know what channel is at the end until
1458 * we've gone past it */
1459 for(size_t i = 0; i < CY_SAR_MAX_NUM_CHANNELS; ++i)
1460 {
1461 cy_rslt_t result2 = Cy_SAR2_Channel_Init(obj->base, i, &channel_configs[i]);
1462 if(CY_RSLT_SUCCESS == result)
1463 {
1464 result = result2;
1465 }
1466 }
1467
1468 if(CY_RSLT_SUCCESS == result)
1469 {
1470 /* We only support one trigger output per ADC instance, so by convention we always drive trigger 0 */
1471 result = Cy_SAR2_SetGenericTriggerOutput(PASS0_EPASS_MMIO, obj->resource.block_num, 0u, last_enabled);
1472 }
1473 }
1474
1475 return result;
1476 }
1477
_cyhal_adc_channel_update_config(cyhal_adc_channel_t * obj,cy_stc_sar2_channel_config_t * pdl_cfg,const cyhal_adc_channel_config_t * cfg)1478 void _cyhal_adc_channel_update_config(cyhal_adc_channel_t* obj, cy_stc_sar2_channel_config_t *pdl_cfg, const cyhal_adc_channel_config_t *cfg)
1479 {
1480 /* We're just applying the HAL configuration provided. The PDL config could already have values that
1481 * aren't derived from cyhal_adc_channel_config_t, especially if we're updating an existing channel,
1482 * so omit the customary memset to 0 step */
1483 pdl_cfg->channelHwEnable = cfg->enabled;
1484 /* There's no hardware field to explicitly enable/disable averaging for a channel, you just set an average count
1485 * of 1 if you don't want to average a channel. Because the HAL also allows the average count to be globally
1486 * set to 1 to disable averaging on all channels, we need to separately keep track of whether this particular
1487 * channel is supposed to be subject to averaging when it is enabled in general. */
1488 obj->avg_enabled = cfg->enable_averaging;
1489 /* Here we only update "primary" data sources that aren't derived from anything other than the
1490 * cyhal_adc_channel_config_t. We don't set anything that can be derived from the channel pdl config
1491 * combined with the ADC config; that is taken care of in _cyhal_adc_apply_channel_configs */
1492 }
1493
1494 #else
_cyhal_adc_populate_acquisition_timers(cyhal_adc_t * obj)1495 cy_rslt_t _cyhal_adc_populate_acquisition_timers(cyhal_adc_t* obj)
1496 {
1497 const uint32_t ACQUISITION_CLOCKS_MIN = 2;
1498 const uint32_t ACQUISITION_CLOCKS_MAX = 1023;
1499
1500 cy_rslt_t result = CY_RSLT_SUCCESS;
1501
1502 uint32_t clock_frequency_hz = cyhal_clock_get_frequency(&(obj->clock));
1503 uint32_t clock_period_ns = (clock_frequency_hz > 0)
1504 ? (_CYHAL_UTILS_NS_PER_SECOND / clock_frequency_hz)
1505 : 0;
1506 uint16_t sample_timer_ns[] = { 0u, 0u, 0u, 0u };
1507 uint8_t assigned_timer[CY_SAR_SEQ_NUM_CHANNELS];
1508 if (clock_period_ns == 0)
1509 {
1510 result = CYHAL_ADC_RSLT_FAILED_CLOCK;
1511 }
1512 if (result == CY_RSLT_SUCCESS)
1513 {
1514 for(uint8_t channel = 0; channel < CY_SAR_SEQ_NUM_CHANNELS; ++channel)
1515 {
1516 cyhal_adc_channel_t* chan_config = obj->channel_config[channel];
1517 assigned_timer[channel] = 0u;
1518 /* If the channel isn't in use, what we select doesn't matter */
1519 if(NULL != chan_config)
1520 {
1521 bool found = false;
1522 for(uint8_t timer = 0; !found && timer < sizeof(sample_timer_ns) / sizeof(sample_timer_ns[0]); ++timer)
1523 {
1524 if(chan_config->minimum_acquisition_ns == sample_timer_ns[timer])
1525 {
1526 /* Matched a pre-existing timer; use that */
1527 assigned_timer[channel] = timer;
1528 found = true;
1529 }
1530 else if(0 == sample_timer_ns[timer])
1531 {
1532 /* Found a free timer - allocate and use that */
1533 sample_timer_ns[timer] = chan_config->minimum_acquisition_ns;
1534 assigned_timer[channel] = timer;
1535 found = true;
1536 }
1537 }
1538
1539 if(false == found)
1540 {
1541 /* Ran out of acquisition timers */
1542 result = CYHAL_ADC_RSLT_BAD_ARGUMENT;
1543 }
1544 }
1545 }
1546 }
1547
1548 if(CY_RSLT_SUCCESS == result)
1549 {
1550 uint16_t sample_timer_clocks[sizeof(sample_timer_ns) / sizeof(sample_timer_ns[0])];
1551 for(uint8_t i = 0; i < sizeof(sample_timer_clocks) / sizeof(sample_timer_clocks[0]); ++i)
1552 {
1553 /* Convert from nanoseconds to clock cycles, rounding up */
1554 uint32_t clock_cycles = (sample_timer_ns[i] + (clock_period_ns - 1)) / clock_period_ns;
1555 if(clock_cycles < ACQUISITION_CLOCKS_MIN)
1556 {
1557 clock_cycles = ACQUISITION_CLOCKS_MIN;
1558 }
1559 else if(clock_cycles > ACQUISITION_CLOCKS_MAX)
1560 {
1561 clock_cycles = ACQUISITION_CLOCKS_MAX;
1562 }
1563 /* Per the register map, this should be one greater than the actual desired sampling cycle count */
1564 sample_timer_clocks[i] = clock_cycles + 1;
1565 }
1566
1567 obj->base->SAMPLE_TIME01 = (uint32_t) (((uint32_t)sample_timer_clocks[0] << SAR_SAMPLE_TIME01_SAMPLE_TIME0_Pos)
1568 | ((uint32_t)sample_timer_clocks[1] << SAR_SAMPLE_TIME01_SAMPLE_TIME1_Pos));
1569 obj->base->SAMPLE_TIME23 = (uint32_t) (((uint32_t)sample_timer_clocks[2] << SAR_SAMPLE_TIME23_SAMPLE_TIME2_Pos)
1570 | ((uint32_t)sample_timer_clocks[3] << SAR_SAMPLE_TIME23_SAMPLE_TIME3_Pos));
1571
1572 for(uint8_t i = 0; i < CY_SAR_SEQ_NUM_CHANNELS; ++i)
1573 {
1574 obj->base->CHAN_CONFIG[i] &= ~SAR_CHAN_CONFIG_SAMPLE_TIME_SEL_Msk;
1575 obj->base->CHAN_CONFIG[i] |= (uint32_t)assigned_timer[i] << SAR_CHAN_CONFIG_SAMPLE_TIME_SEL_Pos;
1576 }
1577 }
1578
1579 return result;
1580 }
1581 #endif
1582
cyhal_adc_configure(cyhal_adc_t * obj,const cyhal_adc_config_t * config)1583 cy_rslt_t cyhal_adc_configure(cyhal_adc_t *obj, const cyhal_adc_config_t *config)
1584 {
1585 cy_rslt_t result = CY_RSLT_SUCCESS;
1586 obj->continuous_scanning = config->continuous_scanning;
1587
1588 #if defined(CY_IP_MXS40EPASS_ESAR)
1589 /* No external bypass or external vref option available */
1590 if (config->is_bypassed
1591 || CYHAL_ADC_REF_INTERNAL != config->vref
1592 || CYHAL_ADC_VNEG_VSSA != config->vneg
1593 || config->average_count < 1u
1594 || config->average_count > (UINT8_MAX + 1)) /* 8-bit field stores (desired_count - 1) */
1595 {
1596 /* No need to check here that the other vref/bypass related parameters are consistent with these
1597 * selections, there are already checks further down that do that */
1598 result = CYHAL_ADC_RSLT_BAD_ARGUMENT;
1599 }
1600
1601 /* Even though average count can technically be any value between 1 and 256, when we're operating in "true"
1602 * average mode (i.e. not accumulate) we're limited to powers of 2 because those are the only division
1603 * ratios that can be achieved through the "shiftRight" functionality.
1604 */
1605
1606 obj->average_is_accumulate = (0u != (config->average_mode_flags & CYHAL_ADC_AVG_MODE_ACCUMULATE));
1607 if(false == obj->average_is_accumulate)
1608 {
1609 bool saw_one = false;
1610 for(uint8_t i = 0; i < 16u; ++i)
1611 {
1612 if(0u != (config->average_count & (1u << i)))
1613 {
1614 if(saw_one) /* Two bits set, not a power of 2 */
1615 {
1616 result = CYHAL_ADC_RSLT_BAD_ARGUMENT;
1617 break;
1618 }
1619 saw_one = true;
1620 }
1621 }
1622 }
1623 #endif
1624 #if defined(CYHAL_PIN_MAP_DRIVE_MODE_PASS_SAR_EXT_VREF0)
1625 if(NC != config->ext_vref)
1626 {
1627 // If this pin wasn't used in the previous config for either vref or bypass, reserve it
1628 if((NC == obj->ext_vref) && (config->ext_vref != obj->bypass_pin))
1629 {
1630 const cyhal_resource_pin_mapping_t* ext_vref_map =
1631 _cyhal_utils_get_resource(config->ext_vref, cyhal_pin_map_pass_sar_ext_vref0,
1632 sizeof(cyhal_pin_map_pass_sar_ext_vref0)/sizeof(cyhal_pin_map_pass_sar_ext_vref0[0]), &(obj->resource),
1633 false);
1634
1635 if (NULL == ext_vref_map)
1636 {
1637 result = CYHAL_ADC_RSLT_BAD_ARGUMENT;
1638 }
1639 else
1640 {
1641 result = _cyhal_utils_reserve_and_connect(ext_vref_map, CYHAL_PIN_MAP_DRIVE_MODE_PASS_SAR_EXT_VREF0);
1642 }
1643
1644 if(CY_RSLT_SUCCESS == result)
1645 {
1646 obj->ext_vref = config->ext_vref;
1647 }
1648 }
1649 }
1650 else
1651 {
1652 if(NC != obj->ext_vref) // We used to have an external vref pin - free it
1653 {
1654 // If the same pin was used as bypass, mark it freed now too
1655 if(obj->ext_vref == obj->bypass_pin)
1656 {
1657 obj->bypass_pin = NC;
1658 }
1659 // It is okay to do this without checking if the pin is still used for bypass,
1660 // because in that case we will just re-reserve the pin below
1661 cyhal_gpio_free(obj->ext_vref);
1662 obj->ext_vref = NC;
1663 }
1664
1665 // If external vref exists as a GPIO, it's an error to set vref to external without passing in the pin
1666 if(CYHAL_ADC_REF_EXTERNAL == config->vref)
1667 {
1668 result = CYHAL_ADC_RSLT_BAD_ARGUMENT;
1669 }
1670 }
1671
1672 if(NC != config->bypass_pin)
1673 {
1674 if(CY_RSLT_SUCCESS == result)
1675 {
1676 // Bypass and ext_vref share the same hard-wired IO connection
1677 const cyhal_resource_pin_mapping_t* bypass_map =
1678 _cyhal_utils_get_resource(config->bypass_pin, cyhal_pin_map_pass_sar_ext_vref0,
1679 sizeof(cyhal_pin_map_pass_sar_ext_vref0)/sizeof(cyhal_pin_map_pass_sar_ext_vref0[0]), &(obj->resource),
1680 false);
1681
1682 if (NULL == bypass_map)
1683 {
1684 result = CYHAL_ADC_RSLT_BAD_ARGUMENT;
1685 }
1686 else if(config->bypass_pin != config->ext_vref) // It's valid to use the same pin for both ext_vref and bypass
1687 {
1688 result = _cyhal_utils_reserve_and_connect(bypass_map, CYHAL_PIN_MAP_DRIVE_MODE_PASS_SAR_EXT_VREF0);
1689 }
1690 }
1691
1692 if(CY_RSLT_SUCCESS == result)
1693 {
1694 obj->bypass_pin = config->bypass_pin;
1695 }
1696 }
1697 else
1698 {
1699 // We used to have an external vref pin - free it, unless it's still used for ext_vref
1700 if((NC != obj->bypass_pin) && (obj->ext_vref != obj->bypass_pin))
1701 {
1702 cyhal_gpio_free(obj->bypass_pin);
1703 obj->bypass_pin = NC;
1704 }
1705
1706 // If bypass exists as a GPIO, it's an error to enable bypass without passing in the pin
1707 if(config->is_bypassed)
1708 {
1709 result = CYHAL_ADC_RSLT_BAD_ARGUMENT;
1710 }
1711 }
1712 #else
1713 /* No GPIO pins for VREF - it must be using a dedicated pad */
1714 if(config->bypass_pin != NC || config->ext_vref != NC)
1715 {
1716 result = CYHAL_ADC_RSLT_BAD_ARGUMENT;
1717 }
1718 #endif
1719
1720 if(false == ((CYHAL_ADC_REF_EXTERNAL == config->vref) ^ (0u == config->ext_vref_mv)))
1721 {
1722 /* Must have exactly one of: ext vref selected, ext vref voltage unspecified */
1723 result = CYHAL_ADC_RSLT_BAD_ARGUMENT;
1724 }
1725
1726 #if !defined(CY_IP_MXS40EPASS_ESAR)
1727 cy_stc_sar_config_t pdl_config;
1728 #if defined(CY_IP_M0S8PASS4A_SAR_INSTANCES)
1729 if(CY_RSLT_SUCCESS == result)
1730 {
1731 obj->resolution = config->resolution;
1732 cy_stc_sar_channel_config_t chan_configs[CY_SAR_SEQ_NUM_CHANNELS];
1733 _cyhal_adc_extract_channel_conf(obj, chan_configs);
1734 result = _cyhal_adc_populate_pdl_config(config, &pdl_config, chan_configs);
1735 }
1736 #else
1737 if(CY_RSLT_SUCCESS == result)
1738 {
1739 result = _cyhal_adc_populate_pdl_config(config, &pdl_config);
1740 }
1741 #endif
1742
1743 if(CY_RSLT_SUCCESS == result)
1744 {
1745 /* Save and restore channel configs */
1746 pdl_config.chanEn = obj->base->CHAN_EN;
1747
1748 /* Don't deinit routing or change the channel config - we're going
1749 * to turn the SAR back on in a minute */
1750 #if defined(CY_IP_M0S8PASS4A_SAR_INSTANCES)
1751 pdl_config.routingConfig = NULL;
1752 #else
1753 pdl_config.configRouting = false;
1754 /* On M0S8 we already extracted the channel configuration as part
1755 * of assembling the PDL config struct. On MxS40 we need to do it here */
1756 for(uint8_t i = 0; i < CY_SAR_SEQ_NUM_CHANNELS; ++i)
1757 {
1758 pdl_config.chanConfig[i] = obj->base->CHAN_CONFIG[i];
1759 }
1760 #endif
1761 Cy_SAR_Disable(obj->base);
1762 Cy_SAR_DeInit(obj->base, false);
1763 result = (cy_rslt_t)Cy_SAR_Init(obj->base, &pdl_config);
1764 _cyhal_adc_populate_acquisition_timers(obj);
1765 Cy_SAR_SetInterruptMask(obj->base, CY_SAR_INTR_EOS);
1766 Cy_SAR_Enable(obj->base);
1767 }
1768 #else
1769 if(CY_RSLT_SUCCESS == result)
1770 {
1771 /* On EPASS, there is no global configuration to update, but we need to repopulate the channel configuration */
1772 obj->average_count = config->average_count;
1773 obj->average_is_accumulate = (0u != (config->average_mode_flags & CYHAL_ADC_AVG_MODE_ACCUMULATE));
1774 cy_stc_sar2_channel_config_t channel_configs[CY_SAR_MAX_NUM_CHANNELS];
1775
1776 _cyhal_adc_extract_channel_conf(obj, channel_configs);
1777 result = _cyhal_adc_apply_channel_configs(obj, channel_configs);
1778 }
1779 #endif
1780
1781 if(obj->continuous_scanning)
1782 {
1783 obj->conversion_complete = false;
1784 _cyhal_adc_update_intr_mask(obj);
1785 _cyhal_adc_start_convert(obj);
1786 }
1787 return result;
1788 }
1789
cyhal_adc_set_power(cyhal_adc_t * obj,cyhal_power_level_t power)1790 cy_rslt_t cyhal_adc_set_power(cyhal_adc_t *obj, cyhal_power_level_t power)
1791 {
1792 // The SAR doesn't have selectable power levels in the same way that the opamps do.
1793 if(CYHAL_POWER_LEVEL_OFF == power)
1794 {
1795 #if !defined(CY_IP_MXS40EPASS_ESAR)
1796 Cy_SAR_Disable(obj->base);
1797 #else
1798 Cy_SAR2_Disable(obj->base);
1799 #endif
1800 }
1801 else
1802 {
1803 #if !defined(CY_IP_MXS40EPASS_ESAR)
1804 Cy_SAR_Enable(obj->base);
1805 #else
1806 Cy_SAR2_Enable(obj->base);
1807 #endif
1808 }
1809 return CY_RSLT_SUCCESS;
1810 }
1811
_cyhal_adc_get_average_count(cyhal_adc_t * obj,int channel_idx)1812 static uint16_t _cyhal_adc_get_average_count(cyhal_adc_t* obj, int channel_idx)
1813 {
1814 #if defined(CY_IP_MXS40EPASS_ESAR)
1815 return _FLD2VAL(PASS_SAR_CH_POST_CTL_AVG_CNT, obj->base->CH[channel_idx].POST_CTL);
1816 #else
1817 uint32_t average_count = 1;
1818 /* If averaging is in interleaved mode, it does not impact the sample time */
1819 #if defined(CY_IP_MXS40PASS_SAR_INSTANCES)
1820 bool is_interleaved = CY_SAR_AVG_MODE_INTERLEAVED == (SAR_SAMPLE_CTRL(obj->base) & SAR_SAMPLE_CTRL_AVG_MODE_Msk);
1821 #else
1822 bool is_interleaved = false;
1823 #endif
1824
1825 if(false == is_interleaved)
1826 {
1827 average_count = (SAR_SAMPLE_CTRL(obj->base) & SAR_SAMPLE_CTRL_AVG_CNT_Msk) >> SAR_SAMPLE_CTRL_AVG_CNT_Pos;
1828 average_count = (1uL << (average_count + 1uL));
1829 }
1830
1831 return (obj->base->CHAN_CONFIG[channel_idx] & SAR_CHAN_CONFIG_AVG_EN_Msk) ? average_count : 1;
1832 #endif
1833 }
1834
1835 /* Gets acquisition times and conversion clocks for all enabled channels, factoring in averaging */
_cyhal_adc_get_sample_times(cyhal_adc_t * obj,uint32_t * min_acquisition_ns,uint32_t * conversion_clock_cycles)1836 static void _cyhal_adc_get_sample_times(cyhal_adc_t* obj, uint32_t* min_acquisition_ns, uint32_t* conversion_clock_cycles)
1837 {
1838 *min_acquisition_ns = *conversion_clock_cycles = 0;
1839 for(uint8_t i = 0; i < CY_SAR_MAX_NUM_CHANNELS; ++i)
1840 {
1841 cyhal_adc_channel_t* chan_config = obj->channel_config[i];
1842 #if defined(CY_IP_MXS40EPASS_ESAR)
1843 if((NULL != chan_config) && (0u != (obj->base->CH[i].ENABLE)))
1844 #else
1845 if((NULL != chan_config) && (0u != (obj->base->CHAN_EN & ((uint32_t)1U << i))))
1846 #endif
1847 {
1848 uint32_t min_time = chan_config->minimum_acquisition_ns;
1849 uint8_t clock_cycles = _CYHAL_ADC_CONVERSION_CYCLES;
1850 uint16_t average_count = _cyhal_adc_get_average_count(obj, i);
1851 min_time *= average_count;
1852 clock_cycles *= average_count;
1853
1854 *min_acquisition_ns += min_time;
1855 *conversion_clock_cycles += clock_cycles;
1856 }
1857 }
1858 }
1859
_cyhal_adc_calc_optimal_clock_rate(cyhal_adc_t * obj,uint32_t target_sample_hz)1860 uint32_t _cyhal_adc_calc_optimal_clock_rate(cyhal_adc_t* obj, uint32_t target_sample_hz)
1861 {
1862 /* From the architecture TRM */
1863 const uint32_t ADC_CLOCK_MAX_HZ = 60000000;
1864 const uint32_t ADC_CLOCK_MIN_HZ = 1000000;
1865
1866 uint32_t sample_period_ns = _CYHAL_UTILS_NS_PER_SECOND / target_sample_hz;
1867 uint32_t total_acquisition_ns, conversion_clock_cycles;
1868 _cyhal_adc_get_sample_times(obj, &total_acquisition_ns, &conversion_clock_cycles);
1869
1870 uint32_t conversion_budget_ns;
1871 if(sample_period_ns < total_acquisition_ns)
1872 {
1873 // Requested sampling rate is impossible - go as fast as we can.
1874 conversion_budget_ns = 1;
1875 }
1876 else
1877 {
1878 conversion_budget_ns = sample_period_ns - total_acquisition_ns;
1879 }
1880
1881 uint32_t target_period_ns = conversion_budget_ns / conversion_clock_cycles;
1882 uint32_t target_clock_hz = _CYHAL_UTILS_NS_PER_SECOND / target_period_ns;
1883 if(target_clock_hz > ADC_CLOCK_MAX_HZ)
1884 {
1885 target_clock_hz = ADC_CLOCK_MAX_HZ;
1886 }
1887 else if(target_clock_hz < ADC_CLOCK_MIN_HZ)
1888 {
1889 target_clock_hz = ADC_CLOCK_MIN_HZ;
1890 }
1891
1892 return target_clock_hz;
1893 }
1894
_cyhal_adc_compute_actual_sample_rate(cyhal_adc_t * obj)1895 uint32_t _cyhal_adc_compute_actual_sample_rate(cyhal_adc_t* obj)
1896 {
1897 /* Assumes that the acquisition timers and clock frequency are already set */
1898 uint32_t clock_frequency_hz = cyhal_clock_get_frequency(&obj->clock);
1899 uint32_t clock_period_ns = (clock_frequency_hz > 0)
1900 ? (_CYHAL_UTILS_NS_PER_SECOND / clock_frequency_hz)
1901 : 0;
1902 CY_ASSERT(clock_period_ns > 0);
1903
1904 uint32_t total_sample_time_ns = 0;
1905 #if defined(CY_IP_MXS40EPASS_ESAR)
1906 for(uint8_t i = 0; i < CY_SAR_MAX_NUM_CHANNELS; ++i)
1907 {
1908 uint32_t sample_count = _FLD2VAL(PASS_SAR_CH_SAMPLE_CTL_SAMPLE_TIME, obj->base->CH[i].SAMPLE_CTL);
1909 total_sample_time_ns += sample_count * clock_period_ns;
1910 }
1911 #else
1912 uint16_t sample_timer[] =
1913 {
1914 (obj->base->SAMPLE_TIME01 & SAR_SAMPLE_TIME01_SAMPLE_TIME0_Msk) >> SAR_SAMPLE_TIME01_SAMPLE_TIME0_Pos,
1915 (obj->base->SAMPLE_TIME01 & SAR_SAMPLE_TIME01_SAMPLE_TIME1_Msk) >> SAR_SAMPLE_TIME01_SAMPLE_TIME1_Pos,
1916 (obj->base->SAMPLE_TIME23 & SAR_SAMPLE_TIME23_SAMPLE_TIME2_Msk) >> SAR_SAMPLE_TIME23_SAMPLE_TIME2_Pos,
1917 (obj->base->SAMPLE_TIME23 & SAR_SAMPLE_TIME23_SAMPLE_TIME3_Msk) >> SAR_SAMPLE_TIME23_SAMPLE_TIME3_Pos,
1918 };
1919
1920 for(uint8_t i = 0; i < CY_SAR_SEQ_NUM_CHANNELS; ++i)
1921 {
1922 if(0u == (obj->base->CHAN_EN & ((uint32_t)1u << i)))
1923 {
1924 continue;
1925 }
1926 uint8_t sample_time_idx =
1927 (obj->base->CHAN_CONFIG[i] & SAR_CHAN_CONFIG_SAMPLE_TIME_SEL_Msk) >> SAR_CHAN_CONFIG_SAMPLE_TIME_SEL_Pos;
1928 /* Per the register map, the register value is one more than the actual cycle number. */
1929 uint32_t sample_cycles = sample_timer[sample_time_idx] - 1;
1930 uint32_t total_cycles = sample_cycles + _CYHAL_ADC_CONVERSION_CYCLES;
1931 uint32_t sample_time_ns = total_cycles * clock_period_ns;
1932 sample_time_ns *= _cyhal_adc_get_average_count(obj, i);
1933 total_sample_time_ns += sample_time_ns;
1934 }
1935 #endif
1936 uint32_t sample_frequency_hz = (total_sample_time_ns > 0)
1937 ? (_CYHAL_UTILS_NS_PER_SECOND / total_sample_time_ns)
1938 : 0;
1939 return sample_frequency_hz;
1940 }
1941
cyhal_adc_set_sample_rate(cyhal_adc_t * obj,uint32_t desired_sample_rate_hz,uint32_t * achieved_sample_rate_hz)1942 cy_rslt_t cyhal_adc_set_sample_rate(cyhal_adc_t* obj, uint32_t desired_sample_rate_hz, uint32_t* achieved_sample_rate_hz)
1943 {
1944 cy_rslt_t result = CY_RSLT_SUCCESS;
1945 /* If we don't own the clock, the caller needs to adjust it and/or the acquisition times to achive the desired rate */
1946 if(obj->dedicated_clock)
1947 {
1948 uint32_t desired_hz = _cyhal_adc_calc_optimal_clock_rate(obj, desired_sample_rate_hz);
1949 result = cyhal_clock_set_frequency(&(obj->clock), desired_hz, NULL);
1950 }
1951
1952 if(CY_RSLT_SUCCESS == result)
1953 {
1954 result = _cyhal_adc_populate_acquisition_timers(obj);
1955 }
1956
1957 if(CY_RSLT_SUCCESS == result)
1958 {
1959 *achieved_sample_rate_hz = _cyhal_adc_compute_actual_sample_rate(obj);
1960 }
1961 else
1962 {
1963 *achieved_sample_rate_hz = 0u;
1964 }
1965 return result;
1966 }
1967
1968 /*******************************************************************************
1969 * ADC Channel HAL Functions
1970 *******************************************************************************/
1971
1972 #if !defined(CY_IP_MXS40EPASS_ESAR)
1973 /* Updates the channel with the new config while preserving configuration parameters that
1974 * cyhal_adc_channel_config_t doesn't impact like pin selection */
_cyhal_adc_channel_update_config(cyhal_adc_channel_t * obj,const cyhal_adc_channel_config_t * config)1975 void _cyhal_adc_channel_update_config(cyhal_adc_channel_t* obj, const cyhal_adc_channel_config_t* config)
1976 {
1977 uint32_t existing_config = obj->adc->base->CHAN_CONFIG[obj->channel_idx];
1978 const uint32_t PRESERVE_MASK = SAR_CHAN_CONFIG_DIFFERENTIAL_EN_Msk
1979 #if defined(CY_IP_M0S8PASS4A_INSTANCES)
1980 | SAR_CHAN_CONFIG_PIN_ADDR_Msk | SAR_CHAN_CONFIG_PORT_ADDR_Msk;
1981 #else
1982 | SAR_CHAN_CONFIG_POS_PIN_ADDR_Msk | SAR_CHAN_CONFIG_POS_PORT_ADDR_Msk
1983 | SAR_CHAN_CONFIG_NEG_PIN_ADDR_Msk | SAR_CHAN_CONFIG_NEG_PORT_ADDR_Msk
1984 | SAR_CHAN_CONFIG_NEG_ADDR_EN_Msk;
1985 #endif
1986 uint32_t result = existing_config & PRESERVE_MASK;
1987 result |=
1988 _BOOL2FLD(SAR_CHAN_CONFIG_AVG_EN, config->enable_averaging)
1989 | _VAL2FLD(SAR_CHAN_CONFIG_SAMPLE_TIME_SEL, 0u); /* Placeholder, will be updated by populate_acquisition_timers */
1990 #if defined(CY_IP_M0S8PASS4A_SAR_INSTANCES)
1991 bool resolution_override = (obj->adc->resolution != _CYHAL_ADC_RESOLUTION);
1992 result |= _VAL2FLD(SAR_CHAN_CONFIG_RESOLUTION, (resolution_override ? CY_SAR_SUB_RES : CY_SAR_MAX_RES));
1993 #endif
1994
1995 obj->adc->base->CHAN_CONFIG[obj->channel_idx] = result;
1996 }
1997
_cyhal_adc_channel_set_pin_config(cyhal_adc_channel_t * obj,cyhal_gpio_t vplus,cyhal_gpio_t vminus)1998 void _cyhal_adc_channel_set_pin_config(cyhal_adc_channel_t* obj, cyhal_gpio_t vplus, cyhal_gpio_t vminus)
1999 {
2000 uint32_t result = 0u;
2001 #if defined(CY_IP_M0S8PASS4A_SAR_INSTANCES)
2002 CY_UNUSED_PARAMETER(vminus); // On M0S8, vminus is implied by vplus
2003 result |= _cyhal_adc_get_pin_addr(vplus);
2004 result |= _BOOL2FLD(SAR_CHAN_CONFIG_DIFFERENTIAL_EN, NC != vminus);
2005 #else
2006 result |= _cyhal_adc_get_pin_addr(vplus, true);
2007 if(vminus == NC)
2008 {
2009 /* Single-ended channel */
2010 result |= (uint32_t)CY_SAR_CHAN_SINGLE_ENDED;
2011 }
2012 else
2013 {
2014 /* Differential */
2015 result |= _cyhal_adc_get_pin_addr(vminus, false);
2016 result |= (uint32_t)CY_SAR_CHAN_DIFFERENTIAL_UNPAIRED;
2017 }
2018 #endif
2019
2020 obj->adc->base->CHAN_CONFIG[obj->channel_idx] = result;
2021 }
2022
_cyhal_adc_update_chan_offset(cyhal_adc_channel_t * obj)2023 static void _cyhal_adc_update_chan_offset(cyhal_adc_channel_t* obj)
2024 {
2025 /* Normally, the PDL sets the offset in the ADC init. But we change the channel config after we initialize
2026 * the ADC itself, so we need to set the offset appropriately here. Otherwise the _uv functions will not
2027 * work correctly.
2028 * The conditions in the PDL are: singleEnded && vrefNegSelect && singleEndedSigned. We always operate
2029 * in signed mode so we only need to check the first two.
2030 */
2031 bool single_ended = Cy_SAR_IsChannelSingleEnded(obj->adc->base, obj->channel_idx);
2032 uint32_t neg_sel_vref_val = (uint32_t)CY_SAR_NEG_SEL_VREF;
2033 #if defined(CY_IP_M0S8PASS4A_SAR_INSTANCES)
2034 // The NEG_SEL values in the M0S8 pdl are not pre-shifted
2035 neg_sel_vref_val = neg_sel_vref_val << SAR_CTRL_NEG_SEL_Pos;
2036 #endif
2037 bool neg_sel_vref = (neg_sel_vref_val == (obj->adc->base->CTRL & SAR_CTRL_NEG_SEL_Msk));
2038 int16_t offset = (single_ended && neg_sel_vref) ? (-1 * ((int16_t) (CY_SAR_WRK_MAX_12BIT / 2))) : 0;
2039
2040 #if defined(CY_IP_MXS40PASS_SAR_INSTANCES) && (CY_IP_MXS40PASS_SAR_INSTANCES < 2)
2041 Cy_SAR_SetOffset(obj->channel_idx, offset);
2042 #else
2043 Cy_SAR_SetChannelOffset(obj->adc->base, obj->channel_idx, offset);
2044 #endif
2045 }
2046 #endif
2047
cyhal_adc_channel_init_diff(cyhal_adc_channel_t * obj,cyhal_adc_t * adc,cyhal_gpio_t vplus,cyhal_gpio_t vminus,const cyhal_adc_channel_config_t * cfg)2048 cy_rslt_t cyhal_adc_channel_init_diff(cyhal_adc_channel_t *obj, cyhal_adc_t* adc, cyhal_gpio_t vplus, cyhal_gpio_t vminus, const cyhal_adc_channel_config_t* cfg)
2049 {
2050 CY_ASSERT(obj != NULL);
2051 CY_ASSERT(adc != NULL);
2052
2053 cy_rslt_t result = CY_RSLT_SUCCESS;
2054
2055 memset(obj, 0, sizeof(cyhal_adc_channel_t));
2056 obj->vplus = NC;
2057 #if !defined(CY_IP_MXS40EPASS_ESAR_INSTANCES)
2058 obj->vminus = NC;
2059 const cyhal_resource_pin_mapping_t *vminus_map = NULL;
2060 #endif
2061
2062 // Check for invalid pin or pin belonging to a different SAR
2063 const cyhal_resource_pin_mapping_t *vplus_map = _cyhal_utils_get_resource(vplus, cyhal_pin_map_pass_sarmux_pads,
2064 sizeof(cyhal_pin_map_pass_sarmux_pads)/sizeof(cyhal_pin_map_pass_sarmux_pads[0]), NULL, false);
2065
2066 if(NULL == vplus_map || adc->resource.block_num != vplus_map->block_num)
2067 {
2068 result = CYHAL_ADC_RSLT_BAD_ARGUMENT;
2069 }
2070
2071 uint8_t chosen_channel = 0;
2072
2073 if (CY_RSLT_SUCCESS == result)
2074 {
2075 // Find the first available channel
2076 #if defined(CY_IP_MXS40EPASS_ESAR_INSTANCES)
2077 for(chosen_channel = _CYHAL_ADC_VBG_CHANNEL_IDX + 1; chosen_channel < CY_SAR_MAX_NUM_CHANNELS; ++chosen_channel)
2078 #else
2079 for(chosen_channel = 0; chosen_channel < CY_SAR_MAX_NUM_CHANNELS; ++chosen_channel)
2080 #endif /* defined(CY_IP_MXS40EPASS_ESAR_INSTANCES) or other */
2081 {
2082 if(NULL == adc->channel_config[chosen_channel])
2083 {
2084 break;
2085 }
2086 }
2087 if (chosen_channel >= CY_SAR_MAX_NUM_CHANNELS) // No channels available
2088 result = CYHAL_ADC_RSLT_NO_CHANNELS;
2089 }
2090
2091 if(CY_RSLT_SUCCESS == result)
2092 {
2093 // Don't set the ADC until here so that free knows whether we have allocated
2094 // the channel on the parent ADC instance (and therefore doesn't try to free it if
2095 // something fails further up)
2096 obj->adc = adc;
2097 obj->channel_idx = chosen_channel;
2098 obj->adc->channel_config[chosen_channel] = obj;
2099 obj->minimum_acquisition_ns = (cfg->min_acquisition_ns > _CYHAL_ADC_MIN_ACQUISITION_TIME_NS)
2100 ? cfg->min_acquisition_ns : _CYHAL_ADC_MIN_ACQUISITION_TIME_NS;
2101 }
2102
2103 if((CY_RSLT_SUCCESS == result) && (CYHAL_ADC_VNEG != vminus))
2104 {
2105 #if defined(CY_IP_MXS40EPASS_ESAR)
2106 /* We don't support differential channels */
2107 result = CYHAL_ADC_RSLT_BAD_ARGUMENT;
2108 #else
2109 vminus_map = _cyhal_utils_get_resource(vminus, cyhal_pin_map_pass_sarmux_pads,
2110 sizeof(cyhal_pin_map_pass_sarmux_pads)/sizeof(cyhal_pin_map_pass_sarmux_pads[0]), NULL, false);
2111 if (NULL == vminus_map || adc->resource.block_num != vminus_map->block_num)
2112 {
2113 result = CYHAL_ADC_RSLT_BAD_ARGUMENT;
2114 }
2115 #if defined(CY_IP_M0S8PASS4A_SAR_INSTANCES)
2116 // For PSoC™ 4A devices, vplus must be an even number pin, and vminus the following odd numbered pin
2117 else if (((vplus & 1) != 0) || ((vplus + 1) != vminus))
2118 {
2119 result = CYHAL_ADC_RSLT_BAD_ARGUMENT;
2120 }
2121 #endif
2122 #endif
2123 }
2124
2125 if(CY_RSLT_SUCCESS == result)
2126 {
2127 result = _cyhal_utils_reserve_and_connect(vplus_map, CYHAL_PIN_MAP_DRIVE_MODE_PASS_SARMUX_PADS);
2128 }
2129
2130 if(CY_RSLT_SUCCESS == result)
2131 {
2132 obj->vplus = vplus;
2133 #if !defined(CY_IP_MXS40EPASS_ESAR_INSTANCES)
2134 if(CYHAL_ADC_VNEG != vminus)
2135 {
2136 result = _cyhal_utils_reserve_and_connect(vminus_map, CYHAL_PIN_MAP_DRIVE_MODE_PASS_SARMUX_PADS);
2137 }
2138 }
2139
2140 if(CY_RSLT_SUCCESS == result)
2141 {
2142 obj->vminus = vminus;
2143 #endif
2144 result = _cyhal_adc_populate_acquisition_timers(obj->adc);
2145 }
2146
2147 if(CY_RSLT_SUCCESS == result)
2148 {
2149 #if defined(CY_IP_MXS40EPASS_ESAR)
2150 cy_stc_sar2_channel_config_t channel_configs[CY_SAR_MAX_NUM_CHANNELS];
2151 _cyhal_adc_extract_channel_conf(obj->adc, channel_configs);
2152 channel_configs[obj->channel_idx] = _CYHAL_ADC_DEFAULT_PDL_CHAN_CONFIG;
2153 channel_configs[obj->channel_idx].pinAddress =
2154 (cy_en_sar2_pin_address_t)(CY_SAR2_PIN_ADDRESS_AN0 + vplus_map->channel_num);
2155
2156 #if defined(CY_IP_MXS40EPASS_ESAR_INSTANCES)
2157 if (false == adc->vbg_chan_inited)
2158 {
2159 uint8_t block_idx = adc->resource.block_num;
2160
2161 _cyhal_adc_vbg_channels[block_idx].adc = adc;
2162 _cyhal_adc_vbg_channels[block_idx].channel_idx = _CYHAL_ADC_VBG_CHANNEL_IDX;
2163 _cyhal_adc_vbg_channels[block_idx].adc->channel_config[_CYHAL_ADC_VBG_CHANNEL_IDX] = &_cyhal_adc_vbg_channels[block_idx];
2164 _cyhal_adc_vbg_channels[block_idx].minimum_acquisition_ns = obj->minimum_acquisition_ns;
2165
2166 channel_configs[_CYHAL_ADC_VBG_CHANNEL_IDX] = _CYHAL_ADC_DEFAULT_PDL_CHAN_CONFIG;
2167 channel_configs[_CYHAL_ADC_VBG_CHANNEL_IDX].pinAddress = CY_SAR2_PIN_ADDRESS_VBG;
2168
2169 _cyhal_adc_channel_update_config(obj, &channel_configs[_CYHAL_ADC_VBG_CHANNEL_IDX], cfg);
2170
2171 adc->vbg_chan_inited = true;
2172 }
2173 #endif /* defined(CY_IP_MXS40EPASS_ESAR_INSTANCES) */
2174
2175 _cyhal_adc_channel_update_config(obj, &channel_configs[obj->channel_idx], cfg);
2176 result = _cyhal_adc_apply_channel_configs(obj->adc, channel_configs);
2177 #else
2178 uint32_t fw_ctrl_plus = _cyhal_adc_get_fw_switch_control(vplus, true);
2179 uint32_t mux_ctrl_plus = _cyhal_adc_get_mux_switch_control(vplus);
2180
2181 _CYHAL_ADC_SET_SWITCH(obj->adc->base, fw_ctrl_plus, true);
2182 Cy_SAR_SetSwitchSarSeqCtrl(obj->adc->base, mux_ctrl_plus, _CYHAL_ADC_SARSEQ_STATE(true));
2183
2184 if(CYHAL_ADC_VNEG != vminus)
2185 {
2186 uint32_t fw_ctrl_minus = _cyhal_adc_get_fw_switch_control(vminus, false);
2187 uint32_t mux_ctrl_minus = _cyhal_adc_get_mux_switch_control(vminus);
2188
2189 _CYHAL_ADC_SET_SWITCH(obj->adc->base, fw_ctrl_minus, true);
2190 Cy_SAR_SetSwitchSarSeqCtrl(obj->adc->base, mux_ctrl_minus, _CYHAL_ADC_SARSEQ_STATE(true));
2191 }
2192
2193 _cyhal_adc_channel_set_pin_config(obj, obj->vplus, obj->vminus);
2194 result = cyhal_adc_channel_configure(obj, cfg);
2195 #endif
2196 }
2197
2198 if(CY_RSLT_SUCCESS != result)
2199 {
2200 cyhal_adc_channel_free(obj);
2201 }
2202
2203 return result;
2204 }
2205
cyhal_adc_channel_configure(cyhal_adc_channel_t * obj,const cyhal_adc_channel_config_t * config)2206 cy_rslt_t cyhal_adc_channel_configure(cyhal_adc_channel_t *obj, const cyhal_adc_channel_config_t *config)
2207 {
2208 CY_ASSERT(NULL != obj);
2209
2210 obj->minimum_acquisition_ns = (config->min_acquisition_ns > _CYHAL_ADC_MIN_ACQUISITION_TIME_NS)
2211 ? config->min_acquisition_ns : _CYHAL_ADC_MIN_ACQUISITION_TIME_NS;
2212
2213 #if defined(CY_IP_MXS40EPASS_ESAR)
2214 cy_stc_sar2_channel_config_t channel_configs[CY_SAR_MAX_NUM_CHANNELS];
2215 _cyhal_adc_extract_channel_conf(obj->adc, channel_configs);
2216 _cyhal_adc_channel_update_config(obj, &channel_configs[obj->channel_idx], config);
2217 return _cyhal_adc_apply_channel_configs(obj->adc, channel_configs);
2218 #else
2219 _cyhal_adc_channel_update_config(obj, config);
2220 if(config->enabled)
2221 {
2222 obj->adc->base->CHAN_EN |= 1u << obj->channel_idx;
2223 }
2224 else
2225 {
2226 obj->adc->base->CHAN_EN &= ~(1u << obj->channel_idx);
2227 }
2228 _cyhal_adc_update_chan_offset(obj);
2229 return _cyhal_adc_populate_acquisition_timers(obj->adc);
2230 #endif
2231 }
2232
cyhal_adc_channel_free(cyhal_adc_channel_t * obj)2233 void cyhal_adc_channel_free(cyhal_adc_channel_t *obj)
2234 {
2235 if(obj->adc != NULL)
2236 {
2237 // Disable the channel, the unconfigure it
2238 obj->adc->channel_config[obj->channel_idx] = NULL;
2239
2240 #if !defined(CY_IP_MXS40EPASS_ESAR)
2241 if(false == obj->adc->owned_by_configurator)
2242 {
2243 if(NC != obj->vplus)
2244 {
2245 uint32_t fw_ctrl_plus = _cyhal_adc_get_fw_switch_control(obj->vplus, true);
2246 uint32_t mux_ctrl_plus = _cyhal_adc_get_mux_switch_control(obj->vplus);
2247
2248 _CYHAL_ADC_SET_SWITCH(obj->adc->base, fw_ctrl_plus, false);
2249 Cy_SAR_SetSwitchSarSeqCtrl(obj->adc->base, mux_ctrl_plus, _CYHAL_ADC_SARSEQ_STATE(false));
2250 }
2251
2252 if(NC != obj->vminus)
2253 {
2254 uint32_t mux_ctrl_minus = _cyhal_adc_get_mux_switch_control(obj->vminus);
2255 uint32_t fw_ctrl_minus = _cyhal_adc_get_fw_switch_control(obj->vminus, false);
2256
2257 _CYHAL_ADC_SET_SWITCH(obj->adc->base, fw_ctrl_minus, false);
2258 Cy_SAR_SetSwitchSarSeqCtrl(obj->adc->base, mux_ctrl_minus, _CYHAL_ADC_SARSEQ_STATE(false));
2259 }
2260 }
2261 obj->adc->base->CHAN_CONFIG[obj->channel_idx] = 0;
2262 #else
2263 Cy_SAR2_Channel_DeInit(obj->adc->base, obj->channel_idx);
2264 #endif
2265
2266 if(false == obj->adc->owned_by_configurator)
2267 {
2268 _cyhal_utils_release_if_used(&(obj->vplus));
2269 #if !defined(CY_IP_MXS40EPASS_ESAR_INSTANCES)
2270 _cyhal_utils_release_if_used(&(obj->vminus));
2271 #endif
2272 }
2273
2274 #if defined(CY_IP_MXS40EPASS_ESAR)
2275 if (obj->adc->vbg_chan_inited)
2276 {
2277 // If VBG sampling channel is activated, go through all channels and find how many activated left.
2278 // If no more active user channels left, DeInit VBG channel too.
2279 uint8_t active_chan_num = 0;
2280 for(uint8_t chan_idx = 0; chan_idx < CY_SAR_MAX_NUM_CHANNELS; ++chan_idx)
2281 {
2282 if(NULL != obj->adc->channel_config[chan_idx])
2283 {
2284 ++active_chan_num;
2285 if (active_chan_num > 1)
2286 {
2287 // If 2 or more channels are active (VBG + at least one user channel), no reason to continue
2288 // as we will definitely not going to DeInit VBG channel
2289 break;
2290 }
2291 }
2292 }
2293 if (1 == active_chan_num)
2294 {
2295 // Only VBG channel left to be active, DeIniting it
2296 Cy_SAR2_Channel_DeInit(obj->adc->base, _CYHAL_ADC_VBG_CHANNEL_IDX);
2297 obj->adc->vbg_chan_inited = false;
2298 }
2299 }
2300 #endif /* defined(CY_IP_MXS40EPASS_ESAR) */
2301
2302 obj->adc = NULL;
2303 }
2304 }
2305
cyhal_adc_read_u16(const cyhal_adc_channel_t * obj)2306 uint16_t cyhal_adc_read_u16(const cyhal_adc_channel_t *obj)
2307 {
2308 int32_t signed_result = cyhal_adc_read(obj);
2309
2310 #if defined(CY_IP_M0S8PASS4A_SAR_INSTANCES)
2311 const uint8_t RESULT_SCALING_FACTOR = UINT16_MAX / ((1 << obj->adc->resolution) - 1); // 12-bit SAR resolution
2312 #else
2313 const uint8_t RESULT_SCALING_FACTOR = UINT16_MAX / 0xFFF; // constant 12-bit SAR resolution
2314 #endif
2315
2316 #if defined(CY_IP_MXS40EPASS_ESAR)
2317 uint16_t unsigned_result = (uint16_t)((uint32_t)(signed_result) & 0xFFFF);
2318 #else
2319 /* Legacy API for BWC. Convert from signed to unsigned by adding 0x800 to
2320 * convert the lowest signed 12-bit number to 0x0.
2321 */
2322 uint16_t unsigned_result = (uint16_t)(signed_result + 0x800);
2323 #endif
2324
2325 /* The SAR provides a 12-bit result, but this API is defined to fill a full 16-bit range */
2326 uint16_t scaled_result = unsigned_result * RESULT_SCALING_FACTOR;
2327 return scaled_result;
2328 }
2329
cyhal_adc_read(const cyhal_adc_channel_t * obj)2330 int32_t cyhal_adc_read(const cyhal_adc_channel_t *obj)
2331 {
2332 uint32_t old_en_mask = 0u;
2333
2334 #if defined(CY_IP_MXS40PASS_SAR_INSTANCES)
2335 bool isInterleaved = (CY_SAR_AVG_MODE_INTERLEAVED == (SAR_SAMPLE_CTRL(obj->adc->base) & SAR_SAMPLE_CTRL_AVG_MODE_Msk));
2336 #elif !defined(CY_IP_MXS40EPASS_ESAR)
2337 bool isInterleaved = false;
2338 #endif
2339 #if defined(CY_IP_MXS40EPASS_ESAR)
2340 cy_stc_sar2_channel_config_t channel_configs[CY_SAR_MAX_NUM_CHANNELS] = {{0}};
2341 #endif
2342 if(!obj->adc->continuous_scanning)
2343 {
2344 /* Enable the selected channel only, then perform an on-demand conversion.
2345 * Save the old enabled channel set to restore after we're done */
2346 #if defined(CY_IP_MXS40EPASS_ESAR)
2347 _cyhal_adc_extract_channel_conf(obj->adc, channel_configs);
2348 /* We need to do a full update because the first and last channels in the group must be enabled */
2349 for(uint8_t i = 0; i < CY_SAR_MAX_NUM_CHANNELS; ++i) /* Fortunately, each ADC supports a max of 32 channels */
2350 {
2351 old_en_mask |= channel_configs[i].channelHwEnable << i;
2352 channel_configs[i].channelHwEnable = (obj->channel_idx == i) || (_CYHAL_ADC_VBG_CHANNEL_IDX == i);
2353 }
2354 _cyhal_adc_apply_channel_configs(obj->adc, channel_configs);
2355 #else
2356 bool isChannelAveraging = (obj->adc->base->CHAN_CONFIG[obj->channel_idx] & SAR_CHAN_CONFIG_AVG_EN_Msk);
2357 bool isChannelInterleaved = (isInterleaved && isChannelAveraging);
2358 old_en_mask = SAR_CHAN_EN(obj->adc->base);
2359 Cy_SAR_SetChanMask(obj->adc->base, (uint32_t) (1U << obj->channel_idx));
2360 #endif
2361
2362 obj->adc->conversion_complete = false;
2363 #if !defined(CY_IP_MXS40EPASS_ESAR)
2364 obj->adc->stop_after_scan = isChannelInterleaved;
2365 #endif
2366 _cyhal_adc_update_intr_mask(obj->adc);
2367
2368 // If interleaved averaging and average is enabled for this channel, set for
2369 // continuous scanning and then stop the scan once we get a result. This is
2370 // because the ADC hardware has a special case where it will not raise
2371 // the EOC interrupt until AVG_COUNT scans have occurred when all enabled
2372 // channels are using interleaved channels. This means that for the first AVG_COUNT - 1
2373 // scans there will be no interrupt, therefore conversion_complete will never
2374 // be set true, and therefore the loop below would be stuck waiting forever,
2375 // never able to trigger a subsequent scan.
2376 #if defined(CY_IP_MXS40EPASS_ESAR)
2377 Cy_SAR2_Channel_SoftwareTrigger(obj->adc->base, _cyhal_adc_first_enabled(obj->adc));
2378 #else
2379 Cy_SAR_StartConvert(obj->adc->base, (isChannelInterleaved) ? CY_SAR_START_CONVERT_CONTINUOUS : CY_SAR_START_CONVERT_SINGLE_SHOT);
2380 #endif
2381 }
2382
2383 /* Cy_SAR_IsEndConversion relies on and clears the EOS interrupt status bit.
2384 * We don't know how this read will be used in combination with interrupts,
2385 * so implement our own interrupt-driven EOS flag
2386 */
2387 while(!obj->adc->conversion_complete) { }
2388
2389 #if defined(CY_IP_MXS40EPASS_ESAR)
2390 /* Cy_SAR2_Channel_GetResult returns 12-bit unsigned value, which represent ADC count value in range from 0V to 3.3V/5V
2391 * (depends on VDDA). Casting it to signed 32 bit int as per cyhal_adc_read return value description. */
2392 int32_t result = (int32_t)(Cy_SAR2_Channel_GetResult(obj->adc->base, obj->channel_idx, NULL /* We don't need the status bits */));
2393 obj->adc->vbg_last_value = Cy_SAR2_Channel_GetResult(obj->adc->base, _CYHAL_ADC_VBG_CHANNEL_IDX, NULL /* We don't need the status bits */);
2394 #else
2395 int32_t result = Cy_SAR_GetResult32(obj->adc->base, obj->channel_idx);
2396 #endif
2397
2398 if(!obj->adc->continuous_scanning)
2399 {
2400 #if defined(CY_IP_MXS40EPASS_ESAR)
2401 for(uint8_t i = 0; i < CY_SAR_MAX_NUM_CHANNELS; ++i)
2402 {
2403 channel_configs[i].channelHwEnable = (0u != (old_en_mask & (1u << i)));
2404 }
2405 _cyhal_adc_apply_channel_configs(obj->adc, channel_configs);
2406 #else
2407 Cy_SAR_SetChanMask(obj->adc->base, old_en_mask);
2408 #endif
2409 }
2410
2411 return result;
2412 }
2413
cyhal_adc_read_uv(const cyhal_adc_channel_t * obj)2414 int32_t cyhal_adc_read_uv(const cyhal_adc_channel_t *obj)
2415 {
2416 CY_ASSERT(NULL != obj);
2417
2418 int32_t counts = cyhal_adc_read(obj);
2419 return _cyhal_adc_counts_to_uvolts(obj->adc, obj->channel_idx, counts);
2420 }
2421
_cyhal_adc_start_async_read(cyhal_adc_t * obj,size_t num_scan,int32_t * result_list)2422 void _cyhal_adc_start_async_read(cyhal_adc_t* obj, size_t num_scan, int32_t* result_list)
2423 {
2424 CY_ASSERT(NULL == obj->async_buff_next); /* Transfer already in progress */
2425 uint32_t savedIntrStatus = cyhal_system_critical_section_enter();
2426 obj->async_scans_remaining = num_scan;
2427 obj->async_buff_next = obj->async_buff_orig = result_list;
2428 _cyhal_adc_update_intr_mask(obj);
2429
2430 if(false == obj->continuous_scanning)
2431 {
2432 _cyhal_adc_start_convert(obj);
2433 }
2434 cyhal_system_critical_section_exit(savedIntrStatus);
2435 }
2436
cyhal_adc_read_async(cyhal_adc_t * obj,size_t num_scan,int32_t * result_list)2437 cy_rslt_t cyhal_adc_read_async(cyhal_adc_t* obj, size_t num_scan, int32_t* result_list)
2438 {
2439 CY_ASSERT(NULL != obj);
2440 obj->async_transfer_in_uv = false;
2441 _cyhal_adc_start_async_read(obj, num_scan, result_list);
2442 return CY_RSLT_SUCCESS;
2443 }
2444
cyhal_adc_read_async_uv(cyhal_adc_t * obj,size_t num_scan,int32_t * result_list)2445 cy_rslt_t cyhal_adc_read_async_uv(cyhal_adc_t* obj, size_t num_scan, int32_t* result_list)
2446 {
2447 CY_ASSERT(NULL != obj);
2448 obj->async_transfer_in_uv = true;
2449 _cyhal_adc_start_async_read(obj, num_scan, result_list);
2450 return CY_RSLT_SUCCESS;
2451 }
2452
cyhal_adc_set_async_mode(cyhal_adc_t * obj,cyhal_async_mode_t mode,uint8_t dma_priority)2453 cy_rslt_t cyhal_adc_set_async_mode(cyhal_adc_t *obj, cyhal_async_mode_t mode, uint8_t dma_priority)
2454 {
2455 CY_ASSERT(NULL != obj);
2456 CY_ASSERT(NULL == obj->async_buff_next); /* Can't swap mode while a transfer is running */
2457
2458 cy_rslt_t result = CY_RSLT_SUCCESS;
2459
2460 if(mode == CYHAL_ASYNC_DMA)
2461 {
2462 #if _CYHAL_ADC_DMA_SUPPORTED
2463 result = cyhal_dma_init(&(obj->dma), CYHAL_DMA_PRIORITY_DEFAULT, CYHAL_DMA_DIRECTION_PERIPH2MEM);
2464 if(CY_RSLT_SUCCESS == result)
2465 {
2466 cyhal_dma_register_callback(&(obj->dma), &_cyhal_adc_dma_handler, obj);
2467 cyhal_dma_enable_event(&(obj->dma), CYHAL_DMA_TRANSFER_COMPLETE, dma_priority, true);
2468 }
2469 #else
2470 CY_UNUSED_PARAMETER(dma_priority);
2471 result = CYHAL_ADC_RSLT_BAD_ARGUMENT; // DMA not supported
2472 #endif
2473 }
2474 else
2475 {
2476 #if _CYHAL_ADC_DMA_SUPPORTED
2477 /* Free the DMA instances if we reserved them but don't need them anymore */
2478 if(CYHAL_RSC_INVALID != obj->dma.resource.type)
2479 {
2480 cyhal_dma_free(&obj->dma);
2481 obj->dma.resource.type = CYHAL_RSC_INVALID;
2482 }
2483 #endif
2484 }
2485
2486 if(CY_RSLT_SUCCESS == result)
2487 {
2488 obj->async_mode = mode;
2489 }
2490 return CY_RSLT_SUCCESS;
2491 }
2492
cyhal_adc_register_callback(cyhal_adc_t * obj,cyhal_adc_event_callback_t callback,void * callback_arg)2493 void cyhal_adc_register_callback(cyhal_adc_t *obj, cyhal_adc_event_callback_t callback, void *callback_arg)
2494 {
2495 CY_ASSERT(NULL != obj);
2496
2497 uint32_t savedIntrStatus = cyhal_system_critical_section_enter();
2498 obj->callback_data.callback = (cy_israddress) callback;
2499 obj->callback_data.callback_arg = callback_arg;
2500 cyhal_system_critical_section_exit(savedIntrStatus);
2501 }
2502
cyhal_adc_enable_event(cyhal_adc_t * obj,cyhal_adc_event_t event,uint8_t intr_priority,bool enable)2503 void cyhal_adc_enable_event(cyhal_adc_t *obj, cyhal_adc_event_t event, uint8_t intr_priority, bool enable)
2504 {
2505 if(enable)
2506 {
2507 obj->user_enabled_events |= event;
2508 }
2509 else
2510 {
2511 obj->user_enabled_events &= ~event;
2512 }
2513
2514 _cyhal_adc_update_intr_mask(obj);
2515
2516 #if defined(CY_IP_MXS40EPASS_ESAR)
2517 for(uint8_t i = 0; i < CY_SAR_MAX_NUM_CHANNELS; ++i)
2518 {
2519 _cyhal_system_irq_t irqn = _cyhal_adc_calc_channel_irq(obj->resource.block_num, i);
2520 _cyhal_irq_set_priority(irqn, intr_priority);
2521 }
2522 #else
2523 _cyhal_system_irq_t irqn = _cyhal_adc_irq_n[obj->resource.block_num];
2524 _cyhal_irq_set_priority(irqn, intr_priority);
2525 #endif
2526 }
2527
_cyhal_adc_calculate_dest(uint8_t block_num)2528 static cyhal_dest_t _cyhal_adc_calculate_dest(uint8_t block_num)
2529 {
2530 CY_ASSERT(block_num < _CYHAL_ADC_SAR_INSTANCES);
2531 return _cyhal_adc_tr_in[block_num];
2532 }
2533
cyhal_adc_connect_digital(cyhal_adc_t * obj,cyhal_source_t source,cyhal_adc_input_t input)2534 cy_rslt_t cyhal_adc_connect_digital(cyhal_adc_t *obj, cyhal_source_t source, cyhal_adc_input_t input)
2535 {
2536 if(input == CYHAL_ADC_INPUT_START_SCAN)
2537 {
2538 #if !defined(CY_IP_MXS40EPASS_ESAR_INSTANCES)
2539 Cy_SAR_SetConvertMode(obj->base, CY_SAR_TRIGGER_MODE_FW_AND_HWEDGE);
2540 #endif
2541 cyhal_dest_t dest = _cyhal_adc_calculate_dest(obj->resource.block_num);
2542 return _cyhal_connect_signal(source, dest);
2543 }
2544
2545 return CYHAL_ADC_RSLT_BAD_ARGUMENT;
2546 }
2547
cyhal_adc_enable_output(cyhal_adc_t * obj,cyhal_adc_output_t output,cyhal_source_t * source)2548 cy_rslt_t cyhal_adc_enable_output(cyhal_adc_t *obj, cyhal_adc_output_t output, cyhal_source_t *source)
2549 {
2550 if(output == CYHAL_ADC_OUTPUT_SCAN_COMPLETE)
2551 {
2552 #if defined(CY_IP_M0S8PASS4A_SAR_INSTANCES)
2553 SAR_SAMPLE_CTRL(obj->base) |= SAR_SAMPLE_CTRL_EOS_DSI_OUT_EN_Msk;
2554 #elif !defined(CY_IP_MXS40EPASS_ESAR_INSTANCES) /* Trigger is always enabled for ESAR */
2555 SAR_SAMPLE_CTRL(obj->base) |= SAR_SAMPLE_CTRL_TRIGGER_OUT_EN_Msk;
2556 #endif
2557 *source = _cyhal_adc_calculate_source(obj);
2558 return CY_RSLT_SUCCESS;
2559 }
2560
2561 return CYHAL_ADC_RSLT_BAD_ARGUMENT;
2562 }
2563
cyhal_adc_disconnect_digital(cyhal_adc_t * obj,cyhal_source_t source,cyhal_adc_input_t input)2564 cy_rslt_t cyhal_adc_disconnect_digital(cyhal_adc_t *obj, cyhal_source_t source, cyhal_adc_input_t input)
2565 {
2566 if(input == CYHAL_ADC_INPUT_START_SCAN)
2567 {
2568 #if !defined(CY_IP_MXS40EPASS_ESAR_INSTANCES)
2569 /* EPASS is always in hw trigger mode, we can just also force the trigger through SW */
2570 Cy_SAR_SetConvertMode(obj->base, CY_SAR_TRIGGER_MODE_FW_ONLY);
2571 #endif
2572 cyhal_dest_t dest = _cyhal_adc_calculate_dest(obj->resource.block_num);
2573 return _cyhal_disconnect_signal(source, dest);
2574 }
2575
2576 return CYHAL_ADC_RSLT_BAD_ARGUMENT;
2577 }
2578
cyhal_adc_disable_output(cyhal_adc_t * obj,cyhal_adc_output_t output)2579 cy_rslt_t cyhal_adc_disable_output(cyhal_adc_t *obj, cyhal_adc_output_t output)
2580 {
2581 if(output != CYHAL_ADC_OUTPUT_SCAN_COMPLETE)
2582 {
2583 return CYHAL_ADC_RSLT_BAD_ARGUMENT;
2584 }
2585
2586 #if defined(CY_IP_M0S8PASS4A_SAR_INSTANCES)
2587 SAR_SAMPLE_CTRL(obj->base) &= ~SAR_SAMPLE_CTRL_EOS_DSI_OUT_EN_Msk;
2588 #elif defined(CY_IP_MXS40EPASS_ESAR_INSTANCES)
2589 /* Output trigger is always enabled for ESAR */
2590 CY_UNUSED_PARAMETER(obj);
2591 #else
2592 SAR_SAMPLE_CTRL(obj->base) &= ~SAR_SAMPLE_CTRL_TRIGGER_OUT_EN_Msk;
2593 #endif
2594
2595 return CY_RSLT_SUCCESS;
2596 }
2597
2598 #if defined(__cplusplus)
2599 }
2600 #endif
2601
2602 #endif /* (_CYHAL_DRIVER_AVAILABLE_ADC_SAR) */
2603