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.
pull/4424/head
Laurent MEUNIER 2017-05-31 09:19:01 +02:00
parent b9b5f0b929
commit 35c68859c0
2 changed files with 27 additions and 25 deletions

View File

@ -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

View File

@ -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);
}
}