1 /*******************************************************************************
2 * \file cyhal_dac.c
3 *
4 * \brief
5 * Provides a high level interface for interacting with the Infineon Digital/Analog converter.
6 * This interface abstracts out the chip specific details. If any chip specific
7 * functionality is necessary, or performance is critical the low level functions
8 * 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 #include <limits.h>
31 #include <math.h>
32 #include <string.h> // For memset
33
34 #include "cyhal_analog_common.h"
35 #include "cyhal_dac.h"
36 #include "cyhal_gpio.h"
37 #include "cyhal_hwmgr.h"
38 #include "cyhal_utils.h"
39 #include "cyhal_syspm.h"
40 #include "cy_pdl.h"
41
42 /**
43 * \addtogroup group_hal_impl_dac DAC (Digital to Analog Converter)
44 * \ingroup group_hal_impl
45 *
46 * \section group_hal_impl_dac_power Power Level Mapping
47 * The following table shows how the HAL-defined power levels map to the hardware-specific power levels
48 * when cyhal_dac uses output pin buffered mode (with opamp). Unbuffered mode only supports ON and OFF.
49 * | HAL Power Level | Opamp Power Level |
50 * | ------------------------------ | ------------------- |
51 * | @ref CYHAL_POWER_LEVEL_HIGH | CY_CTB_POWER_HIGH |
52 * | @ref CYHAL_POWER_LEVEL_MEDIUM | CY_CTB_POWER_MEDIUM |
53 * | @ref CYHAL_POWER_LEVEL_LOW | CY_CTB_POWER_LOW |
54 * | @ref CYHAL_POWER_LEVEL_DEFAULT | CY_CTB_POWER_MEDIUM |
55 *
56 * cyhal_dac automatically choose between buffered and unbuffered mode by selecting pin.
57 * Unbuffered mode - dac pin, buffered - opamp pin.
58 * Buffered mode take care of reserving and configuring the opamp (OA0).
59 * If AREF voltage reference source is selected cyhal_dac takes care of reserving and configuring the opamp (OA1).
60 * By default cyhal_dac use VDDA voltage reference source. Use @ref cyhal_dac_set_reference() to change
61 * between @ref CYHAL_DAC_REF_VDDA and @ref CYHAL_DAC_REF_VREF voltage reference sources.
62 *
63 * \note When initializing the DAC via @ref cyhal_dac_init_cfg, if opamps are required (either for buffered output
64 * or for buffering the AREF output when @ref CYHAL_DAC_REF_VREF is used) then they must be separately configured
65 * via @ref cyhal_opamp_init_cfg before the DAC is initialized. However, once the DAC is initialized, the
66 * @ref cyhal_dac_set_power function will update the power mode for the opamp(s) in the same manner that it
67 * does for DAC instances initialized via @ref cyhal_dac_init.
68 * \note When the DAC has been initialized via @ref cyhal_dac_init_cfg, the @ref cyhal_dac_set_reference function
69 * is not supported and will return @ref CYHAL_DAC_RSLT_INVALID_CONFIGURATOR. This is because the @ref
70 * cyhal_dac_set_reference function needs to manipulate the configuration and routing for OA1, and in this scenario
71 * that configuration and routing is owned by the configurator.
72 */
73
74
75 #if (CYHAL_DRIVER_AVAILABLE_DAC)
76
77 #if defined(__cplusplus)
78 extern "C"
79 {
80 #endif
81
82 #define _CYHAL_DAC_VALUE_SCALING_FACTOR (UINT16_MAX / CY_CTDAC_UNSIGNED_MAX_CODE_VALUE)
83
84 static CTDAC_Type *const _cyhal_dac_base[] = {
85 #if (CY_IP_MXS40PASS_CTDAC_INSTANCES > 0)
86 CTDAC0,
87 #endif
88 #if (CY_IP_MXS40PASS_CTDAC_INSTANCES > 1)
89 CTDAC1,
90 #endif
91 #if (CY_IP_MXS40PASS_CTDAC_INSTANCES > 2)
92 #warning Unhandled CTDAC instance count
93 #endif
94 };
95
96 static const cy_stc_ctdac_config_t _CYHAL_DAC_DEFAULT_CONFIG =
97 {
98 .refSource = CY_CTDAC_REFSOURCE_VDDA,
99 .formatMode = CY_CTDAC_FORMAT_UNSIGNED,
100 .updateMode = CY_CTDAC_UPDATE_DIRECT_WRITE,
101 .deglitchMode = CY_CTDAC_DEGLITCHMODE_UNBUFFERED,
102 .outputMode = CY_CTDAC_OUTPUT_VALUE,
103 //.outputBuffer is configured automatically depending on pin choice
104 .deepSleep = CY_CTDAC_DEEPSLEEP_ENABLE,
105 .deglitchCycles = 0,
106 .value = 0,
107 .nextValue = 0,
108 .enableInterrupt = true,
109 .configClock = false,
110 // The following values are simply placeholders because configClock is false
111 .dividerType = CY_SYSCLK_DIV_8_BIT,
112 .dividerNum = 0,
113 .dividerIntValue = 0,
114 .dividerFracValue = 0,
115 };
116
117 #if defined(CY_IP_MXS40PASS_CTB)
118 static const cy_stc_ctb_opamp_config_t cyhal_opamp_default_config =
119 {
120 .deepSleep = CY_CTB_DEEPSLEEP_ENABLE,
121 .oaPower = CY_CTB_POWER_MEDIUM,
122 .oaMode = CY_CTB_MODE_OPAMP1X,
123 .oaPump = CY_CTB_PUMP_ENABLE,
124 .oaCompEdge = CY_CTB_COMP_EDGE_DISABLE,
125 .oaCompLevel = CY_CTB_COMP_DSI_TRIGGER_OUT_LEVEL,
126 .oaCompBypass = CY_CTB_COMP_BYPASS_SYNC,
127 .oaCompHyst = CY_CTB_COMP_HYST_DISABLE,
128 .oaCompIntrEn = true,
129 };
130
131 /* We can safely assume these indices even if we're owned by a configurator, because
132 * the hardware does not support any other connections to the vout and ref in terminals */
133 static const uint8_t OPAMP_IDX_OUTPUT = 0;
134 static const uint8_t OPAMP_IDX_REF = 1;
135 #endif
136
137 #if defined(CY_IP_MXS40PASS_CTB)
_cyhal_dac_is_output_buffered(const cyhal_dac_t * obj)138 static bool _cyhal_dac_is_output_buffered(const cyhal_dac_t *obj)
139 {
140 /* C06 enables the voutsw terminal on the CTDAC block, which is hard-wired to a pin */
141 return (0u == (obj->base_dac->CTDAC_SW & CTDAC_CTDAC_SW_CTDO_CO6_Msk));
142 }
143 #endif /* defined(CY_IP_MXS40PASS_CTB) */
144
_cyhal_dac_is_external_reference(const cyhal_dac_t * obj)145 static bool _cyhal_dac_is_external_reference(const cyhal_dac_t *obj)
146 {
147 /* CVD connects the DAC reference input to VDDA. It will be opened if the DAC is driven
148 * by an external reference (buffered through OA1) instead */
149 return (0u == (obj->base_dac->CTDAC_SW & CTDAC_CTDAC_SW_CTDD_CVD_Msk));
150 }
151
_cyhal_dac_convert_reference(cyhal_dac_ref_t ref)152 static uint32_t _cyhal_dac_convert_reference(cyhal_dac_ref_t ref)
153 {
154 switch(ref)
155 {
156 case CYHAL_DAC_REF_VDDA:
157 return CY_CTDAC_REFSOURCE_VDDA;
158 case CYHAL_DAC_REF_VREF:
159 return CY_CTDAC_REFSOURCE_EXTERNAL;
160 default:
161 CY_ASSERT(false);
162 return CY_CTDAC_REFSOURCE_VDDA;
163 }
164 }
165
166 #if defined(CY_IP_MXS40PASS_CTB)
_cyhal_dac_configure_oa0(cyhal_dac_t * obj,bool init)167 static cy_rslt_t _cyhal_dac_configure_oa0(cyhal_dac_t *obj, bool init)
168 {
169 cy_rslt_t result = CY_RSLT_SUCCESS;
170 CY_ASSERT(false == obj->owned_by_configurator);
171 if (init && (CYHAL_RSC_INVALID != obj->resource_opamp.type))
172 {
173 /* Configure OA0 for buffered output */
174 /* OA0 require non defaut CY_CTB_MODE_OPAMP10X */
175 cy_stc_ctb_opamp_config_t config = cyhal_opamp_default_config;
176 config.oaMode = CY_CTB_MODE_OPAMP10X;
177 result = Cy_CTB_OpampInit(obj->base_opamp, CY_CTB_OPAMP_0, &config);
178 Cy_CTB_SetAnalogSwitch(obj->base_opamp, CY_CTB_SWITCH_OA0_SW, CY_CTB_SW_OA0_NEG_OUT_MASK | CY_CTB_SW_OA0_OUT_SHORT_1X_10X_MASK, CY_CTB_SWITCH_CLOSE);
179 Cy_CTB_SetAnalogSwitch(obj->base_opamp, CY_CTB_SWITCH_CTD_SW, CY_CTB_SW_CTD_OUT_CHOLD_MASK | CY_CTB_SW_CTD_CHOLD_OA0_POS_MASK, CY_CTB_SWITCH_CLOSE);
180 cyhal_analog_ctb_init(obj->base_opamp);
181 }
182 else
183 {
184 /* Open switches OA0 if used */
185 Cy_CTB_SetAnalogSwitch(obj->base_opamp, CY_CTB_SWITCH_OA0_SW, CY_CTB_SW_OA0_NEG_OUT_MASK | CY_CTB_SW_OA0_OUT_SHORT_1X_10X_MASK, CY_CTB_SWITCH_OPEN);
186 Cy_CTB_SetAnalogSwitch(obj->base_opamp, CY_CTB_SWITCH_CTD_SW, CY_CTB_SW_CTD_OUT_CHOLD_MASK | CY_CTB_SW_CTD_CHOLD_OA0_POS_MASK, CY_CTB_SWITCH_OPEN);
187 cyhal_analog_ctb_free(obj->base_opamp);
188 }
189 return result;
190 }
191
_cyhal_dac_configure_oa1(cyhal_dac_t * obj,bool init)192 static cy_rslt_t _cyhal_dac_configure_oa1(cyhal_dac_t *obj, bool init)
193 {
194 cy_rslt_t result = CY_RSLT_SUCCESS;
195 CY_ASSERT(false == obj->owned_by_configurator);
196
197 if (init && (CYHAL_RSC_INVALID != obj->resource_aref_opamp.type))
198 {
199 /* Configure OA1 for buffered (AREF) voltage reference source */
200 result = Cy_CTB_OpampInit(obj->base_opamp, CY_CTB_OPAMP_1, &cyhal_opamp_default_config);
201 Cy_CTB_SetAnalogSwitch(obj->base_opamp, CY_CTB_SWITCH_OA1_SW, CY_CTB_SW_OA1_NEG_OUT_MASK | CY_CTB_SW_OA1_POS_AREF_MASK, CY_CTB_SWITCH_CLOSE);
202 Cy_CTB_SetAnalogSwitch(obj->base_opamp, CY_CTB_SWITCH_CTD_SW, CY_CTB_SW_CTD_REF_OA1_OUT_MASK, CY_CTB_SWITCH_CLOSE);
203 cyhal_analog_ctb_init(obj->base_opamp);
204 }
205 else
206 {
207 /* Open switches OA1 if used */
208 Cy_CTB_SetAnalogSwitch(obj->base_opamp, CY_CTB_SWITCH_OA1_SW, CY_CTB_SW_OA1_NEG_OUT_MASK | CY_CTB_SW_OA1_POS_AREF_MASK, CY_CTB_SWITCH_OPEN);
209 Cy_CTB_SetAnalogSwitch(obj->base_opamp, CY_CTB_SWITCH_CTD_SW, CY_CTB_SW_CTD_REF_OA1_OUT_MASK, CY_CTB_SWITCH_OPEN);
210 cyhal_analog_ctb_free(obj->base_opamp);
211 }
212 return result;
213 }
214 #endif
215
216 /*******************************************************************************
217 * DAC HAL Functions
218 *******************************************************************************/
_cyhal_dac_init_hw(cyhal_dac_t * obj,const cy_stc_ctdac_config_t * config)219 cy_rslt_t _cyhal_dac_init_hw(cyhal_dac_t *obj, const cy_stc_ctdac_config_t *config)
220 {
221 obj->base_dac = _cyhal_dac_base[obj->resource_dac.block_num];
222 #if (_CYHAL_DRIVER_AVAILABLE_COMP_CTB)
223 obj->base_opamp = _cyhal_ctb_base[obj->resource_dac.block_num];
224 #endif // _CYHAL_DRIVER_AVAILABLE_COMP_CTB
225 cy_rslt_t result = (cy_rslt_t)Cy_CTDAC_Init(obj->base_dac, config);
226
227 /* We deliberately don't initialize the opamp(s), if any, here. In the configurator
228 * flow, these are initialized by the application via separate calls to
229 * cyhal_opamp_init_cfg */
230
231 if (CY_RSLT_SUCCESS == result)
232 {
233 _cyhal_analog_init();
234 Cy_CTDAC_Enable(obj->base_dac);
235 }
236
237 return result;
238 }
239
cyhal_dac_init(cyhal_dac_t * obj,cyhal_gpio_t pin)240 cy_rslt_t cyhal_dac_init(cyhal_dac_t *obj, cyhal_gpio_t pin)
241 {
242 CY_ASSERT(NULL != obj);
243
244 /* Initial values */
245 cy_rslt_t result = CY_RSLT_SUCCESS;
246 memset(obj, 0, sizeof(cyhal_dac_t));
247 obj->resource_dac.type = CYHAL_RSC_INVALID;
248 obj->resource_opamp.type = CYHAL_RSC_INVALID;
249 obj->pin = CYHAL_NC_PIN_VALUE;
250 obj->resource_aref_opamp.type = CYHAL_RSC_INVALID;
251
252 const cyhal_resource_pin_mapping_t *opamp_map = NULL;
253
254 #ifdef CYHAL_PIN_MAP_DRIVE_MODE_DAC_CTDAC_VOUTSW
255 const cyhal_resource_pin_mapping_t *dac_map = _CYHAL_UTILS_GET_RESOURCE(pin, cyhal_pin_map_dac_ctdac_voutsw);
256 #else
257 const cyhal_resource_pin_mapping_t *dac_map = NULL;
258 #endif
259 if (NULL == dac_map)
260 {
261 /* Try to get buffered output pin if unbuffered is not specified. */
262 #ifdef CYHAL_PIN_MAP_DRIVE_MODE_OPAMP_OUT_10X
263 opamp_map = _CYHAL_UTILS_GET_RESOURCE(pin, cyhal_pin_map_opamp_out_10x);
264 #endif
265 }
266
267 /* Check if mapping is successful */
268 if ((NULL == dac_map) && (NULL == opamp_map))
269 {
270 result = CYHAL_DAC_RSLT_BAD_ARGUMENT;
271 }
272
273 #if defined(CY_IP_MXS40PASS_CTB)
274 /* Verify if opamp instance 0 is selected, buffered output can be connected to OA0 */
275 if ((NULL != opamp_map) && (OPAMP_IDX_OUTPUT != (opamp_map->channel_num)))
276 {
277 result = CYHAL_DAC_RSLT_BAD_ARGUMENT;
278 }
279 #endif
280
281 cyhal_resource_inst_t opamp_instance;
282 cyhal_resource_inst_t dac_instance;
283
284 #if defined(CY_IP_MXS40PASS_CTB)
285 if (NULL != opamp_map)
286 {
287 dac_instance.type = CYHAL_RSC_DAC;
288 dac_instance.block_num = opamp_map->block_num;
289 dac_instance.channel_num = 0;
290 }
291 else if (CY_RSLT_SUCCESS == result)
292 {
293 #endif
294 _CYHAL_UTILS_ASSIGN_RESOURCE(dac_instance, CYHAL_RSC_DAC, dac_map);
295 #if defined(CY_IP_MXS40PASS_CTB)
296 }
297 #endif
298
299 if (CY_RSLT_SUCCESS == result)
300 {
301 result = cyhal_hwmgr_reserve(&dac_instance);
302 }
303
304 if (CY_RSLT_SUCCESS == result)
305 {
306 obj->resource_dac = dac_instance;
307 }
308
309 if ((NULL != opamp_map) && (CY_RSLT_SUCCESS == result))
310 {
311 _CYHAL_UTILS_ASSIGN_RESOURCE(opamp_instance, CYHAL_RSC_OPAMP, opamp_map);
312 result = cyhal_hwmgr_reserve(&opamp_instance);
313 if (CY_RSLT_SUCCESS == result)
314 {
315 obj->resource_opamp = opamp_instance;
316 }
317 }
318
319 if (CY_RSLT_SUCCESS == result)
320 {
321 #if defined(CYHAL_PIN_MAP_DRIVE_MODE_DAC_CTDAC_VOUTSW)
322 if (NULL != dac_map)
323 {
324 result = _cyhal_utils_reserve_and_connect(dac_map, CYHAL_PIN_MAP_DRIVE_MODE_DAC_CTDAC_VOUTSW);
325 }
326 #endif
327 #if defined(CYHAL_PIN_MAP_DRIVE_MODE_OPAMP_OUT_10X)
328 if (NULL != opamp_map)
329 {
330 result = _cyhal_utils_reserve_and_connect(opamp_map, CYHAL_PIN_MAP_DRIVE_MODE_OPAMP_OUT_10X);
331 }
332 #endif
333
334 if (CY_RSLT_SUCCESS == result)
335 {
336 obj->pin = pin;
337 }
338 }
339
340 if (CY_RSLT_SUCCESS == result)
341 {
342 /* Verify is output buffered or not */
343 cy_stc_ctdac_config_t config = _CYHAL_DAC_DEFAULT_CONFIG;
344 config.outputBuffer = (obj->resource_opamp.type != CYHAL_RSC_INVALID) ? CY_CTDAC_OUTPUT_BUFFERED : CY_CTDAC_OUTPUT_UNBUFFERED;
345 result = _cyhal_dac_init_hw(obj, &config);
346 }
347
348 #if defined(CY_IP_MXS40PASS_CTB)
349 if ((CY_RSLT_SUCCESS == result) && (obj->resource_opamp.type != CYHAL_RSC_INVALID))
350 {
351 /* Init OA0 for buffered output, don't touch OA1 it may be used by opamp or comp */
352 result = _cyhal_dac_configure_oa0(obj, true);
353 }
354 #endif
355
356 if(CY_RSLT_SUCCESS != result)
357 {
358 /* Freeup resources in case of failure */
359 cyhal_dac_free(obj);
360 }
361 return result;
362 }
363
cyhal_dac_init_cfg(cyhal_dac_t * obj,const cyhal_dac_configurator_t * cfg)364 cy_rslt_t cyhal_dac_init_cfg(cyhal_dac_t *obj, const cyhal_dac_configurator_t *cfg)
365 {
366 memset(obj, 0, sizeof(cyhal_dac_t));
367 obj->owned_by_configurator = true;
368 obj->resource_dac = *cfg->resource;
369 obj->resource_opamp.type = CYHAL_RSC_INVALID;
370 obj->resource_aref_opamp.type = CYHAL_RSC_INVALID;
371 obj->pin = CYHAL_NC_PIN_VALUE;
372 cy_rslt_t result = _cyhal_dac_init_hw(obj, cfg->config);
373
374 if(CY_RSLT_SUCCESS != result)
375 {
376 cyhal_dac_free(obj);
377 }
378 return result;
379 }
380
cyhal_dac_free(cyhal_dac_t * obj)381 void cyhal_dac_free(cyhal_dac_t *obj)
382 {
383 if (NULL != obj->base_dac)
384 {
385 #if defined(CY_IP_MXS40PASS_CTB)
386 /* Power off OA1 if used */
387 if (_cyhal_dac_is_external_reference(obj))
388 {
389 Cy_CTB_SetPower(obj->base_opamp, _cyhal_opamp_convert_sel(OPAMP_IDX_REF), (cy_en_ctb_power_t)_cyhal_opamp_convert_power(CYHAL_POWER_LEVEL_OFF), CY_CTB_PUMP_ENABLE);
390 if(false == obj->owned_by_configurator)
391 {
392 (void)_cyhal_dac_configure_oa1(obj, false);
393 }
394 }
395
396 /* Power off OA0 if used */
397 if (_cyhal_dac_is_output_buffered(obj))
398 {
399 Cy_CTB_SetPower(obj->base_opamp, _cyhal_opamp_convert_sel(OPAMP_IDX_OUTPUT), (cy_en_ctb_power_t)_cyhal_opamp_convert_power(CYHAL_POWER_LEVEL_OFF), CY_CTB_PUMP_ENABLE);
400 if(false == obj->owned_by_configurator)
401 {
402 (void)_cyhal_dac_configure_oa0(obj, false);
403 }
404 }
405 #endif
406
407 _cyhal_analog_free();
408
409 Cy_CTDAC_Disable(obj->base_dac);
410
411 if(false == obj->owned_by_configurator)
412 {
413 cyhal_hwmgr_free(&obj->resource_dac);
414 if(CYHAL_RSC_INVALID != obj->resource_opamp.type)
415 {
416 cyhal_hwmgr_free(&obj->resource_opamp);
417 }
418 if(CYHAL_RSC_INVALID != obj->resource_aref_opamp.type)
419 {
420 cyhal_hwmgr_free(&obj->resource_aref_opamp);
421 }
422
423 _cyhal_utils_release_if_used(&(obj->pin));
424 }
425
426 obj->base_dac = NULL;
427 obj->base_opamp = NULL;
428 }
429 }
430
cyhal_dac_write(const cyhal_dac_t * obj,uint16_t value)431 void cyhal_dac_write(const cyhal_dac_t *obj, uint16_t value)
432 {
433 uint16_t scaled_value = value / _CYHAL_DAC_VALUE_SCALING_FACTOR;
434 Cy_CTDAC_SetValue(obj->base_dac, scaled_value);
435 }
436
cyhal_dac_write_mv(const cyhal_dac_t * obj,uint16_t value)437 cy_rslt_t cyhal_dac_write_mv(const cyhal_dac_t *obj, uint16_t value)
438 {
439 cy_rslt_t result = CY_RSLT_SUCCESS;
440 uint32_t reference_voltage_mv = 0;
441
442 if (_cyhal_dac_is_external_reference(obj))
443 {
444 reference_voltage_mv = cyhal_syspm_get_supply_voltage(CYHAL_VOLTAGE_SUPPLY_VDDA);
445
446 if (0 == reference_voltage_mv)
447 {
448 result = CYHAL_DAC_RSLT_BAD_REF_VOLTAGE;
449 }
450 }
451 else
452 {
453 /* AREF voltage in millivolts */
454 reference_voltage_mv = 1200;
455 }
456
457 if (result == CY_RSLT_SUCCESS)
458 {
459 uint32_t count = (value << 12) / reference_voltage_mv;
460 Cy_CTDAC_SetValue(obj->base_dac, count);
461 }
462
463 return result;
464 }
465
cyhal_dac_read(cyhal_dac_t * obj)466 uint16_t cyhal_dac_read(cyhal_dac_t *obj)
467 {
468 uint16_t value = (uint16_t)obj->base_dac->CTDAC_VAL;
469 uint16_t scaled_value = value * _CYHAL_DAC_VALUE_SCALING_FACTOR;
470 return scaled_value;
471 }
472
cyhal_dac_set_reference(cyhal_dac_t * obj,cyhal_dac_ref_t ref)473 cy_rslt_t cyhal_dac_set_reference(cyhal_dac_t *obj, cyhal_dac_ref_t ref)
474 {
475 cy_rslt_t result = CY_RSLT_SUCCESS;
476
477 if(false == obj->owned_by_configurator)
478 {
479 if (CYHAL_DAC_REF_VDDA == ref)
480 {
481 #if defined(CY_IP_MXS40PASS_CTB) /* If no opamps we just need to check that ref is VDDA, the only supported value */
482 /* Unreserve OA1, not needed for VDDA */
483 if (obj->resource_aref_opamp.type != CYHAL_RSC_INVALID)
484 {
485 cyhal_hwmgr_free(&obj->resource_aref_opamp);
486 obj->resource_aref_opamp.type = CYHAL_RSC_INVALID;
487
488 /* Freeup OA1. Not needed when VDDA reference is set */
489 result = _cyhal_dac_configure_oa1(obj, false);
490 }
491 }
492 else if (CYHAL_DAC_REF_VREF == ref)
493 {
494 if (obj->resource_aref_opamp.type == CYHAL_RSC_INVALID)
495 {
496 /* Reserve OA1 to be able connect to AREF voltage source */
497 obj->resource_aref_opamp.type = CYHAL_RSC_OPAMP;
498 obj->resource_aref_opamp.block_num = obj->resource_dac.block_num;
499 obj->resource_aref_opamp.channel_num = OPAMP_IDX_REF;
500
501 result = cyhal_hwmgr_reserve(&obj->resource_aref_opamp);
502 if (CY_RSLT_SUCCESS != result)
503 {
504 obj->resource_aref_opamp.type = CYHAL_RSC_INVALID;
505 }
506 else
507 {
508 /* Init OA1 to be able connect to AREF voltage source. OA0 is untouched */
509 result = _cyhal_dac_configure_oa1(obj, true);
510 }
511 }
512 #endif
513 }
514 else
515 {
516 result = CYHAL_DAC_RSLT_BAD_REF_VOLTAGE;
517 }
518
519 if (result == CY_RSLT_SUCCESS)
520 {
521 Cy_CTDAC_SetRef(obj->base_dac, (cy_en_ctdac_ref_source_t)_cyhal_dac_convert_reference(ref));
522 }
523 }
524 else
525 {
526 /* We don't own the configuration and routing of OA1, so we can't init/free it and open/close
527 * switches to it, as would be required to change the reference */
528 result = CYHAL_DAC_RSLT_INVALID_CONFIGURATOR;
529 }
530
531 return result;
532 }
533
cyhal_dac_set_power(cyhal_dac_t * obj,cyhal_power_level_t power)534 cy_rslt_t cyhal_dac_set_power(cyhal_dac_t *obj, cyhal_power_level_t power)
535 {
536 #if defined(CY_IP_MXS40PASS_CTB)
537 if (_cyhal_dac_is_output_buffered(obj) || _cyhal_dac_is_external_reference(obj))
538 {
539 /* Safe convert power level from HAL (cyhal_power_level_t) to PDL (cy_en_ctb_power_t) */
540 cy_en_ctb_power_t power_level = (cy_en_ctb_power_t)_cyhal_opamp_convert_power(power);
541 if(_cyhal_dac_is_output_buffered(obj))
542 {
543 Cy_CTB_SetPower(obj->base_opamp, _cyhal_opamp_convert_sel(OPAMP_IDX_OUTPUT), power_level, CY_CTB_PUMP_ENABLE);
544 }
545 if(_cyhal_dac_is_external_reference(obj))
546 {
547 Cy_CTB_SetPower(obj->base_opamp, _cyhal_opamp_convert_sel(OPAMP_IDX_REF), power_level, CY_CTB_PUMP_ENABLE);
548 }
549
550 bool full_ctb_owned = _cyhal_dac_is_output_buffered(obj) || _cyhal_dac_is_external_reference(obj);
551 if(full_ctb_owned)
552 {
553 if (CYHAL_POWER_LEVEL_OFF == power)
554 {
555 Cy_CTB_Disable(obj->base_opamp);
556 }
557 else
558 {
559 Cy_CTB_Enable(obj->base_opamp);
560 }
561 }
562 }
563 #endif
564 if (CYHAL_POWER_LEVEL_OFF == power)
565 {
566 Cy_CTDAC_Disable(obj->base_dac);
567 }
568 else
569 {
570 Cy_CTDAC_Enable(obj->base_dac);
571 }
572 return CY_RSLT_SUCCESS;
573 }
574
575 #if defined(__cplusplus)
576 }
577 #endif
578
579 #endif /* CYHAL_DRIVER_AVAILABLE_DAC */
580