1 /**************************************************************************//**
2 * @file
3 * @brief Operational Amplifier (OPAMP) peripheral API
4 * @author Energy Micro AS
5 * @version 3.0.0
6 ******************************************************************************
7 * @section License
8 * <b>(C) Copyright 2012 Energy Micro AS, http://www.energymicro.com</b>
9 *******************************************************************************
10 *
11 * Permission is granted to anyone to use this software for any purpose,
12 * including commercial applications, and to alter it and redistribute it
13 * freely, subject to the following restrictions:
14 *
15 * 1. The origin of this software must not be misrepresented; you must not
16 * claim that you wrote the original software.
17 * 2. Altered source versions must be plainly marked as such, and must not be
18 * misrepresented as being the original software.
19 * 3. This notice may not be removed or altered from any source distribution.
20 *
21 * DISCLAIMER OF WARRANTY/LIMITATION OF REMEDIES: Energy Micro AS has no
22 * obligation to support this Software. Energy Micro AS is providing the
23 * Software "AS IS", with no express or implied warranties of any kind,
24 * including, but not limited to, any implied warranties of merchantability
25 * or fitness for any particular purpose or warranties against infringement
26 * of any proprietary rights of a third party.
27 *
28 * Energy Micro AS will not be liable for any consequential, incidental, or
29 * special damages, or any other relief, or for any claim by any third party,
30 * arising from your use of this Software.
31 *
32 *****************************************************************************/
33 #include "em_part.h"
34 #if defined( OPAMP_PRESENT ) && ( OPAMP_COUNT == 1 )
35
36 #include "em_system.h"
37 #include "em_assert.h"
38 #include "em_opamp.h"
39
40 /***************************************************************************//**
41 * @addtogroup EM_Library
42 * @{
43 ******************************************************************************/
44
45
46 /***************************************************************************//**
47 * @addtogroup OPAMP
48 * @brief Operational Amplifier (OPAMP) peripheral API
49 * @details
50 * This module contains functions to:
51 * @li OPAMP_Enable() Configure and enable an opamp.
52 * @li OPAMP_Disable() Disable an opamp.
53 *
54 * All OPAMP functions assume that the DAC clock is running. If the DAC is not
55 * used, the clock can be turned off when the opamp's are configured.
56 *
57 * If the available gain values dont suit the application at hand, the resistor
58 * ladders can be disabled and external gain programming resistors used.
59 *
60 * A number of predefined opamp setup macros are available for configuration
61 * of the most common opamp topologies (see figures below).
62 *
63 * @note
64 * <em>The terms POSPAD and NEGPAD in the figures are used to indicate that these
65 * pads should be connected to a suitable signal ground.</em>
66 *
67 * \n<b>Unity gain voltage follower.</b>\n
68 * Use predefined macros @ref OPA_INIT_UNITY_GAIN and
69 * @ref OPA_INIT_UNITY_GAIN_OPA2.
70 * @verbatim
71
72 |\
73 ___________|+\
74 | \_______
75 ___|_ / |
76 | | / |
77 | |/ |
78 |___________|
79 @endverbatim
80 *
81 * \n<b>Non-inverting amplifier.</b>\n
82 * Use predefined macros @ref OPA_INIT_NON_INVERTING and
83 * @ref OPA_INIT_NON_INVERTING_OPA2.
84 * @verbatim
85
86 |\
87 ___________|+\
88 | \_______
89 ___|_ / |
90 | | / |
91 | |/ |
92 |_____R2____|
93 |
94 R1
95 |
96 NEGPAD @endverbatim
97 *
98 * \n<b>Inverting amplifier.</b>\n
99 * Use predefined macros @ref OPA_INIT_INVERTING and
100 * @ref OPA_INIT_INVERTING_OPA2.
101 * @verbatim
102
103 _____R2____
104 | |
105 | |\ |
106 ____R1_|___|_\ |
107 | \____|___
108 ___| /
109 | |+/
110 | |/
111 |
112 POSPAD @endverbatim
113 *
114 * \n<b>Cascaded non-inverting amplifiers.</b>\n
115 * Use predefined macros @ref OPA_INIT_CASCADED_NON_INVERTING_OPA0,
116 * @ref OPA_INIT_CASCADED_NON_INVERTING_OPA1 and
117 * @ref OPA_INIT_CASCADED_NON_INVERTING_OPA2.
118 * @verbatim
119
120 |\ |\ |\
121 ___________|+\ OPA0 ___________|+\ OPA1 ___________|+\ OPA2
122 | \_________| | \_________| | \_______
123 ___|_ / | ___|_ / | ___|_ / |
124 | | / | | | / | | | / |
125 | |/ | | |/ | | |/ |
126 |_____R2____| |_____R2____| |_____R2____|
127 | | |
128 R1 R1 R1
129 | | |
130 NEGPAD NEGPAD NEGPAD @endverbatim
131 *
132 * \n<b>Cascaded inverting amplifiers.</b>\n
133 * Use predefined macros @ref OPA_INIT_CASCADED_INVERTING_OPA0,
134 * @ref OPA_INIT_CASCADED_INVERTING_OPA1 and
135 * @ref OPA_INIT_CASCADED_INVERTING_OPA2.
136 * @verbatim
137
138 _____R2____ _____R2____ _____R2____
139 | | | | | |
140 | |\ | | |\ | | |\ |
141 ____R1_|___|_\ | ____R1_|___|_\ | ____R1_|___|_\ |
142 | \____|____| | \____|___| | \____|__
143 ___| / ___| / ___| /
144 | |+/ OPA0 | |+/ OPA1 | |+/ OPA2
145 | |/ | |/ | |/
146 | | |
147 POSPAD POSPAD POSPAD @endverbatim
148 *
149 * \n<b>Differential driver with two opamp's.</b>\n
150 * Use predefined macros @ref OPA_INIT_DIFF_DRIVER_OPA0 and
151 * @ref OPA_INIT_DIFF_DRIVER_OPA1.
152 * @verbatim
153
154 __________________________
155 | +
156 | _____R2____
157 |\ | | |
158 ___________|+\ OPA0 | | |\ OPA1 |
159 | \_________|____R1_|___|_\ | _
160 ___|_ / | | \____|______
161 | | / | ___| /
162 | |/ | | |+/
163 |________________| | |/
164 |
165 POSPAD @endverbatim
166 *
167 * \n<b>Differential receiver with three opamp's.</b>\n
168 * Use predefined macros @ref OPA_INIT_DIFF_RECEIVER_OPA0,
169 * @ref OPA_INIT_DIFF_RECEIVER_OPA1 and @ref OPA_INIT_DIFF_RECEIVER_OPA2.
170 * @verbatim
171
172 |\
173 __________|+\ OPA1
174 _ | \_________
175 ___|_ / | | _____R2____
176 | | / | | | |
177 | |/ | | | |\ |
178 |___________| |____R1_|___|_\ |
179 | \____|___
180 |\ ____R1_ ___| /
181 +__________|+\ OPA0 | | |+/ OPA2
182 | \_________| | |/
183 ___|_ / | R2
184 | | / | |
185 | |/ | NEGPAD OPA0
186 |___________|
187 @endverbatim
188 *
189 * @{
190 ******************************************************************************/
191
192 /*******************************************************************************
193 ************************** GLOBAL FUNCTIONS *******************************
194 ******************************************************************************/
195
196 /***************************************************************************//**
197 * @brief
198 * Disable an Operational Amplifier.
199 *
200 * @param[in] dac
201 * Pointer to DAC peripheral register block.
202 *
203 * @param[in] opa
204 * Selects an OPA, valid vaules are @ref OPA0, @ref OPA1 and @ref OPA2.
205 ******************************************************************************/
OPAMP_Disable(DAC_TypeDef * dac,OPAMP_TypeDef opa)206 void OPAMP_Disable( DAC_TypeDef *dac, OPAMP_TypeDef opa )
207 {
208 EFM_ASSERT( DAC_REF_VALID( dac ) );
209 EFM_ASSERT( DAC_OPA_VALID( opa ) );
210
211 if ( opa == OPA0 )
212 {
213 dac->CH0CTRL &= ~DAC_CH0CTRL_EN;
214 dac->OPACTRL &= ~DAC_OPACTRL_OPA0EN;
215 }
216 else if ( opa == OPA1 )
217 {
218 dac->CH1CTRL &= ~DAC_CH1CTRL_EN;
219 dac->OPACTRL &= ~DAC_OPACTRL_OPA1EN;
220 }
221 else /* OPA2 */
222 {
223 dac->OPACTRL &= ~DAC_OPACTRL_OPA2EN;
224 }
225 }
226
227
228 /***************************************************************************//**
229 * @brief
230 * Configure and enable an Operational Amplifier.
231 *
232 * @details
233 *
234 * @param[in] dac
235 * Pointer to DAC peripheral register block.
236 *
237 * @param[in] opa
238 * Selects an OPA, valid vaules are @ref OPA0, @ref OPA1 and @ref OPA2.
239 *
240 * @param[in] init
241 * Pointer to a structure containing OPAMP init information.
242 ******************************************************************************/
OPAMP_Enable(DAC_TypeDef * dac,OPAMP_TypeDef opa,const OPAMP_Init_TypeDef * init)243 void OPAMP_Enable( DAC_TypeDef *dac, OPAMP_TypeDef opa, const OPAMP_Init_TypeDef *init )
244 {
245 uint32_t offset;
246
247 EFM_ASSERT( DAC_REF_VALID( dac ) );
248 EFM_ASSERT( DAC_OPA_VALID( opa ) );
249 EFM_ASSERT( init->bias <= ( _DAC_BIASPROG_BIASPROG_MASK >>
250 _DAC_BIASPROG_BIASPROG_SHIFT ) );
251
252 if ( opa == OPA0 )
253 {
254 EFM_ASSERT( ( init->outPen & ~_DAC_OPA0MUX_OUTPEN_MASK ) == 0 );
255
256 dac->BIASPROG = ( dac->BIASPROG
257 & ~( _DAC_BIASPROG_BIASPROG_MASK |
258 DAC_BIASPROG_HALFBIAS ) ) |
259 ( init->bias << _DAC_BIASPROG_BIASPROG_SHIFT ) |
260 ( init->halfBias ? DAC_BIASPROG_HALFBIAS : 0 );
261
262 if ( init->defaultOffset )
263 {
264 offset = SYSTEM_GetCalibrationValue( &dac->CAL );
265 dac->CAL = ( dac->CAL & ~_DAC_CAL_CH0OFFSET_MASK ) |
266 ( offset & _DAC_CAL_CH0OFFSET_MASK );
267 }
268 else
269 {
270 EFM_ASSERT( init->offset <= ( _DAC_CAL_CH0OFFSET_MASK >>
271 _DAC_CAL_CH0OFFSET_SHIFT ) );
272
273 dac->CAL = ( dac->CAL & ~_DAC_CAL_CH0OFFSET_MASK ) |
274 ( init->offset << _DAC_CAL_CH0OFFSET_SHIFT );
275 }
276
277 dac->OPA0MUX = (uint32_t)init->resSel |
278 (uint32_t)init->outMode |
279 init->outPen |
280 (uint32_t)init->resInMux |
281 (uint32_t)init->negSel |
282 (uint32_t)init->posSel |
283 ( init->nextOut ? DAC_OPA0MUX_NEXTOUT : 0 ) |
284 ( init->npEn ? DAC_OPA0MUX_NPEN : 0 ) |
285 ( init->ppEn ? DAC_OPA0MUX_PPEN : 0 );
286
287 dac->CH0CTRL |= DAC_CH0CTRL_EN;
288 dac->OPACTRL = ( dac->OPACTRL
289 & ~( DAC_OPACTRL_OPA0SHORT |
290 _DAC_OPACTRL_OPA0LPFDIS_MASK |
291 DAC_OPACTRL_OPA0HCMDIS ) ) |
292 ( init->shortInputs ? DAC_OPACTRL_OPA0SHORT : 0 ) |
293 ( init->lpfPosPadDisable ?
294 DAC_OPACTRL_OPA0LPFDIS_PLPFDIS : 0 ) |
295 ( init->lpfNegPadDisable ?
296 DAC_OPACTRL_OPA0LPFDIS_NLPFDIS : 0 ) |
297 ( init->hcmDisable ? DAC_OPACTRL_OPA0HCMDIS : 0 ) |
298 ( DAC_OPACTRL_OPA0EN );
299 }
300 else if ( opa == OPA1 )
301 {
302 EFM_ASSERT( ( init->outPen & ~_DAC_OPA1MUX_OUTPEN_MASK ) == 0 );
303
304 dac->BIASPROG = ( dac->BIASPROG
305 & ~( _DAC_BIASPROG_BIASPROG_MASK |
306 DAC_BIASPROG_HALFBIAS ) ) |
307 ( init->bias << _DAC_BIASPROG_BIASPROG_SHIFT ) |
308 ( init->halfBias ? DAC_BIASPROG_HALFBIAS : 0 );
309
310 if ( init->defaultOffset )
311 {
312 offset = SYSTEM_GetCalibrationValue( &dac->CAL );
313 dac->CAL = ( dac->CAL & ~_DAC_CAL_CH1OFFSET_MASK ) |
314 ( offset & _DAC_CAL_CH1OFFSET_MASK );
315 }
316 else
317 {
318 EFM_ASSERT( init->offset <= ( _DAC_CAL_CH1OFFSET_MASK >>
319 _DAC_CAL_CH1OFFSET_SHIFT ) );
320
321 dac->CAL = ( dac->CAL & ~_DAC_CAL_CH1OFFSET_MASK ) |
322 ( init->offset << _DAC_CAL_CH1OFFSET_SHIFT );
323 }
324
325 dac->OPA1MUX = (uint32_t)init->resSel |
326 (uint32_t)init->outMode |
327 init->outPen |
328 (uint32_t)init->resInMux |
329 (uint32_t)init->negSel |
330 (uint32_t)init->posSel |
331 ( init->nextOut ? DAC_OPA1MUX_NEXTOUT : 0 ) |
332 ( init->npEn ? DAC_OPA1MUX_NPEN : 0 ) |
333 ( init->ppEn ? DAC_OPA1MUX_PPEN : 0 );
334
335 dac->CH1CTRL |= DAC_CH1CTRL_EN;
336 dac->OPACTRL = ( dac->OPACTRL
337 & ~( DAC_OPACTRL_OPA1SHORT |
338 _DAC_OPACTRL_OPA1LPFDIS_MASK |
339 DAC_OPACTRL_OPA1HCMDIS ) ) |
340 ( init->shortInputs ? DAC_OPACTRL_OPA1SHORT : 0 ) |
341 ( init->lpfPosPadDisable ?
342 DAC_OPACTRL_OPA1LPFDIS_PLPFDIS : 0 ) |
343 ( init->lpfNegPadDisable ?
344 DAC_OPACTRL_OPA1LPFDIS_NLPFDIS : 0 ) |
345 ( init->hcmDisable ? DAC_OPACTRL_OPA1HCMDIS : 0 ) |
346 ( DAC_OPACTRL_OPA1EN );
347 }
348 else /* OPA2 */
349 {
350 EFM_ASSERT( ( init->posSel == DAC_OPA2MUX_POSSEL_DISABLE ) ||
351 ( init->posSel == DAC_OPA2MUX_POSSEL_POSPAD ) ||
352 ( init->posSel == DAC_OPA2MUX_POSSEL_OPA1INP ) ||
353 ( init->posSel == DAC_OPA2MUX_POSSEL_OPATAP ) );
354
355 EFM_ASSERT( ( init->outMode & ~DAC_OPA2MUX_OUTMODE ) == 0 );
356
357 EFM_ASSERT( ( init->outPen & ~_DAC_OPA2MUX_OUTPEN_MASK ) == 0 );
358
359 dac->BIASPROG = ( dac->BIASPROG
360 & ~( _DAC_BIASPROG_OPA2BIASPROG_MASK |
361 DAC_BIASPROG_OPA2HALFBIAS ) ) |
362 ( init->bias << _DAC_BIASPROG_OPA2BIASPROG_SHIFT ) |
363 ( init->halfBias ? DAC_BIASPROG_OPA2HALFBIAS : 0 );
364
365 if ( init->defaultOffset )
366 {
367 offset = SYSTEM_GetCalibrationValue( &dac->OPAOFFSET );
368 dac->OPAOFFSET = ( dac->OPAOFFSET & ~_DAC_OPAOFFSET_OPA2OFFSET_MASK ) |
369 ( offset & _DAC_OPAOFFSET_OPA2OFFSET_MASK );
370 }
371 else
372 {
373 EFM_ASSERT( init->offset <= ( _DAC_OPAOFFSET_OPA2OFFSET_MASK >>
374 _DAC_OPAOFFSET_OPA2OFFSET_SHIFT ) );
375
376 dac->CAL = ( dac->CAL & ~_DAC_OPAOFFSET_OPA2OFFSET_MASK ) |
377 ( init->offset << _DAC_OPAOFFSET_OPA2OFFSET_SHIFT );
378 }
379
380 dac->OPA2MUX = (uint32_t)init->resSel |
381 (uint32_t)init->outMode |
382 init->outPen |
383 (uint32_t)init->resInMux |
384 (uint32_t)init->negSel |
385 (uint32_t)init->posSel |
386 ( init->nextOut ? DAC_OPA2MUX_NEXTOUT : 0 ) |
387 ( init->npEn ? DAC_OPA2MUX_NPEN : 0 ) |
388 ( init->ppEn ? DAC_OPA2MUX_PPEN : 0 );
389
390 dac->OPACTRL = ( dac->OPACTRL
391 & ~( DAC_OPACTRL_OPA2SHORT |
392 _DAC_OPACTRL_OPA2LPFDIS_MASK |
393 DAC_OPACTRL_OPA2HCMDIS ) ) |
394 ( init->shortInputs ? DAC_OPACTRL_OPA2SHORT : 0 ) |
395 ( init->lpfPosPadDisable ?
396 DAC_OPACTRL_OPA2LPFDIS_PLPFDIS : 0 ) |
397 ( init->lpfNegPadDisable ?
398 DAC_OPACTRL_OPA2LPFDIS_NLPFDIS : 0 ) |
399 ( init->hcmDisable ? DAC_OPACTRL_OPA2HCMDIS : 0 ) |
400 ( DAC_OPACTRL_OPA2EN );
401 }
402 }
403
404 /** @} (end addtogroup OPAMP) */
405 /** @} (end addtogroup EM_Library) */
406
407 #endif /* defined( OPAMP_PRESENT ) && ( OPAMP_COUNT == 1 ) */
408