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/4521/head
Laurent MEUNIER 2017-05-31 09:19:01 +02:00 committed by adbridge
parent 23c04b7365
commit efa1045fa6
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 SlaveCounter;
extern volatile uint32_t oc_int_part; extern volatile uint32_t oc_int_part;
extern volatile uint16_t oc_rem_part;
volatile uint32_t PreviousVal = 0; volatile uint32_t PreviousVal = 0;
void us_ticker_irq_handler(void); void us_ticker_irq_handler(void);
void set_compare(uint16_t count); void set_compare(uint16_t count);
#if defined(TARGET_STM32F0) #if defined(TARGET_STM32F0)
void timer_update_irq_handler(void) { void timer_update_irq_handler(void) {
#else #else
void timer_irq_handler(void) void timer_irq_handler(void)
{ {
#endif #endif
uint16_t cnt_val = TIM_MST->CNT;
TimMasterHandle.Instance = TIM_MST; TimMasterHandle.Instance = TIM_MST;
// Clear Update interrupt flag // Clear Update interrupt flag
@ -53,7 +52,6 @@ void timer_irq_handler(void)
// Used for mbed timeout (channel 1) and HAL tick (channel 2) // Used for mbed timeout (channel 1) and HAL tick (channel 2)
void timer_oc_irq_handler(void) void timer_oc_irq_handler(void)
{ {
uint16_t cnt_val = TIM_MST->CNT;
TimMasterHandle.Instance = TIM_MST; TimMasterHandle.Instance = TIM_MST;
#endif #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_FLAG(&TimMasterHandle, TIM_FLAG_CC1) == SET) {
if (__HAL_TIM_GET_IT_SOURCE(&TimMasterHandle, TIM_IT_CC1) == SET) { if (__HAL_TIM_GET_IT_SOURCE(&TimMasterHandle, TIM_IT_CC1) == SET) {
__HAL_TIM_CLEAR_IT(&TimMasterHandle, TIM_IT_CC1); __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) { if (oc_int_part > 0) {
set_compare(0xFFFF);
oc_rem_part = cnt_val; // To finish the counter loop the next time
oc_int_part--; oc_int_part--;
} else { } else {
us_ticker_irq_handler(); us_ticker_irq_handler();
} }
}
} }
} }
// Channel 2 for HAL tick // Channel 2 for HAL tick
if (__HAL_TIM_GET_FLAG(&TimMasterHandle, TIM_FLAG_CC2) == SET) { if (__HAL_TIM_GET_FLAG(&TimMasterHandle, TIM_FLAG_CC2) == SET) {
if (__HAL_TIM_GET_IT_SOURCE(&TimMasterHandle, TIM_IT_CC2) == SET) { if (__HAL_TIM_GET_IT_SOURCE(&TimMasterHandle, TIM_IT_CC2) == SET) {
__HAL_TIM_CLEAR_IT(&TimMasterHandle, TIM_IT_CC2); __HAL_TIM_CLEAR_IT(&TimMasterHandle, TIM_IT_CC2);
uint32_t val = __HAL_TIM_GET_COUNTER(&TimMasterHandle); 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.Prescaler = (uint32_t)(SystemCoreClock / 1000000) - 1; // 1 us tick
TimMasterHandle.Init.ClockDivision = 0; TimMasterHandle.Init.ClockDivision = 0;
TimMasterHandle.Init.CounterMode = TIM_COUNTERMODE_UP; 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; TimMasterHandle.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
#endif #endif
HAL_TIM_Base_Init(&TimMasterHandle); HAL_TIM_Base_Init(&TimMasterHandle);
//LL_TIM_EnableUpdateEvent(TimMasterHandle.Instance);
// Configure output compare channel 1 for mbed timeout (enabled later when used) // Configure output compare channel 1 for mbed timeout (enabled later when used)
HAL_TIM_OC_Start(&TimMasterHandle, TIM_CHANNEL_1); 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); PreviousVal = __HAL_TIM_GET_COUNTER(&TimMasterHandle);
__HAL_TIM_SET_COMPARE(&TimMasterHandle, TIM_CHANNEL_2, PreviousVal + HAL_TICK_DELAY); __HAL_TIM_SET_COMPARE(&TimMasterHandle, TIM_CHANNEL_2, PreviousVal + HAL_TICK_DELAY);
// Configure interrupts // Configure interrupts
// Update interrupt used for 32-bit counter // Update interrupt used for 32-bit counter
// Output compare channel 1 interrupt for mbed timeout // 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 SlaveCounter = 0;
volatile uint32_t oc_int_part = 0; volatile uint32_t oc_int_part = 0;
volatile uint16_t oc_rem_part = 0;
static int us_ticker_inited = 0; static int us_ticker_inited = 0;
@ -91,22 +90,25 @@ uint32_t us_ticker_read()
void us_ticker_set_interrupt(timestamp_t timestamp) void us_ticker_set_interrupt(timestamp_t timestamp)
{ {
int delta = (int)((uint32_t)timestamp - us_ticker_read()); int current_time = us_ticker_read();
int delta = (int)(timestamp - current_time);
uint16_t cval = TIM_MST->CNT;
if (delta <= 0) { // This event was in the past 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 { } 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_int_part = (uint32_t)(delta >> 16);
oc_rem_part = (uint16_t)(delta & 0xFFFF); set_compare(timestamp & 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);
}
} }
} }