From efa1045fa6fe6e03b218ea9ae186b8b5826dbbad Mon Sep 17 00:00:00 2001 From: Laurent MEUNIER Date: Wed, 31 May 2017 09:19:01 +0200 Subject: [PATCH] STM32: 16 bits ticker, fixes in set function and handler This commit simplifies ticker interrupt set function and handler. There were issues around the 16 bits timer wrap-around timing as we were aligning interrupts with wrap-around limits (0xFFFF) and then reading TIM_MST->CNT again in timer_update_irq_handler which could lead to crossing case with the wrap-around (TIM_FLAG_UPDATE) case. Now we're using the 16 lower bits of the timestamp as the reference from using in set_compare and never changing it. There is also no need to set comparator again in timer_update_irq_handler. This is more robust and also more efficient. --- targets/TARGET_STM/hal_tick_16b.c | 24 ++++++++++++------------ targets/TARGET_STM/us_ticker_16b.c | 28 +++++++++++++++------------- 2 files changed, 27 insertions(+), 25 deletions(-) diff --git a/targets/TARGET_STM/hal_tick_16b.c b/targets/TARGET_STM/hal_tick_16b.c index be93748ce5..be81c24a3e 100644 --- a/targets/TARGET_STM/hal_tick_16b.c +++ b/targets/TARGET_STM/hal_tick_16b.c @@ -24,20 +24,19 @@ extern TIM_HandleTypeDef TimMasterHandle; extern volatile uint32_t SlaveCounter; extern volatile uint32_t oc_int_part; -extern volatile uint16_t oc_rem_part; volatile uint32_t PreviousVal = 0; void us_ticker_irq_handler(void); void set_compare(uint16_t count); + #if defined(TARGET_STM32F0) void timer_update_irq_handler(void) { #else void timer_irq_handler(void) { #endif - uint16_t cnt_val = TIM_MST->CNT; TimMasterHandle.Instance = TIM_MST; // Clear Update interrupt flag @@ -53,7 +52,6 @@ void timer_irq_handler(void) // Used for mbed timeout (channel 1) and HAL tick (channel 2) void timer_oc_irq_handler(void) { - uint16_t cnt_val = TIM_MST->CNT; TimMasterHandle.Instance = TIM_MST; #endif @@ -61,23 +59,18 @@ void timer_oc_irq_handler(void) if (__HAL_TIM_GET_FLAG(&TimMasterHandle, TIM_FLAG_CC1) == SET) { if (__HAL_TIM_GET_IT_SOURCE(&TimMasterHandle, TIM_IT_CC1) == SET) { __HAL_TIM_CLEAR_IT(&TimMasterHandle, TIM_IT_CC1); - if (oc_rem_part > 0) { - set_compare(oc_rem_part); // Finish the remaining time left - oc_rem_part = 0; - } else { + if (oc_int_part > 0) { - set_compare(0xFFFF); - oc_rem_part = cnt_val; // To finish the counter loop the next time oc_int_part--; } else { - us_ticker_irq_handler(); + us_ticker_irq_handler(); } - } } } // Channel 2 for HAL tick if (__HAL_TIM_GET_FLAG(&TimMasterHandle, TIM_FLAG_CC2) == SET) { + if (__HAL_TIM_GET_IT_SOURCE(&TimMasterHandle, TIM_IT_CC2) == SET) { __HAL_TIM_CLEAR_IT(&TimMasterHandle, TIM_IT_CC2); uint32_t val = __HAL_TIM_GET_COUNTER(&TimMasterHandle); @@ -114,11 +107,16 @@ HAL_StatusTypeDef HAL_InitTick(uint32_t TickPriority) TimMasterHandle.Init.Prescaler = (uint32_t)(SystemCoreClock / 1000000) - 1; // 1 us tick TimMasterHandle.Init.ClockDivision = 0; TimMasterHandle.Init.CounterMode = TIM_COUNTERMODE_UP; -#ifdef TARGET_STM32F0 +#if !defined(TARGET_STM32L0) + TimMasterHandle.Init.RepetitionCounter = 0; +#endif +#ifdef TIM_AUTORELOAD_PRELOAD_DISABLE TimMasterHandle.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE; #endif HAL_TIM_Base_Init(&TimMasterHandle); + //LL_TIM_EnableUpdateEvent(TimMasterHandle.Instance); + // Configure output compare channel 1 for mbed timeout (enabled later when used) HAL_TIM_OC_Start(&TimMasterHandle, TIM_CHANNEL_1); @@ -127,6 +125,8 @@ HAL_StatusTypeDef HAL_InitTick(uint32_t TickPriority) PreviousVal = __HAL_TIM_GET_COUNTER(&TimMasterHandle); __HAL_TIM_SET_COMPARE(&TimMasterHandle, TIM_CHANNEL_2, PreviousVal + HAL_TICK_DELAY); + + // Configure interrupts // Update interrupt used for 32-bit counter // Output compare channel 1 interrupt for mbed timeout diff --git a/targets/TARGET_STM/us_ticker_16b.c b/targets/TARGET_STM/us_ticker_16b.c index a131df5776..73bfcf640b 100644 --- a/targets/TARGET_STM/us_ticker_16b.c +++ b/targets/TARGET_STM/us_ticker_16b.c @@ -25,7 +25,6 @@ TIM_HandleTypeDef TimMasterHandle; volatile uint32_t SlaveCounter = 0; volatile uint32_t oc_int_part = 0; -volatile uint16_t oc_rem_part = 0; static int us_ticker_inited = 0; @@ -91,22 +90,25 @@ uint32_t us_ticker_read() void us_ticker_set_interrupt(timestamp_t timestamp) { - int delta = (int)((uint32_t)timestamp - us_ticker_read()); - - uint16_t cval = TIM_MST->CNT; + int current_time = us_ticker_read(); + int delta = (int)(timestamp - current_time); if (delta <= 0) { // This event was in the past - us_ticker_irq_handler(); + /* Force the event to be handled in next interrupt context + * This prevents calling interrupt handlers in loops as + * us_ticker_set_interrupt might called again from the + * application handler + */ + oc_int_part = 0; + TimMasterHandle.Instance = TIM_MST; + HAL_TIM_GenerateEvent(&TimMasterHandle, TIM_EVENTSOURCE_CC1); } else { + /* set the comparator at the timestamp lower 16 bits + * and count the number of wrap-around loops to do with + * the upper 16 bits + */ oc_int_part = (uint32_t)(delta >> 16); - oc_rem_part = (uint16_t)(delta & 0xFFFF); - if (oc_rem_part <= (0xFFFF - cval)) { - set_compare(cval + oc_rem_part); - oc_rem_part = 0; - } else { - set_compare(0xFFFF); - oc_rem_part = oc_rem_part - (0xFFFF - cval); - } + set_compare(timestamp & 0xFFFF); } }