mirror of
https://github.com/RIOT-OS/RIOT.git
synced 2024-12-29 04:50:03 +01:00
cpu/msp430: rework MSP430 x1xx periph drivers
- Move common code for USART (shared SPI / UART peripheral) to its own file and allow sharing the USART peripheral to provide both UART and SPI in round-robin fashion. - Configure both UART and SPI bus via a `struct` in the board's `periph_conf.h` - this allows allocating the two UARTs as needed by the use case - since both USARTs signals have a fixed connection to a single GPIO, most configuration is moved to the CPU - the board now only needs to decide which bus is provided by which USART Note: Sharing an USART used as UART requires cooperation from the app: - If the UART is used in TX-only mode (no RX callback), the driver will release the USART while not sending - If the UART is used to also receive, the application needs to power the UART down while not expecting something to send. An `spi_acquire()` will be blocked while the UART is powered up.
This commit is contained in:
parent
bb07bb6613
commit
675dcc381c
@ -35,7 +35,7 @@ extern "C" {
|
||||
* @brief Clock configuration
|
||||
*/
|
||||
static const msp430_clock_params_t clock_params = {
|
||||
.target_dco_frequency = 7372800U,
|
||||
.target_dco_frequency = MHZ(8),
|
||||
.lfxt1_frequency = 32768,
|
||||
.main_clock_source = MAIN_CLOCK_SOURCE_DCOCLK,
|
||||
.submain_clock_source = SUBMAIN_CLOCK_SOURCE_DCOCLK,
|
||||
@ -49,35 +49,30 @@ static const msp430_clock_params_t clock_params = {
|
||||
* @name UART configuration
|
||||
* @{
|
||||
*/
|
||||
#define UART_NUMOF (1U)
|
||||
static const uart_conf_t uart_config[] = {
|
||||
{
|
||||
.uart = &usart1_as_uart,
|
||||
},
|
||||
};
|
||||
|
||||
#define UART_BASE (&USART_1)
|
||||
#define UART_SFR (&USART_1_SFR)
|
||||
#define UART_IE_RX_BIT (1 << 4)
|
||||
#define UART_IE_TX_BIT (1 << 5)
|
||||
#define UART_ME_BITS (0x30)
|
||||
#define UART_PORT (&PORT_3)
|
||||
#define UART_RX_PIN (1 << 6)
|
||||
#define UART_TX_PIN (1 << 7)
|
||||
#define UART_RX_ISR (USART1RX_VECTOR)
|
||||
#define UART_TX_ISR (USART1TX_VECTOR)
|
||||
#define UART0_RX_ISR (USART1RX_VECTOR) /**< RX IRQ vector of UART 0 */
|
||||
#define UART0_TX_ISR (USART1TX_VECTOR) /**< TX IRQ vector of UART 0 */
|
||||
|
||||
#define UART_NUMOF ARRAY_SIZE(uart_config)
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @name SPI configuration
|
||||
* @{
|
||||
*/
|
||||
#define SPI_NUMOF (1U)
|
||||
static const spi_conf_t spi_config[] = {
|
||||
{
|
||||
/* beware of resource conflict with UART */
|
||||
.spi = &usart1_as_spi,
|
||||
},
|
||||
};
|
||||
|
||||
/* SPI configuration */
|
||||
#define SPI_BASE (&USART_1)
|
||||
#define SPI_SFR (&USART_1_SFR)
|
||||
#define SPI_IE_RX_BIT (1 << 6)
|
||||
#define SPI_IE_TX_BIT (1 << 7)
|
||||
#define SPI_ME_BIT (1 << 6)
|
||||
#define SPI_PIN_MISO GPIO_PIN(P5, 2)
|
||||
#define SPI_PIN_MOSI GPIO_PIN(P5, 1)
|
||||
#define SPI_PIN_CLK GPIO_PIN(P5, 3)
|
||||
#define SPI_NUMOF ARRAY_SIZE(spi_config)
|
||||
/** @} */
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
@ -48,35 +48,29 @@ static const msp430_clock_params_t clock_params = {
|
||||
* @name UART configuration
|
||||
* @{
|
||||
*/
|
||||
#define UART_NUMOF (1U)
|
||||
static const uart_conf_t uart_config[] = {
|
||||
{
|
||||
.uart = &usart1_as_uart,
|
||||
},
|
||||
};
|
||||
|
||||
#define UART_BASE (&USART_1)
|
||||
#define UART_SFR (&USART_1_SFR)
|
||||
#define UART_IE_RX_BIT (1 << 4)
|
||||
#define UART_IE_TX_BIT (1 << 5)
|
||||
#define UART_ME_BITS (0x30)
|
||||
#define UART_PORT (&PORT_3)
|
||||
#define UART_RX_PIN (1 << 6)
|
||||
#define UART_TX_PIN (1 << 7)
|
||||
#define UART_RX_ISR (USART1RX_VECTOR)
|
||||
#define UART_TX_ISR (USART1TX_VECTOR)
|
||||
#define UART0_RX_ISR (USART1RX_VECTOR) /**< RX IRQ vector of UART 0 */
|
||||
#define UART0_TX_ISR (USART1TX_VECTOR) /**< TX IRQ vector of UART 0 */
|
||||
|
||||
#define UART_NUMOF ARRAY_SIZE(uart_config)
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @name SPI configuration
|
||||
* @{
|
||||
*/
|
||||
#define SPI_NUMOF (1U)
|
||||
static const spi_conf_t spi_config[] = {
|
||||
{
|
||||
.spi = &usart0_as_spi,
|
||||
},
|
||||
};
|
||||
|
||||
/* SPI configuration */
|
||||
#define SPI_BASE (&USART_0)
|
||||
#define SPI_SFR (&USART_0_SFR)
|
||||
#define SPI_IE_RX_BIT (1 << 6)
|
||||
#define SPI_IE_TX_BIT (1 << 7)
|
||||
#define SPI_ME_BIT (1 << 6)
|
||||
#define SPI_PIN_MISO GPIO_PIN(P3, 2)
|
||||
#define SPI_PIN_MOSI GPIO_PIN(P3, 1)
|
||||
#define SPI_PIN_CLK GPIO_PIN(P3, 3)
|
||||
#define SPI_NUMOF ARRAY_SIZE(spi_config)
|
||||
/** @} */
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
@ -48,35 +48,29 @@ static const msp430_clock_params_t clock_params = {
|
||||
* @name UART configuration
|
||||
* @{
|
||||
*/
|
||||
#define UART_NUMOF (1U)
|
||||
static const uart_conf_t uart_config[] = {
|
||||
{
|
||||
.uart = &usart1_as_uart,
|
||||
},
|
||||
};
|
||||
|
||||
#define UART_BASE (&USART_1)
|
||||
#define UART_SFR (&USART_1_SFR)
|
||||
#define UART_IE_RX_BIT (1 << 4)
|
||||
#define UART_IE_TX_BIT (1 << 5)
|
||||
#define UART_ME_BITS (0x30)
|
||||
#define UART_PORT (&PORT_3)
|
||||
#define UART_RX_PIN (1 << 6)
|
||||
#define UART_TX_PIN (1 << 7)
|
||||
#define UART_RX_ISR (USART1RX_VECTOR)
|
||||
#define UART_TX_ISR (USART1TX_VECTOR)
|
||||
#define UART0_RX_ISR (USART1RX_VECTOR) /**< RX IRQ vector of UART 0 */
|
||||
#define UART0_TX_ISR (USART1TX_VECTOR) /**< TX IRQ vector of UART 0 */
|
||||
|
||||
#define UART_NUMOF ARRAY_SIZE(uart_config)
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @name SPI configuration
|
||||
* @{
|
||||
*/
|
||||
#define SPI_NUMOF (1U)
|
||||
static const spi_conf_t spi_config[] = {
|
||||
{
|
||||
.spi = &usart0_as_spi,
|
||||
},
|
||||
};
|
||||
|
||||
/* SPI configuration */
|
||||
#define SPI_BASE (&USART_0)
|
||||
#define SPI_SFR (&USART_0_SFR)
|
||||
#define SPI_IE_RX_BIT (1 << 6)
|
||||
#define SPI_IE_TX_BIT (1 << 7)
|
||||
#define SPI_ME_BIT (1 << 6)
|
||||
#define SPI_PIN_MISO GPIO_PIN(P3, 2)
|
||||
#define SPI_PIN_MOSI GPIO_PIN(P3, 1)
|
||||
#define SPI_PIN_CLK GPIO_PIN(P3, 3)
|
||||
#define SPI_NUMOF ARRAY_SIZE(spi_config)
|
||||
/** @} */
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
@ -48,34 +48,29 @@ static const msp430_clock_params_t clock_params = {
|
||||
* @name UART configuration
|
||||
* @{
|
||||
*/
|
||||
#define UART_NUMOF (1U)
|
||||
static const uart_conf_t uart_config[] = {
|
||||
{
|
||||
.uart = &usart1_as_uart,
|
||||
},
|
||||
};
|
||||
|
||||
#define UART_BASE (&USART_1)
|
||||
#define UART_SFR (&USART_1_SFR)
|
||||
#define UART_IE_RX_BIT (1 << 4)
|
||||
#define UART_IE_TX_BIT (1 << 5)
|
||||
#define UART_ME_BITS (0x30)
|
||||
#define UART_PORT (&PORT_3)
|
||||
#define UART_RX_PIN (1 << 6)
|
||||
#define UART_TX_PIN (1 << 7)
|
||||
#define UART_RX_ISR (USART1RX_VECTOR)
|
||||
#define UART_TX_ISR (USART1TX_VECTOR)
|
||||
#define UART0_RX_ISR (USART1RX_VECTOR) /**< RX IRQ vector of UART 0 */
|
||||
#define UART0_TX_ISR (USART1TX_VECTOR) /**< TX IRQ vector of UART 0 */
|
||||
|
||||
#define UART_NUMOF ARRAY_SIZE(uart_config)
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @name SPI configuration
|
||||
* @{
|
||||
*/
|
||||
#define SPI_NUMOF (1U)
|
||||
static const spi_conf_t spi_config[] = {
|
||||
{
|
||||
.spi = &usart0_as_spi,
|
||||
},
|
||||
};
|
||||
|
||||
#define SPI_BASE (&USART_0)
|
||||
#define SPI_SFR (&USART_0_SFR)
|
||||
#define SPI_IE_RX_BIT (1 << 6)
|
||||
#define SPI_IE_TX_BIT (1 << 7)
|
||||
#define SPI_ME_BIT (1 << 6)
|
||||
#define SPI_PIN_MISO GPIO_PIN(P3, 2)
|
||||
#define SPI_PIN_MOSI GPIO_PIN(P3, 1)
|
||||
#define SPI_PIN_CLK GPIO_PIN(P3, 3)
|
||||
#define SPI_NUMOF ARRAY_SIZE(spi_config)
|
||||
/** @} */
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
@ -21,12 +21,31 @@
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "compiler_hints.h"
|
||||
#include "periph_cpu_common.h"
|
||||
#include "macros/units.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief All MSP430 x1xx MCUs have two USART peripherals
|
||||
*/
|
||||
#define USART_NUMOF 2
|
||||
|
||||
/**
|
||||
* @brief The clock divider of the UASRT (BR register) must be at least 2
|
||||
* when in SPI mode
|
||||
*/
|
||||
#define USART_MIN_BR_SPI 2
|
||||
|
||||
/**
|
||||
* @brief The clock divider of the UASRT (BR register) must be at least 3
|
||||
* when in UART mode
|
||||
*/
|
||||
#define USART_MIN_BR_UART 3
|
||||
|
||||
/**
|
||||
* @name Override SPI mode selection values
|
||||
* @{
|
||||
@ -57,14 +76,154 @@ typedef enum {
|
||||
* @brief Support SPI clock frequencies
|
||||
*/
|
||||
typedef enum {
|
||||
SPI_CLK_100KHZ = 100000, /**< 100 kHz */
|
||||
SPI_CLK_400KHZ = 400000, /**< 400 kHz */
|
||||
SPI_CLK_1MHZ = 1000000, /**< 1 MHz */
|
||||
SPI_CLK_5MHZ = 5000000, /**< 5 MHz */
|
||||
SPI_CLK_100KHZ = KHZ(100), /**< 100 kHz */
|
||||
SPI_CLK_400KHZ = KHZ(400), /**< 400 kHz */
|
||||
SPI_CLK_1MHZ = MHZ(1), /**< 1 MHz */
|
||||
SPI_CLK_5MHZ = MHZ(5), /**< 5 MHz */
|
||||
SPI_CLK_10MHZ = SPI_CLK_5MHZ, /**< 10 MHz not supported, falling back to 5 MHz */
|
||||
} spi_clk_t;
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @brief MSP430 x1xx USART configuration
|
||||
*
|
||||
* @details This is intended to be stored in flash.
|
||||
*/
|
||||
typedef struct {
|
||||
msp430_usart_t *dev; /**< The USART device to use */
|
||||
msp430_usart_sfr_t *sfr; /**< The corresponding SFR registers */
|
||||
uint8_t tx_irq_mask; /**< The bitmask to enable the TX IRQ for this
|
||||
USART */
|
||||
uint8_t rx_irq_mask; /**< The bitmask to enable the TX IRQ for this
|
||||
USART */
|
||||
uint8_t num; /**< Number of the USART */
|
||||
} msp430_usart_params_t;
|
||||
|
||||
/**
|
||||
* @brief MSP430 x1xx USART clock source
|
||||
*
|
||||
* @details The UC
|
||||
*/
|
||||
typedef enum {
|
||||
USART_CLK_UCLKI = UXTCTL_SSEL_UCLKI, /**< UCLKI clock source (not supported yet) */
|
||||
USART_CLK_AUX = UXTCTL_SSEL_ACLK, /**< auxiliary clock source */
|
||||
USART_CLK_SUBMAIN = UXTCTL_SSEL_SMCLK, /**< sub-system master clock source */
|
||||
} msp430_usart_clk_t;
|
||||
|
||||
/**
|
||||
* @brief MSP430 x1xx USART prescaler configuration
|
||||
*/
|
||||
typedef struct {
|
||||
msp430_usart_clk_t clk_source; /**< Clock source to use */
|
||||
uint8_t br0; /**< What to write in the BR0 register */
|
||||
uint8_t br1; /**< What to write in the BR1 register */
|
||||
uint8_t mctl; /**< USART modulation control register */
|
||||
} msp430_usart_prescaler_t;
|
||||
|
||||
/**
|
||||
* @brief MSP430 x1xx USART configuration registers
|
||||
*
|
||||
* @details Unlike @ref msp430_usart_params_t this contains configuration that
|
||||
* may depends on runtime settings
|
||||
*/
|
||||
typedef struct {
|
||||
msp430_usart_prescaler_t prescaler; /**< Prescaler configuration */
|
||||
uint8_t ctl; /**< USART control register */
|
||||
} msp430_usart_conf_t;
|
||||
|
||||
/**
|
||||
* @brief MSP430 x1xx UART configuration, CPU level
|
||||
*
|
||||
* The MSP430 x1xx has two USART peripherals which both can be operated in
|
||||
* UART mode. Each is connected to a fixed GPIO for RXD and TXD, respectively.
|
||||
* Hence, there is not much left for the board to configure anyway, so we just
|
||||
* prepare UART configurations at CPU level for the board to refer to. The
|
||||
* unused configuration(s) will be garbage collected by the linker.
|
||||
*/
|
||||
typedef struct {
|
||||
msp430_usart_params_t usart_params; /**< The USART params */
|
||||
/**
|
||||
* @brief The bitmask to write to the SFR register to enable the USART
|
||||
* device in UART mode with TX enabled
|
||||
*
|
||||
* @note Sadly, the layout of the SFR registers corresponding to the
|
||||
* USART peripherals differs.
|
||||
*/
|
||||
uint8_t tx_enable_mask;
|
||||
/**
|
||||
* @brief The bitmask to write to the SFR register to enable the USART
|
||||
* device in UART mode with RX+TX enabled
|
||||
*
|
||||
* @details The RX and TX part of the UART can be enabled individually.
|
||||
* But since there is no way to enable only RX with RIOT's UART
|
||||
* API and this is an internal structure anyway, we optimize this
|
||||
* to avoid an OR function to compile `tx_enable_mask` and
|
||||
* `rx_enable_mask`.
|
||||
*/
|
||||
uint8_t rxtx_enable_mask;
|
||||
gpio_t rxd; /**< RXD pin */
|
||||
gpio_t txd; /**< TXD pin */
|
||||
} msp430_usart_uart_params_t;
|
||||
|
||||
/**
|
||||
* @brief MSP430 x1xx UART configuration, board level
|
||||
*/
|
||||
typedef struct {
|
||||
const msp430_usart_uart_params_t *uart; /**< The UART configuration to use */
|
||||
} uart_conf_t;
|
||||
|
||||
/**
|
||||
* @brief MSP430 x1xx SPI configuration, CPU level
|
||||
*
|
||||
* The MSP430 x1xx has two USART peripherals which both can be operated in
|
||||
* SPI mode. Each is connected to a fixed GPIO for COPI (MOSI), CIPO (MISO),
|
||||
* and SCK, respectively. Hence, there is not much left for the board to
|
||||
* configure anyway, so we just prepare UART configurations at CPU level for
|
||||
* the board to refer to. The unused configuration(s) will be garbage collected
|
||||
* by the linker.
|
||||
*/
|
||||
typedef struct {
|
||||
msp430_usart_params_t usart_params; /**< The USART parameters */
|
||||
/**
|
||||
* @brief The bitmask to write to the SFR register to enable the USART
|
||||
* device in SPI mode
|
||||
*
|
||||
* @note Sadly, the layout of the SFR registers corresponding to the
|
||||
* USART peripherals differs.
|
||||
*/
|
||||
uint8_t enable_mask;
|
||||
gpio_t miso; /**< CIPO (MISO) pin */
|
||||
gpio_t mosi; /**< COPI (MOSI) pin */
|
||||
gpio_t sck; /**< SCK pin */
|
||||
} msp430_usart_spi_params_t;
|
||||
|
||||
/**
|
||||
* @brief MSP430 x1xx SPI configuration, board level
|
||||
*/
|
||||
typedef struct {
|
||||
const msp430_usart_spi_params_t *spi; /**< The SPI configuration to use */
|
||||
} spi_conf_t;
|
||||
|
||||
/**
|
||||
* @brief MSP430 x1xx USART0 in UART configuration
|
||||
*/
|
||||
extern const msp430_usart_uart_params_t usart0_as_uart;
|
||||
|
||||
/**
|
||||
* @brief MSP430 x1xx USART1 in UART configuration
|
||||
*/
|
||||
extern const msp430_usart_uart_params_t usart1_as_uart;
|
||||
|
||||
/**
|
||||
* @brief MSP430 x1xx USART0 in SPI configuration
|
||||
*/
|
||||
extern const msp430_usart_spi_params_t usart0_as_spi;
|
||||
|
||||
/**
|
||||
* @brief MSP430 x1xx USART1 in UART configuration
|
||||
*/
|
||||
extern const msp430_usart_spi_params_t usart1_as_spi;
|
||||
|
||||
/**
|
||||
* @name declare needed generic SPI functions
|
||||
* @{
|
||||
@ -75,6 +234,156 @@ typedef enum {
|
||||
#define PERIPH_SPI_NEEDS_TRANSFER_REGS /**< use shared spi_transfer_regs() */
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @brief Enable the TX interrupt on the given USART
|
||||
* @param[in] usart_conf USART config of the USART to enable the TX IRQ on
|
||||
*
|
||||
* @warning This will not work while the peripheral is still under reset,
|
||||
* as the IRQ configuration is constantly reset while the software
|
||||
* reset bit is set.
|
||||
*/
|
||||
static inline void msp430_usart_enable_tx_irq(const msp430_usart_params_t *usart_conf)
|
||||
{
|
||||
usart_conf->sfr->IE |= usart_conf->tx_irq_mask;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Enable the RX interrupt on the given USART
|
||||
* @param[in] usart_conf USART config of the USART to enable the RX IRQ on
|
||||
*
|
||||
* @warning This will not work while the peripheral is still under reset,
|
||||
* as the IRQ configuration is constantly reset while the software
|
||||
* reset bit is set.
|
||||
*/
|
||||
static inline void msp430_usart_enable_rx_irq(const msp430_usart_params_t *usart_conf)
|
||||
{
|
||||
usart_conf->sfr->IE |= usart_conf->rx_irq_mask;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Disable the TX interrupt on the given USART
|
||||
* @param[in] usart_conf USART config of the USART to disable the TX IRQ on
|
||||
*
|
||||
* @warning This will not work while the peripheral is still under reset,
|
||||
* as the IRQ configuration is constantly reset while the software
|
||||
* reset bit is set.
|
||||
*/
|
||||
static inline void msp430_usart_disable_tx_irq(const msp430_usart_params_t *usart_conf)
|
||||
{
|
||||
usart_conf->sfr->IE &= ~(usart_conf->tx_irq_mask);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Disable the RX interrupt on the given USART
|
||||
* @param[in] usart_conf USART config of the USART to disable the RX IRQ on
|
||||
*
|
||||
* @warning This will not work while the peripheral is still under reset,
|
||||
* as the IRQ configuration is constantly reset while the software
|
||||
* reset bit is set.
|
||||
*/
|
||||
static inline void msp430_usart_disable_rx_irq(const msp430_usart_params_t *usart_conf)
|
||||
{
|
||||
usart_conf->sfr->IE &= ~(usart_conf->rx_irq_mask);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the TX IRQ flag of the given USART
|
||||
* @param[in] usart_conf USART config of the USART to disable the RX IRQ on
|
||||
* @retval true The interrupt flag is set
|
||||
* @retval false The interrupt flag is **NOT** set
|
||||
*/
|
||||
static inline bool msp430_usart_get_tx_irq_flag(const msp430_usart_params_t *usart_conf)
|
||||
{
|
||||
return usart_conf->sfr->IFG & usart_conf->tx_irq_mask;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the RX IRQ flag of the given USART
|
||||
* @param[in] usart_conf USART config of the USART to disable the RX IRQ on
|
||||
* @retval true The interrupt flag is set
|
||||
* @retval false The interrupt flag is **NOT** set
|
||||
*/
|
||||
static inline bool msp430_usart_get_rx_irq_flag(const msp430_usart_params_t *usart_conf)
|
||||
{
|
||||
return usart_conf->sfr->IFG & usart_conf->rx_irq_mask;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Check if both TX *and* RX IRQ flags are set on the given USART
|
||||
* @param[in] usart_conf USART config of the USART to disable the RX IRQ on
|
||||
* @retval true The interrupt flag *both* TX and RX is set
|
||||
* @retval false Either TX IRQ flag *not* set, or RX *not* set, or *neither* set
|
||||
*/
|
||||
static inline bool msp430_usart_are_both_irq_flags_set(const msp430_usart_params_t *usart_conf)
|
||||
{
|
||||
const uint8_t mask = usart_conf->tx_irq_mask | usart_conf->rx_irq_mask;
|
||||
return (usart_conf->sfr->IFG & mask) == mask;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Clear the TX IRQ flag of the given USART
|
||||
* @param[in] usart_conf USART config of the USART to disable the RX IRQ on
|
||||
*/
|
||||
static inline void msp430_usart_clear_tx_irq_flag(const msp430_usart_params_t *usart_conf)
|
||||
{
|
||||
usart_conf->sfr->IFG &= ~(usart_conf->tx_irq_mask);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Clear the RX IRQ flag of the given USART
|
||||
* @param[in] usart_conf USART config of the USART to disable the RX IRQ on
|
||||
*/
|
||||
static inline void msp430_usart_clear_rx_irq_flag(const msp430_usart_params_t *usart_conf)
|
||||
{
|
||||
usart_conf->sfr->IFG &= ~(usart_conf->rx_irq_mask);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get exclusive access to an USART peripheral and initialize it
|
||||
* for operation as configured
|
||||
* @param[in] params Static USART configuration
|
||||
* @param[in] conf Dynamic USART configuration
|
||||
* @param[in] enable_mask Bitmask to write to the SFR register to enable the
|
||||
* peripheral in the intended mode.
|
||||
*
|
||||
* @warning The freshly acquired USART will still be placed in software
|
||||
* reset when this function returns. The caller is expected to
|
||||
* finish configuration such as configuring GPIOs connected to
|
||||
* the USART suitably, clearing error flags, setting up IRQ
|
||||
* handlers etc. and finally releasing the USART from reset.
|
||||
*/
|
||||
void msp430_usart_acquire(const msp430_usart_params_t *params,
|
||||
const msp430_usart_conf_t *conf,
|
||||
uint8_t enable_mask);
|
||||
|
||||
/**
|
||||
* @brief Release exclusive access to an USART peripheral and turn it
|
||||
* off again
|
||||
* @param[in] params Configuration specifying the USART to release
|
||||
*/
|
||||
void msp430_usart_release(const msp430_usart_params_t *params);
|
||||
|
||||
/**
|
||||
* @brief Compute a suitable prescaler
|
||||
*
|
||||
* @param[in] clock SPI clock in Hz or UART symbol rate in Baud
|
||||
* @param[in] min_br Smallest BR0/BR1 value supported by hardware
|
||||
* (@ref USART_MIN_BR_SPI or @ref USART_MIN_BR_UART)
|
||||
* @return Suitable prescaler config
|
||||
* @note If the board has an auxiliary clock generated from a
|
||||
* 32,678 Hz watch crystal with no clock divider, the auxiliary
|
||||
* clock is used for symbol rates of 9,600 Bd, 4,800 Bd, 2,400 Bd,
|
||||
* and 1,200 Bd. For every other symbol rate the subsystem main
|
||||
* clock is used instead.
|
||||
* @warning This will compute the prescaler generating the frequency
|
||||
* *closest* to @p clock. It may generate a frequency higher than
|
||||
* requested, if this is closer to the target frequency than the
|
||||
* next lower frequency. This makes bit-timings better in UART
|
||||
* @warning The mctl `struct` field in the result may be non-zero. Callers
|
||||
* must clear this, if the intend to use the USART in modes
|
||||
* other than UART.
|
||||
*/
|
||||
msp430_usart_prescaler_t msp430_usart_prescale(uint32_t clock, uint16_t min_br);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
@ -6,6 +6,7 @@ MODULE = periph
|
||||
# family it is the (incompatible) USCI.
|
||||
ifeq (msp430_x1xx,$(CPU_FAM))
|
||||
SERIAL_IP_BLOCK := usart
|
||||
SRC += $(SERIAL_IP_BLOCK).c
|
||||
endif
|
||||
ifeq (msp430_f2xx_g2xx,$(CPU_FAM))
|
||||
SERIAL_IP_BLOCK := usci
|
||||
|
@ -1,5 +1,6 @@
|
||||
/*
|
||||
* Copyright (C) 2015-2016 Freie Universität Berlin
|
||||
* 2023 Otto-von-Guericke-Universität Magdeburg
|
||||
*
|
||||
* 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
|
||||
@ -19,32 +20,20 @@
|
||||
* devices - one used as UART and one as SPI.
|
||||
*
|
||||
* @author Hauke Petersen <hauke.petersen@fu-berlin.de>
|
||||
* @author Marian Buschsieweke <marian.buschsieweke@posteo.net>
|
||||
*
|
||||
* @}
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#include "cpu.h"
|
||||
#include "mutex.h"
|
||||
#include "compiler_hints.h"
|
||||
#include "periph/spi.h"
|
||||
|
||||
/**
|
||||
* @brief Mutex for locking the SPI device
|
||||
*/
|
||||
static mutex_t spi_lock = MUTEX_INIT;
|
||||
#include "periph_cpu.h"
|
||||
|
||||
void spi_init(spi_t bus)
|
||||
{
|
||||
assert((unsigned)bus < SPI_NUMOF);
|
||||
|
||||
/* put SPI device in reset state */
|
||||
SPI_BASE->CTL = SWRST;
|
||||
SPI_BASE->CTL |= (CHAR | SYNC | MM);
|
||||
SPI_BASE->RCTL = 0;
|
||||
SPI_BASE->MCTL = 0;
|
||||
/* enable SPI mode */
|
||||
SPI_SFR->ME |= SPI_ME_BIT;
|
||||
assume((unsigned)bus < SPI_NUMOF);
|
||||
|
||||
/* trigger the pin configuration */
|
||||
spi_init_pins(bus);
|
||||
@ -52,53 +41,78 @@ void spi_init(spi_t bus)
|
||||
|
||||
void spi_init_pins(spi_t bus)
|
||||
{
|
||||
(void)bus;
|
||||
assume((unsigned)bus < SPI_NUMOF);
|
||||
|
||||
gpio_periph_mode(SPI_PIN_MISO, true);
|
||||
gpio_periph_mode(SPI_PIN_MOSI, true);
|
||||
gpio_periph_mode(SPI_PIN_CLK, true);
|
||||
const msp430_usart_spi_params_t *params = spi_config[bus].spi;
|
||||
|
||||
/* set output GPIOs to idle levels of the peripheral */
|
||||
gpio_set(params->mosi);
|
||||
gpio_clear(params->sck);
|
||||
|
||||
/* configure the pins as GPIOs, not attaching to the peripheral as of now */
|
||||
gpio_init(params->miso, GPIO_IN);
|
||||
gpio_init(params->mosi, GPIO_OUT);
|
||||
gpio_init(params->sck, GPIO_OUT);
|
||||
}
|
||||
|
||||
void spi_acquire(spi_t bus, spi_cs_t cs, spi_mode_t mode, spi_clk_t clk)
|
||||
{
|
||||
(void)bus;
|
||||
assume((unsigned)bus < SPI_NUMOF);
|
||||
(void)cs;
|
||||
assert((unsigned)bus < SPI_NUMOF);
|
||||
assert(clk != SPI_CLK_10MHZ);
|
||||
|
||||
/* lock the bus */
|
||||
mutex_lock(&spi_lock);
|
||||
const msp430_usart_spi_params_t *params = spi_config[bus].spi;
|
||||
msp430_usart_t *dev = params->usart_params.dev;
|
||||
|
||||
/* calculate baudrate */
|
||||
uint32_t br = msp430_submain_clock_freq() / clk;
|
||||
/* make sure the is not smaller then 2 */
|
||||
if (br < 2) {
|
||||
br = 2;
|
||||
}
|
||||
SPI_BASE->BR0 = (uint8_t)br;
|
||||
SPI_BASE->BR1 = (uint8_t)(br >> 8);
|
||||
msp430_usart_conf_t conf = {
|
||||
.prescaler = msp430_usart_prescale(clk, USART_MIN_BR_SPI),
|
||||
.ctl = CHAR | SYNC | MM,
|
||||
};
|
||||
/* get exclusive access to the USART (this will also indirectly ensure
|
||||
* exclusive SPI bus access */
|
||||
msp430_usart_acquire(¶ms->usart_params, &conf, params->enable_mask);
|
||||
|
||||
/* clock and phase are encoded in mode so that they can be directly be
|
||||
* written into TCTL. TCTL has been initialized by
|
||||
* msp430_usart_acquire(), so we don't need to wipe any previous clock
|
||||
* phase or polarity state.
|
||||
*
|
||||
* STC disables "multi-master" mode, in which the STE pin would be connected
|
||||
* to the CS output of any other SPI controller */
|
||||
dev->TCTL |= STC | mode;
|
||||
|
||||
/* configure bus mode */
|
||||
/* configure mode */
|
||||
SPI_BASE->TCTL = (UXTCTL_SSEL_SMCLK | STC | mode);
|
||||
/* release from software reset */
|
||||
SPI_BASE->CTL &= ~(SWRST);
|
||||
dev->CTL &= ~(SWRST);
|
||||
|
||||
/* attach the pins only now after the peripheral is up and running, as
|
||||
* otherwise noise is send out (could be observed on SCK with a logic
|
||||
* analyzer). */
|
||||
gpio_periph_mode(params->miso, true);
|
||||
gpio_periph_mode(params->mosi, true);
|
||||
gpio_periph_mode(params->sck, true);
|
||||
}
|
||||
|
||||
void spi_release(spi_t bus)
|
||||
{
|
||||
(void)bus;
|
||||
/* put SPI device back in reset state */
|
||||
SPI_BASE->CTL |= SWRST;
|
||||
assume((unsigned)bus < SPI_NUMOF);
|
||||
const msp430_usart_spi_params_t *params = spi_config[bus].spi;
|
||||
|
||||
/* release the bus */
|
||||
mutex_unlock(&spi_lock);
|
||||
/* release the pins to avoid sending noise while the peripheral is
|
||||
* reconfigured or used to provide other interfaces */
|
||||
gpio_periph_mode(params->miso, false);
|
||||
gpio_periph_mode(params->mosi, false);
|
||||
gpio_periph_mode(params->sck, false);
|
||||
|
||||
/* release the peripheral */
|
||||
msp430_usart_release(¶ms->usart_params);
|
||||
}
|
||||
|
||||
void spi_transfer_bytes(spi_t bus, spi_cs_t cs, bool cont,
|
||||
const void *out, void *in, size_t len)
|
||||
{
|
||||
(void)bus;
|
||||
assume((unsigned)bus < SPI_NUMOF);
|
||||
const msp430_usart_spi_params_t *params = spi_config[bus].spi;
|
||||
const msp430_usart_params_t *usart = ¶ms->usart_params;
|
||||
msp430_usart_t *dev = params->usart_params.dev;
|
||||
|
||||
const uint8_t *out_buf = out;
|
||||
uint8_t *in_buf = in;
|
||||
@ -112,26 +126,36 @@ void spi_transfer_bytes(spi_t bus, spi_cs_t cs, bool cont,
|
||||
/* if we only send out data, we do this the fast way... */
|
||||
if (!in_buf) {
|
||||
for (size_t i = 0; i < len; i++) {
|
||||
while (!(SPI_SFR->IFG & SPI_IE_TX_BIT)) {}
|
||||
SPI_BASE->TXBUF = out_buf[i];
|
||||
while (!msp430_usart_get_tx_irq_flag(usart)) {
|
||||
/* still busy waiting for TX to complete */
|
||||
}
|
||||
dev->TXBUF = out_buf[i];
|
||||
}
|
||||
/* finally we need to wait, until all transfers are complete */
|
||||
while (!(SPI_SFR->IFG & SPI_IE_TX_BIT) || !(SPI_SFR->IFG & SPI_IE_RX_BIT)) {}
|
||||
SPI_BASE->RXBUF;
|
||||
while (!msp430_usart_are_both_irq_flags_set(usart)) {
|
||||
/* still either TX, or RX, or both not completed */
|
||||
}
|
||||
(void)dev->RXBUF;
|
||||
}
|
||||
else if (!out_buf) {
|
||||
for (size_t i = 0; i < len; i++) {
|
||||
SPI_BASE->TXBUF = 0;
|
||||
while (!(SPI_SFR->IFG & SPI_IE_RX_BIT)) {}
|
||||
in_buf[i] = (char)SPI_BASE->RXBUF;
|
||||
dev->TXBUF = 0;
|
||||
while (!msp430_usart_get_rx_irq_flag(usart)) {
|
||||
/* still busy waiting for RX to complete */
|
||||
}
|
||||
in_buf[i] = dev->RXBUF;
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (size_t i = 0; i < len; i++) {
|
||||
while (!(SPI_SFR->IFG & SPI_IE_TX_BIT)) {}
|
||||
SPI_BASE->TXBUF = out_buf[i];
|
||||
while (!(SPI_SFR->IFG & SPI_IE_RX_BIT)) {}
|
||||
in_buf[i] = (char)SPI_BASE->RXBUF;
|
||||
while (!msp430_usart_get_tx_irq_flag(usart)) {
|
||||
/* still busy waiting for TX to complete */
|
||||
}
|
||||
dev->TXBUF = out_buf[i];
|
||||
while (!msp430_usart_get_rx_irq_flag(usart)) {
|
||||
/* still busy waiting for RX to complete */
|
||||
}
|
||||
in_buf[i] = dev->RXBUF;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,6 @@
|
||||
/*
|
||||
* Copyright (C) 2015 Freie Universität Berlin
|
||||
* 2023 Otto-von-Guericke-Universität Magdeburg
|
||||
*
|
||||
* 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
|
||||
@ -15,6 +16,7 @@
|
||||
* @brief Low-level UART driver implementation
|
||||
*
|
||||
* @author Hauke Petersen <hauke.petersen@fu-berlin.de>
|
||||
* @author Marian Buschsieweke <marian.buschsieweke@posteo.net>
|
||||
*
|
||||
* @}
|
||||
*/
|
||||
@ -23,105 +25,135 @@
|
||||
#include "periph_cpu.h"
|
||||
#include "periph_conf.h"
|
||||
#include "periph/uart.h"
|
||||
#include "periph/gpio.h"
|
||||
#include "compiler_hints.h"
|
||||
|
||||
/**
|
||||
* @brief Keep track of the interrupt context
|
||||
* @{
|
||||
*/
|
||||
static uart_rx_cb_t ctx_rx_cb;
|
||||
static void *ctx_isr_arg;
|
||||
/** @} */
|
||||
static uart_isr_ctx_t ctx[UART_NUMOF];
|
||||
static msp430_usart_conf_t confs[UART_NUMOF];
|
||||
|
||||
static int init_base(uart_t uart, uint32_t baudrate);
|
||||
|
||||
int uart_init(uart_t uart, uint32_t baudrate, uart_rx_cb_t rx_cb, void *arg)
|
||||
static void init(uart_t uart)
|
||||
{
|
||||
int res = init_base(uart, baudrate);
|
||||
if (res != UART_OK) {
|
||||
return res;
|
||||
const msp430_usart_uart_params_t *params = uart_config[uart].uart;
|
||||
msp430_usart_t *dev = params->usart_params.dev;
|
||||
uint8_t enable_mask = params->rxtx_enable_mask;
|
||||
|
||||
/* most of the time UART is used to both send and receive */
|
||||
if (unlikely(!ctx[uart].rx_cb)) {
|
||||
enable_mask = params->tx_enable_mask;
|
||||
}
|
||||
|
||||
/* save interrupt context */
|
||||
ctx_rx_cb = rx_cb;
|
||||
ctx_isr_arg = arg;
|
||||
/* reset interrupt flags and enable RX interrupt */
|
||||
UART_SFR->IE &= ~(UART_IE_TX_BIT);
|
||||
UART_SFR->IFG &= ~(UART_IE_RX_BIT);
|
||||
UART_SFR->IFG |= (UART_IE_TX_BIT);
|
||||
UART_SFR->IE |= (UART_IE_RX_BIT);
|
||||
return UART_OK;
|
||||
/* acquire USART and put in in UART mode */
|
||||
msp430_usart_acquire(¶ms->usart_params, &confs[uart], enable_mask);
|
||||
|
||||
/* configure pins */
|
||||
gpio_set(params->txd);
|
||||
gpio_init(params->txd, GPIO_OUT);
|
||||
gpio_periph_mode(params->txd, true);
|
||||
|
||||
gpio_init(params->rxd, GPIO_IN);
|
||||
gpio_periph_mode(params->rxd, true);
|
||||
|
||||
/* now that everything is configured, release the software reset bit */
|
||||
dev->CTL &= ~(SWRST);
|
||||
|
||||
/* finally, enable the RX IRQ (won't work prior to releasing the software
|
||||
* reset bit, as this is cleared under reset) */
|
||||
if (likely(ctx[uart].rx_cb)) {
|
||||
msp430_usart_enable_rx_irq(¶ms->usart_params);
|
||||
}
|
||||
}
|
||||
|
||||
static int init_base(uart_t uart, uint32_t baudrate)
|
||||
int uart_init(uart_t uart, uint32_t symbolrate, uart_rx_cb_t rx_cb, void *arg)
|
||||
{
|
||||
if (uart != 0) {
|
||||
return UART_NODEV;
|
||||
assume((unsigned)uart < UART_NUMOF);
|
||||
|
||||
/* save interrupt context */
|
||||
ctx[uart].rx_cb = rx_cb;
|
||||
ctx[uart].arg = arg;
|
||||
|
||||
/* prepare and save UART config */
|
||||
confs[uart].ctl = CHAR;
|
||||
confs[uart].prescaler = msp430_usart_prescale(symbolrate, USART_MIN_BR_UART);
|
||||
|
||||
|
||||
if (rx_cb) {
|
||||
init(uart);
|
||||
}
|
||||
|
||||
/* get the default UART for now -> TODO: enable for multiple devices */
|
||||
msp430_usart_t *dev = UART_BASE;
|
||||
|
||||
/* power off and reset device */
|
||||
uart_poweroff(uart);
|
||||
dev->CTL = SWRST;
|
||||
/* configure to 8N1 and using the SMCLK*/
|
||||
dev->CTL |= CHAR;
|
||||
dev->TCTL = (TXEPT | UXTCTL_SSEL_SMCLK);
|
||||
dev->RCTL = 0x00;
|
||||
/* baudrate configuration */
|
||||
uint16_t br = (uint16_t)(msp430_submain_clock_freq() / baudrate);
|
||||
dev->BR0 = (uint8_t)br;
|
||||
dev->BR1 = (uint8_t)(br >> 8);
|
||||
/* TODO: calculate value for modulation register */
|
||||
dev->MCTL = 0;
|
||||
/* configure pins -> TODO: move into GPIO driver (once implemented) */
|
||||
UART_PORT->SEL |= (UART_RX_PIN | UART_TX_PIN);
|
||||
msp430_port_t *port = &UART_PORT->base;
|
||||
port->OD |= UART_RX_PIN;
|
||||
port->OD &= ~(UART_TX_PIN);
|
||||
port->DIR |= UART_TX_PIN;
|
||||
port->DIR &= ~(UART_RX_PIN);
|
||||
/* enable receiver and transmitter */
|
||||
uart_poweron(uart);
|
||||
/* and finally release the software reset bit */
|
||||
dev->CTL &= ~(SWRST);
|
||||
return UART_OK;
|
||||
}
|
||||
|
||||
void uart_write(uart_t uart, const uint8_t *data, size_t len)
|
||||
{
|
||||
(void)uart;
|
||||
msp430_usart_t *dev = UART_BASE;
|
||||
assume((unsigned)uart < UART_NUMOF);
|
||||
const msp430_usart_uart_params_t *params = uart_config[uart].uart;
|
||||
msp430_usart_t *dev = params->usart_params.dev;
|
||||
|
||||
/* If UART is in TX-only, the USART is released when done sending.
|
||||
* This is not only helpful for power saving, but also to share the USART.
|
||||
*/
|
||||
if (!unlikely(ctx[uart].rx_cb)) {
|
||||
init(uart);
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < len; i++) {
|
||||
while (!(dev->TCTL & TXEPT)) {}
|
||||
dev->TXBUF = data[i];
|
||||
}
|
||||
|
||||
if (!unlikely(ctx[uart].rx_cb)) {
|
||||
msp430_usart_release(¶ms->usart_params);
|
||||
}
|
||||
}
|
||||
|
||||
void uart_poweron(uart_t uart)
|
||||
{
|
||||
(void)uart;
|
||||
UART_SFR->ME |= UART_ME_BITS;
|
||||
assume((unsigned)uart < UART_NUMOF);
|
||||
/* In TX-only mode, the USART is only powered on when transmitting */
|
||||
if (likely(ctx[uart].rx_cb)) {
|
||||
init(uart);
|
||||
}
|
||||
}
|
||||
|
||||
void uart_poweroff(uart_t uart)
|
||||
{
|
||||
(void)uart;
|
||||
UART_SFR->ME &= ~(UART_ME_BITS);
|
||||
assume((unsigned)uart < UART_NUMOF);
|
||||
const msp430_usart_uart_params_t *params = uart_config[uart].uart;
|
||||
/* In TX-only mode, the USART is only powered on when transmitting */
|
||||
if (likely(ctx[uart].rx_cb)) {
|
||||
msp430_usart_release(¶ms->usart_params);
|
||||
}
|
||||
}
|
||||
|
||||
ISR(UART_RX_ISR, isr_uart_0_rx)
|
||||
static void uart_rx_isr(uart_t uart)
|
||||
{
|
||||
__enter_isr();
|
||||
assume((unsigned)uart < UART_NUMOF);
|
||||
const msp430_usart_uart_params_t *params = uart_config[uart].uart;
|
||||
msp430_usart_t *dev = params->usart_params.dev;
|
||||
|
||||
/* read character (resets interrupt flag) */
|
||||
char c = UART_BASE->RXBUF;
|
||||
char c = dev->RXBUF;
|
||||
|
||||
/* only call callback if there was no receive error */
|
||||
if(! (UART_BASE->RCTL & RXERR)) {
|
||||
ctx_rx_cb(ctx_isr_arg, c);
|
||||
if (!(dev->RCTL & RXERR)) {
|
||||
ctx[uart].rx_cb(ctx[uart].arg, c);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef UART0_RX_ISR
|
||||
ISR(UART0_RX_ISR, isr_uart_0_rx)
|
||||
{
|
||||
__enter_isr();
|
||||
uart_rx_isr(UART_DEV(0));
|
||||
__exit_isr();
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef UART1_RX_ISR
|
||||
ISR(UART1_RX_ISR, isr_uart_0_rx)
|
||||
{
|
||||
__enter_isr();
|
||||
uart_rx_isr(UART_DEV(1));
|
||||
__exit_isr();
|
||||
}
|
||||
#endif
|
||||
|
163
cpu/msp430/periph/usart.c
Normal file
163
cpu/msp430/periph/usart.c
Normal file
@ -0,0 +1,163 @@
|
||||
#include "macros/math.h"
|
||||
#include "mutex.h"
|
||||
#include "periph_conf.h"
|
||||
#include "periph_cpu.h"
|
||||
|
||||
const msp430_usart_uart_params_t usart0_as_uart = {
|
||||
.usart_params = {
|
||||
.num = 0,
|
||||
.dev = &USART_0,
|
||||
.sfr = &USART_0_SFR,
|
||||
.tx_irq_mask = UTXE0,
|
||||
.rx_irq_mask = URXE0,
|
||||
},
|
||||
.tx_enable_mask = UTXE0,
|
||||
.rxtx_enable_mask = URXE0 | UTXE0,
|
||||
.txd = GPIO_PIN(P3, 4),
|
||||
.rxd = GPIO_PIN(P3, 5),
|
||||
};
|
||||
|
||||
const msp430_usart_uart_params_t usart1_as_uart = {
|
||||
.usart_params = {
|
||||
.num = 1,
|
||||
.dev = &USART_1,
|
||||
.sfr = &USART_1_SFR,
|
||||
.tx_irq_mask = UTXE1,
|
||||
.rx_irq_mask = URXE1,
|
||||
},
|
||||
.tx_enable_mask = UTXE1,
|
||||
.rxtx_enable_mask = URXE1 | UTXE1,
|
||||
.txd = GPIO_PIN(P3, 6),
|
||||
.rxd = GPIO_PIN(P3, 7),
|
||||
};
|
||||
|
||||
const msp430_usart_spi_params_t usart0_as_spi = {
|
||||
.usart_params = {
|
||||
.num = 0,
|
||||
.dev = &USART_0,
|
||||
.sfr = &USART_0_SFR,
|
||||
.tx_irq_mask = UTXE0,
|
||||
.rx_irq_mask = URXE0,
|
||||
},
|
||||
.enable_mask = USPIE0,
|
||||
.mosi = GPIO_PIN(P3, 1),
|
||||
.miso = GPIO_PIN(P3, 2),
|
||||
.sck = GPIO_PIN(P3, 3),
|
||||
};
|
||||
|
||||
const msp430_usart_spi_params_t usart1_as_spi = {
|
||||
.usart_params = {
|
||||
.num = 1,
|
||||
.dev = &USART_1,
|
||||
.sfr = &USART_1_SFR,
|
||||
.tx_irq_mask = UTXE1,
|
||||
.rx_irq_mask = URXE1,
|
||||
},
|
||||
.enable_mask = USPIE1,
|
||||
.mosi = GPIO_PIN(P5, 1),
|
||||
.miso = GPIO_PIN(P5, 2),
|
||||
.sck = GPIO_PIN(P5, 3),
|
||||
};
|
||||
|
||||
static mutex_t usart_locks[USART_NUMOF] = {
|
||||
MUTEX_INIT,
|
||||
MUTEX_INIT,
|
||||
};
|
||||
|
||||
void msp430_usart_acquire(const msp430_usart_params_t *params,
|
||||
const msp430_usart_conf_t *conf,
|
||||
uint8_t enable_mask)
|
||||
{
|
||||
assume(params->num < USART_NUMOF);
|
||||
|
||||
mutex_lock(&usart_locks[params->num]);
|
||||
msp430_usart_t *dev = params->dev;
|
||||
msp430_usart_sfr_t *sfr = params->sfr;
|
||||
|
||||
/* first, make sure USART is off before reconfiguring it */
|
||||
sfr->ME = 0;
|
||||
/* reset USART */
|
||||
dev->CTL = SWRST;
|
||||
|
||||
/* apply given configuration */
|
||||
dev->CTL = conf->ctl | SWRST;
|
||||
dev->MCTL = conf->prescaler.mctl;
|
||||
dev->TCTL = conf->prescaler.clk_source;
|
||||
dev->BR0 = conf->prescaler.br0;
|
||||
dev->BR1 = conf->prescaler.br1;
|
||||
|
||||
/* disable USART IRQs and clear any spurious IRQ flags */
|
||||
sfr->IE = 0;
|
||||
sfr->IFG = 0;
|
||||
/* enable USART as specified */
|
||||
sfr->ME = enable_mask;
|
||||
}
|
||||
|
||||
void msp430_usart_release(const msp430_usart_params_t *params)
|
||||
{
|
||||
assume(params->num < USART_NUMOF);
|
||||
|
||||
msp430_usart_sfr_t *sfr = params->sfr;
|
||||
|
||||
/* Disable USART */
|
||||
sfr->ME = 0;
|
||||
/* disable USART IRQs and clear any spurious IRQ flags */
|
||||
sfr->IE = 0;
|
||||
sfr->IFG = 0;
|
||||
|
||||
/* Release mutex */
|
||||
mutex_unlock(&usart_locks[params->num]);
|
||||
}
|
||||
|
||||
msp430_usart_prescaler_t msp430_usart_prescale(uint32_t clock, uint16_t min_br)
|
||||
{
|
||||
msp430_usart_prescaler_t result = { .mctl = 0 };
|
||||
uint32_t clk_hz;
|
||||
|
||||
/* If a watch crystal is used for the auxiliary clock, allow using the
|
||||
* auxiliary clock to be used as clock source for well-known
|
||||
* symbol rates, so that enabling low power modes is possible while
|
||||
* UART RX is active */
|
||||
if ((clock_params.lfxt1_frequency == 32768)
|
||||
&& (clock_params.auxiliary_clock_divier == AUXILIARY_CLOCK_DIVIDE_BY_1)) {
|
||||
clk_hz = msp430_auxiliary_clock_freq();
|
||||
assume(clk_hz == 32768);
|
||||
result.clk_source = USART_CLK_AUX;
|
||||
/* Rather than calculating the correct modulation control register
|
||||
* values, just hard-code it for four well-known symbol rates. If the
|
||||
* symbol rate is something else, we go for the high frequency
|
||||
* subsystem main clock, where bit timings are easier to hit even
|
||||
* without fine-tuning it via the modulation control register */
|
||||
switch (clock) {
|
||||
case 9600:
|
||||
result.mctl = 0x4a;
|
||||
break;
|
||||
case 4800:
|
||||
result.mctl = 0x6f;
|
||||
break;
|
||||
case 2400:
|
||||
result.mctl = 0x6b;
|
||||
break;
|
||||
case 1200:
|
||||
result.mctl = 0x03;
|
||||
break;
|
||||
default:
|
||||
clk_hz = msp430_submain_clock_freq();
|
||||
result.clk_source = USART_CLK_SUBMAIN;
|
||||
}
|
||||
}
|
||||
else {
|
||||
clk_hz = msp430_submain_clock_freq();
|
||||
result.clk_source = USART_CLK_SUBMAIN;
|
||||
}
|
||||
|
||||
uint16_t br = DIV_ROUND(clk_hz, clock);
|
||||
|
||||
if (br < min_br) {
|
||||
br = min_br;
|
||||
}
|
||||
|
||||
result.br0 = (uint8_t)br;
|
||||
result.br1 = (uint8_t)(br >> 8);
|
||||
return result;
|
||||
}
|
@ -19,6 +19,7 @@ BOARD_INSUFFICIENT_MEMORY := \
|
||||
nucleo-l011k4 \
|
||||
nucleo-l031k6 \
|
||||
nucleo-l053r8 \
|
||||
olimex-msp430-h1611 \
|
||||
samd10-xmini \
|
||||
slstk3400a \
|
||||
stk3200 \
|
||||
|
@ -10,6 +10,7 @@ BOARD_INSUFFICIENT_MEMORY := \
|
||||
nucleo-l011k4 \
|
||||
nucleo-l031k6 \
|
||||
nucleo-l053r8 \
|
||||
olimex-msp430-h1611 \
|
||||
samd10-xmini \
|
||||
slstk3400a \
|
||||
stk3200 \
|
||||
|
Loading…
Reference in New Issue
Block a user