Improved DAC driver, updated STM32 DACv1.

git-svn-id: svn://svn.code.sf.net/p/chibios/svn/trunk@16315 27425a3e-05d8-49a3-a47f-9c15f0e5edd8
This commit is contained in:
Giovanni Di Sirio 2023-07-09 08:34:39 +00:00
parent f77d00b0c9
commit 665b0d48b4
5 changed files with 2309 additions and 2207 deletions

View File

@ -1,379 +1,385 @@
/*
ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
/**
* @file hal_dac.h
* @brief DAC Driver macros and structures.
*
* @addtogroup DAC
* @{
*/
#ifndef HAL_DAC_H
#define HAL_DAC_H
#if (HAL_USE_DAC == TRUE) || defined(__DOXYGEN__)
/*===========================================================================*/
/* Driver constants. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver pre-compile time settings. */
/*===========================================================================*/
/**
* @name DAC configuration options
* @{
*/
/**
* @brief Enables synchronous APIs.
* @note Disabling this option saves both code and data space.
*/
#if !defined(DAC_USE_WAIT) || defined(__DOXYGEN__)
#define DAC_USE_WAIT TRUE
#endif
/**
* @brief Enables the @p dacAcquireBus() and @p dacReleaseBus() APIs.
* @note Disabling this option saves both code and data space.
*/
#if !defined(DAC_USE_MUTUAL_EXCLUSION) || defined(__DOXYGEN__)
#define DAC_USE_MUTUAL_EXCLUSION TRUE
#endif
/** @} */
/*===========================================================================*/
/* Derived constants and error checks. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver data structures and types. */
/*===========================================================================*/
/**
* @brief Driver state machine possible states.
*/
typedef enum {
DAC_UNINIT = 0, /**< Not initialized. */
DAC_STOP = 1, /**< Stopped. */
DAC_READY = 2, /**< Ready. */
DAC_ACTIVE = 3, /**< Exchanging data. */
DAC_COMPLETE = 4, /**< Asynchronous operation complete. */
DAC_ERROR = 5 /**< Error. */
} dacstate_t;
/**
* @brief Type of a structure representing an DAC driver.
*/
typedef struct hal_dac_driver DACDriver;
/**
* @brief Type of a structure representing an DAC driver configuration.
*/
typedef struct hal_dac_config DACConfig;
/**
* @brief Type of a DAC conversion group.
*/
typedef struct hal_dac_conversion_group DACConversionGroup;
/* Including the low level driver header, it exports information required
for completing types.*/
#include "hal_dac_lld.h"
/**
* @brief DAC notification callback type.
*
* @param[in] dacp pointer to the @p DACDriver object triggering the
*/
typedef void (*daccallback_t)(DACDriver *dacp);
/**
* @brief DAC error callback type.
*
* @param[in] dacp pointer to the @p DACDriver object triggering the
* callback
* @param[in] err DAC error code
*/
typedef void (*dacerrorcallback_t)(DACDriver *dacp, dacerror_t err);
/**
* @brief DAC Conversion group structure.
*/
struct hal_dac_conversion_group {
/**
* @brief Number of DAC channels.
*/
uint32_t num_channels;
/**
* @brief Operation complete callback or @p NULL.
*/
daccallback_t end_cb;
/**
* @brief Error handling callback or @p NULL.
*/
dacerrorcallback_t error_cb;
/* End of the mandatory fields.*/
dac_lld_conversion_group_fields;
};
/**
* @brief Driver configuration structure.
*/
struct hal_dac_config {
/* End of the mandatory fields.*/
dac_lld_config_fields;
};
/**
* @brief Structure representing a DAC driver.
*/
struct hal_dac_driver {
/**
* @brief Driver state.
*/
dacstate_t state;
/**
* @brief Conversion group.
*/
const DACConversionGroup *grpp;
/**
* @brief Samples buffer pointer.
*/
dacsample_t *samples;
/**
* @brief Samples buffer size.
*/
size_t depth;
/**
* @brief Current configuration data.
*/
const DACConfig *config;
#if (DAC_USE_WAIT == TRUE) || defined(__DOXYGEN__)
/**
* @brief Waiting thread.
*/
thread_reference_t thread;
#endif /* DAC_USE_WAIT */
#if (DAC_USE_MUTUAL_EXCLUSION == TRUE) || defined(__DOXYGEN__)
/**
* @brief Mutex protecting the bus.
*/
mutex_t mutex;
#endif /* DAC_USE_MUTUAL_EXCLUSION */
#if defined(DAC_DRIVER_EXT_FIELDS)
DAC_DRIVER_EXT_FIELDS
#endif
/* End of the mandatory fields.*/
dac_lld_driver_fields;
};
/*===========================================================================*/
/* Driver macros. */
/*===========================================================================*/
/**
* @name Low level driver helper macros
* @{
*/
/**
* @brief Buffer state.
* @note This function is meant to be called from the DAC callback only.
*
* @param[in] dacp pointer to the @p DACDriver object
* @return The buffer state.
* @retval false if the driver filled/sent the first half of the
* buffer.
* @retval true if the driver filled/sent the second half of the
* buffer.
*
* @special
*/
#define dacIsBufferComplete(dacp) ((bool)((dacp)->state == DAC_COMPLETE))
#if (DAC_USE_WAIT == TRUE) || defined(__DOXYGEN__)
/**
* @brief Waits for operation completion.
* @details This function waits for the driver to complete the current
* operation.
* @pre An operation must be running while the function is invoked.
* @note No more than one thread can wait on a DAC driver using
* this function.
*
* @param[in] dacp pointer to the @p DACDriver object
*
* @notapi
*/
#define _dac_wait_s(dacp) osalThreadSuspendS(&(dacp)->thread)
/**
* @brief Resumes a thread waiting for a conversion completion.
*
* @param[in] dacp pointer to the @p DACDriver object
*
* @notapi
*/
#define _dac_reset_i(dacp) osalThreadResumeI(&(dacp)->thread, MSG_RESET)
/**
* @brief Resumes a thread waiting for a conversion completion.
*
* @param[in] dacp pointer to the @p DACDriver object
*
* @notapi
*/
#define _dac_reset_s(dacp) osalThreadResumeS(&(dacp)->thread, MSG_RESET)
/**
* @brief Wakes up the waiting thread.
*
* @param[in] dacp pointer to the @p DACDriver object
*
* @notapi
*/
#define _dac_wakeup_isr(dacp) { \
osalSysLockFromISR(); \
osalThreadResumeI(&(dacp)->thread, MSG_OK); \
osalSysUnlockFromISR(); \
}
/**
* @brief Wakes up the waiting thread with a timeout message.
*
* @param[in] dacp pointer to the @p DACDriver object
*
* @notapi
*/
#define _dac_timeout_isr(dacp) { \
osalSysLockFromISR(); \
osalThreadResumeI(&(dacp)->thread, MSG_TIMEOUT); \
osalSysUnlockFromISR(); \
}
#else /* !DAC_USE_WAIT */
#define _dac_wait_s(dacp)
#define _dac_reset_i(dacp)
#define _dac_reset_s(dacp)
#define _dac_wakeup_isr(dacp)
#define _dac_timeout_isr(dacp)
#endif /* !DAC_USE_WAIT */
/**
* @brief Common ISR code, half buffer event.
* @details This code handles the portable part of the ISR code:
* - Callback invocation.
* .
* @note This macro is meant to be used in the low level drivers
* implementation only.
*
* @param[in] dacp pointer to the @p DACDriver object
*
* @notapi
*/
#define _dac_isr_half_code(dacp) { \
if ((dacp)->grpp->end_cb != NULL) { \
(dacp)->grpp->end_cb(dacp); \
} \
}
/**
* @brief Common ISR code, full buffer event.
* @details This code handles the portable part of the ISR code:
* - Callback invocation.
* - Driver state transitions.
* .
* @note This macro is meant to be used in the low level drivers
* implementation only.
*
* @param[in] dacp pointer to the @p DACDriver object
*
* @notapi
*/
#define _dac_isr_full_code(dacp) { \
if ((dacp)->grpp->end_cb) { \
(dacp)->state = DAC_COMPLETE; \
(dacp)->grpp->end_cb(dacp); \
if ((dacp)->state == DAC_COMPLETE) \
(dacp)->state = DAC_ACTIVE; \
} \
}
/**
* @brief Common ISR code, error event.
* @details This code handles the portable part of the ISR code:
* - Callback invocation.
* - Waiting thread timeout signaling, if any.
* - Driver state transitions.
* .
* @note This macro is meant to be used in the low level drivers
* implementation only.
*
* @param[in] dacp pointer to the @p DACDriver object
* @param[in] err platform dependent error code
*
* @notapi
*/
#define _dac_isr_error_code(dacp, err) { \
dac_lld_stop_conversion(dacp); \
if ((dacp)->grpp->error_cb != NULL) { \
(dacp)->state = DAC_ERROR; \
(dacp)->grpp->error_cb(dacp, err); \
if ((dacp)->state == DAC_ERROR) \
(dacp)->state = DAC_READY; \
} \
(dacp)->grpp = NULL; \
_dac_timeout_isr(dacp); \
}
/** @} */
/*===========================================================================*/
/* External declarations. */
/*===========================================================================*/
#ifdef __cplusplus
extern "C" {
#endif
void dacInit(void);
void dacObjectInit(DACDriver *dacp);
msg_t dacStart(DACDriver *dacp, const DACConfig *config);
void dacStop(DACDriver *dacp);
void dacPutChannelX(DACDriver *dacp,
dacchannel_t channel,
dacsample_t sample);
void dacStartConversion(DACDriver *dacp, const DACConversionGroup *grpp,
dacsample_t *samples, size_t depth);
void dacStartConversionI(DACDriver *dacp, const DACConversionGroup *grpp,
dacsample_t *samples, size_t depth);
void dacStopConversion(DACDriver *dacp);
void dacStopConversionI(DACDriver *dacp);
#if DAC_USE_WAIT
msg_t dacConvert(DACDriver *dacp, const DACConversionGroup *grpp,
dacsample_t *samples, size_t depth);
#endif
#if DAC_USE_MUTUAL_EXCLUSION
void dacAcquireBus(DACDriver *dacp);
void dacReleaseBus(DACDriver *dacp);
#endif
#ifdef __cplusplus
}
#endif
#endif /* HAL_USE_DAC == TRUE */
#endif /* HAL_DAC_H */
/** @} */
/*
ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
/**
* @file hal_dac.h
* @brief DAC Driver macros and structures.
*
* @addtogroup DAC
* @{
*/
#ifndef HAL_DAC_H
#define HAL_DAC_H
#if (HAL_USE_DAC == TRUE) || defined(__DOXYGEN__)
/*===========================================================================*/
/* Driver constants. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver pre-compile time settings. */
/*===========================================================================*/
/**
* @name DAC configuration options
* @{
*/
/**
* @brief Support for thread synchronization API.
*/
#if !defined(DAC_USE_SYNCHRONIZATION) || defined(__DOXYGEN__)
#if !defined(DAC_USE_WAIT) || defined(__DOXYGEN__)
#define DAC_USE_SYNCHRONIZATION FALSE
#else
#define DAC_USE_SYNCHRONIZATION DAC_USE_WAIT
#endif
#endif
/**
* @brief Enables the @p dacAcquireBus() and @p dacReleaseBus() APIs.
* @note Disabling this option saves both code and data space.
*/
#if !defined(DAC_USE_MUTUAL_EXCLUSION) || defined(__DOXYGEN__)
#define DAC_USE_MUTUAL_EXCLUSION TRUE
#endif
/** @} */
/*===========================================================================*/
/* Derived constants and error checks. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver data structures and types. */
/*===========================================================================*/
/**
* @brief Driver state machine possible states.
*/
typedef enum {
DAC_UNINIT = 0, /**< Not initialized. */
DAC_STOP = 1, /**< Stopped. */
DAC_READY = 2, /**< Ready. */
DAC_ACTIVE = 3, /**< Exchanging data. */
DAC_COMPLETE = 4, /**< Asynchronous operation complete. */
DAC_ERROR = 5 /**< Error. */
} dacstate_t;
/**
* @brief Type of a structure representing an DAC driver.
*/
typedef struct hal_dac_driver DACDriver;
/**
* @brief Type of a structure representing an DAC driver configuration.
*/
typedef struct hal_dac_config DACConfig;
/**
* @brief Type of a DAC conversion group.
*/
typedef struct hal_dac_conversion_group DACConversionGroup;
/* Including the low level driver header, it exports information required
for completing types.*/
#include "hal_dac_lld.h"
/**
* @brief DAC notification callback type.
*
* @param[in] dacp pointer to the @p DACDriver object triggering the
*/
typedef void (*daccallback_t)(DACDriver *dacp);
/**
* @brief DAC error callback type.
*
* @param[in] dacp pointer to the @p DACDriver object triggering the
* callback
* @param[in] err DAC error code
*/
typedef void (*dacerrorcallback_t)(DACDriver *dacp, dacerror_t err);
/**
* @brief DAC Conversion group structure.
*/
struct hal_dac_conversion_group {
/**
* @brief Number of DAC channels.
*/
uint32_t num_channels;
/**
* @brief Operation complete callback or @p NULL.
*/
daccallback_t end_cb;
/**
* @brief Error handling callback or @p NULL.
*/
dacerrorcallback_t error_cb;
/* End of the mandatory fields.*/
dac_lld_conversion_group_fields;
};
/**
* @brief Driver configuration structure.
*/
struct hal_dac_config {
/* End of the mandatory fields.*/
dac_lld_config_fields;
};
/**
* @brief Structure representing a DAC driver.
*/
struct hal_dac_driver {
/**
* @brief Driver state.
*/
dacstate_t state;
/**
* @brief Conversion group.
*/
const DACConversionGroup *grpp;
/**
* @brief Samples buffer pointer.
*/
dacsample_t *samples;
/**
* @brief Samples buffer size.
*/
size_t depth;
/**
* @brief Current configuration data.
*/
const DACConfig *config;
#if (DAC_USE_SYNCHRONIZATION == TRUE) || defined(__DOXYGEN__)
/**
* @brief Waiting thread.
*/
thread_reference_t thread;
#endif /* DAC_USE_SYNCHRONIZATION */
#if (DAC_USE_MUTUAL_EXCLUSION == TRUE) || defined(__DOXYGEN__)
/**
* @brief Mutex protecting the bus.
*/
mutex_t mutex;
#endif /* DAC_USE_MUTUAL_EXCLUSION */
#if defined(DAC_DRIVER_EXT_FIELDS)
DAC_DRIVER_EXT_FIELDS
#endif
/* End of the mandatory fields.*/
dac_lld_driver_fields;
};
/*===========================================================================*/
/* Driver macros. */
/*===========================================================================*/
/**
* @name Low level driver helper macros
* @{
*/
/**
* @brief Buffer state.
* @note This function is meant to be called from the DAC callback only.
*
* @param[in] dacp pointer to the @p DACDriver object
* @return The buffer state.
* @retval false if the driver filled/sent the first half of the
* buffer.
* @retval true if the driver filled/sent the second half of the
* buffer.
*
* @special
*/
#define dacIsBufferComplete(dacp) ((bool)((dacp)->state == DAC_COMPLETE))
#if (DAC_USE_SYNCHRONIZATION == TRUE) || defined(__DOXYGEN__)
/**
* @brief Waits for operation completion.
* @details This function waits for the driver to complete the current
* operation.
* @pre An operation must be running while the function is invoked.
* @note No more than one thread can wait on a DAC driver using
* this function.
*
* @param[in] dacp pointer to the @p DACDriver object
*
* @notapi
*/
#define _dac_wait_s(dacp) osalThreadSuspendS(&(dacp)->thread)
/**
* @brief Resumes a thread waiting for a conversion completion.
*
* @param[in] dacp pointer to the @p DACDriver object
*
* @notapi
*/
#define _dac_reset_i(dacp) osalThreadResumeI(&(dacp)->thread, MSG_RESET)
/**
* @brief Resumes a thread waiting for a conversion completion.
*
* @param[in] dacp pointer to the @p DACDriver object
*
* @notapi
*/
#define _dac_reset_s(dacp) osalThreadResumeS(&(dacp)->thread, MSG_RESET)
/**
* @brief Wakes up the waiting thread.
*
* @param[in] dacp pointer to the @p DACDriver object
*
* @notapi
*/
#define _dac_wakeup_isr(dacp) { \
osalSysLockFromISR(); \
osalThreadResumeI(&(dacp)->thread, MSG_OK); \
osalSysUnlockFromISR(); \
}
/**
* @brief Wakes up the waiting thread with a timeout message.
*
* @param[in] dacp pointer to the @p DACDriver object
*
* @notapi
*/
#define _dac_timeout_isr(dacp) { \
osalSysLockFromISR(); \
osalThreadResumeI(&(dacp)->thread, MSG_TIMEOUT); \
osalSysUnlockFromISR(); \
}
#else /* !DAC_USE_SYNCHRONIZATION */
#define _dac_wait_s(dacp)
#define _dac_reset_i(dacp)
#define _dac_reset_s(dacp)
#define _dac_wakeup_isr(dacp)
#define _dac_timeout_isr(dacp)
#endif /* !DAC_USE_SYNCHRONIZATION */
/**
* @brief Common ISR code, half buffer event.
* @details This code handles the portable part of the ISR code:
* - Callback invocation.
* .
* @note This macro is meant to be used in the low level drivers
* implementation only.
*
* @param[in] dacp pointer to the @p DACDriver object
*
* @notapi
*/
#define _dac_isr_half_code(dacp) { \
if ((dacp)->grpp->end_cb != NULL) { \
(dacp)->grpp->end_cb(dacp); \
} \
}
/**
* @brief Common ISR code, full buffer event.
* @details This code handles the portable part of the ISR code:
* - Callback invocation.
* - Driver state transitions.
* .
* @note This macro is meant to be used in the low level drivers
* implementation only.
*
* @param[in] dacp pointer to the @p DACDriver object
*
* @notapi
*/
#define _dac_isr_full_code(dacp) { \
if ((dacp)->grpp->end_cb) { \
(dacp)->state = DAC_COMPLETE; \
(dacp)->grpp->end_cb(dacp); \
if ((dacp)->state == DAC_COMPLETE) \
(dacp)->state = DAC_ACTIVE; \
} \
_dac_wakeup_isr(dacp); \
}
/**
* @brief Common ISR code, error event.
* @details This code handles the portable part of the ISR code:
* - Callback invocation.
* - Waiting thread timeout signalling, if any.
* - Driver state transitions.
* .
* @note This macro is meant to be used in the low level drivers
* implementation only.
*
* @param[in] dacp pointer to the @p DACDriver object
* @param[in] err platform dependent error code
*
* @notapi
*/
#define _dac_isr_error_code(dacp, err) { \
dac_lld_stop_conversion(dacp); \
if ((dacp)->grpp->error_cb != NULL) { \
(dacp)->state = DAC_ERROR; \
(dacp)->grpp->error_cb(dacp, err); \
if ((dacp)->state == DAC_ERROR) \
(dacp)->state = DAC_READY; \
} \
(dacp)->grpp = NULL; \
_dac_timeout_isr(dacp); \
}
/** @} */
/*===========================================================================*/
/* External declarations. */
/*===========================================================================*/
#ifdef __cplusplus
extern "C" {
#endif
void dacInit(void);
void dacObjectInit(DACDriver *dacp);
msg_t dacStart(DACDriver *dacp, const DACConfig *config);
void dacStop(DACDriver *dacp);
void dacPutChannelX(DACDriver *dacp,
dacchannel_t channel,
dacsample_t sample);
void dacStartConversion(DACDriver *dacp, const DACConversionGroup *grpp,
dacsample_t *samples, size_t depth);
void dacStartConversionI(DACDriver *dacp, const DACConversionGroup *grpp,
dacsample_t *samples, size_t depth);
void dacStopConversion(DACDriver *dacp);
void dacStopConversionI(DACDriver *dacp);
#if DAC_USE_SYNCHRONIZATION
msg_t dacConvert(DACDriver *dacp, const DACConversionGroup *grpp,
dacsample_t *samples, size_t depth);
msg_t dacSynchronizeS(DACDriver *dacp, sysinterval_t timeout);
msg_t dacSynchronize(DACDriver *dacp, sysinterval_t timeout);
#endif /* DAC_USE_SYNCHRONIZATION */
#if DAC_USE_MUTUAL_EXCLUSION
void dacAcquireBus(DACDriver *dacp);
void dacReleaseBus(DACDriver *dacp);
#endif
#ifdef __cplusplus
}
#endif
#endif /* HAL_USE_DAC == TRUE */
#endif /* HAL_DAC_H */
/** @} */

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,365 +1,422 @@
/*
ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
/**
* @file hal_dac.c
* @brief DAC Driver code.
*
* @addtogroup DAC
* @{
*/
#include "hal.h"
#if (HAL_USE_DAC == TRUE) || defined(__DOXYGEN__)
/*===========================================================================*/
/* Driver local definitions. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver exported variables. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver local variables. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver local functions. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver exported functions. */
/*===========================================================================*/
/**
* @brief DAC Driver initialization.
* @note This function is implicitly invoked by @p halInit(), there is
* no need to explicitly initialize the driver.
*
* @init
*/
void dacInit(void) {
dac_lld_init();
}
/**
* @brief Initializes the standard part of a @p DACDriver structure.
*
* @param[out] dacp pointer to the @p DACDriver object
*
* @init
*/
void dacObjectInit(DACDriver *dacp) {
dacp->state = DAC_STOP;
dacp->config = NULL;
#if DAC_USE_WAIT
dacp->thread = NULL;
#endif
#if DAC_USE_MUTUAL_EXCLUSION
osalMutexObjectInit(&dacp->mutex);
#endif
#if defined(DAC_DRIVER_EXT_INIT_HOOK)
DAC_DRIVER_EXT_INIT_HOOK(dacp);
#endif
}
/**
* @brief Configures and activates the DAC peripheral.
*
* @param[in] dacp pointer to the @p DACDriver object
* @param[in] config pointer to the @p DACConfig object, it can be
* @p NULL if the low level driver implementation
* supports a default configuration
* @return The operation status.
*
* @api
*/
msg_t dacStart(DACDriver *dacp, const DACConfig *config) {
msg_t msg;
osalDbgCheck(dacp != NULL);
osalSysLock();
osalDbgAssert((dacp->state == DAC_STOP) || (dacp->state == DAC_READY),
"invalid state");
dacp->config = config;
#if defined(DAC_LLD_ENHANCED_API)
msg = dac_lld_start(dacp);
#else
dac_lld_start(dacp);
msg = HAL_RET_SUCCESS;
#endif
if (msg == HAL_RET_SUCCESS) {
dacp->state = DAC_READY;
}
else {
dacp->state = DAC_STOP;
}
osalSysUnlock();
return msg;
}
/**
* @brief Deactivates the DAC peripheral.
* @note Deactivating the peripheral also enforces a release of the slave
* select line.
*
* @param[in] dacp pointer to the @p DACDriver object
*
* @api
*/
void dacStop(DACDriver *dacp) {
osalDbgCheck(dacp != NULL);
osalSysLock();
osalDbgAssert((dacp->state == DAC_STOP) || (dacp->state == DAC_READY),
"invalid state");
dac_lld_stop(dacp);
dacp->config = NULL;
dacp->state = DAC_STOP;
osalSysUnlock();
}
/**
* @brief Outputs a value directly on a DAC channel.
*
* @param[in] dacp pointer to the @p DACDriver object
* @param[in] channel DAC channel number
* @param[in] sample value to be output
*
* @xclass
*/
void dacPutChannelX(DACDriver *dacp, dacchannel_t channel, dacsample_t sample) {
osalDbgCheck(channel < (dacchannel_t)DAC_MAX_CHANNELS);
osalDbgAssert(dacp->state == DAC_READY, "invalid state");
dac_lld_put_channel(dacp, channel, sample);
}
/**
* @brief Starts a DAC conversion.
* @details Starts an asynchronous conversion operation.
* @note The buffer is organized as a matrix of M*N elements where M is the
* channels number configured into the conversion group and N is the
* buffer depth. The samples are sequentially written into the buffer
* with no gaps.
*
* @param[in] dacp pointer to the @p DACDriver object
* @param[in] grpp pointer to a @p DACConversionGroup object
* @param[in] samples pointer to the samples buffer
* @param[in] depth buffer depth (matrix rows number). The buffer depth
* must be one or an even number.
*
* @api
*/
void dacStartConversion(DACDriver *dacp,
const DACConversionGroup *grpp,
dacsample_t *samples,
size_t depth) {
osalSysLock();
dacStartConversionI(dacp, grpp, samples, depth);
osalSysUnlock();
}
/**
* @brief Starts a DAC conversion.
* @details Starts an asynchronous conversion operation.
* @post The callbacks associated to the conversion group will be invoked
* on buffer fill and error events.
* @note The buffer is organized as a matrix of M*N elements where M is the
* channels number configured into the conversion group and N is the
* buffer depth. The samples are sequentially written into the buffer
* with no gaps.
*
* @param[in] dacp pointer to the @p DACDriver object
* @param[in] grpp pointer to a @p DACConversionGroup object
* @param[in] samples pointer to the samples buffer
* @param[in] depth buffer depth (matrix rows number). The buffer depth
* must be one or an even number.
*
* @iclass
*/
void dacStartConversionI(DACDriver *dacp,
const DACConversionGroup *grpp,
dacsample_t *samples,
size_t depth) {
osalDbgCheckClassI();
osalDbgCheck((dacp != NULL) && (grpp != NULL) && (samples != NULL) &&
((depth == 1U) || ((depth & 1U) == 0U)));
osalDbgAssert((dacp->state == DAC_READY) ||
(dacp->state == DAC_COMPLETE) ||
(dacp->state == DAC_ERROR),
"not ready");
dacp->samples = samples;
dacp->depth = depth;
dacp->grpp = grpp;
dacp->state = DAC_ACTIVE;
dac_lld_start_conversion(dacp);
}
/**
* @brief Stops an ongoing conversion.
* @details This function stops the currently ongoing conversion and returns
* the driver in the @p DAC_READY state. If there was no conversion
* being processed then the function does nothing.
*
* @param[in] dacp pointer to the @p DACDriver object
*
* @api
*/
void dacStopConversion(DACDriver *dacp) {
osalDbgCheck(dacp != NULL);
osalSysLock();
osalDbgAssert((dacp->state == DAC_READY) ||
(dacp->state == DAC_ACTIVE),
"invalid state");
if (dacp->state != DAC_READY) {
dac_lld_stop_conversion(dacp);
dacp->grpp = NULL;
dacp->state = DAC_READY;
_dac_reset_s(dacp);
}
osalSysUnlock();
}
/**
* @brief Stops an ongoing conversion.
* @details This function stops the currently ongoing conversion and returns
* the driver in the @p DAC_READY state. If there was no conversion
* being processed then the function does nothing.
*
* @param[in] dacp pointer to the @p DACDriver object
*
* @iclass
*/
void dacStopConversionI(DACDriver *dacp) {
osalDbgCheckClassI();
osalDbgCheck(dacp != NULL);
osalDbgAssert((dacp->state == DAC_READY) ||
(dacp->state == DAC_ACTIVE) ||
(dacp->state == DAC_COMPLETE),
"invalid state");
if (dacp->state != DAC_READY) {
dac_lld_stop_conversion(dacp);
dacp->grpp = NULL;
dacp->state = DAC_READY;
_dac_reset_i(dacp);
}
}
#if (DAC_USE_WAIT == TRUE) || defined(__DOXYGEN__)
/**
* @brief Performs a DAC conversion.
* @details Performs a synchronous conversion operation.
* @note The buffer is organized as a matrix of M*N elements where M is the
* channels number configured into the conversion group and N is the
* buffer depth. The samples are sequentially written into the buffer
* with no gaps.
*
* @param[in] dacp pointer to the @p DACDriver object
* @param[in] grpp pointer to a @p DACConversionGroup object
* @param[out] samples pointer to the samples buffer
* @param[in] depth buffer depth (matrix rows number). The buffer depth
* must be one or an even number.
* @return The operation result.
* @retval MSG_OK Conversion finished.
* @retval MSG_RESET The conversion has been stopped using
* @p acdStopConversion() or @p acdStopConversionI(),
* the result buffer may contain incorrect data.
* @retval MSG_TIMEOUT The conversion has been stopped because an hardware
* error.
*
* @api
*/
msg_t dacConvert(DACDriver *dacp,
const DACConversionGroup *grpp,
dacsample_t *samples,
size_t depth) {
msg_t msg;
osalSysLock();
dacStartConversionI(dacp, grpp, samples, depth);
msg = osalThreadSuspendS(&dacp->thread);
osalSysUnlock();
return msg;
}
#endif /* DAC_USE_WAIT == TRUE */
#if (DAC_USE_MUTUAL_EXCLUSION == TRUE) || defined(__DOXYGEN__)
/**
* @brief Gains exclusive access to the DAC bus.
* @details This function tries to gain ownership to the DAC bus, if the bus
* is already being used then the invoking thread is queued.
* @pre In order to use this function the option @p DAC_USE_MUTUAL_EXCLUSION
* must be enabled.
*
* @param[in] dacp pointer to the @p DACDriver object
*
* @api
*/
void dacAcquireBus(DACDriver *dacp) {
osalDbgCheck(dacp != NULL);
osalMutexLock(&dacp->mutex);
}
/**
* @brief Releases exclusive access to the DAC bus.
* @pre In order to use this function the option @p DAC_USE_MUTUAL_EXCLUSION
* must be enabled.
*
* @param[in] dacp pointer to the @p DACDriver object
*
* @api
*/
void dacReleaseBus(DACDriver *dacp) {
osalDbgCheck(dacp != NULL);
osalMutexUnlock(&dacp->mutex);
}
#endif /* DAC_USE_MUTUAL_EXCLUSION == TRUE */
#endif /* HAL_USE_DAC == TRUE */
/** @} */
/*
ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
/**
* @file hal_dac.c
* @brief DAC Driver code.
*
* @addtogroup DAC
* @{
*/
#include "hal.h"
#if (HAL_USE_DAC == TRUE) || defined(__DOXYGEN__)
/*===========================================================================*/
/* Driver local definitions. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver exported variables. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver local variables. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver local functions. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver exported functions. */
/*===========================================================================*/
/**
* @brief DAC Driver initialization.
* @note This function is implicitly invoked by @p halInit(), there is
* no need to explicitly initialize the driver.
*
* @init
*/
void dacInit(void) {
dac_lld_init();
}
/**
* @brief Initializes the standard part of a @p DACDriver structure.
*
* @param[out] dacp pointer to the @p DACDriver object
*
* @init
*/
void dacObjectInit(DACDriver *dacp) {
dacp->state = DAC_STOP;
dacp->config = NULL;
#if DAC_USE_WAIT
dacp->thread = NULL;
#endif
#if DAC_USE_MUTUAL_EXCLUSION
osalMutexObjectInit(&dacp->mutex);
#endif
#if defined(DAC_DRIVER_EXT_INIT_HOOK)
DAC_DRIVER_EXT_INIT_HOOK(dacp);
#endif
}
/**
* @brief Configures and activates the DAC peripheral.
*
* @param[in] dacp pointer to the @p DACDriver object
* @param[in] config pointer to the @p DACConfig object, it can be
* @p NULL if the low level driver implementation
* supports a default configuration
* @return The operation status.
*
* @api
*/
msg_t dacStart(DACDriver *dacp, const DACConfig *config) {
msg_t msg;
osalDbgCheck(dacp != NULL);
osalSysLock();
osalDbgAssert((dacp->state == DAC_STOP) || (dacp->state == DAC_READY),
"invalid state");
dacp->config = config;
#if defined(DAC_LLD_ENHANCED_API)
msg = dac_lld_start(dacp);
#else
dac_lld_start(dacp);
msg = HAL_RET_SUCCESS;
#endif
if (msg == HAL_RET_SUCCESS) {
dacp->state = DAC_READY;
}
else {
dacp->state = DAC_STOP;
}
osalSysUnlock();
return msg;
}
/**
* @brief Deactivates the DAC peripheral.
* @note Deactivating the peripheral also enforces a release of the slave
* select line.
*
* @param[in] dacp pointer to the @p DACDriver object
*
* @api
*/
void dacStop(DACDriver *dacp) {
osalDbgCheck(dacp != NULL);
osalSysLock();
osalDbgAssert((dacp->state == DAC_STOP) || (dacp->state == DAC_READY),
"invalid state");
dac_lld_stop(dacp);
dacp->config = NULL;
dacp->state = DAC_STOP;
osalSysUnlock();
}
/**
* @brief Outputs a value directly on a DAC channel.
*
* @param[in] dacp pointer to the @p DACDriver object
* @param[in] channel DAC channel number
* @param[in] sample value to be output
*
* @xclass
*/
void dacPutChannelX(DACDriver *dacp, dacchannel_t channel, dacsample_t sample) {
osalDbgCheck(channel < (dacchannel_t)DAC_MAX_CHANNELS);
osalDbgAssert(dacp->state == DAC_READY || dacp->state == DAC_ACTIVE,
"invalid state");
dac_lld_put_channel(dacp, channel, sample);
}
/**
* @brief Starts a DAC conversion.
* @details Starts an asynchronous conversion operation.
* @note The buffer is organized as a matrix of M*N elements where M is the
* channels number configured into the conversion group and N is the
* buffer depth. The samples are sequentially written into the buffer
* with no gaps.
*
* @param[in] dacp pointer to the @p DACDriver object
* @param[in] grpp pointer to a @p DACConversionGroup object
* @param[in] samples pointer to the samples buffer
* @param[in] depth buffer depth (matrix rows number). The buffer depth
* must be one or an even number.
*
* @api
*/
void dacStartConversion(DACDriver *dacp,
const DACConversionGroup *grpp,
dacsample_t *samples,
size_t depth) {
osalSysLock();
dacStartConversionI(dacp, grpp, samples, depth);
osalSysUnlock();
}
/**
* @brief Starts a DAC conversion.
* @details Starts an asynchronous conversion operation.
* @post The callbacks associated to the conversion group will be invoked
* on buffer complete and error events.
* @note The buffer is organized as a matrix of M*N elements where M is the
* channels number configured into the conversion group and N is the
* buffer depth. The samples are sequentially organised in the buffer
* with no gaps.
*
* @param[in] dacp pointer to the @p DACDriver object
* @param[in] grpp pointer to a @p DACConversionGroup object
* @param[in] samples pointer to the samples buffer
* @param[in] depth buffer depth (matrix rows number). The buffer depth
* must be one or an even number.
*
* @iclass
*/
void dacStartConversionI(DACDriver *dacp,
const DACConversionGroup *grpp,
dacsample_t *samples,
size_t depth) {
osalDbgCheckClassI();
osalDbgCheck((dacp != NULL) && (grpp != NULL) && (samples != NULL) &&
((depth == 1U) || ((depth & 1U) == 0U)));
osalDbgAssert((dacp->state == DAC_READY) ||
(dacp->state == DAC_COMPLETE) ||
(dacp->state == DAC_ERROR),
"not ready");
dacp->samples = samples;
dacp->depth = depth;
dacp->grpp = grpp;
dacp->state = DAC_ACTIVE;
dac_lld_start_conversion(dacp);
}
/**
* @brief Stops an ongoing conversion.
* @details This function stops the currently ongoing conversion and returns
* the driver in the @p DAC_READY state. If there was no conversion
* being processed then the function does nothing.
*
* @param[in] dacp pointer to the @p DACDriver object
*
* @api
*/
void dacStopConversion(DACDriver *dacp) {
osalDbgCheck(dacp != NULL);
osalSysLock();
osalDbgAssert((dacp->state == DAC_READY) ||
(dacp->state == DAC_ACTIVE),
"invalid state");
if (dacp->state != DAC_READY) {
dac_lld_stop_conversion(dacp);
dacp->grpp = NULL;
dacp->state = DAC_READY;
_dac_reset_s(dacp);
}
osalSysUnlock();
}
/**
* @brief Stops an ongoing conversion.
* @details This function stops the currently ongoing conversion and returns
* the driver in the @p DAC_READY state. If there was no conversion
* being processed then the function does nothing.
*
* @param[in] dacp pointer to the @p DACDriver object
*
* @iclass
*/
void dacStopConversionI(DACDriver *dacp) {
osalDbgCheckClassI();
osalDbgCheck(dacp != NULL);
osalDbgAssert((dacp->state == DAC_READY) ||
(dacp->state == DAC_ACTIVE) ||
(dacp->state == DAC_COMPLETE),
"invalid state");
if (dacp->state != DAC_READY) {
dac_lld_stop_conversion(dacp);
dacp->grpp = NULL;
dacp->state = DAC_READY;
_dac_reset_i(dacp);
}
}
#if (DAC_USE_SYNCHRONIZATION == TRUE) || defined(__DOXYGEN__)
/**
* @brief Performs a DAC conversion.
* @details Performs a synchronous conversion operation.
* @note The buffer is organized as a matrix of M*N elements where M is the
* channels number configured into the conversion group and N is the
* buffer depth. The samples are sequentially organised in the buffer
* with no gaps.
*
* @param[in] dacp pointer to the @p DACDriver object
* @param[in] grpp pointer to a @p DACConversionGroup object
* @param[in] samples pointer to the samples buffer
* @param[in] depth buffer depth (matrix rows number). The buffer depth
* must be one or an even number.
*
* @return The operation result.
* @retval MSG_OK Conversion finished.
* @retval MSG_RESET The conversion has been stopped using
* @p dacStopConversion() or @p dacStopConversionI().
* @retval MSG_TIMEOUT The conversion has been stopped because an hardware
* error.
*
* @api
*/
msg_t dacConvert(DACDriver *dacp,
const DACConversionGroup *grpp,
dacsample_t *samples,
size_t depth) {
msg_t msg;
osalSysLock();
dacStartConversionI(dacp, grpp, samples, depth);
msg = osalThreadSuspendS(&dacp->thread);
osalSysUnlock();
return msg;
}
/**
* @brief Synchronize to a conversion completion.
* @note This function can only be called by a single thread at time.
*
* @param[in] dacp pointer to the @p DACDriver object
* @param[in] timeout wait timeout
*
* @return The wait result.
* @retval MSG_OK if operation completed without errors.
* @retval MSG_TIMEOUT if synchronization request timed out.
* @retval MSG_RESET if the conversion has been stopped.
*
* @sclass
*/
msg_t dacSynchronizeS(DACDriver *dacp, sysinterval_t timeout) {
msg_t msg;
osalDbgCheckClassS();
osalDbgCheck(dacp != NULL);
osalDbgAssert((dacp->state == DAC_ACTIVE) || (dacp->state == DAC_READY),
"invalid state");
if (dacp->state == DAC_ACTIVE) {
msg = osalThreadSuspendTimeoutS(&dacp->thread, timeout);
}
else {
msg = MSG_OK;
}
return msg;
}
/**
* @brief Synchronize to a conversion completion.
* @note This function can only be called by a single thread at time.
*
* @param[in] dacp pointer to the @p DACDriver object
* @param[in] timeout wait timeout
*
* @return The wait result.
* @retval MSG_OK if operation completed without errors.
* @retval MSG_TIMEOUT if synchronization request timed out.
* @retval MSG_RESET if the conversion has been stopped.
*
* @api
*/
msg_t dacSynchronize(DACDriver *dacp, sysinterval_t timeout) {
msg_t msg;
osalSysLock();
msg = dacSynchronizeS(dacp, timeout);
osalSysUnlock();
return msg;
}
#endif /* DAC_USE_SYNCHRONIZATION == TRUE */
#if (DAC_USE_MUTUAL_EXCLUSION == TRUE) || defined(__DOXYGEN__)
/**
* @brief Gains exclusive access to the DAC bus.
* @details This function tries to gain ownership to the DAC bus, if the bus
* is already being used then the invoking thread is queued.
* @pre In order to use this function the option @p DAC_USE_MUTUAL_EXCLUSION
* must be enabled.
*
* @param[in] dacp pointer to the @p DACDriver object
*
* @api
*/
void dacAcquireBus(DACDriver *dacp) {
osalDbgCheck(dacp != NULL);
osalMutexLock(&dacp->mutex);
}
/**
* @brief Releases exclusive access to the DAC bus.
* @pre In order to use this function the option @p DAC_USE_MUTUAL_EXCLUSION
* must be enabled.
*
* @param[in] dacp pointer to the @p DACDriver object
*
* @api
*/
void dacReleaseBus(DACDriver *dacp) {
osalDbgCheck(dacp != NULL);
osalMutexUnlock(&dacp->mutex);
}
#endif /* DAC_USE_MUTUAL_EXCLUSION == TRUE */
#endif /* HAL_USE_DAC == TRUE */
/** @} */

View File

@ -74,6 +74,7 @@
*****************************************************************************
*** Next ***
- NEW: Improved DAC driver, updated STM32 DACv1.
- NEW: STM32 RTCv2 and RTCv3 modified to not use shadow registers.
- NEW: Enhanced STM32F7xx MPU configuration in mcuconf.h.
- NEW: I2C slave support in HAL high level driver.