diff --git a/bsp/lpc408x/drivers/drv_hwtimer.c b/bsp/lpc408x/drivers/drv_hwtimer.c new file mode 100644 index 0000000000..163c91fcd1 --- /dev/null +++ b/bsp/lpc408x/drivers/drv_hwtimer.c @@ -0,0 +1,153 @@ +/* + * File : drv_hwtimer.c + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2015, RT-Thread Development Team + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rt-thread.org/license/LICENSE + * + * Change Logs: + * Date Author Notes + * 2015-09-02 heyuanjie87 the first version + */ + +#include +#include +#include "lpc_timer.h" +#include "lpc_clkpwr.h" +#include "drv_hwtimer.h" + +#ifdef RT_USING_HWTIMER + +static void NVIC_Configuration(void) +{ + NVIC_EnableIRQ(TIMER0_IRQn); +} + +static void timer_init(rt_hwtimer_t *timer, rt_uint32_t state) +{ + LPC_TIM_TypeDef *tim; + TIM_TIMERCFG_Type cfg; + + tim = (LPC_TIM_TypeDef *)timer->parent.user_data; + + TIM_DeInit(tim); + + if (state == 1) + { + NVIC_Configuration(); + + cfg.PrescaleOption = TIM_PRESCALE_TICKVAL; + cfg.PrescaleValue = 0xFFFF; + TIM_Init(tim, TIM_TIMER_MODE, &cfg); + } +} + +static rt_err_t timer_start(rt_hwtimer_t *timer, rt_uint32_t t, rt_hwtimer_mode_t opmode) +{ + LPC_TIM_TypeDef *tim; + TIM_MATCHCFG_Type match; + + tim = (LPC_TIM_TypeDef *)timer->parent.user_data; + + match.MatchChannel = 0; + match.IntOnMatch = ENABLE; + match.ResetOnMatch = ENABLE; + match.StopOnMatch = (opmode == HWTIMER_MODE_ONESHOT)? ENABLE : DISABLE; + match.ExtMatchOutputType = 0; + match.MatchValue = t; + + TIM_ConfigMatch(tim, &match); + TIM_Cmd(tim, ENABLE); + + return RT_EOK; +} + +static void timer_stop(rt_hwtimer_t *timer) +{ + LPC_TIM_TypeDef *tim; + + tim = (LPC_TIM_TypeDef *)timer->parent.user_data; + + TIM_Cmd(tim, DISABLE); +} + +static rt_err_t timer_ctrl(rt_hwtimer_t *timer, rt_uint32_t cmd, void *arg) +{ + LPC_TIM_TypeDef *tim; + rt_err_t err = RT_EOK; + + tim = (LPC_TIM_TypeDef *)timer->parent.user_data; + + switch (cmd) + { + case HWTIMER_CTRL_FREQ_SET: + { + uint32_t clk; + uint32_t pre; + + clk = CLKPWR_GetCLK(CLKPWR_CLKTYPE_PER); + pre = clk / *((uint32_t*)arg) - 1; + tim->PR = pre; + } + break; + default: + { + err = -RT_ENOSYS; + } + break; + } + + return err; +} + +static rt_uint32_t timer_counter_get(rt_hwtimer_t *timer) +{ + LPC_TIM_TypeDef *tim; + + tim = (LPC_TIM_TypeDef *)timer->parent.user_data; + + return tim->TC; +} + +static const struct rt_hwtimer_info _info = +{ + 1000000, /* the maximum count frequency can be set */ + 2000, /* the minimum count frequency can be set */ + 0xFFFFFF, /* the maximum counter value */ + HWTIMER_CNTMODE_UP,/* Increment or Decreasing count mode */ +}; + +static const struct rt_hwtimer_ops _ops = +{ + timer_init, + timer_start, + timer_stop, + timer_counter_get, + timer_ctrl, +}; + +static rt_hwtimer_t _timer0; + +int lpc_hwtimer_init(void) +{ + _timer0.info = &_info; + _timer0.ops = &_ops; + + rt_device_hwtimer_register(&_timer0, "timer0", LPC_TIM0); + + return 0; +} + +void TIMER0_IRQHandler(void) +{ + if (TIM_GetIntStatus(LPC_TIM0, TIM_MR0_INT) != RESET) + { + TIM_ClearIntPending(LPC_TIM0, TIM_MR0_INT); + rt_device_hwtimer_isr(&_timer0); + } +} + +INIT_BOARD_EXPORT(lpc_hwtimer_init); +#endif diff --git a/bsp/lpc408x/drivers/drv_hwtimer.h b/bsp/lpc408x/drivers/drv_hwtimer.h new file mode 100644 index 0000000000..b45b27dc06 --- /dev/null +++ b/bsp/lpc408x/drivers/drv_hwtimer.h @@ -0,0 +1,8 @@ +#ifndef __DRV_HWTIMER_H__ +#define __DRV_HWTIMER_H__ + + +int stm32_hwtimer_init(void); + + +#endif diff --git a/bsp/stm32f40x/drivers/drv_hwtimer.c b/bsp/stm32f40x/drivers/drv_hwtimer.c new file mode 100644 index 0000000000..8802021e18 --- /dev/null +++ b/bsp/stm32f40x/drivers/drv_hwtimer.c @@ -0,0 +1,157 @@ +/* + * File : drv_hwtimer.c + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2015, RT-Thread Development Team + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rt-thread.org/license/LICENSE + * + * Change Logs: + * Date Author Notes + * 2015-09-02 heyuanjie87 the first version + */ + +#include +#include +#include +#include "drv_hwtimer.h" + +#ifdef RT_USING_HWTIMER + +static void NVIC_Configuration(void) +{ + NVIC_InitTypeDef NVIC_InitStructure; + + /* Enable the TIM5 global Interrupt */ + NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn; + NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x00; + NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x00; + NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; + NVIC_Init(&NVIC_InitStructure); +} + +static void timer_init(rt_hwtimer_t *timer, rt_uint32_t state) +{ + TIM_TypeDef *tim; + + tim = (TIM_TypeDef *)timer->parent.user_data; + + TIM_DeInit(tim); + + if (state == 1) + { + NVIC_Configuration(); + RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); + TIM_CounterModeConfig(tim, TIM_CounterMode_Up); + } +} + +static rt_err_t timer_start(rt_hwtimer_t *timer, rt_uint32_t t, rt_hwtimer_mode_t opmode) +{ + TIM_TypeDef *tim; + uint16_t m; + + tim = (TIM_TypeDef *)timer->parent.user_data; + TIM_SetAutoreload(tim, t); + m = (opmode == HWTIMER_MODE_ONESHOT)? TIM_OPMode_Single : TIM_OPMode_Repetitive; + TIM_SelectOnePulseMode(tim, m); + TIM_Cmd(tim, ENABLE); + + return RT_EOK; +} + +static void timer_stop(rt_hwtimer_t *timer) +{ + TIM_TypeDef *tim; + + tim = (TIM_TypeDef *)timer->parent.user_data; + TIM_Cmd(tim, DISABLE); +} + +static rt_err_t timer_ctrl(rt_hwtimer_t *timer, rt_uint32_t cmd, void *arg) +{ + TIM_TypeDef *tim; + rt_err_t err = RT_EOK; + + tim = (TIM_TypeDef *)timer->parent.user_data; + + switch (cmd) + { + case HWTIMER_CTRL_FREQ_SET: + { + RCC_ClocksTypeDef clk; + uint16_t val; + rt_uint32_t freq; + + RCC_GetClocksFreq(&clk); + + freq = *((rt_uint32_t*)arg); + clk.PCLK1_Frequency *= 2; + val = clk.PCLK1_Frequency/freq; + + TIM_ITConfig(tim, TIM_IT_Update, DISABLE); + TIM_PrescalerConfig(tim, val - 1, TIM_PSCReloadMode_Immediate); + TIM_ClearITPendingBit(TIM2, TIM_IT_Update); + TIM_ITConfig(tim, TIM_IT_Update, ENABLE); + } + break; + default: + { + err = -RT_ENOSYS; + } + break; + } + + return err; +} + +static rt_uint32_t timer_counter_get(rt_hwtimer_t *timer) +{ + TIM_TypeDef *tim; + + tim = (TIM_TypeDef *)timer->parent.user_data; + + return TIM_GetCounter(tim); +} + +static const struct rt_hwtimer_info _info = +{ + 1000000, /* the maximum count frequency can be set */ + 2000, /* the minimum count frequency can be set */ + 0xFFFF, /* the maximum counter value */ + HWTIMER_CNTMODE_UP,/* Increment or Decreasing count mode */ +}; + +static const struct rt_hwtimer_ops _ops = +{ + timer_init, + timer_start, + timer_stop, + timer_counter_get, + timer_ctrl, +}; + +static rt_hwtimer_t _timer0; + +int stm32_hwtimer_init(void) +{ + _timer0.info = &_info; + _timer0.ops = &_ops; + + rt_device_hwtimer_register(&_timer0, "timer0", TIM2); + + return 0; +} + +void TIM2_IRQHandler(void) +{ + if (TIM_GetITStatus(TIM2, TIM_IT_Update) != RESET) + { + TIM_ClearITPendingBit(TIM2, TIM_IT_Update); + rt_device_hwtimer_isr(&_timer0); + } +} + +INIT_BOARD_EXPORT(stm32_hwtimer_init); +#endif diff --git a/bsp/stm32f40x/drivers/drv_hwtimer.h b/bsp/stm32f40x/drivers/drv_hwtimer.h new file mode 100644 index 0000000000..b45b27dc06 --- /dev/null +++ b/bsp/stm32f40x/drivers/drv_hwtimer.h @@ -0,0 +1,8 @@ +#ifndef __DRV_HWTIMER_H__ +#define __DRV_HWTIMER_H__ + + +int stm32_hwtimer_init(void); + + +#endif diff --git a/bsp/stm32f40x/rtconfig.h b/bsp/stm32f40x/rtconfig.h index 88dfd0b616..9cca3f8424 100644 --- a/bsp/stm32f40x/rtconfig.h +++ b/bsp/stm32f40x/rtconfig.h @@ -69,6 +69,9 @@ /* Using GPIO pin framework */ #define RT_USING_PIN +/* Using Hardware Timer framework */ +//#define RT_USING_HWTIMER + /* SECTION: Console options */ #define RT_USING_CONSOLE /* the buffer size of console*/ diff --git a/components/drivers/hwtimer/README_CN.md b/components/drivers/hwtimer/README_CN.md new file mode 100644 index 0000000000..fb3b4fa60a --- /dev/null +++ b/components/drivers/hwtimer/README_CN.md @@ -0,0 +1,98 @@ +定时器设备 +=== + +##功能 +--- +* 时间测量 +* 周期或单次执行回调函数 + +##编译 +--- +1. 在rtconfig.h添加 `#define RT_USING_HWTIMER` + +##使用流程 +--- +1. 以读写方式打开设备 +2. 设置超时回调函数(如果需要) +3. 根据需要设置定时模式(单次/周期) +4. 设置计数频率(可选) +5. 写入超时值,定时器随即启动 +6. 停止定时器(可选) +7. 关闭设备(如果需要) + +应用参考 [hwtimer_test] (/examples/test/hwtimer\_test.c) + +##驱动编写指南 +--- +###操作接口 + +``` +struct rt_hwtimer_ops +{ + void (*init)(struct rt_hwtimer_device *timer, rt_uint32_t state); + rt_err_t (*start)(struct rt_hwtimer_device *timer, rt_uint32_t cnt, rt_hwtimer_mode_t mode); + void (*stop)(struct rt_hwtimer_device *timer); + rt_uint32_t (*count_get)(struct rt_hwtimer_device *timer); + rt_err_t (*control)(struct rt_hwtimer_device *timer, rt_uint32_t cmd, void *args); +}; +``` + +* init - state <1 打开设备 0 关闭设备> +* start - cnt <超时值> - mode <单次/周期> +* stop - <停止计数> +* count_get - <读取计数器值> +* control - <设置计数频率 > + +###定时器特征信息 + +``` +struct rt_hwtimer_info +{ + rt_int32_t maxfreq; + rt_int32_t minfreq; + rt_uint32_t maxcnt; + rt_uint8_t cntmode; + }; +``` + +* maxfreq <设备支持的最大计数频率> +* minfreq <设备支持的最小计数频率> +* maxcnt <计数器最大计数值> +* cntmode <递增计数/递减计数> + +###注册设备 +``` +static rt_hwtimer_t _timer0; +int stm32_hwtimer_init(void) +{ + _timer0.info = &_info; + _timer0.ops = &_ops; + + rt_device_hwtimer_register(&_timer0, "timer0", TIM2); + + return 0; +} +``` + +###定时器中断 +``` +void timer_irq_handler(void) +{ + //其它操作 + + rt_device_hwtimer_isr(&_timer0); +} +``` + +##注意事项 +--- + +可能出现定时误差 + + +误差原因: + +假设计数器最大值0xFFFF,计数频率1Mhz,定时时间1秒又1微秒。 + +由于定时器一次最多只能计时到65535us,对于1000001us的定时要求。 +可以50000us定时20次完成,此时将会出现计算误差1us。 diff --git a/components/drivers/hwtimer/SConscript b/components/drivers/hwtimer/SConscript new file mode 100644 index 0000000000..534e04b6c0 --- /dev/null +++ b/components/drivers/hwtimer/SConscript @@ -0,0 +1,8 @@ +from building import * + +cwd = GetCurrentDir() +src = Glob('*.c') +CPPPATH = [cwd + '/../include'] +group = DefineGroup('DeviceDrivers', src, depend = ['RT_USING_HWTIMER'], CPPPATH = CPPPATH) + +Return('group') diff --git a/components/drivers/hwtimer/hwtimer.c b/components/drivers/hwtimer/hwtimer.c new file mode 100644 index 0000000000..22b8d6262c --- /dev/null +++ b/components/drivers/hwtimer/hwtimer.c @@ -0,0 +1,355 @@ +/* + * File : hwtimer.c + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2006 - 2012, RT-Thread Development Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Change Logs: + * Date Author Notes + * 2015-08-31 heyuanjie87 first version + */ + +#include +#include + +rt_inline rt_uint32_t timeout_calc(rt_hwtimer_t *timer, rt_hwtimerval_t *tv) +{ + float overflow; + float timeout; + rt_uint32_t counter; + int i, index; + float tv_sec; + float devi_min = 1; + float devi; + + /* ѶʱʱͶʱʱ任 */ + overflow = timer->info->maxcnt/(float)timer->freq; + tv_sec = tv->sec + tv->usec/(float)1000000; + + if (tv_sec < (1/(float)timer->freq)) + { + /* ʱʱСڼ */ + i = 0; + timeout = 1/(float)timer->freq; + } + else + { + for (i = 1; i > 0; i ++) + { + timeout = tv_sec/i; + + if (timeout <= overflow) + { + counter = timeout*timer->freq; + devi = tv_sec - (counter/(float)timer->freq)*i; + /* С */ + if (devi > devi_min) + { + i = index; + timeout = tv_sec/i; + break; + } + else if (devi == 0) + { + break; + } + else if (devi < devi_min) + { + devi_min = devi; + index = i; + } + } + } + } + + timer->cycles = i; + timer->reload = i; + timer->period_sec = timeout; + counter = timeout*timer->freq; + + return counter; +} + +static rt_err_t rt_hwtimer_init(struct rt_device *dev) +{ + rt_err_t result = RT_EOK; + rt_hwtimer_t *timer; + + timer = (rt_hwtimer_t *)dev; + /* ԽĬϼƵΪ1Mhz */ + if ((1000000 <= timer->info->maxfreq) && (1000000 >= timer->info->minfreq)) + { + timer->freq = 1000000; + } + else + { + timer->freq = timer->info->minfreq; + } + timer->mode = HWTIMER_MODE_ONESHOT; + timer->cycles = 0; + timer->overflow = 0; + + if (timer->ops->init) + { + timer->ops->init(timer, 1); + } + else + { + result = -RT_ENOSYS; + } + + return result; +} + +static rt_err_t rt_hwtimer_open(struct rt_device *dev, rt_uint16_t oflag) +{ + rt_err_t result = RT_EOK; + rt_hwtimer_t *timer; + + timer = (rt_hwtimer_t *)dev; + if (timer->ops->control != RT_NULL) + { + timer->ops->control(timer, HWTIMER_CTRL_FREQ_SET, &timer->freq); + } + else + { + result = -RT_ENOSYS; + } + + return result; +} + +static rt_err_t rt_hwtimer_close(struct rt_device *dev) +{ + rt_err_t result = RT_EOK; + rt_hwtimer_t *timer; + + timer = (rt_hwtimer_t*)dev; + if (timer->ops->init != RT_NULL) + { + timer->ops->init(timer, 0); + } + else + { + result = -RT_ENOSYS; + } + + dev->flag &= ~RT_DEVICE_FLAG_ACTIVATED; + dev->rx_indicate = RT_NULL; + + return result; +} + +static rt_size_t rt_hwtimer_read(struct rt_device *dev, rt_off_t pos, void *buffer, rt_size_t size) +{ + rt_hwtimer_t *timer; + rt_hwtimerval_t tv; + rt_uint32_t cnt; + float t; + + timer = (rt_hwtimer_t *)dev; + if (timer->ops->count_get == RT_NULL) + return 0; + + cnt = timer->ops->count_get(timer); + if (timer->info->cntmode == HWTIMER_CNTMODE_DW) + { + cnt = timer->info->maxcnt - cnt; + } + + t = timer->overflow * timer->period_sec + cnt/(float)timer->freq; + tv.sec = t; + tv.usec = (t - tv.sec) * 1000000; + size = size > sizeof(tv)? sizeof(tv) : size; + rt_memcpy(buffer, &tv, size); + + return size; +} + +static rt_size_t rt_hwtimer_write(struct rt_device *dev, rt_off_t pos, const void *buffer, rt_size_t size) +{ + rt_uint32_t t; + rt_hwtimer_mode_t opm = HWTIMER_MODE_PERIOD; + rt_hwtimer_t *timer; + + timer = (rt_hwtimer_t *)dev; + if ((timer->ops->start == RT_NULL) || (timer->ops->stop == RT_NULL)) + return 0; + + if (size != sizeof(rt_hwtimerval_t)) + return 0; + + if ((timer->cycles <= 1) && (timer->mode == HWTIMER_MODE_ONESHOT)) + { + opm = HWTIMER_MODE_ONESHOT; + } + timer->ops->stop(timer); + timer->overflow = 0; + + t = timeout_calc(timer, (rt_hwtimerval_t*)buffer); + if (timer->ops->start(timer, t, opm) != RT_EOK) + size = 0; + + return size; +} + +static rt_err_t rt_hwtimer_control(struct rt_device *dev, rt_uint8_t cmd, void *args) +{ + rt_err_t result = RT_EOK; + rt_hwtimer_t *timer; + + timer = (rt_hwtimer_t *)dev; + + switch (cmd) + { + case HWTIMER_CTRL_STOP: + { + if (timer->ops->stop != RT_NULL) + { + timer->ops->stop(timer); + } + else + { + result = -RT_ENOSYS; + } + } + break; + case HWTIMER_CTRL_FREQ_SET: + { + rt_uint32_t *f; + + if (args == RT_NULL) + { + result = -RT_EEMPTY; + break; + } + + f = (rt_uint32_t*)args; + if ((*f > timer->info->maxfreq) || (*f < timer->info->minfreq)) + { + result = -RT_ERROR; + break; + } + + if (timer->ops->control != RT_NULL) + { + result = timer->ops->control(timer, cmd, args); + if (result == RT_EOK) + { + timer->freq = *f; + } + } + else + { + result = -RT_ENOSYS; + } + } + break; + case HWTIMER_CTRL_INFO_GET: + { + if (args == RT_NULL) + { + result = -RT_EEMPTY; + break; + } + + *((struct rt_hwtimer_info*)args) = *timer->info; + } + case HWTIMER_CTRL_MODE_SET: + { + rt_hwtimer_mode_t *m; + + if (args == RT_NULL) + { + result = -RT_EEMPTY; + break; + } + + m = (rt_hwtimer_mode_t*)args; + + if ((*m != HWTIMER_MODE_ONESHOT) && (*m != HWTIMER_MODE_PERIOD)) + { + result = -RT_ERROR; + break; + } + + timer->mode = *m; + } + break; + default: + { + result = -RT_ENOSYS; + } + break; + } + + return result; +} + +void rt_device_hwtimer_isr(rt_hwtimer_t *timer) +{ + RT_ASSERT(timer != RT_NULL); + + timer->overflow ++; + + if (timer->cycles != 0) + { + timer->cycles --; + } + + if (timer->cycles == 0) + { + timer->cycles = timer->reload; + + if (timer->mode == HWTIMER_MODE_ONESHOT) + { + if (timer->ops->stop != RT_NULL) + { + timer->ops->stop(timer); + } + } + + if (timer->parent.rx_indicate != RT_NULL) + { + timer->parent.rx_indicate(&timer->parent, sizeof(struct rt_hwtimerval)); + } + } +} + +rt_err_t rt_device_hwtimer_register(rt_hwtimer_t *timer, const char *name, void *user_data) +{ + struct rt_device *device; + + RT_ASSERT(timer != RT_NULL); + RT_ASSERT(timer->ops != RT_NULL); + RT_ASSERT(timer->info != RT_NULL); + + device = &(timer->parent); + + device->type = RT_Device_Class_Timer; + device->rx_indicate = RT_NULL; + device->tx_complete = RT_NULL; + + device->init = rt_hwtimer_init; + device->open = rt_hwtimer_open; + device->close = rt_hwtimer_close; + device->read = rt_hwtimer_read; + device->write = rt_hwtimer_write; + device->control = rt_hwtimer_control; + device->user_data = user_data; + + return rt_device_register(device, name, RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_STANDALONE); +} diff --git a/components/drivers/include/drivers/hwtimer.h b/components/drivers/include/drivers/hwtimer.h new file mode 100644 index 0000000000..24cec74d32 --- /dev/null +++ b/components/drivers/include/drivers/hwtimer.h @@ -0,0 +1,78 @@ +#ifndef __HWTIMER_H__ +#define __HWTIMER_H__ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* Timer Control Command */ +typedef enum +{ + HWTIMER_CTRL_FREQ_SET = 0x01, /* set the count frequency */ + HWTIMER_CTRL_STOP, /* stop timer */ + HWTIMER_CTRL_INFO_GET, /* get a timer feature information */ + HWTIMER_CTRL_MODE_SET /* Setting the timing mode(oneshot/period) */ +} rt_hwtimer_ctrl_t; + +/* Timing Mode */ +typedef enum +{ + HWTIMER_MODE_ONESHOT = 0x01, + HWTIMER_MODE_PERIOD +} rt_hwtimer_mode_t; + +/* Time Value */ +typedef struct rt_hwtimerval +{ + rt_int32_t sec; /* second */ + rt_int32_t usec; /* microsecond */ +} rt_hwtimerval_t; + +#define HWTIMER_CNTMODE_UP 0x01 /* increment count mode */ +#define HWTIMER_CNTMODE_DW 0x02 /* decreasing count mode */ + +struct rt_hwtimer_device; + +struct rt_hwtimer_ops +{ + void (*init)(struct rt_hwtimer_device *timer, rt_uint32_t state); + rt_err_t (*start)(struct rt_hwtimer_device *timer, rt_uint32_t cnt, rt_hwtimer_mode_t mode); + void (*stop)(struct rt_hwtimer_device *timer); + rt_uint32_t (*count_get)(struct rt_hwtimer_device *timer); + rt_err_t (*control)(struct rt_hwtimer_device *timer, rt_uint32_t cmd, void *args); +}; + +/* Timer Feature Information */ +struct rt_hwtimer_info +{ + rt_int32_t maxfreq; /* the maximum count frequency timer support */ + rt_int32_t minfreq; /* the minimum count frequency timer support */ + rt_uint32_t maxcnt; /* counter maximum value */ + rt_uint8_t cntmode; /* count mode (inc/dec) */ +}; + +typedef struct rt_hwtimer_device +{ + struct rt_device parent; + const struct rt_hwtimer_ops *ops; + const struct rt_hwtimer_info *info; + + rt_int32_t freq; /* counting frequency set by the user */ + rt_int32_t overflow; /* timer overflows */ + float period_sec; + rt_int32_t cycles; /* how many times will generate a timeout event after overflow */ + rt_int32_t reload; /* reload cycles(using in period mode) */ + rt_hwtimer_mode_t mode; /* timing mode(oneshot/period) */ +} rt_hwtimer_t; + +rt_err_t rt_device_hwtimer_register(rt_hwtimer_t *timer, const char *name, void *user_data); +void rt_device_hwtimer_isr(rt_hwtimer_t *timer); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/components/drivers/include/rtdevice.h b/components/drivers/include/rtdevice.h index f4d967831c..475adebf80 100644 --- a/components/drivers/include/rtdevice.h +++ b/components/drivers/include/rtdevice.h @@ -370,6 +370,10 @@ rt_inline void rt_work_init(struct rt_work* work, void (*work_func)(struct rt_wo #include "drivers/can.h" #endif +#ifdef RT_USING_HWTIMER +#include "drivers/hwtimer.h" +#endif + #ifdef __cplusplus } #endif diff --git a/components/finsh/cmd.c b/components/finsh/cmd.c index 7d24a33d6a..c42b412f23 100644 --- a/components/finsh/cmd.c +++ b/components/finsh/cmd.c @@ -467,6 +467,7 @@ static long _list_device(struct rt_list_node *list) "PM Pseudo Device", "Pipe", "Portal Device", + "Timer Device", "Miscellaneous Device", "Unknown" }; diff --git a/examples/test/hwtimer_test.c b/examples/test/hwtimer_test.c new file mode 100644 index 0000000000..8f69c4ef87 --- /dev/null +++ b/examples/test/hwtimer_test.c @@ -0,0 +1,80 @@ +#include +#include +#include + +#ifdef RT_USING_HWTIMER + +#define TIMER "timer0" + +static rt_err_t timer_timeout_cb(rt_device_t dev, rt_size_t size) +{ + rt_kprintf("HT %d\n", rt_tick_get()); + + return 0; +} + +int hwtimer(void) +{ + rt_err_t err; + rt_hwtimerval_t val; + rt_device_t dev = RT_NULL; + rt_tick_t tick; + rt_hwtimer_mode_t mode; + int freq = 10000; + int t = 5; + + if ((dev = rt_device_find(TIMER)) == RT_NULL) + { + rt_kprintf("No Device: %s\n", TIMER); + return -1; + } + + if (rt_device_open(dev, RT_DEVICE_OFLAG_RDWR) != RT_EOK) + { + rt_kprintf("Open %s Fail\n", TIMER); + return -1; + } + + rt_device_set_rx_indicate(dev, timer_timeout_cb); + /* ʱ(Ĭ1Mhzֵ֧СƵ) */ + err = rt_device_control(dev, HWTIMER_CTRL_FREQ_SET, &freq); + if (err != RT_EOK) + { + rt_kprintf("Set Freq=%dhz Fail\n", freq); + goto EXIT; + } + + /* ģʽ */ + mode = HWTIMER_MODE_PERIOD; + err = rt_device_control(dev, HWTIMER_CTRL_MODE_SET, &mode); + + tick = rt_tick_get(); + rt_kprintf("Start Timer> Tick: %d\n", tick); + /* öʱʱֵʱ */ + val.sec = t; + val.usec = 0; + rt_kprintf("SetTime: Sec %d, Usec %d\n", val.sec, val.usec); + if (rt_device_write(dev, 0, &val, sizeof(val)) != sizeof(val)) + { + rt_kprintf("SetTime Fail\n"); + goto EXIT; + } + rt_kprintf("Sleep %d sec\n", t); + rt_thread_delay(t*RT_TICK_PER_SECOND); + + /* ֹͣʱ */ + err = rt_device_control(dev, HWTIMER_CTRL_STOP, RT_NULL); + rt_kprintf("Timer Stoped\n"); + /* ȡ */ + rt_device_read(dev, 0, &val, sizeof(val)); + rt_kprintf("Read: Sec = %d, Usec = %d\n", val.sec, val.usec); + +EXIT: + err = rt_device_close(dev); + rt_kprintf("Close %s\n", TIMER); + + return err; +} + +FINSH_FUNCTION_EXPORT(hwtimer, "Test hardware timer"); +#endif diff --git a/include/rtdef.h b/include/rtdef.h index 2587df9c41..a3dad27989 100644 --- a/include/rtdef.h +++ b/include/rtdef.h @@ -758,8 +758,9 @@ enum rt_device_class_type RT_Device_Class_PM, /**< PM pseudo device */ RT_Device_Class_Pipe, /**< Pipe device */ RT_Device_Class_Portal, /**< Portal device */ - RT_Device_Class_Miscellaneous, /**< Miscellaneous device */ - RT_Device_Class_Unknown /**< unknown device */ + RT_Device_Class_Timer, /**< Timer device */ + RT_Device_Class_Miscellaneous, /**< Miscellaneous device */ + RT_Device_Class_Unknown /**< unknown device */ }; /**