Skip to content

Commit 5440cc4

Browse files
authored
Merge pull request #6052 from mprse/feature-hal-spec-ticker_k64f_drivers
us/lp ticker - port K64F platform to new HAL api
2 parents 2f14057 + c74c6c7 commit 5440cc4

File tree

8 files changed

+255
-135
lines changed

8 files changed

+255
-135
lines changed

TESTS/mbed_drivers/rtc/main.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
#include "rtos.h"
2222
#include "rtc_api.h"
2323

24-
#if !DEVICE_RTC
24+
#if !DEVICE_RTC || !DEVICE_USTICKER
2525
#error [NOT_SUPPORTED] test not supported
2626
#endif
2727

TESTS/mbed_hal/lp_ticker/lp_ticker_api_tests.h

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,13 @@ void lp_ticker_info_test(void);
4444
*/
4545
void lp_ticker_deepsleep_test(void);
4646

47-
47+
/** Test that the ticker does not glitch backwards due to an incorrectly implemented ripple counter driver.
48+
*
49+
* Given ticker is available.
50+
* When ticker is enabled and counts.
51+
* Then ticker does not glitch backwards due to an incorrectly implemented ripple counter driver.
52+
*/
53+
void lp_ticker_glitch_test(void);
4854
/**@}*/
4955

5056
#ifdef __cplusplus

TESTS/mbed_hal/lp_ticker/main.cpp

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,24 @@ void lp_ticker_deepsleep_test()
8686
TEST_ASSERT_EQUAL(1, intFlag);
8787
}
8888

89+
/* Test that the ticker does not glitch backwards due to an incorrectly implemented ripple counter driver. */
90+
void lp_ticker_glitch_test()
91+
{
92+
lp_ticker_init();
93+
94+
const ticker_info_t* p_ticker_info = lp_ticker_get_info();
95+
96+
uint32_t last = lp_ticker_read();
97+
const uint32_t start = last;
98+
99+
/* Set test time to 2 sec. */
100+
while (last < (start + p_ticker_info->frequency * 2)) {
101+
const uint32_t cur = lp_ticker_read();
102+
TEST_ASSERT(cur >= last);
103+
last = cur;
104+
}
105+
}
106+
89107
utest::v1::status_t test_setup(const size_t number_of_cases)
90108
{
91109
GREENTEA_SETUP(20, "default_auto");
@@ -95,6 +113,7 @@ utest::v1::status_t test_setup(const size_t number_of_cases)
95113
Case cases[] = {
96114
Case("lp ticker info test", lp_ticker_info_test),
97115
Case("lp ticker sleep test", lp_ticker_deepsleep_test),
116+
Case("lp ticker glitch test", lp_ticker_glitch_test)
98117
};
99118

100119
Specification specification(test_setup, cases);

TESTS/mbed_hal/lp_us_tickers/main.cpp

Lines changed: 36 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,8 @@
2626
#endif
2727

2828
#define FORCE_OVERFLOW_TEST (false)
29-
#define TICKER_INT_VAL 2000
30-
#define TICKER_DELTA 50
29+
#define TICKER_INT_VAL 500
30+
#define TICKER_DELTA 10
3131

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

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

5756
core_util_critical_section_enter();
5857

@@ -133,9 +132,7 @@ void ticker_info_test(void)
133132
/* Test that ticker interrupt fires only when the ticker counter increments to the value set by ticker_set_interrupt. */
134133
void ticker_interrupt_test(void)
135134
{
136-
uint32_t ticker_timeout[] = { 100, 500, 1000, 2000 };
137-
138-
intf->init();
135+
uint32_t ticker_timeout[] = { 100, 200, 300, 500 };
139136

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

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

161158
TEST_ASSERT_EQUAL(1, intFlag);
162159

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

@@ -175,8 +172,6 @@ void ticker_past_test(void)
175172
{
176173
intFlag = 0;
177174

178-
intf->init();
179-
180175
const uint32_t tick_count = intf->read();
181176

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

196-
intf->init();
197-
198191
const uint32_t tick_count = intf->read();
199192

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

230-
intf->init();
231-
232223
intf->fire_interrupt();
233224

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

257248
intFlag = 0;
258249

259-
intf->init();
260-
261250
/* Wait for max count. */
262251
while (intf->read() != (max_count - ticker_overflow_delta)) {
263252
/* Just wait. */
@@ -296,8 +285,6 @@ void ticker_overflow_test(void)
296285
/* Test that the ticker increments by one on each tick. */
297286
void ticker_increment_test(void)
298287
{
299-
intf->init();
300-
301288
const ticker_info_t* p_ticker_info = intf->get_info();
302289

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

337-
intf->init();
338-
339324
/* ---- Test ticker_read function. ---- */
340325
timer.reset();
341326
timer.start();
@@ -391,15 +376,38 @@ void ticker_speed_test(void)
391376
TEST_ASSERT(timer.read_us() < (NUM_OF_CALLS * (MAX_FUNC_EXEC_TIME_US + DELTA_FUNC_EXEC_TIME_US)));
392377
}
393378

379+
/* Since according to the ticker requirements min acceptable counter size is
380+
* 12 bits (low power timer) for which max count is
381+
* 4095, then all test cases must be executed in this time window.
382+
* HAL ticker layer handles overflow and it is not handled in the target
383+
* ticker drivers.
384+
*/
385+
void overflow_protect()
386+
{
387+
const uint32_t ticks_now = intf->read();
388+
const ticker_info_t* p_ticker_info = intf->get_info();
389+
390+
const uint32_t max_count = (1 << p_ticker_info->bits - 1);
391+
392+
if ((max_count - ticks_now) > 4000) {
393+
return;
394+
}
395+
396+
while (intf->read() > ticks_now);
397+
}
394398

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

403+
intf->init();
404+
399405
set_us_ticker_irq_handler(ticker_event_handler_stub);
400406

401407
ticker_overflow_delta = HF_TICKER_OVERFLOW_DELTA;
402408

409+
overflow_protect();
410+
403411
return greentea_case_setup_handler(source, index_of_case);
404412
}
405413

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

419+
intf->init();
420+
411421
set_lp_ticker_irq_handler(ticker_event_handler_stub);
412422

413423
ticker_overflow_delta = LP_TICKER_OVERFLOW_DELTA;
414424

425+
overflow_protect();
426+
415427
return greentea_case_setup_handler(source, index_of_case);
416428
}
417429
#endif

hal/lp_ticker_api.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,9 @@ extern "C" {
4343
* * See the @ref hal_ticker_shared "ticker specification"
4444
* * Calling any function other than lp_ticker_init after calling lp_ticker_free
4545
*
46+
* # Potential bugs
47+
* * Glitches due to ripple counter - Verified by ::lp_ticker_glitch_test
48+
*
4649
* @see hal_lp_ticker_tests
4750
*
4851
* @{

targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_MCU_K64F/us_ticker.c

Lines changed: 62 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/* mbed Microcontroller Library
2-
* Copyright (c) 2006-2013 ARM Limited
2+
* Copyright (c) 2006-2018 ARM Limited
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -19,7 +19,16 @@
1919
#include "fsl_pit.h"
2020
#include "fsl_clock_config.h"
2121

22-
static int us_ticker_inited = 0;
22+
const ticker_info_t* us_ticker_get_info()
23+
{
24+
static const ticker_info_t info = {
25+
1000000, // 1 MHz
26+
32 // 32 bit counter
27+
};
28+
return &info;
29+
}
30+
31+
static bool us_ticker_inited = false;
2332

2433
static void pit_isr(void)
2534
{
@@ -31,72 +40,98 @@ static void pit_isr(void)
3140
us_ticker_irq_handler();
3241
}
3342

43+
/** Initialize the high frequency ticker
44+
*
45+
*/
3446
void us_ticker_init(void)
3547
{
36-
if (us_ticker_inited) {
37-
return;
38-
}
39-
us_ticker_inited = 1;
40-
//Common for ticker/timer
48+
/* Common for ticker/timer. */
4149
uint32_t busClock;
42-
// Structure to initialize PIT
50+
/* Structure to initialize PIT. */
4351
pit_config_t pitConfig;
4452

4553
PIT_GetDefaultConfig(&pitConfig);
4654
PIT_Init(PIT, &pitConfig);
4755

4856
busClock = CLOCK_GetFreq(kCLOCK_BusClk);
4957

50-
//Timer
51-
PIT_SetTimerPeriod(PIT, kPIT_Chnl_0, busClock / 1000000 - 1);
52-
PIT_SetTimerPeriod(PIT, kPIT_Chnl_1, 0xFFFFFFFF);
53-
PIT_SetTimerChainMode(PIT, kPIT_Chnl_1, true);
54-
PIT_StartTimer(PIT, kPIT_Chnl_0);
55-
PIT_StartTimer(PIT, kPIT_Chnl_1);
58+
/* Let the timer to count if re-init. */
59+
if (!us_ticker_inited) {
5660

57-
//Ticker
61+
PIT_SetTimerPeriod(PIT, kPIT_Chnl_0, busClock / 1000000 - 1);
62+
PIT_SetTimerPeriod(PIT, kPIT_Chnl_1, 0xFFFFFFFF);
63+
PIT_SetTimerChainMode(PIT, kPIT_Chnl_1, true);
64+
PIT_StartTimer(PIT, kPIT_Chnl_0);
65+
PIT_StartTimer(PIT, kPIT_Chnl_1);
66+
}
67+
68+
/* Configure interrupt generation counters and disable ticker interrupts. */
69+
PIT_StopTimer(PIT, kPIT_Chnl_3);
70+
PIT_StopTimer(PIT, kPIT_Chnl_2);
5871
PIT_SetTimerPeriod(PIT, kPIT_Chnl_2, busClock / 1000000 - 1);
5972
PIT_SetTimerChainMode(PIT, kPIT_Chnl_3, true);
60-
NVIC_SetVector(PIT3_IRQn, (uint32_t)pit_isr);
73+
NVIC_SetVector(PIT3_IRQn, (uint32_t) pit_isr);
6174
NVIC_EnableIRQ(PIT3_IRQn);
62-
}
75+
PIT_DisableInterrupts(PIT, kPIT_Chnl_3, kPIT_TimerInterruptEnable);
6376

77+
us_ticker_inited = true;
78+
}
6479

80+
/** Read the current counter
81+
*
82+
* @return The current timer's counter value in ticks
83+
*/
6584
uint32_t us_ticker_read()
6685
{
67-
if (!us_ticker_inited) {
68-
us_ticker_init();
69-
}
70-
7186
return ~(PIT_GetCurrentTimerCount(PIT, kPIT_Chnl_1));
7287
}
7388

89+
/** Disable us ticker interrupt
90+
*
91+
*/
7492
void us_ticker_disable_interrupt(void)
7593
{
7694
PIT_DisableInterrupts(PIT, kPIT_Chnl_3, kPIT_TimerInterruptEnable);
7795
}
7896

97+
/** Clear us ticker interrupt
98+
*
99+
*/
79100
void us_ticker_clear_interrupt(void)
80101
{
81102
PIT_ClearStatusFlags(PIT, kPIT_Chnl_3, PIT_TFLG_TIF_MASK);
82103
}
83104

105+
/** Set interrupt for specified timestamp
106+
*
107+
* @param timestamp The time in ticks when interrupt should be generated
108+
*/
84109
void us_ticker_set_interrupt(timestamp_t timestamp)
85110
{
86-
uint32_t now_us, delta_us;
87-
88-
now_us = us_ticker_read();
89-
delta_us = timestamp >= now_us ? timestamp - now_us : (uint32_t)((uint64_t)timestamp + 0xFFFFFFFF - now_us);
111+
/* We get here absolute interrupt time which takes into account counter overflow.
112+
* Since we use additional count-down timer to generate interrupt we need to calculate
113+
* load value based on time-stamp.
114+
*/
115+
const uint32_t now_ticks = us_ticker_read();
116+
uint32_t delta_ticks =
117+
timestamp >= now_ticks ? timestamp - now_ticks : (uint32_t)((uint64_t) timestamp + 0xFFFFFFFF - now_ticks);
118+
119+
if (delta_ticks == 0) {
120+
/* The requested delay is less than the minimum resolution of this counter. */
121+
delta_ticks = 1;
122+
}
90123

91-
uint32_t delta = timestamp - us_ticker_read();
92124
PIT_StopTimer(PIT, kPIT_Chnl_3);
93125
PIT_StopTimer(PIT, kPIT_Chnl_2);
94-
PIT_SetTimerPeriod(PIT, kPIT_Chnl_3, (uint32_t)delta_us);
126+
PIT_SetTimerPeriod(PIT, kPIT_Chnl_3, delta_ticks);
95127
PIT_EnableInterrupts(PIT, kPIT_Chnl_3, kPIT_TimerInterruptEnable);
96128
PIT_StartTimer(PIT, kPIT_Chnl_3);
97129
PIT_StartTimer(PIT, kPIT_Chnl_2);
98130
}
99131

132+
/** Fire us ticker interrupt
133+
*
134+
*/
100135
void us_ticker_fire_interrupt(void)
101136
{
102137
NVIC_SetPendingIRQ(PIT3_IRQn);

0 commit comments

Comments
 (0)