mirror of
https://github.com/RIOT-OS/RIOT.git
synced 2024-12-29 04:50:03 +01:00
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>
This commit is contained in:
commit
7157ff3ffc
@ -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 |
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
296
cpu/gd32v/periph/rtc.c
Normal file
296
cpu/gd32v/periph/rtc.c
Normal file
@ -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;
|
||||
}
|
@ -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"
|
||||
@ -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;
|
||||
|
||||
/**
|
||||
@ -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
|
||||
*
|
||||
@ -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);
|
||||
}
|
||||
|
@ -62,13 +62,6 @@ typedef struct {
|
||||
bool more;
|
||||
} _block_ctx_t;
|
||||
|
||||
static uint16_t _get_id(void)
|
||||
{
|
||||
__attribute__((section(".noinit")))
|
||||
static uint16_t id;
|
||||
return atomic_fetch_add_u16(&id, 1);
|
||||
}
|
||||
|
||||
#if IS_USED(MODULE_NANOCOAP_DTLS)
|
||||
int nanocoap_sock_dtls_connect(nanocoap_sock_t *sock, sock_udp_ep_t *local,
|
||||
const sock_udp_ep_t *remote, credman_tag_t tag)
|
||||
@ -456,7 +449,8 @@ ssize_t nanocoap_sock_get(nanocoap_sock_t *sock, const char *path, void *buf, si
|
||||
.iov_len = len,
|
||||
};
|
||||
|
||||
pktpos += coap_build_hdr(pkt.hdr, COAP_TYPE_CON, NULL, 0, COAP_METHOD_GET, _get_id());
|
||||
pktpos += coap_build_hdr(pkt.hdr, COAP_TYPE_CON, NULL, 0, COAP_METHOD_GET,
|
||||
nanocoap_sock_next_msg_id(sock));
|
||||
pktpos += coap_opt_put_uri_path(pktpos, 0, path);
|
||||
|
||||
pkt.payload = pktpos;
|
||||
@ -488,7 +482,7 @@ ssize_t _sock_put_post(nanocoap_sock_t *sock, const char *path, unsigned code,
|
||||
.iov_len = max_len,
|
||||
};
|
||||
|
||||
pktpos += coap_build_hdr(pkt.hdr, type, NULL, 0, code, _get_id());
|
||||
pktpos += coap_build_hdr(pkt.hdr, type, NULL, 0, code, nanocoap_sock_next_msg_id(sock));
|
||||
pktpos += coap_opt_put_uri_path(pktpos, 0, path);
|
||||
|
||||
if (response == NULL && type == COAP_TYPE_NON) {
|
||||
@ -581,7 +575,8 @@ ssize_t nanocoap_sock_delete(nanocoap_sock_t *sock, const char *path)
|
||||
.hdr = (void *)pktpos,
|
||||
};
|
||||
|
||||
pktpos += coap_build_hdr(pkt.hdr, COAP_TYPE_CON, NULL, 0, COAP_METHOD_DELETE, _get_id());
|
||||
pktpos += coap_build_hdr(pkt.hdr, COAP_TYPE_CON, NULL, 0, COAP_METHOD_DELETE,
|
||||
nanocoap_sock_next_msg_id(sock));
|
||||
pktpos += coap_opt_put_uri_path(pktpos, 0, path);
|
||||
|
||||
pkt.payload = pktpos;
|
||||
@ -665,7 +660,8 @@ static int _fetch_block(nanocoap_sock_t *sock, uint8_t *buf, size_t len,
|
||||
};
|
||||
uint16_t lastonum = 0;
|
||||
|
||||
buf += coap_build_hdr(pkt.hdr, COAP_TYPE_CON, NULL, 0, COAP_METHOD_GET, _get_id());
|
||||
buf += coap_build_hdr(pkt.hdr, COAP_TYPE_CON, NULL, 0, COAP_METHOD_GET,
|
||||
nanocoap_sock_next_msg_id(sock));
|
||||
buf += coap_opt_put_uri_pathquery(buf, &lastonum, path);
|
||||
buf += coap_opt_put_uint(buf, lastonum, COAP_OPT_BLOCK2, (num << 4) | blksize);
|
||||
|
||||
@ -703,7 +699,8 @@ int nanocoap_sock_block_request(coap_block_request_t *req,
|
||||
uint8_t *pktpos = (void *)pkt.hdr;
|
||||
uint16_t lastonum = 0;
|
||||
|
||||
pktpos += coap_build_hdr(pkt.hdr, COAP_TYPE_CON, NULL, 0, req->method, _get_id());
|
||||
pktpos += coap_build_hdr(pkt.hdr, COAP_TYPE_CON, NULL, 0, req->method,
|
||||
nanocoap_sock_next_msg_id(req->sock));
|
||||
pktpos += coap_opt_put_uri_pathquery(pktpos, &lastonum, req->path);
|
||||
pktpos += coap_opt_put_uint(pktpos, lastonum, COAP_OPT_BLOCK1,
|
||||
(req->blknum << 4) | req->blksize | (more ? 0x8 : 0));
|
||||
|
Loading…
Reference in New Issue
Block a user