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) 2022 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 (surcharged) 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 /* Private types -----------------------------------------------------------------------------------------------------*/
231 /* Private variables -------------------------------------------------------------------------------------------------*/
232 /* Private constants -------------------------------------------------------------------------------------------------*/
233 /** @addtogroup OPAMP_Private_Constants
234 * @{
235 */
236
237 /* CSR register reset value */
238 #define OPAMP_CSR_RESET_VALUE 0x00000000U
239
240 /* CSR Init masks */
241 #define OPAMP_CSR_INIT_MASK_PGA (OPAMP_CSR_OPAHSM | OPAMP_CSR_VMSEL | OPAMP_CSR_PGGAIN | OPAMP_CSR_PGGAIN \
242 | OPAMP_CSR_VPSEL | OPAMP_CSR_USERTRIM)
243
244
245 #define OPAMP_CSR_INIT_MASK_FOLLOWER (OPAMP_CSR_OPAHSM | OPAMP_CSR_VMSEL| OPAMP_CSR_VPSEL \
246 | OPAMP_CSR_USERTRIM)
247
248
249 #define OPAMP_CSR_INIT_MASK_STANDALONE (OPAMP_CSR_OPAHSM | OPAMP_CSR_VMSEL | OPAMP_CSR_VPSEL \
250 | OPAMP_CSR_VMSEL | OPAMP_CSR_USERTRIM)
251 /**
252 * @}
253 */
254
255 /* Private macros ----------------------------------------------------------------------------------------------------*/
256 /* Private functions -------------------------------------------------------------------------------------------------*/
257 /* Exported functions ------------------------------------------------------------------------------------------------*/
258
259 /** @defgroup OPAMP_Exported_Functions OPAMP Exported Functions
260 * @{
261 */
262
263 /** @defgroup OPAMP_Exported_Functions_Group1 Initialization and de-initialization functions
264 * @brief Initialization and Configuration functions
265 *
266 @verbatim
267 ======================================================================================================================
268 ##### Initialization and de-initialization functions #####
269 ======================================================================================================================
270
271 @endverbatim
272 * @{
273 */
274
275 /**
276 * @brief Initialize the OPAMP according to the specified
277 * parameters in the OPAMP_InitTypeDef and initialize the associated handle.
278 * @note If the selected opamp is locked, initialization can't be performed.
279 * To unlock the configuration, perform a system reset.
280 * @param hopamp OPAMP handle
281 * @retval HAL status
282 */
HAL_OPAMP_Init(OPAMP_HandleTypeDef * hopamp)283 HAL_StatusTypeDef HAL_OPAMP_Init(OPAMP_HandleTypeDef *hopamp)
284 {
285 HAL_StatusTypeDef status = HAL_OK;
286 uint32_t updateotrlpotr;
287
288 /* Check the OPAMP handle allocation and lock status */
289 /* Init not allowed if calibration is ongoing */
290 if (hopamp == NULL)
291 {
292 return HAL_ERROR;
293 }
294 else if (hopamp->State == HAL_OPAMP_STATE_BUSYLOCKED)
295 {
296 return HAL_ERROR;
297 }
298 else if (hopamp->State == HAL_OPAMP_STATE_CALIBBUSY)
299 {
300 return HAL_ERROR;
301 }
302 else
303 {
304 /* Check the parameter */
305 assert_param(IS_OPAMP_ALL_INSTANCE(hopamp->Instance));
306
307 /* Set OPAMP parameters */
308 assert_param(IS_OPAMP_POWERMODE(hopamp->Init.PowerMode));
309 assert_param(IS_OPAMP_FUNCTIONAL_NORMALMODE(hopamp->Init.Mode));
310 assert_param(IS_OPAMP_NONINVERTING_INPUT(hopamp->Init.NonInvertingInput));
311
312 #if (USE_HAL_OPAMP_REGISTER_CALLBACKS == 1U)
313 if (hopamp->State == HAL_OPAMP_STATE_RESET)
314 {
315 if (hopamp->MspInitCallback == NULL)
316 {
317 hopamp->MspInitCallback = HAL_OPAMP_MspInit;
318 }
319 }
320 #endif /* USE_HAL_OPAMP_REGISTER_CALLBACKS */
321 if ((hopamp->Init.Mode) == OPAMP_STANDALONE_MODE)
322 {
323 assert_param(IS_OPAMP_INVERTING_INPUT_STANDALONE(hopamp->Init.InvertingInput));
324 }
325
326 if ((hopamp->Init.Mode) == OPAMP_PGA_MODE)
327 {
328 assert_param(IS_OPAMP_PGA_GAIN(hopamp->Init.PgaGain));
329 assert_param(IS_OPAMP_PGACONNECT(hopamp->Init.PgaConnect));
330 }
331
332
333 assert_param(IS_OPAMP_TRIMMING(hopamp->Init.UserTrimming));
334
335 if ((hopamp->Init.UserTrimming) == OPAMP_TRIMMING_USER)
336 {
337 if (hopamp->Init.PowerMode == OPAMP_POWERMODE_NORMAL)
338 {
339 assert_param(IS_OPAMP_TRIMMINGVALUE(hopamp->Init.TrimmingValueP));
340 assert_param(IS_OPAMP_TRIMMINGVALUE(hopamp->Init.TrimmingValueN));
341 }
342 else
343 {
344 assert_param(IS_OPAMP_TRIMMINGVALUE(hopamp->Init.TrimmingValuePHighSpeed));
345 assert_param(IS_OPAMP_TRIMMINGVALUE(hopamp->Init.TrimmingValueNHighSpeed));
346 }
347 }
348
349 if (hopamp->State == HAL_OPAMP_STATE_RESET)
350 {
351 /* Allocate lock resource and initialize it */
352 hopamp->Lock = HAL_UNLOCKED;
353 }
354
355 #if (USE_HAL_OPAMP_REGISTER_CALLBACKS == 1U)
356 hopamp->MspInitCallback(hopamp);
357 #else
358 /* Call MSP init function */
359 HAL_OPAMP_MspInit(hopamp);
360 #endif /* USE_HAL_OPAMP_REGISTER_CALLBACKS */
361
362 /* Set operating mode */
363 CLEAR_BIT(hopamp->Instance->CSR, OPAMP_CSR_CALON);
364 /* In PGA mode InvertingInput is Not Applicable */
365 if (hopamp->Init.Mode == OPAMP_PGA_MODE)
366 {
367 MODIFY_REG(hopamp->Instance->CSR, OPAMP_CSR_INIT_MASK_PGA, \
368 hopamp->Init.PowerMode | \
369 hopamp->Init.Mode | \
370 hopamp->Init.PgaGain | \
371 hopamp->Init.PgaConnect | \
372 hopamp->Init.NonInvertingInput | \
373 hopamp->Init.UserTrimming);
374 }
375
376 if (hopamp->Init.Mode == OPAMP_FOLLOWER_MODE)
377 {
378 /* In Follower mode InvertingInput is Not Applicable */
379 MODIFY_REG(hopamp->Instance->CSR, OPAMP_CSR_INIT_MASK_FOLLOWER, \
380 hopamp->Init.PowerMode | \
381 hopamp->Init.Mode | \
382 hopamp->Init.NonInvertingInput | \
383 hopamp->Init.UserTrimming);
384 }
385
386 if (hopamp->Init.Mode == OPAMP_STANDALONE_MODE)
387 {
388 MODIFY_REG(hopamp->Instance->CSR, OPAMP_CSR_INIT_MASK_STANDALONE, \
389 hopamp->Init.PowerMode | \
390 hopamp->Init.Mode | \
391 hopamp->Init.InvertingInput | \
392 hopamp->Init.NonInvertingInput | \
393 hopamp->Init.UserTrimming);
394 }
395
396 if (hopamp->Init.UserTrimming == OPAMP_TRIMMING_USER)
397 {
398 /* Set power mode and associated calibration parameters */
399 if (hopamp->Init.PowerMode != OPAMP_POWERMODE_HIGHSPEED)
400 {
401 /* OPAMP_POWERMODE_NORMAL */
402 /* Set calibration mode (factory or user) and values for */
403 /* transistors differential pair high (PMOS) and low (NMOS) for */
404 /* normal mode. */
405 updateotrlpotr = (((hopamp->Init.TrimmingValueP) << (OPAMP_INPUT_NONINVERTING)) \
406 | (hopamp->Init.TrimmingValueN));
407 MODIFY_REG(hopamp->Instance->OTR, OPAMP_OTR_TRIMOFFSETN | OPAMP_OTR_TRIMOFFSETP, updateotrlpotr);
408 }
409 else
410 {
411 /* OPAMP_POWERMODE_HIGHSPEED*/
412 /* transistors differential pair high (PMOS) and low (NMOS) for */
413 /* high speed mode. */
414 updateotrlpotr = (((hopamp->Init.TrimmingValuePHighSpeed) << (OPAMP_INPUT_NONINVERTING)) \
415 | (hopamp->Init.TrimmingValueNHighSpeed));
416 MODIFY_REG(hopamp->Instance->HSOTR, OPAMP_OTR_TRIMOFFSETN | OPAMP_OTR_TRIMOFFSETP, updateotrlpotr);
417 }
418 }
419
420 /* Update the OPAMP state*/
421 if (hopamp->State == HAL_OPAMP_STATE_RESET)
422 {
423 /* From RESET state to READY State */
424 hopamp->State = HAL_OPAMP_STATE_READY;
425 }
426 /* else: remain in READY or BUSY state (no update) */
427 return status;
428 }
429 }
430
431 /**
432 * @brief DeInitialize the OPAMP peripheral
433 * @note Deinitialization can be performed if the OPAMP configuration is locked.
434 * (the lock is SW in H7)
435 * @param hopamp OPAMP handle
436 * @retval HAL status
437 */
HAL_OPAMP_DeInit(OPAMP_HandleTypeDef * hopamp)438 HAL_StatusTypeDef HAL_OPAMP_DeInit(OPAMP_HandleTypeDef *hopamp)
439 {
440 HAL_StatusTypeDef status = HAL_OK;
441
442 /* Check the OPAMP handle allocation */
443 /* DeInit not allowed if calibration is on going */
444 if (hopamp == NULL)
445 {
446 status = HAL_ERROR;
447 }
448 else if (hopamp->State == HAL_OPAMP_STATE_CALIBBUSY)
449 {
450 status = HAL_ERROR;
451 }
452 else
453 {
454 /* Check the parameter */
455 assert_param(IS_OPAMP_ALL_INSTANCE(hopamp->Instance));
456
457 /* Set OPAMP_CSR register to reset value */
458 WRITE_REG(hopamp->Instance->CSR, OPAMP_CSR_RESET_VALUE);
459
460 /* DeInit the low level hardware */
461 #if (USE_HAL_OPAMP_REGISTER_CALLBACKS == 1U)
462 if (hopamp->MspDeInitCallback == NULL)
463 {
464 hopamp->MspDeInitCallback = HAL_OPAMP_MspDeInit;
465 }
466 /* DeInit the low level hardware */
467 hopamp->MspDeInitCallback(hopamp);
468 #else
469 HAL_OPAMP_MspDeInit(hopamp);
470 #endif /* USE_HAL_OPAMP_REGISTER_CALLBACKS */
471
472 /* Update the OPAMP state*/
473 hopamp->State = HAL_OPAMP_STATE_RESET;
474 /* Process unlocked */
475 __HAL_UNLOCK(hopamp);
476
477 }
478
479 return status;
480 }
481
482
483 /**
484 * @brief Initialize the OPAMP MSP.
485 * @param hopamp OPAMP handle
486 * @retval None
487 */
HAL_OPAMP_MspInit(OPAMP_HandleTypeDef * hopamp)488 __weak void HAL_OPAMP_MspInit(OPAMP_HandleTypeDef *hopamp)
489 {
490 /* Prevent unused argument(s) compilation warning */
491 UNUSED(hopamp);
492
493 /* NOTE : This function should not be modified, when the callback is needed,
494 the function "HAL_OPAMP_MspInit()" must be implemented in the user file.
495 */
496 }
497
498 /**
499 * @brief DeInitialize OPAMP MSP.
500 * @param hopamp OPAMP handle
501 * @retval None
502 */
HAL_OPAMP_MspDeInit(OPAMP_HandleTypeDef * hopamp)503 __weak void HAL_OPAMP_MspDeInit(OPAMP_HandleTypeDef *hopamp)
504 {
505 /* Prevent unused argument(s) compilation warning */
506 UNUSED(hopamp);
507 /* NOTE : This function should not be modified, when the callback is needed,
508 the function "HAL_OPAMP_MspDeInit()" must be implemented in the user file.
509 */
510 }
511
512 /**
513 * @}
514 */
515
516
517 /** @defgroup OPAMP_Exported_Functions_Group2 IO operation functions
518 * @brief IO operation functions
519 *
520 @verbatim
521 =======================================================================================================================
522 ##### IO operation functions #####
523 =======================================================================================================================
524 [..]
525 This subsection provides a set of functions allowing to manage the OPAMP
526 start, stop and calibration actions.
527
528 @endverbatim
529 * @{
530 */
531
532 /**
533 * @brief Start the OPAMP.
534 * @param hopamp OPAMP handle
535 * @retval HAL status
536 */
HAL_OPAMP_Start(OPAMP_HandleTypeDef * hopamp)537 HAL_StatusTypeDef HAL_OPAMP_Start(OPAMP_HandleTypeDef *hopamp)
538 {
539 HAL_StatusTypeDef status = HAL_OK;
540
541 /* Check the OPAMP handle allocation */
542 /* Check if OPAMP locked */
543 if (hopamp == NULL)
544 {
545 status = HAL_ERROR;
546 }
547 else if (hopamp->State == HAL_OPAMP_STATE_BUSYLOCKED)
548 {
549 status = HAL_ERROR;
550 }
551 else
552 {
553 /* Check the parameter */
554 assert_param(IS_OPAMP_ALL_INSTANCE(hopamp->Instance));
555
556 if (hopamp->State == HAL_OPAMP_STATE_READY)
557 {
558 /* Enable the selected opamp */
559 SET_BIT(hopamp->Instance->CSR, OPAMP_CSR_OPAMPxEN);
560
561 /* Update the OPAMP state*/
562 /* From HAL_OPAMP_STATE_READY to HAL_OPAMP_STATE_BUSY */
563 hopamp->State = HAL_OPAMP_STATE_BUSY;
564 }
565 else
566 {
567 status = HAL_ERROR;
568 }
569
570 }
571 return status;
572 }
573
574 /**
575 * @brief Stop the OPAMP.
576 * @param hopamp OPAMP handle
577 * @retval HAL status
578 */
HAL_OPAMP_Stop(OPAMP_HandleTypeDef * hopamp)579 HAL_StatusTypeDef HAL_OPAMP_Stop(OPAMP_HandleTypeDef *hopamp)
580 {
581 HAL_StatusTypeDef status = HAL_OK;
582
583 /* Check the OPAMP handle allocation */
584 /* Check if OPAMP locked */
585 /* Check if OPAMP calibration ongoing */
586 if (hopamp == NULL)
587 {
588 status = HAL_ERROR;
589 }
590 else if (hopamp->State == HAL_OPAMP_STATE_BUSYLOCKED)
591 {
592 status = HAL_ERROR;
593 }
594 else if (hopamp->State == HAL_OPAMP_STATE_CALIBBUSY)
595 {
596 status = HAL_ERROR;
597 }
598 else
599 {
600 /* Check the parameter */
601 assert_param(IS_OPAMP_ALL_INSTANCE(hopamp->Instance));
602
603 if (hopamp->State == HAL_OPAMP_STATE_BUSY)
604 {
605 /* Disable the selected opamp */
606 CLEAR_BIT(hopamp->Instance->CSR, OPAMP_CSR_OPAMPxEN);
607
608 /* Update the OPAMP state*/
609 /* From HAL_OPAMP_STATE_BUSY to HAL_OPAMP_STATE_READY*/
610 hopamp->State = HAL_OPAMP_STATE_READY;
611 }
612 else
613 {
614 status = HAL_ERROR;
615 }
616 }
617 return status;
618 }
619
620 /**
621 * @brief Run the self calibration of one OPAMP.
622 * @note Calibration is performed in the mode specified in OPAMP init
623 * structure (mode normal or high-speed). To perform calibration for
624 * both modes, repeat this function twice after OPAMP init structure
625 * accordingly updated.
626 * @param hopamp handle
627 * @retval Updated offset trimming values (PMOS & NMOS), user trimming is enabled
628 * @retval HAL status
629 */
HAL_OPAMP_SelfCalibrate(OPAMP_HandleTypeDef * hopamp)630 HAL_StatusTypeDef HAL_OPAMP_SelfCalibrate(OPAMP_HandleTypeDef *hopamp)
631 {
632
633 HAL_StatusTypeDef status = HAL_OK;
634
635 uint32_t trimmingvaluen;
636 uint32_t trimmingvaluep;
637 uint32_t delta;
638 uint32_t opampmode;
639
640 /* Selection of register of trimming depending on power mode: OTR or HSOTR */
641 __IO uint32_t *tmp_opamp_reg_trimming;
642
643 /* Check the OPAMP handle allocation */
644 /* Check if OPAMP locked */
645 if (hopamp == NULL)
646 {
647 status = HAL_ERROR;
648 }
649 else if (hopamp->State == HAL_OPAMP_STATE_BUSYLOCKED)
650 {
651 status = HAL_ERROR;
652 }
653 else
654 {
655
656 /* Check if OPAMP in calibration mode and calibration not yet enable */
657 if (hopamp->State == HAL_OPAMP_STATE_READY)
658 {
659 /* Check the parameter */
660 assert_param(IS_OPAMP_ALL_INSTANCE(hopamp->Instance));
661 assert_param(IS_OPAMP_POWERMODE(hopamp->Init.PowerMode));
662
663 opampmode = READ_BIT(hopamp->Instance->CSR, OPAMP_CSR_VMSEL);
664
665 /* Use of standalone mode */
666 MODIFY_REG(hopamp->Instance->CSR, OPAMP_CSR_VMSEL, OPAMP_STANDALONE_MODE);
667 /* user trimming values are used for offset calibration */
668 SET_BIT(hopamp->Instance->CSR, OPAMP_CSR_USERTRIM);
669
670 /* Select trimming settings depending on power mode */
671 if (hopamp->Init.PowerMode == OPAMP_POWERMODE_NORMAL)
672 {
673 tmp_opamp_reg_trimming = &hopamp->Instance->OTR;
674
675 }
676 else
677 {
678 /* high speed Mode */
679 tmp_opamp_reg_trimming = &hopamp->Instance->HSOTR;
680 }
681
682
683 /* Enable calibration */
684 SET_BIT(hopamp->Instance->CSR, OPAMP_CSR_CALON);
685
686 /* Force internal reference on VP */
687 SET_BIT(hopamp->Instance->CSR, OPAMP_CSR_FORCEVP);
688
689 /* 1st calibration - N */
690 MODIFY_REG(hopamp->Instance->CSR, OPAMP_CSR_CALSEL, OPAMP_VREF_90VDDA);
691
692 /* Enable the selected opamp */
693 SET_BIT(hopamp->Instance->CSR, OPAMP_CSR_OPAMPxEN);
694
695 /* Init trimming counter */
696 /* Medium value */
697 trimmingvaluen = 16U;
698 delta = 8U;
699
700 while (delta != 0U)
701 {
702 /* Set candidate trimming */
703 /* OPAMP_POWERMODE_NORMAL */
704 MODIFY_REG(*tmp_opamp_reg_trimming, OPAMP_OTR_TRIMOFFSETN, trimmingvaluen);
705
706 /* OFFTRIMmax delay 2 ms as per datasheet (electrical characteristics */
707 /* Offset trim time: during calibration, minimum time needed between */
708 /* two steps to have 1 mV accuracy */
709 HAL_Delay(OPAMP_TRIMMING_DELAY);
710
711 if (READ_BIT(hopamp->Instance->CSR, OPAMP_CSR_CALOUT) != 0U)
712 {
713 /* OPAMP_CSR_CALOUT is HIGH try higher trimming */
714 trimmingvaluen += delta;
715 }
716 else
717 {
718 /* OPAMP_CSR_CALOUT is LOW try lower trimming */
719 trimmingvaluen -= delta;
720 }
721 /* Divide range by 2 to continue dichotomy sweep */
722 delta >>= 1;
723 }
724
725 /* Still need to check if right calibration is current value or one step below */
726 /* Indeed the first value that causes the OUTCAL bit to change from 1 to 0 */
727
728 MODIFY_REG(*tmp_opamp_reg_trimming, OPAMP_OTR_TRIMOFFSETN, trimmingvaluen);
729
730 /* OFFTRIMmax delay 2 ms as per datasheet (electrical characteristics */
731 /* Offset trim time: during calibration, minimum time needed between */
732 /* two steps to have 1 mV accuracy */
733 HAL_Delay(OPAMP_TRIMMING_DELAY);
734
735 if ((READ_BIT(hopamp->Instance->CSR, OPAMP_CSR_CALOUT)) != 0U)
736 {
737 /* Trimming value is actually one value more */
738 trimmingvaluen++;
739 /* Set right trimming */
740 MODIFY_REG(*tmp_opamp_reg_trimming, OPAMP_OTR_TRIMOFFSETN, trimmingvaluen);
741 }
742
743 /* 2nd calibration - P */
744 MODIFY_REG(hopamp->Instance->CSR, OPAMP_CSR_CALSEL, OPAMP_VREF_10VDDA);
745
746 /* Init trimming counter */
747 /* Medium value */
748 trimmingvaluep = 16U;
749 delta = 8U;
750
751 while (delta != 0U)
752 {
753 /* Set candidate trimming */
754 /* OPAMP_POWERMODE_NORMAL */
755 MODIFY_REG(*tmp_opamp_reg_trimming, OPAMP_OTR_TRIMOFFSETP, (trimmingvaluep << OPAMP_INPUT_NONINVERTING));
756
757 /* OFFTRIMmax delay 2 ms as per datasheet (electrical characteristics */
758 /* Offset trim time: during calibration, minimum time needed between */
759 /* two steps to have 1 mV accuracy */
760 HAL_Delay(OPAMP_TRIMMING_DELAY);
761
762 if (READ_BIT(hopamp->Instance->CSR, OPAMP_CSR_CALOUT) != 0U)
763 {
764 /* OPAMP_CSR_CALOUT is HIGH try higher trimming */
765 trimmingvaluep += delta;
766 }
767 else
768 {
769 /* OPAMP_CSR_CALOUT is LOW try lower trimming */
770 trimmingvaluep -= delta;
771 }
772
773 /* Divide range by 2 to continue dichotomy sweep */
774 delta >>= 1U;
775 }
776
777 /* Still need to check if right calibration is current value or one step below */
778 /* Indeed the first value that causes the OUTCAL bit to change from 1 to 0 */
779 /* Set candidate trimming */
780 MODIFY_REG(*tmp_opamp_reg_trimming, OPAMP_OTR_TRIMOFFSETP, (trimmingvaluep << OPAMP_INPUT_NONINVERTING));
781
782 /* OFFTRIMmax delay 2 ms as per datasheet (electrical characteristics */
783 /* Offset trim time: during calibration, minimum time needed between */
784 /* two steps to have 1 mV accuracy */
785 HAL_Delay(OPAMP_TRIMMING_DELAY);
786
787 if (READ_BIT(hopamp->Instance->CSR, OPAMP_CSR_CALOUT) != 0U)
788 {
789 /* Trimming value is actually one value more */
790 trimmingvaluep++;
791 MODIFY_REG(*tmp_opamp_reg_trimming, OPAMP_OTR_TRIMOFFSETP, (trimmingvaluep << OPAMP_INPUT_NONINVERTING));
792 }
793
794 /* Disable calibration & set normal mode (operating mode) */
795 CLEAR_BIT(hopamp->Instance->CSR, OPAMP_CSR_CALON);
796
797 /* Disable the OPAMP */
798 CLEAR_BIT(hopamp->Instance->CSR, OPAMP_CSR_OPAMPxEN);
799
800 /* Set operating mode back */
801 CLEAR_BIT(hopamp->Instance->CSR, OPAMP_CSR_FORCEVP);
802
803 /* Self calibration is successful */
804 /* Store calibration(user trimming) results in init structure. */
805
806 /* Set user trimming mode */
807 hopamp->Init.UserTrimming = OPAMP_TRIMMING_USER;
808
809 /* Affect calibration parameters depending on mode normal/high speed */
810 if (hopamp->Init.PowerMode != OPAMP_POWERMODE_HIGHSPEED)
811 {
812 /* Write calibration result N */
813 hopamp->Init.TrimmingValueN = trimmingvaluen;
814 /* Write calibration result P */
815 hopamp->Init.TrimmingValueP = trimmingvaluep;
816 }
817 else
818 {
819 /* Write calibration result N */
820 hopamp->Init.TrimmingValueNHighSpeed = trimmingvaluen;
821 /* Write calibration result P */
822 hopamp->Init.TrimmingValuePHighSpeed = trimmingvaluep;
823 }
824 /* Restore OPAMP mode after calibration */
825 MODIFY_REG(hopamp->Instance->CSR, OPAMP_CSR_VMSEL, opampmode);
826 }
827
828 else
829 {
830 /* OPAMP can not be calibrated from this mode */
831 status = HAL_ERROR;
832 }
833 }
834 return status;
835 }
836
837 /**
838 * @}
839 */
840
841 /** @defgroup OPAMP_Exported_Functions_Group3 Peripheral Control functions
842 * @brief Peripheral Control functions
843 *
844 @verbatim
845 =======================================================================================================================
846 ##### Peripheral Control functions #####
847 =======================================================================================================================
848 [..]
849 This subsection provides a set of functions allowing to control the OPAMP data
850 transfers.
851
852
853
854 @endverbatim
855 * @{
856 */
857
858 /**
859 * @brief Lock the selected OPAMP configuration.
860 * @note On STM32H5, HAL OPAMP lock is software lock only (in
861 * contrast of hardware lock available on some other STM32
862 * devices)
863 * @param hopamp OPAMP handle
864 * @retval HAL status
865 */
HAL_OPAMP_Lock(OPAMP_HandleTypeDef * hopamp)866 HAL_StatusTypeDef HAL_OPAMP_Lock(OPAMP_HandleTypeDef *hopamp)
867 {
868 HAL_StatusTypeDef status = HAL_OK;
869
870 /* Check the OPAMP handle allocation */
871 /* Check if OPAMP locked */
872 /* OPAMP can be locked when enabled and running in normal mode */
873 /* It is meaningless otherwise */
874 if (hopamp == NULL)
875 {
876 status = HAL_ERROR;
877 }
878
879 else if (hopamp->State != HAL_OPAMP_STATE_BUSY)
880 {
881 status = HAL_ERROR;
882 }
883 else
884 {
885 /* Check the parameter */
886 assert_param(IS_OPAMP_ALL_INSTANCE(hopamp->Instance));
887
888 /* OPAMP state changed to locked */
889 hopamp->State = HAL_OPAMP_STATE_BUSYLOCKED;
890 }
891 return status;
892 }
893
894 /**
895 * @brief Return the OPAMP factory trimming value.
896 * @note On STM32H5 OPAMP, user can retrieve factory trimming if
897 * OPAMP has never been set to user trimming before.
898 * Therefore, this function must be called when OPAMP init
899 * parameter "UserTrimming" is set to trimming factory,
900 * and before OPAMP calibration (function
901 * "HAL_OPAMP_SelfCalibrate()").
902 * Otherwise, factory trimming value cannot be retrieved and
903 * error status is returned.
904 * @param hopamp OPAMP handle
905 * @param trimmingoffset Trimming offset (P or N)
906 * This parameter must be a value of @ref OPAMP_FactoryTrimming
907 * @note Calibration parameter retrieved is corresponding to the mode
908 * specified in OPAMP init structure (mode normal or high-speed).
909 * To retrieve calibration parameters for both modes, repeat this
910 * function after OPAMP init structure accordingly updated.
911 * @retval Trimming value (P or N): range: 0->31
912 * or OPAMP_FACTORYTRIMMING_DUMMY if trimming value is not available
913 *
914 */
HAL_OPAMP_GetTrimOffset(const OPAMP_HandleTypeDef * hopamp,uint32_t trimmingoffset)915 HAL_OPAMP_TrimmingValueTypeDef HAL_OPAMP_GetTrimOffset(const OPAMP_HandleTypeDef *hopamp, uint32_t trimmingoffset)
916 {
917 HAL_OPAMP_TrimmingValueTypeDef trimmingvalue;
918
919 /* Selection of register of trimming depending on power mode: OTR or LPOTR */
920 __IO uint32_t *tmp_opamp_reg_trimming;
921
922 /* Check the OPAMP handle allocation */
923 /* Value can be retrieved in HAL_OPAMP_STATE_READY state */
924 if (hopamp == NULL)
925 {
926 return OPAMP_FACTORYTRIMMING_DUMMY;
927 }
928
929 if (hopamp->State == HAL_OPAMP_STATE_READY)
930 {
931 /* Check the parameter */
932 assert_param(IS_OPAMP_ALL_INSTANCE(hopamp->Instance));
933 assert_param(IS_OPAMP_FACTORYTRIMMING(trimmingoffset));
934 assert_param(IS_OPAMP_POWERMODE(hopamp->Init.PowerMode));
935
936 /* Check the trimming mode */
937 if (READ_BIT(hopamp->Instance->CSR, OPAMP_CSR_USERTRIM) != 0U)
938 {
939 /* This function must called when OPAMP init parameter "UserTrimming" */
940 /* is set to trimming factory, and before OPAMP calibration (function */
941 /* "HAL_OPAMP_SelfCalibrate()"). */
942 /* Otherwise, factory trimming value cannot be retrieved and error */
943 /* status is returned. */
944 trimmingvalue = OPAMP_FACTORYTRIMMING_DUMMY;
945 }
946 else
947 {
948 /* Select trimming settings depending on power mode */
949 if (hopamp->Init.PowerMode == OPAMP_POWERMODE_NORMAL)
950 {
951 tmp_opamp_reg_trimming = &hopamp->Instance->OTR;
952 }
953 else
954 {
955 tmp_opamp_reg_trimming = &hopamp->Instance->HSOTR;
956 }
957
958 /* Get factory trimming */
959 if (trimmingoffset == OPAMP_FACTORYTRIMMING_P)
960 {
961 /* OPAMP_FACTORYTRIMMING_P */
962 trimmingvalue = ((*tmp_opamp_reg_trimming) & OPAMP_OTR_TRIMOFFSETP) >> OPAMP_INPUT_NONINVERTING;
963 }
964 else
965 {
966 /* OPAMP_FACTORYTRIMMING_N */
967 trimmingvalue = (*tmp_opamp_reg_trimming) & OPAMP_OTR_TRIMOFFSETN;
968 }
969 }
970 }
971 else
972 {
973 return OPAMP_FACTORYTRIMMING_DUMMY;
974 }
975
976 return trimmingvalue;
977 }
978
979 /**
980 * @}
981 */
982
983
984 /** @defgroup OPAMP_Exported_Functions_Group4 Peripheral State functions
985 * @brief Peripheral State functions
986 *
987 @verbatim
988 =======================================================================================================================
989 ##### Peripheral State functions #####
990 =======================================================================================================================
991 [..]
992 This subsection permits to get in run-time the status of the peripheral.
993
994 @endverbatim
995 * @{
996 */
997
998 /**
999 * @brief Return the OPAMP handle state.
1000 * @param hopamp OPAMP handle
1001 * @retval HAL state
1002 */
HAL_OPAMP_GetState(const OPAMP_HandleTypeDef * hopamp)1003 HAL_OPAMP_StateTypeDef HAL_OPAMP_GetState(const OPAMP_HandleTypeDef *hopamp)
1004 {
1005 /* Check the OPAMP handle allocation */
1006 if (hopamp == NULL)
1007 {
1008 return HAL_OPAMP_STATE_RESET;
1009 }
1010
1011 /* Check the parameter */
1012 assert_param(IS_OPAMP_ALL_INSTANCE(hopamp->Instance));
1013
1014 /* Return OPAMP handle state */
1015 return hopamp->State;
1016 }
1017
1018 /**
1019 * @}
1020 */
1021
1022 #if (USE_HAL_OPAMP_REGISTER_CALLBACKS == 1U)
1023 /**
1024 * @brief Register a User OPAMP Callback
1025 * To be used instead of the weak (surcharged) predefined callback
1026 * @note The HAL_OPAMP_RegisterCallback() may be called before HAL_OPAMP_Init() in HAL_OPAMP_STATE_RESET to register
1027 * callbacks for HAL_OPAMP_MSPINIT_CB_ID and HAL_OPAMP_MSPDEINIT_CB_ID
1028 * @param hopamp OPAMP handle
1029 * @param CallbackId ID of the callback to be registered
1030 * This parameter can be one of the following values:
1031 * @arg @ref HAL_OPAMP_MSPINIT_CB_ID OPAMP MspInit callback ID
1032 * @arg @ref HAL_OPAMP_MSPDEINIT_CB_ID OPAMP MspDeInit callback ID
1033 * @param pCallback pointer to the Callback function
1034 * @retval status
1035 */
HAL_OPAMP_RegisterCallback(OPAMP_HandleTypeDef * hopamp,HAL_OPAMP_CallbackIDTypeDef CallbackId,pOPAMP_CallbackTypeDef pCallback)1036 HAL_StatusTypeDef HAL_OPAMP_RegisterCallback(OPAMP_HandleTypeDef *hopamp, HAL_OPAMP_CallbackIDTypeDef CallbackId,
1037 pOPAMP_CallbackTypeDef pCallback)
1038 {
1039 HAL_StatusTypeDef status = HAL_OK;
1040
1041 if (pCallback == NULL)
1042 {
1043 return HAL_ERROR;
1044 }
1045
1046 if (hopamp->State == HAL_OPAMP_STATE_READY)
1047 {
1048 switch (CallbackId)
1049 {
1050 case HAL_OPAMP_MSPINIT_CB_ID :
1051 hopamp->MspInitCallback = pCallback;
1052 break;
1053 case HAL_OPAMP_MSPDEINIT_CB_ID :
1054 hopamp->MspDeInitCallback = pCallback;
1055 break;
1056 default :
1057 /* update return status */
1058 status = HAL_ERROR;
1059 break;
1060 }
1061 }
1062 else if (hopamp->State == HAL_OPAMP_STATE_RESET)
1063 {
1064 switch (CallbackId)
1065 {
1066 case HAL_OPAMP_MSPINIT_CB_ID :
1067 hopamp->MspInitCallback = pCallback;
1068 break;
1069 case HAL_OPAMP_MSPDEINIT_CB_ID :
1070 hopamp->MspDeInitCallback = pCallback;
1071 break;
1072 default :
1073 /* update return status */
1074 status = HAL_ERROR;
1075 break;
1076 }
1077 }
1078 else
1079 {
1080 /* update return status */
1081 status = HAL_ERROR;
1082 }
1083
1084 return status;
1085 }
1086
1087 /**
1088 * @brief Unregister a User OPAMP Callback
1089 * OPAMP Callback is redirected to the weak (surcharged) predefined callback
1090 * @note The HAL_OPAMP_UnRegisterCallback() may be called before HAL_OPAMP_Init() in HAL_OPAMP_STATE_RESET to un-register
1091 * callbacks for HAL_OPAMP_MSPINIT_CB_ID and HAL_OPAMP_MSPDEINIT_CB_ID
1092 * @param hopamp OPAMP handle
1093 * @param CallbackId ID of the callback to be unregistered
1094 * This parameter can be one of the following values:
1095 * @arg @ref HAL_OPAMP_MSPINIT_CB_ID OPAMP MSP Init Callback ID
1096 * @arg @ref HAL_OPAMP_MSPDEINIT_CB_ID OPAMP MSP DeInit Callback ID
1097 * @arg @ref HAL_OPAMP_ALL_CB_ID OPAMP All Callbacks
1098 * @retval status
1099 */
HAL_OPAMP_UnRegisterCallback(OPAMP_HandleTypeDef * hopamp,HAL_OPAMP_CallbackIDTypeDef CallbackId)1100 HAL_StatusTypeDef HAL_OPAMP_UnRegisterCallback(OPAMP_HandleTypeDef *hopamp, HAL_OPAMP_CallbackIDTypeDef CallbackId)
1101 {
1102 HAL_StatusTypeDef status = HAL_OK;
1103
1104 if (hopamp->State == HAL_OPAMP_STATE_READY)
1105 {
1106 switch (CallbackId)
1107 {
1108 case HAL_OPAMP_MSPINIT_CB_ID :
1109 hopamp->MspInitCallback = HAL_OPAMP_MspInit;
1110 break;
1111 case HAL_OPAMP_MSPDEINIT_CB_ID :
1112 hopamp->MspDeInitCallback = HAL_OPAMP_MspDeInit;
1113 break;
1114 case HAL_OPAMP_ALL_CB_ID :
1115 hopamp->MspInitCallback = HAL_OPAMP_MspInit;
1116 hopamp->MspDeInitCallback = HAL_OPAMP_MspDeInit;
1117 break;
1118 default :
1119 /* update return status */
1120 status = HAL_ERROR;
1121 break;
1122 }
1123 }
1124 else if (hopamp->State == HAL_OPAMP_STATE_RESET)
1125 {
1126 switch (CallbackId)
1127 {
1128 case HAL_OPAMP_MSPINIT_CB_ID :
1129 hopamp->MspInitCallback = HAL_OPAMP_MspInit;
1130 break;
1131 case HAL_OPAMP_MSPDEINIT_CB_ID :
1132 hopamp->MspDeInitCallback = HAL_OPAMP_MspDeInit;
1133 break;
1134 default :
1135 /* update return status */
1136 status = HAL_ERROR;
1137 break;
1138 }
1139 }
1140 else
1141 {
1142 /* update return status */
1143 status = HAL_ERROR;
1144 }
1145
1146 return status;
1147 }
1148
1149 #endif /* USE_HAL_OPAMP_REGISTER_CALLBACKS */
1150 /**
1151 * @}
1152 */
1153
1154 /**
1155 * @}
1156 */
1157 #endif /* HAL_OPAMP_MODULE_ENABLED */
1158 /**
1159 * @}
1160 */
1161
1162 /**
1163 * @}
1164 */
1165