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 ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio
Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.
You may obtain a copy of the License at You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0 http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS, distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and See the License for the specific language governing permissions and
limitations under the License. limitations under the License.
*/ */
/** /**
* @file hal_dac.h * @file hal_dac.h
* @brief DAC Driver macros and structures. * @brief DAC Driver macros and structures.
* *
* @addtogroup DAC * @addtogroup DAC
* @{ * @{
*/ */
#ifndef HAL_DAC_H #ifndef HAL_DAC_H
#define HAL_DAC_H #define HAL_DAC_H
#if (HAL_USE_DAC == TRUE) || defined(__DOXYGEN__) #if (HAL_USE_DAC == TRUE) || defined(__DOXYGEN__)
/*===========================================================================*/ /*===========================================================================*/
/* Driver constants. */ /* Driver constants. */
/*===========================================================================*/ /*===========================================================================*/
/*===========================================================================*/ /*===========================================================================*/
/* Driver pre-compile time settings. */ /* Driver pre-compile time settings. */
/*===========================================================================*/ /*===========================================================================*/
/** /**
* @name DAC configuration options * @name DAC configuration options
* @{ * @{
*/ */
/** /**
* @brief Enables synchronous APIs. * @brief Support for thread synchronization API.
* @note Disabling this option saves both code and data space. */
*/ #if !defined(DAC_USE_SYNCHRONIZATION) || defined(__DOXYGEN__)
#if !defined(DAC_USE_WAIT) || defined(__DOXYGEN__) #if !defined(DAC_USE_WAIT) || defined(__DOXYGEN__)
#define DAC_USE_WAIT TRUE #define DAC_USE_SYNCHRONIZATION FALSE
#endif #else
#define DAC_USE_SYNCHRONIZATION DAC_USE_WAIT
/** #endif
* @brief Enables the @p dacAcquireBus() and @p dacReleaseBus() APIs. #endif
* @note Disabling this option saves both code and data space.
*/ /**
#if !defined(DAC_USE_MUTUAL_EXCLUSION) || defined(__DOXYGEN__) * @brief Enables the @p dacAcquireBus() and @p dacReleaseBus() APIs.
#define DAC_USE_MUTUAL_EXCLUSION TRUE * @note Disabling this option saves both code and data space.
#endif */
/** @} */ #if !defined(DAC_USE_MUTUAL_EXCLUSION) || defined(__DOXYGEN__)
#define DAC_USE_MUTUAL_EXCLUSION TRUE
/*===========================================================================*/ #endif
/* Derived constants and error checks. */ /** @} */
/*===========================================================================*/
/*===========================================================================*/
/*===========================================================================*/ /* Derived constants and error checks. */
/* Driver data structures and types. */ /*===========================================================================*/
/*===========================================================================*/
/*===========================================================================*/
/** /* Driver data structures and types. */
* @brief Driver state machine possible states. /*===========================================================================*/
*/
typedef enum { /**
DAC_UNINIT = 0, /**< Not initialized. */ * @brief Driver state machine possible states.
DAC_STOP = 1, /**< Stopped. */ */
DAC_READY = 2, /**< Ready. */ typedef enum {
DAC_ACTIVE = 3, /**< Exchanging data. */ DAC_UNINIT = 0, /**< Not initialized. */
DAC_COMPLETE = 4, /**< Asynchronous operation complete. */ DAC_STOP = 1, /**< Stopped. */
DAC_ERROR = 5 /**< Error. */ DAC_READY = 2, /**< Ready. */
} dacstate_t; DAC_ACTIVE = 3, /**< Exchanging data. */
DAC_COMPLETE = 4, /**< Asynchronous operation complete. */
/** DAC_ERROR = 5 /**< Error. */
* @brief Type of a structure representing an DAC driver. } dacstate_t;
*/
typedef struct hal_dac_driver DACDriver; /**
* @brief Type of a structure representing an DAC driver.
/** */
* @brief Type of a structure representing an DAC driver configuration. typedef struct hal_dac_driver DACDriver;
*/
typedef struct hal_dac_config DACConfig; /**
* @brief Type of a structure representing an DAC driver configuration.
/** */
* @brief Type of a DAC conversion group. typedef struct hal_dac_config DACConfig;
*/
typedef struct hal_dac_conversion_group DACConversionGroup; /**
* @brief Type of a DAC conversion group.
/* Including the low level driver header, it exports information required */
for completing types.*/ typedef struct hal_dac_conversion_group DACConversionGroup;
#include "hal_dac_lld.h"
/* Including the low level driver header, it exports information required
/** for completing types.*/
* @brief DAC notification callback type. #include "hal_dac_lld.h"
*
* @param[in] dacp pointer to the @p DACDriver object triggering the /**
*/ * @brief DAC notification callback type.
typedef void (*daccallback_t)(DACDriver *dacp); *
* @param[in] dacp pointer to the @p DACDriver object triggering the
/** */
* @brief DAC error callback type. typedef void (*daccallback_t)(DACDriver *dacp);
*
* @param[in] dacp pointer to the @p DACDriver object triggering the /**
* callback * @brief DAC error callback type.
* @param[in] err DAC error code *
*/ * @param[in] dacp pointer to the @p DACDriver object triggering the
typedef void (*dacerrorcallback_t)(DACDriver *dacp, dacerror_t err); * callback
* @param[in] err DAC error code
/** */
* @brief DAC Conversion group structure. typedef void (*dacerrorcallback_t)(DACDriver *dacp, dacerror_t err);
*/
struct hal_dac_conversion_group { /**
/** * @brief DAC Conversion group structure.
* @brief Number of DAC channels. */
*/ struct hal_dac_conversion_group {
uint32_t num_channels; /**
/** * @brief Number of DAC channels.
* @brief Operation complete callback or @p NULL. */
*/ uint32_t num_channels;
daccallback_t end_cb; /**
/** * @brief Operation complete callback or @p NULL.
* @brief Error handling callback or @p NULL. */
*/ daccallback_t end_cb;
dacerrorcallback_t error_cb; /**
/* End of the mandatory fields.*/ * @brief Error handling callback or @p NULL.
dac_lld_conversion_group_fields; */
}; 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.*/ * @brief Driver configuration structure.
dac_lld_config_fields; */
}; struct hal_dac_config {
/* End of the mandatory fields.*/
/** dac_lld_config_fields;
* @brief Structure representing a DAC driver. };
*/
struct hal_dac_driver { /**
/** * @brief Structure representing a DAC driver.
* @brief Driver state. */
*/ struct hal_dac_driver {
dacstate_t state; /**
/** * @brief Driver state.
* @brief Conversion group. */
*/ dacstate_t state;
const DACConversionGroup *grpp; /**
/** * @brief Conversion group.
* @brief Samples buffer pointer. */
*/ const DACConversionGroup *grpp;
dacsample_t *samples; /**
/** * @brief Samples buffer pointer.
* @brief Samples buffer size. */
*/ dacsample_t *samples;
size_t depth; /**
/** * @brief Samples buffer size.
* @brief Current configuration data. */
*/ size_t depth;
const DACConfig *config; /**
#if (DAC_USE_WAIT == TRUE) || defined(__DOXYGEN__) * @brief Current configuration data.
/** */
* @brief Waiting thread. const DACConfig *config;
*/ #if (DAC_USE_SYNCHRONIZATION == TRUE) || defined(__DOXYGEN__)
thread_reference_t thread; /**
#endif /* DAC_USE_WAIT */ * @brief Waiting thread.
#if (DAC_USE_MUTUAL_EXCLUSION == TRUE) || defined(__DOXYGEN__) */
/** thread_reference_t thread;
* @brief Mutex protecting the bus. #endif /* DAC_USE_SYNCHRONIZATION */
*/ #if (DAC_USE_MUTUAL_EXCLUSION == TRUE) || defined(__DOXYGEN__)
mutex_t mutex; /**
#endif /* DAC_USE_MUTUAL_EXCLUSION */ * @brief Mutex protecting the bus.
#if defined(DAC_DRIVER_EXT_FIELDS) */
DAC_DRIVER_EXT_FIELDS mutex_t mutex;
#endif #endif /* DAC_USE_MUTUAL_EXCLUSION */
/* End of the mandatory fields.*/ #if defined(DAC_DRIVER_EXT_FIELDS)
dac_lld_driver_fields; DAC_DRIVER_EXT_FIELDS
}; #endif
/* End of the mandatory fields.*/
/*===========================================================================*/ dac_lld_driver_fields;
/* Driver macros. */ };
/*===========================================================================*/
/*===========================================================================*/
/** /* Driver macros. */
* @name Low level driver helper 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 * @brief Buffer state.
* @return The buffer state. * @note This function is meant to be called from the DAC callback only.
* @retval false if the driver filled/sent the first half of the *
* buffer. * @param[in] dacp pointer to the @p DACDriver object
* @retval true if the driver filled/sent the second half of the * @return The buffer state.
* buffer. * @retval false if the driver filled/sent the first half of the
* * buffer.
* @special * @retval true if the driver filled/sent the second half of the
*/ * buffer.
#define dacIsBufferComplete(dacp) ((bool)((dacp)->state == DAC_COMPLETE)) *
* @special
#if (DAC_USE_WAIT == TRUE) || defined(__DOXYGEN__) */
/** #define dacIsBufferComplete(dacp) ((bool)((dacp)->state == DAC_COMPLETE))
* @brief Waits for operation completion.
* @details This function waits for the driver to complete the current #if (DAC_USE_SYNCHRONIZATION == TRUE) || defined(__DOXYGEN__)
* operation. /**
* @pre An operation must be running while the function is invoked. * @brief Waits for operation completion.
* @note No more than one thread can wait on a DAC driver using * @details This function waits for the driver to complete the current
* this function. * operation.
* * @pre An operation must be running while the function is invoked.
* @param[in] dacp pointer to the @p DACDriver object * @note No more than one thread can wait on a DAC driver using
* * this function.
* @notapi *
*/ * @param[in] dacp pointer to the @p DACDriver object
#define _dac_wait_s(dacp) osalThreadSuspendS(&(dacp)->thread) *
* @notapi
/** */
* @brief Resumes a thread waiting for a conversion completion. #define _dac_wait_s(dacp) osalThreadSuspendS(&(dacp)->thread)
*
* @param[in] dacp pointer to the @p DACDriver object /**
* * @brief Resumes a thread waiting for a conversion completion.
* @notapi *
*/ * @param[in] dacp pointer to the @p DACDriver object
#define _dac_reset_i(dacp) osalThreadResumeI(&(dacp)->thread, MSG_RESET) *
* @notapi
/** */
* @brief Resumes a thread waiting for a conversion completion. #define _dac_reset_i(dacp) osalThreadResumeI(&(dacp)->thread, MSG_RESET)
*
* @param[in] dacp pointer to the @p DACDriver object /**
* * @brief Resumes a thread waiting for a conversion completion.
* @notapi *
*/ * @param[in] dacp pointer to the @p DACDriver object
#define _dac_reset_s(dacp) osalThreadResumeS(&(dacp)->thread, MSG_RESET) *
* @notapi
/** */
* @brief Wakes up the waiting thread. #define _dac_reset_s(dacp) osalThreadResumeS(&(dacp)->thread, MSG_RESET)
*
* @param[in] dacp pointer to the @p DACDriver object /**
* * @brief Wakes up the waiting thread.
* @notapi *
*/ * @param[in] dacp pointer to the @p DACDriver object
#define _dac_wakeup_isr(dacp) { \ *
osalSysLockFromISR(); \ * @notapi
osalThreadResumeI(&(dacp)->thread, MSG_OK); \ */
osalSysUnlockFromISR(); \ #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 /**
* * @brief Wakes up the waiting thread with a timeout message.
* @notapi *
*/ * @param[in] dacp pointer to the @p DACDriver object
#define _dac_timeout_isr(dacp) { \ *
osalSysLockFromISR(); \ * @notapi
osalThreadResumeI(&(dacp)->thread, MSG_TIMEOUT); \ */
osalSysUnlockFromISR(); \ #define _dac_timeout_isr(dacp) { \
} osalSysLockFromISR(); \
osalThreadResumeI(&(dacp)->thread, MSG_TIMEOUT); \
#else /* !DAC_USE_WAIT */ osalSysUnlockFromISR(); \
#define _dac_wait_s(dacp) }
#define _dac_reset_i(dacp)
#define _dac_reset_s(dacp) #else /* !DAC_USE_SYNCHRONIZATION */
#define _dac_wakeup_isr(dacp) #define _dac_wait_s(dacp)
#define _dac_timeout_isr(dacp) #define _dac_reset_i(dacp)
#endif /* !DAC_USE_WAIT */ #define _dac_reset_s(dacp)
#define _dac_wakeup_isr(dacp)
/** #define _dac_timeout_isr(dacp)
* @brief Common ISR code, half buffer event. #endif /* !DAC_USE_SYNCHRONIZATION */
* @details This code handles the portable part of the ISR code:
* - Callback invocation. /**
* . * @brief Common ISR code, half buffer event.
* @note This macro is meant to be used in the low level drivers * @details This code handles the portable part of the ISR code:
* implementation only. * - Callback invocation.
* * .
* @param[in] dacp pointer to the @p DACDriver object * @note This macro is meant to be used in the low level drivers
* * implementation only.
* @notapi *
*/ * @param[in] dacp pointer to the @p DACDriver object
#define _dac_isr_half_code(dacp) { \ *
if ((dacp)->grpp->end_cb != NULL) { \ * @notapi
(dacp)->grpp->end_cb(dacp); \ */
} \ #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. * @brief Common ISR code, full buffer event.
* . * @details This code handles the portable part of the ISR code:
* @note This macro is meant to be used in the low level drivers * - Callback invocation.
* implementation only. * - Driver state transitions.
* * .
* @param[in] dacp pointer to the @p DACDriver object * @note This macro is meant to be used in the low level drivers
* * implementation only.
* @notapi *
*/ * @param[in] dacp pointer to the @p DACDriver object
#define _dac_isr_full_code(dacp) { \ *
if ((dacp)->grpp->end_cb) { \ * @notapi
(dacp)->state = DAC_COMPLETE; \ */
(dacp)->grpp->end_cb(dacp); \ #define _dac_isr_full_code(dacp) { \
if ((dacp)->state == DAC_COMPLETE) \ if ((dacp)->grpp->end_cb) { \
(dacp)->state = DAC_ACTIVE; \ (dacp)->state = DAC_COMPLETE; \
} \ (dacp)->grpp->end_cb(dacp); \
} if ((dacp)->state == DAC_COMPLETE) \
(dacp)->state = DAC_ACTIVE; \
/** } \
* @brief Common ISR code, error event. _dac_wakeup_isr(dacp); \
* @details This code handles the portable part of the ISR code: }
* - Callback invocation.
* - Waiting thread timeout signaling, if any. /**
* - Driver state transitions. * @brief Common ISR code, error event.
* . * @details This code handles the portable part of the ISR code:
* @note This macro is meant to be used in the low level drivers * - Callback invocation.
* implementation only. * - Waiting thread timeout signalling, if any.
* * - Driver state transitions.
* @param[in] dacp pointer to the @p DACDriver object * .
* @param[in] err platform dependent error code * @note This macro is meant to be used in the low level drivers
* * implementation only.
* @notapi *
*/ * @param[in] dacp pointer to the @p DACDriver object
#define _dac_isr_error_code(dacp, err) { \ * @param[in] err platform dependent error code
dac_lld_stop_conversion(dacp); \ *
if ((dacp)->grpp->error_cb != NULL) { \ * @notapi
(dacp)->state = DAC_ERROR; \ */
(dacp)->grpp->error_cb(dacp, err); \ #define _dac_isr_error_code(dacp, err) { \
if ((dacp)->state == DAC_ERROR) \ dac_lld_stop_conversion(dacp); \
(dacp)->state = DAC_READY; \ if ((dacp)->grpp->error_cb != NULL) { \
} \ (dacp)->state = DAC_ERROR; \
(dacp)->grpp = NULL; \ (dacp)->grpp->error_cb(dacp, err); \
_dac_timeout_isr(dacp); \ if ((dacp)->state == DAC_ERROR) \
} (dacp)->state = DAC_READY; \
/** @} */ } \
(dacp)->grpp = NULL; \
/*===========================================================================*/ _dac_timeout_isr(dacp); \
/* External declarations. */ }
/*===========================================================================*/ /** @} */
#ifdef __cplusplus /*===========================================================================*/
extern "C" { /* External declarations. */
#endif /*===========================================================================*/
void dacInit(void);
void dacObjectInit(DACDriver *dacp); #ifdef __cplusplus
msg_t dacStart(DACDriver *dacp, const DACConfig *config); extern "C" {
void dacStop(DACDriver *dacp); #endif
void dacPutChannelX(DACDriver *dacp, void dacInit(void);
dacchannel_t channel, void dacObjectInit(DACDriver *dacp);
dacsample_t sample); msg_t dacStart(DACDriver *dacp, const DACConfig *config);
void dacStartConversion(DACDriver *dacp, const DACConversionGroup *grpp, void dacStop(DACDriver *dacp);
dacsample_t *samples, size_t depth); void dacPutChannelX(DACDriver *dacp,
void dacStartConversionI(DACDriver *dacp, const DACConversionGroup *grpp, dacchannel_t channel,
dacsample_t *samples, size_t depth); dacsample_t sample);
void dacStopConversion(DACDriver *dacp); void dacStartConversion(DACDriver *dacp, const DACConversionGroup *grpp,
void dacStopConversionI(DACDriver *dacp); dacsample_t *samples, size_t depth);
#if DAC_USE_WAIT void dacStartConversionI(DACDriver *dacp, const DACConversionGroup *grpp,
msg_t dacConvert(DACDriver *dacp, const DACConversionGroup *grpp, dacsample_t *samples, size_t depth);
dacsample_t *samples, size_t depth); void dacStopConversion(DACDriver *dacp);
#endif void dacStopConversionI(DACDriver *dacp);
#if DAC_USE_MUTUAL_EXCLUSION #if DAC_USE_SYNCHRONIZATION
void dacAcquireBus(DACDriver *dacp); msg_t dacConvert(DACDriver *dacp, const DACConversionGroup *grpp,
void dacReleaseBus(DACDriver *dacp); dacsample_t *samples, size_t depth);
#endif msg_t dacSynchronizeS(DACDriver *dacp, sysinterval_t timeout);
#ifdef __cplusplus msg_t dacSynchronize(DACDriver *dacp, sysinterval_t timeout);
} #endif /* DAC_USE_SYNCHRONIZATION */
#endif #if DAC_USE_MUTUAL_EXCLUSION
void dacAcquireBus(DACDriver *dacp);
#endif /* HAL_USE_DAC == TRUE */ void dacReleaseBus(DACDriver *dacp);
#endif
#endif /* HAL_DAC_H */ #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 ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio
Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.
You may obtain a copy of the License at You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0 http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS, distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and See the License for the specific language governing permissions and
limitations under the License. limitations under the License.
*/ */
/** /**
* @file hal_dac.c * @file hal_dac.c
* @brief DAC Driver code. * @brief DAC Driver code.
* *
* @addtogroup DAC * @addtogroup DAC
* @{ * @{
*/ */
#include "hal.h" #include "hal.h"
#if (HAL_USE_DAC == TRUE) || defined(__DOXYGEN__) #if (HAL_USE_DAC == TRUE) || defined(__DOXYGEN__)
/*===========================================================================*/ /*===========================================================================*/
/* Driver local definitions. */ /* Driver local definitions. */
/*===========================================================================*/ /*===========================================================================*/
/*===========================================================================*/ /*===========================================================================*/
/* Driver exported variables. */ /* Driver exported variables. */
/*===========================================================================*/ /*===========================================================================*/
/*===========================================================================*/ /*===========================================================================*/
/* Driver local variables. */ /* Driver local variables. */
/*===========================================================================*/ /*===========================================================================*/
/*===========================================================================*/ /*===========================================================================*/
/* Driver local functions. */ /* Driver local functions. */
/*===========================================================================*/ /*===========================================================================*/
/*===========================================================================*/ /*===========================================================================*/
/* Driver exported functions. */ /* Driver exported functions. */
/*===========================================================================*/ /*===========================================================================*/
/** /**
* @brief DAC Driver initialization. * @brief DAC Driver initialization.
* @note This function is implicitly invoked by @p halInit(), there is * @note This function is implicitly invoked by @p halInit(), there is
* no need to explicitly initialize the driver. * no need to explicitly initialize the driver.
* *
* @init * @init
*/ */
void dacInit(void) { void dacInit(void) {
dac_lld_init(); dac_lld_init();
} }
/** /**
* @brief Initializes the standard part of a @p DACDriver structure. * @brief Initializes the standard part of a @p DACDriver structure.
* *
* @param[out] dacp pointer to the @p DACDriver object * @param[out] dacp pointer to the @p DACDriver object
* *
* @init * @init
*/ */
void dacObjectInit(DACDriver *dacp) { void dacObjectInit(DACDriver *dacp) {
dacp->state = DAC_STOP; dacp->state = DAC_STOP;
dacp->config = NULL; dacp->config = NULL;
#if DAC_USE_WAIT #if DAC_USE_WAIT
dacp->thread = NULL; dacp->thread = NULL;
#endif #endif
#if DAC_USE_MUTUAL_EXCLUSION #if DAC_USE_MUTUAL_EXCLUSION
osalMutexObjectInit(&dacp->mutex); osalMutexObjectInit(&dacp->mutex);
#endif #endif
#if defined(DAC_DRIVER_EXT_INIT_HOOK) #if defined(DAC_DRIVER_EXT_INIT_HOOK)
DAC_DRIVER_EXT_INIT_HOOK(dacp); DAC_DRIVER_EXT_INIT_HOOK(dacp);
#endif #endif
} }
/** /**
* @brief Configures and activates the DAC peripheral. * @brief Configures and activates the DAC peripheral.
* *
* @param[in] dacp pointer to the @p DACDriver object * @param[in] dacp pointer to the @p DACDriver object
* @param[in] config pointer to the @p DACConfig object, it can be * @param[in] config pointer to the @p DACConfig object, it can be
* @p NULL if the low level driver implementation * @p NULL if the low level driver implementation
* supports a default configuration * supports a default configuration
* @return The operation status. * @return The operation status.
* *
* @api * @api
*/ */
msg_t dacStart(DACDriver *dacp, const DACConfig *config) { msg_t dacStart(DACDriver *dacp, const DACConfig *config) {
msg_t msg; msg_t msg;
osalDbgCheck(dacp != NULL); osalDbgCheck(dacp != NULL);
osalSysLock(); osalSysLock();
osalDbgAssert((dacp->state == DAC_STOP) || (dacp->state == DAC_READY), osalDbgAssert((dacp->state == DAC_STOP) || (dacp->state == DAC_READY),
"invalid state"); "invalid state");
dacp->config = config; dacp->config = config;
#if defined(DAC_LLD_ENHANCED_API) #if defined(DAC_LLD_ENHANCED_API)
msg = dac_lld_start(dacp); msg = dac_lld_start(dacp);
#else #else
dac_lld_start(dacp); dac_lld_start(dacp);
msg = HAL_RET_SUCCESS; msg = HAL_RET_SUCCESS;
#endif #endif
if (msg == HAL_RET_SUCCESS) { if (msg == HAL_RET_SUCCESS) {
dacp->state = DAC_READY; dacp->state = DAC_READY;
} }
else { else {
dacp->state = DAC_STOP; dacp->state = DAC_STOP;
} }
osalSysUnlock(); osalSysUnlock();
return msg; return msg;
} }
/** /**
* @brief Deactivates the DAC peripheral. * @brief Deactivates the DAC peripheral.
* @note Deactivating the peripheral also enforces a release of the slave * @note Deactivating the peripheral also enforces a release of the slave
* select line. * select line.
* *
* @param[in] dacp pointer to the @p DACDriver object * @param[in] dacp pointer to the @p DACDriver object
* *
* @api * @api
*/ */
void dacStop(DACDriver *dacp) { void dacStop(DACDriver *dacp) {
osalDbgCheck(dacp != NULL); osalDbgCheck(dacp != NULL);
osalSysLock(); osalSysLock();
osalDbgAssert((dacp->state == DAC_STOP) || (dacp->state == DAC_READY), osalDbgAssert((dacp->state == DAC_STOP) || (dacp->state == DAC_READY),
"invalid state"); "invalid state");
dac_lld_stop(dacp); dac_lld_stop(dacp);
dacp->config = NULL; dacp->config = NULL;
dacp->state = DAC_STOP; dacp->state = DAC_STOP;
osalSysUnlock(); osalSysUnlock();
} }
/** /**
* @brief Outputs a value directly on a DAC channel. * @brief Outputs a value directly on a DAC channel.
* *
* @param[in] dacp pointer to the @p DACDriver object * @param[in] dacp pointer to the @p DACDriver object
* @param[in] channel DAC channel number * @param[in] channel DAC channel number
* @param[in] sample value to be output * @param[in] sample value to be output
* *
* @xclass * @xclass
*/ */
void dacPutChannelX(DACDriver *dacp, dacchannel_t channel, dacsample_t sample) { void dacPutChannelX(DACDriver *dacp, dacchannel_t channel, dacsample_t sample) {
osalDbgCheck(channel < (dacchannel_t)DAC_MAX_CHANNELS); osalDbgCheck(channel < (dacchannel_t)DAC_MAX_CHANNELS);
osalDbgAssert(dacp->state == DAC_READY, "invalid state"); osalDbgAssert(dacp->state == DAC_READY || dacp->state == DAC_ACTIVE,
"invalid state");
dac_lld_put_channel(dacp, channel, sample);
} dac_lld_put_channel(dacp, channel, sample);
}
/**
* @brief Starts a DAC conversion. /**
* @details Starts an asynchronous conversion operation. * @brief Starts a DAC conversion.
* @note The buffer is organized as a matrix of M*N elements where M is the * @details Starts an asynchronous conversion operation.
* channels number configured into the conversion group and N is the * @note The buffer is organized as a matrix of M*N elements where M is the
* buffer depth. The samples are sequentially written into the buffer * channels number configured into the conversion group and N is the
* with no gaps. * 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] dacp pointer to the @p DACDriver object
* @param[in] samples pointer to the samples buffer * @param[in] grpp pointer to a @p DACConversionGroup object
* @param[in] depth buffer depth (matrix rows number). The buffer depth * @param[in] samples pointer to the samples buffer
* must be one or an even number. * @param[in] depth buffer depth (matrix rows number). The buffer depth
* * must be one or an even number.
* @api *
*/ * @api
void dacStartConversion(DACDriver *dacp, */
const DACConversionGroup *grpp, void dacStartConversion(DACDriver *dacp,
dacsample_t *samples, const DACConversionGroup *grpp,
size_t depth) { dacsample_t *samples,
size_t depth) {
osalSysLock();
dacStartConversionI(dacp, grpp, samples, depth); osalSysLock();
osalSysUnlock(); dacStartConversionI(dacp, grpp, samples, depth);
} osalSysUnlock();
}
/**
* @brief Starts a DAC conversion. /**
* @details Starts an asynchronous conversion operation. * @brief Starts a DAC conversion.
* @post The callbacks associated to the conversion group will be invoked * @details Starts an asynchronous conversion operation.
* on buffer fill and error events. * @post The callbacks associated to the conversion group will be invoked
* @note The buffer is organized as a matrix of M*N elements where M is the * on buffer complete and error events.
* channels number configured into the conversion group and N is the * @note The buffer is organized as a matrix of M*N elements where M is the
* buffer depth. The samples are sequentially written into the buffer * channels number configured into the conversion group and N is the
* with no gaps. * 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] dacp pointer to the @p DACDriver object
* @param[in] samples pointer to the samples buffer * @param[in] grpp pointer to a @p DACConversionGroup object
* @param[in] depth buffer depth (matrix rows number). The buffer depth * @param[in] samples pointer to the samples buffer
* must be one or an even number. * @param[in] depth buffer depth (matrix rows number). The buffer depth
* * must be one or an even number.
* @iclass *
*/ * @iclass
void dacStartConversionI(DACDriver *dacp, */
const DACConversionGroup *grpp, void dacStartConversionI(DACDriver *dacp,
dacsample_t *samples, const DACConversionGroup *grpp,
size_t depth) { dacsample_t *samples,
size_t depth) {
osalDbgCheckClassI();
osalDbgCheck((dacp != NULL) && (grpp != NULL) && (samples != NULL) && osalDbgCheckClassI();
((depth == 1U) || ((depth & 1U) == 0U))); osalDbgCheck((dacp != NULL) && (grpp != NULL) && (samples != NULL) &&
osalDbgAssert((dacp->state == DAC_READY) || ((depth == 1U) || ((depth & 1U) == 0U)));
(dacp->state == DAC_COMPLETE) || osalDbgAssert((dacp->state == DAC_READY) ||
(dacp->state == DAC_ERROR), (dacp->state == DAC_COMPLETE) ||
"not ready"); (dacp->state == DAC_ERROR),
"not ready");
dacp->samples = samples;
dacp->depth = depth; dacp->samples = samples;
dacp->grpp = grpp; dacp->depth = depth;
dacp->state = DAC_ACTIVE; dacp->grpp = grpp;
dac_lld_start_conversion(dacp); dacp->state = DAC_ACTIVE;
} dac_lld_start_conversion(dacp);
}
/**
* @brief Stops an ongoing conversion. /**
* @details This function stops the currently ongoing conversion and returns * @brief Stops an ongoing conversion.
* the driver in the @p DAC_READY state. If there was no conversion * @details This function stops the currently ongoing conversion and returns
* being processed then the function does nothing. * 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 *
* * @param[in] dacp pointer to the @p DACDriver object
* @api *
*/ * @api
void dacStopConversion(DACDriver *dacp) { */
void dacStopConversion(DACDriver *dacp) {
osalDbgCheck(dacp != NULL);
osalDbgCheck(dacp != NULL);
osalSysLock();
osalSysLock();
osalDbgAssert((dacp->state == DAC_READY) ||
(dacp->state == DAC_ACTIVE), osalDbgAssert((dacp->state == DAC_READY) ||
"invalid state"); (dacp->state == DAC_ACTIVE),
"invalid state");
if (dacp->state != DAC_READY) {
dac_lld_stop_conversion(dacp); if (dacp->state != DAC_READY) {
dacp->grpp = NULL; dac_lld_stop_conversion(dacp);
dacp->state = DAC_READY; dacp->grpp = NULL;
_dac_reset_s(dacp); dacp->state = DAC_READY;
} _dac_reset_s(dacp);
}
osalSysUnlock();
} osalSysUnlock();
}
/**
* @brief Stops an ongoing conversion. /**
* @details This function stops the currently ongoing conversion and returns * @brief Stops an ongoing conversion.
* the driver in the @p DAC_READY state. If there was no conversion * @details This function stops the currently ongoing conversion and returns
* being processed then the function does nothing. * 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 *
* * @param[in] dacp pointer to the @p DACDriver object
* @iclass *
*/ * @iclass
void dacStopConversionI(DACDriver *dacp) { */
void dacStopConversionI(DACDriver *dacp) {
osalDbgCheckClassI();
osalDbgCheck(dacp != NULL); osalDbgCheckClassI();
osalDbgAssert((dacp->state == DAC_READY) || osalDbgCheck(dacp != NULL);
(dacp->state == DAC_ACTIVE) || osalDbgAssert((dacp->state == DAC_READY) ||
(dacp->state == DAC_COMPLETE), (dacp->state == DAC_ACTIVE) ||
"invalid state"); (dacp->state == DAC_COMPLETE),
"invalid state");
if (dacp->state != DAC_READY) {
dac_lld_stop_conversion(dacp); if (dacp->state != DAC_READY) {
dacp->grpp = NULL; dac_lld_stop_conversion(dacp);
dacp->state = DAC_READY; dacp->grpp = NULL;
_dac_reset_i(dacp); dacp->state = DAC_READY;
} _dac_reset_i(dacp);
} }
}
#if (DAC_USE_WAIT == TRUE) || defined(__DOXYGEN__)
/** #if (DAC_USE_SYNCHRONIZATION == TRUE) || defined(__DOXYGEN__)
* @brief Performs a DAC conversion. /**
* @details Performs a synchronous conversion operation. * @brief Performs a DAC conversion.
* @note The buffer is organized as a matrix of M*N elements where M is the * @details Performs a synchronous conversion operation.
* channels number configured into the conversion group and N is the * @note The buffer is organized as a matrix of M*N elements where M is the
* buffer depth. The samples are sequentially written into the buffer * channels number configured into the conversion group and N is the
* with no gaps. * 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] dacp pointer to the @p DACDriver object
* @param[out] samples pointer to the samples buffer * @param[in] grpp pointer to a @p DACConversionGroup object
* @param[in] depth buffer depth (matrix rows number). The buffer depth * @param[in] samples pointer to the samples buffer
* must be one or an even number. * @param[in] depth buffer depth (matrix rows number). The buffer depth
* @return The operation result. * must be one or an even number.
* @retval MSG_OK Conversion finished. *
* @retval MSG_RESET The conversion has been stopped using * @return The operation result.
* @p acdStopConversion() or @p acdStopConversionI(), * @retval MSG_OK Conversion finished.
* the result buffer may contain incorrect data. * @retval MSG_RESET The conversion has been stopped using
* @retval MSG_TIMEOUT The conversion has been stopped because an hardware * @p dacStopConversion() or @p dacStopConversionI().
* error. * @retval MSG_TIMEOUT The conversion has been stopped because an hardware
* * error.
* @api *
*/ * @api
msg_t dacConvert(DACDriver *dacp, */
const DACConversionGroup *grpp, msg_t dacConvert(DACDriver *dacp,
dacsample_t *samples, const DACConversionGroup *grpp,
size_t depth) { dacsample_t *samples,
msg_t msg; size_t depth) {
msg_t msg;
osalSysLock();
osalSysLock();
dacStartConversionI(dacp, grpp, samples, depth);
msg = osalThreadSuspendS(&dacp->thread); dacStartConversionI(dacp, grpp, samples, depth);
msg = osalThreadSuspendS(&dacp->thread);
osalSysUnlock();
return msg; osalSysUnlock();
} return msg;
#endif /* DAC_USE_WAIT == TRUE */ }
#if (DAC_USE_MUTUAL_EXCLUSION == TRUE) || defined(__DOXYGEN__) /**
/** * @brief Synchronize to a conversion completion.
* @brief Gains exclusive access to the DAC bus. * @note This function can only be called by a single thread at time.
* @details This function tries to gain ownership to the DAC bus, if the bus *
* is already being used then the invoking thread is queued. * @param[in] dacp pointer to the @p DACDriver object
* @pre In order to use this function the option @p DAC_USE_MUTUAL_EXCLUSION * @param[in] timeout wait timeout
* must be enabled. *
* * @return The wait result.
* @param[in] dacp pointer to the @p DACDriver object * @retval MSG_OK if operation completed without errors.
* * @retval MSG_TIMEOUT if synchronization request timed out.
* @api * @retval MSG_RESET if the conversion has been stopped.
*/ *
void dacAcquireBus(DACDriver *dacp) { * @sclass
*/
osalDbgCheck(dacp != NULL); msg_t dacSynchronizeS(DACDriver *dacp, sysinterval_t timeout) {
msg_t msg;
osalMutexLock(&dacp->mutex);
} osalDbgCheckClassS();
osalDbgCheck(dacp != NULL);
/** osalDbgAssert((dacp->state == DAC_ACTIVE) || (dacp->state == DAC_READY),
* @brief Releases exclusive access to the DAC bus. "invalid state");
* @pre In order to use this function the option @p DAC_USE_MUTUAL_EXCLUSION
* must be enabled. if (dacp->state == DAC_ACTIVE) {
* msg = osalThreadSuspendTimeoutS(&dacp->thread, timeout);
* @param[in] dacp pointer to the @p DACDriver object }
* else {
* @api msg = MSG_OK;
*/ }
void dacReleaseBus(DACDriver *dacp) {
return msg;
osalDbgCheck(dacp != NULL); }
osalMutexUnlock(&dacp->mutex); /**
} * @brief Synchronize to a conversion completion.
#endif /* DAC_USE_MUTUAL_EXCLUSION == TRUE */ * @note This function can only be called by a single thread at time.
*
#endif /* HAL_USE_DAC == TRUE */ * @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 *** *** Next ***
- NEW: Improved DAC driver, updated STM32 DACv1.
- NEW: STM32 RTCv2 and RTCv3 modified to not use shadow registers. - NEW: STM32 RTCv2 and RTCv3 modified to not use shadow registers.
- NEW: Enhanced STM32F7xx MPU configuration in mcuconf.h. - NEW: Enhanced STM32F7xx MPU configuration in mcuconf.h.
- NEW: I2C slave support in HAL high level driver. - NEW: I2C slave support in HAL high level driver.