From dc5a1e9db0f77b5b92710bf6e981ac9495fa8f28 Mon Sep 17 00:00:00 2001 From: Gunar Schorcht Date: Mon, 6 Feb 2023 22:22:01 +0100 Subject: [PATCH] cpu/gd32v: add periph_rtc_mem support --- cpu/gd32v/Kconfig | 1 + cpu/gd32v/Makefile.features | 1 + cpu/gd32v/periph/rtc_mem.c | 107 ++++++++++++++++++++++++++++++++++++ 3 files changed, 109 insertions(+) create mode 100644 cpu/gd32v/periph/rtc_mem.c diff --git a/cpu/gd32v/Kconfig b/cpu/gd32v/Kconfig index 4caf73dc7a..809ba86e63 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_RTC_MEM select HAS_PERIPH_RTT select HAS_PERIPH_TIMER select HAS_PERIPH_TIMER_PERIODIC diff --git a/cpu/gd32v/Makefile.features b/cpu/gd32v/Makefile.features index d7a4e16adc..e2134f9062 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_rtc_mem FEATURES_PROVIDED += periph_rtt FEATURES_PROVIDED += periph_timer FEATURES_PROVIDED += periph_timer_periodic diff --git a/cpu/gd32v/periph/rtc_mem.c b/cpu/gd32v/periph/rtc_mem.c new file mode 100644 index 0000000000..c6ee050c03 --- /dev/null +++ b/cpu/gd32v/periph/rtc_mem.c @@ -0,0 +1,107 @@ +/* + * Copyright (C) 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 backup memory implementation for GD32VF103 + * + * @author Gunar Schorcht + * @} + */ + +#include + +#include "cpu.h" +#include "periph/rtc_mem.h" + +#define ENABLE_DEBUG 0 +#include "debug.h" + +#define RTC_MEM_SIZE 84 /* RTC data register size in byte */ + +extern void rtc_lock(void); +extern void rtc_unlock(void); + +/* Since the registers are only 16-bit, but 32-bit aligned and not linearly + * addressed, it makes more sense to write and read byte by byte instead of + * using memcpy */ + +static volatile uint16_t *_rtc_mem_data_reg(unsigned addr) +{ + /* This function determines the register address of the 16-bit BKP data + * register which are 32-bit aligned and not addressed linearly. The + * layout is the following: + * + * addr 0, 1, ..., 9 are @0x40006c00 + 0x04, 0x08, ...,0x28 + * addr 10, 11, ..., 41 are @0x40006c00 + 0x40, 0x44, ...,0xbc + */ + + /* 16-bit data register index */ + unsigned reg_index = addr >> 1; + /* 16-bit data register address as multiple of 32 bit */ + return (reg_index < 10) ? &BKP->DATA0 + (reg_index << 1) + : &BKP->DATA10 + ((reg_index - 10) << 1); +} + +static void _rtc_mem_write_byte(unsigned addr, uint8_t byte) +{ + volatile uint16_t *reg = _rtc_mem_data_reg(addr); + if (addr % 2) { + /* high byte */ + *reg &= 0x00ff; + *reg |= (uint16_t)byte << 8; + } + else { + /* low byte */ + *reg &= 0xff00; + *reg |= byte; + } +} + +static uint8_t _rtc_mem_read_byte(unsigned addr) +{ + volatile uint16_t *reg = _rtc_mem_data_reg(addr); + return (addr % 2) ? (*reg & 0xff00) >> 8 : *reg & 0x00ff; +} + +size_t rtc_mem_size(void) +{ + return RTC_MEM_SIZE; +} + +void rtc_mem_write(unsigned offset, const void *data, size_t len) +{ + assert(offset + len <= rtc_mem_size()); + + /* 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; + + for (unsigned i = 0; i < len; i++) { + _rtc_mem_write_byte(offset++, ((uint8_t *)data)[i]); + } + + /* disable write access to backup domain registers */ + PMU->CTL &= ~PMU_CTL_BKPWEN_Msk; +} + +void rtc_mem_read(unsigned offset, void *data, size_t len) +{ + assert(offset + len <= rtc_mem_size()); + + /* enable APB1 clocks */ + RCU->APB1EN |= RCU_APB1EN_PMUEN_Msk | RCU_APB1EN_BKPIEN_Msk; + + for (unsigned i = 0; i < len; i++) { + ((uint8_t *)data)[i] = _rtc_mem_read_byte(offset++); + } +}