Merge pull request #7009 from bulislaw/merge_feature_branches_for_5.9

Bring in improved HAL APIs to master
pull/7035/head
Martin Kojtal 2018-05-28 12:31:14 +02:00 committed by GitHub
commit 501a7b6949
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
155 changed files with 6129 additions and 3692 deletions

View File

@ -20,8 +20,15 @@
#include "unity.h"
#include "utest.h"
#if !DEVICE_USTICKER
#error [NOT_SUPPORTED] test not supported
#endif
using namespace utest::v1;
// Assume that tolerance is 5% of measured time.
#define DELTA(ms) (ms / 20)
// TEST_EQUEUE_SIZE was reduced below 1024B to fit this test to devices with small RAM (RAM <= 16kB)
// additionally TEST_EQUEUE_SIZE was expressed in EVENTS_EVENT_SIZE to increase readability
// (for more details about EVENTS_EVENT_SIZE see EventQueue constructor)
@ -89,7 +96,7 @@ SIMPLE_POSTS_TEST(0)
void time_func(Timer *t, int ms) {
TEST_ASSERT_INT_WITHIN(5, ms, t->read_ms());
TEST_ASSERT_INT_WITHIN(DELTA(ms), ms, t->read_ms());
t->reset();
}

View File

@ -24,6 +24,9 @@
using namespace utest::v1;
#if !DEVICE_USTICKER
#error [NOT_SUPPORTED] test not supported
#endif
// Test delay
#ifndef TEST_EVENTS_TIMING_TIME

View File

@ -0,0 +1,144 @@
"""
mbed SDK
Copyright (c) 2017-2017 ARM Limited
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
"""
from __future__ import print_function
from mbed_host_tests import BaseHostTest
from time import sleep
class RtcResetTest(BaseHostTest):
"""This test checks that a device's RTC keeps count through a reset
It does this by setting the RTC's time, triggering a reset,
delaying and then reading the RTC's time again to ensure
that the RTC is still counting.
"""
"""Start of the RTC"""
START_TIME = 50000
START_TIME_TOLERANCE = 10
"""Time to delay after sending reset"""
DELAY_TIME = 5.0
DELAY_TOLERANCE = 1.0
VALUE_PLACEHOLDER = "0"
def setup(self):
"""Register callbacks required for the test"""
self._error = False
generator = self.rtc_reset_test()
generator.next()
def run_gen(key, value, time):
"""Run the generator, and fail testing if the iterator stops"""
if self._error:
return
try:
generator.send((key, value, time))
except StopIteration:
self._error = True
for resp in ("start", "read", "ack"):
self.register_callback(resp, run_gen)
def teardown(self):
"""No work to do here"""
pass
def rtc_reset_test(self):
"""Generator for running the reset test
This function calls yield to wait for the next event from
the device. If the device gives the wrong response, then the
generator terminates by returing which raises a StopIteration
exception and fails the test.
"""
# Wait for start token
key, value, time = yield
if key != "start":
return
# Initialize, and set the time
self.send_kv("init", self.VALUE_PLACEHOLDER)
# Wait for ack from the device
key, value, time = yield
if key != "ack":
return
self.send_kv("write", str(self.START_TIME))
# Wait for ack from the device
key, value, time = yield
if key != "ack":
return
self.send_kv("read", self.VALUE_PLACEHOLDER)
key, value, time = yield
if key != "read":
return
dev_time_start = int(value)
# Unitialize, and reset
self.send_kv("free", self.VALUE_PLACEHOLDER)
# Wait for ack from the device
key, value, time = yield
if key != "ack":
return
self.send_kv("reset", self.VALUE_PLACEHOLDER)
# No ack after reset
sleep(self.DELAY_TIME)
# Restart the test, and send the sync token
self.send_kv("__sync", "00000000-0000-000000000-000000000000")
key, value, time = yield
if key != "start":
return
# Initialize, and read the time
self.send_kv("init", self.VALUE_PLACEHOLDER)
# Wait for ack from the device
key, value, time = yield
if key != "ack":
return
self.send_kv("read", self.VALUE_PLACEHOLDER)
key, value, time = yield
if key != "read":
return
dev_time_end = int(value)
# Check result
elapsed = dev_time_end - dev_time_start
start_time_valid = (self.START_TIME <= dev_time_start <
self.START_TIME + self.START_TIME_TOLERANCE)
elapsed_time_valid = elapsed >= self.DELAY_TIME - self.DELAY_TOLERANCE
passed = start_time_valid and elapsed_time_valid
if not start_time_valid:
self.log("FAIL: Expected start time of %i got %i" %
(self.START_TIME, dev_time_start))
elif not passed:
self.log("FAIL: Delayed for %fs but device "
"reported elapsed time of %fs" %
(self.DELAY_TIME, elapsed))
self.send_kv("exit", "pass" if passed else "fail")
yield # No more events expected

View File

@ -19,7 +19,7 @@
#include "unity/unity.h"
#if !DEVICE_LOWPOWERTIMER
#if !DEVICE_LPTICKER
#error [NOT_SUPPORTED] Low power ticker not supported for this target
#endif
@ -33,8 +33,9 @@ static const int test_timeout = 10;
/* Due to poor accuracy of LowPowerTicker on many platforms
there is no sense to tune tolerance value as it was in Ticker tests.
Tolerance value is set to 2000us to cover this diversity */
#define TOLERANCE_US 2000
Tolerance value is set to 600us for measurement inaccuracy + 5% tolerance
for LowPowerTicker. */
#define TOLERANCE_US(DELAY) (600 + DELAY / 20)
volatile uint32_t ticker_callback_flag;
@ -117,7 +118,7 @@ void test_multi_call_time(void)
while(!ticker_callback_flag);
time_diff = gtimer.read_us();
TEST_ASSERT_UINT32_WITHIN(TOLERANCE_US, MULTI_TICKER_TIME_MS * 1000, time_diff);
TEST_ASSERT_UINT32_WITHIN(TOLERANCE_US(MULTI_TICKER_TIME_MS * 1000), MULTI_TICKER_TIME_MS * 1000, time_diff);
}
}
@ -167,7 +168,7 @@ void test_attach_time(void)
ticker.detach();
const int time_diff = gtimer.read_us();
TEST_ASSERT_UINT64_WITHIN(TOLERANCE_US, DELAY_US, time_diff);
TEST_ASSERT_UINT64_WITHIN(TOLERANCE_US(DELAY_US), DELAY_US, time_diff);
}
/** Test single callback time via attach_us
@ -189,7 +190,7 @@ void test_attach_us_time(void)
ticker.detach();
const int time_diff = gtimer.read_us();
TEST_ASSERT_UINT64_WITHIN(TOLERANCE_US, DELAY_US, time_diff);
TEST_ASSERT_UINT64_WITHIN(TOLERANCE_US(DELAY_US), DELAY_US, time_diff);
}
// Test cases

View File

@ -14,8 +14,8 @@
* limitations under the License.
*/
#if !DEVICE_LOWPOWERTIMER
#error [NOT_SUPPORTED] Low power timer not supported for this target
#if !DEVICE_LPTICKER
#error [NOT_SUPPORTED] Low power timer not supported for this target
#endif
#include "mbed.h"

View File

@ -22,7 +22,7 @@
#include "rtos.h"
#include "hal/us_ticker_api.h"
#if !DEVICE_LOWPOWERTIMER
#if !DEVICE_LPTICKER
#error [NOT_SUPPORTED] test not supported
#endif
@ -35,39 +35,25 @@ extern uint32_t SystemCoreClock;
* timer we need to adjust delta.
*/
/* Macro to define delta based on CPU clock frequency.
/*
* Define tolerance as follows:
* tolerance = 500 us + 5% of measured time
*
* Note that some extra time is counted by the timer.
* Additional time is caused by the function calls and
* additional operations performed by wait and
* stop functions before in fact timer is stopped. This may
* add additional time to the counted result.
* e.g.
* 1 ms delay: tolerance = 550 us
* 10 ms delay: tolerance = 1000 us
* 100 ms delay: tolerance = 5500 us
* 1000 ms delay: tolerance = 50500 us
*
* To take in to account this extra time we introduce DELTA
* value based on CPU clock (speed):
* DELTA = TOLERANCE_FACTOR / SystemCoreClock * US_FACTOR
*
* e.g.
* For K64F DELTA = (80000 / 120000000) * 1000000 = 666[us]
* For NUCLEO_F070RB DELTA = (80000 / 48000000) * 1000000 = 1666[us]
* For NRF51_DK DELTA = (80000 / 16000000) * 1000000 = 5000[us]
*
* As low power timer cannot be too much accurate, this DELTA should not be more precise than 500us,
* which corresponds to a maximum CPU clock around 130MHz
*/
* */
#define US_PER_SEC 1000000
#define US_PER_MSEC 1000
#define TOLERANCE_FACTOR 80000.0f
#define US_FACTOR 1000000.0f
#define CLOCK_MAX 130000000
#define MSEC_PER_SEC 1000
static const int delta_sys_clk_us = (SystemCoreClock < CLOCK_MAX? ((int) (TOLERANCE_FACTOR / (float) SystemCoreClock * US_FACTOR)):((int) (TOLERANCE_FACTOR / (float) CLOCK_MAX * US_FACTOR)));
/* When test performs time measurement using Timer in sequence, then measurement error accumulates
* in the successive attempts. */
#define DELTA_US(i) (delta_sys_clk_us * i)
#define DELTA_S(i) ((float)delta_sys_clk_us * i / US_PER_SEC)
#define DELTA_MS(i) (1 + ( (i * delta_sys_clk_us) / US_PER_MSEC))
#define DELTA_US(delay_ms) (500 + (delay_ms) * US_PER_MSEC / 20)
#define DELTA_MS(delay_ms) (1 + ((delay_ms) * US_PER_MSEC / 20 / US_PER_MSEC))
#define DELTA_S(delay_ms) (0.000500f + (((float)(delay_ms)) / MSEC_PER_SEC / 20))
/* This test verifies if low power timer is stopped after
* creation.
@ -122,10 +108,10 @@ void test_lptimer_time_accumulation()
lp_timer.stop();
/* Check results - totally 10 ms have elapsed. */
TEST_ASSERT_FLOAT_WITHIN(DELTA_S(1), 0.010f, lp_timer.read());
TEST_ASSERT_INT32_WITHIN(DELTA_MS(1), 10, lp_timer.read_ms());
TEST_ASSERT_INT32_WITHIN(DELTA_US(1), 10000, lp_timer.read_us());
TEST_ASSERT_UINT64_WITHIN(DELTA_US(1), 10000, lp_timer.read_high_resolution_us());
TEST_ASSERT_FLOAT_WITHIN(DELTA_S(10), 0.010f, lp_timer.read());
TEST_ASSERT_INT32_WITHIN(DELTA_MS(10), 10, lp_timer.read_ms());
TEST_ASSERT_INT32_WITHIN(DELTA_US(10), 10000, lp_timer.read_us());
TEST_ASSERT_UINT64_WITHIN(DELTA_US(10), 10000, lp_timer.read_high_resolution_us());
/* Wait 50 ms - this is done to show that time elapsed when
* the timer is stopped does not have influence on the
@ -144,10 +130,10 @@ void test_lptimer_time_accumulation()
lp_timer.stop();
/* Check results - totally 30 ms have elapsed. */
TEST_ASSERT_FLOAT_WITHIN(DELTA_S(2), 0.030f, lp_timer.read());
TEST_ASSERT_INT32_WITHIN(DELTA_MS(2), 30, lp_timer.read_ms());
TEST_ASSERT_INT32_WITHIN(DELTA_US(2), 30000, lp_timer.read_us());
TEST_ASSERT_UINT64_WITHIN(DELTA_US(2), 30000, lp_timer.read_high_resolution_us());
TEST_ASSERT_FLOAT_WITHIN(DELTA_S(30), 0.030f, lp_timer.read());
TEST_ASSERT_INT32_WITHIN(DELTA_MS(30), 30, lp_timer.read_ms());
TEST_ASSERT_INT32_WITHIN(DELTA_US(30), 30000, lp_timer.read_us());
TEST_ASSERT_UINT64_WITHIN(DELTA_US(30), 30000, lp_timer.read_high_resolution_us());
/* Wait 50 ms - this is done to show that time elapsed when
* the timer is stopped does not have influence on the
@ -165,10 +151,10 @@ void test_lptimer_time_accumulation()
lp_timer.stop();
/* Check results - totally 60 ms have elapsed. */
TEST_ASSERT_FLOAT_WITHIN(DELTA_S(3), 0.060f, lp_timer.read());
TEST_ASSERT_INT32_WITHIN(DELTA_MS(3), 60, lp_timer.read_ms());
TEST_ASSERT_INT32_WITHIN(DELTA_US(3), 60000, lp_timer.read_us());
TEST_ASSERT_UINT64_WITHIN(DELTA_US(3), 60000, lp_timer.read_high_resolution_us());
TEST_ASSERT_FLOAT_WITHIN(DELTA_S(60), 0.060f, lp_timer.read());
TEST_ASSERT_INT32_WITHIN(DELTA_MS(60), 60, lp_timer.read_ms());
TEST_ASSERT_INT32_WITHIN(DELTA_US(60), 60000, lp_timer.read_us());
TEST_ASSERT_UINT64_WITHIN(DELTA_US(60), 60000, lp_timer.read_high_resolution_us());
/* Wait 50 ms - this is done to show that time elapsed when
* the timer is stopped does not have influence on the
@ -187,10 +173,10 @@ void test_lptimer_time_accumulation()
lp_timer.stop();
/* Check results - totally 1060 ms have elapsed. */
TEST_ASSERT_FLOAT_WITHIN(DELTA_S(4), 1.060f, lp_timer.read());
TEST_ASSERT_INT32_WITHIN(DELTA_MS(4), 1060, lp_timer.read_ms());
TEST_ASSERT_INT32_WITHIN(DELTA_US(4), 1060000, lp_timer.read_us());
TEST_ASSERT_UINT64_WITHIN(DELTA_US(4), 1060000, lp_timer.read_high_resolution_us());
TEST_ASSERT_FLOAT_WITHIN(DELTA_S(1060), 1.060f, lp_timer.read());
TEST_ASSERT_INT32_WITHIN(DELTA_MS(1060), 1060, lp_timer.read_ms());
TEST_ASSERT_INT32_WITHIN(DELTA_US(1060), 1060000, lp_timer.read_us());
TEST_ASSERT_UINT64_WITHIN(DELTA_US(1060), 1060000, lp_timer.read_high_resolution_us());
}
/* This test verifies if reset() function resets the
@ -216,10 +202,10 @@ void test_lptimer_reset()
lp_timer.stop();
/* Check results - totally 10 ms elapsed. */
TEST_ASSERT_FLOAT_WITHIN(DELTA_S(1), 0.010f, lp_timer.read());
TEST_ASSERT_INT32_WITHIN(DELTA_MS(1), 10, lp_timer.read_ms());
TEST_ASSERT_INT32_WITHIN(DELTA_US(1), 10000, lp_timer.read_us());
TEST_ASSERT_UINT64_WITHIN(DELTA_US(1), 10000, lp_timer.read_high_resolution_us());
TEST_ASSERT_FLOAT_WITHIN(DELTA_S(10), 0.010f, lp_timer.read());
TEST_ASSERT_INT32_WITHIN(DELTA_MS(10), 10, lp_timer.read_ms());
TEST_ASSERT_INT32_WITHIN(DELTA_US(10), 10000, lp_timer.read_us());
TEST_ASSERT_UINT64_WITHIN(DELTA_US(10), 10000, lp_timer.read_high_resolution_us());
/* Reset the timer - previous measured time should be lost now. */
lp_timer.reset();
@ -234,10 +220,10 @@ void test_lptimer_reset()
lp_timer.stop();
/* Check results - 20 ms elapsed since the reset. */
TEST_ASSERT_FLOAT_WITHIN(DELTA_S(1), 0.020f, lp_timer.read());
TEST_ASSERT_INT32_WITHIN(DELTA_MS(1), 20, lp_timer.read_ms());
TEST_ASSERT_INT32_WITHIN(DELTA_US(1), 20000, lp_timer.read_us());
TEST_ASSERT_UINT64_WITHIN(DELTA_US(1), 20000, lp_timer.read_high_resolution_us());
TEST_ASSERT_FLOAT_WITHIN(DELTA_S(20), 0.020f, lp_timer.read());
TEST_ASSERT_INT32_WITHIN(DELTA_MS(20), 20, lp_timer.read_ms());
TEST_ASSERT_INT32_WITHIN(DELTA_US(20), 20000, lp_timer.read_us());
TEST_ASSERT_UINT64_WITHIN(DELTA_US(20), 20000, lp_timer.read_high_resolution_us());
}
/* This test verifies if calling start() for already
@ -267,10 +253,10 @@ void test_lptimer_start_started_timer()
lp_timer.stop();
/* Check results - 30 ms have elapsed since the first start. */
TEST_ASSERT_FLOAT_WITHIN(DELTA_S(2), 0.030f, lp_timer.read());
TEST_ASSERT_INT32_WITHIN(DELTA_MS(2), 30, lp_timer.read_ms());
TEST_ASSERT_INT32_WITHIN(DELTA_US(2), 30000, lp_timer.read_us());
TEST_ASSERT_UINT64_WITHIN(DELTA_US(2), 30000, lp_timer.read_high_resolution_us());
TEST_ASSERT_FLOAT_WITHIN(DELTA_S(30), 0.030f, lp_timer.read());
TEST_ASSERT_INT32_WITHIN(DELTA_MS(30), 30, lp_timer.read_ms());
TEST_ASSERT_INT32_WITHIN(DELTA_US(30), 30000, lp_timer.read_us());
TEST_ASSERT_UINT64_WITHIN(DELTA_US(30), 30000, lp_timer.read_high_resolution_us());
}
/* This test verifies low power timer float operator.
@ -294,7 +280,7 @@ void test_lptimer_float_operator()
lp_timer.stop();
/* Check result - 10 ms elapsed. */
TEST_ASSERT_FLOAT_WITHIN(DELTA_S(1), 0.010f, (float )(lp_timer));
TEST_ASSERT_FLOAT_WITHIN(DELTA_S(10), 0.010f, (float )(lp_timer));
}
/* This test verifies if time counted by the low power timer is
@ -310,6 +296,8 @@ void test_lptimer_time_measurement()
{
LowPowerTimer lp_timer;
const int delta_ms = (wait_val_us / US_PER_MSEC);
/* Start the timer. */
lp_timer.start();
@ -320,10 +308,10 @@ void test_lptimer_time_measurement()
lp_timer.stop();
/* Check results - wait_val_us us have elapsed. */
TEST_ASSERT_FLOAT_WITHIN(DELTA_S(1), (float )wait_val_us / 1000000, lp_timer.read());
TEST_ASSERT_INT32_WITHIN(DELTA_MS(1), wait_val_us / 1000, lp_timer.read_ms());
TEST_ASSERT_INT32_WITHIN(DELTA_US(1), wait_val_us, lp_timer.read_us());
TEST_ASSERT_UINT64_WITHIN(DELTA_US(1), wait_val_us, lp_timer.read_high_resolution_us());
TEST_ASSERT_FLOAT_WITHIN(DELTA_S(delta_ms), (float )wait_val_us / 1000000, lp_timer.read());
TEST_ASSERT_INT32_WITHIN(DELTA_MS(delta_ms), wait_val_us / 1000, lp_timer.read_ms());
TEST_ASSERT_INT32_WITHIN(DELTA_US(delta_ms), wait_val_us, lp_timer.read_us());
TEST_ASSERT_UINT64_WITHIN(DELTA_US(delta_ms), wait_val_us, lp_timer.read_high_resolution_us());
}
utest::v1::status_t test_setup(const size_t number_of_cases)

View File

@ -26,6 +26,10 @@
#error [NOT_SUPPORTED] test not supported for single threaded enviroment
#endif
#if !DEVICE_USTICKER
#error [NOT_SUPPORTED] test not supported
#endif
using namespace utest::v1;
#define TEST_STACK_SIZE 512

View File

@ -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

View File

@ -18,6 +18,9 @@
#include "utest/utest.h"
#include "unity/unity.h"
#if !DEVICE_USTICKER
#error [NOT_SUPPORTED] test not supported
#endif
using utest::v1::Case;

View File

@ -19,6 +19,10 @@
#include "unity/unity.h"
#include "timeout_tests.h"
#if !DEVICE_USTICKER
#error [NOT_SUPPORTED] usticker not supported for this target.
#endif
using namespace utest::v1;
utest::v1::status_t greentea_failure_handler(const Case * const source, const failure_t reason)

View File

@ -276,7 +276,7 @@ void test_sleep(void)
timeout.detach();
}
#if DEVICE_LOWPOWERTIMER
#if DEVICE_LPTICKER
/** Template for tests: timeout during deepsleep
*
* Test timeout during deepsleep

View File

@ -22,39 +22,32 @@
#include "rtos.h"
#include "hal/us_ticker_api.h"
#if !DEVICE_USTICKER
#error [NOT_SUPPORTED] test not supported
#endif
using namespace utest::v1;
extern uint32_t SystemCoreClock;
/* Macro to define delta based on CPU clock frequency.
*
* Note that some extra time is counted by the timer.
* Additional time is caused by the function calls and
* additional operations performed by wait and
* stop functions before in fact timer is stopped. This may
* add additional time to the counted result.
*
* To take in to account this extra time we introduce DELTA
* value based on CPU clock (speed):
* DELTA = TOLERANCE_FACTOR / SystemCoreClock * US_FACTOR
*
* e.g.
* For K64F DELTA = (30000 / 120000000) * 1000000 = 250[us]
* For NUCLEO_F070RB DELTA = (30000 / 48000000) * 1000000 = 625[us]
* For NRF51_DK DELTA = (30000 / 16000000) * 1000000 = 1875[us]
*/
#define US_PER_SEC 1000000
#define US_PER_MSEC 1000
#define TOLERANCE_FACTOR 30000.0f
#define US_FACTOR 1000000.0f
#define MSEC_PER_SEC 1000
static const int delta_sys_clk_us = ((int) (TOLERANCE_FACTOR / (float)SystemCoreClock * US_FACTOR));
/* When test performs time measurement using Timer in sequence, then measurement error accumulates
* in the successive attempts. */
#define DELTA_US(i) (delta_sys_clk_us * i)
#define DELTA_S(i) ((float)delta_sys_clk_us * i / US_PER_SEC)
#define DELTA_MS(i) (1 + ( (i * delta_sys_clk_us) / US_PER_MSEC))
/*
* Define tolerance as follows:
* tolerance = 500 us + 2% of measured time
*
* e.g.
* 1 ms delay: tolerance = 520 us
* 10 ms delay: tolerance = 700 us
* 100 ms delay: tolerance = 2500 us
* 1000 ms delay: tolerance = 20500 us
*
* */
#define DELTA_US(delay_ms) (500 + (delay_ms) * US_PER_MSEC / 50)
#define DELTA_MS(delay_ms) (1 + ((delay_ms) * US_PER_MSEC / 50 / US_PER_MSEC))
#define DELTA_S(delay_ms) (0.000500f + (((float)(delay_ms)) / MSEC_PER_SEC / 50))
#define TICKER_FREQ_1MHZ 1000000
#define TICKER_BITS 32
@ -413,10 +406,10 @@ void test_timer_time_accumulation_os_ticker()
p_timer->stop();
/* Check results - totally 10 ms have elapsed. */
TEST_ASSERT_FLOAT_WITHIN(DELTA_S(1), 0.010f, p_timer->read());
TEST_ASSERT_INT32_WITHIN(DELTA_MS(1), 10, p_timer->read_ms());
TEST_ASSERT_INT32_WITHIN(DELTA_US(1), 10000, p_timer->read_us());
TEST_ASSERT_UINT64_WITHIN(DELTA_US(1), 10000, p_timer->read_high_resolution_us());
TEST_ASSERT_FLOAT_WITHIN(DELTA_S(10), 0.010f, p_timer->read());
TEST_ASSERT_INT32_WITHIN(DELTA_MS(10), 10, p_timer->read_ms());
TEST_ASSERT_INT32_WITHIN(DELTA_US(10), 10000, p_timer->read_us());
TEST_ASSERT_UINT64_WITHIN(DELTA_US(10), 10000, p_timer->read_high_resolution_us());
/* Wait 50 ms - this is done to show that time elapsed when
* the timer is stopped does not have influence on the
@ -435,10 +428,10 @@ void test_timer_time_accumulation_os_ticker()
p_timer->stop();
/* Check results - totally 30 ms have elapsed. */
TEST_ASSERT_FLOAT_WITHIN(DELTA_S(2), 0.030f, p_timer->read());
TEST_ASSERT_INT32_WITHIN(DELTA_MS(2), 30, p_timer->read_ms());
TEST_ASSERT_INT32_WITHIN(DELTA_US(2), 30000, p_timer->read_us());
TEST_ASSERT_UINT64_WITHIN(DELTA_US(2), 30000, p_timer->read_high_resolution_us());
TEST_ASSERT_FLOAT_WITHIN(DELTA_S(30), 0.030f, p_timer->read());
TEST_ASSERT_INT32_WITHIN(DELTA_MS(30), 30, p_timer->read_ms());
TEST_ASSERT_INT32_WITHIN(DELTA_US(30), 30000, p_timer->read_us());
TEST_ASSERT_UINT64_WITHIN(DELTA_US(30), 30000, p_timer->read_high_resolution_us());
/* Wait 50 ms - this is done to show that time elapsed when
* the timer is stopped does not have influence on the
@ -456,10 +449,10 @@ void test_timer_time_accumulation_os_ticker()
p_timer->stop();
/* Check results - totally 60 ms have elapsed. */
TEST_ASSERT_FLOAT_WITHIN(DELTA_S(3), 0.060f, p_timer->read());
TEST_ASSERT_INT32_WITHIN(DELTA_MS(3), 60, p_timer->read_ms());
TEST_ASSERT_INT32_WITHIN(DELTA_US(3), 60000, p_timer->read_us());
TEST_ASSERT_UINT64_WITHIN(DELTA_US(3), 60000, p_timer->read_high_resolution_us());
TEST_ASSERT_FLOAT_WITHIN(DELTA_S(60), 0.060f, p_timer->read());
TEST_ASSERT_INT32_WITHIN(DELTA_MS(60), 60, p_timer->read_ms());
TEST_ASSERT_INT32_WITHIN(DELTA_US(60), 60000, p_timer->read_us());
TEST_ASSERT_UINT64_WITHIN(DELTA_US(60), 60000, p_timer->read_high_resolution_us());
/* Wait 50 ms - this is done to show that time elapsed when
* the timer is stopped does not have influence on the
@ -478,10 +471,10 @@ void test_timer_time_accumulation_os_ticker()
p_timer->stop();
/* Check results - totally 1060 ms have elapsed. */
TEST_ASSERT_FLOAT_WITHIN(DELTA_S(4), 1.060f, p_timer->read());
TEST_ASSERT_INT32_WITHIN(DELTA_MS(4), 1060, p_timer->read_ms());
TEST_ASSERT_INT32_WITHIN(DELTA_US(4), 1060000, p_timer->read_us());
TEST_ASSERT_UINT64_WITHIN(DELTA_US(4), 1060000, p_timer->read_high_resolution_us());
TEST_ASSERT_FLOAT_WITHIN(DELTA_S(1060), 1.060f, p_timer->read());
TEST_ASSERT_INT32_WITHIN(DELTA_MS(1060), 1060, p_timer->read_ms());
TEST_ASSERT_INT32_WITHIN(DELTA_US(1060), 1060000, p_timer->read_us());
TEST_ASSERT_UINT64_WITHIN(DELTA_US(1060), 1060000, p_timer->read_high_resolution_us());
}
/* This test verifies if reset() function resets the timer
@ -507,10 +500,10 @@ void test_timer_reset_os_ticker()
p_timer->stop();
/* Check results - totally 10 ms elapsed. */
TEST_ASSERT_FLOAT_WITHIN(DELTA_S(1), 0.010f, p_timer->read());
TEST_ASSERT_INT32_WITHIN(DELTA_MS(1), 10, p_timer->read_ms());
TEST_ASSERT_INT32_WITHIN(DELTA_US(1), 10000, p_timer->read_us());
TEST_ASSERT_UINT64_WITHIN(DELTA_US(1), 10000, p_timer->read_high_resolution_us());
TEST_ASSERT_FLOAT_WITHIN(DELTA_S(10), 0.010f, p_timer->read());
TEST_ASSERT_INT32_WITHIN(DELTA_MS(10), 10, p_timer->read_ms());
TEST_ASSERT_INT32_WITHIN(DELTA_US(10), 10000, p_timer->read_us());
TEST_ASSERT_UINT64_WITHIN(DELTA_US(10), 10000, p_timer->read_high_resolution_us());
/* Reset the timer - previous measured time should be lost now. */
p_timer->reset();
@ -525,10 +518,10 @@ void test_timer_reset_os_ticker()
p_timer->stop();
/* Check results - 20 ms elapsed since the reset. */
TEST_ASSERT_FLOAT_WITHIN(DELTA_S(1), 0.020f, p_timer->read());
TEST_ASSERT_INT32_WITHIN(DELTA_MS(1), 20, p_timer->read_ms());
TEST_ASSERT_INT32_WITHIN(DELTA_US(1), 20000, p_timer->read_us());
TEST_ASSERT_UINT64_WITHIN(DELTA_US(1), 20000, p_timer->read_high_resolution_us());
TEST_ASSERT_FLOAT_WITHIN(DELTA_S(20), 0.020f, p_timer->read());
TEST_ASSERT_INT32_WITHIN(DELTA_MS(20), 20, p_timer->read_ms());
TEST_ASSERT_INT32_WITHIN(DELTA_US(20), 20000, p_timer->read_us());
TEST_ASSERT_UINT64_WITHIN(DELTA_US(20), 20000, p_timer->read_high_resolution_us());
}
/* This test verifies if reset() function resets the timer
@ -609,10 +602,10 @@ void test_timer_start_started_timer_os_ticker()
p_timer->stop();
/* Check results - 30 ms have elapsed since the first start. */
TEST_ASSERT_FLOAT_WITHIN(DELTA_S(2), 0.030f, p_timer->read());
TEST_ASSERT_INT32_WITHIN(DELTA_MS(2), 30, p_timer->read_ms());
TEST_ASSERT_INT32_WITHIN(DELTA_US(2), 30000, p_timer->read_us());
TEST_ASSERT_UINT64_WITHIN(DELTA_US(2), 30000, p_timer->read_high_resolution_us());
TEST_ASSERT_FLOAT_WITHIN(DELTA_S(30), 0.030f, p_timer->read());
TEST_ASSERT_INT32_WITHIN(DELTA_MS(30), 30, p_timer->read_ms());
TEST_ASSERT_INT32_WITHIN(DELTA_US(30), 30000, p_timer->read_us());
TEST_ASSERT_UINT64_WITHIN(DELTA_US(30), 30000, p_timer->read_high_resolution_us());
}
/* This test verifies if calling start() for already
@ -646,10 +639,10 @@ void test_timer_start_started_timer_user_ticker()
p_timer->stop();
/* Check results - 30 ms have elapsed since the first start. */
TEST_ASSERT_FLOAT_WITHIN(DELTA_S(2), 0.030f, p_timer->read());
TEST_ASSERT_INT32_WITHIN(DELTA_MS(2), 30, p_timer->read_ms());
TEST_ASSERT_INT32_WITHIN(DELTA_US(2), 30000, p_timer->read_us());
TEST_ASSERT_UINT64_WITHIN(DELTA_US(2), 30000, p_timer->read_high_resolution_us());
TEST_ASSERT_FLOAT_WITHIN(DELTA_S(30), 0.030f, p_timer->read());
TEST_ASSERT_INT32_WITHIN(DELTA_MS(30), 30, p_timer->read_ms());
TEST_ASSERT_INT32_WITHIN(DELTA_US(30), 30000, p_timer->read_us());
TEST_ASSERT_UINT64_WITHIN(DELTA_US(30), 30000, p_timer->read_high_resolution_us());
}
/* This test verifies Timer float operator.
@ -673,7 +666,7 @@ void test_timer_float_operator_os_ticker()
p_timer->stop();
/* Check result - 10 ms elapsed. */
TEST_ASSERT_FLOAT_WITHIN(DELTA_S(1), 0.010f, (float)(*p_timer));
TEST_ASSERT_FLOAT_WITHIN(DELTA_S(10), 0.010f, (float)(*p_timer));
}
/* This test verifies Timer float operator.
@ -728,10 +721,10 @@ void test_timer_time_measurement()
p_timer->stop();
/* Check results. */
TEST_ASSERT_FLOAT_WITHIN(DELTA_S(1), (float)wait_val_us / 1000000, p_timer->read());
TEST_ASSERT_INT32_WITHIN(DELTA_MS(1), wait_val_us / 1000, p_timer->read_ms());
TEST_ASSERT_INT32_WITHIN(DELTA_US(1), wait_val_us, p_timer->read_us());
TEST_ASSERT_UINT64_WITHIN(DELTA_US(1), wait_val_us, p_timer->read_high_resolution_us());
TEST_ASSERT_FLOAT_WITHIN(DELTA_S(wait_val_us / US_PER_MSEC), (float)wait_val_us / US_PER_SEC, p_timer->read());
TEST_ASSERT_INT32_WITHIN(DELTA_MS(wait_val_us / US_PER_MSEC), wait_val_us / US_PER_MSEC, p_timer->read_ms());
TEST_ASSERT_INT32_WITHIN(DELTA_US(wait_val_us / US_PER_MSEC), wait_val_us, p_timer->read_us());
TEST_ASSERT_UINT64_WITHIN(DELTA_US(wait_val_us / US_PER_MSEC), wait_val_us, p_timer->read_high_resolution_us());
}
utest::v1::status_t test_setup(const size_t number_of_cases) {

View File

@ -13,6 +13,10 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#if !DEVICE_USTICKER
#error [NOT_SUPPORTED] usticker not supported for this target.
#endif
#include "mbed.h"
#include "greentea-client/test_env.h"
#include "unity.h"
@ -23,7 +27,12 @@
using namespace utest::v1;
#if !DEVICE_USTICKER
#error [NOT_SUPPORTED] test not supported
#endif
#define TEST_DELAY_US 50000ULL
#define DELTA 2
class TestTimerEvent: public TimerEvent {
private:
@ -35,6 +44,8 @@ private:
public:
TestTimerEvent() :
TimerEvent(), sem(0, 1) {
sleep_manager_lock_deep_sleep();
}
TestTimerEvent(const ticker_data_t *data) :
@ -42,6 +53,7 @@ public:
}
virtual ~TestTimerEvent() {
sleep_manager_unlock_deep_sleep();
}
// Make these methods publicly accessible
@ -118,7 +130,7 @@ void test_insert(void) {
int32_t sem_slots = tte.sem_wait(0);
TEST_ASSERT_EQUAL(0, sem_slots);
sem_slots = tte.sem_wait(TEST_DELAY_US / 1000 + 1);
sem_slots = tte.sem_wait(TEST_DELAY_US / 1000 + DELTA);
TEST_ASSERT_EQUAL(1, sem_slots);
tte.remove();
@ -147,7 +159,7 @@ void test_remove(void) {
TEST_ASSERT_EQUAL(0, sem_slots);
tte.remove();
sem_slots = tte.sem_wait(TEST_DELAY_US * 2 / 1000 + 1);
sem_slots = tte.sem_wait(TEST_DELAY_US * 2 / 1000 + DELTA);
TEST_ASSERT_EQUAL(0, sem_slots);
}

View File

@ -0,0 +1,537 @@
/* mbed Microcontroller Library
* Copyright (c) 2017 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "mbed.h"
#include "greentea-client/test_env.h"
#include "unity.h"
#include "utest.h"
#include "ticker_api_tests.h"
#include "hal/us_ticker_api.h"
#include "hal/lp_ticker_api.h"
#if !DEVICE_USTICKER
#error [NOT_SUPPORTED] test not supported
#endif
#define FORCE_OVERFLOW_TEST (false)
#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 US_TICKER_OVERFLOW_DELTA 50
#define TICKER_100_TICKS 100
#define MAX_FUNC_EXEC_TIME_US 20
#define DELTA_FUNC_EXEC_TIME_US 5
#define NUM_OF_CALLS 1000
#define NUM_OF_CYCLES 100000
#define US_TICKER_OV_LIMIT 35000
#define LP_TICKER_OV_LIMIT 4000
using namespace utest::v1;
volatile int intFlag = 0;
const ticker_interface_t* intf;
ticker_irq_handler_type prev_irq_handler;
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(uint32_t cycles, uint32_t step)
{
register uint32_t reg_cycles = cycles;
const ticker_info_t* p_ticker_info = intf->get_info();
const uint32_t max_count = ((1 << p_ticker_info->bits) - 1);
core_util_critical_section_enter();
const uint32_t start = intf->read();
while (reg_cycles -= step) {
/* Just wait. */
}
const uint32_t stop = intf->read();
core_util_critical_section_exit();
/* Handle overflow - overflow protection may not work in this case. */
uint32_t diff = (start <= stop) ? (stop - start) : (uint32_t)(max_count - start + stop + 1);
return (diff);
}
/* Since according to the ticker requirements min acceptable counter size is
* - 12 bits for low power timer - max count = 4095,
* - 16 bits for high frequency timer - max count = 65535
* then all test cases must be executed in this time windows.
* HAL ticker layer handles counter overflow and it is not handled in the target
* ticker drivers. Ensure we have enough time to execute test case without overflow.
*/
void overflow_protect()
{
uint32_t time_window;
if (intf == get_us_ticker_data()->interface) {
time_window = US_TICKER_OV_LIMIT;
} else {
time_window = LP_TICKER_OV_LIMIT;
}
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) > time_window) {
return;
}
while (intf->read() > ticks_now);
}
void ticker_event_handler_stub(const ticker_data_t * const ticker)
{
if (ticker == get_us_ticker_data()) {
us_ticker_clear_interrupt();
} else {
#if DEVICE_LPTICKER
lp_ticker_clear_interrupt();
#endif
}
/* Indicate that ISR has been executed in interrupt context. */
if (IsIrqMode()) {
intFlag++;
}
}
void wait_cycles(volatile unsigned int cycles)
{
while (cycles--);
}
/* Test that ticker_init can be called multiple times and
* ticker_init allows the ticker to keep counting and disables the ticker interrupt.
*/
void ticker_init_test()
{
overflow_protect();
intFlag = 0;
intf->init();
/* Wait a while - let the ticker to count. */
wait_cycles(10000);
const uint32_t ticks_start = intf->read();
intf->set_interrupt(ticks_start + TICKER_INT_VAL);
/* Re-initialise the ticker. */
intf->init();
const uint32_t ticks_after_reinit = intf->read();
/* Wait long enough to fire ticker interrupt (should not be fired). */
while (intf->read() < (ticks_start + 2 * TICKER_INT_VAL)) {
/* Just wait. */
}
TEST_ASSERT(intf->read() >= (ticks_start + 2 * TICKER_INT_VAL));
TEST_ASSERT(ticks_start <= ticks_after_reinit);
TEST_ASSERT_EQUAL(0, intFlag);
}
/* Test that ticker frequency is non-zero and counter is at least 8 bits */
void ticker_info_test(void)
{
const ticker_info_t* p_ticker_info = intf->get_info();
TEST_ASSERT(p_ticker_info->frequency != 0);
TEST_ASSERT(p_ticker_info->bits >= 8);
}
/* 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, 200, 300, 500 };
overflow_protect();
for (uint32_t i = 0; i < (sizeof(ticker_timeout) / sizeof(uint32_t)); i++) {
intFlag = 0;
const uint32_t tick_count = intf->read();
/* Set interrupt. Interrupt should be fired when tick count is equal to:
* tick_count + ticker_timeout[i]. */
intf->set_interrupt(tick_count + ticker_timeout[i]);
/* Wait until ticker count reach value: tick_count + ticker_timeout[i] - TICKER_DELTA.
* Interrupt should not be fired. */
while (intf->read() < (tick_count + ticker_timeout[i] - TICKER_DELTA)) {
/* Indicate failure if interrupt has fired earlier. */
TEST_ASSERT_EQUAL_INT_MESSAGE(0, intFlag, "Interrupt fired too early");
}
/* 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] + TICKER_DELTA)) {
/* Just wait. */
}
TEST_ASSERT_EQUAL(1, intFlag);
/* 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 + 2 * ticker_timeout[i] + TICKER_DELTA)) {
/* Just wait. */
}
TEST_ASSERT_EQUAL(1, intFlag);
}
}
/* Test that ticker interrupt is not triggered when ticker_set_interrupt */
void ticker_past_test(void)
{
intFlag = 0;
const uint32_t tick_count = intf->read();
/* Set interrupt tick count to value in the past.
* Interrupt should not be fired. */
intf->set_interrupt(tick_count - TICKER_DELTA);
wait_cycles(1000);
TEST_ASSERT_EQUAL(0, intFlag);
}
/* Test that ticker can be rescheduled repeatedly before the handler has been called. */
void ticker_repeat_reschedule_test(void)
{
overflow_protect();
intFlag = 0;
const uint32_t tick_count = intf->read();
/* Set interrupt. Interrupt should be fired when tick count is equal to:
* tick_count + TICKER_INT_VAL. */
intf->set_interrupt(tick_count + TICKER_INT_VAL);
/* Reschedule interrupt - it should not be fired yet.
* Re-schedule interrupt. */
intf->set_interrupt(tick_count + (2 * TICKER_INT_VAL));
intf->set_interrupt(tick_count + (3 * TICKER_INT_VAL));
/* Wait until ticker count reach value: tick_count + 3*TICKER_INT_VAL - TICKER_DELTA.
* Interrupt should not be fired. */
while (intf->read() < (tick_count + 3 * TICKER_INT_VAL - TICKER_DELTA)) {
/* Indicate failure if interrupt has fired earlier. */
TEST_ASSERT_EQUAL_INT_MESSAGE(0, intFlag, "Interrupt fired too early");
}
/* Wait until ticker count reach value: tick_count + 3*TICKER_INT_VAL + TICKER_DELTA.
* Interrupt should be fired after this time. */
while (intf->read() < (tick_count + 3 * TICKER_INT_VAL + TICKER_DELTA)) {
/* Just wait. */
}
TEST_ASSERT_EQUAL(1, intFlag);
}
/* Test that ticker_fire_interrupt causes and interrupt to get fired immediately. */
void ticker_fire_now_test(void)
{
intFlag = 0;
intf->fire_interrupt();
/* On some platforms set_interrupt function sets interrupt in the nearest feature. */
wait_cycles(1000);
TEST_ASSERT_EQUAL(1, intFlag);
}
/* Test that the ticker correctly handles overflow. */
void ticker_overflow_test(void)
{
const ticker_info_t* p_ticker_info = intf->get_info();
/* We need to check how long it will take to overflow.
* We will perform this test only if this time is no longer than 30 sec.
*/
const uint32_t max_count = (1 << p_ticker_info->bits) - 1;
const uint32_t required_time_sec = (max_count / p_ticker_info->frequency);
if (required_time_sec > 30 && !FORCE_OVERFLOW_TEST) {
TEST_ASSERT_TRUE(true);
printf("Test has been skipped.\n");
return;
}
intFlag = 0;
/* Wait for max count. */
while (intf->read() != (max_count - ticker_overflow_delta)) {
/* Just wait. */
}
/* Now we are near/at the overflow point. Detect rollover. */
while (intf->read() > ticker_overflow_delta);
const uint32_t after_overflow = intf->read();
/* Now we are just after overflow. Wait a while assuming that ticker still counts. */
while (intf->read() < TICKER_100_TICKS) {
/* Just wait. */
}
const uint32_t next_after_overflow = intf->read();
/* Check that after the overflow ticker continue count. */
TEST_ASSERT(after_overflow <= ticker_overflow_delta);
TEST_ASSERT(next_after_overflow >= TICKER_100_TICKS);
TEST_ASSERT_EQUAL(0, intFlag);
const uint32_t tick_count = intf->read();
/* Check if interrupt scheduling still works. */
intf->set_interrupt(tick_count + TICKER_INT_VAL);
/* Wait for the interrupt. */
while (intf->read() < (tick_count + TICKER_INT_VAL + TICKER_DELTA)) {
/* Just wait. */
}
TEST_ASSERT_EQUAL(1, intFlag);
}
/* Test that the ticker increments by one on each tick. */
void ticker_increment_test(void)
{
const ticker_info_t* p_ticker_info = intf->get_info();
/* Perform test based on ticker speed. */
if (p_ticker_info->frequency <= 250000) { // low frequency tickers
const uint32_t base_tick_count = intf->read();
uint32_t next_tick_count = base_tick_count;
while (next_tick_count == base_tick_count) {
next_tick_count = intf->read();
}
TEST_ASSERT_UINT32_WITHIN(1, next_tick_count, base_tick_count);
} else { // high frequency tickers
uint32_t num_of_cycles = NUM_OF_CYCLES;
uint32_t base_tick_count = count_ticks(num_of_cycles, 1);
uint32_t next_tick_count = base_tick_count;
uint32_t inc_val = 0;
while (inc_val < 100) {
next_tick_count = count_ticks(num_of_cycles + inc_val, 1);
if (next_tick_count == base_tick_count) {
/* Same tick count, so increase num of cycles. */
inc_val++;
} else {
/* It is possible that the difference between base and next
* tick count on some platforms is greater that 1, in this case we need
* to repeat counting with the reduced number of cycles (for slower boards).
* In cases if difference is exactly 1 we can exit the loop.
*/
num_of_cycles /= 2;
inc_val = 0;
base_tick_count = count_ticks(num_of_cycles, 1);
if (next_tick_count - base_tick_count == 1 ||
base_tick_count - next_tick_count == 1) {
break;
}
}
}
/* Since we are here we know that next_tick_count != base_tick_count.
* The accuracy of our measurement method is +/- 1 tick, so it is possible that
* next_tick_count == base_tick_count - 1. This is also valid result.
*/
TEST_ASSERT_UINT32_WITHIN(1, next_tick_count, base_tick_count);
}
}
/* Test that common ticker functions complete with the required amount of time. */
void ticker_speed_test(void)
{
Timer timer;
int counter = NUM_OF_CALLS;
/* ---- Test ticker_read function. ---- */
timer.reset();
timer.start();
while (counter--) {
intf->read();
}
timer.stop();
TEST_ASSERT(timer.read_us() < (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();
while (counter--) {
intf->clear_interrupt();
}
timer.stop();
TEST_ASSERT(timer.read_us() < (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();
while (counter--) {
intf->set_interrupt(0);
}
timer.stop();
TEST_ASSERT(timer.read_us() < (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();
while (counter--) {
intf->fire_interrupt();
}
timer.stop();
TEST_ASSERT(timer.read_us() < (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();
while (counter--) {
intf->disable_interrupt();
}
timer.stop();
TEST_ASSERT(timer.read_us() < (NUM_OF_CALLS * (MAX_FUNC_EXEC_TIME_US + DELTA_FUNC_EXEC_TIME_US)));
}
utest::v1::status_t us_ticker_setup(const Case *const source, const size_t index_of_case)
{
intf = get_us_ticker_data()->interface;
OS_Tick_Disable();
intf->init();
prev_irq_handler = set_us_ticker_irq_handler(ticker_event_handler_stub);
ticker_overflow_delta = US_TICKER_OVERFLOW_DELTA;
return greentea_case_setup_handler(source, index_of_case);
}
utest::v1::status_t us_ticker_teardown(const Case * const source, const size_t passed, const size_t failed,
const failure_t reason)
{
set_us_ticker_irq_handler(prev_irq_handler);
prev_irq_handler = NULL;
OS_Tick_Enable();
return greentea_case_teardown_handler(source, passed, failed, reason);
}
#if DEVICE_LPTICKER
utest::v1::status_t lp_ticker_setup(const Case *const source, const size_t index_of_case)
{
intf = get_lp_ticker_data()->interface;
OS_Tick_Disable();
intf->init();
prev_irq_handler = set_lp_ticker_irq_handler(ticker_event_handler_stub);
ticker_overflow_delta = LP_TICKER_OVERFLOW_DELTA;
return greentea_case_setup_handler(source, index_of_case);
}
utest::v1::status_t lp_ticker_teardown(const Case * const source, const size_t passed, const size_t failed,
const failure_t reason)
{
set_lp_ticker_irq_handler(prev_irq_handler);
prev_irq_handler = NULL;
OS_Tick_Enable();
return greentea_case_teardown_handler(source, passed, failed, reason);
}
#endif
utest::v1::status_t test_setup(const size_t number_of_cases)
{
GREENTEA_SETUP(30, "default_auto");
return verbose_test_setup_handler(number_of_cases);
}
Case cases[] = {
Case("Microsecond ticker init is safe to call repeatedly", us_ticker_setup, ticker_init_test, us_ticker_teardown),
Case("Microsecond ticker info test", us_ticker_setup, ticker_info_test, us_ticker_teardown),
Case("Microsecond ticker interrupt test", us_ticker_setup, ticker_interrupt_test, us_ticker_teardown),
Case("Microsecond ticker past interrupt test", us_ticker_setup, ticker_past_test, us_ticker_teardown),
Case("Microsecond ticker reschedule test", us_ticker_setup, ticker_repeat_reschedule_test, us_ticker_teardown),
Case("Microsecond ticker fire interrupt", us_ticker_setup, ticker_fire_now_test, us_ticker_teardown),
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),
#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),
Case("lp ticker interrupt test", lp_ticker_setup, ticker_interrupt_test, lp_ticker_teardown),
Case("lp ticker past interrupt test", lp_ticker_setup, ticker_past_test, lp_ticker_teardown),
Case("lp ticker reschedule test", lp_ticker_setup, ticker_repeat_reschedule_test, lp_ticker_teardown),
Case("lp ticker fire interrupt", lp_ticker_setup, ticker_fire_now_test, lp_ticker_teardown),
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),
#endif
};
Specification specification(test_setup, cases);
int main()
{
return !Harness::run(specification);
}

View File

@ -0,0 +1,129 @@
/* mbed Microcontroller Library
* Copyright (c) 2017-2017 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/** \addtogroup hal_ticker_tests */
/** @{*/
#ifndef TICKER_API_TESTS_H
#define TICKER_API_TESTS_H
#include "device.h"
#ifdef __cplusplus
extern "C" {
#endif
/** Test that ticker_init can be called multiple times and
* ticker_init resets the internal count and disables the ticker interrupt.
*
* Given ticker is initialised and interrupt is set.
* When ticker is re-initialised.
* Then ticker keeps counting and disables the ticker interrupt.
*/
void ticker_init_test(void);
/** Test that ticker frequency is non-zero and counter is at least 8 bits
*
* Given ticker is available.
* When ticker information data is obtained.
* Then ticker information indicate that frequency is non-zero and counter is at least 8 bits.
*/
void ticker_info_test(void);
/** Test that the ticker increments by one on each tick.
*
* We have the following assumption for the timer clock frequency:
*
* NOTE:
* high freq ticker: 250 KHz (1 tick per 4 us) - 8 Mhz (1 tick per 1/8 us)
* low power ticker: 8 KHz (1 tick per 125 us) - 64 KHz (1 tick per ~15.6 us)
*
* Lowest CPU speed is 16 MHz (1 tick per 1/16 us).
*
* For the boards with ticker clock freq less than or equal to 250 KHz we will try to prove that ticker is incremented by one
* straightforward by reading ticker count value in the loop in order to detect a single ticker value update (hopefully by one).
* For faster tickers we need to prove this indirectly using additional count_ticks() function which returns number of
* ticks needed to perform N cycles of the empty while loop. For the same number of cycles function result should be the same with
* accuracy +/- 1 tick. After the first test we will call count_ticks again with number of cycles equal N, N+1, N+2, ...
* until we get other ticks result.
*
* Given ticker is available.
* When ticker is initialised.
* Then ticker counter is incremented by one.
*/
void ticker_increment_test(void);
/** Test that ticker interrupt fires only when the ticker counter increments to the value set by ticker_set_interrupt.
*
* Given ticker is available, initialised.
* When ticker interrupt is set.
* Then ticker interrupt fires at the valid time.
*/
void ticker_interrupt_test(void);
/** Test that ticker interrupt is not triggered when ticker_set_interrupt is called with a time from the past
*
* Given ticker is available, initialised.
* When ticker interrupt is set to the time in the past.
* Then ticker interrupt is not triggered.
*/
void ticker_past_test(void);
/** Test that ticker can be rescheduled repeatedly before the handler has been called.
*
* Given ticker is available, initialised.
* When ticker interrupt is set and then rescheduled (interrupt time is modified).
* Then ticker interrupt is triggered according the rescheduled time.
*/
void ticker_repeat_reschedule_test(void);
/** Test that ticker_fire_interrupt causes the interrupt to get fired immediately.
*
* Given ticker is available.
* When ticker_fire_interrupt is called.
* Then ticker interrupt is triggered.
*/
void ticker_fire_now_test(void);
/** Test that common ticker functions complete with the required amount of time.
*
* Given ticker is available.
* When ticker_read, ticker_clear_interrupt, ticker_set_interrupt, ticker_fire_interrupt or ticker_disable_interrupt function is called.
* Then its execution is not longer than 20 us.
*/
void ticker_speed_test(void);
/** Test that the ticker correctly handles overflow.
*
* Note that for high frequency timers we will only prove that ticker counter rollovers and
* continue counting (it is not possible to prove in deterministic way that after rollover next value is 0).
*
* Given ticker is available.
* When ticker has overflows.
* Then ticker continues counting from the beginning and interrupt scheduling works.
*/
void ticker_overflow_test(void);
/**@}*/
#ifdef __cplusplus
}
#endif
#endif
/**@}*/

View File

@ -0,0 +1,150 @@
/*
* Copyright (c) 2013-2016, ARM Limited, All Rights Reserved
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
* This is the mbed device part of the test to verify if mbed board ticker
* freqency is valid.
*/
#include "mbed.h"
#include "greentea-client/test_env.h"
#include "utest/utest.h"
#include "unity/unity.h"
#include "ticker_api_test_freq.h"
#include "hal/us_ticker_api.h"
#include "hal/lp_ticker_api.h"
#if !DEVICE_USTICKER
#error [NOT_SUPPORTED] test not supported
#endif
#define US_PER_S 1000000
using namespace utest::v1;
const ticker_interface_t* intf;
static volatile unsigned int overflowCounter;
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)
{
if (ticker == get_us_ticker_data()) {
us_ticker_clear_interrupt();
} else {
#if DEVICE_LPTICKER
lp_ticker_clear_interrupt();
#endif
}
overflowCounter++;
}
/* Test that the ticker is operating at the frequency it specifies. */
void ticker_frequency_test()
{
char _key[11] = { };
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();
/* Detect overflow for tickers with lower counters width. */
intf->set_interrupt(0);
greentea_send_kv("timing_drift_check_start", 0);
/* Wait for 1st signal from host. */
do {
greentea_parse_kv(_key, _value, sizeof(_key), sizeof(_value));
expected_key = strcmp(_key, "base_time");
} while (expected_key);
overflowCounter = 0;
const uint32_t begin_ticks = intf->read();
/* 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();
greentea_send_kv(_key, ticks_to_us(end_ticks + overflowCounter * ticker_max, ticker_freq));
/* Get the results from host. */
greentea_parse_kv(_key, _value, sizeof(_key), sizeof(_value));
TEST_ASSERT_EQUAL_STRING_MESSAGE("pass", _key,"Host side script reported a fail...");
intf->disable_interrupt();
}
utest::v1::status_t us_ticker_case_setup_handler_t(const Case * const source, const size_t index_of_case)
{
intf = get_us_ticker_data()->interface;
set_us_ticker_irq_handler(ticker_event_handler_stub);
return greentea_case_setup_handler(source, index_of_case);
}
#if DEVICE_LPTICKER
utest::v1::status_t lp_ticker_case_setup_handler_t(const Case * const source, const size_t index_of_case)
{
intf = get_lp_ticker_data()->interface;
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)
{
return greentea_case_teardown_handler(source, passed, failed, reason);
}
// Test cases
Case cases[] = {
Case("Microsecond ticker frequency test", us_ticker_case_setup_handler_t, ticker_frequency_test,
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),
#endif
};
utest::v1::status_t greentea_test_setup(const size_t number_of_cases)
{
GREENTEA_SETUP(120, "timing_drift_auto");
return greentea_test_setup_handler(number_of_cases);
}
Specification specification(greentea_test_setup, cases, greentea_test_teardown_handler);
int main()
{
Harness::run(specification);
}

View File

@ -0,0 +1,47 @@
/* mbed Microcontroller Library
* Copyright (c) 2017-2017 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/** \addtogroup hal_ticker_tests */
/** @{*/
#ifndef TICKER_API_TEST_FREQ_H
#define TICKER_API_TEST_FREQ_H
#include "device.h"
#ifdef __cplusplus
extern "C" {
#endif
/** Test that the ticker is operating at the frequency it specifies.
*
* Given ticker is available.
* When ticker specifies its frequency.
* Then the specified frequency is valid.
*/
void ticker_frequency_test(void);
/**@}*/
#ifdef __cplusplus
}
#endif
#endif
/**@}*/

View File

@ -29,12 +29,7 @@ using namespace utest::v1;
#define TEST_CYCLES 10000000
#ifdef TARGET_NRF52
/* The increased tolerance is to account for the imprecise timers on the NRF52. */
#define ALLOWED_DRIFT_PPM (1000000/50000) //5.0%
#else
#define ALLOWED_DRIFT_PPM (1000000/5000) //0.5%
#endif
/*
return values to be checked are documented at:
@ -103,16 +98,18 @@ MBED_NOINLINE
static int time_cpu_cycles(uint32_t cycles)
{
Timer timer;
core_util_critical_section_enter();
timer.start();
int timer_start = timer.read_us();
uint32_t delay = cycles;
delay_loop(delay);
int timer_end = timer.read_us();
delay_loop(cycles);
timer.stop();
return timer_end - timer_start;
core_util_critical_section_exit();
return timer.read_us();
}
void flash_init_test()

View File

@ -0,0 +1,62 @@
/* mbed Microcontroller Library
* Copyright (c) 2017-2017 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/** \addtogroup hal_lp_ticker_tests
* @{
*/
#ifndef LP_TICKER_API_TESTS_H
#define LP_TICKER_API_TESTS_H
#include "device.h"
#ifdef __cplusplus
extern "C" {
#endif
/** Test that the ticker has the correct frequency and number of bits.
*
* Given ticker is available.
* When ticker information data is obtained.
* Then collected data indicates that ticker frequency is between 4KHz and 64KHz and the counter is at least 12 bits wide.
*/
void lp_ticker_info_test(void);
/** Test that the ticker continues operating in deep sleep mode.
*
* Given ticker is available.
* When ticker has interrupt set and board enters deep-sleep mode.
* Then ticker continues operating.
*/
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
}
#endif
#endif
/**@}*/

View File

@ -1,5 +1,5 @@
/* mbed Microcontroller Library
* Copyright (c) 2016 ARM Limited
* Copyright (c) 2017 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -13,177 +13,145 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "mbed.h"
#include "greentea-client/test_env.h"
#include "unity.h"
#include "utest.h"
#include "rtos.h"
#include "lp_ticker_api_tests.h"
#include "hal/lp_ticker_api.h"
#if !DEVICE_LOWPOWERTIMER
#if !DEVICE_LPTICKER
#error [NOT_SUPPORTED] Low power timer not supported for this target
#endif
#include "utest/utest.h"
#include "unity/unity.h"
#include "greentea-client/test_env.h"
#include "mbed.h"
#include "lp_ticker_api.h"
using namespace utest::v1;
static volatile bool complete;
static volatile timestamp_t complete_time;
static ticker_event_t delay_event;
static const ticker_data_t *lp_ticker_data = get_lp_ticker_data();
static Timer timer;
static LowPowerTimer lp_timer;
volatile int intFlag = 0;
/* Timeouts are quite arbitrary due to large number of boards with varying level of accuracy */
#define LONG_TIMEOUT (100000)
#define SHORT_TIMEOUT (600)
#define TICKER_GLITCH_TEST_TICKS 1000
void cb_done(uint32_t id) {
if ((uint32_t)&delay_event == id) {
complete_time = timer.read_us();
complete = true;
} else {
// Normal ticker handling
TimerEvent::irq(id);
}
}
#define TICKER_INT_VAL 500
#define TICKER_DELTA 10
void cb_done_deepsleep(uint32_t id) {
if ((uint32_t)&delay_event == id) {
complete_time = lp_timer.read_us();
complete = true;
} else {
// Normal ticker handling
TimerEvent::irq(id);
}
}
#define LP_TICKER_OV_LIMIT 4000
void lp_ticker_delay_us(uint32_t delay_us, uint32_t tolerance)
/* Since according to the ticker requirements min acceptable counter size is
* - 12 bits for low power timer - max count = 4095,
* then all test cases must be executed in this time windows.
* HAL ticker layer handles counter overflow and it is not handled in the target
* ticker drivers. Ensure we have enough time to execute test case without overflow.
*/
void overflow_protect()
{
complete = false;
uint32_t delay_ts;
uint32_t time_window;
ticker_set_handler(lp_ticker_data, cb_done);
ticker_remove_event(lp_ticker_data, &delay_event);
delay_ts = ticker_read(lp_ticker_data) + delay_us;
time_window = LP_TICKER_OV_LIMIT;
timer.reset();
timer.start();
ticker_insert_event(lp_ticker_data, &delay_event, delay_ts, (uint32_t)&delay_event);
while (!complete);
timer.stop();
const uint32_t ticks_now = lp_ticker_read();
const ticker_info_t* p_ticker_info = lp_ticker_get_info();
TEST_ASSERT_UINT32_WITHIN(tolerance, delay_us, complete_time);
TEST_ASSERT_TRUE(complete);
const uint32_t max_count = ((1 << p_ticker_info->bits) - 1);
if ((max_count - ticks_now) > time_window) {
return;
}
while (lp_ticker_read() > ticks_now);
}
void ticker_event_handler_stub(const ticker_data_t * const ticker)
{
/* Indicate that ISR has been executed in interrupt context. */
if (IsIrqMode()) {
intFlag++;
}
/* Clear and disable ticker interrupt. */
lp_ticker_clear_interrupt();
lp_ticker_disable_interrupt();
}
void wait_cycles(volatile unsigned int cycles)
{
while (cycles--);
}
/* Test that the ticker has the correct frequency and number of bits. */
void lp_ticker_info_test()
{
const ticker_info_t* p_ticker_info = lp_ticker_get_info();
TEST_ASSERT(p_ticker_info->frequency >= 4000);
TEST_ASSERT(p_ticker_info->frequency <= 64000);
TEST_ASSERT(p_ticker_info->bits >= 12);
}
#if DEVICE_SLEEP
void lp_ticker_1s_deepsleep()
/* Test that the ticker continues operating in deep sleep mode. */
void lp_ticker_deepsleep_test()
{
complete = false;
uint32_t delay_ts;
intFlag = 0;
/*
* Since deepsleep() may shut down the UART peripheral, we wait for 10ms
* to allow for hardware serial buffers to completely flush.
set_lp_ticker_irq_handler(ticker_event_handler_stub);
* This should be replaced with a better function that checks if the
* hardware buffers are empty. However, such an API does not exist now,
* so we'll use the wait_ms() function for now.
*/
wait_ms(10);
lp_ticker_init();
ticker_set_handler(lp_ticker_data, cb_done_deepsleep);
ticker_remove_event(lp_ticker_data, &delay_event);
delay_ts = ticker_read(lp_ticker_data) + 1000000;
/* Wait for green tea UART transmission before entering deep-sleep mode. */
wait_cycles(400000);
/*
* We use here the low power timer instead of microsecond timer for start and
* end because the microseconds timer might be disable during deepsleep.
*/
lp_timer.reset();
lp_timer.start();
ticker_insert_event(lp_ticker_data, &delay_event, delay_ts, (uint32_t)&delay_event);
/* Make sure deepsleep is allowed, to go to deepsleep */
bool deep_sleep_allowed = sleep_manager_can_deep_sleep();
TEST_ASSERT_TRUE_MESSAGE(deep_sleep_allowed, "Deep sleep should be allowed");
sleep();
while (!complete);
lp_timer.stop();
overflow_protect();
TEST_ASSERT_UINT32_WITHIN(LONG_TIMEOUT, 1000000, complete_time);
TEST_ASSERT_TRUE(complete);
const uint32_t tick_count = lp_ticker_read();
/* Set interrupt. Interrupt should be fired when tick count is equal to:
* tick_count + TICKER_INT_VAL. */
lp_ticker_set_interrupt(tick_count + TICKER_INT_VAL);
TEST_ASSERT_TRUE(sleep_manager_can_deep_sleep());
while (!intFlag) {
sleep();
}
TEST_ASSERT_EQUAL(1, intFlag);
}
#endif
/* Test that the ticker does not glitch backwards due to an incorrectly implemented ripple counter driver. */
void lp_ticker_glitch_test()
{
lp_ticker_init();
overflow_protect();
uint32_t last = lp_ticker_read();
const uint32_t start = last;
while (last < (start + TICKER_GLITCH_TEST_TICKS)) {
const uint32_t cur = lp_ticker_read();
TEST_ASSERT(cur >= last);
last = cur;
}
}
void lp_ticker_1s_sleep()
utest::v1::status_t test_setup(const size_t number_of_cases)
{
complete = false;
uint32_t delay_ts;
ticker_set_handler(lp_ticker_data, cb_done);
ticker_remove_event(lp_ticker_data, &delay_event);
delay_ts = ticker_read(lp_ticker_data) + 1000000;
sleep_manager_lock_deep_sleep();
timer.reset();
timer.start();
bool deep_sleep_allowed = sleep_manager_can_deep_sleep();
TEST_ASSERT_FALSE_MESSAGE(deep_sleep_allowed, "Deep sleep should be disallowed");
ticker_insert_event(lp_ticker_data, &delay_event, delay_ts, (uint32_t)&delay_event);
sleep();
while (!complete);
timer.stop();
sleep_manager_unlock_deep_sleep();
TEST_ASSERT_UINT32_WITHIN(LONG_TIMEOUT, 1000000, complete_time);
TEST_ASSERT_TRUE(complete);
}
#endif /* DEVICE_SLEEP */
void lp_ticker_500us(void)
{
lp_ticker_delay_us(500, SHORT_TIMEOUT);
}
void lp_ticker_1ms(void)
{
lp_ticker_delay_us(1000, SHORT_TIMEOUT);
}
void lp_ticker_1s(void)
{
lp_ticker_delay_us(1000000, LONG_TIMEOUT);
}
void lp_ticker_5s(void)
{
lp_ticker_delay_us(5000000, LONG_TIMEOUT);
}
utest::v1::status_t greentea_failure_handler(const Case *const source, const failure_t reason) {
greentea_case_failure_abort_handler(source, reason);
return STATUS_CONTINUE;
GREENTEA_SETUP(20, "default_auto");
return verbose_test_setup_handler(number_of_cases);
}
Case cases[] = {
Case("500us lp_ticker", lp_ticker_500us, greentea_failure_handler),
Case("1ms lp_ticker", lp_ticker_1ms, greentea_failure_handler),
Case("1s lp_ticker", lp_ticker_1s, greentea_failure_handler),
Case("5s lp_ticker", lp_ticker_5s, greentea_failure_handler),
Case("lp ticker info test", lp_ticker_info_test),
#if DEVICE_SLEEP
Case("1s lp_ticker sleep", lp_ticker_1s_sleep, greentea_failure_handler),
Case("1s lp_ticker deepsleep", lp_ticker_1s_deepsleep, greentea_failure_handler),
#endif /* DEVICE_SLEEP */
Case("lp ticker sleep test", lp_ticker_deepsleep_test),
#endif
Case("lp ticker glitch test", lp_ticker_glitch_test)
};
utest::v1::status_t greentea_test_setup(const size_t number_of_cases) {
GREENTEA_SETUP(20, "default_auto");
lp_ticker_data->interface->init();
return greentea_test_setup_handler(number_of_cases);
}
Specification specification(test_setup, cases);
Specification specification(greentea_test_setup, cases, greentea_test_teardown_handler);
int main() {
Harness::run(specification);
int main()
{
return !Harness::run(specification);
}

View File

@ -1,110 +0,0 @@
/* mbed Microcontroller Library
* Copyright (c) 2017 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "utest/utest.h"
#include "unity/unity.h"
#include "greentea-client/test_env.h"
#include "mbed.h"
#include "us_ticker_api.h"
#include "ticker_api.h"
using namespace utest::v1;
namespace {
volatile bool complete;
const ticker_interface_t* intf;
}
/* Ticker init should be run just once, thus read should always return a value that
* increases (no reset).
*/
void test_ticker_init(void)
{
intf->init();
uint32_t previous = intf->read();
intf->init();
uint32_t current = intf->read();
TEST_ASSERT_TRUE_MESSAGE(previous <= current, "init() changed the counter");
previous = intf->read();
intf->init();
current = intf->read();
TEST_ASSERT_TRUE_MESSAGE(previous <= current, "init() changed the counter");
}
/* Read multiple times, each returned time should be bigger than the previous one
* Counter up.
*/
void test_ticker_read(void)
{
// this test assumes that to wrap around we would need to run >60 minutes
// therefore wrapping should not happen - previous <= current
const uint32_t test_loop = 15000;
uint32_t previous = intf->read();
uint32_t current;
for (uint32_t i = 0UL; i < test_loop; i++) {
current = intf->read();
TEST_ASSERT_TRUE_MESSAGE(previous <= current, "us ticker counter wrapped around");
}
}
/* Implement simple read while loop to check if time is increasing (counter up)
*/
void test_ticker_read_loop()
{
uint32_t future_time = intf->read() + 10000UL;
while (intf->read() < future_time);
TEST_ASSERT_TRUE_MESSAGE(future_time <= intf->read(), "Future time is in the past");
}
utest::v1::status_t us_ticker_setup(const Case *const source, const size_t index_of_case)
{
intf = get_us_ticker_data()->interface;
return greentea_case_setup_handler(source, index_of_case);
}
#if DEVICE_LOWPOWERTIMER
utest::v1::status_t lp_ticker_setup(const Case *const source, const size_t index_of_case)
{
intf = get_lp_ticker_data()->interface;
return greentea_case_setup_handler(source, index_of_case);
}
#endif
Case cases[] = {
Case("us ticker HAL - Init", us_ticker_setup, test_ticker_init),
Case("us ticker HAL - Read", us_ticker_setup, test_ticker_read),
Case("us ticker HAL - Read in the loop", us_ticker_setup, test_ticker_read_loop),
#if DEVICE_LOWPOWERTIMER
Case("lp ticker HAL - Init", lp_ticker_setup, test_ticker_init),
Case("lp ticker HAL - Read", lp_ticker_setup, test_ticker_read),
Case("lp ticker HAL - Read in the loop", lp_ticker_setup, test_ticker_read_loop),
#endif
};
utest::v1::status_t greentea_test_setup(const size_t number_of_cases)
{
GREENTEA_SETUP(20, "default_auto");
return greentea_test_setup_handler(number_of_cases);
}
Specification specification(greentea_test_setup, cases, greentea_test_teardown_handler);
int main()
{
Harness::run(specification);
}

258
TESTS/mbed_hal/rtc/main.cpp Normal file
View File

@ -0,0 +1,258 @@
/* mbed Microcontroller Library
* Copyright (c) 2017 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#if !DEVICE_RTC
#error [NOT_SUPPORTED] RTC API not supported for this target
#endif
#include "utest/utest.h"
#include "unity/unity.h"
#include "greentea-client/test_env.h"
#include "rtc_test.h"
#include "mbed.h"
#include "rtc_api.h"
using namespace utest::v1;
static const uint32_t WAIT_TIME = 4;
static const uint32_t WAIT_TOLERANCE = 1;
#define US_PER_SEC 1000000
#define ACCURACY_FACTOR 10
static const uint32_t DELAY_4S = 4;
static const uint32_t DELAY_10S = 10;
static const uint32_t RTC_TOLERANCE = 1;
static const uint32_t TOLERANCE_ACCURACY_US = (DELAY_10S * US_PER_SEC / ACCURACY_FACTOR);
#if DEVICE_LPTICKER
volatile bool expired;
void callback(void)
{
expired = true;
}
/* Auxiliary function to test if RTC continue counting in
* sleep and deep-sleep modes. */
void rtc_sleep_test_support (bool deepsleep_mode)
{
LowPowerTimeout timeout;
const uint32_t start = 100;
expired = false;
/*
* Since deepsleep() may shut down the UART peripheral, we wait for 10ms
* to allow for hardware serial buffers to completely flush.
* This should be replaced with a better function that checks if the
* hardware buffers are empty. However, such an API does not exist now,
* so we'll use the wait_ms() function for now.
*/
wait_ms(10);
rtc_init();
if(deepsleep_mode == false) {
sleep_manager_lock_deep_sleep();
}
rtc_write(start);
timeout.attach(callback, DELAY_4S);
TEST_ASSERT(sleep_manager_can_deep_sleep() == deepsleep_mode);
while(!expired) sleep();
const uint32_t stop = rtc_read();
TEST_ASSERT_UINT32_WITHIN(RTC_TOLERANCE, DELAY_4S, stop - start);
timeout.detach();
if(deepsleep_mode == false) {
sleep_manager_unlock_deep_sleep();
}
rtc_free();
}
#endif
/* Test that ::rtc_init can be called multiple times. */
void rtc_init_test()
{
for (int i = 0; i < 10; i++) {
rtc_init();
}
rtc_free();
}
#if DEVICE_LPTICKER
/** Test that the RTC keeps counting in the various sleep modes. */
void rtc_sleep_test()
{
/* Test sleep mode. */
rtc_sleep_test_support(false);
/* Test deep-sleep mode. */
rtc_sleep_test_support(true);
}
#endif
/* Test that the RTC keeps counting even after ::rtc_free has been called. */
void rtc_persist_test()
{
const uint32_t start = 100;
rtc_init();
rtc_write(start);
rtc_free();
wait(WAIT_TIME);
rtc_init();
const uint32_t stop = rtc_read();
const int enabled = rtc_isenabled();
rtc_free();
TEST_ASSERT_TRUE(enabled);
TEST_ASSERT_UINT32_WITHIN(WAIT_TOLERANCE, WAIT_TIME, stop - start);
}
/* Test time does not glitch backwards due to an incorrectly implemented ripple counter driver. */
void rtc_glitch_test()
{
const uint32_t start = 0xffffe;
rtc_init();
rtc_write(start);
uint32_t last = start;
while (last < start + 4) {
const uint32_t cur = rtc_read();
TEST_ASSERT(cur >= last);
last = cur;
}
rtc_free();
}
/* Test that the RTC correctly handles different time values. */
void rtc_range_test()
{
static const uint32_t starts[] = {
0x00000000,
0xEFFFFFFF,
0x00001000,
0x00010000,
};
rtc_init();
for (uint32_t i = 0; i < sizeof(starts) / sizeof(starts[0]); i++) {
const uint32_t start = starts[i];
rtc_write(start);
wait(WAIT_TIME);
const uint32_t stop = rtc_read();
TEST_ASSERT_UINT32_WITHIN(WAIT_TOLERANCE, WAIT_TIME, stop - start);
}
rtc_free();
}
/* Test that the RTC accuracy is at least 10%. */
void rtc_accuracy_test()
{
Timer timer1;
const uint32_t start = 100;
rtc_init();
rtc_write(start);
timer1.start();
while(rtc_read() < (start + DELAY_10S)) {
/* Just wait. */
}
timer1.stop();
/* RTC accuracy is at least 10%. */
TEST_ASSERT_INT32_WITHIN(TOLERANCE_ACCURACY_US, DELAY_10S * US_PER_SEC, timer1.read_us());
}
/* Test that ::rtc_write/::rtc_read functions provides availability to set/get RTC time. */
void rtc_write_read_test()
{
static const uint32_t rtc_init_val = 100;
rtc_init();
for (int i = 0; i < 3; i++) {
const uint32_t init_val = (rtc_init_val + i * rtc_init_val);
core_util_critical_section_enter();
rtc_write(init_val);
const uint32_t read_val = rtc_read();
core_util_critical_section_exit();
/* No tolerance is provided since we should have 1 second to
* execute this case after the RTC time is set.
*/
TEST_ASSERT_EQUAL_UINT32(init_val, read_val);
}
rtc_free();
}
/* Test that ::is_enabled function returns 1 if the RTC is counting and the time has been set. */
void rtc_enabled_test()
{
/* Since some platforms use RTC for low power timer RTC may be already enabled.
* Because of that we will only verify if rtc_isenabled() returns 1 in case when init is done
* and RTC time is set.
*/
rtc_init();
rtc_write(0);
TEST_ASSERT_EQUAL_INT(1, rtc_isenabled());
rtc_free();
}
Case cases[] = {
Case("RTC - init", rtc_init_test),
#if DEVICE_LPTICKER
Case("RTC - sleep", rtc_sleep_test),
#endif
Case("RTC - persist", rtc_persist_test),
Case("RTC - glitch", rtc_glitch_test),
Case("RTC - range", rtc_range_test),
Case("RTC - accuracy", rtc_accuracy_test),
Case("RTC - write/read", rtc_write_read_test),
Case("RTC - enabled", rtc_enabled_test),
};
utest::v1::status_t greentea_test_setup(const size_t number_of_cases)
{
GREENTEA_SETUP(60, "default_auto");
return greentea_test_setup_handler(number_of_cases);
}
Specification specification(greentea_test_setup, cases, greentea_test_teardown_handler);
int main()
{
Harness::run(specification);
}

View File

@ -0,0 +1,115 @@
/* mbed Microcontroller Library
* Copyright (c) 2017-2017 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/** \addtogroup hal_rtc_tests
* @{
*/
#ifndef MBED_RTC_TEST_H
#define MBED_RTC_TEST_H
#if DEVICE_RTC
#ifdef __cplusplus
extern "C" {
#endif
/** Test that ::rtc_init can be called multiple times.
*
* Given board provides RTC.
* When ::rtc_init is called multiple times.
* Then ::rtc_init are successfully performed (no exception is generated).
*
*/
void rtc_init_test(void);
/** Test that the RTC keeps counting in the various sleep modes.
*
* Given board provides RTC.
* When system enters sleep/deep-sleep mode.
* RTC keeps counting.
*
*/
void rtc_sleep_test(void);
/** Test that the RTC keeps counting even after ::rtc_free has been called.
*
* Given board provides RTC.
* When ::rtc_free has been called.
* RTC keeps counting.
*
*/
void rtc_persist_test(void);
/** Test time does not glitch backwards due to an incorrectly implemented ripple counter driver.
*
* Given board provides RTC.
* When RTC is enabled and counts.
* Then time does not glitch backwards due to an incorrectly implemented ripple counter driver.
*
*/
void rtc_glitch_test(void);
/** Test that the RTC correctly handles large time values.
*
* Given board provides RTC.
* When RTC is enabled and counts.
* The RTC correctly handles different time values.
*/
void rtc_range_test(void);
/** Test that the RTC accuracy is at least 10%.
*
* Given platform provides Real Time Clock.
* When delay is performed based on RTC (10 sec delay).
* Then the delay time measured using high frequency timer indicate that RTC accuracy is at least 10%.
*
*/
void rtc_accuracy_test(void);
/** Test that ::rtc_write/::rtc_read functions provides availability to set/get RTC time.
*
* Given platform provides Real Time Clock.
* When an example RTC time is set by means of rtc_write function and rtc_read is performed immediately after this operation.
* Then rtc_read function returns time which has been set.
*
*/
void rtc_write_read_test(void);
/** Test that ::rtc_isenabled function returns 1 if the RTC is counting and the time has been set, 0 otherwise
*
* NOTE: RTC is counting when it has been initialised by means of rtc_init().
* RTC time is set by means of rtc_write() function.
* RTC must be initialised before rtc_isenabled() function can be called.
*
* Given platform provides Real Time Clock.
* When rtc_isenabled() function is called.
* Then the result is 1 if RTC time has been set, otherwise the result is 0.
*
*/
void rtc_enabled_test(void);
/**@}*/
#ifdef __cplusplus
}
#endif
#endif
#endif
/** @}*/

View File

@ -0,0 +1,102 @@
/* mbed Microcontroller Library
* Copyright (c) 2017 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#if !DEVICE_RTC
#error [NOT_SUPPORTED] RTC API not supported for this target
#endif
#include "utest/utest.h"
#include "unity/unity.h"
#include "greentea-client/test_env.h"
#include "rtc_reset_test.h"
#include "mbed.h"
#include "rtc_api.h"
typedef enum {
CMD_STATUS_PASS,
CMD_STATUS_FAIL,
CMD_STATUS_CONTINUE,
CMD_STATUS_ERROR
} cmd_status_t;
static cmd_status_t handle_command(const char *key, const char *value)
{
if (strcmp(key, "init") == 0) {
rtc_init();
greentea_send_kv("ack", 0);
return CMD_STATUS_CONTINUE;
} else if (strcmp(key, "free") == 0) {
rtc_free();
greentea_send_kv("ack", 0);
return CMD_STATUS_CONTINUE;
} else if (strcmp(key, "read") == 0) {
static char time_buf[64];
memset(time_buf, 0, sizeof(time_buf));
sprintf(time_buf, "%lu", (uint32_t)rtc_read());
greentea_send_kv("read", time_buf);
return CMD_STATUS_CONTINUE;
} else if (strcmp(key, "write") == 0) {
uint32_t time;
sscanf(value, "%lu", &time);
rtc_write(time);
greentea_send_kv("ack", 0);
return CMD_STATUS_CONTINUE;
} else if (strcmp(key, "reset") == 0) {
NVIC_SystemReset();
// Code shouldn't read this due to the reset
return CMD_STATUS_ERROR;
} else if (strcmp(key, "exit") == 0) {
return strcmp(value, "pass") == 0 ? CMD_STATUS_PASS : CMD_STATUS_FAIL;
} else {
return CMD_STATUS_ERROR;
}
}
/* Test that software reset doesn't stop RTC from counting. */
void rtc_reset_test()
{
GREENTEA_SETUP(100, "rtc_reset");
static char _key[10 + 1] = {};
static char _value[128 + 1] = {};
greentea_send_kv("start", 1);
// Handshake with host
cmd_status_t cmd_status = CMD_STATUS_CONTINUE;
while (CMD_STATUS_CONTINUE == cmd_status) {
memset(_key, 0, sizeof(_key));
memset(_value, 0, sizeof(_value));
greentea_parse_kv(_key, _value, sizeof(_key) - 1, sizeof(_value) - 1);
cmd_status = handle_command(_key, _value);
}
GREENTEA_TESTSUITE_RESULT(CMD_STATUS_PASS == cmd_status);
}
int main()
{
rtc_reset_test();
}

View File

@ -0,0 +1,49 @@
/* mbed Microcontroller Library
* Copyright (c) 2017-2017 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/** \addtogroup hal_rtc_tests
* @{
*/
#ifndef MBED_RTC_TEST_H
#define MBED_RTC_TEST_H
#if DEVICE_RTC
#ifdef __cplusplus
extern "C" {
#endif
/** Test that the RTC does not stop counting after a software reset.
*
* Given board provides RTC.
* When software reset is performed.
* Then the RTC does not stop counting.
*
*/
void rtc_reset_test();
/**@}*/
#ifdef __cplusplus
}
#endif
#endif
#endif
/** @}*/

View File

@ -0,0 +1,246 @@
/* mbed Microcontroller Library
* Copyright (c) 2017 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#if 1 || !DEVICE_SLEEP
#error [NOT_SUPPORTED] sleep not supported for this target
#endif
#include "mbed.h"
#include "utest/utest.h"
#include "unity/unity.h"
#include "greentea-client/test_env.h"
#include "sleep_api_tests.h"
#define US_PER_S 1000000
using namespace utest::v1;
/* The following ticker frequencies are possible:
* high frequency ticker: 250 KHz (1 tick per 4 us) - 8 Mhz (1 tick per 1/8 us)
* low power ticker: 8 KHz (1 tick per 125 us) - 64 KHz (1 tick per ~15.6 us)
*/
/* Used for regular sleep mode, a target should be awake within 10 us. Define us delta value as follows:
* delta = default 10 us + worst ticker resolution + extra time for code execution */
static const uint32_t sleep_mode_delta_us = (10 + 4 + 5);
/* Used for deep-sleep mode, a target should be awake within 10 ms. Define us delta value as follows:
* delta = default 10 ms + worst ticker resolution + extra time for code execution */
static const uint32_t deepsleep_mode_delta_us = (10000 + 125 + 5);
unsigned int ticks_to_us(unsigned int ticks, unsigned int freq)
{
return (unsigned int) ((unsigned long long) ticks * US_PER_S / freq);
}
unsigned int us_to_ticks(unsigned int us, unsigned int freq)
{
return (unsigned int) ((unsigned long long) us * freq / US_PER_S);
}
unsigned int overflow_protect(unsigned int timestamp, unsigned int ticker_width)
{
unsigned int counter_mask = ((1 << ticker_width) - 1);
return (timestamp & counter_mask);
}
bool compare_timestamps(unsigned int delta_ticks, unsigned int ticker_width, unsigned int expected, unsigned int actual)
{
const unsigned int counter_mask = ((1 << ticker_width) - 1);
const unsigned int lower_bound = ((expected - delta_ticks) & counter_mask);
const unsigned int upper_bound = ((expected + delta_ticks) & counter_mask);
if (lower_bound < upper_bound) {
if (actual >= lower_bound && actual <= upper_bound) {
return true;
} else {
return false;
}
} else {
if ((actual >= lower_bound && actual <= counter_mask) || (actual >= 0 && actual <= upper_bound)) {
return true;
} else {
return false;
}
}
}
void us_ticker_isr(const ticker_data_t * const ticker_data)
{
us_ticker_clear_interrupt();
}
#ifdef DEVICE_LPTICKER
void lp_ticker_isr(const ticker_data_t *const ticker_data)
{
lp_ticker_clear_interrupt();
}
#endif
/* Test that wake-up time from sleep should be less than 10 us and
* high frequency ticker interrupt can wake-up target from sleep. */
void sleep_usticker_test()
{
#if 0
const ticker_data_t * ticker = get_us_ticker_data();
const unsigned int ticker_freq = ticker->interface->get_info()->frequency;
const unsigned int ticker_width = ticker->interface->get_info()->bits;
const ticker_irq_handler_type us_ticker_irq_handler_org = set_us_ticker_irq_handler(us_ticker_isr);
/* Test only sleep functionality. */
sleep_manager_lock_deep_sleep();
TEST_ASSERT_FALSE_MESSAGE(sleep_manager_can_deep_sleep(), "deep sleep should be locked");
/* Testing wake-up time 10 us. */
for (timestamp_t i = 100; i < 1000; i += 100) {
/* note: us_ticker_read() operates on ticks. */
const timestamp_t next_match_timestamp = overflow_protect(us_ticker_read() + us_to_ticks(i, ticker_freq),
ticker_width);
us_ticker_set_interrupt(next_match_timestamp);
sleep();
const unsigned int wakeup_timestamp = us_ticker_read();
TEST_ASSERT(
compare_timestamps(us_to_ticks(sleep_mode_delta_us, ticker_freq), ticker_width, next_match_timestamp,
wakeup_timestamp));
}
set_us_ticker_irq_handler(us_ticker_irq_handler_org);
sleep_manager_unlock_deep_sleep();
TEST_ASSERT_TRUE(sleep_manager_can_deep_sleep());
#endif
}
#ifdef DEVICE_LPTICKER
/* Test that wake-up time from sleep should be less than 10 ms and
* low power ticker interrupt can wake-up target from sleep. */
void deepsleep_lpticker_test()
{
const ticker_data_t * ticker = get_lp_ticker_data();
const unsigned int ticker_freq = ticker->interface->get_info()->frequency;
const unsigned int ticker_width = ticker->interface->get_info()->bits;
const ticker_irq_handler_type lp_ticker_irq_handler_org = set_lp_ticker_irq_handler(lp_ticker_isr);
/* Give some time Green Tea to finish UART transmission before entering
* deep-sleep mode.
*/
wait_ms(10);
TEST_ASSERT_TRUE_MESSAGE(sleep_manager_can_deep_sleep(), "deep sleep should not be locked");
/* Testing wake-up time 10 ms. */
for (timestamp_t i = 20000; i < 200000; i += 20000) {
/* note: lp_ticker_read() operates on ticks. */
const timestamp_t next_match_timestamp = overflow_protect(lp_ticker_read() + us_to_ticks(i, ticker_freq), ticker_width);
lp_ticker_set_interrupt(next_match_timestamp);
sleep();
const timestamp_t wakeup_timestamp = lp_ticker_read();
TEST_ASSERT(compare_timestamps(us_to_ticks(deepsleep_mode_delta_us, ticker_freq), ticker_width, next_match_timestamp, wakeup_timestamp));
}
set_lp_ticker_irq_handler(lp_ticker_irq_handler_org);
}
void deepsleep_high_speed_clocks_turned_off_test()
{
const ticker_data_t * us_ticker = get_us_ticker_data();
const ticker_data_t * lp_ticker = get_lp_ticker_data();
const unsigned int us_ticker_freq = us_ticker->interface->get_info()->frequency;
const unsigned int lp_ticker_freq = lp_ticker->interface->get_info()->frequency;
const unsigned int us_ticker_width = us_ticker->interface->get_info()->bits;
const unsigned int lp_ticker_width = lp_ticker->interface->get_info()->bits;
const unsigned int us_ticker_mask = ((1 << us_ticker_width) - 1);
/* Give some time Green Tea to finish UART transmission before entering
* deep-sleep mode.
*/
wait_ms(10);
TEST_ASSERT_TRUE_MESSAGE(sleep_manager_can_deep_sleep(), "deep sleep should not be locked");
const unsigned int us_ticks_before_sleep = us_ticker_read();
const timestamp_t wakeup_time = lp_ticker_read() + us_to_ticks(20000, lp_ticker_freq);
lp_ticker_set_interrupt(wakeup_time);
sleep();
const unsigned int us_ticks_after_sleep = us_ticker_read();
const unsigned int lp_ticks_after_sleep = lp_ticker_read();
/* High freqency ticker should be disabled in deep-sleep mode. We expect that time difference between
* ticker reads before and after the sleep represents only code execution time between calls.
* Since we went to sleep for about 20 ms check if time counted by high frequency timer does not
* exceed 1 ms.
*/
const unsigned int us_ticks_diff = (us_ticks_before_sleep <= us_ticks_after_sleep) ? (us_ticks_after_sleep - us_ticks_before_sleep) : (us_ticker_mask - us_ticks_before_sleep + us_ticks_after_sleep + 1);
TEST_ASSERT_UINT32_WITHIN(1000, 0, ticks_to_us(us_ticks_diff, us_ticker_freq));
/* Check if we have woken-up after expected time. */
TEST_ASSERT(compare_timestamps(us_to_ticks(deepsleep_mode_delta_us, lp_ticker_freq), lp_ticker_width, wakeup_time, lp_ticks_after_sleep));
}
#endif
utest::v1::status_t greentea_failure_handler(const Case * const source, const failure_t reason)
{
greentea_case_failure_abort_handler(source, reason);
return STATUS_CONTINUE;
}
utest::v1::status_t greentea_test_setup(const size_t number_of_cases)
{
GREENTEA_SETUP(60, "default_auto");
us_ticker_init();
#if DEVICE_LPTICKER
lp_ticker_init();
#endif
/* Suspend RTOS Kernel to enable sleep modes. */
osKernelSuspend();
return greentea_test_setup_handler(number_of_cases);
}
Case cases[] =
{ Case("sleep - source of wake-up - us ticker", sleep_usticker_test, greentea_failure_handler),
#if DEVICE_LPTICKER
Case("deep-sleep - source of wake-up - lp ticker",deepsleep_lpticker_test, greentea_failure_handler),
Case("deep-sleep - high-speed clocks are turned off",deepsleep_high_speed_clocks_turned_off_test, greentea_failure_handler),
#endif
};
Specification specification(greentea_test_setup, cases, greentea_test_teardown_handler);
int main()
{
Harness::run(specification);
}

View File

@ -0,0 +1,69 @@
/* mbed Microcontroller Library
* Copyright (c) 2017 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/** \addtogroup hal_sleep_tests */
/** @{*/
#ifndef MBED_SLEEP_API_TESTS_H
#define MBED_SLEEP_API_TESTS_H
#include "device.h"
#if DEVICE_SLEEP
#ifdef __cplusplus
extern "C" {
#endif
/** High frequency ticker interrupt can wake up from sleep (locked deep-sleep).
*
* Given is an environment with high frequency ticker.
* When the board enters sleep mode.
* Then the board can be wake up from the sleep by high frequency ticker interrupt and
* wake-up time should be less than 10 us.
*/
void sleep_usticker_test();
/** Low power ticker interrupt to wake up from deep-sleep (unlocked deep-sleep).
*
* Given is an environment with low power ticker.
* When the board enters deep-sleep mode.
* Then the board can be wake up from the sleep by low power ticker interrupt and
* wake-up time should be less than 10 ms.
*
*/
void deepsleep_lpticker_test();
/** High speed clocks are turned off in deep-sleep (unlocked deep-sleep)
*
* Given is an environment with high frequency ticker.
* When the board enters deep-sleep mode.
* Then high frequency ticker does not count while the board is in the deep-sleep mode.
*
*/
void deepsleep_high_speed_clocks_turned_off_test();
/**@}*/
#ifdef __cplusplus
}
#endif
#endif
#endif
/**@}*/

View File

@ -22,6 +22,10 @@
#error [NOT_SUPPORTED] test not supported
#endif
#if !DEVICE_USTICKER
#error [NOT_SUPPORTED] test not supported
#endif
using namespace utest::v1;
#define TEST_STACK_SIZE 256

View File

@ -0,0 +1,54 @@
/* mbed Microcontroller Library
* Copyright (c) 2017 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "mbed.h"
#include "greentea-client/test_env.h"
#include "unity.h"
#include "utest.h"
#include "us_ticker_api_tests.h"
#include "hal/us_ticker_api.h"
#if !DEVICE_USTICKER
#error [NOT_SUPPORTED] test not supported
#endif
using namespace utest::v1;
/* Test that the ticker has the correct frequency and number of bits. */
void us_ticker_info_test()
{
const ticker_info_t* p_ticker_info = us_ticker_get_info();
TEST_ASSERT(p_ticker_info->frequency >= 250000);
TEST_ASSERT(p_ticker_info->frequency <= 8000000);
TEST_ASSERT(p_ticker_info->bits >= 16);
}
utest::v1::status_t test_setup(const size_t number_of_cases)
{
GREENTEA_SETUP(20, "default_auto");
return verbose_test_setup_handler(number_of_cases);
}
Case cases[] = {
Case("us ticker info test", us_ticker_info_test),
};
Specification specification(test_setup, cases);
int main()
{
return !Harness::run(specification);
}

View File

@ -0,0 +1,47 @@
/* mbed Microcontroller Library
* Copyright (c) 2017-2017 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/** \addtogroup hal_us_ticker_tests */
/** @{*/
#ifndef US_TICKER_API_TESTS_H
#define US_TICKER_API_TESTS_H
#include "device.h"
#ifdef __cplusplus
extern "C" {
#endif
/** Test that the ticker has the correct frequency and number of bits.
*
* Given ticker is available.
* When ticker information data is obtained.
* Then ticker information indicate that frequency between 250KHz and 8MHz and the counter is at least 16 bits wide.
*/
void us_ticker_info_test(void);
/**@}*/
#ifdef __cplusplus
}
#endif
#endif
/**@}*/

View File

@ -21,7 +21,7 @@
#include "mbed.h"
#if !defined(MBED_CPU_STATS_ENABLED) || !defined(DEVICE_LOWPOWERTIMER) || !defined(DEVICE_SLEEP)
#if !defined(MBED_CPU_STATS_ENABLED) || !defined(DEVICE_LPTICKER) || !defined(DEVICE_SLEEP)
#error [NOT_SUPPORTED] test not supported
#endif

View File

@ -23,6 +23,10 @@
#error [NOT_SUPPORTED] test not supported
#endif
#if !DEVICE_USTICKER
#error [NOT_SUPPORTED] test not supported
#endif
using utest::v1::Case;
#define TEST_STACK_SIZE 256

View File

@ -23,6 +23,10 @@
#error [NOT_SUPPORTED] test not supported
#endif
#if !DEVICE_USTICKER
#error [NOT_SUPPORTED] test not supported
#endif
using namespace utest::v1;
#define TEST_STACK_SIZE 512

View File

@ -26,6 +26,10 @@ using utest::v1::Case;
#error [NOT_SUPPORTED] test not supported
#endif
#if !DEVICE_USTICKER
#error [NOT_SUPPORTED] test not supported
#endif
#define THREAD_STACK_SIZE 320 /* 512B stack on GCC_ARM compiler cause out of memory on some 16kB RAM boards e.g. NUCLEO_F070RB */
#define MAX_FLAG_POS 30

View File

@ -16,7 +16,11 @@
*/
#if defined(TARGET_CORTEX_A)
#error [NOT_SUPPORTED] This function not supported for this target
#error [NOT_SUPPORTED] This function not supported for this target
#endif
#if !DEVICE_USTICKER
#error [NOT_SUPPORTED] test not supported
#endif
#include <stdio.h>

View File

@ -23,6 +23,10 @@
#error [NOT_SUPPORTED] test not supported
#endif
#if !DEVICE_USTICKER
#error [NOT_SUPPORTED] test not supported
#endif
using namespace utest::v1;
#define THREAD_STACK_SIZE 320 /* larger stack cause out of heap memory on some 16kB RAM boards in multi thread test*/

View File

@ -23,6 +23,10 @@
#error [NOT_SUPPORTED] test not supported
#endif
#if !DEVICE_USTICKER
#error [NOT_SUPPORTED] test not supported
#endif
using utest::v1::Case;
extern uint32_t mbed_heap_size;

View File

@ -23,6 +23,10 @@
#error [NOT_SUPPORTED] test not supported
#endif
#if !DEVICE_USTICKER
#error [NOT_SUPPORTED] test not supported
#endif
using namespace utest::v1;
#define TEST_STACK_SIZE 512

View File

@ -23,6 +23,10 @@
#error [NOT_SUPPORTED] test not supported
#endif
#if !DEVICE_USTICKER
#error [NOT_SUPPORTED] test not supported
#endif
using namespace utest::v1;
#define THREAD_STACK_SIZE 512

View File

@ -30,6 +30,10 @@ using namespace utest::v1;
#error invalid RESTART_DELAY_MS value
#endif
#if !DEVICE_USTICKER
#error [NOT_SUPPORTED] test not supported
#endif
class Stopwatch: public Timer {
private:
Semaphore _sem;

View File

@ -25,6 +25,10 @@ using namespace utest::v1;
#error [NOT_SUPPORTED] test not supported
#endif
#if !DEVICE_USTICKER
#error [NOT_SUPPORTED] test not supported
#endif
#define THREAD_DELAY 30
#define SEMAPHORE_SLOTS 2
#define SEM_CHANGES 100

View File

@ -20,11 +20,14 @@
using utest::v1::Case;
#if defined(MBED_RTOS_SINGLE_THREAD)
#error [NOT_SUPPORTED] test not supported
#endif
#if !DEVICE_USTICKER
#error [NOT_SUPPORTED] test not supported
#endif
#define TEST_STACK_SIZE 512
#define MAX_FLAG_POS 30

View File

@ -17,7 +17,7 @@
#error [NOT_SUPPORTED] Tickless mode not supported for this target.
#endif
#if !DEVICE_LOWPOWERTIMER
#if !DEVICE_LPTICKER
#error [NOT_SUPPORTED] Current SysTimer implementation requires lp ticker support.
#endif
@ -251,6 +251,7 @@ void test_handler_called_once(void)
TEST_ASSERT_EQUAL_UINT32(1, st.get_tick());
}
#if DEVICE_SLEEP
/** Test wake up from sleep
*
* Given a SysTimer with a tick scheduled in the future
@ -279,7 +280,7 @@ void test_sleep(void)
TEST_ASSERT_UINT64_WITHIN(DELAY_DELTA_US, DELAY_US, timer.read_high_resolution_us());
}
#if DEVICE_LOWPOWERTIMER
#if DEVICE_LPTICKER
/** Test wake up from deepsleep
*
* Given a SysTimer with a tick scheduled in the future
@ -316,6 +317,7 @@ void test_deepsleep(void)
TEST_ASSERT_UINT64_WITHIN(DELAY_DELTA_US, DELAY_US, lptimer.read_high_resolution_us());
}
#endif
#endif
utest::v1::status_t test_setup(const size_t number_of_cases)
{
@ -330,10 +332,12 @@ Case cases[] = {
Case("Tick can be cancelled", test_cancel_tick),
Case("Schedule zero ticks", test_schedule_zero),
Case("Handler called once", test_handler_called_once),
#if DEVICE_SLEEP
Case("Wake up from sleep", test_sleep),
#if DEVICE_LOWPOWERTIMER
#if DEVICE_LPTICKER
Case("Wake up from deep sleep", test_deepsleep),
#endif
#endif
};

View File

@ -25,6 +25,10 @@
#error [NOT_SUPPORTED] test not supported
#endif
#if !DEVICE_USTICKER
#error [NOT_SUPPORTED] test not supported
#endif
#define THREAD_STACK_SIZE 512
#if defined(__CORTEX_A9)
#define PARALLEL_THREAD_STACK_SIZE 512

View File

@ -2079,7 +2079,7 @@ PREDEFINED = DOXYGEN_ONLY \
DEVICE_I2C_ASYNCH \
DEVICE_INTERRUPTIN \
DEVICE_ITM \
DEVICE_LOWPOWERTIMER \
DEVICE_LPTICKER \
DEVICE_PORTIN \
DEVICE_PORTINOUT \
DEVICE_PORTOUT \

View File

@ -6,7 +6,7 @@
"SEARCH_INCLUDES": "YES",
"INCLUDE_PATH": "",
"INCLUDE_FILE_PATTERNS": "",
"PREDEFINED": "DOXYGEN_ONLY DEVICE_ANALOGIN DEVICE_ANALOGOUT DEVICE_CAN DEVICE_CRC DEVICE_ETHERNET DEVICE_EMAC DEVICE_FLASH DEVICE_I2C DEVICE_I2CSLAVE DEVICE_I2C_ASYNCH DEVICE_INTERRUPTIN DEVICE_ITM DEVICE_LOWPOWERTIMER DEVICE_PORTIN DEVICE_PORTINOUT DEVICE_PORTOUT DEVICE_PWMOUT DEVICE_RTC DEVICE_TRNG DEVICE_SERIAL DEVICE_SERIAL_ASYNCH DEVICE_SERIAL_FC DEVICE_SLEEP DEVICE_SPI DEVICE_SPI_ASYNCH DEVICE_SPISLAVE DEVICE_STORAGE \"MBED_DEPRECATED_SINCE(f, g)=\" \"MBED_ENABLE_IF_CALLBACK_COMPATIBLE(F, M)=\" \"MBED_DEPRECATED(s)=\"",
"PREDEFINED": "DOXYGEN_ONLY DEVICE_ANALOGIN DEVICE_ANALOGOUT DEVICE_CAN DEVICE_CRC DEVICE_ETHERNET DEVICE_EMAC DEVICE_FLASH DEVICE_I2C DEVICE_I2CSLAVE DEVICE_I2C_ASYNCH DEVICE_INTERRUPTIN DEVICE_ITM DEVICE_LPTICKER DEVICE_PORTIN DEVICE_PORTINOUT DEVICE_PORTOUT DEVICE_PWMOUT DEVICE_RTC DEVICE_TRNG DEVICE_SERIAL DEVICE_SERIAL_ASYNCH DEVICE_SERIAL_FC DEVICE_SLEEP DEVICE_SPI DEVICE_SPI_ASYNCH DEVICE_SPISLAVE DEVICE_STORAGE \"MBED_DEPRECATED_SINCE(f, g)=\" \"MBED_ENABLE_IF_CALLBACK_COMPATIBLE(F, M)=\" \"MBED_DEPRECATED(s)=\"",
"EXPAND_AS_DEFINED": "",
"SKIP_FUNCTION_MACROS": "NO",
"STRIP_CODE_COMMENTS": "NO",

View File

@ -20,7 +20,7 @@
#include "drivers/Ticker.h"
#include "platform/NonCopyable.h"
#if defined (DEVICE_LOWPOWERTIMER) || defined(DOXYGEN_ONLY)
#if defined (DEVICE_LPTICKER) || defined(DOXYGEN_ONLY)
#include "hal/lp_ticker_api.h"

View File

@ -18,7 +18,7 @@
#include "platform/platform.h"
#if defined (DEVICE_LOWPOWERTIMER) || defined(DOXYGEN_ONLY)
#if defined (DEVICE_LPTICKER) || defined(DOXYGEN_ONLY)
#include "hal/lp_ticker_api.h"
#include "drivers/LowPowerTicker.h"

View File

@ -20,7 +20,7 @@
#include "drivers/Timer.h"
#include "platform/NonCopyable.h"
#if defined (DEVICE_LOWPOWERTIMER) || defined(DOXYGEN_ONLY)
#if defined (DEVICE_LPTICKER) || defined(DOXYGEN_ONLY)
#include "hal/lp_ticker_api.h"

View File

@ -71,7 +71,7 @@ public:
// When low power ticker is in use, then do not disable deep-sleep.
Ticker(const ticker_data_t *data) : TimerEvent(data), _function(0), _lock_deepsleep(true) {
#if DEVICE_LOWPOWERTIMER
#if DEVICE_LPTICKER
_lock_deepsleep = (data != get_lp_ticker_data());
#endif
}

View File

@ -27,7 +27,7 @@ Timer::Timer() : _running(), _start(), _time(), _ticker_data(get_us_ticker_data(
Timer::Timer(const ticker_data_t *data) : _running(), _start(), _time(), _ticker_data(data), _lock_deepsleep(true) {
reset();
#if DEVICE_LOWPOWERTIMER
#if DEVICE_LPTICKER
_lock_deepsleep = (data != get_lp_ticker_data());
#endif
}

View File

@ -21,7 +21,7 @@
/* Low power timer test.
*/
#if !DEVICE_LOWPOWERTIMER
#if !DEVICE_LPTICKER
#error This test unit requires low power to be defined for a target
#endif

View File

@ -21,7 +21,7 @@
#include "device.h"
#if DEVICE_LOWPOWERTIMER
#if DEVICE_LPTICKER
#include "hal/ticker_api.h"
@ -30,10 +30,37 @@ extern "C" {
#endif
/**
* \defgroup hal_LpTicker Low Power Ticker Functions
* \defgroup hal_lp_ticker Low Power Ticker
* Low level interface to the low power ticker of a target
*
* # Defined behavior
* * Has a reported frequency between 4KHz and 64KHz - verified by ::lp_ticker_info_test
* * Has a counter that is at least 12 bits wide - verified by ::lp_ticker_info_test
* * Continues operating in deep sleep mode - verified by ::lp_ticker_deepsleep_test
* * All behavior defined by the @ref hal_ticker_shared "ticker specification"
*
* # Undefined behavior
* * 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
*
* @{
*/
/**
* \defgroup hal_lp_ticker_tests Low Power Ticker tests
* Tests to validate the proper implementation of the low power ticker
*
* To run the low power ticker hal tests use the command:
*
* mbed test -t <toolchain> -m <target> -n tests-mbed_hal-common_ticker*,tests-mbed_hal-lp_ticker*
*
*/
typedef void (*ticker_irq_handler_type)(const ticker_data_t *const);
/** Set low power ticker IRQ handler
@ -42,7 +69,7 @@ typedef void (*ticker_irq_handler_type)(const ticker_data_t *const);
*
* @return previous ticker IRQ handler
*
* @note by default IRQ handler is set to ticker_irq_handler()
* @note by default IRQ handler is set to ::ticker_irq_handler
* @note this function is primarily for testing purposes and it's not required part of HAL implementation
*
*/
@ -63,39 +90,147 @@ void lp_ticker_irq_handler(void);
/** Initialize the low power ticker
*
* Initialize or re-initialize the ticker. This resets all the
* clocking and prescaler registers, along with disabling
* the compare interrupt.
*
* Pseudo Code:
* @code
* void lp_ticker_init()
* {
* // Enable clock gate so processor can read LPTMR registers
* POWER_CTRL |= POWER_CTRL_LPTMR_Msk;
*
* // Disable the timer and ensure it is powered down
* LPTMR_CTRL &= ~(LPTMR_CTRL_ENABLE_Msk | LPTMR_CTRL_COMPARE_ENABLE_Msk);
*
* // Configure divisors - no division necessary
* LPTMR_PRESCALE = 0;
* LPTMR_CTRL |= LPTMR_CTRL_ENABLE_Msk;
*
* // Install the interrupt handler
* NVIC_SetVector(LPTMR_IRQn, (uint32_t)lp_ticker_irq_handler);
* NVIC_EnableIRQ(LPTMR_IRQn);
* }
* @endcode
*/
void lp_ticker_init(void);
/** Read the current counter
/** Deinitialize the lower power ticker
*
* @return The current timer's counter value in microseconds
* Powerdown the lp ticker in preparation for sleep, powerdown, or reset.
*
* After calling this function no other ticker functions should be called except
* lp_ticker_init(). Calling any function other than init after freeing is
* undefined.
*
* @note This function stops the ticker from counting.
*/
void lp_ticker_free(void);
/** Read the current tick
*
* If no rollover has occurred, the seconds passed since lp_ticker_init()
* was called can be found by dividing the ticks returned by this function
* by the frequency returned by ::lp_ticker_get_info.
*
* @return The current timer's counter value in ticks
*
* Pseudo Code:
* @code
* uint32_t lp_ticker_read()
* {
* uint16_t count;
* uint16_t last_count;
*
* // Loop until the same tick is read twice since this
* // is ripple counter on a different clock domain.
* count = LPTMR_COUNT;
* do {
* last_count = count;
* count = LPTMR_COUNT;
* } while (last_count != count);
*
* return count;
* }
* @endcode
*/
uint32_t lp_ticker_read(void);
/** Set interrupt for specified timestamp
*
* @param timestamp The time in microseconds to be set
* @param timestamp The time in ticks to be set
*
* @note no special handling needs to be done for times in the past
* as the common timer code will detect this and call
* lp_ticker_fire_interrupt() if this is the case
*
* @note calling this function with timestamp of more than the supported
* number of bits returned by ::lp_ticker_get_info results in undefined
* behavior.
*
* Pseudo Code:
* @code
* void lp_ticker_set_interrupt(timestamp_t timestamp)
* {
* LPTMR_COMPARE = timestamp;
* LPTMR_CTRL |= LPTMR_CTRL_COMPARE_ENABLE_Msk;
* }
* @endcode
*/
void lp_ticker_set_interrupt(timestamp_t timestamp);
/** Disable low power ticker interrupt
*
* Pseudo Code:
* @code
* void lp_ticker_disable_interrupt(void)
* {
* // Disable the compare interrupt
* LPTMR_CTRL &= ~LPTMR_CTRL_COMPARE_ENABLE_Msk;
* }
* @endcode
*/
void lp_ticker_disable_interrupt(void);
/** Clear the low power ticker interrupt
*
* Pseudo Code:
* @code
* void lp_ticker_clear_interrupt(void)
* {
* // Write to the ICR (interrupt clear register) of the LPTMR
* LPTMR_ICR = LPTMR_ICR_COMPARE_Msk;
* }
* @endcode
*/
void lp_ticker_clear_interrupt(void);
/** Set pending interrupt that should be fired right away.
*
* The ticker should be initialized prior calling this function.
* Pseudo Code:
* @code
* void lp_ticker_fire_interrupt(void)
* {
* NVIC_SetPendingIRQ(LPTMR_IRQn);
* }
* @endcode
*/
void lp_ticker_fire_interrupt(void);
/** Get frequency and counter bits of this ticker.
*
* Pseudo Code:
* @code
* const ticker_info_t* lp_ticker_get_info()
* {
* static const ticker_info_t info = {
* 32768, // 32KHz
* 16 // 16 bit counter
* };
* return &info;
* }
* @endcode
*/
const ticker_info_t* lp_ticker_get_info(void);

View File

@ -15,7 +15,7 @@
*/
#include "hal/lp_ticker_api.h"
#if DEVICE_LOWPOWERTIMER
#if DEVICE_LPTICKER
void lp_ticker_set_interrupt_wrapper(timestamp_t timestamp);
@ -28,7 +28,7 @@ static const ticker_interface_t lp_interface = {
.read = lp_ticker_read,
.disable_interrupt = lp_ticker_disable_interrupt,
.clear_interrupt = lp_ticker_clear_interrupt,
#if LOWPOWERTIMER_DELAY_TICKS > 0
#if LPTICKER_DELAY_TICKS > 0
.set_interrupt = lp_ticker_set_interrupt_wrapper,
#else
.set_interrupt = lp_ticker_set_interrupt,

View File

@ -15,12 +15,12 @@
*/
#include "hal/lp_ticker_api.h"
#if DEVICE_LOWPOWERTIMER && (LOWPOWERTIMER_DELAY_TICKS > 0)
#if DEVICE_LPTICKER && (LPTICKER_DELAY_TICKS > 0)
#include "Timeout.h"
#include "mbed_critical.h"
static const timestamp_t min_delta = LOWPOWERTIMER_DELAY_TICKS;
static const timestamp_t min_delta = LPTICKER_DELAY_TICKS;
static bool init = false;
static bool pending = false;
@ -108,7 +108,7 @@ static void set_interrupt_later()
* Wrapper around lp_ticker_set_interrupt to prevent blocking
*
* Problems this function is solving:
* 1. Interrupt may not fire if set earlier than LOWPOWERTIMER_DELAY_TICKS low power clock cycles
* 1. Interrupt may not fire if set earlier than LPTICKER_DELAY_TICKS low power clock cycles
* 2. Setting the interrupt back-to-back will block
*
* This wrapper function prevents lp_ticker_set_interrupt from being called

View File

@ -34,13 +34,13 @@ static uint16_t deep_sleep_lock = 0U;
static us_timestamp_t sleep_time = 0;
static us_timestamp_t deep_sleep_time = 0;
#if defined(MBED_CPU_STATS_ENABLED) && defined(DEVICE_LOWPOWERTIMER)
#if defined(MBED_CPU_STATS_ENABLED) && defined(DEVICE_LPTICKER)
static ticker_data_t *sleep_ticker = NULL;
#endif
static inline us_timestamp_t read_us(void)
{
#if defined(MBED_CPU_STATS_ENABLED) && defined(DEVICE_LOWPOWERTIMER)
#if defined(MBED_CPU_STATS_ENABLED) && defined(DEVICE_LPTICKER)
if (NULL == sleep_ticker) {
sleep_ticker = (ticker_data_t *)get_lp_ticker_data();
}

View File

@ -42,6 +42,14 @@ static void initialize(const ticker_data_t *ticker)
frequency = 1000000;
}
uint8_t frequency_shifts = 0;
for (uint8_t i = 31; i > 0; --i) {
if ((1 << i) == frequency) {
frequency_shifts = i;
break;
}
}
uint32_t bits = info->bits;
if ((info->bits > 32) || (info->bits < 4)) {
MBED_ASSERT(0);
@ -56,6 +64,7 @@ static void initialize(const ticker_data_t *ticker)
ticker->queue->tick_last_read = ticker->interface->read();
ticker->queue->tick_remainder = 0;
ticker->queue->frequency = frequency;
ticker->queue->frequency_shifts = frequency_shifts;
ticker->queue->bitmask = ((uint64_t)1 << bits) - 1;
ticker->queue->max_delta = max_delta;
ticker->queue->max_delta_us = max_delta_us;
@ -125,14 +134,13 @@ static void update_present_time(const ticker_data_t *const ticker)
// Optimized for 1MHz
elapsed_us = elapsed_ticks;
} else if (32768 == queue->frequency) {
// Optimized for 32KHz
} else if (0 != queue->frequency_shifts) {
// Optimized for frequencies divisible by 2
uint64_t us_x_ticks = elapsed_ticks * 1000000;
elapsed_us = us_x_ticks >> 15;
elapsed_us = us_x_ticks >> queue->frequency_shifts;
// Update remainder
queue->tick_remainder += us_x_ticks - (elapsed_us << 15);
queue->tick_remainder += us_x_ticks - (elapsed_us << queue->frequency_shifts);
if (queue->tick_remainder >= queue->frequency) {
elapsed_us += 1;
queue->tick_remainder -= queue->frequency;
@ -174,10 +182,10 @@ static timestamp_t compute_tick(const ticker_data_t *const ticker, us_timestamp_
if (delta > ticker->queue->max_delta) {
delta = ticker->queue->max_delta;
}
} else if (32768 == queue->frequency) {
// Optimized for 32KHz
} else if (0 != queue->frequency_shifts) {
// Optimized frequencies divisible by 2
delta = (delta_us << 15) / 1000000;
delta = (delta_us << ticker->queue->frequency_shifts) / 1000000;
if (delta > ticker->queue->max_delta) {
delta = ticker->queue->max_delta;
}

View File

@ -1,6 +1,3 @@
/** \addtogroup hal */
/** @{*/
/* mbed Microcontroller Library
* Copyright (c) 2006-2013 ARM Limited
*
@ -16,13 +13,15 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/** \addtogroup hal */
/** @{*/
#ifndef MBED_RTC_API_H
#define MBED_RTC_API_H
#include "device.h"
#if DEVICE_RTC
#include <time.h>
#ifdef __cplusplus
@ -30,37 +29,150 @@ extern "C" {
#endif
/**
* \defgroup hal_rtc RTC hal functions
* \defgroup hal_rtc RTC hal
*
* The RTC hal provides a low level interface to the Real Time Counter (RTC) of a
* target.
*
* # Defined behaviour
* * The function ::rtc_init is safe to call repeatedly - Verified by test ::rtc_init_test.
* * RTC accuracy is at least 10% - Verified by test ::rtc_accuracy_test.
* * Init/free doesn't stop RTC from counting - Verified by test ::rtc_persist_test.
* * Software reset doesn't stop RTC from counting - Verified by test ::rtc_reset_test.
* * Sleep modes don't stop RTC from counting - Verified by test ::rtc_sleep_test.
* * Shutdown mode doesn't stop RTC from counting - Not verified.
* * The functions ::rtc_write/::rtc_read provides availability to set/get RTC time
* - Verified by test ::rtc_write_read_test.
* * The functions ::rtc_isenabled returns 1 if the RTC is counting and the time has been set,
* 0 otherwise - Verified by test ::rtc_enabled_test.
*
* # Undefined behaviour
* * Calling any function other than ::rtc_init before the initialisation of the RTC
*
* # Potential bugs
* * Incorrect overflow handling - Verified by ::rtc_range_test
* * Glitches due to ripple counter - Verified by ::rtc_glitch_test
*
* @see hal_rtc_tests
*
* @{
*/
/**
* \defgroup hal_rtc_tests RTC hal tests
* The RTC test validate proper implementation of the RTC hal.
*
* To run the RTC hal tests use the command:
*
* mbed test -t <toolchain> -m <target> -n tests-mbed_hal-rtc*
*/
/** Initialize the RTC peripheral
*
* Powerup the RTC in perpetration for access. This function must be called
* before any other RTC functions ares called. This does not change the state
* of the RTC. It just enables access to it.
*
* @note This function is safe to call repeatedly - Tested by ::rtc_init_test
*
* Example Implementation Pseudo Code:
* @code
* void rtc_init()
* {
* // Enable clock gate so processor can read RTC registers
* POWER_CTRL |= POWER_CTRL_RTC_Msk;
*
* // See if the RTC is already setup
* if (!(RTC_STATUS & RTC_STATUS_COUNTING_Msk)) {
*
* // Setup the RTC clock source
* RTC_CTRL |= RTC_CTRL_CLK32_Msk;
* }
* }
* @endcode
*/
void rtc_init(void);
/** Deinitialize RTC
*
* TODO: The function is not used by rtc api in mbed-drivers.
* Powerdown the RTC in preparation for sleep, powerdown or reset. That should only
* affect the CPU domain and not the time keeping logic.
* After this function is called no other RTC functions should be called
* except for ::rtc_init.
*
* @note This function does not stop the RTC from counting - Tested by ::rtc_persist_test
*
* Example Implementation Pseudo Code:
* @code
* void rtc_free()
* {
* // Disable clock gate since processor no longer needs to read RTC registers
* POWER_CTRL &= ~POWER_CTRL_RTC_Msk;
* }
* @endcode
*/
void rtc_free(void);
/** Get the RTC enable status
/** Check if the RTC has the time set and is counting
*
* @retval 0 disabled
* @retval 1 enabled
* @retval 0 The time reported by the RTC is not valid
* @retval 1 The time has been set the RTC is counting
*
* Example Implementation Pseudo Code:
* @code
* int rtc_isenabled()
* {
* if (RTC_STATUS & RTC_STATUS_COUNTING_Msk) {
* return 1;
* } else {
* return 0;
* }
* }
* @endcode
*/
int rtc_isenabled(void);
/** Get the current time from the RTC peripheral
*
* @return The current time
* @return The current time in seconds
*
* @note Some RTCs are not synchronized with the main clock. If
* this is the case with your RTC then you must read the RTC time
* in a loop to prevent reading the wrong time due to a glitch.
* The test ::rtc_glitch_test is intended to catch this bug.
*
* Example implementation for an unsynchronized ripple counter:
* @code
* time_t rtc_read()
* {
* uint32_t val;
* uint32_t last_val;
*
* // Loop until the same value is read twice
* val = RTC_SECONDS;
* do {
* last_val = val;
* val = RTC_SECONDS;
* } while (last_val != val);
*
* return (time_t)val;
* }
* @endcode
*/
time_t rtc_read(void);
/** Set the current time to the RTC peripheral
/** Write the current time in seconds to the RTC peripheral
*
* @param t The current time to be set
* @param t The current time to be set in seconds.
*
* Example Implementation Pseudo Code:
* @code
* void rtc_write(time_t t)
* {
* RTC_SECONDS = t;
* }
* @endcode
*/
void rtc_write(time_t t);
@ -72,6 +184,4 @@ void rtc_write(time_t t);
#endif
#endif
/** @}*/

View File

@ -27,37 +27,70 @@
extern "C" {
#endif
/**
* \defgroup hal_sleep sleep hal requirements
* Low level interface to the sleep mode of a target.
*
* # Defined behaviour
*
* * Sleep mode
* * wake-up time should be less than 10 us - Verified by sleep_usticker_test().
* * the processor can be woken up by any internal peripheral interrupt - Verified by sleep_usticker_test().
* * all peripherals operate as in run mode - not verified.
* * the processor can be woken up by external pin interrupt - not verified.
* * Deep sleep
* * the wake-up time should be less than 10 ms - Verified by deepsleep_lpticker_test().
* * lp ticker should wake up a target from this mode - Verified by deepsleep_lpticker_test().
* * RTC should wake up a target from this mode - not verified.
* * an external interrupt on a pin should wake up a target from this mode - not verified.
* * a watchdog timer should wake up a target from this mode - not verified.
* * High-speed clocks are turned off - Verified by deepsleep_high_speed_clocks_turned_off_test().
* * RTC keeps time - Verified by rtc_sleep_test().
*
* # Undefined behaviour
*
* * peripherals aside from RTC, GPIO and lp ticker result in undefined behaviour in deep sleep.
* @{
*/
/**
* \defgroup hal_sleep_tests sleep hal tests
* The sleep HAL tests ensure driver conformance to defined behaviour.
*
* To run the sleep hal tests use the command:
*
* mbed test -t <toolchain> -m <target> -n tests-mbed_hal-sleep*
*
*/
/** Send the microcontroller to sleep
*
* The processor is setup ready for sleep, and sent to sleep using __WFI(). In this mode, the
* The processor is setup ready for sleep, and sent to sleep. In this mode, the
* system clock to the core is stopped until a reset or an interrupt occurs. This eliminates
* dynamic power used by the processor, memory systems and buses. The processor, peripheral and
* memory state are maintained, and the peripherals continue to work and can generate interrupts.
*
* The processor can be woken up by any internal peripheral interrupt or external pin interrupt.
*
* @note
* The mbed interface semihosting is disconnected as part of going to sleep, and can not be restored.
* Flash re-programming and the USB serial port will remain active, but the mbed program will no longer be
* able to access the LocalFileSystem
* The wake-up time shall be less than 10 us.
*
*/
void hal_sleep(void);
/** Send the microcontroller to deep sleep
*
* This processor is setup ready for deep sleep, and sent to sleep using __WFI(). This mode
* has the same sleep features as sleep plus it powers down peripherals and clocks. All state
* is still maintained.
* has the same sleep features as sleep plus it powers down peripherals and high frequency clocks.
* All state is still maintained.
*
* The processor can only be woken up by an external interrupt on a pin or a watchdog timer.
* The processor can only be woken up by low power ticker, RTC, an external interrupt on a pin or a watchdog timer.
*
* @note
* The mbed interface semihosting is disconnected as part of going to sleep, and can not be restored.
* Flash re-programming and the USB serial port will remain active, but the mbed program will no longer be
* able to access the LocalFileSystem
* The wake-up time shall be less than 10 ms.
*/
void hal_deepsleep(void);
/**@}*/
#ifdef __cplusplus
}
#endif
@ -66,4 +99,4 @@ void hal_deepsleep(void);
#endif
/** @}*/
/**@}*/

View File

@ -80,6 +80,7 @@ typedef struct {
uint64_t tick_remainder; /**< Ticks that have not been added to base_time */
us_timestamp_t present_time; /**< Store the timestamp used for present time */
bool initialized; /**< Indicate if the instance is initialized */
uint8_t frequency_shifts; /**< If frequency is a value of 2^n, this is n, otherwise 0 */
} ticker_event_queue_t;
/** Ticker's data structure

View File

@ -27,10 +27,82 @@ extern "C" {
#endif
/**
* \defgroup hal_UsTicker Microseconds Ticker Functions
* \defgroup hal_us_ticker Microsecond Ticker
* Low level interface to the microsecond ticker of a target
*
* # Defined behavior
* * Has a reported frequency between 250KHz and 8MHz - Verified by test ::us_ticker_info_test
* * Has a counter that is at least 16 bits wide - Verified by test ::us_ticker_info_test
* * All behavior defined by the @ref hal_ticker_shared "ticker specification"
*
* # Undefined behavior
* * See the @ref hal_ticker_shared "ticker specification"
*
* @see hal_us_ticker_tests
*
* @{
*/
/**
* \defgroup hal_us_ticker_tests Microsecond Ticker tests
* Tests to validate the proper implementation of the microsecond ticker
*
* To run the microsecond ticker hal tests use the command:
*
* mbed test -t <toolchain> -m <target> -n tests-mbed_hal-common_ticker*,tests-mbed_hal-us_ticker*
*
* @see hal_ticker_tests
*
*/
/**
* \defgroup hal_ticker_shared Ticker Hal
* Low level interface to the ticker of a target
*
* # Defined behavior
* * The function ticker_init is safe to call repeatedly - Verified by test ::ticker_init_test
* * The function ticker_init allows the ticker to keep counting and disables the ticker interrupt - Verified by test ::ticker_init_test
* * Ticker frequency is non-zero and counter is at least 8 bits - Verified by ::ticker_info_test
* * The ticker rolls over at (1 << bits) and continues counting starting from 0 - Verified by ::ticker_overflow_test
* * The ticker counts at the specified frequency +- 10% - Verified by ::ticker_frequency_test
* * The ticker increments by 1 each tick - Verified by ::ticker_increment_test
* * The ticker interrupt fires only when the ticker times increments to or past the value set by ticker_set_interrupt.
* Verified by ::ticker_interrupt_test and ::ticker_past_test
* * It is safe to call ticker_set_interrupt repeatedly before the handler is called - Verified by ::ticker_repeat_reschedule_test
* * The function ticker_fire_interrupt causes ticker_irq_handler to be called immediately from interrupt context -
* 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
*
* # Undefined behavior
* * Calling any function other than ticker_init before the initialization of the ticker
* * Whether ticker_irq_handler is called a second time if the time wraps and matches the value set by ticker_set_interrupt again
* * Calling ticker_set_interrupt with a value that has more than the supported number of bits
* * Calling any function other than us_ticker_init after calling us_ticker_free
*
* # Potential bugs
* * Drift due to reschedule - Verified by ::ticker_repeat_reschedule_test
* * Incorrect overflow handling of timers - Verified by ::ticker_overflow_test
* * Interrupting at a time of 0 - Verified by ::ticker_overflow_test
* * Interrupt triggered more than once - Verified by ::ticker_interrupt_test
*
* @ingroup hal_us_ticker
* @ingroup hal_lp_ticker
*/
/**
* \defgroup hal_ticker_tests Ticker Tests
* Tests to validate the proper implementation of a ticker
*
* To run the ticker hal tests use the command:
*
* mbed test -t <toolchain> -m <target> -n tests-mbed_hal-common_ticker*
*
* @ingroup hal_us_ticker
* @ingroup hal_lp_ticker
*/
typedef void (*ticker_irq_handler_type)(const ticker_data_t *const);
/** Set ticker IRQ handler
@ -39,7 +111,7 @@ typedef void (*ticker_irq_handler_type)(const ticker_data_t *const);
*
* @return previous ticker IRQ handler
*
* @note by default IRQ handler is set to ticker_irq_handler()
* @note by default IRQ handler is set to ::ticker_irq_handler
* @note this function is primarily for testing purposes and it's not required part of HAL implementation
*
*/
@ -47,7 +119,7 @@ ticker_irq_handler_type set_us_ticker_irq_handler(ticker_irq_handler_type ticker
/** Get ticker's data
*
* @return The low power ticker data
* @return The microsecond ticker data
*/
const ticker_data_t* get_us_ticker_data(void);
@ -61,39 +133,141 @@ void us_ticker_irq_handler(void);
/** Initialize the ticker
*
* Initialize or re-initialize the ticker. This resets all the
* clocking and prescaler registers, along with disabling
* the compare interrupt.
*
* @note Initialization properties tested by ::ticker_init_test
*
* Pseudo Code:
* @code
* void us_ticker_init()
* {
* // Enable clock gate so processor can read TIMER registers
* POWER_CTRL |= POWER_CTRL_TIMER_Msk;
*
* // Disable the timer and ensure it is powered down
* TIMER_CTRL &= ~(TIMER_CTRL_ENABLE_Msk | TIMER_CTRL_COMPARE_ENABLE_Msk);
*
* // Configure divisors
* uint32_t prescale = SystemCoreClock / 1000000;
* TIMER_PRESCALE = prescale - 1;
* TIMER_CTRL |= TIMER_CTRL_ENABLE_Msk;
*
* // Install the interrupt handler
* NVIC_SetVector(TIMER_IRQn, (uint32_t)us_ticker_irq_handler);
* NVIC_EnableIRQ(TIMER_IRQn);
* }
* @endcode
*/
void us_ticker_init(void);
/** Deinitialize the us ticker
*
* Powerdown the us ticker in preparation for sleep, powerdown, or reset.
*
* After this function is called, no other ticker functions should be called
* except us_ticker_init(), calling any function other than init is undefined.
*
* @note This function stops the ticker from counting.
*/
void us_ticker_free(void);
/** Read the current counter
*
* @return The current timer's counter value in microseconds
* Read the current counter value without performing frequency conversions.
* If no rollover has occurred, the seconds passed since us_ticker_init()
* was called can be found by dividing the ticks returned by this function
* by the frequency returned by ::us_ticker_get_info.
*
* @return The current timer's counter value in ticks
*
* Pseudo Code:
* @code
* uint32_t us_ticker_read()
* {
* return TIMER_COUNT;
* }
* @endcode
*/
uint32_t us_ticker_read(void);
/** Set interrupt for specified timestamp
*
* @param timestamp The time in microseconds to be set
* @param timestamp The time in ticks to be set
*
* @note no special handling needs to be done for times in the past
* as the common timer code will detect this and call
* us_ticker_fire_interrupt() if this is the case
*
* @note calling this function with timestamp of more than the supported
* number of bits returned by ::us_ticker_get_info results in undefined
* behavior.
*
* Pseudo Code:
* @code
* void us_ticker_set_interrupt(timestamp_t timestamp)
* {
* TIMER_COMPARE = timestamp;
* TIMER_CTRL |= TIMER_CTRL_COMPARE_ENABLE_Msk;
* }
* @endcode
*/
void us_ticker_set_interrupt(timestamp_t timestamp);
/** Disable us ticker interrupt
*
* Pseudo Code:
* @code
* void us_ticker_disable_interrupt(void)
* {
* // Disable the compare interrupt
* TIMER_CTRL &= ~TIMER_CTRL_COMPARE_ENABLE_Msk;
* }
* @endcode
*/
void us_ticker_disable_interrupt(void);
/** Clear us ticker interrupt
*
* Pseudo Code:
* @code
* void us_ticker_clear_interrupt(void)
* {
* // Write to the ICR (interrupt clear register) of the TIMER
* TIMER_ICR = TIMER_ICR_COMPARE_Msk;
* }
* @endcode
*/
void us_ticker_clear_interrupt(void);
/** Set pending interrupt that should be fired right away.
*
*
* The ticker should be initialized prior calling this function.
*
* Pseudo Code:
* @code
* void us_ticker_fire_interrupt(void)
* {
* NVIC_SetPendingIRQ(TIMER_IRQn);
* }
* @endcode
*/
void us_ticker_fire_interrupt(void);
/** Get frequency and counter bits of this ticker.
*
* Pseudo Code:
* @code
* const ticker_info_t* us_ticker_get_info()
* {
* static const ticker_info_t info = {
* 1000000, // 1 MHz
* 32 // 32 bit counter
* };
* return &info;
* }
* @endcode
*/
const ticker_info_t* us_ticker_get_info(void);

View File

@ -29,7 +29,7 @@ static int (*_rtc_isenabled)(void) = rtc_isenabled;
static time_t (*_rtc_read)(void) = rtc_read;
static void (*_rtc_write)(time_t t) = rtc_write;
#elif DEVICE_LOWPOWERTIMER
#elif DEVICE_LPTICKER
#include "drivers/LowPowerTimer.h"
@ -63,13 +63,13 @@ static int (*_rtc_isenabled)(void) = _rtc_lpticker_isenabled;
static time_t (*_rtc_read)(void) = _rtc_lpticker_read;
static void (*_rtc_write)(time_t t) = _rtc_lpticker_write;
#else /* DEVICE_LOWPOWERTIMER */
#else /* DEVICE_LPTICKER */
static void (*_rtc_init)(void) = NULL;
static int (*_rtc_isenabled)(void) = NULL;
static time_t (*_rtc_read)(void) = NULL;
static void (*_rtc_write)(time_t t) = NULL;
#endif /* DEVICE_LOWPOWERTIMER */
#endif /* DEVICE_LPTICKER */
#ifdef __cplusplus
extern "C" {

View File

@ -12,7 +12,7 @@
#warning Statistics are currently not supported without the rtos.
#endif
#if defined(MBED_CPU_STATS_ENABLED) && (!defined(DEVICE_LOWPOWERTIMER) || !defined(DEVICE_SLEEP))
#if defined(MBED_CPU_STATS_ENABLED) && (!defined(DEVICE_LPTICKER) || !defined(DEVICE_SLEEP))
#warning CPU statistics are not supported without low power timer support.
#endif
@ -20,7 +20,7 @@ void mbed_stats_cpu_get(mbed_stats_cpu_t *stats)
{
MBED_ASSERT(stats != NULL);
memset(stats, 0, sizeof(mbed_stats_cpu_t));
#if defined(MBED_CPU_STATS_ENABLED) && defined(DEVICE_LOWPOWERTIMER) && defined(DEVICE_SLEEP)
#if defined(MBED_CPU_STATS_ENABLED) && defined(DEVICE_LPTICKER) && defined(DEVICE_SLEEP)
stats->uptime = mbed_uptime();
stats->idle_time = mbed_time_idle();
stats->sleep_time = mbed_time_sleep();

View File

@ -21,7 +21,7 @@
*/
#include "rtos/TARGET_CORTEX/SysTimer.h"
#if DEVICE_LOWPOWERTIMER
#if DEVICE_LPTICKER
#include "hal/lp_ticker_api.h"
#include "mbed_critical.h"

View File

@ -22,7 +22,7 @@
#ifndef MBED_SYS_TIMER_H
#define MBED_SYS_TIMER_H
#if defined(DEVICE_LOWPOWERTIMER) || defined(DOXYGEN_ONLY)
#if defined(DEVICE_LPTICKER) || defined(DOXYGEN_ONLY)
#include "platform/NonCopyable.h"
#include "drivers/TimerEvent.h"

View File

@ -34,7 +34,7 @@ extern "C" {
using namespace mbed;
#ifdef MBED_TICKLESS
#if (defined(MBED_TICKLESS) && defined(DEVICE_LPTICKER))
#include "rtos/TARGET_CORTEX/SysTimer.h"
@ -129,7 +129,7 @@ static void default_idle_hook(void)
core_util_critical_section_exit();
}
#endif // MBED_TICKLESS
#endif // (defined(MBED_TICKLESS) && defined(DEVICE_LPTICKER))
static void (*idle_hook_fptr)(void) = &default_idle_hook;

View File

@ -30,7 +30,7 @@ static uint32_t lp_ticker_overflows_delta = 0;
/* lp_ticker Overflow limit */
static uint32_t lp_ticker_overflow_limit = 0;
#if DEVICE_LOWPOWERTIMER
#if DEVICE_LPTICKER
/**
* Interrupt Handler
*/

View File

@ -25,6 +25,7 @@
#include "lp_ticker_api.h"
#include "platform_devices.h"
#if DEVICE_LPTICKER
/**
* \brief Calculate clocks to us
*
@ -111,3 +112,5 @@ void TIMER1_IRQHandler(void)
{
cmsdk_ticker_irq_handler(&timer_data);
}
#endif

View File

@ -56,7 +56,7 @@ void us_ticker_irq_handler(void);
static int us_ticker_inited = 0;
static ADI_TMR_CONFIG tmrConfig, tmr2Config;
static ADI_TMR_CONFIG tmrConfig;
static volatile uint32_t Upper_count = 0, largecnt = 0;
@ -201,14 +201,14 @@ static void event_timer()
cnt = 65536u - cnt;
}
tmr2Config.nLoad = cnt;
tmr2Config.nAsyncLoad = cnt;
adi_tmr_ConfigTimer(ADI_TMR_DEVICE_GP2, &tmr2Config);
tmrConfig.nLoad = cnt;
tmrConfig.nAsyncLoad = cnt;
adi_tmr_ConfigTimer(ADI_TMR_DEVICE_GP2, &tmrConfig);
adi_tmr_Enable(ADI_TMR_DEVICE_GP2, true);
} else {
tmr2Config.nLoad = 65535u;
tmr2Config.nAsyncLoad = 65535u;
adi_tmr_ConfigTimer(ADI_TMR_DEVICE_GP2, &tmr2Config);
tmrConfig.nLoad = 65535u;
tmrConfig.nAsyncLoad = 65535u;
adi_tmr_ConfigTimer(ADI_TMR_DEVICE_GP2, &tmrConfig);
adi_tmr_Enable(ADI_TMR_DEVICE_GP2, true);
}
}
@ -249,6 +249,8 @@ static void GP2CallbackFunction(void *pCBParam, uint32_t Event, void * pArg)
void us_ticker_init(void)
{
if (us_ticker_inited) {
// Disable ticker interrupt on reinitialization
adi_tmr_Enable(ADI_TMR_DEVICE_GP2, false);
return;
}
@ -283,15 +285,15 @@ void us_ticker_init(void)
adi_tmr_ConfigTimer(ADI_TMR_DEVICE_GP1, &tmrConfig);
/* Configure GP2 for doing event counts */
tmr2Config.bCountingUp = true;
tmr2Config.bPeriodic = true;
tmr2Config.ePrescaler = ADI_TMR_PRESCALER_256; // TMR2 at 26MHz/256
tmr2Config.eClockSource = ADI_TMR_CLOCK_PCLK; // TMR source is PCLK (most examples use HFOSC)
tmr2Config.nLoad = 0;
tmr2Config.nAsyncLoad = 0;
tmr2Config.bReloading = false;
tmr2Config.bSyncBypass = true; // Allow x1 prescale
adi_tmr_ConfigTimer(ADI_TMR_DEVICE_GP2, &tmr2Config);
tmrConfig.bCountingUp = true;
tmrConfig.bPeriodic = true;
tmrConfig.ePrescaler = ADI_TMR_PRESCALER_256; // TMR2 at 26MHz/256
tmrConfig.eClockSource = ADI_TMR_CLOCK_PCLK; // TMR source is PCLK (most examples use HFOSC)
tmrConfig.nLoad = 0;
tmrConfig.nAsyncLoad = 0;
tmrConfig.bReloading = false;
tmrConfig.bSyncBypass = true; // Allow x1 prescale
adi_tmr_ConfigTimer(ADI_TMR_DEVICE_GP2, &tmrConfig);
/*------------------------- GP TIMER ENABLE ------------------------------*/
@ -328,14 +330,15 @@ void us_ticker_clear_interrupt(void)
void us_ticker_set_interrupt(timestamp_t timestamp)
{
// if timestamp is already past, do not set interrupt
if ((timestamp + 10) <= us_ticker_read()) return;
/* timestamp is when interrupt should fire.
*
* This MUST not be called if another timer event is currently enabled.
*
*/
calc_event_counts(timestamp); // use timestamp to calculate largecnt to control number of timer interrupts
tmr2Config.ePrescaler = ADI_TMR_PRESCALER_256; // TMR2 at 26MHz/256
tmrConfig.ePrescaler = ADI_TMR_PRESCALER_256; // TMR2 at 26MHz/256
event_timer(); // uses largecnt to initiate timer interrupts
}
@ -348,7 +351,7 @@ void us_ticker_set_interrupt(timestamp_t timestamp)
void us_ticker_fire_interrupt(void)
{
largecnt = 1; // set a minimal interval so interrupt fire immediately
tmr2Config.ePrescaler = ADI_TMR_PRESCALER_1; // TMR2 at 26MHz/1
tmrConfig.ePrescaler = ADI_TMR_PRESCALER_1; // TMR2 at 26MHz/1
event_timer(); // enable the timer and interrupt
}

View File

@ -56,7 +56,7 @@ void us_ticker_irq_handler(void);
static int us_ticker_inited = 0;
static ADI_TMR_CONFIG tmrConfig, tmr2Config;
static ADI_TMR_CONFIG tmrConfig;
static volatile uint32_t Upper_count = 0, largecnt = 0;
@ -200,14 +200,14 @@ static void event_timer()
} else
cnt = 65536u - cnt;
tmr2Config.nLoad = cnt;
tmr2Config.nAsyncLoad = cnt;
adi_tmr_ConfigTimer(ADI_TMR_DEVICE_GP2, tmr2Config);
tmrConfig.nLoad = cnt;
tmrConfig.nAsyncLoad = cnt;
adi_tmr_ConfigTimer(ADI_TMR_DEVICE_GP2, tmrConfig);
adi_tmr_Enable(ADI_TMR_DEVICE_GP2, true);
} else {
tmr2Config.nLoad = 65535u;
tmr2Config.nAsyncLoad = 65535u;
adi_tmr_ConfigTimer(ADI_TMR_DEVICE_GP2, tmr2Config);
tmrConfig.nLoad = 65535u;
tmrConfig.nAsyncLoad = 65535u;
adi_tmr_ConfigTimer(ADI_TMR_DEVICE_GP2, tmrConfig);
adi_tmr_Enable(ADI_TMR_DEVICE_GP2, true);
}
}
@ -247,6 +247,8 @@ static void GP2CallbackFunction(void *pCBParam, uint32_t Event, void * pArg)
void us_ticker_init(void)
{
if (us_ticker_inited) {
// Disable ticker interrupt on reinitialization
adi_tmr_Enable(ADI_TMR_DEVICE_GP2, false);
return;
}
@ -281,15 +283,15 @@ void us_ticker_init(void)
adi_tmr_ConfigTimer(ADI_TMR_DEVICE_GP1, tmrConfig);
/* Configure GP2 for doing event counts */
tmr2Config.bCountingUp = true;
tmr2Config.bPeriodic = true;
tmr2Config.ePrescaler = ADI_TMR_PRESCALER_256; // TMR2 at 26MHz/256
tmr2Config.eClockSource = ADI_TMR_CLOCK_PCLK; // TMR source is PCLK (most examples use HFOSC)
tmr2Config.nLoad = 0;
tmr2Config.nAsyncLoad = 0;
tmr2Config.bReloading = false;
tmr2Config.bSyncBypass = true; // Allow x1 prescale
adi_tmr_ConfigTimer(ADI_TMR_DEVICE_GP2, tmr2Config);
tmrConfig.bCountingUp = true;
tmrConfig.bPeriodic = true;
tmrConfig.ePrescaler = ADI_TMR_PRESCALER_256; // TMR2 at 26MHz/256
tmrConfig.eClockSource = ADI_TMR_CLOCK_PCLK; // TMR source is PCLK (most examples use HFOSC)
tmrConfig.nLoad = 0;
tmrConfig.nAsyncLoad = 0;
tmrConfig.bReloading = false;
tmrConfig.bSyncBypass = true; // Allow x1 prescale
adi_tmr_ConfigTimer(ADI_TMR_DEVICE_GP2, tmrConfig);
/*------------------------- GP TIMER ENABLE ------------------------------*/
@ -326,14 +328,15 @@ void us_ticker_clear_interrupt(void)
void us_ticker_set_interrupt(timestamp_t timestamp)
{
// if timestamp is already past, do not set interrupt
if ((timestamp + 10) <= us_ticker_read()) return;
/* timestamp is when interrupt should fire.
*
* This MUST not be called if another timer event is currently enabled.
*
*/
calc_event_counts(timestamp); // use timestamp to calculate largecnt to control number of timer interrupts
tmr2Config.ePrescaler = ADI_TMR_PRESCALER_256; // TMR2 at 26MHz/256
tmrConfig.ePrescaler = ADI_TMR_PRESCALER_256; // TMR2 at 26MHz/256
event_timer(); // uses largecnt to initiate timer interrupts
}
@ -346,7 +349,7 @@ void us_ticker_set_interrupt(timestamp_t timestamp)
void us_ticker_fire_interrupt(void)
{
largecnt = 1; // set a minimal interval so interrupt fire immediately
tmr2Config.ePrescaler = ADI_TMR_PRESCALER_1; // TMR2 at 26MHz/1
tmrConfig.ePrescaler = ADI_TMR_PRESCALER_1; // TMR2 at 26MHz/1
event_timer(); // enable the timer and interrupt
}

View File

@ -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.
@ -18,15 +18,29 @@
#include "PeripheralNames.h"
#include "clk_freqs.h"
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_init(void);
static void lptmr_init(void);
static int us_ticker_inited = 0;
void us_ticker_init(void) {
if (us_ticker_inited) return;
us_ticker_inited = 1;
if (us_ticker_inited) {
/* calling init again should cancel current interrupt */
us_ticker_disable_interrupt();
return;
}
us_ticker_inited = true;
pit_init();
lptmr_init();
}
@ -37,28 +51,25 @@ void us_ticker_init(void) {
static void pit_init(void) {
SIM->SCGC6 |= SIM_SCGC6_PIT_MASK; // Clock PIT
PIT->MCR = 0; // Enable PIT
// Channel 1
PIT->CHANNEL[1].LDVAL = 0xFFFFFFFF;
PIT->CHANNEL[1].TCTRL = PIT_TCTRL_CHN_MASK; // Chain to timer 0, disable Interrupts
PIT->CHANNEL[1].TCTRL |= PIT_TCTRL_TEN_MASK; // Start timer 1
// Use channel 0 as a prescaler for channel 1
PIT->CHANNEL[0].LDVAL = (bus_frequency() + 500000) / 1000000 - 1;
PIT->CHANNEL[0].TCTRL = PIT_TCTRL_TEN_MASK; // Start timer 0, disable interrupts
}
uint32_t us_ticker_read() {
if (!us_ticker_inited)
us_ticker_init();
// The PIT is a countdown timer
return ~(PIT->CHANNEL[1].CVAL);
}
/******************************************************************************
* Timer Event
*
*
* It schedules interrupts at given (32bit)us interval of time.
* It is implemented used the 16bit Low Power Timer that remains powered in all
* power modes.
@ -66,11 +77,11 @@ uint32_t us_ticker_read() {
static void lptmr_isr(void);
static void lptmr_init(void) {
uint32_t extosc;
uint32_t extosc;
/* Clock the timer */
SIM->SCGC5 |= SIM_SCGC5_LPTMR_MASK;
/* Reset */
LPTMR0->CSR = 0;
@ -114,7 +125,7 @@ static void lptmr_init(void) {
}
}
#if defined(TARGET_KL43Z)
//No suitable actual IRC oscillator clock -> Set it to (8MHz / divider)
//No suitable actual IRC oscillator clock -> Set it to (8MHz / divider)
MCG->SC &= ~MCG_SC_FCRDIV_MASK;
MCG->MC &= ~MCG->MC & MCG_MC_LIRC_DIV2_MASK;
LPTMR0->PSR = LPTMR_PSR_PCS(0) | LPTMR_PSR_PRESCALE(2);
@ -135,7 +146,7 @@ static void lptmr_init(void) {
MCG->SC |= MCG_SC_FCRDIV(2);
LPTMR0->PSR |= LPTMR_PSR_PBYP_MASK;
}
#endif
#endif
}
void us_ticker_disable_interrupt(void) {
@ -152,13 +163,13 @@ static uint16_t us_ticker_int_remainder = 0;
static void lptmr_set(unsigned short count) {
/* Reset */
LPTMR0->CSR = 0;
/* Set the compare register */
LPTMR0->CMR = count;
/* Enable interrupt */
LPTMR0->CSR |= LPTMR_CSR_TIE_MASK;
/* Start the timer */
LPTMR0->CSR |= LPTMR_CSR_TEN_MASK;
}
@ -166,17 +177,20 @@ static void lptmr_set(unsigned short count) {
static void lptmr_isr(void) {
// write 1 to TCF to clear the LPT timer compare flag
LPTMR0->CSR |= LPTMR_CSR_TCF_MASK;
if (us_ticker_int_counter > 0) {
lptmr_set(0xFFFF);
us_ticker_int_counter--;
} else {
if (us_ticker_int_remainder > 0) {
lptmr_set(us_ticker_int_remainder);
us_ticker_int_remainder = 0;
} else {
/* Stop the timer */
LPTMR0->CSR &= ~LPTMR_CSR_TEN_MASK;
// This function is going to disable the interrupts if there are
// no other events in the queue
us_ticker_irq_handler();

View File

@ -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.
@ -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)
{
@ -31,15 +40,14 @@ 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);
@ -47,55 +55,83 @@ void us_ticker_init(void)
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);
//Ticker
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_EnableIRQ(PIT3_IRQn);
}
uint32_t us_ticker_read()
{
/* Let the timer to count if re-init. */
if (!us_ticker_inited) {
us_ticker_init();
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_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()
{
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;
/* 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);
now_us = us_ticker_read();
delta_us = timestamp >= now_us ? timestamp - now_us : (uint32_t)((uint64_t)timestamp + 0xFFFFFFFF - now_us);
if (delta_ticks == 0) {
/* The requested delay is less than the minimum resolution of this counter. */
delta_ticks = 1;
}
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);

View File

@ -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.
@ -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)
{
@ -31,15 +40,14 @@ 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);
@ -47,55 +55,83 @@ void us_ticker_init(void)
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);
//Ticker
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_EnableIRQ(PIT3_IRQn);
}
uint32_t us_ticker_read()
{
/* Let the timer to count if re-init. */
if (!us_ticker_inited) {
us_ticker_init();
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_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()
{
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;
/* 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);
now_us = us_ticker_read();
delta_us = timestamp >= now_us ? timestamp - now_us : (uint32_t)((uint64_t)timestamp + 0xFFFFFFFF - now_us);
if (delta_ticks == 0) {
/* The requested delay is less than the minimum resolution of this counter. */
delta_ticks = 1;
}
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);

View File

@ -50,9 +50,7 @@ typedef enum {
PWM_5 = (0 << TPM_SHIFT) | (4), // TPM0 CH4
PWM_6 = (0 << TPM_SHIFT) | (5), // TPM0 CH5
PWM_7 = (1 << TPM_SHIFT) | (0), // TPM1 CH0
PWM_8 = (1 << TPM_SHIFT) | (1), // TPM1 CH1
PWM_9 = (2 << TPM_SHIFT) | (0), // TPM2 CH0
PWM_10 = (2 << TPM_SHIFT) | (1), // TPM2 CH1
PWM_8 = (1 << TPM_SHIFT) | (1) // TPM1 CH1
} PWMName;
#define ADC_INSTANCE_SHIFT 8

View File

@ -180,15 +180,6 @@ const PinMap PinMap_PWM[] = {
{PTB0, PWM_7 , 3},
{PTB1, PWM_8 , 3},
{PTE22, PWM_9 , 3},
{PTE23, PWM_10, 3},
{PTA1 , PWM_9 , 3},
{PTA2 , PWM_10, 3},
{PTB2 , PWM_9 , 3},
{PTB3 , PWM_10, 3},
{PTB18, PWM_9 , 3},
{PTB19, PWM_10, 3},
{NC , NC , 0}
};

View File

@ -22,6 +22,8 @@
void mbed_sdk_init()
{
BOARD_BootClockRUN();
/* Set the TPM clock source to be IRC48M, do not change as TPM2 is used for the usticker */
CLOCK_SetTpmClock(1U);
}
// Enable the RTC oscillator if available on the board

View File

@ -36,8 +36,7 @@ void pwmout_init(pwmout_t* obj, PinName pin)
uint32_t pwm_base_clock;
/* Set the TPM clock source to be IRC 48M */
CLOCK_SetTpmClock(1U);
/* TPM clock source is set to IRC48M during init */
pwm_base_clock = CLOCK_GetFreq(kCLOCK_McgIrc48MClk);
float clkval = (float)pwm_base_clock / 1000000.0f;
uint32_t clkdiv = 0;

View File

@ -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.
@ -17,91 +17,138 @@
#include "us_ticker_api.h"
#include "PeripheralNames.h"
#include "fsl_pit.h"
#include "fsl_lptmr.h"
#include "fsl_tpm.h"
#include "fsl_clock_config.h"
static int us_ticker_inited = 0;
static void lptmr_isr(void)
const ticker_info_t* us_ticker_get_info()
{
LPTMR_ClearStatusFlags(LPTMR0, kLPTMR_TimerCompareFlag);
LPTMR_StopTimer(LPTMR0);
static const ticker_info_t info = {
3000000,
32
};
return &info;
}
us_ticker_irq_handler();
static bool us_ticker_inited = false;
static uint32_t us_ticker_int_counter = 0;
static uint16_t us_ticker_int_remainder = 0;
static void tpm_isr(void)
{
// Clear the TPM timer overflow flag
TPM_ClearStatusFlags(TPM2, kTPM_TimeOverflowFlag);
TPM_StopTimer(TPM2);
if (us_ticker_int_counter > 0) {
TPM2->MOD = 0xFFFF;
TPM_StartTimer(TPM2, kTPM_SystemClock);
us_ticker_int_counter--;
} else {
if (us_ticker_int_remainder > 0) {
TPM2->MOD = us_ticker_int_remainder;
TPM_StartTimer(TPM2, kTPM_SystemClock);
us_ticker_int_remainder = 0;
} else {
// This function is going to disable the interrupts if there are
// no other events in the queue
us_ticker_irq_handler();
}
}
}
void us_ticker_init(void)
{
/* Common for ticker/timer. */
uint32_t busClock;
/* Structure to initialize PIT. */
pit_config_t pitConfig;
if (us_ticker_inited) {
/* calling init again should cancel current interrupt */
TPM_DisableInterrupts(TPM2, kTPM_TimeOverflowInterruptEnable);
return;
}
us_ticker_inited = 1;
//Timer uses PIT
//Common for ticker/timer
uint32_t busClock;
// Structure to initialize PIT
pit_config_t pitConfig;
PIT_GetDefaultConfig(&pitConfig);
PIT_Init(PIT, &pitConfig);
busClock = CLOCK_GetFreq(kCLOCK_BusClk);
PIT_SetTimerPeriod(PIT, kPIT_Chnl_0, busClock / 1000000 - 1);
PIT_SetTimerPeriod(PIT, kPIT_Chnl_0, (busClock / 3000000) - 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);
//Ticker uses LPTMR
lptmr_config_t lptmrConfig;
LPTMR_GetDefaultConfig(&lptmrConfig);
lptmrConfig.prescalerClockSource = kLPTMR_PrescalerClock_0;
LPTMR_Init(LPTMR0, &lptmrConfig);
/* Configure interrupt generation counters and disable ticker interrupts. */
tpm_config_t tpmConfig;
busClock = CLOCK_GetFreq(kCLOCK_McgInternalRefClk);
LPTMR_SetTimerPeriod(LPTMR0, busClock / 1000000 - 1);
/* Set interrupt handler */
NVIC_SetVector(LPTMR0_IRQn, (uint32_t)lptmr_isr);
NVIC_EnableIRQ(LPTMR0_IRQn);
TPM_GetDefaultConfig(&tpmConfig);
/* Set to Div 16 to get 3MHz clock source for TPM */
tpmConfig.prescale = kTPM_Prescale_Divide_16;
TPM_Init(TPM2, &tpmConfig);
NVIC_SetVector(TPM2_IRQn, (uint32_t)tpm_isr);
NVIC_EnableIRQ(TPM2_IRQn);
us_ticker_inited = true;
}
uint32_t us_ticker_read()
{
if (!us_ticker_inited) {
us_ticker_init();
}
return ~(PIT_GetCurrentTimerCount(PIT, kPIT_Chnl_1));
}
void us_ticker_disable_interrupt(void)
{
LPTMR_DisableInterrupts(LPTMR0, kLPTMR_TimerInterruptEnable);
TPM_DisableInterrupts(TPM2, kTPM_TimeOverflowInterruptEnable);
}
void us_ticker_clear_interrupt(void)
{
LPTMR_ClearStatusFlags(LPTMR0, kLPTMR_TimerCompareFlag);
TPM_ClearStatusFlags(TPM2, kTPM_TimeOverflowFlag);
}
void us_ticker_set_interrupt(timestamp_t timestamp)
{
uint32_t now_us, delta_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);
now_us = us_ticker_read();
delta_us = timestamp >= now_us ? timestamp - now_us : (uint32_t)((uint64_t)timestamp + 0xFFFFFFFF - now_us);
if (delta_ticks == 0) {
/* The requested delay is less than the minimum resolution of this counter. */
delta_ticks = 1;
}
LPTMR_StopTimer(LPTMR0);
LPTMR_SetTimerPeriod(LPTMR0, (uint32_t)delta_us);
LPTMR_EnableInterrupts(LPTMR0, kLPTMR_TimerInterruptEnable);
LPTMR_StartTimer(LPTMR0);
us_ticker_int_counter = (uint32_t)(delta_ticks >> 16);
us_ticker_int_remainder = (uint16_t)(0xFFFF & delta_ticks);
TPM_StopTimer(TPM2);
TPM2->CNT = 0;
if (us_ticker_int_counter > 0) {
TPM2->MOD = 0xFFFF;
us_ticker_int_counter--;
} else {
TPM2->MOD = us_ticker_int_remainder;
us_ticker_int_remainder = 0;
}
/* Clear the count and set match value */
TPM_ClearStatusFlags(TPM2, kTPM_TimeOverflowFlag);
TPM_EnableInterrupts(TPM2, kTPM_TimeOverflowInterruptEnable);
TPM_StartTimer(TPM2, kTPM_SystemClock);
}
void us_ticker_fire_interrupt(void)
{
NVIC_SetPendingIRQ(LPTMR0_IRQn);
us_ticker_int_counter = 0;
us_ticker_int_remainder = 0;
NVIC_SetPendingIRQ(TPM2_IRQn);
}

View File

@ -50,9 +50,7 @@ typedef enum {
PWM_5 = (0 << TPM_SHIFT) | (4), // TPM0 CH4
PWM_6 = (0 << TPM_SHIFT) | (5), // TPM0 CH5
PWM_7 = (1 << TPM_SHIFT) | (0), // TPM1 CH0
PWM_8 = (1 << TPM_SHIFT) | (1), // TPM1 CH1
PWM_9 = (2 << TPM_SHIFT) | (0), // TPM2 CH0
PWM_10 = (2 << TPM_SHIFT) | (1), // TPM2 CH1
PWM_8 = (1 << TPM_SHIFT) | (1) // TPM1 CH1
} PWMName;
#define ADC_INSTANCE_SHIFT 8

View File

@ -137,21 +137,15 @@ const PinMap PinMap_SPI_SSEL[] = {
/************PWM***************/
const PinMap PinMap_PWM[] = {
{PTA0, PWM_6, 3}, // PTA0 , TPM0 CH5
{PTA1, PWM_9 , 3}, // PTA1 , TPM2 CH0
{PTA2, PWM_10, 3}, // PTA2 , TPM2 CH1
{PTA0, PWM_6, 3}, // PTA0 , TPM0 CH5
{PTA3, PWM_1, 3}, // PTA3 , TPM0 CH0
{PTA4, PWM_2 , 3}, // PTA4 , TPM0 CH1
{PTA5, PWM_3 , 3}, // PTA5 , TPM0 CH2
{PTA12, PWM_7 , 3}, // PTA12, TPM1 CH0
{PTA13, PWM_8 , 3}, // PTA13, TPM1 CH1
{PTA13, PWM_8 , 3}, // PTA13, TPM1 CH1
{PTB0, PWM_7, 3}, // PTB0 , TPM1 CH0
{PTB1, PWM_8, 3}, // PTB1 , TPM1 CH1
{PTB2, PWM_9, 3}, // PTB2 , TPM2 CH0
{PTB3, PWM_10, 3}, // PTB3 , TPM2 CH1
{PTB18, PWM_9, 3}, // PTB18, TPM2 CH0
{PTB19, PWM_10, 3}, // PTB18, TPM2 CH1
{PTC1, PWM_1, 4}, // PTC1 , TPM0 CH0
{PTC2, PWM_2, 4}, // PTC2 , TPM0 CH1
@ -161,14 +155,12 @@ const PinMap PinMap_PWM[] = {
{PTD0, PWM_1 , 4}, // PTD0 , TPM0 CH0
{PTD1, PWM_2 , 4}, // PTD0 , TPM0 CH1
{PTD2, PWM_3 , 4}, // PTD2 , TPM0 CH2
{PTD3, PWM_4 , 4}, // PTD3 , TPM0 CH3
{PTD3, PWM_4 , 4}, // PTD3 , TPM0 CH3
{PTD4, PWM_5 , 4}, // PTD4 , TPM0 CH4
{PTD5, PWM_6 , 4}, // PTD5 , TPM0 CH5
{PTE20, PWM_7, 3}, // PTE20, TPM1 CH0
{PTE21, PWM_8, 3}, // PTE21, TPM1 CH1
{PTE22, PWM_9, 3}, // PTE22, TPM2 CH0
{PTE23, PWM_10, 3}, // PTE23, TPM2 CH1
{PTE24, PWM_1, 3}, // PTE24, TPM0 CH0
{PTE25, PWM_2, 3}, // PTE25, TPM0 CH1
{PTE29, PWM_3, 3}, // PTE29, TPM0 CH2

View File

@ -22,6 +22,8 @@
void mbed_sdk_init()
{
BOARD_BootClockRUN();
/* Set the TPM clock source to be IRC48M, do not change as TPM2 is used for the usticker */
CLOCK_SetTpmClock(1U);
}
// Enable the RTC oscillator if available on the board

View File

@ -36,8 +36,7 @@ void pwmout_init(pwmout_t* obj, PinName pin)
uint32_t pwm_base_clock;
/* Set the TPM clock source to be IRC 48M */
CLOCK_SetTpmClock(1U);
/* TPM clock source is set to IRC48M during init */
pwm_base_clock = CLOCK_GetFreq(kCLOCK_McgIrc48MClk);
float clkval = (float)pwm_base_clock / 1000000.0f;
uint32_t clkdiv = 0;

View File

@ -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.
@ -17,91 +17,138 @@
#include "us_ticker_api.h"
#include "PeripheralNames.h"
#include "fsl_pit.h"
#include "fsl_lptmr.h"
#include "fsl_tpm.h"
#include "fsl_clock_config.h"
static int us_ticker_inited = 0;
static void lptmr_isr(void)
const ticker_info_t* us_ticker_get_info()
{
LPTMR_ClearStatusFlags(LPTMR0, kLPTMR_TimerCompareFlag);
LPTMR_StopTimer(LPTMR0);
static const ticker_info_t info = {
3000000,
32
};
return &info;
}
us_ticker_irq_handler();
static bool us_ticker_inited = false;
static uint32_t us_ticker_int_counter = 0;
static uint16_t us_ticker_int_remainder = 0;
static void tpm_isr(void)
{
// Clear the TPM timer overflow flag
TPM_ClearStatusFlags(TPM2, kTPM_TimeOverflowFlag);
TPM_StopTimer(TPM2);
if (us_ticker_int_counter > 0) {
TPM2->MOD = 0xFFFF;
TPM_StartTimer(TPM2, kTPM_SystemClock);
us_ticker_int_counter--;
} else {
if (us_ticker_int_remainder > 0) {
TPM2->MOD = us_ticker_int_remainder;
TPM_StartTimer(TPM2, kTPM_SystemClock);
us_ticker_int_remainder = 0;
} else {
// This function is going to disable the interrupts if there are
// no other events in the queue
us_ticker_irq_handler();
}
}
}
void us_ticker_init(void)
{
/* Common for ticker/timer. */
uint32_t busClock;
/* Structure to initialize PIT. */
pit_config_t pitConfig;
if (us_ticker_inited) {
/* calling init again should cancel current interrupt */
TPM_DisableInterrupts(TPM2, kTPM_TimeOverflowInterruptEnable);
return;
}
us_ticker_inited = 1;
//Timer uses PIT
//Common for ticker/timer
uint32_t busClock;
// Structure to initialize PIT
pit_config_t pitConfig;
PIT_GetDefaultConfig(&pitConfig);
PIT_Init(PIT, &pitConfig);
busClock = CLOCK_GetFreq(kCLOCK_BusClk);
PIT_SetTimerPeriod(PIT, kPIT_Chnl_0, busClock / 1000000 - 1);
PIT_SetTimerPeriod(PIT, kPIT_Chnl_0, (busClock / 3000000) - 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);
//Ticker uses LPTMR
lptmr_config_t lptmrConfig;
LPTMR_GetDefaultConfig(&lptmrConfig);
lptmrConfig.prescalerClockSource = kLPTMR_PrescalerClock_0;
LPTMR_Init(LPTMR0, &lptmrConfig);
/* Configure interrupt generation counters and disable ticker interrupts. */
tpm_config_t tpmConfig;
busClock = CLOCK_GetFreq(kCLOCK_McgInternalRefClk);
LPTMR_SetTimerPeriod(LPTMR0, busClock / 1000000 - 1);
/* Set interrupt handler */
NVIC_SetVector(LPTMR0_IRQn, (uint32_t)lptmr_isr);
NVIC_EnableIRQ(LPTMR0_IRQn);
TPM_GetDefaultConfig(&tpmConfig);
/* Set to Div 16 to get 3MHz clock source for TPM */
tpmConfig.prescale = kTPM_Prescale_Divide_16;
TPM_Init(TPM2, &tpmConfig);
NVIC_SetVector(TPM2_IRQn, (uint32_t)tpm_isr);
NVIC_EnableIRQ(TPM2_IRQn);
us_ticker_inited = true;
}
uint32_t us_ticker_read()
{
if (!us_ticker_inited) {
us_ticker_init();
}
return ~(PIT_GetCurrentTimerCount(PIT, kPIT_Chnl_1));
}
void us_ticker_disable_interrupt(void)
{
LPTMR_DisableInterrupts(LPTMR0, kLPTMR_TimerInterruptEnable);
TPM_DisableInterrupts(TPM2, kTPM_TimeOverflowInterruptEnable);
}
void us_ticker_clear_interrupt(void)
{
LPTMR_ClearStatusFlags(LPTMR0, kLPTMR_TimerCompareFlag);
TPM_ClearStatusFlags(TPM2, kTPM_TimeOverflowFlag);
}
void us_ticker_set_interrupt(timestamp_t timestamp)
{
uint32_t now_us, delta_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);
now_us = us_ticker_read();
delta_us = timestamp >= now_us ? timestamp - now_us : (uint32_t)((uint64_t)timestamp + 0xFFFFFFFF - now_us);
if (delta_ticks == 0) {
/* The requested delay is less than the minimum resolution of this counter. */
delta_ticks = 1;
}
LPTMR_StopTimer(LPTMR0);
LPTMR_SetTimerPeriod(LPTMR0, (uint32_t)delta_us);
LPTMR_EnableInterrupts(LPTMR0, kLPTMR_TimerInterruptEnable);
LPTMR_StartTimer(LPTMR0);
us_ticker_int_counter = (uint32_t)(delta_ticks >> 16);
us_ticker_int_remainder = (uint16_t)(0xFFFF & delta_ticks);
TPM_StopTimer(TPM2);
TPM2->CNT = 0;
if (us_ticker_int_counter > 0) {
TPM2->MOD = 0xFFFF;
us_ticker_int_counter--;
} else {
TPM2->MOD = us_ticker_int_remainder;
us_ticker_int_remainder = 0;
}
/* Clear the count and set match value */
TPM_ClearStatusFlags(TPM2, kTPM_TimeOverflowFlag);
TPM_EnableInterrupts(TPM2, kTPM_TimeOverflowInterruptEnable);
TPM_StartTimer(TPM2, kTPM_SystemClock);
}
void us_ticker_fire_interrupt(void)
{
NVIC_SetPendingIRQ(LPTMR0_IRQn);
us_ticker_int_counter = 0;
us_ticker_int_remainder = 0;
NVIC_SetPendingIRQ(TPM2_IRQn);
}

View File

@ -46,7 +46,7 @@ void NMI_Handler(void)
gpio_init_in(&gpio, PTA4);
}
#ifdef DEVICE_RTC
#if DEVICE_RTC || DEVICE_LPTICKER
// Enable the RTC oscillator if available on the board
void rtc_setup_oscillator(RTC_Type *base)
{

View File

@ -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.
@ -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)
{
@ -31,15 +40,14 @@ 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);
@ -47,55 +55,83 @@ void us_ticker_init(void)
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);
//Ticker
PIT_SetTimerPeriod(PIT, kPIT_Chnl_2, busClock / 1000000 - 1);
PIT_SetTimerChainMode(PIT, kPIT_Chnl_3, true);
NVIC_SetVector(PIT0_IRQn, (uint32_t)pit_isr);
NVIC_EnableIRQ(PIT0_IRQn);
}
uint32_t us_ticker_read()
{
/* Let the timer to count if re-init. */
if (!us_ticker_inited) {
us_ticker_init();
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(PIT0_IRQn, (uint32_t) pit_isr);
NVIC_EnableIRQ(PIT0_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()
{
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;
/* 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);
now_us = us_ticker_read();
delta_us = timestamp >= now_us ? timestamp - now_us : (uint32_t)((uint64_t)timestamp + 0xFFFFFFFF - now_us);
if (delta_ticks == 0) {
/* The requested delay is less than the minimum resolution of this counter. */
delta_ticks = 1;
}
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(PIT0_IRQn);

View File

@ -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.
@ -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)
{
@ -31,15 +40,14 @@ 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);
@ -47,55 +55,83 @@ void us_ticker_init(void)
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);
//Ticker
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_EnableIRQ(PIT3_IRQn);
}
uint32_t us_ticker_read()
{
/* Let the timer to count if re-init. */
if (!us_ticker_inited) {
us_ticker_init();
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_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()
{
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;
/* 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);
now_us = us_ticker_read();
delta_us = timestamp >= now_us ? timestamp - now_us : (uint32_t)((uint64_t)timestamp + 0xFFFFFFFF - now_us);
if (delta_ticks == 0) {
/* The requested delay is less than the minimum resolution of this counter. */
delta_ticks = 1;
}
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);

View File

@ -46,9 +46,7 @@ typedef enum {
PWM_3 = (0 << TPM_SHIFT) | (2), // TPM0 CH2
PWM_4 = (0 << TPM_SHIFT) | (3), // TPM0 CH3
PWM_5 = (1 << TPM_SHIFT) | (0), // TPM1 CH0
PWM_6 = (1 << TPM_SHIFT) | (1), // TPM1 CH1
PWM_7 = (2 << TPM_SHIFT) | (0), // TPM2 CH0
PWM_8 = (2 << TPM_SHIFT) | (1), // TPM2 CH1
PWM_6 = (1 << TPM_SHIFT) | (1) // TPM1 CH1
} PWMName;
#define ADC_INSTANCE_SHIFT 8

View File

@ -132,12 +132,5 @@ const PinMap PinMap_PWM[] = {
{PTB3, PWM_6, 5},
{PTC4, PWM_5, 5},
{PTC5, PWM_6, 5},
/* TPM 2 */
{PTA18, PWM_7, 5},
{PTA19, PWM_8, 5},
{PTB16, PWM_7, 5},
{PTB17, PWM_8, 5},
{PTC6, PWM_7, 5},
{PTC7, PWM_8, 5},
{NC , NC , 0}
};

View File

@ -21,6 +21,8 @@
void mbed_sdk_init()
{
BOARD_BootClockRUN();
/* Set the TPM clock source to be OSCERCLK, do not change as TPM2 is used for the usticker */
CLOCK_SetTpmClock(2U);
}
// Enable the RTC oscillator if available on the board

View File

@ -36,9 +36,8 @@ void pwmout_init(pwmout_t* obj, PinName pin)
uint32_t pwm_base_clock;
/* Set the TPM clock source to be MCG FLL clock */
CLOCK_SetTpmClock(1U);
pwm_base_clock = CLOCK_GetFreq(kCLOCK_McgFllClk);
/* TPM clock source is set to OSCERCLK during init */
pwm_base_clock = CLOCK_GetFreq(kCLOCK_Osc0ErClk);
float clkval = (float)pwm_base_clock / 1000000.0f;
uint32_t clkdiv = 0;
while (clkval > 1) {

View File

@ -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.
@ -17,32 +17,58 @@
#include "us_ticker_api.h"
#include "PeripheralNames.h"
#include "fsl_pit.h"
#include "fsl_lptmr.h"
#include "fsl_tpm.h"
#include "fsl_clock_config.h"
static int us_ticker_inited = 0;
static void lptmr_isr(void)
const ticker_info_t* us_ticker_get_info()
{
LPTMR_ClearStatusFlags(LPTMR0, kLPTMR_TimerCompareFlag);
LPTMR_StopTimer(LPTMR0);
static const ticker_info_t info = {
1000000,
32
};
return &info;
}
us_ticker_irq_handler();
static bool us_ticker_inited = false;
static uint32_t us_ticker_int_counter = 0;
static uint16_t us_ticker_int_remainder = 0;
static void tpm_isr(void)
{
// Clear the TPM timer overflow flag
TPM_ClearStatusFlags(TPM2, kTPM_TimeOverflowFlag);
TPM_StopTimer(TPM2);
if (us_ticker_int_counter > 0) {
TPM2->MOD = 0xFFFF;
TPM_StartTimer(TPM2, kTPM_SystemClock);
us_ticker_int_counter--;
} else {
if (us_ticker_int_remainder > 0) {
TPM2->MOD = us_ticker_int_remainder;
TPM_StartTimer(TPM2, kTPM_SystemClock);
us_ticker_int_remainder = 0;
} else {
// This function is going to disable the interrupts if there are
// no other events in the queue
us_ticker_irq_handler();
}
}
}
void us_ticker_init(void)
{
/* Common for ticker/timer. */
uint32_t busClock;
/* Structure to initialize PIT. */
pit_config_t pitConfig;
if (us_ticker_inited) {
/* calling init again should cancel current interrupt */
TPM_DisableInterrupts(TPM2, kTPM_TimeOverflowInterruptEnable);
return;
}
us_ticker_inited = 1;
//Timer uses PIT
//Common for ticker/timer
uint32_t busClock;
// Structure to initialize PIT
pit_config_t pitConfig;
PIT_GetDefaultConfig(&pitConfig);
PIT_Init(PIT, &pitConfig);
@ -55,53 +81,74 @@ void us_ticker_init(void)
PIT_StartTimer(PIT, kPIT_Chnl_0);
PIT_StartTimer(PIT, kPIT_Chnl_1);
//Ticker uses LPTMR
lptmr_config_t lptmrConfig;
LPTMR_GetDefaultConfig(&lptmrConfig);
lptmrConfig.prescalerClockSource = kLPTMR_PrescalerClock_0;
LPTMR_Init(LPTMR0, &lptmrConfig);
/* Configure interrupt generation counters and disable ticker interrupts. */
tpm_config_t tpmConfig;
busClock = CLOCK_GetFreq(kCLOCK_McgInternalRefClk);
LPTMR_SetTimerPeriod(LPTMR0, busClock / 1000000 - 1);
/* Set interrupt handler */
NVIC_SetVector(LPTMR0_IRQn, (uint32_t)lptmr_isr);
NVIC_EnableIRQ(LPTMR0_IRQn);
TPM_GetDefaultConfig(&tpmConfig);
/* Set to Div 32 to get 1MHz clock source for TPM */
tpmConfig.prescale = kTPM_Prescale_Divide_32;
TPM_Init(TPM2, &tpmConfig);
NVIC_SetVector(TPM2_IRQn, (uint32_t)tpm_isr);
NVIC_EnableIRQ(TPM2_IRQn);
us_ticker_inited = true;
}
uint32_t us_ticker_read()
{
if (!us_ticker_inited) {
us_ticker_init();
}
return ~(PIT_GetCurrentTimerCount(PIT, kPIT_Chnl_1));
}
void us_ticker_disable_interrupt(void)
{
LPTMR_DisableInterrupts(LPTMR0, kLPTMR_TimerInterruptEnable);
TPM_DisableInterrupts(TPM2, kTPM_TimeOverflowInterruptEnable);
}
void us_ticker_clear_interrupt(void)
{
LPTMR_ClearStatusFlags(LPTMR0, kLPTMR_TimerCompareFlag);
TPM_ClearStatusFlags(TPM2, kTPM_TimeOverflowFlag);
}
void us_ticker_set_interrupt(timestamp_t timestamp)
{
uint32_t now_us, delta_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);
now_us = us_ticker_read();
delta_us = timestamp >= now_us ? timestamp - now_us : (uint32_t)((uint64_t)timestamp + 0xFFFFFFFF - now_us);
if (delta_ticks == 0) {
/* The requested delay is less than the minimum resolution of this counter. */
delta_ticks = 1;
}
LPTMR_StopTimer(LPTMR0);
LPTMR_SetTimerPeriod(LPTMR0, (uint32_t)delta_us);
LPTMR_EnableInterrupts(LPTMR0, kLPTMR_TimerInterruptEnable);
LPTMR_StartTimer(LPTMR0);
us_ticker_int_counter = (uint32_t)(delta_ticks >> 16);
us_ticker_int_remainder = (uint16_t)(0xFFFF & delta_ticks);
TPM_StopTimer(TPM2);
TPM2->CNT = 0;
if (us_ticker_int_counter > 0) {
TPM2->MOD = 0xFFFF;
us_ticker_int_counter--;
} else {
TPM2->MOD = us_ticker_int_remainder;
us_ticker_int_remainder = 0;
}
/* Clear the count and set match value */
TPM_ClearStatusFlags(TPM2, kTPM_TimeOverflowFlag);
TPM_EnableInterrupts(TPM2, kTPM_TimeOverflowInterruptEnable);
TPM_StartTimer(TPM2, kTPM_SystemClock);
}
void us_ticker_fire_interrupt(void)
{
NVIC_SetPendingIRQ(LPTMR0_IRQn);
us_ticker_int_counter = 0;
us_ticker_int_remainder = 0;
NVIC_SetPendingIRQ(TPM2_IRQn);
}

View File

@ -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.
@ -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)
{
@ -31,15 +40,14 @@ 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);
@ -47,55 +55,83 @@ void us_ticker_init(void)
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);
//Ticker
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_EnableIRQ(PIT3_IRQn);
}
uint32_t us_ticker_read()
{
/* Let the timer to count if re-init. */
if (!us_ticker_inited) {
us_ticker_init();
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_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()
{
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;
/* 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);
now_us = us_ticker_read();
delta_us = timestamp >= now_us ? timestamp - now_us : (uint32_t)((uint64_t)timestamp + 0xFFFFFFFF - now_us);
if (delta_ticks == 0) {
/* The requested delay is less than the minimum resolution of this counter. */
delta_ticks = 1;
}
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);

View File

@ -1,5 +1,5 @@
/* mbed Microcontroller Library
* Copyright (c) 2006-2017 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.
@ -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)
{
@ -31,15 +40,14 @@ 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);
@ -47,55 +55,83 @@ void us_ticker_init(void)
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);
//Ticker
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_EnableIRQ(PIT3_IRQn);
}
uint32_t us_ticker_read()
{
/* Let the timer to count if re-init. */
if (!us_ticker_inited) {
us_ticker_init();
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_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()
{
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;
/* 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);
now_us = us_ticker_read();
delta_us = timestamp >= now_us ? timestamp - now_us : (uint32_t)((uint64_t)timestamp + 0xFFFFFFFF - now_us);
if (delta_ticks == 0) {
/* The requested delay is less than the minimum resolution of this counter. */
delta_ticks = 1;
}
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);

View File

@ -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.
@ -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)
{
@ -31,15 +40,14 @@ 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);
@ -47,55 +55,83 @@ void us_ticker_init(void)
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);
//Ticker
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_EnableIRQ(PIT3_IRQn);
}
uint32_t us_ticker_read()
{
/* Let the timer to count if re-init. */
if (!us_ticker_inited) {
us_ticker_init();
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_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()
{
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;
/* 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);
now_us = us_ticker_read();
delta_us = timestamp >= now_us ? timestamp - now_us : (uint32_t)((uint64_t)timestamp + 0xFFFFFFFF - now_us);
if (delta_ticks == 0) {
/* The requested delay is less than the minimum resolution of this counter. */
delta_ticks = 1;
}
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);

View File

@ -1,5 +1,5 @@
/* mbed Microcontroller Library
* Copyright (c) 2016 ARM Limited
* Copyright (c) 2016 - 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.
@ -14,53 +14,30 @@
* limitations under the License.
*/
#if DEVICE_LOWPOWERTIMER
#if DEVICE_LPTICKER
#include "lp_ticker_api.h"
#include "fsl_rtc.h"
#include "fsl_lptmr.h"
#include "cmsis.h"
#include "rtc_api.h"
#define MAX_SEC_BITS (12)
#define MAX_SEC_MASK ((1 << MAX_SEC_BITS) - 1)
#define SEC_IN_USEC (1000000)
const ticker_info_t* lp_ticker_get_info()
{
static const ticker_info_t info = {
32768, // 32kHz
16 // 16 bit counter
};
return &info;
}
#define OSC32K_CLK_HZ (32768)
#define MAX_LPTMR_SLEEP ((1 << 16) - 1)
static bool lp_ticker_inited = false;
static int lptmr_schedule = 0;
static void rtc_isr(void)
{
uint32_t sr = RTC->SR;
if (sr & RTC_SR_TOF_MASK) {
// Reset RTC to 0 so it keeps counting
RTC_StopTimer(RTC);
RTC->TSR = 0;
RTC_StartTimer(RTC);
} else if (sr & RTC_SR_TAF_MASK) {
RTC_DisableInterrupts(RTC, kRTC_AlarmInterruptEnable);
RTC->TAR = 0; /* Write clears the IRQ flag */
/* Wait subsecond remainder if any */
if (lptmr_schedule) {
LPTMR_SetTimerPeriod(LPTMR0, lptmr_schedule);
LPTMR_EnableInterrupts(LPTMR0, kLPTMR_TimerInterruptEnable);
LPTMR_StartTimer(LPTMR0);
} else {
lp_ticker_irq_handler();
}
} else if (sr & RTC_SR_TIF_MASK) {
RTC_DisableInterrupts(RTC, kRTC_TimeOverflowInterruptEnable);
}
}
extern void rtc_setup_oscillator(RTC_Type *base);
static void lptmr_isr(void)
{
LPTMR_ClearStatusFlags(LPTMR0, kLPTMR_TimerCompareFlag);
LPTMR_StopTimer(LPTMR0);
lp_ticker_irq_handler();
}
@ -71,106 +48,52 @@ void lp_ticker_init(void)
{
lptmr_config_t lptmrConfig;
if (lp_ticker_inited) {
return;
if (!lp_ticker_inited) {
/* Setup high resolution clock - LPTMR */
LPTMR_GetDefaultConfig(&lptmrConfig);
/* Setup the RTC 32KHz oscillator */
CLOCK_EnableClock(kCLOCK_Rtc0);
rtc_setup_oscillator(RTC);
/* Use 32kHz drive */
CLOCK_SetXtal32Freq(OSC32K_CLK_HZ);
lptmrConfig.prescalerClockSource = kLPTMR_PrescalerClock_2;
lptmrConfig.enableFreeRunning = true;
LPTMR_Init(LPTMR0, &lptmrConfig);
LPTMR_DisableInterrupts(LPTMR0, kLPTMR_TimerInterruptEnable);
NVIC_ClearPendingIRQ(LPTMR0_IRQn);
NVIC_SetVector(LPTMR0_IRQn, (uint32_t)lptmr_isr);
EnableIRQ(LPTMR0_IRQn);
lp_ticker_inited = true;
} else {
LPTMR_DisableInterrupts(LPTMR0, kLPTMR_TimerInterruptEnable);
}
lp_ticker_inited = true;
/* Setup low resolution clock - RTC */
if (!rtc_isenabled()) {
rtc_init();
RTC_DisableInterrupts(RTC, kRTC_AlarmInterruptEnable | kRTC_SecondsInterruptEnable);
RTC_StartTimer(RTC);
}
RTC->TAR = 0; /* Write clears the IRQ flag */
NVIC_ClearPendingIRQ(RTC_IRQn);
NVIC_SetVector(RTC_IRQn, (uint32_t)rtc_isr);
NVIC_EnableIRQ(RTC_IRQn);
/* Setup high resolution clock - LPTMR */
LPTMR_GetDefaultConfig(&lptmrConfig);
/* Use 32kHz drive */
CLOCK_SetXtal32Freq(OSC32K_CLK_HZ);
lptmrConfig.prescalerClockSource = kLPTMR_PrescalerClock_2;
LPTMR_Init(LPTMR0, &lptmrConfig);
LPTMR_EnableInterrupts(LPTMR0, kLPTMR_TimerInterruptEnable);
NVIC_ClearPendingIRQ(LPTMR0_IRQn);
NVIC_SetVector(LPTMR0_IRQn, (uint32_t)lptmr_isr);
EnableIRQ(LPTMR0_IRQn);
}
/** Read the current counter
*
* @return The current timer's counter value in microseconds
* @return The current timer's counter value in ticks
*/
uint32_t lp_ticker_read(void)
{
uint32_t sec, pre;
if (!lp_ticker_inited) {
lp_ticker_init();
}
sec = RTC->TSR; /* 32b: Seconds */
pre = RTC->TPR; /* 16b: Increments every 32.768kHz clock cycle (30us) */
/* Final value: 11b (4095) for sec and 21b for usec (pre can reach 1,000,000us which is close to 1<<20) */
uint32_t ret = (((sec & MAX_SEC_MASK) * SEC_IN_USEC) + (((uint64_t)pre * SEC_IN_USEC) / OSC32K_CLK_HZ));
return ret;
return LPTMR_GetCurrentTimerCount(LPTMR0);
}
/** Set interrupt for specified timestamp
*
* @param timestamp The time in microseconds to be set
* @param timestamp The time in ticks to be set
*/
void lp_ticker_set_interrupt(timestamp_t timestamp)
{
uint32_t now_us, delta_us, delta_ticks;
if (!lp_ticker_inited) {
lp_ticker_init();
}
lptmr_schedule = 0;
now_us = lp_ticker_read();
delta_us = timestamp >= now_us ? timestamp - now_us : (uint32_t)((uint64_t)timestamp + 0xFFFFFFFF - now_us);
/* Checking if LPTRM can handle this sleep */
delta_ticks = USEC_TO_COUNT(delta_us, CLOCK_GetFreq(kCLOCK_Er32kClk));
if (delta_ticks == 0) {
/* The requested delay is less than the minimum resolution of this counter */
delta_ticks = 1;
}
if (delta_ticks > MAX_LPTMR_SLEEP) {
/* Using RTC if wait time is over 16b (2s @32kHz) */
uint32_t delta_sec;
delta_us += COUNT_TO_USEC(RTC->TPR, CLOCK_GetFreq(kCLOCK_Er32kClk)); /* Accounting for started second */
delta_sec = delta_us / SEC_IN_USEC;
delta_us -= delta_sec * SEC_IN_USEC;
RTC->TAR = RTC->TSR + delta_sec - 1;
RTC_EnableInterrupts(RTC, kRTC_AlarmInterruptEnable);
/* Set aditional, subsecond, sleep time */
if (delta_us) {
lptmr_schedule = USEC_TO_COUNT(delta_us, CLOCK_GetFreq(kCLOCK_Er32kClk));
if (lptmr_schedule == 0) {
/* The requested delay is less than the minimum resolution of this counter */
lptmr_schedule = 1;
}
}
} else {
/* Below RTC resolution using LPTMR */
LPTMR_SetTimerPeriod(LPTMR0, delta_ticks);
LPTMR_EnableInterrupts(LPTMR0, kLPTMR_TimerInterruptEnable);
LPTMR_StartTimer(LPTMR0);
if (timestamp == 0) {
timestamp = 1;
}
LPTMR_SetTimerPeriod(LPTMR0, timestamp);
LPTMR_ClearStatusFlags(LPTMR0, kLPTMR_TimerCompareFlag);
LPTMR_EnableInterrupts(LPTMR0, kLPTMR_TimerInterruptEnable);
LPTMR_StartTimer(LPTMR0);
}
void lp_ticker_fire_interrupt(void)
@ -184,7 +107,6 @@ void lp_ticker_fire_interrupt(void)
void lp_ticker_disable_interrupt(void)
{
LPTMR_DisableInterrupts(LPTMR0, kLPTMR_TimerInterruptEnable);
RTC_DisableInterrupts(RTC, kRTC_AlarmInterruptEnable);
}
/** Clear the low power ticker interrupt
@ -192,8 +114,7 @@ void lp_ticker_disable_interrupt(void)
*/
void lp_ticker_clear_interrupt(void)
{
RTC->TAR = 0; /* Write clears the IRQ flag */
LPTMR_ClearStatusFlags(LPTMR0, kLPTMR_TimerCompareFlag);
}
#endif /* DEVICE_LOWPOWERTIMER */
#endif /* DEVICE_LPTICKER */

View File

@ -15,7 +15,7 @@
*/
#include "rtc_api.h"
#if DEVICE_RTC
#if DEVICE_RTC || DEVICE_LPTICKER
#include "pinmap.h"
#include "fsl_rtc.h"
@ -23,6 +23,8 @@
extern void rtc_setup_oscillator(RTC_Type *base);
static bool rtc_time_set = false;
void rtc_init(void)
{
rtc_config_t rtcConfig;
@ -37,17 +39,30 @@ void rtc_init(void)
void rtc_free(void)
{
RTC_Deinit(RTC);
#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
/* Gate the module clock */
CLOCK_DisableClock(kCLOCK_Rtc0);
#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
}
/*
* Little check routine to see if the RTC has been enabled
* Little check routine to see if the RTC has been initialized and time has been set
* 0 = Disabled, 1 = Enabled
*/
int rtc_isenabled(void)
{
#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
CLOCK_EnableClock(kCLOCK_Rtc0);
return (int)((RTC->SR & RTC_SR_TCE_MASK) >> RTC_SR_TCE_SHIFT);
#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
const bool rtc_init_done = ((RTC->SR & RTC_SR_TCE_MASK) >> RTC_SR_TCE_SHIFT);
/* If RTC is not initialized, then disable the clock gate on exit. */
if(!rtc_init_done) {
rtc_free();
}
return (rtc_init_done & rtc_time_set);
}
time_t rtc_read(void)
@ -60,6 +75,8 @@ void rtc_write(time_t t)
RTC_StopTimer(RTC);
RTC->TSR = t;
RTC_StartTimer(RTC);
rtc_time_set = true;
}
#endif

View File

@ -33,6 +33,7 @@
#include "rtc_api.h"
#include "lp_ticker_api.h"
#include "ticker_api.h"
#include "cmsis.h"
#include "rtc_regs.h"
#include "pwrseq_regs.h"
@ -73,8 +74,10 @@ void rtc_init(void)
MXC_PWRSEQ->reg0 |= MXC_F_PWRSEQ_REG0_PWR_RTCEN_RUN;
// Prepare interrupt handlers
#ifdef DEVICE_LPTICKER
NVIC_SetVector(RTC0_IRQn, (uint32_t)lp_ticker_irq_handler);
NVIC_EnableIRQ(RTC0_IRQn);
#endif
NVIC_SetVector(RTC3_IRQn, (uint32_t)overflow_handler);
NVIC_EnableIRQ(RTC3_IRQn);
@ -235,20 +238,20 @@ void lp_ticker_fire_interrupt(void)
}
//******************************************************************************
inline void lp_ticker_disable_interrupt(void)
void lp_ticker_disable_interrupt(void)
{
MXC_RTCTMR->inten &= ~MXC_F_RTC_INTEN_COMP0;
}
//******************************************************************************
inline void lp_ticker_clear_interrupt(void)
void lp_ticker_clear_interrupt(void)
{
MXC_RTCTMR->flags = MXC_F_RTC_FLAGS_ASYNC_CLR_FLAGS;
MXC_PWRSEQ->flags = MXC_F_PWRSEQ_MSK_FLAGS_RTC_CMPR0;
}
//******************************************************************************
inline uint32_t lp_ticker_read(void)
uint32_t lp_ticker_read(void)
{
return rtc_read64();
}

View File

@ -31,6 +31,7 @@
*******************************************************************************
*/
#include <string.h>
#include "rtc_api.h"
#include "lp_ticker_api.h"
#include "rtc.h"
@ -83,78 +84,66 @@ static void init_rtc(void)
static void overflow_handler(void)
{
MXC_RTCTMR->comp[1] += ((UINT32_MAX >> LOG2(LP_TIMER_RATE_HZ)) + 1);
RTC_ClearFlags(MXC_F_RTC_FLAGS_ASYNC_CLR_FLAGS);
RTC_ClearFlags(MXC_F_RTC_FLAGS_OVERFLOW);
}
//******************************************************************************
void rtc_init(void)
{
if (rtc_inited) {
return;
}
NVIC_SetVector(RTC3_IRQn, (uint32_t)overflow_handler);
NVIC_EnableIRQ(RTC3_IRQn);
// Enable wakeup on RTC overflow
LP_ConfigRTCWakeUp(lp_ticker_inited, 0, 0, 1);
// Enable as LP wakeup source
MXC_PWRSEQ->msk_flags |= MXC_F_PWRSEQ_FLAGS_RTC_ROLLOVER;
init_rtc();
rtc_inited = 1;
}
//******************************************************************************
void rtc_free(void)
{
if (rtc_inited) {
rtc_inited = 0;
if (lp_ticker_inited) {
RTC_DisableINT(MXC_F_RTC_FLAGS_OVERFLOW);
} else {
MXC_RTCTMR->ctrl |= MXC_F_RTC_CTRL_CLEAR;
RTC_Stop();
}
}
while (MXC_RTCTMR->ctrl & MXC_F_RTC_CTRL_PENDING);
}
//******************************************************************************
int rtc_isenabled(void)
{
return rtc_inited;
return !!RTC_IsActive();
}
//******************************************************************************
void rtc_write(time_t t)
{
if (!rtc_inited) {
rtc_init();
}
MXC_RTCTMR->comp[1] = t - (MXC_RTCTMR->timer >> LOG2(LP_TIMER_RATE_HZ));
// Wait for pending transactions
while (MXC_RTCTMR->ctrl & MXC_F_RTC_CTRL_PENDING);
}
//******************************************************************************
time_t rtc_read(void)
{
if (!rtc_inited) {
rtc_init();
}
return (MXC_RTCTMR->timer >> LOG2(LP_TIMER_RATE_HZ)) + MXC_RTCTMR->comp[1];
}
//******************************************************************************
void lp_ticker_init(void)
{
if (lp_ticker_inited) {
return;
}
RTC_DisableINT(MXC_F_RTC_INTEN_COMP0);
NVIC_SetVector(RTC0_IRQn, (uint32_t)lp_ticker_irq_handler);
NVIC_EnableIRQ(RTC0_IRQn);
init_rtc();
lp_ticker_inited = 1;
}
//******************************************************************************
void lp_ticker_free(void)
{
// Disable interrupt associated with LPTICKER API
RTC_DisableINT(MXC_F_RTC_INTEN_COMP0);
// RTC hardware is shared by LPTICKER and RTC APIs.
// Prior initialization of the RTC API gates disabling the RTC hardware.
if (!(MXC_RTCTMR->inten & MXC_F_RTC_INTEN_OVERFLOW)) {
RTC_Stop();
}
}
//******************************************************************************
@ -167,13 +156,13 @@ uint32_t lp_ticker_read(void)
void lp_ticker_set_interrupt(timestamp_t timestamp)
{
MXC_RTCTMR->comp[0] = timestamp;
MXC_RTCTMR->flags = MXC_F_RTC_FLAGS_ASYNC_CLR_FLAGS;
MXC_RTCTMR->inten |= MXC_F_RTC_INTEN_COMP0;
MXC_RTCTMR->flags = MXC_F_RTC_FLAGS_COMP0;
RTC_EnableINT(MXC_F_RTC_INTEN_COMP0);
// Enable wakeup from RTC compare 0
LP_ConfigRTCWakeUp(1, 0, 0, rtc_inited);
// Enable as LP wakeup source
MXC_PWRSEQ->msk_flags |= MXC_F_PWRSEQ_FLAGS_RTC_CMPR0;
// Wait for pending transactions
// Postponed write pending wait for comp0 and flags
while (MXC_RTCTMR->ctrl & MXC_F_RTC_CTRL_PENDING);
}
@ -186,7 +175,7 @@ void lp_ticker_disable_interrupt(void)
//******************************************************************************
void lp_ticker_clear_interrupt(void)
{
RTC_ClearFlags(MXC_F_RTC_FLAGS_ASYNC_CLR_FLAGS);
RTC_ClearFlags(MXC_F_RTC_FLAGS_COMP0);
}
//******************************************************************************

Some files were not shown because too many files have changed in this diff Show More