STM32L4xx_HAL_Driver  1.14.0
stm32l4xx_hal_opamp_ex.c
Go to the documentation of this file.
1 
27 /* Includes ------------------------------------------------------------------*/
28 #include "stm32l4xx_hal.h"
29 
39 #ifdef HAL_OPAMP_MODULE_ENABLED
40 
41 /* Private typedef -----------------------------------------------------------*/
42 /* Private define ------------------------------------------------------------*/
43 /* Private macro -------------------------------------------------------------*/
44 /* Private variables ---------------------------------------------------------*/
45 /* Private function prototypes -----------------------------------------------*/
46 /* Exported functions --------------------------------------------------------*/
47 
52 #if defined (STM32L471xx) || defined (STM32L475xx) || defined (STM32L476xx) || defined (STM32L485xx) || defined (STM32L486xx) || \
53  defined (STM32L496xx) || defined (STM32L4A6xx) || \
54  defined (STM32L4R5xx) || defined (STM32L4R7xx) || defined (STM32L4R9xx) || defined (STM32L4S5xx) || defined (STM32L4S7xx) || defined (STM32L4S9xx)
55 
70 /* 2 OPAMPS available */
71 /* 2 OPAMPS can be calibrated in parallel */
72 /* Not available on STM32L41x/STM32L42x/STM32L43x/STM32L44x where only one OPAMP available */
73 
90 {
91  HAL_StatusTypeDef status = HAL_OK;
92 
93  uint32_t trimmingvaluen1;
94  uint32_t trimmingvaluep1;
95  uint32_t trimmingvaluen2;
96  uint32_t trimmingvaluep2;
97 
98 /* Selection of register of trimming depending on power mode: OTR or LPOTR */
99  __IO uint32_t* tmp_opamp1_reg_trimming;
100  __IO uint32_t* tmp_opamp2_reg_trimming;
101 
102  uint32_t delta;
103  uint32_t opampmode1;
104  uint32_t opampmode2;
105 
106  if((hopamp1 == NULL) || (hopamp2 == NULL))
107  {
108  status = HAL_ERROR;
109  }
110  /* Check if OPAMP in calibration mode and calibration not yet enable */
111  else if(hopamp1->State != HAL_OPAMP_STATE_READY)
112  {
113  status = HAL_ERROR;
114  }
115  else if(hopamp2->State != HAL_OPAMP_STATE_READY)
116  {
117  status = HAL_ERROR;
118  }
119  else
120  {
121  /* Check the parameter */
122  assert_param(IS_OPAMP_ALL_INSTANCE(hopamp1->Instance));
123  assert_param(IS_OPAMP_ALL_INSTANCE(hopamp2->Instance));
124 
125  assert_param(IS_OPAMP_POWERMODE(hopamp1->Init.PowerMode));
126  assert_param(IS_OPAMP_POWERMODE(hopamp2->Init.PowerMode));
127 
128  /* Save OPAMP mode as in */
129  /* STM32L471xx STM32L475xx STM32L476xx STM32L485xx STM32L486xx */
130  /* the calibration is not working in PGA mode */
131  opampmode1 = READ_BIT(hopamp1->Instance->CSR,OPAMP_CSR_OPAMODE);
132  opampmode2 = READ_BIT(hopamp2->Instance->CSR,OPAMP_CSR_OPAMODE);
133 
134  /* Use of standalone mode */
135  MODIFY_REG(hopamp1->Instance->CSR, OPAMP_CSR_OPAMODE, OPAMP_STANDALONE_MODE);
136  MODIFY_REG(hopamp2->Instance->CSR, OPAMP_CSR_OPAMODE, OPAMP_STANDALONE_MODE);
137 
138  /* user trimming values are used for offset calibration */
139  SET_BIT(hopamp1->Instance->CSR, OPAMP_CSR_USERTRIM);
140  SET_BIT(hopamp2->Instance->CSR, OPAMP_CSR_USERTRIM);
141 
142  /* Select trimming settings depending on power mode */
143  if (hopamp1->Init.PowerMode == OPAMP_POWERMODE_NORMAL)
144  {
145  tmp_opamp1_reg_trimming = &OPAMP1->OTR;
146  }
147  else
148  {
149  tmp_opamp1_reg_trimming = &OPAMP1->LPOTR;
150  }
151 
152  if (hopamp2->Init.PowerMode == OPAMP_POWERMODE_NORMAL)
153  {
154  tmp_opamp2_reg_trimming = &OPAMP2->OTR;
155  }
156  else
157  {
158  tmp_opamp2_reg_trimming = &OPAMP2->LPOTR;
159  }
160 
161  /* Enable calibration */
162  SET_BIT (hopamp1->Instance->CSR, OPAMP_CSR_CALON);
163  SET_BIT (hopamp2->Instance->CSR, OPAMP_CSR_CALON);
164 
165  /* 1st calibration - N */
166  CLEAR_BIT (hopamp1->Instance->CSR, OPAMP_CSR_CALSEL);
167  CLEAR_BIT (hopamp2->Instance->CSR, OPAMP_CSR_CALSEL);
168 
169  /* Enable the selected opamp */
170  SET_BIT (hopamp1->Instance->CSR, OPAMP_CSR_OPAMPxEN);
171  SET_BIT (hopamp2->Instance->CSR, OPAMP_CSR_OPAMPxEN);
172 
173  /* Init trimming counter */
174  /* Medium value */
175  trimmingvaluen1 = 16U;
176  trimmingvaluen2 = 16U;
177  delta = 8U;
178 
179  while (delta != 0U)
180  {
181  /* Set candidate trimming */
182  /* OPAMP_POWERMODE_NORMAL */
183  MODIFY_REG(*tmp_opamp1_reg_trimming, OPAMP_OTR_TRIMOFFSETN, trimmingvaluen1);
184  MODIFY_REG(*tmp_opamp2_reg_trimming, OPAMP_OTR_TRIMOFFSETN, trimmingvaluen2);
185 
186  /* OFFTRIMmax delay 1 ms as per datasheet (electrical characteristics */
187  /* Offset trim time: during calibration, minimum time needed between */
188  /* two steps to have 1 mV accuracy */
189  HAL_Delay(OPAMP_TRIMMING_DELAY);
190 
191  if (READ_BIT(hopamp1->Instance->CSR, OPAMP_CSR_CALOUT) != 0U)
192  {
193  /* OPAMP_CSR_CALOUT is HIGH try lower trimming */
194  trimmingvaluen1 -= delta;
195  }
196  else
197  {
198  /* OPAMP_CSR_CALOUT is LOW try higher trimming */
199  trimmingvaluen1 += delta;
200  }
201 
202  if (READ_BIT(hopamp2->Instance->CSR, OPAMP_CSR_CALOUT) != 0U)
203  {
204  /* OPAMP_CSR_CALOUT is HIGH try lower trimming */
205  trimmingvaluen2 -= delta;
206  }
207  else
208  {
209  /* OPAMP_CSR_CALOUT is LOW try higher trimming */
210  trimmingvaluen2 += delta;
211  }
212  /* Divide range by 2 to continue dichotomy sweep */
213  delta >>= 1U;
214  }
215 
216  /* Still need to check if right calibration is current value or one step below */
217  /* Indeed the first value that causes the OUTCAL bit to change from 0 to 1 */
218  /* Set candidate trimming */
219  MODIFY_REG(*tmp_opamp1_reg_trimming, OPAMP_OTR_TRIMOFFSETN, trimmingvaluen1);
220  MODIFY_REG(*tmp_opamp2_reg_trimming, OPAMP_OTR_TRIMOFFSETN, trimmingvaluen2);
221 
222  /* OFFTRIMmax delay 1 ms as per datasheet (electrical characteristics */
223  /* Offset trim time: during calibration, minimum time needed between */
224  /* two steps to have 1 mV accuracy */
225  HAL_Delay(OPAMP_TRIMMING_DELAY);
226 
227  if ((READ_BIT(hopamp1->Instance->CSR, OPAMP_CSR_CALOUT)) == 0U)
228  {
229  /* Trimming value is actually one value more */
230  trimmingvaluen1++;
231  MODIFY_REG(*tmp_opamp1_reg_trimming, OPAMP_OTR_TRIMOFFSETN, trimmingvaluen1);
232  }
233 
234  if ((READ_BIT(hopamp2->Instance->CSR, OPAMP_CSR_CALOUT)) == 0U)
235  {
236  /* Trimming value is actually one value more */
237  trimmingvaluen2++;
238  MODIFY_REG(*tmp_opamp2_reg_trimming, OPAMP_OTR_TRIMOFFSETN, trimmingvaluen2);
239  }
240 
241  /* 2nd calibration - P */
242  SET_BIT (hopamp1->Instance->CSR, OPAMP_CSR_CALSEL);
243  SET_BIT (hopamp2->Instance->CSR, OPAMP_CSR_CALSEL);
244 
245  /* Init trimming counter */
246  /* Medium value */
247  trimmingvaluep1 = 16U;
248  trimmingvaluep2 = 16U;
249  delta = 8U;
250 
251  while (delta != 0U)
252  {
253  /* Set candidate trimming */
254  /* OPAMP_POWERMODE_NORMAL */
255  MODIFY_REG(*tmp_opamp1_reg_trimming, OPAMP_OTR_TRIMOFFSETP, (trimmingvaluep1<<OPAMP_INPUT_NONINVERTING));
256  MODIFY_REG(*tmp_opamp2_reg_trimming, OPAMP_OTR_TRIMOFFSETP, (trimmingvaluep2<<OPAMP_INPUT_NONINVERTING));
257 
258  /* OFFTRIMmax delay 1 ms as per datasheet (electrical characteristics */
259  /* Offset trim time: during calibration, minimum time needed between */
260  /* two steps to have 1 mV accuracy */
261  HAL_Delay(OPAMP_TRIMMING_DELAY);
262 
263  if (READ_BIT(hopamp1->Instance->CSR, OPAMP_CSR_CALOUT) != 0U)
264  {
265  /* OPAMP_CSR_CALOUT is HIGH try higher trimming */
266  trimmingvaluep1 += delta;
267  }
268  else
269  {
270  /* OPAMP_CSR_CALOUT is HIGH try lower trimming */
271  trimmingvaluep1 -= delta;
272  }
273 
274  if (READ_BIT(hopamp2->Instance->CSR, OPAMP_CSR_CALOUT) != 0U)
275  {
276  /* OPAMP_CSR_CALOUT is HIGH try higher trimming */
277  trimmingvaluep2 += delta;
278  }
279  else
280  {
281  /* OPAMP_CSR_CALOUT is LOW try lower trimming */
282  trimmingvaluep2 -= delta;
283  }
284  /* Divide range by 2 to continue dichotomy sweep */
285  delta >>= 1U;
286  }
287 
288  /* Still need to check if right calibration is current value or one step below */
289  /* Indeed the first value that causes the OUTCAL bit to change from 1 to 0 */
290  /* Set candidate trimming */
291  MODIFY_REG(*tmp_opamp1_reg_trimming, OPAMP_OTR_TRIMOFFSETP, (trimmingvaluep1<<OPAMP_INPUT_NONINVERTING));
292  MODIFY_REG(*tmp_opamp2_reg_trimming, OPAMP_OTR_TRIMOFFSETP, (trimmingvaluep2<<OPAMP_INPUT_NONINVERTING));
293 
294  /* OFFTRIMmax delay 1 ms as per datasheet (electrical characteristics */
295  /* Offset trim time: during calibration, minimum time needed between */
296  /* two steps to have 1 mV accuracy */
297  HAL_Delay(OPAMP_TRIMMING_DELAY);
298 
299  if (READ_BIT(hopamp1->Instance->CSR, OPAMP_CSR_CALOUT) != 0U)
300  {
301  /* Trimming value is actually one value more */
302  trimmingvaluep1++;
303  MODIFY_REG(*tmp_opamp1_reg_trimming, OPAMP_OTR_TRIMOFFSETP, (trimmingvaluep1<<OPAMP_INPUT_NONINVERTING));
304  }
305 
306  if (READ_BIT(hopamp2->Instance->CSR, OPAMP_CSR_CALOUT) != 0U)
307  {
308  /* Trimming value is actually one value more */
309  trimmingvaluep2++;
310  MODIFY_REG(*tmp_opamp2_reg_trimming, OPAMP_OTR_TRIMOFFSETP, (trimmingvaluep2<<OPAMP_INPUT_NONINVERTING));
311  }
312 
313  /* Disable the OPAMPs */
314  CLEAR_BIT (hopamp1->Instance->CSR, OPAMP_CSR_OPAMPxEN);
315  CLEAR_BIT (hopamp2->Instance->CSR, OPAMP_CSR_OPAMPxEN);
316 
317  /* Disable calibration & set normal mode (operating mode) */
318  CLEAR_BIT (hopamp1->Instance->CSR, OPAMP_CSR_CALON);
319  CLEAR_BIT (hopamp2->Instance->CSR, OPAMP_CSR_CALON);
320 
321  /* Self calibration is successful */
322  /* Store calibration (user trimming) results in init structure. */
323 
324  /* Set user trimming mode */
325  hopamp1->Init.UserTrimming = OPAMP_TRIMMING_USER;
326  hopamp2->Init.UserTrimming = OPAMP_TRIMMING_USER;
327 
328  /* Affect calibration parameters depending on mode normal/low power */
329  if (hopamp1->Init.PowerMode != OPAMP_POWERMODE_LOWPOWER)
330  {
331  /* Write calibration result N */
332  hopamp1->Init.TrimmingValueN = trimmingvaluen1;
333  /* Write calibration result P */
334  hopamp1->Init.TrimmingValueP = trimmingvaluep1;
335  }
336  else
337  {
338  /* Write calibration result N */
339  hopamp1->Init.TrimmingValueNLowPower = trimmingvaluen1;
340  /* Write calibration result P */
341  hopamp1->Init.TrimmingValuePLowPower = trimmingvaluep1;
342  }
343 
344  if (hopamp2->Init.PowerMode != OPAMP_POWERMODE_LOWPOWER)
345  {
346  /* Write calibration result N */
347  hopamp2->Init.TrimmingValueN = trimmingvaluen2;
348  /* Write calibration result P */
349  hopamp2->Init.TrimmingValueP = trimmingvaluep2;
350  }
351  else
352  {
353  /* Write calibration result N */
354  hopamp2->Init.TrimmingValueNLowPower = trimmingvaluen2;
355  /* Write calibration result P */
356  hopamp2->Init.TrimmingValuePLowPower = trimmingvaluep2;
357  }
358 
359  /* Update OPAMP state */
360  hopamp1->State = HAL_OPAMP_STATE_READY;
361  hopamp2->State = HAL_OPAMP_STATE_READY;
362 
363  /* Restore OPAMP mode after calibration */
364  MODIFY_REG(hopamp1->Instance->CSR, OPAMP_CSR_OPAMODE, opampmode1);
365  MODIFY_REG(hopamp2->Instance->CSR, OPAMP_CSR_OPAMODE, opampmode2);
366  }
367  return status;
368 }
369 
374 #endif
375 
396 HAL_StatusTypeDef HAL_OPAMPEx_Unlock(OPAMP_HandleTypeDef* hopamp)
397 {
398  HAL_StatusTypeDef status = HAL_OK;
399 
400  /* Check the OPAMP handle allocation */
401  /* Check if OPAMP locked */
402  if(hopamp == NULL)
403  {
404  status = HAL_ERROR;
405  }
406  /* Check the OPAMP handle allocation */
407  /* Check if OPAMP locked */
408  else if(hopamp->State == HAL_OPAMP_STATE_BUSYLOCKED)
409  {
410  /* Check the parameter */
411  assert_param(IS_OPAMP_ALL_INSTANCE(hopamp->Instance));
412 
413  /* OPAMP state changed to locked */
414  hopamp->State = HAL_OPAMP_STATE_BUSY;
415  }
416  else
417  {
418  status = HAL_ERROR;
419  }
420 
421  return status;
422 }
423 
432 #endif /* HAL_OPAMP_MODULE_ENABLED */
433 
441 /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
This file contains all the functions prototypes for the HAL module driver.
void HAL_Delay(uint32_t Delay)
This function provides minimum delay (in milliseconds) based on variable incremented.
HAL_StatusTypeDef HAL_OPAMPEx_Unlock(OPAMP_HandleTypeDef *hopamp)
Unlock the selected OPAMP configuration.
CLEAR_BIT(hrtc->Instance->CR, RTC_CR_WUTE)
struct __OPAMP_HandleTypeDef else typedef struct endif OPAMP_HandleTypeDef
OPAMP Handle Structure definition.
return HAL_OK
HAL_StatusTypeDef HAL_OPAMPEx_SelfCalibrateAll(OPAMP_HandleTypeDef *hopamp1, OPAMP_HandleTypeDef *hopamp2)
Run the self calibration of the 2 OPAMPs in parallel.
MODIFY_REG(hrtc->Instance->CR, RTC_CR_WUCKSEL,(uint32_t) WakeUpClock)
assert_param(IS_RTC_WAKEUP_CLOCK(WakeUpClock))