![](/media/cache/img/default_profile.jpg.50x50_q85.jpg)
Color Oled(SSD1331) connect to STMicroelectronics Nucleo-F466
Diff: mbed-os/TESTS/mbed_hal/common_tickers_freq/main.cpp
- Revision:
- 0:8fdf9a60065b
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mbed-os/TESTS/mbed_hal/common_tickers_freq/main.cpp Wed Oct 10 00:33:53 2018 +0000 @@ -0,0 +1,211 @@ +/* + * 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" +#include "hal/mbed_lp_ticker_wrapper.h" + +#if !DEVICE_USTICKER +#error [NOT_SUPPORTED] test not supported +#endif + +//FastModels not support time drifting test +#if defined(__ARM_FM) +#error [NOT_SUPPORTED] test not supported +#endif + +#define US_PER_S 1000000 + +using namespace utest::v1; + +const ticker_interface_t *intf; +uint32_t intf_mask; +uint32_t intf_last_tick; +uint32_t intf_elapsed_ticks; +ticker_irq_handler_type prev_handler; + +uint32_t ticks_to_us(uint32_t ticks, uint32_t freq) +{ + return (uint32_t)((uint64_t)ticks * US_PER_S / freq); +} + +void elapsed_ticks_reset() +{ + core_util_critical_section_enter(); + + const uint32_t ticker_bits = intf->get_info()->bits; + + intf_mask = (1 << ticker_bits) - 1; + intf_last_tick = intf->read(); + intf_elapsed_ticks = 0; + + core_util_critical_section_exit(); +} + +uint32_t elapsed_ticks_update() +{ + core_util_critical_section_enter(); + + const uint32_t current_tick = intf->read(); + intf_elapsed_ticks += (current_tick - intf_last_tick) & intf_mask; + intf_last_tick = current_tick; + + /* Schedule next interrupt half way to overflow */ + uint32_t next = (current_tick + intf_mask / 2) & intf_mask; + intf->set_interrupt(next); + + uint32_t elapsed = intf_elapsed_ticks; + + core_util_critical_section_exit(); + return elapsed; +} + +void ticker_event_handler_stub(const ticker_data_t *const ticker) +{ + intf->clear_interrupt(); + elapsed_ticks_update(); +} + +/* 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; + + intf->init(); + + elapsed_ticks_reset(); + + /* Detect overflow for tickers with lower counters width. */ + elapsed_ticks_update(); + + 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); + + const uint32_t begin_ticks = elapsed_ticks_update(); + + /* 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 = elapsed_ticks_update(); + + greentea_send_kv(_key, ticks_to_us(end_ticks, 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) +{ +#if DEVICE_LPTICKER && (LPTICKER_DELAY_TICKS > 0) + /* Suspend the lp ticker wrapper since it makes use of the us ticker */ + ticker_suspend(get_lp_ticker_data()); + lp_ticker_wrapper_suspend(); +#endif + ticker_suspend(get_us_ticker_data()); + intf = get_us_ticker_data()->interface; + prev_handler = set_us_ticker_irq_handler(ticker_event_handler_stub); + return greentea_case_setup_handler(source, index_of_case); +} + +utest::v1::status_t us_ticker_case_teardown_handler_t(const Case *const source, const size_t passed, const size_t failed, + const failure_t reason) +{ + set_us_ticker_irq_handler(prev_handler); + ticker_resume(get_us_ticker_data()); +#if DEVICE_LPTICKER && (LPTICKER_DELAY_TICKS > 0) + lp_ticker_wrapper_resume(); + ticker_resume(get_lp_ticker_data()); +#endif + return greentea_case_teardown_handler(source, passed, failed, reason); +} + +#if DEVICE_LPTICKER +utest::v1::status_t lp_ticker_case_setup_handler_t(const Case *const source, const size_t index_of_case) +{ + ticker_suspend(get_lp_ticker_data()); + intf = get_lp_ticker_data()->interface; + prev_handler = set_lp_ticker_irq_handler(ticker_event_handler_stub); + return greentea_case_setup_handler(source, index_of_case); +} + +utest::v1::status_t lp_ticker_case_teardown_handler_t(const Case *const source, const size_t passed, const size_t failed, + const failure_t reason) +{ + set_lp_ticker_irq_handler(prev_handler); + ticker_resume(get_lp_ticker_data()); + return greentea_case_teardown_handler(source, passed, failed, reason); +} +#endif + +// Test cases +Case cases[] = { + Case("Microsecond ticker frequency test", us_ticker_case_setup_handler_t, ticker_frequency_test, + us_ticker_case_teardown_handler_t), +#if DEVICE_LPTICKER + Case("Low power ticker frequency test", lp_ticker_case_setup_handler_t, ticker_frequency_test, + lp_ticker_case_teardown_handler_t), +#endif +}; + +utest::v1::status_t greentea_test_setup(const size_t number_of_cases) +{ + /* Suspend RTOS Kernel so the timers are not in use. */ + osKernelSuspend(); + + GREENTEA_SETUP(120, "timing_drift_auto"); + return greentea_test_setup_handler(number_of_cases); +} + +void greentea_test_teardown(const size_t passed, const size_t failed, const failure_t failure) +{ + osKernelResume(0); + + greentea_test_teardown_handler(passed, failed, failure); +} + +Specification specification(greentea_test_setup, cases, greentea_test_teardown); + +int main() +{ + Harness::run(specification); +}