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