1 /**
2   ******************************************************************************
3   * @file    stm32wlxx_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) 2020 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 "stm32wlxx_hal.h"
45 
46 /** @addtogroup STM32WLxx_HAL_Driver
47   * @{
48   */
49 
50 #ifdef HAL_DAC_MODULE_ENABLED
51 
52 #if defined(DAC)
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 parameters */
125   assert_param(IS_DAC_CHANNEL(Channel));
126   assert_param(IS_DAC_LFSR_UNMASK_TRIANGLE_AMPLITUDE(Amplitude));
127 
128   /* Process locked */
129   __HAL_LOCK(hdac);
130 
131   /* Change DAC state */
132   hdac->State = HAL_DAC_STATE_BUSY;
133 
134   /* Enable the triangle wave generation for the selected DAC channel */
135   MODIFY_REG(hdac->Instance->CR, ((DAC_CR_WAVE1) | (DAC_CR_MAMP1)) << (Channel & 0x10UL),
136              (DAC_CR_WAVE1_1 | Amplitude) << (Channel & 0x10UL));
137 
138   /* Change DAC state */
139   hdac->State = HAL_DAC_STATE_READY;
140 
141   /* Process unlocked */
142   __HAL_UNLOCK(hdac);
143 
144   /* Return function status */
145   return HAL_OK;
146 }
147 
148 /**
149   * @brief  Enable or disable the selected DAC channel wave generation.
150   * @param  hdac pointer to a DAC_HandleTypeDef structure that contains
151   *         the configuration information for the specified DAC.
152   * @param  Channel The selected DAC channel.
153   *          This parameter can be one of the following values:
154   *            @arg DAC_CHANNEL_1: DAC Channel1 selected
155   * @param  Amplitude Unmask DAC channel LFSR for noise wave generation.
156   *          This parameter can be one of the following values:
157   *            @arg DAC_LFSRUNMASK_BIT0: Unmask DAC channel LFSR bit0 for noise wave generation
158   *            @arg DAC_LFSRUNMASK_BITS1_0: Unmask DAC channel LFSR bit[1:0] for noise wave generation
159   *            @arg DAC_LFSRUNMASK_BITS2_0: Unmask DAC channel LFSR bit[2:0] for noise wave generation
160   *            @arg DAC_LFSRUNMASK_BITS3_0: Unmask DAC channel LFSR bit[3:0] for noise wave generation
161   *            @arg DAC_LFSRUNMASK_BITS4_0: Unmask DAC channel LFSR bit[4:0] for noise wave generation
162   *            @arg DAC_LFSRUNMASK_BITS5_0: Unmask DAC channel LFSR bit[5:0] for noise wave generation
163   *            @arg DAC_LFSRUNMASK_BITS6_0: Unmask DAC channel LFSR bit[6:0] for noise wave generation
164   *            @arg DAC_LFSRUNMASK_BITS7_0: Unmask DAC channel LFSR bit[7:0] for noise wave generation
165   *            @arg DAC_LFSRUNMASK_BITS8_0: Unmask DAC channel LFSR bit[8:0] for noise wave generation
166   *            @arg DAC_LFSRUNMASK_BITS9_0: Unmask DAC channel LFSR bit[9:0] for noise wave generation
167   *            @arg DAC_LFSRUNMASK_BITS10_0: Unmask DAC channel LFSR bit[10:0] for noise wave generation
168   *            @arg DAC_LFSRUNMASK_BITS11_0: Unmask DAC channel LFSR bit[11:0] for noise wave generation
169   * @retval HAL status
170   */
HAL_DACEx_NoiseWaveGenerate(DAC_HandleTypeDef * hdac,uint32_t Channel,uint32_t Amplitude)171 HAL_StatusTypeDef HAL_DACEx_NoiseWaveGenerate(DAC_HandleTypeDef *hdac, uint32_t Channel, uint32_t Amplitude)
172 {
173   /* Check the parameters */
174   assert_param(IS_DAC_CHANNEL(Channel));
175   assert_param(IS_DAC_LFSR_UNMASK_TRIANGLE_AMPLITUDE(Amplitude));
176 
177   /* Process locked */
178   __HAL_LOCK(hdac);
179 
180   /* Change DAC state */
181   hdac->State = HAL_DAC_STATE_BUSY;
182 
183   /* Enable the noise wave generation for the selected DAC channel */
184   MODIFY_REG(hdac->Instance->CR, ((DAC_CR_WAVE1) | (DAC_CR_MAMP1)) << (Channel & 0x10UL),
185              (DAC_CR_WAVE1_0 | Amplitude) << (Channel & 0x10UL));
186 
187   /* Change DAC state */
188   hdac->State = HAL_DAC_STATE_READY;
189 
190   /* Process unlocked */
191   __HAL_UNLOCK(hdac);
192 
193   /* Return function status */
194   return HAL_OK;
195 }
196 
197 
198 /**
199   * @brief  Run the self calibration of one DAC channel.
200   * @param  hdac pointer to a DAC_HandleTypeDef structure that contains
201   *         the configuration information for the specified DAC.
202   * @param  sConfig DAC channel configuration structure.
203   * @param  Channel The selected DAC channel.
204   *          This parameter can be one of the following values:
205   *            @arg DAC_CHANNEL_1: DAC Channel1 selected
206   * @retval Updates DAC_TrimmingValue. , DAC_UserTrimming set to DAC_UserTrimming
207   * @retval HAL status
208   * @note   Calibration runs about 7 ms.
209   */
HAL_DACEx_SelfCalibrate(DAC_HandleTypeDef * hdac,DAC_ChannelConfTypeDef * sConfig,uint32_t Channel)210 HAL_StatusTypeDef HAL_DACEx_SelfCalibrate(DAC_HandleTypeDef *hdac, DAC_ChannelConfTypeDef *sConfig, uint32_t Channel)
211 {
212   HAL_StatusTypeDef status = HAL_OK;
213 
214   __IO uint32_t tmp;
215   uint32_t trimmingvalue;
216   uint32_t delta;
217   __IO uint32_t wait_loop_index;
218 
219   /* store/restore channel configuration structure purpose */
220   uint32_t oldmodeconfiguration;
221 
222   /* Check the parameters */
223   assert_param(IS_DAC_CHANNEL(Channel));
224 
225   /* Check the DAC handle allocation */
226   /* Check if DAC running */
227   if (hdac == NULL)
228   {
229     status = HAL_ERROR;
230   }
231   else if (hdac->State == HAL_DAC_STATE_BUSY)
232   {
233     status = HAL_ERROR;
234   }
235   else
236   {
237     /* Process locked */
238     __HAL_LOCK(hdac);
239 
240     /* Store configuration */
241     oldmodeconfiguration = (hdac->Instance->MCR & (DAC_MCR_MODE1 << (Channel & 0x10UL)));
242 
243     /* Disable the selected DAC channel */
244     CLEAR_BIT((hdac->Instance->CR), (DAC_CR_EN1 << (Channel & 0x10UL)));
245 
246     /* Set mode in MCR  for calibration */
247     MODIFY_REG(hdac->Instance->MCR, (DAC_MCR_MODE1 << (Channel & 0x10UL)), 0U);
248 
249     /* Set DAC Channel1 DHR register to the middle value */
250     tmp = (uint32_t)hdac->Instance;
251 
252     if (Channel == DAC_CHANNEL_1)
253     {
254       tmp += DAC_DHR12R1_ALIGNMENT(DAC_ALIGN_12B_R);
255     }
256 
257     *(__IO uint32_t *) tmp = 0x0800UL;
258 
259     /* Enable the selected DAC channel calibration */
260     /* i.e. set DAC_CR_CENx bit */
261     SET_BIT((hdac->Instance->CR), (DAC_CR_CEN1 << (Channel & 0x10UL)));
262 
263     /* Init trimming counter */
264     /* Medium value */
265     trimmingvalue = 16UL;
266     delta = 8UL;
267     while (delta != 0UL)
268     {
269       /* Set candidate trimming */
270       MODIFY_REG(hdac->Instance->CCR, (DAC_CCR_OTRIM1 << (Channel & 0x10UL)), (trimmingvalue << (Channel & 0x10UL)));
271 
272       /* Wait minimum time needed between two calibration steps (OTRIM) */
273       /* Wait loop initialization and execution */
274       /* Note: Variable divided by 2 to compensate partially CPU processing cycles, scaling in us split to not exceed */
275       /*       32 bits register capacity and handle low frequency. */
276       wait_loop_index = ((DAC_DELAY_TRIM_US / 10UL) * ((SystemCoreClock / (100000UL * 2UL)) + 1UL));
277       while(wait_loop_index != 0UL)
278       {
279         wait_loop_index--;
280       }
281 
282       if ((hdac->Instance->SR & (DAC_SR_CAL_FLAG1 << (Channel & 0x10UL))) == (DAC_SR_CAL_FLAG1 << (Channel & 0x10UL)))
283       {
284         /* DAC_SR_CAL_FLAGx is HIGH try higher trimming */
285         trimmingvalue -= delta;
286       }
287       else
288       {
289         /* DAC_SR_CAL_FLAGx is LOW try lower trimming */
290         trimmingvalue += delta;
291       }
292       delta >>= 1UL;
293     }
294 
295     /* Still need to check if right calibration is current value or one step below */
296     /* Indeed the first value that causes the DAC_SR_CAL_FLAGx bit to change from 0 to 1  */
297     /* Set candidate trimming */
298     MODIFY_REG(hdac->Instance->CCR, (DAC_CCR_OTRIM1 << (Channel & 0x10UL)), (trimmingvalue << (Channel & 0x10UL)));
299 
300     /* Wait minimum time needed between two calibration steps (OTRIM) */
301     /* Wait loop initialization and execution */
302     /* Note: Variable divided by 2 to compensate partially CPU processing cycles, scaling in us split to not exceed */
303     /*       32 bits register capacity and handle low frequency. */
304     wait_loop_index = ((DAC_DELAY_TRIM_US / 10UL) * ((SystemCoreClock / (100000UL * 2UL)) + 1UL));
305     while(wait_loop_index != 0UL)
306     {
307       wait_loop_index--;
308     }
309 
310     if ((hdac->Instance->SR & (DAC_SR_CAL_FLAG1 << (Channel & 0x10UL))) == 0UL)
311     {
312       /* Trimming is actually one value more */
313       trimmingvalue++;
314       /* Set right trimming */
315       MODIFY_REG(hdac->Instance->CCR, (DAC_CCR_OTRIM1 << (Channel & 0x10UL)), (trimmingvalue << (Channel & 0x10UL)));
316     }
317 
318     /* Disable the selected DAC channel calibration */
319     /* i.e. clear DAC_CR_CENx bit */
320     CLEAR_BIT((hdac->Instance->CR), (DAC_CR_CEN1 << (Channel & 0x10UL)));
321 
322     sConfig->DAC_TrimmingValue = trimmingvalue;
323     sConfig->DAC_UserTrimming = DAC_TRIMMING_USER;
324 
325     /* Restore configuration */
326     MODIFY_REG(hdac->Instance->MCR, (DAC_MCR_MODE1 << (Channel & 0x10UL)), oldmodeconfiguration);
327 
328     /* Process unlocked */
329     __HAL_UNLOCK(hdac);
330   }
331 
332   return status;
333 }
334 
335 /**
336   * @brief  Set the trimming mode and trimming value (user trimming mode applied).
337   * @param  hdac pointer to a DAC_HandleTypeDef structure that contains
338   *         the configuration information for the specified DAC.
339   * @param  sConfig DAC configuration structure updated with new DAC trimming value.
340   * @param  Channel The selected DAC channel.
341   *          This parameter can be one of the following values:
342   *            @arg DAC_CHANNEL_1: DAC Channel1 selected
343   * @param  NewTrimmingValue DAC new trimming value
344   * @retval HAL status
345   */
HAL_DACEx_SetUserTrimming(DAC_HandleTypeDef * hdac,DAC_ChannelConfTypeDef * sConfig,uint32_t Channel,uint32_t NewTrimmingValue)346 HAL_StatusTypeDef HAL_DACEx_SetUserTrimming(DAC_HandleTypeDef *hdac, DAC_ChannelConfTypeDef *sConfig, uint32_t Channel,
347                                             uint32_t NewTrimmingValue)
348 {
349   HAL_StatusTypeDef status = HAL_OK;
350 
351   /* Check the parameters */
352   assert_param(IS_DAC_CHANNEL(Channel));
353   assert_param(IS_DAC_NEWTRIMMINGVALUE(NewTrimmingValue));
354 
355   /* Check the DAC handle allocation */
356   if (hdac == NULL)
357   {
358     status = HAL_ERROR;
359   }
360   else
361   {
362     /* Process locked */
363     __HAL_LOCK(hdac);
364 
365     /* Set new trimming */
366     MODIFY_REG(hdac->Instance->CCR, (DAC_CCR_OTRIM1 << (Channel & 0x10UL)), (NewTrimmingValue << (Channel & 0x10UL)));
367 
368     /* Update trimming mode */
369     sConfig->DAC_UserTrimming = DAC_TRIMMING_USER;
370     sConfig->DAC_TrimmingValue = NewTrimmingValue;
371 
372     /* Process unlocked */
373     __HAL_UNLOCK(hdac);
374   }
375   return status;
376 }
377 
378 /**
379   * @brief  Return the DAC trimming value.
380   * @param  hdac DAC handle
381   * @param  Channel The selected DAC channel.
382   *          This parameter can be one of the following values:
383   *            @arg DAC_CHANNEL_1: DAC Channel1 selected
384   * @retval Trimming value : range: 0->31
385   *
386  */
HAL_DACEx_GetTrimOffset(const DAC_HandleTypeDef * hdac,uint32_t Channel)387 uint32_t HAL_DACEx_GetTrimOffset(const DAC_HandleTypeDef *hdac, uint32_t Channel)
388 {
389   /* Check the parameter */
390   assert_param(IS_DAC_CHANNEL(Channel));
391 
392   /* Retrieve trimming */
393   return ((hdac->Instance->CCR & (DAC_CCR_OTRIM1 << (Channel & 0x10UL))) >> (Channel & 0x10UL));
394 }
395 
396 /**
397   * @}
398   */
399 
400 /**
401   * @}
402   */
403 
404 /**
405   * @}
406   */
407 
408 #endif /* DAC */
409 
410 #endif /* HAL_DAC_MODULE_ENABLED */
411 
412 /**
413   * @}
414   */
415