From 1b364a1e52c358040b6c2e0cd69312148eb53547 Mon Sep 17 00:00:00 2001 From: Vincenzo Frascino Date: Wed, 20 Jul 2016 10:13:15 +0100 Subject: [PATCH] [BEETLE] Fix Lp_Ticker read MBED OS requires an lp_ticker_read function that returns a 32bit value in microseconds. This can not be represented directly on the Beetle Dual Timer Load register. max_us_on_reg = (0xFFFFFFFF ticks)/DIVIDER_US This patch introduces an intermediate layer that counts the timer wraps around and returns the correct value of us to the MBED library. Signed-off-by: Vincenzo Frascino --- .../TARGET_BEETLE/apb_dualtimer.c | 41 +++++++++++++++++-- .../TARGET_BEETLE/apb_dualtimer.h | 12 ++++++ .../TARGET_ARM_SSG/TARGET_BEETLE/lp_ticker.c | 30 ++++++++++++-- 3 files changed, 75 insertions(+), 8 deletions(-) diff --git a/hal/targets/cmsis/TARGET_ARM_SSG/TARGET_BEETLE/apb_dualtimer.c b/hal/targets/cmsis/TARGET_ARM_SSG/TARGET_BEETLE/apb_dualtimer.c index ea6ec17dbc..930344008d 100644 --- a/hal/targets/cmsis/TARGET_ARM_SSG/TARGET_BEETLE/apb_dualtimer.c +++ b/hal/targets/cmsis/TARGET_ARM_SSG/TARGET_BEETLE/apb_dualtimer.c @@ -228,6 +228,7 @@ void DualTimer_SetInterrupt_1(uint32_t timer, uint32_t time_us, timerenable_t mode) { uint32_t dualtimerControl = 0; + uint32_t load_time_us = 0; /* Verify if the Timer is enabled */ if (DualTimer_isEnabled(timer) == 1) { /* Disable Timer */ @@ -237,9 +238,15 @@ void DualTimer_SetInterrupt_1(uint32_t timer, uint32_t time_us, (DualTimers[timer].dualtimer1)->TimerControl = CMSDK_DUALTIMER_CTRL_INTEN_Msk | dualtimerControl; + + /* Check time us condition */ + if(time_us == DUALTIMER_DEFAULT_RELOAD) + load_time_us = DUALTIMER_MAX_VALUE; + else + load_time_us = time_us * DUALTIMER_TICKS_US; + /* Reload Value */ - DualTimers[timer].dualtimer1Reload = (time_us) - * DUALTIMER_TICKS_US; + DualTimers[timer].dualtimer1Reload = load_time_us; (DualTimers[timer].dualtimer1)->TimerLoad = DualTimers[timer].dualtimer1Reload; /* Enable Counter */ @@ -260,6 +267,7 @@ void DualTimer_SetInterrupt_2(uint32_t timer, uint32_t time_us, timerenable_t mode) { uint32_t dualtimerControl = 0; + uint32_t load_time_us = 0; /* Verify if the Timer is enabled */ if (DualTimer_isEnabled(timer) == 1) { /* Disable Timer */ @@ -269,9 +277,15 @@ void DualTimer_SetInterrupt_2(uint32_t timer, uint32_t time_us, (DualTimers[timer].dualtimer2)->TimerControl = CMSDK_DUALTIMER_CTRL_INTEN_Msk | dualtimerControl; + + /* Check time us condition */ + if(time_us == DUALTIMER_DEFAULT_RELOAD) + load_time_us = DUALTIMER_MAX_VALUE; + else + load_time_us = time_us * DUALTIMER_TICKS_US; + /* Reload Value */ - DualTimers[timer].dualtimer2Reload = (time_us) - * DUALTIMER_TICKS_US; + DualTimers[timer].dualtimer2Reload = load_time_us; (DualTimers[timer].dualtimer2)->TimerLoad = DualTimers[timer].dualtimer2Reload; /* Enable Counter */ @@ -358,3 +372,22 @@ uint32_t DualTimer_GetTicksUS(uint32_t timer) } return 0; } + +/* + * DualTimer_GetReloadValue(): returns the load value of the selected + * singletimer. + * timer: timer associated with the Ticks per us + * singletimer: selected singletimer + * @return: reload value of the selected singletimer - 0 if timer is disabled + */ +uint32_t DualTimer_GetReloadValue(uint32_t timer, uint32_t singletimer) +{ + /* Verify if the Timer is enabled */ + if (DualTimer_isEnabled(timer) == 1) { + if (singletimer == SINGLETIMER1) + return DualTimers[timer].dualtimer1Reload / DUALTIMER_TICKS_US; + else + return DualTimers[timer].dualtimer2Reload / DUALTIMER_TICKS_US; + } + return 0; +} diff --git a/hal/targets/cmsis/TARGET_ARM_SSG/TARGET_BEETLE/apb_dualtimer.h b/hal/targets/cmsis/TARGET_ARM_SSG/TARGET_BEETLE/apb_dualtimer.h index 85c4f02685..bf9caa3232 100644 --- a/hal/targets/cmsis/TARGET_ARM_SSG/TARGET_BEETLE/apb_dualtimer.h +++ b/hal/targets/cmsis/TARGET_ARM_SSG/TARGET_BEETLE/apb_dualtimer.h @@ -50,6 +50,9 @@ typedef uint8_t timerenable_t; #define DUALTIMER_ONESHOT_MASK (3) #define DUALTIMER_ONESHOT (1 << DUALTIMER_ONESHOT_MASK) +/* Default reload */ +#define DUALTIMER_DEFAULT_RELOAD 0xFFFFFFFF + /* * DualTimer_Enable(): Enables a hardware timer * timer: timer to be enabled @@ -136,6 +139,15 @@ uint32_t DualTimer_GetIRQInfo(uint32_t dualtimer); */ uint32_t DualTimer_GetTicksUS(uint32_t timer); +/* + * DualTimer_GetReloadValue(): returns the load value of the selected + * singletimer. + * timer: timer associated with the Ticks per us + * singletimer: selected singletimer + * @return: reload value of the selected singletimer + */ +uint32_t DualTimer_GetReloadValue(uint32_t timer, uint32_t singletimer); + #ifdef __cplusplus } #endif diff --git a/hal/targets/hal/TARGET_ARM_SSG/TARGET_BEETLE/lp_ticker.c b/hal/targets/hal/TARGET_ARM_SSG/TARGET_BEETLE/lp_ticker.c index c5bdf7316c..e2b5b224fa 100644 --- a/hal/targets/hal/TARGET_ARM_SSG/TARGET_BEETLE/lp_ticker.c +++ b/hal/targets/hal/TARGET_ARM_SSG/TARGET_BEETLE/lp_ticker.c @@ -25,8 +25,10 @@ static uint32_t lp_ticker_initialized = 0; /* lp_ticker reload value */ static uint32_t lp_ticker_reload = 0x0; /* Max Value */ -/* Store Overflow Count */ -static uint32_t lp_ticker_overflows_count = 0; +/* Store Overflow Delta */ +static uint32_t lp_ticker_overflows_delta = 0; +/* lp_ticker Overflow limit */ +static uint32_t lp_ticker_overflow_limit = 0; #if DEVICE_LOWPOWERTIMER /** @@ -36,7 +38,13 @@ void __lp_ticker_irq_handler(void) { if (DualTimer_GetIRQInfo(DUALTIMER0) == SINGLETIMER2) { DualTimer_ClearInterrupt(DUALTIMER0); - lp_ticker_overflows_count++; + /* + * For each overflow event adds the timer max represented value to + * the delta. This allows the lp_ticker to keep track of the elapsed + * time: + * elapsed_time = (num_overflow * overflow_limit) + current_time + */ + lp_ticker_overflows_delta += lp_ticker_overflow_limit; } else { lp_ticker_irq_handler(); } @@ -67,6 +75,20 @@ void lp_ticker_init(void) NVIC_SetVector((IRQn_Type)lp_ticker_irqn, (uint32_t)__lp_ticker_irq_handler); NVIC_EnableIRQ((IRQn_Type)lp_ticker_irqn); + + /* DualTimer set interrupt on SINGLETIMER2 */ + DualTimer_SetInterrupt_2(DUALTIMER0, DUALTIMER_DEFAULT_RELOAD, + DUALTIMER_COUNT_32 | DUALTIMER_PERIODIC); + + /* + * Set lp_ticker Overflow limit. The lp_ticker overflow limit is required + * to calculated the return value of the lp_ticker read function in us + * on 32bit. + * A 32bit us value cannot be represented directly in the Dual Timer Load + * register if it is greater than (0xFFFFFFFF ticks)/DUALTIMER_DIVIDER_US. + */ + lp_ticker_overflow_limit = DualTimer_GetReloadValue(DUALTIMER0, + SINGLETIMER2); } /** @@ -82,7 +104,7 @@ uint32_t lp_ticker_read(void) lp_ticker_init(); /* Read Timer Value */ - microseconds = DualTimer_Read_2(DUALTIMER0); + microseconds = lp_ticker_overflows_delta + DualTimer_Read_2(DUALTIMER0); return microseconds; }