diff --git a/bsp/novosns/ns800/libraries/HAL_Drivers/drivers/SConscript b/bsp/novosns/ns800/libraries/HAL_Drivers/drivers/SConscript index 6f2f6c5427a..994c5dcf632 100644 --- a/bsp/novosns/ns800/libraries/HAL_Drivers/drivers/SConscript +++ b/bsp/novosns/ns800/libraries/HAL_Drivers/drivers/SConscript @@ -19,6 +19,9 @@ if GetDepend('BSP_USING_CAN'): if GetDepend('BSP_USING_ECAP'): src += ['drv_ecap.c'] +if GetDepend('BSP_USING_TIM'): + src += ['drv_timer.c'] + group = DefineGroup('HAL_Drivers', src, depend = [''], CPPPATH = path) Return('group') diff --git a/bsp/novosns/ns800/libraries/HAL_Drivers/drivers/drv_timer.c b/bsp/novosns/ns800/libraries/HAL_Drivers/drivers/drv_timer.c new file mode 100644 index 00000000000..683d8888a08 --- /dev/null +++ b/bsp/novosns/ns800/libraries/HAL_Drivers/drivers/drv_timer.c @@ -0,0 +1,288 @@ +/* + * Copyright (c) 2006-2025, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2026-05-16 oxlm First Version + */ + +#include +#include +#include +#include "drv_config.h" +#include "tim.h" +#include "rcc.h" + +#ifdef BSP_USING_TIM + +#define DRV_DEBUG +#define LOG_TAG "drv.timer" +#include + +struct ns800_clock_timer +{ + rt_clock_timer_t timer; + void *instance; + IRQn_Type irqno; + void (*irq_handler)(void); + char *name; + rt_clock_timer_mode_t mode; +}; + +enum +{ +#ifdef BSP_USING_TIM1 + TIM1_INDEX, +#endif +#ifdef BSP_USING_TIM2 + TIM2_INDEX, +#endif +}; + +#ifdef BSP_USING_TIM1 +void TIM1_IRQHandler(void); +#endif +#ifdef BSP_USING_TIM2 +void TIM2_IRQHandler(void); +#endif + +static struct ns800_clock_timer ns800_timers[] = +{ +#ifdef BSP_USING_TIM1 + {.instance = TIM1, .irqno = TIM1_IRQn, .irq_handler = TIM1_IRQHandler, .name = "timer1"}, +#endif +#ifdef BSP_USING_TIM2 + {.instance = TIM2, .irqno = TIM2_IRQn, .irq_handler = TIM2_IRQHandler, .name = "timer2"}, +#endif +}; + +#define NS800_TIMER_NUM (sizeof(ns800_timers) / sizeof(ns800_timers[0])) + +static void ns800_clock_timer_isr(void *param) +{ + rt_interrupt_enter(); + + struct ns800_clock_timer *tim = (struct ns800_clock_timer *)param; + TIM_TypeDef *htim = (TIM_TypeDef *)tim->instance; + + if (TIM_getFlags(htim, TIM_FLAG_UPDATE)) + { + TIM_clearFlags(htim, TIM_FLAG_UPDATE); + rt_clock_timer_isr(&tim->timer); + + if (tim->mode == CLOCK_TIMER_MODE_ONESHOT) + { + TIM_disableCounter(htim); + } + } + + rt_interrupt_leave(); + __DSB(); +} + +#ifdef BSP_USING_TIM1 +void TIM1_IRQHandler(void) +{ + ns800_clock_timer_isr(&ns800_timers[TIM1_INDEX]); +} +#endif +#ifdef BSP_USING_TIM2 +void TIM2_IRQHandler(void) +{ + ns800_clock_timer_isr(&ns800_timers[TIM2_INDEX]); +} +#endif + +static void ns800_clock_timer_init(rt_clock_timer_t *timer, rt_uint32_t state) +{ + struct ns800_clock_timer *tim = (struct ns800_clock_timer *)timer->parent.user_data; + TIM_TypeDef *htim = (TIM_TypeDef *)tim->instance; + + if (state) + { + __IO uint32_t cfg = + TIM_PWMMODE_ONEPOINT | + TIM_CLOCKDIVISION_DIV1 | + TIM_AUTORELOADPRELOAD_ENABLE | + TIM_COUNTERMODE_UP | + TIM_ONEPULSEMODE_REPETITIVE; + + TIM_configTimeBase(htim, 200 - 1, 100 - 1, cfg); + TIM_clearFlags(htim, TIM_FLAG_UPDATE); + TIM_enableInterruptSource(htim, TIM_IT_UPDATE); + } + else + { + TIM_disableInterruptSource(htim, TIM_IT_UPDATE); + TIM_disableCounter(htim); + } +} + +static rt_err_t ns800_clock_timer_start(rt_clock_timer_t *timer, rt_uint32_t cnt, rt_clock_timer_mode_t mode) +{ + struct ns800_clock_timer *tim = (struct ns800_clock_timer *)timer->parent.user_data; + tim->mode = mode; + + TIM_TypeDef *htim = (TIM_TypeDef *)tim->instance; + + if (cnt > 0xFFFF) + { + cnt = 0xFFFF; + } + + TIM_setAutoReload(htim, cnt - 1); + TIM_setCounter(htim, 0); + TIM_enableCounter(htim); + + return RT_EOK; +} + +static void ns800_clock_timer_stop(rt_clock_timer_t *timer) +{ + struct ns800_clock_timer *tim = (struct ns800_clock_timer *)timer->parent.user_data; + + TIM_disableCounter((TIM_TypeDef *)tim->instance); +} + +static rt_uint32_t ns800_clock_timer_count_get(rt_clock_timer_t *timer) +{ + struct ns800_clock_timer *tim = (struct ns800_clock_timer *)timer->parent.user_data; + + return TIM_getCounter((TIM_TypeDef *)tim->instance); +} + +static uint32_t __get_timer_src_clk(TIM_TypeDef *htim) +{ + if (htim == TIM1) + { + uint32_t pclk = RCC_getPclk2Frequency(); + + return (RCC_getApb2ClkDiv() == RCC_APB2_4_HCLK_DIV1) ? pclk : (pclk << 1); + } + else if (htim == TIM2) + { + uint32_t pclk = RCC_getPclk2Frequency(); + + return (RCC_getApb2ClkDiv() == RCC_APB2_4_HCLK_DIV1) ? pclk : (pclk << 1); + } + + return 0; +} + +static rt_err_t __set_timerx_freq(rt_clock_timer_t *timer, uint32_t freq) +{ + struct ns800_clock_timer *tim = timer->parent.user_data; + TIM_TypeDef *htim = (TIM_TypeDef *)tim->instance; + uint32_t timer_clk; + uint32_t psc; + + if (freq == 0) + { + return -RT_ERROR; + } + + timer_clk = __get_timer_src_clk(htim); + if (timer_clk == 0) + { + LOG_E("timer %s does not use internal RCC clock source or clock query failed", tim->name); + return -RT_ERROR; + } + + psc = (timer_clk / freq) - 1; + TIM_setPrescaler(htim, psc); + + return RT_EOK; +} + +static rt_err_t ns800_clock_timer_control(rt_clock_timer_t *timer, rt_uint32_t cmd, void *args) +{ + rt_err_t err = RT_EOK; + rt_int32_t freq; + + switch (cmd) + { + case CLOCK_TIMER_CTRL_FREQ_SET: + freq = *(rt_uint32_t *)args; + __set_timerx_freq(timer, freq); + break; + case CLOCK_TIMER_CTRL_INFO_GET: + *(struct rt_clock_timer_info *)args = *timer->info; + err = RT_EOK; + break; + case CLOCK_TIMER_CTRL_MODE_SET: + timer->mode = *(rt_uint32_t *)args; + break; + case CLOCK_TIMER_CTRL_STOP: + ns800_clock_timer_stop(timer); + break; + } + + return err; +} + +static const struct rt_clock_timer_info ns800_clock_timer_info[] = +{ +#ifdef BSP_USING_TIM1 + { + .maxfreq = 200000000UL, + .minfreq = 1UL, + .maxcnt = 0xFFFF, + .cntmode = CLOCK_TIMER_CNTMODE_UP, + }, +#endif +#ifdef BSP_USING_TIM2 + { + .maxfreq = 200000000UL, + .minfreq = 1UL, + .maxcnt = 0xFFFF, + .cntmode = CLOCK_TIMER_CNTMODE_UP, + }, +#endif +}; + +static const struct rt_clock_timer_ops ns800_clock_timer_ops = +{ + .init = ns800_clock_timer_init, + .start = ns800_clock_timer_start, + .stop = ns800_clock_timer_stop, + .count_get = ns800_clock_timer_count_get, + .control = ns800_clock_timer_control, +}; + +int rt_hw_clock_timer_init(void) +{ + rt_err_t ret = RT_EOK; + + if (NS800_TIMER_NUM == 0) + { + return RT_EOK; + } + + uint8_t i; + IRQn_Type last_irq = (IRQn_Type)0; + + for (i = 0; i < NS800_TIMER_NUM; i++) + { + ns800_timers[i].timer.info = &ns800_clock_timer_info[i]; + ns800_timers[i].timer.ops = &ns800_clock_timer_ops; + + ret = rt_clock_timer_register(&ns800_timers[i].timer, + ns800_timers[i].name, + &ns800_timers[i]); + + if ((ret == RT_EOK) && (ns800_timers[i].irqno != last_irq)) + { + Interrupt_register(ns800_timers[i].irqno, ns800_timers[i].irq_handler); + Interrupt_enable(ns800_timers[i].irqno); + last_irq = ns800_timers[i].irqno; + } + } + + return RT_EOK; +} + +INIT_DEVICE_EXPORT(rt_hw_clock_timer_init); + +#endif /* BSP_USING_TIM */ diff --git a/bsp/novosns/ns800/ns800rt7p65-nssinepad/board/Kconfig b/bsp/novosns/ns800/ns800rt7p65-nssinepad/board/Kconfig index c4bbdf3080b..e3ca09b5736 100644 --- a/bsp/novosns/ns800/ns800rt7p65-nssinepad/board/Kconfig +++ b/bsp/novosns/ns800/ns800rt7p65-nssinepad/board/Kconfig @@ -105,4 +105,23 @@ menu "On-chip Peripheral Drivers" endif + menuconfig BSP_USING_TIM + bool "Enable TIM (Hardware Timer)" + select RT_USING_CLOCK_TIME + default n + help + Enable hardware timer TIM driver + + if BSP_USING_TIM + menu "TIM Timer Configuration" + config BSP_USING_TIM1 + bool "Enable TIM1" + default n + config BSP_USING_TIM2 + bool "Enable TIM2" + default n + endmenu + + endif + endmenu