Skip to content

Commit

Permalink
Merge pull request #7524 from c1728p9/tickless_fix
Browse files Browse the repository at this point in the history
Fixes for tickless and LPTICKER_DELAY_TICKS
  • Loading branch information
Cruz Monrreal authored Aug 21, 2018
2 parents 7c22dca + dc2e2c0 commit e02466a
Show file tree
Hide file tree
Showing 20 changed files with 1,068 additions and 196 deletions.
44 changes: 22 additions & 22 deletions TESTS/mbed_drivers/sleep_lock/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,90 +29,90 @@ using namespace utest::v1;

void deep_sleep_lock_lock_test()
{
TEST_ASSERT_EQUAL(true, sleep_manager_can_deep_sleep());
TEST_ASSERT_EQUAL(true, sleep_manager_can_deep_sleep_test_check());
{
// Check basic usage works
DeepSleepLock lock;
TEST_ASSERT_EQUAL(false, sleep_manager_can_deep_sleep());
TEST_ASSERT_EQUAL(false, sleep_manager_can_deep_sleep_test_check());
}

TEST_ASSERT_EQUAL(true, sleep_manager_can_deep_sleep());
TEST_ASSERT_EQUAL(true, sleep_manager_can_deep_sleep_test_check());
{
// Check that unlock and lock change can deep sleep as expected
DeepSleepLock lock;
TEST_ASSERT_EQUAL(false, sleep_manager_can_deep_sleep());
TEST_ASSERT_EQUAL(false, sleep_manager_can_deep_sleep_test_check());
lock.unlock();
TEST_ASSERT_EQUAL(true, sleep_manager_can_deep_sleep());
TEST_ASSERT_EQUAL(true, sleep_manager_can_deep_sleep_test_check());
lock.lock();
TEST_ASSERT_EQUAL(false, sleep_manager_can_deep_sleep());
TEST_ASSERT_EQUAL(false, sleep_manager_can_deep_sleep_test_check());
}

TEST_ASSERT_EQUAL(true, sleep_manager_can_deep_sleep());
TEST_ASSERT_EQUAL(true, sleep_manager_can_deep_sleep_test_check());
{
// Check that unlock releases sleep based on count
DeepSleepLock lock;
lock.lock();
lock.lock();
lock.unlock();
TEST_ASSERT_EQUAL(false, sleep_manager_can_deep_sleep());
TEST_ASSERT_EQUAL(false, sleep_manager_can_deep_sleep_test_check());
}

TEST_ASSERT_EQUAL(true, sleep_manager_can_deep_sleep());
TEST_ASSERT_EQUAL(true, sleep_manager_can_deep_sleep_test_check());
{
// Check that unbalanced locks do not leave deep sleep locked
DeepSleepLock lock;
lock.lock();
TEST_ASSERT_EQUAL(false, sleep_manager_can_deep_sleep());
TEST_ASSERT_EQUAL(false, sleep_manager_can_deep_sleep_test_check());
}
TEST_ASSERT_EQUAL(true, sleep_manager_can_deep_sleep());
TEST_ASSERT_EQUAL(true, sleep_manager_can_deep_sleep_test_check());

}

void timer_lock_test()
{
TEST_ASSERT_EQUAL(true, sleep_manager_can_deep_sleep());
TEST_ASSERT_EQUAL(true, sleep_manager_can_deep_sleep_test_check());
{
// Just creating a timer object does not lock sleep
Timer timer;
TEST_ASSERT_EQUAL(true, sleep_manager_can_deep_sleep());
TEST_ASSERT_EQUAL(true, sleep_manager_can_deep_sleep_test_check());
}

TEST_ASSERT_EQUAL(true, sleep_manager_can_deep_sleep());
TEST_ASSERT_EQUAL(true, sleep_manager_can_deep_sleep_test_check());
{
// Starting a timer does lock sleep
Timer timer;
timer.start();
TEST_ASSERT_EQUAL(false, sleep_manager_can_deep_sleep());
TEST_ASSERT_EQUAL(false, sleep_manager_can_deep_sleep_test_check());
}

TEST_ASSERT_EQUAL(true, sleep_manager_can_deep_sleep());
TEST_ASSERT_EQUAL(true, sleep_manager_can_deep_sleep_test_check());
{
// Stopping a timer after starting it allows sleep
Timer timer;
timer.start();
timer.stop();
TEST_ASSERT_EQUAL(true, sleep_manager_can_deep_sleep());
TEST_ASSERT_EQUAL(true, sleep_manager_can_deep_sleep_test_check());
}

TEST_ASSERT_EQUAL(true, sleep_manager_can_deep_sleep());
TEST_ASSERT_EQUAL(true, sleep_manager_can_deep_sleep_test_check());
{
// Starting a timer multiple times still lets you sleep
Timer timer;
timer.start();
timer.start();
}
TEST_ASSERT_EQUAL(true, sleep_manager_can_deep_sleep());
TEST_ASSERT_EQUAL(true, sleep_manager_can_deep_sleep_test_check());

TEST_ASSERT_EQUAL(true, sleep_manager_can_deep_sleep());
TEST_ASSERT_EQUAL(true, sleep_manager_can_deep_sleep_test_check());
{
// Stopping a timer multiple times still lets you sleep
Timer timer;
timer.start();
timer.stop();
timer.stop();
TEST_ASSERT_EQUAL(true, sleep_manager_can_deep_sleep());
TEST_ASSERT_EQUAL(true, sleep_manager_can_deep_sleep_test_check());
}
TEST_ASSERT_EQUAL(true, sleep_manager_can_deep_sleep());
TEST_ASSERT_EQUAL(true, sleep_manager_can_deep_sleep_test_check());
}

Case cases[] = {
Expand Down
4 changes: 2 additions & 2 deletions TESTS/mbed_drivers/timeout/timeout_tests.h
Original file line number Diff line number Diff line change
Expand Up @@ -263,7 +263,7 @@ void test_sleep(void)
timer.start();
timeout.attach_callback(mbed::callback(sem_callback, &sem), delay_us);

bool deep_sleep_allowed = sleep_manager_can_deep_sleep();
bool deep_sleep_allowed = sleep_manager_can_deep_sleep_test_check();
TEST_ASSERT_FALSE_MESSAGE(deep_sleep_allowed, "Deep sleep should be disallowed");
while (sem.wait(0) != 1) {
sleep();
Expand Down Expand Up @@ -322,7 +322,7 @@ void test_deepsleep(void)
timer.start();
timeout.attach_callback(mbed::callback(sem_callback, &sem), delay_us);

bool deep_sleep_allowed = sleep_manager_can_deep_sleep();
bool deep_sleep_allowed = sleep_manager_can_deep_sleep_test_check();
TEST_ASSERT_TRUE_MESSAGE(deep_sleep_allowed, "Deep sleep should be allowed");
while (sem.wait(0) != 1) {
sleep();
Expand Down
25 changes: 21 additions & 4 deletions TESTS/mbed_hal/common_tickers/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
#include "ticker_api_tests.h"
#include "hal/us_ticker_api.h"
#include "hal/lp_ticker_api.h"
#include "hal/mbed_lp_ticker_wrapper.h"

#ifdef __cplusplus
extern "C" {
Expand Down Expand Up @@ -496,7 +497,15 @@ utest::v1::status_t us_ticker_setup(const Case *const source, const size_t index
{
intf = get_us_ticker_data()->interface;

OS_Tick_Disable();
/* OS, common ticker and low power ticker wrapper
* may make use of us ticker so suspend them for this test */
osKernelSuspend();
#if DEVICE_LPTICKER && (LPTICKER_DELAY_TICKS > 0)
/* Suspend the lp ticker wrapper since it makes use of the us ticker */
ticker_suspend(get_lp_ticker_data());
lp_ticker_wrapper_suspend();
#endif
ticker_suspend(get_us_ticker_data());

intf->init();

Expand All @@ -515,7 +524,12 @@ utest::v1::status_t us_ticker_teardown(const Case *const source, const size_t pa

prev_irq_handler = NULL;

OS_Tick_Enable();
ticker_resume(get_us_ticker_data());
#if DEVICE_LPTICKER && (LPTICKER_DELAY_TICKS > 0)
lp_ticker_wrapper_resume();
ticker_resume(get_lp_ticker_data());
#endif
osKernelResume(0);

return greentea_case_teardown_handler(source, passed, failed, reason);
}
Expand All @@ -525,7 +539,9 @@ utest::v1::status_t lp_ticker_setup(const Case *const source, const size_t index
{
intf = get_lp_ticker_data()->interface;

OS_Tick_Disable();
/* OS and common ticker may make use of lp ticker so suspend them for this test */
osKernelSuspend();
ticker_suspend(get_lp_ticker_data());

intf->init();

Expand All @@ -544,7 +560,8 @@ utest::v1::status_t lp_ticker_teardown(const Case *const source, const size_t pa

prev_irq_handler = NULL;

OS_Tick_Enable();
ticker_resume(get_lp_ticker_data());
osKernelResume(0);

return greentea_case_teardown_handler(source, passed, failed, reason);
}
Expand Down
110 changes: 83 additions & 27 deletions TESTS/mbed_hal/common_tickers_freq/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
#include "ticker_api_test_freq.h"
#include "hal/us_ticker_api.h"
#include "hal/lp_ticker_api.h"
#include "hal/mbed_lp_ticker_wrapper.h"

#if !DEVICE_USTICKER
#error [NOT_SUPPORTED] test not supported
Expand All @@ -38,25 +39,51 @@
using namespace utest::v1;

const ticker_interface_t *intf;

static volatile unsigned int overflowCounter;
uint32_t intf_mask;
uint32_t intf_last_tick;
uint32_t intf_elapsed_ticks;
ticker_irq_handler_type prev_handler;

uint32_t ticks_to_us(uint32_t ticks, uint32_t freq)
{
return (uint32_t)((uint64_t)ticks * US_PER_S / freq);
}

void ticker_event_handler_stub(const ticker_data_t *const ticker)
void elapsed_ticks_reset()
{
if (ticker == get_us_ticker_data()) {
us_ticker_clear_interrupt();
} else {
#if DEVICE_LPTICKER
lp_ticker_clear_interrupt();
#endif
}
core_util_critical_section_enter();

const uint32_t ticker_bits = intf->get_info()->bits;

intf_mask = (1 << ticker_bits) - 1;
intf_last_tick = intf->read();
intf_elapsed_ticks = 0;

core_util_critical_section_exit();
}

overflowCounter++;
uint32_t elapsed_ticks_update()
{
core_util_critical_section_enter();

const uint32_t current_tick = intf->read();
intf_elapsed_ticks += (current_tick - intf_last_tick) & intf_mask;
intf_last_tick = current_tick;

/* Schedule next interrupt half way to overflow */
uint32_t next = (current_tick + intf_mask / 2) & intf_mask;
intf->set_interrupt(next);

uint32_t elapsed = intf_elapsed_ticks;

core_util_critical_section_exit();
return elapsed;
}

void ticker_event_handler_stub(const ticker_data_t *const ticker)
{
intf->clear_interrupt();
elapsed_ticks_update();
}

/* Test that the ticker is operating at the frequency it specifies. */
Expand All @@ -66,13 +93,13 @@ void ticker_frequency_test()
char _value[128] = { };
int expected_key = 1;
const uint32_t ticker_freq = intf->get_info()->frequency;
const uint32_t ticker_bits = intf->get_info()->bits;
const uint32_t ticker_max = (1 << ticker_bits) - 1;

intf->init();

elapsed_ticks_reset();

/* Detect overflow for tickers with lower counters width. */
intf->set_interrupt(0);
elapsed_ticks_update();

greentea_send_kv("timing_drift_check_start", 0);

Expand All @@ -82,19 +109,17 @@ void ticker_frequency_test()
expected_key = strcmp(_key, "base_time");
} while (expected_key);

overflowCounter = 0;

const uint32_t begin_ticks = intf->read();
const uint32_t begin_ticks = elapsed_ticks_update();

/* Assume that there was no overflow at this point - we are just after init. */
greentea_send_kv(_key, ticks_to_us(begin_ticks, ticker_freq));

/* Wait for 2nd signal from host. */
greentea_parse_kv(_key, _value, sizeof(_key), sizeof(_value));

const uint32_t end_ticks = intf->read();
const uint32_t end_ticks = elapsed_ticks_update();

greentea_send_kv(_key, ticks_to_us(end_ticks + overflowCounter * ticker_max, ticker_freq));
greentea_send_kv(_key, ticks_to_us(end_ticks, ticker_freq));

/* Get the results from host. */
greentea_parse_kv(_key, _value, sizeof(_key), sizeof(_value));
Expand All @@ -106,43 +131,74 @@ void ticker_frequency_test()

utest::v1::status_t us_ticker_case_setup_handler_t(const Case *const source, const size_t index_of_case)
{
#if DEVICE_LPTICKER && (LPTICKER_DELAY_TICKS > 0)
/* Suspend the lp ticker wrapper since it makes use of the us ticker */
ticker_suspend(get_lp_ticker_data());
lp_ticker_wrapper_suspend();
#endif
ticker_suspend(get_us_ticker_data());
intf = get_us_ticker_data()->interface;
set_us_ticker_irq_handler(ticker_event_handler_stub);
prev_handler = set_us_ticker_irq_handler(ticker_event_handler_stub);
return greentea_case_setup_handler(source, index_of_case);
}

utest::v1::status_t us_ticker_case_teardown_handler_t(const Case *const source, const size_t passed, const size_t failed,
const failure_t reason)
{
set_us_ticker_irq_handler(prev_handler);
ticker_resume(get_us_ticker_data());
#if DEVICE_LPTICKER && (LPTICKER_DELAY_TICKS > 0)
lp_ticker_wrapper_resume();
ticker_resume(get_lp_ticker_data());
#endif
return greentea_case_teardown_handler(source, passed, failed, reason);
}

#if DEVICE_LPTICKER
utest::v1::status_t lp_ticker_case_setup_handler_t(const Case *const source, const size_t index_of_case)
{
ticker_suspend(get_lp_ticker_data());
intf = get_lp_ticker_data()->interface;
set_lp_ticker_irq_handler(ticker_event_handler_stub);
prev_handler = set_lp_ticker_irq_handler(ticker_event_handler_stub);
return greentea_case_setup_handler(source, index_of_case);
}
#endif

utest::v1::status_t ticker_case_teardown_handler_t(const Case *const source, const size_t passed, const size_t failed,
const failure_t reason)
utest::v1::status_t lp_ticker_case_teardown_handler_t(const Case *const source, const size_t passed, const size_t failed,
const failure_t reason)
{
set_lp_ticker_irq_handler(prev_handler);
ticker_resume(get_lp_ticker_data());
return greentea_case_teardown_handler(source, passed, failed, reason);
}
#endif

// Test cases
Case cases[] = {
Case("Microsecond ticker frequency test", us_ticker_case_setup_handler_t, ticker_frequency_test,
ticker_case_teardown_handler_t),
us_ticker_case_teardown_handler_t),
#if DEVICE_LPTICKER
Case("Low power ticker frequency test", lp_ticker_case_setup_handler_t, ticker_frequency_test,
ticker_case_teardown_handler_t),
lp_ticker_case_teardown_handler_t),
#endif
};

utest::v1::status_t greentea_test_setup(const size_t number_of_cases)
{
/* Suspend RTOS Kernel so the timers are not in use. */
osKernelSuspend();

GREENTEA_SETUP(120, "timing_drift_auto");
return greentea_test_setup_handler(number_of_cases);
}

Specification specification(greentea_test_setup, cases, greentea_test_teardown_handler);
void greentea_test_teardown(const size_t passed, const size_t failed, const failure_t failure)
{
osKernelResume(0);

greentea_test_teardown_handler(passed, failed, failure);
}

Specification specification(greentea_test_setup, cases, greentea_test_teardown);

int main()
{
Expand Down
Loading

0 comments on commit e02466a

Please sign in to comment.