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