From ed6245c58f40d64d77dde8f0aac0b1d9b20a1966 Mon Sep 17 00:00:00 2001 From: edolomb Date: Tue, 31 Oct 2017 09:56:52 +0000 Subject: Added TC driver in waveform mode git-svn-id: svn://svn.code.sf.net/p/chibios/svn/trunk@10913 35acf78f-673a-0410-8e92-d51de3d6d3f4 --- os/hal/ports/SAMA/SAMA5D2x/hal_tc_lld.c | 571 ++++++++++++++++++++++++++++++++ os/hal/ports/SAMA/SAMA5D2x/hal_tc_lld.h | 338 +++++++++++++++++++ 2 files changed, 909 insertions(+) create mode 100644 os/hal/ports/SAMA/SAMA5D2x/hal_tc_lld.c create mode 100644 os/hal/ports/SAMA/SAMA5D2x/hal_tc_lld.h (limited to 'os/hal') 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 */ -- cgit v1.2.3