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