diff --git a/os/hal/platforms/AT91SAM7/gpt_lld.c b/os/hal/platforms/AT91SAM7/gpt_lld.c new file mode 100644 index 000000000..3d584fee3 --- /dev/null +++ b/os/hal/platforms/AT91SAM7/gpt_lld.c @@ -0,0 +1,456 @@ +/* + ChibiOS/RT - Copyright (C) 2006-2013 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 AT91SAM7/gpt_lld.c + * @brief AT91SAM7 GPT subsystem low level driver source. + * + * @addtogroup GPT + * @{ + */ + +#include "ch.h" +#include "hal.h" + +#if HAL_USE_GPT || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/** + * @brief GPTD1 driver identifier. + * @note The driver GPTD1 allocates the complex timer TC0 when enabled. + */ +#if AT91_GPT_USE_TC0 || defined(__DOXYGEN__) + GPTDriver GPTD1; +#endif + +/** + * @brief GPTD2 driver identifier. + * @note The driver GPTD2 allocates the timer TC1 when enabled. + */ +#if AT91_GPT_USE_TC1 || defined(__DOXYGEN__) + GPTDriver GPTD2; +#endif + +/** + * @brief GPTD3 driver identifier. + * @note The driver GPTD3 allocates the timer TC2 when enabled. + */ +#if AT91_GPT_USE_TC2 || defined(__DOXYGEN__) + GPTDriver GPTD3; +#endif + +/*===========================================================================*/ +/* Driver local variables and types. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +/** + * @brief Shared IRQ handler. + * + * @param[in] gptp pointer to a @p GPTDriver object + */ +static void gpt_lld_serve_interrupt(GPTDriver *gptp) { + // Read the status to clear the interrupts + { + uint32_t isr = gptp->tc->TC_SR; + (void) isr; + } + + // Clear one-shot + if (gptp->state == GPT_ONESHOT) { + gptp->state = GPT_READY; // Back in GPT_READY state. + gptp->tc->TC_IDR = 0xFFFFFFFF; // Disable interrupts (not really needed but safer) + } + + // Do the callback + gptp->config->callback(gptp); +} + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +#if AT91_GPT_USE_TC0 + /** + * @brief TC1 interrupt handler. + * + * @isr + */ + CH_IRQ_HANDLER(TC0_IRQHandler) { + CH_IRQ_PROLOGUE(); + gpt_lld_serve_interrupt(&GPTD1); + AT91C_BASE_AIC->AIC_EOICR = 0; + CH_IRQ_EPILOGUE(); + } +#endif /* AT91_GPT_USE_TC0 */ + +#if AT91_GPT_USE_TC1 + /** + * @brief TC1 interrupt handler. + * + * @isr + */ + CH_IRQ_HANDLER(TC1_IRQHandler) { + CH_IRQ_PROLOGUE(); + gpt_lld_serve_interrupt(&GPTD2); + AT91C_BASE_AIC->AIC_EOICR = 0; + CH_IRQ_EPILOGUE(); + } +#endif /* AT91_GPT_USE_TC1 */ + +#if AT91_GPT_USE_TC2 + /** + * @brief TC1 interrupt handler. + * + * @isr + */ + CH_IRQ_HANDLER(TC2_IRQHandler) { + CH_IRQ_PROLOGUE(); + gpt_lld_serve_interrupt(&GPTD2); + AT91C_BASE_AIC->AIC_EOICR = 0; + CH_IRQ_EPILOGUE(); + } +} +#endif /* AT91_GPT_USE_TC2 */ + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** + * @brief Low level GPT driver initialization. + * + * @notapi + */ +void gpt_lld_init(void) { + + #if AT91_GPT_USE_TC0 + AT91C_BASE_PMC->PMC_PCER = (1 << AT91C_ID_TC0); // Turn on the power + GPTD1.tc = AT91C_BASE_TC0; + gptObjectInit(&GPTD1); + gpt_lld_stop(&GPTD1); // Make sure it is disabled + AIC_ConfigureIT(AT91C_ID_TC0, AT91C_AIC_SRCTYPE_HIGH_LEVEL | AT91_GPT_TC0_IRQ_PRIORITY, TC0_IRQHandler); + AIC_EnableIT(AT91C_ID_TC0); + #endif + + #if AT91_GPT_USE_TC1 + AT91C_BASE_PMC->PMC_PCER = (1 << AT91C_ID_TC1); // Turn on the power + GPTD2.tc = AT91C_BASE_TC1; + gptObjectInit(&GPTD2); + gpt_lld_stop(&GPTD2); // Make sure it is disabled + AIC_ConfigureIT(AT91C_ID_TC1, AT91C_AIC_SRCTYPE_HIGH_LEVEL | AT91_GPT_TC1_IRQ_PRIORITY, TC1_IRQHandler); + AIC_EnableIT(AT91C_ID_TC1); + #endif + + #if AT91_GPT_USE_TC2 + AT91C_BASE_PMC->PMC_PCER = (1 << AT91C_ID_TC2); // Turn on the power + GPTD3.tc = AT91C_BASE_TC2; + gptObjectInit(&GPTD3); + gpt_lld_stop(&GPTD3); // Make sure it is disabled + AIC_ConfigureIT(AT91C_ID_TC2, AT91C_AIC_SRCTYPE_HIGH_LEVEL | AT91_GPT_TC2_IRQ_PRIORITY, TC2_IRQHandler); + AIC_EnableIT(AT91C_ID_TC2); + #endif +} + +/** + * @brief Configures and activates the GPT peripheral. + * + * @param[in] gptp pointer to the @p GPTDriver object + * + * @notapi + */ +void gpt_lld_start(GPTDriver *gptp) { + uint32_t cmr, rc, bmr; + + bmr = *AT91C_TCB_BMR; + rc = 65535; + cmr = (AT91C_TC_ASWTRG_CLEAR | AT91C_TC_ACPC_CLEAR | AT91C_TC_ACPA_SET | + AT91C_TC_WAVE | AT91C_TC_WAVESEL_UP_AUTO); + + // Calculate clock + switch(gptp->config->clocksource) { + case GPT_CLOCK_MCLK: + switch(gptp->config->frequency) { + case MCK/2: cmr |= AT91C_TC_CLKS_TIMER_DIV1_CLOCK; break; + case MCK/8: cmr |= AT91C_TC_CLKS_TIMER_DIV2_CLOCK; break; + case MCK/32: cmr |= AT91C_TC_CLKS_TIMER_DIV3_CLOCK; break; + case MCK/128: cmr |= AT91C_TC_CLKS_TIMER_DIV4_CLOCK; break; + case MCK/1024: cmr |= AT91C_TC_CLKS_TIMER_DIV5_CLOCK; break; + default: + chDbgAssert(TRUE, "gpt_lld_start(), #1", "invalid frequency"); + cmr |= AT91C_TC_CLKS_TIMER_DIV5_CLOCK; + break; + } + break; + case GPT_CLOCK_FREQUENCY: + /* Set the Mode of the Timer Counter and calculate the period */ + rc = (MCK/2)/gptp->config->frequency; + if (rc < (0x10000<<0)) { + cmr |= AT91C_TC_CLKS_TIMER_DIV1_CLOCK; + } else if (rc < (0x10000<<2)) { + rc >>= 2; + cmr |= AT91C_TC_CLKS_TIMER_DIV2_CLOCK; + } else if (rc < (0x10000<<4)) { + rc >>= 4; + cmr |= AT91C_TC_CLKS_TIMER_DIV3_CLOCK; + } else if (rc < (0x10000<<6)) { + rc >>= 6; + cmr |= AT91C_TC_CLKS_TIMER_DIV4_CLOCK; + } else { + rc >>= 9; + cmr |= AT91C_TC_CLKS_TIMER_DIV5_CLOCK; + } + break; + case GPT_CLOCK_RE_TCLK0: + case GPT_CLOCK_FE_TCLK0: + if ((gptp->config->clocksource & 1)) cmr |= AT91C_TC_CLKI; + cmr |= AT91C_TC_CLKS_XC0; + #if AT91_GPT_USE_TC0 + if (gptp == &GPTD1) bmr = (bmr & ~AT91C_TCB_TC0XC0S) | AT91C_TCB_TC0XC0S_TCLK0; + #endif + break; + case GPT_CLOCK_RE_TCLK1: + case GPT_CLOCK_FE_TCLK1: + if ((gptp->config->clocksource & 1)) cmr |= AT91C_TC_CLKI; + cmr |= AT91C_TC_CLKS_XC1; + #if AT91_GPT_USE_TC1 + if (gptp == &GPTD2) bmr = (bmr & ~AT91C_TCB_TC1XC1S) | AT91C_TCB_TC1XC1S_TCLK1; + #endif + break; + case GPT_CLOCK_RE_TCLK2: + case GPT_CLOCK_FE_TCLK2: + if ((gptp->config->clocksource & 1)) cmr |= AT91C_TC_CLKI; + cmr |= AT91C_TC_CLKS_XC2; + #if AT91_GPT_USE_TC2 + if (gptp == &GPTD3) bmr = (bmr & ~AT91C_TCB_TC2XC2S) | AT91C_TCB_TC2XC2S_TCLK2; + #endif + break; + case GPT_CLOCK_RE_TC0: + case GPT_CLOCK_FE_TC0: + if ((gptp->config->clocksource & 1)) cmr |= AT91C_TC_CLKI; + #if AT91_GPT_USE_TC0 + if (gptp == &GPTD1) { + chDbgAssert(TRUE, "gpt_lld_start(), #2", "invalid clock"); + cmr |= AT91C_TC_CLKS_XC0; + bmr = (bmr & ~AT91C_TCB_TC0XC0S) | AT91C_TCB_TC0XC0S_NONE; + break; + } + #endif + #if AT91_GPT_USE_TC1 + if (gptp == &GPTD2) { + cmr |= AT91C_TC_CLKS_XC1; + bmr = (bmr & ~AT91C_TCB_TC1XC1S) | AT91C_TCB_TC1XC1S_TIOA0; + break; + } + #endif + #if AT91_GPT_USE_TC2 + if (gptp == &GPTD3) { + cmr |= AT91C_TC_CLKS_XC2; + bmr = (bmr & ~AT91C_TCB_TC2XC2S) | AT91C_TCB_TC2XC2S_TIOA0; + break; + } + #endif + chDbgAssert(TRUE, "gpt_lld_start(), #3", "invalid GPT device"); + cmr |= AT91C_TC_CLKS_TIMER_DIV5_CLOCK; + break; + case GPT_CLOCK_RE_TC1: + case GPT_CLOCK_FE_TC1: + if ((gptp->config->clocksource & 1)) cmr |= AT91C_TC_CLKI; + #if AT91_GPT_USE_TC0 + if (gptp == &GPTD1) { + cmr |= AT91C_TC_CLKS_XC0; + bmr = (bmr & ~AT91C_TCB_TC0XC0S) | AT91C_TCB_TC0XC0S_TIOA1; + break; + } + #endif + #if AT91_GPT_USE_TC1 + if (gptp == &GPTD2) { + chDbgAssert(TRUE, "gpt_lld_start(), #4", "invalid clock"); + cmr |= AT91C_TC_CLKS_XC1; + bmr = (bmr & ~AT91C_TCB_TC1XC1S) | AT91C_TCB_TC1XC1S_NONE; + break; + } + #endif + #if AT91_GPT_USE_TC2 + if (gptp == &GPTD3) { + cmr |= AT91C_TC_CLKS_XC2; + bmr = (bmr & ~AT91C_TCB_TC2XC2S) | AT91C_TCB_TC2XC2S_TIOA1; + break; + } + #endif + chDbgAssert(TRUE, "gpt_lld_start(), #5", "invalid GPT device"); + cmr |= AT91C_TC_CLKS_TIMER_DIV5_CLOCK; + break; + case GPT_CLOCK_RE_TC2: + case GPT_CLOCK_FE_TC2: + if ((gptp->config->clocksource & 1)) cmr |= AT91C_TC_CLKI; + #if AT91_GPT_USE_TC0 + if (gptp == &GPTD1) { + cmr |= AT91C_TC_CLKS_XC0; + bmr = (bmr & ~AT91C_TCB_TC0XC0S) | AT91C_TCB_TC0XC0S_TIOA2; + break; + } + #endif + #if AT91_GPT_USE_TC1 + if (gptp == &GPTD2) { + cmr |= AT91C_TC_CLKS_XC1; + bmr = (bmr & ~AT91C_TCB_TC1XC1S) | AT91C_TCB_TC1XC1S_TIOA2; + break; + } + #endif + #if AT91_GPT_USE_TC2 + if (gptp == &GPTD3) { + chDbgAssert(TRUE, "gpt_lld_start(), #6", "invalid clock"); + cmr |= AT91C_TC_CLKS_XC2; + bmr = (bmr & ~AT91C_TCB_TC2XC2S) | AT91C_TCB_TC2XC2S_NONE; + break; + } + #endif + chDbgAssert(TRUE, "gpt_lld_start(), #7", "invalid GPT device"); + cmr |= AT91C_TC_CLKS_TIMER_DIV5_CLOCK; + break; + default: + chDbgAssert(TRUE, "gpt_lld_start(), #8", "invalid clock"); + cmr |= AT91C_TC_CLKS_TIMER_DIV5_CLOCK; + break; + } + + // Calculate clock gating + chDbgAssert(gptp->config->clockgate == GPT_GATE_NONE || gptp->config->clockgate == GPT_GATE_TCLK0 + || gptp->config->clockgate == GPT_GATE_TCLK1 || gptp->config->clockgate == GPT_GATE_TCLK2 + , "gpt_lld_start(), #9", "invalid clockgate"); + cmr |= ((uint32_t)(gptp->config->clockgate & 0x03)) << 4; // special magic numbers here + + // Calculate triggers + chDbgAssert(gptp->config->trigger == GPT_TRIGGER_NONE + || gptp->config->trigger == GPT_TRIGGER_RE_TIOB || gptp->config->trigger == GPT_TRIGGER_FE_TIOB || gptp->config->trigger == GPT_TRIGGER_BE_TIOB + || gptp->config->trigger == GPT_TRIGGER_RE_TCLK0 || gptp->config->trigger == GPT_TRIGGER_FE_TCLK0 || gptp->config->trigger == GPT_TRIGGER_BE_TCLK0 + || gptp->config->trigger == GPT_TRIGGER_RE_TCLK1 || gptp->config->trigger == GPT_TRIGGER_FE_TCLK1 || gptp->config->trigger == GPT_TRIGGER_BE_TCLK1 + || gptp->config->trigger == GPT_TRIGGER_RE_TCLK2 || gptp->config->trigger == GPT_TRIGGER_FE_TCLK2 || gptp->config->trigger == GPT_TRIGGER_BE_TCLK2 + , "gpt_lld_start(), #10", "invalid trigger"); + cmr |= ((uint32_t)(gptp->config->trigger & 0x03)) << 10; // special magic numbers here + cmr |= ((uint32_t)(gptp->config->trigger & 0x30)) << (8-4); // special magic numbers here + + /* Set everything up but disabled */ + gptp->tc->TC_CCR = AT91C_TC_CLKDIS; + gptp->tc->TC_IDR = 0xFFFFFFFF; + gptp->tc->TC_CMR = cmr; + gptp->tc->TC_RC = rc; + gptp->tc->TC_RA = rc/2; + *AT91C_TCB_BMR = bmr; + cmr = gptp->tc->TC_SR; // Clear any pending interrupts +} + +/** + * @brief Deactivates the GPT peripheral. + * + * @param[in] gptp pointer to the @p GPTDriver object + * + * @notapi + */ +void gpt_lld_stop(GPTDriver *gptp) { + gptp->tc->TC_CCR = AT91C_TC_CLKDIS; + gptp->tc->TC_IDR = 0xFFFFFFFF; + { uint32_t isr = gptp->tc->TC_SR; (void)isr; } +} + +/** + * @brief Starts the timer in continuous mode. + * + * @param[in] gptp pointer to the @p GPTDriver object + * @param[in] interval period in ticks + * + * @notapi + */ +void gpt_lld_start_timer(GPTDriver *gptp, gptcnt_t interval) { + + if (gptp->config->clocksource != GPT_CLOCK_FREQUENCY) { + gptp->tc->TC_RC = interval; + gptp->tc->TC_RA = interval/2; + } + gptp->tc->TC_CMR &= ~AT91C_TC_CPCDIS; + gptp->tc->TC_CCR = AT91C_TC_CLKEN|AT91C_TC_SWTRG; + gptp->tc->TC_IER = AT91C_TC_CPCS|AT91C_TC_COVFS; +} + +/** + * @brief Stops the timer. + * + * @param[in] gptp pointer to the @p GPTDriver object + * + * @notapi + */ +void gpt_lld_stop_timer(GPTDriver *gptp) { + gptp->tc->TC_CCR = AT91C_TC_CLKDIS; + gptp->tc->TC_IDR = 0xFFFFFFFF; + { uint32_t isr = gptp->tc->TC_SR; (void)isr; } +} + +/** + * @brief Changes the interval of GPT peripheral. + * @details This function changes the interval of a running GPT unit. + * @pre The GPT unit must have been activated using @p gptStart(). + * @pre The GPT unit must have been running in continuous mode using + * @p gptStartContinuous(). + * @post The GPT unit interval is changed to the new value. + * @note The function has effect at the next cycle start. + * + * @param[in] gptp pointer to a @p GPTDriver object + * @param[in] interval new cycle time in timer ticks + * @notapi + */ +void gpt_lld_change_interval(GPTDriver *gptp, gptcnt_t interval) { + if (gptp->config->clocksource != GPT_CLOCK_FREQUENCY) { + gptp->tc->TC_RC = interval; + gptp->tc->TC_RA = interval/2; + } +} + +/** + * @brief Starts the timer in one shot mode and waits for completion. + * @details This function specifically polls the timer waiting for completion + * in order to not have extra delays caused by interrupt servicing, + * this function is only recommended for short delays. + * + * @param[in] gptp pointer to the @p GPTDriver object + * @param[in] interval time interval in ticks + * + * @notapi + */ +void gpt_lld_polled_delay(GPTDriver *gptp, gptcnt_t interval) { + + if (gptp->config->clocksource != GPT_CLOCK_FREQUENCY) { + gptp->tc->TC_RC = interval; + gptp->tc->TC_RA = interval/2; + } + gptp->tc->TC_CMR |= AT91C_TC_CPCDIS; + gptp->tc->TC_CCR = AT91C_TC_CLKEN|AT91C_TC_SWTRG; + while (!(gptp->tc->TC_SR & (AT91C_TC_CPCS|AT91C_TC_COVFS))); +} + +#endif /* HAL_USE_GPT */ + +/** @} */ diff --git a/os/hal/platforms/AT91SAM7/gpt_lld.h b/os/hal/platforms/AT91SAM7/gpt_lld.h new file mode 100644 index 000000000..dc6338210 --- /dev/null +++ b/os/hal/platforms/AT91SAM7/gpt_lld.h @@ -0,0 +1,230 @@ +/* + ChibiOS/RT - Copyright (C) 2006-2013 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 AT91SAM7/gpt_lld.h + * @brief AT91SAM7 GPT subsystem low level driver header. + * + * @addtogroup GPT + * @{ + */ + +#ifndef _GPT_LLD_H_ +#define _GPT_LLD_H_ + +#if HAL_USE_GPT || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Driver constants. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver pre-compile time settings. */ +/*===========================================================================*/ + +/** + * @name Configuration options + * @{ + */ +/** + * @brief GPTD1 driver enable switch. + * @details If set to @p TRUE the support for GPTD1 is included. + * @note The default is @p TRUE. + */ +#if !defined(AT91_GPT_USE_TC0) || defined(__DOXYGEN__) +#define AT91_GPT_USE_TC0 FALSE +#endif + +/** + * @brief GPTD2 driver enable switch. + * @details If set to @p TRUE the support for GPTD2 is included. + * @note The default is @p TRUE. + */ +#if !defined(AT91_GPT_USE_TC1) || defined(__DOXYGEN__) +#define AT91_GPT_USE_TC1 FALSE +#endif + +/** + * @brief GPTD3 driver enable switch. + * @details If set to @p TRUE the support for GPTD3 is included. + * @note The default is @p TRUE. + */ +#if !defined(AT91_GPT_USE_TC2) || defined(__DOXYGEN__) +#define AT91_GPT_USE_TC3 FALSE +#endif + +/** + * @brief GPTD1 interrupt priority level setting. + */ +#if !defined(AT91_GPT_TC0_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define AT91_GPT_TC0_IRQ_PRIORITY (AT91C_AIC_PRIOR_HIGHEST - 2) +#endif + +/** + * @brief GPTD2 interrupt priority level setting. + */ +#if !defined(AT91_GPT_TC1_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define AT91_GPT_TC1_IRQ_PRIORITY (AT91C_AIC_PRIOR_HIGHEST - 2) +#endif + +/** + * @brief GPTD3 interrupt priority level setting. + */ +#if !defined(AT91_GPT_TC2_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define AT91_GPT_TC2_IRQ_PRIORITY (AT91C_AIC_PRIOR_HIGHEST - 2) +#endif + +/** @} */ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +#if !AT91_GPT_USE_TC0 && !AT91_GPT_USE_TC1 && !AT91_GPT_USE_TC2 +#error "GPT driver activated but no TC peripheral assigned" +#endif + +/*===========================================================================*/ +/* Driver data structures and types. */ +/*===========================================================================*/ + +/** + * @brief GPT frequency type. + */ +typedef uint32_t gptfreq_t; + +/** + * @brief GPT counter type. + */ +typedef uint16_t gptcnt_t; + +/** + * @brief Driver configuration structure. + * @note It could be empty on some architectures. + */ +typedef struct { + /** + * @brief Timer clock in Hz. + * @note The low level can use assertions in order to catch invalid + * frequency specifications. + */ + gptfreq_t frequency; + /** + * @brief Timer callback pointer. + * @note This callback is invoked on GPT counter events. + */ + gptcallback_t callback; + /* End of the mandatory fields.*/ + /** + * @brief Timer Clock Source. + */ + uint8_t clocksource; + #define GPT_CLOCK_MCLK 0 // @< Internal clock. frequency must = MCLK/2, MCLK/8, MCLK/32, MCLK/128 or MCLK/1024 + #define GPT_CLOCK_FREQUENCY 1 // @< Internal clock. interval is ignored. frequency determines rate + #define GPT_CLOCK_RE_TCLK0 2 // @< External TCLK0. Rising Edge + #define GPT_CLOCK_FE_TCLK0 3 // @< External TCLK0. Falling Edge + #define GPT_CLOCK_RE_TCLK1 4 // @< External TCLK1. Rising Edge + #define GPT_CLOCK_FE_TCLK1 5 // @< External TCLK1. Falling Edge + #define GPT_CLOCK_RE_TCLK2 6 // @< External TCLK2. Rising Edge + #define GPT_CLOCK_FE_TCLK2 7 // @< External TCLK2. Falling Edge + #define GPT_CLOCK_RE_TC0 8 // @< TC0 output. Rising Edge. Do not use on TC0 + #define GPT_CLOCK_FE_TC0 9 // @< TC0 output. Falling Edge. Do not use on TC0 + #define GPT_CLOCK_RE_TC1 10 // @< TC1 output. Rising Edge. Do not use on TC1 + #define GPT_CLOCK_FE_TC1 11 // @< TC1 output. Falling Edge. Do not use on TC1 + #define GPT_CLOCK_RE_TC2 12 // @< TC2 output. Rising Edge. Do not use on TC2 + #define GPT_CLOCK_FE_TC2 13 // @< TC2 output. Falling Edge. Do not use on TC2 + uint8_t clockgate; + #define GPT_GATE_NONE 0 // @< Clock gating off + #define GPT_GATE_TCLK0 1 // @< Clock on TCLK0 active high signal. If using this on TC0 with GPT_CLOCK_xx_TIMx, the TIMx output will be used instead. + #define GPT_GATE_TCLK1 2 // @< Clock on TCLK1 active high signal. If using this on TC1 with GPT_CLOCK_xx_TIMx, the TIMx output will be used instead. + #define GPT_GATE_TCLK2 3 // @< Clock on TCLK2 active high signal. If using this on TC2 with GPT_CLOCK_xx_TIMx, the TIMx output will be used instead. + uint8_t trigger; + #define GPT_TRIGGER_NONE 0x00 // @< Start immediately + #define GPT_TRIGGER_RE_TIOB 0x10 // @< Start on TIOB signal. Rising Edge. + #define GPT_TRIGGER_FE_TIOB 0x20 // @< Start on TIOB signal. Falling Edge. + #define GPT_TRIGGER_BE_TIOB 0x30 // @< Start on TIOB signal. Both Edges. + #define GPT_TRIGGER_RE_TCLK0 0x11 // @< Start on TCLK0 signal. Rising Edge. If using this on TC0 with GPT_CLOCK_xx_TIMx, the TIMx output will be used instead. + #define GPT_TRIGGER_FE_TCLK0 0x21 // @< Start on TCLK0 signal. Falling Edge. If using this on TC0 with GPT_CLOCK_xx_TIMx, the TIMx output will be used instead. + #define GPT_TRIGGER_BE_TCLK0 0x31 // @< Start on TCLK0 signal. Both Edges. If using this on TC0 with GPT_CLOCK_xx_TIMx, the TIMx output will be used instead. + #define GPT_TRIGGER_RE_TCLK1 0x12 // @< Start on TCLK1 signal. Rising Edge. If using this on TC1 with GPT_CLOCK_xx_TIMx, the TIMx output will be used instead. + #define GPT_TRIGGER_FE_TCLK1 0x22 // @< Start on TCLK1 signal. Falling Edge. If using this on TC1 with GPT_CLOCK_xx_TIMx, the TIMx output will be used instead. + #define GPT_TRIGGER_BE_TCLK1 0x32 // @< Start on TCLK1 signal. Both Edges. If using this on TC1 with GPT_CLOCK_xx_TIMx, the TIMx output will be used instead. + #define GPT_TRIGGER_RE_TCLK2 0x13 // @< Start on TCLK2 signal. Rising Edge. If using this on TC2 with GPT_CLOCK_xx_TIMx, the TIMx output will be used instead. + #define GPT_TRIGGER_FE_TCLK2 0x23 // @< Start on TCLK2 signal. Falling Edge. If using this on TC2 with GPT_CLOCK_xx_TIMx, the TIMx output will be used instead. + #define GPT_TRIGGER_BE_TCLK2 0x33 // @< Start on TCLK2 signal. Both Edges. If using this on TC2 with GPT_CLOCK_xx_TIMx, the TIMx output will be used instead. +} GPTConfig; + +/** + * @brief Structure representing a GPT driver. + */ +struct GPTDriver { + /** + * @brief Driver state. + */ + gptstate_t state; + /** + * @brief Current configuration data. + */ + const GPTConfig *config; +#if defined(GPT_DRIVER_EXT_FIELDS) + GPT_DRIVER_EXT_FIELDS +#endif + /* End of the mandatory fields.*/ + /** + * @brief Pointer to the TCx registers block. + */ + AT91S_TC *tc; +}; + +/*===========================================================================*/ +/* Driver macros. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* External declarations. */ +/*===========================================================================*/ + +#if AT91_GPT_USE_TC0 && !defined(__DOXYGEN__) +extern GPTDriver GPTD1; +#endif + +#if AT91_GPT_USE_TC1 && !defined(__DOXYGEN__) +extern GPTDriver GPTD2; +#endif + +#if AT91_GPT_USE_TC2 && !defined(__DOXYGEN__) +extern GPTDriver GPTD3; +#endif + +#ifdef __cplusplus +extern "C" { +#endif + void gpt_lld_init(void); + void gpt_lld_start(GPTDriver *gptp); + void gpt_lld_stop(GPTDriver *gptp); + void gpt_lld_start_timer(GPTDriver *gptp, gptcnt_t period); + void gpt_lld_stop_timer(GPTDriver *gptp); + void gpt_lld_change_interval(GPTDriver *gptp, gptcnt_t interval); + void gpt_lld_polled_delay(GPTDriver *gptp, gptcnt_t interval); +#ifdef __cplusplus +} +#endif + +#endif /* HAL_USE_GPT */ + +#endif /* _GPT_LLD_H_ */ + +/** @} */ diff --git a/os/hal/platforms/AT91SAM7/platform.mk b/os/hal/platforms/AT91SAM7/platform.mk index 6b8438c6d..1f173f9d5 100644 --- a/os/hal/platforms/AT91SAM7/platform.mk +++ b/os/hal/platforms/AT91SAM7/platform.mk @@ -9,6 +9,7 @@ PLATFORMSRC = ${CHIBIOS}/os/hal/platforms/AT91SAM7/hal_lld.c \ ${CHIBIOS}/os/hal/platforms/AT91SAM7/mac_lld.c \ ${CHIBIOS}/os/hal/platforms/AT91SAM7/pwm_lld.c \ ${CHIBIOS}/os/hal/platforms/AT91SAM7/can_lld.c \ + ${CHIBIOS}/os/hal/platforms/AT91SAM7/gpt_lld.c \ ${CHIBIOS}/os/hal/platforms/AT91SAM7/at91sam7_mii.c \ ${CHIBIOS}/os/hal/platforms/AT91SAM7/at91lib/aic.c