1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2024-12-29 04:50:03 +01:00

Merge pull request #11486 from benpicco/saml21-lpram

cpu/saml21: Make Low-Power SRAM available to programs
This commit is contained in:
Dylan Laduranty 2019-10-01 21:02:42 +02:00 committed by GitHub
commit aed628f08b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 202 additions and 3 deletions

View File

@ -15,6 +15,12 @@ ifneq (,$(ROM_START_ADDR)$(RAM_START_ADDR)$(ROM_LEN)$(RAM_LEN))
LINKFLAGS += $(LINKFLAGPREFIX)--defsym=_ram_length=$(RAM_LEN)
endif
ifneq (,$(BACKUP_RAM_LEN))
LINKFLAGS += $(LINKFLAGPREFIX)--defsym=_backup_ram_start_addr=$(BACKUP_RAM_ADDR)
LINKFLAGS += $(LINKFLAGPREFIX)--defsym=_backup_ram_len=$(BACKUP_RAM_LEN)
CFLAGS += -DCPU_HAS_BACKUP_RAM=1
endif
TOOLCHAINS_SUPPORTED = gnu llvm
# Only define the linker symbol if the variable is set

View File

@ -24,8 +24,8 @@ INCLUDE cortexm_rom_offset.ld
MEMORY
{
rom (rx) : ORIGIN = _rom_start_addr + _rom_offset, LENGTH = _fw_rom_length
ram (w!rx) : ORIGIN = _ram_start_addr, LENGTH = _ram_length
rom (rx) : ORIGIN = _rom_start_addr + _rom_offset, LENGTH = _fw_rom_length
ram (w!rx) : ORIGIN = _ram_start_addr, LENGTH = _ram_length
}
INCLUDE cortexm_base.ld

View File

@ -34,6 +34,15 @@ SEARCH_DIR(.)
/* This is only used by gdb to understand where to start */
ENTRY(reset_handler_default)
_backup_ram_start_addr = DEFINED( _backup_ram_start_addr ) ? _backup_ram_start_addr : 0x0 ;
_backup_ram_len = DEFINED( _backup_ram_len ) ? _backup_ram_len : 0x0 ;
/* not all Cortex-M platforms use cortexm.ld yet */
MEMORY
{
bkup-ram (w!rx) : ORIGIN = _backup_ram_start_addr, LENGTH = _backup_ram_len
}
/* Section Definitions */
SECTIONS
{
@ -159,4 +168,21 @@ SECTIONS
/* Populate information about ram size */
_sram = ORIGIN(ram);
_eram = ORIGIN(ram) + LENGTH(ram);
_sbackup_data_load = LOADADDR(.backup.data);
.backup.data : ALIGN(4) {
_sbackup_data = .;
*(.backup.data)
_ebackup_data = .;
/* Round size so that we can use 4 byte copy in init */
. = ALIGN(4);
} > bkup-ram AT> rom
.backup.bss (NOLOAD) : ALIGN(4) {
_sbackup_bss = .;
*(.backup.bss)
_ebackup_bss = .;
/* Round size so that we can use 4 byte copy in init */
. = ALIGN(4);
} > bkup-ram
}

View File

@ -26,6 +26,7 @@
#include <inttypes.h>
#include "cpu.h"
#include "periph_cpu.h"
#include "kernel_init.h"
#include "board.h"
#include "mpu.h"
@ -39,6 +40,10 @@
#define SRAM_BASE 0
#endif
#ifndef CPU_BACKUP_RAM_NOT_RETAINED
#define CPU_BACKUP_RAM_NOT_RETAINED 0
#endif
/**
* @brief Memory markers, defined in the linker script
* @{
@ -54,6 +59,15 @@ extern uint32_t _sstack;
extern uint32_t _estack;
extern uint8_t _sram;
extern uint8_t _eram;
/* Support for LPRAM. */
#ifdef CPU_HAS_BACKUP_RAM
extern const uint32_t _sbackup_data_load[];
extern uint32_t _sbackup_data[];
extern uint32_t _ebackup_data[];
extern uint32_t _sbackup_bss[];
extern uint32_t _ebackup_bss[];
#endif /* CPU_HAS_BACKUP_RAM */
/** @} */
/**
@ -78,7 +92,7 @@ __attribute__((weak)) void post_startup (void)
void reset_handler_default(void)
{
uint32_t *dst;
uint32_t *src = &_etext;
const uint32_t *src = &_etext;
#ifdef MODULE_PUF_SRAM
puf_sram_init((uint8_t *)&_srelocate, SEED_RAM_LEN);
@ -101,11 +115,30 @@ void reset_handler_default(void)
for (dst = &_srelocate; dst < &_erelocate; ) {
*(dst++) = *(src++);
}
/* default bss section to zero */
for (dst = &_szero; dst < &_ezero; ) {
*(dst++) = 0;
}
#ifdef CPU_HAS_BACKUP_RAM
if (!cpu_woke_from_backup() ||
CPU_BACKUP_RAM_NOT_RETAINED) {
/* load low-power data section. */
for (dst = _sbackup_data, src = _sbackup_data_load;
dst < _ebackup_data;
dst++, src++) {
*dst = *src;
}
/* zero-out low-power bss. */
for (dst = _sbackup_bss; dst < _ebackup_bss; dst++) {
*dst = 0;
}
}
#endif /* CPU_HAS_BACKUP_RAM */
#ifdef MODULE_MPU_STACK_GUARD
if (((uintptr_t)&_sstack) != SRAM_BASE) {
mpu_configure(

View File

@ -476,6 +476,18 @@ static inline void sercom_set_gen(void *sercom, uint32_t gclk)
#endif
}
/**
* @brief Returns true if the CPU woke deep sleep (backup/standby)
*/
static inline bool cpu_woke_from_backup(void)
{
#ifdef RSTC_RCAUSE_BACKUP
return RSTC->RCAUSE.bit.BACKUP;
#else
return false;
#endif
}
/**
* @brief ADC Channel Configuration
*/

View File

@ -1,3 +1,4 @@
FEATURES_PROVIDED += periph_hwrng
FEATURES_PROVIDED += backup_ram
include $(RIOTCPU)/sam0_common/Makefile.features

View File

@ -8,5 +8,8 @@ RIOTBOOT_LEN ?= 0x4000
USEMODULE += pm_layered
BACKUP_RAM_ADDR = 0x47000000
BACKUP_RAM_LEN = 0x2000
include $(RIOTCPU)/sam0_common/Makefile.include
include $(RIOTMAKE)/arch/cortexm.inc.mk

View File

@ -1,8 +1,15 @@
# The SAMR30 line of MCUs does not contain a TRNG
BOARDS_WITHOUT_HWRNG += samr30-xpro
# Low Power SRAM is *not* retained during Backup Sleep.
# It therefore does not fulfill the requirements of the 'backup_ram' interface.
# 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
ifeq (,$(filter $(BOARDS_WITHOUT_HWRNG),$(BOARD)))
FEATURES_PROVIDED += periph_hwrng
endif
include $(RIOTCPU)/sam0_common/Makefile.features

View File

@ -3,5 +3,10 @@ export CPU_FAM = saml21
USEMODULE += pm_layered
ifneq (,$(filter saml21j18b saml21j18a samr30g18a samr34j18b,$(CPU_MODEL)))
BACKUP_RAM_ADDR = 0x30000000
BACKUP_RAM_LEN = 0x2000
endif
include $(RIOTCPU)/sam0_common/Makefile.include
include $(RIOTMAKE)/arch/cortexm.inc.mk

View File

@ -26,6 +26,11 @@
extern "C" {
#endif
/**
* @brief The Low Power SRAM is not retained during deep sleep.
*/
#define CPU_BACKUP_RAM_NOT_RETAINED (1)
/**
* @brief Mapping of pins to EXTI lines, -1 means not EXTI possible
*/

View File

@ -0,0 +1,11 @@
include ../Makefile.tests_common
FEATURES_REQUIRED = backup_ram
USEMODULE += pm_layered
USEMODULE += periph_rtc
USEMODULE += xtimer
CFLAGS += -DLOG_LEVEL=LOG_WARNING
include $(RIOTBASE)/Makefile.include

View File

@ -0,0 +1,10 @@
Expected result
===============
This test periodically puts the device into deep sleep mode.
During deep sleep only the backup RAM is retained and the device is
reset upon leaving deep sleep.
To test the memory retention, a counter is incemented with each wake-up.
Background
==========
Test the functionality of a platforms Backup RAM implementation.

View File

@ -0,0 +1,80 @@
/*
* Copyright (C) 2019 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.
*/
/**
* @ingroup tests
* @{
*
* @file
* @brief Low-level test for backup RAM
*
* @author Benjamin Valentin <benjamin.valentin@ml-pa.com>
*
* @}
*/
#include <stdio.h>
#include "periph/rtc.h"
#include "pm_layered.h"
#include "xtimer.h"
#ifndef SLEEP_SEC
#define SLEEP_SEC 1
#endif
#ifndef DELAY_SEC
#define DELAY_SEC 3
#endif
int main(void)
{
/* We keep a copy of counter in the .noinit section (normal RAM).
* In the deepest sleep normal RAM is not retained, so if it matches
* counter anyway after wakeup, we did not sleep properly.
*/
static int counter_noinit __attribute__((section(".noinit")));
static int counter __attribute__((section(".backup.bss")));
if (counter == 0) {
puts("\nBackup RAM test\n");
printf("This test will increment the counter by 1, "
"then enter deep sleep for %ds.\n\n", SLEEP_SEC);
printf(" Because some tools have trouble re-flashing/debugging in deep sleep,\n"
" the test will wait for %ds before entering deep sleep.\n\n", DELAY_SEC);
} else if (counter_noinit == counter) {
puts("WARNING: non-backup memory retained - did we really enter deep sleep?");
}
printf("counter: %d\n", ++counter);
counter_noinit = counter;
/* Some tools have trouble flashing MCUs in deep sleep.
* Wait a bit to make re-flashing / debugging easier.
*/
xtimer_sleep(DELAY_SEC);
#ifndef CPU_BACKUP_RAM_NOT_RETAINED
/* schedule RTC wake in SLEEP_SEC s */
struct tm time;
rtc_get_time(&time);
time.tm_sec += SLEEP_SEC;
rtc_set_alarm(&time, NULL, NULL);
/* put the device in deep sleep */
pm_set(0);
puts("would sleep now - YOU SHOULD NOT SEE THIS!");
#else
puts("low power RAM not retained during sleep - aborting test.");
#endif
return 0;
}