Index: hal/include/hal_dac.h
===================================================================
--- hal/include/hal_dac.h	(revision 16161)
+++ hal/include/hal_dac.h	(working copy)
@@ -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 */
+
+/** @} */
Index: hal/ports/STM32/LLD/DACv1/hal_dac_lld.h
===================================================================
--- hal/ports/STM32/LLD/DACv1/hal_dac_lld.h	(revision 16161)
+++ hal/ports/STM32/LLD/DACv1/hal_dac_lld.h	(working copy)
@@ -1,662 +1,671 @@
-/*
-    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    DACv1/hal_dac_lld.h
- * @brief   STM32 DAC subsystem low level driver header.
- *
- * @addtogroup DAC
- * @{
- */
-
-#ifndef HAL_DAC_LLD_H
-#define HAL_DAC_LLD_H
-
-#if HAL_USE_DAC || defined(__DOXYGEN__)
-
-/*===========================================================================*/
-/* Driver constants.                                                         */
-/*===========================================================================*/
-
-/**
- * @name    DAC trigger modes
- * @{
- */
-#define DAC_TRG_MASK                    7U
-#define DAC_TRG(n)                      (n)
-/** @} */
-
-/*===========================================================================*/
-/* Driver pre-compile time settings.                                         */
-/*===========================================================================*/
-
-/**
- * @name    Configuration options
- * @{
- */
-/**
- * @brief   Enables the DAC dual mode.
- * @note    In dual mode DAC second channels cannot be accessed individually.
- */
-#if !defined(STM32_DAC_DUAL_MODE) || defined(__DOXYGEN__)
-#define STM32_DAC_DUAL_MODE                 FALSE
-#endif
-
-/**
- * @brief   DAC1 CH1 driver enable switch.
- * @details If set to @p TRUE the support for DAC1 channel 1 is included.
- * @note    The default is @p FALSE.
- */
-#if !defined(STM32_DAC_USE_DAC1_CH1) || defined(__DOXYGEN__)
-#define STM32_DAC_USE_DAC1_CH1              FALSE
-#endif
-
-/**
- * @brief   DAC1 CH2 driver enable switch.
- * @details If set to @p TRUE the support for DAC1 channel 2 is included.
- * @note    The default is @p FALSE.
- */
-#if !defined(STM32_DAC_USE_DAC1_CH2) || defined(__DOXYGEN__)
-#define STM32_DAC_USE_DAC1_CH2              FALSE
-#endif
-
-/**
- * @brief   DAC2 CH1 driver enable switch.
- * @details If set to @p TRUE the support for DAC2 channel 1 is included.
- * @note    The default is @p FALSE.
- */
-#if !defined(STM32_DAC_USE_DAC2_CH1) || defined(__DOXYGEN__)
-#define STM32_DAC_USE_DAC2_CH1              FALSE
-#endif
-
-/**
- * @brief   DAC2 CH2 driver enable switch.
- * @details If set to @p TRUE the support for DAC2 channel 2 is included.
- * @note    The default is @p FALSE.
- */
-#if !defined(STM32_DAC_USE_DAC2_CH2) || defined(__DOXYGEN__)
-#define STM32_DAC_USE_DAC2_CH2              FALSE
-#endif
-
-/**
- * @brief   DAC3 CH1 driver enable switch.
- * @details If set to @p TRUE the support for DAC3 channel 1 is included.
- * @note    The default is @p FALSE.
- */
-#if !defined(STM32_DAC_USE_DAC3_CH1) || defined(__DOXYGEN__)
-#define STM32_DAC_USE_DAC3_CH1              FALSE
-#endif
-
-/**
- * @brief   DAC3 CH2 driver enable switch.
- * @details If set to @p TRUE the support for DAC3 channel 2 is included.
- * @note    The default is @p FALSE.
- */
-#if !defined(STM32_DAC_USE_DAC3_CH2) || defined(__DOXYGEN__)
-#define STM32_DAC_USE_DAC3_CH2              FALSE
-#endif
-
-/**
- * @brief   DAC4 CH1 driver enable switch.
- * @details If set to @p TRUE the support for DAC4 channel 1 is included.
- * @note    The default is @p FALSE.
- */
-#if !defined(STM32_DAC_USE_DAC4_CH1) || defined(__DOXYGEN__)
-#define STM32_DAC_USE_DAC4_CH1              FALSE
-#endif
-
-/**
- * @brief   DAC4 CH2 driver enable switch.
- * @details If set to @p TRUE the support for DAC4 channel 2 is included.
- * @note    The default is @p FALSE.
- */
-#if !defined(STM32_DAC_USE_DAC4_CH2) || defined(__DOXYGEN__)
-#define STM32_DAC_USE_DAC4_CH2              FALSE
-#endif
-
-/**
- * @brief   DAC1 CH1 interrupt priority level setting.
- */
-#if !defined(STM32_DAC_DAC1_CH1_IRQ_PRIORITY) || defined(__DOXYGEN__)
-#define STM32_DAC_DAC1_CH1_IRQ_PRIORITY     10
-#endif
-
-/**
- * @brief   DAC1 CH2 interrupt priority level setting.
- */
-#if !defined(STM32_DAC_DAC1_CH2_IRQ_PRIORITY) || defined(__DOXYGEN__)
-#define STM32_DAC_DAC1_CH2_IRQ_PRIORITY     10
-#endif
-
-/**
- * @brief   DAC2 CH1 interrupt priority level setting.
- */
-#if !defined(STM32_DAC_DAC2_CH1_IRQ_PRIORITY) || defined(__DOXYGEN__)
-#define STM32_DAC_DAC2_CH1_IRQ_PRIORITY     10
-#endif
-
-/**
- * @brief   DAC2 CH2 interrupt priority level setting.
- */
-#if !defined(STM32_DAC_DAC2_CH2_IRQ_PRIORITY) || defined(__DOXYGEN__)
-#define STM32_DAC_DAC2_CH2_IRQ_PRIORITY     10
-#endif
-
-/**
- * @brief   DAC3 CH1 interrupt priority level setting.
- */
-#if !defined(STM32_DAC_DAC3_CH1_IRQ_PRIORITY) || defined(__DOXYGEN__)
-#define STM32_DAC_DAC3_CH1_IRQ_PRIORITY     10
-#endif
-
-/**
- * @brief   DAC3 CH2 interrupt priority level setting.
- */
-#if !defined(STM32_DAC_DAC3_CH2_IRQ_PRIORITY) || defined(__DOXYGEN__)
-#define STM32_DAC_DAC3_CH2_IRQ_PRIORITY     10
-#endif
-
-/**
- * @brief   DAC4 CH1 interrupt priority level setting.
- */
-#if !defined(STM32_DAC_DAC4_CH1_IRQ_PRIORITY) || defined(__DOXYGEN__)
-#define STM32_DAC_DAC4_CH1_IRQ_PRIORITY     10
-#endif
-
-/**
- * @brief   DAC4 CH2 interrupt priority level setting.
- */
-#if !defined(STM32_DAC_DAC4_CH2_IRQ_PRIORITY) || defined(__DOXYGEN__)
-#define STM32_DAC_DAC4_CH2_IRQ_PRIORITY     10
-#endif
-
-/**
- * @brief   DAC1 CH1 DMA priority (0..3|lowest..highest).
- */
-#if !defined(STM32_DAC_DAC1_CH1_DMA_PRIORITY) || defined(__DOXYGEN__)
-#define STM32_DAC_DAC1_CH1_DMA_PRIORITY     2
-#endif
-
-/**
- * @brief   DAC1 CH2 DMA priority (0..3|lowest..highest).
- */
-#if !defined(STM32_DAC_DAC1_CH2_DMA_PRIORITY) || defined(__DOXYGEN__)
-#define STM32_DAC_DAC1_CH2_DMA_PRIORITY     2
-#endif
-
-/**
- * @brief   DAC2 CH1 DMA priority (0..3|lowest..highest).
- */
-#if !defined(STM32_DAC_DAC2_CH1_DMA_PRIORITY) || defined(__DOXYGEN__)
-#define STM32_DAC_DAC2_CH1_DMA_PRIORITY     2
-#endif
-
-/**
- * @brief   DAC2 CH2 DMA priority (0..3|lowest..highest).
- */
-#if !defined(STM32_DAC_DAC2_CH2_DMA_PRIORITY) || defined(__DOXYGEN__)
-#define STM32_DAC_DAC2_CH2_DMA_PRIORITY     2
-#endif
-
-/**
- * @brief   DAC3 CH1 DMA priority (0..3|lowest..highest).
- */
-#if !defined(STM32_DAC_DAC3_CH1_DMA_PRIORITY) || defined(__DOXYGEN__)
-#define STM32_DAC_DAC3_CH1_DMA_PRIORITY     2
-#endif
-
-/**
- * @brief   DAC3 CH2 DMA priority (0..3|lowest..highest).
- */
-#if !defined(STM32_DAC_DAC3_CH2_DMA_PRIORITY) || defined(__DOXYGEN__)
-#define STM32_DAC_DAC3_CH2_DMA_PRIORITY     2
-#endif
-
-/**
- * @brief   DAC4 CH1 DMA priority (0..3|lowest..highest).
- */
-#if !defined(STM32_DAC_DAC4_CH1_DMA_PRIORITY) || defined(__DOXYGEN__)
-#define STM32_DAC_DAC4_CH1_DMA_PRIORITY     2
-#endif
-
-/**
- * @brief   DAC4 CH2 DMA priority (0..3|lowest..highest).
- */
-#if !defined(STM32_DAC_DAC4_CH2_DMA_PRIORITY) || defined(__DOXYGEN__)
-#define STM32_DAC_DAC4_CH2_DMA_PRIORITY     2
-#endif
-/** @} */
-
-/*===========================================================================*/
-/* Derived constants and error checks.                                       */
-/*===========================================================================*/
-
-/* Handling missing registry keys.*/
-#if !defined(STM32_HAS_DAC1_CH1)
-#define STM32_HAS_DAC1_CH1                  FALSE
-#endif
-#if !defined(STM32_HAS_DAC1_CH2)
-#define STM32_HAS_DAC1_CH2                  FALSE
-#endif
-#if !defined(STM32_HAS_DAC2_CH1)
-#define STM32_HAS_DAC2_CH1                  FALSE
-#endif
-#if !defined(STM32_HAS_DAC2_CH2)
-#define STM32_HAS_DAC2_CH2                  FALSE
-#endif
-#if !defined(STM32_HAS_DAC3_CH1)
-#define STM32_HAS_DAC3_CH1                  FALSE
-#endif
-#if !defined(STM32_HAS_DAC3_CH2)
-#define STM32_HAS_DAC3_CH2                  FALSE
-#endif
-#if !defined(STM32_HAS_DAC4_CH1)
-#define STM32_HAS_DAC4_CH1                  FALSE
-#endif
-#if !defined(STM32_HAS_DAC4_CH2)
-#define STM32_HAS_DAC4_CH2                  FALSE
-#endif
-
-#if STM32_DAC_USE_DAC1_CH1 && !STM32_HAS_DAC1_CH1
-#error "DAC1 CH1 not present in the selected device"
-#endif
-
-#if STM32_DAC_USE_DAC1_CH2 && !STM32_HAS_DAC1_CH2
-#error "DAC1 CH2 not present in the selected device"
-#endif
-
-#if STM32_DAC_USE_DAC2_CH1 && !STM32_HAS_DAC2_CH1
-#error "DAC2 CH1 not present in the selected device"
-#endif
-
-#if STM32_DAC_USE_DAC2_CH2 && !STM32_HAS_DAC2_CH2
-#error "DAC2 CH2 not present in the selected device"
-#endif
-
-#if STM32_DAC_USE_DAC3_CH1 && !STM32_HAS_DAC3_CH1
-#error "DAC3 CH1 not present in the selected device"
-#endif
-
-#if STM32_DAC_USE_DAC3_CH2 && !STM32_HAS_DAC3_CH2
-#error "DAC3 CH2 not present in the selected device"
-#endif
-
-#if STM32_DAC_USE_DAC4_CH1 && !STM32_HAS_DAC4_CH1
-#error "DAC4 CH1 not present in the selected device"
-#endif
-
-#if STM32_DAC_USE_DAC4_CH2 && !STM32_HAS_DAC4_CH2
-#error "DAC4 CH2 not present in the selected device"
-#endif
-
-#if (STM32_DAC_USE_DAC1_CH2 || STM32_DAC_USE_DAC2_CH2 ||                    \
-     STM32_DAC_USE_DAC3_CH2 || STM32_DAC_USE_DAC4_CH2) && STM32_DAC_DUAL_MODE
-#error "DACx CH2 cannot be used independently in dual mode"
-#endif
-
-#if !STM32_DAC_USE_DAC1_CH1 && !STM32_DAC_USE_DAC1_CH2 &&                   \
-    !STM32_DAC_USE_DAC2_CH1 && !STM32_DAC_USE_DAC2_CH2 &&                   \
-    !STM32_DAC_USE_DAC3_CH1 && !STM32_DAC_USE_DAC3_CH2 &&                   \
-    !STM32_DAC_USE_DAC4_CH1 && !STM32_DAC_USE_DAC4_CH2
-#error "DAC driver activated but no DAC peripheral assigned"
-#endif
-
-#if STM32_DAC_USE_DAC1_CH1 &&                                               \
-    !OSAL_IRQ_IS_VALID_PRIORITY(STM32_DAC_DAC1_CH1_IRQ_PRIORITY)
-#error "Invalid IRQ priority assigned to DAC1 CH1"
-#endif
-
-#if STM32_DAC_USE_DAC1_CH2 &&                                               \
-    !OSAL_IRQ_IS_VALID_PRIORITY(STM32_DAC_DAC1_CH2_IRQ_PRIORITY)
-#error "Invalid IRQ priority assigned to DAC1 CH2"
-#endif
-
-#if STM32_DAC_USE_DAC2_CH1 &&                                               \
-    !OSAL_IRQ_IS_VALID_PRIORITY(STM32_DAC_DAC2_CH1_IRQ_PRIORITY)
-#error "Invalid IRQ priority assigned to DAC2 CH1"
-#endif
-
-#if STM32_DAC_USE_DAC2_CH2 &&                                               \
-    !OSAL_IRQ_IS_VALID_PRIORITY(STM32_DAC_DAC2_CH2_IRQ_PRIORITY)
-#error "Invalid IRQ priority assigned to DAC2 CH2"
-#endif
-
-#if STM32_DAC_USE_DAC3_CH1 &&                                               \
-    !OSAL_IRQ_IS_VALID_PRIORITY(STM32_DAC_DAC3_CH1_IRQ_PRIORITY)
-#error "Invalid IRQ priority assigned to DAC3 CH1"
-#endif
-
-#if STM32_DAC_USE_DAC3_CH2 &&                                               \
-    !OSAL_IRQ_IS_VALID_PRIORITY(STM32_DAC_DAC3_CH2_IRQ_PRIORITY)
-#error "Invalid IRQ priority assigned to DAC3 CH2"
-#endif
-
-#if STM32_DAC_USE_DAC4_CH1 &&                                               \
-    !OSAL_IRQ_IS_VALID_PRIORITY(STM32_DAC_DAC4_CH1_IRQ_PRIORITY)
-#error "Invalid IRQ priority assigned to DAC4 CH1"
-#endif
-
-#if STM32_DAC_USE_DAC4_CH2 &&                                               \
-    !OSAL_IRQ_IS_VALID_PRIORITY(STM32_DAC_DAC4_CH2_IRQ_PRIORITY)
-#error "Invalid IRQ priority assigned to DAC4 CH2"
-#endif
-
-/* The following checks are only required when there is a DMA able to
-   reassign streams to different channels.*/
-#if STM32_ADVANCED_DMA
-
-/* Check on the presence of the DMA streams settings in mcuconf.h.*/
-#if STM32_DAC_USE_DAC1_CH1 && !defined(STM32_DAC_DAC1_CH1_DMA_STREAM)
-#error "DAC1 CH1 DMA stream not defined"
-#endif
-
-#if STM32_DAC_USE_DAC1_CH2 && !defined(STM32_DAC_DAC1_CH2_DMA_STREAM)
-#error "DAC1 CH2 DMA stream not defined"
-#endif
-
-#if STM32_DAC_USE_DAC2_CH1 && !defined(STM32_DAC_DAC2_CH1_DMA_STREAM)
-#error "DAC2 CH1 DMA stream not defined"
-#endif
-
-#if STM32_DAC_USE_DAC2_CH2 && !defined(STM32_DAC_DAC2_CH2_DMA_STREAM)
-#error "DAC2 CH2 DMA stream not defined"
-#endif
-
-#if STM32_DAC_USE_DAC3_CH1 && !defined(STM32_DAC_DAC3_CH1_DMA_STREAM)
-#error "DAC3 CH1 DMA stream not defined"
-#endif
-
-#if STM32_DAC_USE_DAC3_CH2 && !defined(STM32_DAC_DAC3_CH2_DMA_STREAM)
-#error "DAC3 CH2 DMA stream not defined"
-#endif
-
-#if STM32_DAC_USE_DAC4_CH1 && !defined(STM32_DAC_DAC4_CH1_DMA_STREAM)
-#error "DAC4 CH1 DMA stream not defined"
-#endif
-
-#if STM32_DAC_USE_DAC4_CH2 && !defined(STM32_DAC_DAC4_CH2_DMA_STREAM)
-#error "DAC4 CH2 DMA stream not defined"
-#endif
-
-#if STM32_DMA_SUPPORTS_DMAMUX
-
-#else /* !STM32_DMA_SUPPORTS_DMAMUX */
-
-/* Check on the validity of the assigned DMA streams.*/
-#if STM32_DAC_USE_DAC1_CH1 &&                                               \
-    !STM32_DMA_IS_VALID_ID(STM32_DAC_DAC1_CH1_DMA_STREAM, STM32_DAC1_CH1_DMA_MSK)
-#error "invalid DMA stream associated to DAC1 CH1"
-#endif
-
-#if STM32_DAC_USE_DAC1_CH2 &&                                               \
-    !STM32_DMA_IS_VALID_ID(STM32_DAC_DAC1_CH2_DMA_STREAM, STM32_DAC1_CH2_DMA_MSK)
-#error "invalid DMA stream associated to DAC1 CH2"
-#endif
-
-#if STM32_DAC_USE_DAC2_CH1 &&                                               \
-    !STM32_DMA_IS_VALID_ID(STM32_DAC_DAC2_CH1_DMA_STREAM, STM32_DAC2_CH1_DMA_MSK)
-#error "invalid DMA stream associated to DAC2 CH1"
-#endif
-
-#if STM32_DAC_USE_DAC2_CH2 &&                                               \
-    !STM32_DMA_IS_VALID_ID(STM32_DAC_DAC2_CH2_DMA_STREAM, STM32_DAC2_CH2_DMA_MSK)
-#error "invalid DMA stream associated to DAC2 CH2"
-#endif
-
-#if STM32_DAC_USE_DAC3_CH1 &&                                               \
-    !STM32_DMA_IS_VALID_ID(STM32_DAC_DAC3_CH1_DMA_STREAM, STM32_DAC3_CH1_DMA_MSK)
-#error "invalid DMA stream associated to DAC1 CH1"
-#endif
-
-#if STM32_DAC_USE_DAC3_CH2 &&                                               \
-    !STM32_DMA_IS_VALID_ID(STM32_DAC_DAC3_CH2_DMA_STREAM, STM32_DAC3_CH2_DMA_MSK)
-#error "invalid DMA stream associated to DAC1 CH2"
-#endif
-
-#if STM32_DAC_USE_DAC4_CH1 &&                                               \
-    !STM32_DMA_IS_VALID_ID(STM32_DAC_DAC4_CH1_DMA_STREAM, STM32_DAC4_CH1_DMA_MSK)
-#error "invalid DMA stream associated to DAC2 CH1"
-#endif
-
-#if STM32_DAC_USE_DAC4_CH2 &&                                               \
-    !STM32_DMA_IS_VALID_ID(STM32_DAC_DAC4_CH2_DMA_STREAM, STM32_DAC4_CH2_DMA_MSK)
-#error "invalid DMA stream associated to DAC2 CH2"
-#endif
-
-#endif /* !STM32_DMA_SUPPORTS_DMAMUX */
-
-#endif /* STM32_ADVANCED_DMA */
-
-#if STM32_DAC_USE_DAC1_CH1 &&                                               \
-    !STM32_DMA_IS_VALID_PRIORITY(STM32_DAC_DAC1_CH1_DMA_PRIORITY)
-#error "Invalid DMA priority assigned to DAC1 CH1"
-#endif
-
-#if STM32_DAC_USE_DAC1_CH2 &&                                               \
-    !STM32_DMA_IS_VALID_PRIORITY(STM32_DAC_DAC1_CH2_DMA_PRIORITY)
-#error "Invalid DMA priority assigned to DAC1 CH2"
-#endif
-
-#if STM32_DAC_USE_DAC2_CH1 &&                                               \
-    !STM32_DMA_IS_VALID_PRIORITY(STM32_DAC_DAC2_CH1_DMA_PRIORITY)
-#error "Invalid DMA priority assigned to DAC2 CH1"
-#endif
-
-#if STM32_DAC_USE_DAC2_CH2 &&                                               \
-    !STM32_DMA_IS_VALID_PRIORITY(STM32_DAC_DAC2_CH2_DMA_PRIORITY)
-#error "Invalid DMA priority assigned to DAC2 CH2"
-#endif
-
-#if STM32_DAC_USE_DAC3_CH1 &&                                               \
-    !STM32_DMA_IS_VALID_PRIORITY(STM32_DAC_DAC3_CH1_DMA_PRIORITY)
-#error "Invalid DMA priority assigned to DAC3 CH1"
-#endif
-
-#if STM32_DAC_USE_DAC3_CH2 &&                                               \
-    !STM32_DMA_IS_VALID_PRIORITY(STM32_DAC_DAC3_CH2_DMA_PRIORITY)
-#error "Invalid DMA priority assigned to DAC3 CH2"
-#endif
-
-#if STM32_DAC_USE_DAC4_CH1 &&                                               \
-    !STM32_DMA_IS_VALID_PRIORITY(STM32_DAC_DAC4_CH1_DMA_PRIORITY)
-#error "Invalid DMA priority assigned to DAC4 CH1"
-#endif
-
-#if STM32_DAC_USE_DAC4_CH2 &&                                               \
-    !STM32_DMA_IS_VALID_PRIORITY(STM32_DAC_DAC4_CH2_DMA_PRIORITY)
-#error "Invalid DMA priority assigned to DAC4 CH2"
-#endif
-
-#if !defined(STM32_DMA_REQUIRED)
-#define STM32_DMA_REQUIRED
-#endif
-
-/**
- * @brief   Max DAC channels.
- */
-#if STM32_DAC_DUAL_MODE == FALSE
-#define DAC_MAX_CHANNELS                    2
-#else
-#define DAC_MAX_CHANNELS                    1
-#endif
-
-/*===========================================================================*/
-/* Driver data structures and types.                                         */
-/*===========================================================================*/
-
-/**
- * @brief   Type of a DAC channel index.
- */
-typedef uint32_t dacchannel_t;
-
-/**
- * @brief   Type representing a DAC sample.
- */
-typedef uint16_t dacsample_t;
-
-/**
- * @brief   DAC channel parameters type.
- */
-typedef struct {
-  /**
-   * @brief   Pointer to the DAC registers block.
-   */
-  DAC_TypeDef               *dac;
-  /**
-   * @brief   DAC data registers offset.
-   */
-  uint32_t                  dataoffset;
-  /**
-   * @brief   DAC CR register bit offset.
-   */
-  uint32_t                  regshift;
-  /**
-   * @brief   DAC CR register mask.
-   */
-  uint32_t                  regmask;
-  /**
-   * @brief   Associated DMA stream.
-   */
-  uint32_t                  dmastream;
-  /**
-   * @brief   Mode bits for the DMA.
-   */
-  uint32_t                  dmamode;
-  /**
-   * @brief   DMA channel IRQ priority.
-   */
-  uint32_t                  dmairqprio;
-#if (STM32_DMA_SUPPORTS_DMAMUX == TRUE) || defined(__DOXYGEN__)
-  /**
-   * @brief   DMAMUX peripheral selector.
-   */
-  uint32_t                  peripheral;
-#endif
-} dacparams_t;
-
-/**
- * @brief   Possible DAC failure causes.
- * @note    Error codes are architecture dependent and should not relied
- *          upon.
- */
-typedef enum {
-  DAC_ERR_DMAFAILURE = 0,                   /**< DMA operations failure.    */
-  DAC_ERR_UNDERFLOW = 1                     /**< DAC overflow condition.    */
-} dacerror_t;
-
-/**
- * @brief   Samples alignment and size mode.
- */
-typedef enum {
-  DAC_DHRM_12BIT_RIGHT = 0,
-  DAC_DHRM_12BIT_LEFT = 1,
-  DAC_DHRM_8BIT_RIGHT = 2,
-#if STM32_DAC_DUAL_MODE && !defined(__DOXYGEN__)
-  DAC_DHRM_12BIT_RIGHT_DUAL = 3,
-  DAC_DHRM_12BIT_LEFT_DUAL = 4,
-  DAC_DHRM_8BIT_RIGHT_DUAL = 5
-#endif
-} dacdhrmode_t;
-
-/*===========================================================================*/
-/* Driver macros.                                                            */
-/*===========================================================================*/
-
-/**
- * @brief   Low level fields of the DAC driver structure.
- */
-#define dac_lld_driver_fields                                               \
-  /* DAC channel parameters.*/                                              \
-  const dacparams_t         *params;                                        \
-  /* Associated DMA.*/                                                      \
-  const stm32_dma_stream_t  *dma
-
-/**
- * @brief   Low level fields of the DAC configuration structure.
- */
-#define dac_lld_config_fields                                               \
-  /* Initial output on DAC channels.*/                                      \
-  dacsample_t               init;                                           \
-  /* DAC data holding register mode.*/                                      \
-  dacdhrmode_t              datamode;                                       \
-  /* DAC control register lower 16 bits.*/                                  \
-  uint32_t                  cr
-
-/**
- * @brief   Low level fields of the DAC group configuration structure.
- */
-#define dac_lld_conversion_group_fields                                     \
-  /* DAC initialization data. This field contains the (not shifted) value   \
-     to be put into the TSEL field of the DAC CR register during            \
-     initialization. All other fields are handled internally.*/             \
-  uint32_t                  trigger
-
-/*===========================================================================*/
-/* External declarations.                                                    */
-/*===========================================================================*/
-
-#if STM32_DAC_USE_DAC1_CH1 && !defined(__DOXYGEN__)
-extern DACDriver DACD1;
-#endif
-
-#if STM32_DAC_USE_DAC1_CH2 && !STM32_DAC_DUAL_MODE && !defined(__DOXYGEN__)
-extern DACDriver DACD2;
-#endif
-
-#if STM32_DAC_USE_DAC2_CH1 && !defined(__DOXYGEN__)
-extern DACDriver DACD3;
-#endif
-
-#if STM32_DAC_USE_DAC2_CH2 && !STM32_DAC_DUAL_MODE && !defined(__DOXYGEN__)
-extern DACDriver DACD4;
-#endif
-
-#if STM32_DAC_USE_DAC3_CH1 && !defined(__DOXYGEN__)
-extern DACDriver DACD5;
-#endif
-
-#if STM32_DAC_USE_DAC3_CH2 && !STM32_DAC_DUAL_MODE && !defined(__DOXYGEN__)
-extern DACDriver DACD6;
-#endif
-
-#if STM32_DAC_USE_DAC4_CH1 && !defined(__DOXYGEN__)
-extern DACDriver DACD7;
-#endif
-
-#if STM32_DAC_USE_DAC4_CH2 && !STM32_DAC_DUAL_MODE && !defined(__DOXYGEN__)
-extern DACDriver DACD8;
-#endif
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-  void dac_lld_init(void);
-  void dac_lld_start(DACDriver *dacp);
-  void dac_lld_stop(DACDriver *dacp);
-  void dac_lld_put_channel(DACDriver *dacp,
-                           dacchannel_t channel,
-                           dacsample_t sample);
-  void dac_lld_start_conversion(DACDriver *dacp);
-  void dac_lld_stop_conversion(DACDriver *dacp);
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* HAL_USE_DAC */
-
-#endif /* HAL_DAC_LLD_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    DACv1/hal_dac_lld.h
+ * @brief   STM32 DAC subsystem low level driver header.
+ *
+ * @addtogroup DAC
+ * @{
+ */
+
+#ifndef HAL_DAC_LLD_H
+#define HAL_DAC_LLD_H
+
+#if HAL_USE_DAC || defined(__DOXYGEN__)
+
+/*===========================================================================*/
+/* Driver constants.                                                         */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver pre-compile time settings.                                         */
+/*===========================================================================*/
+
+/**
+ * @name    Configuration options
+ * @{
+ */
+/**
+ * @brief   Enables the DAC dual mode.
+ * @note    In dual mode DAC second channels cannot be accessed individually.
+ */
+#if !defined(STM32_DAC_DUAL_MODE) || defined(__DOXYGEN__)
+#define STM32_DAC_DUAL_MODE                 FALSE
+#endif
+
+/**
+ * @brief   DAC1 CH1 driver enable switch.
+ * @details If set to @p TRUE the support for DAC1 channel 1 is included.
+ * @note    The default is @p FALSE.
+ */
+#if !defined(STM32_DAC_USE_DAC1_CH1) || defined(__DOXYGEN__)
+#define STM32_DAC_USE_DAC1_CH1              FALSE
+#endif
+
+/**
+ * @brief   DAC1 CH2 driver enable switch.
+ * @details If set to @p TRUE the support for DAC1 channel 2 is included.
+ * @note    The default is @p FALSE.
+ */
+#if !defined(STM32_DAC_USE_DAC1_CH2) || defined(__DOXYGEN__)
+#define STM32_DAC_USE_DAC1_CH2              FALSE
+#endif
+
+/**
+ * @brief   DAC2 CH1 driver enable switch.
+ * @details If set to @p TRUE the support for DAC2 channel 1 is included.
+ * @note    The default is @p FALSE.
+ */
+#if !defined(STM32_DAC_USE_DAC2_CH1) || defined(__DOXYGEN__)
+#define STM32_DAC_USE_DAC2_CH1              FALSE
+#endif
+
+/**
+ * @brief   DAC2 CH2 driver enable switch.
+ * @details If set to @p TRUE the support for DAC2 channel 2 is included.
+ * @note    The default is @p FALSE.
+ */
+#if !defined(STM32_DAC_USE_DAC2_CH2) || defined(__DOXYGEN__)
+#define STM32_DAC_USE_DAC2_CH2              FALSE
+#endif
+
+/**
+ * @brief   DAC3 CH1 driver enable switch.
+ * @details If set to @p TRUE the support for DAC3 channel 1 is included.
+ * @note    The default is @p FALSE.
+ */
+#if !defined(STM32_DAC_USE_DAC3_CH1) || defined(__DOXYGEN__)
+#define STM32_DAC_USE_DAC3_CH1              FALSE
+#endif
+
+/**
+ * @brief   DAC3 CH2 driver enable switch.
+ * @details If set to @p TRUE the support for DAC3 channel 2 is included.
+ * @note    The default is @p FALSE.
+ */
+#if !defined(STM32_DAC_USE_DAC3_CH2) || defined(__DOXYGEN__)
+#define STM32_DAC_USE_DAC3_CH2              FALSE
+#endif
+
+/**
+ * @brief   DAC4 CH1 driver enable switch.
+ * @details If set to @p TRUE the support for DAC4 channel 1 is included.
+ * @note    The default is @p FALSE.
+ */
+#if !defined(STM32_DAC_USE_DAC4_CH1) || defined(__DOXYGEN__)
+#define STM32_DAC_USE_DAC4_CH1              FALSE
+#endif
+
+/**
+ * @brief   DAC4 CH2 driver enable switch.
+ * @details If set to @p TRUE the support for DAC4 channel 2 is included.
+ * @note    The default is @p FALSE.
+ */
+#if !defined(STM32_DAC_USE_DAC4_CH2) || defined(__DOXYGEN__)
+#define STM32_DAC_USE_DAC4_CH2              FALSE
+#endif
+
+/**
+ * @brief   DAC1 CH1 interrupt priority level setting.
+ */
+#if !defined(STM32_DAC_DAC1_CH1_IRQ_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_DAC_DAC1_CH1_IRQ_PRIORITY     10
+#endif
+
+/**
+ * @brief   DAC1 CH2 interrupt priority level setting.
+ */
+#if !defined(STM32_DAC_DAC1_CH2_IRQ_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_DAC_DAC1_CH2_IRQ_PRIORITY     10
+#endif
+
+/**
+ * @brief   DAC2 CH1 interrupt priority level setting.
+ */
+#if !defined(STM32_DAC_DAC2_CH1_IRQ_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_DAC_DAC2_CH1_IRQ_PRIORITY     10
+#endif
+
+/**
+ * @brief   DAC2 CH2 interrupt priority level setting.
+ */
+#if !defined(STM32_DAC_DAC2_CH2_IRQ_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_DAC_DAC2_CH2_IRQ_PRIORITY     10
+#endif
+
+/**
+ * @brief   DAC3 CH1 interrupt priority level setting.
+ */
+#if !defined(STM32_DAC_DAC3_CH1_IRQ_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_DAC_DAC3_CH1_IRQ_PRIORITY     10
+#endif
+
+/**
+ * @brief   DAC3 CH2 interrupt priority level setting.
+ */
+#if !defined(STM32_DAC_DAC3_CH2_IRQ_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_DAC_DAC3_CH2_IRQ_PRIORITY     10
+#endif
+
+/**
+ * @brief   DAC4 CH1 interrupt priority level setting.
+ */
+#if !defined(STM32_DAC_DAC4_CH1_IRQ_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_DAC_DAC4_CH1_IRQ_PRIORITY     10
+#endif
+
+/**
+ * @brief   DAC4 CH2 interrupt priority level setting.
+ */
+#if !defined(STM32_DAC_DAC4_CH2_IRQ_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_DAC_DAC4_CH2_IRQ_PRIORITY     10
+#endif
+
+/**
+ * @brief   DAC1 CH1 DMA priority (0..3|lowest..highest).
+ */
+#if !defined(STM32_DAC_DAC1_CH1_DMA_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_DAC_DAC1_CH1_DMA_PRIORITY     2
+#endif
+
+/**
+ * @brief   DAC1 CH2 DMA priority (0..3|lowest..highest).
+ */
+#if !defined(STM32_DAC_DAC1_CH2_DMA_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_DAC_DAC1_CH2_DMA_PRIORITY     2
+#endif
+
+/**
+ * @brief   DAC2 CH1 DMA priority (0..3|lowest..highest).
+ */
+#if !defined(STM32_DAC_DAC2_CH1_DMA_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_DAC_DAC2_CH1_DMA_PRIORITY     2
+#endif
+
+/**
+ * @brief   DAC2 CH2 DMA priority (0..3|lowest..highest).
+ */
+#if !defined(STM32_DAC_DAC2_CH2_DMA_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_DAC_DAC2_CH2_DMA_PRIORITY     2
+#endif
+
+/**
+ * @brief   DAC3 CH1 DMA priority (0..3|lowest..highest).
+ */
+#if !defined(STM32_DAC_DAC3_CH1_DMA_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_DAC_DAC3_CH1_DMA_PRIORITY     2
+#endif
+
+/**
+ * @brief   DAC3 CH2 DMA priority (0..3|lowest..highest).
+ */
+#if !defined(STM32_DAC_DAC3_CH2_DMA_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_DAC_DAC3_CH2_DMA_PRIORITY     2
+#endif
+
+/**
+ * @brief   DAC4 CH1 DMA priority (0..3|lowest..highest).
+ */
+#if !defined(STM32_DAC_DAC4_CH1_DMA_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_DAC_DAC4_CH1_DMA_PRIORITY     2
+#endif
+
+/**
+ * @brief   DAC4 CH2 DMA priority (0..3|lowest..highest).
+ */
+#if !defined(STM32_DAC_DAC4_CH2_DMA_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_DAC_DAC4_CH2_DMA_PRIORITY     2
+#endif
+/** @} */
+
+/*===========================================================================*/
+/* Derived constants and error checks.                                       */
+/*===========================================================================*/
+
+/* Handling missing registry keys.*/
+#if !defined(STM32_HAS_DAC1_CH1)
+#define STM32_HAS_DAC1_CH1                  FALSE
+#endif
+#if !defined(STM32_HAS_DAC1_CH2)
+#define STM32_HAS_DAC1_CH2                  FALSE
+#endif
+#if !defined(STM32_HAS_DAC2_CH1)
+#define STM32_HAS_DAC2_CH1                  FALSE
+#endif
+#if !defined(STM32_HAS_DAC2_CH2)
+#define STM32_HAS_DAC2_CH2                  FALSE
+#endif
+#if !defined(STM32_HAS_DAC3_CH1)
+#define STM32_HAS_DAC3_CH1                  FALSE
+#endif
+#if !defined(STM32_HAS_DAC3_CH2)
+#define STM32_HAS_DAC3_CH2                  FALSE
+#endif
+#if !defined(STM32_HAS_DAC4_CH1)
+#define STM32_HAS_DAC4_CH1                  FALSE
+#endif
+#if !defined(STM32_HAS_DAC4_CH2)
+#define STM32_HAS_DAC4_CH2                  FALSE
+#endif
+
+#if STM32_DAC_USE_DAC1_CH1 && !STM32_HAS_DAC1_CH1
+#error "DAC1 CH1 not present in the selected device"
+#endif
+
+#if STM32_DAC_USE_DAC1_CH2 && !STM32_HAS_DAC1_CH2
+#error "DAC1 CH2 not present in the selected device"
+#endif
+
+#if STM32_DAC_USE_DAC2_CH1 && !STM32_HAS_DAC2_CH1
+#error "DAC2 CH1 not present in the selected device"
+#endif
+
+#if STM32_DAC_USE_DAC2_CH2 && !STM32_HAS_DAC2_CH2
+#error "DAC2 CH2 not present in the selected device"
+#endif
+
+#if STM32_DAC_USE_DAC3_CH1 && !STM32_HAS_DAC3_CH1
+#error "DAC3 CH1 not present in the selected device"
+#endif
+
+#if STM32_DAC_USE_DAC3_CH2 && !STM32_HAS_DAC3_CH2
+#error "DAC3 CH2 not present in the selected device"
+#endif
+
+#if STM32_DAC_USE_DAC4_CH1 && !STM32_HAS_DAC4_CH1
+#error "DAC4 CH1 not present in the selected device"
+#endif
+
+#if STM32_DAC_USE_DAC4_CH2 && !STM32_HAS_DAC4_CH2
+#error "DAC4 CH2 not present in the selected device"
+#endif
+
+#if (STM32_DAC_USE_DAC1_CH2 || STM32_DAC_USE_DAC2_CH2 ||                    \
+     STM32_DAC_USE_DAC3_CH2 || STM32_DAC_USE_DAC4_CH2) && STM32_DAC_DUAL_MODE
+#error "DACx CH2 cannot be used independently in dual mode"
+#endif
+
+#if !STM32_DAC_USE_DAC1_CH1 && !STM32_DAC_USE_DAC1_CH2 &&                   \
+    !STM32_DAC_USE_DAC2_CH1 && !STM32_DAC_USE_DAC2_CH2 &&                   \
+    !STM32_DAC_USE_DAC3_CH1 && !STM32_DAC_USE_DAC3_CH2 &&                   \
+    !STM32_DAC_USE_DAC4_CH1 && !STM32_DAC_USE_DAC4_CH2
+#error "DAC driver activated but no DAC peripheral assigned"
+#endif
+
+#if STM32_DAC_USE_DAC1_CH1 &&                                               \
+    !OSAL_IRQ_IS_VALID_PRIORITY(STM32_DAC_DAC1_CH1_IRQ_PRIORITY)
+#error "Invalid IRQ priority assigned to DAC1 CH1"
+#endif
+
+#if STM32_DAC_USE_DAC1_CH2 &&                                               \
+    !OSAL_IRQ_IS_VALID_PRIORITY(STM32_DAC_DAC1_CH2_IRQ_PRIORITY)
+#error "Invalid IRQ priority assigned to DAC1 CH2"
+#endif
+
+#if STM32_DAC_USE_DAC2_CH1 &&                                               \
+    !OSAL_IRQ_IS_VALID_PRIORITY(STM32_DAC_DAC2_CH1_IRQ_PRIORITY)
+#error "Invalid IRQ priority assigned to DAC2 CH1"
+#endif
+
+#if STM32_DAC_USE_DAC2_CH2 &&                                               \
+    !OSAL_IRQ_IS_VALID_PRIORITY(STM32_DAC_DAC2_CH2_IRQ_PRIORITY)
+#error "Invalid IRQ priority assigned to DAC2 CH2"
+#endif
+
+#if STM32_DAC_USE_DAC3_CH1 &&                                               \
+    !OSAL_IRQ_IS_VALID_PRIORITY(STM32_DAC_DAC3_CH1_IRQ_PRIORITY)
+#error "Invalid IRQ priority assigned to DAC3 CH1"
+#endif
+
+#if STM32_DAC_USE_DAC3_CH2 &&                                               \
+    !OSAL_IRQ_IS_VALID_PRIORITY(STM32_DAC_DAC3_CH2_IRQ_PRIORITY)
+#error "Invalid IRQ priority assigned to DAC3 CH2"
+#endif
+
+#if STM32_DAC_USE_DAC4_CH1 &&                                               \
+    !OSAL_IRQ_IS_VALID_PRIORITY(STM32_DAC_DAC4_CH1_IRQ_PRIORITY)
+#error "Invalid IRQ priority assigned to DAC4 CH1"
+#endif
+
+#if STM32_DAC_USE_DAC4_CH2 &&                                               \
+    !OSAL_IRQ_IS_VALID_PRIORITY(STM32_DAC_DAC4_CH2_IRQ_PRIORITY)
+#error "Invalid IRQ priority assigned to DAC4 CH2"
+#endif
+
+/* The following checks are only required when there is a DMA able to
+   reassign streams to different channels.*/
+#if STM32_ADVANCED_DMA
+
+/* Check on the presence of the DMA streams settings in mcuconf.h.*/
+#if STM32_DAC_USE_DAC1_CH1 && !defined(STM32_DAC_DAC1_CH1_DMA_STREAM)
+#error "DAC1 CH1 DMA stream not defined"
+#endif
+
+#if STM32_DAC_USE_DAC1_CH2 && !defined(STM32_DAC_DAC1_CH2_DMA_STREAM)
+#error "DAC1 CH2 DMA stream not defined"
+#endif
+
+#if STM32_DAC_USE_DAC2_CH1 && !defined(STM32_DAC_DAC2_CH1_DMA_STREAM)
+#error "DAC2 CH1 DMA stream not defined"
+#endif
+
+#if STM32_DAC_USE_DAC2_CH2 && !defined(STM32_DAC_DAC2_CH2_DMA_STREAM)
+#error "DAC2 CH2 DMA stream not defined"
+#endif
+
+#if STM32_DAC_USE_DAC3_CH1 && !defined(STM32_DAC_DAC3_CH1_DMA_STREAM)
+#error "DAC3 CH1 DMA stream not defined"
+#endif
+
+#if STM32_DAC_USE_DAC3_CH2 && !defined(STM32_DAC_DAC3_CH2_DMA_STREAM)
+#error "DAC3 CH2 DMA stream not defined"
+#endif
+
+#if STM32_DAC_USE_DAC4_CH1 && !defined(STM32_DAC_DAC4_CH1_DMA_STREAM)
+#error "DAC4 CH1 DMA stream not defined"
+#endif
+
+#if STM32_DAC_USE_DAC4_CH2 && !defined(STM32_DAC_DAC4_CH2_DMA_STREAM)
+#error "DAC4 CH2 DMA stream not defined"
+#endif
+
+#if STM32_DMA_SUPPORTS_DMAMUX
+
+#else /* !STM32_DMA_SUPPORTS_DMAMUX */
+
+/* Check on the validity of the assigned DMA streams.*/
+#if STM32_DAC_USE_DAC1_CH1 &&                                               \
+    !STM32_DMA_IS_VALID_ID(STM32_DAC_DAC1_CH1_DMA_STREAM, STM32_DAC1_CH1_DMA_MSK)
+#error "invalid DMA stream associated to DAC1 CH1"
+#endif
+
+#if STM32_DAC_USE_DAC1_CH2 &&                                               \
+    !STM32_DMA_IS_VALID_ID(STM32_DAC_DAC1_CH2_DMA_STREAM, STM32_DAC1_CH2_DMA_MSK)
+#error "invalid DMA stream associated to DAC1 CH2"
+#endif
+
+#if STM32_DAC_USE_DAC2_CH1 &&                                               \
+    !STM32_DMA_IS_VALID_ID(STM32_DAC_DAC2_CH1_DMA_STREAM, STM32_DAC2_CH1_DMA_MSK)
+#error "invalid DMA stream associated to DAC2 CH1"
+#endif
+
+#if STM32_DAC_USE_DAC2_CH2 &&                                               \
+    !STM32_DMA_IS_VALID_ID(STM32_DAC_DAC2_CH2_DMA_STREAM, STM32_DAC2_CH2_DMA_MSK)
+#error "invalid DMA stream associated to DAC2 CH2"
+#endif
+
+#if STM32_DAC_USE_DAC3_CH1 &&                                               \
+    !STM32_DMA_IS_VALID_ID(STM32_DAC_DAC3_CH1_DMA_STREAM, STM32_DAC3_CH1_DMA_MSK)
+#error "invalid DMA stream associated to DAC1 CH1"
+#endif
+
+#if STM32_DAC_USE_DAC3_CH2 &&                                               \
+    !STM32_DMA_IS_VALID_ID(STM32_DAC_DAC3_CH2_DMA_STREAM, STM32_DAC3_CH2_DMA_MSK)
+#error "invalid DMA stream associated to DAC1 CH2"
+#endif
+
+#if STM32_DAC_USE_DAC4_CH1 &&                                               \
+    !STM32_DMA_IS_VALID_ID(STM32_DAC_DAC4_CH1_DMA_STREAM, STM32_DAC4_CH1_DMA_MSK)
+#error "invalid DMA stream associated to DAC2 CH1"
+#endif
+
+#if STM32_DAC_USE_DAC4_CH2 &&                                               \
+    !STM32_DMA_IS_VALID_ID(STM32_DAC_DAC4_CH2_DMA_STREAM, STM32_DAC4_CH2_DMA_MSK)
+#error "invalid DMA stream associated to DAC2 CH2"
+#endif
+
+#endif /* !STM32_DMA_SUPPORTS_DMAMUX */
+
+#endif /* STM32_ADVANCED_DMA */
+
+#if STM32_DAC_USE_DAC1_CH1 &&                                               \
+    !STM32_DMA_IS_VALID_PRIORITY(STM32_DAC_DAC1_CH1_DMA_PRIORITY)
+#error "Invalid DMA priority assigned to DAC1 CH1"
+#endif
+
+#if STM32_DAC_USE_DAC1_CH2 &&                                               \
+    !STM32_DMA_IS_VALID_PRIORITY(STM32_DAC_DAC1_CH2_DMA_PRIORITY)
+#error "Invalid DMA priority assigned to DAC1 CH2"
+#endif
+
+#if STM32_DAC_USE_DAC2_CH1 &&                                               \
+    !STM32_DMA_IS_VALID_PRIORITY(STM32_DAC_DAC2_CH1_DMA_PRIORITY)
+#error "Invalid DMA priority assigned to DAC2 CH1"
+#endif
+
+#if STM32_DAC_USE_DAC2_CH2 &&                                               \
+    !STM32_DMA_IS_VALID_PRIORITY(STM32_DAC_DAC2_CH2_DMA_PRIORITY)
+#error "Invalid DMA priority assigned to DAC2 CH2"
+#endif
+
+#if STM32_DAC_USE_DAC3_CH1 &&                                               \
+    !STM32_DMA_IS_VALID_PRIORITY(STM32_DAC_DAC3_CH1_DMA_PRIORITY)
+#error "Invalid DMA priority assigned to DAC3 CH1"
+#endif
+
+#if STM32_DAC_USE_DAC3_CH2 &&                                               \
+    !STM32_DMA_IS_VALID_PRIORITY(STM32_DAC_DAC3_CH2_DMA_PRIORITY)
+#error "Invalid DMA priority assigned to DAC3 CH2"
+#endif
+
+#if STM32_DAC_USE_DAC4_CH1 &&                                               \
+    !STM32_DMA_IS_VALID_PRIORITY(STM32_DAC_DAC4_CH1_DMA_PRIORITY)
+#error "Invalid DMA priority assigned to DAC4 CH1"
+#endif
+
+#if STM32_DAC_USE_DAC4_CH2 &&                                               \
+    !STM32_DMA_IS_VALID_PRIORITY(STM32_DAC_DAC4_CH2_DMA_PRIORITY)
+#error "Invalid DMA priority assigned to DAC4 CH2"
+#endif
+
+#if !defined(STM32_DMA_REQUIRED)
+#define STM32_DMA_REQUIRED
+#endif
+
+/**
+ * @brief   Max DAC channels.
+ */
+#if STM32_DAC_DUAL_MODE == TRUE
+#define DAC_MAX_CHANNELS                    2
+#else
+#define DAC_MAX_CHANNELS                    1
+#endif
+
+/*===========================================================================*/
+/* Driver data structures and types.                                         */
+/*===========================================================================*/
+
+/**
+ * @brief   Type of a DAC channel index.
+ */
+typedef uint32_t dacchannel_t;
+
+/**
+ * @brief   Type representing a DAC sample.
+ */
+typedef uint16_t dacsample_t;
+
+/**
+ * @brief   DAC channel parameters type.
+ */
+typedef struct {
+  /**
+   * @brief   Pointer to the DAC registers block.
+   */
+  DAC_TypeDef               *dac;
+  /**
+   * @brief   DAC data registers offset.
+   */
+  uint32_t                  dataoffset;
+  /**
+   * @brief   DAC CR register bit offset.
+   */
+  uint32_t                  regshift;
+  /**
+   * @brief   DAC CR register mask.
+   */
+  uint32_t                  regmask;
+  /**
+   * @brief   Associated DMA stream.
+   */
+  uint32_t                  dmastream;
+  /**
+   * @brief   Mode bits for the DMA.
+   */
+  uint32_t                  dmamode;
+  /**
+   * @brief   DMA channel IRQ priority.
+   */
+  uint32_t                  dmairqprio;
+#if (STM32_DMA_SUPPORTS_DMAMUX == TRUE) || defined(__DOXYGEN__)
+  /**
+   * @brief   DMAMUX peripheral selector.
+   */
+  uint32_t                  peripheral;
+#endif
+} dacparams_t;
+
+/**
+ * @brief   Possible DAC failure causes.
+ * @note    Error codes are architecture dependent and should not relied
+ *          upon.
+ */
+typedef enum {
+  DAC_ERR_DMAFAILURE = 0,                   /**< DMA operations failure.    */
+  DAC_ERR_UNDERFLOW = 1                     /**< DAC overflow condition.    */
+} dacerror_t;
+
+/**
+ * @brief   Samples alignment and size mode.
+ */
+typedef enum {
+  DAC_DHRM_12BIT_RIGHT = 0,
+  DAC_DHRM_12BIT_LEFT = 1,
+  DAC_DHRM_8BIT_RIGHT = 2,
+#if STM32_DAC_DUAL_MODE && !defined(__DOXYGEN__)
+  DAC_DHRM_12BIT_RIGHT_DUAL = 3,
+  DAC_DHRM_12BIT_LEFT_DUAL = 4,
+  DAC_DHRM_8BIT_RIGHT_DUAL = 5
+#endif
+} dacdhrmode_t;
+
+/**
+ * @brief   Low level fields of the DAC driver structure.
+ */
+#define dac_lld_driver_fields                                               \
+  /* DAC channel parameters.*/                                              \
+  const dacparams_t         *params;                                        \
+  /* Associated DMA.*/                                                      \
+  const stm32_dma_stream_t  *dma
+
+/**
+ * @brief   Low level fields of the DAC configuration structure.
+ * @note    In DUAL mode init, cr and mcr fields hold CH1 settings in their
+ *          lower 16 bits and CH2 settings in the upper 16 bits.
+ */
+#define dac_lld_config_fields                                               \
+  /* Initial output on DAC channel.*/                                       \
+  uint32_t                init;                                             \
+  /* DAC data holding register mode.*/                                      \
+  dacdhrmode_t            datamode;                                         \
+  /* DAC control register.*/                                                \
+  uint32_t                cr;                                               \
+  /* DAC mode control register.*/                                           \
+  uint32_t                mcr
+
+/**
+ * @brief   Low level fields of the DAC group configuration structure.
+ */
+#define dac_lld_conversion_group_fields                                     \
+  /* DAC initialization data. This field contains the (not shifted) value   \
+     to be put into the TSEL field of the DAC CR register during            \
+     initialization. All other fields are handled internally.*/             \
+  uint32_t                  trigger
+
+/*===========================================================================*/
+/* Driver macros.                                                            */
+/*===========================================================================*/
+
+/**
+ * @name    DAC trigger modes
+ * @{
+ */
+#define DAC_TRG_MASK                    7U
+#define DAC_TRG(n)                      (n)
+/** @} */
+
+/**
+ * @brief   Shift of initialisation value for channel 2 in dual mode.
+ */
+#define DAC_VALUE_DUAL(n) ((n) << (sizeof(dacsample_t) * 8))
+
+/*===========================================================================*/
+/* External declarations.                                                    */
+/*===========================================================================*/
+
+#if STM32_DAC_USE_DAC1_CH1 && !defined(__DOXYGEN__)
+extern DACDriver DACD1;
+#endif
+
+#if STM32_DAC_USE_DAC1_CH2 && !STM32_DAC_DUAL_MODE && !defined(__DOXYGEN__)
+extern DACDriver DACD2;
+#endif
+
+#if STM32_DAC_USE_DAC2_CH1 && !defined(__DOXYGEN__)
+extern DACDriver DACD3;
+#endif
+
+#if STM32_DAC_USE_DAC2_CH2 && !STM32_DAC_DUAL_MODE && !defined(__DOXYGEN__)
+extern DACDriver DACD4;
+#endif
+
+#if STM32_DAC_USE_DAC3_CH1 && !defined(__DOXYGEN__)
+extern DACDriver DACD5;
+#endif
+
+#if STM32_DAC_USE_DAC3_CH2 && !STM32_DAC_DUAL_MODE && !defined(__DOXYGEN__)
+extern DACDriver DACD6;
+#endif
+
+#if STM32_DAC_USE_DAC4_CH1 && !defined(__DOXYGEN__)
+extern DACDriver DACD7;
+#endif
+
+#if STM32_DAC_USE_DAC4_CH2 && !STM32_DAC_DUAL_MODE && !defined(__DOXYGEN__)
+extern DACDriver DACD8;
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+  void dac_lld_init(void);
+  void dac_lld_start(DACDriver *dacp);
+  void dac_lld_stop(DACDriver *dacp);
+  void dac_lld_put_channel(DACDriver *dacp,
+                           dacchannel_t channel,
+                           dacsample_t sample);
+  void dac_lld_start_conversion(DACDriver *dacp);
+  void dac_lld_stop_conversion(DACDriver *dacp);
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* HAL_USE_DAC */
+
+#endif /* HAL_DAC_LLD_H */
+
+/** @} */
Index: hal/ports/STM32/LLD/DACv1/hal_dac_lld.c
===================================================================
--- hal/ports/STM32/LLD/DACv1/hal_dac_lld.c	(revision 16161)
+++ hal/ports/STM32/LLD/DACv1/hal_dac_lld.c	(working copy)
@@ -1,801 +1,834 @@
-/*
-    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    DACv1/hal_dac_lld.c
- * @brief   STM32 DAC subsystem low level driver source.
- *
- * @addtogroup DAC
- * @{
- */
-
-#include "hal.h"
-
-#if HAL_USE_DAC || defined(__DOXYGEN__)
-
-/*===========================================================================*/
-/* Driver local definitions.                                                 */
-/*===========================================================================*/
-
-/* Because ST headers naming inconsistencies.*/
-#if !defined(DAC1)
-#define DAC1 DAC
-#endif
-
-#define DAC1_CH1_DMA_CHANNEL                                                \
-  STM32_DMA_GETCHANNEL(STM32_DAC_DAC1_CH1_DMA_STREAM,                       \
-                       STM32_DAC1_CH1_DMA_CHN)
-
-#define DAC1_CH2_DMA_CHANNEL                                                \
-  STM32_DMA_GETCHANNEL(STM32_DAC_DAC1_CH2_DMA_STREAM,                       \
-                       STM32_DAC1_CH2_DMA_CHN)
-
-#define DAC2_CH1_DMA_CHANNEL                                                \
-  STM32_DMA_GETCHANNEL(STM32_DAC_DAC2_CH1_DMA_STREAM,                       \
-                       STM32_DAC2_CH1_DMA_CHN)
-
-#define DAC2_CH2_DMA_CHANNEL                                                \
-  STM32_DMA_GETCHANNEL(STM32_DAC_DAC2_CH2_DMA_STREAM,                       \
-                       STM32_DAC2_CH2_DMA_CHN)
-
-#define DAC3_CH1_DMA_CHANNEL                                                \
-  STM32_DMA_GETCHANNEL(STM32_DAC_DAC3_CH1_DMA_STREAM,                       \
-                       STM32_DAC3_CH1_DMA_CHN)
-
-#define DAC3_CH2_DMA_CHANNEL                                                \
-  STM32_DMA_GETCHANNEL(STM32_DAC_DAC3_CH2_DMA_STREAM,                       \
-                       STM32_DAC3_CH2_DMA_CHN)
-
-#define DAC4_CH1_DMA_CHANNEL                                                \
-  STM32_DMA_GETCHANNEL(STM32_DAC_DAC4_CH1_DMA_STREAM,                       \
-                       STM32_DAC4_CH1_DMA_CHN)
-
-#define DAC4_CH2_DMA_CHANNEL                                                \
-  STM32_DMA_GETCHANNEL(STM32_DAC_DAC4_CH2_DMA_STREAM,                       \
-                       STM32_DAC4_CH2_DMA_CHN)
-
-#define CHANNEL_DATA_OFFSET 3U
-
-/*===========================================================================*/
-/* Driver exported variables.                                                */
-/*===========================================================================*/
-
-/** @brief DAC1 CH1 driver identifier.*/
-#if STM32_DAC_USE_DAC1_CH1 || defined(__DOXYGEN__)
-DACDriver DACD1;
-#endif
-
-/** @brief DAC1 CH2 driver identifier.*/
-#if (STM32_DAC_USE_DAC1_CH2 && !STM32_DAC_DUAL_MODE) || defined(__DOXYGEN__)
-DACDriver DACD2;
-#endif
-
-/** @brief DAC2 CH1 driver identifier.*/
-#if STM32_DAC_USE_DAC2_CH1 || defined(__DOXYGEN__)
-DACDriver DACD3;
-#endif
-
-/** @brief DAC2 CH2 driver identifier.*/
-#if (STM32_DAC_USE_DAC2_CH2 && !STM32_DAC_DUAL_MODE) || defined(__DOXYGEN__)
-DACDriver DACD4;
-#endif
-
-/** @brief DAC3 CH1 driver identifier.*/
-#if STM32_DAC_USE_DAC3_CH1 || defined(__DOXYGEN__)
-DACDriver DACD5;
-#endif
-
-/** @brief DAC3 CH2 driver identifier.*/
-#if (STM32_DAC_USE_DAC3_CH2 && !STM32_DAC_DUAL_MODE) || defined(__DOXYGEN__)
-DACDriver DACD6;
-#endif
-
-/** @brief DAC4 CH1 driver identifier.*/
-#if STM32_DAC_USE_DAC4_CH1 || defined(__DOXYGEN__)
-DACDriver DACD7;
-#endif
-
-/** @brief DAC4 CH2 driver identifier.*/
-#if (STM32_DAC_USE_DAC4_CH2 && !STM32_DAC_DUAL_MODE) || defined(__DOXYGEN__)
-DACDriver DACD8;
-#endif
-
-/*===========================================================================*/
-/* Driver local variables.                                                   */
-/*===========================================================================*/
-
-#if STM32_DAC_USE_DAC1_CH1 == TRUE
-static const dacparams_t dac1_ch1_params = {
-  .dac          = DAC1,
-  .dataoffset   = 0U,
-  .regshift     = 0U,
-  .regmask      = 0xFFFF0000U,
-  .dmastream    = STM32_DAC_DAC1_CH1_DMA_STREAM,
-#if STM32_DMA_SUPPORTS_DMAMUX
-  .peripheral   = STM32_DMAMUX1_DAC1_CH1,
-#endif
-  .dmamode      = STM32_DMA_CR_CHSEL(DAC1_CH1_DMA_CHANNEL) |
-                  STM32_DMA_CR_PL(STM32_DAC_DAC1_CH1_DMA_PRIORITY) |
-                  STM32_DMA_CR_MINC | STM32_DMA_CR_CIRC | STM32_DMA_CR_DIR_M2P |
-                  STM32_DMA_CR_DMEIE | STM32_DMA_CR_TEIE | STM32_DMA_CR_HTIE |
-                  STM32_DMA_CR_TCIE,
-  .dmairqprio   = STM32_DAC_DAC1_CH1_IRQ_PRIORITY
-};
-#endif
-
-#if STM32_DAC_USE_DAC1_CH2 == TRUE
-static const dacparams_t dac1_ch2_params = {
-  .dac          = DAC1,
-  .dataoffset   = CHANNEL_DATA_OFFSET,
-  .regshift     = 16U,
-  .regmask      = 0x0000FFFFU,
-  .dmastream    = STM32_DAC_DAC1_CH2_DMA_STREAM,
-#if STM32_DMA_SUPPORTS_DMAMUX
-  .peripheral   = STM32_DMAMUX1_DAC1_CH2,
-#endif
-  .dmamode      = STM32_DMA_CR_CHSEL(DAC1_CH2_DMA_CHANNEL) |
-                  STM32_DMA_CR_PL(STM32_DAC_DAC1_CH2_DMA_PRIORITY) |
-                  STM32_DMA_CR_MINC | STM32_DMA_CR_CIRC | STM32_DMA_CR_DIR_M2P |
-                  STM32_DMA_CR_DMEIE | STM32_DMA_CR_TEIE | STM32_DMA_CR_HTIE |
-                  STM32_DMA_CR_TCIE,
-  .dmairqprio   = STM32_DAC_DAC1_CH2_IRQ_PRIORITY
-};
-#endif
-
-#if STM32_DAC_USE_DAC2_CH1 == TRUE
-static const dacparams_t dac2_ch1_params = {
-  .dac          = DAC2,
-  .dataoffset   = 0U,
-  .regshift     = 0U,
-  .regmask      = 0xFFFF0000U,
-  .dmastream    = STM32_DAC_DAC2_CH1_DMA_STREAM,
-#if STM32_DMA_SUPPORTS_DMAMUX
-  .peripheral   = STM32_DMAMUX1_DAC2_CH1,
-#endif
-  .dmamode      = STM32_DMA_CR_CHSEL(DAC2_CH1_DMA_CHANNEL) |
-                  STM32_DMA_CR_PL(STM32_DAC_DAC2_CH1_DMA_PRIORITY) |
-                  STM32_DMA_CR_MINC | STM32_DMA_CR_CIRC | STM32_DMA_CR_DIR_M2P |
-                  STM32_DMA_CR_DMEIE | STM32_DMA_CR_TEIE | STM32_DMA_CR_HTIE |
-                  STM32_DMA_CR_TCIE,
-  .dmairqprio   = STM32_DAC_DAC2_CH1_IRQ_PRIORITY
-};
-#endif
-
-#if STM32_DAC_USE_DAC2_CH2 == TRUE
-static const dacparams_t dac2_ch2_params = {
-  .dac          = DAC2,
-  .dataoffset   = CHANNEL_DATA_OFFSET,
-  .regshift     = 16U,
-  .regmask      = 0x0000FFFFU,
-  .dmastream    = STM32_DAC_DAC2_CH2_DMA_STREAM,
-#if STM32_DMA_SUPPORTS_DMAMUX
-  .peripheral   = STM32_DMAMUX1_DAC2_CH2,
-#endif
-  .dmamode      = STM32_DMA_CR_CHSEL(DAC2_CH2_DMA_CHANNEL) |
-                  STM32_DMA_CR_PL(STM32_DAC_DAC2_CH2_DMA_PRIORITY) |
-                  STM32_DMA_CR_MINC | STM32_DMA_CR_CIRC | STM32_DMA_CR_DIR_M2P |
-                  STM32_DMA_CR_DMEIE | STM32_DMA_CR_TEIE | STM32_DMA_CR_HTIE |
-                  STM32_DMA_CR_TCIE,
-  .dmairqprio   = STM32_DAC_DAC2_CH2_IRQ_PRIORITY
-};
-#endif
-
-#if STM32_DAC_USE_DAC3_CH1 == TRUE
-static const dacparams_t dac3_ch1_params = {
-  .dac          = DAC3,
-  .dataoffset   = 0U,
-  .regshift     = 0U,
-  .regmask      = 0xFFFF0000U,
-  .dmastream    = STM32_DAC_DAC3_CH1_DMA_STREAM,
-#if STM32_DMA_SUPPORTS_DMAMUX
-  .peripheral   = STM32_DMAMUX1_DAC3_CH1,
-#endif
-  .dmamode      = STM32_DMA_CR_CHSEL(DAC3_CH1_DMA_CHANNEL) |
-                  STM32_DMA_CR_PL(STM32_DAC_DAC3_CH1_DMA_PRIORITY) |
-                  STM32_DMA_CR_MINC | STM32_DMA_CR_CIRC | STM32_DMA_CR_DIR_M2P |
-                  STM32_DMA_CR_DMEIE | STM32_DMA_CR_TEIE | STM32_DMA_CR_HTIE |
-                  STM32_DMA_CR_TCIE,
-  .dmairqprio   = STM32_DAC_DAC3_CH1_IRQ_PRIORITY
-};
-#endif
-
-#if STM32_DAC_USE_DAC3_CH2 == TRUE
-static const dacparams_t dac3_ch2_params = {
-  .dac          = DAC3,
-  .dataoffset   = CHANNEL_DATA_OFFSET,
-  .regshift     = 16U,
-  .regmask      = 0x0000FFFFU,
-  .dmastream    = STM32_DAC_DAC3_CH2_DMA_STREAM,
-#if STM32_DMA_SUPPORTS_DMAMUX
-  .peripheral   = STM32_DMAMUX1_DAC3_CH2,
-#endif
-  .dmamode      = STM32_DMA_CR_CHSEL(DAC3_CH2_DMA_CHANNEL) |
-                  STM32_DMA_CR_PL(STM32_DAC_DAC3_CH2_DMA_PRIORITY) |
-                  STM32_DMA_CR_MINC | STM32_DMA_CR_CIRC | STM32_DMA_CR_DIR_M2P |
-                  STM32_DMA_CR_DMEIE | STM32_DMA_CR_TEIE | STM32_DMA_CR_HTIE |
-                  STM32_DMA_CR_TCIE,
-  .dmairqprio   = STM32_DAC_DAC3_CH2_IRQ_PRIORITY
-};
-#endif
-
-#if STM32_DAC_USE_DAC4_CH1 == TRUE
-static const dacparams_t dac4_ch1_params = {
-  .dac          = DAC4,
-  .dataoffset   = 0U,
-  .regshift     = 0U,
-  .regmask      = 0xFFFF0000U,
-  .dmastream    = STM32_DAC_DAC4_CH1_DMA_STREAM,
-#if STM32_DMA_SUPPORTS_DMAMUX
-  .peripheral   = STM32_DMAMUX1_DAC4_CH1,
-#endif
-  .dmamode      = STM32_DMA_CR_CHSEL(DAC4_CH1_DMA_CHANNEL) |
-                  STM32_DMA_CR_PL(STM32_DAC_DAC4_CH1_DMA_PRIORITY) |
-                  STM32_DMA_CR_MINC | STM32_DMA_CR_CIRC | STM32_DMA_CR_DIR_M2P |
-                  STM32_DMA_CR_DMEIE | STM32_DMA_CR_TEIE | STM32_DMA_CR_HTIE |
-                  STM32_DMA_CR_TCIE,
-  .dmairqprio   = STM32_DAC_DAC4_CH1_IRQ_PRIORITY
-};
-#endif
-
-#if STM32_DAC_USE_DAC4_CH2 == TRUE
-static const dacparams_t dac4_ch2_params = {
-  .dac          = DAC4,
-  .dataoffset   = CHANNEL_DATA_OFFSET,
-  .regshift     = 16U,
-  .regmask      = 0x0000FFFFU,
-  .dmastream    = STM32_DAC_DAC4_CH2_DMA_STREAM,
-#if STM32_DMA_SUPPORTS_DMAMUX
-  .peripheral   = STM32_DMAMUX1_DAC4_CH2,
-#endif
-  .dmamode      = STM32_DMA_CR_CHSEL(DAC4_CH2_DMA_CHANNEL) |
-                  STM32_DMA_CR_PL(STM32_DAC_DAC4_CH2_DMA_PRIORITY) |
-                  STM32_DMA_CR_MINC | STM32_DMA_CR_CIRC | STM32_DMA_CR_DIR_M2P |
-                  STM32_DMA_CR_DMEIE | STM32_DMA_CR_TEIE | STM32_DMA_CR_HTIE |
-                  STM32_DMA_CR_TCIE,
-  .dmairqprio   = STM32_DAC_DAC4_CH2_IRQ_PRIORITY
-};
-#endif
-
-/*===========================================================================*/
-/* Driver local functions.                                                   */
-/*===========================================================================*/
-
-/**
- * @brief   Shared end/half-of-tx service routine.
- *
- * @param[in] dacp      pointer to the @p DACDriver object
- * @param[in] flags     pre-shifted content of the ISR register
- */
-static void dac_lld_serve_tx_interrupt(DACDriver *dacp, uint32_t flags) {
-
-  if ((flags & (STM32_DMA_ISR_TEIF | STM32_DMA_ISR_DMEIF)) != 0) {
-    /* DMA errors handling.*/
-    dac_lld_stop_conversion(dacp);
-    _dac_isr_error_code(dacp, DAC_ERR_DMAFAILURE);
-  }
-  else {
-    if ((flags & STM32_DMA_ISR_HTIF) != 0) {
-      /* Half transfer processing.*/
-      _dac_isr_half_code(dacp);
-    }
-    if ((flags & STM32_DMA_ISR_TCIF) != 0) {
-      /* Transfer complete processing.*/
-      _dac_isr_full_code(dacp);
-    }
-  }
-}
-
-/*===========================================================================*/
-/* Driver interrupt handlers.                                                */
-/*===========================================================================*/
-
-/*===========================================================================*/
-/* Driver exported functions.                                                */
-/*===========================================================================*/
-
-/**
- * @brief   Low level DAC driver initialization.
- *
- * @notapi
- */
-void dac_lld_init(void) {
-
-#if STM32_DAC_USE_DAC1_CH1
-  dacObjectInit(&DACD1);
-  DACD1.params  = &dac1_ch1_params;
-  DACD1.dma = NULL;
-#endif
-
-#if STM32_DAC_USE_DAC1_CH2
-  dacObjectInit(&DACD2);
-  DACD2.params  = &dac1_ch2_params;
-  DACD2.dma = NULL;
-#endif
-
-#if STM32_DAC_USE_DAC2_CH1
-  dacObjectInit(&DACD3);
-  DACD3.params  = &dac2_ch1_params;
-  DACD3.dma = NULL;
-#endif
-
-#if STM32_DAC_USE_DAC2_CH2
-  dacObjectInit(&DACD4);
-  DACD4.params  = &dac2_ch2_params;
-  DACD4.dma = NULL;
-#endif
-
-#if STM32_DAC_USE_DAC3_CH1
-  dacObjectInit(&DACD5);
-  DACD5.params  = &dac3_ch1_params;
-  DACD5.dma = NULL;
-#endif
-
-#if STM32_DAC_USE_DAC3_CH2
-  dacObjectInit(&DACD6);
-  DACD6.params  = &dac3_ch2_params;
-  DACD6.dma = NULL;
-#endif
-
-#if STM32_DAC_USE_DAC4_CH1
-  dacObjectInit(&DACD7);
-  DACD7.params  = &dac4_ch1_params;
-  DACD7.dma = NULL;
-#endif
-
-#if STM32_DAC_USE_DAC4_CH2
-  dacObjectInit(&DACD8);
-  DACD8.params  = &dac4_ch2_params;
-  DACD8.dma = NULL;
-#endif
-}
-
-/**
- * @brief   Configures and activates the DAC peripheral.
- *
- * @param[in] dacp      pointer to the @p DACDriver object
- *
- * @notapi
- */
-void dac_lld_start(DACDriver *dacp) {
-
-  /* If the driver is in DAC_STOP state then a full initialization is
-     required.*/
-  if (dacp->state == DAC_STOP) {
-    dacchannel_t channel = 0;
-
-    /* Enabling the clock source.*/
-#if STM32_DAC_USE_DAC1_CH1
-    if (&DACD1 == dacp) {
-      rccEnableDAC1(true);
-    }
-#endif
-
-#if STM32_DAC_USE_DAC1_CH2
-    if (&DACD2 == dacp) {
-      rccEnableDAC1(true);
-      channel = 1;
-    }
-#endif
-
-#if STM32_DAC_USE_DAC2_CH1
-    if (&DACD3 == dacp) {
-      rccEnableDAC2(true);
-    }
-#endif
-
-#if STM32_DAC_USE_DAC2_CH2
-    if (&DACD4 == dacp) {
-      rccEnableDAC2(true);
-      channel = 1;
-    }
-#endif
-
-#if STM32_DAC_USE_DAC3_CH1
-    if (&DACD5 == dacp) {
-      rccEnableDAC3(true);
-    }
-#endif
-
-#if STM32_DAC_USE_DAC3_CH2
-    if (&DACD6 == dacp) {
-      rccEnableDAC3(true);
-      channel = 1;
-    }
-#endif
-
-#if STM32_DAC_USE_DAC4_CH1
-    if (&DACD7 == dacp) {
-      rccEnableDAC4(true);
-    }
-#endif
-
-#if STM32_DAC_USE_DAC4_CH2
-    if (&DACD8 == dacp) {
-      rccEnableDAC4(true);
-      channel = 1;
-    }
-#endif
-
-    /* Enabling DAC in SW triggering mode initially, initializing data to
-       zero.*/
-#if STM32_DAC_DUAL_MODE == FALSE
-    {
-      uint32_t cr;
-
-      cr = dacp->params->dac->CR;
-      cr &= dacp->params->regmask;
-      cr |= (DAC_CR_EN1 | dacp->config->cr) << dacp->params->regshift;
-      dacp->params->dac->CR = cr;
-      dac_lld_put_channel(dacp, channel, dacp->config->init);
-    }
-#else
-    if ((dacp->config->datamode == DAC_DHRM_12BIT_RIGHT_DUAL) ||
-        (dacp->config->datamode == DAC_DHRM_12BIT_LEFT_DUAL) ||
-        (dacp->config->datamode == DAC_DHRM_8BIT_RIGHT_DUAL)) {
-      dacp->params->dac->CR = DAC_CR_EN2 | (dacp->config->cr << 16) | DAC_CR_EN1 | dacp->config->cr;
-      dac_lld_put_channel(dacp, 1U, dacp->config->init);
-    }
-    else {
-      dacp->params->dac->CR = DAC_CR_EN1 | dacp->config->cr;
-    }
-    dac_lld_put_channel(dacp, channel, dacp->config->init);
-#endif
-  }
-}
-
-/**
- * @brief   Deactivates the DAC peripheral.
- *
- * @param[in] dacp      pointer to the @p DACDriver object
- *
- * @notapi
- */
-void dac_lld_stop(DACDriver *dacp) {
-
-  /* If in ready state then disables the DAC clock.*/
-  if (dacp->state == DAC_READY) {
-
-    /* Disabling DAC.*/
-    dacp->params->dac->CR &= dacp->params->regmask;
-
-#if STM32_DAC_USE_DAC1_CH1
-    if (&DACD1 == dacp) {
-#if defined(DAC_CR_EN2)
-      if ((dacp->params->dac->CR & DAC_CR_EN2) == 0U) {
-        rccDisableDAC1();
-      }
-#else
-      rccDisableDAC1();
-#endif
-    }
-#endif
-
-#if STM32_DAC_USE_DAC1_CH2
-    if (&DACD2 == dacp) {
-      if ((dacp->params->dac->CR & DAC_CR_EN1) == 0U) {
-        rccDisableDAC1();
-      }
-    }
-#endif
-
-#if STM32_DAC_USE_DAC2_CH1
-    if (&DACD3 == dacp) {
-#if defined(DAC_CR_EN2)
-      if ((dacp->params->dac->CR & DAC_CR_EN2) == 0U) {
-        rccDisableDAC2();
-      }
-#else
-      rccDisableDAC2();
-#endif
-    }
-#endif
-
-#if STM32_DAC_USE_DAC2_CH2
-    if (&DACD4 == dacp) {
-      if ((dacp->params->dac->CR & DAC_CR_EN1) == 0U) {
-        rccDisableDAC2();
-      }
-    }
-#endif
-
-#if STM32_DAC_USE_DAC3_CH1
-    if (&DACD5 == dacp) {
-#if defined(DAC_CR_EN2)
-      if ((dacp->params->dac->CR & DAC_CR_EN2) == 0U) {
-        rccDisableDAC3();
-      }
-#else
-      rccDisableDAC3();
-#endif
-    }
-#endif
-
-#if STM32_DAC_USE_DAC3_CH2
-    if (&DACD6 == dacp) {
-      if ((dacp->params->dac->CR & DAC_CR_EN1) == 0U) {
-        rccDisableDAC3();
-      }
-    }
-#endif
-
-#if STM32_DAC_USE_DAC4_CH1
-    if (&DACD7 == dacp) {
-#if defined(DAC_CR_EN2)
-      if ((dacp->params->dac->CR & DAC_CR_EN2) == 0U) {
-        rccDisableDAC4();
-      }
-#else
-      rccDisableDAC4();
-#endif
-    }
-#endif
-
-#if STM32_DAC_USE_DAC4_CH2
-    if (&DACD8 == dacp) {
-      if ((dacp->params->dac->CR & DAC_CR_EN1) == 0U) {
-        rccDisableDAC4();
-      }
-    }
-#endif
-  }
-}
-
-/**
- * @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
- *
- * @api
- */
-void dac_lld_put_channel(DACDriver *dacp,
-                         dacchannel_t channel,
-                         dacsample_t sample) {
-
-  switch (dacp->config->datamode) {
-  case DAC_DHRM_12BIT_RIGHT:
-#if STM32_DAC_DUAL_MODE
-  case DAC_DHRM_12BIT_RIGHT_DUAL:
-#endif
-    if (channel == 0U) {
-#if STM32_DAC_DUAL_MODE
-      dacp->params->dac->DHR12R1 = (uint32_t)sample;
-#else
-      *(&dacp->params->dac->DHR12R1 + dacp->params->dataoffset) = (uint32_t)sample;
-#endif
-    }
-#if (STM32_HAS_DAC1_CH2 || STM32_HAS_DAC2_CH2 ||                            \
-     STM32_HAS_DAC3_CH2 || STM32_HAS_DAC4_CH2)
-    else {
-      dacp->params->dac->DHR12R2 = (uint32_t)sample;
-    }
-#endif
-    break;
-  case DAC_DHRM_12BIT_LEFT:
-#if STM32_DAC_DUAL_MODE
-  case DAC_DHRM_12BIT_LEFT_DUAL:
-#endif
-    if (channel == 0U) {
-#if STM32_DAC_DUAL_MODE
-      dacp->params->dac->DHR12L1 = (uint32_t)sample;
-#else
-      *(&dacp->params->dac->DHR12L1 + dacp->params->dataoffset) = (uint32_t)sample;
-#endif
-    }
-#if (STM32_HAS_DAC1_CH2 || STM32_HAS_DAC2_CH2 ||                            \
-     STM32_HAS_DAC3_CH2 || STM32_HAS_DAC4_CH2)
-    else {
-      dacp->params->dac->DHR12L2 = (uint32_t)sample;
-    }
-#endif
-    break;
-  case DAC_DHRM_8BIT_RIGHT:
-#if STM32_DAC_DUAL_MODE
-  case DAC_DHRM_8BIT_RIGHT_DUAL:
-#endif
-    if (channel == 0U) {
-#if STM32_DAC_DUAL_MODE
-      dacp->params->dac->DHR8R1 = (uint32_t)sample;
-#else
-      *(&dacp->params->dac->DHR8R1 + dacp->params->dataoffset) = (uint32_t)sample;
-#endif
-    }
-#if (STM32_HAS_DAC1_CH2 || STM32_HAS_DAC2_CH2 ||                            \
-     STM32_HAS_DAC3_CH2 || STM32_HAS_DAC4_CH2)
-    else {
-      dacp->params->dac->DHR8R2 = (uint32_t)sample;
-    }
-#endif
-    break;
-  default:
-    osalDbgAssert(false, "unexpected DAC mode");
-    break;
-  }
-}
-
-/**
- * @brief   Starts a DAC conversion.
- * @details Starts an asynchronous conversion operation.
- * @note    In @p DAC_DHRM_8BIT_RIGHT mode the parameters passed to the
- *          callback are wrong because two samples are packed in a single
- *          dacsample_t element. This will not be corrected, do not rely
- *          on those parameters.
- * @note    In @p DAC_DHRM_8BIT_RIGHT_DUAL mode two samples are treated
- *          as a single 16 bits sample and packed into a single dacsample_t
- *          element. The num_channels must be set to one in the group
- *          conversion configuration structure.
- *
- * @param[in] dacp      pointer to the @p DACDriver object
- *
- * @notapi
- */
-void dac_lld_start_conversion(DACDriver *dacp) {
-  uint32_t n, cr, dmamode;
-
-  /* Number of DMA operations per buffer.*/
-  n = dacp->depth * dacp->grpp->num_channels;
-
-  /* Allocating the DMA channel.*/
-  dacp->dma = dmaStreamAllocI(dacp->params->dmastream,
-                              dacp->params->dmairqprio,
-                              (stm32_dmaisr_t)dac_lld_serve_tx_interrupt,
-                              (void *)dacp);
-  osalDbgAssert(dacp->dma != NULL, "unable to allocate stream");
-#if STM32_DMA_SUPPORTS_DMAMUX
-  dmaSetRequestSource(dacp->dma, dacp->params->peripheral);
-#endif
-
-  /* DMA settings depend on the chosen DAC mode.*/
-  switch (dacp->config->datamode) {
-  /* Sets the DAC data register */
-  case DAC_DHRM_12BIT_RIGHT:
-    osalDbgAssert(dacp->grpp->num_channels == 1, "invalid number of channels");
-
-    dmaStreamSetPeripheral(dacp->dma, &dacp->params->dac->DHR12R1 +
-                                      dacp->params->dataoffset);
-    dmamode = dacp->params->dmamode |
-#if STM32_DMA_ADVANCED == FALSE
-              STM32_DMA_CR_PSIZE_WORD  | STM32_DMA_CR_MSIZE_HWORD;
-#else
-              STM32_DMA_CR_PSIZE_HWORD | STM32_DMA_CR_MSIZE_HWORD;
-#endif
-    break;
-  case DAC_DHRM_12BIT_LEFT:
-    osalDbgAssert(dacp->grpp->num_channels == 1, "invalid number of channels");
-
-    dmaStreamSetPeripheral(dacp->dma, &dacp->params->dac->DHR12L1 +
-                                      dacp->params->dataoffset);
-    dmamode = dacp->params->dmamode |
-#if STM32_DMA_ADVANCED == FALSE
-              STM32_DMA_CR_PSIZE_WORD  | STM32_DMA_CR_MSIZE_HWORD;
-#else
-              STM32_DMA_CR_PSIZE_HWORD | STM32_DMA_CR_MSIZE_HWORD;
-#endif
-    break;
-  case DAC_DHRM_8BIT_RIGHT:
-    osalDbgAssert(dacp->grpp->num_channels == 1, "invalid number of channels");
-
-    dmaStreamSetPeripheral(dacp->dma, &dacp->params->dac->DHR8R1 +
-                                      dacp->params->dataoffset);
-    dmamode = dacp->params->dmamode |
-#if STM32_DMA_ADVANCED == FALSE
-              STM32_DMA_CR_PSIZE_WORD  | STM32_DMA_CR_MSIZE_BYTE;
-#else
-              STM32_DMA_CR_MSIZE_BYTE  | STM32_DMA_CR_MSIZE_BYTE;
-#endif
-
-    /* In this mode the size of the buffer is halved because two samples
-       packed in a single dacsample_t element.*/
-    n = (n + 1) / 2;
-    break;
-#if STM32_DAC_DUAL_MODE == TRUE
-  case DAC_DHRM_12BIT_RIGHT_DUAL:
-    osalDbgAssert(dacp->grpp->num_channels == 2, "invalid number of channels");
-
-    dmaStreamSetPeripheral(dacp->dma, &dacp->params->dac->DHR12RD);
-    dmamode = dacp->params->dmamode |
-              STM32_DMA_CR_PSIZE_WORD | STM32_DMA_CR_MSIZE_WORD;
-    n /= 2;
-    break;
-  case DAC_DHRM_12BIT_LEFT_DUAL:
-    osalDbgAssert(dacp->grpp->num_channels == 2, "invalid number of channels");
-
-    dmaStreamSetPeripheral(dacp->dma, &dacp->params->dac->DHR12LD);
-    dmamode = dacp->params->dmamode |
-              STM32_DMA_CR_PSIZE_WORD | STM32_DMA_CR_MSIZE_WORD;
-    n /= 2;
-    break;
-  case DAC_DHRM_8BIT_RIGHT_DUAL:
-    osalDbgAssert(dacp->grpp->num_channels == 1, "invalid number of channels");
-
-    dmaStreamSetPeripheral(dacp->dma, &dacp->params->dac->DHR8RD);
-    dmamode = dacp->params->dmamode |
-#if STM32_DMA_ADVANCED == FALSE
-              STM32_DMA_CR_PSIZE_WORD  | STM32_DMA_CR_MSIZE_HWORD;
-#else
-              STM32_DMA_CR_PSIZE_HWORD | STM32_DMA_CR_MSIZE_HWORD;
-#endif
-    n /= 2;
-    break;
-#endif
-  default:
-    osalDbgAssert(false, "unexpected DAC mode");
-    return;
-  }
-
-  dmaStreamSetMemory0(dacp->dma, dacp->samples);
-  dmaStreamSetTransactionSize(dacp->dma, n);
-  dmaStreamSetMode(dacp->dma, dmamode            |
-                              STM32_DMA_CR_DMEIE | STM32_DMA_CR_TEIE |
-                              STM32_DMA_CR_HTIE  | STM32_DMA_CR_TCIE);
-  dmaStreamEnable(dacp->dma);
-
-  /* DAC configuration.*/
-  cr = dacp->params->dac->CR;
-
-#if STM32_DAC_DUAL_MODE == FALSE
-  cr &= dacp->params->regmask;
-  cr |= (DAC_CR_DMAEN1 | (dacp->grpp->trigger << DAC_CR_TSEL1_Pos) | DAC_CR_TEN1 | DAC_CR_EN1 | dacp->config->cr) << dacp->params->regshift;
-#else
-  cr = DAC_CR_DMAEN1 | (dacp->grpp->trigger << DAC_CR_TSEL1_Pos) | DAC_CR_TEN1 | DAC_CR_EN1 | dacp->config->cr
-                     | (dacp->grpp->trigger << DAC_CR_TSEL2_Pos) | DAC_CR_TEN2 | DAC_CR_EN2 | (dacp->config->cr << 16);
-#endif
-
-  dacp->params->dac->CR = cr;
-}
-
-/**
- * @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 dac_lld_stop_conversion(DACDriver *dacp) {
-  uint32_t cr;
-
-  /* DMA channel disabled and released.*/
-  dmaStreamDisable(dacp->dma);
-  dmaStreamFreeI(dacp->dma);
-  dacp->dma = NULL;
-
-  cr = dacp->params->dac->CR;
-
-#if STM32_DAC_DUAL_MODE == FALSE
-  cr &= dacp->params->regmask;
-  cr |= (DAC_CR_EN1 | dacp->config->cr) << dacp->params->regshift;
-#else
-  if ((dacp->config->datamode == DAC_DHRM_12BIT_RIGHT_DUAL) ||
-      (dacp->config->datamode == DAC_DHRM_12BIT_LEFT_DUAL) ||
-      (dacp->config->datamode == DAC_DHRM_8BIT_RIGHT_DUAL)) {
-    cr = DAC_CR_EN2 | (dacp->config->cr << 16) |
-         DAC_CR_EN1 | dacp->config->cr;
-  }
-  else {
-    cr = DAC_CR_EN1 | dacp->config->cr;
-  }
-#endif
-
-  dacp->params->dac->CR = cr;
-}
-
-#endif /* HAL_USE_DAC */
-
-/** @} */
+/*
+    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    DACv1/hal_dac_lld.c
+ * @brief   STM32 DAC subsystem low level driver source.
+ *
+ * @addtogroup DAC
+ * @{
+ */
+
+#include "hal.h"
+
+#if HAL_USE_DAC || defined(__DOXYGEN__)
+
+/*===========================================================================*/
+/* Driver local definitions.                                                 */
+/*===========================================================================*/
+
+/* Because ST headers naming inconsistencies.*/
+#if !defined(DAC1)
+#define DAC1 DAC
+#endif
+
+#define DAC1_CH1_DMA_CHANNEL                                                \
+  STM32_DMA_GETCHANNEL(STM32_DAC_DAC1_CH1_DMA_STREAM,                       \
+                       STM32_DAC1_CH1_DMA_CHN)
+
+#define DAC1_CH2_DMA_CHANNEL                                                \
+  STM32_DMA_GETCHANNEL(STM32_DAC_DAC1_CH2_DMA_STREAM,                       \
+                       STM32_DAC1_CH2_DMA_CHN)
+
+#define DAC2_CH1_DMA_CHANNEL                                                \
+  STM32_DMA_GETCHANNEL(STM32_DAC_DAC2_CH1_DMA_STREAM,                       \
+                       STM32_DAC2_CH1_DMA_CHN)
+
+#define DAC2_CH2_DMA_CHANNEL                                                \
+  STM32_DMA_GETCHANNEL(STM32_DAC_DAC2_CH2_DMA_STREAM,                       \
+                       STM32_DAC2_CH2_DMA_CHN)
+
+#define DAC3_CH1_DMA_CHANNEL                                                \
+  STM32_DMA_GETCHANNEL(STM32_DAC_DAC3_CH1_DMA_STREAM,                       \
+                       STM32_DAC3_CH1_DMA_CHN)
+
+#define DAC3_CH2_DMA_CHANNEL                                                \
+  STM32_DMA_GETCHANNEL(STM32_DAC_DAC3_CH2_DMA_STREAM,                       \
+                       STM32_DAC3_CH2_DMA_CHN)
+
+#define DAC4_CH1_DMA_CHANNEL                                                \
+  STM32_DMA_GETCHANNEL(STM32_DAC_DAC4_CH1_DMA_STREAM,                       \
+                       STM32_DAC4_CH1_DMA_CHN)
+
+#define DAC4_CH2_DMA_CHANNEL                                                \
+  STM32_DMA_GETCHANNEL(STM32_DAC_DAC4_CH2_DMA_STREAM,                       \
+                       STM32_DAC4_CH2_DMA_CHN)
+
+#define CHANNEL_DATA_OFFSET     3U
+#define CHANNEL_REGISTER_SHIFT  16U
+#define CHANNEL_REGISTER_MASK1  0xFFFF0000U
+#define CHANNEL_REGISTER_MASK2  0x0000FFFFU
+
+/*===========================================================================*/
+/* Driver exported variables.                                                */
+/*===========================================================================*/
+
+/** @brief DAC1 CH1 driver identifier.*/
+#if STM32_DAC_USE_DAC1_CH1 || defined(__DOXYGEN__)
+DACDriver DACD1;
+#endif
+
+/** @brief DAC1 CH2 driver identifier.*/
+#if (STM32_DAC_USE_DAC1_CH2 && !STM32_DAC_DUAL_MODE) || defined(__DOXYGEN__)
+DACDriver DACD2;
+#endif
+
+/** @brief DAC2 CH1 driver identifier.*/
+#if STM32_DAC_USE_DAC2_CH1 || defined(__DOXYGEN__)
+DACDriver DACD3;
+#endif
+
+/** @brief DAC2 CH2 driver identifier.*/
+#if (STM32_DAC_USE_DAC2_CH2 && !STM32_DAC_DUAL_MODE) || defined(__DOXYGEN__)
+DACDriver DACD4;
+#endif
+
+/** @brief DAC3 CH1 driver identifier.*/
+#if STM32_DAC_USE_DAC3_CH1 || defined(__DOXYGEN__)
+DACDriver DACD5;
+#endif
+
+/** @brief DAC3 CH2 driver identifier.*/
+#if (STM32_DAC_USE_DAC3_CH2 && !STM32_DAC_DUAL_MODE) || defined(__DOXYGEN__)
+DACDriver DACD6;
+#endif
+
+/** @brief DAC4 CH1 driver identifier.*/
+#if STM32_DAC_USE_DAC4_CH1 || defined(__DOXYGEN__)
+DACDriver DACD7;
+#endif
+
+/** @brief DAC4 CH2 driver identifier.*/
+#if (STM32_DAC_USE_DAC4_CH2 && !STM32_DAC_DUAL_MODE) || defined(__DOXYGEN__)
+DACDriver DACD8;
+#endif
+
+/*===========================================================================*/
+/* Driver local variables.                                                   */
+/*===========================================================================*/
+
+#if STM32_DAC_USE_DAC1_CH1 == TRUE
+static const dacparams_t dac1_ch1_params = {
+  .dac          = DAC1,
+  .dataoffset   = 0U,
+  .regshift     = 0U,
+  .regmask      = CHANNEL_REGISTER_MASK1,
+  .dmastream    = STM32_DAC_DAC1_CH1_DMA_STREAM,
+#if STM32_DMA_SUPPORTS_DMAMUX
+  .peripheral   = STM32_DMAMUX1_DAC1_CH1,
+#endif
+  .dmamode      = STM32_DMA_CR_CHSEL(DAC1_CH1_DMA_CHANNEL) |
+                  STM32_DMA_CR_PL(STM32_DAC_DAC1_CH1_DMA_PRIORITY) |
+                  STM32_DMA_CR_MINC | STM32_DMA_CR_CIRC | STM32_DMA_CR_DIR_M2P |
+                  STM32_DMA_CR_DMEIE | STM32_DMA_CR_TEIE | STM32_DMA_CR_HTIE |
+                  STM32_DMA_CR_TCIE,
+  .dmairqprio   = STM32_DAC_DAC1_CH1_IRQ_PRIORITY
+};
+#endif
+
+#if STM32_DAC_USE_DAC1_CH2 == TRUE
+static const dacparams_t dac1_ch2_params = {
+  .dac          = DAC1,
+  .dataoffset   = CHANNEL_DATA_OFFSET,
+  .regshift     = CHANNEL_REGISTER_SHIFT,
+  .regmask      = CHANNEL_REGISTER_MASK2,
+  .dmastream    = STM32_DAC_DAC1_CH2_DMA_STREAM,
+#if STM32_DMA_SUPPORTS_DMAMUX
+  .peripheral   = STM32_DMAMUX1_DAC1_CH2,
+#endif
+  .dmamode      = STM32_DMA_CR_CHSEL(DAC1_CH2_DMA_CHANNEL) |
+                  STM32_DMA_CR_PL(STM32_DAC_DAC1_CH2_DMA_PRIORITY) |
+                  STM32_DMA_CR_MINC | STM32_DMA_CR_CIRC | STM32_DMA_CR_DIR_M2P |
+                  STM32_DMA_CR_DMEIE | STM32_DMA_CR_TEIE | STM32_DMA_CR_HTIE |
+                  STM32_DMA_CR_TCIE,
+  .dmairqprio   = STM32_DAC_DAC1_CH2_IRQ_PRIORITY
+};
+#endif
+
+#if STM32_DAC_USE_DAC2_CH1 == TRUE
+static const dacparams_t dac2_ch1_params = {
+  .dac          = DAC2,
+  .dataoffset   = 0U,
+  .regshift     = 0U,
+  .regmask      = CHANNEL_REGISTER_MASK1,
+  .dmastream    = STM32_DAC_DAC2_CH1_DMA_STREAM,
+#if STM32_DMA_SUPPORTS_DMAMUX
+  .peripheral   = STM32_DMAMUX1_DAC2_CH1,
+#endif
+  .dmamode      = STM32_DMA_CR_CHSEL(DAC2_CH1_DMA_CHANNEL) |
+                  STM32_DMA_CR_PL(STM32_DAC_DAC2_CH1_DMA_PRIORITY) |
+                  STM32_DMA_CR_MINC | STM32_DMA_CR_CIRC | STM32_DMA_CR_DIR_M2P |
+                  STM32_DMA_CR_DMEIE | STM32_DMA_CR_TEIE | STM32_DMA_CR_HTIE |
+                  STM32_DMA_CR_TCIE,
+  .dmairqprio   = STM32_DAC_DAC2_CH1_IRQ_PRIORITY
+};
+#endif
+
+#if STM32_DAC_USE_DAC2_CH2 == TRUE
+static const dacparams_t dac2_ch2_params = {
+  .dac          = DAC2,
+  .dataoffset   = CHANNEL_DATA_OFFSET,
+  .regshift     = CHANNEL_REGISTER_SHIFT,
+  .regmask      = CHANNEL_REGISTER_MASK2,
+  .dmastream    = STM32_DAC_DAC2_CH2_DMA_STREAM,
+#if STM32_DMA_SUPPORTS_DMAMUX
+  .peripheral   = STM32_DMAMUX1_DAC2_CH2,
+#endif
+  .dmamode      = STM32_DMA_CR_CHSEL(DAC2_CH2_DMA_CHANNEL) |
+                  STM32_DMA_CR_PL(STM32_DAC_DAC2_CH2_DMA_PRIORITY) |
+                  STM32_DMA_CR_MINC | STM32_DMA_CR_CIRC | STM32_DMA_CR_DIR_M2P |
+                  STM32_DMA_CR_DMEIE | STM32_DMA_CR_TEIE | STM32_DMA_CR_HTIE |
+                  STM32_DMA_CR_TCIE,
+  .dmairqprio   = STM32_DAC_DAC2_CH2_IRQ_PRIORITY
+};
+#endif
+
+#if STM32_DAC_USE_DAC3_CH1 == TRUE
+static const dacparams_t dac3_ch1_params = {
+  .dac          = DAC3,
+  .dataoffset   = 0U,
+  .regshift     = 0U,
+  .regmask      = CHANNEL_REGISTER_MASK1,
+  .dmastream    = STM32_DAC_DAC3_CH1_DMA_STREAM,
+#if STM32_DMA_SUPPORTS_DMAMUX
+  .peripheral   = STM32_DMAMUX1_DAC3_CH1,
+#endif
+  .dmamode      = STM32_DMA_CR_CHSEL(DAC3_CH1_DMA_CHANNEL) |
+                  STM32_DMA_CR_PL(STM32_DAC_DAC3_CH1_DMA_PRIORITY) |
+                  STM32_DMA_CR_MINC | STM32_DMA_CR_CIRC | STM32_DMA_CR_DIR_M2P |
+                  STM32_DMA_CR_DMEIE | STM32_DMA_CR_TEIE | STM32_DMA_CR_HTIE |
+                  STM32_DMA_CR_TCIE,
+  .dmairqprio   = STM32_DAC_DAC3_CH1_IRQ_PRIORITY
+};
+#endif
+
+#if STM32_DAC_USE_DAC3_CH2 == TRUE
+static const dacparams_t dac3_ch2_params = {
+  .dac          = DAC3,
+  .dataoffset   = CHANNEL_DATA_OFFSET,
+  .regshift     = CHANNEL_REGISTER_SHIFT,
+  .regmask      = CHANNEL_REGISTER_MASK2,
+  .dmastream    = STM32_DAC_DAC3_CH2_DMA_STREAM,
+#if STM32_DMA_SUPPORTS_DMAMUX
+  .peripheral   = STM32_DMAMUX1_DAC3_CH2,
+#endif
+  .dmamode      = STM32_DMA_CR_CHSEL(DAC3_CH2_DMA_CHANNEL) |
+                  STM32_DMA_CR_PL(STM32_DAC_DAC3_CH2_DMA_PRIORITY) |
+                  STM32_DMA_CR_MINC | STM32_DMA_CR_CIRC | STM32_DMA_CR_DIR_M2P |
+                  STM32_DMA_CR_DMEIE | STM32_DMA_CR_TEIE | STM32_DMA_CR_HTIE |
+                  STM32_DMA_CR_TCIE,
+  .dmairqprio   = STM32_DAC_DAC3_CH2_IRQ_PRIORITY
+};
+#endif
+
+#if STM32_DAC_USE_DAC4_CH1 == TRUE
+static const dacparams_t dac4_ch1_params = {
+  .dac          = DAC4,
+  .dataoffset   = 0U,
+  .regshift     = 0U,
+  .regmask      = CHANNEL_REGISTER_MASK1,
+  .dmastream    = STM32_DAC_DAC4_CH1_DMA_STREAM,
+#if STM32_DMA_SUPPORTS_DMAMUX
+  .peripheral   = STM32_DMAMUX1_DAC4_CH1,
+#endif
+  .dmamode      = STM32_DMA_CR_CHSEL(DAC4_CH1_DMA_CHANNEL) |
+                  STM32_DMA_CR_PL(STM32_DAC_DAC4_CH1_DMA_PRIORITY) |
+                  STM32_DMA_CR_MINC | STM32_DMA_CR_CIRC | STM32_DMA_CR_DIR_M2P |
+                  STM32_DMA_CR_DMEIE | STM32_DMA_CR_TEIE | STM32_DMA_CR_HTIE |
+                  STM32_DMA_CR_TCIE,
+  .dmairqprio   = STM32_DAC_DAC4_CH1_IRQ_PRIORITY
+};
+#endif
+
+#if STM32_DAC_USE_DAC4_CH2 == TRUE
+static const dacparams_t dac4_ch2_params = {
+  .dac          = DAC4,
+  .dataoffset   = CHANNEL_DATA_OFFSET,
+  .regshift     = CHANNEL_REGISTER_SHIFT,
+  .regmask      = CHANNEL_REGISTER_MASK2,
+  .dmastream    = STM32_DAC_DAC4_CH2_DMA_STREAM,
+#if STM32_DMA_SUPPORTS_DMAMUX
+  .peripheral   = STM32_DMAMUX1_DAC4_CH2,
+#endif
+  .dmamode      = STM32_DMA_CR_CHSEL(DAC4_CH2_DMA_CHANNEL) |
+                  STM32_DMA_CR_PL(STM32_DAC_DAC4_CH2_DMA_PRIORITY) |
+                  STM32_DMA_CR_MINC | STM32_DMA_CR_CIRC | STM32_DMA_CR_DIR_M2P |
+                  STM32_DMA_CR_DMEIE | STM32_DMA_CR_TEIE | STM32_DMA_CR_HTIE |
+                  STM32_DMA_CR_TCIE,
+  .dmairqprio   = STM32_DAC_DAC4_CH2_IRQ_PRIORITY
+};
+#endif
+
+/*===========================================================================*/
+/* Driver local functions.                                                   */
+/*===========================================================================*/
+
+/**
+ * @brief   Shared end/half-of-tx service routine.
+ *
+ * @param[in] dacp      pointer to the @p DACDriver object
+ * @param[in] flags     pre-shifted content of the ISR register
+ */
+static void dac_lld_serve_tx_interrupt(DACDriver *dacp, uint32_t flags) {
+
+  if ((flags & (STM32_DMA_ISR_TEIF | STM32_DMA_ISR_DMEIF)) != 0) {
+    /* DMA errors handling.*/
+    dac_lld_stop_conversion(dacp);
+    _dac_isr_error_code(dacp, DAC_ERR_DMAFAILURE);
+  }
+  else {
+    if ((flags & STM32_DMA_ISR_HTIF) != 0) {
+      /* Half transfer processing.*/
+      _dac_isr_half_code(dacp);
+    }
+    if ((flags & STM32_DMA_ISR_TCIF) != 0) {
+      /* Transfer complete processing.*/
+      _dac_isr_full_code(dacp);
+    }
+  }
+}
+
+/*===========================================================================*/
+/* Driver interrupt handlers.                                                */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver exported functions.                                                */
+/*===========================================================================*/
+
+/**
+ * @brief   Low level DAC driver initialization.
+ *
+ * @notapi
+ */
+void dac_lld_init(void) {
+
+#if STM32_DAC_USE_DAC1_CH1
+  dacObjectInit(&DACD1);
+  DACD1.params  = &dac1_ch1_params;
+  DACD1.dma = NULL;
+#endif
+
+#if STM32_DAC_USE_DAC1_CH2
+  dacObjectInit(&DACD2);
+  DACD2.params  = &dac1_ch2_params;
+  DACD2.dma = NULL;
+#endif
+
+#if STM32_DAC_USE_DAC2_CH1
+  dacObjectInit(&DACD3);
+  DACD3.params  = &dac2_ch1_params;
+  DACD3.dma = NULL;
+#endif
+
+#if STM32_DAC_USE_DAC2_CH2
+  dacObjectInit(&DACD4);
+  DACD4.params  = &dac2_ch2_params;
+  DACD4.dma = NULL;
+#endif
+
+#if STM32_DAC_USE_DAC3_CH1
+  dacObjectInit(&DACD5);
+  DACD5.params  = &dac3_ch1_params;
+  DACD5.dma = NULL;
+#endif
+
+#if STM32_DAC_USE_DAC3_CH2
+  dacObjectInit(&DACD6);
+  DACD6.params  = &dac3_ch2_params;
+  DACD6.dma = NULL;
+#endif
+
+#if STM32_DAC_USE_DAC4_CH1
+  dacObjectInit(&DACD7);
+  DACD7.params  = &dac4_ch1_params;
+  DACD7.dma = NULL;
+#endif
+
+#if STM32_DAC_USE_DAC4_CH2
+  dacObjectInit(&DACD8);
+  DACD8.params  = &dac4_ch2_params;
+  DACD8.dma = NULL;
+#endif
+}
+
+/**
+ * @brief   Configures and activates the DAC peripheral.
+ *
+ * @param[in] dacp      pointer to the @p DACDriver object
+ *
+ * @notapi
+ */
+void dac_lld_start(DACDriver *dacp) {
+
+  /* If the driver is in DAC_STOP state then a full initialization is
+     required.*/
+  if (dacp->state == DAC_STOP) {
+    dacchannel_t channel = 0;
+
+    /* Enabling the clock source.*/
+#if STM32_DAC_USE_DAC1_CH1
+    if (&DACD1 == dacp) {
+      rccEnableDAC1(true);
+    }
+#endif
+
+#if STM32_DAC_USE_DAC1_CH2
+    if (&DACD2 == dacp) {
+      rccEnableDAC1(true);
+      channel = 1;
+    }
+#endif
+
+#if STM32_DAC_USE_DAC2_CH1
+    if (&DACD3 == dacp) {
+      rccEnableDAC2(true);
+    }
+#endif
+
+#if STM32_DAC_USE_DAC2_CH2
+    if (&DACD4 == dacp) {
+      rccEnableDAC2(true);
+      channel = 1;
+    }
+#endif
+
+#if STM32_DAC_USE_DAC3_CH1
+    if (&DACD5 == dacp) {
+      rccEnableDAC3(true);
+    }
+#endif
+
+#if STM32_DAC_USE_DAC3_CH2
+    if (&DACD6 == dacp) {
+      rccEnableDAC3(true);
+      channel = 1;
+    }
+#endif
+
+#if STM32_DAC_USE_DAC4_CH1
+    if (&DACD7 == dacp) {
+      rccEnableDAC4(true);
+    }
+#endif
+
+#if STM32_DAC_USE_DAC4_CH2
+    if (&DACD8 == dacp) {
+      rccEnableDAC4(true);
+      channel = 1;
+    }
+#endif
+
+    /* Enabling DAC in SW triggering mode initially, initializing data to
+       configuration default.*/
+
+    uint32_t reg;
+
+#if STM32_DAC_DUAL_MODE == FALSE
+    {
+      /* Operating in SINGLE mode with one channel to set. Set registers for
+         specified channel from configuration. Lower half word of
+         configuration specifies configuration for any channel.*/
+      reg = dacp->params->dac->MCR & dacp->params->regmask;
+      dacp->params->dac->MCR = reg |
+        ((dacp->config->mcr & ~dacp->params->regmask) << dacp->params->regshift);
+
+      /* Enable and initialise the channel.*/
+      reg = dacp->params->dac->CR;
+      reg &= dacp->params->regmask;
+      reg |= (DAC_CR_EN1 | dacp->config->cr) << dacp->params->regshift;
+      dacp->params->dac->CR = reg;
+      dac_lld_put_channel(dacp, channel, (dacsample_t)dacp->config->init);
+    }
+#else /* STM32_DAC_DUAL_MODE != FALSE */
+    /* Operating in DUAL mode with two channels to setup. Set registers for
+       both channels from configuration. Lower and upper half words specify
+       configuration for channels CH1 & CH2 respectively.*/
+    (void)channel;
+    dacp->params->dac->MCR = dacp->config->mcr;
+
+    /* Enable and initialise both CH1 and CH2. Mask out DMA and calibrate.*/
+    reg = dacp->config->cr;
+    reg &= ~(DAC_CR_DMAEN1 | DAC_CR_DMAEN2 | DAC_CR_CEN1 | DAC_CR_CEN2);
+    dacp->params->dac->CR = DAC_CR_EN2 | DAC_CR_EN1 | reg;
+    dac_lld_put_channel(dacp, 0U, (dacsample_t)dacp->config->init);
+    dac_lld_put_channel(dacp, 1U, (dacsample_t)(dacp->config->init >>
+                                               (sizeof(dacsample_t) * 8)));
+#endif /* STM32_DAC_DUAL_MODE == FALSE */
+  }
+}
+
+/**
+ * @brief   Deactivates the DAC peripheral.
+ *
+ * @param[in] dacp      pointer to the @p DACDriver object
+ *
+ * @notapi
+ */
+void dac_lld_stop(DACDriver *dacp) {
+
+  /* If in ready state then disables the DAC clock.*/
+  if (dacp->state == DAC_READY) {
+
+    /* Disabling DAC.*/
+    dacp->params->dac->CR &= dacp->params->regmask;
+
+#if STM32_DAC_USE_DAC1_CH1
+    if (&DACD1 == dacp) {
+#if defined(DAC_CR_EN2)
+      if ((dacp->params->dac->CR & DAC_CR_EN2) == 0U) {
+        rccDisableDAC1();
+      }
+#else
+      rccDisableDAC1();
+#endif
+    }
+#endif
+
+#if STM32_DAC_USE_DAC1_CH2
+    if (&DACD2 == dacp) {
+      if ((dacp->params->dac->CR & DAC_CR_EN1) == 0U) {
+        rccDisableDAC1();
+      }
+    }
+#endif
+
+#if STM32_DAC_USE_DAC2_CH1
+    if (&DACD3 == dacp) {
+#if defined(DAC_CR_EN2)
+      if ((dacp->params->dac->CR & DAC_CR_EN2) == 0U) {
+        rccDisableDAC2();
+      }
+#else
+      rccDisableDAC2();
+#endif
+    }
+#endif
+
+#if STM32_DAC_USE_DAC2_CH2
+    if (&DACD4 == dacp) {
+      if ((dacp->params->dac->CR & DAC_CR_EN1) == 0U) {
+        rccDisableDAC2();
+      }
+    }
+#endif
+
+#if STM32_DAC_USE_DAC3_CH1
+    if (&DACD5 == dacp) {
+#if defined(DAC_CR_EN2)
+      if ((dacp->params->dac->CR & DAC_CR_EN2) == 0U) {
+        rccDisableDAC3();
+      }
+#else
+      rccDisableDAC3();
+#endif
+    }
+#endif
+
+#if STM32_DAC_USE_DAC3_CH2
+    if (&DACD6 == dacp) {
+      if ((dacp->params->dac->CR & DAC_CR_EN1) == 0U) {
+        rccDisableDAC3();
+      }
+    }
+#endif
+
+#if STM32_DAC_USE_DAC4_CH1
+    if (&DACD7 == dacp) {
+#if defined(DAC_CR_EN2)
+      if ((dacp->params->dac->CR & DAC_CR_EN2) == 0U) {
+        rccDisableDAC4();
+      }
+#else
+      rccDisableDAC4();
+#endif
+    }
+#endif
+
+#if STM32_DAC_USE_DAC4_CH2
+    if (&DACD8 == dacp) {
+      if ((dacp->params->dac->CR & DAC_CR_EN1) == 0U) {
+        rccDisableDAC4();
+      }
+    }
+#endif
+  }
+}
+
+/**
+ * @brief   Outputs a value directly on a DAC channel.
+ * @note    While a group is active in DUAL mode on CH1 only then CH2
+ *          is available for normal output (put) operations.
+ *
+ * @param[in] dacp      pointer to the @p DACDriver object
+ * @param[in] channel   DAC channel number
+ * @param[in] sample    value to be output
+ *
+ * @api
+ */
+void dac_lld_put_channel(DACDriver *dacp, dacchannel_t channel,
+                                               dacsample_t sample) {
+
+#if STM32_DAC_DUAL_MODE
+  if (dacp->grpp != NULL) {
+    osalDbgAssert(dacp->grpp->num_channels == 1 && channel == 1,
+                                          "channel busy");
+  }
+#endif /* STM32_DAC_DUAL_MODE */
+
+  switch (dacp->config->datamode) {
+  case DAC_DHRM_12BIT_RIGHT:
+#if STM32_DAC_DUAL_MODE
+  case DAC_DHRM_12BIT_RIGHT_DUAL:
+#endif
+    if (channel == 0U) {
+#if STM32_DAC_DUAL_MODE
+      dacp->params->dac->DHR12R1 = (uint32_t)sample;
+#else
+      *(&dacp->params->dac->DHR12R1 + dacp->params->dataoffset) =
+                                                    (uint32_t)sample;
+#endif
+    }
+#if (STM32_HAS_DAC1_CH2 || STM32_HAS_DAC2_CH2 ||                            \
+     STM32_HAS_DAC3_CH2 || STM32_HAS_DAC4_CH2)
+    else {
+      dacp->params->dac->DHR12R2 = (uint32_t)sample;
+    }
+#endif
+    break;
+  case DAC_DHRM_12BIT_LEFT:
+#if STM32_DAC_DUAL_MODE
+  case DAC_DHRM_12BIT_LEFT_DUAL:
+#endif
+    if (channel == 0U) {
+#if STM32_DAC_DUAL_MODE
+      dacp->params->dac->DHR12L1 = (uint32_t)sample;
+#else
+      *(&dacp->params->dac->DHR12L1 + dacp->params->dataoffset) =
+                                                    (uint32_t)sample;
+#endif
+    }
+#if (STM32_HAS_DAC1_CH2 || STM32_HAS_DAC2_CH2 ||                            \
+     STM32_HAS_DAC3_CH2 || STM32_HAS_DAC4_CH2)
+    else {
+      dacp->params->dac->DHR12L2 = (uint32_t)sample;
+    }
+#endif
+    break;
+  case DAC_DHRM_8BIT_RIGHT:
+#if STM32_DAC_DUAL_MODE
+  case DAC_DHRM_8BIT_RIGHT_DUAL:
+#endif
+    if (channel == 0U) {
+#if STM32_DAC_DUAL_MODE
+      dacp->params->dac->DHR8R1 = (uint32_t)sample;
+#else
+      *(&dacp->params->dac->DHR8R1 + dacp->params->dataoffset) =
+                                                    (uint32_t)sample;
+#endif
+    }
+#if (STM32_HAS_DAC1_CH2 || STM32_HAS_DAC2_CH2 ||                            \
+     STM32_HAS_DAC3_CH2 || STM32_HAS_DAC4_CH2)
+    else {
+      dacp->params->dac->DHR8R2 = (uint32_t)sample;
+    }
+#endif
+    break;
+  default:
+    osalDbgAssert(false, "unexpected DAC mode");
+    break;
+  }
+}
+
+/**
+ * @brief   Starts a DAC conversion.
+ * @details Starts an asynchronous conversion operation.
+ * @note    In @p DAC_DHRM_8BIT_RIGHT mode the parameters passed to the
+ *          callback are wrong because two samples are packed in a single
+ *          dacsample_t element. This will not be corrected, do not rely
+ *          on those parameters.
+ * @note    In @p DAC_DHRM_8BIT_RIGHT_DUAL mode two samples are treated
+ *          as a single 16 bits sample and packed into a single dacsample_t
+ *          element. The num_channels must be set to one in the group
+ *          conversion configuration structure.
+ * @note    If using DUAL mode with a single channel conversion then CH2
+ *          is enabled for manual (put_channel) for non DMA triggered use. The
+ *          the data format for put operations is specified in the upper half
+ *          word of the 'datamode' field. The CR setting is in the upper half
+ *          word of the 'cr' field of the configuration.
+ *
+ * @param[in] dacp      pointer to the @p DACDriver object
+ *
+ * @notapi
+ */
+void dac_lld_start_conversion(DACDriver *dacp) {
+  uint32_t n, cr, dmamode;
+
+  /* Number of DMA operations per buffer.*/
+  n = dacp->depth * dacp->grpp->num_channels;
+
+  /* Allocating the DMA channel.*/
+  dacp->dma = dmaStreamAllocI(dacp->params->dmastream,
+                              dacp->params->dmairqprio,
+                              (stm32_dmaisr_t)dac_lld_serve_tx_interrupt,
+                              (void *)dacp);
+  osalDbgAssert(dacp->dma != NULL, "unable to allocate stream");
+#if STM32_DMA_SUPPORTS_DMAMUX
+  dmaSetRequestSource(dacp->dma, dacp->params->peripheral);
+#endif
+
+  /* DMA settings depend on the chosen DAC mode.*/
+  switch (dacp->config->datamode) {
+  /* Sets the DAC data register */
+  case DAC_DHRM_12BIT_RIGHT:
+    osalDbgAssert(dacp->grpp->num_channels == 1, "invalid number of channels");
+
+    dmaStreamSetPeripheral(dacp->dma, &dacp->params->dac->DHR12R1 +
+                                      dacp->params->dataoffset);
+    dmamode = dacp->params->dmamode |
+#if STM32_DMA_ADVANCED == FALSE
+              STM32_DMA_CR_PSIZE_WORD  | STM32_DMA_CR_MSIZE_HWORD;
+#else
+              STM32_DMA_CR_PSIZE_HWORD | STM32_DMA_CR_MSIZE_HWORD;
+#endif
+    break;
+  case DAC_DHRM_12BIT_LEFT:
+    osalDbgAssert(dacp->grpp->num_channels == 1, "invalid number of channels");
+
+    dmaStreamSetPeripheral(dacp->dma, &dacp->params->dac->DHR12L1 +
+                                      dacp->params->dataoffset);
+    dmamode = dacp->params->dmamode |
+#if STM32_DMA_ADVANCED == FALSE
+              STM32_DMA_CR_PSIZE_WORD  | STM32_DMA_CR_MSIZE_HWORD;
+#else
+              STM32_DMA_CR_PSIZE_HWORD | STM32_DMA_CR_MSIZE_HWORD;
+#endif
+    break;
+  case DAC_DHRM_8BIT_RIGHT:
+    osalDbgAssert(dacp->grpp->num_channels == 1, "invalid number of channels");
+
+    dmaStreamSetPeripheral(dacp->dma, &dacp->params->dac->DHR8R1 +
+                                      dacp->params->dataoffset);
+    dmamode = dacp->params->dmamode |
+#if STM32_DMA_ADVANCED == FALSE
+              STM32_DMA_CR_PSIZE_WORD  | STM32_DMA_CR_MSIZE_BYTE;
+#else
+              STM32_DMA_CR_MSIZE_BYTE  | STM32_DMA_CR_MSIZE_BYTE;
+#endif
+
+    /* In this mode the size of the buffer is halved because two samples
+       packed in a single dacsample_t element.*/
+    n = (n + 1) / 2;
+    break;
+#if STM32_DAC_DUAL_MODE == TRUE
+  case DAC_DHRM_12BIT_RIGHT_DUAL:
+    osalDbgAssert(dacp->grpp->num_channels == 2, "invalid number of channels");
+
+    dmaStreamSetPeripheral(dacp->dma, &dacp->params->dac->DHR12RD);
+    dmamode = dacp->params->dmamode |
+              STM32_DMA_CR_PSIZE_WORD | STM32_DMA_CR_MSIZE_WORD;
+    n /= 2;
+    break;
+  case DAC_DHRM_12BIT_LEFT_DUAL:
+    osalDbgAssert(dacp->grpp->num_channels == 2, "invalid number of channels");
+
+    dmaStreamSetPeripheral(dacp->dma, &dacp->params->dac->DHR12LD);
+    dmamode = dacp->params->dmamode |
+              STM32_DMA_CR_PSIZE_WORD | STM32_DMA_CR_MSIZE_WORD;
+    n /= 2;
+    break;
+  case DAC_DHRM_8BIT_RIGHT_DUAL:
+    osalDbgAssert(dacp->grpp->num_channels == 1, "invalid number of channels");
+
+    dmaStreamSetPeripheral(dacp->dma, &dacp->params->dac->DHR8RD);
+    dmamode = dacp->params->dmamode |
+#if STM32_DMA_ADVANCED == FALSE
+              STM32_DMA_CR_PSIZE_WORD  | STM32_DMA_CR_MSIZE_HWORD;
+#else
+              STM32_DMA_CR_PSIZE_HWORD | STM32_DMA_CR_MSIZE_HWORD;
+#endif
+    n /= 2;
+    break;
+#endif
+  default:
+    osalDbgAssert(false, "unexpected DAC mode");
+    return;
+  }
+
+  dmaStreamSetMemory0(dacp->dma, dacp->samples);
+  dmaStreamSetTransactionSize(dacp->dma, n);
+  dmaStreamSetMode(dacp->dma, dmamode            |
+                              STM32_DMA_CR_DMEIE | STM32_DMA_CR_TEIE |
+                              STM32_DMA_CR_HTIE  | STM32_DMA_CR_TCIE);
+  dmaStreamEnable(dacp->dma);
+
+  /* DAC configuration. Mask out DMA and calibration.*/
+  cr = dacp->params->dac->CR;
+  cr &= ~(DAC_CR_CEN1 | DAC_CR_CEN2 | DAC_CR_DMAEN2);
+#if STM32_DAC_DUAL_MODE == FALSE
+  /* Start the DMA on the single channel.*/
+  cr &= dacp->params->regmask;
+  cr |= (DAC_CR_DMAEN1 | (dacp->grpp->trigger << DAC_CR_TSEL1_Pos) |
+      DAC_CR_TEN1 | DAC_CR_EN1 | dacp->config->cr) << dacp->params->regshift;
+#else
+  /* Enable the DMA operation on CH1.*/
+  cr = DAC_CR_DMAEN1 | (dacp->grpp->trigger << DAC_CR_TSEL1_Pos) |
+       DAC_CR_TEN1 | DAC_CR_EN1 | dacp->config->cr;
+#endif
+
+  dacp->params->dac->CR = cr;
+}
+
+/**
+ * @brief   Stops an ongoing conversion.
+ * @details This function stops the currently ongoing conversion. The
+ *          configuration is restored to start condition. The DOR values
+ *          are not updated.
+ *
+ * @param[in] dacp      pointer to the @p DACDriver object
+ *
+ * @iclass
+ */
+void dac_lld_stop_conversion(DACDriver *dacp) {
+
+  uint32_t cr;
+
+  /* DMA channel disabled and released.*/
+  dmaStreamDisable(dacp->dma);
+  dmaStreamFreeI(dacp->dma);
+  dacp->dma = NULL;
+
+  /* Restore start configuration but leave DORx at current values.*/
+  cr = dacp->params->dac->CR;
+#if STM32_DAC_DUAL_MODE == FALSE
+  uint32_t mcr;
+  mcr = dacp->params->dac->MCR & dacp->params->regmask;
+  dacp->params->dac->MCR = mcr |
+    ((dacp->config->mcr & dacp->params->regmask) << dacp->params->regshift);
+  cr &= dacp->params->regmask;
+  cr |= (DAC_CR_EN1 | (dacp->config->cr & ~dacp->params->regmask)) <<
+                                      dacp->params->regshift;
+#else
+  dacp->params->dac->MCR = dacp->config->mcr;
+  cr = dacp->config->cr | DAC_CR_EN1 | DAC_CR_EN2;
+#endif
+
+  dacp->params->dac->CR = cr;
+}
+
+#endif /* HAL_USE_DAC */
+
+/** @} */
Index: hal/src/hal_dac.c
===================================================================
--- hal/src/hal_dac.c	(revision 16161)
+++ hal/src/hal_dac.c	(working copy)
@@ -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 */
+
+/** @} */
