1 /**
2 ******************************************************************************
3 * @file stm32l1xx_hal_opamp_ex.c
4 * @author MCD Application Team
5 * @brief Extended OPAMP HAL module driver.
6 *
7 * This file provides firmware functions to manage the following
8 * functionalities of the operational amplifier(s) peripheral:
9 * + Extended Initialization and de-initialization functions
10 * + Extended Peripheral Control functions
11 *
12 ******************************************************************************
13 * @attention
14 *
15 * Copyright (c) 2017 STMicroelectronics.
16 * All rights reserved.
17 *
18 * This software is licensed under terms that can be found in the LICENSE file
19 * in the root directory of this software component.
20 * If no LICENSE file comes with this software, it is provided AS-IS.
21 *
22 ******************************************************************************
23 */
24
25 /* Includes ------------------------------------------------------------------*/
26 #include "stm32l1xx_hal.h"
27
28 #ifdef HAL_OPAMP_MODULE_ENABLED
29
30 #if defined (STM32L151xCA) || defined (STM32L151xD) || defined (STM32L152xCA) || defined (STM32L152xD) || defined (STM32L162xCA) || defined (STM32L162xD) || defined (STM32L151xE) || defined (STM32L151xDX) || defined (STM32L152xE) || defined (STM32L152xDX) || defined (STM32L162xE) || defined (STM32L162xDX) || defined (STM32L162xC) || defined (STM32L152xC) || defined (STM32L151xC)
31
32 /** @addtogroup STM32L1xx_HAL_Driver
33 * @{
34 */
35
36 /** @defgroup OPAMPEx OPAMPEx
37 * @brief OPAMP Extended HAL module driver.
38 * @{
39 */
40
41 /* Private typedef -----------------------------------------------------------*/
42 /* Private define ------------------------------------------------------------*/
43 /* Private macro -------------------------------------------------------------*/
44 /* Private variables ---------------------------------------------------------*/
45 /* Private function prototypes -----------------------------------------------*/
46 /* Exported functions --------------------------------------------------------*/
47
48 /** @addtogroup OPAMPEx_Exported_Functions OPAMPEx Exported Functions
49 * @{
50 */
51
52 /** @addtogroup OPAMPEx_Exported_Functions_Group1
53 * @brief Extended operation functions
54 *
55 @verbatim
56 ===============================================================================
57 ##### Extended IO operation functions #####
58 ===============================================================================
59 [..]
60 (+) OPAMP Self calibration.
61
62 @endverbatim
63 * @{
64 */
65
66 #if defined (STM32L151xD) || defined (STM32L152xD) || defined (STM32L162xD)
67
68 /* 3 OPAMPS available */
69 /* 3 OPAMPS can be calibrated in parallel */
70
71 /**
72 * @brief Run the self calibration of the 3 OPAMPs in parallel.
73 * @note Trimming values (PMOS & NMOS) are updated and user trimming is
74 * enabled is calibration is successful.
75 * @note Calibration is performed in the mode specified in OPAMP init
76 * structure (mode normal or low-power). To perform calibration for
77 * both modes, repeat this function twice after OPAMP init structure
78 * accordingly updated.
79 * @note Calibration runs about 10 ms (5 dichotmy steps, repeated for P
80 * and N transistors: 10 steps with 1 ms for each step).
81 * @param hopamp1 handle
82 * @param hopamp2 handle
83 * @param hopamp3 handle
84 * @retval HAL status
85 */
HAL_OPAMPEx_SelfCalibrateAll(OPAMP_HandleTypeDef * hopamp1,OPAMP_HandleTypeDef * hopamp2,OPAMP_HandleTypeDef * hopamp3)86 HAL_StatusTypeDef HAL_OPAMPEx_SelfCalibrateAll(OPAMP_HandleTypeDef *hopamp1, OPAMP_HandleTypeDef *hopamp2, OPAMP_HandleTypeDef *hopamp3)
87 {
88 HAL_StatusTypeDef status = HAL_OK;
89
90 uint32_t* opamp1_trimmingvalue;
91 uint32_t opamp1_trimmingvaluen = 0;
92 uint32_t opamp1_trimmingvaluep = 0;
93
94 uint32_t* opamp2_trimmingvalue;
95 uint32_t opamp2_trimmingvaluen = 0;
96 uint32_t opamp2_trimmingvaluep = 0;
97
98 uint32_t* opamp3_trimmingvalue;
99 uint32_t opamp3_trimmingvaluen = 0;
100 uint32_t opamp3_trimmingvaluep = 0;
101
102 uint32_t trimming_diff_pair; /* Selection of differential transistors pair high or low */
103
104 __IO uint32_t* tmp_opamp1_reg_trimming; /* Selection of register of trimming depending on power mode: OTR or LPOTR */
105 __IO uint32_t* tmp_opamp2_reg_trimming;
106 __IO uint32_t* tmp_opamp3_reg_trimming;
107 uint32_t tmp_opamp1_otr_otuser; /* Selection of bit OPAMP_OTR_OT_USER depending on trimming register pointed: OTR or LPOTR */
108 uint32_t tmp_opamp2_otr_otuser;
109 uint32_t tmp_opamp3_otr_otuser;
110
111 uint32_t tmp_Opa1calout_DefaultSate; /* Bit OPAMP_CSR_OPA1CALOUT default state when trimming value is 00000b. Used to detect the bit toggling */
112 uint32_t tmp_Opa2calout_DefaultSate; /* Bit OPAMP_CSR_OPA2CALOUT default state when trimming value is 00000b. Used to detect the bit toggling */
113 uint32_t tmp_Opa3calout_DefaultSate; /* Bit OPAMP_CSR_OPA3CALOUT default state when trimming value is 00000b. Used to detect the bit toggling */
114
115 uint32_t tmp_OpaxSwitchesContextBackup = 0x0U;
116
117 uint8_t trimming_diff_pair_iteration_count = 0x0U; /* For calibration loop algorithm: to repeat the calibration loop for both differential transistors pair high and low */
118 uint8_t delta; /* For calibration loop algorithm: Variable for dichotomy steps value */
119 uint8_t final_step_check = 0x0U; /* For calibration loop algorithm: Flag for additional check of last trimming step */
120
121
122 if((hopamp1 == NULL) || (hopamp2 == NULL) || (hopamp3 == NULL))
123 {
124 status = HAL_ERROR;
125 }
126 /* Check if OPAMP in calibration mode and calibration not yet enable */
127 else if(hopamp1->State != HAL_OPAMP_STATE_READY)
128 {
129 status = HAL_ERROR;
130 }
131 else if(hopamp2->State != HAL_OPAMP_STATE_READY)
132 {
133 status = HAL_ERROR;
134 }
135 else if(hopamp3->State != HAL_OPAMP_STATE_READY)
136 {
137 status = HAL_ERROR;
138 }
139
140 else
141 {
142 /* Check the parameter */
143 assert_param(IS_OPAMP_ALL_INSTANCE(hopamp1->Instance));
144 assert_param(IS_OPAMP_ALL_INSTANCE(hopamp2->Instance));
145 assert_param(IS_OPAMP_ALL_INSTANCE(hopamp3->Instance));
146 assert_param(IS_OPAMP_POWERMODE(hopamp1->Init.PowerMode));
147 assert_param(IS_OPAMP_POWERMODE(hopamp2->Init.PowerMode));
148 assert_param(IS_OPAMP_POWERMODE(hopamp3->Init.PowerMode));
149
150 /* Update OPAMP state */
151 hopamp1->State = HAL_OPAMP_STATE_CALIBBUSY;
152 hopamp2->State = HAL_OPAMP_STATE_CALIBBUSY;
153 hopamp3->State = HAL_OPAMP_STATE_CALIBBUSY;
154
155 /* Backup of switches configuration to restore it at the end of the */
156 /* calibration. */
157 tmp_OpaxSwitchesContextBackup = READ_BIT(OPAMP->CSR, OPAMP_CSR_ALL_SWITCHES_ALL_OPAMPS);
158
159 /* Open all switches on non-inverting input, inverting input and output */
160 /* feedback. */
161 CLEAR_BIT(OPAMP->CSR, OPAMP_CSR_ALL_SWITCHES_ALL_OPAMPS);
162
163 /* Set calibration mode to user programmed trimming values */
164 SET_BIT(OPAMP->OTR, OPAMP_OTR_OT_USER);
165
166 /* Select trimming settings depending on power mode */
167 if (hopamp1->Init.PowerMode == OPAMP_POWERMODE_NORMAL)
168 {
169 tmp_opamp1_otr_otuser = OPAMP_OTR_OT_USER;
170 tmp_opamp1_reg_trimming = &OPAMP->OTR;
171 }
172 else
173 {
174 tmp_opamp1_otr_otuser = 0x00000000;
175 tmp_opamp1_reg_trimming = &OPAMP->LPOTR;
176 }
177
178 if (hopamp2->Init.PowerMode == OPAMP_POWERMODE_NORMAL)
179 {
180 tmp_opamp2_otr_otuser = OPAMP_OTR_OT_USER;
181 tmp_opamp2_reg_trimming = &OPAMP->OTR;
182 }
183 else
184 {
185 tmp_opamp2_otr_otuser = 0x00000000;
186 tmp_opamp2_reg_trimming = &OPAMP->LPOTR;
187 }
188
189 if (hopamp3->Init.PowerMode == OPAMP_POWERMODE_NORMAL)
190 {
191 tmp_opamp3_otr_otuser = OPAMP_OTR_OT_USER;
192 tmp_opamp3_reg_trimming = &OPAMP->OTR;
193 }
194 else
195 {
196 tmp_opamp3_otr_otuser = 0x00000000;
197 tmp_opamp3_reg_trimming = &OPAMP->LPOTR;
198 }
199
200 /* Enable the selected opamp */
201 CLEAR_BIT (OPAMP->CSR, OPAMP_CSR_OPAXPD_ALL);
202
203 /* Perform trimming for both differential transistors pair high and low */
204 for (trimming_diff_pair_iteration_count = 0U; trimming_diff_pair_iteration_count <= 1U; trimming_diff_pair_iteration_count++)
205 {
206 if (trimming_diff_pair_iteration_count == 0U)
207 {
208 /* Calibration of transistors differential pair high (NMOS) */
209 trimming_diff_pair = OPAMP_FACTORYTRIMMING_N;
210 opamp1_trimmingvalue = &opamp1_trimmingvaluen;
211 opamp2_trimmingvalue = &opamp2_trimmingvaluen;
212 opamp3_trimmingvalue = &opamp3_trimmingvaluen;
213
214 /* Set bit OPAMP_CSR_OPAXCALOUT default state when trimming value */
215 /* is 00000b. Used to detect the bit toggling during trimming. */
216 tmp_Opa1calout_DefaultSate = RESET;
217 tmp_Opa2calout_DefaultSate = RESET;
218 tmp_Opa3calout_DefaultSate = RESET;
219
220 /* Enable calibration for N differential pair */
221 MODIFY_REG(OPAMP->CSR, OPAMP_CSR_OPAXCAL_L_ALL,
222 OPAMP_CSR_OPAXCAL_H_ALL);
223 }
224 else /* (trimming_diff_pair_iteration_count == 1) */
225 {
226 /* Calibration of transistors differential pair low (PMOS) */
227 trimming_diff_pair = OPAMP_FACTORYTRIMMING_P;
228 opamp1_trimmingvalue = &opamp1_trimmingvaluep;
229 opamp2_trimmingvalue = &opamp2_trimmingvaluep;
230 opamp3_trimmingvalue = &opamp3_trimmingvaluep;
231
232 /* Set bit OPAMP_CSR_OPAXCALOUT default state when trimming value */
233 /* is 00000b. Used to detect the bit toggling during trimming. */
234 tmp_Opa1calout_DefaultSate = OPAMP_CSR_OPAXCALOUT(hopamp1);
235 tmp_Opa2calout_DefaultSate = OPAMP_CSR_OPAXCALOUT(hopamp2);
236 tmp_Opa3calout_DefaultSate = OPAMP_CSR_OPAXCALOUT(hopamp3);
237
238 /* Enable calibration for P differential pair */
239 MODIFY_REG(OPAMP->CSR, OPAMP_CSR_OPAXCAL_H_ALL,
240 OPAMP_CSR_OPAXCAL_L_ALL);
241 }
242
243
244 /* Perform calibration parameter search by dichotomy sweep */
245 /* - Delta initial value 16: for 5 dichotomy steps: 16 for the */
246 /* initial range, then successive delta sweeps (8, 4, 2, 1). */
247 /* can extend the search range to +/- 15 units. */
248 /* - Trimming initial value 15: search range will go from 0 to 30 */
249 /* (Trimming value 31 is forbidden). */
250 /* Note: After dichotomy sweep, the trimming result is determined. */
251 /* However, the final trimming step is deduced from previous */
252 /* trimming steps tested but is not effectively tested. */
253 /* An additional test step (using variable "final_step_check") */
254 /* allow to Test the final trimming step. */
255 *opamp1_trimmingvalue = 15U;
256 *opamp2_trimmingvalue = 15U;
257 *opamp3_trimmingvalue = 15U;
258 delta = 16U;
259
260 while ((delta != 0U) || (final_step_check == 1U))
261 {
262 /* Set candidate trimming */
263 MODIFY_REG(*tmp_opamp1_reg_trimming, OPAMP_OFFSET_TRIM_SET(hopamp1, trimming_diff_pair, OPAMP_TRIM_VALUE_MASK) ,
264 OPAMP_OFFSET_TRIM_SET(hopamp1, trimming_diff_pair, *opamp1_trimmingvalue) | tmp_opamp1_otr_otuser);
265
266 MODIFY_REG(*tmp_opamp2_reg_trimming, OPAMP_OFFSET_TRIM_SET(hopamp2, trimming_diff_pair, OPAMP_TRIM_VALUE_MASK) ,
267 OPAMP_OFFSET_TRIM_SET(hopamp2, trimming_diff_pair, *opamp2_trimmingvalue) | tmp_opamp2_otr_otuser);
268
269 MODIFY_REG(*tmp_opamp3_reg_trimming, OPAMP_OFFSET_TRIM_SET(hopamp3, trimming_diff_pair, OPAMP_TRIM_VALUE_MASK) ,
270 OPAMP_OFFSET_TRIM_SET(hopamp3, trimming_diff_pair, *opamp3_trimmingvalue) | tmp_opamp3_otr_otuser);
271
272 /* Offset trimming time: during calibration, minimum time needed */
273 /* between two steps to have 1 mV accuracy. */
274 HAL_Delay(OPAMP_TRIMMING_DELAY);
275
276 /* Set flag for additional check of last trimming step equal to */
277 /* dichotomy step before its division by 2 (equivalent to previous */
278 /* value of dichotomy step). */
279 final_step_check = delta;
280
281 /* Divide range by 2 to continue dichotomy sweep */
282 delta >>= 1U;
283
284 /* Set trimming values for next iteration in function of trimming */
285 /* result toggle (versus initial state). */
286 /* Trimming values update with dichotomy delta of previous */
287 /* iteration. */
288 /* Note: on the last trimming loop, delta is equal to 0 and */
289 /* therefore has no effect. */
290 if (READ_BIT(OPAMP->CSR, OPAMP_CSR_OPAXCALOUT(hopamp1)) != tmp_Opa1calout_DefaultSate)
291 {
292 /* If calibration output is has toggled, try lower trimming */
293 *opamp1_trimmingvalue -= delta;
294 }
295 else
296 {
297 /* If calibration output is has not toggled, try higher trimming */
298 *opamp1_trimmingvalue += delta;
299 }
300
301 if (READ_BIT(OPAMP->CSR, OPAMP_CSR_OPAXCALOUT(hopamp2)) != tmp_Opa2calout_DefaultSate)
302 {
303 /* If calibration output is has toggled, try lower trimming */
304 *opamp2_trimmingvalue -= delta;
305 }
306 else
307 {
308 /* If calibration output is has not toggled, try higher trimming */
309 *opamp2_trimmingvalue += delta;
310 }
311
312 if (READ_BIT(OPAMP->CSR, OPAMP_CSR_OPAXCALOUT(hopamp3)) != tmp_Opa3calout_DefaultSate)
313 {
314 /* If calibration output is has toggled, try lower trimming */
315 *opamp3_trimmingvalue -= delta;
316 }
317 else
318 {
319 /* If calibration output is has not toggled, try higher trimming */
320 *opamp3_trimmingvalue += delta;
321 }
322 }
323
324 /* Check trimming result of the selected step and perform final fine */
325 /* trimming. */
326 /* - If calibration output is has toggled: the current step is */
327 /* already optimized. */
328 /* - If calibration output is has not toggled: the current step can */
329 /* be optimized by incrementing it of one step. */
330 if (READ_BIT(OPAMP->CSR, OPAMP_CSR_OPAXCALOUT(hopamp1)) == tmp_Opa1calout_DefaultSate)
331 {
332 *opamp1_trimmingvalue += 1U;
333
334 /* Set final fine trimming */
335 MODIFY_REG(*tmp_opamp1_reg_trimming, OPAMP_OFFSET_TRIM_SET(hopamp1, trimming_diff_pair, OPAMP_TRIM_VALUE_MASK) ,
336 OPAMP_OFFSET_TRIM_SET(hopamp1, trimming_diff_pair, *opamp1_trimmingvalue) | tmp_opamp1_otr_otuser);
337 }
338 if (READ_BIT(OPAMP->CSR, OPAMP_CSR_OPAXCALOUT(hopamp2)) == tmp_Opa2calout_DefaultSate)
339 {
340 *opamp2_trimmingvalue += 1U;
341
342 /* Set final fine trimming */
343 MODIFY_REG(*tmp_opamp2_reg_trimming, OPAMP_OFFSET_TRIM_SET(hopamp2, trimming_diff_pair, OPAMP_TRIM_VALUE_MASK) ,
344 OPAMP_OFFSET_TRIM_SET(hopamp2, trimming_diff_pair, *opamp2_trimmingvalue) | tmp_opamp2_otr_otuser);
345 }
346 if (READ_BIT(OPAMP->CSR, OPAMP_CSR_OPAXCALOUT(hopamp3)) == tmp_Opa3calout_DefaultSate)
347 {
348 *opamp3_trimmingvalue += 1U;
349
350 /* Set final fine trimming */
351 MODIFY_REG(*tmp_opamp3_reg_trimming, OPAMP_OFFSET_TRIM_SET(hopamp3, trimming_diff_pair, OPAMP_TRIM_VALUE_MASK) ,
352 OPAMP_OFFSET_TRIM_SET(hopamp3, trimming_diff_pair, *opamp3_trimmingvalue) | tmp_opamp3_otr_otuser);
353 }
354
355 }
356
357
358 /* Disable calibration for P and N differential pairs */
359 /* Disable the selected opamp */
360 CLEAR_BIT (OPAMP->CSR, (OPAMP_CSR_OPAXCAL_H_ALL |
361 OPAMP_CSR_OPAXCAL_L_ALL |
362 OPAMP_CSR_OPAXPD_ALL ));
363
364 /* Backup of switches configuration to restore it at the end of the */
365 /* calibration. */
366 SET_BIT(OPAMP->CSR, tmp_OpaxSwitchesContextBackup);
367
368 /* Self calibration is successful */
369 /* Store calibration (user trimming) results in init structure. */
370
371 /* Set user trimming mode */
372 hopamp1->Init.UserTrimming = OPAMP_TRIMMING_USER;
373 hopamp2->Init.UserTrimming = OPAMP_TRIMMING_USER;
374 hopamp3->Init.UserTrimming = OPAMP_TRIMMING_USER;
375
376 /* Affect calibration parameters depending on mode normal/low power */
377 if (hopamp1->Init.PowerMode != OPAMP_POWERMODE_LOWPOWER)
378 {
379 /* Write calibration result N */
380 hopamp1->Init.TrimmingValueN = opamp1_trimmingvaluen;
381 /* Write calibration result P */
382 hopamp1->Init.TrimmingValueP = opamp1_trimmingvaluep;
383 }
384 else
385 {
386 /* Write calibration result N */
387 hopamp1->Init.TrimmingValueNLowPower = opamp1_trimmingvaluen;
388 /* Write calibration result P */
389 hopamp1->Init.TrimmingValuePLowPower = opamp1_trimmingvaluep;
390 }
391
392 if (hopamp2->Init.PowerMode != OPAMP_POWERMODE_LOWPOWER)
393 {
394 /* Write calibration result N */
395 hopamp2->Init.TrimmingValueN = opamp2_trimmingvaluen;
396 /* Write calibration result P */
397 hopamp2->Init.TrimmingValueP = opamp2_trimmingvaluep;
398 }
399 else
400 {
401 /* Write calibration result N */
402 hopamp2->Init.TrimmingValueNLowPower = opamp2_trimmingvaluen;
403 /* Write calibration result P */
404 hopamp2->Init.TrimmingValuePLowPower = opamp2_trimmingvaluep;
405 }
406
407 if (hopamp3->Init.PowerMode != OPAMP_POWERMODE_LOWPOWER)
408 {
409 /* Write calibration result N */
410 hopamp3->Init.TrimmingValueN = opamp3_trimmingvaluen;
411 /* Write calibration result P */
412 hopamp3->Init.TrimmingValueP = opamp3_trimmingvaluep;
413 }
414 else
415 {
416 /* Write calibration result N */
417 hopamp3->Init.TrimmingValueNLowPower = opamp3_trimmingvaluen;
418 /* Write calibration result P */
419 hopamp3->Init.TrimmingValuePLowPower = opamp3_trimmingvaluep;
420 }
421
422 /* Update OPAMP state */
423 hopamp1->State = HAL_OPAMP_STATE_READY;
424 hopamp2->State = HAL_OPAMP_STATE_READY;
425 hopamp3->State = HAL_OPAMP_STATE_READY;
426 }
427 return status;
428 }
429
430 #else
431
432 /* 2 OPAMPS available */
433 /* 2 OPAMPS can be calibrated in parallel */
434
435 /**
436 * @brief Run the self calibration of the 2 OPAMPs in parallel.
437 * @note Trimming values (PMOS & NMOS) are updated and user trimming is
438 * enabled is calibration is successful.
439 * @note Calibration is performed in the mode specified in OPAMP init
440 * structure (mode normal or low-power). To perform calibration for
441 * both modes, repeat this function twice after OPAMP init structure
442 * accordingly updated.
443 * @note Calibration runs about 10 ms (5 dichotmy steps, repeated for P
444 * and N transistors: 10 steps with 1 ms for each step).
445 * @param hopamp1 handle
446 * @param hopamp2 handle
447 * @retval HAL status
448 */
HAL_OPAMPEx_SelfCalibrateAll(OPAMP_HandleTypeDef * hopamp1,OPAMP_HandleTypeDef * hopamp2)449 HAL_StatusTypeDef HAL_OPAMPEx_SelfCalibrateAll(OPAMP_HandleTypeDef *hopamp1, OPAMP_HandleTypeDef *hopamp2)
450 {
451 HAL_StatusTypeDef status = HAL_OK;
452
453 uint32_t* opamp1_trimmingvalue;
454 uint32_t opamp1_trimmingvaluen = 0;
455 uint32_t opamp1_trimmingvaluep = 0;
456
457 uint32_t* opamp2_trimmingvalue;
458 uint32_t opamp2_trimmingvaluen = 0;
459 uint32_t opamp2_trimmingvaluep = 0;
460
461 uint32_t trimming_diff_pair; /* Selection of differential transistors pair high or low */
462
463 __IO uint32_t* tmp_opamp1_reg_trimming; /* Selection of register of trimming depending on power mode: OTR or LPOTR */
464 __IO uint32_t* tmp_opamp2_reg_trimming;
465 uint32_t tmp_opamp1_otr_otuser; /* Selection of bit OPAMP_OTR_OT_USER depending on trimming register pointed: OTR or LPOTR */
466 uint32_t tmp_opamp2_otr_otuser;
467
468 uint32_t tmp_Opa1calout_DefaultSate; /* Bit OPAMP_CSR_OPA1CALOUT default state when trimming value is 00000b. Used to detect the bit toggling */
469 uint32_t tmp_Opa2calout_DefaultSate; /* Bit OPAMP_CSR_OPA2CALOUT default state when trimming value is 00000b. Used to detect the bit toggling */
470
471 uint32_t tmp_OpaxSwitchesContextBackup;
472
473 uint8_t trimming_diff_pair_iteration_count; /* For calibration loop algorithm: to repeat the calibration loop for both differential transistors pair high and low */
474 uint8_t delta; /* For calibration loop algorithm: Variable for dichotomy steps value */
475 uint8_t final_step_check = 0x0U; /* For calibration loop algorithm: Flag for additional check of last trimming step */
476
477
478 if((hopamp1 == NULL) || (hopamp2 == NULL))
479 {
480 status = HAL_ERROR;
481 }
482 /* Check if OPAMP in calibration mode and calibration not yet enable */
483 else if(hopamp1->State != HAL_OPAMP_STATE_READY)
484 {
485 status = HAL_ERROR;
486 }
487 else if(hopamp2->State != HAL_OPAMP_STATE_READY)
488 {
489 status = HAL_ERROR;
490 }
491 else
492 {
493 /* Check the parameter */
494 assert_param(IS_OPAMP_ALL_INSTANCE(hopamp1->Instance));
495 assert_param(IS_OPAMP_ALL_INSTANCE(hopamp2->Instance));
496 assert_param(IS_OPAMP_POWERMODE(hopamp1->Init.PowerMode));
497 assert_param(IS_OPAMP_POWERMODE(hopamp2->Init.PowerMode));
498
499 /* Update OPAMP state */
500 hopamp1->State = HAL_OPAMP_STATE_CALIBBUSY;
501 hopamp2->State = HAL_OPAMP_STATE_CALIBBUSY;
502
503 /* Backup of switches configuration to restore it at the end of the */
504 /* calibration. */
505 tmp_OpaxSwitchesContextBackup = READ_BIT(OPAMP->CSR, OPAMP_CSR_ALL_SWITCHES_ALL_OPAMPS);
506
507 /* Open all switches on non-inverting input, inverting input and output */
508 /* feedback. */
509 CLEAR_BIT(OPAMP->CSR, OPAMP_CSR_ALL_SWITCHES_ALL_OPAMPS);
510
511 /* Set calibration mode to user programmed trimming values */
512 SET_BIT(OPAMP->OTR, OPAMP_OTR_OT_USER);
513
514 /* Select trimming settings depending on power mode */
515 if (hopamp1->Init.PowerMode == OPAMP_POWERMODE_NORMAL)
516 {
517 tmp_opamp1_otr_otuser = OPAMP_OTR_OT_USER;
518 tmp_opamp1_reg_trimming = &OPAMP->OTR;
519 }
520 else
521 {
522 tmp_opamp1_otr_otuser = 0x00000000U;
523 tmp_opamp1_reg_trimming = &OPAMP->LPOTR;
524 }
525
526 if (hopamp2->Init.PowerMode == OPAMP_POWERMODE_NORMAL)
527 {
528 tmp_opamp2_otr_otuser = OPAMP_OTR_OT_USER;
529 tmp_opamp2_reg_trimming = &OPAMP->OTR;
530 }
531 else
532 {
533 tmp_opamp2_otr_otuser = 0x00000000U;
534 tmp_opamp2_reg_trimming = &OPAMP->LPOTR;
535 }
536
537 /* Enable the selected opamp */
538 CLEAR_BIT (OPAMP->CSR, OPAMP_CSR_OPAXPD_ALL);
539
540 /* Perform trimming for both differential transistors pair high and low */
541 for (trimming_diff_pair_iteration_count = 0U; trimming_diff_pair_iteration_count <= 1U; trimming_diff_pair_iteration_count++)
542 {
543 if (trimming_diff_pair_iteration_count == 0U)
544 {
545 /* Calibration of transistors differential pair high (NMOS) */
546 trimming_diff_pair = OPAMP_FACTORYTRIMMING_N;
547 opamp1_trimmingvalue = &opamp1_trimmingvaluen;
548 opamp2_trimmingvalue = &opamp2_trimmingvaluen;
549
550 /* Set bit OPAMP_CSR_OPAXCALOUT default state when trimming value */
551 /* is 00000b. Used to detect the bit toggling during trimming. */
552 tmp_Opa1calout_DefaultSate = 0U;
553 tmp_Opa2calout_DefaultSate = 0U;
554
555 /* Enable calibration for N differential pair */
556 MODIFY_REG(OPAMP->CSR, OPAMP_CSR_OPAXCAL_L_ALL,
557 OPAMP_CSR_OPAXCAL_H_ALL);
558 }
559 else /* (trimming_diff_pair_iteration_count == 1) */
560 {
561 /* Calibration of transistors differential pair low (PMOS) */
562 trimming_diff_pair = OPAMP_FACTORYTRIMMING_P;
563 opamp1_trimmingvalue = &opamp1_trimmingvaluep;
564 opamp2_trimmingvalue = &opamp2_trimmingvaluep;
565
566 /* Set bit OPAMP_CSR_OPAXCALOUT default state when trimming value */
567 /* is 00000b. Used to detect the bit toggling during trimming. */
568 tmp_Opa1calout_DefaultSate = (uint32_t) OPAMP_CSR_OPAXCALOUT(hopamp1);
569 tmp_Opa2calout_DefaultSate = OPAMP_CSR_OPAXCALOUT(hopamp2);
570
571 /* Enable calibration for P differential pair */
572 MODIFY_REG(OPAMP->CSR, OPAMP_CSR_OPAXCAL_H_ALL,
573 OPAMP_CSR_OPAXCAL_L_ALL);
574 }
575
576
577 /* Perform calibration parameter search by dichotomy sweep */
578 /* - Delta initial value 16: for 5 dichotomy steps: 16 for the */
579 /* initial range, then successive delta sweeps (8, 4, 2, 1). */
580 /* can extend the search range to +/- 15 units. */
581 /* - Trimming initial value 15: search range will go from 0 to 30 */
582 /* (Trimming value 31 is forbidden). */
583 /* Note: After dichotomy sweep, the trimming result is determined. */
584 /* However, the final trimming step is deduced from previous */
585 /* trimming steps tested but is not effectively tested. */
586 /* An additional test step (using variable "final_step_check") */
587 /* allow to Test the final trimming step. */
588 *opamp1_trimmingvalue = 15U;
589 *opamp2_trimmingvalue = 15U;
590 delta = 16U;
591
592 while ((delta != 0U) || (final_step_check == 1U))
593 {
594 /* Set candidate trimming */
595 MODIFY_REG(*tmp_opamp1_reg_trimming, OPAMP_OFFSET_TRIM_SET(hopamp1, trimming_diff_pair, OPAMP_TRIM_VALUE_MASK) ,
596 OPAMP_OFFSET_TRIM_SET(hopamp1, trimming_diff_pair, *opamp1_trimmingvalue) | tmp_opamp1_otr_otuser);
597
598 MODIFY_REG(*tmp_opamp2_reg_trimming, OPAMP_OFFSET_TRIM_SET(hopamp2, trimming_diff_pair, OPAMP_TRIM_VALUE_MASK) ,
599 OPAMP_OFFSET_TRIM_SET(hopamp2, trimming_diff_pair, *opamp2_trimmingvalue) | tmp_opamp2_otr_otuser);
600
601
602 /* Offset trimming time: during calibration, minimum time needed */
603 /* between two steps to have 1 mV accuracy. */
604 HAL_Delay(OPAMP_TRIMMING_DELAY);
605
606 /* Set flag for additional check of last trimming step equal to */
607 /* dichotomy step before its division by 2 (equivalent to previous */
608 /* value of dichotomy step). */
609 final_step_check = delta;
610
611 /* Divide range by 2 to continue dichotomy sweep */
612 delta >>= 1U;
613
614 /* Set trimming values for next iteration in function of trimming */
615 /* result toggle (versus initial state). */
616 /* Trimming values update with dichotomy delta of previous */
617 /* iteration. */
618 /* Note: on the last trimming loop, delta is equal to 0 and */
619 /* therefore has no effect. */
620 if (READ_BIT(OPAMP->CSR, OPAMP_CSR_OPAXCALOUT(hopamp1)) != tmp_Opa1calout_DefaultSate)
621 {
622 /* If calibration output is has toggled, try lower trimming */
623 *opamp1_trimmingvalue -= delta;
624 }
625 else
626 {
627 /* If calibration output is has not toggled, try higher trimming */
628 *opamp1_trimmingvalue += delta;
629 }
630
631 if (READ_BIT(OPAMP->CSR, OPAMP_CSR_OPAXCALOUT(hopamp2)) != tmp_Opa2calout_DefaultSate)
632 {
633 /* If calibration output is has toggled, try lower trimming */
634 *opamp2_trimmingvalue -= delta;
635 }
636 else
637 {
638 /* If calibration output is has not toggled, try higher trimming */
639 *opamp2_trimmingvalue += delta;
640 }
641 }
642
643 /* Check trimming result of the selected step and perform final fine */
644 /* trimming. */
645 /* - If calibration output is has toggled: the current step is */
646 /* already optimized. */
647 /* - If calibration output is has not toggled: the current step can */
648 /* be optimized by incrementing it of one step. */
649 if (READ_BIT(OPAMP->CSR, OPAMP_CSR_OPAXCALOUT(hopamp1)) == tmp_Opa1calout_DefaultSate)
650 {
651 *opamp1_trimmingvalue += 1U;
652
653 /* Set final fine trimming */
654 MODIFY_REG(*tmp_opamp1_reg_trimming, OPAMP_OFFSET_TRIM_SET(hopamp1, trimming_diff_pair, OPAMP_TRIM_VALUE_MASK) ,
655 OPAMP_OFFSET_TRIM_SET(hopamp1, trimming_diff_pair, *opamp1_trimmingvalue) | tmp_opamp1_otr_otuser);
656 }
657 if (READ_BIT(OPAMP->CSR, OPAMP_CSR_OPAXCALOUT(hopamp2)) == tmp_Opa2calout_DefaultSate)
658 {
659 *opamp2_trimmingvalue += 1U;
660
661 /* Set final fine trimming */
662 MODIFY_REG(*tmp_opamp2_reg_trimming, OPAMP_OFFSET_TRIM_SET(hopamp2, trimming_diff_pair, OPAMP_TRIM_VALUE_MASK) ,
663 OPAMP_OFFSET_TRIM_SET(hopamp2, trimming_diff_pair, *opamp2_trimmingvalue) | tmp_opamp2_otr_otuser);
664
665 }
666
667 }
668
669
670 /* Disable calibration for P and N differential pairs */
671 /* Disable the selected opamp */
672 CLEAR_BIT (OPAMP->CSR, (OPAMP_CSR_OPAXCAL_H_ALL |
673 OPAMP_CSR_OPAXCAL_L_ALL |
674 OPAMP_CSR_OPAXPD_ALL ));
675
676 /* Backup of switches configuration to restore it at the end of the */
677 /* calibration. */
678 SET_BIT(OPAMP->CSR, tmp_OpaxSwitchesContextBackup);
679
680 /* Self calibration is successful */
681 /* Store calibration (user trimming) results in init structure. */
682
683 /* Set user trimming mode */
684 hopamp1->Init.UserTrimming = OPAMP_TRIMMING_USER;
685 hopamp2->Init.UserTrimming = OPAMP_TRIMMING_USER;
686
687 /* Affect calibration parameters depending on mode normal/low power */
688 if (hopamp1->Init.PowerMode != OPAMP_POWERMODE_LOWPOWER)
689 {
690 /* Write calibration result N */
691 hopamp1->Init.TrimmingValueN = opamp1_trimmingvaluen;
692 /* Write calibration result P */
693 hopamp1->Init.TrimmingValueP = opamp1_trimmingvaluep;
694 }
695 else
696 {
697 /* Write calibration result N */
698 hopamp1->Init.TrimmingValueNLowPower = opamp1_trimmingvaluen;
699 /* Write calibration result P */
700 hopamp1->Init.TrimmingValuePLowPower = opamp1_trimmingvaluep;
701 }
702
703 if (hopamp2->Init.PowerMode != OPAMP_POWERMODE_LOWPOWER)
704 {
705 /* Write calibration result N */
706 hopamp2->Init.TrimmingValueN = opamp2_trimmingvaluen;
707 /* Write calibration result P */
708 hopamp2->Init.TrimmingValueP = opamp2_trimmingvaluep;
709 }
710 else
711 {
712 /* Write calibration result N */
713 hopamp2->Init.TrimmingValueNLowPower = opamp2_trimmingvaluen;
714 /* Write calibration result P */
715 hopamp2->Init.TrimmingValuePLowPower = opamp2_trimmingvaluep;
716 }
717
718 /* Update OPAMP state */
719 hopamp1->State = HAL_OPAMP_STATE_READY;
720 hopamp2->State = HAL_OPAMP_STATE_READY;
721 }
722 return status;
723 }
724
725 #endif /* STM32L151xD || STM32L152xD || STM32L162xD */
726
727 /**
728 * @}
729 */
730
731 /** @defgroup OPAMPEx_Exported_Functions_Group2 Extended Peripheral Control functions
732 * @brief Extended peripheral control functions
733 *
734 @verbatim
735 ===============================================================================
736 ##### Peripheral Control functions #####
737 ===============================================================================
738 [..]
739 (+) OPAMP unlock.
740
741 @endverbatim
742 * @{
743 */
744
745 /**
746 * @brief Unlock the selected OPAMP configuration.
747 * This function must be called only when OPAMP is in state "locked".
748 * @param hopamp OPAMP handle
749 * @retval HAL status
750 */
HAL_OPAMPEx_Unlock(OPAMP_HandleTypeDef * hopamp)751 HAL_StatusTypeDef HAL_OPAMPEx_Unlock(OPAMP_HandleTypeDef* hopamp)
752 {
753 HAL_StatusTypeDef status = HAL_OK;
754
755 /* Check the OPAMP handle allocation */
756 /* Check if OPAMP locked */
757 if(hopamp == NULL)
758 {
759 status = HAL_ERROR;
760 }
761 /* Check the OPAMP handle allocation */
762 /* Check if OPAMP locked */
763 else if(hopamp->State == HAL_OPAMP_STATE_BUSYLOCKED)
764 {
765 /* Check the parameter */
766 assert_param(IS_OPAMP_ALL_INSTANCE(hopamp->Instance));
767
768 /* OPAMP state changed to locked */
769 hopamp->State = HAL_OPAMP_STATE_BUSY;
770 }
771 else
772 {
773 status = HAL_ERROR;
774 }
775
776 return status;
777 }
778
779 /**
780 * @}
781 */
782
783 /**
784 * @}
785 */
786
787 #endif /* STM32L151xCA || STM32L151xD || STM32L152xCA || STM32L152xD || STM32L162xCA || STM32L162xD || STM32L151xE || STM32L151xDX || STM32L152xE || STM32L152xDX || STM32L162xE || STM32L162xDX || STM32L162xC || STM32L152xC || STM32L151xC */
788
789 #endif /* HAL_OPAMP_MODULE_ENABLED */
790 /**
791 * @}
792 */
793
794 /**
795 * @}
796 */
797
798