From c84887d021bc0d66352ead42366bd45868e1e4df Mon Sep 17 00:00:00 2001 From: heyuanjie87 Date: Wed, 2 Sep 2015 22:00:24 +0800 Subject: 加入定时器设备 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- components/drivers/hwtimer/SConscript | 8 + components/drivers/hwtimer/hwtimer.c | 397 +++++++++++++++++++++++++++ components/drivers/include/drivers/hwtimer.h | 83 ++++++ components/drivers/include/rtdevice.h | 4 + components/finsh/cmd.c | 1 + 5 files changed, 493 insertions(+) create mode 100644 components/drivers/hwtimer/SConscript create mode 100644 components/drivers/hwtimer/hwtimer.c create mode 100644 components/drivers/include/drivers/hwtimer.h (limited to 'components') 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..0d2df8f8ea --- /dev/null +++ b/components/drivers/hwtimer/hwtimer.c @@ -0,0 +1,397 @@ +/* + * 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_err_t timeout_set(rt_hwtimer_t *timer, rt_hwtimerval_t *tv) +{ + rt_err_t err; + float overflow; + float timeout; + rt_uint32_t counter; + int i, index; + float tv_sec; + float devi_min = 1; + float devi; + + if (timer->ops->stop != RT_NULL) + { + timer->ops->stop(timer); + } + else + { + return -RT_ENOSYS; + } + + /* °Ñ¶¨Ê±Æ÷Òç³öʱ¼äºÍ¶¨Ê±Ê±¼ä»»Ëã³ÉÃë */ + 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; + + if (timer->ops->timeout_set != RT_NULL) + { + err = timer->ops->timeout_set(timer, counter); + } + + return err; +} + +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; + + if (timer->ops->init) + { + timer->ops->init(timer); + } + 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->deinit != RT_NULL) + { + timer->ops->deinit(timer); + } + 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_size_t len = 0; + rt_hwtimerval_t *t; + rt_err_t err; + + if (size == sizeof(rt_hwtimerval_t)) + { + t = (rt_hwtimerval_t*)buffer; + err = timeout_set((rt_hwtimer_t*)dev, t); + if (err == RT_EOK) + { + len = size; + } + } + + return len; +} + +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_START: + { + if (timer->ops->start != RT_NULL) + { + rt_hwtimer_mode_t opm; + + if ((timer->cycles <= 1) && (timer->mode == HWTIMER_MODE_ONESHOT)) + { + opm = HWTIMER_MODE_ONESHOT; + } + else + { + opm = HWTIMER_MODE_PERIOD; + } + + timer->overflow = 0; + + timer->ops->start(timer, opm); + } + else + { + result = -RT_ENOSYS; + } + } + break; + case HWTIMER_CTRL_STOP: + { + if (timer->ops->stop != RT_NULL) + { + timer->ops->stop(timer); + } + else + { + result = -RT_ENOSYS; + } + } + break; + case HWTIMER_CTRL_TIMEOUT_SET: + { + if (args == RT_NULL) + { + result = -RT_EEMPTY; + break; + } + + result = timeout_set(timer, (rt_hwtimerval_t*)args); + } + 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_HwTimer; + 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..e5b5d4661b --- /dev/null +++ b/components/drivers/include/drivers/hwtimer.h @@ -0,0 +1,83 @@ +#ifndef __HWTIMER_H__ +#define __HWTIMER_H__ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* ¶¨Ê±Æ÷¿ØÖÆÃüÁî */ +typedef enum +{ + HWTIMER_CTRL_TIMEOUT_SET = 0x01, /* ÉèÖó¬Ê±Öµ */ + HWTIMER_CTRL_FREQ_SET, /* ÉèÖüÆÊýƵÂÊ */ + HWTIMER_CTRL_START, /* Æô¶¯¶¨Ê±Æ÷ */ + HWTIMER_CTRL_STOP, /* Í£Ö¹¶¨Ê±Æ÷ */ + HWTIMER_CTRL_INFO_GET, /* »ñÈ¡¶¨Ê±Æ÷ÌØÕ÷ÐÅÏ¢ */ + HWTIMER_CTRL_MODE_SET /* ÉèÖö¨Ê±Ä£Ê½ */ +} rt_hwtimer_ctrl_t; + +/* ¶¨Ê±Ä£Ê½ */ +typedef enum +{ + HWTIMER_MODE_ONESHOT = 0x01, + HWTIMER_MODE_PERIOD +} rt_hwtimer_mode_t; + +/* ¶¨Ê±Æ÷¼ÆÊýÖµ */ +typedef struct rt_hwtimerval +{ + rt_int32_t sec; /* Ãë */ + rt_int32_t usec; /* ΢Ãë */ +} rt_hwtimerval_t; + +#define HWTIMER_CNTMODE_UP 0x01 /* ¶¨Ê±Æ÷µÝÔö¼ÆÊý·½Ê½ */ +#define HWTIMER_CNTMODE_DW 0x02 /* ¶¨Ê±Æ÷µÝ¼õ¼ÆÊý·½Ê½ */ + +struct rt_hwtimer_device; + +struct rt_hwtimer_ops +{ + void (*init)(struct rt_hwtimer_device *timer); + void (*deinit)(struct rt_hwtimer_device *timer); + void (*start)(struct rt_hwtimer_device *timer, rt_hwtimer_mode_t mode); + void (*stop)(struct rt_hwtimer_device *timer); + rt_err_t (*timeout_set)(struct rt_hwtimer_device *timer, rt_uint32_t t); + 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); +}; + +/* ¶¨Ê±Æ÷»ù±¾²ÎÊý(²»¿É¶¯Ì¬¸ü¸Ä) */ +struct rt_hwtimer_info +{ + rt_int32_t maxfreq; /* ¶¨Ê±Æ÷Ö§³ÖµÄ×î´ó¼ÆÊýʱÖÓ */ + rt_int32_t minfreq; /* ¶¨Ê±Æ÷Ö§³ÖµÄ×îС¼ÆÊýʱÖÓ */ + rt_uint32_t maxcnt; /* ¼ÆÊýÆ÷×î´ó³¬Ê±Öµ */ + rt_uint8_t cntmode; /* ¼ÆÊýģʽ(µÝÔö/µÝ¼õ,Ó¦ÓòãÎÞÐè¹ØÐĴ˲ÎÊý) */ +}; + +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; /* ¼ÆÊýƵÂÊ */ + rt_int32_t overflow; /* Òç³ö´ÎÊý */ + float period_sec; /* Òç³öÖÜÆÚ(s) */ + rt_int32_t cycles; /* Ñ­»·´ÎÊý */ + rt_int32_t reload; /* ÖØÔØcycles */ + rt_hwtimer_mode_t mode; /* ¶¨Ê±Ä£Ê½ */ +} 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..6e2ca631e3 100644 --- a/components/finsh/cmd.c +++ b/components/finsh/cmd.c @@ -468,6 +468,7 @@ static long _list_device(struct rt_list_node *list) "Pipe", "Portal Device", "Miscellaneous Device", + "Hardware Timer Device", "Unknown" }; -- cgit v1.3.1