aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--examples/test-bkp.cpp78
-rw-r--r--libmaple/bkp.c110
-rw-r--r--libmaple/bkp.h98
-rw-r--r--libmaple/pwr.c42
-rw-r--r--libmaple/pwr.h64
-rw-r--r--libmaple/rcc.c20
-rw-r--r--libmaple/rcc.h6
7 files changed, 322 insertions, 96 deletions
diff --git a/examples/test-bkp.cpp b/examples/test-bkp.cpp
new file mode 100644
index 0000000..27f87bd
--- /dev/null
+++ b/examples/test-bkp.cpp
@@ -0,0 +1,78 @@
+#include <stdio.h>
+
+#include "wirish.h"
+#include "bkp.h"
+#include "iwdg.h"
+
+void print_bkp_contents();
+void write_to_bkp(uint16 val);
+
+void setup() {
+ pinMode(BOARD_BUTTON_PIN, INPUT);
+
+ Serial2.begin(9600);
+ Serial2.println("*** Beginning BKP test");
+
+ Serial2.println("Init...");
+ bkp_init();
+ Serial2.println("Done.");
+
+ print_bkp_contents();
+ write_to_bkp(10);
+ print_bkp_contents();
+
+ Serial2.println("Enabling backup writes.");
+ bkp_enable_writes();
+ write_to_bkp(20);
+ print_bkp_contents();
+
+ Serial2.println("Disabling backup writes.");
+ bkp_disable_writes();
+ write_to_bkp(30);
+ print_bkp_contents();
+
+ Serial2.println("Done testing backup registers; press button to enable "
+ "independent watchdog (in order to cause a reset).");
+ waitForButtonPress(0);
+ iwdg_init(IWDG_PRE_4, 1);
+ Serial2.println();
+}
+
+void loop() {
+}
+
+void print_bkp_contents() {
+ Serial2.println("Backup data register contents:");
+ char buf[100];
+ for (int i = 1; i <= NR_BKP_REGS; i++) {
+ snprintf(buf, sizeof buf, "DR%d: %d ", i, bkp_read(i));
+ Serial2.print(buf);
+ if (i % 5 == 0) Serial2.println();
+ }
+ Serial2.println();
+}
+
+void write_to_bkp(uint16 val) {
+ Serial2.print("Attempting to write ");
+ Serial2.print(val);
+ Serial2.println(" to backup registers...");
+ for (int i = 1; i <= NR_BKP_REGS; i++) {
+ bkp_write(i, val);
+ }
+ Serial2.println("Done.");
+}
+
+__attribute__((constructor)) void premain() {
+ init();
+}
+
+int main(void) {
+ init();
+ setup();
+
+ while (1) {
+ loop();
+ }
+ return 0;
+}
+
diff --git a/libmaple/bkp.c b/libmaple/bkp.c
index e89abd0..ac9aeae 100644
--- a/libmaple/bkp.c
+++ b/libmaple/bkp.c
@@ -24,63 +24,99 @@
* SOFTWARE.
*****************************************************************************/
-#include "libmaple.h"
#include "bkp.h"
#include "pwr.h"
#include "rcc.h"
#include "util.h"
-/* Data register memory layout is not contiguous. It's split up from
- 1--NR_LOW_DRS, beginning at BKP_LOW_OFFSET, through
- (NR_LOW_DRS+1)--NR_DRS, beginning at BKP_HIGH_OFFSET. */
-#define NR_LOW_DRS 10
-#define BKP_LOW_OFFSET 0x4 /* start offset for data registers 1--10 */
-#define BKP_HIGH_OFFSET 0x40 /* start offset for data registers 11--42 */
+static inline __io uint32* data_register(uint8 reg);
-inline volatile uint16* reg_addr(uint8 reg) {
- if (1 <= reg) {
- if (reg <= NR_LOW_DRS) {
- return (volatile uint16*)(BKP_BASE + BKP_LOW_OFFSET +
- (reg - 1) * 4);
- } else if (reg <= NR_BKP_REGS) {
- return (volatile uint16*)(BKP_BASE + BKP_HIGH_OFFSET +
- (reg - NR_LOW_DRS - 1) * 4);
- }
- }
- return 0;
-}
+bkp_dev bkp = {
+ .regs = BKP_BASE,
+};
-void bkp_init(void) {
- /* Set PWREN (28) and BKPEN (27) bits */
- __set_bits(RCC_APB1ENR, BIT(28) | BIT(27));
-}
+const bkp_dev *BKP = &bkp;
-void bkp_disable(void) {
- __clear_bits(RCC_APB1ENR, BIT(28) | BIT(27));
+/**
+ * @brief Initialize backup interface.
+ *
+ * Enables the power and backup interface clocks, and resets the
+ * backup device.
+ */
+void bkp_init(void) {
+ /* Don't call pwr_init(), or you'll reset the device. We just
+ * need the clock. */
+ rcc_clk_enable(RCC_PWR);
+ rcc_clk_enable(RCC_BKP);
+ rcc_reset_dev(RCC_BKP);
}
+/**
+ * Enable write access to the backup registers. Backup interface must
+ * be initialized for subsequent register writes to work.
+ * @see bkp_init()
+ */
void bkp_enable_writes(void) {
- /* Set the DBP bit in PWR_CR */
- __write(BITBAND_PERI(PWR_CR, PWR_CR_DBP), 1);
+ __write(BITBAND_PERI(&(PWR_BASE->CR), PWR_CR_DBP), 1);
}
+/**
+ * Disable write access to the backup registers.
+ */
void bkp_disable_writes(void) {
- __write(BITBAND_PERI(PWR_CR, PWR_CR_DBP), 0);
+ __write(BITBAND_PERI(&(PWR_BASE->CR), PWR_CR_DBP), 0);
}
+/**
+ * Read a value from given backup data register.
+ * @param reg Data register to read, from 1 to NR_BKP_REGS (10 on Maple).
+ */
uint16 bkp_read(uint8 reg) {
- volatile uint16* addr = reg_addr(reg);
- if (addr != 0) {
- return *addr;
+ __io uint32* dr = data_register(reg);
+ if (!dr) {
+ ASSERT(0); /* nonexistent register */
+ return 0;
}
- ASSERT(0); /* nonexistent register */
- return 0;
+ return (uint16)*dr;
}
+/**
+ * @brief Write a value to given data register.
+ *
+ * Write access to backup registers must be enabled.
+ *
+ * @param reg Data register to write, from 1 to NR_BKP_REGS (10 on Maple).
+ * @param val Value to write into the register.
+ * @see bkp_enable_writes()
+ */
void bkp_write(uint8 reg, uint16 val) {
- volatile uint16* addr = reg_addr(reg);
- if (addr != 0) {
- *addr = val;
+ __io uint32* dr = data_register(reg);
+ if (!dr) {
+ ASSERT(0); /* nonexistent register */
+ return;
+ }
+ *dr = (uint32)val;
+}
+
+/*
+ * Data register memory layout is not contiguous. It's split up from
+ * 1--NR_LOW_DRS, beginning at BKP_BASE->DR1, through to
+ * (NR_LOW_DRS+1)--NR_BKP_REGS, beginning at BKP_BASE->DR10.
+ */
+#define NR_LOW_DRS 10
+
+static inline __io uint32* data_register(uint8 reg) {
+ if (reg < 1 || reg > NR_BKP_REGS) {
+ return 0;
+ }
+
+#if NR_BKP_REGS == NR_LOW_DRS
+ return (uint32*)BKP_BASE + reg;
+#else
+ if (reg <= NR_LOW_DRS) {
+ return (uint32*)BKP_BASE + reg;
+ } else {
+ return (uint32*)&(BKP_BASE->DR11) + (reg - NR_LOW_DRS - 1);
}
- ASSERT(0); /* nonexistent register */
+#endif
}
diff --git a/libmaple/bkp.h b/libmaple/bkp.h
index 9ad4c41..ce8e6c7 100644
--- a/libmaple/bkp.h
+++ b/libmaple/bkp.h
@@ -32,51 +32,83 @@
#ifndef _BKP_H_
#define _BKP_H_
+#include "libmaple.h"
+
#ifdef __cplusplus
extern "C" {
#endif
-#define BKP_BASE 0x40006C00
-#define BKP_RTCCR (BKP_BASE + 0x2C)
-#define BKP_CR (BKP_BASE + 0x30)
-#define BKP_CSR (BKP_BASE + 0x34)
-
-/**
- * Initialize backup interface. This function enables the power and
- * backup interface clocks. It does not enable write access to the
- * backup registers.
- */
-void bkp_init(void);
+typedef struct bkp_reg_map {
+ const uint32 RESERVED1;
+ __io uint32 DR1; ///< Data register 1
+ __io uint32 DR2; ///< Data register 2
+ __io uint32 DR3; ///< Data register 3
+ __io uint32 DR4; ///< Data register 4
+ __io uint32 DR5; ///< Data register 5
+ __io uint32 DR6; ///< Data register 6
+ __io uint32 DR7; ///< Data register 7
+ __io uint32 DR8; ///< Data register 8
+ __io uint32 DR9; ///< Data register 9
+ __io uint32 DR10; ///< Data register 10
+ __io uint32 RTCCR; ///< RTC control register
+ __io uint32 CR; ///< Control register
+ __io uint32 CSR; ///< Control and status register
+#if NR_BKP_REGS > 10
+ const uint32 RESERVED2;
+ const uint32 RESERVED3;
+ __io uint32 DR11; ///< Data register 11
+ __io uint32 DR12; ///< Data register 12
+ __io uint32 DR13; ///< Data register 13
+ __io uint32 DR14; ///< Data register 14
+ __io uint32 DR15; ///< Data register 15
+ __io uint32 DR16; ///< Data register 16
+ __io uint32 DR17; ///< Data register 17
+ __io uint32 DR18; ///< Data register 18
+ __io uint32 DR19; ///< Data register 19
+ __io uint32 DR20; ///< Data register 20
+ __io uint32 DR21; ///< Data register 21
+ __io uint32 DR22; ///< Data register 22
+ __io uint32 DR23; ///< Data register 23
+ __io uint32 DR24; ///< Data register 24
+ __io uint32 DR25; ///< Data register 25
+ __io uint32 DR26; ///< Data register 26
+ __io uint32 DR27; ///< Data register 27
+ __io uint32 DR28; ///< Data register 28
+ __io uint32 DR29; ///< Data register 29
+ __io uint32 DR30; ///< Data register 30
+ __io uint32 DR31; ///< Data register 31
+ __io uint32 DR32; ///< Data register 32
+ __io uint32 DR33; ///< Data register 33
+ __io uint32 DR34; ///< Data register 34
+ __io uint32 DR35; ///< Data register 35
+ __io uint32 DR36; ///< Data register 36
+ __io uint32 DR37; ///< Data register 37
+ __io uint32 DR38; ///< Data register 38
+ __io uint32 DR39; ///< Data register 39
+ __io uint32 DR40; ///< Data register 40
+ __io uint32 DR41; ///< Data register 41
+ __io uint32 DR42; ///< Data register 42
+#endif
+} bkp_reg_map;
-/** Disable power and backup interface clocks. */
-void bkp_disable(void);
+typedef struct bkp_dev {
+ bkp_reg_map *regs;
+} bkp_dev;
/**
- * Enable write access to the backup registers. Backup interface must
- * be initialized for subsequent register writes to work.
- * @see bkp_init()
+ * Backup device.
*/
-void bkp_enable_writes(void);
+extern const bkp_dev *BKP;
-/**
- * Disable write access to the backup registers. Does not disable
- * backup interface clocks.
+/*
+ * Backup peripheral base.
*/
-void bkp_disable_writes(void);
+#define BKP_BASE ((bkp_reg_map*)0x40006C00)
-/**
- * Read a value from given backup data register.
- * @param reg Data register to read, from 1 to NR_BKP_REGS (10 on Maple).
- */
+void bkp_init(void);
+void bkp_enable_writes(void);
+void bkp_disable_writes(void);
uint16 bkp_read(uint8 reg);
-
-/**
- * Write a value to given data register. Backup interface must have
- * been previously initialized, and write access to backup registers
- * must be enabled.
- * @param reg Data register to write, from 1 to NR_BKP_REGS (10 on Maple).
- * @param val Value to write into the register.
- */
void bkp_write(uint8 reg, uint16 val);
#ifdef __cplusplus
diff --git a/libmaple/pwr.c b/libmaple/pwr.c
new file mode 100644
index 0000000..b43193e
--- /dev/null
+++ b/libmaple/pwr.c
@@ -0,0 +1,42 @@
+/******************************************************************************
+ * The MIT License
+ *
+ * Copyright (c) 2011 LeafLabs, LLC.
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *****************************************************************************/
+
+#include "pwr.h"
+#include "rcc.h"
+
+pwr_dev pwr = {
+ .regs = PWR_BASE;
+};
+
+const pwr_dev *PWR = &pwr;
+
+/**
+ * Enables the power interface clock, and resets the power device.
+ */
+void pwr_init(void) {
+ rcc_clk_enable(RCC_PWR);
+ rcc_reset_dev(RCC_PWR);
+}
diff --git a/libmaple/pwr.h b/libmaple/pwr.h
index 96a8356..5ff815d 100644
--- a/libmaple/pwr.h
+++ b/libmaple/pwr.h
@@ -29,18 +29,52 @@
* @brief Power control (PWR) defines.
*/
-#define PWR_BASE 0x40007000
-
-#define PWR_CR (PWR_BASE + 0x0)
-#define PWR_CR_DBP 8 /* Disable backup domain write protection bit */
-#define PWR_CR_PVDE 4 /* Power voltage detector enable bit */
-#define PWR_CR_CSBF 3 /* Clear standby flag bit */
-#define PWR_CR_CWUF 2 /* Clear wakeup flag bit */
-#define PWR_CR_PDDS 1 /* Power down deepsleep bit */
-#define PWR_CR_LPDS 0 /* Low-power deepsleep bit */
-
-#define PWR_CSR (PWR_BASE + 0x4)
-#define PWR_CSR_EWUP 8 /* Enable wakeup pin bit */
-#define PWR_CSR_PVDO 2 /* PVD output bit */
-#define PWR_CSR_SBF 1 /* Standby flag bit */
-#define PWR_CSR_WUF 0 /* Wakeup flag bit */
+#include "libmaple.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** Power interface register map. */
+typedef struct pwr_reg_map {
+ __io uint32 CR; /**< Control register */
+ __io uint32 CSR; /**< Control and status register */
+} pwr_reg_map;
+
+/*
+ * Power peripheral base.
+ */
+#define PWR_BASE ((pwr_reg_map*)0x40007000)
+
+/** Power interface device. */
+typedef struct pwr_dev {
+ pwr_reg_map *regs;
+} pwr_dev;
+
+/**
+ * Power device.
+ */
+extern const pwr_dev *PWR;
+/*
+ * Register bit definitions
+ */
+
+/* Control register */
+#define PWR_CR_DBP 8 /**< Disable backup domain write protection bit */
+#define PWR_CR_PVDE 4 /**< Power voltage detector enable bit */
+#define PWR_CR_CSBF 3 /**< Clear standby flag bit */
+#define PWR_CR_CWUF 2 /**< Clear wakeup flag bit */
+#define PWR_CR_PDDS 1 /**< Power down deepsleep bit */
+#define PWR_CR_LPDS 0 /**< Low-power deepsleep bit */
+
+/* Control and status register */
+#define PWR_CSR_EWUP 8 /**< Enable wakeup pin bit */
+#define PWR_CSR_PVDO 2 /**< PVD output bit */
+#define PWR_CSR_SBF 1 /**< Standby flag bit */
+#define PWR_CSR_WUF 0 /**< Wakeup flag bit */
+
+void pwr_init(void);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/libmaple/rcc.c b/libmaple/rcc.c
index a9d7c96..2841af3 100644
--- a/libmaple/rcc.c
+++ b/libmaple/rcc.c
@@ -74,6 +74,8 @@ static const struct rcc_dev_info rcc_dev_table[] = {
[RCC_DAC] = { .clk_domain = APB1, .line_num = 29 }, // High-density only
[RCC_DMA1] = { .clk_domain = AHB, .line_num = 0 },
[RCC_DMA2] = { .clk_domain = AHB, .line_num = 1 }, // High-density only
+ [RCC_PWR] = { .clk_domain = APB1, .line_num = 28},
+ [RCC_BKP] = { .clk_domain = APB1, .line_num = 27}
};
/**
@@ -117,18 +119,18 @@ void rcc_clk_init(uint32 sysclk_src, uint32 pll_src, uint32 pll_mul) {
/**
* @brief Turn on the clock line on a device
- * @param dev_num device to turn on
+ * @param device Clock ID of the device to turn on.
*/
-void rcc_clk_enable(uint32 dev_num) {
+void rcc_clk_enable(rcc_clk_id device) {
static const uint32 enable_regs[] = {
[APB1] = RCC_APB1ENR,
[APB2] = RCC_APB2ENR,
[AHB] = RCC_AHBENR,
};
- uint8 clk_domain = rcc_dev_table[dev_num].clk_domain;
+ uint8 clk_domain = rcc_dev_table[device].clk_domain;
- __set_bits(enable_regs[clk_domain], BIT(rcc_dev_table[dev_num].line_num));
+ __set_bits(enable_regs[clk_domain], BIT(rcc_dev_table[device].line_num));
}
/**
@@ -154,16 +156,16 @@ void rcc_set_prescaler(uint32 prescaler, uint32 divider) {
/**
* @brief reset a device
- * @param dev_num device to reset
+ * @param device Clock ID of the device to reset.
*/
-void rcc_reset_dev(uint32 dev_num) {
+void rcc_reset_dev(rcc_clk_id device) {
static const uint32 reset_regs[] = {
[APB1] = RCC_APB1RSTR,
[APB2] = RCC_APB2RSTR,
};
- uint8 clk_domain = rcc_dev_table[dev_num].clk_domain;
+ uint8 clk_domain = rcc_dev_table[device].clk_domain;
- __set_bits(reset_regs[clk_domain], BIT(rcc_dev_table[dev_num].line_num));
- __clear_bits(reset_regs[clk_domain], BIT(rcc_dev_table[dev_num].line_num));
+ __set_bits(reset_regs[clk_domain], BIT(rcc_dev_table[device].line_num));
+ __clear_bits(reset_regs[clk_domain], BIT(rcc_dev_table[device].line_num));
}
diff --git a/libmaple/rcc.h b/libmaple/rcc.h
index 5daca57..410ab8b 100644
--- a/libmaple/rcc.h
+++ b/libmaple/rcc.h
@@ -178,12 +178,14 @@ typedef enum {
RCC_DAC, // High-density devices only (Maple Native)
RCC_DMA1,
RCC_DMA2, // High-density devices only (Maple Native)
+ RCC_PWR,
+ RCC_BKP,
} rcc_clk_id;
void rcc_clk_init(uint32 sysclk_src, uint32 pll_src, uint32 pll_mul);
-void rcc_clk_enable(uint32 dev);
-void rcc_reset_dev(uint32 dev);
+void rcc_clk_enable(rcc_clk_id device);
+void rcc_reset_dev(rcc_clk_id device);
void rcc_set_prescaler(uint32 prescaler, uint32 divider);
#ifdef __cplusplus