mirror of https://github.com/ARMmbed/mbed-os.git
Fix a bug that Ticker driver has the potential to loop infinitely.
Ticker driver has the potential to loop infinitely. Because, running "us_ticker_irq_handler()" from "us_ticker_set_interrupt()" before "obj->next = p;" of "us_ticker_insert_event()" is executed.pull/933/head
parent
2047acae11
commit
d7bc024a6a
|
|
@ -30,6 +30,7 @@ int us_ticker_inited = 0;
|
||||||
static double count_clock = 0;
|
static double count_clock = 0;
|
||||||
static uint32_t last_read = 0;
|
static uint32_t last_read = 0;
|
||||||
static uint32_t wrap_arround = 0;
|
static uint32_t wrap_arround = 0;
|
||||||
|
static uint64_t ticker_us_last64 = 0;
|
||||||
|
|
||||||
void us_ticker_interrupt(void) {
|
void us_ticker_interrupt(void) {
|
||||||
us_ticker_irq_handler();
|
us_ticker_irq_handler();
|
||||||
|
|
@ -61,69 +62,67 @@ void us_ticker_init(void) {
|
||||||
GIC_EnableIRQ(US_TICKER_TIMER_IRQn);
|
GIC_EnableIRQ(US_TICKER_TIMER_IRQn);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64_t us_ticker_read64() {
|
static uint64_t ticker_read_counter64(void) {
|
||||||
uint32_t val;
|
uint32_t cnt_val;
|
||||||
volatile uint64_t val64;
|
uint64_t cnt_val64;
|
||||||
int check_irq_masked;
|
|
||||||
|
|
||||||
check_irq_masked = __disable_irq();
|
|
||||||
|
|
||||||
if (!us_ticker_inited)
|
if (!us_ticker_inited)
|
||||||
us_ticker_init();
|
us_ticker_init();
|
||||||
|
|
||||||
/* read counter */
|
/* read counter */
|
||||||
val = OSTM1CNT;
|
cnt_val = OSTM1CNT;
|
||||||
if ( last_read > val ) {
|
if (last_read > cnt_val) {
|
||||||
wrap_arround++;
|
wrap_arround++;
|
||||||
}
|
}
|
||||||
last_read = val;
|
last_read = cnt_val;
|
||||||
val64 = ((uint64_t)wrap_arround << 32) + val;
|
cnt_val64 = ((uint64_t)wrap_arround << 32) + cnt_val;
|
||||||
|
|
||||||
/* clock to us */
|
return cnt_val64;
|
||||||
val64 = val64 / count_clock;
|
}
|
||||||
|
|
||||||
|
uint32_t us_ticker_read() {
|
||||||
|
uint64_t cnt_val64;
|
||||||
|
uint64_t us_val64;
|
||||||
|
int check_irq_masked;
|
||||||
|
|
||||||
|
check_irq_masked = __disable_irq();
|
||||||
|
|
||||||
|
cnt_val64 = ticker_read_counter64();
|
||||||
|
us_val64 = (cnt_val64 / count_clock);
|
||||||
|
ticker_us_last64 = us_val64;
|
||||||
|
|
||||||
if (!check_irq_masked) {
|
if (!check_irq_masked) {
|
||||||
__enable_irq();
|
__enable_irq();
|
||||||
}
|
}
|
||||||
|
|
||||||
return val64;
|
/* clock to us */
|
||||||
}
|
return (uint32_t)us_val64;
|
||||||
|
|
||||||
uint32_t us_ticker_read() {
|
|
||||||
return (uint32_t)us_ticker_read64();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void us_ticker_set_interrupt(timestamp_t timestamp) {
|
void us_ticker_set_interrupt(timestamp_t timestamp) {
|
||||||
// set match value
|
// set match value
|
||||||
volatile uint64_t set_cmp_val = 0;
|
uint64_t timestamp64;
|
||||||
uint64_t timestamp_tmp;
|
uint64_t set_cmp_val64;
|
||||||
int64_t timestamp_req;
|
volatile uint32_t set_cmp_val;
|
||||||
int64_t timestamp_comp;
|
uint64_t count_val_64;
|
||||||
uint64_t timestamp_now = us_ticker_read64();
|
|
||||||
|
|
||||||
/* calc compare mach timestamp */
|
/* calc compare mach timestamp */
|
||||||
set_cmp_val = (timestamp_now & 0xFFFFFFFF00000000) + timestamp;
|
timestamp64 = (ticker_us_last64 & 0xFFFFFFFF00000000) + timestamp;
|
||||||
|
if (timestamp < (ticker_us_last64 & 0x00000000FFFFFFFF)) {
|
||||||
timestamp_tmp = (uint64_t)timestamp;
|
|
||||||
timestamp_req = (int64_t)timestamp_tmp;
|
|
||||||
|
|
||||||
timestamp_tmp = (uint64_t)(timestamp_now & 0x00000000FFFFFFFF);
|
|
||||||
timestamp_comp = (int64_t)timestamp_tmp;
|
|
||||||
|
|
||||||
if (timestamp_req <= timestamp_comp + 1) {
|
|
||||||
if (((timestamp_req - timestamp_comp) <= 1) && ((timestamp_req - timestamp_comp) >= -10)) {
|
|
||||||
/* This event was in the past */
|
|
||||||
us_ticker_irq_handler();
|
|
||||||
return;
|
|
||||||
} else {
|
|
||||||
/* This event is wrap arround */
|
/* This event is wrap arround */
|
||||||
set_cmp_val += 0x100000000;
|
timestamp64 += 0x100000000;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* calc compare mach timestamp */
|
/* calc compare mach timestamp */
|
||||||
set_cmp_val = set_cmp_val * count_clock;
|
set_cmp_val64 = timestamp64 * count_clock;
|
||||||
OSTM1CMP = (uint32_t)(set_cmp_val & 0xffffffff);
|
set_cmp_val = (uint32_t)(set_cmp_val64 & 0x00000000FFFFFFFF);
|
||||||
|
count_val_64 = ticker_read_counter64();
|
||||||
|
if (set_cmp_val64 <= (count_val_64 + 500)) {
|
||||||
|
GIC_SetPendingIRQ(US_TICKER_TIMER_IRQn);
|
||||||
|
GIC_EnableIRQ(US_TICKER_TIMER_IRQn);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
OSTM1CMP = set_cmp_val;
|
||||||
GIC_EnableIRQ(US_TICKER_TIMER_IRQn);
|
GIC_EnableIRQ(US_TICKER_TIMER_IRQn);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -132,6 +131,5 @@ void us_ticker_disable_interrupt(void) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void us_ticker_clear_interrupt(void) {
|
void us_ticker_clear_interrupt(void) {
|
||||||
/* There are no Flags of OSTM1 to clear here */
|
GIC_ClearPendingIRQ(US_TICKER_TIMER_IRQn);
|
||||||
/* Do Nothing */
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue