ChibiOS 21.11.5
hal_dac.c
Go to the documentation of this file.
1/*
2 ChibiOS - Copyright (C) 2006-2026 Giovanni Di Sirio.
3
4 Licensed under the Apache License, Version 2.0 (the "License");
5 you may not use this file except in compliance with the License.
6 You may obtain a copy of the License at
7
8 http://www.apache.org/licenses/LICENSE-2.0
9
10 Unless required by applicable law or agreed to in writing, software
11 distributed under the License is distributed on an "AS IS" BASIS,
12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 See the License for the specific language governing permissions and
14 limitations under the License.
15*/
16
17/**
18 * @file hal_dac.c
19 * @brief DAC Driver code.
20 *
21 * @addtogroup DAC
22 * @{
23 */
24
25#include "hal.h"
26
27#if (HAL_USE_DAC == TRUE) || defined(__DOXYGEN__)
28
29/*===========================================================================*/
30/* Driver local definitions. */
31/*===========================================================================*/
32
33/*===========================================================================*/
34/* Driver exported variables. */
35/*===========================================================================*/
36
37/*===========================================================================*/
38/* Driver local variables. */
39/*===========================================================================*/
40
41/*===========================================================================*/
42/* Driver local functions. */
43/*===========================================================================*/
44
45/*===========================================================================*/
46/* Driver exported functions. */
47/*===========================================================================*/
48
49/**
50 * @brief DAC Driver initialization.
51 * @note This function is implicitly invoked by @p halInit(), there is
52 * no need to explicitly initialize the driver.
53 *
54 * @init
55 */
56void dacInit(void) {
57
59}
60
61/**
62 * @brief Initializes the standard part of a @p DACDriver structure.
63 *
64 * @param[out] dacp pointer to the @p DACDriver object
65 *
66 * @init
67 */
69
70 dacp->state = DAC_STOP;
71 dacp->config = NULL;
72#if (DAC_USE_SYNCHRONIZATION == TRUE)
73 dacp->thread = NULL;
74#endif
75#if DAC_USE_MUTUAL_EXCLUSION
77#endif
78#if defined(DAC_DRIVER_EXT_INIT_HOOK)
79 DAC_DRIVER_EXT_INIT_HOOK(dacp);
80#endif
81}
82
83/**
84 * @brief Configures and activates the DAC peripheral.
85 *
86 * @param[in] dacp pointer to the @p DACDriver object
87 * @param[in] config pointer to the @p DACConfig object, it can be
88 * @p NULL if the low level driver implementation
89 * supports a default configuration
90 *
91 * @return The operation status.
92 *
93 * @api
94 */
95msg_t dacStart(DACDriver *dacp, const DACConfig *config) {
96 msg_t msg;
97
98 osalDbgCheck(dacp != NULL);
99
100 osalSysLock();
101
102 osalDbgAssert((dacp->state == DAC_STOP) || (dacp->state == DAC_READY),
103 "invalid state");
104
105 dacp->config = config;
106
107#if defined(DAC_LLD_ENHANCED_API)
108 msg = dac_lld_start(dacp);
109 if (msg == HAL_RET_SUCCESS) {
110 dacp->state = DAC_READY;
111 }
112 else {
113 dacp->state = DAC_STOP;
114 }
115#else
116 dac_lld_start(dacp);
117 dacp->state = DAC_READY;
118 msg = HAL_RET_SUCCESS;
119#endif
120
122
123 return msg;
124}
125
126/**
127 * @brief Deactivates the DAC peripheral.
128 *
129 * @param[in] dacp pointer to the @p DACDriver object
130 *
131 * @api
132 */
133void dacStop(DACDriver *dacp) {
134
135 osalDbgCheck(dacp != NULL);
136
137 osalSysLock();
138
139 osalDbgAssert((dacp->state == DAC_STOP) || (dacp->state == DAC_READY),
140 "invalid state");
141
142 dac_lld_stop(dacp);
143 dacp->config = NULL;
144 dacp->state = DAC_STOP;
145
147}
148
149/**
150 * @brief Outputs a value directly on a DAC channel.
151 *
152 * @param[in] dacp pointer to the @p DACDriver object
153 * @param[in] channel DAC channel number
154 * @param[in] sample value to be output
155 *
156 * @xclass
157 */
159
161 osalDbgAssert((dacp->state == DAC_READY) ||
162 (dacp->state == DAC_ACTIVE) ||
163 (dacp->state == DAC_COMPLETE), "invalid state");
164 msg_t msg;
165#if defined(DAC_LLD_ENHANCED_API)
166 msg = dac_lld_put_channel(dacp, channel, sample);
167#else
168 dac_lld_put_channel(dacp, channel, sample);
169 msg = HAL_RET_SUCCESS;
170#endif
171 return msg;
172}
173
174/**
175 * @brief Starts a DAC conversion.
176 * @details Starts an asynchronous conversion operation.
177 * @note The buffer is organized as a matrix of M*N elements where M is the
178 * channels number configured into the conversion group and N is the
179 * buffer depth. The samples are sequentially written into the buffer
180 * with no gaps.
181 *
182 * @param[in] dacp pointer to the @p DACDriver object
183 * @param[in] grpp pointer to a @p DACConversionGroup object
184 * @param[in] samples pointer to the samples buffer
185 * @param[in] depth buffer depth (matrix rows number). The buffer depth
186 * must be one or an even number.
187 *
188 * @return The operation status.
189 *
190 * @api
191 */
193 const DACConversionGroup *grpp,
194 dacsample_t *samples,
195 size_t depth) {
196 msg_t msg;
197 osalSysLock();
198#if defined(DAC_LLD_ENHANCED_API)
199 msg = dacStartConversionI(dacp, grpp, samples, depth);
200#else
201 (void) dacStartConversionI(dacp, grpp, samples, depth);
202 msg = HAL_RET_SUCCESS;
203#endif
205 return msg;
206}
207
208/**
209 * @brief Starts a DAC conversion.
210 * @details Starts an asynchronous conversion operation.
211 * @post The callbacks associated to the conversion group will be invoked
212 * on buffer complete and error events.
213 * @note DAC conversions are circular/streaming operations, a new
214 * conversion can only be started after stopping the current one.
215 * @note The buffer is organized as a matrix of M*N elements where M is the
216 * channels number configured into the conversion group and N is the
217 * buffer depth. The samples are sequentially organised in the buffer
218 * with no gaps.
219 *
220 * @param[in] dacp pointer to the @p DACDriver object
221 * @param[in] grpp pointer to a @p DACConversionGroup object
222 * @param[in] samples pointer to the samples buffer
223 * @param[in] depth buffer depth (matrix rows number). The buffer depth
224 * must be one or an even number.
225 *
226 * @return The operation status.
227 *
228 * @iclass
229 */
231 const DACConversionGroup *grpp,
232 dacsample_t *samples,
233 size_t depth) {
234 msg_t msg;
235
237 osalDbgCheck((dacp != NULL) && (grpp != NULL) && (samples != NULL) &&
238 ((depth == 1U) || ((depth & 1U) == 0U)));
239 osalDbgAssert((dacp->state == DAC_READY) ||
240 (dacp->state == DAC_ERROR),
241 "not ready");
242
243 dacp->samples = samples;
244 dacp->depth = depth;
245 dacp->grpp = grpp;
246#if defined(DAC_LLD_ENHANCED_API)
247 msg = dac_lld_start_conversion(dacp);
248 if (msg == HAL_RET_SUCCESS) {
249 dacp->state = DAC_ACTIVE;
250 }
251 else {
252 dacp->grpp = NULL;
253 }
254#else
256 dacp->state = DAC_ACTIVE;
257 msg = HAL_RET_SUCCESS;
258#endif
259
260 return msg;
261}
262
263/**
264 * @brief Stops an ongoing conversion.
265 * @details This function stops the currently ongoing conversion and returns
266 * the driver in the @p DAC_READY state. If there was no conversion
267 * being processed then the function does nothing.
268 *
269 * @param[in] dacp pointer to the @p DACDriver object
270 *
271 * @api
272 */
274
275 osalDbgCheck(dacp != NULL);
276
277 osalSysLock();
278
279 osalDbgAssert((dacp->state == DAC_READY) ||
280 (dacp->state == DAC_ACTIVE),
281 "invalid state");
282
283 if (dacp->state != DAC_READY) {
285 dacp->grpp = NULL;
286 dacp->state = DAC_READY;
287 _dac_reset_s(dacp);
288 }
289
291}
292
293/**
294 * @brief Stops an ongoing conversion.
295 * @details This function stops the currently ongoing conversion and returns
296 * the driver in the @p DAC_READY state. If there was no conversion
297 * being processed then the function does nothing.
298 *
299 * @param[in] dacp pointer to the @p DACDriver object
300 *
301 * @iclass
302 */
304
306 osalDbgCheck(dacp != NULL);
307 osalDbgAssert((dacp->state == DAC_READY) ||
308 (dacp->state == DAC_ACTIVE) ||
309 (dacp->state == DAC_COMPLETE),
310 "invalid state");
311
312 if (dacp->state != DAC_READY) {
314 dacp->grpp = NULL;
315 dacp->state = DAC_READY;
316 _dac_reset_i(dacp);
317 }
318}
319
320#if (DAC_USE_SYNCHRONIZATION == TRUE) || defined(__DOXYGEN__)
321/**
322 * @brief Performs a DAC conversion.
323 * @details Performs a synchronous conversion operation.
324 * @note The buffer is organized as a matrix of M*N elements where M is the
325 * channels number configured into the conversion group and N is the
326 * buffer depth. The samples are sequentially organised in the buffer
327 * with no gaps.
328 *
329 * @param[in] dacp pointer to the @p DACDriver object
330 * @param[in] grpp pointer to a @p DACConversionGroup object
331 * @param[in] samples pointer to the samples buffer
332 * @param[in] depth buffer depth (matrix rows number). The buffer depth
333 * must be one or an even number.
334 *
335 * @return The operation result.
336 * @retval MSG_OK Conversion finished.
337 * @retval MSG_RESET The conversion has been stopped using
338 * @p dacStopConversion() or @p dacStopConversionI().
339 * @retval MSG_TIMEOUT The conversion has been stopped because an hardware
340 * error.
341 * @note Starting a follow-on conversion from the callback before this
342 * function returns is undefined behavior.
343 *
344 * @api
345 */
347 const DACConversionGroup *grpp,
348 dacsample_t *samples,
349 size_t depth) {
350 msg_t msg;
351
352 osalSysLock();
353
354 msg = dacStartConversionI(dacp, grpp, samples, depth);
355 if (msg != HAL_RET_SUCCESS) {
357 return msg;
358 }
359 msg = osalThreadSuspendS(&dacp->thread);
360
362
363 return msg;
364}
365
366/**
367 * @brief Synchronize to a conversion completion.
368 * @note This function can only be called by a single thread at time.
369 * @note Starting a follow-on conversion from the callback before this
370 * function returns is undefined behavior.
371 *
372 * @param[in] dacp pointer to the @p DACDriver object
373 * @param[in] timeout wait timeout
374 *
375 * @return The wait result.
376 * @retval MSG_OK if operation completed without errors.
377 * @retval MSG_TIMEOUT if synchronization request timed out.
378 * @retval MSG_RESET if the conversion has been stopped.
379 *
380 * @sclass
381 */
383 msg_t msg;
384
386 osalDbgCheck(dacp != NULL);
387 osalDbgAssert((dacp->state == DAC_ACTIVE) || (dacp->state == DAC_READY),
388 "invalid state");
389
390 if (dacp->state == DAC_ACTIVE) {
391 msg = osalThreadSuspendTimeoutS(&dacp->thread, timeout);
392 }
393 else {
394 msg = MSG_OK;
395 }
396
397 return msg;
398}
399
400/**
401 * @brief Synchronize to a conversion completion.
402 * @note This function can only be called by a single thread at time.
403 *
404 * @param[in] dacp pointer to the @p DACDriver object
405 * @param[in] timeout wait timeout
406 *
407 * @return The wait result.
408 * @retval MSG_OK if operation completed without errors.
409 * @retval MSG_TIMEOUT if synchronization request timed out.
410 * @retval MSG_RESET if the conversion has been stopped.
411 *
412 * @api
413 */
415 msg_t msg;
416
417 osalSysLock();
418 msg = dacSynchronizeS(dacp, timeout);
420
421 return msg;
422}
423#endif /* DAC_USE_SYNCHRONIZATION == TRUE */
424
425#if (DAC_USE_MUTUAL_EXCLUSION == TRUE) || defined(__DOXYGEN__)
426/**
427 * @brief Gains exclusive access to the DAC bus.
428 * @details This function tries to gain ownership to the DAC bus, if the bus
429 * is already being used then the invoking thread is queued.
430 * @pre In order to use this function the option @p DAC_USE_MUTUAL_EXCLUSION
431 * must be enabled.
432 *
433 * @param[in] dacp pointer to the @p DACDriver object
434 *
435 * @api
436 */
438
439 osalDbgCheck(dacp != NULL);
440
441 osalMutexLock(&dacp->mutex);
442}
443
444/**
445 * @brief Releases exclusive access to the DAC bus.
446 * @pre In order to use this function the option @p DAC_USE_MUTUAL_EXCLUSION
447 * must be enabled.
448 *
449 * @param[in] dacp pointer to the @p DACDriver object
450 *
451 * @api
452 */
454
455 osalDbgCheck(dacp != NULL);
456
457 osalMutexUnlock(&dacp->mutex);
458}
459#endif /* DAC_USE_MUTUAL_EXCLUSION == TRUE */
460
461#endif /* HAL_USE_DAC == TRUE */
462
463/** @} */
void dac_lld_put_channel(DACDriver *dacp, dacchannel_t channel, dacsample_t sample)
Outputs a value directly on a DAC channel.
msg_t dacSynchronizeS(DACDriver *dacp, sysinterval_t timeout)
Synchronize to a conversion completion.
Definition hal_dac.c:382
void dac_lld_init(void)
Low level DAC driver initialization.
Definition hal_dac_lld.c:63
uint16_t dacsample_t
Type representing a DAC sample.
Definition hal_dac_lld.h:73
struct hal_dac_driver DACDriver
Type of a structure representing an DAC driver.
Definition hal_dac.h:85
void dacStop(DACDriver *dacp)
Deactivates the DAC peripheral.
Definition hal_dac.c:133
uint32_t dacchannel_t
Type of a DAC channel index.
Definition hal_dac_lld.h:68
msg_t dacStartConversionI(DACDriver *dacp, const DACConversionGroup *grpp, dacsample_t *samples, size_t depth)
Starts a DAC conversion.
Definition hal_dac.c:230
void dacReleaseBus(DACDriver *dacp)
Releases exclusive access to the DAC bus.
Definition hal_dac.c:453
void dacStopConversion(DACDriver *dacp)
Stops an ongoing conversion.
Definition hal_dac.c:273
void dac_lld_start_conversion(DACDriver *dacp)
Starts a DAC conversion.
void dacAcquireBus(DACDriver *dacp)
Gains exclusive access to the DAC bus.
Definition hal_dac.c:437
void dacObjectInit(DACDriver *dacp)
Initializes the standard part of a DACDriver structure.
Definition hal_dac.c:68
msg_t dacStartConversion(DACDriver *dacp, const DACConversionGroup *grpp, dacsample_t *samples, size_t depth)
Starts a DAC conversion.
Definition hal_dac.c:192
void dacInit(void)
DAC Driver initialization.
Definition hal_dac.c:56
void dacStopConversionI(DACDriver *dacp)
Stops an ongoing conversion.
Definition hal_dac.c:303
void dac_lld_start(DACDriver *dacp)
Configures and activates the DAC peripheral.
Definition hal_dac_lld.c:77
msg_t dacSynchronize(DACDriver *dacp, sysinterval_t timeout)
Synchronize to a conversion completion.
Definition hal_dac.c:414
#define _dac_reset_s(dacp)
Resumes a thread waiting for a conversion completion.
Definition hal_dac.h:249
struct hal_dac_config DACConfig
Type of a structure representing an DAC driver configuration.
Definition hal_dac.h:90
msg_t dacStart(DACDriver *dacp, const DACConfig *config)
Configures and activates the DAC peripheral.
Definition hal_dac.c:95
msg_t dacPutChannelX(DACDriver *dacp, dacchannel_t channel, dacsample_t sample)
Outputs a value directly on a DAC channel.
Definition hal_dac.c:158
void dac_lld_stop_conversion(DACDriver *dacp)
Stops an ongoing conversion.
struct hal_dac_conversion_group DACConversionGroup
Type of a DAC conversion group.
Definition hal_dac.h:95
#define DAC_MAX_CHANNELS
Maximum number of DAC channels per unit.
Definition hal_dac_lld.h:37
#define _dac_reset_i(dacp)
Resumes a thread waiting for a conversion completion.
Definition hal_dac.h:240
void dac_lld_stop(DACDriver *dacp)
Deactivates the DAC peripheral.
Definition hal_dac_lld.c:98
msg_t dacConvert(DACDriver *dacp, const DACConversionGroup *grpp, dacsample_t *samples, size_t depth)
Performs a DAC conversion.
Definition hal_dac.c:346
@ DAC_READY
Definition hal_dac.h:76
@ DAC_ACTIVE
Definition hal_dac.h:77
@ DAC_COMPLETE
Definition hal_dac.h:78
@ DAC_STOP
Definition hal_dac.h:75
@ DAC_ERROR
Definition hal_dac.h:79
#define HAL_RET_SUCCESS
Definition hal.h:93
static void osalSysLock(void)
Enters a critical zone from thread context.
Definition osal.h:601
static void osalMutexObjectInit(mutex_t *mp)
Initializes a mutex_t object.
Definition osal.h:753
static void osalSysUnlock(void)
Leaves a critical zone from thread context.
Definition osal.h:611
msg_t osalThreadSuspendS(thread_reference_t *trp)
Sends the current thread sleeping and sets a reference variable.
Definition osal.c:183
void osalMutexLock(mutex_t *mp)
Locks the specified mutex.
Definition osal.c:380
#define osalDbgCheckClassS()
S-Class state check.
Definition osal.h:304
#define osalDbgAssert(c, remark)
Condition assertion.
Definition osal.h:264
void osalMutexUnlock(mutex_t *mp)
Unlocks the specified mutex.
Definition osal.c:400
msg_t osalThreadSuspendTimeoutS(thread_reference_t *trp, sysinterval_t timeout)
Sends the current thread sleeping and sets a reference variable.
Definition osal.c:208
#define osalDbgCheck(c)
Function parameters check.
Definition osal.h:284
#define osalDbgCheckClassI()
I-Class state check.
Definition osal.h:298
int32_t msg_t
Definition chearly.h:87
#define MSG_OK
Normal wakeup message.
Definition chschd.h:38
uint64_t sysinterval_t
Type of time interval.
Definition chtime.h:118
HAL subsystem header.
const DACConversionGroup * grpp
Conversion group.
Definition hal_dac.h:161
size_t depth
Samples buffer size.
Definition hal_dac.h:169
dacsample_t * samples
Samples buffer pointer.
Definition hal_dac.h:165
thread_reference_t thread
Waiting thread.
Definition hal_dac.h:178
const DACConfig * config
Current configuration data.
Definition hal_dac.h:173
dacstate_t state
Driver state.
Definition hal_dac.h:157
mutex_t mutex
Mutex protecting the bus.
Definition hal_dac.h:184