1 /**
2 ******************************************************************************
3 * @file stm32l4xx_hal_opamp.c
4 * @author MCD Application Team
5 * @brief OPAMP HAL module driver.
6 * This file provides firmware functions to manage the following
7 * functionalities of the operational amplifier(s) peripheral:
8 * + Initialization and de-initialization functions
9 * + IO operation functions
10 * + Peripheral Control functions
11 * + Peripheral State functions
12 *
13 ******************************************************************************
14 * @attention
15 *
16 * Copyright (c) 2017 STMicroelectronics.
17 * All rights reserved.
18 *
19 * This software is licensed under terms that can be found in the LICENSE file
20 * in the root directory of this software component.
21 * If no LICENSE file comes with this software, it is provided AS-IS.
22 *
23 ******************************************************************************
24 @verbatim
25 ================================================================================
26 ##### OPAMP Peripheral Features #####
27 ================================================================================
28
29 [..] The device integrates 1 or 2 operational amplifiers OPAMP1 & OPAMP2
30
31 (#) The OPAMP(s) provide(s) several exclusive running modes.
32 (++) 1 OPAMP: STM32L412xx STM32L422xx STM32L431xx STM32L432xx STM32L433xx STM32L442xx STM32L443xx
33 (++) 2 OPAMP: STM32L471xx STM32L475xx STM32L476xx STM32L485xx STM32L486xx
34
35 (#) The OPAMP(s) provide(s) several exclusive running modes.
36 (++) Standalone mode
37 (++) Programmable Gain Amplifier (PGA) mode (Resistor feedback output)
38 (++) Follower mode
39
40 (#) All OPAMP (same for all OPAMPs) can operate in
41 (++) Either Low range (VDDA < 2.4V) power supply
42 (++) Or High range (VDDA > 2.4V) power supply
43
44 (#) Each OPAMP(s) can be configured in normal and low power mode.
45
46 (#) The OPAMP(s) provide(s) calibration capabilities.
47 (++) Calibration aims at correcting some offset for running mode.
48 (++) The OPAMP uses either factory calibration settings OR user defined
49 calibration (trimming) settings (i.e. trimming mode).
50 (++) The user defined settings can be figured out using self calibration
51 handled by HAL_OPAMP_SelfCalibrate, HAL_OPAMPEx_SelfCalibrateAll
52 (++) HAL_OPAMP_SelfCalibrate:
53 (+++) Runs automatically the calibration.
54 (+++) Enables the user trimming mode
55 (+++) Updates the init structure with trimming values with fresh calibration
56 results.
57 The user may store the calibration results for larger
58 (ex monitoring the trimming as a function of temperature
59 for instance)
60 (+++) HAL_OPAMPEx_SelfCalibrateAll
61 runs calibration of all OPAMPs in parallel to save search time.
62
63 (#) Running mode: Standalone mode
64 (++) Gain is set externally (gain depends on external loads).
65 (++) Follower mode also possible externally by connecting the inverting input to
66 the output.
67
68 (#) Running mode: Follower mode
69 (++) No Inverting Input is connected.
70
71 (#) Running mode: Programmable Gain Amplifier (PGA) mode
72 (Resistor feedback output)
73 (++) The OPAMP(s) output(s) can be internally connected to resistor feedback
74 output.
75 (++) OPAMP gain is either 2, 4, 8 or 16.
76
77 (#) The OPAMPs inverting input can be selected according to the Reference Manual
78 "OPAMP function description" chapter.
79
80 (#) The OPAMPs non inverting input can be selected according to the Reference Manual
81 "OPAMP function description" chapter.
82
83
84 ##### How to use this driver #####
85 ================================================================================
86 [..]
87
88 *** Power supply range ***
89 ============================================
90 [..] To run in low power mode:
91
92 (#) Configure the OPAMP using HAL_OPAMP_Init() function:
93 (++) Select OPAMP_POWERSUPPLY_LOW (VDDA lower than 2.4V)
94 (++) Otherwise select OPAMP_POWERSUPPLY_HIGH (VDDA higher than 2.4V)
95
96 *** Low / normal power mode ***
97 ============================================
98 [..] To run in low power mode:
99
100 (#) Configure the OPAMP using HAL_OPAMP_Init() function:
101 (++) Select OPAMP_POWERMODE_LOWPOWER
102 (++) Otherwise select OPAMP_POWERMODE_NORMALPOWER
103
104 *** Calibration ***
105 ============================================
106 [..] To run the OPAMP calibration self calibration:
107
108 (#) Start calibration using HAL_OPAMP_SelfCalibrate.
109 Store the calibration results.
110
111 *** Running mode ***
112 ============================================
113
114 [..] To use the OPAMP, perform the following steps:
115
116 (#) Fill in the HAL_OPAMP_MspInit() to
117 (++) Enable the OPAMP Peripheral clock using macro __HAL_RCC_OPAMP_CLK_ENABLE()
118 (++) Configure the OPAMP input AND output in analog mode using
119 HAL_GPIO_Init() to map the OPAMP output to the GPIO pin.
120
121 (#) Registrate Callbacks
122 (++) The compilation define USE_HAL_OPAMP_REGISTER_CALLBACKS when set to 1
123 allows the user to configure dynamically the driver callbacks.
124
125 (++) Use Functions HAL_OPAMP_RegisterCallback() to register a user callback,
126 it allows to register following callbacks:
127 (+++) MspInitCallback : OPAMP MspInit.
128 (+++) MspDeInitCallback : OPAMP MspFeInit.
129 This function takes as parameters the HAL peripheral handle, the Callback ID
130 and a pointer to the user callback function.
131
132 (++) Use function HAL_OPAMP_UnRegisterCallback() to reset a callback to the default
133 weak (surcharged) function. It allows to reset following callbacks:
134 (+++) MspInitCallback : OPAMP MspInit.
135 (+++) MspDeInitCallback : OPAMP MspdeInit.
136 (+++) All Callbacks
137
138 (#) Configure the OPAMP using HAL_OPAMP_Init() function:
139 (++) Select the mode
140 (++) Select the inverting input
141 (++) Select the non-inverting input
142 (++) If PGA mode is enabled, Select if inverting input is connected.
143 (++) Select either factory or user defined trimming mode.
144 (++) If the user-defined trimming mode is enabled, select PMOS & NMOS trimming values
145 (typically values set by HAL_OPAMP_SelfCalibrate function).
146
147 (#) Enable the OPAMP using HAL_OPAMP_Start() function.
148
149 (#) Disable the OPAMP using HAL_OPAMP_Stop() function.
150
151 (#) Lock the OPAMP in running mode using HAL_OPAMP_Lock() function.
152 Caution: On STM32L4, HAL OPAMP lock is software lock only (not
153 hardware lock as on some other STM32 devices)
154
155 (#) If needed, unlock the OPAMP using HAL_OPAMPEx_Unlock() function.
156
157 *** Running mode: change of configuration while OPAMP ON ***
158 ============================================
159 [..] To Re-configure OPAMP when OPAMP is ON (change on the fly)
160 (#) If needed, fill in the HAL_OPAMP_MspInit()
161 (++) This is the case for instance if you wish to use new OPAMP I/O
162
163 (#) Configure the OPAMP using HAL_OPAMP_Init() function:
164 (++) As in configure case, select first the parameters you wish to modify.
165
166 (#) Change from low power mode to normal power mode (& vice versa) requires
167 first HAL_OPAMP_DeInit() (force OPAMP OFF) and then HAL_OPAMP_Init().
168 In other words, of OPAMP is ON, HAL_OPAMP_Init can NOT change power mode
169 alone.
170
171 @endverbatim
172 ******************************************************************************
173
174 Table 1. OPAMPs inverting/non-inverting inputs for the STM32L4 devices:
175 +------------------------------------------------------------------------|
176 | | | OPAMP1 | OPAMP2 |
177 |-----------------|---------|----------------------|---------------------|
178 | Inverting Input | VM_SEL | | |
179 | | | IO0-> PA1 | IO0-> PA7 |
180 | | | LOW LEAKAGE IO (2) | LOW LEAKAGE IO (2) |
181 | | | Not connected | Not connected |
182 | (1) | | PGA mode only | PGA mode only |
183 |-----------------|---------|----------------------|---------------------|
184 | Non Inverting | VP_SEL | | |
185 | | | IO0-> PA0 (GPIO) | IO0-> PA6 (GPIO) |
186 | Input | | DAC1_OUT1 internal | DAC1_OUT2 internal |
187 +------------------------------------------------------------------------|
188 (1): NA in follower mode.
189 (2): Available on some package only (ex. BGA132).
190
191
192 Table 2. OPAMPs outputs for the STM32L4 devices:
193
194 +-------------------------------------------------------------------------
195 | | | OPAMP1 | OPAMP2 |
196 |-----------------|--------|-----------------------|---------------------|
197 | Output | VOUT | PA3 | PB0 |
198 | | | & (1) ADC12_IN if | & (1) ADC12_IN if |
199 | | | connected internally | connected internally|
200 |-----------------|--------|-----------------------|---------------------|
201 (1): ADC1 or ADC2 shall select IN15.
202
203 */
204
205 /* Includes ------------------------------------------------------------------*/
206 #include "stm32l4xx_hal.h"
207
208 /** @addtogroup STM32L4xx_HAL_Driver
209 * @{
210 */
211
212 /** @defgroup OPAMP OPAMP
213 * @brief OPAMP module driver
214 * @{
215 */
216
217 #ifdef HAL_OPAMP_MODULE_ENABLED
218
219 /* Private types -------------------------------------------------------------*/
220 /* Private variables ---------------------------------------------------------*/
221 /* Private constants ---------------------------------------------------------*/
222 /** @addtogroup OPAMP_Private_Constants
223 * @{
224 */
225
226 /* CSR register reset value */
227 #define OPAMP_CSR_RESET_VALUE ((uint32_t)0x00000000)
228
229 #define OPAMP_CSR_RESET_BITS (OPAMP_CSR_OPAMPxEN | OPAMP_CSR_OPALPM | OPAMP_CSR_OPAMODE \
230 | OPAMP_CSR_PGGAIN | OPAMP_CSR_VMSEL | OPAMP_CSR_VPSEL \
231 | OPAMP_CSR_CALON | OPAMP_CSR_USERTRIM)
232
233 /* CSR Init masks */
234 #define OPAMP_CSR_INIT_MASK_PGA (OPAMP_CSR_OPALPM | OPAMP_CSR_OPAMODE| OPAMP_CSR_PGGAIN \
235 | OPAMP_CSR_VMSEL | OPAMP_CSR_VPSEL | OPAMP_CSR_USERTRIM)
236
237 #define OPAMP_CSR_INIT_MASK_FOLLOWER (OPAMP_CSR_OPALPM | OPAMP_CSR_OPAMODE| OPAMP_CSR_VPSEL \
238 | OPAMP_CSR_USERTRIM)
239
240 #define OPAMP_CSR_INIT_MASK_STANDALONE (OPAMP_CSR_OPALPM | OPAMP_CSR_OPAMODE| OPAMP_CSR_VPSEL \
241 | OPAMP_CSR_VMSEL | OPAMP_CSR_USERTRIM)
242
243
244 /**
245 * @}
246 */
247
248 /* Private macros ------------------------------------------------------------*/
249 /* Private functions ---------------------------------------------------------*/
250 /* Exported functions --------------------------------------------------------*/
251
252 /** @defgroup OPAMP_Exported_Functions OPAMP Exported Functions
253 * @{
254 */
255
256 /** @defgroup OPAMP_Exported_Functions_Group1 Initialization and de-initialization functions
257 * @brief Initialization and Configuration functions
258 *
259 @verbatim
260 ==============================================================================
261 ##### Initialization and de-initialization functions #####
262 ==============================================================================
263
264 @endverbatim
265 * @{
266 */
267
268 /**
269 * @brief Initializes the OPAMP according to the specified
270 * parameters in the OPAMP_InitTypeDef and initialize the associated handle.
271 * @note If the selected opamp is locked, initialization can't be performed.
272 * To unlock the configuration, perform a system reset.
273 * @param hopamp OPAMP handle
274 * @retval HAL status
275 */
HAL_OPAMP_Init(OPAMP_HandleTypeDef * hopamp)276 HAL_StatusTypeDef HAL_OPAMP_Init(OPAMP_HandleTypeDef *hopamp)
277 {
278 HAL_StatusTypeDef status = HAL_OK;
279 uint32_t updateotrlpotr;
280
281 /* Check the OPAMP handle allocation and lock status */
282 /* Init not allowed if calibration is ongoing */
283 if(hopamp == NULL)
284 {
285 return HAL_ERROR;
286 }
287 else if(hopamp->State == HAL_OPAMP_STATE_BUSYLOCKED)
288 {
289 return HAL_ERROR;
290 }
291 else if(hopamp->State == HAL_OPAMP_STATE_CALIBBUSY)
292 {
293 return HAL_ERROR;
294 }
295 else
296 {
297 /* Check the parameter */
298 assert_param(IS_OPAMP_ALL_INSTANCE(hopamp->Instance));
299
300 /* Set OPAMP parameters */
301 assert_param(IS_OPAMP_POWER_SUPPLY_RANGE(hopamp->Init.PowerSupplyRange));
302 assert_param(IS_OPAMP_POWERMODE(hopamp->Init.PowerMode));
303 assert_param(IS_OPAMP_FUNCTIONAL_NORMALMODE(hopamp->Init.Mode));
304 assert_param(IS_OPAMP_NONINVERTING_INPUT(hopamp->Init.NonInvertingInput));
305
306 #if (USE_HAL_OPAMP_REGISTER_CALLBACKS == 1)
307 if(hopamp->State == HAL_OPAMP_STATE_RESET)
308 {
309 if(hopamp->MspInitCallback == NULL)
310 {
311 hopamp->MspInitCallback = HAL_OPAMP_MspInit;
312 }
313 }
314 #endif /* USE_HAL_OPAMP_REGISTER_CALLBACKS */
315
316 if ((hopamp->Init.Mode) == OPAMP_STANDALONE_MODE)
317 {
318 assert_param(IS_OPAMP_INVERTING_INPUT_STANDALONE(hopamp->Init.InvertingInput));
319 }
320
321 if ((hopamp->Init.Mode) == OPAMP_PGA_MODE)
322 {
323 assert_param(IS_OPAMP_INVERTING_INPUT_PGA(hopamp->Init.InvertingInput));
324 }
325
326 if ((hopamp->Init.Mode) == OPAMP_PGA_MODE)
327 {
328 assert_param(IS_OPAMP_PGA_GAIN(hopamp->Init.PgaGain));
329 }
330
331 assert_param(IS_OPAMP_TRIMMING(hopamp->Init.UserTrimming));
332 if ((hopamp->Init.UserTrimming) == OPAMP_TRIMMING_USER)
333 {
334 if (hopamp->Init.PowerMode == OPAMP_POWERMODE_NORMALPOWER)
335 {
336 assert_param(IS_OPAMP_TRIMMINGVALUE(hopamp->Init.TrimmingValueP));
337 assert_param(IS_OPAMP_TRIMMINGVALUE(hopamp->Init.TrimmingValueN));
338 }
339 else
340 {
341 assert_param(IS_OPAMP_TRIMMINGVALUE(hopamp->Init.TrimmingValuePLowPower));
342 assert_param(IS_OPAMP_TRIMMINGVALUE(hopamp->Init.TrimmingValueNLowPower));
343 }
344 }
345
346 if(hopamp->State == HAL_OPAMP_STATE_RESET)
347 {
348 /* Allocate lock resource and initialize it */
349 hopamp->Lock = HAL_UNLOCKED;
350 }
351
352 #if (USE_HAL_OPAMP_REGISTER_CALLBACKS == 1)
353 hopamp->MspInitCallback(hopamp);
354 #else
355 /* Call MSP init function */
356 HAL_OPAMP_MspInit(hopamp);
357 #endif /* USE_HAL_OPAMP_REGISTER_CALLBACKS */
358
359 /* Set operating mode */
360 CLEAR_BIT(hopamp->Instance->CSR, OPAMP_CSR_CALON);
361
362 if (hopamp->Init.Mode == OPAMP_PGA_MODE)
363 {
364 MODIFY_REG(hopamp->Instance->CSR, OPAMP_CSR_INIT_MASK_PGA, \
365 hopamp->Init.PowerMode | \
366 hopamp->Init.Mode | \
367 hopamp->Init.PgaGain | \
368 hopamp->Init.InvertingInput | \
369 hopamp->Init.NonInvertingInput | \
370 hopamp->Init.UserTrimming);
371 }
372
373 if (hopamp->Init.Mode == OPAMP_FOLLOWER_MODE)
374 {
375 /* In Follower mode InvertingInput is Not Applicable */
376 MODIFY_REG(hopamp->Instance->CSR, OPAMP_CSR_INIT_MASK_FOLLOWER, \
377 hopamp->Init.PowerMode | \
378 hopamp->Init.Mode | \
379 hopamp->Init.NonInvertingInput | \
380 hopamp->Init.UserTrimming);
381 }
382
383 if (hopamp->Init.Mode == OPAMP_STANDALONE_MODE)
384 {
385 MODIFY_REG(hopamp->Instance->CSR, OPAMP_CSR_INIT_MASK_STANDALONE, \
386 hopamp->Init.PowerMode | \
387 hopamp->Init.Mode | \
388 hopamp->Init.InvertingInput | \
389 hopamp->Init.NonInvertingInput | \
390 hopamp->Init.UserTrimming);
391 }
392
393 if (hopamp->Init.UserTrimming == OPAMP_TRIMMING_USER)
394 {
395 /* Set power mode and associated calibration parameters */
396 if (hopamp->Init.PowerMode != OPAMP_POWERMODE_LOWPOWER)
397 {
398 /* OPAMP_POWERMODE_NORMALPOWER */
399 /* Set calibration mode (factory or user) and values for */
400 /* transistors differential pair high (PMOS) and low (NMOS) for */
401 /* normal mode. */
402 updateotrlpotr = (((hopamp->Init.TrimmingValueP) << (OPAMP_INPUT_NONINVERTING)) \
403 | (hopamp->Init.TrimmingValueN));
404 MODIFY_REG(hopamp->Instance->OTR, OPAMP_OTR_TRIMOFFSETN | OPAMP_OTR_TRIMOFFSETP, updateotrlpotr);
405 }
406 else
407 {
408 /* OPAMP_POWERMODE_LOWPOWER */
409 /* transistors differential pair high (PMOS) and low (NMOS) for */
410 /* low power mode. */
411 updateotrlpotr = (((hopamp->Init.TrimmingValuePLowPower) << (OPAMP_INPUT_NONINVERTING)) \
412 | (hopamp->Init.TrimmingValueNLowPower));
413 MODIFY_REG(hopamp->Instance->LPOTR, OPAMP_OTR_TRIMOFFSETN | OPAMP_OTR_TRIMOFFSETP, updateotrlpotr);
414 }
415 }
416
417 /* Configure the power supply range */
418 /* The OPAMP_CSR_OPARANGE is common configuration for all OPAMPs */
419 /* bit OPAMP1_CSR_OPARANGE is used for both OPAMPs */
420 MODIFY_REG(OPAMP1->CSR, OPAMP1_CSR_OPARANGE, hopamp->Init.PowerSupplyRange);
421
422 /* Update the OPAMP state*/
423 if (hopamp->State == HAL_OPAMP_STATE_RESET)
424 {
425 /* From RESET state to READY State */
426 hopamp->State = HAL_OPAMP_STATE_READY;
427 }
428 /* else: remain in READY or BUSY state (no update) */
429 return status;
430 }
431 }
432
433 /**
434 * @brief DeInitialize the OPAMP peripheral.
435 * @note Deinitialization can be performed if the OPAMP configuration is locked.
436 * (the lock is SW in L4)
437 * @param hopamp OPAMP handle
438 * @retval HAL status
439 */
HAL_OPAMP_DeInit(OPAMP_HandleTypeDef * hopamp)440 HAL_StatusTypeDef HAL_OPAMP_DeInit(OPAMP_HandleTypeDef *hopamp)
441 {
442 HAL_StatusTypeDef status = HAL_OK;
443
444 /* Check the OPAMP handle allocation */
445 /* DeInit not allowed if calibration is ongoing */
446 if(hopamp == NULL)
447 {
448 status = HAL_ERROR;
449 }
450 else if(hopamp->State == HAL_OPAMP_STATE_CALIBBUSY)
451 {
452 status = HAL_ERROR;
453 }
454 else
455 {
456 /* Check the parameter */
457 assert_param(IS_OPAMP_ALL_INSTANCE(hopamp->Instance));
458
459 /* Set OPAMP_CSR register to reset value */
460 /* Mind that OPAMP1_CSR_OPARANGE of CSR of OPAMP1 remains unchanged (applies to both OPAMPs) */
461 /* OPAMP shall be disabled first separately */
462 CLEAR_BIT(hopamp->Instance->CSR, OPAMP_CSR_OPAMPxEN);
463 MODIFY_REG(hopamp->Instance->CSR, OPAMP_CSR_RESET_BITS, OPAMP_CSR_RESET_VALUE);
464
465 #if (USE_HAL_OPAMP_REGISTER_CALLBACKS == 1)
466 if(hopamp->MspDeInitCallback == NULL)
467 {
468 hopamp->MspDeInitCallback = HAL_OPAMP_MspDeInit;
469 }
470 /* DeInit the low level hardware */
471 hopamp->MspDeInitCallback(hopamp);
472 #else
473 /* DeInit the low level hardware: GPIO, CLOCK and NVIC */
474 HAL_OPAMP_MspDeInit(hopamp);
475 #endif /* USE_HAL_OPAMP_REGISTER_CALLBACKS */
476 /* Update the OPAMP state*/
477 hopamp->State = HAL_OPAMP_STATE_RESET;
478
479 /* Process unlocked */
480 __HAL_UNLOCK(hopamp);
481 }
482 return status;
483 }
484
485 /**
486 * @brief Initialize the OPAMP MSP.
487 * @param hopamp OPAMP handle
488 * @retval None
489 */
HAL_OPAMP_MspInit(OPAMP_HandleTypeDef * hopamp)490 __weak void HAL_OPAMP_MspInit(OPAMP_HandleTypeDef *hopamp)
491 {
492 /* Prevent unused argument(s) compilation warning */
493 UNUSED(hopamp);
494
495 /* NOTE : This function should not be modified, when the callback is needed,
496 the function "HAL_OPAMP_MspInit()" must be implemented in the user file.
497 */
498 }
499
500 /**
501 * @brief DeInitialize OPAMP MSP.
502 * @param hopamp OPAMP handle
503 * @retval None
504 */
HAL_OPAMP_MspDeInit(OPAMP_HandleTypeDef * hopamp)505 __weak void HAL_OPAMP_MspDeInit(OPAMP_HandleTypeDef *hopamp)
506 {
507 /* Prevent unused argument(s) compilation warning */
508 UNUSED(hopamp);
509
510 /* NOTE : This function should not be modified, when the callback is needed,
511 the function "HAL_OPAMP_MspDeInit()" must be implemented in the user file.
512 */
513 }
514
515 /**
516 * @}
517 */
518
519
520 /** @defgroup OPAMP_Exported_Functions_Group2 IO operation functions
521 * @brief IO operation functions
522 *
523 @verbatim
524 ===============================================================================
525 ##### IO operation functions #####
526 ===============================================================================
527 [..]
528 This subsection provides a set of functions allowing to manage the OPAMP
529 start, stop and calibration actions.
530
531 @endverbatim
532 * @{
533 */
534
535 /**
536 * @brief Start the OPAMP.
537 * @param hopamp OPAMP handle
538 * @retval HAL status
539 */
540
HAL_OPAMP_Start(OPAMP_HandleTypeDef * hopamp)541 HAL_StatusTypeDef HAL_OPAMP_Start(OPAMP_HandleTypeDef *hopamp)
542 {
543 HAL_StatusTypeDef status = HAL_OK;
544
545 /* Check the OPAMP handle allocation */
546 /* Check if OPAMP locked */
547 if(hopamp == NULL)
548 {
549 status = HAL_ERROR;
550 }
551 else if(hopamp->State == HAL_OPAMP_STATE_BUSYLOCKED)
552 {
553 status = HAL_ERROR;
554 }
555 else
556 {
557 /* Check the parameter */
558 assert_param(IS_OPAMP_ALL_INSTANCE(hopamp->Instance));
559
560 if(hopamp->State == HAL_OPAMP_STATE_READY)
561 {
562 /* Enable the selected opamp */
563 SET_BIT (hopamp->Instance->CSR, OPAMP_CSR_OPAMPxEN);
564
565 /* Update the OPAMP state*/
566 /* From HAL_OPAMP_STATE_READY to HAL_OPAMP_STATE_BUSY */
567 hopamp->State = HAL_OPAMP_STATE_BUSY;
568 }
569 else
570 {
571 status = HAL_ERROR;
572 }
573
574 }
575 return status;
576 }
577
578 /**
579 * @brief Stop the OPAMP.
580 * @param hopamp OPAMP handle
581 * @retval HAL status
582 */
HAL_OPAMP_Stop(OPAMP_HandleTypeDef * hopamp)583 HAL_StatusTypeDef HAL_OPAMP_Stop(OPAMP_HandleTypeDef *hopamp)
584 {
585 HAL_StatusTypeDef status = HAL_OK;
586
587 /* Check the OPAMP handle allocation */
588 /* Check if OPAMP locked */
589 /* Check if OPAMP calibration ongoing */
590 if(hopamp == NULL)
591 {
592 status = HAL_ERROR;
593 }
594 else if(hopamp->State == HAL_OPAMP_STATE_BUSYLOCKED)
595 {
596 status = HAL_ERROR;
597 }
598 else if(hopamp->State == HAL_OPAMP_STATE_CALIBBUSY)
599 {
600 status = HAL_ERROR;
601 }
602 else
603 {
604 /* Check the parameter */
605 assert_param(IS_OPAMP_ALL_INSTANCE(hopamp->Instance));
606
607 if(hopamp->State == HAL_OPAMP_STATE_BUSY)
608 {
609 /* Disable the selected opamp */
610 CLEAR_BIT (hopamp->Instance->CSR, OPAMP_CSR_OPAMPxEN);
611
612 /* Update the OPAMP state*/
613 /* From HAL_OPAMP_STATE_BUSY to HAL_OPAMP_STATE_READY*/
614 hopamp->State = HAL_OPAMP_STATE_READY;
615 }
616 else
617 {
618 status = HAL_ERROR;
619 }
620 }
621 return status;
622 }
623
624 /**
625 * @brief Run the self calibration of one OPAMP.
626 * @note Calibration is performed in the mode specified in OPAMP init
627 * structure (mode normal or low-power). To perform calibration for
628 * both modes, repeat this function twice after OPAMP init structure
629 * accordingly updated.
630 * @note Calibration runs about 10 ms.
631 * @param hopamp handle
632 * @retval Updated offset trimming values (PMOS & NMOS), user trimming is enabled
633 * @retval HAL status
634
635 */
636
HAL_OPAMP_SelfCalibrate(OPAMP_HandleTypeDef * hopamp)637 HAL_StatusTypeDef HAL_OPAMP_SelfCalibrate(OPAMP_HandleTypeDef *hopamp)
638 {
639
640 HAL_StatusTypeDef status = HAL_OK;
641
642 uint32_t trimmingvaluen;
643 uint32_t trimmingvaluep;
644 uint32_t delta;
645 uint32_t opampmode;
646
647 __IO uint32_t* tmp_opamp_reg_trimming; /* Selection of register of trimming depending on power mode: OTR or LPOTR */
648
649 /* Check the OPAMP handle allocation */
650 /* Check if OPAMP locked */
651 if(hopamp == NULL)
652 {
653 status = HAL_ERROR;
654 }
655 else if(hopamp->State == HAL_OPAMP_STATE_BUSYLOCKED)
656 {
657 status = HAL_ERROR;
658 }
659 else
660 {
661 /* Check if OPAMP in calibration mode and calibration not yet enable */
662 if(hopamp->State == HAL_OPAMP_STATE_READY)
663 {
664 /* Check the parameter */
665 assert_param(IS_OPAMP_ALL_INSTANCE(hopamp->Instance));
666 assert_param(IS_OPAMP_POWERMODE(hopamp->Init.PowerMode));
667
668 /* Save OPAMP mode as in */
669 /* STM32L471xx STM32L475xx STM32L476xx STM32L485xx STM32L486xx */
670 /* the calibration is not working in PGA mode */
671 opampmode = READ_BIT(hopamp->Instance->CSR,OPAMP_CSR_OPAMODE);
672
673 /* Use of standalone mode */
674 MODIFY_REG(hopamp->Instance->CSR, OPAMP_CSR_OPAMODE, OPAMP_STANDALONE_MODE);
675
676 /* user trimming values are used for offset calibration */
677 SET_BIT(hopamp->Instance->CSR, OPAMP_CSR_USERTRIM);
678
679 /* Select trimming settings depending on power mode */
680 if (hopamp->Init.PowerMode == OPAMP_POWERMODE_NORMALPOWER)
681 {
682 tmp_opamp_reg_trimming = &hopamp->Instance->OTR;
683 }
684 else
685 {
686 tmp_opamp_reg_trimming = &hopamp->Instance->LPOTR;
687 }
688
689 /* Enable calibration */
690 SET_BIT (hopamp->Instance->CSR, OPAMP_CSR_CALON);
691
692 /* 1st calibration - N */
693 CLEAR_BIT (hopamp->Instance->CSR, OPAMP_CSR_CALSEL);
694
695 /* Enable the selected opamp */
696 SET_BIT (hopamp->Instance->CSR, OPAMP_CSR_OPAMPxEN);
697
698 /* Init trimming counter */
699 /* Medium value */
700 trimmingvaluen = 16U;
701 delta = 8U;
702
703 while (delta != 0U)
704 {
705 /* Set candidate trimming */
706 /* OPAMP_POWERMODE_NORMALPOWER */
707 MODIFY_REG(*tmp_opamp_reg_trimming, OPAMP_OTR_TRIMOFFSETN, trimmingvaluen);
708
709 /* OFFTRIMmax delay 1 ms as per datasheet (electrical characteristics */
710 /* Offset trim time: during calibration, minimum time needed between */
711 /* two steps to have 1 mV accuracy */
712 HAL_Delay(OPAMP_TRIMMING_DELAY);
713
714 if (READ_BIT(hopamp->Instance->CSR, OPAMP_CSR_CALOUT) != 0U)
715 {
716 /* OPAMP_CSR_CALOUT is HIGH try higher trimming */
717 trimmingvaluen -= delta;
718 }
719 else
720 {
721 /* OPAMP_CSR_CALOUT is LOW try lower trimming */
722 trimmingvaluen += delta;
723 }
724 /* Divide range by 2 to continue dichotomy sweep */
725 delta >>= 1U;
726 }
727
728 /* Still need to check if right calibration is current value or one step below */
729 /* Indeed the first value that causes the OUTCAL bit to change from 0 to 1 */
730 /* Set candidate trimming */
731 MODIFY_REG(*tmp_opamp_reg_trimming, OPAMP_OTR_TRIMOFFSETN, trimmingvaluen);
732
733 /* OFFTRIMmax delay 1 ms as per datasheet (electrical characteristics */
734 /* Offset trim time: during calibration, minimum time needed between */
735 /* two steps to have 1 mV accuracy */
736 HAL_Delay(OPAMP_TRIMMING_DELAY);
737
738 if ((READ_BIT(hopamp->Instance->CSR, OPAMP_CSR_CALOUT)) == 0U)
739 {
740 /* Trimming value is actually one value more */
741 trimmingvaluen++;
742 /* Set right trimming */
743 MODIFY_REG(*tmp_opamp_reg_trimming, OPAMP_OTR_TRIMOFFSETN, trimmingvaluen);
744 }
745
746 /* 2nd calibration - P */
747 SET_BIT (hopamp->Instance->CSR, OPAMP_CSR_CALSEL);
748
749 /* Init trimming counter */
750 /* Medium value */
751 trimmingvaluep = 16U;
752 delta = 8U;
753
754 while (delta != 0U)
755 {
756 /* Set candidate trimming */
757 /* OPAMP_POWERMODE_NORMALPOWER */
758 MODIFY_REG(*tmp_opamp_reg_trimming, OPAMP_OTR_TRIMOFFSETP, (trimmingvaluep<<OPAMP_INPUT_NONINVERTING));
759
760 /* OFFTRIMmax delay 1 ms as per datasheet (electrical characteristics */
761 /* Offset trim time: during calibration, minimum time needed between */
762 /* two steps to have 1 mV accuracy */
763 HAL_Delay(OPAMP_TRIMMING_DELAY);
764
765 if (READ_BIT(hopamp->Instance->CSR, OPAMP_CSR_CALOUT) != 0U)
766 {
767 /* OPAMP_CSR_CALOUT is HIGH try higher trimming */
768 trimmingvaluep += delta;
769 }
770 else
771 {
772 /* OPAMP_CSR_CALOUT is LOW try lower trimming */
773 trimmingvaluep -= delta;
774 }
775
776 /* Divide range by 2 to continue dichotomy sweep */
777 delta >>= 1U;
778 }
779
780 /* Still need to check if right calibration is current value or one step below */
781 /* Indeed the first value that causes the OUTCAL bit to change from 1 to 0 */
782 /* Set candidate trimming */
783 MODIFY_REG(*tmp_opamp_reg_trimming, OPAMP_OTR_TRIMOFFSETP, (trimmingvaluep<<OPAMP_INPUT_NONINVERTING));
784
785 /* OFFTRIMmax delay 1 ms as per datasheet (electrical characteristics */
786 /* Offset trim time: during calibration, minimum time needed between */
787 /* two steps to have 1 mV accuracy */
788 HAL_Delay(OPAMP_TRIMMING_DELAY);
789
790 if (READ_BIT(hopamp->Instance->CSR, OPAMP_CSR_CALOUT) != 0U)
791 {
792 /* Trimming value is actually one value more */
793 trimmingvaluep++;
794 MODIFY_REG(*tmp_opamp_reg_trimming, OPAMP_OTR_TRIMOFFSETP, (trimmingvaluep<<OPAMP_INPUT_NONINVERTING));
795 }
796
797 /* Disable the OPAMP */
798 CLEAR_BIT (hopamp->Instance->CSR, OPAMP_CSR_OPAMPxEN);
799
800 /* Disable calibration & set normal mode (operating mode) */
801 CLEAR_BIT (hopamp->Instance->CSR, OPAMP_CSR_CALON);
802
803 /* Self calibration is successful */
804 /* Store calibration(user trimming) results in init structure. */
805
806 /* Set user trimming mode */
807 hopamp->Init.UserTrimming = OPAMP_TRIMMING_USER;
808
809 /* Affect calibration parameters depending on mode normal/low power */
810 if (hopamp->Init.PowerMode != OPAMP_POWERMODE_LOWPOWER)
811 {
812 /* Write calibration result N */
813 hopamp->Init.TrimmingValueN = trimmingvaluen;
814 /* Write calibration result P */
815 hopamp->Init.TrimmingValueP = trimmingvaluep;
816 }
817 else
818 {
819 /* Write calibration result N */
820 hopamp->Init.TrimmingValueNLowPower = trimmingvaluen;
821 /* Write calibration result P */
822 hopamp->Init.TrimmingValuePLowPower = trimmingvaluep;
823 }
824
825 /* Restore OPAMP mode after calibration */
826 MODIFY_REG(hopamp->Instance->CSR, OPAMP_CSR_OPAMODE, opampmode);
827 }
828 else
829 {
830 /* OPAMP can not be calibrated from this mode */
831 status = HAL_ERROR;
832 }
833 }
834 return status;
835 }
836
837 /**
838 * @}
839 */
840
841 /** @defgroup OPAMP_Exported_Functions_Group3 Peripheral Control functions
842 * @brief Peripheral Control functions
843 *
844 @verbatim
845 ===============================================================================
846 ##### Peripheral Control functions #####
847 ===============================================================================
848 [..]
849 This subsection provides a set of functions allowing to control the OPAMP data
850 transfers.
851
852
853
854 @endverbatim
855 * @{
856 */
857
858 /**
859 * @brief Lock the selected OPAMP configuration.
860 * @note On STM32L4, HAL OPAMP lock is software lock only (in
861 * contrast of hardware lock available on some other STM32
862 * devices).
863 * @param hopamp OPAMP handle
864 * @retval HAL status
865 */
HAL_OPAMP_Lock(OPAMP_HandleTypeDef * hopamp)866 HAL_StatusTypeDef HAL_OPAMP_Lock(OPAMP_HandleTypeDef *hopamp)
867 {
868 HAL_StatusTypeDef status = HAL_OK;
869
870 /* Check the OPAMP handle allocation */
871 /* Check if OPAMP locked */
872 /* OPAMP can be locked when enabled and running in normal mode */
873 /* It is meaningless otherwise */
874 if(hopamp == NULL)
875 {
876 status = HAL_ERROR;
877 }
878 else if(hopamp->State == HAL_OPAMP_STATE_BUSY)
879 {
880 /* Check the parameter */
881 assert_param(IS_OPAMP_ALL_INSTANCE(hopamp->Instance));
882
883 /* OPAMP state changed to locked */
884 hopamp->State = HAL_OPAMP_STATE_BUSYLOCKED;
885 }
886 else
887 {
888 status = HAL_ERROR;
889 }
890 return status;
891 }
892
893 /**
894 * @brief Return the OPAMP factory trimming value.
895 * @note On STM32L4 OPAMP, user can retrieve factory trimming if
896 * OPAMP has never been set to user trimming before.
897 * Therefore, this function must be called when OPAMP init
898 * parameter "UserTrimming" is set to trimming factory,
899 * and before OPAMP calibration (function
900 * "HAL_OPAMP_SelfCalibrate()").
901 * Otherwise, factory trimming value cannot be retrieved and
902 * error status is returned.
903 * @param hopamp : OPAMP handle
904 * @param trimmingoffset : Trimming offset (P or N)
905 * This parameter must be a value of @ref OPAMP_FactoryTrimming
906 * @note Calibration parameter retrieved is corresponding to the mode
907 * specified in OPAMP init structure (mode normal or low-power).
908 * To retrieve calibration parameters for both modes, repeat this
909 * function after OPAMP init structure accordingly updated.
910 * @retval Trimming value (P or N): range: 0->31
911 * or OPAMP_FACTORYTRIMMING_DUMMY if trimming value is not available
912 *
913 */
914
HAL_OPAMP_GetTrimOffset(OPAMP_HandleTypeDef * hopamp,uint32_t trimmingoffset)915 HAL_OPAMP_TrimmingValueTypeDef HAL_OPAMP_GetTrimOffset (OPAMP_HandleTypeDef *hopamp, uint32_t trimmingoffset)
916 {
917 HAL_OPAMP_TrimmingValueTypeDef trimmingvalue;
918 __IO uint32_t* tmp_opamp_reg_trimming; /* Selection of register of trimming depending on power mode: OTR or LPOTR */
919
920 /* Check the OPAMP handle allocation */
921 /* Value can be retrieved in HAL_OPAMP_STATE_READY state */
922 if(hopamp == NULL)
923 {
924 return OPAMP_FACTORYTRIMMING_DUMMY;
925 }
926
927 /* Check the OPAMP handle allocation */
928 /* Value can be retrieved in HAL_OPAMP_STATE_READY state */
929 if(hopamp->State == HAL_OPAMP_STATE_READY)
930 {
931 /* Check the parameter */
932 assert_param(IS_OPAMP_ALL_INSTANCE(hopamp->Instance));
933 assert_param(IS_OPAMP_FACTORYTRIMMING(trimmingoffset));
934 assert_param(IS_OPAMP_POWERMODE(hopamp->Init.PowerMode));
935
936 /* Check the trimming mode */
937 if (READ_BIT(hopamp->Instance->CSR,OPAMP_CSR_USERTRIM) != 0U)
938 {
939 /* This function must called when OPAMP init parameter "UserTrimming" */
940 /* is set to trimming factory, and before OPAMP calibration (function */
941 /* "HAL_OPAMP_SelfCalibrate()"). */
942 /* Otherwise, factory trimming value cannot be retrieved and error */
943 /* status is returned. */
944 trimmingvalue = OPAMP_FACTORYTRIMMING_DUMMY;
945 }
946 else
947 {
948 /* Select trimming settings depending on power mode */
949 if (hopamp->Init.PowerMode == OPAMP_POWERMODE_NORMALPOWER)
950 {
951 tmp_opamp_reg_trimming = &OPAMP->OTR;
952 }
953 else
954 {
955 tmp_opamp_reg_trimming = &OPAMP->LPOTR;
956 }
957
958 /* Get factory trimming */
959 if (trimmingoffset == OPAMP_FACTORYTRIMMING_P)
960 {
961 /* OPAMP_FACTORYTRIMMING_P */
962 trimmingvalue = ((*tmp_opamp_reg_trimming) & OPAMP_OTR_TRIMOFFSETP) >> OPAMP_INPUT_NONINVERTING;
963 }
964 else
965 {
966 /* OPAMP_FACTORYTRIMMING_N */
967 trimmingvalue = (*tmp_opamp_reg_trimming) & OPAMP_OTR_TRIMOFFSETN;
968 }
969 }
970 }
971 else
972 {
973 return OPAMP_FACTORYTRIMMING_DUMMY;
974 }
975 return trimmingvalue;
976 }
977
978 /**
979 * @}
980 */
981
982
983 /** @defgroup OPAMP_Exported_Functions_Group4 Peripheral State functions
984 * @brief Peripheral State functions
985 *
986 @verbatim
987 ===============================================================================
988 ##### Peripheral State functions #####
989 ===============================================================================
990 [..]
991 This subsection permits to get in run-time the status of the peripheral.
992
993 @endverbatim
994 * @{
995 */
996
997 /**
998 * @brief Return the OPAMP handle state.
999 * @param hopamp : OPAMP handle
1000 * @retval HAL state
1001 */
HAL_OPAMP_GetState(OPAMP_HandleTypeDef * hopamp)1002 HAL_OPAMP_StateTypeDef HAL_OPAMP_GetState(OPAMP_HandleTypeDef *hopamp)
1003 {
1004 /* Check the OPAMP handle allocation */
1005 if(hopamp == NULL)
1006 {
1007 return HAL_OPAMP_STATE_RESET;
1008 }
1009
1010 /* Check the parameter */
1011 assert_param(IS_OPAMP_ALL_INSTANCE(hopamp->Instance));
1012
1013 /* Return OPAMP handle state */
1014 return hopamp->State;
1015 }
1016
1017 /**
1018 * @}
1019 */
1020
1021 #if (USE_HAL_OPAMP_REGISTER_CALLBACKS == 1)
1022 /**
1023 * @brief Register a User OPAMP Callback
1024 * To be used instead of the weak (surcharged) predefined callback
1025 * @param hopamp : OPAMP handle
1026 * @param CallbackID : ID of the callback to be registered
1027 * This parameter can be one of the following values:
1028 * @arg @ref HAL_OPAMP_MSPINIT_CB_ID OPAMP MspInit callback ID
1029 * @arg @ref HAL_OPAMP_MSPDEINIT_CB_ID OPAMP MspDeInit callback ID
1030 * @param pCallback : pointer to the Callback function
1031 * @retval status
1032 */
HAL_OPAMP_RegisterCallback(OPAMP_HandleTypeDef * hopamp,HAL_OPAMP_CallbackIDTypeDef CallbackID,pOPAMP_CallbackTypeDef pCallback)1033 HAL_StatusTypeDef HAL_OPAMP_RegisterCallback (OPAMP_HandleTypeDef *hopamp, HAL_OPAMP_CallbackIDTypeDef CallbackID, pOPAMP_CallbackTypeDef pCallback)
1034 {
1035 HAL_StatusTypeDef status = HAL_OK;
1036
1037 if(pCallback == NULL)
1038 {
1039 return HAL_ERROR;
1040 }
1041
1042 /* Process locked */
1043 __HAL_LOCK(hopamp);
1044
1045 if(hopamp->State == HAL_OPAMP_STATE_READY)
1046 {
1047 switch (CallbackID)
1048 {
1049 case HAL_OPAMP_MSPINIT_CB_ID :
1050 hopamp->MspInitCallback = pCallback;
1051 break;
1052 case HAL_OPAMP_MSPDEINIT_CB_ID :
1053 hopamp->MspDeInitCallback = pCallback;
1054 break;
1055 default :
1056 /* update return status */
1057 status = HAL_ERROR;
1058 break;
1059 }
1060 }
1061 else if (hopamp->State == HAL_OPAMP_STATE_RESET)
1062 {
1063 switch (CallbackID)
1064 {
1065 case HAL_OPAMP_MSPINIT_CB_ID :
1066 hopamp->MspInitCallback = pCallback;
1067 break;
1068 case HAL_OPAMP_MSPDEINIT_CB_ID :
1069 hopamp->MspDeInitCallback = pCallback;
1070 break;
1071 default :
1072 /* update return status */
1073 status = HAL_ERROR;
1074 break;
1075 }
1076 }
1077 else
1078 {
1079 /* update return status */
1080 status = HAL_ERROR;
1081 }
1082
1083 /* Release Lock */
1084 __HAL_UNLOCK(hopamp);
1085 return status;
1086 }
1087
1088 /**
1089 * @brief Unregister a User OPAMP Callback
1090 * OPAMP Callback is redirected to the weak (surcharged) predefined callback
1091 * @param hopamp : OPAMP handle
1092 * @param CallbackID : ID of the callback to be unregistered
1093 * This parameter can be one of the following values:
1094 * @arg @ref HAL_OPAMP_MSPINIT_CB_ID OPAMP MSP Init Callback ID
1095 * @arg @ref HAL_OPAMP_MSPDEINIT_CB_ID OPAMP MSP DeInit Callback ID
1096 * @arg @ref HAL_OPAMP_ALL_CB_ID OPAMP All Callbacks
1097 * @retval status
1098 */
1099
HAL_OPAMP_UnRegisterCallback(OPAMP_HandleTypeDef * hopamp,HAL_OPAMP_CallbackIDTypeDef CallbackID)1100 HAL_StatusTypeDef HAL_OPAMP_UnRegisterCallback (OPAMP_HandleTypeDef *hopamp, HAL_OPAMP_CallbackIDTypeDef CallbackID)
1101 {
1102 HAL_StatusTypeDef status = HAL_OK;
1103
1104 /* Process locked */
1105 __HAL_LOCK(hopamp);
1106
1107 if(hopamp->State == HAL_OPAMP_STATE_READY)
1108 {
1109 switch (CallbackID)
1110 {
1111 case HAL_OPAMP_MSPINIT_CB_ID :
1112 hopamp->MspInitCallback = HAL_OPAMP_MspInit;
1113 break;
1114 case HAL_OPAMP_MSPDEINIT_CB_ID :
1115 hopamp->MspDeInitCallback = HAL_OPAMP_MspDeInit;
1116 break;
1117 case HAL_OPAMP_ALL_CB_ID :
1118 hopamp->MspInitCallback = HAL_OPAMP_MspInit;
1119 hopamp->MspDeInitCallback = HAL_OPAMP_MspDeInit;
1120 break;
1121 default :
1122 /* update return status */
1123 status = HAL_ERROR;
1124 break;
1125 }
1126 }
1127 else if (hopamp->State == HAL_OPAMP_STATE_RESET)
1128 {
1129 switch (CallbackID)
1130 {
1131 case HAL_OPAMP_MSPINIT_CB_ID :
1132 hopamp->MspInitCallback = HAL_OPAMP_MspInit;
1133 break;
1134 case HAL_OPAMP_MSPDEINIT_CB_ID :
1135 hopamp->MspDeInitCallback = HAL_OPAMP_MspDeInit;
1136 break;
1137 default :
1138 /* update return status */
1139 status = HAL_ERROR;
1140 break;
1141 }
1142 }
1143 else
1144 {
1145 /* update return status */
1146 status = HAL_ERROR;
1147 }
1148
1149 /* Release Lock */
1150 __HAL_UNLOCK(hopamp);
1151 return status;
1152 }
1153
1154 #endif /* USE_HAL_OPAMP_REGISTER_CALLBACKS */
1155
1156
1157 /**
1158 * @}
1159 */
1160
1161 /**
1162 * @}
1163 */
1164
1165 #endif /* HAL_OPAMP_MODULE_ENABLED */
1166 /**
1167 * @}
1168 */
1169
1170 /**
1171 * @}
1172 */
1173