BSCIF module reference

Header :
#include <bscif.h>
Makefile : bscif is already included by default

Description

The BSCIF (Backup System Control Interface) manages the low-power clocks, the internal voltage regulator and brown-out detectors, and a few general-purpose backup registers.

API

Clocks

void enableOSC32K()
Enable the external 32.768kHz crystal oscillator. This requires that this crystal is connected. This function is called in Core::init().
void getOSC32KFrequency()
Return 32768.
void enableRC32K()
Enable the internal 32.768kHz RC oscillator. This oscillator doesn't require any external component but is a lot less accurate than the external crystal (it runs between 20 and 44kHz).
void getRC32KFrequency()
Return 32768.
void enableRC1M()
Enable the internal 1MHz RC oscillator.
void getRC1MFrequency()
Return 1000000.

Backup registers

void storeBackupData(int n, uint32_t data)
Store data in one of the four 32-bit backup registers. This data is kept even in BACKUP low-power mode, when all other registers not in the Backup domain are lost. n must be between 0 and 3.
void readBackupData(int n)
Read data that was previously stored using storeBackupData. n must be between 0 and 3.

Hacking

The configuration of the voltage regulator and brown-out detectors is not implemented. For applications that require more advanced management and monitoring of the power source, look at the §12.6.3 Brown-Out Detector (BOD) Operation and §12.6.4 Voltage Regulator (VREG) sections in the datasheet for more details about these features.

Code

Header

#ifndef _BSCIF_H_
#define _BSCIF_H_

#include <stdint.h>

// Backup System Control Interface
// This module manages low-power clocks, the voltage regulator and 
// some general-purpose backup data registers
namespace BSCIF {

    // Peripheral memory space base address
    const uint32_t BSCIF_BASE = 0x400F0400;

    // Registers addresses
    const uint32_t OFFSET_IER =             0x0000; // Interrupt Enable Register
    const uint32_t OFFSET_IDR =             0x0004; // Interrupt Disable Register
    const uint32_t OFFSET_IMR =             0x0008; // Interrupt Mask Register
    const uint32_t OFFSET_ISR =             0x000C; // Interrupt Status Register
    const uint32_t OFFSET_ICR =             0x0010; // Interrupt Clear Register
    const uint32_t OFFSET_PCLKSR =          0x0014; // Power and Clocks Status Register
    const uint32_t OFFSET_UNLOCK =          0x0018; // Unlock Register
    const uint32_t OFFSET_CSCR =            0x001C; // Chip Specific Configuration Register
    const uint32_t OFFSET_OSCCTRL32 =       0x0020; // Oscillator 32 Control Register
    const uint32_t OFFSET_RC32KCR =         0x0024; // 32kHz RC Oscillator Control Register
    const uint32_t OFFSET_RC32KTUNE =       0x0028; // 32kHz RC Oscillator Tuning Register
    const uint32_t OFFSET_BOD33CTRL =       0x002C; // BOD33 Control Register
    const uint32_t OFFSET_BOD33LEVEL =      0x0030; // BOD33 Level Register
    const uint32_t OFFSET_BOD33SAMPLING =   0x0034; // BOD33 Sampling Control Register
    const uint32_t OFFSET_BOD18CTRL =       0x0038; // BOD18 Control Register
    const uint32_t OFFSET_BOD18LEVEL =      0x003C; // BOD18 Level Register
    const uint32_t OFFSET_BOD18SAMPLING =   0x0040; // BOD18 Sampling Control Register
    const uint32_t OFFSET_VREGCR =          0x0044; // Voltage Regulator Configuration Register
    const uint32_t OFFSET_RC1MCR =          0x0048; // 1MHz RC Clock Configuration Register
    const uint32_t OFFSET_BGCTRL =          0x0060; // Bandgap Control Register
    const uint32_t OFFSET_BGSR =            0x0064; // Bandgap Status Register
    const uint32_t OFFSET_BR =              0x0078; // Backup register

    // Subregisters
    const uint32_t PCLKSR_OSC32RDY = 0;
    const uint32_t PCLKSR_RC32KRDY = 1;
    const uint32_t PCLKSR_RC32KLOCK = 2;
    const uint32_t PCLKSR_RC32KREFE = 3;
    const uint32_t PCLKSR_RC32SAT = 4;
    const uint32_t PCLKSR_BOD33DET = 5;
    const uint32_t PCLKSR_BOD18DET = 6;
    const uint32_t PCLKSR_BOD33SYNRDY = 7;
    const uint32_t PCLKSR_BOD18SYNRDY = 8;
    const uint32_t PCLKSR_SSWRDY = 9;
    const uint32_t PCLKSR_VREGOK = 10;
    const uint32_t PCLKSR_RC1MRDY = 11;
    const uint32_t PCLKSR_LPBGRDY = 12;
    const uint32_t OSCCTRL32_OSC32EN = 0;
    const uint32_t OSCCTRL32_EN32K = 2;
    const uint32_t OSCCTRL32_EN1K = 3;
    const uint32_t OSCCTRL32_MODE = 8;
    const uint32_t OSCCTRL32_SELCURR = 12;
    const uint32_t OSCCTRL32_STARTUP = 16;
    const uint32_t RC32KCR_EN = 0;
    const uint32_t RC32KCR_TCEN = 1;
    const uint32_t RC32KCR_EN32K = 2;
    const uint32_t RC32KCR_EN1K = 3;
    const uint32_t RC32KCR_MODE = 4;
    const uint32_t RC32KCR_REF = 5;
    const uint32_t RC32KCR_FCD = 7;
    const uint32_t RC1MCR_CLKOEN = 0;

    // Constants
    const uint32_t UNLOCK_KEY = 0xAA << 24;


    // Module API
    void enableOSC32K();
    unsigned long getOSC32KFrequency();
    void enableRC32K();
    unsigned long getRC32KFrequency();
    void enableRC1M();
    unsigned long getRC1MFrequency();
    void storeBackupData(int register, uint32_t data);
    uint32_t readBackupData(int register);

}


#endif

Module

#include "bscif.h"
#include "bpm.h"

namespace BSCIF {

    unsigned long _osc32kFrequency = 0;
    unsigned long _rc32kFrequency = 0;
    unsigned long _rc1mFrequency = 0;

    void enableOSC32K() {
        // Save the frequency for future use
        _osc32kFrequency = 32768;

        // Unlock the OSCCTRL32 register, which is locked by default as a safety mesure
        (*(volatile uint32_t*)(BSCIF_BASE + OFFSET_UNLOCK))
                = UNLOCK_KEY            // KEY : Magic word (see datasheet)
                | OFFSET_OSCCTRL32;     // ADDR : unlock OSCCTRL32

        // Configure OSC32
        (*(volatile uint32_t*)(BSCIF_BASE + OFFSET_OSCCTRL32))
                = 1 << OSCCTRL32_EN32K      // EN32K : enable 32kHz output
                | 1 << OSCCTRL32_EN1K       // EN1K : enable 1kHz output
                | 3 << OSCCTRL32_MODE       // MODE : crystal
                | 8 << OSCCTRL32_SELCURR    // SELCURR : current driven into the crystal
                | 0 << OSCCTRL32_STARTUP;   // STARTUP : oscillator startup time

        // Enable OSC32
        (*(volatile uint32_t*)(BSCIF_BASE + OFFSET_OSCCTRL32))
                |= 1 << OSCCTRL32_OSC32EN;  // OSC32EN : enable crystal

        // Wait for OSC32K to be ready
        while (!((*(volatile uint32_t*)(BSCIF_BASE + OFFSET_PCLKSR)) & (1 << PCLKSR_OSC32RDY)));

        // Select OSC32K as the 32KHz clock source
        BPM::set32KHzClockSource(BPM::CLK32KSource::OSC32K);
    }

    unsigned long getOSC32KFrequency() {
        return _osc32kFrequency;
    }

    void enableRC32K() {
        // Save the frequency for future use
        _rc32kFrequency = 32768;

        // Unlock the RC32KCR register, which is locked by default as a safety mesure
        (*(volatile uint32_t*)(BSCIF_BASE + OFFSET_UNLOCK))
                = UNLOCK_KEY            // KEY : Magic word (see datasheet)
                | OFFSET_RC32KCR;       // ADDR : unlock RC32KCR

        // Configure RC32K
        (*(volatile uint32_t*)(BSCIF_BASE + OFFSET_RC32KCR))
                = 1 << RC32KCR_TCEN     // TCEN : enable temperature compensation
                | 1 << RC32KCR_EN32K    // EN32K : enable 32kHz output
                | 1 << RC32KCR_EN1K     // EN1K : enable 1kHz output
                | 1 << RC32KCR_MODE     // MODE : closed loop mode
                | 0 << RC32KCR_REF;     // REF : closed loop mode reference : OSC32K

        // Enable RC32K
        (*(volatile uint32_t*)(BSCIF_BASE + OFFSET_RC32KCR))
                |= 1 << RC32KCR_EN;     // EN : enable generic clock source

        // Wait for RC32K to be ready
        while (!((*(volatile uint32_t*)(BSCIF_BASE + OFFSET_PCLKSR)) & ((1 << PCLKSR_RC32KRDY) | (1 << PCLKSR_RC32KLOCK))));

        // Select RC32K as the 32KHz clock source
        BPM::set32KHzClockSource(BPM::CLK32KSource::RC32K);
    }

    unsigned long getRC32KFrequency() {
        return _rc32kFrequency;
    }

    void enableRC1M() {
        // Save the frequency for future use
        _rc1mFrequency = 1000000;

        // Unlock the RC1MCR register, which is locked by default as a safety mesure
        (*(volatile uint32_t*)(BSCIF_BASE + OFFSET_UNLOCK))
                = UNLOCK_KEY         // KEY : Magic word (see datasheet)
                | OFFSET_RC1MCR;     // ADDR : unlock RC1MCR

        // Configure RC1M
        (*(volatile uint32_t*)(BSCIF_BASE + OFFSET_RC1MCR))
                = 1 << RC1MCR_CLKOEN;    // CLKOEN : enable oscillator

        // Wait for RC1M to be ready
        while (!((*(volatile uint32_t*)(BSCIF_BASE + OFFSET_PCLKSR)) & (1 << PCLKSR_RC1MRDY)));
    }

    unsigned long getRC1MFrequency() {
        return _rc1mFrequency;
    }

    // Store data in one of the four 32-bit backup registers
    // This data is kept even in BACKUP low-power mode, when all other
    // registers not in the Backup domain are lost
    void storeBackupData(int n, uint32_t data) {
        // Register offset
        if (n < 0 || n > 3) {
            return;
        }
        const uint32_t offset = OFFSET_BR + n * 4;

        // Unlock the BRn register, which is locked by default as a safety mesure
        (*(volatile uint32_t*)(BSCIF_BASE + OFFSET_UNLOCK))
                = UNLOCK_KEY         // KEY : Magic word (see datasheet)
                | offset;            // ADDR : unlock BRn

        // Store data
        (*(volatile uint32_t*)(BSCIF_BASE + offset)) = data;
    }

    // Read data from one of the four 32-bit backup registers
    uint32_t readBackupData(int n) {
        // Register offset
        if (n < 0 || n > 3) {
            return 0;
        }
        const uint32_t offset = OFFSET_BR + n * 4;

        return (*(volatile uint32_t*)(BSCIF_BASE + offset));
    }

}