Skip to content

Ticker free() - requirements, pseudo code, tests, implementation #7508

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 8 commits into from
Aug 3, 2018
7 changes: 7 additions & 0 deletions TESTS/mbed_drivers/timer/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,12 @@ static void stub_fire_interrupt(void)
/* do nothing. */
}

/* User ticker interface function. */
static void stub_free(void)
{
/* do nothing. */
}

ticker_info_t info =
{ TICKER_FREQ_1MHZ, TICKER_BITS };

Expand All @@ -122,6 +128,7 @@ static const ticker_interface_t us_interface = {
.clear_interrupt = stub_clear_interrupt,
.set_interrupt = stub_set_interrupt,
.fire_interrupt = stub_fire_interrupt,
.free = stub_free,
.get_info = stub_get_info,
};

Expand Down
134 changes: 112 additions & 22 deletions TESTS/mbed_hal/common_tickers/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ extern "C" {
#error [NOT_SUPPORTED] test not supported
#endif

#define US_PER_S 1000000

#define FORCE_OVERFLOW_TEST (false)
#define TICKER_INT_VAL 500
#define TICKER_DELTA 10
Expand All @@ -43,10 +45,11 @@ extern "C" {
#define US_TICKER_OVERFLOW_DELTA2 60

#define TICKER_100_TICKS 100
#define TICKER_500_TICKS 500

#define MAX_FUNC_EXEC_TIME_US 20
#define DELTA_FUNC_EXEC_TIME_US 5
#define NUM_OF_CALLS 1000
#define NUM_OF_CALLS 100

#define NUM_OF_CYCLES 100000

Expand Down Expand Up @@ -149,6 +152,19 @@ void wait_cycles(volatile unsigned int cycles)
while (cycles--);
}

/* Auxiliary function to determine how long ticker function are executed.
* This function returns number of us between <start_ticks> and <stop_ticks>
* taking into account counter roll-over, counter size and frequency.
*/
uint32_t diff_us(uint32_t start_ticks, uint32_t stop_ticks, const ticker_info_t * info)
{
uint32_t counter_mask = ((1 << info->bits) - 1);

uint32_t diff_ticks = ((stop_ticks - start_ticks) & counter_mask);

return (uint32_t) ((uint64_t) diff_ticks * US_PER_S / info->frequency);
}

/* Test that ticker_init can be called multiple times and
* ticker_init allows the ticker to keep counting and disables the ticker interrupt.
*/
Expand Down Expand Up @@ -419,64 +435,134 @@ void ticker_increment_test(void)
/* Test that common ticker functions complete with the required amount of time. */
void ticker_speed_test(void)
{
Timer timer;
int counter = NUM_OF_CALLS;
uint32_t start;
uint32_t stop;

const ticker_info_t * us_ticker_info = get_us_ticker_data()->interface->get_info();

/* Free function will disable the ticker. For time measurement
* we need to use other one if available.
*/
#if DEVICE_LPTICKER
const ticker_info_t * lp_ticker_info = get_lp_ticker_data()->interface->get_info();
bool us_ticker_test = (intf == get_us_ticker_data()->interface);
#endif

/* ---- Test ticker_read function. ---- */
timer.reset();
timer.start();
start = us_ticker_read();
while (counter--) {
intf->read();
}
timer.stop();
stop = us_ticker_read();

TEST_ASSERT(timer.read_us() < (NUM_OF_CALLS * (MAX_FUNC_EXEC_TIME_US + DELTA_FUNC_EXEC_TIME_US)));
TEST_ASSERT(diff_us(start, stop, us_ticker_info) < (NUM_OF_CALLS * (MAX_FUNC_EXEC_TIME_US + DELTA_FUNC_EXEC_TIME_US)));

/* ---- Test ticker_clear_interrupt function. ---- */
counter = NUM_OF_CALLS;
timer.reset();
timer.start();
start = us_ticker_read();
while (counter--) {
intf->clear_interrupt();
}
timer.stop();
stop = us_ticker_read();

TEST_ASSERT(timer.read_us() < (NUM_OF_CALLS * (MAX_FUNC_EXEC_TIME_US + DELTA_FUNC_EXEC_TIME_US)));
TEST_ASSERT(diff_us(start, stop, us_ticker_info) < (NUM_OF_CALLS * (MAX_FUNC_EXEC_TIME_US + DELTA_FUNC_EXEC_TIME_US)));

/* ---- Test ticker_set_interrupt function. ---- */
counter = NUM_OF_CALLS;
timer.reset();
timer.start();
start = us_ticker_read();
while (counter--) {
intf->set_interrupt(0);
}
timer.stop();
stop = us_ticker_read();

TEST_ASSERT(timer.read_us() < (NUM_OF_CALLS * (MAX_FUNC_EXEC_TIME_US + DELTA_FUNC_EXEC_TIME_US)));
TEST_ASSERT(diff_us(start, stop, us_ticker_info) < (NUM_OF_CALLS * (MAX_FUNC_EXEC_TIME_US + DELTA_FUNC_EXEC_TIME_US)));

/* ---- Test fire_interrupt function. ---- */
counter = NUM_OF_CALLS;
timer.reset();
timer.start();
start = us_ticker_read();
while (counter--) {
intf->fire_interrupt();
}
timer.stop();
stop = us_ticker_read();

TEST_ASSERT(timer.read_us() < (NUM_OF_CALLS * (MAX_FUNC_EXEC_TIME_US + DELTA_FUNC_EXEC_TIME_US)));
TEST_ASSERT(diff_us(start, stop, us_ticker_info) < (NUM_OF_CALLS * (MAX_FUNC_EXEC_TIME_US + DELTA_FUNC_EXEC_TIME_US)));

/* ---- Test disable_interrupt function. ---- */
counter = NUM_OF_CALLS;
timer.reset();
timer.start();
start = us_ticker_read();
while (counter--) {
intf->disable_interrupt();
}
timer.stop();
stop = us_ticker_read();

TEST_ASSERT(diff_us(start, stop, us_ticker_info) < (NUM_OF_CALLS * (MAX_FUNC_EXEC_TIME_US + DELTA_FUNC_EXEC_TIME_US)));

/* ---- Test free function. ---- */
#if DEVICE_LPTICKER
counter = NUM_OF_CALLS;
if (us_ticker_test) {
lp_ticker_init();
}
start = us_ticker_test ? lp_ticker_read() : us_ticker_read();
while (counter--) {
intf->free();
}
stop = us_ticker_test ? lp_ticker_read() : us_ticker_read();

TEST_ASSERT(diff_us(start, stop, us_ticker_info) < (NUM_OF_CALLS * (MAX_FUNC_EXEC_TIME_US + DELTA_FUNC_EXEC_TIME_US)));
#endif
}

/* Test that ticker_free disables ticker interrupt. */
void ticker_free_interrupt_test(void)
{
overflow_protect();

uint32_t cycles_500_ticks = 50;
uint32_t reference_ticks_count = 0;

while(reference_ticks_count < TICKER_500_TICKS) {
cycles_500_ticks *= 2;
const uint32_t start = intf->read();
wait_cycles(cycles_500_ticks);
reference_ticks_count = intf->read() - start;
}

intFlag = 0;

intf->set_interrupt(intf->read() + (TICKER_500_TICKS / 2));
intf->free();
wait_cycles(cycles_500_ticks);
intf->init();
TEST_ASSERT_EQUAL(0, intFlag);
}

/* Test that ticker can be successfully re-initialized after free(). */
void ticker_init_free_test(void)
{
intf->free();
intf->init();

overflow_protect();

intFlag = 0;

const uint32_t tick_count = intf->read();

intf->set_interrupt(intf->read() + TICKER_INT_VAL);

while (intf->read() < (tick_count + TICKER_INT_VAL - TICKER_DELTA)) {
TEST_ASSERT_EQUAL_INT_MESSAGE(0, intFlag, "Interrupt fired too early");
}

while (intf->read() < (tick_count + TICKER_INT_VAL + TICKER_DELTA)) {
}

TEST_ASSERT(timer.read_us() < (NUM_OF_CALLS * (MAX_FUNC_EXEC_TIME_US + DELTA_FUNC_EXEC_TIME_US)));
TEST_ASSERT_EQUAL(1, intFlag);
}


utest::v1::status_t us_ticker_setup(const Case *const source, const size_t index_of_case)
{
intf = get_us_ticker_data()->interface;
Expand Down Expand Up @@ -551,6 +637,8 @@ Case cases[] = {
Case("Microsecond ticker overflow test", us_ticker_setup, ticker_overflow_test, us_ticker_teardown),
Case("Microsecond ticker increment test", us_ticker_setup, ticker_increment_test, us_ticker_teardown),
Case("Microsecond ticker speed test", us_ticker_setup, ticker_speed_test, us_ticker_teardown),
Case("Microsecond ticker free interrupt test", us_ticker_setup, ticker_free_interrupt_test, us_ticker_teardown),
Case("Microsecond re-init after free test", us_ticker_setup, ticker_init_free_test, us_ticker_teardown),
#if DEVICE_LPTICKER
Case("lp ticker init is safe to call repeatedly", lp_ticker_setup, ticker_init_test, lp_ticker_teardown),
Case("lp ticker info test", lp_ticker_setup, ticker_info_test, lp_ticker_teardown),
Expand All @@ -561,6 +649,8 @@ Case cases[] = {
Case("lp ticker overflow test", lp_ticker_setup, ticker_overflow_test, lp_ticker_teardown),
Case("lp ticker increment test", lp_ticker_setup, ticker_increment_test, lp_ticker_teardown),
Case("lp ticker speed test", lp_ticker_setup, ticker_speed_test, lp_ticker_teardown),
Case("lp ticker free interrupt test", lp_ticker_setup, ticker_free_interrupt_test, lp_ticker_teardown),
Case("lp ticker re-init after free test", lp_ticker_setup, ticker_init_free_test, lp_ticker_teardown),
#endif
};

Expand Down
15 changes: 15 additions & 0 deletions TESTS/mbed_hal/common_tickers/ticker_api_tests.h
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,21 @@ void ticker_speed_test(void);
*/
void ticker_overflow_test(void);

/** Test ticker_free disables ticker interrupt.
*
* Given ticker is available.
* When ticker interrupt is set and then ticker_free is called.
* Then ticker interrupt is not triggered.
*/
void ticker_free_interrupt_test(void);

/** Test that ticker can be successfully re-initialized after free().
*
* Given ticker is available.
* When ticker has been re-initialized after free().
* Then ticker counts and generates interrupts.
*/
void ticker_init_free_test(void);
/**@}*/

#ifdef __cplusplus
Expand Down
5 changes: 5 additions & 0 deletions TESTS/mbedmicro-rtos-mbed/systimer/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,10 @@ void mock_ticker_fire_interrupt()
{
}

void mock_ticker_free()
{
}

const ticker_info_t *mock_ticker_get_info()
{
static const ticker_info_t mock_ticker_info = {
Expand All @@ -115,6 +119,7 @@ ticker_interface_t mock_ticker_interface = {
.clear_interrupt = mock_ticker_clear_interrupt,
.set_interrupt = mock_ticker_set_interrupt,
.fire_interrupt = mock_ticker_fire_interrupt,
.free = mock_ticker_free,
.get_info = mock_ticker_get_info,
};

Expand Down
1 change: 1 addition & 0 deletions hal/mbed_lp_ticker_api.c
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ static const ticker_interface_t lp_interface = {
#endif
.fire_interrupt = lp_ticker_fire_interrupt,
.get_info = lp_ticker_get_info,
.free = lp_ticker_free,
};

static const ticker_data_t lp_data = {
Expand Down
1 change: 1 addition & 0 deletions hal/mbed_us_ticker_api.c
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ static const ticker_interface_t us_interface = {
.set_interrupt = us_ticker_set_interrupt,
.fire_interrupt = us_ticker_fire_interrupt,
.get_info = us_ticker_get_info,
.free = us_ticker_free,
};

static const ticker_data_t us_data = {
Expand Down
1 change: 1 addition & 0 deletions hal/ticker_api.h
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ typedef struct {
void (*clear_interrupt)(void); /**< Clear interrupt function */
void (*set_interrupt)(timestamp_t timestamp); /**< Set interrupt function */
void (*fire_interrupt)(void); /**< Fire interrupt right-away */
void (*free)(void); /**< Disable function */
const ticker_info_t *(*get_info)(void); /**< Return info about this ticker's implementation */
} ticker_interface_t;

Expand Down
21 changes: 21 additions & 0 deletions hal/us_ticker_api.h
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,8 @@ extern "C" {
* Verified by ::ticker_fire_now_test
* * The ticker operations ticker_read, ticker_clear_interrupt, ticker_set_interrupt and ticker_fire_interrupt
* take less than 20us to complete - Verified by ::ticker_speed_test
* * The function ticker_free disables the ticker interrupt - ::ticker_free_interrupt_test
* * The function ticker_init re-initializes ticker after has been disabled by means of ticker_free - Verified by ::ticker_init_free_test
*
* # Undefined behavior
* * Calling any function other than ticker_init before the initialization of the ticker
Expand Down Expand Up @@ -170,6 +172,25 @@ void us_ticker_init(void);
* except us_ticker_init(), calling any function other than init is undefined.
*
* @note This function stops the ticker from counting.
*
* Pseudo Code:
* @code
* uint32_t us_ticker_free()
* {
* // Disable timer
* TIMER_CTRL &= ~TIMER_CTRL_ENABLE_Msk;
*
* // Disable the compare interrupt
* TIMER_CTRL &= ~TIMER_CTRL_COMPARE_ENABLE_Msk;
*
* // Disable timer interrupt
* NVIC_DisableIRQ(TIMER_IRQn);
*
* // Disable clock gate so processor cannot read TIMER registers
* POWER_CTRL &= ~POWER_CTRL_TIMER_Msk;
* }
* @endcode
*
*/
void us_ticker_free(void);

Expand Down
5 changes: 5 additions & 0 deletions targets/TARGET_ARM_SSG/TARGET_BEETLE/lp_ticker.c
Original file line number Diff line number Diff line change
Expand Up @@ -152,4 +152,9 @@ void lp_ticker_clear_interrupt(void)
DualTimer_ClearInterrupt(DUALTIMER0);
}

void lp_ticker_free(void)
{

}

#endif
5 changes: 5 additions & 0 deletions targets/TARGET_ARM_SSG/TARGET_BEETLE/us_ticker.c
Original file line number Diff line number Diff line change
Expand Up @@ -111,3 +111,8 @@ void us_ticker_disable_interrupt(void) {
void us_ticker_clear_interrupt(void) {
Timer_ClearInterrupt(TIMER0);
}

void us_ticker_free(void)
{

}
5 changes: 5 additions & 0 deletions targets/TARGET_ARM_SSG/TARGET_CM3DS_MPS2/lp_ticker.c
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,11 @@ void lp_ticker_fire_interrupt(void)
cmsdk_ticker_fire_interrupt(&timer_data);
}

void lp_ticker_free(void)
{

}

void TIMER1_IRQHandler(void)
{
cmsdk_ticker_irq_handler(&timer_data);
Expand Down
5 changes: 5 additions & 0 deletions targets/TARGET_ARM_SSG/TARGET_CM3DS_MPS2/us_ticker.c
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,11 @@ void us_ticker_fire_interrupt(void)
cmsdk_ticker_fire_interrupt(&timer_data);
}

void us_ticker_free(void)
{

}

void TIMER0_IRQHandler(void)
{
cmsdk_ticker_irq_handler(&timer_data);
Expand Down
5 changes: 5 additions & 0 deletions targets/TARGET_ARM_SSG/TARGET_IOTSS/us_ticker.c
Original file line number Diff line number Diff line change
Expand Up @@ -87,3 +87,8 @@ void us_ticker_clear_interrupt(void) {
US_TICKER_TIMER2->TimerIntClr = 0x1;

}

void us_ticker_free(void)
{

}
5 changes: 5 additions & 0 deletions targets/TARGET_ARM_SSG/TARGET_MPS2/us_ticker.c
Original file line number Diff line number Diff line change
Expand Up @@ -81,3 +81,8 @@ void us_ticker_clear_interrupt(void) {
US_TICKER_TIMER2->TimerIntClr = 0x1;

}

void us_ticker_free(void)
{

}
Loading