Skip to content
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

Fixes for tickless and LPTICKER_DELAY_TICKS #7524

Merged
merged 7 commits into from
Aug 21, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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