mirror of https://github.com/ARMmbed/mbed-os.git
Update STM32 16 bits us_tickers in line with new mbed HAL
The new HAL allows to share the timer bit width and frequency, the actual handling of mapping 16 bits counter up to 32 bits or 64 bits is now managed by mbed common layer. This makes this ticker layer very similar to 32bits one and much easier than before.pull/7009/head
parent
1448f81620
commit
c3d5daf80a
|
@ -22,9 +22,6 @@
|
|||
|
||||
extern TIM_HandleTypeDef TimMasterHandle;
|
||||
|
||||
extern volatile uint32_t SlaveCounter;
|
||||
extern volatile uint32_t oc_int_part;
|
||||
|
||||
volatile uint32_t PreviousVal = 0;
|
||||
|
||||
void us_ticker_irq_handler(void);
|
||||
|
@ -37,14 +34,6 @@ void timer_irq_handler(void)
|
|||
#endif
|
||||
TimMasterHandle.Instance = TIM_MST;
|
||||
|
||||
// Clear Update interrupt flag
|
||||
if (__HAL_TIM_GET_FLAG(&TimMasterHandle, TIM_FLAG_UPDATE) == SET) {
|
||||
if (__HAL_TIM_GET_IT_SOURCE(&TimMasterHandle, TIM_IT_UPDATE) == SET) {
|
||||
__HAL_TIM_CLEAR_IT(&TimMasterHandle, TIM_IT_UPDATE);
|
||||
SlaveCounter++;
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(TARGET_STM32F0)
|
||||
} // end timer_update_irq_handler function
|
||||
// Used for mbed timeout (channel 1) and HAL tick (channel 2)
|
||||
|
@ -57,12 +46,7 @@ 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_int_part > 0) {
|
||||
oc_int_part--;
|
||||
} else {
|
||||
us_ticker_irq_handler();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -142,7 +126,6 @@ HAL_StatusTypeDef HAL_InitTick(uint32_t TickPriority)
|
|||
#endif
|
||||
|
||||
// Enable interrupts
|
||||
__HAL_TIM_ENABLE_IT(&TimMasterHandle, TIM_IT_UPDATE); // For 32-bit counter
|
||||
__HAL_TIM_ENABLE_IT(&TimMasterHandle, TIM_IT_CC2); // For HAL tick
|
||||
|
||||
// Enable timer
|
||||
|
|
|
@ -23,157 +23,48 @@
|
|||
|
||||
TIM_HandleTypeDef TimMasterHandle;
|
||||
|
||||
volatile uint32_t SlaveCounter = 0;
|
||||
volatile uint32_t oc_int_part = 0;
|
||||
// Declare ticker as 16 bits - mbed layer takes care of mapping to 32 or 64
|
||||
// bits
|
||||
const ticker_info_t* us_ticker_get_info()
|
||||
{
|
||||
static const ticker_info_t info = {
|
||||
1000000,
|
||||
16
|
||||
};
|
||||
return &info;
|
||||
}
|
||||
|
||||
void us_ticker_init(void)
|
||||
{
|
||||
/* NOTE: assuming that HAL tick has already been initialized! */
|
||||
/* NOTE: assuming thaiHAL tick has already been initialized! */
|
||||
us_ticker_disable_interrupt();
|
||||
}
|
||||
|
||||
uint32_t us_ticker_read()
|
||||
{
|
||||
uint16_t cntH_old, cntH, cntL;
|
||||
do {
|
||||
cntH_old = SlaveCounter;
|
||||
/* SlaveCounter needs to be checked before AND after we read the
|
||||
* current counter TIM_MST->CNT, in case it wraps around.
|
||||
* there are 2 possible cases of wrap around
|
||||
* 1) in case this function is interrupted by timer_irq_handler and
|
||||
* the SlaveCounter is updated. In that case we will loop again.
|
||||
* 2) in case this function is called from interrupt context during
|
||||
* wrap-around condtion. That would prevent/delay the timer_irq_handler
|
||||
* from being called so we need to locally check the FLAG_UPDATE and
|
||||
* update the cntH accordingly. The SlaveCounter variable itself will
|
||||
* be updated in the interrupt handler just after ...
|
||||
*/
|
||||
if (__HAL_TIM_GET_FLAG(&TimMasterHandle, TIM_FLAG_UPDATE) == SET) {
|
||||
cntH_old += 1;
|
||||
}
|
||||
cntL = TIM_MST->CNT;
|
||||
cntH = SlaveCounter;
|
||||
if (__HAL_TIM_GET_FLAG(&TimMasterHandle, TIM_FLAG_UPDATE) == SET) {
|
||||
cntH += 1;
|
||||
}
|
||||
} while(cntH_old != cntH);
|
||||
// Glue the upper and lower part together to get a 32 bit timer
|
||||
return (uint32_t)(cntH << 16 | cntL);
|
||||
return TIM_MST->CNT;
|
||||
}
|
||||
|
||||
void us_ticker_set_interrupt(timestamp_t timestamp)
|
||||
{
|
||||
// NOTE: This function must be called with interrupts disabled to keep our
|
||||
// timer interrupt setup atomic
|
||||
|
||||
// Set new output compare value
|
||||
__HAL_TIM_SET_COMPARE(&TimMasterHandle, TIM_CHANNEL_1, timestamp & 0xFFFF);
|
||||
// Ensure the compare event starts clear
|
||||
__HAL_TIM_CLEAR_FLAG(&TimMasterHandle, TIM_FLAG_CC1);
|
||||
// Enable IT
|
||||
__HAL_TIM_ENABLE_IT(&TimMasterHandle, TIM_IT_CC1);
|
||||
|
||||
/* Set the number of timer wrap-around loops before the actual timestamp
|
||||
* is reached. If the calculated delta time is more than halfway to the
|
||||
* next compare event, check to see if a compare event has already been
|
||||
* set, and if so, add one to the wrap-around count. This is done to
|
||||
* ensure the correct wrap count is used in the corner cases where the
|
||||
* 16 bit counter passes the compare value during the process of
|
||||
* configuring this interrupt.
|
||||
*
|
||||
* Assumption: The time to execute this function is less than 32ms
|
||||
* (otherwise incorrect behaviour could result)
|
||||
*
|
||||
* Consider the following corner cases:
|
||||
* 1) timestamp is 1 us in the future:
|
||||
* oc_int_part = 0 initially
|
||||
* oc_int_part left at 0 because ((delta - 1) & 0xFFFF) < 0x8000
|
||||
* Compare event should happen in 1 us and us_ticker_irq_handler()
|
||||
* called
|
||||
* 2) timestamp is 0x8000 us in the future:
|
||||
* oc_int_part = 0 initially
|
||||
* oc_int_part left at 0 because ((delta - 1) & 0xFFFF) < 0x8000
|
||||
* There should be no possibility of the CC1 flag being set yet
|
||||
* (see assumption above). When the compare event does occur in
|
||||
* 32768 us, us_ticker_irq_handler() will be called
|
||||
* 3) timestamp is 0x8001 us in the future:
|
||||
* oc_int_part = 0 initially
|
||||
* ((delta - 1) & 0xFFFF) >= 0x8000 but there should be no
|
||||
* possibility of the CC1 flag being set yet (see assumption above),
|
||||
* so oc_int_part will be left at 0, and when the compare event
|
||||
* does occur in 32769 us, us_ticker_irq_handler() will be called
|
||||
* 4) timestamp is 0x10000 us in the future:
|
||||
* oc_int_part = 0 initially
|
||||
* ((delta - 1) & 0xFFFF) >= 0x8000
|
||||
* There are two subcases:
|
||||
* a) The timer counter has not incremented past the compare
|
||||
* value while setting up the interrupt. In this case, the
|
||||
* CC1 flag will not be set, so oc_int_part will be
|
||||
* left at 0, and when the compare event occurs in 65536 us,
|
||||
* us_ticker_irq_handler() will be called
|
||||
* b) The timer counter has JUST incremented past the compare
|
||||
* value. In this case, the CC1 flag will be set, so
|
||||
* oc_int_part will be incremented to 1, and the interrupt will
|
||||
* occur immediately after this function returns, where
|
||||
* oc_int_part will decrement to 0 without calling
|
||||
* us_ticker_irq_handler(). Then about 65536 us later, the
|
||||
* compare event will occur again, and us_ticker_irq_handler()
|
||||
* will be called
|
||||
* 5) timestamp is 0x10001 us in the future:
|
||||
* oc_int_part = 1 initially
|
||||
* oc_int_part left at 1 because ((delta - 1) & 0xFFFF) < 0x8000
|
||||
* CC1 flag will not be set (see assumption above). In 1 us the
|
||||
* compare event will cause an interrupt, where oc_int_part will be
|
||||
* decremented to 0 without calling us_ticker_irq_handler(). Then
|
||||
* about 65536 us later, the compare event will occur again, and
|
||||
* us_ticker_irq_handler() will be called
|
||||
* 6) timestamp is 0x18000 us in the future:
|
||||
* oc_int_part = 1 initially
|
||||
* oc_int_part left at 1 because ((delta - 1) & 0xFFFF) < 0x8000
|
||||
* There should be no possibility of the CC1 flag being set yet
|
||||
* (see assumption above). When the compare event does occur in
|
||||
* 32768 us, oc_int_part will be decremented to 0 without calling
|
||||
* us_ticker_irq_handler(). Then about 65536 us later, the
|
||||
* compare event will occur again, and us_ticker_irq_handler() will
|
||||
* be called
|
||||
* 7) timestamp is 0x18001 us in the future:
|
||||
* oc_int_part = 1 initially
|
||||
* ((delta - 1) & 0xFFFF) >= 0x8000 but there should be no
|
||||
* possibility of the CC1 flag being set yet (see assumption above),
|
||||
* so oc_int_part will be left at 1, and when the compare event
|
||||
* does occur in 32769 us, oc_int_part will be decremented to 0
|
||||
* without calling us_ticker_irq_handler(). Then about 65536 us
|
||||
* later, the compare event will occur again, and
|
||||
* us_ticker_irq_handler() will be called
|
||||
*
|
||||
* delta - 1 is used because the timer compare event happens on the
|
||||
* counter incrementing to match the compare value, and it won't occur
|
||||
* immediately when the compare value is set to the current counter
|
||||
* value.
|
||||
*/
|
||||
uint32_t current_time = us_ticker_read();
|
||||
uint32_t delta = timestamp - current_time;
|
||||
/* Note: The case of delta <= 0 is handled in MBED upper layer */
|
||||
oc_int_part = (delta - 1) >> 16;
|
||||
if ( ((delta - 1) & 0xFFFF) >= 0x8000 &&
|
||||
__HAL_TIM_GET_FLAG(&TimMasterHandle, TIM_FLAG_CC1) == SET ) {
|
||||
++oc_int_part;
|
||||
/* NOTE: Instead of incrementing oc_int_part here, we could clear
|
||||
* the CC1 flag, but then you'd have to wait to ensure the
|
||||
* interrupt is knocked down before returning and reenabling
|
||||
* interrupts. Since this is a rare case, it's not worth it
|
||||
* to try and optimize it, and it keeps the code simpler and
|
||||
* safer to just do this increment instead.
|
||||
*/
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void us_ticker_fire_interrupt(void)
|
||||
{
|
||||
/* When firing the event, the number of 16 bits counter wrap-ups (oc_int)
|
||||
* must be re-initialized */
|
||||
oc_int_part = 0;
|
||||
HAL_TIM_GenerateEvent(&TimMasterHandle, TIM_EVENTSOURCE_CC1);
|
||||
// Ensure the compare event starts clear
|
||||
__HAL_TIM_CLEAR_FLAG(&TimMasterHandle, TIM_FLAG_CC1);
|
||||
LL_TIM_GenerateEvent_CC1(TimMasterHandle.Instance);
|
||||
// Enable IT
|
||||
__HAL_TIM_ENABLE_IT(&TimMasterHandle, TIM_IT_CC1);
|
||||
|
||||
}
|
||||
|
||||
/* NOTE: must be called with interrupts disabled! */
|
||||
|
|
Loading…
Reference in New Issue