diff --git a/os/hal/ports/NUMICRO/LLD/TIMv1/driver.mk b/os/hal/ports/NUMICRO/LLD/TIMv1/driver.mk index 49d545af7b..773d9b08d2 100644 --- a/os/hal/ports/NUMICRO/LLD/TIMv1/driver.mk +++ b/os/hal/ports/NUMICRO/LLD/TIMv1/driver.mk @@ -2,8 +2,12 @@ ifeq ($(USE_SMART_BUILD),yes) ifneq ($(findstring HAL_USE_PWM TRUE,$(HALCONF)),) PLATFORMSRC += $(CHIBIOS_CONTRIB)/os/hal/ports/NUMICRO/LLD/TIMv1/hal_pwm_lld.c endif +ifneq ($(findstring HAL_USE_GPT TRUE,$(HALCONF)),) +PLATFORMSRC += $(CHIBIOS_CONTRIB)/os/hal/ports/NUMICRO/LLD/TIMv1/hal_gpt_lld.c +endif else PLATFORMSRC += $(CHIBIOS_CONTRIB)/os/hal/ports/NUMICRO/LLD/TIMv1/hal_pwm_lld.c +PLATFORMSRC += $(CHIBIOS_CONTRIB)/os/hal/ports/NUMICRO/LLD/TIMv1/hal_gpt_lld.c endif PLATFORMSRC += $(CHIBIOS_CONTRIB)/os/hal/ports/NUMICRO/LLD/TIMv1/hal_st_lld.c diff --git a/os/hal/ports/NUMICRO/LLD/TIMv1/hal_gpt_lld.c b/os/hal/ports/NUMICRO/LLD/TIMv1/hal_gpt_lld.c new file mode 100644 index 0000000000..703ed61ea2 --- /dev/null +++ b/os/hal/ports/NUMICRO/LLD/TIMv1/hal_gpt_lld.c @@ -0,0 +1,296 @@ +/* + Copyright (C) 2024 Hansem Ro + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +/** + * @file hal_gpt_lld.c + * @brief PLATFORM GPT subsystem low level driver source. + * + * @addtogroup GPT + * @{ + */ + +#include "hal.h" + +#if (HAL_USE_GPT == TRUE) || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +#define NUC123_TIMER_CLKSRC_HSE 0x0UL +#define NUC123_TIMER_CLKSRC_HCLK 0x2UL +#define NUC123_TIMER_CLKSRC_HSI 0x3UL +#define NUC123_TIMER_CLKSRC_LSI 0x7UL + +#define NUC123_TIMER_TCSR_MODE_ONESHOT 0x0UL << TIMER_TCSR_MODE_Pos +#define NUC123_TIMER_TCSR_MODE_PERIODIC 0x1UL << TIMER_TCSR_MODE_Pos +#define NUC123_TIMER_TCSR_MODE_TOGGLEOUTPUT 0x2UL << TIMER_TCSR_MODE_Pos +#define NUC123_TIMER_TCSR_MODE_CONTINUOUS 0x3UL << TIMER_TCSR_MODE_Pos + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/** + * @brief GPTD0 (TIMER0) driver identifier. + */ +#if (NUC123_GPT_USE_TIMER0 == TRUE) || defined(__DOXYGEN__) +GPTDriver GPTD0; +#endif + +/** + * @brief GPTD1 (TIMER1) driver identifier. + */ +#if (NUC123_GPT_USE_TIMER1 == TRUE) || defined(__DOXYGEN__) +GPTDriver GPTD1; +#endif + +/** + * @brief GPTD2 (TIMER2) driver identifier. + */ +#if (NUC123_GPT_USE_TIMER2 == TRUE) || defined(__DOXYGEN__) +GPTDriver GPTD2; +#endif + +/** + * @brief GPTD3 (TIMER3) driver identifier. + */ +#if (NUC123_GPT_USE_TIMER3 == TRUE) || defined(__DOXYGEN__) +GPTDriver GPTD3; +#endif + +/*===========================================================================*/ +/* Driver local variables and types. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +static void gpt_lld_handler(GPTDriver *gptp) { + if (gptp->TIMER->TISR & TIMER_TISR_TIF_Msk) { + gptp->TIMER->TISR |= TIMER_TISR_TIF_Msk; + if (gptp->config->callback) + gptp->config->callback(gptp); + } +} + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +#if (NUC123_GPT_USE_TIMER0 == TRUE) || defined(__DOXYGEN__) +OSAL_IRQ_HANDLER(NUC123_TIM1_HANDLER) { + OSAL_IRQ_PROLOGUE(); + gpt_lld_handler(&GPTD0); + OSAL_IRQ_EPILOGUE(); +} +#endif + +#if (NUC123_GPT_USE_TIMER1 == TRUE) || defined(__DOXYGEN__) +OSAL_IRQ_HANDLER(NUC123_TIM2_HANDLER) { + OSAL_IRQ_PROLOGUE(); + gpt_lld_handler(&GPTD1); + OSAL_IRQ_EPILOGUE(); +} +#endif + +#if (NUC123_GPT_USE_TIMER2 == TRUE) || defined(__DOXYGEN__) +OSAL_IRQ_HANDLER(NUC123_TIM3_HANDLER) { + OSAL_IRQ_PROLOGUE(); + gpt_lld_handler(&GPTD2); + OSAL_IRQ_EPILOGUE(); +} +#endif + +#if (NUC123_GPT_USE_TIMER3 == TRUE) || defined(__DOXYGEN__) +OSAL_IRQ_HANDLER(NUC123_TIM4_HANDLER) { + OSAL_IRQ_PROLOGUE(); + gpt_lld_handler(&GPTD3); + OSAL_IRQ_EPILOGUE(); +} +#endif + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** + * @brief Low level GPT driver initialization. + * + * @notapi + */ +void gpt_lld_init(void) { + /* Driver initialization.*/ +#if NUC123_GPT_USE_TIMER0 == TRUE + gptObjectInit(&GPTD0); + GPTD0.TIMER = TIMER0; +#endif +#if NUC123_GPT_USE_TIMER1 == TRUE + gptObjectInit(&GPTD1); + GPTD1.TIMER = TIMER1; +#endif +#if NUC123_GPT_USE_TIMER2 == TRUE + gptObjectInit(&GPTD2); + GPTD2.TIMER = TIMER2; +#endif +#if NUC123_GPT_USE_TIMER3 == TRUE + gptObjectInit(&GPTD3); + GPTD3.TIMER = TIMER3; +#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 clksel1; + if (gptp->state == GPT_STOP) { + clksel1 = CLK->CLKSEL1; + /* Enables the peripheral.*/ +#if NUC123_GPT_USE_TIMER0 == TRUE + if (&GPTD0 == gptp) { + clksel1 &= (~CLK_CLKSEL1_TMR0_S_Msk) | (NUC123_TIMER_CLKSRC_HCLK << CLK_CLKSEL1_TMR0_S_Pos); + CLK->APBCLK |= CLK_APBCLK_TMR0_EN_Msk; + nvicEnableVector(NUC123_TIM1_NUMBER, NUC123_GPT_TIMER0_IRQ_PRIORITY); + } +#endif +#if NUC123_GPT_USE_TIMER1 == TRUE + if (&GPTD1 == gptp) { + clksel1 &= (~CLK_CLKSEL1_TMR1_S_Msk) | (NUC123_TIMER_CLKSRC_HCLK << CLK_CLKSEL1_TMR1_S_Pos); + CLK->APBCLK |= CLK_APBCLK_TMR1_EN_Msk; + nvicEnableVector(NUC123_TIM2_NUMBER, NUC123_GPT_TIMER1_IRQ_PRIORITY); + } +#endif +#if NUC123_GPT_USE_TIMER2 == TRUE + if (&GPTD2 == gptp) { + clksel1 &= (~CLK_CLKSEL1_TMR2_S_Msk) | (NUC123_TIMER_CLKSRC_HCLK << CLK_CLKSEL1_TMR2_S_Pos); + CLK->APBCLK |= CLK_APBCLK_TMR2_EN_Msk; + nvicEnableVector(NUC123_TIM3_NUMBER, NUC123_GPT_TIMER2_IRQ_PRIORITY); + } +#endif +#if NUC123_GPT_USE_TIMER3 == TRUE + if (&GPTD3 == gptp) { + clksel1 &= (~CLK_CLKSEL1_TMR3_S_Msk) | (NUC123_TIMER_CLKSRC_HCLK << CLK_CLKSEL1_TMR3_S_Pos); + CLK->APBCLK |= CLK_APBCLK_TMR3_EN_Msk; + nvicEnableVector(NUC123_TIM4_NUMBER, NUC123_GPT_TIMER3_IRQ_PRIORITY); + } +#endif + } + + /* Configures the peripheral.*/ + gptp->TIMER->TCSR = 0; +} + +/** + * @brief Deactivates the GPT peripheral. + * + * @param[in] gptp pointer to the @p GPTDriver object + * + * @notapi + */ +void gpt_lld_stop(GPTDriver *gptp) { + if (gptp->state == GPT_READY) { + /* Resets the peripheral.*/ + /* Disables the peripheral.*/ +#if NUC123_GPT_USE_TIMER0 == TRUE + if (&GPTD0 == gptp) { + SYS->IPRSTC2 |= SYS_IPRSTC2_TMR0_RST_Msk; + SYS->IPRSTC2 &= ~SYS_IPRSTC2_TMR0_RST_Msk; + CLK->APBCLK &= ~CLK_APBCLK_TMR0_EN_Msk; + nvicDisableVector(NUC123_TIM1_NUMBER); + } +#endif +#if NUC123_GPT_USE_TIMER1 == TRUE + if (&GPTD1 == gptp) { + SYS->IPRSTC2 |= SYS_IPRSTC2_TMR1_RST_Msk; + SYS->IPRSTC2 &= ~SYS_IPRSTC2_TMR1_RST_Msk; + CLK->APBCLK &= ~CLK_APBCLK_TMR1_EN_Msk; + nvicDisableVector(NUC123_TIM2_NUMBER); + } +#endif +#if NUC123_GPT_USE_TIMER2 == TRUE + if (&GPTD2 == gptp) { + SYS->IPRSTC2 |= SYS_IPRSTC2_TMR2_RST_Msk; + SYS->IPRSTC2 &= ~SYS_IPRSTC2_TMR2_RST_Msk; + CLK->APBCLK &= ~CLK_APBCLK_TMR2_EN_Msk; + nvicDisableVector(NUC123_TIM3_NUMBER); + } +#endif +#if NUC123_GPT_USE_TIMER3 == TRUE + if (&GPTD3 == gptp) { + SYS->IPRSTC2 |= SYS_IPRSTC2_TMR3_RST_Msk; + SYS->IPRSTC2 &= ~SYS_IPRSTC2_TMR3_RST_Msk; + CLK->APBCLK &= ~CLK_APBCLK_TMR3_EN_Msk; + nvicDisableVector(NUC123_TIM4_NUMBER); + } +#endif + } +} + +/** + * @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) { + gptp->TIMER->TISR = TIMER_TISR_TIF_Msk | TIMER_TISR_TWF_Msk; + gptp->TIMER->TCMPR = ((NUC123_HCLK / gptp->config->frequency) * interval) & 0xFFFFFF; + gptp->TIMER->TCSR = NUC123_TIMER_TCSR_MODE_PERIODIC | TIMER_TCSR_CRST_Msk | + TIMER_TCSR_TDR_EN_Msk | TIMER_TCSR_CEN_Msk | TIMER_TCSR_IE_Msk; +} + +/** + * @brief Stops the timer. + * + * @param[in] gptp pointer to the @p GPTDriver object + * + * @notapi + */ +void gpt_lld_stop_timer(GPTDriver *gptp) { + gptp->TIMER->TCSR &= (~TIMER_TCSR_CEN_Msk) | (~TIMER_TCSR_IE_Msk); +} + +/** + * @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) { + gptp->TIMER->TISR = TIMER_TISR_TIF_Msk | TIMER_TISR_TWF_Msk; + gptp->TIMER->TCMPR = ((NUC123_HCLK / gptp->config->frequency) * interval) & 0xFFFFFF; + gptp->TIMER->TCSR = NUC123_TIMER_TCSR_MODE_ONESHOT | TIMER_TCSR_CRST_Msk | + TIMER_TCSR_TDR_EN_Msk | TIMER_TCSR_CEN_Msk | TIMER_TCSR_IE_Msk; + while (!(gptp->TIMER->TISR & TIMER_TISR_TIF_Msk)) + ; +} + +#endif /* HAL_USE_GPT == TRUE */ + +/** @} */ diff --git a/os/hal/ports/NUMICRO/LLD/TIMv1/hal_gpt_lld.h b/os/hal/ports/NUMICRO/LLD/TIMv1/hal_gpt_lld.h new file mode 100644 index 0000000000..e5d5a38227 --- /dev/null +++ b/os/hal/ports/NUMICRO/LLD/TIMv1/hal_gpt_lld.h @@ -0,0 +1,241 @@ +/* + Copyright (C) 2024 Hansem Ro + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +/** + * @file hal_gpt_lld.h + * @brief PLATFORM GPT subsystem low level driver header. + * + * @addtogroup GPT + * @{ + */ + +#ifndef HAL_GPT_LLD_H +#define HAL_GPT_LLD_H + +#if (HAL_USE_GPT == TRUE) || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Driver constants. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver pre-compile time settings. */ +/*===========================================================================*/ + +/** + * @name PLATFORM configuration options + * @{ + */ +/** + * @brief GPTD0 driver enable switch. + * @details If set to @p TRUE the support for GPTD0 is included. + * @note The default is @p FALSE. + */ +#if !defined(NUC123_GPT_USE_TIMER0) || defined(__DOXYGEN__) +#define NUC123_GPT_USE_TIMER0 FALSE +#endif + +/** + * @brief GPTD1 driver enable switch. + * @details If set to @p TRUE the support for GPTD1 is included. + * @note The default is @p FALSE. + */ +#if !defined(NUC123_GPT_USE_TIMER1) || defined(__DOXYGEN__) +#define NUC123_GPT_USE_TIMER1 FALSE +#endif + +/** + * @brief GPTD2 driver enable switch. + * @details If set to @p TRUE the support for GPTD2 is included. + * @note The default is @p FALSE. + */ +#if !defined(NUC123_GPT_USE_TIMER2) || defined(__DOXYGEN__) +#define NUC123_GPT_USE_TIMER2 FALSE +#endif + +/** + * @brief GPTD3 driver enable switch. + * @details If set to @p TRUE the support for GPTD3 is included. + * @note The default is @p FALSE. + */ +#if !defined(NUC123_GPT_USE_TIMER3) || defined(__DOXYGEN__) +#define NUC123_GPT_USE_TIMER3 FALSE +#endif + +/** + * @brief GPTD0 interrupt priority level setting. + */ +#if !defined(NUC123_GPT_TIMER0_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define NUC123_GPT_TIMER0_IRQ_PRIORITY 3 +#endif + +/** + * @brief GPTD1 interrupt priority level setting. + */ +#if !defined(NUC123_GPT_TIMER1_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define NUC123_GPT_TIMER1_IRQ_PRIORITY 3 +#endif + +/** + * @brief GPTD2 interrupt priority level setting. + */ +#if !defined(NUC123_GPT_TIMER2_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define NUC123_GPT_TIMER2_IRQ_PRIORITY 3 +#endif + +/** + * @brief GPTD3 interrupt priority level setting. + */ +#if !defined(NUC123_GPT_TIMER3_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define NUC123_GPT_TIMER3_IRQ_PRIORITY 3 +#endif +/** @} */ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* 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.*/ +} 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.*/ + TIMER_T *TIMER; +}; + +/*===========================================================================*/ +/* Driver macros. */ +/*===========================================================================*/ + +/** + * @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 + */ +#define gpt_lld_change_interval(gptp, interval) \ + ((gptp)->TIMER->TCMPR = (NUC123_HCLK / (gptp)->config->frequency) * (interval)) + +/** + * @brief Returns the interval of GPT peripheral. + * @pre The GPT unit must be running in continuous mode. + * + * @param[in] gptp pointer to a @p GPTDriver object + * @return The current interval. + * @notapi + */ +#define gpt_lld_get_interval(gptp) \ + ((gptcnt_t)(gptp)->TIMER->TCMPR / (NUC122_HCLK / (gptp)->config->frequency)) + +/** + * @brief Returns the counter value of GPT peripheral. + * @pre The GPT unit must be running in continuous mode. + * @note The nature of the counter is not defined, it may count upward + * or downward, it could be continuously running or not. + * + * @param[in] gptp pointer to a @p GPTDriver object + * @return The current counter value. + * @notapi + */ +#define gpt_lld_get_counter(gptp) \ + ((gptcnt_t)((gptp)->TIMER->TDR / (NUC123_HCLK / (gptp)->config->frequency))) + +/*===========================================================================*/ +/* External declarations. */ +/*===========================================================================*/ + +#if (NUC123_GPT_USE_TIMER0 == TRUE) && !defined(__DOXYGEN__) +extern GPTDriver GPTD0; +#endif +#if (NUC123_GPT_USE_TIMER1 == TRUE) && !defined(__DOXYGEN__) +extern GPTDriver GPTD1; +#endif +#if (NUC123_GPT_USE_TIMER2 == TRUE) && !defined(__DOXYGEN__) +extern GPTDriver GPTD2; +#endif +#if (NUC123_GPT_USE_TIMER3 == TRUE) && !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 interval); + void gpt_lld_stop_timer(GPTDriver *gptp); + void gpt_lld_polled_delay(GPTDriver *gptp, gptcnt_t interval); +#ifdef __cplusplus +} +#endif + +#endif /* HAL_USE_GPT == TRUE */ + +#endif /* HAL_GPT_LLD_H */ + +/** @} */