diff --git a/APP_Framework/Applications/app_test/Kconfig b/APP_Framework/Applications/app_test/Kconfig index c3fde9f87..e1e9b084e 100644 --- a/APP_Framework/Applications/app_test/Kconfig +++ b/APP_Framework/Applications/app_test/Kconfig @@ -102,6 +102,43 @@ menu "test app" endif endif + menuconfig USER_TEST_HWTIMER + select BSP_USING_HWTIMER + select BSP_USING_GPIO + bool "Config test hwtimer" + default n + if USER_TEST_HWTIMER + if ADD_XIZI_FETURES + config HWTIMER_PIN_DEV_DRIVER + string "Set pin dev path" + default "/dev/pin_dev" + endif + endif + + menuconfig USER_TEST_WDT + select BSP_USING_WDT0 + bool "Config test watchdog" + default n + if USER_TEST_WDT + if ADD_XIZI_FETURES + config WDT0_DEV_DRIVER + string "Set wdt dev path" + default "/dev/wdt0_dev0" + endif + endif + + menuconfig USER_TEST_LCD_EDU + select BSP_USING_LCD + bool "Config test lcd in PrivOpen" + default n + if USER_TEST_LCD_EDU + if ADD_XIZI_FETURES + config EDU_LCD_DEV_DRIVER + string "Set lcd dev path" + default "/dev/lcd_dev" + endif + endif + menuconfig USER_TEST_I2C select BSP_USING_I2C bool "Config test i2c" @@ -110,7 +147,7 @@ menu "test app" if ADD_XIZI_FETURES config I2C_DEV_DRIVER string "Set i2c dev path" - default "/dev/i2c_dev" + default "/dev/i2c1_dev0" endif endif diff --git a/APP_Framework/Applications/app_test/Makefile b/APP_Framework/Applications/app_test/Makefile index b511ec9e6..28e2f25e5 100644 --- a/APP_Framework/Applications/app_test/Makefile +++ b/APP_Framework/Applications/app_test/Makefile @@ -57,5 +57,17 @@ ifeq ($(CONFIG_ADD_XIZI_FETURES),y) SRC_FILES += test_rs485.c endif + ifeq ($(CONFIG_USER_TEST_HWTIMER),y) + SRC_FILES += test_hwtimer.c + endif + + ifeq ($(CONFIG_USER_TEST_LCD_EDU),y) + SRC_FILES += test_lcd_edu.c + endif + + ifeq ($(CONFIG_USER_TEST_WDT),y) + SRC_FILES += test_wdt.c + endif + include $(KERNEL_ROOT)/compiler.mk endif diff --git a/APP_Framework/Applications/app_test/test_hwtimer.c b/APP_Framework/Applications/app_test/test_hwtimer.c new file mode 100644 index 000000000..985d7fac7 --- /dev/null +++ b/APP_Framework/Applications/app_test/test_hwtimer.c @@ -0,0 +1,62 @@ +#include +#include +#include + +#define BSP_LED_PIN 29 +#define NULL_PARAMETER 0 + +static uint16_t pinval=0; + +void ledflip(void *parameter) +{ + int tmp_fd = *(int*)parameter; + struct PinStat pin_led; + pin_led.pin = BSP_LED_PIN; + pin_led.val = !pinval; + pinval = !pinval; + PrivWrite(tmp_fd,&pin_led,NULL_PARAMETER); + printf("Timer has callback once\n"); +} + +void TestHwTimer(int argc, char *argv[]) +{ + x_ticks_t period = 100;//uint:10ms + + if(argc>1){ + period = (x_ticks_t)atoi(argv[1]); + } + + + int pin_fd = PrivOpen(HWTIMER_PIN_DEV_DRIVER, O_RDWR); + if(pin_fd<0){ + printf("open pin fd error:%d\n",pin_fd); + return; + } + + //config led pin in board + struct PinParam parameter; + parameter.cmd = GPIO_CONFIG_MODE; + parameter.pin = BSP_LED_PIN; + parameter.mode = GPIO_CFG_OUTPUT; + + struct PrivIoctlCfg ioctl_cfg; + ioctl_cfg.ioctl_driver_type = PIN_TYPE; + ioctl_cfg.args = (void *)¶meter; + + if (0 != PrivIoctl(pin_fd, OPE_CFG, &ioctl_cfg)) { + printf("ioctl pin fd error %d\n", pin_fd); + PrivClose(pin_fd); + return; + } + + int32 timer_handle = KCreateTimer("LED on and off by 1s",&ledflip,&pin_fd,period,TIMER_TRIGGER_PERIODIC); + + KTimerStartRun(timer_handle); + PrivTaskDelay(10000); + KTimerQuitRun(timer_handle); + + KDeleteTimer(timer_handle); + +} + +PRIV_SHELL_CMD_FUNCTION(TestHwTimer, a timer test sample, PRIV_SHELL_CMD_MAIN_ATTR); \ No newline at end of file diff --git a/APP_Framework/Applications/app_test/test_i2c.c b/APP_Framework/Applications/app_test/test_i2c.c index 77a62c5f9..43a2f224a 100644 --- a/APP_Framework/Applications/app_test/test_i2c.c +++ b/APP_Framework/Applications/app_test/test_i2c.c @@ -2,10 +2,49 @@ #include #include +#define I2C_SLAVE_ADDRESS 0x0012U -void TestI2C(void) +void TestI2C(void) { - + // config IIC pin(SCL:34.SDA:35) in menuconfig + int iic_fd = PrivOpen(I2C_DEV_DRIVER, O_RDWR); + if (iic_fd < 0) + { + printf("open iic_fd fd error:%d\n", iic_fd); + return; + } + printf("IIC open successful!\n"); + + // init iic + uint16 iic_address = I2C_SLAVE_ADDRESS; + + struct PrivIoctlCfg ioctl_cfg; + ioctl_cfg.ioctl_driver_type = I2C_TYPE; + ioctl_cfg.args = (void *)&iic_address; + + if (0 != PrivIoctl(iic_fd, OPE_INT, &ioctl_cfg)) + { + printf("ioctl iic fd error %d\n", iic_fd); + PrivClose(iic_fd); + return; + } + printf("IIC configure successful!\n"); + + // I2C read and write + char tmp_buff[100]; + while (1) + { + PrivTaskDelay(1000); + PrivWrite(iic_fd, "Hello World!\n", sizeof("Hello World!\n")); + printf("msg send:%s\n", "Hello World!\n"); + PrivTaskDelay(1000); + memset(tmp_buff, 0, sizeof(tmp_buff)); + PrivRead(iic_fd, tmp_buff, sizeof(tmp_buff)); + printf("msg recv:%s\n", tmp_buff); + } + + PrivClose(iic_fd); + return; } PRIV_SHELL_CMD_FUNCTION(TestI2C, a iic test sample, PRIV_SHELL_CMD_MAIN_ATTR); diff --git a/APP_Framework/Applications/app_test/test_lcd_edu.c b/APP_Framework/Applications/app_test/test_lcd_edu.c new file mode 100644 index 000000000..0d87ef2ea --- /dev/null +++ b/APP_Framework/Applications/app_test/test_lcd_edu.c @@ -0,0 +1,50 @@ +#include +#include +#include + +#define GRAPHIC_CTRL_RECT_UPDATE 0x00 +#define LCD_STRING_TYPE 0 +#define LCD_DOT_TYPE 1 +#define LCD_FONT_RECT_WIDTH 150 +#define LCD_FONT_RECT_HEIGHT 50 +#define NULL_PARAMETER 0 + +void TestLcd(void) +{ + int lcd_fd = PrivOpen(EDU_LCD_DEV_DRIVER, O_RDWR); + if (lcd_fd < 0) + { + printf("open lcd fd error:%d\n", lcd_fd); + return; + } + + // draw text + LcdWriteParam graph_param; + graph_param.type = LCD_STRING_TYPE; + graph_param.string_info.x_pos = 0; + graph_param.string_info.y_pos = 0; + graph_param.string_info.width = 250; + graph_param.string_info.height = 24; + graph_param.string_info.font_size = 24; + graph_param.string_info.back_color = 0xFFFF; + graph_param.string_info.font_color = 0x0000; + graph_param.string_info.addr = "hello_world!"; + + PrivWrite(lcd_fd, &graph_param, NULL_PARAMETER); + + uint16 color_select = 0xF800; + for (int i = 0; i < 5; i++) + { + graph_param.type = LCD_DOT_TYPE; + graph_param.pixel_info.x_startpos = 0; + graph_param.pixel_info.y_startpos = 50 * i; + graph_param.pixel_info.x_endpos = 320; + graph_param.pixel_info.y_endpos = 50 * i; + graph_param.pixel_info.pixel_color = &color_select; + PrivWrite(lcd_fd, &graph_param, NULL_PARAMETER); + } + + PrivClose(lcd_fd); +} + +PRIV_SHELL_CMD_FUNCTION(TestLcd, a lcd test sample, PRIV_SHELL_CMD_MAIN_ATTR); \ No newline at end of file diff --git a/APP_Framework/Applications/app_test/test_rs485.c b/APP_Framework/Applications/app_test/test_rs485.c index 8b9fd5e1e..029c7d4b1 100644 --- a/APP_Framework/Applications/app_test/test_rs485.c +++ b/APP_Framework/Applications/app_test/test_rs485.c @@ -81,7 +81,6 @@ void Test485(void) PrivClose(pin_fd); PrivClose(uart_fd); return; - } PRIV_SHELL_CMD_FUNCTION(Test485, a RS485 test sample, PRIV_SHELL_CMD_MAIN_ATTR); \ No newline at end of file diff --git a/APP_Framework/Applications/app_test/test_wdt.c b/APP_Framework/Applications/app_test/test_wdt.c new file mode 100644 index 000000000..67195466d --- /dev/null +++ b/APP_Framework/Applications/app_test/test_wdt.c @@ -0,0 +1,45 @@ +#include +#include +#include + +void TestWDT(int argc, char *agrv[]) +{ + int wdt_fd = PrivOpen(WDT0_DEV_DRIVER, O_RDWR); + if (wdt_fd < 0) + { + printf("open wdt_fd fd error:%d\n", wdt_fd); + return; + } + printf("hw watchdog open!\n"); + + // init watchdog + int wdt_time = 1000; + + struct PrivIoctlCfg ioctl_cfg; + ioctl_cfg.ioctl_driver_type = WDT_TYPE; + ioctl_cfg.args = (void *)&wdt_time; + + if (0 != PrivIoctl(wdt_fd, OPER_WDT_SET_TIMEOUT, &ioctl_cfg)) + { + printf("ioctl wdt fd error %d\n", wdt_fd); + PrivClose(wdt_fd); + return; + } + + int test_counter = 100; + + // wdt feed or not according to argc,if argc!=1 then dog won't be feed + while (test_counter--) + { + if (1 == argc) + { + printf("dog is feed\n"); + PrivIoctl(wdt_fd, OPER_WDT_KEEPALIVE, &ioctl_cfg); // feed dog + } + PrivTaskDelay(100); + } + PrivClose(wdt_fd); + return; +} + +PRIV_SHELL_CMD_FUNCTION(TestWDT, a wdt test sample, PRIV_SHELL_CMD_MAIN_ATTR); \ No newline at end of file diff --git a/Ubiquitous/XiZi_IIoT/board/edu-riscv64/board.c b/Ubiquitous/XiZi_IIoT/board/edu-riscv64/board.c index 63351f357..0107071e8 100644 --- a/Ubiquitous/XiZi_IIoT/board/edu-riscv64/board.c +++ b/Ubiquitous/XiZi_IIoT/board/edu-riscv64/board.c @@ -46,6 +46,8 @@ Modification: #include "connect_gpio.h" #include "connect_soft_spi.h" #include "connect_rtc.h" +#include "connect_hwtimer.h" +#include "connect_wdt.h" // #if defined(FS_VFS) // #include @@ -188,9 +190,6 @@ struct InitSequenceDesc _board_init[] = #ifdef BSP_USING_RTC { "hw_rtc", HwRtcInit }, #endif -#ifdef BSP_USING_UART - { "hw_uart", HwUartInit }, -#endif #ifdef BSP_USING_SPI { "hw_spi", HwSpiInit }, #endif @@ -205,6 +204,12 @@ struct InitSequenceDesc _board_init[] = #endif #ifdef BSP_USING_SOFT_SPI {"soft_spi", HwSoftSPIInit }, +#endif +#ifdef BSP_USING_HWTIMER + {"hw_timer", HwTimerInit }, +#endif +#ifdef BSP_USING_WDT + {"hw_wdt", HwWdtInit }, #endif { " NONE ",NONE }, }; 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 ba7047a33..11ecca978 100755 --- a/Ubiquitous/XiZi_IIoT/board/edu-riscv64/third_party_driver/Kconfig +++ b/Ubiquitous/XiZi_IIoT/board/edu-riscv64/third_party_driver/Kconfig @@ -96,3 +96,19 @@ menuconfig BSP_USING_RTC if BSP_USING_RTC source "$BSP_DIR/third_party_driver/rtc/Kconfig" endif + +menuconfig BSP_USING_HWTIMER + bool "Using TIMER device" + default y + select RESOURCES_HWTIMER + if BSP_USING_HWTIMER + source "$BSP_DIR/third_party_driver/timer/Kconfig" + endif + +menuconfig BSP_USING_WDT + bool "Using WATCHDOG device" + default y + select RESOURCES_WDT + if BSP_USING_WDT + source "$BSP_DIR/third_party_driver/watchdog/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 b4ab9bb14..b8f466166 100644 --- a/Ubiquitous/XiZi_IIoT/board/edu-riscv64/third_party_driver/Makefile +++ b/Ubiquitous/XiZi_IIoT/board/edu-riscv64/third_party_driver/Makefile @@ -48,5 +48,13 @@ ifeq ($(CONFIG_BSP_USING_RTC),y) SRC_DIR += rtc endif +ifeq ($(CONFIG_BSP_USING_HWTIMER),y) + SRC_DIR += timer +endif + +ifeq ($(CONFIG_BSP_USING_WDT),y) + SRC_DIR += watchdog +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 1bd31c747..fa2b4617f 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 @@ -75,7 +75,7 @@ static struct io_config IOCONFIG(BSP_UART3_TXD_PIN, FUNC_UART3_RX), IOCONFIG(BSP_UART3_RXD_PIN, FUNC_UART3_TX), #endif -#ifdef BSP_USING_I2C1 +#ifdef BSP_USING_I2C IOCONFIG(BSP_I2C_SDA, FUNC_GPIO3), IOCONFIG(BSP_I2C_SCL, FUNC_GPIO4), #endif @@ -121,7 +121,6 @@ static struct io_config #ifdef BSP_USING_KEY IOCONFIG(BSP_KEY_PIN,FUNC_GPIO6); #endif - }; static int PrintIoConfig() diff --git a/Ubiquitous/XiZi_IIoT/board/edu-riscv64/third_party_driver/i2c/Kconfig b/Ubiquitous/XiZi_IIoT/board/edu-riscv64/third_party_driver/i2c/Kconfig index c93536961..da6562c44 100644 --- a/Ubiquitous/XiZi_IIoT/board/edu-riscv64/third_party_driver/i2c/Kconfig +++ b/Ubiquitous/XiZi_IIoT/board/edu-riscv64/third_party_driver/i2c/Kconfig @@ -12,6 +12,6 @@ if BSP_USING_I2C string "i2c bus 1 driver name" default "i2c1_drv" config I2C_1_DEVICE_NAME_0 - string "i2c bus 1 device 0 name" - default "i2c1_dev0" + string "i2c bus 1 device 0 name" + default "i2c1_dev0" endif diff --git a/Ubiquitous/XiZi_IIoT/board/edu-riscv64/third_party_driver/include/connect_hwtimer.h b/Ubiquitous/XiZi_IIoT/board/edu-riscv64/third_party_driver/include/connect_hwtimer.h new file mode 100644 index 000000000..cb0a99eda --- /dev/null +++ b/Ubiquitous/XiZi_IIoT/board/edu-riscv64/third_party_driver/include/connect_hwtimer.h @@ -0,0 +1,37 @@ +/* +* 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_hwtimer.h +* @brief define aiit-riscv64-board hwtimer function and struct +* @version 1.0 +* @author AIIT XUOS Lab +* @date 2021-04-25 +*/ + +#ifndef CONNECT_HWTIMER_H +#define CONNECT_HWTIMER_H + +#include +#include "hardware_hwtimer.h" + +#ifdef __cplusplus +extern "C" { +#endif + +int HwTimerInit(void); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Ubiquitous/XiZi_IIoT/board/edu-riscv64/third_party_driver/include/connect_wdt.h b/Ubiquitous/XiZi_IIoT/board/edu-riscv64/third_party_driver/include/connect_wdt.h new file mode 100644 index 000000000..96cdb3e0e --- /dev/null +++ b/Ubiquitous/XiZi_IIoT/board/edu-riscv64/third_party_driver/include/connect_wdt.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_wdt.h +* @brief define aiit-riscv64-board wdt function and struct +* @version 1.0 +* @author AIIT XUOS Lab +* @date 2021-04-25 +*/ + +#ifndef CONNECT_WDT_H +#define CONNECT_WDT_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +int HwWdtInit(void); + +#ifdef __cplusplus +} +#endif + +#endif \ No newline at end of file diff --git a/Ubiquitous/XiZi_IIoT/board/edu-riscv64/third_party_driver/include/hardware_hwtimer.h b/Ubiquitous/XiZi_IIoT/board/edu-riscv64/third_party_driver/include/hardware_hwtimer.h new file mode 100644 index 000000000..57ac51a3c --- /dev/null +++ b/Ubiquitous/XiZi_IIoT/board/edu-riscv64/third_party_driver/include/hardware_hwtimer.h @@ -0,0 +1,171 @@ +/* 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_hwtimer.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_HWTIMER_H__ +#define __HARDWARE_HWTIMER_H__ + +#include +#include +#ifdef __cplusplus +extern "C" { +#endif + +/* clang-format off */ +typedef struct _timer_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))) timer_channel_t; + +typedef struct _kendryte_timer +{ + /* TIMER_N Register (0x00-0x4c) */ + volatile timer_channel_t channel[4]; + /* 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))) kendryte_timer_t; + +typedef enum _timer_deivce_number +{ + TIMER_DEVICE_0, + TIMER_DEVICE_1, + TIMER_DEVICE_2, + TIMER_DEVICE_MAX, +} timer_device_number_t; + +typedef enum _timer_channel_number +{ + TIMER_CHANNEL_0, + TIMER_CHANNEL_1, + TIMER_CHANNEL_2, + TIMER_CHANNEL_3, + TIMER_CHANNEL_MAX, +} timer_channel_number_t; + +/* 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 +/* clang-format on */ + +extern volatile kendryte_timer_t *const timer[3]; + +/** + * @brief Definitions for the timer callbacks + */ +typedef int (*timer_callback_t)(void *ctx); + +/** + * @brief Set timer timeout + * + * @param[in] timer timer + * @param[in] channel channel + * @param[in] nanoseconds timeout + * + * @return the real timeout + */ +size_t timer_set_interval(timer_device_number_t timer_number, timer_channel_number_t channel, size_t nanoseconds); + +/** + * @brief Init timer + * + * @param[in] timer timer + */ +void timer_init(timer_device_number_t timer_number); + +/** + * @brief [DEPRECATED] Set timer timeout function + * + * @param[in] timer timer + * @param[in] channel channel + * @param[in] func timeout function + * @param[in] priority interrupt priority + * + */ +void timer_set_irq(timer_device_number_t timer_number, timer_channel_number_t channel, void(*func)(), uint32_t priority); + +/** + * @brief Register timer interrupt user callback function + * + * @param[in] device The timer device number + * @param[in] channel The channel + * @param[in] is_one_shot Indicates if single shot + * @param[in] priority The priority + * @param[in] callback The callback function + * @param[in] ctx The context + * + * @return result + * - 0 Success + * - Other Fail + */ +int timer_irq_register(timer_device_number_t device, timer_channel_number_t channel, int is_single_shot, uint32_t priority, timer_callback_t callback, void *ctx); + +/** + * @brief Deregister timer interrupt user callback function + * + * @param[in] device The timer device number + * @param[in] channel The channel + * + * @return result + * - 0 Success + * - Other Fail + */ +int timer_irq_unregister(timer_device_number_t device, timer_channel_number_t channel); + +/** + * @brief Enable timer + * + * @param[in] timer timer + * @param[in] channel channel + * @param[in] enable Enable or disable + * + */ +void timer_set_enable(timer_device_number_t timer_number, timer_channel_number_t channel, uint32_t enable); + +#ifdef __cplusplus +} +#endif + +#endif /* __TIMER_H__ */ diff --git a/Ubiquitous/XiZi_IIoT/board/edu-riscv64/third_party_driver/include/wdt.h b/Ubiquitous/XiZi_IIoT/board/edu-riscv64/third_party_driver/include/wdt.h new file mode 100644 index 000000000..cd7fc49eb --- /dev/null +++ b/Ubiquitous/XiZi_IIoT/board/edu-riscv64/third_party_driver/include/wdt.h @@ -0,0 +1,180 @@ +/* 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 wdt.h +* @brief add from Canaan k210 SDK +* https://canaan-creative.com/developer +* @version 1.0 +* @author AIIT XUOS Lab +* @date 2021-04-25 +*/ + +#ifndef __WDT_H__ +#define __WDT_H__ + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* clang-format off */ +typedef struct _wdt +{ + /* WDT Control Register (0x00) */ + volatile uint32_t cr; + /* WDT Timeout Range Register (0x04) */ + volatile uint32_t torr; + /* WDT Current Counter Value Register (0x08) */ + volatile uint32_t ccvr; + /* WDT Counter Restart Register (0x0c) */ + volatile uint32_t crr; + /* WDT Interrupt Status Register (0x10) */ + volatile uint32_t stat; + /* WDT Interrupt Clear Register (0x14) */ + volatile uint32_t eoi; + /* reserverd (0x18) */ + volatile uint32_t resv1; + /* WDT Protection level Register (0x1c) */ + volatile uint32_t prot_level; + /* reserved (0x20-0xe0) */ + volatile uint32_t resv4[49]; + /* WDT Component Parameters Register 5 (0xe4) */ + volatile uint32_t comp_param_5; + /* WDT Component Parameters Register 4 (0xe8) */ + volatile uint32_t comp_param_4; + /* WDT Component Parameters Register 3 (0xec) */ + volatile uint32_t comp_param_3; + /* WDT Component Parameters Register 2 (0xf0) */ + volatile uint32_t comp_param_2; + /* WDT Component Parameters Register 1 (0xf4) */ + volatile uint32_t comp_param_1; + /* WDT Component Version Register (0xf8) */ + volatile uint32_t comp_version; + /* WDT Component Type Register (0xfc) */ + volatile uint32_t comp_type; +} __attribute__((packed, aligned(4))) wdt_t; + +typedef enum _wdt_device_number +{ + WDT_DEVICE_0, + WDT_DEVICE_1, + WDT_DEVICE_MAX, +} wdt_device_number_t; + + +#define WDT_RESET_ALL 0x00000000U +#define WDT_RESET_CPU 0x00000001U + +/* WDT Control Register */ +#define WDT_CR_ENABLE 0x00000001U +#define WDT_CR_RMOD_MASK 0x00000002U +#define WDT_CR_RMOD_RESET 0x00000000U +#define WDT_CR_RMOD_INTERRUPT 0x00000002U +#define WDT_CR_RPL_MASK 0x0000001CU +#define WDT_CR_RPL(x) ((x) << 2) +/* WDT Timeout Range Register */ +#define WDT_TORR_TOP_MASK 0x000000FFU +#define WDT_TORR_TOP(x) ((x) << 4 | (x) << 0) +/* WDT Current Counter Value Register */ +#define WDT_CCVR_MASK 0xFFFFFFFFU +/* WDT Counter Restart Register */ +#define WDT_CRR_MASK 0x00000076U +/* WDT Interrupt Status Register */ +#define WDT_STAT_MASK 0x00000001U +/* WDT Interrupt Clear Register */ +#define WDT_EOI_MASK 0x00000001U +/* WDT Protection level Register */ +#define WDT_PROT_LEVEL_MASK 0x00000007U +/* WDT Component Parameter Register 5 */ +#define WDT_COMP_PARAM_5_CP_WDT_USER_TOP_MAX_MASK 0xFFFFFFFFU +/* WDT Component Parameter Register 4 */ +#define WDT_COMP_PARAM_4_CP_WDT_USER_TOP_INIT_MAX_MASK 0xFFFFFFFFU +/* WDT Component Parameter Register 3 */ +#define WDT_COMP_PARAM_3_CD_WDT_TOP_RST_MASK 0xFFFFFFFFU +/* WDT Component Parameter Register 2 */ +#define WDT_COMP_PARAM_3_CP_WDT_CNT_RST_MASK 0xFFFFFFFFU +/* WDT Component Parameter Register 1 */ +#define WDT_COMP_PARAM_1_WDT_ALWAYS_EN_MASK 0x00000001U +#define WDT_COMP_PARAM_1_WDT_DFLT_RMOD_MASK 0x00000002U +#define WDT_COMP_PARAM_1_WDT_DUAL_TOP_MASK 0x00000004U +#define WDT_COMP_PARAM_1_WDT_HC_RMOD_MASK 0x00000008U +#define WDT_COMP_PARAM_1_WDT_HC_RPL_MASK 0x00000010U +#define WDT_COMP_PARAM_1_WDT_HC_TOP_MASK 0x00000020U +#define WDT_COMP_PARAM_1_WDT_USE_FIX_TOP_MASK 0x00000040U +#define WDT_COMP_PARAM_1_WDT_PAUSE_MASK 0x00000080U +#define WDT_COMP_PARAM_1_APB_DATA_WIDTH_MASK 0x00000300U +#define WDT_COMP_PARAM_1_WDT_DFLT_RPL_MASK 0x00001C00U +#define WDT_COMP_PARAM_1_WDT_DFLT_TOP_MASK 0x000F0000U +#define WDT_COMP_PARAM_1_WDT_DFLT_TOP_INIT_MASK 0x00F00000U +#define WDT_COMP_PARAM_1_WDT_CNT_WIDTH_MASK 0x1F000000U +/* WDT Component Version Register */ +#define WDT_COMP_VERSION_MASK 0xFFFFFFFFU +/* WDT Component Type Register */ +#define WDT_COMP_TYPE_MASK 0xFFFFFFFFU +/* clang-format on */ + +/** + * @brief Feed wdt + */ +void wdt_feed(wdt_device_number_t id); + +/** + * @brief Start wdt + * + * @param[in] id Wdt id 0 or 1 + * @param[in] time_out_ms Wdt trigger time + * @param[in] on_irq Wdt interrupt callback + * + */ +void wdt_start(wdt_device_number_t id, uint64_t time_out_ms, plic_irq_callback_t on_irq); + +/** + * @brief Start wdt + * + * @param[in] id Wdt id 0 or 1 + * @param[in] time_out_ms Wdt trigger time + * @param[in] on_irq Wdt interrupt callback + * @param[in] ctx Param of callback + * + * @return Wdt time + * + */ +uint32_t wdt_init(wdt_device_number_t id, uint64_t time_out_ms, plic_irq_callback_t on_irq, void *ctx); + +/** + * @brief Stop wdt + * + * @param[in] id Wdt id 0 or 1 + * + */ +void wdt_stop(wdt_device_number_t id); + +/** + * @brief Clear wdt interrupt + * + * @param[in] id Wdt id 0 or 1 + * + */ +void wdt_clear_interrupt(wdt_device_number_t id); + +#ifdef __cplusplus +} +#endif + +#endif /* __WDT_H__ */ diff --git a/Ubiquitous/XiZi_IIoT/board/edu-riscv64/third_party_driver/timer/Kconfig b/Ubiquitous/XiZi_IIoT/board/edu-riscv64/third_party_driver/timer/Kconfig new file mode 100644 index 000000000..fdc67b1ac --- /dev/null +++ b/Ubiquitous/XiZi_IIoT/board/edu-riscv64/third_party_driver/timer/Kconfig @@ -0,0 +1,19 @@ +if BSP_USING_HWTIMER + config HWTIMER_BUS_NAME_1 + string "hwtimer bus name" + default "hwtim1" + + menuconfig ENABLE_TIM1 + bool "enable TIM1" + default y + + if ENABLE_TIM1 + config HWTIMER_1_DEVICE_NAME_1 + string "TIM1 dev name" + default "hwtim1_dev1" + + config HWTIMER_DRIVER_NAME_1 + string "TIM1 drv name" + default "hwtim1_drv" + endif +endif diff --git a/Ubiquitous/XiZi_IIoT/board/edu-riscv64/third_party_driver/timer/Makefile b/Ubiquitous/XiZi_IIoT/board/edu-riscv64/third_party_driver/timer/Makefile new file mode 100644 index 000000000..24d4ccfac --- /dev/null +++ b/Ubiquitous/XiZi_IIoT/board/edu-riscv64/third_party_driver/timer/Makefile @@ -0,0 +1,5 @@ +SRC_FILES := hardware_hwtimer.c connect_hwtimer.c + + + +include $(KERNEL_ROOT)/compiler.mk diff --git a/Ubiquitous/XiZi_IIoT/board/edu-riscv64/third_party_driver/timer/connect_hwtimer.c b/Ubiquitous/XiZi_IIoT/board/edu-riscv64/third_party_driver/timer/connect_hwtimer.c new file mode 100644 index 000000000..7a7d23c08 --- /dev/null +++ b/Ubiquitous/XiZi_IIoT/board/edu-riscv64/third_party_driver/timer/connect_hwtimer.c @@ -0,0 +1,153 @@ +/* +* 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_hwtimer.c +* @brief support aiit-riscv64-board hwtimer function and register to bus framework +* @version 1.0 +* @author AIIT XUOS Lab +* @date 2021-04-25 +*/ + +#include +#include +#include +#include +#include +#include +#include + +static struct HwtimerCallBackInfo *ptim2_cb_info = NULL; + +int timer_callback(void *ctx) +{ + if (ptim2_cb_info) { + if (ptim2_cb_info->timeout_callback) { + ptim2_cb_info->timeout_callback(ptim2_cb_info->param); + } + } + return 0; +} + +uint32 HwtimerOpen(void *dev) +{ + struct HwtimerHardwareDevice *hwtimer_dev = dev; + + ptim2_cb_info = &hwtimer_dev->hwtimer_param.cb_info; + + plic_init(); + sysctl_enable_irq(); + timer_init(TIMER_DEVICE_1); + + size_t real_time = timer_set_interval(TIMER_DEVICE_1, TIMER_CHANNEL_1, hwtimer_dev->hwtimer_param.period_millisecond *1000); + KPrintf("timer_set_interval -- real_time : %ld\n", real_time); + timer_irq_register(TIMER_DEVICE_1, TIMER_CHANNEL_1, !hwtimer_dev->hwtimer_param.repeat, 1, timer_callback, NULL); + + timer_set_enable(TIMER_DEVICE_1, TIMER_CHANNEL_1, 1); + + return EOK; +} + +uint32 HwtimerClose(void *dev) +{ + timer_set_enable(TIMER_DEVICE_1, TIMER_CHANNEL_1, 0); + + return EOK; +} + +/*manage the hwtimer device operations*/ +static const struct HwtimerDevDone dev_done = +{ + .open = HwtimerOpen, + .close = HwtimerClose, + .write = NONE, + .read = NONE, +}; + +/*Init hwtimer bus*/ +static int BoardHwtimerBusInit(struct HwtimerBus *hwtimer_bus, struct HwtimerDriver *hwtimer_driver) +{ + x_err_t ret = EOK; + + /*Init the hwtimer bus */ + ret = HwtimerBusInit(hwtimer_bus, HWTIMER_BUS_NAME_1); + if (EOK != ret) { + KPrintf("board_hwtimer_init HwtimerBusInit error %d\n", ret); + return ERROR; + } + + /*Init the hwtimer driver*/ + hwtimer_driver->configure = NONE; + ret = HwtimerDriverInit(hwtimer_driver, HWTIMER_DRIVER_NAME_1); + if (EOK != ret) { + KPrintf("board_hwtimer_init HwtimerDriverInit error %d\n", ret); + return ERROR; + } + + /*Attach the hwtimer driver to the hwtimer bus*/ + ret = HwtimerDriverAttachToBus(HWTIMER_DRIVER_NAME_1, HWTIMER_BUS_NAME_1); + if (EOK != ret) { + KPrintf("board_hwtimer_init USEDriverAttachToBus error %d\n", ret); + return ERROR; + } + + return ret; +} + +/*Attach the hwtimer device to the hwtimer bus*/ +static int BoardHwtimerDevBend(void) +{ + x_err_t ret = EOK; + static struct HwtimerHardwareDevice hwtimer_device_0; + memset(&hwtimer_device_0, 0, sizeof(struct HwtimerHardwareDevice)); + + hwtimer_device_0.dev_done = &dev_done; + + ret = HwtimerDeviceRegister(&hwtimer_device_0, NONE, HWTIMER_1_DEVICE_NAME_1); + if (EOK != ret) { + KPrintf("BoardHwtimerDevBend HwtimerDeviceRegister device %s error %d\n", HWTIMER_1_DEVICE_NAME_1, ret); + return ERROR; + } + + ret = HwtimerDeviceAttachToBus(HWTIMER_1_DEVICE_NAME_1, HWTIMER_BUS_NAME_1); + if (EOK != ret) { + KPrintf("BoardHwtimerDevBend HwtimerDeviceAttachToBus device %s error %d\n", HWTIMER_1_DEVICE_NAME_1, ret); + return ERROR; + } + + return ret; +} + +/*K210 BOARD HWTIMER INIT*/ +int HwTimerInit(void) +{ + x_err_t ret = EOK; + static struct HwtimerBus hwtimer_bus; + memset(&hwtimer_bus, 0, sizeof(struct HwtimerBus)); + + static struct HwtimerDriver hwtimer_driver; + memset(&hwtimer_driver, 0, sizeof(struct HwtimerDriver)); + + ret = BoardHwtimerBusInit(&hwtimer_bus, &hwtimer_driver); + if (EOK != ret) { + KPrintf("board_hwtimer_Init error ret %u\n", ret); + return ERROR; + } + + ret = BoardHwtimerDevBend(); + if (EOK != ret) { + KPrintf("board_hwtimer_Init error ret %u\n", ret); + return ERROR; + } + + return ret; +} diff --git a/Ubiquitous/XiZi_IIoT/board/edu-riscv64/third_party_driver/timer/hardware_hwtimer.c b/Ubiquitous/XiZi_IIoT/board/edu-riscv64/third_party_driver/timer/hardware_hwtimer.c new file mode 100644 index 000000000..62fcd84ac --- /dev/null +++ b/Ubiquitous/XiZi_IIoT/board/edu-riscv64/third_party_driver/timer/hardware_hwtimer.c @@ -0,0 +1,407 @@ +/* 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_hwtimer.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 +#include +#include + +/** + * @brief Private definitions for the timer instance + */ +typedef struct timer_instance +{ + timer_callback_t callback; + void *ctx; + bool single_shot; +} timer_instance_t; + +typedef void(*irq_manager_callback_t)(int irq, void* arg); + +volatile timer_instance_t timer_instance[TIMER_DEVICE_MAX][TIMER_CHANNEL_MAX]; + +volatile kendryte_timer_t *const timer[3] = +{ + (volatile kendryte_timer_t *)TIMER0_BASE_ADDR, + (volatile kendryte_timer_t *)TIMER1_BASE_ADDR, + (volatile kendryte_timer_t *)TIMER2_BASE_ADDR +}; + +void timer_init(timer_device_number_t timer_number) +{ + for(size_t i = 0; i < TIMER_CHANNEL_MAX; i++) + timer_instance[timer_number][i] = (const timer_instance_t) { + .callback = NULL, + .ctx = NULL, + .single_shot = 0, + }; + + sysctl_clock_enable(SYSCTL_CLOCK_TIMER0 + timer_number); +} + +void timer_set_clock_div(timer_device_number_t timer_number, uint32_t div) +{ + sysctl_clock_set_threshold(timer_number == 0 ? SYSCTL_THRESHOLD_TIMER0 : + timer_number == 1 ? SYSCTL_THRESHOLD_TIMER1 : + SYSCTL_THRESHOLD_TIMER2, div); +} + +void timer_enable(timer_device_number_t timer_number, timer_channel_number_t channel) +{ + timer[timer_number]->channel[channel].control |= TIMER_CR_ENABLE; +} + +void timer_disable(timer_device_number_t timer_number, timer_channel_number_t channel) +{ + timer[timer_number]->channel[channel].control &= (~TIMER_CR_ENABLE); +} + +void timer_enable_pwm(timer_device_number_t timer_number, timer_channel_number_t channel) +{ + timer[timer_number]->channel[channel].control |= TIMER_CR_PWM_ENABLE; +} + +void timer_disable_pwm(timer_device_number_t timer_number, timer_channel_number_t channel) +{ + timer[timer_number]->channel[channel].control &= (~TIMER_CR_PWM_ENABLE); +} + +void timer_enable_interrupt(timer_device_number_t timer_number, timer_channel_number_t channel) +{ + timer[timer_number]->channel[channel].control &= (~TIMER_CR_INTERRUPT_MASK); +} + +void timer_disable_interrupt(timer_device_number_t timer_number, timer_channel_number_t channel) +{ + timer[timer_number]->channel[channel].control |= TIMER_CR_INTERRUPT_MASK; +} + +void timer_set_mode(timer_device_number_t timer_number, timer_channel_number_t channel, uint32_t mode) +{ + timer[timer_number]->channel[channel].control &= (~TIMER_CR_MODE_MASK); + timer[timer_number]->channel[channel].control |= mode; +} + +void timer_set_reload(timer_device_number_t timer_number, timer_channel_number_t channel, uint32_t count) +{ + timer[timer_number]->channel[channel].load_count = count; +} + +void timer_set_reload2(timer_device_number_t timer_number, timer_channel_number_t channel, uint32_t count) +{ + timer[timer_number]->load_count2[channel] = count; +} + +uint32_t timer_get_count(timer_device_number_t timer_number, timer_channel_number_t channel) +{ + return timer[timer_number]->channel[channel].current_value; +} + +uint32_t timer_get_reload(timer_device_number_t timer_number, timer_channel_number_t channel) +{ + return timer[timer_number]->channel[channel].load_count; +} + +uint32_t timer_get_reload2(timer_device_number_t timer_number, timer_channel_number_t channel) +{ + return timer[timer_number]->load_count2[channel]; +} + +uint32_t timer_get_interrupt_status(timer_device_number_t timer_number) +{ + return timer[timer_number]->intr_stat; +} + +uint32_t timer_get_raw_interrupt_status(timer_device_number_t timer_number) +{ + return timer[timer_number]->raw_intr_stat; +} + +uint32_t timer_channel_get_interrupt_status(timer_device_number_t timer_number, timer_channel_number_t channel) +{ + return timer[timer_number]->channel[channel].intr_stat; +} + +void timer_clear_interrupt(timer_device_number_t timer_number) +{ + timer[timer_number]->eoi = timer[timer_number]->eoi; +} + +void timer_channel_clear_interrupt(timer_device_number_t timer_number, timer_channel_number_t channel) +{ + timer[timer_number]->channel[channel].eoi = timer[timer_number]->channel[channel].eoi; +} + +void timer_set_enable(timer_device_number_t timer_number, timer_channel_number_t channel, uint32_t enable) +{ + if (enable) + timer[timer_number]->channel[channel].control = TIMER_CR_USER_MODE | TIMER_CR_ENABLE; + else + timer[timer_number]->channel[channel].control = TIMER_CR_INTERRUPT_MASK; +} + +size_t timer_set_interval(timer_device_number_t timer_number, timer_channel_number_t channel, size_t useconds) +{ + uint32_t clk_freq = SysctlClockGetFreq(SYSCTL_CLOCK_TIMER0 + timer_number); + + double min_step = 1e6 / clk_freq; + size_t value = (size_t)(useconds / min_step); + configASSERT(value > 0 && value < UINT32_MAX); + timer[timer_number]->channel[channel].load_count = (uint32_t)value; + return (size_t)(min_step * value); +} + +typedef void(*timer_ontick)(); +timer_ontick time_irq[3][4] = { NULL }; + +static int timer_isr(void *parm) +{ + uint32_t timer_number; + for (timer_number = 0; timer_number < 3; timer_number++) + { + if (parm == timer[timer_number]) + break; + } + + uint32_t channel = timer[timer_number]->intr_stat; + size_t i = 0; + for (i = 0; i < 4; i++) + { + if (channel & 1) + { + if (time_irq[timer_number][i]) + (time_irq[timer_number][i])(); + break; + } + + channel >>= 1; + } + + readl(&timer[timer_number]->eoi); + return 0; +} + +void timer_set_irq(timer_device_number_t timer_number, timer_channel_number_t channel, void(*func)(), uint32_t priority) +{ + time_irq[timer_number][channel] = func; + if (channel < 2) + { + plic_set_priority(IRQN_TIMER0A_INTERRUPT + timer_number * 2, priority); + plic_irq_register(IRQN_TIMER0A_INTERRUPT + timer_number * 2, timer_isr, (void *)timer[timer_number]); + plic_irq_enable(IRQN_TIMER0A_INTERRUPT + timer_number * 2); + } + else + { + plic_set_priority(IRQN_TIMER0B_INTERRUPT + timer_number * 2, priority); + plic_irq_register(IRQN_TIMER0B_INTERRUPT + timer_number * 2, timer_isr, (void *)timer[timer_number]); + plic_irq_enable(IRQN_TIMER0B_INTERRUPT + timer_number * 2); + } +} + +/** + * @brief Get the timer irqn by device and channel object + * + * @note Internal function, not public + * @param device The device + * @param channel The channel + * @return plic_irq_t IRQ number + */ +static plic_irq_t get_timer_irqn_by_device_and_channel(timer_device_number_t device, timer_channel_number_t channel) +{ + if (device < TIMER_DEVICE_MAX && channel < TIMER_CHANNEL_MAX) { + /* + * Select timer interrupt part + * Hierarchy of Timer interrupt to PLIC + * +---------+ +-----------+ + * | 0+----+ | | + * | | +--+0A | + * | 1+----+ | | + * | TIMER0 | | | + * | 2+----+ | | + * | | +--+0B | + * | 3+----+ | | + * +---------+ | | + * | | + * +---------+ | | + * | 0+----+ | | + * | | +--+1A | + * | 1+----+ | | + * | TIMER1 | | PLIC | + * | 2+----+ | | + * | | +--+1B | + * | 3+----+ | | + * +---------+ | | + * | | + * +---------+ | | + * | 0+----+ | | + * | | +--+2A | + * | 1+----+ | | + * | TIMER2 | | | + * | 2+----+ | | + * | | +--+2B | + * | 3+----+ | | + * +---------+ +-----------+ + * + */ + if (channel < 2) { + /* It is part A interrupt, offset + 0 */ + return IRQN_TIMER0A_INTERRUPT + device * 2; + } + else { + /* It is part B interrupt, offset + 1 */ + return IRQN_TIMER0B_INTERRUPT + device * 2; + } + } + return IRQN_NO_INTERRUPT; +} + +/** + * @brief Process user callback function + * + * @note Internal function, not public + * @param device The timer device + * @param ctx The context + * @return int The callback result + */ +static int timer_interrupt_handler(timer_device_number_t device, void *ctx) +{ + uint32_t channel_int_stat = timer[device]->intr_stat; + + for (size_t i = 0; i < TIMER_CHANNEL_MAX; i++) + { + /* Check every bit for interrupt status */ + if (channel_int_stat & 1) + { + if (timer_instance[device][i].callback) { + /* Process user callback function */ + timer_instance[device][i].callback(timer_instance[device][i].ctx); + /* Check if this timer is a single shot timer */ + if (timer_instance[device][i].single_shot) { + /* Single shot timer, disable it */ + timer_set_enable(device, i, 0); + } + } + /* Clear timer interrupt flag for specific channel */ + readl(&timer[device]->channel[i].eoi); + } + channel_int_stat >>= 1; + } + + /* + * NOTE: + * Don't read timer[device]->eoi here, or you will lost some interrupt + * readl(&timer[device]->eoi); + */ + + return 0; +} + +/** + * @brief Callback function bus for timer interrupt + * + * @note Internal function, not public + * @param ctx The context + * @return int The callback result + */ +static void timer0_interrupt_callback(int irq, void *ctx) +{ + timer_interrupt_handler(TIMER_DEVICE_0, ctx); +} + +/** + * @brief Callback function bus for timer interrupt + * + * @note Internal function, not public + * @param ctx The context + * @return int The callback result + */ +static void timer1_interrupt_callback(int irq, void *ctx) +{ + timer_interrupt_handler(TIMER_DEVICE_1, ctx); +} + +/** + * @brief Callback function bus for timer interrupt + * + * @note Internal function, not public + * @param ctx The context + * @return int The callback result + */ +static void timer2_interrupt_callback(int irq, void *ctx) +{ + timer_interrupt_handler(TIMER_DEVICE_2, ctx); +} + +int timer_irq_register(timer_device_number_t device, timer_channel_number_t channel, int is_single_shot, uint32_t priority, timer_callback_t callback, void *ctx) +{ + if (device < TIMER_DEVICE_MAX && channel < TIMER_CHANNEL_MAX) { + plic_irq_t irq_number = get_timer_irqn_by_device_and_channel(device, channel); + irq_manager_callback_t plic_irq_callback[TIMER_DEVICE_MAX] = { + timer0_interrupt_callback, + timer1_interrupt_callback, + timer2_interrupt_callback, + }; + + timer_instance[device][channel] = (const timer_instance_t) { + .callback = callback, + .ctx = ctx, + .single_shot = is_single_shot, + }; + + // plic_set_priority(irq_number, priority); + // plic_irq_register(irq_number, plic_irq_callback[device], (void *)&timer_instance[device]); + // plic_irq_enable(irq_number); + + isrManager.done->registerIrq(irq_number, plic_irq_callback[device], NULL); + isrManager.done->enableIrq(irq_number); + return 0; + } + return -1; +} + +int timer_irq_unregister(timer_device_number_t device, timer_channel_number_t channel) +{ + if (device < TIMER_DEVICE_MAX && channel < TIMER_CHANNEL_MAX) { + timer_instance[device][channel] = (const timer_instance_t) { + .callback = NULL, + .ctx = NULL, + .single_shot = 0, + }; + + /* Combine 0 and 1 to A interrupt, 2 and 3 to B interrupt */ + if ((!(timer_instance[device][TIMER_CHANNEL_0].callback || + timer_instance[device][TIMER_CHANNEL_1].callback)) || + (!(timer_instance[device][TIMER_CHANNEL_2].callback || + timer_instance[device][TIMER_CHANNEL_3].callback))) { + plic_irq_t irq_number = get_timer_irqn_by_device_and_channel(device, channel); + plic_irq_unregister(irq_number); + } + return 0; + } + return -1; +} \ No newline at end of file diff --git a/Ubiquitous/XiZi_IIoT/board/edu-riscv64/third_party_driver/watchdog/Kconfig b/Ubiquitous/XiZi_IIoT/board/edu-riscv64/third_party_driver/watchdog/Kconfig new file mode 100644 index 000000000..e801fa0ea --- /dev/null +++ b/Ubiquitous/XiZi_IIoT/board/edu-riscv64/third_party_driver/watchdog/Kconfig @@ -0,0 +1,34 @@ +menuconfig BSP_USING_WDT0 +bool "Using watchdog 0 " +default n +if BSP_USING_WDT0 +config WDT_BUS_NAME_0 + string "watchdog bus 0 name" + default "wdt0" + +config WDT_DRIVER_NAME_0 + string "watchdog driver 0 name" + default "wdt0_drv" + +config WDT_0_DEVICE_NAME_0 + string "watchdog device 0 name" + default "wdt0_dev0" +endif + +menuconfig BSP_USING_WDT1 +bool "Using watchdog 1 " +default n +if BSP_USING_WDT1 +config WDT_BUS_NAME_1 + string "watchdog bus 1 name" + default "wdt1" + +config WDT_DRIVER_NAME_1 + string "watchdog driver 1 name" + default "wdt1_drv" + +config WDT_1_DEVICE_NAME_1 + string "watchdog device 1 name" + default "wdt1_dev1" +endif + diff --git a/Ubiquitous/XiZi_IIoT/board/edu-riscv64/third_party_driver/watchdog/Makefile b/Ubiquitous/XiZi_IIoT/board/edu-riscv64/third_party_driver/watchdog/Makefile new file mode 100644 index 000000000..c4842fd3a --- /dev/null +++ b/Ubiquitous/XiZi_IIoT/board/edu-riscv64/third_party_driver/watchdog/Makefile @@ -0,0 +1,6 @@ +SRC_FILES := wdt.c connect_wdt.c + + + + +include $(KERNEL_ROOT)/compiler.mk diff --git a/Ubiquitous/XiZi_IIoT/board/edu-riscv64/third_party_driver/watchdog/connect_wdt.c b/Ubiquitous/XiZi_IIoT/board/edu-riscv64/third_party_driver/watchdog/connect_wdt.c new file mode 100644 index 000000000..30ac2630e --- /dev/null +++ b/Ubiquitous/XiZi_IIoT/board/edu-riscv64/third_party_driver/watchdog/connect_wdt.c @@ -0,0 +1,176 @@ +/* +* 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_wdt.c +* @brief support aiit-riscv64-board watchdog function and register to bus framework +* @version 1.0 +* @author AIIT XUOS Lab +* @date 2021-04-25 +*/ + +#include +#include + +static uint32 WdtOpen(void *dev) +{ + NULL_PARAM_CHECK(dev); + + wdt_device_number_t id; + struct WdtHardwareDevice *wdt = (struct WdtHardwareDevice *)dev; + id = *(wdt_device_number_t *)wdt->private_data; + + wdt_init(id, 4095, NONE, NONE); + return EOK; +} + +static uint32 WdtConfigure(void *drv, struct BusConfigureInfo *args) +{ + NULL_PARAM_CHECK(drv); + NULL_PARAM_CHECK(args); + + struct WdtDriver *wdt = (struct WdtDriver *)drv; + wdt_device_number_t id = *(wdt_device_number_t *)wdt->private_data; + + switch (args->configure_cmd) + { + case OPER_WDT_SET_TIMEOUT: + if (wdt_init(id, (uint64_t)*(int *)args->private_data, NONE, NONE) == 0) { + return ERROR; + } + break; + case OPER_WDT_KEEPALIVE: + wdt_feed(id); + break; + default: + return ERROR; + } + return EOK; +} + +static const struct WdtDevDone dev_done = +{ + WdtOpen, + NONE, + NONE, + NONE, +}; + +/** + * @description: Watchdog function + * @return success: EOK, failure: other + */ +int StartWatchdog(void) +{ + //add feed watchdog task function + + return EOK; +} + +int HwWdtInit(void) +{ + wdt_device_number_t id; + + x_err_t ret = EOK; + +#ifdef BSP_USING_WDT0 + { + static struct WdtBus wdt0; + + ret = WdtBusInit(&wdt0, WDT_BUS_NAME_0); + if (ret != EOK) { + KPrintf("Watchdog bus init error %d\n", ret); + return ERROR; + } + + static struct WdtDriver drv0; + drv0.configure = WdtConfigure; + id = WDT_DEVICE_0; + drv0.private_data = &id; + + ret = WdtDriverInit(&drv0, WDT_DRIVER_NAME_0); + if (ret != EOK) { + KPrintf("Watchdog driver init error %d\n", ret); + return ERROR; + } + + ret = WdtDriverAttachToBus(WDT_DRIVER_NAME_0, WDT_BUS_NAME_0); + if (ret != EOK) { + KPrintf("Watchdog driver attach error %d\n", ret); + return ERROR; + } + + static struct WdtHardwareDevice dev0; + dev0.dev_done = &dev_done; + dev0.private_data = &id; + + ret = WdtDeviceRegister(&dev0, WDT_0_DEVICE_NAME_0); + if (ret != EOK) { + KPrintf("Watchdog device register error %d\n", ret); + return ERROR; + } + + ret = WdtDeviceAttachToBus(WDT_0_DEVICE_NAME_0, WDT_BUS_NAME_0); + if (ret != EOK) { + KPrintf("Watchdog device register error %d\n", ret); + return ERROR; + } + } +#endif + +#ifdef BSP_USING_WDT1 + { + static struct WdtBus wdt1; + + ret = WdtBusInit(&wdt1, WDT_BUS_NAME_1); + if (ret != EOK) { + KPrintf("Watchdog bus init error %d\n", ret); + return ERROR; + } + + static struct WdtDriver drv1; + drv1.configure = WdtConfigure; + id = WDT_DEVICE_1; + drv1.private_data = &id; + + ret = WdtDriverInit(&drv1, WDT_DRIVER_NAME_1); + if (ret != EOK) { + KPrintf("Watchdog driver init error %d\n", ret); + return ERROR; + } + + ret = WdtDriverAttachToBus(WDT_DRIVER_NAME_1, WDT_BUS_NAME_1); + if (ret != EOK) { + KPrintf("Watchdog driver attach error %d\n", ret); + return ERROR; + } + + static struct WdtHardwareDevice dev1; + dev1.dev_done = &dev_done; + dev1.private_data = &id; + + ret = WdtDeviceRegister(&dev1, WDT_1_DEVICE_NAME_1); + if (ret != EOK) { + KPrintf("Watchdog device register error %d\n", ret); + return ERROR; + } + + ret = WdtDeviceAttachToBus(WDT_1_DEVICE_NAME_1, WDT_BUS_NAME_1); + if (ret != EOK) { + KPrintf("Watchdog device register error %d\n", ret); + return ERROR; + } + } +#endif + + return ret; +} diff --git a/Ubiquitous/XiZi_IIoT/board/edu-riscv64/third_party_driver/watchdog/wdt.c b/Ubiquitous/XiZi_IIoT/board/edu-riscv64/third_party_driver/watchdog/wdt.c new file mode 100644 index 000000000..b106444a2 --- /dev/null +++ b/Ubiquitous/XiZi_IIoT/board/edu-riscv64/third_party_driver/watchdog/wdt.c @@ -0,0 +1,125 @@ +/* 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 wdt.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 +#include + +volatile wdt_t *const wdt[2] = +{ + (volatile wdt_t *)WDT0_BASE_ADDR, + (volatile wdt_t *)WDT1_BASE_ADDR +}; + +static void wdt_enable(wdt_device_number_t id) +{ + wdt[id]->crr = WDT_CRR_MASK; + wdt[id]->cr |= WDT_CR_ENABLE; +} + +static void wdt_disable(wdt_device_number_t id) +{ + wdt[id]->crr = WDT_CRR_MASK; + wdt[id]->cr &= (~WDT_CR_ENABLE); +} + +static void wdt_set_timeout(wdt_device_number_t id, uint8_t timeout) +{ + wdt[id]->torr = WDT_TORR_TOP(timeout); +} + +static void wdt_response_mode(wdt_device_number_t id, uint8_t mode) +{ + wdt[id]->cr &= (~WDT_CR_RMOD_MASK); + wdt[id]->cr |= mode; +} + +static uint64_t wdt_get_pclk(wdt_device_number_t id) +{ + return id ? SysctlClockGetFreq(SYSCTL_CLOCK_WDT1) : SysctlClockGetFreq(SYSCTL_CLOCK_WDT0); +} + +static uint8_t wdt_get_top(wdt_device_number_t id, uint64_t timeout_ms) +{ + uint64_t wdt_clk = wdt_get_pclk(id); + uint64_t ret = (timeout_ms * wdt_clk / 1000) >> 16; + if (ret) + ret = (uint32_t)log2(ret); + if (ret > 0xf) + ret = 0xf; + return (uint8_t)ret; +} + +void wdt_feed(wdt_device_number_t id) +{ + wdt[id]->crr = WDT_CRR_MASK; +} + +void wdt_clear_interrupt(wdt_device_number_t id) +{ + wdt[id]->eoi = wdt[id]->eoi; +} + +void wdt_start(wdt_device_number_t id, uint64_t time_out_ms, plic_irq_callback_t on_irq) +{ + sysctl_reset(id ? SYSCTL_RESET_WDT1 : SYSCTL_RESET_WDT0); + sysctl_clock_set_threshold(id ? SYSCTL_THRESHOLD_WDT1 : SYSCTL_THRESHOLD_WDT0, 0); + sysctl_clock_enable(id ? SYSCTL_CLOCK_WDT1 : SYSCTL_CLOCK_WDT0); + + plic_set_priority(id ? IRQN_WDT1_INTERRUPT : IRQN_WDT0_INTERRUPT, 1); + plic_irq_enable(id ? IRQN_WDT1_INTERRUPT : IRQN_WDT0_INTERRUPT); + plic_irq_register(id ? IRQN_WDT1_INTERRUPT : IRQN_WDT0_INTERRUPT, on_irq, NULL); + + wdt_response_mode(id, WDT_CR_RMOD_INTERRUPT); + uint8_t m_top = wdt_get_top(id, time_out_ms); + wdt_set_timeout(id, m_top); + wdt_enable(id); +} + +uint32_t wdt_init(wdt_device_number_t id, uint64_t time_out_ms, plic_irq_callback_t on_irq, void *ctx) +{ + sysctl_reset(id ? SYSCTL_RESET_WDT1 : SYSCTL_RESET_WDT0); + sysctl_clock_set_threshold(id ? SYSCTL_THRESHOLD_WDT1 : SYSCTL_THRESHOLD_WDT0, 0); + sysctl_clock_enable(id ? SYSCTL_CLOCK_WDT1 : SYSCTL_CLOCK_WDT0); + + plic_set_priority(id ? IRQN_WDT1_INTERRUPT : IRQN_WDT0_INTERRUPT, 1); + plic_irq_enable(id ? IRQN_WDT1_INTERRUPT : IRQN_WDT0_INTERRUPT); + plic_irq_register(id ? IRQN_WDT1_INTERRUPT : IRQN_WDT0_INTERRUPT, on_irq, ctx); + + wdt_response_mode(id, WDT_CR_RMOD_INTERRUPT); + uint8_t m_top = wdt_get_top(id, time_out_ms); + wdt_set_timeout(id, m_top); + wdt_enable(id); + return (1UL << (m_top + 16 + 1)) * 1000UL / wdt_get_pclk(id); +} + +void wdt_stop(wdt_device_number_t id) +{ + wdt_disable(id); +} + diff --git a/Ubiquitous/XiZi_IIoT/kernel/kernel_test/Makefile b/Ubiquitous/XiZi_IIoT/kernel/kernel_test/Makefile index ed3599ccb..1c4f0656a 100644 --- a/Ubiquitous/XiZi_IIoT/kernel/kernel_test/Makefile +++ b/Ubiquitous/XiZi_IIoT/kernel/kernel_test/Makefile @@ -92,8 +92,4 @@ ifeq ($(CONFIG_KERNEL_TEST_SPI_FLASH),y) SRC_FILES += test_spi_flash.c endif -ifeq ($(KERNEL_TEST_SOFT_SPI_SD),y) - SRC_FILES += test_softspi_sd.c -endif - include $(KERNEL_ROOT)/compiler.mk diff --git a/Ubiquitous/XiZi_IIoT/kernel/kernel_test/test_main.c b/Ubiquitous/XiZi_IIoT/kernel/kernel_test/test_main.c index 33f15d9a9..18d6f85f0 100644 --- a/Ubiquitous/XiZi_IIoT/kernel/kernel_test/test_main.c +++ b/Ubiquitous/XiZi_IIoT/kernel/kernel_test/test_main.c @@ -118,8 +118,6 @@ int TestMain(int argc, char*argv[]) #ifdef KERNEL_TEST_REALTIME if (argc > 2) TestRealtime(argc-2, &argv[2]); -#endif -#ifdef KERNEL_TEST_SOFT_SPI_SD #endif default: break; diff --git a/Ubiquitous/XiZi_IIoT/kernel/kernel_test/test_softspi_sd.c b/Ubiquitous/XiZi_IIoT/kernel/kernel_test/test_softspi_sd.c deleted file mode 100644 index b07c8a672..000000000 --- a/Ubiquitous/XiZi_IIoT/kernel/kernel_test/test_softspi_sd.c +++ /dev/null @@ -1,105 +0,0 @@ -/* - * Copyright (c) 2006-2021, RT-Thread Development Team - * - * SPDX-License-Identifier: Apache-2.0 - * - * Change Logs: - * Date Author Notes - * 2016-09-28 armink first version. - */ - -/** -* @file test_spi_flash.c -* @brief support to test spi flash function -* @version 1.0 -* @author AIIT XUOS Lab -* @date 2021-05-17 -*/ - -/************************************************* -File name: test_spi_flash.c -Description: support spi flash function test -Others: add spi flash test cmd from SFUD/blob/master/demo/stm32f2xx_rtt/RT-Thread-2.1.0/components/drivers/spi/spi_flash_sfud.c - https://github.com/armink/SFUD/ -History: -1. Date: 2021-05-17 -Author: AIIT XUOS Lab -Modification: -1. support spi flash open, read and write function -*************************************************/ - -#include -#include -#include - -// void SDpen(void) -// { -// x_err_t ret = EOK; - -// ret=HwTFInit(); -// if (ret < 0) { -// KPrintf("open spi flash fd error %d\n", ret); -// } - -// KPrintf("Spi Flash init succeed\n"); - -// return; -// } - -// SHELL_EXPORT_CMD(SHELL_CMD_PERMISSION(0)|SHELL_CMD_TYPE(SHELL_TYPE_CMD_MAIN), -// SDpen, SDpen, open spi flash device); - -// void SDRead(int argc, char *argv[]) -// { -// x_err_t ret = EOK; - -// } -// SHELL_EXPORT_CMD(SHELL_CMD_PERMISSION(0)|SHELL_CMD_TYPE(SHELL_TYPE_CMD_MAIN), -// SDRead, SDRead, read data from spi flash device); - -// void SDWrite(int argc, char *argv[]) -// { -// x_err_t ret = EOK; -// x_size_t i, j = 0; -// uint32 addr; -// uint32 size; -// uint8 data[16]; - -// struct BusBlockWriteParam write_param; -// memset(&write_param, 0, sizeof(struct BusBlockWriteParam)); - -// memset(data, 0, 16); - -// if (argc < 3) { -// KPrintf("FlashWrite cmd format: FlashWrite addr data.\n"); -// return; -// } else { -// addr = strtol(argv[1], NULL, 0); -// size = argc - 2; - -// write_param.buffer = data; -// write_param.pos = addr; -// write_param.size = size; - -// if (data) { -// for (i = 0; i < size; i++) { -// data[i] = strtol(argv[2 + i], NULL, 0); -// } - -// ret = write(spi_flash_fd, &write_param, size); -// if (EOK == ret) { -// KPrintf("Write the %s flash data success. Start from 0x%08X, size is %ld.\n", -// SPI_FLASH_PATH, addr, size); -// KPrintf("Write data: "); -// for (i = 0; i < size; i++) { -// KPrintf("%d ", data[i]); -// } -// KPrintf(".\n"); -// } -// } else { -// KPrintf("SpiFlashWrite alloc write buffer failed!\n"); -// } -// } -// } -// SHELL_EXPORT_CMD(SHELL_CMD_PERMISSION(0)|SHELL_CMD_TYPE(SHELL_TYPE_CMD_MAIN), -// SDWrite, SDWrite, write data to spi flash device);