mirror of
https://github.com/RIOT-OS/RIOT.git
synced 2025-12-15 09:33:50 +01:00
This implements `pm_set_lowest()` for the MSP430. Unlike most other platforms, it intentionally does not use pm_layered. It is pretty similar to `pm_layered` in that is does use reference counters, but it uses them for two independent clock sources. The main difference is that the low frequency clock domain can be disabled even when the high frequency clock is still active. With the layers, disabling layer n-1 while layer n is still blocked would not work.
409 lines
12 KiB
C
409 lines
12 KiB
C
/*
|
|
* Copyright (C) 2015 Freie Universität Berlin
|
|
*
|
|
* 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_msp430_x1xx
|
|
* @{
|
|
*
|
|
* @file
|
|
* @brief CPU specific definitions for internal peripheral handling
|
|
*
|
|
* @author Hauke Petersen <hauke.petersen@fu-berlin.de>
|
|
*/
|
|
|
|
#ifndef PERIPH_CPU_COMMON_H
|
|
#define PERIPH_CPU_COMMON_H
|
|
|
|
#include <stdbool.h>
|
|
|
|
#include "bitarithm.h"
|
|
#include "compiler_hints.h"
|
|
#include "cpu.h"
|
|
#include "msp430_regs.h"
|
|
|
|
#ifdef __cplusplus
|
|
extern "C" {
|
|
#endif
|
|
|
|
/**
|
|
* @brief Define a custom type for GPIO pins
|
|
* @{
|
|
*/
|
|
#define HAVE_GPIO_T
|
|
typedef uint16_t gpio_t;
|
|
/** @} */
|
|
|
|
/**
|
|
* @brief Definition of a fitting UNDEF value
|
|
*/
|
|
#define GPIO_UNDEF (0xffff)
|
|
|
|
/**
|
|
* @brief Mandatory function for defining a GPIO pins
|
|
*/
|
|
#define GPIO_PIN(x, y) ((gpio_t)(((x & 0xff) << 8) | (1 << (y & 0x07))))
|
|
|
|
/**
|
|
* @brief No support for HW chip select...
|
|
*/
|
|
#define SPI_HWCS(x) (SPI_CS_UNDEF)
|
|
|
|
/**
|
|
* @brief The MSP430 timer peripheral can have up to 8 channels
|
|
*
|
|
* @note The actual number of channels should be queried per timer, as
|
|
* timers have either 7 or 3 capture/compare channels; typically both
|
|
* variants are present in the same MCU. This is the highest number
|
|
* of channels supported, e.g. useful for "worst case" static memory
|
|
* allocation.
|
|
*/
|
|
#define TIMER_CHANNEL_NUMOF 7
|
|
|
|
/**
|
|
* @name Override flank selection values
|
|
* @{
|
|
*/
|
|
#define HAVE_GPIO_FLANK_T /**< MSP430 has a custom gpio_flank_t */
|
|
/**
|
|
* @brief Enumeration of supported GPIO flanks
|
|
*/
|
|
typedef enum {
|
|
GPIO_FALLING = 0xff, /**< emit interrupt on falling flank */
|
|
GPIO_RISING = 0x00, /**< emit interrupt on rising flank */
|
|
GPIO_BOTH = 0xab /**< not supported -> random value*/
|
|
} gpio_flank_t;
|
|
/** @} */
|
|
|
|
/**
|
|
* @brief Available ports on MSP430 platforms
|
|
*/
|
|
enum {
|
|
P1 = 1, /**< PORT 1 */
|
|
P2 = 2, /**< PORT 2 */
|
|
P3 = 3, /**< PORT 3 */
|
|
P4 = 4, /**< PORT 4 */
|
|
P5 = 5, /**< PORT 5 */
|
|
P6 = 6, /**< PORT 6 */
|
|
};
|
|
|
|
/**
|
|
* @brief Enable or disable a pin to be used by peripheral modules
|
|
*
|
|
* @param[in] pin pin to (de-)select
|
|
* @param[in] enable true for enabling peripheral use, false for disabling it
|
|
*/
|
|
void gpio_periph_mode(gpio_t pin, bool enable);
|
|
|
|
/**
|
|
* @brief The measured DCO frequency
|
|
*
|
|
* @warning This will have a value of 0 if the DCO is not enabled in the boards
|
|
* `periph_conf.h`
|
|
*/
|
|
extern uint32_t msp430_dco_freq;
|
|
|
|
/**
|
|
* @brief Possible clock sources to generate the main clock from
|
|
*/
|
|
typedef enum {
|
|
/**
|
|
* @brief Internal digitally controlled oscillator (DCO) with RC-type
|
|
* characteristics.
|
|
*/
|
|
MAIN_CLOCK_SOURCE_DCOCLK = SELM_0,
|
|
/**
|
|
* @brief High frequency crystal between 450 kHz and 8 MHz
|
|
*
|
|
* @note If XT2 is not enabled, this will behave identical to
|
|
* @ref MAIN_CLOCK_SOURCE_LFXT1CLK
|
|
*/
|
|
MAIN_CLOCK_SOURCE_XT2CLK = SELM_2,
|
|
/**
|
|
* @brief Low frequency 32.768 kHz or high frequency crystal
|
|
* between 450 kHz and 8 MHz
|
|
*/
|
|
MAIN_CLOCK_SOURCE_LFXT1CLK = SELM_3,
|
|
} msp430_main_clock_source_t;
|
|
|
|
/**
|
|
* @brief Possible clock sources to generate the submain clock from
|
|
*/
|
|
typedef enum {
|
|
/**
|
|
* @brief Internal digitally controlled oscillator (DCO) with RC-type
|
|
* characteristics.
|
|
*/
|
|
SUBMAIN_CLOCK_SOURCE_DCOCLK = 0,
|
|
/**
|
|
* @brief High frequency crystal between 450 kHz and 8 MHz
|
|
*
|
|
* @note If XT2 is not enabled, this will behave identical to
|
|
* @ref SUBMAIN_CLOCK_SOURCE_LFXT1CLK
|
|
*/
|
|
SUBMAIN_CLOCK_SOURCE_XT2CLK = SELS,
|
|
/**
|
|
* @brief Low frequency 32.768 kHz or high frequency crystal
|
|
* between 450 kHz and 8 MHz
|
|
*
|
|
* @note If XT2 is enabled, this will behave identical to
|
|
* @ref SUBMAIN_CLOCK_SOURCE_XT2CLK
|
|
*
|
|
* It is recommended to use @ref SUBMAIN_CLOCK_SOURCE_XT2CLK when XT2 is present
|
|
* in the config to avoid confusion.
|
|
*/
|
|
SUBMAIN_CLOCK_SOURCE_LFXT1CLK = SELS,
|
|
} msp430_submain_clock_source_t;
|
|
|
|
/**
|
|
* @brief Clock dividers for the main clock
|
|
*/
|
|
typedef enum {
|
|
/**
|
|
* @brief Divide the main clock by 1
|
|
*/
|
|
MAIN_CLOCK_DIVIDE_BY_1 = DIVM_0,
|
|
/**
|
|
* @brief Divide the main clock by 2
|
|
*/
|
|
MAIN_CLOCK_DIVIDE_BY_2 = DIVM_1,
|
|
/**
|
|
* @brief Divide the main clock by 4
|
|
*/
|
|
MAIN_CLOCK_DIVIDE_BY_4 = DIVM_2,
|
|
/**
|
|
* @brief Divide the main clock by 8
|
|
*/
|
|
MAIN_CLOCK_DIVIDE_BY_8 = DIVM_3,
|
|
} msp430_main_clock_divider_t;
|
|
|
|
/**
|
|
* @brief Clock dividers for the submain clock
|
|
*/
|
|
typedef enum {
|
|
/**
|
|
* @brief Divide the main clock by 1
|
|
*/
|
|
SUBMAIN_CLOCK_DIVIDE_BY_1 = DIVS_0,
|
|
/**
|
|
* @brief Divide the main clock by 2
|
|
*/
|
|
SUBMAIN_CLOCK_DIVIDE_BY_2 = DIVS_1,
|
|
/**
|
|
* @brief Divide the main clock by 4
|
|
*/
|
|
SUBMAIN_CLOCK_DIVIDE_BY_4 = DIVS_2,
|
|
/**
|
|
* @brief Divide the main clock by 8
|
|
*/
|
|
SUBMAIN_CLOCK_DIVIDE_BY_8 = DIVS_3,
|
|
} msp430_submain_clock_divider_t;
|
|
|
|
/**
|
|
* @brief Clock dividers for the auxiliary clock
|
|
*/
|
|
typedef enum {
|
|
/**
|
|
* @brief Divide the main clock by 1
|
|
*/
|
|
AUXILIARY_CLOCK_DIVIDE_BY_1 = DIVA_0,
|
|
/**
|
|
* @brief Divide the main clock by 2
|
|
*/
|
|
AUXILIARY_CLOCK_DIVIDE_BY_2 = DIVA_1,
|
|
/**
|
|
* @brief Divide the main clock by 4
|
|
*/
|
|
AUXILIARY_CLOCK_DIVIDE_BY_4 = DIVA_2,
|
|
/**
|
|
* @brief Divide the main clock by 8
|
|
*/
|
|
AUXILIARY_CLOCK_DIVIDE_BY_8 = DIVA_3,
|
|
} msp430_auxiliary_clock_divider_t;
|
|
|
|
/**
|
|
* @brief MSP430Fxzy Basic Clock System Parameters
|
|
*
|
|
* @details This structure is optimized for readability under the assumption
|
|
* that its values are readily available compile time constants.
|
|
* Hence, accesses to the structure will be fully optimized out be
|
|
* a decent optimizing compiler.
|
|
*
|
|
* MSP430Fxzy boards are expected to declare the parameters to configure the
|
|
* Basic Clock System in their `periph_conf.h` as
|
|
* `static const msp430_fxzy_clock_params_t clock_params;`.
|
|
*/
|
|
typedef struct {
|
|
/**
|
|
* @brief The target frequency to run the DCO at in Hz
|
|
*
|
|
* A frequency between 160 kHz and 4 MHz is enforced by compile time tests
|
|
* to make sure DCO calibration will succeed reliable.
|
|
*/
|
|
uint32_t target_dco_frequency;
|
|
/**
|
|
* @brief The frequency of the LFXT1 crystal in Hz
|
|
*
|
|
* This should be either 32768 Hz watch crystal or a high frequency
|
|
* crystal anywhere between 450 kHz and 8 MHz. The clock driver will
|
|
* automatically configure high frequency mode of the LFXT1 clock source
|
|
* when the frequency is >= 450 kHz.
|
|
*/
|
|
uint32_t lfxt1_frequency;
|
|
/**
|
|
* @brief The frequency of the XT2 crystal in Hz
|
|
*
|
|
* A value of 0 Hz means no XT2 crystal is present. Otherwise the frequency
|
|
* must be anywhere between 450 kHz and 8 MHz.
|
|
*/
|
|
uint32_t xt2_frequency;
|
|
/**
|
|
* @brief The clock source to select for the main clock
|
|
*
|
|
* @details This is the clock the CPU will run at
|
|
*/
|
|
msp430_main_clock_source_t main_clock_source;
|
|
/**
|
|
* @brief The clock source to select for the submain CPU clock
|
|
*
|
|
* @details This is the clock high speed peripherals will run at
|
|
*/
|
|
msp430_submain_clock_source_t submain_clock_source;
|
|
/**
|
|
* @brief Divider of the main clock
|
|
*/
|
|
msp430_main_clock_divider_t main_clock_divier;
|
|
/**
|
|
* @brief Divider of the submain clock
|
|
*/
|
|
msp430_submain_clock_divider_t submain_clock_divier;
|
|
/**
|
|
* @brief Divider of the auxiliary clock
|
|
*/
|
|
msp430_auxiliary_clock_divider_t auxiliary_clock_divier;
|
|
/**
|
|
* @brief An external resistor connected to source the current for the DCO
|
|
*
|
|
* From the datasheet:
|
|
*
|
|
* > The DCO temperature coefficient can be reduced by using an external
|
|
* > resistor R_OSC tied to D_VCC to source the current for the DC generator.
|
|
*/
|
|
bool has_r_osc;
|
|
/**
|
|
* @brief A high frequency crystal (e.g. 8 MHz) is connected between
|
|
* XT2IN and XT2OUT
|
|
*/
|
|
bool has_xt2;
|
|
} msp430_clock_params_t;
|
|
|
|
/**
|
|
* @brief Enumeration of possible clock sources for a timer
|
|
*/
|
|
typedef enum {
|
|
TIMER_CLOCK_SOURCE_TXCLK = TXSSEL_TXCLK, /**< External TxCLK as clock source */
|
|
TIMER_CLOCK_SOURCE_AUXILIARY_CLOCK = TXSSEL_ACLK, /**< Auxiliary clock as clock source */
|
|
TIMER_CLOCK_SOURCE_SUBMAIN_CLOCK = TXSSEL_SMCLK, /**< Sub-system master clock as clock source */
|
|
TIMER_CLOCK_SOURCE_INCLK = TXSSEL_INCLK, /**< External INCLK as clock source */
|
|
} msp430_timer_clock_source_t;
|
|
|
|
/**
|
|
* @brief IDs of the different clock domains on the MSP430
|
|
*
|
|
* These can be used as internal clock sources for peripherals
|
|
*/
|
|
typedef enum {
|
|
MSP430_CLOCK_SUBMAIN, /**< Subsystem main clock */
|
|
MSP430_CLOCK_AUXILIARY, /**< Auxiliary clock */
|
|
MSP430_CLOCK_NUMOF, /**< Number of clock domains */
|
|
} msp430_clock_t;
|
|
|
|
/**
|
|
* @brief Timer configuration on an MSP430 timer
|
|
*/
|
|
typedef struct {
|
|
msp430_timer_t *timer; /**< Hardware timer to use */
|
|
/**
|
|
* @brief "Timer interrupt vector" register
|
|
*
|
|
* Use `&TIMER_A_IRQFLAGS` for `TIMER_A` or
|
|
* `&TIMER_B_IRQFLAGS` for `TIMER_B`.
|
|
*/
|
|
REG16 *irq_flags;
|
|
msp430_timer_clock_source_t clock_source; /**< Clock source to use */
|
|
} timer_conf_t;
|
|
|
|
/**
|
|
* @brief Initialize the basic clock system to provide the main clock,
|
|
* the subsystem clock, and the auxiliary clock.
|
|
*
|
|
* The main clock, the subsystem clock, and the auxiliary clock will be set up
|
|
* as specified by `static const msp430_clock_params_t clock_params` in
|
|
* the `periph_conf.h` of the board.
|
|
*
|
|
* @note This function takes some time and typically is only called during
|
|
* boot.
|
|
*
|
|
* @post The main clock, the subsystem clock and the auxiliary clock are
|
|
* are set up and stable
|
|
*/
|
|
void default_clock_init(void);
|
|
|
|
/**
|
|
* @brief Call during boot up process to initialize the clock
|
|
*
|
|
* @note This is a weak alias for @ref default_clock_init so that this can
|
|
* be overwritten with a strong symbol from the board in case some
|
|
* special handling is required. The boards custom `clock_init()` can
|
|
* still call @ref default_clock_init if that is useful; or it could
|
|
* do everything from scratch.
|
|
*/
|
|
void clock_init(void);
|
|
|
|
/**
|
|
* @brief Get the configured submain clock frequency
|
|
*
|
|
* @note This is only useful when implementing MSP430 peripheral drivers
|
|
*/
|
|
uint32_t PURE msp430_submain_clock_freq(void);
|
|
|
|
/**
|
|
* @brief Get the configured auxiliary clock frequency
|
|
*
|
|
* @note This is only useful when implementing MSP430 peripheral drivers
|
|
*/
|
|
uint32_t PURE msp430_auxiliary_clock_freq(void);
|
|
|
|
/**
|
|
* @brief Increase the refcount of the given clock
|
|
*
|
|
* @param[in] clock clock domain to acquire
|
|
*
|
|
* @warning This is an internal function and must only be called from
|
|
* peripheral drivers
|
|
* @note An assertion will blow when the count exceeds capacity
|
|
*/
|
|
void msp430_clock_acquire(msp430_clock_t clock);
|
|
|
|
/**
|
|
* @brief Decrease the refcount of the subsystem main clock
|
|
*
|
|
* @param[in] clock clock domain to acquire
|
|
*
|
|
* @warning This is an internal function and must only be called from
|
|
* peripheral drivers
|
|
* @note An assertion will blow when the count drops below zero
|
|
*/
|
|
void msp430_clock_release(msp430_clock_t clock);
|
|
|
|
#ifdef __cplusplus
|
|
}
|
|
#endif
|
|
|
|
#endif /* PERIPH_CPU_COMMON_H */
|
|
/** @} */
|