aboutsummaryrefslogtreecommitdiffstats
path: root/os
diff options
context:
space:
mode:
authoredolomb <none@example.com>2017-10-31 09:56:52 +0000
committeredolomb <none@example.com>2017-10-31 09:56:52 +0000
commited6245c58f40d64d77dde8f0aac0b1d9b20a1966 (patch)
tree0711b90fcae8d30704b9714cf108eebba25009e2 /os
parent4b17048a2e72369f95bd374dfa3368843ff36d8f (diff)
downloadChibiOS-ed6245c58f40d64d77dde8f0aac0b1d9b20a1966.tar.gz
ChibiOS-ed6245c58f40d64d77dde8f0aac0b1d9b20a1966.tar.bz2
ChibiOS-ed6245c58f40d64d77dde8f0aac0b1d9b20a1966.zip
Added TC driver in waveform mode
git-svn-id: svn://svn.code.sf.net/p/chibios/svn/trunk@10913 35acf78f-673a-0410-8e92-d51de3d6d3f4
Diffstat (limited to 'os')
-rw-r--r--os/hal/ports/SAMA/SAMA5D2x/hal_tc_lld.c571
-rw-r--r--os/hal/ports/SAMA/SAMA5D2x/hal_tc_lld.h338
2 files changed, 909 insertions, 0 deletions
diff --git a/os/hal/ports/SAMA/SAMA5D2x/hal_tc_lld.c b/os/hal/ports/SAMA/SAMA5D2x/hal_tc_lld.c
new file mode 100644
index 000000000..4c3ecd9e1
--- /dev/null
+++ b/os/hal/ports/SAMA/SAMA5D2x/hal_tc_lld.c
@@ -0,0 +1,571 @@
+/*
+ ChibiOS - Copyright (C) 2006..2016 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 SAMA5D2x/hal_tc_lld.c
+ * @brief SAMA TC subsystem low level driver header.
+ *
+ * @addtogroup TC
+ * @{
+ */
+
+#include "hal.h"
+
+#if HAL_USE_TC || defined(__DOXYGEN__)
+
+/*===========================================================================*/
+/* Driver local macros. */
+/*===========================================================================*/
+
+/**
+ * @brief Enable write protection on TC registers block.
+ *
+ * @param[in] tcp pointer to a TC register block
+ *
+ * @notapi
+ */
+#define tcEnableWP(tcp) { \
+ tcp->tim->TC_WPMR = TC_WPMR_WPKEY_PASSWD | TC_WPMR_WPEN; \
+}
+
+/**
+ * @brief Disable write protection on TC registers block.
+ *
+ * @param[in] tcp pointer to a TC register block
+ *
+ * @notapi
+ */
+#define tcDisableWP(tcp) { \
+ tcp->tim->TC_WPMR = TC_WPMR_WPKEY_PASSWD; \
+}
+
+/*===========================================================================*/
+/* Driver exported variables. */
+/*===========================================================================*/
+
+/**
+ * @brief TCD0 driver identifier.
+ * @note The driver TCD0 allocates the timer TC0 when enabled.
+ */
+#if SAMA_USE_TC0 || defined(__DOXYGEN__)
+TCDriver TCD0;
+#endif
+
+/**
+ * @brief TCD1 driver identifier.
+ * @note The driver TCD1 allocates the timer TC1 when enabled.
+ */
+#if SAMA_USE_TC1 || defined(__DOXYGEN__)
+TCDriver TCD1;
+#endif
+
+/*===========================================================================*/
+/* Driver local variables and types. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver local functions. */
+/*===========================================================================*/
+/**
+ * @brief Common IRQ handler.
+ * @note It is assumed that the various sources are only activated if the
+ * associated callback pointer is not equal to @p NULL in order to not
+ * perform an extra check in a potentially critical interrupt handler.
+ *
+ * @param[in] tcp pointer to a @p TCDriver object
+ *
+ * @notapi
+ */
+void tc_lld_serve_interrupt(TCDriver *tcp) {
+ uint32_t sr, imr, i;
+
+ for (i = 0; i < TC_CHANNELS; i++) {
+ sr = tcp->tim->TC_CHANNEL[i].TC_SR;
+ imr = tcp->tim->TC_CHANNEL[i].TC_IMR;
+ if (((sr & TC_SR_CPCS) != 0) && ((imr & TC_IMR_CPCS) != 0) &&
+ (tcp->config->channels[i].callback != NULL)) {
+ tcp->config->channels[i].callback(tcp);
+ }
+ }
+}
+/*===========================================================================*/
+/* Driver interrupt handlers. */
+/*===========================================================================*/
+
+#if SAMA_USE_TC0 || defined(__DOXYGEN__)
+#if !defined(SAMA_TC0_SUPPRESS_ISR)
+/**
+ * @brief TC0 interrupt handler.
+ * @note It is assumed that this interrupt is only activated if the callback
+ * pointer is not equal to @p NULL in order to not perform an extra
+ * check in a potentially critical interrupt handler.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(SAMA_TC0_HANDLER) {
+
+ OSAL_IRQ_PROLOGUE();
+
+ tc_lld_serve_interrupt(&TCD0);
+ aicAckInt();
+ OSAL_IRQ_EPILOGUE();
+}
+#endif /* !defined(SAMA_TC0_SUPPRESS_ISR) */
+#endif /* SAMA_USE_TC0 */
+
+#if SAMA_USE_TC1 || defined(__DOXYGEN__)
+#if !defined(SAMA_TC1_SUPPRESS_ISR)
+/**
+ * @brief TC1 interrupt handler.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(SAMA_TC1_HANDLER) {
+
+ OSAL_IRQ_PROLOGUE();
+
+ tc_lld_serve_interrupt(&TCD1);
+ aicAckInt();
+ OSAL_IRQ_EPILOGUE();
+}
+#endif /* !defined(SAMA_TC1_SUPPRESS_ISR) */
+#endif /* SAMA_USE_TC1 */
+
+/*===========================================================================*/
+/* Driver exported functions. */
+/*===========================================================================*/
+
+/**
+ * @brief Low level TC driver initialization.
+ *
+ * @notapi
+ */
+void tc_lld_init(void) {
+
+#if SAMA_USE_TC0
+ /* Driver initialization.*/
+ tcObjectInit(&TCD0);
+ TCD0.channels = TC_CHANNELS;
+ TCD0.tim = TC0;
+ TCD0.clock = SAMA_TC0CLK;
+#endif
+
+#if SAMA_USE_TC1
+ /* Driver initialization.*/
+ tcObjectInit(&TCD1);
+ TCD1.channels = TC_CHANNELS;
+ TCD1.tim = TC1;
+ TCD1.clock = SAMA_TC1CLK;
+#endif
+
+}
+
+/**
+ * @brief Configures and activates the TC peripheral.
+ *
+ * @param[in] tcp pointer to a @p TCDriver object
+ *
+ * @notapi
+ */
+void tc_lld_start(TCDriver *tcp) {
+ uint32_t rc = 0;
+
+ if (tcp->state == TC_STOP) {
+ /* Clock activation.*/
+#if SAMA_USE_TC0
+ if (&TCD0 == tcp) {
+ pmcEnableTC0();
+#if !defined(SAMA_TC0_SUPPRESS_ISR)
+ aicSetSourcePriority(ID_TC0, SAMA_TC0_IRQ_PRIORITY);
+ aicSetSourceHandler(ID_TC0, SAMA_TC0_HANDLER);
+ aicEnableInt(ID_TC0);
+#endif
+ }
+#endif
+
+#if SAMA_USE_TC1
+ if (&TCD1 == tcp) {
+ pmcEnableTC1();
+#if !defined(SAMA_TC1_SUPPRESS_ISR)
+ aicSetSourcePriority(ID_TC1, SAMA_TC1_IRQ_PRIORITY);
+ aicSetSourceHandler(ID_TC1, SAMA_TC1_HANDLER);
+ aicEnableInt(ID_TC1);
+#endif
+ }
+#endif
+ }
+ /* Disable Write Protection */
+ tcDisableWP(tcp);
+ /* Output enables*/
+ switch (tcp->config->channels[0].mode & TC_OUTPUT_MASK) {
+ case TC_OUTPUT_ACTIVE:
+ rc = (tcp->clock) / (tcp->config->channels[0].frequency);
+ tcp->tim->TC_CHANNEL[0].TC_EMR = TC_EMR_NODIVCLK;
+ tcp->tim->TC_CHANNEL[0].TC_CMR = TC_CMR_WAVE | TC_CMR_ACPA_SET |
+ TC_CMR_ACPC_CLEAR | TC_CMR_WAVSEL_UP_RC;
+
+ tcp->tim->TC_CHANNEL[0].TC_RC = TC_RC_RC(rc);
+ tcp->tim->TC_CHANNEL[0].TC_SR; /* Clear pending IRQs. */
+ default:
+ ;
+ }
+ switch (tcp->config->channels[1].mode & TC_OUTPUT_MASK) {
+ case TC_OUTPUT_ACTIVE:
+ rc = (tcp->clock) / (tcp->config->channels[1].frequency);
+ tcp->tim->TC_CHANNEL[1].TC_EMR = TC_EMR_NODIVCLK;
+ tcp->tim->TC_CHANNEL[1].TC_CMR = TC_CMR_WAVE | TC_CMR_ACPA_SET |
+ TC_CMR_ACPC_CLEAR | TC_CMR_WAVSEL_UP_RC;
+
+ tcp->tim->TC_CHANNEL[1].TC_RC = TC_RC_RC(rc);
+ tcp->tim->TC_CHANNEL[1].TC_SR; /* Clear pending IRQs. */
+ default:
+ ;
+ }
+ switch (tcp->config->channels[2].mode & TC_OUTPUT_MASK) {
+ case TC_OUTPUT_ACTIVE:
+ rc = (tcp->clock) / (tcp->config->channels[2].frequency);
+ tcp->tim->TC_CHANNEL[2].TC_EMR = TC_EMR_NODIVCLK;
+ tcp->tim->TC_CHANNEL[2].TC_CMR = TC_CMR_WAVE | TC_CMR_ACPA_SET |
+ TC_CMR_ACPC_CLEAR | TC_CMR_WAVSEL_UP_RC;
+
+ tcp->tim->TC_CHANNEL[2].TC_RC = TC_RC_RC(rc);
+ tcp->tim->TC_CHANNEL[2].TC_SR; /* Clear pending IRQs. */
+ default:
+ ;
+ }
+ /* Enable Write Protection */
+ tcEnableWP(tcp);
+}
+
+/**
+ * @brief Deactivates the TC peripheral.
+ *
+ * @param[in] tcp pointer to a @p TCDriver object
+ *
+ * @notapi
+ */
+void tc_lld_stop(TCDriver *tcp) {
+
+ /* If in ready state then disables the TC clock.*/
+ if (tcp->state == TC_READY) {
+#if SAMA_USE_TC0
+ if (&TCD0 == tcp) {
+ aicDisableInt(ID_TC0);
+ pmcDisableTC0();
+ }
+#endif
+
+#if SAMA_USE_TC1
+ if (&TCD1 == tcp) {
+ aicDisableInt(ID_TC1);
+ pmcDisableTC1();
+ }
+#endif
+ }
+}
+
+/**
+ * @brief Enables a TC channel.
+ * @pre The TC unit must have been activated using @p tcStart().
+ * @post The channel is active using the specified configuration.
+ * @note The function has effect at the next cycle start.
+ * @note Channel notification is not enabled.
+ *
+ * @param[in] tcp pointer to a @p TCDriver object
+ * @param[in] channel TC channel identifier (0...channels-1)
+ * @param[in] width TC pulse width as clock pulses number
+ *
+ * @notapi
+ */
+void tc_lld_enable_channel(TCDriver *tcp,
+ tcchannel_t channel,
+ tccnt_t width) {
+ /* Disable Write Protection */
+ tcDisableWP(tcp);
+
+ /* Changing channel duty cycle on the fly.*/
+ uint32_t rc = tcp->tim->TC_CHANNEL[channel].TC_RC;
+ tcp->tim->TC_CHANNEL[channel].TC_RA = TC_RA_RA((100 - width) * rc / 100);
+ tcp->tim->TC_CHANNEL[channel].TC_CCR = TC_CCR_CLKEN;
+ tcp->tim->TC_CHANNEL[channel].TC_CCR = TC_CCR_SWTRG;
+
+ /* Enable Write Protection */
+ tcEnableWP(tcp);
+}
+
+/**
+ * @brief Disables a TC channel and its notification.
+ * @pre The TC unit must have been activated using @p tcStart().
+ * @post The channel is disabled and its output line returned to the
+ * idle state.
+ * @note The function has effect at the next cycle start.
+ *
+ * @param[in] tcp pointer to a @p TCDriver object
+ * @param[in] channel TC channel identifier (0...channels-1)
+ *
+ * @notapi
+ */
+void tc_lld_disable_channel(TCDriver *tcp, tcchannel_t channel) {
+
+ tcp->tim->TC_CHANNEL[channel].TC_CCR = TC_CCR_CLKDIS;
+}
+
+/**
+ * @brief Enables a channel de-activation edge notification.
+ * @pre The TC unit must have been activated using @p tcStart().
+ * @pre The channel must have been activated using @p tcEnableChannel().
+ * @note If the notification is already enabled then the call has no effect.
+ *
+ * @param[in] tcp pointer to a @p TCDriver object
+ * @param[in] channel TC channel identifier (0...channels-1)
+ *
+ * @notapi
+ */
+void tc_lld_enable_channel_notification(TCDriver *tcp,
+ tcchannel_t channel) {
+ tcp->tim->TC_CHANNEL[channel].TC_IER |= TC_IER_CPCS;
+}
+
+/**
+ * @brief Disables a channel de-activation edge notification.
+ * @pre The TC unit must have been activated using @p tcStart().
+ * @pre The channel must have been activated using @p tcEnableChannel().
+ * @note If the notification is already disabled then the call has no effect.
+ *
+ * @param[in] tcp pointer to a @p TCDriver object
+ * @param[in] channel TC channel identifier (0...channels-1)
+ *
+ * @notapi
+ */
+void tc_lld_disable_channel_notification(TCDriver *tcp,
+ tcchannel_t channel) {
+
+ tcp->tim->TC_CHANNEL[channel].TC_IDR |= TC_IDR_CPCS;
+}
+
+/**
+ * @brief Changes TC channel's frequency.
+ * @pre The TC unit must have been activated using @p tcStart().
+ * @post The channel must be enabled using @p tcEnableChannel().
+ * @note Depending on the hardware implementation this function has
+ * effect starting on the next cycle (recommended implementation)
+ * or immediately (fallback implementation).
+ *
+ * @param[in] tcp pointer to a @p TCDriver object
+ * @param[in] channel TC channel identifier (0...channels-1)
+ *
+ */
+
+void tcChangeChannelFrequency(TCDriver *tcp,
+ tcchannel_t channel,uint32_t frequency) {
+ tcDisableWP(tcp);
+ uint32_t rc =(tcp->clock) / (frequency);
+ tcp->tim->TC_CHANNEL[channel].TC_RC = TC_RC_RC(rc);
+ tcEnableWP(tcp);
+}
+/**
+ * @brief TC Driver initialization.
+ * @note This function is implicitly invoked by @p halInit(), there is
+ * no need to explicitly initialize the driver.
+ *
+ * @init
+ */
+void tcInit(void) {
+
+ tc_lld_init();
+}
+
+/**
+ * @brief Initializes the standard part of a @p TCDriver structure.
+ *
+ * @param[out] tcp pointer to a @p TCDriver object
+ *
+ * @init
+ */
+void tcObjectInit(TCDriver *tcp) {
+
+ tcp->state = TC_STOP;
+ tcp->config = NULL;
+ tcp->enabled = 0;
+ tcp->channels = 0;
+}
+
+
+/**
+ * @brief Configures and activates the TC peripheral.
+ *
+ * @param[in] tcp pointer to a @p TCDriver object
+ * @param[in] config pointer to a @p TCConfig object
+ *
+ * @api
+ */
+void tcStart(TCDriver *tcp, const TCConfig *config) {
+
+ osalDbgCheck((tcp != NULL) && (config != NULL));
+
+ osalSysLock();
+ osalDbgAssert((tcp->state == TC_STOP) || (tcp->state == TC_READY),
+ "invalid state");
+ tcp->config = config;
+ tc_lld_start(tcp);
+ tcp->enabled = 0;
+ tcp->state = TC_READY;
+ osalSysUnlock();
+}
+
+/**
+ * @brief Deactivates the TC peripheral.
+ *
+ * @param[in] tcp pointer to a @p TCDriver object
+ *
+ * @api
+ */
+void tcStop(TCDriver *tcp) {
+
+ osalDbgCheck(tcp != NULL);
+
+ osalSysLock();
+
+ osalDbgAssert((tcp->state == TC_STOP) || (tcp->state == TC_READY),
+ "invalid state");
+
+ tc_lld_stop(tcp);
+ tcp->enabled = 0;
+ tcp->config = NULL;
+ tcp->state = TC_STOP;
+
+ osalSysUnlock();
+}
+
+/**
+ * @brief Enables a TC channel.
+ * @pre The TC unit must have been activated using @p tcStart().
+ * @post The channel is active using the specified configuration.
+ * @note Depending on the hardware implementation this function has
+ * effect starting on the next cycle (recommended implementation)
+ * or immediately (fallback implementation).
+ *
+ * @param[in] tcp pointer to a @p TCDriver object
+ * @param[in] channel TC channel identifier (0...channels-1)
+ * @param[in] width TC pulse width as clock pulses number
+ *
+ * @api
+ */
+void tcEnableChannel(TCDriver *tcp,
+ tcchannel_t channel,
+ tccnt_t width) {
+
+ osalDbgCheck((tcp != NULL) && (channel < tcp->channels));
+
+ osalSysLock();
+
+ osalDbgAssert(tcp->state == TC_READY, "not ready");
+
+ tcEnableChannelI(tcp, channel, width);
+
+ osalSysUnlock();
+}
+
+/**
+ * @brief Disables a TC channel and its notification.
+ * @pre The TC unit must have been activated using @p tcStart().
+ * @post The channel is disabled and its output line returned to the
+ * idle state.
+ * @note Depending on the hardware implementation this function has
+ * effect starting on the next cycle (recommended implementation)
+ * or immediately (fallback implementation).
+ *
+ * @param[in] tcp pointer to a @p TCDriver object
+ * @param[in] channel TC channel identifier (0...channels-1)
+ *
+ * @api
+ */
+void tcDisableChannel(TCDriver *tcp, tcchannel_t channel) {
+
+ osalDbgCheck((tcp != NULL) && (channel < tcp->channels));
+
+ osalSysLock();
+
+ osalDbgAssert(tcp->state == TC_READY, "not ready");
+
+ tcDisableChannelI(tcp, channel);
+
+ osalSysUnlock();
+}
+
+/**
+ * @brief Enables a channel de-activation edge notification.
+ * @pre The TC unit must have been activated using @p tcStart().
+ * @pre The channel must have been activated using @p tcEnableChannel().
+ * @note If the notification is already enabled then the call has no effect.
+ *
+ * @param[in] tcp pointer to a @p TCDriver object
+ * @param[in] channel TC channel identifier (0...channels-1)
+ *
+ * @api
+ */
+void tcEnableChannelNotification(TCDriver *tcp, tcchannel_t channel) {
+
+ osalDbgCheck((tcp != NULL) && (channel < tcp->channels));
+
+ osalSysLock();
+
+ osalDbgAssert(tcp->state == TC_READY, "not ready");
+ osalDbgAssert((tcp->enabled & ((tcchnmsk_t)1U << (tcchnmsk_t)channel)) != 0U,
+ "channel not enabled");
+ osalDbgAssert(tcp->config->channels[channel].callback != NULL,
+ "undefined channel callback");
+
+ tcEnableChannelNotificationI(tcp, channel);
+
+ osalSysUnlock();
+}
+
+/**
+ * @brief Disables a channel de-activation edge notification.
+ * @pre The TC unit must have been activated using @p tcStart().
+ * @pre The channel must have been activated using @p tcEnableChannel().
+ * @note If the notification is already disabled then the call has no effect.
+ *
+ * @param[in] tcp pointer to a @p TCDriver object
+ * @param[in] channel TC channel identifier (0...channels-1)
+ *
+ * @api
+ */
+void tcDisableChannelNotification(TCDriver *tcp, tcchannel_t channel) {
+
+ osalDbgCheck((tcp != NULL) && (channel < tcp->channels));
+
+ osalSysLock();
+
+ osalDbgAssert(tcp->state == TC_READY, "not ready");
+ osalDbgAssert((tcp->enabled & ((tcchnmsk_t)1U << (tcchnmsk_t)channel)) != 0U,
+ "channel not enabled");
+ osalDbgAssert(tcp->config->channels[channel].callback != NULL,
+ "undefined channel callback");
+
+ tcDisableChannelNotificationI(tcp, channel);
+
+ osalSysUnlock();
+}
+
+#endif /* HAL_USE_TC */
+
+/** @} */
+
+
+
+
diff --git a/os/hal/ports/SAMA/SAMA5D2x/hal_tc_lld.h b/os/hal/ports/SAMA/SAMA5D2x/hal_tc_lld.h
new file mode 100644
index 000000000..908ed173b
--- /dev/null
+++ b/os/hal/ports/SAMA/SAMA5D2x/hal_tc_lld.h
@@ -0,0 +1,338 @@
+/*
+ ChibiOS - Copyright (C) 2006..2016 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 SAMA5D2x/hal_tc_lld.h
+ * @brief SAMA TC subsystem low level driver header.
+ *
+ * @addtogroup TC
+ * @{
+ */
+
+#ifndef HAL_TC_LLD_H
+#define HAL_TC_LLD_H
+
+#if HAL_USE_TC || defined(__DOXYGEN__)
+
+/*===========================================================================*/
+/* Driver constants. */
+/*===========================================================================*/
+
+/**
+ * @brief Number of TC channels per TC driver.
+ */
+#define TC_CHANNELS TCCHANNEL_NUMBER
+
+/**
+ * @name TC output mode macros
+ * @{
+ */
+/**
+ * @brief Standard output modes mask.
+ */
+#define TC_OUTPUT_MASK 0x0FU
+
+/**
+ * @brief Output not driven, callback only.
+ */
+#define TC_OUTPUT_DISABLED 0x00U
+
+/**
+ * @brief Output active.
+ */
+#define TC_OUTPUT_ACTIVE 0x01U
+
+/** @} */
+
+/*===========================================================================*/
+/* Driver data structures and types. */
+/*===========================================================================*/
+
+/**
+ * @brief Driver state machine possible states.
+ */
+typedef enum {
+ TC_UNINIT = 0, /**< Not initialized. */
+ TC_STOP = 1, /**< Stopped. */
+ TC_READY = 2 /**< Ready. */
+} tcstate_t;
+
+/**
+ * @brief Type of a structure representing a TC driver.
+ */
+typedef struct TCDriver TCDriver;
+
+/**
+ * @brief Type of a TC notification callback.
+ *
+ * @param[in] tcp pointer to a @p TCDriver object
+ */
+typedef void (*tccallback_t)(TCDriver *tcp);
+
+
+/*===========================================================================*/
+/* Driver pre-compile time settings. */
+/*===========================================================================*/
+
+/**
+ * @name Configuration options
+ * @{
+ */
+/**
+ * @brief TCD0 driver enable switch.
+ * @details If set to @p TRUE the support for TCD0 is included.
+ * @note The default is @p TRUE.
+ */
+#if !defined(SAMA_USE_TC0) || defined(__DOXYGEN__)
+#define SAMA_USE_TC0 FALSE
+#endif
+
+/**
+ * @brief TCD1 driver enable switch.
+ * @details If set to @p TRUE the support for TCD1 is included.
+ * @note The default is @p TRUE.
+ */
+#if !defined(SAMA_USE_TC1) || defined(__DOXYGEN__)
+#define SAMA_USE_TC1 FALSE
+#endif
+
+/**
+ * @brief TCD0 interrupt priority level setting.
+ */
+#if !defined(SAMA_TC0_IRQ_PRIORITY) || defined(__DOXYGEN__)
+#define SAMA_TC0_IRQ_PRIORITY 4
+#endif
+
+/**
+ * @brief TCD1 interrupt priority level setting.
+ */
+#if !defined(SAMA_TC1_IRQ_PRIORITY) || defined(__DOXYGEN__)
+#define SAMA_TC1_IRQ_PRIORITY 4
+#endif
+
+/** @} */
+
+/*===========================================================================*/
+/* Configuration checks. */
+/*===========================================================================*/
+
+#if !SAMA_USE_TC0 && !SAMA_USE_TC1
+#error "TC driver activated but no TC peripheral assigned"
+#endif
+
+/*===========================================================================*/
+/* Driver data structures and types. */
+/*===========================================================================*/
+
+/**
+ * @brief Type of a TC mode.
+ */
+typedef uint32_t tcmode_t;
+
+/**
+ * @brief Type of a TC channel.
+ */
+typedef uint8_t tcchannel_t;
+
+/**
+ * @brief Type of a channels mask.
+ */
+typedef uint32_t tcchnmsk_t;
+
+/**
+ * @brief Type of a TC counter.
+ */
+typedef uint32_t tccnt_t;
+
+/**
+ * @brief Type of a TC driver channel configuration structure.
+ */
+typedef struct {
+ /**
+ * @brief Channel active logic level.
+ */
+ tcmode_t mode;
+ /**
+ * @brief Timer clock in Hz.
+ * @note The low level can use assertions in order to catch invalid
+ * frequency specifications.
+ */
+ uint32_t frequency;
+ /**
+ * @brief Channel callback pointer.
+ * @note This callback is invoked on the channel compare event. If set to
+ * @p NULL then the callback is disabled.
+ */
+ tccallback_t callback;
+ /* End of the mandatory fields.*/
+} TCChannelConfig;
+
+/**
+ * @brief Type of a TC driver configuration structure.
+ */
+typedef struct {
+ /**
+ * @brief Channels configurations.
+ */
+ TCChannelConfig channels[TC_CHANNELS];
+ /* End of the mandatory fields.*/
+} TCConfig;
+
+/**
+ * @brief Structure representing a TC driver.
+ */
+struct TCDriver {
+ /**
+ * @brief Driver state.
+ */
+ tcstate_t state;
+ /**
+ * @brief Current driver configuration data.
+ */
+ const TCConfig *config;
+ /**
+ * @brief Mask of the enabled channels.
+ */
+ tcchnmsk_t enabled;
+ /**
+ * @brief Number of channels in this instance.
+ */
+ tcchannel_t channels;
+ /* End of the mandatory fields.*/
+ /**
+ * @brief Timer base clock.
+ */
+ uint32_t clock;
+ /**
+ * @brief Pointer to the TCx registers block.
+ */
+ Tc *tim;
+};
+
+/*===========================================================================*/
+/* Driver macros. */
+/*===========================================================================*/
+/**
+ * @brief Enables a TC channel.
+ * @pre The TC unit must have been activated using @p tcStart().
+ * @post The channel is active using the specified configuration.
+ * @note Depending on the hardware implementation this function has
+ * effect starting on the next cycle (recommended implementation)
+ * or immediately (fallback implementation).
+ *
+ * @param[in] tcp pointer to a @p TCDriver object
+ * @param[in] channel TC channel identifier (0...channels-1)
+ * @param[in] width TC pulse width as clock pulses number
+ *
+ * @iclass
+ */
+#define tcEnableChannelI(tcp, channel, width) do { \
+ (tcp)->enabled |= ((tcchnmsk_t)1U << (tcchnmsk_t)(channel)); \
+ tc_lld_enable_channel(tcp, channel, width); \
+} while (false)
+
+/**
+ * @brief Disables a TC channel.
+ * @pre The TC unit must have been activated using @p tcStart().
+ * @post The channel is disabled and its output line returned to the
+ * idle state.
+ * @note Depending on the hardware implementation this function has
+ * effect starting on the next cycle (recommended implementation)
+ * or immediately (fallback implementation).
+ *
+ * @param[in] tcp pointer to a @p TCDriver object
+ * @param[in] channel TC channel identifier (0...channels-1)
+ *
+ * @iclass
+ */
+#define tcDisableChannelI(tcp, channel) do { \
+ (tcp)->enabled &= ~((tcchnmsk_t)1U << (tcchnmsk_t)(channel)); \
+ tc_lld_disable_channel(tcp, channel); \
+} while (false)
+
+/**
+ * @brief Returns a TC channel status.
+ * @pre The TC unit must have been activated using @p tcStart().
+ *
+ * @param[in] tcp pointer to a @p TCDriver object
+ * @param[in] channel TC channel identifier (0...channels-1)
+ *
+ * @iclass
+ */
+#define tcIsChannelEnabledI(tcp, channel) \
+ (((tcp)->enabled & ((tcchnmsk_t)1U << (tcchnmsk_t)(channel))) != 0U)
+
+/**
+ * @brief Enables a channel de-activation edge notification.
+ * @pre The TC unit must have been activated using @p tcStart().
+ * @pre The channel must have been activated using @p tcEnableChannel().
+ * @note If the notification is already enabled then the call has no effect.
+ *
+ * @param[in] tcp pointer to a @p TCDriver object
+ * @param[in] channel TC channel identifier (0...channels-1)
+ *
+ * @iclass
+ */
+#define tcEnableChannelNotificationI(tcp, channel) \
+ tc_lld_enable_channel_notification(tcp, channel)
+
+/**
+ * @brief Disables a channel de-activation edge notification.
+ * @pre The TC unit must have been activated using @p tcStart().
+ * @pre The channel must have been activated using @p tcEnableChannel().
+ * @note If the notification is already disabled then the call has no effect.
+ *
+ * @param[in] tcp pointer to a @p TCDriver object
+ * @param[in] channel TC channel identifier (0...channels-1)
+ *
+ * @iclass
+ */
+#define tcDisableChannelNotificationI(tcp, channel) \
+ tc_lld_disable_channel_notification(tcp, channel)
+
+/*===========================================================================*/
+/* External declarations. */
+/*===========================================================================*/
+
+#if SAMA_USE_TC0 && !defined(__DOXYGEN__)
+extern TCDriver TCD0;
+#endif
+
+#if SAMA_USE_TC1 && !defined(__DOXYGEN__)
+extern TCDriver TCD1;
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+ void tcInit(void);
+ void tcObjectInit(TCDriver *tcp);
+ void tcStart(TCDriver *tcp, const TCConfig *config);
+ void tcStop(TCDriver *tcp);
+ void tcEnableChannel(TCDriver *tcp,
+ tcchannel_t channel,
+ tccnt_t width);
+ void tcDisableChannel(TCDriver *tcp, tcchannel_t channel);
+ void tcEnableChannelNotification(TCDriver *tcp, tcchannel_t channel);
+ void tcDisableChannelNotification(TCDriver *tcp, tcchannel_t channel);
+ void tcChangeChannelFrequency(TCDriver *tcp, tcchannel_t channel, uint32_t frequency);
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* HAL_USE_TC */
+
+#endif /* HAL_TC_LLD_H */