1 /***************************************************************************/ /**
2 * \file cyhal_opamp.c
3 *
4 * \brief
5 * Provides a high level interface for interacting with the Infineon Continuous
6 * Time Block. 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 #include <string.h>
31 #include "cyhal_opamp.h"
32 #include "cyhal_gpio.h"
33 #include "cyhal_analog_common.h"
34 #include "cyhal_hwmgr.h"
35 #include "cy_ctb.h"
36
37 /**
38 * \addtogroup group_hal_impl_opamp Opamp (Operational Amplifier)
39 * \ingroup group_hal_impl
40 *
41 * \section group_hal_impl_opamp_power Power Level Mapping
42 * The following table shows how the HAL-defined power levels map to the hardware-specific power levels
43 * | HAL Power Level | Opamp Power Level |
44 * | ------------------------------ | ------------------- |
45 * | @ref CYHAL_POWER_LEVEL_HIGH | CY_CTB_POWER_HIGH |
46 * | @ref CYHAL_POWER_LEVEL_MEDIUM | CY_CTB_POWER_MEDIUM |
47 * | @ref CYHAL_POWER_LEVEL_LOW | CY_CTB_POWER_LOW |
48 * | @ref CYHAL_POWER_LEVEL_DEFAULT | CY_CTB_POWER_MEDIUM |
49 *
50 */
51
52 #if (CYHAL_DRIVER_AVAILABLE_OPAMP)
53
54 static const cy_stc_ctb_opamp_config_t _cyhal_opamp_default_config =
55 {
56 #if defined(CY_IP_MXS40PASS_CTB_INSTANCES)
57 .deepSleep = CY_CTB_DEEPSLEEP_ENABLE,
58 .oaPower = CY_CTB_POWER_OFF,
59 .oaMode = CY_CTB_MODE_OPAMP10X,
60 .oaPump = _CYHAL_CTB_PUMP_ENABLE,
61 .oaCompEdge = CY_CTB_COMP_EDGE_DISABLE,
62 .oaCompLevel = CY_CTB_COMP_DSI_TRIGGER_OUT_LEVEL,
63 .oaCompBypass = CY_CTB_COMP_BYPASS_SYNC,
64 .oaCompHyst = CY_CTB_COMP_HYST_DISABLE,
65 .oaCompIntrEn = true,
66 #else
67 .power = CY_CTB_POWER_OFF,
68 .outputMode = CY_CTB_MODE_OPAMP_EXTERNAL,
69 .pump = _CYHAL_CTB_PUMP_ENABLE,
70 .compEdge = CY_CTB_COMP_EDGE_DISABLE,
71 .compLevel = CY_CTB_COMP_TRIGGER_OUT_LEVEL,
72 .compBypass = false,
73 .compHyst = false,
74 .compIntrEn = true,
75 #endif
76 };
77
78 #if defined(__cplusplus)
79 extern "C"
80 {
81 #endif
82
_cyhal_opamp_init_hw(cyhal_opamp_t * obj,const cy_stc_ctb_opamp_config_t * cfg)83 cy_rslt_t _cyhal_opamp_init_hw(cyhal_opamp_t *obj, const cy_stc_ctb_opamp_config_t* cfg)
84 {
85 obj->base = _cyhal_ctb_base[obj->resource.block_num];
86 cy_rslt_t result = Cy_CTB_OpampInit(obj->base, _cyhal_opamp_convert_sel(obj->resource.channel_num), cfg);
87 if(CY_RSLT_SUCCESS == result)
88 {
89 obj->is_init_success = true;
90 /* Initialize the programmable analog */
91 cyhal_analog_ctb_init(obj->base);
92 }
93 return result;
94 }
95
cyhal_opamp_init(cyhal_opamp_t * obj,cyhal_gpio_t vin_p,cyhal_gpio_t vin_m,cyhal_gpio_t vout)96 cy_rslt_t cyhal_opamp_init(cyhal_opamp_t *obj, cyhal_gpio_t vin_p, cyhal_gpio_t vin_m, cyhal_gpio_t vout)
97 {
98 /* Check if obj is free */
99 CY_ASSERT(NULL != obj);
100
101 /* Initial values */
102 cy_rslt_t result = CY_RSLT_SUCCESS;
103 memset(obj, 0, sizeof(cyhal_opamp_t));
104 obj->base = NULL;
105 obj->resource.type = CYHAL_RSC_INVALID;
106 obj->is_init_success = false;
107
108 /* Validate input pins. vin_p and vout are mandatory pins, vin_m is optional. */
109 if ((NC == vin_p) || (NC == vout))
110 {
111 result = CYHAL_OPAMP_RSLT_ERR_INVALID_PIN;
112 }
113
114 /* Allocate resources */
115 if(CY_RSLT_SUCCESS == result)
116 {
117 result = _cyhal_opamp_init_common(&(obj->resource), CYHAL_OPAMP_RSLT_BAD_ARGUMENT, vin_p, vin_m, vout, NC /* comp_out unused by opamp */);
118 }
119
120
121 /* Configure the opamp */
122 if (result == CY_RSLT_SUCCESS)
123 {
124 obj->pin_vin_p = vin_p;
125 obj->pin_vin_m = vin_m;
126 obj->pin_vout = vout;
127
128 result = _cyhal_opamp_init_hw(obj, &_cyhal_opamp_default_config);
129 }
130
131 if (result == CY_RSLT_SUCCESS)
132 {
133 /* OPAMP Routing. Close input switches for OA0 or OA1. */
134 Cy_CTB_SetAnalogSwitch(obj->base, _cyhal_opamp_convert_switch(obj->resource.channel_num), _cyhal_opamp_pin_to_mask(obj->resource.channel_num, vin_p, vin_m, vout), _CYHAL_CTB_SW_CLOSE);
135 _cyhal_opamp_set_isolation_switch(obj->resource.channel_num, obj->base, true);
136 }
137
138 /* Free OPAMP in case of failure */
139 if (result != CY_RSLT_SUCCESS)
140 {
141 cyhal_opamp_free(obj);
142 }
143 return result;
144 }
145
cyhal_opamp_init_cfg(cyhal_opamp_t * obj,const cyhal_opamp_configurator_t * cfg)146 cy_rslt_t cyhal_opamp_init_cfg(cyhal_opamp_t *obj, const cyhal_opamp_configurator_t *cfg)
147 {
148 memset(obj, 0, sizeof(cyhal_opamp_t));
149 obj->owned_by_configurator = true;
150 obj->resource = *cfg->resource;
151 obj->is_init_success = false;
152 obj->pin_vin_p = NC;
153 obj->pin_vin_m = NC;
154 obj->pin_vout = NC;
155 cy_rslt_t result = _cyhal_opamp_init_hw(obj, cfg->config);
156 if(CY_RSLT_SUCCESS != result)
157 {
158 cyhal_opamp_free(obj);
159 }
160
161 return result;
162 }
163
cyhal_opamp_set_power(cyhal_opamp_t * obj,cyhal_power_level_t power)164 cy_rslt_t cyhal_opamp_set_power(cyhal_opamp_t *obj, cyhal_power_level_t power)
165 {
166 /* Safe convert power level from HAL (cyhal_power_level_t) to PDL (cy_en_ctb_power_t) */
167 cy_en_ctb_power_t power_level = (cy_en_ctb_power_t)_cyhal_opamp_convert_power(power);
168
169 Cy_CTB_SetPower(obj->base, _cyhal_opamp_convert_sel(obj->resource.channel_num), power_level, _CYHAL_CTB_PUMP_ENABLE);
170
171 return CY_RSLT_SUCCESS;
172 }
173
cyhal_opamp_free(cyhal_opamp_t * obj)174 void cyhal_opamp_free(cyhal_opamp_t *obj)
175 {
176 if (NULL != obj && NULL != obj->base)
177 {
178 if (obj->is_init_success)
179 {
180 cyhal_opamp_set_power(obj, CYHAL_POWER_LEVEL_OFF);
181 if(false == obj->owned_by_configurator)
182 {
183 Cy_CTB_SetAnalogSwitch(obj->base, _cyhal_opamp_convert_switch(obj->resource.channel_num), _cyhal_opamp_pin_to_mask(obj->resource.channel_num, obj->pin_vin_p, obj->pin_vin_m, obj->pin_vout), _CYHAL_CTB_SW_OPEN);
184 _cyhal_opamp_set_isolation_switch(obj->resource.channel_num, obj->base, false);
185 }
186 cyhal_analog_ctb_free(obj->base);
187 }
188 }
189
190 if((NULL != obj) && (CYHAL_RSC_INVALID != obj->resource.type))
191 {
192 if(false == obj->owned_by_configurator)
193 {
194 cyhal_hwmgr_free(&obj->resource);
195 }
196 obj->base = NULL;
197 obj->resource.type = CYHAL_RSC_INVALID;
198 }
199
200 if(NULL != obj)
201 {
202 _cyhal_utils_release_if_used(&(obj->pin_vin_p));
203 _cyhal_utils_release_if_used(&(obj->pin_vout));
204 _cyhal_utils_release_if_used(&(obj->pin_vin_m));
205 }
206 }
207
208 #if defined(__cplusplus)
209 }
210 #endif
211
212 #endif /* CYHAL_DRIVER_AVAILABLE_OPAMP */
213