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