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