1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2024-12-29 04:50:03 +01:00
RIOT/cpu/msp430/include/periph_cpu_common.h
2024-08-02 13:41:37 +02:00

512 lines
14 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
/**
* @brief Lowest address of the RAM, peripherals are below
*/
#define RAMSTART 0x200
/**
* @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 */
};
#ifndef DOXYGEN
#define HAVE_GPIO_STATE_T
typedef enum {
GPIO_INPUT,
GPIO_OUTPUT_PUSH_PULL,
GPIO_OUTPUT_OPEN_DRAIN, /**< not supported */
GPIO_OUTPUT_OPEN_SOURCE, /**< not supported */
GPIO_USED_BY_PERIPHERAL, /**< not supported */
GPIO_DISCONNECT = GPIO_INPUT,
} gpio_state_t;
#define HAVE_GPIO_SLEW_T
typedef enum {
GPIO_SLEW_SLOWEST = 0,
GPIO_SLEW_SLOW = 0,
GPIO_SLEW_FAST = 0,
GPIO_SLEW_FASTEST = 0,
} gpio_slew_t;
#define HAVE_GPIO_PULL_STRENGTH_T
typedef enum {
GPIO_PULL_WEAKEST = 0,
GPIO_PULL_WEAK = 0,
GPIO_PULL_STRONG = 0,
GPIO_PULL_STRONGEST = 0
} gpio_pull_strength_t;
#define HAVE_GPIO_DRIVE_STRENGTH_T
typedef enum {
GPIO_DRIVE_WEAKEST = 0,
GPIO_DRIVE_WEAK = 0,
GPIO_DRIVE_STRONG = 0,
GPIO_DRIVE_STRONGEST = 0
} gpio_drive_strength_t;
#endif /* !DOXYGEN */
/**
* @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;
/**
* @name MSP430 Common Peripheral Register Maps
*
* @details The addresses will be provided by the linker script using the
* vendor files.
* @{
*/
/**
* @brief Register map of GPIO PORT 1
*/
extern msp430_port_p1_p2_t PORT_1;
/**
* @brief Register map of GPIO PORT 2
*/
extern msp430_port_p1_p2_t PORT_2;
/**
* @brief Register map of GPIO PORT 3
*/
extern msp430_port_p3_p6_t PORT_3;
/**
* @brief Register map of GPIO PORT 4
*/
extern msp430_port_p3_p6_t PORT_4;
/**
* @brief Register map of GPIO PORT 5
*/
extern msp430_port_p3_p6_t PORT_5;
/**
* @brief Register map of GPIO PORT 6
*/
extern msp430_port_p3_p6_t PORT_6;
/**
* @brief Register map of the timer A control registers
*/
extern msp430_timer_t TIMER_A;
/**
* @brief IRQ flags for TIMER_A
*
* Called TAIV in the data sheet / vendor files. This shallow alias
* makes the name more readable and does impedance matching for the type
* (`volatile uint16_t` vs `volatile short`).
*/
extern REG16 TIMER_A_IRQFLAGS;
/**
* @brief IRQ flags for TIMER_B
*
* Called TBIV in the data sheet / vendor files. This shallow alias
* makes the name more readable and does impedance matching for the type
* (`volatile uint16_t` vs `volatile short`).
*/
extern REG16 TIMER_B_IRQFLAGS;
/**
* @brief Register map of the timer B control registers
*/
extern msp430_timer_t TIMER_B;
/** @} */
/**
* @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 */
/** @} */