2 ******************************************************************************
3 * @file stm32l1xx_hal_opamp.c
4 * @author MCD Application Team
6 * @date 5-September-2014
7 * @brief OPAMP HAL module driver.
9 * This file provides firmware functions to manage the following
10 * functionalities of the operational amplifiers (OPAMP1 ,... ,OPAMP3)
12 * + OPAMP configuration
16 * + Initialization and de-initialization functions
17 * + IO operation functions
18 * + Peripheral Control functions
19 * + Peripheral State functions
22 ================================================================================
23 ##### OPAMP Peripheral Features #####
24 ================================================================================
26 [..] The device integrates up to 3 operational amplifiers OPAMP1, OPAMP2,
27 OPAMP3 (OPAMP3 availability depends on device category)
29 (#) The OPAMP(s) provides several exclusive running modes.
33 (#) The OPAMP(s) provide(s) calibration capabilities.
34 (+) Calibration aims at correcting some offset for running mode.
35 (+) The OPAMP uses either factory calibration settings OR user defined
36 calibration (trimming) settings (i.e. trimming mode).
37 (+) The user defined settings can be figured out using self calibration
38 handled by HAL_OPAMP_SelfCalibrate, HAL_OPAMPEx_SelfCalibrateAll
39 (+) HAL_OPAMP_SelfCalibrate:
40 (++) Runs automatically the calibration in 2 steps: for transistors
41 differential pair high (PMOS) or low (NMOS)
42 (++) Enables the user trimming mode
43 (++) Updates the init structure with trimming values with fresh calibration
45 The user may store the calibration results for larger
46 (ex monitoring the trimming as a function of temperature
48 (++) for devices having several OPAMPs, HAL_OPAMPEx_SelfCalibrateAll
49 runs calibration of all OPAMPs in parallel to save trimming search
52 (#) Running mode: Standalone mode
53 (+) Gain is set externally (gain depends on external loads).
54 (+) Follower mode also possible externally by connecting the inverting input to
57 (#) Running mode: Follower mode
58 (+) No Inverting Input is connected.
59 (+) The OPAMP(s) output(s) are internally connected to inverting input
61 (#) The OPAMPs inverting input can be selected among the list shown
64 (#) The OPAMPs non inverting input can be selected among the list shown
67 [..] Table 1. OPAMPs inverting/non-inverting inputs for STM32L1 devices:
69 +--------------------------------------------------------------------------+
70 | | HAL param | OPAMP1 | OPAMP2 | OPAMP3(4) |
72 |----------------|------------|--------------|--------------|--------------|
73 | Inverting | VM0 | PA2 | PA7 | PC2 |
74 | input (1) | VM1 | VINM pin (2) | VINM pin (2) | VINM pin (2) |
75 |----------------|------------|--------------|--------------|--------------|
76 | Non Inverting | VP0 | PA1 | PA6 | PC1 |
77 | input | DAC_CH1 (3)| DAC_CH1 | DAC_CH1 | --- |
78 | | DAC_CH2 (3)| --- | DAC_CH2 | DAC_CH2 |
79 +--------------------------------------------------------------------------+
80 (1): NA in follower mode.
81 (2): OPAMP input OPAMPx_VINM are dedicated OPAMP pins, their availability
82 depends on device package.
83 (3): DAC channels 1 and 2 are connected internally to OPAMP. Nevertheless,
84 I/O pins connected to DAC can still be used as DAC output (pins PA4
86 (4): OPAMP3 availability depends on device category.
89 [..] Table 2. OPAMPs outputs for STM32L1 devices:
91 +--------------------------------------------------------+
92 | | OPAMP1 | OPAMP2 | OPAMP3(4) |
93 |-----------------|------------|------------|------------|
94 | Output | PA3 | PB0 | PC3 |
95 +--------------------------------------------------------+
96 (4) : OPAMP3 availability depends on device category
99 ##### How to use this driver #####
100 ================================================================================
104 ============================================
105 To run the opamp calibration self calibration:
107 (#) Start calibration using HAL_OPAMP_SelfCalibrate.
108 Store the calibration results.
111 ============================================
113 To use the opamp, perform the following steps:
115 (#) Fill in the HAL_OPAMP_MspInit() to
116 (+) Enable the OPAMP Peripheral clock using macro "__OPAMP_CLK_ENABLE()"
117 (++) Configure the opamp input AND output in analog mode using
118 HAL_GPIO_Init() to map the opamp output to the GPIO pin.
120 (#) Configure the opamp using HAL_OPAMP_Init() function:
122 (+) Select the inverting input
123 (+) Select the non-inverting input
124 (+) Select either factory or user defined trimming mode.
125 (+) If the user defined trimming mode is enabled, select PMOS & NMOS trimming values
126 (typ. settings returned by HAL_OPAMP_SelfCalibrate function).
128 (#) Enable the opamp using HAL_OPAMP_Start() function.
130 (#) Disable the opamp using HAL_OPAMP_Stop() function.
132 (#) Lock the opamp in running mode using HAL_OPAMP_Lock() function.
133 Caution: On STM32L1, HAL OPAMP lock is software lock only (not
134 hardware lock as on some other STM32 devices)
136 (#) If needed, unlock the opamp using HAL_OPAMPEx_Unlock() function.
138 *** Running mode: change of configuration while OPAMP ON ***
139 ============================================
140 To Re-configure OPAMP when OPAMP is ON (change on the fly)
141 (#) If needed, Fill in the HAL_OPAMP_MspInit()
142 (+) This is the case for instance if you wish to use new OPAMP I/O
144 (#) Configure the opamp using HAL_OPAMP_Init() function:
145 (+) As in configure case, selects first the parameters you wish to modify.
148 ******************************************************************************
151 * <h2><center>© COPYRIGHT(c) 2014 STMicroelectronics</center></h2>
153 * Redistribution and use in source and binary forms, with or without modification,
154 * are permitted provided that the following conditions are met:
155 * 1. Redistributions of source code must retain the above copyright notice,
156 * this list of conditions and the following disclaimer.
157 * 2. Redistributions in binary form must reproduce the above copyright notice,
158 * this list of conditions and the following disclaimer in the documentation
159 * and/or other materials provided with the distribution.
160 * 3. Neither the name of STMicroelectronics nor the names of its contributors
161 * may be used to endorse or promote products derived from this software
162 * without specific prior written permission.
164 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
165 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
166 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
167 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
168 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
169 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
170 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
171 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
172 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
173 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
175 ******************************************************************************
178 /* Includes ------------------------------------------------------------------*/
179 #include "stm32l1xx_hal.h"
181 /** @addtogroup STM32L1xx_HAL_Driver
185 /** @defgroup OPAMP OPAMP
186 * @brief OPAMP HAL module driver
190 #ifdef HAL_OPAMP_MODULE_ENABLED
192 #if defined (STM32L151xCA) || defined (STM32L151xD) || defined (STM32L152xCA) || defined (STM32L152xD) || defined (STM32L162xCA) || defined (STM32L162xD) || defined (STM32L151xE) || defined (STM32L152xE) || defined (STM32L162xE) || defined (STM32L162xC) || defined (STM32L152xC) || defined (STM32L151xC)
194 /* Private typedef -----------------------------------------------------------*/
195 /* Private define ------------------------------------------------------------*/
196 /* Private macro -------------------------------------------------------------*/
197 /* Private variables ---------------------------------------------------------*/
198 /* Private function prototypes -----------------------------------------------*/
199 /* Private functions ---------------------------------------------------------*/
201 /** @defgroup OPAMP_Exported_Functions OPAMP Exported Functions
205 /** @defgroup OPAMP_Exported_Functions_Group1 Initialization and de-initialization functions
206 * @brief Initialization and Configuration functions
209 ===============================================================================
210 ##### Initialization and de-initialization functions #####
211 ===============================================================================
212 [..] This section provides functions allowing to:
219 * @brief Initializes the OPAMP according to the specified
220 * parameters in the OPAMP_InitTypeDef and create the associated handle.
221 * @note If the selected opamp is locked, initialization can't be performed.
222 * To unlock the configuration, perform a system reset.
223 * @param hopamp: OPAMP handle
226 HAL_StatusTypeDef
HAL_OPAMP_Init(OPAMP_HandleTypeDef
* hopamp
)
228 HAL_StatusTypeDef status
= HAL_OK
;
229 uint32_t tmp_csr
= 0; /* Temporary variable to update register CSR, except bits ANAWSSELx, S7SEL2, OPA_RANGE, OPAxCALOUT */
231 /* Check the OPAMP handle allocation and lock status */
232 /* Init not allowed if calibration is ongoing */
233 if((hopamp
== HAL_NULL
) || (hopamp
->State
== HAL_OPAMP_STATE_BUSYLOCKED
)
234 || (hopamp
->State
== HAL_OPAMP_STATE_CALIBBUSY
) )
240 /* Check the parameter */
241 assert_param(IS_OPAMP_ALL_INSTANCE(hopamp
->Instance
));
243 /* Set OPAMP parameters */
244 assert_param(IS_OPAMP_FUNCTIONAL_NORMALMODE(hopamp
->Init
.Mode
));
245 assert_param(IS_OPAMP_NONINVERTING_INPUT(hopamp
->Init
.NonInvertingInput
));
246 assert_param(IS_OPAMP_POWERMODE(hopamp
->Init
.PowerMode
));
247 assert_param(IS_OPAMP_POWER_SUPPLY_RANGE(hopamp
->Init
.PowerSupplyRange
));
248 assert_param(IS_OPAMP_TRIMMING(hopamp
->Init
.UserTrimming
));
250 if (hopamp
->Init
.Mode
!= OPAMP_FOLLOWER_MODE
)
252 assert_param(IS_OPAMP_INVERTING_INPUT(hopamp
->Init
.InvertingInput
));
255 if (hopamp
->Init
.UserTrimming
== OPAMP_TRIMMING_USER
)
257 if (hopamp
->Init
.PowerMode
== OPAMP_POWERMODE_NORMAL
)
259 assert_param(IS_OPAMP_TRIMMINGVALUE(hopamp
->Init
.TrimmingValueP
));
260 assert_param(IS_OPAMP_TRIMMINGVALUE(hopamp
->Init
.TrimmingValueN
));
264 assert_param(IS_OPAMP_TRIMMINGVALUE(hopamp
->Init
.TrimmingValuePLowPower
));
265 assert_param(IS_OPAMP_TRIMMINGVALUE(hopamp
->Init
.TrimmingValueNLowPower
));
269 /* Call MSP init function */
270 HAL_OPAMP_MspInit(hopamp
);
273 /* Set OPAMP parameters */
274 /* - Set internal switches in function of: */
275 /* - OPAMP selected mode: standalone or follower. */
276 /* - Non-inverting input connection */
277 /* - Inverting input connection */
278 /* - Set power supply range */
279 /* - Set power mode and associated calibration parameters */
281 /* Get OPAMP CSR register into temporary variable */
282 tmp_csr
= OPAMP
->CSR
;
284 /* Open all switches on non-inverting input, inverting input and output */
286 CLEAR_BIT(tmp_csr
, __OPAMP_CSR_ALL_SWITCHES(hopamp
));
288 /* Set internal switches in function of OPAMP mode selected: standalone */
290 /* If follower mode is selected, feedback switch S3 is closed and */
291 /* inverting inputs switches are let opened. */
292 /* If standalone mode is selected, feedback switch S3 is let opened and */
293 /* the selected inverting inputs switch is closed. */
294 if (hopamp
->Init
.Mode
== OPAMP_FOLLOWER_MODE
)
296 /* Follower mode: Close switches S3 and SanB */
297 SET_BIT(tmp_csr
, __OPAMP_CSR_S3SELX(hopamp
));
301 /* Set internal switches in function of inverting input selected: */
302 /* Close switch to connect comparator inverting input to the selected */
303 /* input: dedicated IO pin or alternative IO pin available on some */
304 /* device packages. */
305 if (hopamp
->Init
.InvertingInput
== OPAMP_INVERTINGINPUT_VM0
)
307 /* Close switch to connect comparator non-inverting input to */
308 /* dedicated IO pin low-leakage. */
309 SET_BIT(tmp_csr
, __OPAMP_CSR_S4SELX(hopamp
));
313 /* Close switch to connect comparator inverting input to alternative */
314 /* IO pin available on some device packages. */
315 SET_BIT(tmp_csr
, __OPAMP_CSR_ANAWSELX(hopamp
));
319 /* Set internal switches in function of non-inverting input selected: */
320 /* Close switch to connect comparator non-inverting input to the selected */
321 /* input: dedicated IO pin or DAC channel. */
322 if (hopamp
->Init
.NonInvertingInput
== OPAMP_NONINVERTINGINPUT_VP0
)
324 /* Close switch to connect comparator non-inverting input to */
325 /* dedicated IO pin low-leakage. */
326 SET_BIT(tmp_csr
, __OPAMP_CSR_S5SELX(hopamp
));
328 else if (hopamp
->Init
.NonInvertingInput
== OPAMP_NONINVERTINGINPUT_DAC_CH1
)
331 /* Particular case for connection to DAC channel 1: */
332 /* OPAMP_NONINVERTINGINPUT_DAC_CH1 available on OPAMP1 and OPAMP2 only */
333 /* (OPAMP3 availability depends on device category). */
334 if ((hopamp
->Instance
== OPAMP1
) || (hopamp
->Instance
== OPAMP2
))
336 /* Close switch to connect comparator non-inverting input to */
338 SET_BIT(tmp_csr
, __OPAMP_CSR_S6SELX(hopamp
));
342 /* Set HAL status to error if another OPAMP instance as OPAMP1 or */
343 /* OPAMP2 is intended to be connected to DAC channel 2. */
347 else /* if (hopamp->Init.NonInvertingInput == */
348 /* OPAMP_NONINVERTINGINPUT_DAC_CH2 ) */
350 /* Particular case for connection to DAC channel 2: */
351 /* OPAMP_NONINVERTINGINPUT_DAC_CH2 available on OPAMP2 and OPAMP3 only */
352 /* (OPAMP3 availability depends on device category). */
353 if (hopamp
->Instance
== OPAMP2
)
355 /* Close switch to connect comparator non-inverting input to */
357 SET_BIT(tmp_csr
, OPAMP_CSR_S7SEL2
);
359 /* If OPAMP3 is selected (if available) */
360 else if (hopamp
->Instance
!= OPAMP1
)
362 /* Close switch to connect comparator non-inverting input to */
364 SET_BIT(tmp_csr
, __OPAMP_CSR_S6SELX(hopamp
));
368 /* Set HAL status to error if another OPAMP instance as OPAMP2 or */
369 /* OPAMP3 (if available) is intended to be connected to DAC channel 2.*/
374 /* Continue OPAMP configuration if settings of switches are correct */
375 if (status
!= HAL_ERROR
)
377 /* Set power mode and associated calibration parameters */
378 if (hopamp
->Init
.PowerMode
!= OPAMP_POWERMODE_LOWPOWER
)
380 /* Set normal mode */
381 CLEAR_BIT(tmp_csr
, __OPAMP_CSR_OPAXLPM(hopamp
));
383 if (hopamp
->Init
.UserTrimming
== OPAMP_TRIMMING_USER
)
385 /* Set calibration mode (factory or user) and values for */
386 /* transistors differential pair high (PMOS) and low (NMOS) for */
388 MODIFY_REG(OPAMP
->OTR
, OPAMP_OTR_OT_USER
|
389 __OPAMP_OFFSET_TRIM_SET(hopamp
, OPAMP_FACTORYTRIMMING_N
, OPAMP_TRIM_VALUE_MASK
) |
390 __OPAMP_OFFSET_TRIM_SET(hopamp
, OPAMP_FACTORYTRIMMING_P
, OPAMP_TRIM_VALUE_MASK
) ,
391 hopamp
->Init
.UserTrimming
|
392 __OPAMP_OFFSET_TRIM_SET(hopamp
, OPAMP_FACTORYTRIMMING_N
, hopamp
->Init
.TrimmingValueN
) |
393 __OPAMP_OFFSET_TRIM_SET(hopamp
, OPAMP_FACTORYTRIMMING_P
, hopamp
->Init
.TrimmingValueP
) );
397 /* Set calibration mode to factory */
398 CLEAR_BIT(OPAMP
->OTR
, OPAMP_OTR_OT_USER
);
404 /* Set low power mode */
405 SET_BIT(tmp_csr
, __OPAMP_CSR_OPAXLPM(hopamp
));
407 if (hopamp
->Init
.UserTrimming
== OPAMP_TRIMMING_USER
)
409 /* Set calibration mode to user trimming */
410 SET_BIT(OPAMP
->OTR
, OPAMP_OTR_OT_USER
);
412 /* Set values for transistors differential pair high (PMOS) and low */
413 /* (NMOS) for low power mode. */
414 MODIFY_REG(OPAMP
->LPOTR
, __OPAMP_OFFSET_TRIM_SET(hopamp
, OPAMP_FACTORYTRIMMING_N
, OPAMP_TRIM_VALUE_MASK
) |
415 __OPAMP_OFFSET_TRIM_SET(hopamp
, OPAMP_FACTORYTRIMMING_P
, OPAMP_TRIM_VALUE_MASK
) ,
416 __OPAMP_OFFSET_TRIM_SET(hopamp
, OPAMP_FACTORYTRIMMING_N
, hopamp
->Init
.TrimmingValueNLowPower
) |
417 __OPAMP_OFFSET_TRIM_SET(hopamp
, OPAMP_FACTORYTRIMMING_P
, hopamp
->Init
.TrimmingValuePLowPower
) );
421 /* Set calibration mode to factory trimming */
422 CLEAR_BIT(OPAMP
->OTR
, OPAMP_OTR_OT_USER
);
428 /* Configure the power supply range */
429 MODIFY_REG(tmp_csr
, OPAMP_CSR_AOP_RANGE
,
430 hopamp
->Init
.PowerSupplyRange
);
432 /* Set OPAMP CSR register from temporary variable */
433 /* This allows to apply all changes on one time, in case of update on */
434 /* the fly with OPAMP previously set and running: */
435 /* - to avoid hazardous transient switches settings (risk of short */
437 /* - to avoid interruption of input signal */
438 OPAMP
->CSR
= tmp_csr
;
441 /* Update the OPAMP state */
442 /* If coming from state reset: Update from state RESET to state READY */
443 /* else: remain in state READY or BUSY (no update) */
444 if (hopamp
->State
== HAL_OPAMP_STATE_RESET
)
446 hopamp
->State
= HAL_OPAMP_STATE_READY
;
456 * @brief DeInitializes the OPAMP peripheral
457 * @note Deinitialization can't be performed if the OPAMP configuration is locked.
458 * To unlock the configuration, perform a system reset.
459 * @param hopamp: OPAMP handle
462 HAL_StatusTypeDef
HAL_OPAMP_DeInit(OPAMP_HandleTypeDef
* hopamp
)
464 HAL_StatusTypeDef status
= HAL_OK
;
466 /* Check the OPAMP handle allocation */
467 /* Check if OPAMP locked */
468 /* DeInit not allowed if calibration is ongoing */
469 if((hopamp
== HAL_NULL
) || (hopamp
->State
== HAL_OPAMP_STATE_BUSYLOCKED
) \
470 || (hopamp
->State
== HAL_OPAMP_STATE_CALIBBUSY
))
477 /* Check the parameter */
478 assert_param(IS_OPAMP_ALL_INSTANCE(hopamp
->Instance
));
480 /* Open all switches on non-inverting input, inverting input and output */
482 CLEAR_BIT(OPAMP
->CSR
, __OPAMP_CSR_ALL_SWITCHES(hopamp
));
484 /* DeInit the low level hardware */
485 HAL_OPAMP_MspDeInit(hopamp
);
487 /* Update the OPAMP state*/
488 hopamp
->State
= HAL_OPAMP_STATE_RESET
;
491 /* Process unlocked */
492 __HAL_UNLOCK(hopamp
);
499 * @brief Initializes the OPAMP MSP.
500 * @param hopamp: OPAMP handle
503 __weak
void HAL_OPAMP_MspInit(OPAMP_HandleTypeDef
* hopamp
)
505 /* NOTE : This function Should not be modified, when the callback is needed,
506 the function "HAL_OPAMP_MspInit()" must be implemented in the user file.
511 * @brief DeInitializes OPAMP MSP.
512 * @param hopamp: OPAMP handle
515 __weak
void HAL_OPAMP_MspDeInit(OPAMP_HandleTypeDef
* hopamp
)
517 /* NOTE : This function Should not be modified, when the callback is needed,
518 the function "HAL_OPAMP_MspDeInit()" must be implemented in the user file.
527 /** @defgroup OPAMP_Exported_Functions_Group2 IO operation functions
528 * @brief IO operation functions
531 ===============================================================================
532 ##### IO operation functions #####
533 ===============================================================================
535 This subsection provides a set of functions allowing to manage the OPAMP
536 start, stop and calibration actions.
543 * @brief Start the opamp
544 * @param hopamp: OPAMP handle
548 HAL_StatusTypeDef
HAL_OPAMP_Start(OPAMP_HandleTypeDef
* hopamp
)
550 HAL_StatusTypeDef status
= HAL_OK
;
552 /* Check the OPAMP handle allocation */
553 /* Check if OPAMP locked */
554 if((hopamp
== HAL_NULL
) || (hopamp
->State
== HAL_OPAMP_STATE_BUSYLOCKED
))
560 /* Check the parameter */
561 assert_param(IS_OPAMP_ALL_INSTANCE(hopamp
->Instance
));
563 if(hopamp
->State
== HAL_OPAMP_STATE_READY
)
565 /* Enable the selected opamp */
566 CLEAR_BIT (OPAMP
->CSR
, __OPAMP_CSR_OPAXPD(hopamp
));
568 /* Update the OPAMP state */
569 /* From HAL_OPAMP_STATE_READY to HAL_OPAMP_STATE_BUSY */
570 hopamp
->State
= HAL_OPAMP_STATE_BUSY
;
582 * @brief Stop the opamp
583 * @param hopamp: OPAMP handle
586 HAL_StatusTypeDef
HAL_OPAMP_Stop(OPAMP_HandleTypeDef
* hopamp
)
588 HAL_StatusTypeDef status
= HAL_OK
;
590 /* Check the OPAMP handle allocation */
591 /* Check if OPAMP locked */
592 /* Check if OPAMP calibration ongoing */
593 if((hopamp
== HAL_NULL
) || (hopamp
->State
== HAL_OPAMP_STATE_BUSYLOCKED
) \
594 || (hopamp
->State
== HAL_OPAMP_STATE_CALIBBUSY
))
600 /* Check the parameter */
601 assert_param(IS_OPAMP_ALL_INSTANCE(hopamp
->Instance
));
603 if(hopamp
->State
== HAL_OPAMP_STATE_BUSY
)
605 /* Disable the selected opamp */
606 SET_BIT (OPAMP
->CSR
, __OPAMP_CSR_OPAXPD(hopamp
));
608 /* Update the OPAMP state*/
609 /* From HAL_OPAMP_STATE_BUSY to HAL_OPAMP_STATE_READY*/
610 hopamp
->State
= HAL_OPAMP_STATE_READY
;
621 * @brief Run the self calibration of one OPAMP
622 * @note Trimming values (PMOS & NMOS) are updated and user trimming is
623 * enabled is calibration is succesful.
624 * @note Calibration is performed in the mode specified in OPAMP init
625 * structure (mode normal or low-power). To perform calibration for
626 * both modes, repeat this function twice after OPAMP init structure
627 * accordingly updated.
628 * @note Calibration runs about 10 ms (5 dichotmy steps, repeated for P
629 * and N transistors: 10 steps with 1 ms for each step).
630 * @param hopamp: handle
631 * @retval Updated offset trimming values (PMOS & NMOS), user trimming is enabled
634 HAL_StatusTypeDef
HAL_OPAMP_SelfCalibrate(OPAMP_HandleTypeDef
* hopamp
)
636 HAL_StatusTypeDef status
= HAL_OK
;
638 uint32_t* opamp_trimmingvalue
= 0;
639 uint32_t opamp_trimmingvaluen
= 0;
640 uint32_t opamp_trimmingvaluep
= 0;
642 uint32_t trimming_diff_pair
= 0; /* Selection of differential transistors pair high or low */
644 __IO
uint32_t* tmp_opamp_reg_trimming
; /* Selection of register of trimming depending on power mode: OTR or LPOTR */
645 uint32_t tmp_opamp_otr_otuser
= 0; /* Selection of bit OPAMP_OTR_OT_USER depending on trimming register pointed: OTR or LPOTR */
647 uint32_t tmp_Opaxcalout_DefaultSate
= 0; /* Bit OPAMP_CSR_OPAXCALOUT default state when trimming value is 00000b. Used to detect the bit toggling */
649 uint32_t tmp_OpaxSwitchesContextBackup
= 0;
651 uint8_t trimming_diff_pair_iteration_count
= 0;
655 /* Check the OPAMP handle allocation */
656 /* Check if OPAMP locked */
657 if((hopamp
== HAL_NULL
) || (hopamp
->State
== HAL_OPAMP_STATE_BUSYLOCKED
))
664 /* Check if OPAMP in calibration mode and calibration not yet enable */
665 if(hopamp
->State
== HAL_OPAMP_STATE_READY
)
667 /* Check the parameter */
668 assert_param(IS_OPAMP_ALL_INSTANCE(hopamp
->Instance
));
669 assert_param(IS_OPAMP_POWERMODE(hopamp
->Init
.PowerMode
));
671 /* Update OPAMP state */
672 hopamp
->State
= HAL_OPAMP_STATE_CALIBBUSY
;
674 /* Backup of switches configuration to restore it at the end of the */
676 tmp_OpaxSwitchesContextBackup
= READ_BIT(OPAMP
->CSR
, __OPAMP_CSR_ALL_SWITCHES(hopamp
));
678 /* Open all switches on non-inverting input, inverting input and output */
680 CLEAR_BIT(OPAMP
->CSR
, __OPAMP_CSR_ALL_SWITCHES(hopamp
));
682 /* Set calibration mode to user programmed trimming values */
683 SET_BIT(OPAMP
->OTR
, OPAMP_OTR_OT_USER
);
686 /* Select trimming settings depending on power mode */
687 if (hopamp
->Init
.PowerMode
== OPAMP_POWERMODE_NORMAL
)
689 tmp_opamp_otr_otuser
= OPAMP_OTR_OT_USER
;
690 tmp_opamp_reg_trimming
= &OPAMP
->OTR
;
694 tmp_opamp_otr_otuser
= 0x00000000;
695 tmp_opamp_reg_trimming
= &OPAMP
->LPOTR
;
699 /* Enable the selected opamp */
700 CLEAR_BIT (OPAMP
->CSR
, __OPAMP_CSR_OPAXPD(hopamp
));
702 /* Perform trimming for both differential transistors pair high and low */
703 for (trimming_diff_pair_iteration_count
= 0; trimming_diff_pair_iteration_count
<=1; trimming_diff_pair_iteration_count
++)
705 if (trimming_diff_pair_iteration_count
== 0)
707 /* Calibration of transistors differential pair high (NMOS) */
708 trimming_diff_pair
= OPAMP_FACTORYTRIMMING_N
;
709 opamp_trimmingvalue
= &opamp_trimmingvaluen
;
711 /* Set bit OPAMP_CSR_OPAXCALOUT default state when trimming value */
712 /* is 00000b. Used to detect the bit toggling during trimming. */
713 tmp_Opaxcalout_DefaultSate
= RESET
;
715 /* Enable calibration for N differential pair */
716 MODIFY_REG(OPAMP
->CSR
, __OPAMP_CSR_OPAXCAL_L(hopamp
),
717 __OPAMP_CSR_OPAXCAL_H(hopamp
) );
719 else /* (trimming_diff_pair_iteration_count == 1) */
721 /* Calibration of transistors differential pair low (PMOS) */
722 trimming_diff_pair
= OPAMP_FACTORYTRIMMING_P
;
723 opamp_trimmingvalue
= &opamp_trimmingvaluep
;
725 /* Set bit OPAMP_CSR_OPAXCALOUT default state when trimming value */
726 /* is 00000b. Used to detect the bit toggling during trimming. */
727 tmp_Opaxcalout_DefaultSate
= __OPAMP_CSR_OPAXCALOUT(hopamp
);
729 /* Enable calibration for P differential pair */
730 MODIFY_REG(OPAMP
->CSR
, __OPAMP_CSR_OPAXCAL_H(hopamp
),
731 __OPAMP_CSR_OPAXCAL_L(hopamp
) );
735 /* Perform calibration parameter search by dichotomy sweep */
736 /* - Delta initial value 16: for 5 dichotomy steps: 16 for the */
737 /* initial range, then successive delta sweeps (8, 4, 2, 1). */
738 /* can extend the search range to +/- 15 units. */
739 /* - Trimming initial value 15: search range will go from 0 to 30 */
740 /* (Trimming value 31 is forbidden). */
741 *opamp_trimmingvalue
= 15;
746 /* Set candidate trimming */
747 MODIFY_REG(*tmp_opamp_reg_trimming
, __OPAMP_OFFSET_TRIM_SET(hopamp
, trimming_diff_pair
, OPAMP_TRIM_VALUE_MASK
) ,
748 __OPAMP_OFFSET_TRIM_SET(hopamp
, trimming_diff_pair
, *opamp_trimmingvalue
) | tmp_opamp_otr_otuser
);
750 /* Offset trimming time: during calibration, minimum time needed */
751 /* between two steps to have 1 mV accuracy. */
752 HAL_Delay(OPAMP_TRIMMING_DELAY
);
754 /* Divide range by 2 to continue dichotomy sweep */
757 /* Set trimming values for next iteration in function of trimming */
758 /* result toggle (versus initial state). */
759 if (READ_BIT(OPAMP
->CSR
, __OPAMP_CSR_OPAXCALOUT(hopamp
)) != tmp_Opaxcalout_DefaultSate
)
761 /* If calibration output is has toggled, try lower trimming */
762 *opamp_trimmingvalue
-= delta
;
766 /* If calibration output is has not toggled, try higher trimming */
767 *opamp_trimmingvalue
+= delta
;
773 /* Disable calibration for P and N differential pairs */
774 /* Disable the selected opamp */
775 CLEAR_BIT (OPAMP
->CSR
, (__OPAMP_CSR_OPAXCAL_H(hopamp
) |
776 __OPAMP_CSR_OPAXCAL_L(hopamp
) |
777 __OPAMP_CSR_OPAXPD(hopamp
)) );
779 /* Backup of switches configuration to restore it at the end of the */
781 SET_BIT(OPAMP
->CSR
, tmp_OpaxSwitchesContextBackup
);
783 /* Self calibration is successful */
784 /* Store calibration (user trimming) results in init structure. */
786 /* Set user trimming mode */
787 hopamp
->Init
.UserTrimming
= OPAMP_TRIMMING_USER
;
789 /* Affect calibration parameters depending on mode normal/low power */
790 if (hopamp
->Init
.PowerMode
!= OPAMP_POWERMODE_LOWPOWER
)
792 /* Write calibration result N */
793 hopamp
->Init
.TrimmingValueN
= opamp_trimmingvaluen
;
794 /* Write calibration result P */
795 hopamp
->Init
.TrimmingValueP
= opamp_trimmingvaluep
;
799 /* Write calibration result N */
800 hopamp
->Init
.TrimmingValueNLowPower
= opamp_trimmingvaluen
;
801 /* Write calibration result P */
802 hopamp
->Init
.TrimmingValuePLowPower
= opamp_trimmingvaluep
;
805 /* Update OPAMP state */
806 hopamp
->State
= HAL_OPAMP_STATE_READY
;
811 /* OPAMP can not be calibrated from this mode */
820 * @brief Return the OPAMP factory trimming value
821 * Caution: On STM32L1 OPAMP, user can retrieve factory trimming if
822 * OPAMP has never been set to user trimming before.
823 * Therefore, this fonction must be called when OPAMP init
824 * parameter "UserTrimming" is set to trimming factory,
825 * and before OPAMP calibration (function
826 * "HAL_OPAMP_SelfCalibrate()").
827 * Otherwise, factory triming value cannot be retrieved and
828 * error status is returned.
829 * @param hopamp : OPAMP handle
830 * @param trimmingoffset : Trimming offset (P or N)
831 * This parameter must be a value of @ref OPAMP_FactoryTrimming
832 * @note Calibration parameter retrieved is corresponding to the mode
833 * specified in OPAMP init structure (mode normal or low-power).
834 * To retrieve calibration parameters for both modes, repeat this
835 * function after OPAMP init structure accordingly updated.
836 * @retval Trimming value (P or N): range: 0->31
837 * or OPAMP_FACTORYTRIMMING_DUMMY if trimming value is not available
840 OPAMP_TrimmingValueTypeDef
HAL_OPAMP_GetTrimOffset (OPAMP_HandleTypeDef
*hopamp
, uint32_t trimmingoffset
)
842 OPAMP_TrimmingValueTypeDef trimmingvalue
;
843 __IO
uint32_t* tmp_opamp_reg_trimming
; /* Selection of register of trimming depending on power mode: OTR or LPOTR */
845 /* Check the OPAMP handle allocation */
846 /* Value can be retrieved in HAL_OPAMP_STATE_READY state */
847 if((hopamp
== HAL_NULL
) || (hopamp
->State
== HAL_OPAMP_STATE_RESET
)
848 || (hopamp
->State
== HAL_OPAMP_STATE_BUSY
)
849 || (hopamp
->State
== HAL_OPAMP_STATE_CALIBBUSY
)
850 || (hopamp
->State
== HAL_OPAMP_STATE_BUSYLOCKED
))
852 trimmingvalue
= OPAMP_FACTORYTRIMMING_DUMMY
;
856 /* Check the parameter */
857 assert_param(IS_OPAMP_ALL_INSTANCE(hopamp
->Instance
));
858 assert_param(IS_OPAMP_FACTORYTRIMMING(trimmingoffset
));
859 assert_param(IS_OPAMP_POWERMODE(hopamp
->Init
.PowerMode
));
861 /* Check the trimming mode */
862 if (hopamp
->Init
.UserTrimming
== OPAMP_TRIMMING_USER
)
864 /* This fonction must called when OPAMP init parameter "UserTrimming" */
865 /* is set to trimming factory, and before OPAMP calibration (function */
866 /* "HAL_OPAMP_SelfCalibrate()"). */
867 /* Otherwise, factory triming value cannot be retrieved and error */
868 /* status is returned. */
869 trimmingvalue
= OPAMP_FACTORYTRIMMING_DUMMY
;
873 /* Select trimming settings depending on power mode */
874 if (hopamp
->Init
.PowerMode
== OPAMP_POWERMODE_NORMAL
)
876 tmp_opamp_reg_trimming
= &OPAMP
->OTR
;
880 tmp_opamp_reg_trimming
= &OPAMP
->LPOTR
;
883 /* Get factory trimming */
884 trimmingvalue
= ((*tmp_opamp_reg_trimming
>> __OPAMP_OFFSET_TRIM_BITSPOSITION(hopamp
, trimmingoffset
)) & OPAMP_TRIM_VALUE_MASK
);
888 return trimmingvalue
;
899 /** @defgroup OPAMP_Exported_Functions_Group3 Peripheral Control functions
900 * @brief Peripheral Control functions
903 ===============================================================================
904 ##### Peripheral Control functions #####
905 ===============================================================================
913 * @brief Lock the selected opamp configuration.
914 * Caution: On STM32L1, HAL OPAMP lock is software lock only (not
915 * hardware lock as on some other STM32 devices)
916 * @param hopamp: OPAMP handle
919 HAL_StatusTypeDef
HAL_OPAMP_Lock(OPAMP_HandleTypeDef
* hopamp
)
921 HAL_StatusTypeDef status
= HAL_OK
;
923 /* Check the OPAMP handle allocation */
924 /* Check if OPAMP locked */
925 /* OPAMP can be locked when enabled and running in normal mode */
926 /* It is meaningless otherwise */
927 if((hopamp
== HAL_NULL
) || (hopamp
->State
== HAL_OPAMP_STATE_RESET
) \
928 || (hopamp
->State
== HAL_OPAMP_STATE_READY
) \
929 || (hopamp
->State
== HAL_OPAMP_STATE_CALIBBUSY
)\
930 || (hopamp
->State
== HAL_OPAMP_STATE_BUSYLOCKED
))
938 /* Check the parameter */
939 assert_param(IS_OPAMP_ALL_INSTANCE(hopamp
->Instance
));
941 /* OPAMP state changed to locked */
942 hopamp
->State
= HAL_OPAMP_STATE_BUSYLOCKED
;
952 /** @defgroup OPAMP_Exported_Functions_Group4 Peripheral State functions
953 * @brief Peripheral State functions
956 ===============================================================================
957 ##### Peripheral State functions #####
958 ===============================================================================
960 This subsection permit to get in run-time the status of the peripheral.
967 * @brief Return the OPAMP state
968 * @param hopamp : OPAMP handle
971 HAL_OPAMP_StateTypeDef
HAL_OPAMP_GetState(OPAMP_HandleTypeDef
* hopamp
)
973 /* Check the OPAMP handle allocation */
974 if(hopamp
== HAL_NULL
)
976 return HAL_OPAMP_STATE_RESET
;
979 /* Check the parameter */
980 assert_param(IS_OPAMP_ALL_INSTANCE(hopamp
->Instance
));
982 return hopamp
->State
;
993 #endif /* STM32L151xCA || STM32L151xD || STM32L152xCA || STM32L152xD || STM32L162xCA || STM32L162xD || STM32L151xE || STM32L152xE || STM32L162xE || STM32L162xC || STM32L152xC || STM32L151xC */
995 #endif /* HAL_OPAMP_MODULE_ENABLED */
1004 /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/