Skip to content

us/lp ticker - port K64F platform to new HAL api #6052

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

2 changes: 1 addition & 1 deletion TESTS/mbed_drivers/rtc/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
#include "rtos.h"
#include "rtc_api.h"

#if !DEVICE_RTC
#if !DEVICE_RTC || !DEVICE_USTICKER
#error [NOT_SUPPORTED] test not supported
#endif

Expand Down
8 changes: 7 additions & 1 deletion TESTS/mbed_hal/lp_ticker/lp_ticker_api_tests.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,13 @@ void lp_ticker_info_test(void);
*/
void lp_ticker_deepsleep_test(void);


/** Test that the ticker does not glitch backwards due to an incorrectly implemented ripple counter driver.
*
* Given ticker is available.
* When ticker is enabled and counts.
* Then ticker does not glitch backwards due to an incorrectly implemented ripple counter driver.
*/
void lp_ticker_glitch_test(void);
/**@}*/

#ifdef __cplusplus
Expand Down
19 changes: 19 additions & 0 deletions TESTS/mbed_hal/lp_ticker/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,24 @@ void lp_ticker_deepsleep_test()
TEST_ASSERT_EQUAL(1, intFlag);
}

/* Test that the ticker does not glitch backwards due to an incorrectly implemented ripple counter driver. */
void lp_ticker_glitch_test()
{
lp_ticker_init();

const ticker_info_t* p_ticker_info = lp_ticker_get_info();

uint32_t last = lp_ticker_read();
const uint32_t start = last;

/* Set test time to 2 sec. */
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi
This test is not protected for overflow.
Regards,

Copy link
Contributor Author

@mprse mprse Apr 9, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll try to provide fix tomorrow.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fix can be found here: PR #6584.

while (last < (start + p_ticker_info->frequency * 2)) {
const uint32_t cur = lp_ticker_read();
TEST_ASSERT(cur >= last);
last = cur;
}
}

utest::v1::status_t test_setup(const size_t number_of_cases)
{
GREENTEA_SETUP(20, "default_auto");
Expand All @@ -95,6 +113,7 @@ utest::v1::status_t test_setup(const size_t number_of_cases)
Case cases[] = {
Case("lp ticker info test", lp_ticker_info_test),
Case("lp ticker sleep test", lp_ticker_deepsleep_test),
Case("lp ticker glitch test", lp_ticker_glitch_test)
};

Specification specification(test_setup, cases);
Expand Down
60 changes: 36 additions & 24 deletions TESTS/mbed_hal/lp_us_tickers/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@
#endif

#define FORCE_OVERFLOW_TEST (false)
#define TICKER_INT_VAL 2000
#define TICKER_DELTA 50
#define TICKER_INT_VAL 500
#define TICKER_DELTA 10

#define LP_TICKER_OVERFLOW_DELTA 0 // this will allow to detect that ticker counter rollovers to 0
#define HF_TICKER_OVERFLOW_DELTA 50
Expand All @@ -49,10 +49,9 @@ unsigned int ticker_overflow_delta;

/* Auxiliary function to count ticker ticks elapsed during execution of N cycles of empty while loop.
* Parameter <step> is used to disable compiler optimisation. */
uint32_t count_ticks(volatile uint32_t cycles, uint32_t step)
uint32_t count_ticks(uint32_t cycles, uint32_t step)
{
/* Init the ticker. */
intf->init();
register uint32_t reg_cycles = cycles;

core_util_critical_section_enter();

Expand Down Expand Up @@ -133,9 +132,7 @@ void ticker_info_test(void)
/* Test that ticker interrupt fires only when the ticker counter increments to the value set by ticker_set_interrupt. */
void ticker_interrupt_test(void)
{
uint32_t ticker_timeout[] = { 100, 500, 1000, 2000 };

intf->init();
uint32_t ticker_timeout[] = { 100, 200, 300, 500 };

for (uint32_t i = 0; i < (sizeof(ticker_timeout) / sizeof(uint32_t)); i++) {
intFlag = 0;
Expand All @@ -152,17 +149,17 @@ void ticker_interrupt_test(void)
TEST_ASSERT_EQUAL_INT_MESSAGE(0, intFlag, "Interrupt fired too early");
}

/* Wait until ticker count reach value: tick_count + ticker_timeout[i].
/* Wait until ticker count reach value: tick_count + ticker_timeout[i] + TICKER_DELTA.
* Interrupt should be fired after this time. */
while (intf->read() < (tick_count + ticker_timeout[i])) {
while (intf->read() < (tick_count + ticker_timeout[i] + TICKER_DELTA)) {
/* Just wait. */
}

TEST_ASSERT_EQUAL(1, intFlag);

/* Wait until ticker count reach value: tick_count + 3 * ticker_timeout[i].
/* Wait until ticker count reach value: tick_count + 2 * ticker_timeout[i] + TICKER_DELTA.
* Interrupt should not be triggered again. */
while (intf->read() < (tick_count + 3 * ticker_timeout[i])) {
while (intf->read() < (tick_count + 2 * ticker_timeout[i] + TICKER_DELTA)) {
/* Just wait. */
}

Expand All @@ -175,8 +172,6 @@ void ticker_past_test(void)
{
intFlag = 0;

intf->init();

const uint32_t tick_count = intf->read();

/* Set interrupt tick count to value in the past.
Expand All @@ -193,8 +188,6 @@ void ticker_repeat_reschedule_test(void)
{
intFlag = 0;

intf->init();

const uint32_t tick_count = intf->read();

/* Set interrupt. Interrupt should be fired when tick count is equal to:
Expand Down Expand Up @@ -227,8 +220,6 @@ void ticker_fire_now_test(void)
{
intFlag = 0;

intf->init();

intf->fire_interrupt();

/* On some platforms set_interrupt function sets interrupt in the nearest feature. */
Expand Down Expand Up @@ -256,8 +247,6 @@ void ticker_overflow_test(void)

intFlag = 0;

intf->init();

/* Wait for max count. */
while (intf->read() != (max_count - ticker_overflow_delta)) {
/* Just wait. */
Expand Down Expand Up @@ -296,8 +285,6 @@ void ticker_overflow_test(void)
/* Test that the ticker increments by one on each tick. */
void ticker_increment_test(void)
{
intf->init();

const ticker_info_t* p_ticker_info = intf->get_info();

/* Perform test based on ticker speed. */
Expand Down Expand Up @@ -334,8 +321,6 @@ void ticker_speed_test(void)
Timer timer;
int counter = NUM_OF_CALLS;

intf->init();

/* ---- Test ticker_read function. ---- */
timer.reset();
timer.start();
Expand Down Expand Up @@ -391,15 +376,38 @@ void ticker_speed_test(void)
TEST_ASSERT(timer.read_us() < (NUM_OF_CALLS * (MAX_FUNC_EXEC_TIME_US + DELTA_FUNC_EXEC_TIME_US)));
}

/* Since according to the ticker requirements min acceptable counter size is
* 12 bits (low power timer) for which max count is
* 4095, then all test cases must be executed in this time window.
* HAL ticker layer handles overflow and it is not handled in the target
* ticker drivers.
*/
void overflow_protect()
{
const uint32_t ticks_now = intf->read();
const ticker_info_t* p_ticker_info = intf->get_info();

const uint32_t max_count = (1 << p_ticker_info->bits - 1);

if ((max_count - ticks_now) > 4000) {
return;
}

while (intf->read() > ticks_now);
}

utest::v1::status_t hf_ticker_setup(const Case *const source, const size_t index_of_case)
{
intf = get_us_ticker_data()->interface;

intf->init();

set_us_ticker_irq_handler(ticker_event_handler_stub);

ticker_overflow_delta = HF_TICKER_OVERFLOW_DELTA;

overflow_protect();

return greentea_case_setup_handler(source, index_of_case);
}

Expand All @@ -408,10 +416,14 @@ utest::v1::status_t lp_ticker_setup(const Case *const source, const size_t index
{
intf = get_lp_ticker_data()->interface;

intf->init();

set_lp_ticker_irq_handler(ticker_event_handler_stub);

ticker_overflow_delta = LP_TICKER_OVERFLOW_DELTA;

overflow_protect();

return greentea_case_setup_handler(source, index_of_case);
}
#endif
Expand Down
3 changes: 3 additions & 0 deletions hal/lp_ticker_api.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,9 @@ extern "C" {
* * See the @ref hal_ticker_shared "ticker specification"
* * Calling any function other than lp_ticker_init after calling lp_ticker_free
*
* # Potential bugs
* * Glitches due to ripple counter - Verified by ::lp_ticker_glitch_test
*
* @see hal_lp_ticker_tests
*
* @{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/* mbed Microcontroller Library
* Copyright (c) 2006-2013 ARM Limited
* Copyright (c) 2006-2018 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -19,7 +19,16 @@
#include "fsl_pit.h"
#include "fsl_clock_config.h"

static int us_ticker_inited = 0;
const ticker_info_t* us_ticker_get_info()
{
static const ticker_info_t info = {
1000000, // 1 MHz
32 // 32 bit counter
};
return &info;
}

static bool us_ticker_inited = false;

static void pit_isr(void)
{
Expand All @@ -31,72 +40,98 @@ static void pit_isr(void)
us_ticker_irq_handler();
}

/** Initialize the high frequency ticker
*
*/
void us_ticker_init(void)
{
if (us_ticker_inited) {
return;
}
us_ticker_inited = 1;
//Common for ticker/timer
/* Common for ticker/timer. */
uint32_t busClock;
// Structure to initialize PIT
/* Structure to initialize PIT. */
pit_config_t pitConfig;

PIT_GetDefaultConfig(&pitConfig);
PIT_Init(PIT, &pitConfig);

busClock = CLOCK_GetFreq(kCLOCK_BusClk);

//Timer
PIT_SetTimerPeriod(PIT, kPIT_Chnl_0, busClock / 1000000 - 1);
PIT_SetTimerPeriod(PIT, kPIT_Chnl_1, 0xFFFFFFFF);
PIT_SetTimerChainMode(PIT, kPIT_Chnl_1, true);
PIT_StartTimer(PIT, kPIT_Chnl_0);
PIT_StartTimer(PIT, kPIT_Chnl_1);
/* Let the timer to count if re-init. */
if (!us_ticker_inited) {

//Ticker
PIT_SetTimerPeriod(PIT, kPIT_Chnl_0, busClock / 1000000 - 1);
PIT_SetTimerPeriod(PIT, kPIT_Chnl_1, 0xFFFFFFFF);
PIT_SetTimerChainMode(PIT, kPIT_Chnl_1, true);
PIT_StartTimer(PIT, kPIT_Chnl_0);
PIT_StartTimer(PIT, kPIT_Chnl_1);
}

/* Configure interrupt generation counters and disable ticker interrupts. */
PIT_StopTimer(PIT, kPIT_Chnl_3);
PIT_StopTimer(PIT, kPIT_Chnl_2);
PIT_SetTimerPeriod(PIT, kPIT_Chnl_2, busClock / 1000000 - 1);
PIT_SetTimerChainMode(PIT, kPIT_Chnl_3, true);
NVIC_SetVector(PIT3_IRQn, (uint32_t)pit_isr);
NVIC_SetVector(PIT3_IRQn, (uint32_t) pit_isr);
NVIC_EnableIRQ(PIT3_IRQn);
}
PIT_DisableInterrupts(PIT, kPIT_Chnl_3, kPIT_TimerInterruptEnable);

us_ticker_inited = true;
}

/** Read the current counter
*
* @return The current timer's counter value in ticks
*/
uint32_t us_ticker_read()
{
if (!us_ticker_inited) {
us_ticker_init();
}

return ~(PIT_GetCurrentTimerCount(PIT, kPIT_Chnl_1));
}

/** Disable us ticker interrupt
*
*/
void us_ticker_disable_interrupt(void)
{
PIT_DisableInterrupts(PIT, kPIT_Chnl_3, kPIT_TimerInterruptEnable);
}

/** Clear us ticker interrupt
*
*/
void us_ticker_clear_interrupt(void)
{
PIT_ClearStatusFlags(PIT, kPIT_Chnl_3, PIT_TFLG_TIF_MASK);
}

/** Set interrupt for specified timestamp
*
* @param timestamp The time in ticks when interrupt should be generated
*/
void us_ticker_set_interrupt(timestamp_t timestamp)
{
uint32_t now_us, delta_us;

now_us = us_ticker_read();
delta_us = timestamp >= now_us ? timestamp - now_us : (uint32_t)((uint64_t)timestamp + 0xFFFFFFFF - now_us);
/* We get here absolute interrupt time which takes into account counter overflow.
* Since we use additional count-down timer to generate interrupt we need to calculate
* load value based on time-stamp.
*/
const uint32_t now_ticks = us_ticker_read();
uint32_t delta_ticks =
timestamp >= now_ticks ? timestamp - now_ticks : (uint32_t)((uint64_t) timestamp + 0xFFFFFFFF - now_ticks);

if (delta_ticks == 0) {
/* The requested delay is less than the minimum resolution of this counter. */
delta_ticks = 1;
}

uint32_t delta = timestamp - us_ticker_read();
PIT_StopTimer(PIT, kPIT_Chnl_3);
PIT_StopTimer(PIT, kPIT_Chnl_2);
PIT_SetTimerPeriod(PIT, kPIT_Chnl_3, (uint32_t)delta_us);
PIT_SetTimerPeriod(PIT, kPIT_Chnl_3, delta_ticks);
PIT_EnableInterrupts(PIT, kPIT_Chnl_3, kPIT_TimerInterruptEnable);
PIT_StartTimer(PIT, kPIT_Chnl_3);
PIT_StartTimer(PIT, kPIT_Chnl_2);
}

/** Fire us ticker interrupt
*
*/
void us_ticker_fire_interrupt(void)
{
NVIC_SetPendingIRQ(PIT3_IRQn);
Expand Down
Loading