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