From 8525e087093846d928ba8c5c5df86a77006f1010 Mon Sep 17 00:00:00 2001 From: Chen Wang Date: Wed, 28 May 2025 15:56:09 +0800 Subject: [PATCH] bsp: k230: add hwtimer support K230 support 6 general hardware timers and 3 stc timers. This patch only implement drivers for general hw timers. Signed-off-by: Chen Wang --- bsp/k230/.config | 1 + bsp/k230/board/Kconfig | 31 ++ bsp/k230/drivers/interdrv/hwtimer/SConscript | 19 + bsp/k230/drivers/interdrv/hwtimer/drv_timer.c | 333 ++++++++++++++++++ bsp/k230/drivers/interdrv/hwtimer/drv_timer.h | 96 +++++ bsp/k230/drivers/utest/SConscript | 3 + bsp/k230/drivers/utest/test_timer.c | 153 ++++++++ 7 files changed, 636 insertions(+) create mode 100644 bsp/k230/drivers/interdrv/hwtimer/SConscript create mode 100644 bsp/k230/drivers/interdrv/hwtimer/drv_timer.c create mode 100644 bsp/k230/drivers/interdrv/hwtimer/drv_timer.h create mode 100644 bsp/k230/drivers/utest/test_timer.c diff --git a/bsp/k230/.config b/bsp/k230/.config index b019e93de7..427b666995 100644 --- a/bsp/k230/.config +++ b/bsp/k230/.config @@ -1497,6 +1497,7 @@ CONFIG_BSP_USING_SDIO0=y # CONFIG_BSP_SDIO0_1V8 is not set # CONFIG_BSP_USING_SDIO1 is not set CONFIG_BSP_SD_MNT_DEVNAME="sd0p1" +# CONFIG_BSP_USING_TIMERS is not set # CONFIG_BSP_USING_WDT is not set # CONFIG_BSP_UTEST_DRIVERS is not set # end of Drivers Configuration diff --git a/bsp/k230/board/Kconfig b/bsp/k230/board/Kconfig index c91fed4f61..63fd86b1b0 100644 --- a/bsp/k230/board/Kconfig +++ b/bsp/k230/board/Kconfig @@ -39,6 +39,37 @@ menu "Drivers Configuration" default "sd0p1" endif + menuconfig BSP_USING_TIMERS + bool "Enable Hardware Timers" + select RT_USING_HWTIMER + default n + + if BSP_USING_TIMERS + config BSP_USING_TIMER0 + bool "Enable Timer0" + default n + + config BSP_USING_TIMER1 + bool "Enable Timer1" + default n + + config BSP_USING_TIMER2 + bool "Enable Timer2" + default n + + config BSP_USING_TIMER3 + bool "Enable Timer3" + default n + + config BSP_USING_TIMER4 + bool "Enable Timer4" + default n + + config BSP_USING_TIMER5 + bool "Enable Timer5" + default n + endif + menuconfig BSP_USING_WDT bool "Enable Watchdog Timer" select RT_USING_WDT diff --git a/bsp/k230/drivers/interdrv/hwtimer/SConscript b/bsp/k230/drivers/interdrv/hwtimer/SConscript new file mode 100644 index 0000000000..5a96dfa5b8 --- /dev/null +++ b/bsp/k230/drivers/interdrv/hwtimer/SConscript @@ -0,0 +1,19 @@ +# RT-Thread building script for component + +from building import * + +cwd = GetCurrentDir() +src = Glob('*.c') +CPPPATH = [cwd] + +group = DefineGroup('TIMER', src, depend = ['BSP_USING_TIMERS'], CPPPATH = CPPPATH) + +objs = [group] + +list = os.listdir(cwd) + +for item in list: + if os.path.isfile(os.path.join(cwd, item, 'SConscript')): + objs = objs + SConscript(os.path.join(item, 'SConscript')) + +Return('objs') diff --git a/bsp/k230/drivers/interdrv/hwtimer/drv_timer.c b/bsp/k230/drivers/interdrv/hwtimer/drv_timer.c new file mode 100644 index 0000000000..4ec803739c --- /dev/null +++ b/bsp/k230/drivers/interdrv/hwtimer/drv_timer.c @@ -0,0 +1,333 @@ +/* Copyright (c) 2023, Canaan Bright Sight Co., Ltd + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * Copyright (c) 2006-2025, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/* + * K230 Hardware Timer Driver + * + * K230 provides 9 timers, 6 general-purpose timers (TIMER0-TIMER5) and + * 3 STC timers. + * This driver only implements the general-purpose timers (TIMER0-TIMER5). + * This driver only supports the ONESHOT mode. + * Support frequency options: 12.5M(min), 25M, 50M, 100M(max) + */ + +#include +#include +#include "riscv_io.h" +#include "board.h" +#include "ioremap.h" +#include +#include +#include +#include +#include "sysctl_rst.h" +#include "drv_timer.h" +#include + +static void k230_timer_stop(rt_hwtimer_t *timer); +static void k230_timer_init(rt_hwtimer_t *timer, rt_uint32_t state) +{ + struct k230_timer *kd_timer = rt_container_of(timer, struct k230_timer, device); + + uint8_t id = kd_timer->id; + if (state == 0) + { + k230_timer_stop(timer); + } + else + { + sysctl_clk_set_leaf_parent(kd_timer->clk, kd_timer->clk_src); + if (timer->freq == timer->info->minfreq) + sysctl_clk_set_leaf_div(kd_timer->clk_src, 1, 8); + if (timer->freq == timer->info->maxfreq) + sysctl_clk_set_leaf_div(kd_timer->clk_src, 1, 1); + if (timer->freq == 50*MHz) + sysctl_clk_set_leaf_div(kd_timer->clk_src, 1, 2); + if (timer->freq == 25*MHz) + sysctl_clk_set_leaf_div(kd_timer->clk_src, 1, 4); + } +} + +static rt_err_t k230_timer_start(rt_hwtimer_t *timer, rt_uint32_t cnt, rt_hwtimer_mode_t mode) +{ + struct k230_timer *kd_timer = rt_container_of(timer, struct k230_timer, device); + uint8_t id = kd_timer->id; + k230_timer_regs_t* reg = (k230_timer_regs_t *)kd_timer->base; + reg->channel[id].load_count = cnt; + reg->channel[id].control &= ~(TIMER_CR_INTERRUPT_MASK); + reg->channel[id].control |= (TIMER_CR_USER_MODE | TIMER_CR_ENABLE); + return RT_EOK; +} + +static void k230_timer_stop(rt_hwtimer_t *timer) +{ + struct k230_timer *kd_timer = rt_container_of(timer, struct k230_timer, device); + uint8_t id = kd_timer->id; + k230_timer_regs_t* reg = (k230_timer_regs_t *)kd_timer->base; + reg->channel[id].control &= ~TIMER_CR_ENABLE; + reg->channel[id].control |= TIMER_CR_INTERRUPT_MASK; +} + +static rt_uint32_t k230_timer_get(rt_hwtimer_t *timer) +{ + struct k230_timer *kd_timer = rt_container_of(timer, struct k230_timer, device); + uint8_t id = kd_timer->id; + k230_timer_regs_t* reg = (k230_timer_regs_t *)kd_timer->base; + return reg->channel[id].current_value; +} + +static rt_err_t k230_timer_ctrl(rt_hwtimer_t *timer, rt_uint32_t cmd, void *arg) +{ + struct k230_timer *kd_timer = rt_container_of(timer, struct k230_timer, device); + + switch (cmd) + { + case HWTIMER_CTRL_FREQ_SET: + timer->freq = *((rt_uint32_t*)arg); + sysctl_clk_set_leaf_parent(kd_timer->clk, kd_timer->clk_src); + if (timer->freq == timer->info->minfreq) + sysctl_clk_set_leaf_div(kd_timer->clk_src, 1, 8); + if (timer->freq == timer->info->maxfreq) + sysctl_clk_set_leaf_div(kd_timer->clk_src, 1, 1); + if (timer->freq == 50*MHz) + sysctl_clk_set_leaf_div(kd_timer->clk_src, 1, 2); + if (timer->freq == 25*MHz) + sysctl_clk_set_leaf_div(kd_timer->clk_src, 1, 4); + break; + case HWTIMER_CTRL_STOP: + k230_timer_stop(timer); + break; + case HWTIMER_CTRL_INFO_GET: + if (arg == RT_NULL) + { + LOG_E("HWTIMER_CTRL_INFO_GET arg is NULL"); + return -RT_ERROR; + } + *(struct rt_hwtimer_info *)arg = *(kd_timer->device.info); + break; + case HWTIMER_CTRL_MODE_SET: + if (arg == RT_NULL) + { + LOG_E("HWTIMER_CTRL_MODE_SET arg is NULL"); + return -RT_ERROR; + } + timer->mode = *(rt_hwtimer_mode_t *)arg; + if (timer->mode != HWTIMER_MODE_ONESHOT) + { + LOG_E("mode is invalid/unsupported, only ONESHOT is supported"); + return -RT_ERROR; + } + break; + default: + LOG_E("HWTIMER_CTRL cmd is invalid"); + return -RT_ERROR; + } + return RT_EOK; +} + +static int k230_timer_fops_open(struct dfs_file* fd) +{ + rt_device_t device = (rt_device_t)fd->vnode->data; + return rt_device_open(device, RT_DEVICE_OFLAG_RDWR); +} + +static int k230_timer_fops_close(struct dfs_file* fd) +{ + rt_device_t device = (rt_device_t)fd->vnode->data; + return rt_device_close(device); +} + +static const struct rt_hwtimer_info k230_timer_info = +{ + 100000000, /* the maximum count frequency can be set */ + 12500000, /* the minimum count frequency can be set */ + 0xFFFFFFFF, /* the maximum counter value */ + HWTIMER_CNTMODE_DW, /* Increment or Decreasing count mode */ +}; + +static const struct rt_hwtimer_ops k230_timer_ops = +{ + .init = k230_timer_init, + .start = k230_timer_start, + .stop = k230_timer_stop, + .count_get = k230_timer_get, + .control = k230_timer_ctrl, +}; + +static const struct dfs_file_ops k230_timer_fops = { + k230_timer_fops_open, + k230_timer_fops_close, +}; + +void k230_hwtimer_isr(int vector, void *param) +{ + uint32_t ret; + struct k230_timer *kd_timer = (struct k230_timer *)param; + rt_hwtimer_t *hwtimer = (rt_hwtimer_t *)&(kd_timer->device); + + RT_ASSERT(kd_timer != RT_NULL && hwtimer != RT_NULL); + + int id = kd_timer->id; + k230_timer_regs_t* reg = (k230_timer_regs_t *)kd_timer->base; + + ret = (reg->channel[id].eoi); + + rt_device_hwtimer_isr(hwtimer); +} + +static struct k230_timer timer_devices[] = +{ +#ifdef BSP_USING_TIMER0 + { + .device.info = &k230_timer_info, + .device.ops = &k230_timer_ops, + .device.parent.fops = &k230_timer_fops, + + .name = "hwtimer0", + .id = 0, + .clk = SYSCTL_CLK_TIMER0, + .clk_src = SYSCTL_CLK_TIMER0_SRC, + .irq_num = IRQN_TIMER_0_INTERRUPT + }, +#endif /* BSP_USING_TIMER0 */ + +#ifdef BSP_USING_TIMER1 + { + .device.info = &k230_timer_info, + .device.ops = &k230_timer_ops, + .device.parent.fops = &k230_timer_fops, + + .name = "hwtimer1", + .id = 1, + .clk = SYSCTL_CLK_TIMER1, + .clk_src = SYSCTL_CLK_TIMER1_SRC, + .irq_num = IRQN_TIMER_1_INTERRUPT + }, +#endif /* BSP_USING_TIMER1 */ + +#ifdef BSP_USING_TIMER2 + { + .device.info = &k230_timer_info, + .device.ops = &k230_timer_ops, + .device.parent.fops = &k230_timer_fops, + + .name = "hwtimer2", + .id = 2, + .clk = SYSCTL_CLK_TIMER2, + .clk_src = SYSCTL_CLK_TIMER2_SRC, + .irq_num = IRQN_TIMER_2_INTERRUPT + }, +#endif /* BSP_USING_TIMER0 */ + +#ifdef BSP_USING_TIMER3 + { + .device.info = &k230_timer_info, + .device.ops = &k230_timer_ops, + .device.parent.fops = &k230_timer_fops, + + .name = "hwtimer3", + .id = 3, + .clk = SYSCTL_CLK_TIMER3, + .clk_src = SYSCTL_CLK_TIMER3_SRC, + .irq_num = IRQN_TIMER_3_INTERRUPT + }, +#endif /* BSP_USING_TIMER3 */ + +#ifdef BSP_USING_TIMER4 + { + .device.info = &k230_timer_info, + .device.ops = &k230_timer_ops, + .device.parent.fops = &k230_timer_fops, + + .name = "hwtimer4", + .id = 4, + .clk = SYSCTL_CLK_TIMER4, + .clk_src = SYSCTL_CLK_TIMER4_SRC, + .irq_num = IRQN_TIMER_4_INTERRUPT + }, +#endif /* BSP_USING_TIMER4 */ + +#ifdef BSP_USING_TIMER5 + { + .device.info = &k230_timer_info, + .device.ops = &k230_timer_ops, + .device.parent.fops = &k230_timer_fops, + + .name = "hwtimer5", + .id = 5, + .clk = SYSCTL_CLK_TIMER5, + .clk_src = SYSCTL_CLK_TIMER5_SRC, + .irq_num = IRQN_TIMER_5_INTERRUPT + }, +#endif /* BSP_USING_TIMER5 */ + +#if !defined(BSP_USING_TIMER0) && \ + !defined(BSP_USING_TIMER1) && \ + !defined(BSP_USING_TIMER2) && \ + !defined(BSP_USING_TIMER3) && \ + !defined(BSP_USING_TIMER4) && \ + !defined(BSP_USING_TIMER5) +#error "No hardware timer device enabled!" +#endif +}; + +int rt_hw_timer_init(void) +{ + rt_uint8_t i, array_size; + + array_size = sizeof(timer_devices) / sizeof(struct k230_timer); + if (array_size == 0) + { + LOG_E("No timer device defined!"); + return -RT_ERROR; + } + + volatile void* base = (void *)rt_ioremap((void *)HW_TIMER_BASE_ADDR, HW_TIMER_IO_SIZE); + for (i = 0; i < array_size; i++) + { + timer_devices[i].base = (rt_ubase_t)base; + + if (rt_device_hwtimer_register(&timer_devices[i].device, timer_devices[i].name, RT_NULL) != RT_EOK) + { + LOG_E("%s register failed!", timer_devices[i].name); + return -RT_ERROR; + } + LOG_D("%s register OK!", timer_devices[i].name); + + rt_hw_interrupt_install(timer_devices[i].irq_num, + k230_hwtimer_isr, + &timer_devices[i], + timer_devices[i].name); + rt_hw_interrupt_umask(timer_devices[i].irq_num); + } + return RT_EOK; +} +INIT_BOARD_EXPORT(rt_hw_timer_init); \ No newline at end of file diff --git a/bsp/k230/drivers/interdrv/hwtimer/drv_timer.h b/bsp/k230/drivers/interdrv/hwtimer/drv_timer.h new file mode 100644 index 0000000000..bce258bb19 --- /dev/null +++ b/bsp/k230/drivers/interdrv/hwtimer/drv_timer.h @@ -0,0 +1,96 @@ +/* Copyright (c) 2023, Canaan Bright Sight Co., Ltd + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * Copyright (c) 2006-2025, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef DRV_TIMER_H__ +#define DRV_TIMER_H__ +#include +#include +#include "sysctl_clk.h" + +#define MHz 1000000 +/* TIMER Control Register */ +#define TIMER_CR_ENABLE 0x00000001 +#define TIMER_CR_MODE_MASK 0x00000002 +#define TIMER_CR_FREE_MODE 0x00000000 +#define TIMER_CR_USER_MODE 0x00000002 +#define TIMER_CR_INTERRUPT_MASK 0x00000004 +#define TIMER_CR_PWM_ENABLE 0x00000008 + +#define IRQN_TIMER_0_INTERRUPT 16+85 +#define IRQN_TIMER_1_INTERRUPT 16+86 +#define IRQN_TIMER_2_INTERRUPT 16+87 +#define IRQN_TIMER_3_INTERRUPT 16+88 +#define IRQN_TIMER_4_INTERRUPT 16+89 +#define IRQN_TIMER_5_INTERRUPT 16+90 + +typedef struct _timer_regs_channel +{ + /* TIMER_N Load Count Register (0x00+(N-1)*0x14) */ + volatile uint32_t load_count; + /* TIMER_N Current Value Register (0x04+(N-1)*0x14) */ + volatile uint32_t current_value; + /* TIMER_N Control Register (0x08+(N-1)*0x14) */ + volatile uint32_t control; + /* TIMER_N Interrupt Clear Register (0x0c+(N-1)*0x14) */ + volatile uint32_t eoi; + /* TIMER_N Interrupt Status Register (0x10+(N-1)*0x14) */ + volatile uint32_t intr_stat; +} __attribute__((packed, aligned(4))) k230_timer_regs_channel_t; + +typedef struct _k230_timer_regs +{ + /* TIMER_N Register (0x00-0x4c) */ + volatile k230_timer_regs_channel_t channel[5]; + /* reserverd (0x50-0x9c) */ + volatile uint32_t resv1[20]; + /* TIMER Interrupt Status Register (0xa0) */ + volatile uint32_t intr_stat; + /* TIMER Interrupt Clear Register (0xa4) */ + volatile uint32_t eoi; + /* TIMER Raw Interrupt Status Register (0xa8) */ + volatile uint32_t raw_intr_stat; + /* TIMER Component Version Register (0xac) */ + volatile uint32_t comp_version; + /* TIMER_N Load Count2 Register (0xb0-0xbc) */ + volatile uint32_t load_count2[4]; +} __attribute__((packed, aligned(4))) k230_timer_regs_t; + +struct k230_timer { + struct rt_hwtimer_device device; + const char *name; + rt_ubase_t base; + uint32_t id; + sysctl_clk_node_e clk; + sysctl_clk_node_e clk_src; + int irq_num; +}; + +#endif \ No newline at end of file diff --git a/bsp/k230/drivers/utest/SConscript b/bsp/k230/drivers/utest/SConscript index d8032f3923..b5c8e2ed55 100644 --- a/bsp/k230/drivers/utest/SConscript +++ b/bsp/k230/drivers/utest/SConscript @@ -4,6 +4,9 @@ src = [] if GetDepend('RT_UTEST_USING_ALL_CASES') or GetDepend('BSP_UTEST_DRIVERS'): + if GetDepend('BSP_USING_TIMERS'): + src += ['test_timer.c'] + if GetDepend('BSP_USING_WDT'): src += ['test_wdt.c'] diff --git a/bsp/k230/drivers/utest/test_timer.c b/bsp/k230/drivers/utest/test_timer.c new file mode 100644 index 0000000000..30db354783 --- /dev/null +++ b/bsp/k230/drivers/utest/test_timer.c @@ -0,0 +1,153 @@ +/* Copyright (c) 2023, Canaan Bright Sight Co., Ltd + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + /* + * Copyright (c) 2006-2025, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +#include "../interdrv/hwtimer/drv_timer.h" +#include "utest.h" + +/* + * This test case is designed to test the hardware timer driver. + * It will: + * 1. Find two hardware timer devices. + * 2. Open both devices. + * 3. Set a custom frequency for timer0 and use the default frequency for timer1. + * 4. Start both timers with different timeout values. + * 5. Poll and print the current value of each timer every second. + * 6. Trigger the interrupt callback when the timer times out and print a message. + */ + +#define DEVICE_NAME0 "hwtimer0" +#define DEVICE_NAME1 "hwtimer1" + +static rt_device_t tmr_dev_0; +static rt_device_t tmr_dev_1; + +#define TIMEOUT_SEC_0 10 +#define TIMEOUT_SEC_1 5 +#define MAX_TIMEOUT_SEC \ + (TIMEOUT_SEC_0 > TIMEOUT_SEC_1 ? TIMEOUT_SEC_0 : TIMEOUT_SEC_1) + +static rt_err_t tmr_timeout_cb(rt_device_t dev, rt_size_t size) +{ + struct rt_hwtimer_device *rt_timer = rt_container_of(dev, struct rt_hwtimer_device, parent); + struct k230_timer *kd_timer = rt_container_of(rt_timer, struct k230_timer, device); + + LOG_I("---> [%s] timeout callback fucntion!\n", kd_timer->name); + return RT_EOK; +} + +static void test_hwtimer(void) +{ + rt_hwtimerval_t timerval; + rt_hwtimer_mode_t mode; + rt_size_t tsize; + rt_uint32_t freq = 25000000; /* Frequency options: 12.5M 25M 50M 100M */ + rt_err_t ret; + rt_ssize_t size; + int loop_count = 0; + + LOG_I("test_hwtimer start"); + + tmr_dev_0 = rt_device_find(DEVICE_NAME0); + uassert_not_null(tmr_dev_0); + tmr_dev_1 = rt_device_find(DEVICE_NAME1); + uassert_not_null(tmr_dev_1); + + ret = rt_device_open(tmr_dev_0, RT_DEVICE_OFLAG_RDWR); + uassert_int_equal(ret, RT_EOK); + ret = rt_device_open(tmr_dev_1, RT_DEVICE_OFLAG_RDWR); + uassert_int_equal(ret, RT_EOK); + + ret = rt_device_control(tmr_dev_0, HWTIMER_CTRL_FREQ_SET, &freq); + uassert_int_equal(ret, RT_EOK); + + ret = rt_device_set_rx_indicate(tmr_dev_0, tmr_timeout_cb); + uassert_int_equal(ret, RT_EOK); + ret = rt_device_set_rx_indicate(tmr_dev_1, tmr_timeout_cb); + uassert_int_equal(ret, RT_EOK); + + timerval.sec = TIMEOUT_SEC_0; + timerval.usec = 0; + tsize = sizeof(timerval); + mode = HWTIMER_MODE_ONESHOT; + ret = rt_device_control(tmr_dev_0, HWTIMER_CTRL_MODE_SET, &mode); + uassert_int_equal(ret, RT_EOK); + size = rt_device_write(tmr_dev_0, 0, &timerval, tsize); + uassert_int_equal(size, tsize); + LOG_I("timer0 start: [%d:%d]\n", timerval.sec, timerval.usec); + + timerval.sec = TIMEOUT_SEC_1; + timerval.usec = 0; + tsize = sizeof(timerval); + mode = HWTIMER_MODE_ONESHOT; + ret = rt_device_control(tmr_dev_1, HWTIMER_CTRL_MODE_SET, &mode); + uassert_int_equal(ret, RT_EOK); + size = rt_device_write(tmr_dev_1, 0, &timerval, tsize); + uassert_int_equal(size, tsize); + LOG_I("timer1 start: [%d:%d]\n", timerval.sec, timerval.usec); + + while (loop_count++ < MAX_TIMEOUT_SEC + 1) + { + size = rt_device_read(tmr_dev_0, 0, &timerval, sizeof(timerval)); + uassert_int_equal(size, sizeof(timerval)); + LOG_I("timer0: [%d:%d]\n", timerval.sec, timerval.usec); + + size = rt_device_read(tmr_dev_1, 0, &timerval, sizeof(timerval)); + uassert_int_equal(size, sizeof(timerval)); + LOG_I("timer1: [%d:%d]\n", timerval.sec, timerval.usec); + + rt_thread_mdelay(1000); + } + + ret = rt_device_close(tmr_dev_0); + uassert_int_equal(ret, RT_EOK); + ret = rt_device_close(tmr_dev_1); + uassert_int_equal(ret, RT_EOK); + LOG_I("test_hwtimer end"); +} + +static void hw_timer_testcase(void) +{ + UTEST_UNIT_RUN(test_hwtimer); +} + +static rt_err_t utest_tc_init(void) +{ + return RT_EOK; +} +static rt_err_t utest_tc_cleanup(void) +{ + return RT_EOK; +} + +UTEST_TC_EXPORT(hw_timer_testcase, "timer", utest_tc_init, utest_tc_cleanup, 10); \ No newline at end of file