1 /**
2   ******************************************************************************
3   * @file    stm32u0xx_hal_dac_ex.c
4   * @author  MCD Application Team
5   * @brief   Extended DAC HAL module driver.
6   *          This file provides firmware functions to manage the extended
7   *          functionalities of the DAC peripheral.
8   *
9   *
10   ******************************************************************************
11   * @attention
12   *
13   * Copyright (c) 2023 STMicroelectronics.
14   * All rights reserved.
15   *
16   * This software is licensed under terms that can be found in the LICENSE file
17   * in the root directory of this software component.
18   * If no LICENSE file comes with this software, it is provided AS-IS.
19   *
20   ******************************************************************************
21   @verbatim
22   ==============================================================================
23                       ##### How to use this driver #####
24   ==============================================================================
25     [..]
26      *** Signal generation operation ***
27      ===================================
28      [..]
29       (+) Use HAL_DACEx_TriangleWaveGenerate() to generate Triangle signal.
30       (+) Use HAL_DACEx_NoiseWaveGenerate() to generate Noise signal.
31 
32       (+) HAL_DACEx_SelfCalibrate to calibrate one DAC channel.
33       (+) HAL_DACEx_SetUserTrimming to set user trimming value.
34       (+) HAL_DACEx_GetTrimOffset to retrieve trimming value (factory setting
35           after reset, user setting if HAL_DACEx_SetUserTrimming have been used
36           at least one time after reset).
37 
38  @endverbatim
39   ******************************************************************************
40   */
41 
42 
43 /* Includes ------------------------------------------------------------------*/
44 #include "stm32u0xx_hal.h"
45 
46 /** @addtogroup STM32U0xx_HAL_Driver
47   * @{
48   */
49 
50 #ifdef HAL_DAC_MODULE_ENABLED
51 
52 #if defined(DAC1)
53 
54 /** @defgroup DACEx DACEx
55   * @brief DAC Extended HAL module driver
56   * @{
57   */
58 
59 /* Private typedef -----------------------------------------------------------*/
60 /* Private define ------------------------------------------------------------*/
61 
62 /* Delay for DAC minimum trimming time.                                       */
63 /* Note: minimum time needed between two calibration steps                    */
64 /*       The delay below is specified under conditions:                       */
65 /*        - DAC channel output buffer enabled                                 */
66 /* Literal set to maximum value (refer to device datasheet,                   */
67 /* electrical characteristics, parameter "tTRIM").                            */
68 /* Unit: us                                                                   */
69 #define DAC_DELAY_TRIM_US          (50UL)     /*!< Delay for DAC minimum trimming time */
70 
71 /* Private macro -------------------------------------------------------------*/
72 /* Private variables ---------------------------------------------------------*/
73 /* Private function prototypes -----------------------------------------------*/
74 /* Exported functions --------------------------------------------------------*/
75 
76 /** @defgroup DACEx_Exported_Functions DACEx Exported Functions
77   * @{
78   */
79 
80 /** @defgroup DACEx_Exported_Functions_Group2 IO operation functions
81   *  @brief    Extended IO operation functions
82   *
83 @verbatim
84   ==============================================================================
85                  ##### Extended features functions #####
86   ==============================================================================
87     [..]  This section provides functions allowing to:
88       (+) Start conversion.
89       (+) Stop conversion.
90       (+) Start conversion and enable DMA transfer.
91       (+) Stop conversion and disable DMA transfer.
92       (+) Get result of conversion.
93       (+) Get result of dual mode conversion.
94 
95 @endverbatim
96   * @{
97   */
98 
99 /**
100   * @brief  Enable or disable the selected DAC channel wave generation.
101   * @param  hdac pointer to a DAC_HandleTypeDef structure that contains
102   *         the configuration information for the specified DAC.
103   * @param  Channel The selected DAC channel.
104   *          This parameter can be one of the following values:
105   *            @arg DAC_CHANNEL_1: DAC Channel1 selected
106   * @param  Amplitude Select max triangle amplitude.
107   *          This parameter can be one of the following values:
108   *            @arg DAC_TRIANGLEAMPLITUDE_1: Select max triangle amplitude of 1
109   *            @arg DAC_TRIANGLEAMPLITUDE_3: Select max triangle amplitude of 3
110   *            @arg DAC_TRIANGLEAMPLITUDE_7: Select max triangle amplitude of 7
111   *            @arg DAC_TRIANGLEAMPLITUDE_15: Select max triangle amplitude of 15
112   *            @arg DAC_TRIANGLEAMPLITUDE_31: Select max triangle amplitude of 31
113   *            @arg DAC_TRIANGLEAMPLITUDE_63: Select max triangle amplitude of 63
114   *            @arg DAC_TRIANGLEAMPLITUDE_127: Select max triangle amplitude of 127
115   *            @arg DAC_TRIANGLEAMPLITUDE_255: Select max triangle amplitude of 255
116   *            @arg DAC_TRIANGLEAMPLITUDE_511: Select max triangle amplitude of 511
117   *            @arg DAC_TRIANGLEAMPLITUDE_1023: Select max triangle amplitude of 1023
118   *            @arg DAC_TRIANGLEAMPLITUDE_2047: Select max triangle amplitude of 2047
119   *            @arg DAC_TRIANGLEAMPLITUDE_4095: Select max triangle amplitude of 4095
120   * @retval HAL status
121   */
HAL_DACEx_TriangleWaveGenerate(DAC_HandleTypeDef * hdac,uint32_t Channel,uint32_t Amplitude)122 HAL_StatusTypeDef HAL_DACEx_TriangleWaveGenerate(DAC_HandleTypeDef *hdac, uint32_t Channel, uint32_t Amplitude)
123 {
124   /* Check the DAC peripheral handle */
125   if (hdac == NULL)
126   {
127     return HAL_ERROR;
128   }
129 
130   /* Check the parameters */
131   assert_param(IS_DAC_CHANNEL(Channel));
132   assert_param(IS_DAC_LFSR_UNMASK_TRIANGLE_AMPLITUDE(Amplitude));
133 
134   /* Process locked */
135   __HAL_LOCK(hdac);
136 
137   /* Change DAC state */
138   hdac->State = HAL_DAC_STATE_BUSY;
139 
140   /* Enable the triangle wave generation for the selected DAC channel */
141   MODIFY_REG(hdac->Instance->CR, ((DAC_CR_WAVE1) | (DAC_CR_MAMP1)) << (Channel & 0x10UL),
142              (DAC_CR_WAVE1_1 | Amplitude) << (Channel & 0x10UL));
143 
144   /* Change DAC state */
145   hdac->State = HAL_DAC_STATE_READY;
146 
147   /* Process unlocked */
148   __HAL_UNLOCK(hdac);
149 
150   /* Return function status */
151   return HAL_OK;
152 }
153 
154 /**
155   * @brief  Enable or disable the selected DAC channel wave generation.
156   * @param  hdac pointer to a DAC_HandleTypeDef structure that contains
157   *         the configuration information for the specified DAC.
158   * @param  Channel The selected DAC channel.
159   *          This parameter can be one of the following values:
160   *            @arg DAC_CHANNEL_1: DAC Channel1 selected
161   * @param  Amplitude Unmask DAC channel LFSR for noise wave generation.
162   *          This parameter can be one of the following values:
163   *            @arg DAC_LFSRUNMASK_BIT0: Unmask DAC channel LFSR bit0 for noise wave generation
164   *            @arg DAC_LFSRUNMASK_BITS1_0: Unmask DAC channel LFSR bit[1:0] for noise wave generation
165   *            @arg DAC_LFSRUNMASK_BITS2_0: Unmask DAC channel LFSR bit[2:0] for noise wave generation
166   *            @arg DAC_LFSRUNMASK_BITS3_0: Unmask DAC channel LFSR bit[3:0] for noise wave generation
167   *            @arg DAC_LFSRUNMASK_BITS4_0: Unmask DAC channel LFSR bit[4:0] for noise wave generation
168   *            @arg DAC_LFSRUNMASK_BITS5_0: Unmask DAC channel LFSR bit[5:0] for noise wave generation
169   *            @arg DAC_LFSRUNMASK_BITS6_0: Unmask DAC channel LFSR bit[6:0] for noise wave generation
170   *            @arg DAC_LFSRUNMASK_BITS7_0: Unmask DAC channel LFSR bit[7:0] for noise wave generation
171   *            @arg DAC_LFSRUNMASK_BITS8_0: Unmask DAC channel LFSR bit[8:0] for noise wave generation
172   *            @arg DAC_LFSRUNMASK_BITS9_0: Unmask DAC channel LFSR bit[9:0] for noise wave generation
173   *            @arg DAC_LFSRUNMASK_BITS10_0: Unmask DAC channel LFSR bit[10:0] for noise wave generation
174   *            @arg DAC_LFSRUNMASK_BITS11_0: Unmask DAC channel LFSR bit[11:0] for noise wave generation
175   * @retval HAL status
176   */
HAL_DACEx_NoiseWaveGenerate(DAC_HandleTypeDef * hdac,uint32_t Channel,uint32_t Amplitude)177 HAL_StatusTypeDef HAL_DACEx_NoiseWaveGenerate(DAC_HandleTypeDef *hdac, uint32_t Channel, uint32_t Amplitude)
178 {
179   /* Check the DAC peripheral handle */
180   if (hdac == NULL)
181   {
182     return HAL_ERROR;
183   }
184 
185   /* Check the parameters */
186   assert_param(IS_DAC_CHANNEL(Channel));
187   assert_param(IS_DAC_LFSR_UNMASK_TRIANGLE_AMPLITUDE(Amplitude));
188 
189   /* Process locked */
190   __HAL_LOCK(hdac);
191 
192   /* Change DAC state */
193   hdac->State = HAL_DAC_STATE_BUSY;
194 
195   /* Enable the noise wave generation for the selected DAC channel */
196   MODIFY_REG(hdac->Instance->CR, ((DAC_CR_WAVE1) | (DAC_CR_MAMP1)) << (Channel & 0x10UL),
197              (DAC_CR_WAVE1_0 | Amplitude) << (Channel & 0x10UL));
198 
199   /* Change DAC state */
200   hdac->State = HAL_DAC_STATE_READY;
201 
202   /* Process unlocked */
203   __HAL_UNLOCK(hdac);
204 
205   /* Return function status */
206   return HAL_OK;
207 }
208 
209 
210 /**
211   * @brief  Run the self calibration of one DAC channel.
212   * @param  hdac pointer to a DAC_HandleTypeDef structure that contains
213   *         the configuration information for the specified DAC.
214   * @param  sConfig DAC channel configuration structure.
215   * @param  Channel The selected DAC channel.
216   *          This parameter can be one of the following values:
217   *            @arg DAC_CHANNEL_1: DAC Channel1 selected
218   * @retval Updates DAC_TrimmingValue. , DAC_UserTrimming set to DAC_UserTrimming
219   * @retval HAL status
220   * @note   Calibration runs about 7 ms.
221   */
HAL_DACEx_SelfCalibrate(DAC_HandleTypeDef * hdac,DAC_ChannelConfTypeDef * sConfig,uint32_t Channel)222 HAL_StatusTypeDef HAL_DACEx_SelfCalibrate(DAC_HandleTypeDef *hdac, DAC_ChannelConfTypeDef *sConfig, uint32_t Channel)
223 {
224   HAL_StatusTypeDef status = HAL_OK;
225 
226   __IO uint32_t tmp;
227   uint32_t trimmingvalue;
228   uint32_t delta;
229   __IO uint32_t wait_loop_index;
230 
231   /* store/restore channel configuration structure purpose */
232   uint32_t oldmodeconfiguration;
233 
234   /* Check the parameters */
235   assert_param(IS_DAC_CHANNEL(Channel));
236 
237   /* Check the DAC handle allocation */
238   /* Check if DAC running */
239   if ((hdac == NULL) || (sConfig == NULL))
240   {
241     status = HAL_ERROR;
242   }
243   else if (hdac->State == HAL_DAC_STATE_BUSY)
244   {
245     status = HAL_ERROR;
246   }
247   else
248   {
249     /* Process locked */
250     __HAL_LOCK(hdac);
251 
252     /* Store configuration */
253     oldmodeconfiguration = (hdac->Instance->MCR & (DAC_MCR_MODE1 << (Channel & 0x10UL)));
254 
255     /* Disable the selected DAC channel */
256     CLEAR_BIT((hdac->Instance->CR), (DAC_CR_EN1 << (Channel & 0x10UL)));
257 
258     /* Set mode in MCR  for calibration */
259     MODIFY_REG(hdac->Instance->MCR, (DAC_MCR_MODE1 << (Channel & 0x10UL)), 0U);
260 
261     /* Set DAC Channel1 DHR register to the middle value */
262     tmp = (uint32_t)hdac->Instance;
263 
264     if (Channel == DAC_CHANNEL_1)
265     {
266       tmp += DAC_DHR12R1_ALIGNMENT(DAC_ALIGN_12B_R);
267     }
268 
269     *(__IO uint32_t *) tmp = 0x0800UL;
270 
271     /* Enable the selected DAC channel calibration */
272     /* i.e. set DAC_CR_CENx bit */
273     SET_BIT((hdac->Instance->CR), (DAC_CR_CEN1 << (Channel & 0x10UL)));
274 
275     /* Init trimming counter */
276     /* Medium value */
277     trimmingvalue = 16UL;
278     delta = 8UL;
279     while (delta != 0UL)
280     {
281       /* Set candidate trimming */
282       MODIFY_REG(hdac->Instance->CCR, (DAC_CCR_OTRIM1 << (Channel & 0x10UL)), (trimmingvalue << (Channel & 0x10UL)));
283 
284       /* Wait minimum time needed between two calibration steps (OTRIM) */
285       /* Wait loop initialization and execution */
286       /* Note: Variable divided by 2 to compensate partially CPU processing cycles, scaling in us split to not exceed */
287       /*       32 bits register capacity and handle low frequency. */
288       wait_loop_index = ((DAC_DELAY_TRIM_US / 10UL) * ((SystemCoreClock / (100000UL * 2UL)) + 1UL));
289       while (wait_loop_index != 0UL)
290       {
291         wait_loop_index--;
292       }
293 
294       if ((hdac->Instance->SR & (DAC_SR_CAL_FLAG1 << (Channel & 0x10UL))) == (DAC_SR_CAL_FLAG1 << (Channel & 0x10UL)))
295       {
296         /* DAC_SR_CAL_FLAGx is HIGH try higher trimming */
297         trimmingvalue -= delta;
298       }
299       else
300       {
301         /* DAC_SR_CAL_FLAGx is LOW try lower trimming */
302         trimmingvalue += delta;
303       }
304       delta >>= 1UL;
305     }
306 
307     /* Still need to check if right calibration is current value or one step below */
308     /* Indeed the first value that causes the DAC_SR_CAL_FLAGx bit to change from 0 to 1  */
309     /* Set candidate trimming */
310     MODIFY_REG(hdac->Instance->CCR, (DAC_CCR_OTRIM1 << (Channel & 0x10UL)), (trimmingvalue << (Channel & 0x10UL)));
311 
312     /* Wait minimum time needed between two calibration steps (OTRIM) */
313     /* Wait loop initialization and execution */
314     /* Note: Variable divided by 2 to compensate partially CPU processing cycles, scaling in us split to not exceed */
315     /*       32 bits register capacity and handle low frequency. */
316     wait_loop_index = ((DAC_DELAY_TRIM_US / 10UL) * ((SystemCoreClock / (100000UL * 2UL)) + 1UL));
317     while (wait_loop_index != 0UL)
318     {
319       wait_loop_index--;
320     }
321 
322     if ((hdac->Instance->SR & (DAC_SR_CAL_FLAG1 << (Channel & 0x10UL))) == 0UL)
323     {
324       /* Trimming is actually one value more */
325       trimmingvalue++;
326       /* Set right trimming */
327       MODIFY_REG(hdac->Instance->CCR, (DAC_CCR_OTRIM1 << (Channel & 0x10UL)), (trimmingvalue << (Channel & 0x10UL)));
328     }
329 
330     /* Disable the selected DAC channel calibration */
331     /* i.e. clear DAC_CR_CENx bit */
332     CLEAR_BIT((hdac->Instance->CR), (DAC_CR_CEN1 << (Channel & 0x10UL)));
333 
334     sConfig->DAC_TrimmingValue = trimmingvalue;
335     sConfig->DAC_UserTrimming = DAC_TRIMMING_USER;
336 
337     /* Restore configuration */
338     MODIFY_REG(hdac->Instance->MCR, (DAC_MCR_MODE1 << (Channel & 0x10UL)), oldmodeconfiguration);
339 
340     /* Process unlocked */
341     __HAL_UNLOCK(hdac);
342   }
343 
344   return status;
345 }
346 
347 /**
348   * @brief  Set the trimming mode and trimming value (user trimming mode applied).
349   * @param  hdac pointer to a DAC_HandleTypeDef structure that contains
350   *         the configuration information for the specified DAC.
351   * @param  sConfig DAC configuration structure updated with new DAC trimming value.
352   * @param  Channel The selected DAC channel.
353   *          This parameter can be one of the following values:
354   *            @arg DAC_CHANNEL_1: DAC Channel1 selected
355   * @param  NewTrimmingValue DAC new trimming value
356   * @retval HAL status
357   */
HAL_DACEx_SetUserTrimming(DAC_HandleTypeDef * hdac,DAC_ChannelConfTypeDef * sConfig,uint32_t Channel,uint32_t NewTrimmingValue)358 HAL_StatusTypeDef HAL_DACEx_SetUserTrimming(DAC_HandleTypeDef *hdac, DAC_ChannelConfTypeDef *sConfig, uint32_t Channel,
359                                             uint32_t NewTrimmingValue)
360 {
361   HAL_StatusTypeDef status = HAL_OK;
362 
363   /* Check the parameters */
364   assert_param(IS_DAC_CHANNEL(Channel));
365   assert_param(IS_DAC_NEWTRIMMINGVALUE(NewTrimmingValue));
366 
367   /* Check the DAC handle and channel configuration struct allocation */
368   if ((hdac == NULL) || (sConfig == NULL))
369   {
370     status = HAL_ERROR;
371   }
372   else
373   {
374     /* Process locked */
375     __HAL_LOCK(hdac);
376 
377     /* Set new trimming */
378     MODIFY_REG(hdac->Instance->CCR, (DAC_CCR_OTRIM1 << (Channel & 0x10UL)), (NewTrimmingValue << (Channel & 0x10UL)));
379 
380     /* Update trimming mode */
381     sConfig->DAC_UserTrimming = DAC_TRIMMING_USER;
382     sConfig->DAC_TrimmingValue = NewTrimmingValue;
383 
384     /* Process unlocked */
385     __HAL_UNLOCK(hdac);
386   }
387   return status;
388 }
389 
390 /**
391   * @brief  Return the DAC trimming value.
392   * @param  hdac DAC handle
393   * @param  Channel The selected DAC channel.
394   *          This parameter can be one of the following values:
395   *            @arg DAC_CHANNEL_1: DAC Channel1 selected
396   * @retval Trimming value : range: 0->31
397   *
398  */
HAL_DACEx_GetTrimOffset(const DAC_HandleTypeDef * hdac,uint32_t Channel)399 uint32_t HAL_DACEx_GetTrimOffset(const DAC_HandleTypeDef *hdac, uint32_t Channel)
400 {
401   /* Check the parameter */
402   assert_param(IS_DAC_CHANNEL(Channel));
403 
404   /* Retrieve trimming */
405   return ((hdac->Instance->CCR & (DAC_CCR_OTRIM1 << (Channel & 0x10UL))) >> (Channel & 0x10UL));
406 }
407 
408 /**
409   * @}
410   */
411 
412 /**
413   * @}
414   */
415 
416 /**
417   * @}
418   */
419 
420 #endif /* DAC1 */
421 
422 #endif /* HAL_DAC_MODULE_ENABLED */
423 
424 /**
425   * @}
426   */
427