From 9136ea9015c68fba7302dbe33a759aea43860b2f Mon Sep 17 00:00:00 2001 From: Marti Bolivar Date: Sun, 27 Feb 2011 05:39:55 -0500 Subject: Refactor backup (BKP) and power (PWR) routines. --- examples/test-bkp.cpp | 78 +++++++++++++++++++++++++++++++++++ libmaple/bkp.c | 110 +++++++++++++++++++++++++++++++++----------------- libmaple/bkp.h | 98 +++++++++++++++++++++++++++++--------------- libmaple/pwr.c | 42 +++++++++++++++++++ libmaple/pwr.h | 64 ++++++++++++++++++++++------- libmaple/rcc.c | 20 ++++----- libmaple/rcc.h | 6 ++- 7 files changed, 322 insertions(+), 96 deletions(-) create mode 100644 examples/test-bkp.cpp create mode 100644 libmaple/pwr.c 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 + +#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 -- cgit v1.2.3