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++); + } +} diff --git a/tests/driver_dac_dds/main.c b/tests/driver_dac_dds/main.c index 43e9f93b18..ac8adcb1db 100644 --- a/tests/driver_dac_dds/main.c +++ b/tests/driver_dac_dds/main.c @@ -98,24 +98,17 @@ typedef void (*sample_gen_t)(uint8_t *dst, size_t len, uint16_t period); static void _fill_saw_samples_8(uint8_t *buf, size_t len, uint16_t period) { - uint8_t x = 0; - unsigned step = 0xFF / period; - for (uint16_t i = 0; i < len; ++i) { - x += step; - buf[i] = x; + buf[i] = (i * 0xFFUL) / period; } } static void _fill_saw_samples_16(uint8_t *buf, size_t len, uint16_t period) { - uint16_t x = 0; - unsigned step = 0xFFFF / period; - for (uint16_t i = 0; i < len; ++i) { - x += step; - buf[i] = x; - buf[++i] = x >> 8; + uint16_t y = (i * 0xFFFFUL) / period; + buf[i] = y; + buf[++i] = y >> 8; } } @@ -126,8 +119,7 @@ static void _fill_sine_samples_8(uint8_t *buf, size_t len, uint16_t period) for (uint16_t i = 0; i < period; ++i) { x += step; - buf[i] = isin(x) >> 5; - buf[i] += INT8_MAX + 1; + buf[i] = (isin(x) + 4096) >> 6; } for (uint16_t i = period; i < len; i += period) { @@ -145,8 +137,7 @@ static void _fill_sine_samples_16(uint8_t *buf, size_t len, uint16_t period) for (uint16_t i = 0; i < period; ++i) { x += step; - uint16_t y = isin(x); - y += INT16_MAX + 1; + uint16_t y = (isin(x) + 4096) << 2; buf[i] = y; buf[++i] = y >> 8; } diff --git a/tests/periph_rtt/main.c b/tests/periph_rtt/main.c index 7095a9f7f0..57fe608292 100644 --- a/tests/periph_rtt/main.c +++ b/tests/periph_rtt/main.c @@ -65,7 +65,7 @@ static void _set_rtc_mem(void) static void _get_rtc_mem(void) { - char buf[4]; + char buf[sizeof(riot_msg) - 1]; rtc_mem_read(riot_msg_offset, buf, sizeof(buf)); if (memcmp(buf, riot_msg, sizeof(buf))) {