From 25ac0db6064d56d81cf82f643b848d991d9eebdf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Roussel?= Date: Mon, 28 Apr 2014 14:28:34 +0200 Subject: [PATCH 1/2] Robust use of TimerA for 'hwtimer' module --- cpu/cc430/hwtimer_cc430.c | 2 + cpu/msp430-common/hwtimer_cpu.c | 87 +++++++++++++++++++++---- cpu/msp430-common/include/hwtimer_cpu.h | 44 ++++++++++--- cpu/msp430fxyz/hwtimer_msp430.c | 45 ++++++++----- 4 files changed, 138 insertions(+), 40 deletions(-) diff --git a/cpu/cc430/hwtimer_cc430.c b/cpu/cc430/hwtimer_cc430.c index 3423aaee0b..02e8dd26d1 100644 --- a/cpu/cc430/hwtimer_cc430.c +++ b/cpu/cc430/hwtimer_cc430.c @@ -32,6 +32,8 @@ extern void (*int_handler)(int); extern void timer_unset(short timer); +msp430_timer_t msp430_timer[HWTIMER_MAXTIMERS]; + void timerA_init(void) { volatile unsigned int *ccr = &TA0CCR0; diff --git a/cpu/msp430-common/hwtimer_cpu.c b/cpu/msp430-common/hwtimer_cpu.c index 195ba1eee3..06f4f5cf71 100644 --- a/cpu/msp430-common/hwtimer_cpu.c +++ b/cpu/msp430-common/hwtimer_cpu.c @@ -1,14 +1,30 @@ /* - * Copyright (C) 2013, Freie Universitaet Berlin (FUB). All rights reserved. + * Copyright (C) 2014 Freie Universitaet Berlin (FUB) and INRIA. All rights reserved. * * 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 + * @{ + */ + +/** + * @file + * @brief msp430 hardware timer driver generic functions + * + * @author Freie Universitaet Berlin, Computer Systems and Telematics group + * @author Oliver Hahm + * @author Kévin Roussel + * + */ + #include #include "cpu.h" +#include "crash.h" #include "hwtimer.h" #include "arch/hwtimer_arch.h" @@ -19,36 +35,83 @@ void (*int_handler)(int); extern void timerA_init(void); +extern volatile msp430_timer_t msp430_timer[HWTIMER_MAXTIMERS]; + +/* + * the 3 following functions handle the diversity of timers + * we can encounter in the various MCUs in the MSP430 family + */ + +static volatile unsigned int *get_control_reg_for_msp430_timer(int index) +{ + volatile unsigned int *ptr = NULL; +#ifndef CC430 + switch (msp430_timer[index].base_timer) { + case TIMER_A: + ptr = &TACCTL0; + break; + case TIMER_B: + ptr = &TBCCTL0; + break; + default: + core_panic(0x0, "Wrong timer kind for MSP430"); + } +#else + ptr = &TA0CCTL0; +#endif + ptr += msp430_timer[index].ccr_num; + return ptr; +} + +static volatile unsigned int *get_comparator_reg_for_msp430_timer(int index) +{ + volatile unsigned int *ptr = NULL; +#ifndef CC430 + switch (msp430_timer[index].base_timer) { + case TIMER_A: + ptr = &TACCR0; + break; + case TIMER_B: + ptr = &TBCCR0; + break; + default: + core_panic(0x0, "Wrong timer kind for MSP430"); + } +#else + ptr = &TA0CCR0; +#endif + ptr += msp430_timer[index].ccr_num; + return ptr; +} + #ifdef CC430 /* CC430 have "TimerA0", "TimerA1" and so on... */ - #define CNT_CTRL_BASE_REG (TA0CCTL0) - #define CNT_COMP_BASE_REG (TA0CCR0) - #define TIMER_VAL_REG (TA0R) + #define TIMER_VAL_REG (TA0R) #else /* ... while other MSP430 MCUs have "TimerA", "TimerB". - Cheers for TI and its consistency! */ - #define CNT_CTRL_BASE_REG (TACCTL0) - #define CNT_COMP_BASE_REG (TACCR0) - #define TIMER_VAL_REG (TAR) + Cheers for TI and its consistency! */ + #define TIMER_VAL_REG (TAR) #endif +/* hardware-dependent functions */ + static void timer_disable_interrupt(short timer) { - volatile unsigned int *ptr = &CNT_CTRL_BASE_REG + (timer); + volatile unsigned int *ptr = get_control_reg_for_msp430_timer(timer); *ptr &= ~(CCIFG); *ptr &= ~(CCIE); } static void timer_enable_interrupt(short timer) { - volatile unsigned int *ptr = &CNT_CTRL_BASE_REG + (timer); + volatile unsigned int *ptr = get_control_reg_for_msp430_timer(timer); *ptr |= CCIE; *ptr &= ~(CCIFG); } static void timer_set_nostart(uint32_t value, short timer) { - volatile unsigned int *ptr = &CNT_COMP_BASE_REG + (timer); + volatile unsigned int *ptr = get_comparator_reg_for_msp430_timer(timer); /* ensure we won't set the timer to a "past" tick */ if (value <= hwtimer_arch_now()) { value = hwtimer_arch_now() + 2; @@ -65,7 +128,7 @@ static void timer_set(uint32_t value, short timer) void timer_unset(short timer) { - volatile unsigned int *ptr = &CNT_COMP_BASE_REG + (timer); + volatile unsigned int *ptr = get_comparator_reg_for_msp430_timer(timer); timer_disable_interrupt(timer); *ptr = 0; } diff --git a/cpu/msp430-common/include/hwtimer_cpu.h b/cpu/msp430-common/include/hwtimer_cpu.h index 0bcd9b9490..afefc05b2c 100644 --- a/cpu/msp430-common/include/hwtimer_cpu.h +++ b/cpu/msp430-common/include/hwtimer_cpu.h @@ -1,11 +1,26 @@ /* - * Copyright (C) 2013, Freie Universitaet Berlin (FUB). All rights reserved. + * Copyright (C) 2014 Freie Universitaet Berlin (FUB) and INRIA. All rights reserved. * * 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 + * @{ + */ + +/** + * @file + * @brief msp430 hardware timer driver definitions + * + * @author Freie Universitaet Berlin, Computer Systems and Telematics group + * @author Oliver Hahm + * @author Kévin Roussel + * + */ + #ifndef __HWTIMER_CPU_H #define __HWTIMER_CPU_H @@ -17,22 +32,31 @@ extern "C" { #endif -#ifdef __MSP430_HAS_TA2__ -#define HWTIMER_MAXTIMERS 2 -#endif -#ifdef __MSP430_HAS_TA3__ -#define HWTIMER_MAXTIMERS 3 -#endif -#ifdef __MSP430_HAS_T0A5__ -#define HWTIMER_MAXTIMERS 5 +#if defined (__MSP430_HAS_TA2__) +#define TIMER_A_MAXCOMP 2 +#elif defined (__MSP430_HAS_TA3__) +#define TIMER_A_MAXCOMP 3 +#elif defined (__MSP430_HAS_T0A5__) +#define TIMER_A_MAXCOMP 5 +#else +#define TIMER_A_MAXCOMP 0 #endif +#define HWTIMER_MAXTIMERS (TIMER_A_MAXCOMP) #ifndef HWTIMER_MAXTIMERS #warning "HWTIMER_MAXTIMERS UNSET!" -#define HWTIMER_MAXTIMERS 0 +#define HWTIMER_MAXTIMERS 0 #endif +typedef struct { + enum { + TIMER_A, + TIMER_B, + } base_timer; + uint8_t ccr_num; +} msp430_timer_t; + #define HWTIMER_SPEED (F_RC_OSCILLATOR) #define HWTIMER_MAXTICKS (0x0000FFFF) diff --git a/cpu/msp430fxyz/hwtimer_msp430.c b/cpu/msp430fxyz/hwtimer_msp430.c index 5d17c1f0eb..954c3940c1 100644 --- a/cpu/msp430fxyz/hwtimer_msp430.c +++ b/cpu/msp430fxyz/hwtimer_msp430.c @@ -24,46 +24,55 @@ #include "hwtimer.h" #include "arch/hwtimer_arch.h" -#define ENABLE_DEBUG (0) +#define ENABLE_DEBUG (1) #include "debug.h" extern void (*int_handler)(int); extern void timer_unset(short timer); +msp430_timer_t msp430_timer[HWTIMER_MAXTIMERS]; + +#define CCRA_NUM_TO_INDEX(ccr) (ccr) + void timerA_init(void) { - TACTL = TASSEL_1 + TACLR; /* Clear the timer counter, set ACLK */ - TACTL &= ~TAIFG; /* Clear the IFG */ - TACTL &= ~TAIE; /* Disable TAIE (overflow IRQ) */ + TACTL &= ~(TAIFG); /* Clear the IFG */ + TACTL &= ~(TAIE); /* Disable TAIE (overflow IRQ) */ - for (int i = 0; i < HWTIMER_MAXTIMERS; i++) { + for (uint8_t i = 0; i < TIMER_A_MAXCOMP; i++) { volatile unsigned int *ccr = &TACCR0 + (i); volatile unsigned int *ctl = &TACCTL0 + (i); *ccr = 0; *ctl &= ~(CCIFG); *ctl &= ~(CCIE); + + /* intialize the corresponding msp430_timer struct */ + short index = CCRA_NUM_TO_INDEX(i); + msp430_timer[index].base_timer = TIMER_A; + msp430_timer[index].ccr_num = i; } TACTL |= MC_2; } -interrupt(TIMERA0_VECTOR) __attribute__((naked)) timer_isr_ccr0(void) +interrupt(TIMERA0_VECTOR) __attribute__((naked)) timerA_isr_ccr0(void) { __enter_isr(); - timer_unset(0); - int_handler(0); - - __exit_isr(); -} - -interrupt(TIMERA1_VECTOR) __attribute__((naked)) timer_isr(void) -{ - __enter_isr(); - - /* determine which CCR has been hit, and fire the appropriate callback */ - short timer = TAIV >> 1; + short timer = CCRA_NUM_TO_INDEX(0); + timer_unset(timer); + int_handler(timer); + + __exit_isr(); +} + +interrupt(TIMERA1_VECTOR) __attribute__((naked)) timerA_isr(void) +{ + __enter_isr(); + + /* determine which CCR has been hit, and fire the appropriate callback */ + short timer = CCRA_NUM_TO_INDEX(TAIV >> 1); timer_unset(timer); int_handler(timer); From f9b0df7e4b65ec54d2b978026660ca979022747a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Roussel?= Date: Mon, 28 Apr 2014 14:55:38 +0200 Subject: [PATCH 2/2] Use TimerB for 'hwtimer' module implementation --- cpu/msp430-common/hwtimer_cpu.c | 8 +++- cpu/msp430-common/include/hwtimer_cpu.h | 10 ++++- cpu/msp430fxyz/hwtimer_msp430.c | 49 ++++++++++++++++++++++++- 3 files changed, 64 insertions(+), 3 deletions(-) diff --git a/cpu/msp430-common/hwtimer_cpu.c b/cpu/msp430-common/hwtimer_cpu.c index 06f4f5cf71..511d341810 100644 --- a/cpu/msp430-common/hwtimer_cpu.c +++ b/cpu/msp430-common/hwtimer_cpu.c @@ -34,6 +34,9 @@ void (*int_handler)(int); extern void timerA_init(void); +#ifndef CC430 +extern void timerB_init(void); +#endif extern volatile msp430_timer_t msp430_timer[HWTIMER_MAXTIMERS]; @@ -90,7 +93,7 @@ static volatile unsigned int *get_comparator_reg_for_msp430_timer(int index) #else /* ... while other MSP430 MCUs have "TimerA", "TimerB". Cheers for TI and its consistency! */ - #define TIMER_VAL_REG (TAR) + #define TIMER_VAL_REG (TBR) #endif /* hardware-dependent functions */ @@ -141,6 +144,9 @@ unsigned long hwtimer_arch_now(void) void hwtimer_arch_init(void (*handler)(int), uint32_t fcpu) { (void) fcpu; +#ifndef CC430 + timerB_init(); +#endif timerA_init(); int_handler = handler; } diff --git a/cpu/msp430-common/include/hwtimer_cpu.h b/cpu/msp430-common/include/hwtimer_cpu.h index afefc05b2c..167471c7f5 100644 --- a/cpu/msp430-common/include/hwtimer_cpu.h +++ b/cpu/msp430-common/include/hwtimer_cpu.h @@ -42,7 +42,15 @@ extern "C" { #define TIMER_A_MAXCOMP 0 #endif -#define HWTIMER_MAXTIMERS (TIMER_A_MAXCOMP) +#if defined (__MSP430_HAS_TB3__) +#define TIMER_B_MAXCOMP 3 +#elif defined (__MSP430_HAS_TB7__) +#define TIMER_B_MAXCOMP 7 +#else +#define TIMER_B_MAXCOMP 0 +#endif + +#define HWTIMER_MAXTIMERS (TIMER_A_MAXCOMP + TIMER_B_MAXCOMP) #ifndef HWTIMER_MAXTIMERS #warning "HWTIMER_MAXTIMERS UNSET!" diff --git a/cpu/msp430fxyz/hwtimer_msp430.c b/cpu/msp430fxyz/hwtimer_msp430.c index 954c3940c1..ad4d3f78fd 100644 --- a/cpu/msp430fxyz/hwtimer_msp430.c +++ b/cpu/msp430fxyz/hwtimer_msp430.c @@ -24,7 +24,7 @@ #include "hwtimer.h" #include "arch/hwtimer_arch.h" -#define ENABLE_DEBUG (1) +#define ENABLE_DEBUG (0) #include "debug.h" extern void (*int_handler)(int); @@ -33,6 +33,7 @@ extern void timer_unset(short timer); msp430_timer_t msp430_timer[HWTIMER_MAXTIMERS]; #define CCRA_NUM_TO_INDEX(ccr) (ccr) +#define CCRB_NUM_TO_INDEX(ccr) ((ccr) + TIMER_A_MAXCOMP) void timerA_init(void) { @@ -56,6 +57,29 @@ void timerA_init(void) TACTL |= MC_2; } +void timerB_init(void) +{ + + TBCTL = TBSSEL_1 + TBCLR; /* Clear the timer counter, set ACLK */ + TBCTL &= ~(TBIFG); /* Clear the IFG */ + TBCTL &= ~(TBIE); /* Disable TBIE (overflow IRQ) */ + + for (uint8_t i = 0; i < TIMER_B_MAXCOMP; i++) { + volatile unsigned int *ccr = &TBCCR0 + (i); + volatile unsigned int *ctl = &TBCCTL0 + (i); + *ccr = 0; + *ctl &= ~(CCIFG); + *ctl &= ~(CCIE); + + /* intialize the corresponding msp430_timer struct */ + short index = CCRB_NUM_TO_INDEX(i); + msp430_timer[index].base_timer = TIMER_B; + msp430_timer[index].ccr_num = i; + } + + TBCTL |= MC_2; +} + interrupt(TIMERA0_VECTOR) __attribute__((naked)) timerA_isr_ccr0(void) { __enter_isr(); @@ -78,3 +102,26 @@ interrupt(TIMERA1_VECTOR) __attribute__((naked)) timerA_isr(void) __exit_isr(); } + +interrupt(TIMERB0_VECTOR) __attribute__((naked)) timerB_isr_ccr0(void) +{ + __enter_isr(); + + short timer = CCRB_NUM_TO_INDEX(0); + timer_unset(timer); + int_handler(timer); + + __exit_isr(); +} + +interrupt(TIMERB1_VECTOR) __attribute__((naked)) timerB_isr(void) +{ + __enter_isr(); + + /* determine which CCR has been hit, and fire the appropriate callback */ + short timer = CCRB_NUM_TO_INDEX(TBIV >> 1); + timer_unset(timer); + int_handler(timer); + + __exit_isr(); +}