From e7175c27455dc48c164644ef3109ebef43466cd1 Mon Sep 17 00:00:00 2001 From: wuzheng Date: Fri, 11 Nov 2022 17:39:03 +0800 Subject: [PATCH] add edu-riscv64 RTC test example --- .../Applications/app_test/test_i2c.c | 2 + .../Applications/app_test/test_rtc.c | 38 ++ .../transform_layer/xizi/transform.c | 1 + .../transform_layer/xizi/transform.h | 7 + .../XiZi_IIoT/board/edu-riscv64/board.c | 3 +- .../edu-riscv64/third_party_driver/Kconfig | 8 + .../edu-riscv64/third_party_driver/Makefile | 5 + .../third_party_driver/gpio/drv_io_config.c | 5 + .../third_party_driver/include/connect_rtc.h | 36 ++ .../third_party_driver/include/hardware_rtc.h | 448 +++++++++++++ .../third_party_driver/rtc/Kconfig | 11 + .../third_party_driver/rtc/Makefile | 3 + .../third_party_driver/rtc/connect_rtc.c | 183 ++++++ .../third_party_driver/rtc/hardware_rtc.c | 597 ++++++++++++++++++ 14 files changed, 1346 insertions(+), 1 deletion(-) create mode 100644 APP_Framework/Applications/app_test/test_rtc.c create mode 100644 Ubiquitous/XiZi_IIoT/board/edu-riscv64/third_party_driver/include/connect_rtc.h create mode 100644 Ubiquitous/XiZi_IIoT/board/edu-riscv64/third_party_driver/include/hardware_rtc.h create mode 100644 Ubiquitous/XiZi_IIoT/board/edu-riscv64/third_party_driver/rtc/Kconfig create mode 100644 Ubiquitous/XiZi_IIoT/board/edu-riscv64/third_party_driver/rtc/Makefile create mode 100644 Ubiquitous/XiZi_IIoT/board/edu-riscv64/third_party_driver/rtc/connect_rtc.c create mode 100644 Ubiquitous/XiZi_IIoT/board/edu-riscv64/third_party_driver/rtc/hardware_rtc.c diff --git a/APP_Framework/Applications/app_test/test_i2c.c b/APP_Framework/Applications/app_test/test_i2c.c index d41a215e8..77a62c5f9 100644 --- a/APP_Framework/Applications/app_test/test_i2c.c +++ b/APP_Framework/Applications/app_test/test_i2c.c @@ -7,3 +7,5 @@ void TestI2C(void) { } + +PRIV_SHELL_CMD_FUNCTION(TestI2C, a iic test sample, PRIV_SHELL_CMD_MAIN_ATTR); diff --git a/APP_Framework/Applications/app_test/test_rtc.c b/APP_Framework/Applications/app_test/test_rtc.c new file mode 100644 index 000000000..683478dd1 --- /dev/null +++ b/APP_Framework/Applications/app_test/test_rtc.c @@ -0,0 +1,38 @@ +#include +#include +#include + +void TestRTC(int argc,char *argv[]) +{ + int rtc_fd = PrivOpen(RTC_DEV_DRIVER, O_RDWR); + if(rtc_fd<0){ + printf("open rtc fd error:%d\n",rtc_fd); + return; + } + + if(argc>1){ + + int times = atoi(argv[1]); + printf("Time will be printf times %d\n",times); + struct RtcDrvConfigureParam rtc_para; + rtc_para.rtc_operation_cmd = OPER_RTC_SET_TIME; + *(rtc_para.time) = 0; + + struct PrivIoctlCfg ioctl_cfg; + ioctl_cfg.ioctl_driver_type = RTC_TYPE; + ioctl_cfg.args = (void *)&rtc_para; + PrivIoctl(rtc_fd,0,&ioctl_cfg); + + rtc_para.rtc_operation_cmd = OPER_RTC_GET_TIME; + for(size_t i=0;iargs); break; + case RTC_TYPE: case ADC_TYPE: case DAC_TYPE: case WDT_TYPE: diff --git a/APP_Framework/Framework/transform_layer/xizi/transform.h b/APP_Framework/Framework/transform_layer/xizi/transform.h index eddcf2153..0a0780798 100644 --- a/APP_Framework/Framework/transform_layer/xizi/transform.h +++ b/APP_Framework/Framework/transform_layer/xizi/transform.h @@ -149,6 +149,7 @@ enum IoctlDriverType ADC_TYPE, DAC_TYPE, WDT_TYPE, + RTC_TYPE, DEFAULT_TYPE, }; @@ -193,6 +194,12 @@ typedef struct uint16_t press; }TouchDataParam; +struct RtcDrvConfigureParam +{ + int rtc_operation_cmd; + time_t *time; +}; + #define PRIV_SYSTICK_GET (CurrentTicksGain()) #define PRIV_LCD_DEV "/dev/lcd_dev" #define MY_DISP_HOR_RES BSP_LCD_Y_MAX diff --git a/Ubiquitous/XiZi_IIoT/board/edu-riscv64/board.c b/Ubiquitous/XiZi_IIoT/board/edu-riscv64/board.c index 924e3e9a3..63351f357 100644 --- a/Ubiquitous/XiZi_IIoT/board/edu-riscv64/board.c +++ b/Ubiquitous/XiZi_IIoT/board/edu-riscv64/board.c @@ -45,6 +45,7 @@ Modification: #include "dmac.h" #include "connect_gpio.h" #include "connect_soft_spi.h" +#include "connect_rtc.h" // #if defined(FS_VFS) // #include @@ -185,7 +186,7 @@ struct InitSequenceDesc _board_init[] = { "hw_i2c", HwI2cInit }, #endif #ifdef BSP_USING_RTC - { "hw_uart", HwRTC }, + { "hw_rtc", HwRtcInit }, #endif #ifdef BSP_USING_UART { "hw_uart", HwUartInit }, diff --git a/Ubiquitous/XiZi_IIoT/board/edu-riscv64/third_party_driver/Kconfig b/Ubiquitous/XiZi_IIoT/board/edu-riscv64/third_party_driver/Kconfig index eed2fa64b..ba7047a33 100755 --- a/Ubiquitous/XiZi_IIoT/board/edu-riscv64/third_party_driver/Kconfig +++ b/Ubiquitous/XiZi_IIoT/board/edu-riscv64/third_party_driver/Kconfig @@ -88,3 +88,11 @@ menuconfig BSP_USING_UART if BSP_USING_UART source "$BSP_DIR/third_party_driver/uart/Kconfig" endif + +menuconfig BSP_USING_RTC + bool "Using RTC device" + default y + select RESOURCES_RTC + if BSP_USING_RTC + source "$BSP_DIR/third_party_driver/rtc/Kconfig" + endif diff --git a/Ubiquitous/XiZi_IIoT/board/edu-riscv64/third_party_driver/Makefile b/Ubiquitous/XiZi_IIoT/board/edu-riscv64/third_party_driver/Makefile index 7494b84fe..b4ab9bb14 100644 --- a/Ubiquitous/XiZi_IIoT/board/edu-riscv64/third_party_driver/Makefile +++ b/Ubiquitous/XiZi_IIoT/board/edu-riscv64/third_party_driver/Makefile @@ -44,4 +44,9 @@ ifeq ($(CONFIG_BSP_USING_SOFT_SPI),y) SRC_DIR += soft_spi endif +ifeq ($(CONFIG_BSP_USING_RTC),y) + SRC_DIR += rtc +endif + + include $(KERNEL_ROOT)/compiler.mk diff --git a/Ubiquitous/XiZi_IIoT/board/edu-riscv64/third_party_driver/gpio/drv_io_config.c b/Ubiquitous/XiZi_IIoT/board/edu-riscv64/third_party_driver/gpio/drv_io_config.c index ee1c55960..f49c62d8f 100644 --- a/Ubiquitous/XiZi_IIoT/board/edu-riscv64/third_party_driver/gpio/drv_io_config.c +++ b/Ubiquitous/XiZi_IIoT/board/edu-riscv64/third_party_driver/gpio/drv_io_config.c @@ -105,6 +105,11 @@ static struct io_config IOCONFIG(BSP_SOFT_SPI_NCS_PIN, HS_GPIO(FPIOA_SOFT_SPI_NCS)), #endif +#ifdef BSP_USING_LORA + IOCONFIG(BSP_E220_M0_PIN, HS_GPIO(FUNC_GPIOHS10)), + IOCONFIG(BSP_E220_M1_PIN, HS_GPIO(FUNC_GPIOHS11)), +#endif + #ifdef BSP_USING_LED IOCONFIG(BSP_LED_PIN,FUNC_GPIO5); #endif diff --git a/Ubiquitous/XiZi_IIoT/board/edu-riscv64/third_party_driver/include/connect_rtc.h b/Ubiquitous/XiZi_IIoT/board/edu-riscv64/third_party_driver/include/connect_rtc.h new file mode 100644 index 000000000..8d02d6e6b --- /dev/null +++ b/Ubiquitous/XiZi_IIoT/board/edu-riscv64/third_party_driver/include/connect_rtc.h @@ -0,0 +1,36 @@ +/* +* Copyright (c) 2020 AIIT XUOS Lab +* XiUOS is licensed under Mulan PSL v2. +* You can use this software according to the terms and conditions of the Mulan PSL v2. +* You may obtain a copy of Mulan PSL v2 at: +* http://license.coscl.org.cn/MulanPSL2 +* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, +* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, +* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +* See the Mulan PSL v2 for more details. +*/ + +/** +* @file connect_rtc.h +* @brief define aiit-riscv64-board rtc function and struct +* @version 1.0 +* @author AIIT XUOS Lab +* @date 2021-04-25 +*/ + +#ifndef CONNECT_RTC_H +#define CONNECT_RTC_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +int HwRtcInit(void); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Ubiquitous/XiZi_IIoT/board/edu-riscv64/third_party_driver/include/hardware_rtc.h b/Ubiquitous/XiZi_IIoT/board/edu-riscv64/third_party_driver/include/hardware_rtc.h new file mode 100644 index 000000000..b9c416dbb --- /dev/null +++ b/Ubiquitous/XiZi_IIoT/board/edu-riscv64/third_party_driver/include/hardware_rtc.h @@ -0,0 +1,448 @@ +/* Copyright 2018 Canaan Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @file + * @brief A real-time clock (RTC) is a computer clock that keeps track of + * the current time. + */ + +/** +* @file hardware_rtc.h +* @brief add from Canaan k210 SDK +* https://canaan-creative.com/developer +* @version 1.0 +* @author AIIT XUOS Lab +* @date 2021-04-25 +*/ + +#ifndef __HARDWARE_RTC_H__ +#define __HARDWARE_RTC_H__ + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief RTC timer mode + * + * Timer mode selector + * | Mode | Description | + * |------|------------------------| + * | 0 | Timer pause | + * | 1 | Timer time running | + * | 2 | Timer time setting | + */ +typedef enum _rtc_timer_mode_e +{ + /* 0: Timer pause */ + RTC_TIMER_PAUSE, + /* 1: Timer time running */ + RTC_TIMER_RUNNING, + /* 2: Timer time setting */ + RTC_TIMER_SETTING, + /* Max count of this enum*/ + RTC_TIMER_MAX +} rtc_timer_mode_t; + +/* + * @brief RTC tick interrupt mode + * + * Tick interrupt mode selector + * | Mode | Description | + * |------|------------------------| + * | 0 | Interrupt every second | + * | 1 | Interrupt every minute | + * | 2 | Interrupt every hour | + * | 3 | Interrupt every day | + */ +typedef enum _rtc_tick_interrupt_mode_e +{ + /* 0: Interrupt every second */ + RTC_INT_SECOND, + /* 1: Interrupt every minute */ + RTC_INT_MINUTE, + /* 2: Interrupt every hour */ + RTC_INT_HOUR, + /* 3: Interrupt every day */ + RTC_INT_DAY, + /* Max count of this enum*/ + RTC_INT_MAX +} rtc_tick_interrupt_mode_t; + +/** + * @brief RTC mask structure + * + * RTC mask structure for common use + */ +typedef struct _rtc_mask +{ + /* Reserved */ + uint32_t resv : 1; + /* Second mask */ + uint32_t second : 1; + /* Minute mask */ + uint32_t minute : 1; + /* Hour mask */ + uint32_t hour : 1; + /* Week mask */ + uint32_t week : 1; + /* Day mask */ + uint32_t day : 1; + /* Month mask */ + uint32_t month : 1; + /* Year mask */ + uint32_t year : 1; +} __attribute__((packed, aligned(1))) rtc_mask_t; + +/** + * @brief RTC register + * + * @note RTC register table + * + * | Offset | Name | Description | + * |-----------|----------------|-------------------------------------| + * | 0x00 | date | Timer date information | + * | 0x04 | time | Timer time information | + * | 0x08 | alarm_date | Alarm date information | + * | 0x0c | alarm_time | Alarm time information | + * | 0x10 | initial_count | Timer counter initial value | + * | 0x14 | current_count | Timer counter current value | + * | 0x18 | interrupt_ctrl | RTC interrupt settings | + * | 0x1c | register_ctrl | RTC register settings | + * | 0x20 | reserved0 | Reserved | + * | 0x24 | reserved1 | Reserved | + * | 0x28 | extended | Timer extended information | + * + */ + + +/** + * @brief Timer date information + * + * No. 0 Register (0x00) + */ +typedef struct _rtc_date +{ + /* Week. Range [0,6]. 0 is Sunday. */ + uint32_t week : 3; + /* Reserved */ + uint32_t resv0 : 5; + /* Day. Range [1,31] or [1,30] or [1,29] or [1,28] */ + uint32_t day : 5; + /* Reserved */ + uint32_t resv1 : 3; + /* Month. Range [1,12] */ + uint32_t month : 4; + /* Year. Range [0,99] */ + uint32_t year : 12; +} __attribute__((packed, aligned(4))) rtc_date_t; + +/** + * @brief Timer time information + * + * No. 1 Register (0x04) + */ +typedef struct _rtc_time +{ + /* Reserved */ + uint32_t resv0 : 10; + /* Second. Range [0,59] */ + uint32_t second : 6; + /* Minute. Range [0,59] */ + uint32_t minute : 6; + /* Reserved */ + uint32_t resv1 : 2; + /* Hour. Range [0,23] */ + uint32_t hour : 5; + /* Reserved */ + uint32_t resv2 : 3; +} __attribute__((packed, aligned(4))) rtc_time_t; + +/** + * @brief Alarm date information + * + * No. 2 Register (0x08) + */ +typedef struct _rtc_alarm_date +{ + /* Alarm Week. Range [0,6]. 0 is Sunday. */ + uint32_t week : 3; + /* Reserved */ + uint32_t resv0 : 5; + /* Alarm Day. Range [1,31] or [1,30] or [1,29] or [1,28] */ + uint32_t day : 5; + /* Reserved */ + uint32_t resv1 : 3; + /* Alarm Month. Range [1,12] */ + uint32_t month : 4; + /* Alarm Year. Range [0,99] */ + uint32_t year : 12; +} __attribute__((packed, aligned(4))) rtc_alarm_date_t; + +/** + * @brief Alarm time information + * + * No. 3 Register (0x0c) + */ +typedef struct _rtc_alarm_time +{ + /* Reserved */ + uint32_t resv0 : 10; + /* Alarm Second. Range [0,59] */ + uint32_t second : 6; + /* Alarm Minute. Range [0,59] */ + uint32_t minute : 6; + /* Reserved */ + uint32_t resv1 : 2; + /* Alarm Hour. Range [0,23] */ + uint32_t hour : 5; + /* Reserved */ + uint32_t resv2 : 3; +} __attribute__((packed, aligned(4))) rtc_alarm_time_t; + +/** + * @brief Timer counter initial value + * + * No. 4 Register (0x10) + */ +typedef struct _rtc_initial_count +{ + /* RTC counter initial value */ + uint32_t count : 32; +} __attribute__((packed, aligned(4))) rtc_initial_count_t; + +/** + * @brief Timer counter current value + * + * No. 5 Register (0x14) + */ +typedef struct _rtc_current_count +{ + /* RTC counter current value */ + uint32_t count : 32; +} __attribute__((packed, aligned(4))) rtc_current_count_t; + +/** + * @brief RTC interrupt settings + * + * No. 6 Register (0x18) + */ +typedef struct _rtc_interrupt_ctrl +{ + /* Reserved */ + uint32_t tick_enable : 1; + /* Alarm interrupt enable */ + uint32_t alarm_enable : 1; + /* Tick interrupt enable */ + uint32_t tick_int_mode : 2; + /* Reserved */ + uint32_t resv : 20; + /* Alarm compare mask for interrupt */ + uint32_t alarm_compare_mask : 8; +} __attribute__((packed, aligned(4))) rtc_interrupt_ctrl_t; + +/** + * @brief RTC register settings + * + * No. 7 Register (0x1c) + */ +typedef struct _rtc_register_ctrl +{ + /* RTC timer read enable */ + uint32_t read_enable : 1; + /* RTC timer write enable */ + uint32_t write_enable : 1; + /* Reserved */ + uint32_t resv0 : 11; + /* RTC timer mask */ + uint32_t TimerMask : 8; + /* RTC alarm mask */ + uint32_t alarm_mask : 8; + /* RTC counter initial count value mask */ + uint32_t initial_count_mask : 1; + /* RTC interrupt register mask */ + uint32_t interrupt_register_mask : 1; + /* Reserved */ + uint32_t resv1 : 1; +} __attribute__((packed, aligned(4))) rtc_register_ctrl_t; + +/** + * @brief Reserved + * + * No. 8 Register (0x20) + */ +typedef struct _rtc_reserved0 +{ + /* Reserved */ + uint32_t resv : 32; +} __attribute__((packed, aligned(4))) rtc_reserved0_t; + +/** + * @brief Reserved + * + * No. 9 Register (0x24) + */ +typedef struct _rtc_reserved1 +{ + /* Reserved */ + uint32_t resv : 32; +} __attribute__((packed, aligned(4))) rtc_reserved1_t; + +/** + * @brief Timer extended information + * + * No. 10 Register (0x28) + */ +typedef struct _rtc_extended +{ + /* Century. Range [0,31] */ + uint32_t century : 5; + /* Is leap year. 1 is leap year, 0 is not leap year */ + uint32_t leap_year : 1; + /* Reserved */ + uint32_t resv : 26; +} __attribute__((packed, aligned(4))) rtc_extended_t; + + +/** + * @brief Real-time clock struct + * + * A real-time clock (RTC) is a computer clock that keeps track of + * the current time. + */ +typedef struct _rtc +{ + /* No. 0 (0x00): Timer date information */ + rtc_date_t date; + /* No. 1 (0x04): Timer time information */ + rtc_time_t time; + /* No. 2 (0x08): Alarm date information */ + rtc_alarm_date_t alarm_date; + /* No. 3 (0x0c): Alarm time information */ + rtc_alarm_time_t alarm_time; + /* No. 4 (0x10): Timer counter initial value */ + rtc_initial_count_t initial_count; + /* No. 5 (0x14): Timer counter current value */ + rtc_current_count_t current_count; + /* No. 6 (0x18): RTC interrupt settings */ + rtc_interrupt_ctrl_t interrupt_ctrl; + /* No. 7 (0x1c): RTC register settings */ + rtc_register_ctrl_t register_ctrl; + /* No. 8 (0x20): Reserved */ + rtc_reserved0_t reserved0; + /* No. 9 (0x24): Reserved */ + rtc_reserved1_t reserved1; + /* No. 10 (0x28): Timer extended information */ + rtc_extended_t extended; +} __attribute__((packed, aligned(4))) rtc_t; + + +/** + * @brief Real-time clock object + */ +extern volatile rtc_t *const rtc; +extern volatile uint32_t *const rtc_base; + +/** + * @brief Set date time to RTC + * + * @param[in] year The year + * @param[in] month The month + * @param[in] day The day + * @param[in] hour The hour + * @param[in] minute The minute + * @param[in] second The second + * + * @return result + * - 0 Success + * - Other Fail + */ +int rtc_timer_set(int year, int month, int day, int hour, int minute, int second); + +/** + * @brief Get date time from RTC + * + * @param year The year + * @param month The month + * @param day The day + * @param hour The hour + * @param minute The minute + * @param second The second + * + * @return result + * - 0 Success + * - Other Fail + */ +int rtc_timer_get(int *year, int *month, int *day, int *hour, int *minute, int *second); + +/** + * @brief Initialize RTC + * + * @return Result + * - 0 Success + * - Other Fail + */ +int rtc_init(void); + +/** + * @brief Set RTC in protect mode or not + * + * @param enable Enable flag + * + * @return result + * - 0 Success + * - Other Fail + */ +int rtc_protect_set(int enable); + +/** + * @brief Set RTC timer mode + * + * @param timer_mode Timer mode + * + */ +void rtc_timer_set_mode(rtc_timer_mode_t timer_mode); + +/** + * @brief Set RTC timer clock frequency + * + * @param frequency Frequency + * + * @return result + * - 0 Success + * - Other Fail + */ +int rtc_timer_set_clock_frequency(unsigned int frequency); + +/** + * @brief Set RTC timer clock count value + * + * @param count Count + * + * @return result + * - 0 Success + * - Other Fail + */ +int rtc_timer_set_clock_count_value(unsigned int count); + +#ifdef __cplusplus +} +#endif + +#endif /* _DRIVER_RTC_H */ diff --git a/Ubiquitous/XiZi_IIoT/board/edu-riscv64/third_party_driver/rtc/Kconfig b/Ubiquitous/XiZi_IIoT/board/edu-riscv64/third_party_driver/rtc/Kconfig new file mode 100644 index 000000000..e853dd40a --- /dev/null +++ b/Ubiquitous/XiZi_IIoT/board/edu-riscv64/third_party_driver/rtc/Kconfig @@ -0,0 +1,11 @@ +if BSP_USING_RTC + config RTC_BUS_NAME + string "rtc bus name" + default "rtc" + config RTC_DRV_NAME + string "rtc bus driver name" + default "rtc_drv" + config RTC_DEVICE_NAME + string "rtc bus device name" + default "rtc_dev" +endif diff --git a/Ubiquitous/XiZi_IIoT/board/edu-riscv64/third_party_driver/rtc/Makefile b/Ubiquitous/XiZi_IIoT/board/edu-riscv64/third_party_driver/rtc/Makefile new file mode 100644 index 000000000..23575e62e --- /dev/null +++ b/Ubiquitous/XiZi_IIoT/board/edu-riscv64/third_party_driver/rtc/Makefile @@ -0,0 +1,3 @@ +SRC_FILES := connect_rtc.c hardware_rtc.c + +include $(KERNEL_ROOT)/compiler.mk diff --git a/Ubiquitous/XiZi_IIoT/board/edu-riscv64/third_party_driver/rtc/connect_rtc.c b/Ubiquitous/XiZi_IIoT/board/edu-riscv64/third_party_driver/rtc/connect_rtc.c new file mode 100644 index 000000000..fc512b865 --- /dev/null +++ b/Ubiquitous/XiZi_IIoT/board/edu-riscv64/third_party_driver/rtc/connect_rtc.c @@ -0,0 +1,183 @@ +/* +* Copyright (c) 2020 AIIT XUOS Lab +* XiUOS is licensed under Mulan PSL v2. +* You can use this software according to the terms and conditions of the Mulan PSL v2. +* You may obtain a copy of Mulan PSL v2 at: +* http://license.coscl.org.cn/MulanPSL2 +* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, +* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, +* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +* See the Mulan PSL v2 for more details. +*/ + +/** +* @file connect_rtc.c +* @brief support aiit-riscv64-board rtc function and register to bus framework +* @version 1.0 +* @author AIIT XUOS Lab +* @date 2021-04-25 +*/ + +#include +#include +#include +#include +#include +#include + +static int GetWeekDay(int year, int month, int day) +{ + /* Magic method to get weekday */ + int weekday = (day += month < 3 ? year-- : year - 2, + 23 * month / 9 + day + 4 + year / 4 - year / 100 + year / 400) % 7; + return weekday; +} + +static uint32 RtcConfigure(void *drv, struct BusConfigureInfo *configure_info) +{ + NULL_PARAM_CHECK(drv); + + struct RtcDriver *rtc_drv = (struct RtcDriver *)drv; + struct RtcDrvConfigureParam *drv_param = (struct RtcDrvConfigureParam *)configure_info->private_data; + + int cmd = drv_param->rtc_operation_cmd; + time_t *time = drv_param->time; + + switch (cmd) + { + case OPER_RTC_GET_TIME: + { + struct tm ct; + int year,month,day,hour,minute,second; + memset(&ct,0,sizeof(struct tm)); + + rtc_timer_get(&year, &month, &day, &hour, &minute, &second); + + ct.tm_year = year - 1900; + ct.tm_mon = month - 1; + ct.tm_mday = day; + ct.tm_wday = GetWeekDay(year, month, day); + + ct.tm_hour = hour; + ct.tm_min = minute; + ct.tm_sec = second; + + *time = mktime(&ct); + } + break; + case OPER_RTC_SET_TIME: + { + struct tm *ct; + struct tm tm_new; + x_base lock; + + lock = CriticalAreaLock(); + ct = localtime(time); + memcpy(&tm_new, ct, sizeof(struct tm)); + CriticalAreaUnLock(lock); + + sysctl_reset(SYSCTL_RESET_RTC); + sysctl_clock_enable(SYSCTL_CLOCK_RTC); + rtc_protect_set(0); + rtc_timer_set_clock_frequency(SysctlClockGetFreq(SYSCTL_CLOCK_IN0)); + rtc_timer_set_clock_count_value(1); + rtc_timer_set_mode(RTC_TIMER_RUNNING); + + if (rtc_timer_set(tm_new.tm_year+1900,tm_new.tm_mon+1,tm_new.tm_mday, + tm_new.tm_hour,tm_new.tm_min,tm_new.tm_sec)==-1) + return ERROR; + } + break; + } + return EOK; +} + +/*manage the rtc device operations*/ +static const struct RtcDevDone dev_done = +{ + .open = NONE, + .close = NONE, + .write = NONE, + .read = NONE, +}; + +static int BoardRtcBusInit(struct RtcBus *rtc_bus, struct RtcDriver *rtc_driver) +{ + x_err_t ret = EOK; + + /*Init the rtc bus */ + ret = RtcBusInit(rtc_bus, RTC_BUS_NAME); + if (EOK != ret) { + KPrintf("HwRtcInit RtcBusInit error %d\n", ret); + return ERROR; + } + + /*Init the rtc driver*/ + ret = RtcDriverInit(rtc_driver, RTC_DRV_NAME); + if (EOK != ret) { + KPrintf("HwRtcInit RtcDriverInit error %d\n", ret); + return ERROR; + } + + /*Attach the rtc driver to the rtc bus*/ + ret = RtcDriverAttachToBus(RTC_DRV_NAME, RTC_BUS_NAME); + if (EOK != ret) { + KPrintf("HwRtcInit RtcDriverAttachToBus error %d\n", ret); + return ERROR; + } + + return ret; +} + +/*Attach the rtc device to the rtc bus*/ +static int BoardRtcDevBend(void) +{ + x_err_t ret = EOK; + + static struct RtcHardwareDevice rtc_device; + memset(&rtc_device, 0, sizeof(struct RtcHardwareDevice)); + + rtc_device.dev_done = &(dev_done); + + ret = RtcDeviceRegister(&rtc_device, NONE, RTC_DEVICE_NAME); + if (EOK != ret) { + KPrintf("HwRtcInit RtcDeviceInit device %s error %d\n", RTC_DEVICE_NAME, ret); + return ERROR; + } + + ret = RtcDeviceAttachToBus(RTC_DEVICE_NAME, RTC_BUS_NAME); + if (EOK != ret) { + KPrintf("HwRtcInit RtcDeviceAttachToBus device %s error %d\n", RTC_DEVICE_NAME, ret); + return ERROR; + } + + return ret; +} + +int HwRtcInit(void) +{ + x_err_t ret = EOK; + + static struct RtcBus rtc_bus; + memset(&rtc_bus, 0, sizeof(struct RtcBus)); + + static struct RtcDriver rtc_driver; + memset(&rtc_driver, 0, sizeof(struct RtcDriver)); + + rtc_driver.configure = &(RtcConfigure); + + ret = BoardRtcBusInit(&rtc_bus, &rtc_driver); + if (EOK != ret) { + KPrintf("HwRtcInit error ret %u\n", ret); + return ERROR; + } + + ret = BoardRtcDevBend(); + if (EOK != ret) { + KPrintf("HwRtcInit error ret %u\n", ret); + } + + rtc_init(); + + return ret; +} diff --git a/Ubiquitous/XiZi_IIoT/board/edu-riscv64/third_party_driver/rtc/hardware_rtc.c b/Ubiquitous/XiZi_IIoT/board/edu-riscv64/third_party_driver/rtc/hardware_rtc.c new file mode 100644 index 000000000..3f168dbf6 --- /dev/null +++ b/Ubiquitous/XiZi_IIoT/board/edu-riscv64/third_party_driver/rtc/hardware_rtc.c @@ -0,0 +1,597 @@ +/* Copyright 2018 Canaan Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** +* @file hardware_rtc.c +* @brief add from Canaan k210 SDK +* https://canaan-creative.com/developer +* @version 1.0 +* @author AIIT XUOS Lab +* @date 2021-04-25 +*/ + +#include +#include +#include +#include +#include +#include + +volatile rtc_t *const rtc = (volatile rtc_t *)RTC_BASE_ADDR; + +struct tm rtc_date_time; + +void rtc_timer_set_mode(rtc_timer_mode_t timer_mode) +{ + rtc_register_ctrl_t register_ctrl = rtc->register_ctrl; + + switch (timer_mode) + { + case RTC_TIMER_PAUSE: + register_ctrl.read_enable = 0; + register_ctrl.write_enable = 0; + break; + case RTC_TIMER_RUNNING: + register_ctrl.read_enable = 1; + register_ctrl.write_enable = 0; + break; + case RTC_TIMER_SETTING: + register_ctrl.read_enable = 0; + register_ctrl.write_enable = 1; + break; + default: + register_ctrl.read_enable = 0; + register_ctrl.write_enable = 0; + break; + } + rtc->register_ctrl = register_ctrl; +} + +rtc_timer_mode_t rtc_timer_get_mode(void) +{ + rtc_register_ctrl_t register_ctrl = rtc->register_ctrl; + rtc_timer_mode_t timer_mode = RTC_TIMER_PAUSE; + + if ((!register_ctrl.read_enable) && (!register_ctrl.write_enable)) + { + /* RTC_TIMER_PAUSE */ + timer_mode = RTC_TIMER_PAUSE; + } + else if ((register_ctrl.read_enable) && (!register_ctrl.write_enable)) + { + /* RTC_TIMER_RUNNING */ + timer_mode = RTC_TIMER_RUNNING; + } + else if ((!register_ctrl.read_enable) && (register_ctrl.write_enable)) { + /* RTC_TIMER_SETTING */ + timer_mode = RTC_TIMER_SETTING; + } + else + { + /* Something is error, reset timer mode */ + rtc_timer_set_mode(timer_mode); + } + + return timer_mode; +} + +static inline int rtc_in_range(int value, int min, int max) +{ + return ((value >= min) && (value <= max)); +} + +int rtc_timer_set_tm(const struct tm *tm) +{ + rtc_date_t timer_date; + rtc_time_t timer_time; + rtc_extended_t timer_extended; + + if (tm) + { + /* + * Range of tm->tm_sec could be [0,61] + * + * Range of tm->tm_sec allows for a positive leap second. Two + * leap seconds in the same minute are not allowed (the C90 + * range 0..61 was a defect) + */ + if (rtc_in_range(tm->tm_sec, 0, 59)) + timer_time.second = tm->tm_sec; + else + return -1; + + /* Range of tm->tm_min could be [0,59] */ + if (rtc_in_range(tm->tm_min, 0, 59)) + timer_time.minute = tm->tm_min; + else + return -1; + + /* Range of tm->tm_hour could be [0, 23] */ + if (rtc_in_range(tm->tm_hour, 0, 23)) + timer_time.hour = tm->tm_hour; + else + return -1; + + /* Range of tm->tm_mday could be [1, 31] */ + if (rtc_in_range(tm->tm_mday, 1, 31)) + timer_date.day = tm->tm_mday; + else + return -1; + + /* + * Range of tm->tm_mon could be [0, 11] + * But in this RTC, date.month should be [1, 12] + */ + if (rtc_in_range(tm->tm_mon, 0, 11)) + timer_date.month = tm->tm_mon + 1; + else + return -1; + + /* + * Range of tm->tm_year is the years since 1900 + * But in this RTC, year is split into year and century + * In this RTC, century range is [0,31], year range is [0,99] + */ + int human_year = tm->tm_year + 1900; + int rtc_year = human_year % 100; + int rtc_century = human_year / 100; + + if (rtc_in_range(rtc_year, 0, 99) && + rtc_in_range(rtc_century, 0, 31)) + { + timer_date.year = rtc_year; + timer_extended.century = rtc_century; + } + else + return -1; + + /* Range of tm->tm_wday could be [0, 6] */ + if (rtc_in_range(tm->tm_wday, 0, 6)) + timer_date.week = tm->tm_wday; + else + return -1; + + /* Set RTC mode to timer setting mode */ + rtc_timer_set_mode(RTC_TIMER_SETTING); + /* Write value to RTC */ + rtc->date = timer_date; + rtc->time = timer_time; + rtc->extended = timer_extended; + /* Get CPU current freq */ + unsigned long freq = SysctlClockGetFreq(SYSCTL_CLOCK_CPU); + /* Set threshold to 1/26000000 s */ + freq = freq / 26000000; + /* Get current CPU cycle */ + unsigned long start_cycle = read_cycle(); + /* Wait for 1/26000000 s to sync data */ + while (read_cycle() - start_cycle < freq) + continue; + /* Set RTC mode to timer running mode */ + rtc_timer_set_mode(RTC_TIMER_RUNNING); + } + + return 0; +} + +int rtc_timer_set_alarm_tm(const struct tm *tm) +{ + rtc_alarm_date_t alarm_date; + rtc_alarm_time_t alarm_time; + + if (tm) { + /* + * Range of tm->tm_sec could be [0,61] + * + * Range of tm->tm_sec allows for a positive leap second. Two + * leap seconds in the same minute are not allowed (the C90 + * range 0..61 was a defect) + */ + if (rtc_in_range(tm->tm_sec, 0, 59)) + alarm_time.second = tm->tm_sec; + else + return -1; + + /* Range of tm->tm_min could be [0,59] */ + if (rtc_in_range(tm->tm_min, 0, 59)) + alarm_time.minute = tm->tm_min; + else + return -1; + + /* Range of tm->tm_hour could be [0, 23] */ + if (rtc_in_range(tm->tm_hour, 0, 23)) + alarm_time.hour = tm->tm_hour; + else + return -1; + + /* Range of tm->tm_mday could be [1, 31] */ + if (rtc_in_range(tm->tm_mday, 1, 31)) + alarm_date.day = tm->tm_mday; + else + return -1; + + /* + * Range of tm->tm_mon could be [0, 11] + * But in this RTC, date.month should be [1, 12] + */ + if (rtc_in_range(tm->tm_mon, 0, 11)) + alarm_date.month = tm->tm_mon + 1; + else + return -1; + + /* + * Range of tm->tm_year is the years since 1900 + * But in this RTC, year is split into year and century + * In this RTC, century range is [0,31], year range is [0,99] + */ + int human_year = tm->tm_year + 1900; + int rtc_year = human_year % 100; + int rtc_century = human_year / 100; + + if (rtc_in_range(rtc_year, 0, 99) && + rtc_in_range(rtc_century, 0, 31)) + { + alarm_date.year = rtc_year; + } else + return -1; + + /* Range of tm->tm_wday could be [0, 6] */ + if (rtc_in_range(tm->tm_wday, 0, 6)) + alarm_date.week = tm->tm_wday; + else + return -1; + + /* Write value to RTC */ + rtc->alarm_date = alarm_date; + rtc->alarm_time = alarm_time; + } + + return 0; +} + +static int rtc_year_is_leap(int year) +{ + return (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0); +} + +static int rtc_get_yday(int year, int month, int day) +{ + static const int days[2][13] = + { + {0, 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334}, + {0, 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335} + }; + int leap = rtc_year_is_leap(year); + + return days[leap][month] + day; +} + +static int rtc_get_wday(int year, int month, int day) +{ + /* Magic method to get weekday */ + int weekday = (day += month < 3 ? year-- : year - 2, 23 * month / 9 + day + 4 + year / 4 - year / 100 + year / 400) % 7; + return weekday; +} + +struct tm *rtc_timer_get_tm(void) +{ + if (rtc_timer_get_mode() != RTC_TIMER_RUNNING) + return NULL; + + rtc_date_t timer_date = rtc->date; + rtc_time_t timer_time = rtc->time; + rtc_extended_t timer_extended = rtc->extended; + + struct tm *tm = &rtc_date_time; + + tm->tm_sec = timer_time.second % 60; + tm->tm_min = timer_time.minute % 60; + tm->tm_hour = timer_time.hour % 24; + tm->tm_mday = (timer_date.day - 1) % 31 + 1; + tm->tm_mon = (timer_date.month - 1)% 12; + tm->tm_year = (timer_date.year % 100) + (timer_extended.century * 100) - 1900; + tm->tm_wday = timer_date.week; + tm->tm_yday = rtc_get_yday(tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday); + tm->tm_isdst = -1; + + return tm; +} + +struct tm *rtc_timer_get_alarm_tm(void) +{ + if (rtc_timer_get_mode() != RTC_TIMER_RUNNING) + return NULL; + + rtc_alarm_date_t alarm_date = rtc->alarm_date; + rtc_alarm_time_t alarm_time = rtc->alarm_time; + rtc_extended_t timer_extended = rtc->extended; + + struct tm *tm = &rtc_date_time; + + tm->tm_sec = alarm_time.second % 60; + tm->tm_min = alarm_time.minute % 60; + tm->tm_hour = alarm_time.hour % 24; + tm->tm_mday = alarm_date.day % 31; + tm->tm_mon = (alarm_date.month % 12) - 1; + /* Alarm and Timer use same timer_extended.century */ + tm->tm_year = (alarm_date.year % 100) + (timer_extended.century * 100) - 1900; + tm->tm_wday = alarm_date.week; + tm->tm_yday = rtc_get_yday(tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday); + tm->tm_isdst = -1; + + return tm; +} + +int rtc_timer_set(int year, int month, int day, int hour, int minute, int second) +{ + struct tm date_time = + { + .tm_sec = second, + .tm_min = minute, + .tm_hour = hour, + .tm_mday = day, + .tm_mon = month - 1, + .tm_year = year - 1900, + .tm_wday = rtc_get_wday(year, month, day), + .tm_yday = rtc_get_yday(year, month, day), + .tm_isdst = -1, + }; + return rtc_timer_set_tm(&date_time); +} + +int rtc_timer_get(int *year, int *month, int *day, int *hour, int *minute, int *second) +{ + struct tm *tm = rtc_timer_get_tm(); + + if (tm) + { + if (year) + *year = tm->tm_year + 1900; + if (month) + *month = tm->tm_mon + 1; + if (day) + *day = tm->tm_mday; + if (hour) + *hour = tm->tm_hour; + if (minute) + *minute = tm->tm_min; + if (second) + *second = tm->tm_sec; + } else + return -1; + + return 0; +} + +int rtc_timer_set_alarm(int year, int month, int day, int hour, int minute, int second) +{ + struct tm date_time = { + .tm_sec = second, + .tm_min = minute, + .tm_hour = hour, + .tm_mday = day, + .tm_mon = month - 1, + .tm_year = year - 1900, + .tm_wday = rtc_get_wday(year, month, day), + .tm_yday = rtc_get_yday(year, month, day), + .tm_isdst = -1, + }; + + return rtc_timer_set_alarm_tm(&date_time); +} + +int rtc_timer_get_alarm(int *year, int *month, int *day, int *hour, int *minute, int *second) +{ + struct tm *tm = rtc_timer_get_alarm_tm(); + + if (tm) { + if (year) + *year = tm->tm_year + 1900; + if (month) + *month = tm->tm_mon + 1; + if (day) + *day = tm->tm_mday; + if (hour) + *hour = tm->tm_hour; + if (minute) + *minute = tm->tm_min; + if (second) + *second = tm->tm_sec; + } else + return -1; + + return 0; +} + +int rtc_timer_set_clock_frequency(unsigned int frequency) +{ + + rtc_initial_count_t initial_count; + + initial_count.count = frequency; + rtc_timer_set_mode(RTC_TIMER_SETTING); + rtc->initial_count = initial_count; + rtc_timer_set_mode(RTC_TIMER_RUNNING); + return 0; +} + +unsigned int rtc_timer_get_clock_frequency(void) +{ + return rtc->initial_count.count; +} + +int rtc_timer_set_clock_count_value(unsigned int count) +{ + + rtc_current_count_t current_count; + + current_count.count = count; + rtc_timer_set_mode(RTC_TIMER_SETTING); + rtc->current_count = current_count; + rtc_timer_set_mode(RTC_TIMER_RUNNING); + return 0; +} + +unsigned int rtc_timer_get_clock_count_value(void) +{ + return rtc->current_count.count; +} + +int rtc_tick_interrupt_set(int enable) +{ + rtc_interrupt_ctrl_t interrupt_ctrl = rtc->interrupt_ctrl; + interrupt_ctrl.tick_enable = enable; + rtc_timer_set_mode(RTC_TIMER_SETTING); + rtc->interrupt_ctrl = interrupt_ctrl; + rtc_timer_set_mode(RTC_TIMER_RUNNING); + return 0; +} + +int rtc_tick_interrupt_get(void) +{ + rtc_interrupt_ctrl_t interrupt_ctrl = rtc->interrupt_ctrl; + + return interrupt_ctrl.tick_enable; +} + +int rtc_tick_interrupt_mode_set(rtc_tick_interrupt_mode_t mode) +{ + rtc_interrupt_ctrl_t interrupt_ctrl = rtc->interrupt_ctrl; + + interrupt_ctrl.tick_int_mode = mode; + rtc_timer_set_mode(RTC_TIMER_SETTING); + rtc->interrupt_ctrl = interrupt_ctrl; + rtc_timer_set_mode(RTC_TIMER_RUNNING); + return 0; +} + +rtc_tick_interrupt_mode_t rtc_tick_interrupt_mode_get(void) +{ + rtc_interrupt_ctrl_t interrupt_ctrl = rtc->interrupt_ctrl; + + return interrupt_ctrl.tick_int_mode; +} + +int rtc_alarm_interrupt_set(int enable) +{ + rtc_interrupt_ctrl_t interrupt_ctrl = rtc->interrupt_ctrl; + + interrupt_ctrl.alarm_enable = enable; + rtc->interrupt_ctrl = interrupt_ctrl; + return 0; +} + +int rtc_alarm_interrupt_get(void) +{ + rtc_interrupt_ctrl_t interrupt_ctrl = rtc->interrupt_ctrl; + + return interrupt_ctrl.alarm_enable; +} + +int rtc_alarm_interrupt_mask_set(rtc_mask_t mask) +{ + rtc_interrupt_ctrl_t interrupt_ctrl = rtc->interrupt_ctrl; + + interrupt_ctrl.alarm_compare_mask = *(uint8_t *)&mask; + rtc->interrupt_ctrl = interrupt_ctrl; + return 0; +} + +rtc_mask_t rtc_alarm_interrupt_mask_get(void) +{ + rtc_interrupt_ctrl_t interrupt_ctrl = rtc->interrupt_ctrl; + + uint8_t compare_mask = interrupt_ctrl.alarm_compare_mask; + + return *(rtc_mask_t *)&compare_mask; +} + +int rtc_protect_set(int enable) +{ + rtc_register_ctrl_t register_ctrl = rtc->register_ctrl; + + rtc_mask_t mask = + { + .second = 1, + /* Second mask */ + .minute = 1, + /* Minute mask */ + .hour = 1, + /* Hour mask */ + .week = 1, + /* Week mask */ + .day = 1, + /* Day mask */ + .month = 1, + /* Month mask */ + .year = 1, + }; + + rtc_mask_t unmask = + { + .second = 0, + /* Second mask */ + .minute = 0, + /* Minute mask */ + .hour = 0, + /* Hour mask */ + .week = 0, + /* Week mask */ + .day = 0, + /* Day mask */ + .month = 0, + /* Month mask */ + .year = 0, + }; + + if (enable) + { + /* Turn RTC in protect mode, no one can write time */ + register_ctrl.TimerMask = *(uint8_t *)&unmask; + register_ctrl.alarm_mask = *(uint8_t *)&unmask; + register_ctrl.initial_count_mask = 0; + register_ctrl.interrupt_register_mask = 0; + } + else + { + /* Turn RTC in unprotect mode, everyone can write time */ + register_ctrl.TimerMask = *(uint8_t *)&mask; + register_ctrl.alarm_mask = *(uint8_t *)&mask; + register_ctrl.initial_count_mask = 1; + register_ctrl.interrupt_register_mask = 1; + } + rtc_timer_set_mode(RTC_TIMER_SETTING); + rtc->register_ctrl = register_ctrl; + rtc_timer_set_mode(RTC_TIMER_RUNNING); + return 0; +} + +int rtc_init(void) +{ + /* Reset RTC */ + sysctl_reset(SYSCTL_RESET_RTC); + /* Enable RTC */ + sysctl_clock_enable(SYSCTL_CLOCK_RTC); + /* Unprotect RTC */ + rtc_protect_set(0); + /* Set RTC clock frequency */ + rtc_timer_set_clock_frequency( + SysctlClockGetFreq(SYSCTL_CLOCK_IN0) + ); + rtc_timer_set_clock_count_value(1); + + /* Set RTC mode to timer running mode */ + rtc_timer_set_mode(RTC_TIMER_RUNNING); + return 0; +}