Skip to content

Commit

Permalink
cpu/gd32v: add periph_rtc_mem support
Browse files Browse the repository at this point in the history
  • Loading branch information
gschorcht committed Feb 6, 2023
1 parent f0f9a02 commit dc5a1e9
Show file tree
Hide file tree
Showing 3 changed files with 109 additions and 0 deletions.
1 change: 1 addition & 0 deletions cpu/gd32v/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
1 change: 1 addition & 0 deletions cpu/gd32v/Makefile.features
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
107 changes: 107 additions & 0 deletions cpu/gd32v/periph/rtc_mem.c
Original file line number Diff line number Diff line change
@@ -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 <gunar@schorcht.net>
* @}
*/

#include <string.h>

#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++);
}
}

0 comments on commit dc5a1e9

Please sign in to comment.