Skip to content

Commit

Permalink
Merge #19178 #19186
Browse files Browse the repository at this point in the history
19178: nanocoap_sock: store message ID in nanocoap_sock_t r=benpicco a=benpicco



19186: cpu/gd32v: add periph_rtc support r=benpicco a=gschorcht

### Contribution description

This PR provides the `periph_rtc` support and is one of a bunch of follow up PRs that complete the peripheral drivers for GD32VF103.

### Testing procedure

`tests/periph_rtc` should work and should give the following output:
```
Help: Press s to start test, r to print it is ready
START
main(): This is RIOT! (Version: 2023.04-devel-144-gc17695-cpu/gd32v/periph_rtc)

RIOT RTC low-level driver test
This test will display 'Alarm!' every 2 seconds for 4 times
  Setting clock to   2020-02-28 23:59:57
Clock value is now   2020-02-28 23:59:57
  Setting alarm to   2020-02-28 23:59:59
   Alarm is set to   2020-02-28 23:59:59
  Alarm cleared at   2020-02-28 23:59:57
       No alarm at   2020-02-28 23:59:59
  Setting alarm to   2020-02-29 00:00:01

Alarm!
Alarm!
Alarm!
Alarm!
```

### Issues/PRs references


Co-authored-by: Benjamin Valentin <benjamin.valentin@bht-berlin.de>
Co-authored-by: Gunar Schorcht <gunar@schorcht.net>
  • Loading branch information
3 people authored Jan 23, 2023
3 parents 36d230e + d041a5f + 899661d commit 7157ff3
Show file tree
Hide file tree
Showing 7 changed files with 329 additions and 15 deletions.
2 changes: 1 addition & 1 deletion boards/seeedstudio-gd32/doc.txt
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ on-board components:
| Power Modes | 3 (Sleep, Deep Sleep, Standby) | no |
| GPIOs | 80 | yes |
| Timers | 5 x 16-bit timer | yes |
| RTC | 1 x 32-bit counter, 20-bit prescaler | no |
| RTC | 1 x 32-bit counter, 20-bit prescaler | yes |
| WDT | 2 x 12-bit counter, 3-bit prescaler | yes |
| ADC | 2 x 12-bit units, 16 channels, 1 Msps | no |
| DAC | 2 x 12-bit channel | no |
Expand Down
7 changes: 5 additions & 2 deletions boards/seeedstudio-gd32/include/periph_conf.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,12 @@
extern "C" {
#endif

/* This board provides an high frequency oscillator */
#ifndef CONFIG_BOARD_HAS_HXTAL
#define CONFIG_BOARD_HAS_HXTAL 1
#define CONFIG_BOARD_HAS_HXTAL 1 /**< This board provides an high frequency oscillator */
#endif

#ifndef CONFIG_BOARD_HAS_LXTAL
#define CONFIG_BOARD_HAS_LXTAL 1 /**< The board provides a low frequency oscillator. */
#endif

#ifndef CONFIG_CLOCK_HXTAL
Expand Down
1 change: 1 addition & 0 deletions cpu/gd32v/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ config CPU_FAM_GD32V
select HAS_PERIPH_FLASHPAGE_IN_ADDRESS_SPACE
select HAS_PERIPH_FLASHPAGE_PAGEWISE
select HAS_PERIPH_PM
select HAS_PERIPH_RTC
select HAS_PERIPH_TIMER
select HAS_PERIPH_TIMER_PERIODIC
select HAS_PERIPH_WDT
Expand Down
1 change: 1 addition & 0 deletions cpu/gd32v/Makefile.features
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ CPU_CORE := rv32imac

FEATURES_PROVIDED += periph_clic
FEATURES_PROVIDED += periph_gpio
FEATURES_PROVIDED += periph_rtc
FEATURES_PROVIDED += periph_timer
FEATURES_PROVIDED += periph_timer_periodic
FEATURES_PROVIDED += periph_wdt
Expand Down
296 changes: 296 additions & 0 deletions cpu/gd32v/periph/rtc.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,296 @@
/*
* Copyright (C) 2019 Alexei Bezborodov
* 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
* @{
* @file
* @brief Low-level RTC driver implementation for GD32VF103
*
* This driver is a modified copy of the RTC driver for the STM32F1 family.
*
* @author Alexei Bezborodov <alexeibv+riotos@narod.ru>
* @author Gunar Schorcht <gunar@schorcht.net>
* @}
*/

#include <time.h>
#include "cpu.h"
#include "periph/rtc.h"

#define ENABLE_DEBUG 0
#include "debug.h"

#define EXTI_RTC_BIT (1UL << 17)

static struct {
rtc_alarm_cb_t cb; /**< callback called from RTC interrupt */
void *arg; /**< argument passed to the callback */
} isr_ctx;

/* forward declaration of ISR */
static void isr_rtc_alarm(unsigned irqn);

static void _rtc_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 void _rtc_exit_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 bool _is_rtc_enable(void)
{
return ((RCU->BDCTL & RCU_BDCTL_RTCEN_Msk) == RCU_BDCTL_RTCEN_Msk);
}

#define RCU_BDCTL_RTCSRC_CK_LXTAL 1
#define RCU_BDCTL_RTCSRC_CK_IRC40K 2

static void _rtc_config(void)
{
DEBUG("[RTC] config\n");

/* enable APB1 clocks */
RCU->APB1EN |= RCU_APB1EN_PMUEN_Msk | RCU_APB1EN_BKPIEN_Msk;

/* enable write access to backup domain registers */
PMU->CTL |= PMU_CTL_BKPWEN_Msk;

/* resets the entire backup domain */
RCU->BDCTL |= RCU_BDCTL_BKPRST_Msk;
/* reset not activated */
RCU->BDCTL &= ~RCU_BDCTL_BKPRST_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;

/* calibration clock from 0 to 0x7F */
BKP->OCTL |= 0;
BKP->OCTL |= BKP_OCTL_ASOEN_Msk;

/* second interrupt is disabled. */
RTC->INTEN &= ~RTC_INTEN_SCIE_Msk;

_rtc_enter_config_mode();

#if CONFIG_BOARD_HAS_LXTAL
/* if the input clock frequency (fRTCCLK) is 32.768 kHz, write 7FFFh in
* this register to get a signal period of 1 second. */
RTC->PSCH = 0;
RTC->PSCL = 0x7FFF;
#else
/* if the input clock frequency (fRTCCLK) is 40 kHz, write 39999 in
* this register to get a signal period of 1 second. */
RTC->PSCH = 0;
RTC->PSCL = 39999;
#endif

_rtc_exit_config_mode();

/* wait registers synchronize flag */
RTC->CTL &= (uint16_t)~RTC_CTL_RSYNF_Msk;
while ((RTC->CTL & RTC_CTL_RSYNF_Msk) != RTC_CTL_RSYNF_Msk) { }

/* disable write access to backup domain registers */
PMU->CTL &= ~PMU_CTL_BKPWEN_Msk;

/* 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(RTC_ALARM_IRQn, isr_rtc_alarm);
clic_enable_interrupt(RTC_ALARM_IRQn, CPU_DEFAULT_IRQ_PRIO);
}

static uint32_t _rtc_get_time(void)
{
return (RTC->CNTH << 16) | RTC->CNTL;
}

static void _rtc_set_time(uint32_t counter_val)
{
_rtc_enter_config_mode();
RTC->CNTH = (counter_val & 0xffff0000) >> 16;
RTC->CNTL = counter_val & 0x0000ffff;
_rtc_exit_config_mode();
}

void rtc_init(void)
{
/* save current time if RTC already works */
bool is_rtc_enable = _is_rtc_enable();
uint32_t cur_time = 0;
if (is_rtc_enable) {
cur_time = _rtc_get_time();
}

/* config RTC */
_rtc_config();

/* restore current time after config */
if (is_rtc_enable) {
_rtc_set_time(cur_time);
}
}

int rtc_set_time(struct tm *time)
{
rtc_tm_normalize(time);

uint32_t timestamp = rtc_mktime(time);

_rtc_set_time(timestamp);

DEBUG("%s timestamp=%"PRIu32"\n", __func__, timestamp);

return 0;
}

int rtc_get_time(struct tm *time)
{
uint32_t timestamp = _rtc_get_time();
rtc_localtime(timestamp, time);

DEBUG("%s timestamp=%"PRIu32"\n", __func__, timestamp);
return 0;
}

static void _rtc_enable_alarm(void)
{
/* clear alarm flag */
RTC->CTL &= ~RTC_CTL_ALRMIF_Msk;

_rtc_enter_config_mode();
RTC->INTEN |= (RTC_INTEN_ALRMIE_Msk);
_rtc_exit_config_mode();
}

static void _rtc_disable_alarm(void)
{
_rtc_enter_config_mode();
RTC->INTEN &= ~RTC_INTEN_ALRMIE_Msk;
_rtc_exit_config_mode();
}

/* RTC->ALRMH and RTC->ALRML are writable only. Therefore the current alarm
* time must be stored separately in a variable for _rtc_get_alarm_time. */
static uint32_t _rtc_alarm_time = 0;

static uint32_t _rtc_get_alarm_time(void)
{
return _rtc_alarm_time;
}

static void _rtc_set_alarm_time(uint32_t alarm_time)
{
/* save the current alarm time */
_rtc_alarm_time = alarm_time;
/* set RTC alarm registers */
_rtc_enter_config_mode();
RTC->ALRML = (alarm_time & 0x0000ffff);
RTC->ALRMH = (alarm_time & 0xffff0000) >> 16;
_rtc_exit_config_mode();
}

int rtc_set_alarm(struct tm *time, rtc_alarm_cb_t cb, void *arg)
{
rtc_tm_normalize(time);

uint32_t timestamp = rtc_mktime(time);

/* disable existing alarm (if enabled) */
rtc_clear_alarm();

/* save callback and argument */
isr_ctx.cb = cb;
isr_ctx.arg = arg;

/* set wakeup time */
_rtc_set_alarm_time(timestamp);

/* enable Alarm */
_rtc_enable_alarm();

DEBUG("%s timestamp=%"PRIu32"\n", __func__, timestamp);

return 0;
}

int rtc_get_alarm(struct tm *time)
{
uint32_t timestamp = _rtc_get_alarm_time();
rtc_localtime(timestamp, time);

DEBUG("%s timestamp=%"PRIu32"\n", __func__, timestamp);

return 0;
}

void rtc_clear_alarm(void)
{
_rtc_disable_alarm();

isr_ctx.cb = NULL;
isr_ctx.arg = NULL;
}

void rtc_poweron(void)
{
/* RTC is always on */
return;
}

void rtc_poweroff(void)
{
/* RTC is always on */
return;
}

static void isr_rtc_alarm(unsigned irqn)
{
(void)irqn;

if (RTC->CTL & RTC_CTL_ALRMIF_Msk) {
if (isr_ctx.cb != NULL) {
isr_ctx.cb(isr_ctx.arg);
}
RTC->CTL &= ~RTC_CTL_ALRMIF_Msk;
}
EXTI->PD |= EXTI_RTC_BIT;
}
16 changes: 16 additions & 0 deletions sys/include/net/nanocoap_sock.h
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,7 @@
#include <stdint.h>
#include <unistd.h>

#include "random.h"
#include "net/nanocoap.h"
#include "net/sock/udp.h"
#include "net/sock/util.h"
Expand Down Expand Up @@ -186,6 +187,7 @@ typedef struct {
functions. */
nanocoap_socket_type_t type; /**< Socket type (UDP, DTLS) */
#endif
uint16_t msg_id; /**< next CoAP message ID */
} nanocoap_sock_t;

/**
Expand All @@ -199,6 +201,19 @@ typedef struct {
uint8_t blksize; /**< CoAP blocksize exponent */
} coap_block_request_t;

/**
* @brief Get next consecutive message ID for use when building a new
* CoAP request.
*
* @param[in] sock CoAP socket on which the ID is used
*
* @return A new message ID that can be used for a request or response.
*/
static inline uint16_t nanocoap_sock_next_msg_id(nanocoap_sock_t *sock)
{
return sock->msg_id++;
}

/**
* @brief Start a nanocoap server instance
*
Expand Down Expand Up @@ -230,6 +245,7 @@ static inline int nanocoap_sock_connect(nanocoap_sock_t *sock,
#if IS_USED(MODULE_NANOCOAP_DTLS)
sock->type = COAP_SOCKET_TYPE_UDP;
#endif
sock->msg_id = random_uint32();

return sock_udp_create(&sock->udp, local, remote, 0);
}
Expand Down
Loading

0 comments on commit 7157ff3

Please sign in to comment.