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