ChibiOS/HAL 9.0.0
hal_dac.c
Go to the documentation of this file.
1/*
2 ChibiOS - Copyright (C) 2006..2024 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_WAIT
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 * @note Deactivating the peripheral also enforces a release of the slave
129 * select line.
130 *
131 * @param[in] dacp pointer to the @p DACDriver object
132 *
133 * @api
134 */
135void dacStop(DACDriver *dacp) {
136
137 osalDbgCheck(dacp != NULL);
138
139 osalSysLock();
140
141 osalDbgAssert((dacp->state == DAC_STOP) || (dacp->state == DAC_READY),
142 "invalid state");
143
144 dac_lld_stop(dacp);
145 dacp->config = NULL;
146 dacp->state = DAC_STOP;
147
149}
150
151/**
152 * @brief Outputs a value directly on a DAC channel.
153 *
154 * @param[in] dacp pointer to the @p DACDriver object
155 * @param[in] channel DAC channel number
156 * @param[in] sample value to be output
157 *
158 * @xclass
159 */
161
163 osalDbgAssert((dacp->state == DAC_READY) ||
164 (dacp->state == DAC_ACTIVE) ||
165 (dacp->state == DAC_COMPLETE), "invalid state");
166 msg_t msg;
167#if defined(DAC_LLD_ENHANCED_API)
168 msg = dac_lld_put_channel(dacp, channel, sample);
169#else
170 dac_lld_put_channel(dacp, channel, sample);
171 msg = HAL_RET_SUCCESS;
172#endif
173 return msg;
174}
175
176/**
177 * @brief Starts a DAC conversion.
178 * @details Starts an asynchronous conversion operation.
179 * @note The buffer is organized as a matrix of M*N elements where M is the
180 * channels number configured into the conversion group and N is the
181 * buffer depth. The samples are sequentially written into the buffer
182 * with no gaps.
183 *
184 * @param[in] dacp pointer to the @p DACDriver object
185 * @param[in] grpp pointer to a @p DACConversionGroup object
186 * @param[in] samples pointer to the samples buffer
187 * @param[in] depth buffer depth (matrix rows number). The buffer depth
188 * must be one or an even number.
189 *
190 * @return The operation status.
191 *
192 * @api
193 */
195 const DACConversionGroup *grpp,
196 dacsample_t *samples,
197 size_t depth) {
198 msg_t msg;
199 osalSysLock();
200#if defined(DAC_LLD_ENHANCED_API)
201 msg = dacStartConversionI(dacp, grpp, samples, depth);
202#else
203 (void) dacStartConversionI(dacp, grpp, samples, depth);
204 msg = HAL_RET_SUCCESS;
205#endif
207 return msg;
208}
209
210/**
211 * @brief Starts a DAC conversion.
212 * @details Starts an asynchronous conversion operation.
213 * @post The callbacks associated to the conversion group will be invoked
214 * on buffer complete and error events.
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_COMPLETE) ||
241 (dacp->state == DAC_ERROR),
242 "not ready");
243
244 dacp->samples = samples;
245 dacp->depth = depth;
246 dacp->grpp = grpp;
247#if defined(DAC_LLD_ENHANCED_API)
248 msg = dac_lld_start_conversion(dacp);
249 if (msg == HAL_RET_SUCCESS) {
250 dacp->state = DAC_ACTIVE;
251 }
252 else {
253 dacp->grpp = NULL;
254 }
255#else
257 dacp->state = DAC_ACTIVE;
258 msg = HAL_RET_SUCCESS;
259#endif
260
261 return msg;
262}
263
264/**
265 * @brief Stops an ongoing conversion.
266 * @details This function stops the currently ongoing conversion and returns
267 * the driver in the @p DAC_READY state. If there was no conversion
268 * being processed then the function does nothing.
269 *
270 * @param[in] dacp pointer to the @p DACDriver object
271 *
272 * @api
273 */
275
276 osalDbgCheck(dacp != NULL);
277
278 osalSysLock();
279
280 osalDbgAssert((dacp->state == DAC_READY) ||
281 (dacp->state == DAC_ACTIVE),
282 "invalid state");
283
284 if (dacp->state != DAC_READY) {
286 dacp->grpp = NULL;
287 dacp->state = DAC_READY;
288 _dac_reset_s(dacp);
289 }
290
292}
293
294/**
295 * @brief Stops an ongoing conversion.
296 * @details This function stops the currently ongoing conversion and returns
297 * the driver in the @p DAC_READY state. If there was no conversion
298 * being processed then the function does nothing.
299 *
300 * @param[in] dacp pointer to the @p DACDriver object
301 *
302 * @iclass
303 */
305
307 osalDbgCheck(dacp != NULL);
308 osalDbgAssert((dacp->state == DAC_READY) ||
309 (dacp->state == DAC_ACTIVE) ||
310 (dacp->state == DAC_COMPLETE),
311 "invalid state");
312
313 if (dacp->state != DAC_READY) {
315 dacp->grpp = NULL;
316 dacp->state = DAC_READY;
317 _dac_reset_i(dacp);
318 }
319}
320
321#if (DAC_USE_SYNCHRONIZATION == TRUE) || defined(__DOXYGEN__)
322/**
323 * @brief Performs a DAC conversion.
324 * @details Performs a synchronous conversion operation.
325 * @note The buffer is organized as a matrix of M*N elements where M is the
326 * channels number configured into the conversion group and N is the
327 * buffer depth. The samples are sequentially organised in the buffer
328 * with no gaps.
329 *
330 * @param[in] dacp pointer to the @p DACDriver object
331 * @param[in] grpp pointer to a @p DACConversionGroup object
332 * @param[in] samples pointer to the samples buffer
333 * @param[in] depth buffer depth (matrix rows number). The buffer depth
334 * must be one or an even number.
335 *
336 * @return The operation result.
337 * @retval MSG_OK Conversion finished.
338 * @retval MSG_RESET The conversion has been stopped using
339 * @p dacStopConversion() or @p dacStopConversionI().
340 * @retval MSG_TIMEOUT The conversion has been stopped because an hardware
341 * error.
342 *
343 * @api
344 */
346 const DACConversionGroup *grpp,
347 dacsample_t *samples,
348 size_t depth) {
349 msg_t msg;
350
351 osalSysLock();
352
353 msg = dacStartConversionI(dacp, grpp, samples, depth);
354 if (msg != HAL_RET_SUCCESS) {
355 return msg;
356 }
357 msg = osalThreadSuspendS(&dacp->thread);
358
360
361 return msg;
362}
363
364/**
365 * @brief Synchronize to a conversion completion.
366 * @note This function can only be called by a single thread at time.
367 *
368 * @param[in] dacp pointer to the @p DACDriver object
369 * @param[in] timeout wait timeout
370 *
371 * @return The wait result.
372 * @retval MSG_OK if operation completed without errors.
373 * @retval MSG_TIMEOUT if synchronization request timed out.
374 * @retval MSG_RESET if the conversion has been stopped.
375 *
376 * @sclass
377 */
379 msg_t msg;
380
382 osalDbgCheck(dacp != NULL);
383 osalDbgAssert((dacp->state == DAC_ACTIVE) || (dacp->state == DAC_READY),
384 "invalid state");
385
386 if (dacp->state == DAC_ACTIVE) {
387 msg = osalThreadSuspendTimeoutS(&dacp->thread, timeout);
388 }
389 else {
390 msg = MSG_OK;
391 }
392
393 return msg;
394}
395
396/**
397 * @brief Synchronize to a conversion completion.
398 * @note This function can only be called by a single thread at time.
399 *
400 * @param[in] dacp pointer to the @p DACDriver object
401 * @param[in] timeout wait timeout
402 *
403 * @return The wait result.
404 * @retval MSG_OK if operation completed without errors.
405 * @retval MSG_TIMEOUT if synchronization request timed out.
406 * @retval MSG_RESET if the conversion has been stopped.
407 *
408 * @api
409 */
411 msg_t msg;
412
413 osalSysLock();
414 msg = dacSynchronizeS(dacp, timeout);
416
417 return msg;
418}
419#endif /* DAC_USE_SYNCHRONIZATION == TRUE */
420
421#if (DAC_USE_MUTUAL_EXCLUSION == TRUE) || defined(__DOXYGEN__)
422/**
423 * @brief Gains exclusive access to the DAC bus.
424 * @details This function tries to gain ownership to the DAC bus, if the bus
425 * is already being used then the invoking thread is queued.
426 * @pre In order to use this function the option @p DAC_USE_MUTUAL_EXCLUSION
427 * must be enabled.
428 *
429 * @param[in] dacp pointer to the @p DACDriver object
430 *
431 * @api
432 */
434
435 osalDbgCheck(dacp != NULL);
436
437 osalMutexLock(&dacp->mutex);
438}
439
440/**
441 * @brief Releases exclusive access to the DAC bus.
442 * @pre In order to use this function the option @p DAC_USE_MUTUAL_EXCLUSION
443 * must be enabled.
444 *
445 * @param[in] dacp pointer to the @p DACDriver object
446 *
447 * @api
448 */
450
451 osalDbgCheck(dacp != NULL);
452
453 osalMutexUnlock(&dacp->mutex);
454}
455#endif /* DAC_USE_MUTUAL_EXCLUSION == TRUE */
456
457#endif /* HAL_USE_DAC == TRUE */
458
459/** @} */
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:378
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:135
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:449
void dacStopConversion(DACDriver *dacp)
Stops an ongoing conversion.
Definition hal_dac.c:274
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:433
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:194
void dacInit(void)
DAC Driver initialization.
Definition hal_dac.c:56
void dacStopConversionI(DACDriver *dacp)
Stops an ongoing conversion.
Definition hal_dac.c:304
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:410
#define _dac_reset_s(dacp)
Resumes a thread waiting for a conversion completion.
Definition hal_dac.h:242
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:160
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:233
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:345
@ 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
int32_t msg_t
Type of a message.
Definition osal.h:159
uint32_t sysinterval_t
Type of system time interval.
Definition osal.h:169
msg_t osalThreadSuspendS(thread_reference_t *trp)
Sends the current thread sleeping and sets a reference variable.
Definition osal.c:183
#define MSG_OK
Definition osal.h:56
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
HAL subsystem header.
const DACConversionGroup * grpp
Conversion group.
Definition hal_dac.h:156
size_t depth
Samples buffer size.
Definition hal_dac.h:164
dacsample_t * samples
Samples buffer pointer.
Definition hal_dac.h:160
thread_reference_t thread
Waiting thread.
Definition hal_dac.h:173
const DACConfig * config
Current configuration data.
Definition hal_dac.h:168
dacstate_t state
Driver state.
Definition hal_dac.h:152
mutex_t mutex
Mutex protecting the bus.
Definition hal_dac.h:179