Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

drivers/periph: define rtc_mem and implement it for sam0_common #16758

Merged
merged 4 commits into from
Sep 3, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
82 changes: 82 additions & 0 deletions cpu/sam0_common/periph/rtc_rtt.c
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
*/

#include <stdint.h>
#include <string.h>
#include "periph/rtc.h"
#include "periph/rtt.h"
#include "periph_conf.h"
Expand Down Expand Up @@ -215,10 +216,70 @@ static void _rtt_clock_setup(void)
#endif /* MODULE_PERIPH_RTT */
#endif /* !CPU_COMMON_SAMD21 - Clock Setup */

#ifdef MODULE_PERIPH_RTC_MEM
/* first two GP registers are shared with COMP[0] / ALARM[0] */
#ifdef RTC_MODE2_CTRLB_GP2EN
#define RTC_GPR_START (2)
#else
#define RTC_GPR_START (0)
#endif

#define RTC_GPR_NUM_AVAIL (RTC_GPR_NUM - RTC_GPR_START)
#define RTC_MEM_SIZE (RTC_GPR_NUM_AVAIL * sizeof(uint32_t))

size_t rtc_mem_size(void)
{
return RTC_MEM_SIZE;
}

static void _read_gp(uint32_t *dst)
{
for (unsigned i = RTC_GPR_START; i < RTC_GPR_NUM; ++i) {
dst[i - RTC_GPR_START] = RTC->MODE0.GP[i].reg;
}
}

static void _write_gp(const uint32_t *src)
{
for (unsigned i = RTC_GPR_START; i < RTC_GPR_NUM; ++i) {
_wait_syncbusy();
RTC->MODE0.GP[i].reg = src[i - RTC_GPR_START];
}
}

void rtc_mem_read(unsigned offset, void *data, size_t len)
{
uint32_t tmp[RTC_GPR_NUM_AVAIL];

if (offset + len > RTC_MEM_SIZE) {
assert(0);
return;
}

_read_gp(tmp);
memcpy(data, ((uint8_t *)tmp) + offset, len);
}

void rtc_mem_write(unsigned offset, void *data, size_t len)
{
uint32_t tmp[RTC_GPR_NUM_AVAIL];

if (offset + len > RTC_MEM_SIZE) {
assert(0);
return;
}

_read_gp(tmp);
memcpy(((uint8_t *)tmp) + offset, data, len);
_write_gp(tmp);
}
#endif /* MODULE_PERIPH_RTC_MEM */

#ifdef MODULE_PERIPH_RTC
static void _rtc_init(void)
{
#ifdef REG_RTC_MODE2_CTRLA
/* skip reset if already in RTC mode */
if (RTC->MODE2.CTRLA.bit.MODE == RTC_MODE2_CTRLA_MODE_CLOCK_Val) {
return;
}
Expand All @@ -229,6 +290,11 @@ static void _rtc_init(void)
RTC->MODE2.CTRLA.reg = RTC_MODE2_CTRLA_PRESCALER_DIV1024 /* CLK_RTC_CNT = 1KHz / 1024 -> 1Hz */
| RTC_MODE2_CTRLA_CLOCKSYNC /* Clock Read Synchronization Enable */
| RTC_MODE2_CTRLA_MODE_CLOCK;
#ifdef RTC_MODE2_CTRLB_GP2EN
/* RTC driver does not use COMP[1] or ALARM[1] */
/* Use second set of Compare registers as general purpose register */
RTC->MODE2.CTRLB.reg = RTC_MODE2_CTRLB_GP2EN;
#endif
#else
if (RTC->MODE2.CTRL.bit.MODE == RTC_MODE2_CTRL_MODE_CLOCK_Val) {
return;
Expand Down Expand Up @@ -268,10 +334,26 @@ void rtc_init(void)
#ifdef MODULE_PERIPH_RTT
void rtt_init(void)
{

_rtt_clock_setup();
_poweron();

#ifdef MODULE_PERIPH_RTC_MEM
uint32_t backup[RTC_GPR_NUM_AVAIL];
_read_gp(backup);
#endif

_rtt_reset();

#ifdef MODULE_PERIPH_RTC_MEM
#ifdef RTC_MODE2_CTRLB_GP2EN
/* RTC driver does not use COMP[1] or ALARM[1] */
/* Use second set of Compare registers as general purpose register */
RTC->MODE2.CTRLB.reg = RTC_MODE2_CTRLB_GP2EN;
#endif
_write_gp(backup);
#endif /* MODULE_PERIPH_RTC_MEM */

/* set 32bit counting mode & enable the RTC */
#ifdef REG_RTC_MODE0_CTRLA
RTC->MODE0.CTRLA.reg = RTC_MODE0_CTRLA_MODE(0)
Expand Down
1 change: 1 addition & 0 deletions cpu/samd5x/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ config CPU_COMMON_SAMD5X
select HAS_PERIPH_DMA
select HAS_PERIPH_GPIO_TAMPER_WAKE
select HAS_PERIPH_HWRNG
select HAS_PERIPH_RTC_MEM
select HAS_PERIPH_SPI_ON_QSPI

config CPU_FAM_SAMD51
Expand Down
1 change: 1 addition & 0 deletions cpu/samd5x/Makefile.features
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ FEATURES_PROVIDED += periph_hwrng
FEATURES_PROVIDED += backup_ram
FEATURES_PROVIDED += cortexm_mpu
FEATURES_PROVIDED += periph_gpio_tamper_wake
FEATURES_PROVIDED += periph_rtc_mem
FEATURES_PROVIDED += periph_spi_on_qspi

include $(RIOTCPU)/sam0_common/Makefile.features
1 change: 1 addition & 0 deletions cpu/saml21/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ config CPU_COMMON_SAML21
select HAS_CPU_SAML21
select HAS_PERIPH_DMA
select HAS_PERIPH_GPIO_FAST_READ
select HAS_PERIPH_RTC_MEM

config CPU_FAM_SAML21
bool
Expand Down
1 change: 1 addition & 0 deletions cpu/saml21/Makefile.features
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ FEATURES_PROVIDED += periph_gpio_fast_read
# It can still be used in normal and standby mode, but code that relies on it
# being availiable during deep sleep / backup mode will not be portable here.
FEATURES_PROVIDED += backup_ram
FEATURES_PROVIDED += periph_rtc_mem

ifeq (,$(filter $(CPU_MODELS_WITHOUT_HWRNG),$(CPU_MODEL)))
FEATURES_PROVIDED += periph_hwrng
Expand Down
70 changes: 70 additions & 0 deletions drivers/include/periph/rtc_mem.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
/*
* Copyright (C) 2021 ML!PA Consulting GmbH
*
* 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.
*/

/**
* @defgroup drivers_periph_rtc_mem Low-Power RTC Memory
* @ingroup drivers_periph_rtc
* @brief Low-level RTC Memory peripheral driver
*
* This API provides an interface to access low-power memory present on some RTCs.
* This memory is retained even when the rest of the system is powered off.
*
* @{
* @file
* @brief Low-level RTC memory peripheral driver interface definitions
*
* @author Benjamin Valentin <[email protected]>
*/

#ifndef PERIPH_RTC_MEM_H
#define PERIPH_RTC_MEM_H

#include <stddef.h>
#include <stdint.h>

#ifdef __cplusplus
extern "C" {
#endif

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need to tie this to rtc? For stm32 this could be used regardless of the rtc.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If STM32 have persistent GP registers across reset we can extend and move this interface somewhere later.

/**
* @brief Get the amount of RTC memory.
*
* @return The usable amount of RTC memory in bytes
*/
size_t rtc_mem_size(void);

/**
* @brief Read from RTC memory
*
* @note Reading beyond @ref rtc_mem_size are illegal and trigger an
* assertion / be discarded.
*
* @param[in] offset Offset to the start of RTC memory in bytes
* @param[out] data Destination buffer
* @param[in] len Amount of bytes to read
*/
void rtc_mem_read(unsigned offset, void *data, size_t len);

/**
* @brief Write to RTC memory
*
* @note Writing beyond @ref rtc_mem_size are illegal and trigger an
* assertion / be discarded.
*
* @param[in] offset Offset to the start of RTC memory in bytes
* @param[in] data Source buffer
* @param[in] len Amount of bytes to write
*/
void rtc_mem_write(unsigned offset, const void *data, size_t len);

#ifdef __cplusplus
}
#endif

#endif /* PERIPH_RTC_MEM_H */
/** @} */
5 changes: 5 additions & 0 deletions kconfigs/Kconfig.features
Original file line number Diff line number Diff line change
Expand Up @@ -257,6 +257,11 @@ config HAS_PERIPH_RTC
help
Indicates that an RTC peripheral is present.

config HAS_PERIPH_RTC_MEM
bool
help
Indicates that the RTC peripheral provides storage memory for deep sleep.

config HAS_PERIPH_RTC_MS
bool
help
Expand Down
1 change: 1 addition & 0 deletions tests/periph_rtc/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ include ../Makefile.tests_common

FEATURES_REQUIRED += periph_rtc
FEATURES_OPTIONAL += periph_rtc_ms
FEATURES_OPTIONAL += periph_rtc_mem

DISABLE_MODULE += periph_init_rtc

Expand Down
73 changes: 65 additions & 8 deletions tests/periph_rtc/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,12 @@

#include <stdio.h>
#include <time.h>
#include <string.h>

#include "mutex.h"
#include "periph_conf.h"
#include "periph/rtc.h"
#include "periph/rtc_mem.h"
#include "xtimer.h"

#define PERIOD (2U)
Expand Down Expand Up @@ -69,6 +71,58 @@ static void cb(void *arg)
mutex_unlock(arg);
}

#ifdef MODULE_PERIPH_RTC_MEM
static const uint8_t riot_msg_offset = 1;
static const char riot_msg[] = "RIOT";
static void _set_rtc_mem(void)
{
/* first fill the whole memory */
uint8_t size = rtc_mem_size();
while (size--) {
rtc_mem_write(size, &size, sizeof(size));
}

/* write test data */
rtc_mem_write(riot_msg_offset, riot_msg, sizeof(riot_msg) - 1);
}

static void _get_rtc_mem(void)
{
char buf[4];
rtc_mem_read(riot_msg_offset, buf, sizeof(buf));

if (memcmp(buf, riot_msg, sizeof(buf))) {
puts("RTC mem content does not match");
for (unsigned i = 0; i < sizeof(buf); ++i) {
printf("%02x - %02x\n", riot_msg[i], buf[i]);
}
return;
}

uint8_t size = rtc_mem_size();
while (size--) {
uint8_t data;

if (size >= riot_msg_offset &&
size < riot_msg_offset + sizeof(riot_msg)) {
continue;
}

rtc_mem_read(size, &data, 1);
if (data != size) {
puts("RTC mem content does not match");
printf("%02x: %02x\n", size, data);
}
}


puts("RTC mem OK");
}
#else
static inline void _set_rtc_mem(void) {}
static inline void _get_rtc_mem(void) {}
#endif

int main(void)
{
struct tm time = {
Expand All @@ -88,6 +142,9 @@ int main(void)

rtc_init();

_set_rtc_mem();
_get_rtc_mem();

/* set RTC */
print_time(" Setting clock to ", &time);
rtc_set_time(&time);
Expand Down Expand Up @@ -149,17 +206,17 @@ int main(void)
puts("");

/* loop over a few alarm cycles */
while (1) {
do {
mutex_lock(&rtc_mtx);
puts("Alarm!");

if (++cnt < REPEAT) {
struct tm time;
rtc_get_alarm(&time);
inc_secs(&time, PERIOD);
rtc_set_alarm(&time, cb, &rtc_mtx);
}
}
struct tm time;
rtc_get_alarm(&time);
inc_secs(&time, PERIOD);
rtc_set_alarm(&time, cb, &rtc_mtx);
} while (++cnt < REPEAT);

_get_rtc_mem();

return 0;
}
1 change: 1 addition & 0 deletions tests/periph_rtt/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ include ../Makefile.tests_common

FEATURES_REQUIRED = periph_rtt
FEATURES_OPTIONAL += periph_rtt_set_counter
FEATURES_OPTIONAL += periph_rtc_mem

DISABLE_MODULE += periph_init_rtt

Expand Down
Loading