diff --git a/boards/common/msb-430/Makefile.include b/boards/common/msb-430/Makefile.include index cf53ed4586b6..ced846ef8d4b 100644 --- a/boards/common/msb-430/Makefile.include +++ b/boards/common/msb-430/Makefile.include @@ -1,11 +1,3 @@ INCLUDES += -I$(RIOTBOARD)/common/msb-430/include -# set default port depending on operating system -PORT_LINUX ?= /dev/ttyUSB0 -PORT_DARWIN ?= $(firstword $(sort $(wildcard /dev/tty.SLAB_USBtoUART*))) - -# setup flash tool -PROGRAMMER ?= mspdebug -MSPDEBUG_PROGRAMMER ?= olimex - -PROGRAMMERS_SUPPORTED += mspdebug +include $(RIOTBOARD)/common/msp430/Makefile.include diff --git a/boards/common/msp430/Makefile.include b/boards/common/msp430/Makefile.include new file mode 100644 index 000000000000..0e75f748d2fe --- /dev/null +++ b/boards/common/msp430/Makefile.include @@ -0,0 +1,11 @@ +INCLUDES += -I$(RIOTBOARD)/common/msp430/include + +# set default port depending on operating system +PORT_LINUX ?= /dev/ttyUSB0 +PORT_DARWIN ?= $(firstword $(sort $(wildcard /dev/tty.SLAB_USBtoUART*))) + +# setup flash tool +PROGRAMMER ?= mspdebug +MSPDEBUG_PROGRAMMER ?= olimex + +PROGRAMMERS_SUPPORTED += mspdebug diff --git a/boards/common/msp430/doc.txt b/boards/common/msp430/doc.txt new file mode 100644 index 000000000000..fa6c1f46e562 --- /dev/null +++ b/boards/common/msp430/doc.txt @@ -0,0 +1,17 @@ +/* + * Copyright (C) 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 + * directory for more details. + */ + +/** + * @defgroup boards_common_msp430 Common Configuration Snippets for MSP430 boards + * @ingroup boards_common + * @brief Board configuration snippets for MSP430-based boards + * + * All boards using a CPU from the MSP430 family share certain parts of their + * configuration. This module provides a collection of fine grained + * configuration snippets that can be reused for different boards. + */ diff --git a/boards/common/msp430/include/cfg_timer_a_smclk_b_aclk.h b/boards/common/msp430/include/cfg_timer_a_smclk_b_aclk.h new file mode 100644 index 000000000000..3ae3cd66159c --- /dev/null +++ b/boards/common/msp430/include/cfg_timer_a_smclk_b_aclk.h @@ -0,0 +1,61 @@ +/* + * Copyright (C) 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 + * directory for more details. + */ + +/** + * @ingroup boards_common_msp430 + * @{ + * + * @file + * @brief Common timer configuration for TIMER_A clocked by SMCLK and + * TIMER_B clocked by ACLK + * + * @author Marian Buschsieweke + */ + +#ifndef CFG_TIMER_A_SMCLK_B_ACLK_H +#define CFG_TIMER_A_SMCLK_B_ACLK_H + +#include "periph_cpu.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @name Timer configuration + * @{ + */ +/** + * @brief Timer configuration + */ +static const timer_conf_t timer_conf[] = { + { + .timer = &TIMER_A, + .irq_flags = &TIMER_A_IRQFLAGS, + .clock_source = TIMER_CLOCK_SOURCE_SUBMAIN_CLOCK, + }, + { + .timer = &TIMER_B, + .irq_flags = &TIMER_B_IRQFLAGS, + .clock_source = TIMER_CLOCK_SOURCE_AUXILIARY_CLOCK, + } +}; +#define TIMER_NUMOF ARRAY_SIZE(timer_conf) /**< Number of timers available */ + +#define TIMER0_ISR_CC0 (TIMERA0_VECTOR) /**< IRQ vector for channel 0 of TIMER_DEV(0) */ +#define TIMER0_ISR_CCX (TIMERA1_VECTOR) /**< IRQ vector for channels !=0 of TIMER_DEV(0) */ +#define TIMER1_ISR_CC0 (TIMERB0_VECTOR) /**< IRQ vector for channel 0 of TIMER_DEV(0) */ +#define TIMER1_ISR_CCX (TIMERB1_VECTOR) /**< IRQ vector for channels !=0 of TIMER_DEV(1) */ +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif /* CFG_TIMER_A_SMCLK_B_ACLK_H */ +/** @} */ diff --git a/boards/msb-430/include/periph_conf.h b/boards/msb-430/include/periph_conf.h index 881650809638..f4c9f036535b 100644 --- a/boards/msb-430/include/periph_conf.h +++ b/boards/msb-430/include/periph_conf.h @@ -23,6 +23,7 @@ #include "periph_cpu.h" #include "macros/units.h" +#include "cfg_timer_a_smclk_b_aclk.h" #ifdef __cplusplus extern "C" { @@ -44,17 +45,6 @@ static const msp430_clock_params_t clock_params = { .has_r_osc = true, }; -/** - * @name Timer configuration - * @{ - */ -#define TIMER_NUMOF (1U) -#define TIMER_BASE (&TIMER_A) -#define TIMER_CHAN (3) -#define TIMER_ISR_CC0 (TIMERA0_VECTOR) -#define TIMER_ISR_CCX (TIMERA1_VECTOR) -/** @} */ - /** * @name UART configuration * @{ diff --git a/boards/msb-430h/include/periph_conf.h b/boards/msb-430h/include/periph_conf.h index 7f0dc217e816..d7151bbc3d37 100644 --- a/boards/msb-430h/include/periph_conf.h +++ b/boards/msb-430h/include/periph_conf.h @@ -22,6 +22,7 @@ #define PERIPH_CONF_H #include "periph_cpu.h" +#include "cfg_timer_a_smclk_b_aclk.h" #ifdef __cplusplus extern "C" { @@ -43,17 +44,6 @@ static const msp430_clock_params_t clock_params = { .has_r_osc = true, }; -/** - * @name Timer configuration - * @{ - */ -#define TIMER_NUMOF (1U) -#define TIMER_BASE (&TIMER_A) -#define TIMER_CHAN (3) -#define TIMER_ISR_CC0 (TIMERA0_VECTOR) -#define TIMER_ISR_CCX (TIMERA1_VECTOR) -/** @} */ - /** * @name UART configuration * @{ diff --git a/boards/olimex-msp430-h1611/Makefile.include b/boards/olimex-msp430-h1611/Makefile.include index d49e656df6f8..e2fb1150be70 100644 --- a/boards/olimex-msp430-h1611/Makefile.include +++ b/boards/olimex-msp430-h1611/Makefile.include @@ -1,13 +1,3 @@ -# set default port depending on operating system -PORT_LINUX ?= /dev/ttyUSB0 -PORT_DARWIN ?= $(firstword $(sort $(wildcard /dev/tty.usbserial-MXV*))) - -# flash tool configuration -PROGRAMMER ?= mspdebug -MSPDEBUG_PROGRAMMER ?= olimex - -PROGRAMMERS_SUPPORTED += mspdebug - # When freshly plugged in the Olimex MSP430-JTAG-Tiny debugger provides a # ttyACM interface, which is only available until the first flashing. A # `make term` or even a `make flash term` may pick the JTAG debugger instead @@ -24,3 +14,5 @@ TTY_SELECT_CMD := $(RIOTTOOLS)/usb-serial/ttys.py \ $(RIOTTOOLS)/usb-serial/ttys.py \ --most-recent \ --format path serial + +include $(RIOTBOARD)/common/msp430/Makefile.include diff --git a/boards/olimex-msp430-h1611/include/periph_conf.h b/boards/olimex-msp430-h1611/include/periph_conf.h index de59e548f20a..79603ceccc3d 100644 --- a/boards/olimex-msp430-h1611/include/periph_conf.h +++ b/boards/olimex-msp430-h1611/include/periph_conf.h @@ -23,6 +23,7 @@ #include "periph_cpu.h" #include "macros/units.h" +#include "cfg_timer_a_smclk_b_aclk.h" #ifdef __cplusplus extern "C" { @@ -43,17 +44,6 @@ static const msp430_clock_params_t clock_params = { .auxiliary_clock_divier = AUXILIARY_CLOCK_DIVIDE_BY_1, }; -/** - * @name Timer configuration - * @{ - */ -#define TIMER_NUMOF (1U) -#define TIMER_BASE (&TIMER_A) -#define TIMER_CHAN (3) -#define TIMER_ISR_CC0 (TIMERA0_VECTOR) -#define TIMER_ISR_CCX (TIMERA1_VECTOR) -/** @} */ - /** * @name UART configuration * @{ diff --git a/boards/olimex-msp430-h2618/Makefile.include b/boards/olimex-msp430-h2618/Makefile.include index d49e656df6f8..e2fb1150be70 100644 --- a/boards/olimex-msp430-h2618/Makefile.include +++ b/boards/olimex-msp430-h2618/Makefile.include @@ -1,13 +1,3 @@ -# set default port depending on operating system -PORT_LINUX ?= /dev/ttyUSB0 -PORT_DARWIN ?= $(firstword $(sort $(wildcard /dev/tty.usbserial-MXV*))) - -# flash tool configuration -PROGRAMMER ?= mspdebug -MSPDEBUG_PROGRAMMER ?= olimex - -PROGRAMMERS_SUPPORTED += mspdebug - # When freshly plugged in the Olimex MSP430-JTAG-Tiny debugger provides a # ttyACM interface, which is only available until the first flashing. A # `make term` or even a `make flash term` may pick the JTAG debugger instead @@ -24,3 +14,5 @@ TTY_SELECT_CMD := $(RIOTTOOLS)/usb-serial/ttys.py \ $(RIOTTOOLS)/usb-serial/ttys.py \ --most-recent \ --format path serial + +include $(RIOTBOARD)/common/msp430/Makefile.include diff --git a/boards/olimex-msp430-h2618/include/periph_conf.h b/boards/olimex-msp430-h2618/include/periph_conf.h index ebec03431a70..d7375946dcf6 100644 --- a/boards/olimex-msp430-h2618/include/periph_conf.h +++ b/boards/olimex-msp430-h2618/include/periph_conf.h @@ -22,6 +22,7 @@ #include "periph_cpu.h" #include "macros/units.h" +#include "cfg_timer_a_smclk_b_aclk.h" #ifdef __cplusplus extern "C" { @@ -42,17 +43,6 @@ static const msp430_clock_params_t clock_params = { .auxiliary_clock_divier = AUXILIARY_CLOCK_DIVIDE_BY_1, }; -/** - * @name Timer configuration - * @{ - */ -#define TIMER_NUMOF (1U) -#define TIMER_BASE (&TIMER_A) -#define TIMER_CHAN (3) -#define TIMER_ISR_CC0 (TIMERA0_VECTOR) -#define TIMER_ISR_CCX (TIMERA1_VECTOR) -/** @} */ - /** * @name UART configuration * @{ diff --git a/boards/telosb/Makefile.include b/boards/telosb/Makefile.include index 89ae2fdc8626..62146219f18b 100644 --- a/boards/telosb/Makefile.include +++ b/boards/telosb/Makefile.include @@ -1,11 +1,7 @@ -# set default port depending on operating system -PORT_LINUX ?= /dev/ttyUSB0 -PORT_DARWIN ?= $(firstword $(sort $(wildcard /dev/tty.usbserial-MXV*))) -# setup serial terminal -BAUD ?= 9600 - # flash tool configuration PROGRAMMER ?= goodfet GOODFET_FLAGS ?= --telosb PROGRAMMERS_SUPPORTED += goodfet + +include $(RIOTBOARD)/common/msp430/Makefile.include diff --git a/boards/telosb/include/periph_conf.h b/boards/telosb/include/periph_conf.h index 5ee5a858d982..b5d27ee68f33 100644 --- a/boards/telosb/include/periph_conf.h +++ b/boards/telosb/include/periph_conf.h @@ -23,6 +23,7 @@ #include "macros/units.h" #include "periph_cpu.h" +#include "cfg_timer_a_smclk_b_aclk.h" #ifdef __cplusplus extern "C" { @@ -43,17 +44,6 @@ static const msp430_clock_params_t clock_params = { .auxiliary_clock_divier = AUXILIARY_CLOCK_DIVIDE_BY_1, }; -/** - * @name Timer configuration - * @{ - */ -#define TIMER_NUMOF (1U) -#define TIMER_BASE (&TIMER_A) -#define TIMER_CHAN (3) -#define TIMER_ISR_CC0 (TIMERA0_VECTOR) -#define TIMER_ISR_CCX (TIMERA1_VECTOR) -/** @} */ - /** * @name UART configuration * @{ diff --git a/boards/z1/Makefile.include b/boards/z1/Makefile.include index 09ba9d15e1b5..5a5e2aaf0950 100644 --- a/boards/z1/Makefile.include +++ b/boards/z1/Makefile.include @@ -1,9 +1,7 @@ -# set default port depending on operating system -PORT_LINUX ?= /dev/ttyUSB0 -PORT_DARWIN ?= $(firstword $(sort $(wildcard /dev/tty.SLAB_USBtoUART*))) - # setup flash tool PROGRAMMER ?= goodfet GOODFET_FLAGS ?= --z1 PROGRAMMERS_SUPPORTED += goodfet + +include $(RIOTBOARD)/common/msp430/Makefile.include diff --git a/boards/z1/include/periph_conf.h b/boards/z1/include/periph_conf.h index b3c32638f8f5..47230821604f 100644 --- a/boards/z1/include/periph_conf.h +++ b/boards/z1/include/periph_conf.h @@ -23,6 +23,7 @@ #include "macros/units.h" #include "periph_cpu.h" +#include "cfg_timer_a_smclk_b_aclk.h" #ifdef __cplusplus extern "C" { @@ -43,17 +44,6 @@ static const msp430_clock_params_t clock_params = { .auxiliary_clock_divier = AUXILIARY_CLOCK_DIVIDE_BY_1, }; -/** - * @name Timer configuration - * @{ - */ -#define TIMER_NUMOF (1U) -#define TIMER_BASE (&TIMER_A) -#define TIMER_CHAN (3) -#define TIMER_ISR_CC0 (TIMERA0_VECTOR) -#define TIMER_ISR_CCX (TIMERA1_VECTOR) -/** @} */ - /** * @name UART configuration * @{ diff --git a/cpu/msp430/Kconfig b/cpu/msp430/Kconfig index 91f95da20219..c807082d896c 100644 --- a/cpu/msp430/Kconfig +++ b/cpu/msp430/Kconfig @@ -18,6 +18,7 @@ config CPU_ARCH_MSP430 select HAS_PERIPH_FLASHPAGE_IN_ADDRESS_SPACE select HAS_PERIPH_FLASHPAGE_PAGEWISE select HAS_PERIPH_PM + select HAS_PERIPH_TIMER_QUERY_FREQS select MODULE_MALLOC_THREAD_SAFE if TEST_KCONFIG config HAS_CPU_MSP430 diff --git a/cpu/msp430/Makefile.features b/cpu/msp430/Makefile.features index fb3684e65398..6c6c3fe4b4e6 100644 --- a/cpu/msp430/Makefile.features +++ b/cpu/msp430/Makefile.features @@ -18,3 +18,4 @@ FEATURES_PROVIDED += periph_flashpage FEATURES_PROVIDED += periph_flashpage_in_address_space FEATURES_PROVIDED += periph_flashpage_pagewise FEATURES_PROVIDED += periph_pm +FEATURES_PROVIDED += periph_timer_query_freqs diff --git a/cpu/msp430/clock.c b/cpu/msp430/clock.c index eb27cd01ee4d..e9d7f5507001 100644 --- a/cpu/msp430/clock.c +++ b/cpu/msp430/clock.c @@ -348,7 +348,8 @@ void default_clock_init(void) __attribute__((weak, alias("default_clock_init"))) void clock_init(void); -uint32_t msp430_submain_clock_freq(void) { +uint32_t PURE msp430_submain_clock_freq(void) +{ uint16_t shift = (clock_params.submain_clock_divier >> 1) & 0x3; switch (clock_params.submain_clock_source) { case SUBMAIN_CLOCK_SOURCE_LFXT1CLK: @@ -365,7 +366,7 @@ uint32_t msp430_submain_clock_freq(void) { } } -uint32_t msp430_auxiliary_clock_freq(void) +uint32_t PURE msp430_auxiliary_clock_freq(void) { uint16_t shift = (clock_params.auxiliary_clock_divier >> 4) & 0x3; return clock_params.lfxt1_frequency >> shift; diff --git a/cpu/msp430/include/msp430_regs_common.h b/cpu/msp430/include/msp430_regs_common.h index 56d53028f257..9d3abd9e594d 100644 --- a/cpu/msp430/include/msp430_regs_common.h +++ b/cpu/msp430/include/msp430_regs_common.h @@ -57,13 +57,16 @@ extern "C" { * @name Timer Input Divider Values * * @details The vendor header macros are again non-obvious in their naming, so - * provide better alies names. + * provide better alias names. * @{ */ #define TXID_DIV_1 ID_0 /**< Input Divider: Divide by 1 */ #define TXID_DIV_2 ID_1 /**< Input Divider: Divide by 2 */ #define TXID_DIV_4 ID_2 /**< Input Divider: Divide by 4 */ -#define TXID_DIV_8 ID_3 /**< Input Divider: Divide by 4 */ +#define TXID_DIV_8 ID_3 /**< Input Divider: Divide by 8 */ +#define TXID_DIV_Msk ID_3 /**< Mask to get the TXID field */ +#define TXID_DIV_Pos 6U /**< Position of the TXID field */ +#define TXID_DIV_MAX 3 /**< Maximum configuration value in the TXID field */ /** @} */ /** @@ -108,18 +111,11 @@ typedef struct { REG8 SEL; /**< alternative function select */ } msp430_port_p3_p6_t; - -/** - * @brief Timer interrupt status registers - */ -typedef struct { - REG16 TBIV; /**< TIMER_A interrupt status */ - REG16 reserved[7];/**< reserved */ - REG16 TAIV; /**< TIMER_B interrupt status */ -} msp430_timer_ivec_t; - /** - * @brief Timer module registers + * @brief Timer peripheral registers + * + * @note The TIMER_A timer only has 3 CC channels instead of the 8 channels + * the TIMER_B has, the memory layout is the same nonetheless. */ typedef struct { REG16 CTL; /**< timer control */ @@ -161,14 +157,27 @@ extern msp430_port_p3_p6_t PORT_5; extern msp430_port_p3_p6_t PORT_6; /** - * @brief Register map of the timer interrupt control registers + * @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 msp430_timer_ivec_t TIMER_IVEC; +extern REG16 TIMER_A_IRQFLAGS; /** - * @brief Register map of the timer A control registers + * @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 msp430_timer_t TIMER_A; +extern REG16 TIMER_B_IRQFLAGS; /** * @brief Register map of the timer B control registers diff --git a/cpu/msp430/include/periph_cpu_common.h b/cpu/msp430/include/periph_cpu_common.h index 69dbf3628668..8034e0d79dd2 100644 --- a/cpu/msp430/include/periph_cpu_common.h +++ b/cpu/msp430/include/periph_cpu_common.h @@ -22,6 +22,7 @@ #include #include "bitarithm.h" +#include "compiler_hints.h" #include "cpu.h" #include "msp430_regs.h" @@ -52,6 +53,17 @@ typedef uint16_t gpio_t; */ #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 * @{ @@ -289,6 +301,31 @@ typedef struct { 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 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. @@ -321,14 +358,14 @@ void clock_init(void); * * @note This is only useful when implementing MSP430 peripheral drivers */ -uint32_t msp430_submain_clock_freq(void); +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 msp430_auxiliary_clock_freq(void); +uint32_t PURE msp430_auxiliary_clock_freq(void); #ifdef __cplusplus } diff --git a/cpu/msp430/ldscripts/msp430_common.ld b/cpu/msp430/ldscripts/msp430_common.ld index 9fb517ed65c2..e4207a2f1708 100644 --- a/cpu/msp430/ldscripts/msp430_common.ld +++ b/cpu/msp430/ldscripts/msp430_common.ld @@ -24,16 +24,15 @@ SECTIONS /* provide address for register maps by taking the address of the first * register (as provided by the vendor files) */ -PROVIDE(PORT_1 = P1IN); -PROVIDE(PORT_2 = P2IN); -PROVIDE(PORT_3 = P3IN); -PROVIDE(PORT_3 = P3IN); -PROVIDE(PORT_4 = P4IN); -PROVIDE(PORT_5 = P5IN); -PROVIDE(PORT_6 = P6IN); +PROVIDE(PORT_1 = P1IN); +PROVIDE(PORT_2 = P2IN); +PROVIDE(PORT_3 = P3IN); +PROVIDE(PORT_3 = P3IN); +PROVIDE(PORT_4 = P4IN); +PROVIDE(PORT_5 = P5IN); +PROVIDE(PORT_6 = P6IN); -/* no typo: TBIV indeed comes before TAIV in memory, see msp430_timer_ivec_t */ -PROVIDE(TIMER_IVEC = TBIV); - -PROVIDE(TIMER_A = TACTL); -PROVIDE(TIMER_B = TBCTL); +PROVIDE(TIMER_A = TACTL); +PROVIDE(TIMER_B = TBCTL); +PROVIDE(TIMER_A_IRQFLAGS = TAIV); +PROVIDE(TIMER_B_IRQFLAGS = TBIV); diff --git a/cpu/msp430/periph/timer.c b/cpu/msp430/periph/timer.c index 6150a90d7585..0f0015acdedf 100644 --- a/cpu/msp430/periph/timer.c +++ b/cpu/msp430/periph/timer.c @@ -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 @@ -21,107 +22,248 @@ * through the board's `periph_conf.h` * * @author Hauke Petersen + * @author Marian Buschsieweke * * @} */ +#include "compiler_hints.h" #include "cpu.h" -#include "periph_cpu.h" -#include "periph_conf.h" #include "periph/timer.h" +#include "periph_conf.h" +#include "periph_cpu.h" /** - * @brief Save reference to the timer callback + * @brief Interrupt context for each configured timer */ -static timer_cb_t isr_cb; +static timer_isr_ctx_t isr_ctx[TIMER_NUMOF]; -/** - * @brief Save argument for the ISR callback - */ -static void *isr_arg; +/* Hack to count the number of ISR vectors provided by the board */ +enum { +#ifdef TIMER0_ISR_CC0 + TIMER_ISR_COUNT_HELPER_0, +#endif +#ifdef TIMER1_ISR_CC0 + TIMER_ISR_COUNT_HELPER_1, +#endif + TIMER_ISR_NUMOF +}; -int timer_init(tim_t dev, uint32_t freq, timer_cb_t cb, void *arg) +static_assert((TXID_DIV_MAX << TXID_DIV_Pos) == TXID_DIV_Msk, "TXID_DIV_MAX or TXID_DIV_Pos is incorrect."); +static_assert(TIMER_ISR_NUMOF == TIMER_NUMOF, + "For each provided timer a corresponding IRQ number needs to be provided by the board."); + +static uint32_t abs_diff(uint32_t a, uint32_t b) { - /* using fixed TIMER_BASE for now */ - if (dev != 0) { - return -1; + if (a >= b) { + return a - b; } - /* TODO: configure time-base depending on freq value */ - if (freq != 1000000ul) { - return -1; + + return b - a; +} + +static uint16_t prescale(msp430_timer_clock_source_t clock_source, uint32_t freq) +{ + uint32_t clock_freq; + assume((clock_source == TIMER_CLOCK_SOURCE_AUXILIARY_CLOCK) || + (clock_source == TIMER_CLOCK_SOURCE_SUBMAIN_CLOCK)); + switch (clock_source) { + default: + case TIMER_CLOCK_SOURCE_AUXILIARY_CLOCK: + clock_freq = msp430_auxiliary_clock_freq(); + break; + case TIMER_CLOCK_SOURCE_SUBMAIN_CLOCK: + clock_freq = msp430_submain_clock_freq(); + break; + } + + unsigned prescaler = 0; + uint32_t best_diff = UINT32_MAX; + + for (unsigned i = 0; i <= TXID_DIV_MAX; i++) { + uint32_t prescaled_freq = clock_freq >> i; + uint32_t off = abs_diff(freq, prescaled_freq); + if (off < best_diff) { + best_diff = off; + prescaler = i; + } } + return clock_source | (prescaler << TXID_DIV_Pos); +} + +int timer_init(tim_t dev, uint32_t freq, timer_cb_t cb, void *arg) +{ + assume((unsigned)dev < TIMER_NUMOF); + msp430_timer_t *msptimer = timer_conf[dev].timer; + /* reset the timer A configuration */ - TIMER_BASE->CTL = TACLR; + msptimer->CTL = TACLR; /* save callback */ - isr_cb = cb; - isr_arg = arg; - /* configure timer to use the SMCLK with prescaler of 8 */ - TIMER_BASE->CTL = (TXSSEL_SMCLK | TXID_DIV_8); + isr_ctx[dev].cb = cb; + isr_ctx[dev].arg = arg; + /* compute prescaler */ + uint16_t ctl = prescale(timer_conf[dev].clock_source, freq); + msptimer->CTL = ctl; /* configure CC channels */ - for (int i = 0; i < TIMER_CHAN; i++) { - TIMER_BASE->CCTL[i] = 0; + for (unsigned i = 0; i < timer_query_channel_numof(dev); i++) { + msptimer->CCTL[i] = 0; } /* start the timer in continuous mode */ - TIMER_BASE->CTL |= TXMC_CONT; + msptimer->CTL = ctl | TXMC_CONT; return 0; } int timer_set_absolute(tim_t dev, int channel, unsigned int value) { - if (dev != 0 || channel >= TIMER_CHAN) { + assume((unsigned)dev < TIMER_NUMOF); + msp430_timer_t *msptimer = timer_conf[dev].timer; + + if ((unsigned)channel >= timer_query_channel_numof(dev)) { return -1; } - TIMER_BASE->CCR[channel] = value; - TIMER_BASE->CCTL[channel] &= ~(CCIFG); - TIMER_BASE->CCTL[channel] |= CCIE; + + msptimer->CCR[channel] = value; + msptimer->CCTL[channel] &= ~(CCIFG); + msptimer->CCTL[channel] |= CCIE; return 0; } int timer_clear(tim_t dev, int channel) { - if (dev != 0 || channel >= TIMER_CHAN) { + assume((unsigned)dev < TIMER_NUMOF); + msp430_timer_t *msptimer = timer_conf[dev].timer; + + if ((unsigned)channel >= timer_query_channel_numof(dev)) { return -1; } - TIMER_BASE->CCTL[channel] &= ~(CCIE); + msptimer->CCTL[channel] &= ~(CCIE); return 0; } unsigned int timer_read(tim_t dev) { - (void)dev; - return (unsigned int)TIMER_BASE->R; + assume((unsigned)dev < TIMER_NUMOF); + msp430_timer_t *msptimer = timer_conf[dev].timer; + return msptimer->R; } void timer_start(tim_t dev) { - (void)dev; - TIMER_BASE->CTL |= TXMC_CONT; + assume((unsigned)dev < TIMER_NUMOF); + msp430_timer_t *msptimer = timer_conf[dev].timer; + msptimer->CTL |= TXMC_CONT; } void timer_stop(tim_t dev) { - (void)dev; - TIMER_BASE->CTL &= ~(TXMC_MASK); + assume((unsigned)dev < TIMER_NUMOF); + msp430_timer_t *msptimer = timer_conf[dev].timer; + msptimer->CTL &= ~(TXMC_MASK); +} + +__attribute__((pure)) +uword_t timer_query_freqs_numof(tim_t dev) +{ + assume((unsigned)dev < TIMER_NUMOF); + /* Smallest div value is 0, so number is max + 1 */ + return TXID_DIV_MAX + 1; +} + +__attribute__((pure)) +uword_t timer_query_channel_numof(tim_t dev) +{ + assume((unsigned)dev < TIMER_NUMOF); + if (timer_conf[dev].timer == &TIMER_A) { + return 3; + } + + return 7; +} + +uint32_t timer_query_freqs(tim_t dev, uword_t index) +{ + assume((unsigned)dev < TIMER_NUMOF); + const msp430_timer_clock_source_t clock_source = timer_conf[dev].clock_source; + assume((clock_source == TIMER_CLOCK_SOURCE_AUXILIARY_CLOCK) || + (clock_source == TIMER_CLOCK_SOURCE_SUBMAIN_CLOCK)); + + uint32_t clock_freq; + switch (clock_source) { + default: + case TIMER_CLOCK_SOURCE_AUXILIARY_CLOCK: + clock_freq = msp430_auxiliary_clock_freq(); + break; + case TIMER_CLOCK_SOURCE_SUBMAIN_CLOCK: + clock_freq = msp430_submain_clock_freq(); + break; + } + + return clock_freq >> index; +} + +static void timer_isr(tim_t dev, unsigned chan) +{ + assume((unsigned)dev < TIMER_NUMOF); + msp430_timer_t *msptimer = timer_conf[dev].timer; + /* disable IRQ */ + msptimer->CCTL[chan] &= ~(CCIE); + isr_ctx[dev].cb(isr_ctx[dev].arg, chan); + +} +static void timer_isr_cc0(tim_t dev) +{ + assume((unsigned)dev < TIMER_NUMOF); + timer_isr(dev, 0); +} + +static void timer_isr_ccx(tim_t dev) +{ + assume((unsigned)dev < TIMER_NUMOF); + unsigned chan = *timer_conf[dev].irq_flags >> 1U; + if (chan >= timer_query_channel_numof(dev)) { + /* timer overflown */ + } + else { + /* CC matched */ + timer_isr(dev, chan); + } +} + +ISR(TIMER0_ISR_CC0, isr_timer0_cc0) +{ + __enter_isr(); + + timer_isr_cc0(0); + + __exit_isr(); +} + +ISR(TIMER0_ISR_CCX, isr_timer0_ccx) +{ + __enter_isr(); + + timer_isr_ccx(0); + + __exit_isr(); } -ISR(TIMER_ISR_CC0, isr_timer_a_cc0) +#ifdef TIMER1_ISR_CC0 +ISR(TIMER1_ISR_CC0, isr_timer1_cc0) { __enter_isr(); - TIMER_BASE->CCTL[0] &= ~(CCIE); - isr_cb(isr_arg, 0); + timer_isr_cc0(1); __exit_isr(); } -ISR(TIMER_ISR_CCX, isr_timer_a_ccx) +ISR(TIMER1_ISR_CCX, isr_timer1_ccx) { __enter_isr(); - int chan = (int)(TIMER_IVEC.TAIV >> 1); - TIMER_BASE->CCTL[chan] &= ~(CCIE); - isr_cb(isr_arg, chan); + timer_isr_ccx(1); __exit_isr(); } +#endif diff --git a/examples/gnrc_minimal/Makefile.ci b/examples/gnrc_minimal/Makefile.ci index a6233fa0dfa7..1bc33cf78f8d 100644 --- a/examples/gnrc_minimal/Makefile.ci +++ b/examples/gnrc_minimal/Makefile.ci @@ -10,4 +10,5 @@ BOARD_INSUFFICIENT_MEMORY := \ nucleo-l011k4 \ samd10-xmini \ stm32f030f4-demo \ + telosb \ # diff --git a/tests/net/gnrc_netif_ipv6_wait_for_global_address/Makefile.ci b/tests/net/gnrc_netif_ipv6_wait_for_global_address/Makefile.ci index b2b69bc42bbd..99e4a29d44c8 100644 --- a/tests/net/gnrc_netif_ipv6_wait_for_global_address/Makefile.ci +++ b/tests/net/gnrc_netif_ipv6_wait_for_global_address/Makefile.ci @@ -26,5 +26,6 @@ BOARD_INSUFFICIENT_MEMORY := \ stm32f0discovery \ stm32g0316-disco \ stm32l0538-disco \ + telosb \ waspmote-pro \ # diff --git a/tests/net/gnrc_sock_udp/Makefile.ci b/tests/net/gnrc_sock_udp/Makefile.ci index f8384639143b..eb01c2674c11 100644 --- a/tests/net/gnrc_sock_udp/Makefile.ci +++ b/tests/net/gnrc_sock_udp/Makefile.ci @@ -19,4 +19,5 @@ BOARD_INSUFFICIENT_MEMORY := \ stm32g0316-disco \ telosb \ waspmote-pro \ + z1 \ #