mirror of
https://github.com/RT-Thread/rt-thread.git
synced 2026-08-19 05:13:04 +08:00
[novosns][ns800][drivers] 增加 TIM 硬件定时器支持#11395
ToolsCI / Tools (push) Has been cancelled
RT-Thread BSP Static Build Check / 🔍 Summary of Git Diff Changes (push) Has been cancelled
RT-Thread BSP Static Build Check / ${{ matrix.legs.RTT_BSP }} (push) Has been cancelled
RT-Thread BSP Static Build Check / collect-artifacts (push) Has been cancelled
pkgs_test / change (push) Has been cancelled
ToolsCI / Tools (push) Has been cancelled
RT-Thread BSP Static Build Check / 🔍 Summary of Git Diff Changes (push) Has been cancelled
RT-Thread BSP Static Build Check / ${{ matrix.legs.RTT_BSP }} (push) Has been cancelled
RT-Thread BSP Static Build Check / collect-artifacts (push) Has been cancelled
pkgs_test / change (push) Has been cancelled
This commit is contained in:
@@ -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')
|
||||
|
||||
@@ -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 <board.h>
|
||||
#include <rtthread.h>
|
||||
#include <rtdevice.h>
|
||||
#include "drv_config.h"
|
||||
#include "tim.h"
|
||||
#include "rcc.h"
|
||||
|
||||
#ifdef BSP_USING_TIM
|
||||
|
||||
#define DRV_DEBUG
|
||||
#define LOG_TAG "drv.timer"
|
||||
#include <drv_log.h>
|
||||
|
||||
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 */
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user