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