Added TC driver in waveform mode
git-svn-id: svn://svn.code.sf.net/p/chibios/svn/trunk@10913 35acf78f-673a-0410-8e92-d51de3d6d3f4
This commit is contained in:
parent
4b17048a2e
commit
ed6245c58f
|
@ -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 */
|
||||||
|
|
||||||
|
/** @} */
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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 */
|
Loading…
Reference in New Issue