mirror of https://github.com/ARMmbed/mbed-os.git
Merge pull request #7009 from bulislaw/merge_feature_branches_for_5.9
Bring in improved HAL APIs to masterpull/7035/head
commit
501a7b6949
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
|
@ -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
|
||||
|
||||
/**@}*/
|
|
@ -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);
|
||||
}
|
|
@ -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
|
||||
|
||||
/**@}*/
|
|
@ -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()
|
||||
|
|
|
@ -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
|
||||
|
||||
/**@}*/
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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
|
||||
|
||||
/** @}*/
|
|
@ -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();
|
||||
}
|
|
@ -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
|
||||
|
||||
/** @}*/
|
|
@ -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);
|
||||
}
|
|
@ -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
|
||||
|
||||
/**@}*/
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
|
@ -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
|
||||
|
||||
/**@}*/
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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*/
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
};
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -2079,7 +2079,7 @@ PREDEFINED = DOXYGEN_ONLY \
|
|||
DEVICE_I2C_ASYNCH \
|
||||
DEVICE_INTERRUPTIN \
|
||||
DEVICE_ITM \
|
||||
DEVICE_LOWPOWERTIMER \
|
||||
DEVICE_LPTICKER \
|
||||
DEVICE_PORTIN \
|
||||
DEVICE_PORTINOUT \
|
||||
DEVICE_PORTOUT \
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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"
|
||||
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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"
|
||||
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
140
hal/rtc_api.h
140
hal/rtc_api.h
|
@ -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
|
||||
|
||||
/** @}*/
|
||||
|
|
|
@ -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
|
||||
|
||||
/** @}*/
|
||||
/**@}*/
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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" {
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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
|
||||
*/
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -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
|
||||
}
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -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();
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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}
|
||||
};
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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}
|
||||
};
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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
Loading…
Reference in New Issue