diff --git a/boards/seeedstudio-gd32/include/periph_conf.h b/boards/seeedstudio-gd32/include/periph_conf.h index 49f1267d9b..4f941ad273 100644 --- a/boards/seeedstudio-gd32/include/periph_conf.h +++ b/boards/seeedstudio-gd32/include/periph_conf.h @@ -19,11 +19,7 @@ #ifndef PERIPH_CONF_H #define PERIPH_CONF_H -#include "periph_cpu.h" -#include "periph_common_conf.h" - -#include "cfg_timer_default.h" -#include "cfg_uart_default.h" +#include "macros/units.h" #ifndef CONFIG_BOARD_HAS_HXTAL #define CONFIG_BOARD_HAS_HXTAL 1 /**< The board provides a high frequency oscillator. */ @@ -37,6 +33,12 @@ #define CONFIG_CLOCK_HXTAL MHZ(8) /**< HXTAL frequency */ #endif +#include "periph_cpu.h" +#include "periph_common_conf.h" + +#include "cfg_timer_default.h" +#include "cfg_uart_default.h" + #ifdef __cplusplus extern "C" { #endif diff --git a/boards/sipeed-longan-nano/include/periph_conf.h b/boards/sipeed-longan-nano/include/periph_conf.h index 7c0a616c38..3fd5b2c749 100644 --- a/boards/sipeed-longan-nano/include/periph_conf.h +++ b/boards/sipeed-longan-nano/include/periph_conf.h @@ -19,11 +19,7 @@ #ifndef PERIPH_CONF_H #define PERIPH_CONF_H -#include "periph_cpu.h" -#include "periph_common_conf.h" - -#include "cfg_timer_default.h" -#include "cfg_uart_default.h" +#include "macros/units.h" #ifndef CONFIG_BOARD_HAS_HXTAL #define CONFIG_BOARD_HAS_HXTAL 1 /**< The board provides a high frequency oscillator. */ @@ -37,6 +33,12 @@ #define CONFIG_CLOCK_HXTAL MHZ(8) /**< HXTAL frequency */ #endif +#include "periph_cpu.h" +#include "periph_common_conf.h" + +#include "cfg_timer_default.h" +#include "cfg_uart_default.h" + #ifdef __cplusplus extern "C" { #endif diff --git a/cpu/gd32v/Kconfig b/cpu/gd32v/Kconfig index cbc022bd87..4caf73dc7a 100644 --- a/cpu/gd32v/Kconfig +++ b/cpu/gd32v/Kconfig @@ -18,6 +18,7 @@ config CPU_FAM_GD32V select HAS_PERIPH_FLASHPAGE_PAGEWISE select HAS_PERIPH_PM select HAS_PERIPH_RTC + select HAS_PERIPH_RTT select HAS_PERIPH_TIMER select HAS_PERIPH_TIMER_PERIODIC select HAS_PERIPH_WDT diff --git a/cpu/gd32v/Makefile.features b/cpu/gd32v/Makefile.features index 45cd6720ab..d7a4e16adc 100644 --- a/cpu/gd32v/Makefile.features +++ b/cpu/gd32v/Makefile.features @@ -5,6 +5,7 @@ FEATURES_PROVIDED += periph_clic FEATURES_PROVIDED += periph_gpio FEATURES_PROVIDED += periph_gpio_irq FEATURES_PROVIDED += periph_rtc +FEATURES_PROVIDED += periph_rtt FEATURES_PROVIDED += periph_timer FEATURES_PROVIDED += periph_timer_periodic FEATURES_PROVIDED += periph_wdt diff --git a/cpu/gd32v/include/periph_cpu.h b/cpu/gd32v/include/periph_cpu.h index 3c42de2527..98bdf9f5b8 100644 --- a/cpu/gd32v/include/periph_cpu.h +++ b/cpu/gd32v/include/periph_cpu.h @@ -276,12 +276,20 @@ typedef struct { * * @{ */ -#define RTT_INTR_PRIORITY (2) +#define RTT_DEV RTC /**< RTC is used as RTT device */ + +#define RTT_IRQ RTC_ALARM_IRQn /**< RTC_ALARM_IRQn is used as IRQ number */ +#define RTT_IRQ_PRIORITY (2) /**< RTT interrupt priority */ + +#if CONFIG_BOARD_HAS_LXTAL +#define RTT_CLOCK_FREQUENCY (32768U) /**< Low frequency XTAL is used as clock source */ +#else +#define RTT_CLOCK_FREQUENCY (40000U) /**< IRC40K is used as clock source */ +#endif -#define RTT_MAX_VALUE (0xffffffff) -#define RTT_CLOCK_FREQUENCY (32768U) /* in Hz */ -#define RTT_MAX_FREQUENCY (RTT_CLOCK_FREQUENCY) /* in Hz */ #define RTT_MIN_FREQUENCY (1U) /* in Hz */ +#define RTT_MAX_FREQUENCY (RTT_CLOCK_FREQUENCY) /* in Hz */ +#define RTT_MAX_VALUE (0xffffffff) #ifndef RTT_FREQUENCY #define RTT_FREQUENCY (RTT_MAX_FREQUENCY) /* in Hz */ diff --git a/cpu/gd32v/periph/flashpage.c b/cpu/gd32v/periph/flashpage.c index 2832659b1a..e222156209 100644 --- a/cpu/gd32v/periph/flashpage.c +++ b/cpu/gd32v/periph/flashpage.c @@ -8,7 +8,7 @@ */ /** - * @ingroup cpu_stm32 + * @ingroup cpu_gd32v * @{ * * @file diff --git a/cpu/gd32v/periph/rtt.c b/cpu/gd32v/periph/rtt.c new file mode 100644 index 0000000000..7fdf0ce545 --- /dev/null +++ b/cpu/gd32v/periph/rtt.c @@ -0,0 +1,267 @@ +/* + * Copyright (C) 2014 Freie Universität Berlin + * 2023 Gunar Schorcht + * + * This file is subject to the terms and conditions of the GNU Lesser General + * Public License v2.1. See the file LICENSE in the top level directory for more + * details. + */ + +/** + * @ingroup cpu_gd32v + * @ingroup drivers_periph_rtt + * @{ + * + * @file + * @brief Low-level RTT driver implementation for STM32F1 + * + * @author Thomas Eichinger + * @author Gunar Schorcht + * + * @} + */ + +#include "cpu.h" +#include "periph/rtt.h" +#include "periph_conf.h" + +#define ENABLE_DEBUG 0 +#include "debug.h" + +#define EXTI_RTC_BIT (1UL << 17) + +#define RTT_PRESCALER ((RTT_CLOCK_FREQUENCY / RTT_FREQUENCY) - 1 ) + +static inline void _rtt_enter_config_mode(void); +static inline void _rtt_leave_config_mode(void); +static void isr_rtc(unsigned irqn); + +static rtt_cb_t alarm_cb; +static void *alarm_arg; + +static rtt_cb_t overflow_cb; +static void *overflow_arg; + +void rtt_init(void) +{ + /* enable backup domain clock */ + periph_clk_en(APB1, RCU_APB1EN_BKPIEN_Msk); + + /* enable write access to backup domain registers */ + PMU->CTL |= PMU_CTL_BKPWEN_Msk; + + /* reset the entire backup domain */ + RCU->BDCTL |= RCU_BDCTL_BKPRST_Msk; + RCU->BDCTL &= ~RCU_BDCTL_BKPRST_Msk; + + rtt_poweron(); + + /* clear RSYN flag */ + RTT_DEV->CTL &= ~(RTC_CTL_RSYNF_Msk); + while ((RTC->CTL & RTC_CTL_RSYNF_Msk) != RTC_CTL_RSYNF_Msk) { } + + _rtt_enter_config_mode(); + + /* reset RTC counter */ + RTT_DEV->CNTH = 0x0000; + RTT_DEV->CNTL = 0x0000; + + /* set prescaler */ + RTT_DEV->PSCH = (RTT_PRESCALER >> 16) & 0x000f; + RTT_DEV->PSCL = RTT_PRESCALER & 0xffff; + + _rtt_leave_config_mode(); + + /* configure the EXTI channel, as RTC interrupts are routed through it. + * Needs to be configured to trigger on rising edges. */ + EXTI->FTEN &= ~(EXTI_RTC_BIT); + EXTI->RTEN |= EXTI_RTC_BIT; + EXTI->INTEN |= EXTI_RTC_BIT; + EXTI->PD |= EXTI_RTC_BIT; + + /* enable global RTC interrupt */ + clic_set_handler(RTT_IRQ, isr_rtc); + clic_enable_interrupt(RTT_IRQ, RTT_IRQ_PRIORITY); +} + +void rtt_set_overflow_cb(rtt_cb_t cb, void *arg) +{ + overflow_cb = cb; + overflow_arg = arg; + + _rtt_enter_config_mode(); + + /* Enable overflow interrupt */ + RTT_DEV->INTEN |= RTC_INTEN_OVIE_Msk; + + _rtt_leave_config_mode(); +} + +void rtt_clear_overflow_cb(void) +{ + _rtt_enter_config_mode(); + + /* Clear overflow interrupt */ + RTT_DEV->INTEN &= ~(RTC_INTEN_OVIE_Msk); + + _rtt_leave_config_mode(); + + overflow_cb = NULL; + overflow_arg = NULL; +} + +uint32_t rtt_get_counter(void) +{ + /* wait for synchronization */ + while (!(RTT_DEV->CTL & RTC_CTL_RSYNF_Msk)) { } + + return ((uint32_t)RTT_DEV->CNTH << 16 ) | (uint32_t)(RTT_DEV->CNTL); +} + +void rtt_set_counter(uint32_t counter) +{ + _rtt_enter_config_mode(); + + /* Set RTC counter MSB word */ + RTT_DEV->CNTH = counter >> 16; + /* Set RTC counter LSB word */ + RTT_DEV->CNTL = counter & 0xffff; + + _rtt_leave_config_mode(); +} + +/* RTC->ALRMH and RTC->ALRML are writable only. Therefore the current alarm + * time must be stored separately in a variable for rtt_get_alarm. */ +static uint32_t _rtt_alarm = 0; + +uint32_t rtt_get_alarm(void) +{ + /* wait for synchronization */ + while (!(RTT_DEV->CTL & RTC_CTL_RSYNF_Msk)) { } + + return _rtt_alarm; +} + +void rtt_set_alarm(uint32_t alarm, rtt_cb_t cb, void *arg) +{ + /* save the current alarm time */ + _rtt_alarm = alarm; + + _rtt_enter_config_mode(); + + /* Disable alarm*/ + RTT_DEV->INTEN &= ~RTC_INTEN_ALRMIE_Msk; + /* Save new cb and argument */ + alarm_cb = cb; + alarm_arg = arg; + + /* Set the alarm MSB word */ + RTT_DEV->ALRMH = alarm >> 16; + /* Set the alarm LSB word */ + RTT_DEV->ALRML = (alarm & 0xffff); + + /* Enable alarm interrupt */ + RTT_DEV->INTEN |= RTC_INTEN_ALRMIE_Msk; + + _rtt_leave_config_mode(); +} + +void rtt_clear_alarm(void) +{ + _rtt_enter_config_mode(); + + /* Disable alarm interrupt */ + RTT_DEV->INTEN &= ~RTC_INTEN_ALRMIE_Msk; + /* Set the ALARM MSB word to reset value */ + RTT_DEV->ALRMH = 0xffff; + /* Set the ALARM LSB word to reset value */ + RTT_DEV->ALRML = 0xffff; + + _rtt_leave_config_mode(); +} + +#define RCU_BDCTL_RTCSRC_CK_LXTAL 1 +#define RCU_BDCTL_RTCSRC_CK_IRC40K 2 + +void rtt_poweron(void) +{ + /* enable backup domain clock */ + periph_clk_en(APB1, RCU_APB1EN_BKPIEN_Msk); + + /* enable write access to backup domain registers */ + PMU->CTL |= PMU_CTL_BKPWEN_Msk; + +#if CONFIG_BOARD_HAS_LXTAL + /* oscillator clock used as RTC clock */ + RCU->BDCTL |= RCU_BDCTL_RTCSRC_CK_LXTAL << RCU_BDCTL_RTCSRC_Pos; + RCU->BDCTL |= RCU_BDCTL_LXTALEN_Msk; + while ((RCU->BDCTL & RCU_BDCTL_LXTALSTB_Msk) != RCU_BDCTL_LXTALSTB_Msk) { } +#else + RCU->BDCTL |= RCU_BDCTL_RTCSRC_CK_IRC40K << RCU_BDCTL_RTCSRC_Pos; +#endif + + /* enable RTC clock */ + RCU->BDCTL |= RCU_BDCTL_RTCEN_Msk; + + /* disable write access to backup domain registers */ + PMU->CTL &= ~PMU_CTL_BKPWEN_Msk; +} + +void rtt_poweroff(void) +{ + /* enable write access to backup domain registers */ + PMU->CTL |= PMU_CTL_BKPWEN_Msk; + + /* enable RTC clock */ + RCU->BDCTL &= ~RCU_BDCTL_RTCEN_Msk; + + /* disable write access to backup domain registers */ + PMU->CTL &= ~PMU_CTL_BKPWEN_Msk; + + /* disable backup domain clock */ + periph_clk_dis(APB1, RCU_APB1EN_BKPIEN_Msk); +} + +static inline void _rtt_enter_config_mode(void) +{ + /* enable write access to backup domain registers */ + PMU->CTL |= PMU_CTL_BKPWEN_Msk; + + /* wait until the LWOFF bit is 1 (Last write operation finished). */ + while ((RTC->CTL & RTC_CTL_LWOFF_Msk) == 0) { } + + /* enter configuration mode. */ + RTC->CTL |= RTC_CTL_CMF_Msk; +} + +static inline void _rtt_leave_config_mode(void) +{ + /* exit configuration mode. */ + RTC->CTL &= ~RTC_CTL_CMF_Msk; + + /* wait until the LWOFF bit is 1 (Last write operation finished). */ + while ((RTC->CTL & RTC_CTL_LWOFF_Msk) == 0) { } + + /* disable write access to backup domain registers */ + PMU->CTL &= ~PMU_CTL_BKPWEN_Msk; +} + +static void isr_rtc(unsigned irqn) +{ + (void)irqn; + + if (RTT_DEV->CTL & RTC_CTL_ALRMIF_Msk) { + RTT_DEV->CTL &= ~(RTC_CTL_ALRMIF_Msk); + if (alarm_cb) { + alarm_cb(alarm_arg); + } + } + if (RTT_DEV->CTL & RTC_CTL_OVIF_Msk) { + RTT_DEV->CTL &= ~(RTC_CTL_OVIF_Msk); + if (overflow_cb) { + overflow_cb(overflow_arg); + } + } + + EXTI->PD |= EXTI_RTC_BIT; +}