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