diff --git a/bsp/k230/.config b/bsp/k230/.config index 48d24617eec..2031a0ba16a 100644 --- a/bsp/k230/.config +++ b/bsp/k230/.config @@ -602,6 +602,7 @@ CONFIG_RT_USING_VDSO=y # CONFIG_PKG_USING_FREEMODBUS is not set # CONFIG_PKG_USING_NANOPB is not set # CONFIG_PKG_USING_WIFI_HOST_DRIVER is not set +# CONFIG_PKG_USING_ESP_HOSTED is not set # # Wi-Fi @@ -709,6 +710,7 @@ CONFIG_RT_USING_VDSO=y # CONFIG_PKG_USING_QMODBUS is not set # CONFIG_PKG_USING_PNET is not set # CONFIG_PKG_USING_OPENER is not set +# CONFIG_PKG_USING_FREEMQTT is not set # end of IoT - internet of things # @@ -798,6 +800,7 @@ CONFIG_RT_USING_VDSO=y # tools packages # # CONFIG_PKG_USING_CMBACKTRACE is not set +# CONFIG_PKG_USING_MCOREDUMP is not set # CONFIG_PKG_USING_EASYFLASH is not set # CONFIG_PKG_USING_EASYLOGGER is not set # CONFIG_PKG_USING_SYSTEMVIEW is not set @@ -843,6 +846,7 @@ CONFIG_RT_USING_VDSO=y # CONFIG_PKG_USING_ZDEBUG is not set # CONFIG_PKG_USING_RVBACKTRACE is not set # CONFIG_PKG_USING_HPATCHLITE is not set +# CONFIG_PKG_USING_THREAD_METRIC is not set # end of tools packages # @@ -936,6 +940,7 @@ CONFIG_RT_USING_VDSO=y # CONFIG_PKG_USING_RMP is not set # CONFIG_PKG_USING_R_RHEALSTONE is not set # CONFIG_PKG_USING_HEARTBEAT is not set +# CONFIG_PKG_USING_MICRO_ROS_RTTHREAD_PACKAGE is not set # end of system packages # @@ -1018,6 +1023,7 @@ CONFIG_RT_USING_VDSO=y # CONFIG_PKG_USING_NRF5X_SDK is not set # CONFIG_PKG_USING_NRFX is not set # CONFIG_PKG_USING_NUCLEI_SDK is not set +# CONFIG_PKG_USING_RASPBERRYPI_PICO_RP2350_SDK is not set # CONFIG_PKG_USING_RASPBERRYPI_PICO_SDK is not set # CONFIG_PKG_USING_MM32 is not set @@ -1060,6 +1066,10 @@ CONFIG_RT_USING_VDSO=y # # HC32 DDL Drivers # +# CONFIG_PKG_USING_HC32F3_CMSIS_DRIVER is not set +# CONFIG_PKG_USING_HC32F3_SERIES_DRIVER is not set +# CONFIG_PKG_USING_HC32F4_CMSIS_DRIVER is not set +# CONFIG_PKG_USING_HC32F4_SERIES_DRIVER is not set # end of HC32 DDL Drivers # @@ -1073,6 +1083,21 @@ CONFIG_RT_USING_VDSO=y # CONFIG_PKG_USING_NXP_IMX6UL_DRIVER is not set # CONFIG_PKG_USING_NXP_IMXRT_DRIVER is not set # end of NXP HAL & SDK Drivers + +# +# NUVOTON Drivers +# +# CONFIG_PKG_USING_NUVOTON_CMSIS_DRIVER is not set +# CONFIG_PKG_USING_NUVOTON_SERIES_DRIVER is not set +# CONFIG_PKG_USING_NUVOTON_ARM926_LIB is not set +# end of NUVOTON Drivers + +# +# GD32 Drivers +# +# CONFIG_PKG_USING_GD32_ARM_CMSIS_DRIVER is not set +# CONFIG_PKG_USING_GD32_ARM_SERIES_DRIVER is not set +# end of GD32 Drivers # end of HAL & SDK Drivers # @@ -1148,6 +1173,7 @@ CONFIG_RT_USING_VDSO=y # CONFIG_PKG_USING_STHS34PF80 is not set # CONFIG_PKG_USING_P3T1755 is not set # CONFIG_PKG_USING_QMI8658 is not set +# CONFIG_PKG_USING_ICM20948 is not set # end of sensors drivers # @@ -1242,6 +1268,8 @@ CONFIG_RT_USING_VDSO=y # CONFIG_PKG_USING_SERVO is not set # CONFIG_PKG_USING_SEAN_WS2812B is not set # CONFIG_PKG_USING_IC74HC165 is not set +# CONFIG_PKG_USING_IST8310 is not set +# CONFIG_PKG_USING_ST7789_SPI is not set # CONFIG_PKG_USING_SPI_TOOLS is not set # end of peripheral libraries and drivers @@ -1589,6 +1617,7 @@ CONFIG_PKG_ZLIB_VER="latest" # # Drivers Configuration # +# CONFIG_BSP_USING_RTC is not set # CONFIG_BSP_USING_ADC is not set # CONFIG_BSP_USING_TS is not set CONFIG_BSP_USING_UART=y diff --git a/bsp/k230/board/Kconfig b/bsp/k230/board/Kconfig index 4c88e5df886..3604e5ad81e 100644 --- a/bsp/k230/board/Kconfig +++ b/bsp/k230/board/Kconfig @@ -1,10 +1,15 @@ menu "Drivers Configuration" + config BSP_USING_RTC + bool "Enable RTC" + select RT_USING_RTC + default n + config BSP_USING_ADC bool "Enable ADC" select RT_USING_ADC default n - + config BSP_USING_TS bool "Enable Temperature Sensor" select RT_USING_TS @@ -27,15 +32,15 @@ menu "Drivers Configuration" config BSP_USING_UART1 bool "Enable UART1" default n - + config BSP_USING_UART2 bool "Enable UART2" default n - + config BSP_USING_UART3 bool "Enable UART3" default n - + config BSP_USING_UART4 bool "Enable UART4" default n @@ -146,37 +151,37 @@ menu "Drivers Configuration" menuconfig BSP_USING_PDMA bool "Enable PDMA" select RT_USING_PDMA - default n - + default n + if BSP_USING_PDMA config BSP_USING_PDMA_CHANNEL0 bool "Enable PDMA Channel 0" default n - + config BSP_USING_PDMA_CHANNEL1 bool "Enable PDMA Channel 1" default n - + config BSP_USING_PDMA_CHANNEL2 bool "Enable PDMA Channel 2" default n - + config BSP_USING_PDMA_CHANNEL3 bool "Enable PDMA Channel 3" default n - + config BSP_USING_PDMA_CHANNEL4 bool "Enable PDMA Channel 4" default n - + config BSP_USING_PDMA_CHANNEL5 bool "Enable PDMA Channel 5" default n - + config BSP_USING_PDMA_CHANNEL6 bool "Enable PDMA Channel 6" default n - + config BSP_USING_PDMA_CHANNEL7 bool "Enable PDMA Channel 7" default n diff --git a/bsp/k230/drivers/interdrv/rtc/SConscript b/bsp/k230/drivers/interdrv/rtc/SConscript new file mode 100644 index 00000000000..035ecc94adc --- /dev/null +++ b/bsp/k230/drivers/interdrv/rtc/SConscript @@ -0,0 +1,11 @@ +# RT-Thread building script for RTC component + +from building import * + +cwd = GetCurrentDir() +src = Glob('*.c') +CPPPATH = [cwd] + +group = DefineGroup('RTC', src, depend = ['BSP_USING_RTC'], CPPPATH = CPPPATH) + +Return('group') diff --git a/bsp/k230/drivers/interdrv/rtc/drv_rtc.c b/bsp/k230/drivers/interdrv/rtc/drv_rtc.c new file mode 100644 index 00000000000..b4820dc79a1 --- /dev/null +++ b/bsp/k230/drivers/interdrv/rtc/drv_rtc.c @@ -0,0 +1,486 @@ +/* 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 +#include +#include +#include +#include "board.h" +#include "drv_rtc.h" + +#undef DBG_TAG +#undef DBG_LVL +#define DBG_TAG "drv_rtc" +#define DBG_LVL DBG_INFO +#include + +struct k230_rtc_dev +{ + struct rt_device device; + const char *name; + rt_ubase_t base; + size_t size; + int vector; + void (*vector_callback)(void); +}; + +static void pmu_isolation_rtc(void) +{ + /* map pwr base address */ + volatile void *reg_pmu_pwr = rt_ioremap((void *)PWR_BASE_ADDR, PWR_IO_SIZE); + uint32_t *addr = (uint32_t *)(reg_pmu_pwr + 0x158); /* pmu power control register */ + uint32_t data; + + /* disable pmu isolation */ + data = *addr; + data &= ~0x20; + *addr = data; + rt_iounmap(reg_pmu_pwr); + + /* map pmu base address */ + volatile void *reg_pmu = rt_ioremap((void*)PMU_BASE_ADDR, PMU_IO_SIZE); + addr = (uint32_t*)(reg_pmu + 0x48); /* pmu int0 to cpu register */ + /* enable int6 int7 */ + data = *addr; + data |= 0x06; + *addr = data; + + addr = (uint32_t*)(reg_pmu + 0x4c); /* pmu int detect en register */ + /* enable int6 rtc alarm detection and int7 rtc tick detection */ + data = *addr; + data |= 0x06; + *addr = data; + rt_iounmap(reg_pmu); +} + +static int rtc_year_is_leap(int year) +{ + return (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0); +} + +static void rtc_timer_set_clock_count_value(struct k230_rtc_dev *dev, uint16_t count) +{ + volatile volatile rtc_t *rtc = (rtc_t *)dev->base; + + rtc->count.curr_count = count; + rtc->count.sum_count = 0x7FFF; + rtc->int_ctrl.timer_w_en = 1; + rt_thread_mdelay(1); + rtc->int_ctrl.timer_w_en = 0; + rtc->int_ctrl.timer_r_en = 1; +} + +static void rtc_interrupt_ctrl_set(struct k230_rtc_dev *dev, rtc_interrupt_mode_t mode) +{ + volatile rtc_t *rtc = (rtc_t *)dev->base; + + if (mode < RTC_INT_TICK_YEAR) + { + rtc->int_ctrl.year_cmp = 0; + rtc->int_ctrl.month_cmp = 0; + rtc->int_ctrl.day_cmp = 0; + rtc->int_ctrl.week_cmp = 0; + rtc->int_ctrl.hour_cmp = 0; + rtc->int_ctrl.minute_cmp = 0; + rtc->int_ctrl.second_cmp = 0; + + if (mode & RTC_INT_ALARM_YEAR) + { + rtc->int_ctrl.year_cmp = 1; + } + if (mode & RTC_INT_ALARM_MONTH) + { + rtc->int_ctrl.month_cmp = 1; + } + if (mode & RTC_INT_ALARM_DAY) + { + rtc->int_ctrl.day_cmp = 1; + } + if (mode & RTC_INT_ALARM_WEEK) + { + rtc->int_ctrl.week_cmp = 1; + } + if (mode & RTC_INT_ALARM_HOUR) + { + rtc->int_ctrl.hour_cmp = 1; + } + if (mode & RTC_INT_ALARM_MINUTE) + { + rtc->int_ctrl.minute_cmp = 1; + } + if (mode & RTC_INT_ALARM_SECOND) + { + rtc->int_ctrl.second_cmp = 1; + } + rtc->int_ctrl.alarm_en = 1; + } + else + { + switch(mode) + { + case RTC_INT_TICK_YEAR: + rtc->int_ctrl.tick_sel = 0x8; + rtc->int_ctrl.tick_en = 1; + break; + case RTC_INT_TICK_MONTH: + rtc->int_ctrl.tick_sel = 0x7; + rtc->int_ctrl.tick_en = 1; + break; + case RTC_INT_TICK_DAY: + rtc->int_ctrl.tick_sel = 0x6; + rtc->int_ctrl.tick_en = 1; + break; + case RTC_INT_TICK_WEEK: + rtc->int_ctrl.tick_sel = 0x5; + rtc->int_ctrl.tick_en = 1; + break; + case RTC_INT_TICK_HOUR: + rtc->int_ctrl.tick_sel = 0x4; + rtc->int_ctrl.tick_en = 1; + break; + case RTC_INT_TICK_MINUTE: + rtc->int_ctrl.tick_sel = 0x3; + rtc->int_ctrl.tick_en = 1; + break; + case RTC_INT_TICK_SECOND: + rtc->int_ctrl.tick_sel = 0x2; + rtc->int_ctrl.tick_en = 1; + break; + case RTC_INT_TICK_S8: + rtc->int_ctrl.tick_sel = 0x1; + rtc->int_ctrl.tick_en = 1; + break; + case RTC_INT_TICK_S64: + rtc->int_ctrl.tick_sel = 0x0; + rtc->int_ctrl.tick_en = 1; + break; + default : + break; + } + } +} + +static void rtc_stop_interrupt(struct k230_rtc_dev *dev) +{ + rt_hw_interrupt_mask(dev->vector); +} + +static void rtc_alarm_stop(struct k230_rtc_dev *dev) +{ + volatile rtc_t *rtc = (rtc_t *)dev->base; + rtc->int_ctrl.alarm_en = 0; + rtc_stop_interrupt(dev); +} + +static void rtc_tick_stop(struct k230_rtc_dev *dev) +{ + volatile rtc_t *rtc = (rtc_t *)dev->base; + rtc->int_ctrl.tick_en = 0; + rtc_stop_interrupt(dev); +} + +static void rtc_alarm_clear_interrupt(struct k230_rtc_dev *dev) +{ + volatile rtc_t *rtc = (rtc_t *)dev->base; + + rtc->int_ctrl.alarm_clr = 1; +} + +static void rtc_irq(int vector, void *param) +{ + struct k230_rtc_dev *dev = (struct k230_rtc_dev *)param; + + rtc_alarm_clear_interrupt(dev); + if (dev->vector_callback != RT_NULL) + { + dev->vector_callback(); + } +} + +static void rtc_date_time_set(struct k230_rtc_dev *dev, int year, int month, int day, \ + int hour, int minute, int second, int week) +{ + rtc_date_t date; + rtc_time_t time; + rtc_count_t count; + volatile rtc_t *rtc = (rtc_t *)dev->base; + + int val = year % 100; + int year_l, year_h; + if(val == 0) + { + year_l = 100; + year_h = year / 100 - 1; + } + else + { + year_l = val; + year_h = (year - val) / 100; + } + + rtc->int_ctrl.timer_w_en = 1; + + date.year_h = year_h; + date.year_l = year_l; + date.month = month; + date.day = day; + date.leap_year = rtc_year_is_leap(year); + time.week = week; + time.hour = hour; + time.minute = minute; + time.second = second; + + rtc->date = date; + rtc->time = time; +} + +static void rtc_timer_get(struct k230_rtc_dev *dev, time_t *t) +{ + volatile rtc_t *rtc = (rtc_t *)dev->base; + struct tm tm; + + if (rtc->int_ctrl.timer_r_en == 0) + { + rtc->int_ctrl.timer_r_en = 1; + } + + tm.tm_sec = rtc->time.second; + tm.tm_min = rtc->time.minute; + tm.tm_hour = rtc->time.hour; + tm.tm_mday = rtc->date.day; + tm.tm_mon = rtc->date.month - 1; + tm.tm_year = (rtc->date.year_h * 100 + rtc->date.year_l) - 1900; + tm.tm_wday = rtc->time.week; + + *t = timegm(&tm); +} + +static void rtc_timer_set(struct k230_rtc_dev *dev, time_t *t) +{ + struct tm p_tm; + gmtime_r(t, &p_tm); + + rtc_date_time_set(dev, (p_tm.tm_year + 1900), p_tm.tm_mon + 1, p_tm.tm_mday, \ + p_tm.tm_hour, p_tm.tm_min, p_tm.tm_sec, p_tm.tm_wday); + + rtc_timer_set_clock_count_value(dev, 0); +} + +static void rtc_alarm_get(struct k230_rtc_dev *dev, void *args) +{ + struct tm *tm = (struct tm*)args; + volatile rtc_t *rtc = (rtc_t *)dev->base; + rtc_alarm_date_t alarm_date = rtc->alarm_date; + rtc_alarm_time_t alarm_time = rtc->alarm_time; + + tm->tm_year = (alarm_date.alarm_year_h * 100 + alarm_date.alarm_year_l) -1900; + tm->tm_mon = alarm_date.alarm_month - 1; + tm->tm_mday = alarm_date.alarm_day; + tm->tm_hour = alarm_time.alarm_hour; + tm->tm_min = alarm_time.alarm_minute; + tm->tm_sec = alarm_time.alarm_second; +} + +static void rtc_alarm_set(struct k230_rtc_dev *dev, void *args) +{ + rtc_alarm_setup_t *setup = (rtc_alarm_setup_t *)args; + struct tm tm = setup->tm; + time_t t; + struct tm p_tm; + volatile rtc_t *rtc = (rtc_t *)dev->base; + rtc_alarm_time_t alarm_time; + rtc_alarm_date_t alarm_date; + rtc_date_t date = rtc->date; + int year, year_l, year_h, val; + + t = mktime(&tm); + gmtime_r(&t, &p_tm); + + year = p_tm.tm_year + 1900; + val = year % 100; + + if(val == 0) + { + year_l = 100; + year_h = year / 100 - 1; + } + else + { + year_l = val; + year_h = (year - val) / 100; + } + + alarm_date.alarm_year_h = year_h; + alarm_date.alarm_year_l = year_l; + alarm_date.alarm_month = p_tm.tm_mon + 1; + alarm_date.alarm_day = p_tm.tm_mday; + alarm_time.alarm_hour = p_tm.tm_hour; + alarm_time.alarm_minute = p_tm.tm_min; + alarm_time.alarm_second = p_tm.tm_sec; + + rtc->alarm_date = alarm_date; + rtc->alarm_time = alarm_time; + + rtc_alarm_clear_interrupt(dev); + rt_hw_interrupt_install(dev->vector, rtc_irq, dev, "rtc"); + rt_hw_interrupt_umask(dev->vector); + rtc_interrupt_ctrl_set(dev, setup->flag); +} + +static rt_err_t rtc_device_init(rt_device_t dev) +{ + struct k230_rtc_dev *rtc_dev = rt_container_of(dev, struct k230_rtc_dev, device); + + rtc_alarm_stop(rtc_dev); + rtc_tick_stop(rtc_dev); + + return RT_EOK; +} + +static rt_err_t rtc_device_open(rt_device_t dev, rt_uint16_t oflag) +{ + return RT_EOK; +} + +static rt_err_t rtc_device_close(rt_device_t dev) +{ + return RT_EOK; +} + +static rt_ssize_t rtc_device_read(rt_device_t dev, rt_off_t pos, void *buffer, rt_size_t size) +{ + time_t t; + struct k230_rtc_dev *rtc_dev = rt_container_of(dev, struct k230_rtc_dev, device); + + rtc_timer_get(rtc_dev, &t); + rt_memcpy(buffer, (void*)&t, sizeof(t)); + return size; +} + +static rt_ssize_t rtc_device_write(rt_device_t dev, rt_off_t pos, const void *buffer, rt_size_t size) +{ + struct tm *tm = (struct tm*)buffer; + time_t t = mktime(tm); + struct k230_rtc_dev *rtc_dev = rt_container_of(dev, struct k230_rtc_dev, device); + + rtc_timer_set(rtc_dev, &t); + return size; +} + +static rt_err_t rtc_device_control(rt_device_t dev, int cmd, void *args) +{ + time_t time; + RT_ASSERT(dev != RT_NULL); + + struct k230_rtc_dev *rtc_dev = rt_container_of(dev, struct k230_rtc_dev, device); + RT_ASSERT(rtc_dev != RT_NULL); + + switch (cmd) + { + case RT_DEVICE_CTRL_RTC_GET_TIME: + rtc_timer_get(rtc_dev, (time_t*)args); + break; + case RT_DEVICE_CTRL_RTC_SET_TIME: + rtc_timer_set(rtc_dev, (time_t *)args); + break; + case RT_DEVICE_CTRL_RTC_GET_ALARM: + rtc_alarm_get(rtc_dev, args); + break; + case RT_DEVICE_CTRL_RTC_SET_ALARM: + rtc_alarm_set(rtc_dev, args); + break; + case RT_DEVICE_CTRL_RTC_STOP_ALARM: + rtc_alarm_stop(rtc_dev); + break; + case RT_DEVICE_CTRL_RTC_STOP_TICK: + rtc_tick_stop(rtc_dev); + break; + case RT_DEVICE_CTRL_RTC_SET_CALLBACK: + rtc_dev->vector_callback = args; + break; + default: + return -RT_EINVAL; + } + return RT_EOK; +} + +const static struct rt_device_ops rtc_ops = +{ + .init = rtc_device_init, + .open = rtc_device_open, + .close = rtc_device_close, + .read = rtc_device_read, + .write = rtc_device_write, + .control = rtc_device_control, +}; + +static struct k230_rtc_dev rtc_dev = +{ + .name = "rtc", + .base = RTC_BASE_ADDR, + .size = RTC_IO_SIZE, + .vector = K230_IRQ_PMU, + .vector_callback = RT_NULL, +}; + +static int rt_hw_rtc_init(void) +{ + rt_err_t ret; + + pmu_isolation_rtc(); + rtc_dev.device.type = RT_Device_Class_RTC; + rtc_dev.device.rx_indicate = RT_NULL; + rtc_dev.device.tx_complete = RT_NULL; +#ifdef RT_USING_DEVICE_OPS + rtc_dev.device.ops = &rtc_ops; +#else + rtc_dev.device.init = rtc_device_init; + rtc_dev.device.open = rtc_device_open; + rtc_dev.device.close = rtc_device_close; + rtc_dev.device.read = rtc_device_read; + rtc_dev.device.write = rtc_device_write; + rtc_dev.device.control = rtc_device_control; +#endif /* RT_USING_DEVICE_OPS */ + rtc_dev.device.user_data = RT_NULL; + rtc_dev.base = (rt_ubase_t)rt_ioremap((void *)rtc_dev.base, rtc_dev.size); + RT_ASSERT(rtc_dev.base != RT_NULL); + + ret = rt_device_register(&rtc_dev.device, "rtc", RT_DEVICE_FLAG_RDWR); + RT_ASSERT(ret == RT_EOK); + LOG_I("rtc driver register OK\n"); + + rtc_alarm_stop(&rtc_dev); + rtc_tick_stop(&rtc_dev); + return ret; +} +INIT_DEVICE_EXPORT(rt_hw_rtc_init); diff --git a/bsp/k230/drivers/interdrv/rtc/drv_rtc.h b/bsp/k230/drivers/interdrv/rtc/drv_rtc.h new file mode 100644 index 00000000000..ce026c4e7b3 --- /dev/null +++ b/bsp/k230/drivers/interdrv/rtc/drv_rtc.h @@ -0,0 +1,161 @@ +/* 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_RTC_H__ +#define __DRV_RTC_H__ +#include +#include + +#define RT_DEVICE_CTRL_RTC_SET_CALLBACK 0x44 +#define RT_DEVICE_CTRL_RTC_STOP_ALARM 0x45 +#define RT_DEVICE_CTRL_RTC_STOP_TICK 0x46 +#define BIT(n) (1 << n) + +/* date register(reset value 0x10101, offset address 0x00) */ +typedef struct _rtc_date +{ + uint32_t day : 5; + uint32_t resv0 : 3; + uint32_t month : 4; + uint32_t resv1 : 4; + uint32_t year_l : 7; + uint32_t leap_year : 1; + uint32_t year_h : 7; + uint32_t resv2 : 1; +} __attribute__((packed, aligned(4))) rtc_date_t; + +/* time register(reset value 0x00, offset address 0x04) */ +typedef struct _rtc_time +{ + uint32_t second : 6; + uint32_t resv0 : 2; + uint32_t minute : 6; + uint32_t resv1 : 2; + uint32_t hour : 5; + uint32_t resv2 : 3; + uint32_t week : 3; + uint32_t resv3 : 5; +} __attribute__((packed, aligned(4))) rtc_time_t; + +/* alarm date register(reset value 0x10101, offset address 0x08) */ +typedef struct _rtc_alarm_date +{ + uint32_t alarm_day : 5; + uint32_t resv0 : 3; + uint32_t alarm_month : 4; + uint32_t resv1 : 4; + uint32_t alarm_year_l : 7; + uint32_t resv2 : 1; + uint32_t alarm_year_h : 7; + uint32_t resv3 : 1; +} __attribute__((packed, aligned(4))) rtc_alarm_date_t; + +/* alarm time register(reset value 0x00, offset address 0x0C) */ +typedef struct _rtc_alarm_time +{ + uint32_t alarm_second : 6; + uint32_t resv0 : 2; + uint32_t alarm_minute : 6; + uint32_t resv1 : 2; + uint32_t alarm_hour : 5; + uint32_t resv2 : 3; + uint32_t alarm_week : 3; + uint32_t resv3 : 5; +} __attribute__((packed, aligned(4))) rtc_alarm_time_t; + +/* count register(reset value 0x7FFF0000, offset address 0x10) */ +typedef struct _rtc_count +{ + uint32_t curr_count : 15; /*!< RTC counter currunt value */ + uint32_t resv0 : 1; + uint32_t sum_count : 15; /*!< RTC counter max value */ + uint32_t resv1 : 1; +} __attribute__((packed, aligned(4))) rtc_count_t; + +/* interrupt control register(reset value 0x00, offset address 0x14) */ +typedef struct _rtc_int_ctrl +{ + uint32_t timer_w_en : 1; + uint32_t timer_r_en : 1; + uint32_t resv0 : 6; + uint32_t tick_en : 1; + uint32_t tick_sel : 4; + uint32_t resv1 : 3; + uint32_t alarm_en : 1; + uint32_t alarm_clr : 1; + uint32_t resv2 : 6; + uint32_t second_cmp : 1; + uint32_t minute_cmp : 1; + uint32_t hour_cmp : 1; + uint32_t week_cmp : 1; + uint32_t day_cmp : 1; + uint32_t month_cmp : 1; + uint32_t year_cmp : 1; + uint32_t resv3 : 1; +} __attribute__((packed, aligned(4))) rtc_int_ctrl_t; + +/* rtc register */ +typedef struct _rtc +{ + rtc_date_t date; + rtc_time_t time; + rtc_alarm_date_t alarm_date; + rtc_alarm_time_t alarm_time; + rtc_count_t count; + rtc_int_ctrl_t int_ctrl; +} __attribute__((packed, aligned(4))) rtc_t; + +typedef enum _rtc_tick_interrupt_mode_e +{ + RTC_INT_ALARM_YEAR = BIT(0), + RTC_INT_ALARM_MONTH = BIT(1), + RTC_INT_ALARM_DAY = BIT(2), + RTC_INT_ALARM_WEEK = BIT(3), + RTC_INT_ALARM_HOUR = BIT(4), + RTC_INT_ALARM_MINUTE = BIT(5), + RTC_INT_ALARM_SECOND = BIT(6), + RTC_INT_TICK_YEAR = BIT(7), + RTC_INT_TICK_MONTH, + RTC_INT_TICK_DAY, + RTC_INT_TICK_WEEK, + RTC_INT_TICK_HOUR, + RTC_INT_TICK_MINUTE, + RTC_INT_TICK_SECOND, + RTC_INT_TICK_S8, + RTC_INT_TICK_S64, +} rtc_interrupt_mode_t; + +typedef struct _rtc_alarm_setup +{ + rt_uint32_t flag; /* alarm flag */ + struct tm tm; /* when will the alarm wake up user */ +} rtc_alarm_setup_t; + +#endif /* __DRV_RTC_H__ */ diff --git a/bsp/k230/drivers/utest/SConscript b/bsp/k230/drivers/utest/SConscript index 92ea98982fc..eeaa0f78f45 100644 --- a/bsp/k230/drivers/utest/SConscript +++ b/bsp/k230/drivers/utest/SConscript @@ -26,6 +26,9 @@ if GetDepend('RT_UTEST_USING_ALL_CASES') or GetDepend('BSP_UTEST_DRIVERS'): if GetDepend('BSP_USING_UART'): src += ['test_uart.c'] + + if GetDepend('BSP_USING_RTC'): + src += ['test_rtc.c'] group = DefineGroup('utestcases', src, depend = ['']) diff --git a/bsp/k230/drivers/utest/test_rtc.c b/bsp/k230/drivers/utest/test_rtc.c new file mode 100644 index 00000000000..0b1ffaab1cf --- /dev/null +++ b/bsp/k230/drivers/utest/test_rtc.c @@ -0,0 +1,217 @@ +/* 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 +#include +#include +#include "drv_rtc.h" + +/* + * 测试 RTC 的时间功能与闹钟功能,在RTCd的寄存器中保存的时间信息 + * 是以 UTC 时间保存的,要使用本地时间需要配置时区,当前配置的时 + * 区是东八区,即北京时间(CST) + * + * 在设置时间日期时使用 set_time() 与 set_date() 接口,设置的时 + * 间这两个接口内部会做时区转换 + * + * 测试说明: + * 基于庐山派开发板测试(01Studio 的开发板无法使用硬件RTC, + * 因为没有接 int0/4 的上拉) + * RTC 为 K230 自带的 RTC + * RTC 的时钟源为外部 32.768KHz 晶振 + * 在测试终端运行该测试后,会分别进行 test_rtc_set(), + * test_rtc_alarm() 与 test_rtc_interface() 三个测试。 + * 其中 test_rtc_set() 会通过 set_time() 与 set_date() 设置时间, + * 注意设置的时间需要为本地时间,内部会转换成 UTC 时间,然后调用 + * drv_rtc.c 内的接口设置到 RTC 寄存器中; + * test_rtc_alarm() 会设置一个 5 秒后的闹钟时间,并注册一个闹钟 + * 中断回调函数,同样用户设置的闹钟时间为本地时间,内部会转换成UTC + * 时间然后保存进 RTC 中; + * test_rtc_interface() 会测试读写 RTC 的接口,写 RTC 时同样需要 + * 提供本地时间,读出来后需要转换成本地时间(如果有需要)。 + */ + +#define RTC_NAME "rtc" + +static void test_rtc_set(void) +{ + rt_err_t ret = RT_EOK; + time_t now; + uint32_t i; + rt_device_t rtc_dev = RT_NULL; + + LOG_I("rtc set time test\n"); + rtc_dev = rt_device_find(RTC_NAME); + uassert_not_null(rtc_dev); + ret = rt_device_open(rtc_dev, RT_DEVICE_OFLAG_RDWR); + uassert_int_equal(ret, RT_EOK); + ret = set_time(23, 59, 59); + uassert_int_equal(ret, RT_EOK); + ret = set_date(2025, 9, 16); + uassert_int_equal(ret, RT_EOK); + rt_thread_mdelay(500); + /* 设置完时间后打印10次时间 */ + for (i=0; i<10; i++) + { + now = time(RT_NULL); + LOG_I("%s\n", ctime(&now)); + rt_thread_mdelay(1000); + } + + rt_device_close(rtc_dev); +} + +static void test_rtc_alarm_callback(void) +{ + LOG_I("rtc alarm triggered!\n"); +} + +static void test_rtc_alarm(void) +{ + rt_err_t ret = RT_EOK; + time_t now; + uint32_t i; + struct tm p_tm; + rt_device_t rtc_dev = RT_NULL; + struct rt_alarm *alarm = RT_NULL; + rtc_alarm_setup_t setup; + + LOG_I("rtc alarm test\n"); + rtc_dev = rt_device_find(RTC_NAME); + uassert_not_null(rtc_dev); + ret = rt_device_open(rtc_dev, RT_DEVICE_OFLAG_RDWR); + uassert_int_equal(ret, RT_EOK); + ret = set_time(23, 59, 59); + uassert_int_equal(ret, RT_EOK); + ret = set_date(2025, 9, 16); + uassert_int_equal(ret, RT_EOK); + rt_thread_mdelay(500); + now = time(RT_NULL); + LOG_I("%s\n", ctime(&now)); + now += 5; //alarm after 5s + localtime_r(&now, &p_tm); + + setup.flag = RTC_INT_ALARM_MINUTE | RTC_INT_ALARM_SECOND; + setup.tm.tm_year = p_tm.tm_year; + setup.tm.tm_mon = p_tm.tm_mon; + setup.tm.tm_mday = p_tm.tm_mday; + setup.tm.tm_wday = p_tm.tm_wday; + setup.tm.tm_hour = p_tm.tm_hour; + setup.tm.tm_min = p_tm.tm_min; + setup.tm.tm_sec = p_tm.tm_sec; + + rt_device_control(rtc_dev, RT_DEVICE_CTRL_RTC_SET_CALLBACK, &test_rtc_alarm_callback); //set rtc intr callback + rt_device_control(rtc_dev, RT_DEVICE_CTRL_RTC_SET_ALARM, &setup); //set alarm time + rt_memset(&p_tm, 0, sizeof(p_tm)); + rt_device_control(rtc_dev, RT_DEVICE_CTRL_RTC_GET_ALARM, &p_tm); //get alarm time + now = timegm(&p_tm); + LOG_I("get alarm time: %s\n", ctime(&now)); + + for (i=0; i<10; i++) + { + now = time(RT_NULL); + LOG_I("%s\n", ctime(&now)); + rt_thread_mdelay(1000); + } + rt_device_control(rtc_dev, RT_DEVICE_CTRL_RTC_STOP_ALARM, RT_NULL); //stop alarm + + rt_device_close(rtc_dev); +} + +static void test_rtc_interface(void) +{ + rt_err_t ret = RT_EOK; + uint32_t i; + rt_device_t rtc_dev = RT_NULL; + time_t now; + struct tm tm; + + LOG_I("rtc interface test\n"); + rtc_dev = rt_device_find(RTC_NAME); + uassert_not_null(rtc_dev); + ret = rt_device_open(rtc_dev, RT_DEVICE_OFLAG_RDWR); + uassert_int_equal(ret, RT_EOK); + + LOG_I("write rtc\n"); + tm.tm_year = 2025 - 1900; + tm.tm_mon = 9 - 1; + tm.tm_mday = 16; + tm.tm_wday = 2; + tm.tm_hour = 23; + tm.tm_min = 59; + tm.tm_sec = 59; + rt_device_write(rtc_dev, RT_NULL, (void*)&tm, sizeof(tm)); + rt_thread_mdelay(500); + + /* 设置完时间后打印10次时间 */ + for (i=0; i<10; i++) + { + now = time(RT_NULL); + LOG_I("[sys]:%s\n", ctime(&now)); + rt_thread_mdelay(1000); + } + + LOG_I("read rtc\n"); + for (i=0; i<10; i++) + { + rt_device_read(rtc_dev, RT_NULL, (void*)&now, sizeof(now)); + LOG_I("[read]: %s\n", ctime(&now)); + rt_thread_mdelay(1000); + } + + rt_device_close(rtc_dev); +} + +static void test_rtc(void) +{ + test_rtc_set(); + test_rtc_alarm(); + test_rtc_interface(); +} + +static void testcase(void) +{ + LOG_I("This is a rtc test case.\n"); + UTEST_UNIT_RUN(test_rtc); +} + +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(testcase, "bsp.k230.drivers.rtc", utest_tc_init, utest_tc_cleanup, 100); diff --git a/bsp/k230/rtconfig.h b/bsp/k230/rtconfig.h index 9c521884a67..a1ba8e430e6 100644 --- a/bsp/k230/rtconfig.h +++ b/bsp/k230/rtconfig.h @@ -494,6 +494,14 @@ /* NXP HAL & SDK Drivers */ /* end of NXP HAL & SDK Drivers */ + +/* NUVOTON Drivers */ + +/* end of NUVOTON Drivers */ + +/* GD32 Drivers */ + +/* end of GD32 Drivers */ /* end of HAL & SDK Drivers */ /* sensors drivers */