1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2024-12-29 04:50:03 +01:00
RIOT/cpu/lpc2387/cpu.c
Benjamin Valentin 32bbba2fc5 cpu/lpc2387: add support for backup RAM
lpc23xx has 2k of battery RAM that is retained in Deep Power Down mode.

To not overwrite that data it must only be initialized on Power On Reset.
However, RSIR looks the same when waking up from Deep Power Down as it does
on the power-on case.

So use 4 bytes of the backup RAM to keep a signature that is only valid if
memory was retained (no power-on Reset).

A small change to the linker script is required so two sections can be
placed into flash.
2019-11-28 11:33:03 +01:00

173 lines
4.2 KiB
C

/*
* Copyright (C) 2013, Freie Universitaet Berlin (FUB). All rights reserved.
*
* 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_lpc2387
* @{
*/
#include <stdint.h>
#include "cpu.h"
#include "irq.h"
#include "VIC.h"
#include "stdio_base.h"
#include "periph/init.h"
void lpc2387_pclk_scale(uint32_t source, uint32_t target, uint32_t *pclksel, uint32_t *prescale)
{
uint32_t pclkdiv;
*prescale = source / target;
if ((*prescale % 16) == 0) {
*pclksel = 3;
pclkdiv = 8;
}
else if ((*prescale % 8) == 0) {
*pclksel = 0;
pclkdiv = 4;
}
else if ((*prescale % 4) == 0) {
*pclksel = 2;
pclkdiv = 2;
}
else {
*pclksel = 1;
pclkdiv = 1;
}
*prescale /= pclkdiv;
if (*prescale % 2) {
(*prescale)++;
}
}
void cpu_clock_scale(uint32_t source, uint32_t target, uint32_t *prescale)
{
uint32_t pclksel;
lpc2387_pclk_scale(source, target, &pclksel, prescale);
PCLKSEL0 = (PCLKSEL0 & ~(BIT2 | BIT3)) | (pclksel << 2); /* timer 0 */
PCLKSEL0 = (PCLKSEL0 & ~(BIT4 | BIT5)) | (pclksel << 4); /* timer 1 */
PCLKSEL1 = (PCLKSEL1 & ~(BIT12 | BIT13)) | (pclksel << 12); /* timer 2 */
}
/******************************************************************************
** Function name: install_irq
**
** Descriptions: Install interrupt handler
** parameters: Interrupt number, interrupt handler address,
** interrupt priority
** Returned value: true or false, return false if IntNum is out of range
**
******************************************************************************/
#define VIC_BASE_ADDR 0xFFFFF000
bool install_irq(int IntNumber, void (*HandlerAddr)(void), int Priority)
{
VICIntEnClr = 1 << IntNumber; /* Disable Interrupt */
if (IntNumber >= VIC_SIZE) {
return (false);
}
else {
/* find first un-assigned VIC address for the handler */
int *vect_addr = (int *)(VIC_BASE_ADDR + VECT_ADDR_INDEX + IntNumber * 4);
int *vect_cntl = (int *)(VIC_BASE_ADDR + VECT_CNTL_INDEX + IntNumber * 4);
*vect_addr = (int)HandlerAddr; /* set interrupt vector */
*vect_cntl = Priority;
VICIntEnable = 1 << IntNumber; /* Enable Interrupt */
return(true);
}
}
void arm_reset(void)
{
/*
* We abuse the watchdog timer for a reset.
*/
irq_disable();
/* Set the watchdog timeout constant to 0xFFFF */
WDTC = 0xFFFF;
/*
* Enable watchdog interrupt and enable reset on watchdog timeout.
* (The reset on watchdog timeout flag is ignored, if interrupt on watchdog
* timeout is not set. Thus, we set both. The reset takes precedence over
* the interrupt, anyway.)
*/
WDMOD = 0x03;
/*
* Feed the watchdog by writing 0xAA followed by 0x55:
* Reload the watchdog timer with the value in WDTC (0xFFFF)
*/
WDFEED = 0xAA;
WDFEED = 0x55;
/* Wait for the watchdog timer to expire, thus performing a reset */
while(1) {}
}
/**
* @brief Initialize the CPU, set IRQ priorities, clocks
*/
void cpu_init(void)
{
extern void board_init(void);
/* configure CPU clock */
cpu_init_clks();
/* set up GPIOs */
gpio_init_ports();
/* board specific setup of i/o pins */
board_init();
/* initialize stdio prior to periph_init() to allow use of DEBUG() there */
stdio_init();
/* trigger static peripheral initialization */
periph_init();
}
/* RSIR will only have POR bit set even when waking up from Deep Power Down
* Use signature in battery RAM to discriminate between Deep Power Down and POR
*/
bool cpu_woke_from_backup(void)
{
static char signature[] __attribute__((section(".backup.data"))) = {
'R', 'I', 'O', 'T'
};
/* external reset */
if (RSIR & RSIR_EXTR) {
return false;
}
if (signature[0] != 'R') {
return false;
}
if (signature[1] != 'I') {
return false;
}
if (signature[2] != 'O') {
return false;
}
if (signature[3] != 'T') {
return false;
}
return true;
}
/** @} */