diff --git a/.codecheckignore b/.codecheckignore index c55a298..51c45db 100644 --- a/.codecheckignore +++ b/.codecheckignore @@ -17,6 +17,8 @@ ^storage/filesystem/littlefsv2/littlefs/ ^features/unsupported/ ^hal/storage_abstraction +^hal/tests/TESTS/mbed_hal/trng/pithy +^hal/tests/TESTS/mbed_hal/trng/pithy ^platform/cxxsupport ^platform/FEATURE_EXPERIMENTAL_API/FEATURE_PSA/TARGET_MBED_PSA_SRV ^platform/FEATURE_EXPERIMENTAL_API/FEATURE_PSA/TARGET_TFM @@ -25,8 +27,6 @@ ^rtos/source/TARGET_CORTEX/rtx4 ^rtos/source/TARGET_CORTEX/rtx5 ^targets -^TESTS/mbed_hal/trng/pithy -^TESTS/mbed_hal/trng/pithy ^tools ^UNITTESTS ^storage/blockdevice/tests/UNITTESTS diff --git a/TESTS/mbed_hal/common_tickers/main.cpp b/TESTS/mbed_hal/common_tickers/main.cpp deleted file mode 100644 index 442eb01..0000000 --- a/TESTS/mbed_hal/common_tickers/main.cpp +++ /dev/null @@ -1,634 +0,0 @@ -/* mbed Microcontroller Library - * Copyright (c) 2017 ARM Limited - * 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. - */ - -#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" -#include "hal/mbed_lp_ticker_wrapper.h" - -#ifdef MBED_CONF_RTOS_PRESENT -#ifdef __cplusplus -extern "C" { -#endif -#include "os_tick.h" -#ifdef __cplusplus -} -#endif // __cplusplus -#endif - -#if !DEVICE_USTICKER -#error [NOT_SUPPORTED] test not supported -#else - -#define US_PER_S 1000000 - -#define FORCE_OVERFLOW_TEST (false) -#define TICKER_INT_VAL 500 -#define TICKER_DELTA 10 - -#define LP_TICKER_OVERFLOW_DELTA1 0 // this will allow to detect that ticker counter rollovers to 0 -#define LP_TICKER_OVERFLOW_DELTA2 0 -#define US_TICKER_OVERFLOW_DELTA1 50 -#define US_TICKER_OVERFLOW_DELTA2 60 - -#define TICKER_100_TICKS 100 -#define TICKER_500_TICKS 500 - -#define MAX_FUNC_EXEC_TIME_US 20 -#define DELTA_FUNC_EXEC_TIME_US 5 -#define NUM_OF_CALLS 100 - -#define NUM_OF_CYCLES 100000 - -#define US_TICKER_OV_LIMIT 35000 -#define LP_TICKER_OV_LIMIT 4000 - -#define TICKS_TO_US(ticks, freq) ((uint32_t) ((uint64_t)ticks * US_PER_S /freq)) - -using namespace utest::v1; - -volatile int intFlag = 0; -const ticker_interface_t *intf; -ticker_irq_handler_type prev_irq_handler; -/* Some targets might fail overflow test uncertainly due to getting trapped in busy - * intf->read() loop. In the loop, some ticker values wouldn't get caught in time - * because of: - * 1. Lower CPU clock - * 2. Compiled code with worse performance - * 3. Interrupt at that time - * - * We fix it by checking small ticker value range rather than one exact ticker point - * in near overflow check. - */ -unsigned int ticker_overflow_delta1; -unsigned int ticker_overflow_delta2; - -/* Auxiliary function to count ticker ticks elapsed during execution of N cycles of empty while loop. - * Parameter is used to disable compiler optimisation. */ -MBED_NOINLINE -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 (core_util_is_isr_active()) { - intFlag++; - } -} - -void wait_cycles(volatile unsigned int cycles) -{ - while (cycles--); -} - -/* Auxiliary function to determine how long ticker function are executed. - * This function returns number of us between and - * taking into account counter roll-over, counter size and frequency. - */ -uint32_t diff_us(uint32_t start_ticks, uint32_t stop_ticks, const ticker_info_t *info) -{ - uint32_t counter_mask = ((1 << info->bits) - 1); - - uint32_t diff_ticks = ((stop_ticks - start_ticks) & counter_mask); - - return (uint32_t)((uint64_t) diff_ticks * US_PER_S / info->frequency); -} - -/* 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, 400, 500, 600, 700, 800, 900, 1000, 1100, 1200 }; - uint8_t run_count = 0; - const ticker_info_t *p_ticker_info = intf->get_info(); - - overflow_protect(); - - for (uint32_t i = 0; i < (sizeof(ticker_timeout) / sizeof(uint32_t)); i++) { - - /* Skip timeout if less than max allowed execution time of set_interrupt() - 20 us */ - if (TICKS_TO_US(ticker_timeout[i], p_ticker_info->frequency) < (MAX_FUNC_EXEC_TIME_US + DELTA_FUNC_EXEC_TIME_US)) { - continue; - } - - run_count++; - 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); - } - - /* At least 3 sub test cases must be executed. */ - TEST_ASSERT_MESSAGE(run_count >= 3, "At least 3 sub test cases must be executed"); -} - -/* 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_delta2) && - intf->read() <= (max_count - ticker_overflow_delta1)) { - /* Just wait. */ - } - - /* Now we are near/at the overflow point. Detect rollover. */ - while (intf->read() > ticker_overflow_delta1); - - 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_delta1); - 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; - const uint32_t repeat_count = 20; - const uint32_t max_inc_val = 100; - - uint32_t base_tick_count = count_ticks(num_of_cycles, 1); - uint32_t next_tick_count = base_tick_count; - uint32_t inc_val = 0; - uint32_t repeat_cnt = 0; - - while (inc_val < max_inc_val) { - next_tick_count = count_ticks(num_of_cycles + inc_val, 1); - - if (next_tick_count == base_tick_count) { - - /* Same tick count, so repeat 20 times and than - * increase num of cycles by 1. - */ - if (repeat_cnt == repeat_count) { - inc_val++; - repeat_cnt = 0; - } - - repeat_cnt++; - } else { - /* Check if we got 1 tick diff. */ - if (next_tick_count - base_tick_count == 1 || - base_tick_count - next_tick_count == 1) { - break; - } - - /* 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; - repeat_cnt = 0; - base_tick_count = count_ticks(num_of_cycles, 1); - } - } - - /* 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) -{ - int counter = NUM_OF_CALLS; - uint32_t start; - uint32_t stop; - - const ticker_info_t *us_ticker_info = get_us_ticker_data()->interface->get_info(); - - /* ---- Test ticker_read function. ---- */ - start = us_ticker_read(); - while (counter--) { - intf->read(); - } - stop = us_ticker_read(); - - TEST_ASSERT(diff_us(start, stop, us_ticker_info) < (NUM_OF_CALLS * (MAX_FUNC_EXEC_TIME_US + DELTA_FUNC_EXEC_TIME_US))); - - /* ---- Test ticker_clear_interrupt function. ---- */ - counter = NUM_OF_CALLS; - start = us_ticker_read(); - while (counter--) { - intf->clear_interrupt(); - } - stop = us_ticker_read(); - - TEST_ASSERT(diff_us(start, stop, us_ticker_info) < (NUM_OF_CALLS * (MAX_FUNC_EXEC_TIME_US + DELTA_FUNC_EXEC_TIME_US))); - - /* ---- Test ticker_set_interrupt function. ---- */ - counter = NUM_OF_CALLS; - start = us_ticker_read(); - while (counter--) { - intf->set_interrupt(0); - } - stop = us_ticker_read(); - - TEST_ASSERT(diff_us(start, stop, us_ticker_info) < (NUM_OF_CALLS * (MAX_FUNC_EXEC_TIME_US + DELTA_FUNC_EXEC_TIME_US))); - - /* ---- Test fire_interrupt function. ---- */ - counter = NUM_OF_CALLS; - /* Disable ticker interrupt which would interfere with speed test */ - core_util_critical_section_enter(); - start = us_ticker_read(); - while (counter--) { - intf->fire_interrupt(); - } - stop = us_ticker_read(); - core_util_critical_section_exit(); - - TEST_ASSERT(diff_us(start, stop, us_ticker_info) < (NUM_OF_CALLS * (MAX_FUNC_EXEC_TIME_US + DELTA_FUNC_EXEC_TIME_US))); - - /* ---- Test disable_interrupt function. ---- */ - counter = NUM_OF_CALLS; - start = us_ticker_read(); - while (counter--) { - intf->disable_interrupt(); - } - stop = us_ticker_read(); - - TEST_ASSERT(diff_us(start, stop, us_ticker_info) < (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; - -#ifdef MBED_CONF_RTOS_PRESENT - /* OS, common ticker and low power ticker wrapper - * may make use of us ticker so suspend them for this test */ - osKernelSuspend(); -#endif -#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->init(); - - prev_irq_handler = set_us_ticker_irq_handler(ticker_event_handler_stub); - - ticker_overflow_delta1 = US_TICKER_OVERFLOW_DELTA1; - ticker_overflow_delta2 = US_TICKER_OVERFLOW_DELTA2; - - 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; - - ticker_resume(get_us_ticker_data()); -#if DEVICE_LPTICKER && (LPTICKER_DELAY_TICKS > 0) - lp_ticker_wrapper_resume(); - ticker_resume(get_lp_ticker_data()); -#endif -#ifdef MBED_CONF_RTOS_PRESENT - osKernelResume(0); -#endif - - 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; - -#ifdef MBED_CONF_RTOS_PRESENT - /* OS and common ticker may make use of lp ticker so suspend them for this test */ - osKernelSuspend(); -#endif - ticker_suspend(get_lp_ticker_data()); - - intf->init(); - - prev_irq_handler = set_lp_ticker_irq_handler(ticker_event_handler_stub); - - ticker_overflow_delta1 = LP_TICKER_OVERFLOW_DELTA1; - ticker_overflow_delta2 = LP_TICKER_OVERFLOW_DELTA2; - - 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; - - ticker_resume(get_lp_ticker_data()); -#ifdef MBED_CONF_RTOS_PRESENT - osKernelResume(0); -#endif - - return greentea_case_teardown_handler(source, passed, failed, reason); -} -#endif - -utest::v1::status_t test_setup(const size_t number_of_cases) -{ - GREENTEA_SETUP(80, "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); -} -#endif // !DEVICE_USTICKER diff --git a/TESTS/mbed_hal/common_tickers/ticker_api_tests.h b/TESTS/mbed_hal/common_tickers/ticker_api_tests.h deleted file mode 100644 index d7e0a84..0000000 --- a/TESTS/mbed_hal/common_tickers/ticker_api_tests.h +++ /dev/null @@ -1,130 +0,0 @@ -/* mbed Microcontroller Library - * Copyright (c) 2017-2017 ARM Limited - * 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. - */ - -/** \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 - -/**@}*/ diff --git a/TESTS/mbed_hal/common_tickers_freq/main.cpp b/TESTS/mbed_hal/common_tickers_freq/main.cpp deleted file mode 100644 index fb4a886..0000000 --- a/TESTS/mbed_hal/common_tickers_freq/main.cpp +++ /dev/null @@ -1,215 +0,0 @@ -/* - * 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] UsTicker need to be enabled for this test -#else - -#if defined(SKIP_TIME_DRIFT_TESTS) -#error [NOT_SUPPORTED] timing accuracy tests skipped -#endif // defined(SKIP_TIME_DRIFT_TESTS) - -#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) -{ -#ifdef MBED_CONF_RTOS_PRESENT - /* Suspend RTOS Kernel so the timers are not in use. */ - osKernelSuspend(); -#endif - - 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) -{ -#ifdef MBED_CONF_RTOS_PRESENT - osKernelResume(0); -#endif - - greentea_test_teardown_handler(passed, failed, failure); -} - -Specification specification(greentea_test_setup, cases, greentea_test_teardown); - -int main() -{ - Harness::run(specification); -} - -#endif // !DEVICE_USTICKER diff --git a/TESTS/mbed_hal/common_tickers_freq/ticker_api_test_freq.h b/TESTS/mbed_hal/common_tickers_freq/ticker_api_test_freq.h deleted file mode 100644 index 8390044..0000000 --- a/TESTS/mbed_hal/common_tickers_freq/ticker_api_test_freq.h +++ /dev/null @@ -1,48 +0,0 @@ -/* mbed Microcontroller Library - * Copyright (c) 2017-2017 ARM Limited - * 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. - */ - -/** \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 - -/**@}*/ diff --git a/TESTS/mbed_hal/crc/crc_api_tests.h b/TESTS/mbed_hal/crc/crc_api_tests.h deleted file mode 100644 index cedd4e1..0000000 --- a/TESTS/mbed_hal/crc/crc_api_tests.h +++ /dev/null @@ -1,115 +0,0 @@ -/* mbed Microcontroller Library - * Copyright (c) 2018 ARM Limited - * 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. - */ - -/** \addtogroup hal_crc_tests */ -/** @{*/ - -#ifndef MBED_CRC_API_TESTS_H -#define MBED_CRC_API_TESTS_H - -#include "device.h" - -#if DEVICE_CRC - -#ifdef __cplusplus -extern "C" { -#endif - -/** Test that hal_crc_is_supported() function returns true if given polynomial/width - * is supported, false otherwise (at least one predefined polynomial/width must be supported). - * - * Given is platform with hardware CRC support. - * - * When given polynomial/width is supported. - * Then hal_crc_is_supported() function returns true. - * - * When given polynomial/width is not supported. - * Then hal_crc_is_supported() function returns false. - * - * Note: - * At least one predefined polynomial/width config must be supported. - * - */ -void crc_is_supported_test(); - -/** Test that CRC module can be successfully configured, fed with data and the result can - * be successfully obtained. - * - * Given is platform with hardware CRC support. - * - * When hal_crc_compute_partial_start() function is called. - * Then it configures CRC module with the given polynomial. - * - * When hal_crc_compute_partial() function is called with valid buffer and data length. - * Then it feeds CRC module with data. - * - * When hal_crc_get_result() function is called. - * Then CRC value for the given data is returned. - * - */ -void crc_calc_single_test(); - -/** Test that hal_crc_compute_partial() function can be call multiple times in - * succession in order to provide additional data to CRC module. - * - * Given is platform with hardware CRC support and CRC module is configured. - * When hal_crc_compute_partial() function is called multiple times. - * Then each call provides additional data to CRC module. - * - */ -void crc_calc_multi_test(); - -/** Test that calling hal_crc_compute_partial_start() without finalising the - * CRC calculation overrides the current configuration and partial result. - * - * Given is platform with hardware CRC support. - * When CRC module has been configured and fed with data and reconfigured (without reading the result). - * Then the configuration has been overwritten and the new data can be successfully processed. - * - */ -void crc_reconfigure_test(); - -/** Test that hal_crc_compute_partial() does nothing if pointer to buffer is undefined or - * data length is equal to 0. - * - * Given is platform with hardware CRC support. - * When hal_crc_compute_partial() is called with invalid parameters. - * Then no data is provided to CRC module and no exception is generated. - * - */ -void crc_compute_partial_invalid_param_test(); - -/** Test that hal_crc_is_supported() returns false if pointer to the config structure is undefined. - * - * Given is platform with hardware CRC support. - * When hal_crc_is_supported() is called with invalid parameter. - * Then function returns false. - * - */ -void crc_is_supported_invalid_param_test(); - -/**@}*/ - -#ifdef __cplusplus -} -#endif - -#endif - -#endif - -/**@}*/ diff --git a/TESTS/mbed_hal/crc/main.cpp b/TESTS/mbed_hal/crc/main.cpp deleted file mode 100644 index 58ac7d2..0000000 --- a/TESTS/mbed_hal/crc/main.cpp +++ /dev/null @@ -1,284 +0,0 @@ -/* mbed Microcontroller Library - * Copyright (c) 2018 ARM Limited - * 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. - */ -#include "utest/utest.h" -#include "unity/unity.h" -#include "greentea-client/test_env.h" -#include "mbed.h" -#include "math.h" -#include "crc_api.h" - -#if !DEVICE_CRC -#error [NOT_SUPPORTED] CRC not supported for this target -#else - -using namespace utest::v1; - -#define POLY_8BIT_MAXIM 0x31 - -#define UNSUPPORTED (-1) -#define POL_CNT (2) - -const uint8_t input_data[] = "123456789"; - -typedef struct { - const crc_mbed_config config_data; - uint32_t expected_result; - -} TEST_CASE; - -/* We will allocate test case array on stack since memory limits on some boards - * like NUCLEO_F070RB. */ -static TEST_CASE *test_cases; -static uint32_t test_cases_size; - -/* Test that hal_crc_is_supported() function returns true if given polynomial - * is supported, false otherwise (at least one polynomial from the predefined list must be supported). */ -void crc_is_supported_test() -{ - /* Check if at least one crc polynomial/config is supported. */ - uint32_t num_of_supported_polynomials = 0; - - for (unsigned int i = 0; i < (test_cases_size / sizeof(TEST_CASE)); i++) { - if (HAL_CRC_IS_SUPPORTED(test_cases[i].config_data.polynomial, test_cases[i].config_data.width)) { - - num_of_supported_polynomials++; - } - } - - TEST_ASSERT(num_of_supported_polynomials > 0); -} - -/* Test that CRC module can be successfully configured, fed with data and the result can - * be successfully obtained. */ -void crc_calc_single_test() -{ - for (unsigned int i = 0; i < (test_cases_size / sizeof(TEST_CASE)); i++) { - if (HAL_CRC_IS_SUPPORTED(test_cases[i].config_data.polynomial, test_cases[i].config_data.width)) { - - hal_crc_compute_partial_start(&test_cases[i].config_data); - hal_crc_compute_partial((uint8_t *) input_data, strlen((const char *) input_data)); - const uint32_t crc = hal_crc_get_result(); - - TEST_ASSERT_EQUAL(test_cases[i].expected_result, crc); - } - } -} - -/* Test that hal_crc_compute_partial() function can be call multiple times in - * succession in order to provide additional data to CRC module. */ -void crc_calc_multi_test() -{ - for (unsigned int i = 0; i < (test_cases_size / sizeof(TEST_CASE)); i++) { - if (HAL_CRC_IS_SUPPORTED(test_cases[i].config_data.polynomial, test_cases[i].config_data.width)) { - - const uint32_t first_part_bytes = 3; - const uint32_t second_part_bytes = 1; - const uint32_t third_part_bytes = strlen((const char *) input_data) - first_part_bytes - - second_part_bytes; - - hal_crc_compute_partial_start(&test_cases[i].config_data); - hal_crc_compute_partial((uint8_t *) input_data, first_part_bytes); - hal_crc_compute_partial((uint8_t *)(input_data + first_part_bytes), second_part_bytes); - hal_crc_compute_partial((uint8_t *)(input_data + first_part_bytes + second_part_bytes), - third_part_bytes); - const uint32_t crc = hal_crc_get_result(); - - TEST_ASSERT_EQUAL(test_cases[i].expected_result, crc); - } - } -} - -/* Test that calling hal_crc_compute_partial_start() without finalising the - * CRC calculation overrides the current configuration. */ -void crc_reconfigure_test() -{ - int pol_idx[POL_CNT] = - { UNSUPPORTED, UNSUPPORTED }; - int pol_cnt = 0; - const uint8_t dummy_input_data[] = "abcdefghijklmnopqrstuvwxyz"; - - /* At least one configuration must be supported. If two are supported, then - * re-initialize CRC module using different config. */ - for (unsigned int i = 0; i < (test_cases_size / sizeof(TEST_CASE)); i++) { - - /* Find two supported polynomials if possible. */ - if (HAL_CRC_IS_SUPPORTED(test_cases[i].config_data.polynomial, test_cases[i].config_data.width)) { - if (pol_cnt == 0) { - pol_idx[pol_cnt] = i; - pol_cnt++; - } else if (test_cases[pol_idx[0]].config_data.polynomial != test_cases[i].config_data.polynomial) { - pol_idx[pol_cnt] = i; - pol_cnt++; - } - - if (pol_cnt == POL_CNT) { - break; - } - } - } - - pol_cnt = 0; - - /* Init CRC module and provide some data, but do not read the result. */ - hal_crc_compute_partial_start(&test_cases[pol_idx[pol_cnt]].config_data); - hal_crc_compute_partial((uint8_t *) dummy_input_data, strlen((const char *) dummy_input_data)); - - /* Change index only if more than one supported polynomial has been found. */ - if (pol_idx[POL_CNT - 1] != UNSUPPORTED) { - pol_cnt++; - } - - /* Now re-init CRC module and provide new data and check the result. */ - hal_crc_compute_partial_start(&test_cases[pol_idx[pol_cnt]].config_data); - hal_crc_compute_partial((uint8_t *) input_data, strlen((const char *) input_data)); - const uint32_t crc = hal_crc_get_result(); - - TEST_ASSERT_EQUAL(test_cases[pol_idx[pol_cnt]].expected_result, crc); -} - -/* Test that hal_crc_compute_partial() does nothing if pointer to buffer is undefined or - * data length is equal to 0. */ -void crc_compute_partial_invalid_param_test() -{ - uint32_t crc = 0; - - /* At least one polynomial must be supported. */ - for (unsigned int i = 0; i < (test_cases_size / sizeof(TEST_CASE)); i++) { - if (HAL_CRC_IS_SUPPORTED(test_cases[i].config_data.polynomial, test_cases[i].config_data.width)) { - - hal_crc_compute_partial_start(&test_cases[i].config_data); - - /* Call hal_crc_compute_partial() with invalid parameters. */ - hal_crc_compute_partial((uint8_t *) NULL, strlen((const char *) input_data)); - hal_crc_compute_partial((uint8_t *) input_data, 0); - - /* Now use valid parameters. */ - hal_crc_compute_partial((uint8_t *) input_data, - strlen((const char *) input_data)); - - crc = hal_crc_get_result(); - - TEST_ASSERT_EQUAL(test_cases[i].expected_result, crc); - - break; - } - } -} - -Case cases[] = { - Case("test: supported polynomials.", crc_is_supported_test), - Case("test: CRC calculation - single input.", crc_calc_single_test), - Case("test: CRC calculation - multi input.", crc_calc_multi_test), - Case("test: re-configure without getting the result.", crc_reconfigure_test), - Case("test: hal_crc_compute_partial() - invalid parameters.", crc_compute_partial_invalid_param_test), -}; - -utest::v1::status_t greentea_test_setup(const size_t number_of_cases) -{ - GREENTEA_SETUP(30, "default_auto"); - return greentea_test_setup_handler(number_of_cases); -} - -Specification specification(greentea_test_setup, cases, greentea_test_teardown_handler); - -int main() -{ - // *INDENT-OFF* - TEST_CASE local_test_cases[] = { - /* Predefined polynomials. */ - { {POLY_7BIT_SD , 7, 0x00000000, 0x00000000, false, false}, 0x75 }, - { {POLY_7BIT_SD , 7, 0x0000007F, 0x00000000, false, false}, 0x50 }, - { {POLY_7BIT_SD , 7, 0x0000002B, 0x00000000, false, false}, 0x3A }, - { {POLY_7BIT_SD , 7, 0x00000000, 0x0000007F, false, false}, 0x0A }, - { {POLY_7BIT_SD , 7, 0x00000000, 0x0000002B, false, false}, 0x5E }, - { {POLY_7BIT_SD , 7, 0x00000000, 0x00000000, true , false}, 0x52 }, - { {POLY_7BIT_SD , 7, 0x00000000, 0x00000000, false, true }, 0x57 }, - { {POLY_7BIT_SD , 7, 0x0000002B, 0x00000000, true , false}, 0x1D }, - { {POLY_7BIT_SD , 7, 0x0000002B, 0x00000000, false, true }, 0x2E }, - { {POLY_7BIT_SD , 7, 0x0000002B, 0x00000000, true , true }, 0x5C }, - { {POLY_7BIT_SD , 7, 0x00000000, 0x0000002B, false, true }, 0x7C }, - - { {POLY_8BIT_CCITT , 8, 0x00000000, 0x00000000, false, false}, 0xF4 }, - { {POLY_8BIT_CCITT , 8, 0x000000FF, 0x00000000, false, false}, 0xFB }, - { {POLY_8BIT_CCITT , 8, 0x000000AB, 0x00000000, false, false}, 0x87 }, - { {POLY_8BIT_CCITT , 8, 0x00000000, 0x000000FF, false, false}, 0x0B }, - { {POLY_8BIT_CCITT , 8, 0x00000000, 0x000000AB, false, false}, 0x5F }, - { {POLY_8BIT_CCITT , 8, 0x00000000, 0x00000000, true , false}, 0x04 }, - { {POLY_8BIT_CCITT , 8, 0x00000000, 0x00000000, false, true }, 0x2F }, - { {POLY_8BIT_CCITT , 8, 0x000000AB, 0x00000000, true, false}, 0x77 }, - { {POLY_8BIT_CCITT , 8, 0x000000AB, 0x00000000, false, true }, 0xE1 }, - { {POLY_8BIT_CCITT , 8, 0x000000AB, 0x00000000, true, true }, 0xEE }, - { {POLY_8BIT_CCITT , 8, 0x00000000, 0x000000AB, false, true }, 0x84 }, - - { {POLY_16BIT_CCITT , 16, 0x00000000, 0x00000000, false, false}, 0x31C3 }, - { {POLY_16BIT_CCITT , 16, 0x0000FFFF, 0x00000000, false, false}, 0x29B1 }, - { {POLY_16BIT_CCITT , 16, 0x0000ABAB, 0x00000000, false, false}, 0x7D70 }, - { {POLY_16BIT_CCITT , 16, 0x00000000, 0x0000FFFF, false, false}, 0xCE3C }, - { {POLY_16BIT_CCITT , 16, 0x00000000, 0x0000ABAB, false, false}, 0x9A68 }, - { {POLY_16BIT_CCITT , 16, 0x00000000, 0x00000000, true , false}, 0x9184 }, - { {POLY_16BIT_CCITT , 16, 0x00000000, 0x00000000, false, true }, 0xC38C }, - { {POLY_16BIT_CCITT , 16, 0x0000ABAB, 0x00000000, true, false}, 0xDD37 }, - { {POLY_16BIT_CCITT , 16, 0x0000ABAB, 0x00000000, false, true }, 0x0EBE }, - { {POLY_16BIT_CCITT , 16, 0x0000ABAB, 0x00000000, true, true }, 0xECBB }, - { {POLY_16BIT_CCITT , 16, 0x00000000, 0x0000ABAB, false, true }, 0x6827 }, - - { {POLY_16BIT_IBM , 16, 0x00000000, 0x00000000, false, false}, 0xFEE8 }, - { {POLY_16BIT_IBM , 16, 0x0000FFFF, 0x00000000, false, false}, 0xAEE7 }, - { {POLY_16BIT_IBM , 16, 0x0000ABAB, 0x00000000, false, false}, 0x0887 }, - { {POLY_16BIT_IBM , 16, 0x00000000, 0x0000FFFF, false, false}, 0x0117 }, - { {POLY_16BIT_IBM , 16, 0x00000000, 0x0000ABAB, false, false}, 0x5543 }, - { {POLY_16BIT_IBM , 16, 0x00000000, 0x00000000, true , false}, 0xBCDD }, - { {POLY_16BIT_IBM , 16, 0x00000000, 0x00000000, false, true }, 0x177F }, - { {POLY_16BIT_IBM , 16, 0x0000ABAB, 0x00000000, true, false}, 0x4AB2 }, - { {POLY_16BIT_IBM , 16, 0x0000ABAB, 0x00000000, false, true }, 0xE110 }, - { {POLY_16BIT_IBM , 16, 0x0000ABAB, 0x00000000, true, true }, 0x4D52 }, - { {POLY_16BIT_IBM , 16, 0x00000000, 0x0000ABAB, false, true }, 0xBCD4 }, - - { {POLY_32BIT_ANSI , 32, 0x00000000, 0x00000000, false, false}, 0x89A1897F }, - { {POLY_32BIT_ANSI , 32, 0xFFFFFFFF, 0x00000000, false, false}, 0x0376E6E7 }, - { {POLY_32BIT_ANSI , 32, 0xABABABAB, 0x00000000, false, false}, 0x871A2FAA }, - { {POLY_32BIT_ANSI , 32, 0x00000000, 0xFFFFFFFF, false, false}, 0x765E7680 }, - { {POLY_32BIT_ANSI , 32, 0x00000000, 0xABABABAB, false, false}, 0x220A22D4 }, - { {POLY_32BIT_ANSI , 32, 0x00000000, 0x00000000, true , false}, 0x11B4BFB4 }, - { {POLY_32BIT_ANSI , 32, 0x00000000, 0x00000000, false, true }, 0xFE918591 }, - { {POLY_32BIT_ANSI , 32, 0xABABABAB, 0x00000000, true, false}, 0x1F0F1961 }, - { {POLY_32BIT_ANSI , 32, 0xABABABAB, 0x00000000, false, true }, 0x55F458E1 }, - { {POLY_32BIT_ANSI , 32, 0xABABABAB, 0x00000000, true, true }, 0x8698F0F8 }, - { {POLY_32BIT_ANSI , 32, 0x00000000, 0xABABABAB, false, true }, 0x553A2E3A }, - - /* Not-predefined polynomials. */ - { {POLY_8BIT_MAXIM , 8, 0x00000000, 0x00000000, false, false}, 0xA2 }, - { {POLY_8BIT_MAXIM , 8, 0x000000FF, 0x00000000, false, false}, 0xF7 }, - { {POLY_8BIT_MAXIM , 8, 0x000000AB, 0x00000000, false, false}, 0x71 }, - { {POLY_8BIT_MAXIM , 8, 0x00000000, 0x000000FF, false, false}, 0x5D }, - { {POLY_8BIT_MAXIM , 8, 0x00000000, 0x000000AB, false, false}, 0x09 }, - { {POLY_8BIT_MAXIM , 8, 0x00000000, 0x00000000, true , false}, 0x85 }, - { {POLY_8BIT_MAXIM , 8, 0x00000000, 0x00000000, false, true }, 0x45 }, - { {POLY_8BIT_MAXIM , 8, 0x000000AB, 0x00000000, true, false}, 0x56 }, - { {POLY_8BIT_MAXIM , 8, 0x000000AB, 0x00000000, false, true }, 0x8E }, - { {POLY_8BIT_MAXIM , 8, 0x000000AB, 0x00000000, true, true }, 0x6A }, - { {POLY_8BIT_MAXIM , 8, 0x00000000, 0x000000AB, false, true }, 0xEE }, - }; - // *INDENT-ON* - - test_cases = local_test_cases; - test_cases_size = sizeof(local_test_cases); - - Harness::run(specification); -} - -#endif // !DEVICE_CRC diff --git a/TESTS/mbed_hal/critical_section/critical_section_test.h b/TESTS/mbed_hal/critical_section/critical_section_test.h deleted file mode 100644 index d3b882a..0000000 --- a/TESTS/mbed_hal/critical_section/critical_section_test.h +++ /dev/null @@ -1,55 +0,0 @@ -/* mbed Microcontroller Library - * Copyright (c) 2018 ARM Limited - * 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. - */ - -/** \addtogroup hal_critical - * @{ - * \defgroup hal_critical_test Tests - * Tests definitions of the HAL Critical module. - * @{ - */ - -#ifndef MBED_CRITICAL_SECTION_TEST_H -#define MBED_CRITICAL_SECTION_TEST_H - -/** Template for HAL critical section tests - * - * Test critical section - * Given a critical section HAL mechanism - * When before critical section - * Then interrupts are enabled - * When inside critical section - * Then interrupts are disabled - * When after critical section - * Then interrupts are enabled again - * - * Test critical section - nested lock - * Given a critical section HAL mechanism - * When before critical section - * Then interrupts are enabled - * When inside nested critical section - * Then interrupts are disabled - * When after nested critical section - * Then interrupts are enabled again - * - */ -template -void test_critical_section(); - -/**@}*/ -/**@}*/ - -#endif // MBED_CRITICAL_SECTION_TEST_H diff --git a/TESTS/mbed_hal/critical_section/main.cpp b/TESTS/mbed_hal/critical_section/main.cpp deleted file mode 100644 index 0741b0f..0000000 --- a/TESTS/mbed_hal/critical_section/main.cpp +++ /dev/null @@ -1,76 +0,0 @@ -/* mbed Microcontroller Library - * Copyright (c) 2018 ARM Limited - * 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. - */ -#include "critical_section_test.h" -#include "hal/critical_section_api.h" -#include "utest/utest.h" -#include "unity/unity.h" -#include "greentea-client/test_env.h" -#include "mbed.h" -#include "cmsis.h" -#if defined(TARGET_NRF5x) // for all NRF5x targets -#include "nrf_nvic.h" // for __NRF_NVIC_APP_IRQS_0 / __NRF_NVIC_APP_IRQS_1 -#endif - -using utest::v1::Case; - -bool test_are_interrupts_enabled(void) -{ -#if defined(__CORTEX_A9) - return ((__get_CPSR() & 0x80) == 0); -#else - return ((__get_PRIMASK() & 0x1) == 0); -#endif - -} - - -template -void test_critical_section() -{ - TEST_ASSERT_FALSE(hal_in_critical_section()); - TEST_ASSERT_TRUE(test_are_interrupts_enabled()); - - for (int i = 0; i < N; i++) { - hal_critical_section_enter(); - TEST_ASSERT_TRUE(hal_in_critical_section()); - TEST_ASSERT_FALSE(test_are_interrupts_enabled()); - } - - // assumed to be called once (according API) - hal_critical_section_exit(); - - TEST_ASSERT_FALSE(hal_in_critical_section()); - TEST_ASSERT_TRUE(test_are_interrupts_enabled()); -} - -Case cases[] = { - Case("Test critical section single lock", test_critical_section<1>), - Case("Test critical section nested lock", test_critical_section<10>) -}; - -utest::v1::status_t greentea_test_setup(const size_t number_of_cases) -{ - GREENTEA_SETUP(10, "default_auto"); - return utest::v1::greentea_test_setup_handler(number_of_cases); -} - -utest::v1::Specification specification(greentea_test_setup, cases); - -int main() -{ - return !utest::v1::Harness::run(specification); -} diff --git a/TESTS/mbed_hal/flash/functional_tests/main.cpp b/TESTS/mbed_hal/flash/functional_tests/main.cpp deleted file mode 100644 index b6dcc5d..0000000 --- a/TESTS/mbed_hal/flash/functional_tests/main.cpp +++ /dev/null @@ -1,273 +0,0 @@ -/* mbed Microcontroller Library - * Copyright (c) 2017 ARM Limited - * 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. - */ - -#if !DEVICE_FLASH -#error [NOT_SUPPORTED] Flash API not supported for this target -#else - -#include "utest/utest.h" -#include "unity/unity.h" -#include "greentea-client/test_env.h" -#include "platform/mbed_mpu_mgmt.h" - -#include "mbed.h" -#include "flash_api.h" - -using namespace utest::v1; - -#define TEST_CYCLES 10000000 - -#define ALLOWED_DRIFT_PPM (1000000/5000) //0.5% - -/* - return values to be checked are documented at: - http://arm-software.github.io/CMSIS_5/Pack/html/algorithmFunc.html#Verify -*/ - -#ifndef ALIGN_DOWN -#define ALIGN_DOWN(x, a) ((x)& ~((a) - 1)) -#endif - -static int timer_diff_start; - -static void erase_range(flash_t *flash, uint32_t addr, uint32_t size) -{ - while (size > 0) { - uint32_t sector_size = flash_get_sector_size(flash, addr); - TEST_ASSERT_NOT_EQUAL(0, sector_size); - int32_t ret = flash_erase_sector(flash, addr); - TEST_ASSERT_EQUAL_INT32(0, ret); - addr += sector_size; - size = size > sector_size ? size - sector_size : 0; - } -} -#if defined (__ICCARM__) -MBED_NOINLINE -static void delay_loop(uint32_t count) -{ - __asm volatile( - "loop: \n" - " SUBS %0, %0, #1 \n" - " BCS.n loop\n" - : "+r"(count) - : - : "cc" - ); -} -#elif defined ( __GNUC__ ) || defined(__ARMCC_VERSION) -MBED_NOINLINE -static void delay_loop(uint32_t count) -{ - __asm__ volatile( - "%=:\n\t" -#if defined(__thumb__) && !defined(__thumb2__) && !defined(__ARMCC_VERSION) - "SUB %0, #1\n\t" -#else - "SUBS %0, %0, #1\n\t" -#endif - "BCS %=b\n\t" - : "+l"(count) - : - : "cc" - ); -} -#endif - -MBED_NOINLINE -static int time_cpu_cycles(uint32_t cycles) -{ - Timer timer; - - core_util_critical_section_enter(); - - timer.start(); - - delay_loop(cycles); - - timer.stop(); - - core_util_critical_section_exit(); - - return timer.read_us(); -} - -void flash_init_test() -{ - timer_diff_start = time_cpu_cycles(TEST_CYCLES); - - flash_t test_flash; - int32_t ret = flash_init(&test_flash); - TEST_ASSERT_EQUAL_INT32(0, ret); - ret = flash_free(&test_flash); - TEST_ASSERT_EQUAL_INT32(0, ret); -} - -void flash_mapping_alignment_test() -{ - flash_t test_flash; - int32_t ret = flash_init(&test_flash); - TEST_ASSERT_EQUAL_INT32(0, ret); - - const uint32_t page_size = flash_get_page_size(&test_flash); - const uint32_t flash_start = flash_get_start_address(&test_flash); - const uint32_t flash_size = flash_get_size(&test_flash); - TEST_ASSERT_TRUE(page_size != 0UL); - - uint32_t sector_size = flash_get_sector_size(&test_flash, flash_start); - for (uint32_t offset = 0; offset < flash_size; offset += sector_size) { - const uint32_t sector_start = flash_start + offset; - sector_size = flash_get_sector_size(&test_flash, sector_start); - const uint32_t sector_end = sector_start + sector_size - 1; - const uint32_t end_sector_size = flash_get_sector_size(&test_flash, sector_end); - - // Sector size must be a valid value - TEST_ASSERT_NOT_EQUAL(MBED_FLASH_INVALID_SIZE, sector_size); - // Sector size must be greater than zero - TEST_ASSERT_NOT_EQUAL(0, sector_size); - // All flash sectors must be a multiple of page size - TEST_ASSERT_EQUAL(0, sector_size % page_size); - // Sector address must be a multiple of sector size - TEST_ASSERT_EQUAL(0, sector_start % sector_size); - // All address in a sector must return the same sector size - TEST_ASSERT_EQUAL(sector_size, end_sector_size); - } - - // Make sure unmapped flash is reported correctly - TEST_ASSERT_EQUAL(MBED_FLASH_INVALID_SIZE, flash_get_sector_size(&test_flash, flash_start - 1)); - TEST_ASSERT_EQUAL(MBED_FLASH_INVALID_SIZE, flash_get_sector_size(&test_flash, flash_start + flash_size)); - - ret = flash_free(&test_flash); - TEST_ASSERT_EQUAL_INT32(0, ret); -} - -void flash_erase_sector_test() -{ - flash_t test_flash; - int32_t ret = flash_init(&test_flash); - TEST_ASSERT_EQUAL_INT32(0, ret); - - uint32_t addr_after_last = flash_get_start_address(&test_flash) + flash_get_size(&test_flash); - uint32_t last_sector_size = flash_get_sector_size(&test_flash, addr_after_last - 1); - uint32_t last_sector = addr_after_last - last_sector_size; - TEST_ASSERT_EQUAL_INT32(0, last_sector % last_sector_size); - - utest_printf("ROM ends at 0x%lx, test starts at 0x%lx\n", FLASHIAP_APP_ROM_END_ADDR, last_sector); - TEST_SKIP_UNLESS_MESSAGE(last_sector >= FLASHIAP_APP_ROM_END_ADDR, "Test skipped. Test region overlaps code."); - - ret = flash_erase_sector(&test_flash, last_sector); - TEST_ASSERT_EQUAL_INT32(0, ret); - - ret = flash_free(&test_flash); - TEST_ASSERT_EQUAL_INT32(0, ret); -} - -// Erase sector, write one page, erase sector and write new data -void flash_program_page_test() -{ - flash_t test_flash; - int32_t ret = flash_init(&test_flash); - TEST_ASSERT_EQUAL_INT32(0, ret); - - uint32_t test_size = flash_get_page_size(&test_flash); - uint8_t *data = new uint8_t[test_size]; - uint8_t *data_flashed = new uint8_t[test_size]; - for (uint32_t i = 0; i < test_size; i++) { - data[i] = 0xCE; - } - - // the one before the last page in the system - uint32_t address = flash_get_start_address(&test_flash) + flash_get_size(&test_flash) - (2 * test_size); - - // sector size might not be same as page size - uint32_t erase_sector_boundary = ALIGN_DOWN(address, flash_get_sector_size(&test_flash, address)); - utest_printf("ROM ends at 0x%lx, test starts at 0x%lx\n", FLASHIAP_APP_ROM_END_ADDR, erase_sector_boundary); - TEST_SKIP_UNLESS_MESSAGE(erase_sector_boundary >= FLASHIAP_APP_ROM_END_ADDR, "Test skipped. Test region overlaps code."); - - ret = flash_erase_sector(&test_flash, erase_sector_boundary); - TEST_ASSERT_EQUAL_INT32(0, ret); - - ret = flash_program_page(&test_flash, address, data, test_size); - TEST_ASSERT_EQUAL_INT32(0, ret); - - ret = flash_read(&test_flash, address, data_flashed, test_size); - TEST_ASSERT_EQUAL_INT32(0, ret); - TEST_ASSERT_EQUAL_UINT8_ARRAY(data, data_flashed, test_size); - - // sector size might not be same as page size - erase_sector_boundary = ALIGN_DOWN(address, flash_get_sector_size(&test_flash, address)); - ret = flash_erase_sector(&test_flash, erase_sector_boundary); - TEST_ASSERT_EQUAL_INT32(0, ret); - - // write another data to be certain we are re-flashing - for (uint32_t i = 0; i < test_size; i++) { - data[i] = 0xAC; - } - ret = flash_program_page(&test_flash, address, data, test_size); - TEST_ASSERT_EQUAL_INT32(0, ret); - - ret = flash_read(&test_flash, address, data_flashed, test_size); - TEST_ASSERT_EQUAL_INT32(0, ret); - TEST_ASSERT_EQUAL_UINT8_ARRAY(data, data_flashed, test_size); - - ret = flash_free(&test_flash); - TEST_ASSERT_EQUAL_INT32(0, ret); - delete[] data; - delete[] data_flashed; -} - -// check the execution speed at the start and end of the test to make sure -// cache settings weren't changed -void flash_clock_and_cache_test() -{ - const int timer_diff_end = time_cpu_cycles(TEST_CYCLES); - const int acceptable_range = timer_diff_start / (ALLOWED_DRIFT_PPM); - TEST_ASSERT_UINT32_WITHIN(acceptable_range, timer_diff_start, timer_diff_end); -} - -Case cases[] = { - Case("Flash - init", flash_init_test), - Case("Flash - mapping alignment", flash_mapping_alignment_test), - Case("Flash - erase sector", flash_erase_sector_test), - Case("Flash - program page", flash_program_page_test), - Case("Flash - clock and cache test", flash_clock_and_cache_test), -}; - -utest::v1::status_t greentea_test_setup(const size_t number_of_cases) -{ - mbed_mpu_manager_lock_ram_execution(); - mbed_mpu_manager_lock_rom_write(); - - GREENTEA_SETUP(20, "default_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) -{ - mbed_mpu_manager_unlock_ram_execution(); - mbed_mpu_manager_unlock_rom_write(); - - greentea_test_teardown_handler(passed, failed, failure); -} - -Specification specification(greentea_test_setup, cases, greentea_test_teardown); - -int main() -{ - Harness::run(specification); -} - -#endif !DEVICE_FLASH diff --git a/TESTS/mbed_hal/gpio/main.cpp b/TESTS/mbed_hal/gpio/main.cpp deleted file mode 100644 index 2281957..0000000 --- a/TESTS/mbed_hal/gpio/main.cpp +++ /dev/null @@ -1,57 +0,0 @@ -/* mbed Microcontroller Library - * Copyright (c) 2019 ARM Limited - * 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. - */ - -#include "utest/utest.h" -#include "unity/unity.h" -#include "greentea-client/test_env.h" - -using namespace utest::v1; - -#include "PinNames.h" -#include "gpio_api.h" - -static void gpio_nc_test() -{ - gpio_t nc_obj; - gpio_init(&nc_obj, NC); - TEST_ASSERT_FALSE(gpio_is_connected(&nc_obj)); - - gpio_t led_obj; - gpio_init(&led_obj, LED1); - if (LED1 == NC) { - TEST_ASSERT_FALSE(gpio_is_connected(&led_obj)); - } else { - TEST_ASSERT_TRUE(gpio_is_connected(&led_obj)); - } -} - -Case cases[] = { - Case("gpio NC test", gpio_nc_test) -}; - -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); -} diff --git a/TESTS/mbed_hal/lp_ticker/lp_ticker_api_tests.h b/TESTS/mbed_hal/lp_ticker/lp_ticker_api_tests.h deleted file mode 100644 index 0fbb3a5..0000000 --- a/TESTS/mbed_hal/lp_ticker/lp_ticker_api_tests.h +++ /dev/null @@ -1,63 +0,0 @@ -/* mbed Microcontroller Library - * Copyright (c) 2017-2017 ARM Limited - * 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. - */ - -/** \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 - -/**@}*/ diff --git a/TESTS/mbed_hal/lp_ticker/main.cpp b/TESTS/mbed_hal/lp_ticker/main.cpp deleted file mode 100644 index 7331edf..0000000 --- a/TESTS/mbed_hal/lp_ticker/main.cpp +++ /dev/null @@ -1,214 +0,0 @@ -/* mbed Microcontroller Library - * Copyright (c) 2017 ARM Limited - * 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. - */ - -#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" -#include "hal/mbed_lp_ticker_wrapper.h" -#include "hal/us_ticker_api.h" - -#if !DEVICE_LPTICKER -#error [NOT_SUPPORTED] Low power timer not supported for this target -#else - -using namespace utest::v1; - -volatile int intFlag = 0; - -ticker_irq_handler_type prev_handler; - -#define US_PER_MS 1000 - -#define TICKER_GLITCH_TEST_TICKS 1000 - -#define TICKER_INT_VAL 500 -#define TICKER_DELTA 10 - -#define LP_TICKER_OV_LIMIT 4000 - -/* To prevent a loss of Greentea data, the serial buffers have to be flushed - * before the UART peripheral shutdown. The UART shutdown happens when the - * device is entering the deepsleep mode or performing a reset. - * - * With the current API, it is not possible to check if the hardware buffers - * are empty. However, it is possible to determine the time required for the - * buffers to flush. - * - * Assuming the biggest Tx FIFO of 128 bytes (as for CY8CPROTO_062_4343W) - * and a default UART config (9600, 8N1), flushing the Tx FIFO wold take: - * (1 start_bit + 8 data_bits + 1 stop_bit) * 128 * 1000 / 9600 = 133.3 ms. - * To be on the safe side, set the wait time to 150 ms. - */ -#define SERIAL_FLUSH_TIME_MS 150 - -void busy_wait_ms(int ms) -{ - const ticker_data_t *const ticker = get_us_ticker_data(); - uint32_t start = ticker_read(ticker); - while ((ticker_read(ticker) - start) < (uint32_t)(ms * US_PER_MS)); -} - -/* 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() -{ - uint32_t time_window; - - time_window = LP_TICKER_OV_LIMIT; - - const uint32_t ticks_now = lp_ticker_read(); - const ticker_info_t *p_ticker_info = lp_ticker_get_info(); - - 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 (core_util_is_isr_active()) { - intFlag++; - } - - /* Clear and disable ticker interrupt. */ - lp_ticker_clear_interrupt(); - lp_ticker_disable_interrupt(); -} - -/* 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 -/* Test that the ticker continues operating in deep sleep mode. */ -void lp_ticker_deepsleep_test() -{ - intFlag = 0; - - lp_ticker_init(); - - /* Give some time Green Tea to finish UART transmission before entering - * deep-sleep mode. - */ - busy_wait_ms(SERIAL_FLUSH_TIME_MS); - - overflow_protect(); - - 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_test_check()); - - 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; - } -} - -#if DEVICE_LPTICKER -utest::v1::status_t lp_ticker_deepsleep_test_setup_handler(const Case *const source, const size_t index_of_case) -{ -#ifdef MBED_CONF_RTOS_PRESENT - /* disable everything using the lp ticker for this test */ - osKernelSuspend(); -#endif - ticker_suspend(get_lp_ticker_data()); -#if DEVICE_LPTICKER && (LPTICKER_DELAY_TICKS > 0) - lp_ticker_wrapper_suspend(); -#endif - 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_deepsleep_test_teardown_handler(const Case *const source, const size_t passed, const size_t failed, - const failure_t reason) -{ - set_lp_ticker_irq_handler(prev_handler); -#if DEVICE_LPTICKER && (LPTICKER_DELAY_TICKS > 0) - lp_ticker_wrapper_resume(); -#endif - ticker_resume(get_lp_ticker_data()); -#ifdef MBED_CONF_RTOS_PRESENT - osKernelResume(0); -#endif - return greentea_case_teardown_handler(source, passed, failed, reason); -} -#endif - -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("lp ticker info test", lp_ticker_info_test), -#if DEVICE_SLEEP - Case("lp ticker sleep test", lp_ticker_deepsleep_test_setup_handler, lp_ticker_deepsleep_test, lp_ticker_deepsleep_test_teardown_handler), -#endif - Case("lp ticker glitch test", lp_ticker_glitch_test) -}; - -Specification specification(test_setup, cases); - -int main() -{ - return !Harness::run(specification); -} - -#endif // !DEVICE_LPTICKER diff --git a/TESTS/mbed_hal/minimum_requirements/main.cpp b/TESTS/mbed_hal/minimum_requirements/main.cpp deleted file mode 100644 index 3e58adf..0000000 --- a/TESTS/mbed_hal/minimum_requirements/main.cpp +++ /dev/null @@ -1,73 +0,0 @@ -/* mbed Microcontroller Library - * Copyright (c) 2017 ARM Limited - * 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. - */ - -#include "utest/utest.h" -#include "unity/unity.h" -#include "greentea-client/test_env.h" - -#include "mbed.h" - -using namespace utest::v1; - -/** - * This test is intended to gate devices that do not have enough RAM to run - * Mbed os. Devices passing this test should have enough RAM to run all - * other Mbed OS tests. - * - * If your device does not pass this test, then you should determine the - * cause of high memory usage and fix it. If you cannot free enough memory, - * then you should turn off Mbed OS support for this device. - */ - -#define MIN_HEAP_SIZE 2048 -#define MIN_DATA_SIZE 2048 - -volatile uint8_t test_buffer[MIN_DATA_SIZE]; - -static void minimum_heap_test() -{ - void *mem = malloc(MIN_HEAP_SIZE); - TEST_ASSERT_NOT_EQUAL(NULL, mem); - free(mem); -} - -static void minimum_data_test() -{ - // Use test buffer so it is not optimized away - for (int i = 0; i < MIN_DATA_SIZE; i++) { - test_buffer[i] = i & 0xFF; - } -} - - -utest::v1::status_t greentea_test_setup(const size_t number_of_cases) -{ - GREENTEA_SETUP(30, "default_auto"); - return greentea_test_setup_handler(number_of_cases); -} - -Case cases[] = { - Case("Minimum heap test", minimum_heap_test), - Case("Minimum data test", minimum_data_test), -}; - -Specification specification(greentea_test_setup, cases, greentea_test_teardown_handler); - -int main() -{ - Harness::run(specification); -} diff --git a/TESTS/mbed_hal/mpu/main.cpp b/TESTS/mbed_hal/mpu/main.cpp deleted file mode 100644 index fe79ccb..0000000 --- a/TESTS/mbed_hal/mpu/main.cpp +++ /dev/null @@ -1,202 +0,0 @@ -/* mbed Microcontroller Library - * Copyright (c) 2017 ARM Limited - * 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. - */ - -#include "utest/utest.h" -#include "unity/unity.h" -#include "greentea-client/test_env.h" - -#include "cmsis.h" -#include - -#include "mpu_api.h" -#include "mpu_test.h" - -#if !DEVICE_MPU -#error [NOT_SUPPORTED] MPU API not supported for this target -#else - -using namespace utest::v1; - -#define HARDFAULT_IRQn ((IRQn_Type)-13) -#define MEMFAULT_IRQn ((IRQn_Type)-12) - -// Assembly return instruction: bx lr -#define ASM_BX_LR 0x4770 - -volatile uint32_t fault_count; -uint32_t real_hard_fault_handler; -uint32_t real_mem_fault_handler; - -static volatile uint16_t data_function = ASM_BX_LR; -static volatile uint16_t bss_function; - -static void clear_caches() -{ -#if defined(__CORTEX_M7) - /* Data cache clean and invalid */ - SCB_CleanInvalidateDCache(); - - /* Instruction cache invalid */ - SCB_InvalidateICache(); -#endif - - __ISB(); - __DSB(); - -} - -static void call_mem(const volatile uint16_t *mem_function) -{ - // or the address with 1 to ensure the thumb bit is set - ((void (*)())((uint32_t)mem_function | 1))(); -} - -static void hard_fault_handler_test() -{ - fault_count++; - mbed_mpu_enable_ram_xn(false); -} - -static void mpu_fault_test(const volatile uint16_t *mem_function) -{ - // Verify that the mpu causes faults when executing ram after init - fault_count = 0; - mbed_mpu_init(); - call_mem(mem_function); - TEST_ASSERT_EQUAL(1, fault_count); - - // Verify that the mpu can be turned off - fault_count = 0; - mbed_mpu_enable_ram_xn(false); - call_mem(mem_function); - TEST_ASSERT_EQUAL(0, fault_count); - - // Verify that the mpu can be turned back on - fault_count = 0; - mbed_mpu_enable_ram_xn(true); - call_mem(mem_function); - TEST_ASSERT_EQUAL(1, fault_count); - - // Verify that free turns off the mpu - fault_count = 0; - mbed_mpu_free(); - call_mem(mem_function); - TEST_ASSERT_EQUAL(0, fault_count); -} - -void mpu_init_test() -{ - for (int i = 0; i < 10; i++) { - mbed_mpu_init(); - } - - mbed_mpu_free(); -} - -void mpu_free_test() -{ - mbed_mpu_init(); - - // Enable the MPU - mbed_mpu_enable_ram_xn(true); - - // Free and ensure execution from RAM is allowed - mbed_mpu_free(); - - call_mem(&data_function); -} - -void mpu_fault_test_data() -{ - mpu_fault_test(&data_function); -} - -void mpu_fault_test_bss() -{ - bss_function = ASM_BX_LR; - clear_caches(); - mpu_fault_test(&bss_function); -} - -void mpu_fault_test_stack() -{ - uint16_t stack_function; - - stack_function = ASM_BX_LR; - clear_caches(); - mpu_fault_test(&stack_function); -} - -void mpu_fault_test_heap() -{ - uint16_t *heap_function = (uint16_t *)malloc(2); - - TEST_ASSERT_NOT_EQUAL(NULL, heap_function); - *heap_function = ASM_BX_LR; - clear_caches(); - mpu_fault_test(heap_function); - - free(heap_function); -} - -utest::v1::status_t fault_override_setup(const Case *const source, const size_t index_of_case) -{ - // Save old fault handlers and replace it with a new one - real_hard_fault_handler = NVIC_GetVector(HARDFAULT_IRQn); - real_mem_fault_handler = NVIC_GetVector(MEMFAULT_IRQn); - NVIC_SetVector(HARDFAULT_IRQn, (uint32_t)&hard_fault_handler_test); - NVIC_SetVector(MEMFAULT_IRQn, (uint32_t)&hard_fault_handler_test); - - return greentea_case_setup_handler(source, index_of_case); -} - -utest::v1::status_t fault_override_teardown(const Case *const source, const size_t passed, const size_t failed, - const failure_t reason) -{ - // Restore real fault handlers - NVIC_SetVector(HARDFAULT_IRQn, real_hard_fault_handler); - NVIC_SetVector(MEMFAULT_IRQn, real_mem_fault_handler); - - return greentea_case_teardown_handler(source, passed, failed, reason); -} - -Case cases[] = { - Case("MPU - init", fault_override_setup, mpu_init_test, fault_override_teardown), - Case("MPU - free", fault_override_setup, mpu_free_test, fault_override_teardown), -#if !((__ARM_ARCH_8M_BASE__ == 1U) || (__ARM_ARCH_8M_MAIN__ == 1U)) - // Skip fault tests for ARMv8-M until a fault handler hook is provided - Case("MPU - data fault", fault_override_setup, mpu_fault_test_data, fault_override_teardown), - Case("MPU - bss fault", fault_override_setup, mpu_fault_test_bss, fault_override_teardown), - Case("MPU - stack fault", fault_override_setup, mpu_fault_test_stack, fault_override_teardown), - Case("MPU - heap fault", fault_override_setup, mpu_fault_test_heap, fault_override_teardown) -#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); -} - -#endif // !DEVICE_MPU diff --git a/TESTS/mbed_hal/mpu/mpu_test.h b/TESTS/mbed_hal/mpu/mpu_test.h deleted file mode 100644 index 0a916ca..0000000 --- a/TESTS/mbed_hal/mpu/mpu_test.h +++ /dev/null @@ -1,95 +0,0 @@ -/* mbed Microcontroller Library - * Copyright (c) 2018-2018 ARM Limited - * 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. - */ - -/** \addtogroup hal_mpu_tests - * @{ - */ - -#ifndef MBED_MPU_TEST_H -#define MBED_MPU_TEST_H - -#if DEVICE_MPU - -#ifdef __cplusplus -extern "C" { -#endif - -/** Test that ::mbed_mpu_init can be called multiple times. - * - * Given board provides MPU. - * When ::mbed_mpu_init is called multiple times. - * Then ::mbed_mpu_init are successfully performed (no exception is generated). - * - */ -void mpu_init_test(void); - -/** Test that ::mbed_mpu_free disables the MPU - * - * Given board provides MPU. - * When ::mbed_mpu_free is called. - * Then execution from RAM is allowed. - * - */ -void mpu_free_test(void); - -/** Test that MPU protection works for global data - * - * Given board provides MPU. - * When RAM execution is disabled with a call to ::mbed_mpu_enable_ram_xn. - * Then execution from global initialized data results in a fault. - * - */ -void mpu_fault_test_data(void); - -/** Test that MPU protection works for zero initialized data - * - * Given board provides MPU. - * When RAM execution is disabled with a call to ::mbed_mpu_enable_ram_xn. - * Then execution from global uninitialized data results in a fault. - * - */ -void mpu_fault_test_bss(void); - -/** Test that MPU protection works for the stack - * - * Given board provides MPU. - * When RAM execution is disabled with a call to ::mbed_mpu_enable_ram_xn. - * Then execution from stack memory results in a fault. - * - */ -void mpu_fault_test_stack(void); - -/** Test that MPU protection works for the heap - * - * Given board provides MPU. - * When RAM execution is disabled with a call to ::mbed_mpu_enable_ram_xn. - * Then execution from heap memory results in a fault. - * - */ -void mpu_fault_test_heap(void); - -/**@}*/ - -#ifdef __cplusplus -} -#endif - -#endif - -#endif - -/** @}*/ diff --git a/TESTS/mbed_hal/pinmap/main.cpp b/TESTS/mbed_hal/pinmap/main.cpp deleted file mode 100644 index 1b87414..0000000 --- a/TESTS/mbed_hal/pinmap/main.cpp +++ /dev/null @@ -1,128 +0,0 @@ -/* mbed Microcontroller Library - * Copyright (c) 2019 ARM Limited - * 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. - */ - -#include "utest/utest.h" -#include "unity/unity.h" -#include "greentea-client/test_env.h" - -using namespace utest::v1; - -#include "analogin_api.h" -#include "analogout_api.h" -#include "can_api.h" -#include "i2c_api.h" -#include "pwmout_api.h" -#include "qspi_api.h" -#include "serial_api.h" -#include "spi_api.h" - -#define PINMAP_TEST_ENTRY(function) {function, #function} - -typedef const PinMap *(*get_pinmap_func_t)(void); -typedef struct { - get_pinmap_func_t function; - const char *name; -} pinmap_info_t; - -const pinmap_info_t pinmap_functions[] = { -#if DEVICE_ANALOGIN - PINMAP_TEST_ENTRY(analogin_pinmap), -#endif -#if DEVICE_ANALOGOUT - PINMAP_TEST_ENTRY(analogout_pinmap), -#endif -#if DEVICE_CAN - PINMAP_TEST_ENTRY(can_rd_pinmap), - PINMAP_TEST_ENTRY(can_td_pinmap), -#endif -#if DEVICE_I2C - PINMAP_TEST_ENTRY(i2c_master_sda_pinmap), - PINMAP_TEST_ENTRY(i2c_master_scl_pinmap), -#if DEVICE_I2CSLAVE - PINMAP_TEST_ENTRY(i2c_slave_sda_pinmap), - PINMAP_TEST_ENTRY(i2c_slave_scl_pinmap), -#endif -#endif -#if DEVICE_PWMOUT - PINMAP_TEST_ENTRY(pwmout_pinmap), -#endif -#if DEVICE_QSPI - PINMAP_TEST_ENTRY(qspi_master_sclk_pinmap), - PINMAP_TEST_ENTRY(qspi_master_ssel_pinmap), - PINMAP_TEST_ENTRY(qspi_master_data0_pinmap), - PINMAP_TEST_ENTRY(qspi_master_data1_pinmap), - PINMAP_TEST_ENTRY(qspi_master_data2_pinmap), - PINMAP_TEST_ENTRY(qspi_master_data3_pinmap), -#endif -#if DEVICE_SERIAL - PINMAP_TEST_ENTRY(serial_tx_pinmap), - PINMAP_TEST_ENTRY(serial_rx_pinmap), -#if DEVICE_SERIAL_FC - PINMAP_TEST_ENTRY(serial_cts_pinmap), - PINMAP_TEST_ENTRY(serial_rts_pinmap), -#endif -#endif -#if DEVICE_SPI - PINMAP_TEST_ENTRY(spi_master_mosi_pinmap), - PINMAP_TEST_ENTRY(spi_master_miso_pinmap), - PINMAP_TEST_ENTRY(spi_master_clk_pinmap), - PINMAP_TEST_ENTRY(spi_master_cs_pinmap), -#if DEVICE_SPISLAVE - PINMAP_TEST_ENTRY(spi_slave_mosi_pinmap), - PINMAP_TEST_ENTRY(spi_slave_miso_pinmap), - PINMAP_TEST_ENTRY(spi_slave_clk_pinmap), - PINMAP_TEST_ENTRY(spi_slave_cs_pinmap), -#endif -#endif - {NULL, NULL} -}; - -void pinmap_validation() -{ - for (size_t i = 0; i < sizeof(pinmap_functions) / sizeof(pinmap_functions[0]) - 1; i++) { - printf("Testing pinmap %s\r\n", pinmap_functions[i].name); - - get_pinmap_func_t function = pinmap_functions[i].function; - TEST_ASSERT_NOT_EQUAL(NULL, function); - - const PinMap *map = function(); - TEST_ASSERT_NOT_EQUAL(NULL, map); - - while (map->pin != NC) { - map++; - } - - TEST_ASSERT_EQUAL(NC, map->peripheral); - } -} - -Case cases[] = { - Case("pinmap - validation", pinmap_validation) -}; - -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); -} diff --git a/TESTS/mbed_hal/qspi/flash_configs/MT25Q_config.h b/TESTS/mbed_hal/qspi/flash_configs/MT25Q_config.h deleted file mode 100644 index ff3d064..0000000 --- a/TESTS/mbed_hal/qspi/flash_configs/MT25Q_config.h +++ /dev/null @@ -1,250 +0,0 @@ -/* mbed Microcontroller Library - * Copyright (c) 2018 ARM Limited - * 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. - */ -#ifndef MBED_QSPI_FLASH_MT25Q_H -#define MBED_QSPI_FLASH_MT25Q_H -#define QSPI_FLASH_CHIP_STRING "Micron MT25Q" -// Command for reading status register -#define QSPI_CMD_RDSR 0x05 -// Command for reading configuration register 0 (NONVOLATILE CONFIGURATION REGISTER) -#define QSPI_CMD_RDCR0 0xB5 -// Command for reading configuration register 1 (VOLATILE CONFIGURATION REGISTER) -#define QSPI_CMD_RDCR1 0x85 -// Command for reading configuration register 2 (ENHANCED VOLATILE CONFIGURATION REGISTER) -#define QSPI_CMD_RDCR2 0x65 -// Command for writing status register -#define QSPI_CMD_WRSR 0x01 -// Command for writing configuration register 0 (NONVOLATILE CONFIGURATION REGISTER) -#define QSPI_CMD_WRCR0 0xB1 -// Command for writing configuration register 1 (VOLATILE CONFIGURATION REGISTER) -#define QSPI_CMD_WRCR1 0x81 -// Command for writing configuration register 2 (ENHANCED VOLATILE CONFIGURATION REGISTER) -#define QSPI_CMD_WRCR2 0x61 -// Command for setting Reset Enable -#define QSPI_CMD_RSTEN 0x66 -// Command for setting Reset -#define QSPI_CMD_RST 0x99 -// Command for setting write enable -#define QSPI_CMD_WREN 0x06 -// Command for setting write disable -#define QSPI_CMD_WRDI 0x04 -// WRSR operations max time [us] (datasheet max time + 15%) -#define QSPI_WRSR_MAX_TIME 9200 // 8ms -// general wait max time [us] -#define QSPI_WAIT_MAX_TIME 100000 // 100ms -// Commands for writing (page programming) -#define QSPI_CMD_WRITE_1IO 0x02 // 1-1-1 mode -#define QSPI_CMD_WRITE_1I2O 0xA2 // 1-1-2 mode -#define QSPI_CMD_WRITE_2IO 0xD2 // 1-2-2 mode -#define QSPI_CMD_WRITE_1I4O 0x32 // 1-1-4 mode -#define QSPI_CMD_WRITE_4IO 0x38 // 1-4-4 mode -#define QSPI_CMD_WRITE_DPI 0xD2 // 2-2-2 mode -#define QSPI_CMD_WRITE_QPI 0x38 // 4-4-4 mode -// write operations max time [us] (datasheet max time + 15%) -#define QSPI_PAGE_PROG_MAX_TIME 2070 // 1.8ms -#define QSPI_PAGE_SIZE 256 // 256B -#define QSPI_SECTOR_SIZE 4096 // 4kB -#define QSPI_SECTOR_COUNT 4096 // for 128Mb chip -// Commands for reading -#define QSPI_CMD_READ_1IO_FAST 0x0B // 1-1-1 mode -#define QSPI_CMD_READ_1IO 0x03 // 1-1-1 mode -#define QSPI_CMD_READ_1I2O 0x3B // 1-1-2 mode -#define QSPI_CMD_READ_2IO 0xBB // 1-2-2 mode -#define QSPI_CMD_READ_DPI 0xBB // 2-2-2 mode -#define QSPI_CMD_READ_1I4O 0x6B // 1-1-4 mode -#define QSPI_CMD_READ_4IO 0xEB // 1-4-4 mode -#define QSPI_CMD_READ_QPI 0xEB // 4-4-4 mode -#define QSPI_READ_1IO_DUMMY_CYCLE 0 // 1-1-1 mode -#define QSPI_READ_FAST_DUMMY_CYCLE 8 // 1-1-1 mode -#define QSPI_READ_1I2O_DUMMY_CYCLE 8 // 1-1-2 mode -#define QSPI_READ_2IO_DUMMY_CYCLE 8 // 1-2-2 mode -#define QSPI_READ_DPI_DUMMY_CYCLE 8 // 2-2-2 mode -#define QSPI_READ_1I4O_DUMMY_CYCLE 8 // 1-1-4 mode -#define QSPI_READ_4IO_DUMMY_CYCLE 10 // 1-4-4 mode -#define QSPI_READ_QPI_DUMMY_CYCLE 10 // 4-4-4 mode -// Commands for erasing -#define QSPI_CMD_ERASE_SECTOR 0x20 // 4kB -#define QSPI_CMD_ERASE_BLOCK_32 0x52 // 32kB -#define QSPI_CMD_ERASE_BLOCK_64 0xD8 // 64kB -#define QSPI_CMD_ERASE_CHIP 0x60 // or 0xC7 -// erase operations max time [us] (datasheet max time + 15%) -#define QSPI_ERASE_SECTOR_MAX_TIME 460000 // 0.4s -#define QSPI_ERASE_BLOCK_32_MAX_TIME 1150000 // 1s -#define QSPI_ERASE_BLOCK_64_MAX_TIME 1150000 // 1s -// max frequency for basic rw operation -#define QSPI_COMMON_MAX_FREQUENCY 50000000 -#define QSPI_STATUS_REG_SIZE 1 -#define QSPI_CONFIG_REG_0_SIZE 2 -#define QSPI_CONFIG_REG_1_SIZE 1 -#define QSPI_CONFIG_REG_2_SIZE 1 -#define QSPI_MAX_REG_SIZE 2 -// status register -#define STATUS_BIT_WIP (1 << 0) // write in progress bit -#define STATUS_BIT_WEL (1 << 1) // write enable latch -#define STATUS_BIT_BP0 (1 << 2) // Block protect -#define STATUS_BIT_BP1 (1 << 3) // Block protect -#define STATUS_BIT_BP2 (1 << 4) // Block protect -#define STATUS_BIT_BP_TB (1 << 5) // Block protect top/bottom -#define STATUS_BIT_BP3 (1 << 6) // Block protect -#define STATUS_BIT_SRWD (1 << 7) // status register write protect -// configuration register 0 (Nonvolatile Configuration Register) -// bit 0, 1 reserved -#define CONFIG0_BIT_DE (1 << 2) // Dual Enable 0 = Enabled / 1 = Disabled -#define CONFIG0_BIT_QE (1 << 3) // Quad Enable 0 = Enabled / 1 = Disabled -#define CONFIG0_BIT_RH (1 << 4) // Reset/hold -#define CONFIG0_BIT_DTR (1 << 5) // Double transfer rate protocol -#define CONFIG0_BIT_ODS0 (1 << 6) // Output driver strength -#define CONFIG0_BIT_ODS1 (1 << 7) // Output driver strength -#define CONFIG0_BIT_ODS2 (1 << 8) // Output driver strength -#define CONFIG0_BIT_XIP_MODE0 (1 << 9) // XIP mode at power-on reset -#define CONFIG0_BIT_XIP_MODE1 (1 << 10) // XIP mode at power-on reset -#define CONFIG0_BIT_XIP_MODE2 (1 << 11) // XIP mode at power-on reset -#define CONFIG0_BIT_DCYCLE0 (1 << 12) // Dummy Cycle -#define CONFIG0_BIT_DCYCLE1 (1 << 13) // Dummy Cycle -#define CONFIG0_BIT_DCYCLE2 (1 << 14) // Dummy Cycle -#define CONFIG0_BIT_DCYCLE3 (1 << 15) // Dummy Cycle -// configuration register 1 (Volatile Configuration Register) -// bit 2, reserved -#define CONFIG1_BIT_WRAP0 (1 << 0) // Output data wrap -#define CONFIG1_BIT_WRAP1 (1 << 1) // Output data wrap -#define CONFIG1_BIT_XIP (1 << 3) // 0 = Enable / 1 = Disable (default) -#define CONFIG1_BIT_DCYCLE0 (1 << 4) // Number of dummy clock cycles -#define CONFIG1_BIT_DCYCLE1 (1 << 5) // Number of dummy clock cycles -#define CONFIG1_BIT_DCYCLE2 (1 << 6) // Number of dummy clock cycles -#define CONFIG1_BIT_DCYCLE3 (1 << 7) // Number of dummy clock cycles -// configuration register 2 (Enhanced Volatile Configuration Register) -// bit 3, reserved -#define CONFIG2_BIT_ODS0 (1 << 0) // Output driver strength 111 = 30 Ohms (Default) -#define CONFIG2_BIT_ODS1 (1 << 1) // Output driver strength -#define CONFIG2_BIT_ODS2 (1 << 2) // Output driver strength -#define CONFIG2_BIT_RH (1 << 4) // Reset/hold -#define CONFIG2_BIT_DTR (1 << 5) // Double transfer rate protocol -#define CONFIG2_BIT_DE (1 << 6) // Dual I/O protocol 0 = Enabled / 1 = Disabled (Default, extended SPI protocol) -#define CONFIG2_BIT_QE (1 << 7) // Quad I/O protocol 0 = Enabled / 1 = Disabled (Default, extended SPI protocol) -#define DUAL_ENABLE() \ - \ - uint8_t reg_data[QSPI_CONFIG_REG_2_SIZE]; \ - \ - memset(reg_data, 0, QSPI_CONFIG_REG_2_SIZE); \ - if (read_register(QSPI_CMD_RDCR2, reg_data, \ - QSPI_CONFIG_REG_2_SIZE, qspi) != QSPI_STATUS_OK) { \ - return QSPI_STATUS_ERROR; \ - } \ - if (write_enable(qspi) != QSPI_STATUS_OK) { \ - return QSPI_STATUS_ERROR; \ - } \ - \ - reg_data[0] = reg_data[0] & ~(CONFIG2_BIT_DE); \ - if (write_register(QSPI_CMD_WRCR2, reg_data, \ - QSPI_CONFIG_REG_2_SIZE, qspi) != QSPI_STATUS_OK) { \ - return QSPI_STATUS_ERROR; \ - } \ - qspi.cmd.configure(MODE_2_2_2, ADDR_SIZE_24, ALT_SIZE_8); \ - WAIT_FOR(WRSR_MAX_TIME, qspi); \ - memset(reg_data, 0, QSPI_CONFIG_REG_2_SIZE); \ - if (read_register(QSPI_CMD_RDCR2, reg_data, \ - QSPI_CONFIG_REG_2_SIZE, qspi) != QSPI_STATUS_OK) { \ - return QSPI_STATUS_ERROR; \ - } \ - \ - return ((reg_data[0] & (CONFIG2_BIT_DE)) == 0 ? \ - QSPI_STATUS_OK : QSPI_STATUS_ERROR) -#define DUAL_DISABLE() \ - \ - uint8_t reg_data[QSPI_CONFIG_REG_2_SIZE]; \ - \ - memset(reg_data, 0, QSPI_CONFIG_REG_2_SIZE); \ - if (read_register(QSPI_CMD_RDCR2, reg_data, \ - QSPI_CONFIG_REG_2_SIZE, qspi) != QSPI_STATUS_OK) { \ - return QSPI_STATUS_ERROR; \ - } \ - if (write_enable(qspi) != QSPI_STATUS_OK) { \ - return QSPI_STATUS_ERROR; \ - } \ - \ - reg_data[0] = reg_data[0] | (CONFIG2_BIT_DE); \ - if (write_register(QSPI_CMD_WRCR2, reg_data, \ - QSPI_CONFIG_REG_2_SIZE, qspi) != QSPI_STATUS_OK) { \ - return QSPI_STATUS_ERROR; \ - } \ - qspi.cmd.configure(MODE_1_1_1, ADDR_SIZE_24, ALT_SIZE_8); \ - WAIT_FOR(WRSR_MAX_TIME, qspi); \ - memset(reg_data, 0, QSPI_CONFIG_REG_2_SIZE); \ - if (read_register(QSPI_CMD_RDCR2, reg_data, \ - QSPI_CONFIG_REG_2_SIZE, qspi) != QSPI_STATUS_OK) { \ - return QSPI_STATUS_ERROR; \ - } \ - \ - return ((reg_data[0] & CONFIG2_BIT_DE) != 1 ? \ - QSPI_STATUS_OK : QSPI_STATUS_ERROR) -#define QUAD_ENABLE() \ - \ - uint8_t reg_data[QSPI_CONFIG_REG_2_SIZE]; \ - \ - memset(reg_data, 0, QSPI_CONFIG_REG_2_SIZE); \ - if (read_register(QSPI_CMD_RDCR2, reg_data, \ - QSPI_CONFIG_REG_2_SIZE, qspi) != QSPI_STATUS_OK) { \ - return QSPI_STATUS_ERROR; \ - } \ - if (write_enable(qspi) != QSPI_STATUS_OK) { \ - return QSPI_STATUS_ERROR; \ - } \ - \ - reg_data[0] = reg_data[0] & ~(CONFIG2_BIT_QE); \ - if (write_register(QSPI_CMD_WRCR2, reg_data, \ - QSPI_CONFIG_REG_2_SIZE, qspi) != QSPI_STATUS_OK) { \ - return QSPI_STATUS_ERROR; \ - } \ - qspi.cmd.configure(MODE_4_4_4, ADDR_SIZE_24, ALT_SIZE_8); \ - WAIT_FOR(WRSR_MAX_TIME, qspi); \ - memset(reg_data, 0, QSPI_CONFIG_REG_2_SIZE); \ - if (read_register(QSPI_CMD_RDCR2, reg_data, \ - QSPI_CONFIG_REG_2_SIZE, qspi) != QSPI_STATUS_OK) { \ - return QSPI_STATUS_ERROR; \ - } \ - \ - return ((reg_data[0] & (CONFIG2_BIT_QE)) == 0 ? \ - QSPI_STATUS_OK : QSPI_STATUS_ERROR) -#define QUAD_DISABLE() \ - \ - uint8_t reg_data[QSPI_CONFIG_REG_2_SIZE]; \ - \ - memset(reg_data, 0, QSPI_CONFIG_REG_2_SIZE); \ - if (read_register(QSPI_CMD_RDCR2, reg_data, \ - QSPI_CONFIG_REG_2_SIZE, qspi) != QSPI_STATUS_OK) { \ - return QSPI_STATUS_ERROR; \ - } \ - if (write_enable(qspi) != QSPI_STATUS_OK) { \ - return QSPI_STATUS_ERROR; \ - } \ - \ - reg_data[0] = reg_data[0] | (CONFIG2_BIT_QE); \ - if (write_register(QSPI_CMD_WRCR2, reg_data, \ - QSPI_CONFIG_REG_2_SIZE, qspi) != QSPI_STATUS_OK) { \ - return QSPI_STATUS_ERROR; \ - } \ - qspi.cmd.configure(MODE_1_1_1, ADDR_SIZE_24, ALT_SIZE_8); \ - WAIT_FOR(WRSR_MAX_TIME, qspi); \ - memset(reg_data, 0, QSPI_CONFIG_REG_2_SIZE); \ - if (read_register(QSPI_CMD_RDCR2, reg_data, \ - QSPI_CONFIG_REG_2_SIZE, qspi) != QSPI_STATUS_OK) { \ - return QSPI_STATUS_ERROR; \ - } \ - \ - return ((reg_data[0] & CONFIG2_BIT_QE) != 1 ? \ - QSPI_STATUS_OK : QSPI_STATUS_ERROR) -#endif // MBED_QSPI_FLASH_MT25Q_H - diff --git a/TESTS/mbed_hal/qspi/flash_configs/MX25L51245G_config.h b/TESTS/mbed_hal/qspi/flash_configs/MX25L51245G_config.h deleted file mode 100644 index 6f50ed8..0000000 --- a/TESTS/mbed_hal/qspi/flash_configs/MX25L51245G_config.h +++ /dev/null @@ -1,107 +0,0 @@ -/* mbed Microcontroller Library - * Copyright (c) 2018-2018 ARM Limited - * 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. - */ -#ifndef MBED_QSPI_FLASH_MX25L51245G_H -#define MBED_QSPI_FLASH_MX25L51245G_H - - -#define QSPI_FLASH_CHIP_STRING "macronix MX25L51245G" - -// Command for reading status register -#define QSPI_CMD_RDSR 0x05 -// Command for reading configuration register -#define QSPI_CMD_RDCR0 0x15 -// Command for writing status/configuration register -#define QSPI_CMD_WRSR 0x01 -// Command for reading security register -#define QSPI_CMD_RDSCUR 0x2B - -// Command for setting Reset Enable -#define QSPI_CMD_RSTEN 0x66 -// Command for setting Reset -#define QSPI_CMD_RST 0x99 - -// Command for setting write enable -#define QSPI_CMD_WREN 0x06 -// Command for setting write disable -#define QSPI_CMD_WRDI 0x04 - -// WRSR operations max time [us] (datasheet max time + 15%) -#define QSPI_WRSR_MAX_TIME 34500 // 30ms -// general wait max time [us] -#define QSPI_WAIT_MAX_TIME 100000 // 100ms - - -// Commands for writing (page programming) -#define QSPI_CMD_WRITE_1IO 0x02 // 1-1-1 mode -#define QSPI_CMD_WRITE_4IO 0x38 // 1-4-4 mode - -// write operations max time [us] (datasheet max time + 15%) -#define QSPI_PAGE_PROG_MAX_TIME 11500 // 10ms - -#define QSPI_PAGE_SIZE 256 // 256B -#define QSPI_SECTOR_SIZE 4096 // 4kB -#define QSPI_SECTOR_COUNT 2048 // - -// Commands for reading -#define QSPI_CMD_READ_1IO_FAST 0x0B // 1-1-1 mode -#define QSPI_CMD_READ_1IO 0x03 // 1-1-1 mode -#define QSPI_CMD_READ_2IO 0xBB // 1-2-2 mode -#define QSPI_CMD_READ_1I2O 0x3B // 1-1-2 mode -#define QSPI_CMD_READ_4IO 0xEB // 1-4-4 mode -#define QSPI_CMD_READ_1I4O 0x6B // 1-1-4 mode - -#define QSPI_READ_1IO_DUMMY_CYCLE 0 -#define QSPI_READ_FAST_DUMMY_CYCLE 8 -#define QSPI_READ_2IO_DUMMY_CYCLE 4 -#define QSPI_READ_1I2O_DUMMY_CYCLE 8 -#define QSPI_READ_4IO_DUMMY_CYCLE 6 -#define QSPI_READ_1I4O_DUMMY_CYCLE 8 - -// Commands for erasing -#define QSPI_CMD_ERASE_SECTOR 0x20 // 4kB -#define QSPI_CMD_ERASE_BLOCK_32 0x52 // 32kB -#define QSPI_CMD_ERASE_BLOCK_64 0xD8 // 64kB -#define QSPI_CMD_ERASE_CHIP 0x60 // or 0xC7 - -// erase operations max time [us] (datasheet max time + 15%) -#define QSPI_ERASE_SECTOR_MAX_TIME 480000 // 400 ms -#define QSPI_ERASE_BLOCK_32_MAX_TIME 1200000 // 1s -#define QSPI_ERASE_BLOCK_64_MAX_TIME 2400000 // 2s - -// max frequency for basic rw operation (for fast mode) -#define QSPI_COMMON_MAX_FREQUENCY 32000000 - -#define QSPI_STATUS_REG_SIZE 1 -#define QSPI_CONFIG_REG_0_SIZE 2 -#define QSPI_SECURITY_REG_SIZE 1 -#define QSPI_MAX_REG_SIZE 2 - -// status register -#define STATUS_BIT_WIP (1 << 0) // write in progress bit -#define STATUS_BIT_WEL (1 << 1) // write enable latch -#define STATUS_BIT_BP0 (1 << 2) // -#define STATUS_BIT_BP1 (1 << 3) // -#define STATUS_BIT_BP2 (1 << 4) // -#define STATUS_BIT_BP3 (1 << 5) // -#define STATUS_BIT_QE (1 << 6) // Quad Enable -#define STATUS_BIT_SRWD (1 << 7) // status register write protect - -// configuration register 0 -// bit 0, 1, 2, 4, 5, 7 reserved -#define CONFIG0_BIT_TB (1 << 3) // Top/Bottom area protect - -#endif // MBED_QSPI_FLASH_MX25L51245G_H diff --git a/TESTS/mbed_hal/qspi/flash_configs/MX25LM51245G_config.h b/TESTS/mbed_hal/qspi/flash_configs/MX25LM51245G_config.h deleted file mode 100644 index 6957b8f..0000000 --- a/TESTS/mbed_hal/qspi/flash_configs/MX25LM51245G_config.h +++ /dev/null @@ -1,96 +0,0 @@ -/* mbed Microcontroller Library - * Copyright (c) 2018-2018 ARM Limited - * 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. - */ -#ifndef MBED_QSPI_FLASH_MX25LM51245G_H -#define MBED_QSPI_FLASH_MX25LM51245G_H - - -#define QSPI_FLASH_CHIP_STRING "macronix MX25LM51245G" - -// Command for reading status register -#define QSPI_CMD_RDSR 0x05 -// Command for reading configuration register -#define QSPI_CMD_RDCR0 0x15 -#define QSPI_CMD_RDCR1 0x71 -// Command for writing status/configuration register -#define QSPI_CMD_WRSR 0x01 -// Command for reading security register -#define QSPI_CMD_RDSCUR 0x2B - -// Command for setting Reset Enable -#define QSPI_CMD_RSTEN 0x66 -// Command for setting Reset -#define QSPI_CMD_RST 0x99 - -// Command for setting write enable -#define QSPI_CMD_WREN 0x06 -// Command for setting write disable -#define QSPI_CMD_WRDI 0x04 - -// WRSR operations max time [us] (datasheet max time + 15%) -#define QSPI_WRSR_MAX_TIME 34500 // 30ms -// general wait max time [us] -#define QSPI_WAIT_MAX_TIME 100000 // 100ms - - -// Commands for writing (page programming) -// Only single/octal mode supported with this memory -// So only single 1-1-1 mode in this QSPI config -#define QSPI_CMD_WRITE_1IO 0x02 // 1-1-1 mode -// write operations max time [us] (datasheet max time + 15%) -#define QSPI_PAGE_PROG_MAX_TIME 11500 // 10ms - -#define QSPI_PAGE_SIZE 256 // 256B -#define QSPI_SECTOR_SIZE 4096 // 4kB -#define QSPI_SECTOR_COUNT 131072 // 512MB / QSPI_SECTOR_SIZE - -// Commands for reading -// Only single/octal mode supported with this memory -// So only single 1-1-1 mode in this QSPI config -#define QSPI_CMD_READ_1IO_FAST 0x0B // 1-1-1 mode -#define QSPI_CMD_READ_1IO 0x03 // 1-1-1 mode - -#define QSPI_READ_1IO_DUMMY_CYCLE 0 -#define QSPI_READ_FAST_DUMMY_CYCLE 8 - -// Commands for erasing -#define QSPI_CMD_ERASE_SECTOR 0x20 // 4kB -//#define QSPI_CMD_ERASE_BLOCK_32 // not supported -#define QSPI_CMD_ERASE_BLOCK_64 0xD8 // 64kB -#define QSPI_CMD_ERASE_CHIP 0x60 // or 0xC7 - -// erase operations max time [us] (datasheet max time + 15%) -#define QSPI_ERASE_SECTOR_MAX_TIME 480000 // 400 ms -#define QSPI_ERASE_BLOCK_64_MAX_TIME 2400000 // 2s - -// max frequency for basic rw operation (for fast mode) -#define QSPI_COMMON_MAX_FREQUENCY 66000000 - -#define QSPI_STATUS_REG_SIZE 1 -#define QSPI_CONFIG_REG_0_SIZE 1 -#define QSPI_CONFIG_REG_1_SIZE 12 -#define QSPI_SECURITY_REG_SIZE 1 -#define QSPI_MAX_REG_SIZE 12 - -// status register -#define STATUS_BIT_WIP (1 << 0) // write in progress bit -#define STATUS_BIT_WEL (1 << 1) // write enable latch -#define STATUS_BIT_BP0 (1 << 2) // -#define STATUS_BIT_BP1 (1 << 3) // -#define STATUS_BIT_BP2 (1 << 4) // -#define STATUS_BIT_BP3 (1 << 5) // - -#endif // MBED_QSPI_FLASH_MX25LM51245G_H diff --git a/TESTS/mbed_hal/qspi/flash_configs/MX25RXX35F_config.h b/TESTS/mbed_hal/qspi/flash_configs/MX25RXX35F_config.h deleted file mode 100644 index 0119c4f..0000000 --- a/TESTS/mbed_hal/qspi/flash_configs/MX25RXX35F_config.h +++ /dev/null @@ -1,255 +0,0 @@ -/* mbed Microcontroller Library - * Copyright (c) 2018-2018 ARM Limited - * 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. - */ -#ifndef MBED_QSPI_FLASH_MX25RXX35F_H -#define MBED_QSPI_FLASH_MX25RXX35F_H - - -#define QSPI_FLASH_CHIP_STRING "macronix MX25RXX35F" - -// Command for reading status register -#define QSPI_CMD_RDSR 0x05 -// Command for reading configuration register -#define QSPI_CMD_RDCR0 0x15 -// Command for writing status/configuration register -#define QSPI_CMD_WRSR 0x01 -// Command for reading security register -#define QSPI_CMD_RDSCUR 0x2B - -// Command for setting Reset Enable -#define QSPI_CMD_RSTEN 0x66 -// Command for setting Reset -#define QSPI_CMD_RST 0x99 - -// Command for setting write enable -#define QSPI_CMD_WREN 0x06 -// Command for setting write disable -#define QSPI_CMD_WRDI 0x04 - -// WRSR operations max time [us] (datasheet max time + 15%) -#define QSPI_WRSR_MAX_TIME 34500 // 30ms -// general wait max time [us] -#define QSPI_WAIT_MAX_TIME 100000 // 100ms - - -// Commands for writing (page programming) -#define QSPI_CMD_WRITE_1IO 0x02 // 1-1-1 mode -#define QSPI_CMD_WRITE_4IO 0x38 // 1-4-4 mode - -// write operations max time [us] (datasheet max time + 15%) -#define QSPI_PAGE_PROG_MAX_TIME 11500 // 10ms - -#define QSPI_PAGE_SIZE 256 // 256B -#define QSPI_SECTOR_SIZE 4096 // 4kB -#define QSPI_SECTOR_COUNT 32 // adjusted to MX25R1035F smallest one from MX25RXX35F family - -// Commands for reading -#define QSPI_CMD_READ_1IO_FAST 0x0B // 1-1-1 mode -#define QSPI_CMD_READ_1IO 0x03 // 1-1-1 mode -#define QSPI_CMD_READ_2IO 0xBB // 1-2-2 mode -#define QSPI_CMD_READ_1I2O 0x3B // 1-1-2 mode -#define QSPI_CMD_READ_4IO 0xEB // 1-4-4 mode -#define QSPI_CMD_READ_1I4O 0x6B // 1-1-4 mode - -#define QSPI_READ_1IO_DUMMY_CYCLE 0 -#define QSPI_READ_FAST_DUMMY_CYCLE 8 -#define QSPI_READ_2IO_DUMMY_CYCLE 4 -#define QSPI_READ_1I2O_DUMMY_CYCLE 8 -#define QSPI_READ_4IO_DUMMY_CYCLE 6 -#define QSPI_READ_1I4O_DUMMY_CYCLE 8 - -// Commands for erasing -#define QSPI_CMD_ERASE_SECTOR 0x20 // 4kB -#define QSPI_CMD_ERASE_BLOCK_32 0x52 // 32kB -#define QSPI_CMD_ERASE_BLOCK_64 0xD8 // 64kB -#define QSPI_CMD_ERASE_CHIP 0x60 // or 0xC7 - -// erase operations max time [us] (datasheet max time + 15%) -#define QSPI_ERASE_SECTOR_MAX_TIME 276000 // 240 ms -#define QSPI_ERASE_BLOCK_32_MAX_TIME 3450000 // 3s -#define QSPI_ERASE_BLOCK_64_MAX_TIME 4025000 // 3.5s - -// max frequency for basic rw operation (for fast mode) -#define QSPI_COMMON_MAX_FREQUENCY 32000000 - -#define QSPI_STATUS_REG_SIZE 1 -#define QSPI_CONFIG_REG_0_SIZE 2 -#define QSPI_SECURITY_REG_SIZE 1 -#define QSPI_MAX_REG_SIZE 2 - -// status register -#define STATUS_BIT_WIP (1 << 0) // write in progress bit -#define STATUS_BIT_WEL (1 << 1) // write enable latch -#define STATUS_BIT_BP0 (1 << 2) // -#define STATUS_BIT_BP1 (1 << 3) // -#define STATUS_BIT_BP2 (1 << 4) // -#define STATUS_BIT_BP3 (1 << 5) // -#define STATUS_BIT_QE (1 << 6) // Quad Enable -#define STATUS_BIT_SRWD (1 << 7) // status register write protect - -// configuration register 0 -// bit 0, 1, 2, 4, 5, 7 reserved -#define CONFIG0_BIT_TB (1 << 3) // Top/Bottom area protect -#define CONFIG0_BIT_DC (1 << 6) // Dummy Cycle - -// configuration register 1 -// bit 0, 2, 3, 4, 5, 6, 7 reserved -#define CONFIG1_BIT_LH (1 << 1) // 0 = Ultra Low power mode, 1 = High performance mode - - - -#define EXTENDED_SPI_ENABLE() \ - \ - const int32_t reg_size = QSPI_STATUS_REG_SIZE + QSPI_CONFIG_REG_0_SIZE; \ - uint8_t reg_data[reg_size] = { 0 }; \ - \ - if (read_register(STATUS_REG, reg_data, \ - QSPI_STATUS_REG_SIZE, qspi) != QSPI_STATUS_OK) { \ - return QSPI_STATUS_ERROR; \ - } \ - if (read_register(CONFIG_REG0, reg_data + QSPI_STATUS_REG_SIZE, \ - QSPI_CONFIG_REG_0_SIZE, qspi) != QSPI_STATUS_OK) { \ - return QSPI_STATUS_ERROR; \ - } \ - \ - if (write_enable(qspi) != QSPI_STATUS_OK) { \ - return QSPI_STATUS_ERROR; \ - } \ - \ - reg_data[0] = STATUS_BIT_QE; \ - if (write_register(QSPI_CMD_WRSR, reg_data, \ - reg_size, qspi) != QSPI_STATUS_OK) { \ - return QSPI_STATUS_ERROR; \ - } \ - WAIT_FOR(WRSR_MAX_TIME, qspi); \ - \ - memset(reg_data, 0, QSPI_STATUS_REG_SIZE); \ - if (read_register(STATUS_REG, reg_data, \ - QSPI_STATUS_REG_SIZE, qspi) != QSPI_STATUS_OK) { \ - return QSPI_STATUS_ERROR; \ - } \ - \ - return ((reg_data[0] & STATUS_BIT_QE) != 0 ? \ - QSPI_STATUS_OK : QSPI_STATUS_ERROR) - - - -#define EXTENDED_SPI_DISABLE() \ - \ - const int32_t reg_size = QSPI_STATUS_REG_SIZE + QSPI_CONFIG_REG_0_SIZE; \ - uint8_t reg_data[reg_size] = { 0 }; \ - \ - if (read_register(STATUS_REG, reg_data, \ - QSPI_STATUS_REG_SIZE, qspi) != QSPI_STATUS_OK) { \ - return QSPI_STATUS_ERROR; \ - } \ - if (read_register(CONFIG_REG0, reg_data + QSPI_STATUS_REG_SIZE, \ - QSPI_CONFIG_REG_0_SIZE, qspi) != QSPI_STATUS_OK) { \ - return QSPI_STATUS_ERROR; \ - } \ - \ - if (write_enable(qspi) != QSPI_STATUS_OK) { \ - return QSPI_STATUS_ERROR; \ - } \ - \ - reg_data[0] &= ~(STATUS_BIT_QE); \ - \ - if (write_register(QSPI_CMD_WRSR, reg_data, \ - reg_size, qspi) != QSPI_STATUS_OK) { \ - return QSPI_STATUS_ERROR; \ - } \ - WAIT_FOR(WRSR_MAX_TIME, qspi); \ - \ - reg_data[0] = 0; \ - if (read_register(STATUS_REG, reg_data, \ - QSPI_STATUS_REG_SIZE, qspi) != QSPI_STATUS_OK) { \ - return QSPI_STATUS_ERROR; \ - } \ - \ - return ((reg_data[0] & STATUS_BIT_QE) == 0 ? \ - QSPI_STATUS_OK : QSPI_STATUS_ERROR) - - - -#define FAST_MODE_ENABLE() \ - \ - const int32_t reg_size = QSPI_STATUS_REG_SIZE + QSPI_CONFIG_REG_0_SIZE; \ - uint8_t reg_data[reg_size]; \ - \ - if (read_register(STATUS_REG, reg_data, \ - QSPI_STATUS_REG_SIZE, qspi) != QSPI_STATUS_OK) { \ - return QSPI_STATUS_ERROR; \ - } \ - if (read_register(CONFIG_REG0, reg_data + QSPI_STATUS_REG_SIZE, \ - QSPI_CONFIG_REG_0_SIZE, qspi) != QSPI_STATUS_OK) { \ - return QSPI_STATUS_ERROR; \ - } \ - \ - if (write_enable(qspi) != QSPI_STATUS_OK) { \ - return QSPI_STATUS_ERROR; \ - } \ - \ - reg_data[2] |= CONFIG1_BIT_LH; \ - if (write_register(QSPI_CMD_WRSR, reg_data, \ - reg_size, qspi) != QSPI_STATUS_OK) { \ - return QSPI_STATUS_ERROR; \ - } \ - WAIT_FOR(WRSR_MAX_TIME, qspi); \ - \ - if (read_register(CONFIG_REG0, reg_data, \ - QSPI_CONFIG_REG_0_SIZE, qspi) != QSPI_STATUS_OK) { \ - return QSPI_STATUS_ERROR; \ - } \ - \ - return ((reg_data[1] & CONFIG1_BIT_LH) != 0 ? \ - QSPI_STATUS_OK : QSPI_STATUS_ERROR) - - -#define FAST_MODE_DISABLE() \ - \ - const int32_t reg_size = QSPI_STATUS_REG_SIZE + QSPI_CONFIG_REG_0_SIZE; \ - uint8_t reg_data[reg_size]; \ - \ - if (read_register(STATUS_REG, reg_data, \ - QSPI_STATUS_REG_SIZE, qspi) != QSPI_STATUS_OK) { \ - return QSPI_STATUS_ERROR; \ - } \ - if (read_register(CONFIG_REG0, reg_data + QSPI_STATUS_REG_SIZE, \ - QSPI_CONFIG_REG_0_SIZE, qspi) != QSPI_STATUS_OK) { \ - return QSPI_STATUS_ERROR; \ - } \ - \ - if (write_enable(qspi) != QSPI_STATUS_OK) { \ - return QSPI_STATUS_ERROR; \ - } \ - \ - reg_data[2] &= ~(CONFIG1_BIT_LH); \ - if (write_register(QSPI_CMD_WRSR, reg_data, \ - reg_size, qspi) != QSPI_STATUS_OK) { \ - return QSPI_STATUS_ERROR; \ - } \ - WAIT_FOR(WRSR_MAX_TIME, qspi); \ - \ - if (read_register(CONFIG_REG0, reg_data, \ - QSPI_CONFIG_REG_0_SIZE, qspi) != QSPI_STATUS_OK) { \ - return QSPI_STATUS_ERROR; \ - } \ - \ - return ((reg_data[1] & CONFIG1_BIT_LH) == 0 ? \ - QSPI_STATUS_OK : QSPI_STATUS_ERROR) - - -#endif // MBED_QSPI_FLASH_MX25RXX35F_H diff --git a/TESTS/mbed_hal/qspi/flash_configs/N25Q128A_config.h b/TESTS/mbed_hal/qspi/flash_configs/N25Q128A_config.h deleted file mode 100644 index 30c3bc2..0000000 --- a/TESTS/mbed_hal/qspi/flash_configs/N25Q128A_config.h +++ /dev/null @@ -1,283 +0,0 @@ -/* mbed Microcontroller Library - * Copyright (c) 2018-2018 ARM Limited - * 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. - */ -#ifndef MBED_QSPI_FLASH_N25Q128A_H -#define MBED_QSPI_FLASH_N25Q128A_H - - -#define QSPI_FLASH_CHIP_STRING "Micron N25Q128A" - -// Command for reading status register -#define QSPI_CMD_RDSR 0x05 -// Command for reading configuration register 0 (NONVOLATILE CONFIGURATION REGISTER) -#define QSPI_CMD_RDCR0 0xB5 -// Command for reading configuration register 1 (VOLATILE CONFIGURATION REGISTER) -#define QSPI_CMD_RDCR1 0x85 -// Command for reading configuration register 2 (ENHANCED VOLATILE CONFIGURATION REGISTER) -#define QSPI_CMD_RDCR2 0x65 -// Command for writing status -#define QSPI_CMD_WRSR 0x01 -// Command for writing configuration register 0 (NONVOLATILE CONFIGURATION REGISTER) -#define QSPI_CMD_WRCR0 0xB1 -// Command for writing configuration register 1 (VOLATILE CONFIGURATION REGISTER) -#define QSPI_CMD_WRCR1 0x81 -// Command for writing configuration register 2 (ENHANCED VOLATILE CONFIGURATION REGISTER) -#define QSPI_CMD_WRCR2 0x61 -// Command for reading security register -#define QSPI_CMD_RDSCUR 0x2B - -// Command for setting Reset Enable -#define QSPI_CMD_RSTEN 0x66 -// Command for setting Reset -#define QSPI_CMD_RST 0x99 - -// Command for setting write enable -#define QSPI_CMD_WREN 0x06 -// Command for setting write disable -#define QSPI_CMD_WRDI 0x04 - -// WRSR operations max time [us] (datasheet max time + 15%) -#define QSPI_WRSR_MAX_TIME 9200 // 8ms -// general wait max time [us] -#define QSPI_WAIT_MAX_TIME 100000 // 100ms - - -// Commands for writing (page programming) -#define QSPI_CMD_WRITE_1IO 0x02 // 1-1-1 mode -#define QSPI_CMD_WRITE_2IO 0xD2 // 1-2-2 mode -#define QSPI_CMD_WRITE_4IO 0x12 // 1-4-4 mode -#define QSPI_CMD_WRITE_DPI 0xD2 // 2-2-2 mode -#define QSPI_CMD_WRITE_QPI 0x12 // 4-4-4 mode - -// write operations max time [us] (datasheet max time + 15%) -#define QSPI_PAGE_PROG_MAX_TIME 5750 // 5ms - -#define QSPI_PAGE_SIZE 256 // 256B -#define QSPI_SECTOR_SIZE 4096 // 4kB -#define QSPI_SECTOR_COUNT 4096 - -// Commands for reading -#define QSPI_CMD_READ_1IO_FAST 0x0B // 1-1-1 mode -#define QSPI_CMD_READ_1IO 0x03 // 1-1-1 mode -#define QSPI_CMD_READ_2IO 0xBB // 1-2-2 mode -#define QSPI_CMD_READ_DPI 0xBB // 2-2-2 mode -#define QSPI_CMD_READ_1I2O 0x3B // 1-1-2 mode -#define QSPI_CMD_READ_4IO 0xEB // 1-4-4 mode -#define QSPI_CMD_READ_QPI 0xEB // 4-4-4 mode -#define QSPI_CMD_READ_1I4O 0x6B // 1-1-4 mode - - -#define QSPI_READ_1IO_DUMMY_CYCLE 0 -#define QSPI_READ_FAST_DUMMY_CYCLE 8 -// 8 dummy (10 dummy when quad SPI protocol is enabled) -#define QSPI_READ_2IO_DUMMY_CYCLE 8 -#define QSPI_READ_1I2O_DUMMY_CYCLE 8 -#define QSPI_READ_4IO_DUMMY_CYCLE 10 -#define QSPI_READ_1I4O_DUMMY_CYCLE 8 - -// Commands for erasing -#define QSPI_CMD_ERASE_SECTOR 0x20 // 4kB -#define QSPI_CMD_ERASE_BLOCK_32 0x52 // 32kB -#define QSPI_CMD_ERASE_BLOCK_64 0xD8 // 64kB -#define QSPI_CMD_ERASE_CHIP 0x60 // or 0xC7 - -// erase operations max time [us] (datasheet max time + 15%) -#define QSPI_ERASE_SECTOR_MAX_TIME 920000 // 0.8s -#define QSPI_ERASE_BLOCK_32_MAX_TIME 3000000 // 3s -#define QSPI_ERASE_BLOCK_64_MAX_TIME 3500000 // 3.5s - -// max frequency for basic rw operation -#define QSPI_COMMON_MAX_FREQUENCY 50000000 - -#define QSPI_STATUS_REG_SIZE 1 -#define QSPI_CONFIG_REG_0_SIZE 2 -#define QSPI_CONFIG_REG_1_SIZE 1 -#define QSPI_CONFIG_REG_2_SIZE 1 -#define QSPI_MAX_REG_SIZE 2 - -// status register -#define STATUS_BIT_WIP (1 << 0) // write in progress bit -#define STATUS_BIT_WEL (1 << 1) // write enable latch -#define STATUS_BIT_BP0 (1 << 2) // block -#define STATUS_BIT_BP1 (1 << 3) // -#define STATUS_BIT_BP2 (1 << 4) // -#define STATUS_BIT_BP_TB (1 << 5) // Block protect top/bottom -#define STATUS_BIT_BP3 (1 << 6) // -#define STATUS_BIT_SRWD (1 << 7) // status register write protect - -// configuration register 0 (Nonvolatile Configuration Register) -// bit 1, 5, reserved -#define CONFIG0_BIT_LOCK (1 << 0) // Lock nonvolatile configuration register -#define CONFIG0_BIT_DE (1 << 2) // Dual Enable 0 = Enabled / 1 = Disabled -#define CONFIG0_BIT_QE (1 << 3) // Quad Enable 0 = Enabled / 1 = Disabled -#define CONFIG0_BIT_RH (1 << 4) // Reset/hold -#define CONFIG0_BIT_ODS0 (1 << 6) // Output driver strength -#define CONFIG0_BIT_ODS1 (1 << 7) // Output driver strength -#define CONFIG0_BIT_ODS2 (1 << 8) // Output driver strength -#define CONFIG0_BIT_XIP_MODE0 (1 << 9) // XIP mode at power-on reset -#define CONFIG0_BIT_XIP_MODE1 (1 << 10) // XIP mode at power-on reset -#define CONFIG0_BIT_XIP_MODE2 (1 << 11) // XIP mode at power-on reset -#define CONFIG0_BIT_DCYCLE0 (1 << 12) // Dummy Cycle -#define CONFIG0_BIT_DCYCLE1 (1 << 13) // Dummy Cycle -#define CONFIG0_BIT_DCYCLE2 (1 << 14) // Dummy Cycle -#define CONFIG0_BIT_DCYCLE3 (1 << 15) // Dummy Cycle -#define CONFIG0_BITS_DEFAULT 0xFFFF // reg default state - - -// configuration register 1 (Volatile Configuration Register) -// bit 2, reserved -#define CONFIG1_BIT_WRAP0 (1 << 0) // Output data wrap -#define CONFIG1_BIT_WRAP1 (1 << 1) // Output data wrap -#define CONFIG1_BIT_XIP (1 << 3) // 0 = Enable / 1 = Disable (default) -#define CONFIG1_BIT_DCYCLE0 (1 << 4) // Number of dummy clock cycles -#define CONFIG1_BIT_DCYCLE1 (1 << 5) // Number of dummy clock cycles -#define CONFIG1_BIT_DCYCLE2 (1 << 6) // Number of dummy clock cycles -#define CONFIG1_BIT_DCYCLE3 (1 << 7) // Number of dummy clock cycles -#define CONFIG1_BITS_DEFAULT 0xB // reg default state - - -// configuration register 2 (Enhanced Volatile Configuration Register) -// bit 5, reserved -#define CONFIG2_BIT_ODS0 (1 << 0) // Output driver strength 111 = 30 Ohms (Default) -#define CONFIG2_BIT_ODS1 (1 << 1) // Output driver strength -#define CONFIG2_BIT_ODS2 (1 << 2) // Output driver strength -#define CONFIG2_BIT_VPP (1 << 3) // VPP accelerator 1 = Disabled (Default) -#define CONFIG2_BIT_RH (1 << 4) // Reset/hold -#define CONFIG2_BIT_DE (1 << 6) // Dual I/O protocol 0 = Enabled / 1 = Disabled (Default, extended SPI protocol) -#define CONFIG2_BIT_QE (1 << 7) // Quad I/O protocol 0 = Enabled / 1 = Disabled (Default, extended SPI protocol) -#define CONFIG2_BITS_DEFAULT 0xDF // reg default state - - -#define DUAL_ENABLE() \ - \ - uint8_t reg_data[QSPI_CONFIG_REG_2_SIZE]; \ - \ - memset(reg_data, 0, QSPI_CONFIG_REG_2_SIZE); \ - if (read_register(QSPI_CMD_RDCR2, reg_data, \ - QSPI_CONFIG_REG_2_SIZE, qspi) != QSPI_STATUS_OK) { \ - return QSPI_STATUS_ERROR; \ - } \ - if (write_enable(qspi) != QSPI_STATUS_OK) { \ - return QSPI_STATUS_ERROR; \ - } \ - \ - reg_data[0] = reg_data[0] & ~(CONFIG2_BIT_DE); \ - if (write_register(QSPI_CMD_WRCR2, reg_data, \ - QSPI_CONFIG_REG_2_SIZE, qspi) != QSPI_STATUS_OK) { \ - return QSPI_STATUS_ERROR; \ - } \ - qspi.cmd.configure(MODE_2_2_2, ADDR_SIZE_24, ALT_SIZE_8); \ - WAIT_FOR(WRSR_MAX_TIME, qspi); \ - memset(reg_data, 0, QSPI_CONFIG_REG_2_SIZE); \ - if (read_register(QSPI_CMD_RDCR2, reg_data, \ - QSPI_CONFIG_REG_2_SIZE, qspi) != QSPI_STATUS_OK) { \ - return QSPI_STATUS_ERROR; \ - } \ - \ - return ((reg_data[0] & (CONFIG2_BIT_DE)) == 0 ? \ - QSPI_STATUS_OK : QSPI_STATUS_ERROR) - - -#define DUAL_DISABLE() \ - \ - uint8_t reg_data[QSPI_CONFIG_REG_2_SIZE]; \ - \ - memset(reg_data, 0, QSPI_CONFIG_REG_2_SIZE); \ - if (read_register(QSPI_CMD_RDCR2, reg_data, \ - QSPI_CONFIG_REG_2_SIZE, qspi) != QSPI_STATUS_OK) { \ - return QSPI_STATUS_ERROR; \ - } \ - if (write_enable(qspi) != QSPI_STATUS_OK) { \ - return QSPI_STATUS_ERROR; \ - } \ - \ - reg_data[0] = reg_data[0] | (CONFIG2_BIT_DE); \ - if (write_register(QSPI_CMD_WRCR2, reg_data, \ - QSPI_CONFIG_REG_2_SIZE, qspi) != QSPI_STATUS_OK) { \ - return QSPI_STATUS_ERROR; \ - } \ - WAIT_FOR(WRSR_MAX_TIME, qspi); \ - qspi.cmd.configure(MODE_1_1_1, ADDR_SIZE_24, ALT_SIZE_8); \ - memset(reg_data, 0, QSPI_CONFIG_REG_2_SIZE); \ - if (read_register(QSPI_CMD_RDCR2, reg_data, \ - QSPI_CONFIG_REG_2_SIZE, qspi) != QSPI_STATUS_OK) { \ - return QSPI_STATUS_ERROR; \ - } \ - \ - return ((reg_data[0] & CONFIG2_BIT_DE) != 1 ? \ - QSPI_STATUS_OK : QSPI_STATUS_ERROR) - - -#define QUAD_ENABLE() \ - \ - uint8_t reg_data[QSPI_CONFIG_REG_2_SIZE]; \ - \ - memset(reg_data, 0, QSPI_CONFIG_REG_2_SIZE); \ - if (read_register(QSPI_CMD_RDCR2, reg_data, \ - QSPI_CONFIG_REG_2_SIZE, qspi) != QSPI_STATUS_OK) { \ - return QSPI_STATUS_ERROR; \ - } \ - if (write_enable(qspi) != QSPI_STATUS_OK) { \ - return QSPI_STATUS_ERROR; \ - } \ - \ - reg_data[0] = reg_data[0] & ~(CONFIG2_BIT_QE); \ - if (write_register(QSPI_CMD_WRCR2, reg_data, \ - QSPI_CONFIG_REG_2_SIZE, qspi) != QSPI_STATUS_OK) { \ - return QSPI_STATUS_ERROR; \ - } \ - qspi.cmd.configure(MODE_4_4_4, ADDR_SIZE_24, ALT_SIZE_8); \ - WAIT_FOR(WRSR_MAX_TIME, qspi); \ - memset(reg_data, 0, QSPI_CONFIG_REG_2_SIZE); \ - if (read_register(QSPI_CMD_RDCR2, reg_data, \ - QSPI_CONFIG_REG_2_SIZE, qspi) != QSPI_STATUS_OK) { \ - return QSPI_STATUS_ERROR; \ - } \ - \ - return ((reg_data[0] & (CONFIG2_BIT_QE)) == 0 ? \ - QSPI_STATUS_OK : QSPI_STATUS_ERROR) - - -#define QUAD_DISABLE() \ - \ - uint8_t reg_data[QSPI_CONFIG_REG_2_SIZE]; \ - \ - memset(reg_data, 0, QSPI_CONFIG_REG_2_SIZE); \ - if (read_register(QSPI_CMD_RDCR2, reg_data, \ - QSPI_CONFIG_REG_2_SIZE, qspi) != QSPI_STATUS_OK) { \ - return QSPI_STATUS_ERROR; \ - } \ - if (write_enable(qspi) != QSPI_STATUS_OK) { \ - return QSPI_STATUS_ERROR; \ - } \ - \ - reg_data[0] = reg_data[0] | (CONFIG2_BIT_QE); \ - if (write_register(QSPI_CMD_WRCR2, reg_data, \ - QSPI_CONFIG_REG_2_SIZE, qspi) != QSPI_STATUS_OK) { \ - return QSPI_STATUS_ERROR; \ - } \ - WAIT_FOR(WRSR_MAX_TIME, qspi); \ - qspi.cmd.configure(MODE_1_1_1, ADDR_SIZE_24, ALT_SIZE_8); \ - memset(reg_data, 0, QSPI_CONFIG_REG_2_SIZE); \ - if (read_register(QSPI_CMD_RDCR2, reg_data, \ - QSPI_CONFIG_REG_2_SIZE, qspi) != QSPI_STATUS_OK) { \ - return QSPI_STATUS_ERROR; \ - } \ - \ - return ((reg_data[0] & CONFIG2_BIT_QE) != 1 ? \ - QSPI_STATUS_OK : QSPI_STATUS_ERROR) - -#endif // MBED_QSPI_FLASH_N25Q128A_H diff --git a/TESTS/mbed_hal/qspi/flash_configs/NORDIC/EP_AGORA/flash_config.h b/TESTS/mbed_hal/qspi/flash_configs/NORDIC/EP_AGORA/flash_config.h deleted file mode 100644 index 8fba66e..0000000 --- a/TESTS/mbed_hal/qspi/flash_configs/NORDIC/EP_AGORA/flash_config.h +++ /dev/null @@ -1,38 +0,0 @@ -/* mbed Microcontroller Library - * Copyright (c) 2018-2018 ARM Limited - * 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. - */ -#ifndef MBED_QSPI_FLASH_CONFIG_H -#define MBED_QSPI_FLASH_CONFIG_H - -#include "../../W25Q32JV_config.h" - -// NRF doesn't uses read/write opcodes, instead it uses commands id's. -// Before sending it to H/W opcodes are mapped to id's in Mbed hal qspi implementation -// -// for more details see: -// targets\TARGET_NORDIC\TARGET_NRF5x\TARGET_SDK_15_0\modules\nrfx\mdk\nrf52840_bitfields.h -// targets\TARGET_NORDIC\TARGET_NRF5x\qspi_api.c - -// NRF doesn't support read 1IO (opcode 0x03) -#undef QSPI_CMD_READ_1IO -#define QSPI_CMD_READ_1IO QSPI_CMD_READ_1IO_FAST - -#ifdef QSPI_SECTOR_COUNT -#undef QSPI_SECTOR_COUNT -#define QSPI_SECTOR_COUNT 1024 // for W25Q32JV -#endif - -#endif // MBED_QSPI_FLASH_CONFIG_H diff --git a/TESTS/mbed_hal/qspi/flash_configs/NORDIC/NRF52840_DK/flash_config.h b/TESTS/mbed_hal/qspi/flash_configs/NORDIC/NRF52840_DK/flash_config.h deleted file mode 100644 index bda5464..0000000 --- a/TESTS/mbed_hal/qspi/flash_configs/NORDIC/NRF52840_DK/flash_config.h +++ /dev/null @@ -1,38 +0,0 @@ -/* mbed Microcontroller Library - * Copyright (c) 2018-2018 ARM Limited - * 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. - */ -#ifndef MBED_QSPI_FLASH_CONFIG_H -#define MBED_QSPI_FLASH_CONFIG_H - -#include "../../MX25RXX35F_config.h" - -// NRF doesn't uses read/write opcodes, instead it uses commands id's. -// Before sending it to H/W opcodes are mapped to id's in Mbed hal qspi implementation -// -// for more details see: -// targets\TARGET_NORDIC\TARGET_NRF5x\TARGET_SDK_14_2\device\nrf52840_bitfields.h -// targets\TARGET_NORDIC\TARGET_NRF5x\qspi_api.c - -// NRF doesn't support read 1IO (opcode 0x03) -#undef QSPI_CMD_READ_1IO -#define QSPI_CMD_READ_1IO QSPI_CMD_READ_1IO_FAST - -#ifdef QSPI_SECTOR_COUNT -#undef QSPI_SECTOR_COUNT -#define QSPI_SECTOR_COUNT 2048 // for MX25R6435F -#endif - -#endif // MBED_QSPI_FLASH_CONFIG_H diff --git a/TESTS/mbed_hal/qspi/flash_configs/NXP/K82F/flash_config.h b/TESTS/mbed_hal/qspi/flash_configs/NXP/K82F/flash_config.h deleted file mode 100644 index f0e25fd..0000000 --- a/TESTS/mbed_hal/qspi/flash_configs/NXP/K82F/flash_config.h +++ /dev/null @@ -1,119 +0,0 @@ -/* mbed Microcontroller Library - * Copyright (c) 2018-2018 ARM Limited - * 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. - */ -#ifndef MBED_QSPI_FLASH_CONFIG_H -#define MBED_QSPI_FLASH_CONFIG_H - -#include "../../MX25RXX35F_config.h" - -/* Fast mode not supported in MX25U3235F */ -#undef FAST_MODE_ENABLE -#undef FAST_MODE_DISABLE - -#ifdef QSPI_SECTOR_COUNT -#undef QSPI_SECTOR_COUNT -#define QSPI_SECTOR_COUNT 1024 // for MX25U3235F -#endif - -/* The values for MX25U3235F are different, specify this here */ -#undef QSPI_COMMON_MAX_FREQUENCY -#undef QSPI_WRSR_MAX_TIME -#undef QSPI_PAGE_PROG_MAX_TIME -#undef QSPI_ERASE_SECTOR_MAX_TIME -#undef QSPI_ERASE_BLOCK_32_MAX_TIME -#undef QSPI_ERASE_BLOCK_64_MAX_TIME - -/* Implementation of these macros are slightly different for MX25U3235F */ -#undef EXTENDED_SPI_ENABLE -#undef EXTENDED_SPI_DISABLE - -/* Max frequency for basic rw operation in MX25U3235F */ -#define QSPI_COMMON_MAX_FREQUENCY 54000000 - -/* WRSR operations max time [us] (datasheet max time + 15%) */ -#define QSPI_WRSR_MAX_TIME 46000 // 40ms - -/* Write operations max time [us] (datasheet max time + 15%) */ -#define QSPI_PAGE_PROG_MAX_TIME 3450 // 3ms - -/* erase operations max time [us] (datasheet max time + 15%) */ -#define QSPI_ERASE_SECTOR_MAX_TIME 230000 // 200 ms -#define QSPI_ERASE_BLOCK_32_MAX_TIME 1150000 // 1s -#define QSPI_ERASE_BLOCK_64_MAX_TIME 2300000 // 2s - -#define EXTENDED_SPI_ENABLE() \ - \ - const int32_t reg_size = QSPI_STATUS_REG_SIZE; \ - uint8_t reg_data[reg_size] = { 0 }; \ - \ - if (read_register(STATUS_REG, reg_data, \ - QSPI_STATUS_REG_SIZE, qspi) != QSPI_STATUS_OK) { \ - return QSPI_STATUS_ERROR; \ - } \ - if (write_enable(qspi) != QSPI_STATUS_OK) { \ - return QSPI_STATUS_ERROR; \ - } \ - \ - reg_data[0] = STATUS_BIT_QE; \ - if (write_register(QSPI_CMD_WRSR, reg_data, \ - reg_size, qspi) != QSPI_STATUS_OK) { \ - return QSPI_STATUS_ERROR; \ - } \ - WAIT_FOR(WRSR_MAX_TIME, qspi); \ - \ - memset(reg_data, 0, QSPI_STATUS_REG_SIZE); \ - if (read_register(STATUS_REG, reg_data, \ - QSPI_STATUS_REG_SIZE, qspi) != QSPI_STATUS_OK) { \ - return QSPI_STATUS_ERROR; \ - } \ - \ - return ((reg_data[0] & STATUS_BIT_QE) != 0 ? \ - QSPI_STATUS_OK : QSPI_STATUS_ERROR) - - - -#define EXTENDED_SPI_DISABLE() \ - \ - const int32_t reg_size = QSPI_STATUS_REG_SIZE; \ - uint8_t reg_data[reg_size] = { 0 }; \ - \ - if (read_register(STATUS_REG, reg_data, \ - QSPI_STATUS_REG_SIZE, qspi) != QSPI_STATUS_OK) { \ - return QSPI_STATUS_ERROR; \ - } \ - \ - if (write_enable(qspi) != QSPI_STATUS_OK) { \ - return QSPI_STATUS_ERROR; \ - } \ - \ - reg_data[0] &= ~(STATUS_BIT_QE); \ - \ - if (write_register(QSPI_CMD_WRSR, reg_data, \ - reg_size, qspi) != QSPI_STATUS_OK) { \ - return QSPI_STATUS_ERROR; \ - } \ - WAIT_FOR(WRSR_MAX_TIME, qspi); \ - \ - reg_data[0] = 0; \ - if (read_register(STATUS_REG, reg_data, \ - QSPI_STATUS_REG_SIZE, qspi) != QSPI_STATUS_OK) { \ - return QSPI_STATUS_ERROR; \ - } \ - \ - return ((reg_data[0] & STATUS_BIT_QE) == 0 ? \ - QSPI_STATUS_OK : QSPI_STATUS_ERROR) - -#endif // MBED_QSPI_FLASH_CONFIG_H diff --git a/TESTS/mbed_hal/qspi/flash_configs/NXP/LPC546XX/flash_config.h b/TESTS/mbed_hal/qspi/flash_configs/NXP/LPC546XX/flash_config.h deleted file mode 100644 index d0e3541..0000000 --- a/TESTS/mbed_hal/qspi/flash_configs/NXP/LPC546XX/flash_config.h +++ /dev/null @@ -1,22 +0,0 @@ -/* mbed Microcontroller Library - * Copyright (c) 2018-2018 ARM Limited - * 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. - */ -#ifndef MBED_QSPI_FLASH_CONFIG_H -#define MBED_QSPI_FLASH_CONFIG_H - -#include "../../MT25Q_config.h" - -#endif // MBED_QSPI_FLASH_CONFIG_H diff --git a/TESTS/mbed_hal/qspi/flash_configs/S25FL128S_config.h b/TESTS/mbed_hal/qspi/flash_configs/S25FL128S_config.h deleted file mode 100644 index 01b1050..0000000 --- a/TESTS/mbed_hal/qspi/flash_configs/S25FL128S_config.h +++ /dev/null @@ -1,191 +0,0 @@ -/* mbed Microcontroller Library - * Copyright (c) 2018-2018 ARM Limited - * 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. - */ -#ifndef MBED_QSPI_FLASH_S25FL128S_H -#define MBED_QSPI_FLASH_S25FL128S_H - -#define QSPI_FLASH_CHIP_STRING "Cypress S25FL128S" -#define QSPI_FLASH_CYPRESS_S25FL128S - -// Command for reading configuration register -#define QSPI_CMD_RDCR0 0x35 // To read Quad (QE) enable bit -// Command for writing status/configuration register -#define QSPI_CMD_WRSR 0x01 // To write Qual (QE) enable bit -// Command for reading status register -#define QSPI_CMD_RDSR 0x05 // To read WIP bit of status register 1 - - - -// Command for reading security register -#define QSPI_CMD_RDSCUR 0x2B - -// Command for setting Reset Enable -#define QSPI_CMD_RSTEN 0x66 -// Command for setting Reset -#define QSPI_CMD_RST 0xF0 //0x99 - -// Command for setting write enable -#define QSPI_CMD_WREN 0x06 -// Command for setting write disable -#define QSPI_CMD_WRDI 0x04 - -// WRSR operations max time [us] (datasheet max time + 15%) -#define QSPI_WRSR_MAX_TIME 575000 // 575 ms -// general wait max time [us] -#define QSPI_WAIT_MAX_TIME 100000 // 100 ms - - -// Commands for writing (page programming) -#define QSPI_CMD_WRITE_1IO 0x02 // 1-1-1 mode -#define QSPI_CMD_WRITE_1I4O 0x32 // 1-1-4 mode // 1-4-4 is not supported by S25FL512S - -// write operations max time [us] (datasheet max time + 15%) -#define QSPI_PAGE_PROG_MAX_TIME 800 // 800 us - -#define QSPI_PAGE_SIZE 512 // 512B -#define QSPI_SECTOR_SIZE 262144 // 256kB -#define QSPI_SECTOR_COUNT 64 // 16 MB - -// Commands for reading -#define QSPI_CMD_READ_1IO_FAST 0x0B // 1-1-1 mode -#define QSPI_CMD_READ_1IO 0x03 // 1-1-1 mode -#define QSPI_CMD_READ_2IO 0xBB // 1-2-2 mode - dual I/O -#define QSPI_CMD_READ_1I2O 0x3B // 1-1-2 mode - dual output -#define QSPI_CMD_READ_4IO 0xEB // 1-4-4 mode - quad I/O -#define QSPI_CMD_READ_1I4O 0x6B // 1-1-4 mode - quad output - -// Alt (mode) value for quad I/O read -#define QSPI_ALT_READ_4IO 0x01 // 1-4-4 mode only - -#define QSPI_READ_1IO_DUMMY_CYCLE 0 -#define QSPI_READ_FAST_DUMMY_CYCLE 8 -#define QSPI_READ_2IO_DUMMY_CYCLE 4 // dual I/O -#define QSPI_READ_1I2O_DUMMY_CYCLE 8 // dual output -#define QSPI_READ_4IO_DUMMY_CYCLE 6 // quad I/O - 2 cycles for Mode or Alt (4 bits per cycle x 2 cycles = 1 byte) + 4 dummy cycles -#define QSPI_READ_1I4O_DUMMY_CYCLE 8 // quad output - -// Commands for erasing -#define QSPI_CMD_ERASE_SECTOR 0xD8 // 256kB -#define QSPI_CMD_ERASE_CHIP 0x60 // or 0xC7 - -// erase operations max time [us] (datasheet max time + 15%) -#define QSPI_ERASE_SECTOR_MAX_TIME 750000 // 1.15*650 ~ 750 ms - -// max frequency for basic rw operation (for fast mode) -#define QSPI_COMMON_MAX_FREQUENCY 50000000 - -#define QSPI_STATUS_REG_SIZE 1 -#define QSPI_CONFIG_REG_0_SIZE 1 -#define QSPI_SECURITY_REG_SIZE 1 -#define QSPI_MAX_REG_SIZE 2 - -// status register -#define STATUS_BIT_WIP (1 << 0) // write in progress bit -#define STATUS_BIT_WEL (1 << 1) // write enable latch -#define STATUS_BIT_BP0 (1 << 2) // -#define STATUS_BIT_BP1 (1 << 3) // -#define STATUS_BIT_BP2 (1 << 4) // -#define STATUS_BIT_BP3 (1 << 5) // -#define STATUS_BIT_QE (1 << 1) // Quad Enable -#define STATUS_BIT_SRWD (1 << 7) // status register write protect - -// configuration register 0 -// bit 0, 1, 2, 4, 5, 7 reserved -#define CONFIG0_BIT_TB (1 << 3) // Top/Bottom area protect -#define CONFIG0_BIT_DC (1 << 6) // Dummy Cycle - -// configuration register 1 -// bit 0, 2, 3, 4, 5, 6, 7 reserved -#define CONFIG1_BIT_LH (1 << 1) // 0 = Ultra Low power mode, 1 = High performance mode - - - -#define EXTENDED_SPI_ENABLE() \ - \ - const int32_t reg_size = QSPI_STATUS_REG_SIZE + QSPI_CONFIG_REG_0_SIZE; \ - uint8_t reg_data[reg_size] = { 0 }; \ - \ - if (read_register(STATUS_REG, reg_data, \ - QSPI_STATUS_REG_SIZE, qspi) != QSPI_STATUS_OK) { \ - return QSPI_STATUS_ERROR; \ - } \ - if (read_register(CONFIG_REG0, reg_data + QSPI_STATUS_REG_SIZE, \ - QSPI_CONFIG_REG_0_SIZE, qspi) != QSPI_STATUS_OK) { \ - return QSPI_STATUS_ERROR; \ - } \ - \ - if (write_enable(qspi) != QSPI_STATUS_OK) { \ - return QSPI_STATUS_ERROR; \ - } \ - \ - reg_data[1] |= STATUS_BIT_QE; \ - if (write_register(QSPI_CMD_WRSR, reg_data, \ - reg_size, qspi) != QSPI_STATUS_OK) { \ - return QSPI_STATUS_ERROR; \ - } \ - \ - WAIT_FOR(WRSR_MAX_TIME, qspi); \ - \ - memset(reg_data, 0, QSPI_STATUS_REG_SIZE); \ - if (read_register(CONFIG_REG0, reg_data, \ - QSPI_STATUS_REG_SIZE, qspi) != QSPI_STATUS_OK) { \ - return QSPI_STATUS_ERROR; \ - } \ - \ - return ((reg_data[0] & STATUS_BIT_QE) != 0 ? \ - QSPI_STATUS_OK : QSPI_STATUS_ERROR) - - - -#define EXTENDED_SPI_DISABLE() \ - \ - const int32_t reg_size = QSPI_STATUS_REG_SIZE + QSPI_CONFIG_REG_0_SIZE; \ - uint8_t reg_data[reg_size] = { 0 }; \ - \ - if (read_register(STATUS_REG, reg_data, \ - QSPI_STATUS_REG_SIZE, qspi) != QSPI_STATUS_OK) { \ - return QSPI_STATUS_ERROR; \ - } \ - \ - if (read_register(CONFIG_REG0, reg_data + QSPI_STATUS_REG_SIZE, \ - QSPI_CONFIG_REG_0_SIZE, qspi) != QSPI_STATUS_OK) { \ - return QSPI_STATUS_ERROR; \ - } \ - \ - if (write_enable(qspi) != QSPI_STATUS_OK) { \ - return QSPI_STATUS_ERROR; \ - } \ - \ - reg_data[1] &= ~(STATUS_BIT_QE); \ - \ - if (write_register(QSPI_CMD_WRSR, reg_data, \ - reg_size, qspi) != QSPI_STATUS_OK) { \ - return QSPI_STATUS_ERROR; \ - } \ - \ - WAIT_FOR(WRSR_MAX_TIME, qspi); \ - \ - reg_data[0] = 0; \ - if (read_register(CONFIG_REG0, reg_data, \ - QSPI_STATUS_REG_SIZE, qspi) != QSPI_STATUS_OK) { \ - return QSPI_STATUS_ERROR; \ - } \ - \ - return ((reg_data[0] & STATUS_BIT_QE) == 0 ? \ - QSPI_STATUS_OK : QSPI_STATUS_ERROR) - - -#endif // MBED_QSPI_FLASH_S25FL128S_H diff --git a/TESTS/mbed_hal/qspi/flash_configs/S25FL512S_config.h b/TESTS/mbed_hal/qspi/flash_configs/S25FL512S_config.h deleted file mode 100755 index 4b866c8..0000000 --- a/TESTS/mbed_hal/qspi/flash_configs/S25FL512S_config.h +++ /dev/null @@ -1,191 +0,0 @@ -/* mbed Microcontroller Library - * Copyright (c) 2018-2018 ARM Limited - * 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. - */ -#ifndef MBED_QSPI_FLASH_S25FL512S_H -#define MBED_QSPI_FLASH_S25FL512S_H - -#define QSPI_FLASH_CHIP_STRING "Cypress S25FL512S" -#define QSPI_FLASH_CYPRESS_S25FL512S - -// Command for reading configuration register -#define QSPI_CMD_RDCR0 0x35 // To read Quad (QE) enable bit -// Command for writing status/configuration register -#define QSPI_CMD_WRSR 0x01 // To write Qual (QE) enable bit -// Command for reading status register -#define QSPI_CMD_RDSR 0x05 // To read WIP bit of status register 1 - - - -// Command for reading security register -#define QSPI_CMD_RDSCUR 0x2B - -// Command for setting Reset Enable -#define QSPI_CMD_RSTEN 0x66 -// Command for setting Reset -#define QSPI_CMD_RST 0xF0 //0x99 - -// Command for setting write enable -#define QSPI_CMD_WREN 0x06 -// Command for setting write disable -#define QSPI_CMD_WRDI 0x04 - -// WRSR operations max time [us] (datasheet max time + 15%) -#define QSPI_WRSR_MAX_TIME 2300000 // 2.3 seconds -// general wait max time [us] -#define QSPI_WAIT_MAX_TIME 100000 // 100ms - - -// Commands for writing (page programming) -#define QSPI_CMD_WRITE_1IO 0x02 // 1-1-1 mode -#define QSPI_CMD_WRITE_1I4O 0x32 // 1-1-4 mode // 1-4-4 is not supported by S25FL512S - -// write operations max time [us] (datasheet max time + 15%) -#define QSPI_PAGE_PROG_MAX_TIME 1500 // 1.5ms - -#define QSPI_PAGE_SIZE 512 // 512B -#define QSPI_SECTOR_SIZE 262144 // 256kB -#define QSPI_SECTOR_COUNT 256 // 64 MB - -// Commands for reading -#define QSPI_CMD_READ_1IO_FAST 0x0B // 1-1-1 mode -#define QSPI_CMD_READ_1IO 0x03 // 1-1-1 mode -#define QSPI_CMD_READ_2IO 0xBB // 1-2-2 mode - dual I/O -#define QSPI_CMD_READ_1I2O 0x3B // 1-1-2 mode - dual output -#define QSPI_CMD_READ_4IO 0xEB // 1-4-4 mode - quad I/O -#define QSPI_CMD_READ_1I4O 0x6B // 1-1-4 mode - quad output - -// Alt (mode) value for quad I/O read -#define QSPI_ALT_READ_4IO 0x01 // 1-4-4 mode only - -#define QSPI_READ_1IO_DUMMY_CYCLE 0 -#define QSPI_READ_FAST_DUMMY_CYCLE 8 -#define QSPI_READ_2IO_DUMMY_CYCLE 4 // dual I/O -#define QSPI_READ_1I2O_DUMMY_CYCLE 8 // dual output -#define QSPI_READ_4IO_DUMMY_CYCLE 6 // quad I/O - 2 cycles for Mode or Alt (4 bits per cycle x 2 cycles = 1 byte) + 4 dummy cycles -#define QSPI_READ_1I4O_DUMMY_CYCLE 8 // quad output - -// Commands for erasing -#define QSPI_CMD_ERASE_SECTOR 0xD8 // 256kB -#define QSPI_CMD_ERASE_CHIP 0x60 // or 0xC7 - -// erase operations max time [us] (datasheet max time + 15%) -#define QSPI_ERASE_SECTOR_MAX_TIME 2990000 // 1.15*2600 ~ 2900 ms - -// max frequency for basic rw operation (for fast mode) -#define QSPI_COMMON_MAX_FREQUENCY 50000000 - -#define QSPI_STATUS_REG_SIZE 1 -#define QSPI_CONFIG_REG_0_SIZE 1 -#define QSPI_SECURITY_REG_SIZE 1 -#define QSPI_MAX_REG_SIZE 2 - -// status register -#define STATUS_BIT_WIP (1 << 0) // write in progress bit -#define STATUS_BIT_WEL (1 << 1) // write enable latch -#define STATUS_BIT_BP0 (1 << 2) // -#define STATUS_BIT_BP1 (1 << 3) // -#define STATUS_BIT_BP2 (1 << 4) // -#define STATUS_BIT_BP3 (1 << 5) // -#define STATUS_BIT_QE (1 << 1) // Quad Enable -#define STATUS_BIT_SRWD (1 << 7) // status register write protect - -// configuration register 0 -// bit 0, 1, 2, 4, 5, 7 reserved -#define CONFIG0_BIT_TB (1 << 3) // Top/Bottom area protect -#define CONFIG0_BIT_DC (1 << 6) // Dummy Cycle - -// configuration register 1 -// bit 0, 2, 3, 4, 5, 6, 7 reserved -#define CONFIG1_BIT_LH (1 << 1) // 0 = Ultra Low power mode, 1 = High performance mode - - - -#define EXTENDED_SPI_ENABLE() \ - \ - const int32_t reg_size = QSPI_STATUS_REG_SIZE + QSPI_CONFIG_REG_0_SIZE; \ - uint8_t reg_data[reg_size] = { 0 }; \ - \ - if (read_register(STATUS_REG, reg_data, \ - QSPI_STATUS_REG_SIZE, qspi) != QSPI_STATUS_OK) { \ - return QSPI_STATUS_ERROR; \ - } \ - if (read_register(CONFIG_REG0, reg_data + QSPI_STATUS_REG_SIZE, \ - QSPI_CONFIG_REG_0_SIZE, qspi) != QSPI_STATUS_OK) { \ - return QSPI_STATUS_ERROR; \ - } \ - \ - if (write_enable(qspi) != QSPI_STATUS_OK) { \ - return QSPI_STATUS_ERROR; \ - } \ - \ - reg_data[1] |= STATUS_BIT_QE; \ - if (write_register(QSPI_CMD_WRSR, reg_data, \ - reg_size, qspi) != QSPI_STATUS_OK) { \ - return QSPI_STATUS_ERROR; \ - } \ - \ - WAIT_FOR(WRSR_MAX_TIME, qspi); \ - \ - memset(reg_data, 0, QSPI_STATUS_REG_SIZE); \ - if (read_register(CONFIG_REG0, reg_data, \ - QSPI_STATUS_REG_SIZE, qspi) != QSPI_STATUS_OK) { \ - return QSPI_STATUS_ERROR; \ - } \ - \ - return ((reg_data[0] & STATUS_BIT_QE) != 0 ? \ - QSPI_STATUS_OK : QSPI_STATUS_ERROR) - - - -#define EXTENDED_SPI_DISABLE() \ - \ - const int32_t reg_size = QSPI_STATUS_REG_SIZE + QSPI_CONFIG_REG_0_SIZE; \ - uint8_t reg_data[reg_size] = { 0 }; \ - \ - if (read_register(STATUS_REG, reg_data, \ - QSPI_STATUS_REG_SIZE, qspi) != QSPI_STATUS_OK) { \ - return QSPI_STATUS_ERROR; \ - } \ - \ - if (read_register(CONFIG_REG0, reg_data + QSPI_STATUS_REG_SIZE, \ - QSPI_CONFIG_REG_0_SIZE, qspi) != QSPI_STATUS_OK) { \ - return QSPI_STATUS_ERROR; \ - } \ - \ - if (write_enable(qspi) != QSPI_STATUS_OK) { \ - return QSPI_STATUS_ERROR; \ - } \ - \ - reg_data[1] &= ~(STATUS_BIT_QE); \ - \ - if (write_register(QSPI_CMD_WRSR, reg_data, \ - reg_size, qspi) != QSPI_STATUS_OK) { \ - return QSPI_STATUS_ERROR; \ - } \ - \ - WAIT_FOR(WRSR_MAX_TIME, qspi); \ - \ - reg_data[0] = 0; \ - if (read_register(CONFIG_REG0, reg_data, \ - QSPI_STATUS_REG_SIZE, qspi) != QSPI_STATUS_OK) { \ - return QSPI_STATUS_ERROR; \ - } \ - \ - return ((reg_data[0] & STATUS_BIT_QE) == 0 ? \ - QSPI_STATUS_OK : QSPI_STATUS_ERROR) - - -#endif // MBED_QSPI_FLASH_S25FL512S_H diff --git a/TESTS/mbed_hal/qspi/flash_configs/S25FS512S_config.h b/TESTS/mbed_hal/qspi/flash_configs/S25FS512S_config.h deleted file mode 100644 index 6be35f5..0000000 --- a/TESTS/mbed_hal/qspi/flash_configs/S25FS512S_config.h +++ /dev/null @@ -1,191 +0,0 @@ -/* mbed Microcontroller Library - * Copyright (c) 2018-2018 ARM Limited - * 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. - */ -#ifndef MBED_QSPI_FLASH_S25FS512S_H -#define MBED_QSPI_FLASH_S25FS512S_H - -#define QSPI_FLASH_CHIP_STRING "Cypress S25FS512S" -#define QSPI_FLASH_CYPRESS_S25FS512S - -// Command for reading configuration register -#define QSPI_CMD_RDCR0 0x35 // To read Quad (QE) enable bit -// Command for writing status/configuration register -#define QSPI_CMD_WRSR 0x01 // To write Qual (QE) enable bit -// Command for reading status register -#define QSPI_CMD_RDSR 0x05 // To read WIP bit of status register 1 - - - -// Command for reading security register -#define QSPI_CMD_RDSCUR 0x2B - -// Command for setting Reset Enable -#define QSPI_CMD_RSTEN 0x66 -// Command for setting Reset -#define QSPI_CMD_RST 0xF0 //0x99 - -// Command for setting write enable -#define QSPI_CMD_WREN 0x06 -// Command for setting write disable -#define QSPI_CMD_WRDI 0x04 - -// WRSR operations max time [us] (datasheet max time + 15%) -#define QSPI_WRSR_MAX_TIME 2300000 // 2.3 seconds -// general wait max time [us] -#define QSPI_WAIT_MAX_TIME 100000 // 100ms - - -// Commands for writing (page programming) -#define QSPI_CMD_WRITE_1IO 0x02 // 1-1-1 mode -#define QSPI_CMD_WRITE_1I4O 0x32 // 1-1-4 mode // 1-4-4 is not supported by S25FS512S - -// write operations max time [us] (datasheet max time + 15%) -#define QSPI_PAGE_PROG_MAX_TIME 2300 // 2.3ms - -#define QSPI_PAGE_SIZE 256 // 256B -#define QSPI_SECTOR_SIZE 262144 // 256kB -#define QSPI_SECTOR_COUNT 256 // 64 MB - -// Commands for reading -#define QSPI_CMD_READ_1IO_FAST 0x0B // 1-1-1 mode -#define QSPI_CMD_READ_1IO 0x03 // 1-1-1 mode -#define QSPI_CMD_READ_2IO 0xBB // 1-2-2 mode - dual I/O -#define QSPI_CMD_READ_1I2O 0x3B // 1-1-2 mode - dual output -#define QSPI_CMD_READ_4IO 0xEB // 1-4-4 mode - quad I/O -#define QSPI_CMD_READ_1I4O 0x6B // 1-1-4 mode - quad output - -// Alt (mode) value for quad I/O read -#define QSPI_ALT_READ_4IO 0x01 // 1-4-4 mode only - -#define QSPI_READ_1IO_DUMMY_CYCLE 0 -#define QSPI_READ_FAST_DUMMY_CYCLE 8 -#define QSPI_READ_2IO_DUMMY_CYCLE 4 // dual I/O -#define QSPI_READ_1I2O_DUMMY_CYCLE 8 // dual output -#define QSPI_READ_4IO_DUMMY_CYCLE 6 // quad I/O - 2 cycles for Mode or Alt (4 bits per cycle x 2 cycles = 1 byte) + 4 dummy cycles -#define QSPI_READ_1I4O_DUMMY_CYCLE 8 // quad output - -// Commands for erasing -#define QSPI_CMD_ERASE_SECTOR 0xD8 // 256kB -#define QSPI_CMD_ERASE_CHIP 0x60 // or 0xC7 - -// erase operations max time [us] (datasheet max time + 15%) -#define QSPI_ERASE_SECTOR_MAX_TIME 850000 // 1.15*725 ~ 850 ms - -// max frequency for basic rw operation (for fast mode) -#define QSPI_COMMON_MAX_FREQUENCY 50000000 - -#define QSPI_STATUS_REG_SIZE 1 -#define QSPI_CONFIG_REG_0_SIZE 1 -#define QSPI_SECURITY_REG_SIZE 1 -#define QSPI_MAX_REG_SIZE 2 - -// status register -#define STATUS_BIT_WIP (1 << 0) // write in progress bit -#define STATUS_BIT_WEL (1 << 1) // write enable latch -#define STATUS_BIT_BP0 (1 << 2) // -#define STATUS_BIT_BP1 (1 << 3) // -#define STATUS_BIT_BP2 (1 << 4) // -#define STATUS_BIT_BP3 (1 << 5) // -#define STATUS_BIT_QE (1 << 1) // Quad Enable -#define STATUS_BIT_SRWD (1 << 7) // status register write protect - -// configuration register 0 -// bit 0, 1, 2, 4, 5, 7 reserved -#define CONFIG0_BIT_TB (1 << 3) // Top/Bottom area protect -#define CONFIG0_BIT_DC (1 << 6) // Dummy Cycle - -// configuration register 1 -// bit 0, 2, 3, 4, 5, 6, 7 reserved -#define CONFIG1_BIT_LH (1 << 1) // 0 = Ultra Low power mode, 1 = High performance mode - - - -#define EXTENDED_SPI_ENABLE() \ - \ - const int32_t reg_size = QSPI_STATUS_REG_SIZE + QSPI_CONFIG_REG_0_SIZE; \ - uint8_t reg_data[reg_size] = { 0 }; \ - \ - if (read_register(STATUS_REG, reg_data, \ - QSPI_STATUS_REG_SIZE, qspi) != QSPI_STATUS_OK) { \ - return QSPI_STATUS_ERROR; \ - } \ - if (read_register(CONFIG_REG0, reg_data + QSPI_STATUS_REG_SIZE, \ - QSPI_CONFIG_REG_0_SIZE, qspi) != QSPI_STATUS_OK) { \ - return QSPI_STATUS_ERROR; \ - } \ - \ - if (write_enable(qspi) != QSPI_STATUS_OK) { \ - return QSPI_STATUS_ERROR; \ - } \ - \ - reg_data[1] |= STATUS_BIT_QE; \ - if (write_register(QSPI_CMD_WRSR, reg_data, \ - reg_size, qspi) != QSPI_STATUS_OK) { \ - return QSPI_STATUS_ERROR; \ - } \ - \ - WAIT_FOR(WRSR_MAX_TIME, qspi); \ - \ - memset(reg_data, 0, QSPI_STATUS_REG_SIZE); \ - if (read_register(CONFIG_REG0, reg_data, \ - QSPI_STATUS_REG_SIZE, qspi) != QSPI_STATUS_OK) { \ - return QSPI_STATUS_ERROR; \ - } \ - \ - return ((reg_data[0] & STATUS_BIT_QE) != 0 ? \ - QSPI_STATUS_OK : QSPI_STATUS_ERROR) - - - -#define EXTENDED_SPI_DISABLE() \ - \ - const int32_t reg_size = QSPI_STATUS_REG_SIZE + QSPI_CONFIG_REG_0_SIZE; \ - uint8_t reg_data[reg_size] = { 0 }; \ - \ - if (read_register(STATUS_REG, reg_data, \ - QSPI_STATUS_REG_SIZE, qspi) != QSPI_STATUS_OK) { \ - return QSPI_STATUS_ERROR; \ - } \ - \ - if (read_register(CONFIG_REG0, reg_data + QSPI_STATUS_REG_SIZE, \ - QSPI_CONFIG_REG_0_SIZE, qspi) != QSPI_STATUS_OK) { \ - return QSPI_STATUS_ERROR; \ - } \ - \ - if (write_enable(qspi) != QSPI_STATUS_OK) { \ - return QSPI_STATUS_ERROR; \ - } \ - \ - reg_data[1] &= ~(STATUS_BIT_QE); \ - \ - if (write_register(QSPI_CMD_WRSR, reg_data, \ - reg_size, qspi) != QSPI_STATUS_OK) { \ - return QSPI_STATUS_ERROR; \ - } \ - \ - WAIT_FOR(WRSR_MAX_TIME, qspi); \ - \ - reg_data[0] = 0; \ - if (read_register(CONFIG_REG0, reg_data, \ - QSPI_STATUS_REG_SIZE, qspi) != QSPI_STATUS_OK) { \ - return QSPI_STATUS_ERROR; \ - } \ - \ - return ((reg_data[0] & STATUS_BIT_QE) == 0 ? \ - QSPI_STATUS_OK : QSPI_STATUS_ERROR) - - -#endif // MBED_QSPI_FLASH_S25FS512S_H diff --git a/TESTS/mbed_hal/qspi/flash_configs/SiliconLabs/EFM32GG11_STK3701/flash_config.h b/TESTS/mbed_hal/qspi/flash_configs/SiliconLabs/EFM32GG11_STK3701/flash_config.h deleted file mode 100644 index 5ff3dde..0000000 --- a/TESTS/mbed_hal/qspi/flash_configs/SiliconLabs/EFM32GG11_STK3701/flash_config.h +++ /dev/null @@ -1,29 +0,0 @@ -/* mbed Microcontroller Library - * Copyright (c) 2018-2018 ARM Limited - * 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. - */ -#ifndef MBED_QSPI_FLASH_CONFIG_H -#define MBED_QSPI_FLASH_CONFIG_H - -#include "../../MX25RXX35F_config.h" - -#ifdef QSPI_SECTOR_COUNT -#undef QSPI_SECTOR_COUNT -#define QSPI_SECTOR_COUNT 1024 // for MX25R3235F -#endif - -#define QSPI_MIN_FREQUENCY 2000000 - -#endif // MBED_QSPI_FLASH_CONFIG_H diff --git a/TESTS/mbed_hal/qspi/flash_configs/W25Q32JV_config.h b/TESTS/mbed_hal/qspi/flash_configs/W25Q32JV_config.h deleted file mode 100644 index 3ab306b..0000000 --- a/TESTS/mbed_hal/qspi/flash_configs/W25Q32JV_config.h +++ /dev/null @@ -1,185 +0,0 @@ -/* mbed Microcontroller Library - * Copyright (c) 2018-2018 ARM Limited - * 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. - */ -#ifndef MBED_QSPI_FLASH_W25Q32JV_H -#define MBED_QSPI_FLASH_W25Q32JV_H - - -#define QSPI_FLASH_CHIP_STRING "Winbond W25Q32JV" - -// Command for reading status register -#define QSPI_CMD_RDSR 0x05 -// Command for reading configuration register -#define QSPI_CMD_RDCR0 0x35 -#define QSPI_CMD_RDCR1 0x15 -// Command for writing status/configuration register -#define QSPI_CMD_WRSR 0x01 -// Command for writing configuration register -#define QSPI_CMD_WRCR0 0x31 -#define QSPI_CMD_WRCR1 0x11 -// Command for reading security register -#define QSPI_CMD_RDSCUR 0x48 - -// Command for setting Reset Enable -#define QSPI_CMD_RSTEN 0x66 -// Command for setting Reset -#define QSPI_CMD_RST 0x99 - -// Command for setting write enable -#define QSPI_CMD_WREN 0x06 -// Command for setting write disable -#define QSPI_CMD_WRDI 0x04 - -// WRSR operations max time [us] (datasheet max time + 15%) -#define QSPI_WRSR_MAX_TIME 34500 // 30ms -// general wait max time [us] -#define QSPI_WAIT_MAX_TIME 100000 // 100ms - - -// Commands for writing (page programming) -#define QSPI_CMD_WRITE_1IO 0x02 // 1-1-1 mode - -// write operations max time [us] (datasheet max time + 15%) -#define QSPI_PAGE_PROG_MAX_TIME 11500 // 10ms - -#define QSPI_PAGE_SIZE 256 // 256B -#define QSPI_SECTOR_SIZE 4096 // 4kB -#define QSPI_SECTOR_COUNT 1024 - -// Commands for reading -#define QSPI_CMD_READ_1IO_FAST 0x0B // 1-1-1 mode -#define QSPI_CMD_READ_1IO 0x03 // 1-1-1 mode -#define QSPI_CMD_READ_2IO 0xBB // 1-2-2 mode -#define QSPI_CMD_READ_1I2O 0x3B // 1-1-2 mode -#define QSPI_CMD_READ_4IO 0xEB // 1-4-4 mode -#define QSPI_CMD_READ_1I4O 0x6B // 1-1-4 mode - -#define QSPI_READ_1IO_DUMMY_CYCLE 0 -#define QSPI_READ_FAST_DUMMY_CYCLE 8 -#define QSPI_READ_2IO_DUMMY_CYCLE 4 -#define QSPI_READ_1I2O_DUMMY_CYCLE 8 -#define QSPI_READ_4IO_DUMMY_CYCLE 6 -#define QSPI_READ_1I4O_DUMMY_CYCLE 8 - -// Commands for erasing -#define QSPI_CMD_ERASE_SECTOR 0x20 // 4kB -#define QSPI_CMD_ERASE_BLOCK_32 0x52 // 32kB -#define QSPI_CMD_ERASE_BLOCK_64 0xD8 // 64kB -#define QSPI_CMD_ERASE_CHIP 0x60 // or 0xC7 - -// erase operations max time [us] (datasheet max time + 15%) -#define QSPI_ERASE_SECTOR_MAX_TIME 480000 // 400 ms -#define QSPI_ERASE_BLOCK_32_MAX_TIME 3450000 // 3s -#define QSPI_ERASE_BLOCK_64_MAX_TIME 4025000 // 3.5s - -// max frequency for basic rw operation (for fast mode) -#define QSPI_COMMON_MAX_FREQUENCY 32000000 - -#define QSPI_STATUS_REG_SIZE 1 -#define QSPI_CONFIG_REG_0_SIZE 1 -#define QSPI_CONFIG_REG_1_SIZE 1 - -#define QSPI_SECURITY_REG_SIZE 1 -#define QSPI_MAX_REG_SIZE 1 - -// status register -#define STATUS_BIT_WIP (1 << 0) // write in progress bit -#define STATUS_BIT_WEL (1 << 1) // write enable latch -#define STATUS_BIT_BP0 (1 << 2) // block protect 0 -#define STATUS_BIT_BP1 (1 << 3) // block protect 1 -#define STATUS_BIT_BP2 (1 << 4) // block protect 2 -#define STATUS_BIT_BP_TB (1 << 5) // block protect top/bottom -#define STATUS_BIT_SP (1 << 6) // sector protect -#define STATUS_BIT_SRWD (1 << 7) // status register protect - -// configuration register 0 -// bit 2 reserved -#define CONFIG0_BIT_SRL (1 << 0) // status register lock -#define CONFIG0_BIT_QE (1 << 1) // quad enable -#define CONFIG0_BIT_LB1 (1 << 3) // security register lock 1 -#define CONFIG0_BIT_LB2 (1 << 4) // security register lock 2 -#define CONFIG0_BIT_LB3 (1 << 5) // security register lock 3 -#define CONFIG0_BIT_CMP (1 << 6) // complement protect -#define CONFIG0_BIT_SUS (1 << 7) // suspend status - -// configuration register 1 -// bits 0, 1, 3, 4, 7 reserved -#define CONFIG1_BIT_WPS (1 << 2) // write protect selection -#define CONFIG1_BIT_DRV2 (1 << 5) // output driver strength 2 -#define CONFIG1_BIT_DRV1 (1 << 6) // output driver strength 1 - - - -#define QUAD_ENABLE() \ - \ - uint8_t reg_data[QSPI_CONFIG_REG_0_SIZE]; \ - \ - memset(reg_data, 0, QSPI_CONFIG_REG_0_SIZE); \ - if (read_register(QSPI_CMD_RDCR0, reg_data, \ - QSPI_CONFIG_REG_0_SIZE, qspi) != QSPI_STATUS_OK) { \ - return QSPI_STATUS_ERROR; \ - } \ - if (write_enable(qspi) != QSPI_STATUS_OK) { \ - return QSPI_STATUS_ERROR; \ - } \ - \ - reg_data[0] = reg_data[0] & ~(CONFIG0_BIT_QE); \ - if (write_register(QSPI_CMD_WRCR0, reg_data, \ - QSPI_CONFIG_REG_0_SIZE, qspi) != QSPI_STATUS_OK) { \ - return QSPI_STATUS_ERROR; \ - } \ - qspi.cmd.configure(MODE_4_4_4, ADDR_SIZE_24, ALT_SIZE_8); \ - WAIT_FOR(WRSR_MAX_TIME, qspi); \ - memset(reg_data, 0, QSPI_CONFIG_REG_0_SIZE); \ - if (read_register(QSPI_CMD_RDCR0, reg_data, \ - QSPI_CONFIG_REG_0_SIZE, qspi) != QSPI_STATUS_OK) { \ - return QSPI_STATUS_ERROR; \ - } \ - \ - return ((reg_data[0] & (CONFIG0_BIT_QE)) == 0 ? \ - QSPI_STATUS_OK : QSPI_STATUS_ERROR) - - -#define QUAD_DISABLE() \ - \ - uint8_t reg_data[QSPI_CONFIG_REG_0_SIZE]; \ - \ - memset(reg_data, 0, QSPI_CONFIG_REG_0_SIZE); \ - if (read_register(QSPI_CMD_RDCR0, reg_data, \ - QSPI_CONFIG_REG_0_SIZE, qspi) != QSPI_STATUS_OK) { \ - return QSPI_STATUS_ERROR; \ - } \ - if (write_enable(qspi) != QSPI_STATUS_OK) { \ - return QSPI_STATUS_ERROR; \ - } \ - \ - reg_data[0] = reg_data[0] | (CONFIG0_BIT_QE); \ - if (write_register(QSPI_CMD_WRCR0, reg_data, \ - QSPI_CONFIG_REG_0_SIZE, qspi) != QSPI_STATUS_OK) { \ - return QSPI_STATUS_ERROR; \ - } \ - WAIT_FOR(WRSR_MAX_TIME, qspi); \ - qspi.cmd.configure(MODE_1_1_1, ADDR_SIZE_24, ALT_SIZE_8); \ - memset(reg_data, 0, QSPI_CONFIG_REG_0_SIZE); \ - if (read_register(QSPI_CMD_RDCR0, reg_data, \ - QSPI_CONFIG_REG_0_SIZE, qspi) != QSPI_STATUS_OK) { \ - return QSPI_STATUS_ERROR; \ - } \ - \ - return ((reg_data[0] & CONFIG0_BIT_QE) != 1 ? \ - QSPI_STATUS_OK : QSPI_STATUS_ERROR) - -#endif // MBED_QSPI_FLASH_W25Q32JV_H diff --git a/TESTS/mbed_hal/qspi/flash_configs/flash_configs.h b/TESTS/mbed_hal/qspi/flash_configs/flash_configs.h deleted file mode 100644 index cca4212..0000000 --- a/TESTS/mbed_hal/qspi/flash_configs/flash_configs.h +++ /dev/null @@ -1,83 +0,0 @@ -/* mbed Microcontroller Library - * Copyright (c) 2018-2018 ARM Limited - * 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. - */ - -#ifndef MBED_FLASH_CONFIGS_H -#define MBED_FLASH_CONFIGS_H - -#if defined(TARGET_MX25R6435F) -#include "MX25RXX35F_config.h" - -#elif defined(TARGET_DISCO_L476VG) -#include "N25Q128A_config.h" // N25Q128A13EF840E -/* See STM32L476 Errata Sheet, it is not possible to use Dual-/Quad-mode for the command phase */ -#undef QSPI_CMD_READ_DPI -#undef QSPI_CMD_READ_QPI -#undef QSPI_CMD_WRITE_DPI -#undef QSPI_CMD_WRITE_QPI - -#elif defined(TARGET_N25Q128A) -#include "N25Q128A_config.h" - -#elif defined(TARGET_MX25L51245G) -#include "MX25L51245G_config.h" - -#elif defined(TARGET_MX25LM51245G) -#include "MX25LM51245G_config.h" - -#elif defined(TARGET_RHOMBIO_L476DMW1K) -#include "MT25Q_config.h" // MT25QL128ABA1EW7 -/* See STM32L476 Errata Sheet, it is not possible to use Dual-/Quad-mode for the command phase */ -#undef QSPI_CMD_READ_DPI -#undef QSPI_CMD_READ_QPI -#undef QSPI_CMD_WRITE_DPI -#undef QSPI_CMD_WRITE_QPI - -#elif defined(TARGET_NRF52840) -#if TARGET_EP_AGORA -#include "NORDIC/EP_AGORA/flash_config.h" -#else -#include "NORDIC/NRF52840_DK/flash_config.h" -#endif - -#elif defined(TARGET_EFM32GG11_STK3701) -#include "SiliconLabs/EFM32GG11_STK3701/flash_config.h" - -#elif defined(TARGET_K82F) -#include "NXP/K82F/flash_config.h" - -#elif defined(TARGET_LPC546XX) -#include "NXP/LPC546XX/flash_config.h" - -#elif( defined(TARGET_CY8CKIT_062_BLE) || \ - defined(TARGET_CY8CKIT_062_WIFI_BT) || \ - defined(TARGET_CY8CKIT_062S2_43012) || \ - defined(TARGET_CY8CKIT_062S2_4343W) || \ - defined(TARGET_CY8CKIT_064S2_4343W) || \ - defined(TARGET_CY8CKIT_064B0S2_4343W) || \ - defined(TARGET_CY8CPROTO_062_4343W) || \ - defined(TARGET_CY8CPROTO_062S2_43012) || \ - defined(TARGET_CY8CPROTO_062S3_4343W) || \ - defined(TARGET_CYW9P62S1_43438EVB_01) || \ - defined(TARGET_CYSBSYSKIT_01)) -#include "S25FL512S_config.h" - -#elif defined(TARGET_CYW9P62S1_43012EVB_01) -#include "S25FS512S_config.h" - -#endif - -#endif // MBED_FLASH_CONFIGS_H diff --git a/TESTS/mbed_hal/qspi/main.cpp b/TESTS/mbed_hal/qspi/main.cpp deleted file mode 100644 index 4259f61..0000000 --- a/TESTS/mbed_hal/qspi/main.cpp +++ /dev/null @@ -1,628 +0,0 @@ -/* mbed Microcontroller Library - * Copyright (c) 2018-2018 ARM Limited - * 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. - */ - -#if !DEVICE_QSPI -#error [NOT_SUPPORTED] QSPI not supported for this target -#else - -#include "utest/utest.h" -#include "unity/unity.h" -#include "greentea-client/test_env.h" -#include "qspi_test.h" -#include "qspi_test_utils.h" - -#include "mbed.h" -#include "qspi_api.h" -#include "hal/us_ticker_api.h" - - -#if !defined(QSPI_FLASH_CHIP_STRING) -#error [NOT_SUPPORTED] QSPI test not supported for this target -#else - -using namespace utest::v1; - -// uncomment to enable verbose mode -//#define QSPI_TEST_LOG_DATA -//#define QSPI_TEST_LOG_FLASH_TIME -//#define QSPI_TEST_LOG_FLASH_STATUS - - - -#ifndef QSPI_MIN_FREQUENCY -#define QSPI_MIN_FREQUENCY 1000000 -#endif - -// max write size is usually page size -#define DATA_SIZE_256 (QSPI_PAGE_SIZE) -#define DATA_SIZE_1024 (QSPI_PAGE_SIZE * 4) - -uint8_t tx_buf[DATA_SIZE_1024]; -uint8_t rx_buf[DATA_SIZE_1024]; - - -// write address should be page aligned -#define TEST_FLASH_ADDRESS 0x0 - -#define TEST_REPEAT_SINGLE 1 -#define TEST_REPEAT_MULTIPLE 4 - -// write block of data in single write operation -#define WRITE_SINGLE 1 -// write block of data in adjacent locations in multiple write operations -#define WRITE_MULTIPLE 4 - -// read block of data in single read operation -#define READ_SINGLE 1 -// read block of data in adjacent locations in multiple read operations -#define READ_MULTIPLE 4 - - -// some target defines QSPI pins as integers thus conversion needed -#define QPIN_0 static_cast(MBED_CONF_DRIVERS_QSPI_IO0) -#define QPIN_1 static_cast(MBED_CONF_DRIVERS_QSPI_IO1) -#define QPIN_2 static_cast(MBED_CONF_DRIVERS_QSPI_IO2) -#define QPIN_3 static_cast(MBED_CONF_DRIVERS_QSPI_IO3) -#define QSCK static_cast(MBED_CONF_DRIVERS_QSPI_SCK) -#define QCSN static_cast(MBED_CONF_DRIVERS_QSPI_CSN) - - -static uint32_t gen_flash_address() -{ - srand(ticker_read(get_us_ticker_data())); - uint32_t address = (((uint32_t)rand()) % QSPI_SECTOR_COUNT) * QSPI_SECTOR_SIZE; - address &= 0xFFFFFF; // Ensure address is within 24 bits so as to not have to deal with 4-byte addressing - return address; -} - -static void log_data(const char *str, uint8_t *data, uint32_t size) -{ - utest_printf("%s: ", str); - for (uint32_t j = 0; j < size; j++) { - utest_printf("%02X ", data[j]); - } - utest_printf("\r\n"); -} - - -static void _qspi_write_read_test(Qspi &qspi, qspi_bus_width_t write_inst_width, qspi_bus_width_t write_addr_width, - qspi_bus_width_t write_data_width, qspi_bus_width_t write_alt_width, uint32_t write_cmd, - qspi_address_size_t write_addr_size, qspi_alt_size_t write_alt_size, - uint32_t write_count, qspi_bus_width_t read_inst_width, qspi_bus_width_t read_addr_width, - qspi_bus_width_t read_data_width, qspi_bus_width_t read_alt_width, uint32_t read_cmd, - int read_dummy_cycles, qspi_address_size_t read_addr_size, qspi_alt_size_t read_alt_size, - uint32_t read_count, uint32_t test_count, uint32_t data_size, - uint32_t flash_addr) -{ - qspi_status_t ret = QSPI_STATUS_OK; - - Timer timer; - int erase_time = 0, write_time = 0, read_time = 0; - size_t buf_len = data_size; - - for (uint32_t tc = 0; tc < test_count; tc++) { - - srand(ticker_read(get_us_ticker_data())); - for (uint32_t i = 0; i < data_size; i++) { - tx_buf[i] = (uint8_t)(rand() & 0xFF); - } - - ret = write_enable(qspi); - TEST_ASSERT_EQUAL(QSPI_STATUS_OK, ret); - - timer.reset(); - timer.start(); - - ret = erase(SECTOR_ERASE, flash_addr, qspi); - TEST_ASSERT_EQUAL(QSPI_STATUS_OK, ret); - WAIT_FOR(SECTOR_ERASE_MAX_TIME, qspi); - - timer.stop(); - erase_time = timer.read_us(); - - // switching to extended-SPI/DPI/QPI mode here for write operation - // for DPI/QPI qspi.cmd is automatically switched to 2_2_2/4_4_4 mode - ret = mode_enable(qspi, write_inst_width, write_addr_width, write_data_width); - TEST_ASSERT_EQUAL(QSPI_STATUS_OK, ret); - - const uint32_t write_size = data_size / write_count; - for (uint32_t wc = 0, write_start = flash_addr; wc < write_count; wc++, write_start += write_size) { - ret = write_enable(qspi); - TEST_ASSERT_EQUAL(QSPI_STATUS_OK, ret); - - timer.reset(); - timer.start(); - - buf_len = write_size; - qspi.cmd.configure(write_inst_width, write_addr_width, write_data_width, write_alt_width, write_addr_size, write_alt_size); - qspi.cmd.build(write_cmd, write_start); - ret = qspi_write(&qspi.handle, qspi.cmd.get(), tx_buf + wc * write_size, &buf_len); - TEST_ASSERT_EQUAL(QSPI_STATUS_OK, ret); - TEST_ASSERT_EQUAL(write_size, buf_len); - - if (is_extended_mode(write_inst_width, write_addr_width, write_data_width)) { - // on some flash chips in extended-SPI mode, control commands works only in 1-1-1 mode - // so switching back to 1-1-1 mode - qspi.cmd.configure(MODE_1_1_1, ADDR_SIZE_24, ALT_SIZE_8); - } - - WAIT_FOR(PAGE_PROG_MAX_TIME, qspi); - - timer.stop(); - write_time = timer.read_us(); - } - - // switching back to single channel SPI - ret = mode_disable(qspi, write_inst_width, write_addr_width, write_data_width); - TEST_ASSERT_EQUAL(QSPI_STATUS_OK, ret); - - // switching to extended-SPI/DPI/QPI mode here for read operation - // for DPI/QPI qspi.cmd is automatically switched to 2_2_2/4_4_4 mode - ret = mode_enable(qspi, read_inst_width, read_addr_width, read_data_width); - TEST_ASSERT_EQUAL(QSPI_STATUS_OK, ret); - - memset(rx_buf, 0, sizeof(rx_buf)); - const uint32_t read_size = data_size / read_count; - qspi.cmd.configure(read_inst_width, read_addr_width, read_data_width, read_alt_width, read_addr_size, read_alt_size, read_dummy_cycles); - for (uint32_t rc = 0, read_start = flash_addr; rc < read_count; rc++, read_start += read_size) { - timer.reset(); - timer.start(); - - buf_len = read_size; - qspi.cmd.build(read_cmd, read_start); - ret = qspi_read(&qspi.handle, qspi.cmd.get(), rx_buf + rc * read_size, &buf_len); - TEST_ASSERT_EQUAL(QSPI_STATUS_OK, ret); - TEST_ASSERT_EQUAL(read_size, buf_len); - - timer.stop(); - read_time = timer.read_us(); - } - qspi.cmd.set_dummy_cycles(0); - - if (is_extended_mode(read_inst_width, read_addr_width, read_data_width)) { - // on some flash chips in extended-SPI mode, control commands works only in 1-1-1 mode - // so switching back to 1-1-1 mode - qspi.cmd.configure(MODE_1_1_1, ADDR_SIZE_24, ALT_SIZE_8); - } - - // switching back to single channel SPI - ret = mode_disable(qspi, read_inst_width, read_addr_width, read_data_width); - TEST_ASSERT_EQUAL(QSPI_STATUS_OK, ret); - - for (uint32_t i = 0; i < data_size; i++) { - if (tx_buf[i] != rx_buf[i]) { - log_data("tx data", tx_buf, data_size); - log_data("rx data", rx_buf, data_size); - utest_printf("erase/write/read time: %d/%d/%d [us]\r\n", erase_time, write_time, read_time); - TEST_ASSERT_EQUAL(tx_buf[i], rx_buf[i]); - } - } - -#ifdef QSPI_TEST_LOG_FLASH_TIME - utest_printf("erase/write/read time: %d/%d/%d [us]\r\n", erase_time, write_time, read_time); -#endif - -#ifdef QSPI_TEST_LOG_DATA - log_data("tx data", tx_buf, data_size); - log_data("rx data", rx_buf, data_size); - utest_printf("rx/tx data match\r\n"); -#endif - } -} - - -template < qspi_bus_width_t write_inst_width, - qspi_bus_width_t write_addr_width, - qspi_bus_width_t write_data_width, - qspi_bus_width_t write_alt_width, - unsigned int write_cmd, - qspi_address_size_t write_addr_size, - qspi_alt_size_t write_alt_size, - uint32_t write_count, - qspi_bus_width_t read_inst_width, - qspi_bus_width_t read_addr_width, - qspi_bus_width_t read_data_width, - qspi_bus_width_t read_alt_width, - unsigned int read_cmd, - int read_dummy_cycles, - qspi_address_size_t read_addr_size, - qspi_alt_size_t read_alt_size, - int frequency, - uint32_t read_count, - uint32_t test_count, - uint32_t data_size, - uint32_t flash_addr> -void qspi_write_read_test(void) -{ - qspi_status_t ret; - Qspi qspi; - - uint32_t addr = flash_addr; - if (addr == 0) { - // if no specified address selected, use random one to extend flash life - addr = gen_flash_address(); - } - - qspi_init(&qspi.handle, QPIN_0, QPIN_1, QPIN_2, QPIN_3, QSCK, QCSN, QSPI_COMMON_MAX_FREQUENCY, 0); - - ret = qspi_frequency(&qspi.handle, frequency); - TEST_ASSERT_EQUAL(QSPI_STATUS_OK, ret); - - qspi.cmd.configure(MODE_1_1_1, ADDR_SIZE_24, ALT_SIZE_8); - flash_init(qspi); - - // switch memory to high performance mode (if available) - ret = fast_mode_enable(qspi); - TEST_ASSERT_EQUAL(QSPI_STATUS_OK, ret); - -#ifdef QSPI_TEST_LOG_FLASH_STATUS - log_register(STATUS_REG, QSPI_STATUS_REG_SIZE, qspi, "Status register"); - log_register(CONFIG_REG0, QSPI_CONFIG_REG_0_SIZE, qspi, "Config register 0"); -#ifdef CONFIG_REG1 - log_register(CONFIG_REG1, QSPI_CONFIG_REG_1_SIZE, qspi, "Config register 1"); -#endif -#ifdef CONFIG_REG2 - log_register(CONFIG_REG2, QSPI_CONFIG_REG_2_SIZE, qspi, "Config register 2"); -#endif -#endif - - _qspi_write_read_test(qspi, write_inst_width, write_addr_width, write_data_width, write_alt_width, write_cmd, - write_addr_size, write_alt_size, write_count, read_inst_width, - read_addr_width, read_data_width, read_alt_width, read_cmd, read_dummy_cycles, - read_addr_size, read_alt_size, read_count, test_count, - data_size, addr); - - ret = fast_mode_disable(qspi); - TEST_ASSERT_EQUAL(QSPI_STATUS_OK, ret); - - qspi_free(&qspi.handle); -} - - -void qspi_init_free_test(void) -{ - Qspi qspi; - qspi_status_t ret; - - ret = qspi_init(&qspi.handle, QPIN_0, QPIN_1, QPIN_2, QPIN_3, QSCK, QCSN, QSPI_COMMON_MAX_FREQUENCY, 0); - TEST_ASSERT_EQUAL(QSPI_STATUS_OK, ret); - ret = qspi_free(&qspi.handle); - TEST_ASSERT_EQUAL(QSPI_STATUS_OK, ret); - - - ret = qspi_init(&qspi.handle, QPIN_0, QPIN_1, QPIN_2, QPIN_3, QSCK, QCSN, QSPI_COMMON_MAX_FREQUENCY, 0); - TEST_ASSERT_EQUAL(QSPI_STATUS_OK, ret); - ret = qspi_free(&qspi.handle); - TEST_ASSERT_EQUAL(QSPI_STATUS_OK, ret); - - - ret = qspi_init(&qspi.handle, QPIN_0, QPIN_1, QPIN_2, QPIN_3, QSCK, QCSN, QSPI_COMMON_MAX_FREQUENCY, 0); - TEST_ASSERT_EQUAL(QSPI_STATUS_OK, ret); - ret = qspi_free(&qspi.handle); - TEST_ASSERT_EQUAL(QSPI_STATUS_OK, ret); - - - ret = qspi_init(&qspi.handle, QPIN_0, QPIN_1, QPIN_2, QPIN_3, QSCK, QCSN, QSPI_COMMON_MAX_FREQUENCY, 0); - TEST_ASSERT_EQUAL(QSPI_STATUS_OK, ret); - - // check if the memory is working properly - qspi.cmd.configure(MODE_1_1_1, ADDR_SIZE_24, ALT_SIZE_8); - flash_init(qspi); - -#ifdef QSPI_TEST_LOG_FLASH_STATUS - log_register(STATUS_REG, QSPI_STATUS_REG_SIZE, qspi, "Status register"); - log_register(CONFIG_REG0, QSPI_CONFIG_REG_0_SIZE, qspi, "Config register 0"); -#ifdef CONFIG_REG1 - log_register(CONFIG_REG1, QSPI_CONFIG_REG_1_SIZE, qspi, "Config register 1"); -#endif -#ifdef CONFIG_REG2 - log_register(CONFIG_REG2, QSPI_CONFIG_REG_2_SIZE, qspi, "Config register 2"); -#endif -#endif - - _qspi_write_read_test(qspi, WRITE_1_1_1, ADDR_SIZE_24, ALT_SIZE_8, WRITE_SINGLE, READ_1_1_1, ADDR_SIZE_24, ALT_SIZE_8, READ_SINGLE, TEST_REPEAT_SINGLE, DATA_SIZE_256, TEST_FLASH_ADDRESS); - qspi_free(&qspi.handle); -} - - -void qspi_frequency_test(void) -{ - Qspi qspi; - qspi_status_t ret; - int freq = QSPI_COMMON_MAX_FREQUENCY; - - ret = qspi_init(&qspi.handle, QPIN_0, QPIN_1, QPIN_2, QPIN_3, QSCK, QCSN, freq, 0); - TEST_ASSERT_EQUAL(QSPI_STATUS_OK, ret); - - while (ret == QSPI_STATUS_OK && freq >= QSPI_MIN_FREQUENCY) { - // check if the memory is working properly - qspi.cmd.configure(MODE_1_1_1, ADDR_SIZE_24, ALT_SIZE_8); - ret = qspi_frequency(&qspi.handle, freq); - flash_init(qspi); - _qspi_write_read_test(qspi, WRITE_1_1_1, ADDR_SIZE_24, ALT_SIZE_8, WRITE_SINGLE, READ_1_1_1, ADDR_SIZE_24, ALT_SIZE_8, READ_SINGLE, TEST_REPEAT_SINGLE, DATA_SIZE_256, TEST_FLASH_ADDRESS); - - utest_printf("frequency setting %d [Hz] - OK\r\n", freq); - - freq /= 2; - } - - qspi_free(&qspi.handle); -} - - -void qspi_memory_id_test() -{ - utest_printf("*** %s memory config loaded ***\r\n", QSPI_FLASH_CHIP_STRING); -} - - -Case cases[] = { - Case("qspi memory id test", qspi_memory_id_test), - Case("qspi init/free test", qspi_init_free_test), - Case("qspi frequency setting test", qspi_frequency_test), - // read/x1 write/x1 - read/write block of data in single write/read operation - // read/x4 write/x4 - read/write block of data in adjacent locations in multiple write/read operations - // repeat/xN - test repeat count (new data pattern each time) - // 1-1-1 - single channel SPI - // 1-1-2 - Dual data (extended SPI) - // 1-2-2 - Dual I/O (extended SPI) - // 1-1-4 - Quad data (extended SPI) - // 1-4-4 - Quad I/O (extended SPI) - // 2-2-2 - DPI (multi-channel SPI) - // 4-4-4 - QPI (multi-channel SPI) - Case("qspi write(1-1-1)/x1 read(1-1-1)/x1 repeat/x1 test", qspi_write_read_test), - Case("qspi write(1-1-1)/x4 read(1-1-1)/x1 repeat/x1 test", qspi_write_read_test), - Case("qspi write(1-1-1)/x1 read(1-1-1)/x4 repeat/x1 test", qspi_write_read_test), - Case("qspi write(1-1-1)/x1 read(1-1-1)/x1 repeat/x4 test", qspi_write_read_test), -#ifdef READ_1_1_2 - Case("qspi write(1-1-1)/x1 read(1-1-2)/x1 repeat/x1 test", qspi_write_read_test), - Case("qspi write(1-1-1)/x4 read(1-1-2)/x1 repeat/x1 test", qspi_write_read_test), - Case("qspi write(1-1-1)/x1 read(1-1-2)/x4 repeat/x1 test", qspi_write_read_test), - Case("qspi write(1-1-1)/x1 read(1-1-2)/x1 repeat/x4 test", qspi_write_read_test), -#endif -#ifdef READ_1_2_2 - Case("qspi write(1-1-1)/x1 read(1-2-2)/x1 repeat/x1 test", qspi_write_read_test), - Case("qspi write(1-1-1)/x4 read(1-2-2)/x1 repeat/x1 test", qspi_write_read_test), - Case("qspi write(1-1-1)/x1 read(1-2-2)/x4 repeat/x1 test", qspi_write_read_test), - Case("qspi write(1-1-1)/x1 read(1-2-2)/x1 repeat/x4 test", qspi_write_read_test), -#endif -#ifdef READ_2_2_2 - Case("qspi write(1-1-1)/x1 read(2-2-2)/x1 repeat/x1 test", qspi_write_read_test), - Case("qspi write(1-1-1)/x4 read(2-2-2)/x1 repeat/x1 test", qspi_write_read_test), - Case("qspi write(1-1-1)/x1 read(2-2-2)/x4 repeat/x1 test", qspi_write_read_test), - Case("qspi write(1-1-1)/x1 read(2-2-2)/x1 repeat/x4 test", qspi_write_read_test), -#endif -#ifdef READ_1_1_4 - Case("qspi write(1-1-1)/x1 read(1-1-4)/x1 repeat/x1 test", qspi_write_read_test), - Case("qspi write(1-1-1)/x4 read(1-1-4)/x1 repeat/x1 test", qspi_write_read_test), - Case("qspi write(1-1-1)/x1 read(1-1-4)/x4 repeat/x1 test", qspi_write_read_test), - Case("qspi write(1-1-1)/x1 read(1-1-4)/x1 repeat/x4 test", qspi_write_read_test), -#endif -#ifdef READ_1_4_4 - Case("qspi write(1-1-1)/x1 read(1-4-4)/x1 repeat/x1 test", qspi_write_read_test), - Case("qspi write(1-1-1)/x4 read(1-4-4)/x1 repeat/x1 test", qspi_write_read_test), - Case("qspi write(1-1-1)/x1 read(1-4-4)/x4 repeat/x1 test", qspi_write_read_test), - Case("qspi write(1-1-1)/x1 read(1-4-4)/x1 repeat/x4 test", qspi_write_read_test), -#endif -#ifdef READ_4_4_4 - Case("qspi write(1-1-1)/x1 read(4-4-4)/x1 repeat/x1 test", qspi_write_read_test), - Case("qspi write(1-1-1)/x4 read(4-4-4)/x1 repeat/x1 test", qspi_write_read_test), - Case("qspi write(1-1-1)/x1 read(4-4-4)/x4 repeat/x1 test", qspi_write_read_test), - Case("qspi write(1-1-1)/x1 read(4-4-4)/x1 repeat/x4 test", qspi_write_read_test), -#endif - -#ifdef WRITE_1_2_2 - Case("qspi write(1-2-2)/x1 read(1-1-1)/x1 repeat/x1 test", qspi_write_read_test), - Case("qspi write(1-2-2)/x4 read(1-1-1)/x1 repeat/x1 test", qspi_write_read_test), - Case("qspi write(1-2-2)/x1 read(1-1-1)/x4 repeat/x1 test", qspi_write_read_test), - Case("qspi write(1-2-2)/x1 read(1-1-1)/x1 repeat/x4 test", qspi_write_read_test), - Case("qspi write(1-2-2)/x1 read(1-1-2)/x1 repeat/x1 test", qspi_write_read_test), - Case("qspi write(1-2-2)/x4 read(1-1-2)/x1 repeat/x1 test", qspi_write_read_test), - Case("qspi write(1-2-2)/x1 read(1-1-2)/x4 repeat/x1 test", qspi_write_read_test), - Case("qspi write(1-2-2)/x1 read(1-1-2)/x1 repeat/x4 test", qspi_write_read_test), - Case("qspi write(1-2-2)/x1 read(1-2-2)/x1 repeat/x1 test", qspi_write_read_test), - Case("qspi write(1-2-2)/x4 read(1-2-2)/x1 repeat/x1 test", qspi_write_read_test), - Case("qspi write(1-2-2)/x1 read(1-2-2)/x4 repeat/x1 test", qspi_write_read_test), - Case("qspi write(1-2-2)/x1 read(1-2-2)/x1 repeat/x4 test", qspi_write_read_test), -#ifdef READ_2_2_2 - Case("qspi write(1-2-2)/x1 read(2-2-2)/x1 repeat/x1 test", qspi_write_read_test), - Case("qspi write(1-2-2)/x4 read(2-2-2)/x1 repeat/x1 test", qspi_write_read_test), - Case("qspi write(1-2-2)/x1 read(2-2-2)/x4 repeat/x1 test", qspi_write_read_test), - Case("qspi write(1-2-2)/x1 read(2-2-2)/x1 repeat/x4 test", qspi_write_read_test), -#endif -#ifdef READ_1_1_4 - Case("qspi write(1-2-2)/x1 read(1-1-4)/x1 repeat/x1 test", qspi_write_read_test), - Case("qspi write(1-2-2)/x4 read(1-1-4)/x1 repeat/x1 test", qspi_write_read_test), - Case("qspi write(1-2-2)/x1 read(1-1-4)/x4 repeat/x1 test", qspi_write_read_test), - Case("qspi write(1-2-2)/x1 read(1-1-4)/x1 repeat/x4 test", qspi_write_read_test), -#endif - Case("qspi write(1-2-2)/x1 read(1-4-4)/x1 repeat/x1 test", qspi_write_read_test), - Case("qspi write(1-2-2)/x4 read(1-4-4)/x1 repeat/x1 test", qspi_write_read_test), - Case("qspi write(1-2-2)/x1 read(1-4-4)/x4 repeat/x1 test", qspi_write_read_test), - Case("qspi write(1-2-2)/x1 read(1-4-4)/x1 repeat/x4 test", qspi_write_read_test), -#ifdef READ_4_4_4 - Case("qspi write(1-2-2)/x1 read(4-4-4)/x1 repeat/x1 test", qspi_write_read_test), - Case("qspi write(1-2-2)/x4 read(4-4-4)/x1 repeat/x1 test", qspi_write_read_test), - Case("qspi write(1-2-2)/x1 read(4-4-4)/x4 repeat/x1 test", qspi_write_read_test), - Case("qspi write(1-2-2)/x1 read(4-4-4)/x1 repeat/x4 test", qspi_write_read_test), -#endif -#endif - -#ifdef WRITE_2_2_2 - Case("qspi write(2-2-2)/x1 read(1-1-1)/x1 repeat/x1 test", qspi_write_read_test), - Case("qspi write(2-2-2)/x4 read(1-1-1)/x1 repeat/x1 test", qspi_write_read_test), - Case("qspi write(2-2-2)/x1 read(1-1-1)/x4 repeat/x1 test", qspi_write_read_test), - Case("qspi write(2-2-2)/x1 read(1-1-1)/x1 repeat/x4 test", qspi_write_read_test), - Case("qspi write(2-2-2)/x1 read(1-1-2)/x1 repeat/x1 test", qspi_write_read_test), - Case("qspi write(2-2-2)/x4 read(1-1-2)/x1 repeat/x1 test", qspi_write_read_test), - Case("qspi write(2-2-2)/x1 read(1-1-2)/x4 repeat/x1 test", qspi_write_read_test), - Case("qspi write(2-2-2)/x1 read(1-1-2)/x1 repeat/x4 test", qspi_write_read_test), - Case("qspi write(2-2-2)/x1 read(1-2-2)/x1 repeat/x1 test", qspi_write_read_test), - Case("qspi write(2-2-2)/x4 read(1-2-2)/x1 repeat/x1 test", qspi_write_read_test), - Case("qspi write(2-2-2)/x1 read(1-2-2)/x4 repeat/x1 test", qspi_write_read_test), - Case("qspi write(2-2-2)/x1 read(1-2-2)/x1 repeat/x4 test", qspi_write_read_test), -#ifdef READ_2_2_2 - Case("qspi write(2-2-2)/x1 read(2-2-2)/x1 repeat/x1 test", qspi_write_read_test), - Case("qspi write(2-2-2)/x4 read(2-2-2)/x1 repeat/x1 test", qspi_write_read_test), - Case("qspi write(2-2-2)/x1 read(2-2-2)/x4 repeat/x1 test", qspi_write_read_test), - Case("qspi write(2-2-2)/x1 read(2-2-2)/x1 repeat/x4 test", qspi_write_read_test), -#endif -#ifdef READ_1_1_4 - Case("qspi write(2-2-2)/x1 read(1-1-4)/x1 repeat/x1 test", qspi_write_read_test), - Case("qspi write(2-2-2)/x4 read(1-1-4)/x1 repeat/x1 test", qspi_write_read_test), - Case("qspi write(2-2-2)/x1 read(1-1-4)/x4 repeat/x1 test", qspi_write_read_test), - Case("qspi write(2-2-2)/x1 read(1-1-4)/x1 repeat/x4 test", qspi_write_read_test), -#endif - Case("qspi write(2-2-2)/x1 read(1-4-4)/x1 repeat/x1 test", qspi_write_read_test), - Case("qspi write(2-2-2)/x4 read(1-4-4)/x1 repeat/x1 test", qspi_write_read_test), - Case("qspi write(2-2-2)/x1 read(1-4-4)/x4 repeat/x1 test", qspi_write_read_test), - Case("qspi write(2-2-2)/x1 read(1-4-4)/x1 repeat/x4 test", qspi_write_read_test), -#ifdef READ_4_4_4 - Case("qspi write(2-2-2)/x1 read(4-4-4)/x1 repeat/x1 test", qspi_write_read_test), - Case("qspi write(2-2-2)/x4 read(4-4-4)/x1 repeat/x1 test", qspi_write_read_test), - Case("qspi write(2-2-2)/x1 read(4-4-4)/x4 repeat/x1 test", qspi_write_read_test), - Case("qspi write(2-2-2)/x1 read(4-4-4)/x1 repeat/x4 test", qspi_write_read_test), -#endif -#endif - -#ifdef WRITE_1_1_4 - Case("qspi write(1-1-4)/x1 read(1-1-1)/x1 repeat/x1 test", qspi_write_read_test), - Case("qspi write(1-1-4)/x4 read(1-1-1)/x1 repeat/x1 test", qspi_write_read_test), - Case("qspi write(1-1-4)/x1 read(1-1-1)/x4 repeat/x1 test", qspi_write_read_test), - Case("qspi write(1-1-4)/x1 read(1-1-1)/x1 repeat/x4 test", qspi_write_read_test), - Case("qspi write(1-1-4)/x1 read(1-1-2)/x1 repeat/x1 test", qspi_write_read_test), - Case("qspi write(1-1-4)/x4 read(1-1-2)/x1 repeat/x1 test", qspi_write_read_test), - Case("qspi write(1-1-4)/x1 read(1-1-2)/x4 repeat/x1 test", qspi_write_read_test), - Case("qspi write(1-1-4)/x1 read(1-1-2)/x1 repeat/x4 test", qspi_write_read_test), - Case("qspi write(1-1-4)/x1 read(1-2-2)/x1 repeat/x1 test", qspi_write_read_test), - Case("qspi write(1-1-4)/x4 read(1-2-2)/x1 repeat/x1 test", qspi_write_read_test), - Case("qspi write(1-1-4)/x1 read(1-2-2)/x4 repeat/x1 test", qspi_write_read_test), - Case("qspi write(1-1-4)/x1 read(1-2-2)/x1 repeat/x4 test", qspi_write_read_test), -#ifdef READ_2_2_2 - Case("qspi write(1-1-4)/x1 read(2-2-2)/x1 repeat/x1 test", qspi_write_read_test), - Case("qspi write(1-1-4)/x4 read(2-2-2)/x1 repeat/x1 test", qspi_write_read_test), - Case("qspi write(1-1-4)/x1 read(2-2-2)/x4 repeat/x1 test", qspi_write_read_test), - Case("qspi write(1-1-4)/x1 read(2-2-2)/x1 repeat/x4 test", qspi_write_read_test), -#endif -#ifdef READ_1_1_4 - Case("qspi write(1-1-4)/x1 read(1-1-4)/x1 repeat/x1 test", qspi_write_read_test), - Case("qspi write(1-1-4)/x4 read(1-1-4)/x1 repeat/x1 test", qspi_write_read_test), - Case("qspi write(1-1-4)/x1 read(1-1-4)/x4 repeat/x1 test", qspi_write_read_test), - Case("qspi write(1-1-4)/x1 read(1-1-4)/x1 repeat/x4 test", qspi_write_read_test), -#endif - Case("qspi write(1-1-4)/x1 read(1-4-4)/x1 repeat/x1 test", qspi_write_read_test), - Case("qspi write(1-1-4)/x4 read(1-4-4)/x1 repeat/x1 test", qspi_write_read_test), - Case("qspi write(1-1-4)/x1 read(1-4-4)/x4 repeat/x1 test", qspi_write_read_test), - Case("qspi write(1-1-4)/x1 read(1-4-4)/x1 repeat/x4 test", qspi_write_read_test), -#ifdef READ_4_4_4 - Case("qspi write(1-1-4)/x1 read(4-4-4)/x1 repeat/x1 test", qspi_write_read_test), - Case("qspi write(1-1-4)/x4 read(4-4-4)/x1 repeat/x1 test", qspi_write_read_test), - Case("qspi write(1-1-4)/x1 read(4-4-4)/x4 repeat/x1 test", qspi_write_read_test), - Case("qspi write(1-1-4)/x1 read(4-4-4)/x1 repeat/x4 test", qspi_write_read_test), -#endif -#endif - -#ifdef WRITE_1_4_4 - Case("qspi write(1-4-4)/x1 read(1-1-1)/x1 repeat/x1 test", qspi_write_read_test), - Case("qspi write(1-4-4)/x4 read(1-1-1)/x1 repeat/x1 test", qspi_write_read_test), - Case("qspi write(1-4-4)/x1 read(1-1-1)/x4 repeat/x1 test", qspi_write_read_test), - Case("qspi write(1-4-4)/x1 read(1-1-1)/x1 repeat/x4 test", qspi_write_read_test), - Case("qspi write(1-4-4)/x1 read(1-1-2)/x1 repeat/x1 test", qspi_write_read_test), - Case("qspi write(1-4-4)/x4 read(1-1-2)/x1 repeat/x1 test", qspi_write_read_test), - Case("qspi write(1-4-4)/x1 read(1-1-2)/x4 repeat/x1 test", qspi_write_read_test), - Case("qspi write(1-4-4)/x1 read(1-1-2)/x1 repeat/x4 test", qspi_write_read_test), - Case("qspi write(1-4-4)/x1 read(1-2-2)/x1 repeat/x1 test", qspi_write_read_test), - Case("qspi write(1-4-4)/x4 read(1-2-2)/x1 repeat/x1 test", qspi_write_read_test), - Case("qspi write(1-4-4)/x1 read(1-2-2)/x4 repeat/x1 test", qspi_write_read_test), - Case("qspi write(1-4-4)/x1 read(1-2-2)/x1 repeat/x4 test", qspi_write_read_test), -#ifdef READ_2_2_2 - Case("qspi write(1-4-4)/x1 read(2-2-2)/x1 repeat/x1 test", qspi_write_read_test), - Case("qspi write(1-4-4)/x4 read(2-2-2)/x1 repeat/x1 test", qspi_write_read_test), - Case("qspi write(1-4-4)/x1 read(2-2-2)/x4 repeat/x1 test", qspi_write_read_test), - Case("qspi write(1-4-4)/x1 read(2-2-2)/x1 repeat/x4 test", qspi_write_read_test), -#endif -#ifdef READ_1_1_4 - Case("qspi write(1-4-4)/x1 read(1-1-4)/x1 repeat/x1 test", qspi_write_read_test), - Case("qspi write(1-4-4)/x4 read(1-1-4)/x1 repeat/x1 test", qspi_write_read_test), - Case("qspi write(1-4-4)/x1 read(1-1-4)/x4 repeat/x1 test", qspi_write_read_test), - Case("qspi write(1-4-4)/x1 read(1-1-4)/x1 repeat/x4 test", qspi_write_read_test), -#endif - Case("qspi write(1-4-4)/x1 read(1-4-4)/x1 repeat/x1 test", qspi_write_read_test), - Case("qspi write(1-4-4)/x4 read(1-4-4)/x1 repeat/x1 test", qspi_write_read_test), - Case("qspi write(1-4-4)/x1 read(1-4-4)/x4 repeat/x1 test", qspi_write_read_test), - Case("qspi write(1-4-4)/x1 read(1-4-4)/x1 repeat/x4 test", qspi_write_read_test), -#ifdef READ_4_4_4 - Case("qspi write(1-4-4)/x1 read(4-4-4)/x1 repeat/x1 test", qspi_write_read_test), - Case("qspi write(1-4-4)/x4 read(4-4-4)/x1 repeat/x1 test", qspi_write_read_test), - Case("qspi write(1-4-4)/x1 read(4-4-4)/x4 repeat/x1 test", qspi_write_read_test), - Case("qspi write(1-4-4)/x1 read(4-4-4)/x1 repeat/x4 test", qspi_write_read_test), -#endif -#endif - -#ifdef WRITE_4_4_4 - Case("qspi write(4-4-4)/x1 read(1-1-1)/x1 repeat/x1 test", qspi_write_read_test), - Case("qspi write(4-4-4)/x4 read(1-1-1)/x1 repeat/x1 test", qspi_write_read_test), - Case("qspi write(4-4-4)/x1 read(1-1-1)/x4 repeat/x1 test", qspi_write_read_test), - Case("qspi write(4-4-4)/x1 read(1-1-1)/x1 repeat/x4 test", qspi_write_read_test), - Case("qspi write(4-4-4)/x1 read(1-1-2)/x1 repeat/x1 test", qspi_write_read_test), - Case("qspi write(4-4-4)/x4 read(1-1-2)/x1 repeat/x1 test", qspi_write_read_test), - Case("qspi write(4-4-4)/x1 read(1-1-2)/x4 repeat/x1 test", qspi_write_read_test), - Case("qspi write(4-4-4)/x1 read(1-1-2)/x1 repeat/x4 test", qspi_write_read_test), - Case("qspi write(4-4-4)/x1 read(1-2-2)/x1 repeat/x1 test", qspi_write_read_test), - Case("qspi write(4-4-4)/x4 read(1-2-2)/x1 repeat/x1 test", qspi_write_read_test), - Case("qspi write(4-4-4)/x1 read(1-2-2)/x4 repeat/x1 test", qspi_write_read_test), - Case("qspi write(4-4-4)/x1 read(1-2-2)/x1 repeat/x4 test", qspi_write_read_test), -#ifdef READ_2_2_2 - Case("qspi write(4-4-4)/x1 read(2-2-2)/x1 repeat/x1 test", qspi_write_read_test), - Case("qspi write(4-4-4)/x4 read(2-2-2)/x1 repeat/x1 test", qspi_write_read_test), - Case("qspi write(4-4-4)/x1 read(2-2-2)/x4 repeat/x1 test", qspi_write_read_test), - Case("qspi write(4-4-4)/x1 read(2-2-2)/x1 repeat/x4 test", qspi_write_read_test), -#endif -#ifdef READ_1_1_4 - Case("qspi write(4-4-4)/x1 read(1-1-4)/x1 repeat/x1 test", qspi_write_read_test), - Case("qspi write(4-4-4)/x4 read(1-1-4)/x1 repeat/x1 test", qspi_write_read_test), - Case("qspi write(4-4-4)/x1 read(1-1-4)/x4 repeat/x1 test", qspi_write_read_test), - Case("qspi write(4-4-4)/x1 read(1-1-4)/x1 repeat/x4 test", qspi_write_read_test), -#endif - Case("qspi write(4-4-4)/x1 read(1-4-4)/x1 repeat/x1 test", qspi_write_read_test), - Case("qspi write(4-4-4)/x4 read(1-4-4)/x1 repeat/x1 test", qspi_write_read_test), - Case("qspi write(4-4-4)/x1 read(1-4-4)/x4 repeat/x1 test", qspi_write_read_test), - Case("qspi write(4-4-4)/x1 read(1-4-4)/x1 repeat/x4 test", qspi_write_read_test), -#ifdef READ_4_4_4 - Case("qspi write(4-4-4)/x1 read(4-4-4)/x1 repeat/x1 test", qspi_write_read_test), - Case("qspi write(4-4-4)/x4 read(4-4-4)/x1 repeat/x1 test", qspi_write_read_test), - Case("qspi write(4-4-4)/x1 read(4-4-4)/x4 repeat/x1 test", qspi_write_read_test), - Case("qspi write(4-4-4)/x1 read(4-4-4)/x1 repeat/x4 test", qspi_write_read_test), -#endif -#endif -}; - -utest::v1::status_t greentea_test_setup(const size_t number_of_cases) -{ - GREENTEA_SETUP(180, "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); -} - -#endif // !defined(QSPI_FLASH_CHIP_STRING) -#endif // !DEVICE_QSPI diff --git a/TESTS/mbed_hal/qspi/qspi_test.h b/TESTS/mbed_hal/qspi/qspi_test.h deleted file mode 100644 index 61c3dc7..0000000 --- a/TESTS/mbed_hal/qspi/qspi_test.h +++ /dev/null @@ -1,102 +0,0 @@ -/* mbed Microcontroller Library - * Copyright (c) 2018-2018 ARM Limited - * 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. - */ - -/** \addtogroup hal_qspi - * @{ - * \defgroup hal_qspi_tests Tests - * QSPI tests of the HAL. - * @{ - */ -#ifndef MBED_QSPI_TEST_H -#define MBED_QSPI_TEST_H - -#include "qspi_api.h" -#include "qspi_test_utils.h" - - -#if DEVICE_QSPI - -/** Test that qspi_init/qspi_free can be called multiple times. - * - * Given board provides QSPI. - * When qspi_init/qspi_free is called multiple times. - * Then qspi_init/qspi_free are successfully performed (no exception is generated). - * - */ -void qspi_init_free_test(void); - -/** Test qspi frequency setting. - * - * Given board provides QSPI, with QSPI already initialized. - * When set QSPI frequency. - * Then freguency setting is successfully performed (no exception is generated). - * - */ -void qspi_frequency_test(void); - -/** Template for write/read tests - * - * Test single write/read operation of a block of data to/from the specific memory address - * Given board provides QSPI, with QSPI already initialized. - * When perform write and then read operations. - * Then data is successfully written and then read (no exception is generated) and the read data is valid. - * - * Test multiple write/read operation of a block of data to/from the same specific memory address - * Given board provides QSPI, with QSPI already initialized. - * When perform write and then read operations. - * Then data is successfully written and then read (no exception is generated) and the read data is valid. - * - * Test multiple adjacent write and single read operation of a block of data to/from the specific memory address - * Given board provides QSPI, with QSPI already initialized. - * When perform write and then read operations. - * Then data is successfully written and then read (no exception is generated) and the read data is valid. - * - * Test single write and multiple adjacent read operation of a block of data to/from the specific memory address - * Given board provides QSPI, with QSPI already initialized. - * When perform write and then read operations. - * Then data is successfully written and then read (no exception is generated) and the read data is valid. - * - */ -template < qspi_bus_width_t write_inst_width, - qspi_bus_width_t write_addr_width, - qspi_bus_width_t write_data_width, - qspi_bus_width_t write_alt_width, - unsigned int write_cmd, - qspi_address_size_t write_addr_size, - qspi_alt_size_t write_alt_size, - uint32_t write_count, - qspi_bus_width_t read_inst_width, - qspi_bus_width_t read_addr_width, - qspi_bus_width_t read_data_width, - qspi_bus_width_t read_alt_width, - unsigned int read_cmd, - int read_dummy_cycles, - qspi_address_size_t read_addr_size, - qspi_alt_size_t read_alt_size, - int frequency, - uint32_t read_count, - uint32_t test_count, - uint32_t data_size, - uint32_t flash_addr> -void qspi_write_read_test(void); - -#endif - -#endif - -/** @}*/ -/** @}*/ diff --git a/TESTS/mbed_hal/qspi/qspi_test_utils.cpp b/TESTS/mbed_hal/qspi/qspi_test_utils.cpp deleted file mode 100644 index 4c69f92..0000000 --- a/TESTS/mbed_hal/qspi/qspi_test_utils.cpp +++ /dev/null @@ -1,332 +0,0 @@ -/* mbed Microcontroller Library - * Copyright (c) 2018-2018 ARM Limited - * 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. - */ - -#include "utest/utest.h" - -#include "hal/qspi_api.h" -#include "hal/us_ticker_api.h" -#include "qspi_test_utils.h" - -#include "unity/unity.h" - -#include // for memset - -#include "flash_configs/flash_configs.h" -#include "mbed.h" - -static qspi_status_t extended_enable(Qspi &qspi); -static qspi_status_t extended_disable(Qspi &qspi); -static qspi_status_t dual_enable(Qspi &qspi); -static qspi_status_t dual_disable(Qspi &qspi); -static qspi_status_t quad_enable(Qspi &qspi); -static qspi_status_t quad_disable(Qspi &qspi); - -void QspiCommand::configure(qspi_bus_width_t inst_width, qspi_bus_width_t addr_width, - qspi_bus_width_t data_width, qspi_bus_width_t alt_width, - qspi_address_size_t addr_size, qspi_alt_size_t alt_size, - int dummy_cycles) -{ - memset(&_cmd, 0, sizeof(qspi_command_t)); - _cmd.instruction.disabled = _cmd.address.disabled = _cmd.alt.disabled = true; - - _cmd.instruction.bus_width = inst_width; - _cmd.address.bus_width = addr_width; - _cmd.address.size = addr_size; - _cmd.alt.bus_width = alt_width; - _cmd.alt.size = alt_size; - _cmd.data.bus_width = data_width; - _cmd.dummy_count = dummy_cycles; -} - -void QspiCommand::set_dummy_cycles(int dummy_cycles) -{ - _cmd.dummy_count = dummy_cycles; -} - -void QspiCommand::build(int instruction, int address, int alt) -{ - _cmd.instruction.disabled = (instruction == QSPI_NO_INST); - if (!_cmd.instruction.disabled) { - _cmd.instruction.value = instruction; - } - - _cmd.address.disabled = (address == QSPI_NONE); - if (!_cmd.address.disabled) { - _cmd.address.value = address; - } - - _cmd.alt.disabled = (alt == QSPI_NONE); - if (!_cmd.alt.disabled) { - _cmd.alt.value = alt; - } -} - -qspi_command_t *QspiCommand::get() -{ - return &_cmd; -} - - -qspi_status_t read_register(uint32_t cmd, uint8_t *buf, uint32_t size, Qspi &q) -{ - q.cmd.build(cmd); - return qspi_command_transfer(&q.handle, q.cmd.get(), NULL, 0, buf, size); -} - -qspi_status_t write_register(uint32_t cmd, uint8_t *buf, uint32_t size, Qspi &q) -{ - q.cmd.build(cmd); - return qspi_command_transfer(&q.handle, q.cmd.get(), buf, size, NULL, 0); -} - - -QspiStatus flash_wait_for(uint32_t time_us, Qspi &qspi) -{ - uint8_t reg[QSPI_STATUS_REG_SIZE]; - qspi_status_t ret; - uint32_t curr_time; - - const ticker_data_t *const ticker = get_us_ticker_data(); - const uint32_t start = ticker_read(ticker); - - memset(reg, 255, QSPI_STATUS_REG_SIZE); - do { - ret = read_register(STATUS_REG, reg, QSPI_STATUS_REG_SIZE, qspi); - curr_time = ticker_read(ticker); - } while (((reg[0] & STATUS_BIT_WIP) != 0) && ((curr_time - start) < time_us)); - - if (((reg[0] & STATUS_BIT_WIP) == 0) && (ret == QSPI_STATUS_OK)) { - return sOK; - } else if (ret != QSPI_STATUS_OK) { - return sError; - } else if ((curr_time - start) >= time_us) { - return sTimeout; - } - return sUnknown; -} - -void flash_init(Qspi &qspi) -{ - uint8_t status[QSPI_STATUS_REG_SIZE]; - qspi_status_t ret; - - qspi.cmd.build(QSPI_CMD_RDSR); - ret = qspi_command_transfer(&qspi.handle, qspi.cmd.get(), NULL, 0, status, QSPI_STATUS_REG_SIZE); - TEST_ASSERT_EQUAL(QSPI_STATUS_OK, ret); - - // Only do reset enable if device needs it - if (QSPI_CMD_RSTEN != 0) { - qspi.cmd.build(QSPI_CMD_RSTEN); - ret = qspi_command_transfer(&qspi.handle, qspi.cmd.get(), NULL, 0, NULL, 0); - TEST_ASSERT_EQUAL(QSPI_STATUS_OK, ret); - - WAIT_FOR(WRSR_MAX_TIME, qspi); - } - - qspi.cmd.build(QSPI_CMD_RST); - ret = qspi_command_transfer(&qspi.handle, qspi.cmd.get(), NULL, 0, NULL, 0); - TEST_ASSERT_EQUAL(QSPI_STATUS_OK, ret); - - WAIT_FOR(WAIT_MAX_TIME, qspi); - - // Zero out status register to attempt to clear block protection bits - uint8_t blanks[QSPI_STATUS_REG_SIZE] = {0}; - - qspi.cmd.build(QSPI_CMD_WREN); - ret = qspi_command_transfer(&qspi.handle, qspi.cmd.get(), NULL, 0, NULL, 0); - TEST_ASSERT_EQUAL(QSPI_STATUS_OK, ret); - - qspi.cmd.build(QSPI_CMD_WRSR); - ret = qspi_command_transfer(&qspi.handle, qspi.cmd.get(), blanks, 1, NULL, 0); - TEST_ASSERT_EQUAL(QSPI_STATUS_OK, ret); - - WAIT_FOR(WRSR_MAX_TIME, qspi); -} - - -qspi_status_t write_enable(Qspi &qspi) -{ - uint8_t reg[QSPI_STATUS_REG_SIZE]; - qspi.cmd.build(QSPI_CMD_WREN); - - if (qspi_command_transfer(&qspi.handle, qspi.cmd.get(), NULL, 0, NULL, 0) != QSPI_STATUS_OK) { - return QSPI_STATUS_ERROR; - } - WAIT_FOR(WRSR_MAX_TIME, qspi); - - memset(reg, 0, QSPI_STATUS_REG_SIZE); - if (read_register(STATUS_REG, reg, QSPI_STATUS_REG_SIZE, qspi) != QSPI_STATUS_OK) { - return QSPI_STATUS_ERROR; - } - - return ((reg[0] & STATUS_BIT_WEL) != 0 ? QSPI_STATUS_OK : QSPI_STATUS_ERROR); -} - -qspi_status_t write_disable(Qspi &qspi) -{ - uint8_t reg[QSPI_STATUS_REG_SIZE]; - qspi.cmd.build(QSPI_CMD_WRDI); - - if (qspi_command_transfer(&qspi.handle, qspi.cmd.get(), NULL, 0, NULL, 0) != QSPI_STATUS_OK) { - return QSPI_STATUS_ERROR; - } - WAIT_FOR(WRSR_MAX_TIME, qspi); - - memset(reg, 0, QSPI_STATUS_REG_SIZE); - if (read_register(STATUS_REG, reg, QSPI_STATUS_REG_SIZE, qspi) != QSPI_STATUS_OK) { - return QSPI_STATUS_ERROR; - } - - return ((reg[0] & STATUS_BIT_WEL) == 0 ? QSPI_STATUS_OK : QSPI_STATUS_ERROR); -} - -void log_register(uint32_t cmd, uint32_t reg_size, Qspi &qspi, const char *str) -{ - qspi_status_t ret; - static uint8_t reg[QSPI_MAX_REG_SIZE]; - - ret = read_register(cmd, reg, reg_size, qspi); - TEST_ASSERT_EQUAL(QSPI_STATUS_OK, ret); - - for (uint32_t j = 0; j < reg_size; j++) { - utest_printf("%s byte %u (MSB first): ", str != NULL ? str : "", j); - for (int i = 0; i < 8; i++) { - utest_printf("%s ", ((reg[j] & (1 << (7 - i))) & 0xFF) == 0 ? "0" : "1"); - } - utest_printf("\r\n"); - } -} - -qspi_status_t erase(uint32_t erase_cmd, uint32_t flash_addr, Qspi &qspi) -{ - qspi.cmd.build(erase_cmd, flash_addr); - return qspi_command_transfer(&qspi.handle, qspi.cmd.get(), NULL, 0, NULL, 0); -} - -qspi_status_t mode_enable(Qspi &qspi, qspi_bus_width_t inst_width, qspi_bus_width_t addr_width, qspi_bus_width_t data_width) -{ - if (is_extended_mode(inst_width, addr_width, data_width)) { - return extended_enable(qspi); - } else if (is_dual_mode(inst_width, addr_width, data_width)) { - return dual_enable(qspi); - } else if (is_quad_mode(inst_width, addr_width, data_width)) { - return quad_enable(qspi); - } else { - return QSPI_STATUS_OK; - } -} - -qspi_status_t mode_disable(Qspi &qspi, qspi_bus_width_t inst_width, qspi_bus_width_t addr_width, qspi_bus_width_t data_width) -{ - if (is_extended_mode(inst_width, addr_width, data_width)) { - return extended_disable(qspi); - } else if (is_dual_mode(inst_width, addr_width, data_width)) { - return dual_disable(qspi); - } else if (is_quad_mode(inst_width, addr_width, data_width)) { - return quad_disable(qspi); - } else { - return QSPI_STATUS_OK; - } -} - -static qspi_status_t extended_enable(Qspi &qspi) -{ -#ifdef EXTENDED_SPI_ENABLE - EXTENDED_SPI_ENABLE(); -#else - return QSPI_STATUS_OK; -#endif -} - -static qspi_status_t extended_disable(Qspi &qspi) -{ -#ifdef EXTENDED_SPI_DISABLE - EXTENDED_SPI_DISABLE(); -#else - return QSPI_STATUS_OK; -#endif -} - -static qspi_status_t dual_enable(Qspi &qspi) -{ -#ifdef DUAL_ENABLE - DUAL_ENABLE(); -#else - return QSPI_STATUS_OK; -#endif -} - -static qspi_status_t dual_disable(Qspi &qspi) -{ -#ifdef DUAL_DISABLE - DUAL_DISABLE(); -#else - return QSPI_STATUS_OK; -#endif - -} - -static qspi_status_t quad_enable(Qspi &qspi) -{ -#ifdef QUAD_ENABLE - QUAD_ENABLE(); -#else - return QSPI_STATUS_OK; -#endif -} - -static qspi_status_t quad_disable(Qspi &qspi) -{ -#ifdef QUAD_DISABLE - QUAD_DISABLE(); -#else - return QSPI_STATUS_OK; -#endif -} - -qspi_status_t fast_mode_enable(Qspi &qspi) -{ -#ifdef FAST_MODE_ENABLE - FAST_MODE_ENABLE(); -#else - return QSPI_STATUS_OK; -#endif -} - -qspi_status_t fast_mode_disable(Qspi &qspi) -{ -#ifdef FAST_MODE_DISABLE - FAST_MODE_DISABLE(); -#else - return QSPI_STATUS_OK; -#endif -} - -bool is_extended_mode(qspi_bus_width_t inst_width, qspi_bus_width_t addr_width, qspi_bus_width_t data_width) -{ - return (inst_width == QSPI_CFG_BUS_SINGLE) && ((addr_width != QSPI_CFG_BUS_SINGLE) || (data_width != QSPI_CFG_BUS_SINGLE)); -} - -bool is_dual_mode(qspi_bus_width_t inst_width, qspi_bus_width_t addr_width, qspi_bus_width_t data_width) -{ - return (inst_width == QSPI_CFG_BUS_DUAL) && (addr_width == QSPI_CFG_BUS_DUAL) && (data_width == QSPI_CFG_BUS_DUAL); -} - -bool is_quad_mode(qspi_bus_width_t inst_width, qspi_bus_width_t addr_width, qspi_bus_width_t data_width) -{ - return (inst_width == QSPI_CFG_BUS_QUAD) && (addr_width == QSPI_CFG_BUS_QUAD) && (data_width == QSPI_CFG_BUS_QUAD); -} diff --git a/TESTS/mbed_hal/qspi/qspi_test_utils.h b/TESTS/mbed_hal/qspi/qspi_test_utils.h deleted file mode 100644 index 1e2efc9..0000000 --- a/TESTS/mbed_hal/qspi/qspi_test_utils.h +++ /dev/null @@ -1,170 +0,0 @@ -/* mbed Microcontroller Library - * Copyright (c) 2018-2018 ARM Limited - * 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. - */ -#ifndef MBED_QSPI_TEST_UTILS_H -#define MBED_QSPI_TEST_UTILS_H - -#include "flash_configs/flash_configs.h" -#include "unity/unity.h" - -#define QSPI_NONE (-1) - -enum QspiStatus { - sOK, - sError, - sTimeout, - sUnknown -}; - -class QspiCommand { -public: - void configure(qspi_bus_width_t inst_width, qspi_bus_width_t addr_width, qspi_bus_width_t data_width, - qspi_bus_width_t alt_width, qspi_address_size_t addr_size, qspi_alt_size_t alt_size, - int dummy_cycles = 0); - - void set_dummy_cycles(int dummy_cycles); - - void build(int instruction, int address = QSPI_NONE, int alt = QSPI_NONE); - - qspi_command_t *get(); - -private: - qspi_command_t _cmd; -}; - -struct Qspi { - qspi_t handle; - QspiCommand cmd; -}; - -// MODE_Command_Address_Data_Alt -#define MODE_1_1_1 QSPI_CFG_BUS_SINGLE, QSPI_CFG_BUS_SINGLE, QSPI_CFG_BUS_SINGLE, QSPI_CFG_BUS_SINGLE -#define MODE_1_1_2 QSPI_CFG_BUS_SINGLE, QSPI_CFG_BUS_SINGLE, QSPI_CFG_BUS_DUAL, QSPI_CFG_BUS_DUAL -#define MODE_1_2_2 QSPI_CFG_BUS_SINGLE, QSPI_CFG_BUS_DUAL, QSPI_CFG_BUS_DUAL, QSPI_CFG_BUS_DUAL -#define MODE_2_2_2 QSPI_CFG_BUS_DUAL, QSPI_CFG_BUS_DUAL, QSPI_CFG_BUS_DUAL, QSPI_CFG_BUS_DUAL -#define MODE_1_1_4 QSPI_CFG_BUS_SINGLE, QSPI_CFG_BUS_SINGLE, QSPI_CFG_BUS_QUAD, QSPI_CFG_BUS_QUAD -#define MODE_1_4_4 QSPI_CFG_BUS_SINGLE, QSPI_CFG_BUS_QUAD, QSPI_CFG_BUS_QUAD, QSPI_CFG_BUS_QUAD -#define MODE_4_4_4 QSPI_CFG_BUS_QUAD, QSPI_CFG_BUS_QUAD, QSPI_CFG_BUS_QUAD, QSPI_CFG_BUS_QUAD - -#define WRITE_1_1_1 MODE_1_1_1, QSPI_CMD_WRITE_1IO -#ifdef QSPI_CMD_WRITE_2IO -#define WRITE_1_2_2 MODE_1_2_2, QSPI_CMD_WRITE_2IO -#endif -#ifdef QSPI_CMD_WRITE_1I4O // Quad page program - command: 0x32 -#define WRITE_1_1_4 MODE_1_1_4, QSPI_CMD_WRITE_1I4O -#endif -#ifdef QSPI_CMD_WRITE_4IO -#define WRITE_1_4_4 MODE_1_4_4, QSPI_CMD_WRITE_4IO -#endif -#ifdef QSPI_CMD_WRITE_DPI -#define WRITE_2_2_2 MODE_2_2_2, QSPI_CMD_WRITE_DPI -#endif -#ifdef QSPI_CMD_WRITE_QPI -#define WRITE_4_4_4 MODE_4_4_4, QSPI_CMD_WRITE_QPI -#endif - - -#define READ_1_1_1 MODE_1_1_1, QSPI_CMD_READ_1IO, QSPI_READ_1IO_DUMMY_CYCLE -#ifdef QSPI_CMD_READ_1I2O -#define READ_1_1_2 MODE_1_1_2, QSPI_CMD_READ_1I2O, QSPI_READ_1I2O_DUMMY_CYCLE -#endif -#ifdef QSPI_CMD_READ_2IO -#define READ_1_2_2 MODE_1_2_2, QSPI_CMD_READ_2IO, QSPI_READ_2IO_DUMMY_CYCLE -#endif -#ifdef QSPI_CMD_READ_1I4O -#define READ_1_1_4 MODE_1_1_4, QSPI_CMD_READ_1I4O, QSPI_READ_1I4O_DUMMY_CYCLE -#endif -#ifdef QSPI_CMD_READ_4IO -#define READ_1_4_4 MODE_1_4_4, QSPI_CMD_READ_4IO, QSPI_READ_4IO_DUMMY_CYCLE -#endif - -#ifdef QSPI_CMD_READ_DPI -#define READ_2_2_2 MODE_2_2_2, QSPI_CMD_READ_DPI, QSPI_READ_2IO_DUMMY_CYCLE -#endif -#ifdef QSPI_CMD_READ_QPI -#define READ_4_4_4 MODE_4_4_4, QSPI_CMD_READ_QPI, QSPI_READ_4IO_DUMMY_CYCLE -#endif - -#define ADDR_SIZE_8 QSPI_CFG_ADDR_SIZE_8 -#define ADDR_SIZE_16 QSPI_CFG_ADDR_SIZE_16 -#define ADDR_SIZE_24 QSPI_CFG_ADDR_SIZE_24 -#define ADDR_SIZE_32 QSPI_CFG_ADDR_SIZE_32 - -#define ALT_SIZE_8 QSPI_CFG_ALT_SIZE_8 -#define ALT_SIZE_16 QSPI_CFG_ALT_SIZE_16 -#define ALT_SIZE_24 QSPI_CFG_ALT_SIZE_24 -#define ALT_SIZE_32 QSPI_CFG_ALT_SIZE_32 - -#define STATUS_REG QSPI_CMD_RDSR -#define CONFIG_REG0 QSPI_CMD_RDCR0 -#ifdef QSPI_CMD_RDCR1 -#define CONFIG_REG1 QSPI_CMD_RDCR1 -#endif -#ifdef QSPI_CMD_RDCR2 -#define CONFIG_REG2 QSPI_CMD_RDCR2 -#endif -#define SECURITY_REG QSPI_CMD_RDSCUR - -#ifndef QSPI_CONFIG_REG_1_SIZE -#define QSPI_CONFIG_REG_1_SIZE 0 -#endif - -#ifndef QSPI_CONFIG_REG_2_SIZE -#define QSPI_CONFIG_REG_2_SIZE 0 -#endif - - -#define SECTOR_ERASE QSPI_CMD_ERASE_SECTOR -#define BLOCK_ERASE QSPI_CMD_ERASE_BLOCK_64 - - -#define SECTOR_ERASE_MAX_TIME QSPI_ERASE_SECTOR_MAX_TIME -#define BLOCK32_ERASE_MAX_TIME QSPI_ERASE_BLOCK_32_MAX_TIME -#define BLOCK64_ERASE_MAX_TIME QSPI_ERASE_BLOCK_64_MAX_TIME -#define PAGE_PROG_MAX_TIME QSPI_PAGE_PROG_MAX_TIME -#define WRSR_MAX_TIME QSPI_WRSR_MAX_TIME -#define WAIT_MAX_TIME QSPI_WAIT_MAX_TIME - - - -qspi_status_t read_register(uint32_t cmd, uint8_t *buf, uint32_t size, Qspi &q); -qspi_status_t write_register(uint32_t cmd, uint8_t *buf, uint32_t size, Qspi &q); - -QspiStatus flash_wait_for(uint32_t time_us, Qspi &qspi); - -void flash_init(Qspi &qspi); - -qspi_status_t write_enable(Qspi &qspi); -qspi_status_t write_disable(Qspi &qspi); - -void log_register(uint32_t cmd, uint32_t reg_size, Qspi &qspi, const char *str = NULL); - -qspi_status_t mode_enable(Qspi &qspi, qspi_bus_width_t inst_width, qspi_bus_width_t addr_width, qspi_bus_width_t data_width); -qspi_status_t mode_disable(Qspi &qspi, qspi_bus_width_t inst_width, qspi_bus_width_t addr_width, qspi_bus_width_t data_width); - -qspi_status_t fast_mode_enable(Qspi &qspi); -qspi_status_t fast_mode_disable(Qspi &qspi); - -qspi_status_t erase(uint32_t erase_cmd, uint32_t flash_addr, Qspi &qspi); - -bool is_extended_mode(qspi_bus_width_t inst_width, qspi_bus_width_t addr_width, qspi_bus_width_t data_width); -bool is_dual_mode(qspi_bus_width_t inst_width, qspi_bus_width_t addr_width, qspi_bus_width_t data_width); -bool is_quad_mode(qspi_bus_width_t inst_width, qspi_bus_width_t addr_width, qspi_bus_width_t data_width); - -#define WAIT_FOR(timeout, q) TEST_ASSERT_EQUAL_MESSAGE(sOK, flash_wait_for(timeout, q), "flash_wait_for failed!!!") - - -#endif // MBED_QSPI_TEST_UTILS_H diff --git a/TESTS/mbed_hal/reset_reason/main.cpp b/TESTS/mbed_hal/reset_reason/main.cpp deleted file mode 100644 index f449963..0000000 --- a/TESTS/mbed_hal/reset_reason/main.cpp +++ /dev/null @@ -1,161 +0,0 @@ -/* - * Copyright (c) 2018-2019 Arm Limited and affiliates. - * 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. - */ -#if !DEVICE_RESET_REASON -#error [NOT_SUPPORTED] Reset reason API not supported for this target -#else - -#include "greentea-client/test_env.h" -#include "unity/unity.h" -#include "hal/reset_reason_api.h" -#include "reset_reason_api_tests.h" -#include "mbed.h" - -#if DEVICE_WATCHDOG -# include "hal/watchdog_api.h" -# define MSG_VALUE_WATCHDOG_STATUS 1 -# define WDG_TIMEOUT_MS 50UL -#else -# define MSG_VALUE_WATCHDOG_STATUS 0 -#endif - -#define MSG_VALUE_DUMMY "0" -#define MSG_VALUE_RESET_REASON_GET "get" -#define MSG_VALUE_RESET_REASON_CLEAR "clear" -#define MSG_VALUE_RESET_REASON_CLEAR_ACK "cleared" -#define MSG_VALUE_DEVICE_RESET_ACK "ack" -#define MSG_VALUE_DEVICE_RESET_NVIC "nvic" -#define MSG_VALUE_DEVICE_RESET_WATCHDOG "watchdog" -#define MSG_VALUE_LEN 16 -#define MSG_KEY_LEN 16 - -#define MSG_KEY_DEVICE_READY "ready" -#define MSG_KEY_RESET_REASON_RAW "reason_raw" -#define MSG_KEY_RESET_REASON "reason" -#define MSG_KEY_DEVICE_RESET "reset" - -/* To prevent a loss of Greentea data, the serial buffers have to be flushed - * before the UART peripheral shutdown. The UART shutdown happens when the - * device is entering the deepsleep mode or performing a reset. - * - * With the current API, it is not possible to check if the hardware buffers - * are empty. However, it is possible to determine the time required for the - * buffers to flush. - * - * Assuming the biggest Tx FIFO of 128 bytes (as for CY8CPROTO_062_4343W) - * and a default UART config (9600, 8N1), flushing the Tx FIFO wold take: - * (1 start_bit + 8 data_bits + 1 stop_bit) * 128 * 1000 / 9600 = 133.3 ms. - * To be on the safe side, set the wait time to 150 ms. - */ -#define SERIAL_FLUSH_TIME_MS 150 - -typedef enum { - CMD_STATUS_CONTINUE, - CMD_STATUS_ERROR -} cmd_status_t; - -static cmd_status_t handle_command(const char *key, const char *value) -{ - if (strcmp(key, MSG_KEY_RESET_REASON_RAW) == 0) { - uint32_t raw_reason = hal_reset_reason_get_raw(); - char raw_reason_hex_str[9] = { }; - int raw_reason_hex_str_len = snprintf(raw_reason_hex_str, - sizeof raw_reason_hex_str, "%08lx", raw_reason); - - if (raw_reason_hex_str_len < 0) { - TEST_ASSERT_MESSAGE(0, "Failed to compose raw reset reason hex string."); - return CMD_STATUS_ERROR; - } - - greentea_send_kv(MSG_KEY_RESET_REASON_RAW, raw_reason_hex_str); - return CMD_STATUS_CONTINUE; - } - - if (strcmp(key, MSG_KEY_RESET_REASON) == 0 && strcmp(value, MSG_VALUE_RESET_REASON_GET) == 0) { - int reason = (int) hal_reset_reason_get(); - greentea_send_kv(MSG_KEY_RESET_REASON, reason); - return CMD_STATUS_CONTINUE; - } - - if (strcmp(key, MSG_KEY_RESET_REASON) == 0 && strcmp(value, MSG_VALUE_RESET_REASON_CLEAR) == 0) { - hal_reset_reason_clear(); - greentea_send_kv(MSG_KEY_RESET_REASON, MSG_VALUE_RESET_REASON_CLEAR_ACK); - return CMD_STATUS_CONTINUE; - } - - if (strcmp(key, MSG_KEY_DEVICE_RESET) == 0 && strcmp(value, MSG_VALUE_DEVICE_RESET_NVIC) == 0) { - greentea_send_kv(MSG_KEY_DEVICE_RESET, MSG_VALUE_DEVICE_RESET_ACK); - ThisThread::sleep_for(SERIAL_FLUSH_TIME_MS); // Wait for the serial buffers to flush. - NVIC_SystemReset(); - TEST_ASSERT_MESSAGE(0, "NVIC_SystemReset did not reset the device as expected."); - return CMD_STATUS_ERROR; - } - -#if DEVICE_WATCHDOG - if (strcmp(key, MSG_KEY_DEVICE_RESET) == 0 && strcmp(value, MSG_VALUE_DEVICE_RESET_WATCHDOG) == 0) { - greentea_send_kv(MSG_KEY_DEVICE_RESET, MSG_VALUE_DEVICE_RESET_ACK); - ThisThread::sleep_for(SERIAL_FLUSH_TIME_MS); // Wait for the serial buffers to flush. - watchdog_config_t config = { .timeout_ms = WDG_TIMEOUT_MS }; - if (hal_watchdog_init(&config) != WATCHDOG_STATUS_OK) { - TEST_ASSERT_MESSAGE(0, "hal_watchdog_init() error."); - return CMD_STATUS_ERROR; - } - ThisThread::sleep_for(2 * WDG_TIMEOUT_MS); // Watchdog should fire before twice the timeout value. - TEST_ASSERT_MESSAGE(0, "Watchdog did not reset the device as expected."); - return CMD_STATUS_ERROR; - } -#endif - - TEST_ASSERT_MESSAGE(0, "Invalid message key."); - return CMD_STATUS_ERROR; -} - -void test_reset_reason() -{ - reset_reason_capabilities_t rrcap = {}; - hal_reset_reason_get_capabilities(&rrcap); - char msg_value[11]; - int str_len = snprintf(msg_value, sizeof msg_value, "%08lx,%01x", rrcap.reasons, MSG_VALUE_WATCHDOG_STATUS); - if (str_len < 0) { - printf("Failed to compose a value string to be sent to host."); - GREENTEA_TESTSUITE_RESULT(0); - return; - } - - // Report readiness, capabilities and watchdog status. - greentea_send_kv(MSG_KEY_DEVICE_READY, msg_value); - - cmd_status_t cmd_status = CMD_STATUS_CONTINUE; - static char _key[MSG_KEY_LEN + 1] = { }; - static char _value[MSG_VALUE_LEN + 1] = { }; - - // Let the host side decide what to do and just handle the commands. - while (CMD_STATUS_CONTINUE == cmd_status) { - memset(_key, 0, sizeof _key); - memset(_value, 0, sizeof _value); - greentea_parse_kv(_key, _value, MSG_KEY_LEN, MSG_VALUE_LEN); - cmd_status = handle_command(_key, _value); - } -} - -int main() -{ - GREENTEA_SETUP(90, "reset_reason"); - test_reset_reason(); // The result of this test suite is reported by the host side. - GREENTEA_TESTSUITE_RESULT(0); // Fail on any error. -} - -#endif //!DEVICE_RESET_REASON diff --git a/TESTS/mbed_hal/reset_reason/reset_reason_api_tests.h b/TESTS/mbed_hal/reset_reason/reset_reason_api_tests.h deleted file mode 100644 index 80df8e0..0000000 --- a/TESTS/mbed_hal/reset_reason/reset_reason_api_tests.h +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright (c) 2018-2019 Arm Limited and affiliates. - * 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. - */ - -/** - * @addtogroup hal_reset_reason_tests - * @{ - */ - -#ifndef MBED_HAL_RESET_REASON_API_TESTS_H -#define MBED_HAL_RESET_REASON_API_TESTS_H - -#if DEVICE_RESET_REASON - -#ifdef __cplusplus -extern "C" { -#endif - -/** Test the Reset Reason HAL API - * - * Given a device supporting a Reset Reason API, - * when the device is restarted, - * then the device returns a correct reset reason for every restart. - */ -void test_reset_reason(); - -#ifdef __cplusplus -} -#endif - -#endif - -#endif - -/** @}*/ - diff --git a/TESTS/mbed_hal/rtc/main.cpp b/TESTS/mbed_hal/rtc/main.cpp deleted file mode 100644 index 179bb3d..0000000 --- a/TESTS/mbed_hal/rtc/main.cpp +++ /dev/null @@ -1,261 +0,0 @@ -/* mbed Microcontroller Library - * Copyright (c) 2017 ARM Limited - * 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. - */ - -#if !DEVICE_RTC -#error [NOT_SUPPORTED] RTC API not supported for this target -#else - -#include "utest/utest.h" -#include "unity/unity.h" -#include "greentea-client/test_env.h" -#include "rtc_test.h" - -#include "mbed.h" -#include "drivers/RealTimeClock.h" -#include "rtc_api.h" -#include -#include - -using namespace utest::v1; -using namespace std::chrono; - -static constexpr auto WAIT_TIME = 4s; -static constexpr auto WAIT_TOLERANCE = 1s; - -#define TEST_ASSERT_DURATION_WITHIN(delta, expected, actual) \ - do { \ - using ct = std::common_type_t; \ - TEST_ASSERT_INT_WITHIN(ct(delta).count(), ct(expected).count(), ct(actual).count()); \ - } while (0) - -#if DEVICE_LPTICKER -mstd::atomic_bool expired; - -void set_flag_true(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 auto start = RealTimeClock::time_point(100s); - 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 ThisThread::sleep_for() function for now. - */ - ThisThread::sleep_for(10ms); - - RealTimeClock::init(); - - if (deepsleep_mode == false) { - sleep_manager_lock_deep_sleep(); - } - - RealTimeClock::write(start); - - timeout.attach(set_flag_true, 4s); - - TEST_ASSERT(sleep_manager_can_deep_sleep_test_check() == deepsleep_mode); - - while (!expired) { - sleep(); - } - - const auto stop = RealTimeClock::now(); - - TEST_ASSERT_DURATION_WITHIN(1s, 4s, stop - start); - - timeout.detach(); - - if (deepsleep_mode == false) { - sleep_manager_unlock_deep_sleep(); - } - - RealTimeClock::free(); -} -#endif - -/* Test that ::rtc_init can be called multiple times. */ -void rtc_init_test() -{ - for (int i = 0; i < 10; i++) { - RealTimeClock::init(); - } - - RealTimeClock::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 auto start = RealTimeClock::time_point(100s); - RealTimeClock::init(); - RealTimeClock::write(start); - RealTimeClock::free(); - - ThisThread::sleep_for(WAIT_TIME); - - RealTimeClock::init(); - const auto stop = RealTimeClock::now(); - const bool enabled = RealTimeClock::isenabled(); - RealTimeClock::free(); - - TEST_ASSERT_TRUE(enabled); - TEST_ASSERT_DURATION_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 auto start = RealTimeClock::time_point(0xffffes); - RealTimeClock::init(); - - RealTimeClock::write(start); - auto last = start; - while (last < start + 4s) { - const auto cur = RealTimeClock::now(); - TEST_ASSERT(cur >= last); - last = cur; - } - - RealTimeClock::free(); -} - -/* Test that the RTC correctly handles different time values. */ -void rtc_range_test() -{ - static const RealTimeClock::time_point starts[] = { - RealTimeClock::time_point{0x00000000s}, - RealTimeClock::time_point{0xEFFFFFFFs}, - RealTimeClock::time_point{0x00001000s}, - RealTimeClock::time_point{0x00010000s}, - }; - - RealTimeClock::init(); - for (const auto &start : starts) { - RealTimeClock::write(start); - ThisThread::sleep_for(WAIT_TIME); - const auto stop = RealTimeClock::now(); - TEST_ASSERT_DURATION_WITHIN(WAIT_TOLERANCE, WAIT_TIME, stop - start); - } - RealTimeClock::free(); -} - -/* Test that the RTC accuracy is at least 10%. */ -void rtc_accuracy_test() -{ - Timer timer1; - - const auto start = RealTimeClock::time_point(100s); - RealTimeClock::init(); - RealTimeClock::write(start); - - timer1.start(); - while (RealTimeClock::now() < (start + 10s)) { - /* Just wait. */ - } - timer1.stop(); - - /* RTC accuracy is at least 10%. */ - TEST_ASSERT_DURATION_WITHIN(1s, 10s, timer1.elapsed_time()); -} - -/* Test that ::rtc_write/::rtc_read functions provides availability to set/get RTC time. */ -void rtc_write_read_test() -{ - RealTimeClock::init(); - - /* NB: IAR compilation issue with "auto init_val = RealTimeClock::time_point(100s)" */ - for (auto init_val = RealTimeClock::time_point(seconds(100)); init_val < RealTimeClock::time_point(400s); init_val += 100s) { - core_util_critical_section_enter(); - - RealTimeClock::write(init_val); - const auto read_val = RealTimeClock::now(); - - 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(init_val == read_val); - } - - RealTimeClock::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. - */ - - RealTimeClock::init(); - RealTimeClock::write(RealTimeClock::time_point(0s)); - TEST_ASSERT_TRUE(RealTimeClock::isenabled()); - RealTimeClock::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); -} - -#endif // !DEVICE_RTC diff --git a/TESTS/mbed_hal/rtc/rtc_test.h b/TESTS/mbed_hal/rtc/rtc_test.h deleted file mode 100644 index eb75995..0000000 --- a/TESTS/mbed_hal/rtc/rtc_test.h +++ /dev/null @@ -1,116 +0,0 @@ -/* mbed Microcontroller Library - * Copyright (c) 2017-2017 ARM Limited - * 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. - */ - -/** \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 - -/** @}*/ diff --git a/TESTS/mbed_hal/rtc_reset/main.cpp b/TESTS/mbed_hal/rtc_reset/main.cpp deleted file mode 100644 index ca01b1b..0000000 --- a/TESTS/mbed_hal/rtc_reset/main.cpp +++ /dev/null @@ -1,105 +0,0 @@ -/* mbed Microcontroller Library - * Copyright (c) 2017 ARM Limited - * 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. - */ - -#if !DEVICE_RTC -#error [NOT_SUPPORTED] RTC API not supported for this target -#else - -#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(); -} - -#endif // !DEVICE_RTC diff --git a/TESTS/mbed_hal/rtc_reset/rtc_reset_test.h b/TESTS/mbed_hal/rtc_reset/rtc_reset_test.h deleted file mode 100644 index 66dfc53..0000000 --- a/TESTS/mbed_hal/rtc_reset/rtc_reset_test.h +++ /dev/null @@ -1,50 +0,0 @@ -/* mbed Microcontroller Library - * Copyright (c) 2017-2017 ARM Limited - * 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. - */ - -/** \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 - -/** @}*/ diff --git a/TESTS/mbed_hal/rtc_time/main.cpp b/TESTS/mbed_hal/rtc_time/main.cpp deleted file mode 100644 index c4c47b3..0000000 --- a/TESTS/mbed_hal/rtc_time/main.cpp +++ /dev/null @@ -1,221 +0,0 @@ -/* mbed Microcontroller Library - * Copyright (c) 2017 ARM Limited - * 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. - */ - -#include "utest/utest.h" -#include "unity/unity.h" -#include "greentea-client/test_env.h" - -#include "mbed.h" -#include "mbed_mktime.h" - -#define LAST_VALID_YEAR 206 - -using namespace utest::v1; - -/* Regular is_leap_year, see platform/mbed_mktime.c for the optimised version. */ -bool is_leap_year(int year) -{ - year = 1900 + year; - if (year % 4) { - return false; - } else if (year % 100) { - return true; - } else if (year % 400) { - return false; - } - return true; -} - -/* Test the optimised version of _rtc_is_leap_year() against the generic version. - * - * Note: This test case is designed for both types of RTC devices: - * - RTC devices which handle correctly leap years in whole range (1970 - 2106). - * - RTC devices which does not handle correctly leap years in whole range (1970 - 2106). - * This RTC devices uses simpler leap year detection and incorrectly treat 2100 as a leap year. - * rtc_leap_year_support variable specifies which device is tested. - * - * Given is year in valid range. - * When _rtc_is_leap_year() function is called. - * Then _rtc_is_leap_year() returns true if given year is a leap year; false otherwise. - */ -template -void test_is_leap_year() -{ - for (int i = 70; i <= LAST_VALID_YEAR; ++i) { - bool expected = is_leap_year(i); - - /* Add exception for year 2100. */ - if (rtc_leap_year_support == RTC_4_YEAR_LEAP_YEAR_SUPPORT && i == 200) { - expected = true; - } - - bool actual_value = _rtc_is_leap_year(i, rtc_leap_year_support); - - if (expected != actual_value) { - printf("Leap year failed with i = %d\r\n", i); - } - TEST_ASSERT_EQUAL(expected, actual_value); - } -} - -/* Structure to test border values for _rtc_maketime(). */ -typedef struct { - struct tm timeinfo; - time_t exp_seconds; // if result is false then exp_seconds is irrelevant - bool result; -} test_mk_time_struct; - -/* Test boundary values for _rtc_maketime(). - * - * Note: This test case is designed for both types of RTC devices: - * - RTC devices which handle correctly leap years in whole range (1970 - 2106). - * - RTC devices which does not handle correctly leap years in whole range (1970 - 2106). - * This RTC devices uses simpler leap year detection and incorrectly treat 2100 as a leap year. - * rtc_leap_year_support variable specifies which device is tested. - * - * Given is boundary calendar time. - * When _rtc_maketime() function is called to convert the calendar time into timestamp. - * Then if given calendar time is valid function returns true and conversion result, otherwise returns false. - */ -template -void test_mk_time_boundary() -{ - test_mk_time_struct *pTestCases; - - /* Array which contains data to test boundary values for the RTC devices which handles correctly leap years in - * whole range (1970 - 2106). - * Expected range: the 1st of January 1970 at 00:00:00 (seconds: 0) to the 7th of February 2106 at 06:28:15 (seconds: UINT_MAX). - */ - test_mk_time_struct test_mk_time_arr_full[] = { - {{ 0, 0, 0, 1, 0, 70, 0, 0, 0 }, (time_t) 0, true}, // valid lower bound - the 1st of January 1970 at 00:00:00 - {{ 59, 59, 23, 31, 11, 59, 0, 0, 0 }, (time_t) 0, false }, // invalid lower bound - the 31st of December 1969 at 23:59:59 - - {{ 15, 28, 6, 7, 1, 206, 0, 0, 0 }, (time_t)(UINT_MAX), true }, // valid upper bound - the 7th of February 2106 at 06:28:15 - {{ 16, 28, 6, 7, 1, 206, 0, 0, 0 }, (time_t) 0, false }, // invalid upper bound - the 7th of February 2106 at 06:28:16 - }; - - /* Array which contains data to test boundary values for the RTC devices which does not handle correctly leap years in - * whole range (1970 - 2106). On this platforms we will be one day off after 28.02.2100 since 2100 year will be - * incorrectly treated as a leap year. - * Expected range: the 1st of January 1970 at 00:00:00 (seconds: 0) to the 6th of February 2106 at 06:28:15 (seconds: UINT_MAX). - */ - test_mk_time_struct test_mk_time_arr_partial[] = { - {{ 0, 0, 0, 1, 0, 70, 0, 0, 0 }, (time_t) 0, true}, // valid lower bound - the 1st of January 1970 at 00:00:00 - {{ 59, 59, 23, 31, 11, 59, 0, 0, 0 }, (time_t) 0, false }, // invalid lower bound - the 31st of December 1969 at 23:59:59 - - {{ 15, 28, 6, 6, 1, 206, 0, 0, 0 }, (time_t)(UINT_MAX), true }, // valid upper bound - the 6th of February 2106 at 06:28:15 - {{ 16, 28, 6, 6, 1, 206, 0, 0, 0 }, (time_t) 0, false }, // invalid upper bound - the 6th of February 2106 at 06:28:16 - }; - - /* Select array with test cases. */ - if (rtc_leap_year_support == RTC_FULL_LEAP_YEAR_SUPPORT) { - pTestCases = test_mk_time_arr_full; - } else { - pTestCases = test_mk_time_arr_partial; - } - - for (int i = 0; i < (sizeof(test_mk_time_arr_full) / (sizeof(test_mk_time_struct))); i++) { - time_t seconds; - bool result = _rtc_maketime(&pTestCases[i].timeinfo, &seconds, rtc_leap_year_support); - - TEST_ASSERT_EQUAL(pTestCases[i].result, result); - - /* If the result is false, then we have conversion error - skip checking seconds. */ - if (pTestCases[i].result) { - TEST_ASSERT_EQUAL_UINT32(pTestCases[i].exp_seconds, seconds); - } - } -} - -/* Test _rtc_maketime() function - call with invalid parameters. - * - * Given is _rtc_maketime() function. - * When _rtc_maketime() function is called with invalid parameter. - * Then _rtc_maketime() function returns false. - */ -void test_mk_time_invalid_param() -{ - time_t seconds; - struct tm timeinfo; - - TEST_ASSERT_EQUAL(false, _rtc_maketime(NULL, &seconds, RTC_FULL_LEAP_YEAR_SUPPORT)); - TEST_ASSERT_EQUAL(false, _rtc_maketime(NULL, &seconds, RTC_4_YEAR_LEAP_YEAR_SUPPORT)); - TEST_ASSERT_EQUAL(false, _rtc_maketime(&timeinfo, NULL, RTC_FULL_LEAP_YEAR_SUPPORT)); - TEST_ASSERT_EQUAL(false, _rtc_maketime(&timeinfo, NULL, RTC_4_YEAR_LEAP_YEAR_SUPPORT)); -} - -/* Test _rtc_localtime() function - call with invalid parameters. - * - * Given is _rtc_localtime() function. - * When _rtc_localtime() function is called with invalid parameter. - * Then _rtc_localtime() function returns false. - */ -void test_local_time_invalid_param() -{ - TEST_ASSERT_EQUAL(false, _rtc_localtime(1, NULL, RTC_FULL_LEAP_YEAR_SUPPORT)); - TEST_ASSERT_EQUAL(false, _rtc_localtime(1, NULL, RTC_4_YEAR_LEAP_YEAR_SUPPORT)); -} - -/* Test set_time() function called a few seconds apart. - * - * Given is set_time() function. - * When set_time() is used to set the system time two times. - * Then if the value returned from time() is always correct return true, otherwise return false. - */ -#define NEW_TIME 15 -void test_set_time_twice() -{ - time_t current_time; - - /* Set the time to NEW_TIME and check it */ - set_time(NEW_TIME); - current_time = time(NULL); - TEST_ASSERT_EQUAL(true, (current_time == NEW_TIME)); - - /* Wait 2 seconds */ - ThisThread::sleep_for(2000); - - /* set the time to NEW_TIME again and check it */ - set_time(NEW_TIME); - current_time = time(NULL); - TEST_ASSERT_EQUAL(true, (current_time == NEW_TIME)); -} - -Case cases[] = { - Case("test is leap year - RTC leap years full support", test_is_leap_year), - Case("test is leap year - RTC leap years partial support", test_is_leap_year), - Case("test make time boundary values - RTC leap years full support", test_mk_time_boundary), - Case("test make time boundary values - RTC leap years partial support", test_mk_time_boundary), - Case("test make time - invalid param", test_mk_time_invalid_param), - Case("test local time - invalid param", test_local_time_invalid_param), -#if DEVICE_RTC || DEVICE_LPTICKER - Case("test set_time twice", test_set_time_twice), -#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() -{ - return Harness::run(specification); -} diff --git a/TESTS/mbed_hal/rtc_time_conv/main.cpp b/TESTS/mbed_hal/rtc_time_conv/main.cpp deleted file mode 100644 index 0a71654..0000000 --- a/TESTS/mbed_hal/rtc_time_conv/main.cpp +++ /dev/null @@ -1,211 +0,0 @@ -/* - * 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: - * - _rtc_maketime() function converts a calendar time into time since UNIX epoch as a time_t, - * - _rtc_localtime() function converts a given time in seconds since epoch into calendar time. - */ - -#include "mbed.h" -#include "greentea-client/test_env.h" -#include "utest/utest.h" -#include "unity/unity.h" -#include "mbed_mktime.h" - -#define LAST_VALID_YEAR 206 - -using namespace utest::v1; - -static rtc_leap_year_support_t rtc_leap_year_support; - -/* - * regular is_leap_year, see platform/mbed_mktime.c for the optimised version - */ -bool is_leap_year(int year) -{ - year = 1900 + year; - if (year % 4) { - return false; - } else if (year % 100) { - return true; - } else if (year % 400) { - return false; - } - return true; -} - -struct tm make_time_info(int year, int month, int day, int hours, int minutes, int seconds) -{ - struct tm timeinfo = { - seconds, // tm_sec - minutes, // tm_min - hours, // tm_hour - day, // tm_mday - month, // tm_mon - year, // tm_year - 0, // tm_wday - 0, // tm_yday - 0, // tm_isdst - }; - return timeinfo; -} - -/* Test _rtc_maketime() and _rtc_localtime() across wide range - * - * Note: This test functions handles both types of RTC devices: - * - devices which supports full leap years support in range 1970 - 2106. - * - devices which supports parial leap years support and incorrectly treats 2100 year as a leap year. - * - * Given is valid calendar time. - * When _rtc_maketime() is used to generate timestamp from calendar time and _rtc_localtime() is used to convert - * timestamp to calendar time. - * Then both operations gives valid results. - */ -void test_case_mktime_localtime() -{ - char _key[11] = - { }; - char _value[128] = - { }; - - size_t years[] = {70, 71, 100, 196, 200, 205}; - - /* Inform host part of the test about tested RTC type. */ - greentea_send_kv("leap_year_setup", rtc_leap_year_support); - - /* Check the first and last last day of each month. */ - for (size_t year_id = 0; year_id < (sizeof(years) / sizeof(size_t)) ; ++year_id) { - for (size_t month = 0; month < 12; ++month) { - for (size_t dayid = 0; dayid < 2; ++dayid) { - - size_t year = years[year_id]; - - size_t day = 0; - /* Test the first and the last day of each month: - * day 0 - first, - * day 1 - last - * */ - switch (dayid) { - case 0: - day = 1; - break; - - case 1: - day = 31; - - if (month == 3 || month == 5 || month == 8 || month == 10) { - day = 30; - } - - if (month == 1) { - day = 28; - } - - if (month == 1 && is_leap_year(year)) { - day = 29; - } - - /* Additional conditions for RTCs with partial leap year support. */ - if (month == 1 && year == 200 && rtc_leap_year_support == RTC_4_YEAR_LEAP_YEAR_SUPPORT) { - day = 29; - } - - break; - - default: - break; - } - - tm time_info = make_time_info(year, month, day, 23, dayid ? 59 : 0, dayid ? 59 : 0); - - time_t actual_timestamp; - - TEST_ASSERT_TRUE(_rtc_maketime(&time_info, &actual_timestamp, rtc_leap_year_support)); - - greentea_send_kv("timestamp", (int) actual_timestamp); - - greentea_parse_kv(_key, _value, sizeof(_key), sizeof(_value)); - - TEST_ASSERT_EQUAL_STRING("passed", _key); - - /* Response which indicates success contains encoded week day - * and year day needed to verify _rtc_localtime(). - * Use validated timestamp to generate and validate calendar time. - */ - - unsigned int buf = (unsigned int) strtol(_value, NULL, 10); - - time_info.tm_wday = ((buf >> 16) & 0x0000FFFF); - time_info.tm_yday = (buf & 0x0000FFFF); - - tm actual_time_info; - - bool result = _rtc_localtime((time_t) actual_timestamp, &actual_time_info, rtc_leap_year_support); - - TEST_ASSERT_TRUE(result); - TEST_ASSERT_EQUAL_UINT32_MESSAGE(time_info.tm_sec, actual_time_info.tm_sec, "invalid seconds"); - TEST_ASSERT_EQUAL_UINT32_MESSAGE(time_info.tm_min, actual_time_info.tm_min, "invalid minutes"); - TEST_ASSERT_EQUAL_UINT32_MESSAGE(time_info.tm_hour, actual_time_info.tm_hour, "invalid hours"); - TEST_ASSERT_EQUAL_UINT32_MESSAGE(time_info.tm_mday, actual_time_info.tm_mday, "invalid day"); - TEST_ASSERT_EQUAL_UINT32_MESSAGE(time_info.tm_mon, actual_time_info.tm_mon, "invalid month"); - TEST_ASSERT_EQUAL_UINT32_MESSAGE(time_info.tm_year, actual_time_info.tm_year, "invalid year"); - TEST_ASSERT_EQUAL_UINT32_MESSAGE(time_info.tm_wday, actual_time_info.tm_wday, "invalid weekday"); - TEST_ASSERT_EQUAL_UINT32_MESSAGE(time_info.tm_yday, actual_time_info.tm_yday, "invalid year day"); - } - } - } -} - -utest::v1::status_t full_leap_year_case_setup_handler_t(const Case *const source, const size_t index_of_case) -{ - rtc_leap_year_support = RTC_FULL_LEAP_YEAR_SUPPORT; - - return greentea_case_setup_handler(source, index_of_case); -} - -utest::v1::status_t partial_leap_year_case_setup_handler_t(const Case *const source, const size_t index_of_case) -{ - rtc_leap_year_support = RTC_4_YEAR_LEAP_YEAR_SUPPORT; - - return greentea_case_setup_handler(source, index_of_case); -} - -utest::v1::status_t 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("test make time and local time - RTC leap years full support", full_leap_year_case_setup_handler_t, test_case_mktime_localtime, teardown_handler_t), - Case("test make time and local time - RTC leap years partial support", partial_leap_year_case_setup_handler_t, test_case_mktime_localtime, teardown_handler_t), -}; - -utest::v1::status_t greentea_test_setup(const size_t number_of_cases) -{ - GREENTEA_SETUP(300, "rtc_calc_auto"); - return greentea_test_setup_handler(number_of_cases); -} - -Specification specification(greentea_test_setup, cases, greentea_test_teardown_handler); - -int main() -{ - Harness::run(specification); -} diff --git a/TESTS/mbed_hal/sleep/main.cpp b/TESTS/mbed_hal/sleep/main.cpp deleted file mode 100644 index c0a21d8..0000000 --- a/TESTS/mbed_hal/sleep/main.cpp +++ /dev/null @@ -1,268 +0,0 @@ -/* mbed Microcontroller Library - * Copyright (c) 2017 ARM Limited - * 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. - */ -#if !DEVICE_SLEEP -#error [NOT_SUPPORTED] sleep not supported for this target -#else - -#include "mbed.h" - -#include "utest/utest.h" -#include "unity/unity.h" -#include "greentea-client/test_env.h" -#include "mbed_lp_ticker_wrapper.h" -#include "hal/us_ticker_api.h" - -#include "sleep_test_utils.h" -#include "sleep_api_tests.h" - -using namespace utest::v1; - -static char info[512] = {0}; - -/* 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 */ -#if defined(MBED_CPU_STATS_ENABLED) -/* extra 25us for stats computation (for more details see MBED_CPU_STATS_ENABLED) */ -static const uint32_t sleep_mode_delta_us = (10 + 4 + 5 + 25); -#else -static const uint32_t sleep_mode_delta_us = (10 + 4 + 5); -#endif - -/* 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); - -/* 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() -{ - 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) { - /* Give some time Green Tea to finish UART transmission before entering - * sleep mode. - */ - busy_wait_ms(SERIAL_FLUSH_TIME_MS); - - /* note: us_ticker_read() operates on ticks. */ - const timestamp_t start_timestamp = us_ticker_read(); - const timestamp_t next_match_timestamp = overflow_protect(start_timestamp + us_to_ticks(i, ticker_freq), - ticker_width); - - us_ticker_set_interrupt(next_match_timestamp); - - sleep(); - - const unsigned int wakeup_timestamp = us_ticker_read(); - - sprintf(info, "Delta ticks: %u, Ticker width: %u, Expected wake up tick: %d, Actual wake up tick: %d, delay ticks: %d, wake up after ticks: %d", - us_to_ticks(sleep_mode_delta_us, ticker_freq), ticker_width, next_match_timestamp, wakeup_timestamp, us_to_ticks(i, ticker_freq), wakeup_timestamp - start_timestamp); - - TEST_ASSERT_MESSAGE(compare_timestamps(us_to_ticks(sleep_mode_delta_us, ticker_freq), - ticker_width, next_match_timestamp, wakeup_timestamp), info); - } - - set_us_ticker_irq_handler(us_ticker_irq_handler_org); - - sleep_manager_unlock_deep_sleep(); - TEST_ASSERT_TRUE(sleep_manager_can_deep_sleep()); -} - -#if 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); - - 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) { - /* Give some time Green Tea to finish UART transmission before entering - * deep-sleep mode. - */ - busy_wait_ms(SERIAL_FLUSH_TIME_MS); - - /* note: lp_ticker_read() operates on ticks. */ - const timestamp_t start_timestamp = lp_ticker_read(); - const timestamp_t next_match_timestamp = overflow_protect(start_timestamp + us_to_ticks(i, ticker_freq), ticker_width); - - lp_ticker_set_interrupt(next_match_timestamp); - - /* On some targets like STM family boards with LPTIM enabled there is a required delay (~100 us) before we are able to - reprogram LPTIM_COMPARE register back to back. This is handled by the low level lp ticker wrapper which uses LPTIM_CMPOK interrupt. - CMPOK fires when LPTIM_COMPARE register can be safely reprogrammed again. During this period deep-sleep is locked. - This means that on these platforms we have additional interrupt (CMPOK) fired always ~100 us after programming lp ticker. - Since this interrupt wakes-up the board from the sleep we need to go to sleep after CMPOK is handled. */ - TEST_ASSERT_TRUE(sleep_manager_can_deep_sleep_test_check()); - - sleep(); - - /* On some targets like STM family boards with LPTIM enabled an interrupt is triggered on counter rollover. - We need special handling for cases when next_match_timestamp < start_timestamp (interrupt is to be fired after rollover). - In such case after first wake-up we need to reset interrupt and go back to sleep waiting for the valid one. - NOTE: Above comment (CMPOK) applies also here.*/ -#if MBED_CONF_TARGET_LPTICKER_LPTIM - if ((next_match_timestamp < start_timestamp) && lp_ticker_read() < next_match_timestamp) { - lp_ticker_set_interrupt(next_match_timestamp); - wait_ns(200000); - sleep(); - } -#endif - - const timestamp_t wakeup_timestamp = lp_ticker_read(); - - sprintf(info, "Delta ticks: %u, Ticker width: %u, Expected wake up tick: %d, Actual wake up tick: %d, delay ticks: %d, wake up after ticks: %d", - us_to_ticks(deepsleep_mode_delta_us, ticker_freq), ticker_width, next_match_timestamp, wakeup_timestamp, us_to_ticks(i, ticker_freq), wakeup_timestamp - start_timestamp); - - TEST_ASSERT_MESSAGE(compare_timestamps(us_to_ticks(deepsleep_mode_delta_us, ticker_freq), ticker_width, - next_match_timestamp, wakeup_timestamp), info); - } - - 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. - */ - busy_wait_ms(SERIAL_FLUSH_TIME_MS); - - TEST_ASSERT_TRUE_MESSAGE(sleep_manager_can_deep_sleep(), "deep sleep should not be locked"); - - const timestamp_t wakeup_time = lp_ticker_read() + us_to_ticks(20000, lp_ticker_freq); - lp_ticker_set_interrupt(wakeup_time); - - /* Wait for CMPOK */ - TEST_ASSERT_TRUE(sleep_manager_can_deep_sleep_test_check()); - - const unsigned int us_ticks_before_sleep = us_ticker_read(); - - 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)); - - sprintf(info, "Delta ticks: %u, Ticker width: %u, Expected wake up tick: %d, Actual wake up tick: %d", - us_to_ticks(deepsleep_mode_delta_us, lp_ticker_freq), lp_ticker_width, wakeup_time, lp_ticks_after_sleep); - - /* Check if we have woken-up after expected time. */ - TEST_ASSERT_MESSAGE(compare_timestamps(us_to_ticks(deepsleep_mode_delta_us, lp_ticker_freq), lp_ticker_width, - wakeup_time, lp_ticks_after_sleep), info); -} - -#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"); - /* Suspend RTOS Kernel to enable sleep modes. */ -#if defined(MBED_CONF_RTOS_PRESENT) - osKernelSuspend(); -#endif -#if DEVICE_LPTICKER - ticker_suspend(get_lp_ticker_data()); -#if DEVICE_LPTICKER && (LPTICKER_DELAY_TICKS > 0) - lp_ticker_wrapper_suspend(); -#endif -#endif - ticker_suspend(get_us_ticker_data()); - - us_ticker_init(); -#if DEVICE_LPTICKER - lp_ticker_init(); -#endif - - return greentea_test_setup_handler(number_of_cases); -} - -void greentea_test_teardown(const size_t passed, const size_t failed, const failure_t failure) -{ - ticker_resume(get_us_ticker_data()); -#if DEVICE_LPTICKER -#if DEVICE_LPTICKER && (LPTICKER_DELAY_TICKS > 0) - lp_ticker_wrapper_resume(); -#endif - ticker_resume(get_lp_ticker_data()); -#endif -#if defined(MBED_CONF_RTOS_PRESENT) - osKernelResume(0); -#endif - greentea_test_teardown_handler(passed, failed, failure); -} - -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); - -int main() -{ - Harness::run(specification); -} - -#endif // !DEVICE_SLEEP diff --git a/TESTS/mbed_hal/sleep/sleep_api_tests.h b/TESTS/mbed_hal/sleep/sleep_api_tests.h deleted file mode 100644 index 2e056af..0000000 --- a/TESTS/mbed_hal/sleep/sleep_api_tests.h +++ /dev/null @@ -1,70 +0,0 @@ -/* mbed Microcontroller Library - * Copyright (c) 2017 ARM Limited - * 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. - */ - -/** \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 - -/**@}*/ diff --git a/TESTS/mbed_hal/sleep/sleep_test_utils.h b/TESTS/mbed_hal/sleep/sleep_test_utils.h deleted file mode 100644 index e9e3de7..0000000 --- a/TESTS/mbed_hal/sleep/sleep_test_utils.h +++ /dev/null @@ -1,118 +0,0 @@ -/* mbed Microcontroller Library - * Copyright (c) 2017 ARM Limited - * 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. - */ - -/** - * @addtogroup hal_sleep - * @{ - * @defgroup hal_sleep_test_util Tests - * Tests of the sleep HAL. - * @{ - */ - -#ifndef MBED_SLEEP_TEST_UTILS_H -#define MBED_SLEEP_TEST_UTILS_H - -#include "hal/ticker_api.h" -#include "hal/us_ticker_api.h" -#include "hal/lp_ticker_api.h" - -/* To prevent a loss of Greentea data, the serial buffers have to be flushed - * before the UART peripheral shutdown. The UART shutdown happens when the - * device is entering the deepsleep mode or performing a reset. - * - * With the current API, it is not possible to check if the hardware buffers - * are empty. However, it is possible to determine the time required for the - * buffers to flush. - * - * Assuming the biggest Tx FIFO of 128 bytes (as for CY8CPROTO_062_4343W) - * and a default UART config (9600, 8N1), flushing the Tx FIFO wold take: - * (1 start_bit + 8 data_bits + 1 stop_bit) * 128 * 1000 / 9600 = 133.3 ms. - * To be on the safe side, set the wait time to 150 ms. - */ -#define SERIAL_FLUSH_TIME_MS 150 - -#define US_PER_S 1000000 - -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 busy_wait_ms(int ms) -{ - const ticker_info_t *info = us_ticker_get_info(); - uint32_t mask = (1 << info->bits) - 1; - int delay = (int)((uint64_t) ms * info->frequency / 1000); - - uint32_t prev = us_ticker_read(); - while (delay > 0) { - uint32_t next = us_ticker_read(); - delay -= (next - prev) & mask; - prev = next; - } -} - -void us_ticker_isr(const ticker_data_t *const ticker_data) -{ - us_ticker_clear_interrupt(); -} - -#if DEVICE_LPTICKER -void lp_ticker_isr(const ticker_data_t *const ticker_data) -{ - lp_ticker_clear_interrupt(); -} -#endif - -#endif - -/** @}*/ -/** @}*/ diff --git a/TESTS/mbed_hal/sleep_manager/main.cpp b/TESTS/mbed_hal/sleep_manager/main.cpp deleted file mode 100644 index 09a0ad1..0000000 --- a/TESTS/mbed_hal/sleep_manager/main.cpp +++ /dev/null @@ -1,346 +0,0 @@ -/* mbed Microcontroller Library - * Copyright (c) 2017 ARM Limited - * 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. - */ -#include "utest/utest.h" -#include "unity/unity.h" -#include "greentea-client/test_env.h" -#include -#include "mbed.h" -#include "mbed_lp_ticker_wrapper.h" -#include "hal/us_ticker_api.h" -#include "../sleep/sleep_test_utils.h" -#include "sleep_manager_api_tests.h" - -#if !DEVICE_SLEEP -#error [NOT_SUPPORTED] test not supported -#else - -#define SLEEP_DURATION_US 20000ULL -#define DEEP_SLEEP_TEST_CHECK_WAIT_US 2000 -// As sleep_manager_can_deep_sleep_test_check() is based on wait_ns -// and wait_ns can be up to 40% slower, use a 50% delta here. -#define DEEP_SLEEP_TEST_CHECK_WAIT_DELTA_US 1000 - -using utest::v1::Case; -using utest::v1::Specification; -using utest::v1::Harness; - -#if DEVICE_LPTICKER -/* Make sure there are enough ticks to cope with more than SLEEP_DURATION_US sleep - * without hitting the wrap-around. - */ -void wraparound_lp_protect(void) -{ - const uint32_t ticks_now = get_lp_ticker_data()->interface->read(); - const ticker_info_t *p_ticker_info = get_lp_ticker_data()->interface->get_info(); - - const uint32_t max_count = ((1 << p_ticker_info->bits) - 1); - const uint32_t delta_ticks = us_to_ticks(SLEEP_DURATION_US * 1.5, p_ticker_info->frequency); - - if (ticks_now < (max_count - delta_ticks)) { - return; - } - - while (get_lp_ticker_data()->interface->read() > (max_count - delta_ticks)); -} -#endif - -void test_lock_unlock() -{ - TEST_ASSERT_TRUE(sleep_manager_can_deep_sleep()); - - sleep_manager_lock_deep_sleep(); - TEST_ASSERT_FALSE(sleep_manager_can_deep_sleep()); - - sleep_manager_unlock_deep_sleep(); - TEST_ASSERT_TRUE(sleep_manager_can_deep_sleep()); -} - -void test_lock_eq_ushrt_max() -{ - uint32_t lock_count = 0; - while (lock_count < USHRT_MAX) { - sleep_manager_lock_deep_sleep(); - lock_count++; - TEST_ASSERT_FALSE(sleep_manager_can_deep_sleep()); - } - while (lock_count > 1) { - sleep_manager_unlock_deep_sleep(); - lock_count--; - TEST_ASSERT_FALSE(sleep_manager_can_deep_sleep()); - } - sleep_manager_unlock_deep_sleep(); - TEST_ASSERT_TRUE(sleep_manager_can_deep_sleep()); -} - -utest::v1::status_t testcase_setup(const Case *const source, const size_t index_of_case) -{ - // Suspend the RTOS kernel scheduler to prevent interference with duration of sleep. -#if defined(MBED_CONF_RTOS_PRESENT) - osKernelSuspend(); -#endif -#if DEVICE_LPTICKER - ticker_suspend(get_lp_ticker_data()); -#if (LPTICKER_DELAY_TICKS > 0) - // Suspend the low power ticker wrapper to prevent interference with deep sleep lock. - lp_ticker_wrapper_suspend(); -#endif -#endif - ticker_suspend(get_us_ticker_data()); - // Make sure HAL tickers are initialized. - us_ticker_init(); -#if DEVICE_LPTICKER - lp_ticker_init(); -#endif - return utest::v1::greentea_case_setup_handler(source, index_of_case); -} - -utest::v1::status_t testcase_teardown(const Case *const source, const size_t passed, const size_t failed, - const utest::v1::failure_t failure) -{ - ticker_resume(get_us_ticker_data()); -#if DEVICE_LPTICKER -#if (LPTICKER_DELAY_TICKS > 0) - lp_ticker_wrapper_resume(); -#endif - ticker_resume(get_lp_ticker_data()); -#endif -#if defined(MBED_CONF_RTOS_PRESENT) - osKernelResume(0); -#endif - return utest::v1::greentea_case_teardown_handler(source, passed, failed, failure); -} - -#if DEVICE_LPTICKER -#if DEVICE_USTICKER -/* This test is based on the fact that the high-speed clocks are turned off - * in deep sleep mode but remain on in the ordinary sleep mode. Low-speed - * clocks stay on for both sleep and deep sleep modes. - * - * The type of sleep that was actually used by sleep_manager_sleep_auto() - * can be detected by comparing times measured by us and lp tickers. - */ -void test_sleep_auto() -{ - const ticker_info_t *us_ticker_info = get_us_ticker_data()->interface->get_info(); - const unsigned us_ticker_mask = ((1 << us_ticker_info->bits) - 1); - const ticker_irq_handler_type us_ticker_irq_handler_org = set_us_ticker_irq_handler(us_ticker_isr); - const ticker_info_t *lp_ticker_info = get_lp_ticker_data()->interface->get_info(); - const unsigned lp_ticker_mask = ((1 << lp_ticker_info->bits) - 1); - const ticker_irq_handler_type lp_ticker_irq_handler_org = set_lp_ticker_irq_handler(lp_ticker_isr); - uint32_t us_ts1, us_ts2, lp_ts1, lp_ts2, us_diff1, us_diff2, lp_diff1, lp_diff2; - - /* Let's avoid the Lp ticker wrap-around case */ - wraparound_lp_protect(); - uint32_t lp_wakeup_ts_raw = lp_ticker_read() + us_to_ticks(SLEEP_DURATION_US, lp_ticker_info->frequency); - timestamp_t lp_wakeup_ts = overflow_protect(lp_wakeup_ts_raw, lp_ticker_info->bits); - lp_ticker_set_interrupt(lp_wakeup_ts); - - /* Some targets may need an interrupt short time after LPTIM interrupt is - * set and forbid deep_sleep during that period. Let this period pass */ - TEST_ASSERT_TRUE(sleep_manager_can_deep_sleep_test_check()); - - sleep_manager_lock_deep_sleep(); - - us_ts1 = us_ticker_read(); - lp_ts1 = lp_ticker_read(); - - sleep_manager_sleep_auto(); - - us_ts2 = us_ticker_read(); - lp_ts2 = lp_ticker_read(); - - us_diff1 = ticks_to_us((us_ts1 <= us_ts2) ? (us_ts2 - us_ts1) : (us_ticker_mask - us_ts1 + us_ts2 + 1), us_ticker_info->frequency); - lp_diff1 = ticks_to_us((lp_ts1 <= lp_ts2) ? (lp_ts2 - lp_ts1) : (lp_ticker_mask - lp_ts1 + lp_ts2 + 1), lp_ticker_info->frequency); - - // Deep sleep locked -- ordinary sleep mode used: - // * us_ticker powered ON, - // * lp_ticker powered ON, - // so both should increment equally. - - // Verify us and lp tickers incremented equally, with 10% tolerance. - TEST_ASSERT_UINT64_WITHIN_MESSAGE( - SLEEP_DURATION_US / 10ULL, lp_diff1, us_diff1, - "Deep sleep mode locked, but still used"); - - sleep_manager_unlock_deep_sleep(); - TEST_ASSERT_TRUE(sleep_manager_can_deep_sleep()); - - // Wait for hardware serial buffers to flush. - busy_wait_ms(SERIAL_FLUSH_TIME_MS); - - /* Let's avoid the Lp ticker wrap-around case */ - wraparound_lp_protect(); - lp_wakeup_ts_raw = lp_ticker_read() + us_to_ticks(SLEEP_DURATION_US, lp_ticker_info->frequency); - lp_wakeup_ts = overflow_protect(lp_wakeup_ts_raw, lp_ticker_info->bits); - lp_ticker_set_interrupt(lp_wakeup_ts); - - /* Some targets may need an interrupt short time after LPTIM interrupt is - * set and forbid deep_sleep during that period. Let this period pass */ - TEST_ASSERT_TRUE(sleep_manager_can_deep_sleep_test_check()); - - us_ts1 = us_ticker_read(); - lp_ts1 = lp_ticker_read(); - - sleep_manager_sleep_auto(); - - us_ts2 = us_ticker_read(); - lp_ts2 = lp_ticker_read(); - - us_diff2 = ticks_to_us((us_ts1 <= us_ts2) ? (us_ts2 - us_ts1) : (us_ticker_mask - us_ts1 + us_ts2 + 1), us_ticker_info->frequency); - lp_diff2 = ticks_to_us((lp_ts1 <= lp_ts2) ? (lp_ts2 - lp_ts1) : (lp_ticker_mask - lp_ts1 + lp_ts2 + 1), lp_ticker_info->frequency); - - // Deep sleep unlocked -- deep sleep mode used: - // * us_ticker powered OFF, - // * lp_ticker powered ON. - // The us_ticker increment represents only the code execution time - // and should be much shorter than both: - // 1. current lp_ticker increment, - // 2. previous us_ticker increment (locked sleep test above) - - // Verify that the current us_ticker increment: - // 1. is at most 10% of lp_ticker increment - // 2. is at most 10% of previous us_ticker increment. - TEST_ASSERT_MESSAGE(us_diff2 < lp_diff2 / 10ULL, "Deep sleep mode unlocked, but not used"); - TEST_ASSERT_MESSAGE(us_diff2 < us_diff1 / 10ULL, "Deep sleep mode unlocked, but not used"); - - set_us_ticker_irq_handler(us_ticker_irq_handler_org); - set_lp_ticker_irq_handler(lp_ticker_irq_handler_org); -} -#endif - -#define US_PER_S 1000000 - -uint32_t diff_us(uint32_t start_ticks, uint32_t stop_ticks, const ticker_info_t *info) -{ - uint32_t counter_mask = ((1 << info->bits) - 1); - - uint32_t diff_ticks = ((stop_ticks - start_ticks) & counter_mask); - - return (uint32_t)((uint64_t) diff_ticks * US_PER_S / info->frequency); -} - -volatile bool unlock_deep_sleep = false; - -void ticker_event_handler_stub(const ticker_data_t *const ticker) -{ - lp_ticker_clear_interrupt(); - if (unlock_deep_sleep) { - sleep_manager_unlock_deep_sleep_internal(); - unlock_deep_sleep = false; - } -} - -ticker_irq_handler_type prev_irq_handler; - -void test_lock_unlock_test_check() -{ - prev_irq_handler = set_lp_ticker_irq_handler(ticker_event_handler_stub); - - for (int i = 0; i < 1000; i++) { - - wraparound_lp_protect(); - - const ticker_info_t *p_ticker_info = get_lp_ticker_data()->interface->get_info(); - - // Use LowPowerTimer instead of Timer to prevent deep sleep lock. - us_timestamp_t exec_time_unlocked, exec_time_locked; - uint32_t start, stop; - - // Deep sleep unlocked: - // * sleep_manager_can_deep_sleep() returns true, - // * sleep_manager_can_deep_sleep_test_check() returns true instantly. - TEST_ASSERT_TRUE(sleep_manager_can_deep_sleep()); - start = lp_ticker_read(); - TEST_ASSERT_TRUE(sleep_manager_can_deep_sleep_test_check()); - stop = lp_ticker_read(); - exec_time_unlocked = diff_us(start, stop, p_ticker_info); - - // Deep sleep locked: - // * sleep_manager_can_deep_sleep() returns false, - // * sleep_manager_can_deep_sleep_test_check() returns false with 2 ms delay. - sleep_manager_lock_deep_sleep(); - TEST_ASSERT_FALSE(sleep_manager_can_deep_sleep()); - start = lp_ticker_read(); - TEST_ASSERT_FALSE(sleep_manager_can_deep_sleep_test_check()); - stop = lp_ticker_read(); - exec_time_locked = diff_us(start, stop, p_ticker_info); - TEST_ASSERT_UINT64_WITHIN(DEEP_SLEEP_TEST_CHECK_WAIT_DELTA_US, DEEP_SLEEP_TEST_CHECK_WAIT_US, - exec_time_locked - exec_time_unlocked); - - // Deep sleep unlocked with a 1 ms delay: - // * sleep_manager_can_deep_sleep() returns false, - // * sleep_manager_can_deep_sleep_test_check() returns true with a 1 ms delay, - // * sleep_manager_can_deep_sleep() returns true when checked again. - unlock_deep_sleep = true; - /* Let's avoid the Lp ticker wrap-around case */ - wraparound_lp_protect(); - start = lp_ticker_read(); - uint32_t lp_wakeup_ts_raw = start + us_to_ticks(DEEP_SLEEP_TEST_CHECK_WAIT_US / 2, p_ticker_info->frequency); - timestamp_t lp_wakeup_ts = overflow_protect(lp_wakeup_ts_raw, p_ticker_info->bits); - lp_ticker_set_interrupt(lp_wakeup_ts); - - // Extra wait after setting interrupt to handle CMPOK - wait_ns(100000); - TEST_ASSERT_FALSE(sleep_manager_can_deep_sleep()); - TEST_ASSERT_TRUE(sleep_manager_can_deep_sleep_test_check()); - stop = lp_ticker_read(); - TEST_ASSERT(diff_us(start, stop, p_ticker_info) > 0UL); - TEST_ASSERT(diff_us(start, stop, p_ticker_info) < DEEP_SLEEP_TEST_CHECK_WAIT_US); - TEST_ASSERT_TRUE(sleep_manager_can_deep_sleep()); - } - - set_lp_ticker_irq_handler(prev_irq_handler); -} -#endif - -utest::v1::status_t testsuite_setup(const size_t number_of_cases) -{ - GREENTEA_SETUP(15, "default_auto"); - return utest::v1::greentea_test_setup_handler(number_of_cases); -} - -Case cases[] = { - Case("deep sleep lock/unlock", - (utest::v1::case_setup_handler_t) testcase_setup, - test_lock_unlock, - (utest::v1::case_teardown_handler_t) testcase_teardown), - Case("deep sleep locked USHRT_MAX times", - (utest::v1::case_setup_handler_t) testcase_setup, - test_lock_eq_ushrt_max, - (utest::v1::case_teardown_handler_t) testcase_teardown), -#if DEVICE_LPTICKER -#if DEVICE_USTICKER - Case("sleep_auto calls sleep/deep sleep based on lock", - (utest::v1::case_setup_handler_t) testcase_setup, - test_sleep_auto, - (utest::v1::case_teardown_handler_t) testcase_teardown), -#endif - Case("deep sleep lock/unlock test_check", - (utest::v1::case_setup_handler_t) testcase_setup, - test_lock_unlock_test_check, - (utest::v1::case_teardown_handler_t) testcase_teardown) -#endif -}; - -Specification specification(testsuite_setup, cases); - -int main() -{ - return !Harness::run(specification); -} - -#endif // !DEVICE_SLEEP diff --git a/TESTS/mbed_hal/sleep_manager/sleep_manager_api_tests.h b/TESTS/mbed_hal/sleep_manager/sleep_manager_api_tests.h deleted file mode 100644 index dc353d0..0000000 --- a/TESTS/mbed_hal/sleep_manager/sleep_manager_api_tests.h +++ /dev/null @@ -1,87 +0,0 @@ -/* mbed Microcontroller Library - * Copyright (c) 2018 ARM Limited - * 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. - */ - -/** - * @addtogroup hal_sleep_manager_tests - * @{ - */ - -#ifndef MBED_HAL_SLEEP_MANAGER_API_TESTS_H -#define MBED_HAL_SLEEP_MANAGER_API_TESTS_H - -#if DEVICE_SLEEP - -/** Test lock/unlock - * - * Given no prior calls to lock/unlock - * When the deep sleep status is checked - * Then the deep sleep is allowed - * - * When the lock function is called - * Then the deep sleep is not allowed - * - * When the unlock function is called - * Then the deep sleep is allowed again - */ -void test_lock_unlock(); - -/** Test lock USHRT_MAX times - * - * Given a device with sleep mode support - * When deep sleep mode is locked USHRT_MAX times - * Then the deep sleep mode is locked - * - * When unlock is called repeatedly - * Then deep sleep mode stays locked until the number - * of unlock calls is equal to number of lock calls - */ -void test_lock_eq_ushrt_max(); - -/** Test sleep_auto calls sleep and deep sleep based on lock - * - * Given a device with sleep mode support - * When the deep sleep mode is locked - * Then sleep_auto uses sleep mode - * - * When the deep sleep mode is unlocked - * Then sleep_auto uses deep sleep mode - */ -void test_sleep_auto(); - -/** Test lock/unlock test_check fun - * - * Given the deep sleep has not been locked - * When the deep sleep status is checked - * Then sleep_manager_can_deep_sleep() returns true - * and sleep_manager_can_deep_sleep_test_check() returns true instantly. - * - * When the deep sleep mode is locked - * Then sleep_manager_can_deep_sleep() returns false - * and sleep_manager_can_deep_sleep_test_check() returns false with 2 ms delay. - * - * When the deep sleep mode is unlocked with a 1 ms delay - * Then sleep_manager_can_deep_sleep() returns false - * and sleep_manager_can_deep_sleep_test_check() returns true with 1 ms delay - * and sleep_manager_can_deep_sleep() returns true when checked again. - */ -void test_lock_unlock_test_check(); - -#endif - -#endif - -/** @}*/ diff --git a/TESTS/mbed_hal/sleep_manager_racecondition/main.cpp b/TESTS/mbed_hal/sleep_manager_racecondition/main.cpp deleted file mode 100644 index 034b41c..0000000 --- a/TESTS/mbed_hal/sleep_manager_racecondition/main.cpp +++ /dev/null @@ -1,109 +0,0 @@ -/* mbed Microcontroller Library - * Copyright (c) 2017 ARM Limited - * 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. - */ -#include "utest/utest.h" -#include "unity/unity.h" -#include "greentea-client/test_env.h" -#include "mbed.h" -#include "sleep_manager_api_racecondition_tests.h" - -#if !DEVICE_SLEEP || !DEVICE_USTICKER -#error [NOT_SUPPORTED] test not supported -#else - -using namespace utest::v1; - -#define TEST_STACK_SIZE 256 -#if defined(MBED_CONF_RTOS_PRESENT) -void sleep_manager_locking_thread_test() -{ - for (uint32_t i = 0; i < 100; i++) { - sleep_manager_lock_deep_sleep(); - ThisThread::sleep_for(25); - sleep_manager_unlock_deep_sleep(); - } -} - -void sleep_manager_multithread_test() -{ - { - Callback cb(sleep_manager_locking_thread_test); - Thread t1(osPriorityNormal, TEST_STACK_SIZE); - Thread t2(osPriorityNormal, TEST_STACK_SIZE); - - t1.start(callback(cb)); - ThisThread::sleep_for(25); - t2.start(callback(cb)); - - // Wait for the threads to finish - t1.join(); - t2.join(); - } - - bool deep_sleep_allowed = sleep_manager_can_deep_sleep_test_check(); - TEST_ASSERT_TRUE_MESSAGE(deep_sleep_allowed, "Deep sleep should be allowed"); -} -#endif - -void sleep_manager_locking_irq_test() -{ - sleep_manager_lock_deep_sleep(); - sleep_manager_unlock_deep_sleep(); -} - -void sleep_manager_irq_test() -{ - { - Ticker ticker1; - Timer timer; - - ticker1.attach_us(&sleep_manager_locking_irq_test, 1000); - - // run this for 10 seconds - timer.start(); - int start = timer.read(); - int end = start + 10; - while (timer.read() < end) { - sleep_manager_locking_irq_test(); - } - timer.stop(); - } - - bool deep_sleep_allowed = sleep_manager_can_deep_sleep_test_check(); - TEST_ASSERT_TRUE_MESSAGE(deep_sleep_allowed, "Deep sleep should be allowed"); -} - -utest::v1::status_t greentea_test_setup(const size_t number_of_cases) -{ - GREENTEA_SETUP(30, "default_auto"); - return greentea_test_setup_handler(number_of_cases); -} - -Case cases[] = { -#if defined(MBED_CONF_RTOS_PRESENT) - Case("deep sleep lock/unlock is thread safe", sleep_manager_multithread_test), -#endif - Case("deep sleep lock/unlock is IRQ safe", sleep_manager_irq_test), -}; - -Specification specification(greentea_test_setup, cases, greentea_test_teardown_handler); - -int main() -{ - Harness::run(specification); -} - -#endif // !DEVICE_SLEEP || !DEVICE_USTICKER diff --git a/TESTS/mbed_hal/sleep_manager_racecondition/sleep_manager_api_racecondition_tests.h b/TESTS/mbed_hal/sleep_manager_racecondition/sleep_manager_api_racecondition_tests.h deleted file mode 100644 index 5af8c6a..0000000 --- a/TESTS/mbed_hal/sleep_manager_racecondition/sleep_manager_api_racecondition_tests.h +++ /dev/null @@ -1,44 +0,0 @@ -/* mbed Microcontroller Library - * Copyright (c) 2018 ARM Limited - * 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. - */ - -/** - * @addtogroup hal_sleep_manager_tests - * @{ - */ - -#ifndef MBED_HAL_SLEEP_MANAGER_API_RACECONDITION_TESTS_H -#define MBED_HAL_SLEEP_MANAGER_API_RACECONDITION_TESTS_H - -/** Test lock/unlock is thread safe - * - * Given a device with sleep mode support - * When multiple threads are using the sleep manager API - * Then lock/unlock calls are thread safe - */ -void sleep_manager_multithread_test(); - -/** Test lock/unlock is IRQ safe - * - * Given a device with sleep mode support - * When the sleep manager API is used from IRQ and the main thread concurrently - * Then lock/unlock calls are IRQ safe - */ -void sleep_manager_irq_test(); - -#endif - -/** @}*/ diff --git a/TESTS/mbed_hal/stack_size_unification/main.cpp b/TESTS/mbed_hal/stack_size_unification/main.cpp deleted file mode 100644 index 23c84a4..0000000 --- a/TESTS/mbed_hal/stack_size_unification/main.cpp +++ /dev/null @@ -1,78 +0,0 @@ -/* mbed Microcontroller Library - * Copyright (c) 2019-2019 ARM Limited - * - * 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. - */ -#include "mbed.h" -#include "greentea-client/test_env.h" -#include "unity.h" -#include "utest.h" - -#ifdef TARGET_RENESAS -#error [NOT_SUPPORTED] Cortex-A target not supported for this test -#else - -using namespace utest::v1; - -#ifdef MBED_CONF_RTOS_PRESENT -extern osThreadAttr_t _main_thread_attr; -#endif -extern uint32_t mbed_stack_isr_size; - -#define EXPECTED_ISR_STACK_SIZE (MBED_CONF_TARGET_BOOT_STACK_SIZE) - -#define EXPECTED_MAIN_THREAD_STACK_SIZE (MBED_CONF_RTOS_MAIN_THREAD_STACK_SIZE) - -#define EXPECTED_USER_THREAD_DEFAULT_STACK_SIZE (MBED_CONF_RTOS_THREAD_STACK_SIZE) - -#if ((MBED_RAM_SIZE - MBED_BOOT_STACK_SIZE) <= (EXPECTED_MAIN_THREAD_STACK_SIZE + EXPECTED_ISR_STACK_SIZE)) -#error [NOT_SUPPORTED] Insufficient stack for staci_size_unification tests -#endif - - -/* Test sizes of ISR stack, main thread stack, default user thread stack. - * - * On some platforms with lower RAM size (e.g. NUCLEO_F070RB - 16 KB RAM) it is impossible - * to create thread with default stack size to check its size, that is why we will - * check only macro which specifies default user thread stack. - * - */ -void stack_size_unification_test() -{ - TEST_ASSERT_EQUAL(EXPECTED_ISR_STACK_SIZE, mbed_stack_isr_size); -#ifdef MBED_CONF_RTOS_PRESENT - TEST_ASSERT_EQUAL(EXPECTED_MAIN_THREAD_STACK_SIZE, _main_thread_attr.stack_size); - TEST_ASSERT_EQUAL(EXPECTED_USER_THREAD_DEFAULT_STACK_SIZE, OS_STACK_SIZE); -#endif -} - -utest::v1::status_t test_setup(const size_t number_of_cases) -{ - GREENTEA_SETUP(10, "default_auto"); - return verbose_test_setup_handler(number_of_cases); -} - -Case cases[] = { - Case("Stack size unification test", stack_size_unification_test) -}; - -Specification specification(test_setup, cases); - -int main() -{ - return !Harness::run(specification); -} - -#endif // TARGET_RENESAS diff --git a/TESTS/mbed_hal/stack_size_unification/stack_size_unification.h b/TESTS/mbed_hal/stack_size_unification/stack_size_unification.h deleted file mode 100644 index 2c038a9..0000000 --- a/TESTS/mbed_hal/stack_size_unification/stack_size_unification.h +++ /dev/null @@ -1,51 +0,0 @@ -/* mbed Microcontroller Library - * Copyright (c) 2019-2019 ARM Limited - * - * 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. - */ - -/** \addtogroup hal_rtc_tests - * @{ - */ - -#ifndef MBED_STACK_SIZE_UNIFICATION_H -#define MBED_STACK_SIZE_UNIFICATION_H - -#ifdef __cplusplus -extern "C" { -#endif - -/** Test sizes of ISR stack, main thread stack, default user thread stack. - * - * Given is Mbed OS configuration. - * When ISR stack, main thread stack, default user thread stack sizes are defined. - * Then ISR stack size is equal to 1 KB, - * main thread stack size is equal to 4 KB, - * default user thread stack size is equal to 4 KB. - * - * NOTE: - * It is impossible to verify RTOS-less thread stack size since all tests are build with RTOS. - */ -void stack_size_unification_test(void); - -/**@}*/ - -#ifdef __cplusplus -} -#endif - -#endif - -/** @}*/ diff --git a/TESTS/mbed_hal/ticker/main.cpp b/TESTS/mbed_hal/ticker/main.cpp deleted file mode 100644 index a8db500..0000000 --- a/TESTS/mbed_hal/ticker/main.cpp +++ /dev/null @@ -1,2473 +0,0 @@ -/* mbed Microcontroller Library - * Copyright (c) 2017 ARM Limited - * 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. - */ - -#define __STDC_LIMIT_MACROS -#include -#include - -#include "utest/utest.h" -#include "unity/unity.h" -#include "greentea-client/test_env.h" - -#include "mbed.h" -#include "ticker_api.h" - -using namespace utest::v1; - -#define MBED_ARRAY_SIZE(array) (sizeof(array)/sizeof(array[0])) - -#define TIMESTAMP_MAX_DELTA_BITS(bits) ((uint64_t)(0x7 << ((bits) - 4))) -#define TIMESTAMP_MAX_DELTA TIMESTAMP_MAX_DELTA_BITS(32) - -struct ticker_interface_stub_t { - ticker_interface_t interface; - bool initialized; - bool interrupt_flag; - timestamp_t timestamp ; - timestamp_t interrupt_timestamp; - unsigned int init_call; - unsigned int read_call; - unsigned int disable_interrupt_call; - unsigned int clear_interrupt_call; - unsigned int set_interrupt_call; - unsigned int fire_interrupt_call; - unsigned int get_info_call; -}; - -static ticker_interface_stub_t interface_stub = { 0 }; -static ticker_info_t interface_info_stub = { 0 }; - -static void ticker_interface_stub_init() -{ - ++interface_stub.init_call; - interface_stub.initialized = true; -} - -static uint32_t ticker_interface_stub_read() -{ - ++interface_stub.read_call; - return interface_stub.timestamp; -} - -static void ticker_interface_stub_disable_interrupt() -{ - ++interface_stub.disable_interrupt_call; -} - -static void ticker_interface_stub_clear_interrupt() -{ - ++interface_stub.clear_interrupt_call; - interface_stub.interrupt_flag = false; -} - -static void ticker_interface_stub_set_interrupt(timestamp_t timestamp) -{ - ++interface_stub.set_interrupt_call; - interface_stub.interrupt_timestamp = timestamp; -} - -static void ticker_interface_stub_fire_interrupt() -{ - ++interface_stub.fire_interrupt_call; -} - -static const ticker_info_t *ticker_interface_stub_get_info() -{ - ++interface_stub.get_info_call; - return &interface_info_stub; -} - -static void reset_ticker_interface_stub() -{ - interface_stub.interface.init = ticker_interface_stub_init; - interface_stub.interface.read = ticker_interface_stub_read; - interface_stub.interface.disable_interrupt = - ticker_interface_stub_disable_interrupt; - interface_stub.interface.clear_interrupt = - ticker_interface_stub_clear_interrupt; - interface_stub.interface.set_interrupt = ticker_interface_stub_set_interrupt; - interface_stub.interface.fire_interrupt = ticker_interface_stub_fire_interrupt; - interface_stub.interface.get_info = ticker_interface_stub_get_info; - interface_stub.initialized = false; - interface_stub.interrupt_flag = false; - interface_stub.timestamp = 0; - interface_stub.interrupt_timestamp = 0; - interface_stub.init_call = 0; - interface_stub.read_call = 0; - interface_stub.disable_interrupt_call = 0; - interface_stub.clear_interrupt_call = 0; - interface_stub.set_interrupt_call = 0; - interface_stub.fire_interrupt_call = 0; - - interface_info_stub.frequency = 1000000; - interface_info_stub.bits = 32; -} - -// stub of the event queue -static ticker_event_queue_t queue_stub = { - /* event handler */ NULL, - /* head */ NULL, - /* timestamp */ 0, - /* initialized */ false -}; - -static void reset_queue_stub() -{ - queue_stub.event_handler = NULL; - queue_stub.head = NULL, - queue_stub.tick_last_read = 0; - queue_stub.tick_remainder = 0; - queue_stub.frequency = 0; - queue_stub.bitmask = 0; - queue_stub.max_delta = 0; - queue_stub.max_delta_us = 0; - queue_stub.present_time = 0; - queue_stub.initialized = false; -} - -// stub of the ticker -static ticker_data_t ticker_stub = { - /* interface */ &interface_stub.interface, - /* queue */ &queue_stub -}; - -static void reset_ticker_stub() -{ - reset_queue_stub(); - reset_ticker_interface_stub(); -} - -const uint32_t test_frequencies[] = { - 1, - 32768, // 2^15 - 1000000, - 0xFFFFFFFF // 2^32 - 1 -}; - -const uint32_t test_bitwidths[] = { - 32, - 31, - 16, - 8 -}; - -template < void (F)(uint32_t a, uint32_t b)> -static void test_over_frequency_and_width(void) -{ - for (unsigned int i = 0; i < MBED_ARRAY_SIZE(test_frequencies); i++) { - for (unsigned int j = 0; j < MBED_ARRAY_SIZE(test_bitwidths); j++) { - reset_ticker_stub(); - interface_info_stub.frequency = test_frequencies[i]; - interface_info_stub.bits = test_bitwidths[j]; - - F(test_frequencies[i], test_bitwidths[j]); - } - } -} - -static utest::v1::status_t case_setup_handler( - const Case *const source, const size_t index_of_case -) -{ - utest::v1::status_t status = greentea_case_setup_handler(source, index_of_case); - reset_ticker_stub(); - return status; -} - -static utest::v1::status_t case_teardown_handler( - const Case *const source, const size_t passed, const size_t failed, const failure_t reason -) -{ - reset_ticker_stub(); - utest::v1::status_t status = greentea_case_teardown_handler( - source, passed, failed, reason - ); - return status; -} - -static utest::v1::status_t greentea_failure_handler( - const Case *const source, const failure_t reason -) -{ - utest::v1::status_t status = greentea_case_failure_abort_handler( - source, reason - ); - return status; -} - -#define MAKE_TEST_CASE(description, handler) \ - { \ - description, \ - handler, \ - NULL, \ - NULL, \ - case_setup_handler, \ - case_teardown_handler, \ - greentea_failure_handler \ - } - -/** - * Given an unitialized ticker_data instance. - * When the ticker is initialized - * Then: - * - The ticker interface should be initialized - * - The queue handler should be set to the handler provided in parameter - * - The internal ticker timestamp should be zero - * - interrupt should be scheduled in current timestamp + - * TIMESTAMP_MAX_DELTA - * - The queue should not contains any event - */ -static void test_ticker_initialization() -{ - ticker_event_handler dummy_handler = (ticker_event_handler)0xDEADBEEF; - - // setup of the stub - interface_stub.timestamp = 0xFEEDBABE; - - ticker_set_handler(&ticker_stub, dummy_handler); - - TEST_ASSERT_TRUE(interface_stub.initialized); - TEST_ASSERT_EQUAL_PTR(dummy_handler, queue_stub.event_handler); - TEST_ASSERT_EQUAL_UINT64(0, queue_stub.present_time); - TEST_ASSERT_EQUAL(1, interface_stub.set_interrupt_call); - TEST_ASSERT_EQUAL_UINT32( - interface_stub.timestamp + TIMESTAMP_MAX_DELTA, - interface_stub.interrupt_timestamp - ); - TEST_ASSERT_EQUAL_PTR(NULL, queue_stub.head); - TEST_ASSERT_EQUAL(0, interface_stub.disable_interrupt_call); -} - -/** - * Given an initialized ticker_data instance. - * When the ticker handler is set to a new value - * Then: - * - The ticker interface initialization function should not be called. - * - The queue handler should be set to the new handler. - * - The events in the queue should remains the same. - */ -static void test_ticker_re_initialization() -{ - ticker_event_handler dummy_handler = (ticker_event_handler) 0xDEADBEEF; - ticker_event_handler expected_handler = (ticker_event_handler) 0xFEEDDEAF; - - ticker_event_t first_event = { 0 }; - ticker_event_t second_event = { 0 }; - ticker_event_t third_event = { 0 }; - - first_event.next = &second_event; - second_event.next = &third_event; - - // initialize the ticker and put few events in the queue. - ticker_set_handler(&ticker_stub, dummy_handler); - // simulate insertion, it shouldn't affect the queue behaviour for this test - queue_stub.head = &first_event; - interface_stub.init_call = 0; - - ticker_set_handler(&ticker_stub, expected_handler); - - TEST_ASSERT_TRUE(interface_stub.initialized); - TEST_ASSERT_EQUAL(0, interface_stub.init_call); - TEST_ASSERT_EQUAL(expected_handler, queue_stub.event_handler); - TEST_ASSERT_EQUAL(&first_event, queue_stub.head); - TEST_ASSERT_EQUAL(&second_event, queue_stub.head->next); - TEST_ASSERT_EQUAL(&third_event, queue_stub.head->next->next); - TEST_ASSERT_EQUAL(NULL, queue_stub.head->next->next->next); - TEST_ASSERT_EQUAL(0, interface_stub.disable_interrupt_call); -} - -/** - * Given an initialized ticker_data instance. - * When the ticker is read - * Then it should return the value present in the ticker interface - */ -static void test_ticker_read() -{ - ticker_set_handler(&ticker_stub, NULL); - - timestamp_t timestamps[] = { - 0xA, - 0xAA, - 0xAAA, - 0xAAAA, - 0xAAAAA, - 0xAAAAAA, - 0xAAAAAAA, - 0xAAAAAAAA - }; - - for (size_t i = 0; i < MBED_ARRAY_SIZE(timestamps); ++i) { - interface_stub.timestamp = timestamps[i]; - TEST_ASSERT_EQUAL_UINT32(timestamps[i], ticker_read(&ticker_stub)); - TEST_ASSERT_EQUAL_UINT64(timestamps[i], ticker_read_us(&ticker_stub)); - } - - TEST_ASSERT_EQUAL(0, interface_stub.disable_interrupt_call); -} - -/** - * Given an initialized ticker_data instance. - * When the ticker is read and the value read is less than the previous - * value read. - * Then: - * - ticker_read should return the value read in the ticker interface - * - ticker_read_us should return a value where: - * + lower 8 bytes should be equal to the value in the ticker interface - * + upper 8 bytes should be equal to the previous value of upper 8 bytes - * plus one. - */ -static void test_ticker_read_overflow() -{ - const timestamp_t timestamps[] = { - 0xAAAAAAAA, - 0xAAAAAAA, - 0xAAAAAA, - 0xAAAAA, - 0xAAAA, - 0xAAA, - 0xAA, - 0xA - }; - - ticker_set_handler(&ticker_stub, NULL); - - uint32_t upper_bytes_begin = ticker_read_us(&ticker_stub) >> 32; - - for (size_t i = 0; i < MBED_ARRAY_SIZE(timestamps); ++i) { - interface_stub.timestamp = timestamps[i]; - TEST_ASSERT_EQUAL_UINT32(timestamps[i], ticker_read(&ticker_stub)); - TEST_ASSERT_EQUAL_UINT32(timestamps[i], ticker_read_us(&ticker_stub)); - TEST_ASSERT_EQUAL_UINT64( - upper_bytes_begin + i, ticker_read_us(&ticker_stub) >> 32 - ); - } - - TEST_ASSERT_EQUAL(0, interface_stub.disable_interrupt_call); -} - -/** - * Given an initialized ticker without user registered events. - * When an event is inserted with ticker_insert_event and the timestamp passed - * in parameter is in range [ticker_timestamp : ticker_timestamp + - * TIMESTAMP_MAX_DELTA[. - * Then - * - The event should be in the queue - * - The interrupt timestamp should be equal to the timestamp of the event - * - The timestamp of the event should reflect the timestamp requested. - * - The id of the event should be equal to the id passed in parameter. - */ -static void test_legacy_insert_event_outside_overflow_range() -{ - ticker_set_handler(&ticker_stub, NULL); - interface_stub.set_interrupt_call = 0; - - // test the end of the range - ticker_event_t last_event = { 0 }; - const timestamp_t timestamp_last_event = - interface_stub.timestamp + TIMESTAMP_MAX_DELTA; - const uint32_t id_last_event = 0xDEADDEAF; - - ticker_insert_event( - &ticker_stub, - &last_event, timestamp_last_event, id_last_event - ); - - TEST_ASSERT_EQUAL_PTR(&last_event, queue_stub.head); - TEST_ASSERT_EQUAL(1, interface_stub.set_interrupt_call); - TEST_ASSERT_EQUAL_UINT32( - timestamp_last_event, interface_stub.interrupt_timestamp - ); - TEST_ASSERT_EQUAL_PTR(NULL, queue_stub.head->next); - TEST_ASSERT_EQUAL_UINT32(timestamp_last_event, last_event.timestamp); - TEST_ASSERT_EQUAL_UINT32(id_last_event, last_event.id); - - // test the beginning of the range - ticker_event_t first_event = { 0 }; - const timestamp_t timestamp_first_event = interface_stub.timestamp + 1; - const uint32_t id_first_event = 0xAAAAAAAA; - - ticker_insert_event( - &ticker_stub, - &first_event, timestamp_first_event, id_first_event - ); - - TEST_ASSERT_EQUAL_PTR(&first_event, queue_stub.head); - TEST_ASSERT_EQUAL(2, interface_stub.set_interrupt_call); - TEST_ASSERT_EQUAL_UINT32( - timestamp_first_event, interface_stub.interrupt_timestamp - ); - TEST_ASSERT_EQUAL_PTR(&last_event, queue_stub.head->next); - TEST_ASSERT_EQUAL_UINT32( - timestamp_first_event, first_event.timestamp - ); - TEST_ASSERT_EQUAL_UINT32(id_first_event, first_event.id); - - TEST_ASSERT_EQUAL(0, interface_stub.disable_interrupt_call); -} - -/** - * Given an initialized ticker without user registered events. - * When an event is inserted with ticker_insert_event and a timestamp in the - * range [ticker_timestamp + TIMESTAMP_MAX_DELTA + 1 : - * ticker_timestamp + UINT32MAX [ - * Then - * - The event should be in the queue - * - The interrupt timestamp should be equal to - * TIMESTAMP_MAX_DELTA - * - The timestamp of the event should reflect the timestamp requested. - * - The id of the event should be equal to the id passed in parameter. - */ -static void test_legacy_insert_event_in_overflow_range() -{ - ticker_set_handler(&ticker_stub, NULL); - interface_stub.set_interrupt_call = 0; - - // test the end of the range - ticker_event_t last_event = { 0 }; - const timestamp_t timestamp_last_event = - interface_stub.timestamp + UINT32_MAX; - const uint32_t id_last_event = 0xDEADDEAF; - - ticker_insert_event( - &ticker_stub, - &last_event, timestamp_last_event, id_last_event - ); - - TEST_ASSERT_EQUAL_PTR(&last_event, queue_stub.head); - TEST_ASSERT_EQUAL(1, interface_stub.set_interrupt_call); - TEST_ASSERT_EQUAL_UINT32( - interface_stub.timestamp + TIMESTAMP_MAX_DELTA, - interface_stub.interrupt_timestamp - ); - TEST_ASSERT_EQUAL_PTR(NULL, queue_stub.head->next); - TEST_ASSERT_EQUAL_UINT32(timestamp_last_event, last_event.timestamp); - TEST_ASSERT_EQUAL_UINT32(id_last_event, last_event.id); - - // test the beginning of the range - ++interface_stub.timestamp; - - ticker_event_t first_event = { 0 }; - const timestamp_t timestamp_first_event = - interface_stub.timestamp + TIMESTAMP_MAX_DELTA + 1; - const uint32_t id_first_event = 0xAAAAAAAA; - - ticker_insert_event( - &ticker_stub, - &first_event, timestamp_first_event, id_first_event - ); - - TEST_ASSERT_EQUAL_PTR(&first_event, queue_stub.head); - TEST_ASSERT_EQUAL(2, interface_stub.set_interrupt_call); - TEST_ASSERT_EQUAL_UINT32( - interface_stub.timestamp + TIMESTAMP_MAX_DELTA, - interface_stub.interrupt_timestamp - ); - TEST_ASSERT_EQUAL_PTR(&last_event, queue_stub.head->next); - TEST_ASSERT_EQUAL_UINT32( - timestamp_first_event, first_event.timestamp - ); - TEST_ASSERT_EQUAL_UINT32(id_first_event, first_event.id); - - TEST_ASSERT_EQUAL(0, interface_stub.disable_interrupt_call); -} - -/** - * Given an initialized ticker without user registered events. - * When an event is inserted with ticker_insert_event and the timestamp in - * parameter is less than the current timestamp value. - * Then - * - The event should be in the queue - * - The timestamp of the event should reflect the timestamp requested: - * + lower 8 bytes should be equal to the timestamp in input. - * + upper 8 bytes should be equal to the upper of the upper 8 bytes of the - * timestamp state stored in the queue plus one. - * - The id of the event should be equal to the id passed in parameter. - */ -static void test_legacy_insert_event_overflow() -{ - ticker_set_handler(&ticker_stub, NULL); - interface_stub.set_interrupt_call = 0; - - interface_stub.timestamp = 0x20000000; - ticker_read(&ticker_stub); - - ticker_event_t event = { 0 }; - const timestamp_t expected_timestamp = - interface_stub.timestamp + - TIMESTAMP_MAX_DELTA + - 1; - const us_timestamp_t expected_us_timestamp = - (((queue_stub.present_time >> 32) + 1) << 32) | expected_timestamp; - const uint32_t expected_id = 0xDEADDEAF; - - ticker_insert_event( - &ticker_stub, - &event, expected_timestamp, expected_id - ); - - TEST_ASSERT_EQUAL_PTR(&event, queue_stub.head); - TEST_ASSERT_EQUAL(1, interface_stub.set_interrupt_call); - TEST_ASSERT_EQUAL_UINT32( - interface_stub.timestamp + TIMESTAMP_MAX_DELTA, - interface_stub.interrupt_timestamp - ); - TEST_ASSERT_EQUAL_PTR(NULL, queue_stub.head->next); - TEST_ASSERT_EQUAL_UINT32(expected_us_timestamp, event.timestamp); - TEST_ASSERT_EQUAL_UINT32(expected_id, event.id); - - TEST_ASSERT_EQUAL(0, interface_stub.disable_interrupt_call); -} - -/** - * Given an initialized ticker. - * When an event is inserted with ticker_insert_event and a timestamp less than - * the one for the next scheduled timestamp. - * Then - * - The event inserted should be the first in the queue - * - The interrupt timestamp should be equal to the timestamp of the event or - * TIMESTAMP_MAX_DELTA if in the overflow range. - * - The timestamp of the event should reflect the timestamp requested. - * - The id of the event should be equal to the id passed in parameter. - * - Events in the queue should remained ordered by timestamp. - */ -static void test_legacy_insert_event_head() -{ - ticker_set_handler(&ticker_stub, NULL); - interface_stub.set_interrupt_call = 0; - - const timestamp_t timestamps[] = { - UINT32_MAX, - TIMESTAMP_MAX_DELTA + 1, - TIMESTAMP_MAX_DELTA, - TIMESTAMP_MAX_DELTA / 2, - TIMESTAMP_MAX_DELTA / 4, - TIMESTAMP_MAX_DELTA / 8, - TIMESTAMP_MAX_DELTA / 16, - }; - ticker_event_t events[MBED_ARRAY_SIZE(timestamps)] = { 0 }; - - for (size_t i = 0; i < MBED_ARRAY_SIZE(events); ++i) { - ticker_insert_event( - &ticker_stub, - &events[i], timestamps[i], i - ); - - TEST_ASSERT_EQUAL_PTR(&events[i], queue_stub.head); - TEST_ASSERT_EQUAL(i + 1, interface_stub.set_interrupt_call); - if (timestamps[i] < TIMESTAMP_MAX_DELTA) { - TEST_ASSERT_EQUAL_UINT32( - timestamps[i], - interface_stub.interrupt_timestamp - ); - } else { - TEST_ASSERT_EQUAL_UINT32( - TIMESTAMP_MAX_DELTA, - interface_stub.interrupt_timestamp - ); - } - - TEST_ASSERT_EQUAL_UINT32( - timestamps[i], events[i].timestamp - ); - TEST_ASSERT_EQUAL_UINT32(i, events[i].id); - - ticker_event_t *e = &events[i]; - while (e) { - TEST_ASSERT_EQUAL_UINT32(timestamps[e->id], e->timestamp); - if (e->next) { - TEST_ASSERT_TRUE(e->id > e->next->id); - TEST_ASSERT_TRUE(e->timestamp < e->next->timestamp); - } else { - TEST_ASSERT_EQUAL_UINT32(0, e->id); - } - e = e->next; - } - } - - TEST_ASSERT_EQUAL(0, interface_stub.disable_interrupt_call); -} - -/** - * Given an initialized ticker. - * When an event is inserted with ticker_insert_event and its timestamp is bigger - * than the one of the last event in the queue. - * Then - * - The event inserted should be the last in the queue - * - The interrupt timestamp should remains equal to the interrupt timestamp - * of the head event . - * - The timestamp of the event should reflect the timestamp requested. - * - The id of the event should be equal to the id passed in parameter. - * - Events in the queue should remained ordered by timestamp. - */ -static void test_legacy_insert_event_tail() -{ - ticker_set_handler(&ticker_stub, NULL); - interface_stub.set_interrupt_call = 0; - - const timestamp_t timestamps[] = { - 0xA, - 0xAA, - 0xAAA, - 0xAAAA, - 0xAAAAA, - 0xAAAAAA, - 0xAAAAAAA, - 0xAAAAAAAA, - }; - ticker_event_t events[MBED_ARRAY_SIZE(timestamps)] = { 0 }; - - for (size_t i = 0; i < MBED_ARRAY_SIZE(events); ++i) { - ticker_insert_event( - &ticker_stub, - &events[i], timestamps[i], i - ); - - TEST_ASSERT_EQUAL_PTR(&events[0], queue_stub.head); - TEST_ASSERT_EQUAL_UINT32( - timestamps[0], interface_stub.interrupt_timestamp - ); - - TEST_ASSERT_EQUAL_UINT32(timestamps[i], events[i].timestamp); - TEST_ASSERT_EQUAL_UINT32(i, events[i].id); - - ticker_event_t *e = queue_stub.head; - while (e) { - TEST_ASSERT_EQUAL_UINT32(timestamps[e->id], e->timestamp); - if (e->next) { - TEST_ASSERT_TRUE(e->id < e->next->id); - TEST_ASSERT_TRUE(e->timestamp < e->next->timestamp); - } else { - TEST_ASSERT_EQUAL_UINT32(&events[i], e); - } - e = e->next; - } - } - - TEST_ASSERT_EQUAL(0, interface_stub.disable_interrupt_call); -} - -/** - * Given an initialized ticker. - * When an event is inserted with ticker_insert_event and a timestamp less - * than the current timestamp in the interface and less than the relative - * timestamp of the next event to execute. - * Then - * - The event inserted should be after the head - * - The interrupt timestamp should remains equal to the interrupt timestamp - * of the head event . - * - The timestamp of the event should reflect the timestamp requested (overflow) - * - The id of the event should be equal to the id passed in parameter. - * - Events in the queue should remained ordered by timestamp. - */ -static void test_legacy_insert_event_multiple_overflow() -{ - ticker_set_handler(&ticker_stub, NULL); - interface_stub.set_interrupt_call = 0; - - const timestamp_t timestamps[] = { - 0xA, - 0xAA, - 0xAAA, - 0xAAAA, - 0xAAAAA, - 0xAAAAAA, - 0xAAAAAAA, - 0xAAAAAAAA - }; - ticker_event_t events[MBED_ARRAY_SIZE(timestamps)] = { 0 }; - - ticker_event_t ref_event; - timestamp_t ref_event_timestamp = 0xCCCCCCCC; - ticker_insert_event( - &ticker_stub, - &ref_event, ref_event_timestamp, 0xDEADBEEF - ); - - timestamp_t last_timestamp_to_insert = - timestamps[MBED_ARRAY_SIZE(timestamps) - 1]; - interface_stub.timestamp = - last_timestamp_to_insert + - ((ref_event_timestamp - last_timestamp_to_insert) / 2); - ticker_irq_handler(&ticker_stub); - - for (size_t i = 0; i < MBED_ARRAY_SIZE(events); ++i) { - ticker_insert_event( - &ticker_stub, - &events[i], timestamps[i], i - ); - - TEST_ASSERT_EQUAL_PTR(&ref_event, queue_stub.head); - TEST_ASSERT_EQUAL_PTR(&events[0], queue_stub.head->next); - TEST_ASSERT_EQUAL_UINT32( - ref_event_timestamp, interface_stub.interrupt_timestamp - ); - - TEST_ASSERT_EQUAL_UINT32(timestamps[i], events[i].timestamp); - TEST_ASSERT_EQUAL_UINT32(i, events[i].id); - - ticker_event_t *e = queue_stub.head->next; - while (e) { - TEST_ASSERT_EQUAL_UINT32(timestamps[e->id], e->timestamp); - if (e->next) { - TEST_ASSERT_TRUE(e->id < e->next->id); - TEST_ASSERT_TRUE(e->timestamp < e->next->timestamp); - } else { - TEST_ASSERT_EQUAL_UINT32(&events[i], e); - } - e = e->next; - } - } - - TEST_ASSERT_EQUAL(0, interface_stub.disable_interrupt_call); -} - -/** - * Given an initialized ticker. - * When an event is inserted with ticker_insert_event. - * Then - * - The event inserted should be at the correct position in the queue - * - The event queue should remain ordered by timestamp - * - The interrupt timestamp should be equal to the interrupt timestamp - * of the head event or TIMESTAMP_MAX_DELTA if the - * timestamp is in the overflow range. - * - The timestamp of the event should reflect the timestamp requested (overflow) - * - The id of the event should be equal to the id passed in parameter. - * - Events in the queue should remained ordered by timestamp. - */ -static void test_legacy_insert_event_multiple_random() -{ - ticker_set_handler(&ticker_stub, NULL); - interface_stub.set_interrupt_call = 0; - - const timestamp_t ref_timestamp = UINT32_MAX / 2; - interface_stub.timestamp = ref_timestamp; - - // insert first event at the head of the queue - ticker_event_t first_event; - const timestamp_t first_event_timestamp = - ref_timestamp + TIMESTAMP_MAX_DELTA + 100; - - ticker_insert_event( - &ticker_stub, - &first_event, first_event_timestamp, (uint32_t) &first_event - ); - - TEST_ASSERT_EQUAL_PTR(&first_event, queue_stub.head); - TEST_ASSERT_EQUAL_PTR(NULL, first_event.next); - TEST_ASSERT_EQUAL_UINT32( - ref_timestamp + TIMESTAMP_MAX_DELTA, interface_stub.interrupt_timestamp - ); - TEST_ASSERT_EQUAL_UINT32(first_event_timestamp, first_event.timestamp); - TEST_ASSERT_EQUAL_UINT64( - first_event.timestamp, - first_event_timestamp + - ((first_event_timestamp < ref_timestamp) ? (1ULL << 32) : 0) - ); - TEST_ASSERT_EQUAL_UINT32((uint32_t) &first_event, first_event.id); - - // insert second event at the tail of the queue - ticker_event_t second_event; - const timestamp_t second_event_timestamp = first_event_timestamp + 1; - - ticker_insert_event( - &ticker_stub, - &second_event, second_event_timestamp, (uint32_t) &second_event - ); - - TEST_ASSERT_EQUAL_PTR(&first_event, queue_stub.head); - TEST_ASSERT_EQUAL_PTR(&second_event, first_event.next); - TEST_ASSERT_EQUAL_PTR(NULL, second_event.next); - TEST_ASSERT_EQUAL_UINT32( - ref_timestamp + TIMESTAMP_MAX_DELTA, interface_stub.interrupt_timestamp - ); - TEST_ASSERT_EQUAL_UINT32(second_event_timestamp, second_event.timestamp); - TEST_ASSERT_EQUAL_UINT64( - second_event.timestamp, - second_event_timestamp + - ((second_event_timestamp < ref_timestamp) ? (1ULL << 32) : 0) - ); - TEST_ASSERT_EQUAL_UINT32((uint32_t) &second_event, second_event.id); - - - // insert third event at the head of the queue out the overflow zone - ticker_event_t third_event; - const timestamp_t third_event_timestamp = - ref_timestamp + TIMESTAMP_MAX_DELTA - 100; - - ticker_insert_event( - &ticker_stub, - &third_event, third_event_timestamp, (uint32_t) &third_event - ); - - TEST_ASSERT_EQUAL_PTR(&third_event, queue_stub.head); - TEST_ASSERT_EQUAL_PTR(&first_event, third_event.next); - TEST_ASSERT_EQUAL_PTR(&second_event, first_event.next); - TEST_ASSERT_EQUAL_PTR(NULL, second_event.next); - TEST_ASSERT_EQUAL_UINT32( - third_event_timestamp, interface_stub.interrupt_timestamp - ); - TEST_ASSERT_EQUAL_UINT32(third_event_timestamp, third_event.timestamp); - TEST_ASSERT_EQUAL_UINT64( - third_event.timestamp, - third_event_timestamp + - ((third_event_timestamp < ref_timestamp) ? (1ULL << 32) : 0) - ); - TEST_ASSERT_EQUAL_UINT32((uint32_t) &third_event, third_event.id); - - // insert fourth event right after the third event - ticker_event_t fourth_event; - const timestamp_t fourth_event_timestamp = third_event_timestamp + 50; - - ticker_insert_event( - &ticker_stub, - &fourth_event, fourth_event_timestamp, (uint32_t) &fourth_event - ); - - TEST_ASSERT_EQUAL_PTR(&third_event, queue_stub.head); - TEST_ASSERT_EQUAL_PTR(&fourth_event, third_event.next); - TEST_ASSERT_EQUAL_PTR(&first_event, fourth_event.next); - TEST_ASSERT_EQUAL_PTR(&second_event, first_event.next); - TEST_ASSERT_EQUAL_PTR(NULL, second_event.next); - TEST_ASSERT_EQUAL_UINT32( - third_event_timestamp, interface_stub.interrupt_timestamp - ); - TEST_ASSERT_EQUAL_UINT32(fourth_event_timestamp, fourth_event.timestamp); - TEST_ASSERT_EQUAL_UINT64( - fourth_event.timestamp, - fourth_event_timestamp + - ((fourth_event_timestamp < ref_timestamp) ? (1ULL << 32) : 0) - ); - TEST_ASSERT_EQUAL_UINT32((uint32_t) &fourth_event, fourth_event.id); - - TEST_ASSERT_EQUAL(0, interface_stub.disable_interrupt_call); -} - -/** - * Given an initialized ticker without user registered events. - * When an event is inserted with ticker_insert_event_us and the timestamp passed - * in parameter is in range [ticker_timestamp : ticker_timestamp + - * TIMESTAMP_MAX_DELTA[. - * Then - * - The event should be in the queue - * - The interrupt timestamp should be equal to the lower 8 bytes of the event. - * - The timestamp of the event should be equal to the timestamp requested. - * - The id of the event should be equal to the id passed in parameter. - */ -static void test_insert_event_us_outside_overflow_range() -{ - ticker_set_handler(&ticker_stub, NULL); - interface_stub.set_interrupt_call = 0; - interface_stub.timestamp = 0xAAAAAAAA; - queue_stub.tick_last_read = interface_stub.timestamp; - queue_stub.present_time = 10ULL << 32 | interface_stub.timestamp; - - // test the end of the range - ticker_event_t last_event = { 0 }; - const us_timestamp_t timestamp_last_event = - queue_stub.present_time + TIMESTAMP_MAX_DELTA; - const uint32_t id_last_event = 0xDEADDEAF; - - ticker_insert_event_us( - &ticker_stub, - &last_event, timestamp_last_event, id_last_event - ); - - TEST_ASSERT_EQUAL_PTR(&last_event, queue_stub.head); - TEST_ASSERT_EQUAL(1, interface_stub.set_interrupt_call); - TEST_ASSERT_EQUAL_UINT32( - timestamp_last_event, interface_stub.interrupt_timestamp - ); - TEST_ASSERT_EQUAL_PTR(NULL, queue_stub.head->next); - TEST_ASSERT_EQUAL_UINT64(timestamp_last_event, last_event.timestamp); - TEST_ASSERT_EQUAL_UINT32(id_last_event, last_event.id); - - // test the beginning of the range - ticker_event_t first_event = { 0 }; - const us_timestamp_t timestamp_first_event = queue_stub.present_time + 1; - const uint32_t id_first_event = 0xAAAAAAAA; - - ticker_insert_event_us( - &ticker_stub, - &first_event, timestamp_first_event, id_first_event - ); - - TEST_ASSERT_EQUAL_PTR(&first_event, queue_stub.head); - TEST_ASSERT_EQUAL(2, interface_stub.set_interrupt_call); - TEST_ASSERT_EQUAL_UINT32( - timestamp_first_event, interface_stub.interrupt_timestamp - ); - TEST_ASSERT_EQUAL_PTR(&last_event, queue_stub.head->next); - TEST_ASSERT_EQUAL_UINT64( - timestamp_first_event, first_event.timestamp - ); - TEST_ASSERT_EQUAL_UINT32(id_first_event, first_event.id); - - TEST_ASSERT_EQUAL(0, interface_stub.disable_interrupt_call); -} - -/** - * Given an initialized ticker without user registered events. - * When an event is inserted with ticker_insert_event_us and a timestamp in the - * range [ticker_timestamp + TIMESTAMP_MAX_DELTA + 1 : UINT64_MAX [ - * Then - * - The event should be in the queue - * - The interrupt timestamp should be equal to TIMESTAMP_MAX_DELTA - * - The timestamp of the event should be equal to the timestamp in parameter. - * - The id of the event should be equal to the id passed in parameter. - */ -static void test_insert_event_us_in_overflow_range() -{ - ticker_set_handler(&ticker_stub, NULL); - interface_stub.set_interrupt_call = 0; - interface_stub.timestamp = 0xAAAAAAAA; - queue_stub.tick_last_read = interface_stub.timestamp; - queue_stub.present_time = 10ULL << 32 | interface_stub.timestamp; - - // test the end of the range - ticker_event_t last_event = { 0 }; - const us_timestamp_t timestamp_last_event = UINT64_MAX; - const uint32_t id_last_event = 0xDEADDEAF; - - ticker_insert_event_us( - &ticker_stub, - &last_event, timestamp_last_event, id_last_event - ); - - TEST_ASSERT_EQUAL_PTR(&last_event, queue_stub.head); - TEST_ASSERT_EQUAL(1, interface_stub.set_interrupt_call); - TEST_ASSERT_EQUAL_UINT32( - interface_stub.timestamp + TIMESTAMP_MAX_DELTA, - interface_stub.interrupt_timestamp - ); - TEST_ASSERT_EQUAL_PTR(NULL, queue_stub.head->next); - TEST_ASSERT_EQUAL_UINT64(timestamp_last_event, last_event.timestamp); - TEST_ASSERT_EQUAL_UINT32(id_last_event, last_event.id); - - // test the beginning of the range - ++interface_stub.timestamp; - ++queue_stub.present_time; - - ticker_event_t first_event = { 0 }; - const us_timestamp_t timestamp_first_event = - queue_stub.present_time + TIMESTAMP_MAX_DELTA + 1; - uint32_t id_first_event = 0xAAAAAAAA; - - ticker_insert_event_us(&ticker_stub, - &first_event, timestamp_first_event, id_first_event - ); - - TEST_ASSERT_EQUAL_PTR(&first_event, queue_stub.head); - TEST_ASSERT_EQUAL(2, interface_stub.set_interrupt_call); - TEST_ASSERT_EQUAL_UINT32( - interface_stub.timestamp + TIMESTAMP_MAX_DELTA, - interface_stub.interrupt_timestamp - ); - TEST_ASSERT_EQUAL_PTR(&last_event, queue_stub.head->next); - TEST_ASSERT_EQUAL_UINT64(timestamp_first_event, first_event.timestamp); - TEST_ASSERT_EQUAL_UINT32(id_first_event, first_event.id); - - TEST_ASSERT_EQUAL(0, interface_stub.disable_interrupt_call); -} - -/** - * Given an initialized ticker without user registered events. - * When an event is inserted with ticker_insert_event_us and a timestamp less - * than timestamp value in the ticker interface. - * Then - * - The event should be in the queue - * - The interrupt timestamp should be set to interface_stub.timestamp so it - * is scheduled immediately. - */ -static void test_insert_event_us_underflow() -{ - ticker_set_handler(&ticker_stub, NULL); - interface_stub.set_interrupt_call = 0; - - interface_stub.timestamp = 0xAAAAAAAA; - queue_stub.tick_last_read = interface_stub.timestamp; - queue_stub.present_time = 10ULL << 32 | interface_stub.timestamp; - - // test the end of the range - ticker_event_t event = { 0 }; - const timestamp_t expected_timestamp = queue_stub.present_time - 1; - const uint32_t expected_id = 0xDEADDEAF; - - ticker_insert_event_us( - &ticker_stub, - &event, expected_timestamp, expected_id - ); - - TEST_ASSERT_EQUAL_PTR(&event, queue_stub.head); - TEST_ASSERT_EQUAL(1, interface_stub.fire_interrupt_call); - - TEST_ASSERT_EQUAL(0, interface_stub.disable_interrupt_call); -} - -/** - * Given an initialized ticker. - * When an event is inserted with ticker_insert_event_us and a timestamp less - * than the one for the next scheduled timestamp. - * Then - * - The event inserted should be the first in the queue - * - The interrupt timestamp should be equal to the timestamp of the event or - * TIMESTAMP_MAX_DELTA if in the overflow range. - * - The timestamp of the event should be equal to the timestamp in parameter. - * - The id of the event should be equal to the id passed in parameter. - * - Events in the queue should remained ordered by timestamp. - */ -static void test_insert_event_us_head() -{ - ticker_set_handler(&ticker_stub, NULL); - interface_stub.set_interrupt_call = 0; - interface_stub.timestamp = 0xAAAAAAAA; - queue_stub.tick_last_read = interface_stub.timestamp; - queue_stub.present_time = 10ULL << 32 | interface_stub.timestamp; - - const us_timestamp_t timestamps[] = { - UINT64_MAX, - queue_stub.present_time + TIMESTAMP_MAX_DELTA + 1, - queue_stub.present_time + TIMESTAMP_MAX_DELTA, - queue_stub.present_time + (TIMESTAMP_MAX_DELTA / 2), - queue_stub.present_time + (TIMESTAMP_MAX_DELTA / 4), - queue_stub.present_time + (TIMESTAMP_MAX_DELTA / 8), - queue_stub.present_time + (TIMESTAMP_MAX_DELTA / 16), - }; - ticker_event_t events[MBED_ARRAY_SIZE(timestamps)] = { 0 }; - - for (size_t i = 0; i < MBED_ARRAY_SIZE(events); ++i) { - ticker_insert_event_us( - &ticker_stub, - &events[i], timestamps[i], i - ); - - TEST_ASSERT_EQUAL_PTR(&events[i], queue_stub.head); - if ((timestamps[i] - queue_stub.present_time) < TIMESTAMP_MAX_DELTA) { - TEST_ASSERT_EQUAL_UINT32( - timestamps[i], - interface_stub.interrupt_timestamp - ); - } else { - TEST_ASSERT_EQUAL_UINT32( - queue_stub.present_time + TIMESTAMP_MAX_DELTA, - interface_stub.interrupt_timestamp - ); - } - - TEST_ASSERT_EQUAL_UINT64(timestamps[i], events[i].timestamp); - TEST_ASSERT_EQUAL_UINT32(i, events[i].id); - - ticker_event_t *e = &events[i]; - while (e) { - TEST_ASSERT_EQUAL_UINT32(timestamps[e->id], e->timestamp); - if (e->next) { - TEST_ASSERT_TRUE(e->id > e->next->id); - TEST_ASSERT_TRUE(e->timestamp < e->next->timestamp); - } else { - TEST_ASSERT_EQUAL_UINT32(0, e->id); - } - e = e->next; - } - } - - TEST_ASSERT_EQUAL(0, interface_stub.disable_interrupt_call); -} - -/** - * Given an initialized ticker. - * When an event is inserted with ticker_insert_event_us and its timestamp is - * bigger than the one of the last event in the queue. - * Then - * - The event inserted should be the last in the queue - * - The interrupt timestamp should remains equal to the interrupt timestamp - * of the head event . - * - The timestamp of the event should reflect the timestamp requested. - * - The id of the event should be equal to the id passed in parameter. - * - Events in the queue should remained ordered by timestamp. - */ -static void test_insert_event_us_tail() -{ - ticker_set_handler(&ticker_stub, NULL); - interface_stub.set_interrupt_call = 0; - - const us_timestamp_t timestamps[] = { - 0xA, - (1ULL << 32), - (2ULL << 32), - (4ULL << 32), - (8ULL << 32), - (16ULL << 32), - (32ULL << 32), - (64ULL << 32), - }; - ticker_event_t events[MBED_ARRAY_SIZE(timestamps)] = { 0 }; - - for (size_t i = 0; i < MBED_ARRAY_SIZE(events); ++i) { - ticker_insert_event_us( - &ticker_stub, - &events[i], timestamps[i], i - ); - - TEST_ASSERT_EQUAL_PTR(&events[0], queue_stub.head); - TEST_ASSERT_EQUAL_UINT32( - timestamps[0], interface_stub.interrupt_timestamp - ); - TEST_ASSERT_EQUAL_UINT64(timestamps[i], events[i].timestamp); - TEST_ASSERT_EQUAL_UINT32(i, events[i].id); - - ticker_event_t *e = queue_stub.head; - while (e) { - TEST_ASSERT_EQUAL_UINT32(timestamps[e->id], e->timestamp); - if (e->next) { - TEST_ASSERT_TRUE(e->id < e->next->id); - TEST_ASSERT_TRUE(e->timestamp < e->next->timestamp); - } else { - TEST_ASSERT_EQUAL_UINT32(&events[i], e); - } - e = e->next; - } - } - - TEST_ASSERT_EQUAL(0, interface_stub.disable_interrupt_call); -} - -/** - * Given an initialized ticker. - * When an event is inserted with ticker_insert_event_us. - * Then - * - The event inserted should be at the correct position in the queue - * - The event queue should remain ordered by timestamp - * - The interrupt timestamp should be equal to the interrupt timestamp - * of the head event or TIMESTAMP_MAX_DELTA if the - * timestamp is in the overflow range. - * - The timestamp of the event should be equal to the timestamp parameter. - * - The id of the event should be equal to the id passed in parameter. - * - Events in the queue should remained ordered by timestamp. - */ -static void test_insert_event_us_multiple_random() -{ - ticker_set_handler(&ticker_stub, NULL); - interface_stub.set_interrupt_call = 0; - - const timestamp_t ref_timestamp = UINT32_MAX / 2; - interface_stub.timestamp = ref_timestamp; - - // insert first event at the head of the queue - ticker_event_t first_event; - const us_timestamp_t first_event_timestamp = - ref_timestamp + TIMESTAMP_MAX_DELTA + 100; - - ticker_insert_event_us( - &ticker_stub, - &first_event, first_event_timestamp, (uint32_t) &first_event - ); - - TEST_ASSERT_EQUAL_PTR(&first_event, queue_stub.head); - TEST_ASSERT_EQUAL_PTR(NULL, first_event.next); - TEST_ASSERT_EQUAL_UINT32( - ref_timestamp + TIMESTAMP_MAX_DELTA, interface_stub.interrupt_timestamp - ); - TEST_ASSERT_EQUAL_UINT64(first_event.timestamp, first_event_timestamp); - TEST_ASSERT_EQUAL_UINT32((uint32_t) &first_event, first_event.id); - - // insert second event at the tail of the queue - ticker_event_t second_event; - const us_timestamp_t second_event_timestamp = first_event_timestamp + 1; - - ticker_insert_event_us( - &ticker_stub, - &second_event, second_event_timestamp, (uint32_t) &second_event - ); - - TEST_ASSERT_EQUAL_PTR(&first_event, queue_stub.head); - TEST_ASSERT_EQUAL_PTR(&second_event, first_event.next); - TEST_ASSERT_EQUAL_PTR(NULL, second_event.next); - TEST_ASSERT_EQUAL_UINT32( - ref_timestamp + TIMESTAMP_MAX_DELTA, interface_stub.interrupt_timestamp - ); - TEST_ASSERT_EQUAL_UINT64(second_event_timestamp, second_event.timestamp); - TEST_ASSERT_EQUAL_UINT32((uint32_t) &second_event, second_event.id); - - - // insert third event at the head of the queue out the overflow zone - ticker_event_t third_event; - const us_timestamp_t third_event_timestamp = - ref_timestamp + TIMESTAMP_MAX_DELTA - 100; - - ticker_insert_event_us( - &ticker_stub, - &third_event, third_event_timestamp, (uint32_t) &third_event - ); - - TEST_ASSERT_EQUAL_PTR(&third_event, queue_stub.head); - TEST_ASSERT_EQUAL_PTR(&first_event, third_event.next); - TEST_ASSERT_EQUAL_PTR(&second_event, first_event.next); - TEST_ASSERT_EQUAL_PTR(NULL, second_event.next); - TEST_ASSERT_EQUAL_UINT32( - third_event_timestamp, interface_stub.interrupt_timestamp - ); - TEST_ASSERT_EQUAL_UINT64(third_event_timestamp, third_event.timestamp); - TEST_ASSERT_EQUAL_UINT32((uint32_t) &third_event, third_event.id); - - // insert fourth event right after the third event - ticker_event_t fourth_event; - const us_timestamp_t fourth_event_timestamp = third_event_timestamp + 50; - - ticker_insert_event_us( - &ticker_stub, - &fourth_event, fourth_event_timestamp, (uint32_t) &fourth_event - ); - - TEST_ASSERT_EQUAL_PTR(&third_event, queue_stub.head); - TEST_ASSERT_EQUAL_PTR(&fourth_event, third_event.next); - TEST_ASSERT_EQUAL_PTR(&first_event, fourth_event.next); - TEST_ASSERT_EQUAL_PTR(&second_event, first_event.next); - TEST_ASSERT_EQUAL_PTR(NULL, second_event.next); - TEST_ASSERT_EQUAL_UINT32( - third_event_timestamp, interface_stub.interrupt_timestamp - ); - TEST_ASSERT_EQUAL_UINT64(fourth_event_timestamp, fourth_event.timestamp); - TEST_ASSERT_EQUAL_UINT32((uint32_t) &fourth_event, fourth_event.id); - - TEST_ASSERT_EQUAL(0, interface_stub.disable_interrupt_call); -} - -/** - * Given an initialized ticker with multiple events registered. - * When the event at the tail of the queue is removed from the queue. - * Then: - * - The event should not be in the queue. - * - The events in the queue should remain ordered - * - The interrupt timestamp should be unchanged. - */ -static void test_remove_event_tail() -{ - ticker_set_handler(&ticker_stub, NULL); - const us_timestamp_t timestamps[] = { - 0xA, - (1ULL << 32), - (2ULL << 32), - (4ULL << 32), - (8ULL << 32), - (16ULL << 32), - (32ULL << 32), - (64ULL << 32), - }; - ticker_event_t events[MBED_ARRAY_SIZE(timestamps)] = { 0 }; - - for (size_t i = 0; i < MBED_ARRAY_SIZE(events); ++i) { - ticker_insert_event_us( - &ticker_stub, - &events[i], timestamps[i], i - ); - } - - for (ssize_t i = MBED_ARRAY_SIZE(events) - 1; i >= 0; --i) { - ticker_remove_event(&ticker_stub, &events[i]); - - ticker_event_t *e = queue_stub.head; - size_t event_count = 0; - while (e) { - TEST_ASSERT_NOT_EQUAL(e, &events[i]); - if (e->next) { - TEST_ASSERT_TRUE(e->timestamp <= e->next->timestamp); - } - e = e->next; - ++event_count; - } - - TEST_ASSERT_EQUAL(i, event_count); - - if (i != 0) { - TEST_ASSERT_EQUAL( - timestamps[0], - interface_stub.interrupt_timestamp - ); - } else { - TEST_ASSERT_EQUAL( - interface_stub.timestamp + TIMESTAMP_MAX_DELTA, - interface_stub.interrupt_timestamp - ); - } - } - - TEST_ASSERT_EQUAL(0, interface_stub.disable_interrupt_call); -} - -/** - * Given an initialized ticker with multiple events registered. - * When the event at the head of the queue is removed from the queue. - * Then: - * - The event should not be in the queue. - * - The event at the head of the queue should be the equal to the one - * after the event removed. - * - The interrupt timestamp should be equal to the interrupt timestamp - * of the head event or TIMESTAMP_MAX_DELTA if the - * timestamp is in the overflow range. - */ -static void test_remove_event_head() -{ - ticker_set_handler(&ticker_stub, NULL); - const us_timestamp_t timestamps[] = { - TIMESTAMP_MAX_DELTA / 8, - TIMESTAMP_MAX_DELTA / 4, - TIMESTAMP_MAX_DELTA / 2, - TIMESTAMP_MAX_DELTA - 1, - TIMESTAMP_MAX_DELTA, - TIMESTAMP_MAX_DELTA + 1, - (1ULL << 32) | TIMESTAMP_MAX_DELTA, - UINT64_MAX - }; - ticker_event_t events[MBED_ARRAY_SIZE(timestamps)] = { 0 }; - - for (size_t i = 0; i < MBED_ARRAY_SIZE(events); ++i) { - ticker_insert_event_us(&ticker_stub, - &events[i], timestamps[i], i - ); - } - - for (size_t i = 0; i < MBED_ARRAY_SIZE(events); ++i) { - ticker_remove_event(&ticker_stub, &events[i]); - - ticker_event_t *e = queue_stub.head; - size_t event_count = 0; - while (e) { - TEST_ASSERT_NOT_EQUAL(e, &events[i]); - if (e->next) { - TEST_ASSERT_TRUE(e->timestamp <= e->next->timestamp); - } - e = e->next; - ++event_count; - } - - TEST_ASSERT_EQUAL(MBED_ARRAY_SIZE(events) - i - 1, event_count); - - if (event_count) { - TEST_ASSERT_EQUAL( - std::min( - timestamps[i + 1], - interface_stub.timestamp + TIMESTAMP_MAX_DELTA - ), - interface_stub.interrupt_timestamp - ); - } else { - TEST_ASSERT_EQUAL( - interface_stub.timestamp + TIMESTAMP_MAX_DELTA, - interface_stub.interrupt_timestamp - ); - } - - } - - TEST_ASSERT_EQUAL(0, interface_stub.disable_interrupt_call); -} - -/** - * Given an initialized ticker with multiple events registered. - * When an event not in the queue is attempted to be removed. - * Then the queue should remains identical as before. - */ -static void test_remove_event_invalid() -{ - ticker_set_handler(&ticker_stub, NULL); - const us_timestamp_t timestamps[] = { - TIMESTAMP_MAX_DELTA / 8, - TIMESTAMP_MAX_DELTA / 4, - TIMESTAMP_MAX_DELTA / 2, - TIMESTAMP_MAX_DELTA - 1, - TIMESTAMP_MAX_DELTA, - TIMESTAMP_MAX_DELTA + 1, - (1ULL << 32) | TIMESTAMP_MAX_DELTA, - UINT64_MAX - }; - ticker_event_t events[MBED_ARRAY_SIZE(timestamps)] = { 0 }; - - for (size_t i = 0; i < MBED_ARRAY_SIZE(events); ++i) { - ticker_insert_event_us( - &ticker_stub, - &events[i], timestamps[i], i - ); - } - - ticker_event_t invalid_event; - ticker_remove_event(&ticker_stub, &invalid_event); - - TEST_ASSERT_EQUAL(&events[0], queue_stub.head); - - ticker_event_t *e = queue_stub.head; - size_t event_count = 0; - while (e) { - TEST_ASSERT_EQUAL(e, &events[event_count]); - e = e->next; - ++event_count; - } - TEST_ASSERT_EQUAL(MBED_ARRAY_SIZE(events), event_count); -} - -/** - * Given an initialized ticker with multiple events inserted. - * When an event is remoced - * Then: - * - the event should not be in the queue - * - the queue should remain ordered - * - the interrupt timestamp should be set to either head->timestamp or - * TIMESTAMP_MAX_DELTA depending on the distance between the current time - * ans the timestamp of the event at the head of the queue. - */ -static void test_remove_random() -{ - ticker_set_handler(&ticker_stub, NULL); - interface_stub.set_interrupt_call = 0; - - const timestamp_t ref_timestamp = UINT32_MAX / 2; - interface_stub.timestamp = ref_timestamp; - - // insert all events - ticker_event_t first_event; - const us_timestamp_t first_event_timestamp = - ref_timestamp + TIMESTAMP_MAX_DELTA + 100; - - ticker_insert_event_us( - &ticker_stub, - &first_event, first_event_timestamp, (uint32_t) &first_event - ); - - - ticker_event_t second_event; - const us_timestamp_t second_event_timestamp = first_event_timestamp + 1; - - ticker_insert_event_us( - &ticker_stub, - &second_event, second_event_timestamp, (uint32_t) &second_event - ); - - ticker_event_t third_event; - const us_timestamp_t third_event_timestamp = - ref_timestamp + TIMESTAMP_MAX_DELTA - 100; - - ticker_insert_event_us( - &ticker_stub, - &third_event, third_event_timestamp, (uint32_t) &third_event - ); - - ticker_event_t fourth_event; - const us_timestamp_t fourth_event_timestamp = third_event_timestamp + 50; - - ticker_insert_event_us( - &ticker_stub, - &fourth_event, fourth_event_timestamp, (uint32_t) &fourth_event - ); - - // test that the queue is in the correct state - TEST_ASSERT_EQUAL_PTR(&third_event, queue_stub.head); - TEST_ASSERT_EQUAL_PTR(&fourth_event, third_event.next); - TEST_ASSERT_EQUAL_PTR(&first_event, fourth_event.next); - TEST_ASSERT_EQUAL_PTR(&second_event, first_event.next); - TEST_ASSERT_EQUAL_PTR(NULL, second_event.next); - TEST_ASSERT_EQUAL_UINT32( - third_event_timestamp, interface_stub.interrupt_timestamp - ); - TEST_ASSERT_EQUAL_UINT64(fourth_event_timestamp, fourth_event.timestamp); - TEST_ASSERT_EQUAL_UINT32((uint32_t) &fourth_event, fourth_event.id); - - // remove fourth event - ticker_remove_event(&ticker_stub, &fourth_event); - - TEST_ASSERT_EQUAL_PTR(&third_event, queue_stub.head); - TEST_ASSERT_EQUAL_PTR(&first_event, third_event.next); - TEST_ASSERT_EQUAL_PTR(&second_event, first_event.next); - TEST_ASSERT_EQUAL_PTR(NULL, second_event.next); - TEST_ASSERT_EQUAL_UINT32( - third_event_timestamp, interface_stub.interrupt_timestamp - ); - TEST_ASSERT_EQUAL_UINT64(third_event_timestamp, third_event.timestamp); - TEST_ASSERT_EQUAL_UINT32((uint32_t) &third_event, third_event.id); - - // remove third event - ticker_remove_event(&ticker_stub, &third_event); - - TEST_ASSERT_EQUAL_PTR(&first_event, queue_stub.head); - TEST_ASSERT_EQUAL_PTR(&second_event, first_event.next); - TEST_ASSERT_EQUAL_PTR(NULL, second_event.next); - TEST_ASSERT_EQUAL_UINT32( - ref_timestamp + TIMESTAMP_MAX_DELTA, interface_stub.interrupt_timestamp - ); - TEST_ASSERT_EQUAL_UINT64(second_event_timestamp, second_event.timestamp); - TEST_ASSERT_EQUAL_UINT32((uint32_t) &second_event, second_event.id); - - // remove second event - ticker_remove_event(&ticker_stub, &second_event); - - TEST_ASSERT_EQUAL_PTR(&first_event, queue_stub.head); - TEST_ASSERT_EQUAL_PTR(NULL, first_event.next); - TEST_ASSERT_EQUAL_UINT32( - ref_timestamp + TIMESTAMP_MAX_DELTA, interface_stub.interrupt_timestamp - ); - TEST_ASSERT_EQUAL_UINT64(first_event.timestamp, first_event_timestamp); - TEST_ASSERT_EQUAL_UINT32((uint32_t) &first_event, first_event.id); - - // remove first event - ticker_remove_event(&ticker_stub, &first_event); - - TEST_ASSERT_EQUAL_PTR(NULL, queue_stub.head); - TEST_ASSERT_EQUAL_PTR(NULL, first_event.next); - TEST_ASSERT_EQUAL_UINT32( - ref_timestamp + TIMESTAMP_MAX_DELTA, interface_stub.interrupt_timestamp - ); - - TEST_ASSERT_EQUAL(0, interface_stub.disable_interrupt_call); -} - -/** - * Given an initialized ticker without user registered events and a ticker - * interface timestamp equal or bigger than the one registered by the overflow - * event. - * When the interrupt handler is called. - * Then: - * - The interrupt timestamp should be updated to the timestamp of the ticker - * interface plus TIMESTAMP_MAX_DELTA. - * - The irq handler registered should not be called. - */ -static void test_overflow_event_update() -{ - static uint32_t handler_call = 0; - struct irq_handler_stub_t { - static void event_handler(uint32_t id) - { - ++handler_call; - } - }; - handler_call = 0; - - ticker_set_handler(&ticker_stub, irq_handler_stub_t::event_handler); - interface_stub.set_interrupt_call = 0; - - for (size_t i = 0; i < 8; ++i) { - us_timestamp_t previous_timestamp = queue_stub.present_time; - timestamp_t interface_timestamp = - previous_timestamp + (TIMESTAMP_MAX_DELTA + i * 100); - interface_stub.timestamp = interface_timestamp; - - ticker_irq_handler(&ticker_stub); - TEST_ASSERT_EQUAL(i + 1, interface_stub.clear_interrupt_call); - - TEST_ASSERT_EQUAL(i + 1, interface_stub.set_interrupt_call); - TEST_ASSERT_EQUAL_UINT32( - interface_timestamp + TIMESTAMP_MAX_DELTA, - interface_stub.interrupt_timestamp - ); - TEST_ASSERT_EQUAL(0, handler_call); - } - - TEST_ASSERT_EQUAL(0, interface_stub.disable_interrupt_call); -} - -/** - * Given an initialized ticker without user registered events and a ticker - * interface timestamp less than the one registered to handle overflow. - * When the interrupt handler is called. - * Then: - * - The interrupt timestamp should be updated to the timestamp of the ticker - * interface plus TIMESTAMP_MAX_DELTA. - * - The irq handler registered should not be called. - */ -static void test_overflow_event_update_when_spurious_interrupt() -{ - static uint32_t handler_call = 0; - struct irq_handler_stub_t { - static void event_handler(uint32_t id) - { - ++handler_call; - } - }; - handler_call = 0; - - ticker_set_handler(&ticker_stub, irq_handler_stub_t::event_handler); - interface_stub.set_interrupt_call = 0; - - for (size_t i = 0; i < 8; ++i) { - us_timestamp_t previous_timestamp = queue_stub.present_time; - timestamp_t interface_timestamp = - previous_timestamp + (TIMESTAMP_MAX_DELTA / (2 + i)); - interface_stub.timestamp = interface_timestamp; - - ticker_irq_handler(&ticker_stub); - - TEST_ASSERT_EQUAL(i + 1, interface_stub.clear_interrupt_call); - TEST_ASSERT_EQUAL(i + 1, interface_stub.set_interrupt_call); - TEST_ASSERT_EQUAL_UINT32( - interface_timestamp + TIMESTAMP_MAX_DELTA, - interface_stub.interrupt_timestamp - ); - TEST_ASSERT_EQUAL(0, handler_call); - } - - TEST_ASSERT_EQUAL(0, interface_stub.disable_interrupt_call); -} - -/** - * Given an initialized ticker with a single ticker event inserted and a ticker - * interface timestamp bigger than the one set for interrupt. - * When ticker_irq_handler is called. - * Then: - * - The IRQ handler should be called with the id of the event at the head of - * the queue. - * - The event at the head of the queue should be replaced by the next event. - * - The interrupt timestamp in the ticker interface should be set to the - * value of the interface timestamp + TIMESTAMP_MAX_DELTA - */ -static void test_irq_handler_single_event() -{ - static const timestamp_t event_timestamp = 0xAAAAAAAA; - static const timestamp_t interface_timestamp_after_irq = event_timestamp + 100; - - uint32_t handler_call = 0; - struct irq_handler_stub_t { - static void event_handler(uint32_t id) - { - ++ (*((uint32_t *) id)); - interface_stub.timestamp = interface_timestamp_after_irq; - } - }; - - ticker_set_handler(&ticker_stub, irq_handler_stub_t::event_handler); - interface_stub.set_interrupt_call = 0; - - ticker_event_t e; - ticker_insert_event(&ticker_stub, &e, event_timestamp, (uint32_t) &handler_call); - - interface_stub.timestamp = event_timestamp; - interface_stub.set_interrupt_call = 0; - - ticker_irq_handler(&ticker_stub); - - TEST_ASSERT_EQUAL(1, interface_stub.clear_interrupt_call); - TEST_ASSERT_EQUAL(1, interface_stub.set_interrupt_call); - TEST_ASSERT_EQUAL(1, handler_call); - TEST_ASSERT_EQUAL_UINT32( - interface_timestamp_after_irq + TIMESTAMP_MAX_DELTA, - interface_stub.interrupt_timestamp - ); - - TEST_ASSERT_NULL(queue_stub.head); - - TEST_ASSERT_EQUAL(0, interface_stub.disable_interrupt_call); -} - -/** - * Given an initialized ticker with at least a ticker event inserted and a ticker - * interface timestamp less than the one set for interrupt. - * When ticker_irq_handler is called. - * Then: - * - The IRQ handler should not be called. - * - The event at the head of the queue should remains the same. - * - The interrupt timestamp in the ticker interface should be set to the - * value of the event timestamp - */ -static void test_irq_handler_single_event_spurious() -{ - struct irq_handler_stub_t { - static void event_handler(uint32_t id) - { - TEST_FAIL(); - } - }; - - ticker_set_handler(&ticker_stub, irq_handler_stub_t::event_handler); - interface_stub.set_interrupt_call = 0; - - const us_timestamp_t timestamps [] = { - UINT32_MAX, - TIMESTAMP_MAX_DELTA + 1, - TIMESTAMP_MAX_DELTA, - TIMESTAMP_MAX_DELTA - 1 - }; - - ticker_event_t events[MBED_ARRAY_SIZE(timestamps)] = { 0 }; - - for (size_t i = 0; i < MBED_ARRAY_SIZE(events); ++i) { - ticker_insert_event_us( - &ticker_stub, - &events[i], timestamps[i], timestamps[i] - ); - interface_stub.set_interrupt_call = 0; - interface_stub.clear_interrupt_call = 0; - - ticker_irq_handler(&ticker_stub); - - TEST_ASSERT_EQUAL(1, interface_stub.clear_interrupt_call); - TEST_ASSERT_EQUAL(1, interface_stub.set_interrupt_call); - TEST_ASSERT_EQUAL_UINT32( - std::min(timestamps[i], TIMESTAMP_MAX_DELTA), - interface_stub.interrupt_timestamp - ); - } - - TEST_ASSERT_EQUAL(0, interface_stub.disable_interrupt_call); -} - -/** - * Given an initialized ticker with multiple ticker event inserted, its - * interface timestamp at greater than the timestamp of the next schedule event - * and all event execution time taking at least the time befor ethe next event. - * When ticker_irq_handler is called. - * Then: - * - The IRQ handler should have been called for every event. - * - The head of the queue should be set to NULL. - * - The interrupt timestamp in the ticker interface should be scheduled in - * TIMESTAMP_MAX_DELTAs - */ -static void test_irq_handler_multiple_event_multiple_dequeue() -{ - const us_timestamp_t timestamps [] = { - 10, - 10 + TIMESTAMP_MAX_DELTA - 1, - 10 + TIMESTAMP_MAX_DELTA, - 10 + TIMESTAMP_MAX_DELTA + 1, - UINT32_MAX - }; - - static size_t handler_called = 0; - struct irq_handler_stub_t { - static void event_handler(uint32_t id) - { - ++handler_called; - ticker_event_t *e = (ticker_event_t *) id; - if (e->next) { - interface_stub.timestamp = e->next->timestamp; - } - } - }; - handler_called = 0; - - ticker_set_handler(&ticker_stub, irq_handler_stub_t::event_handler); - interface_stub.set_interrupt_call = 0; - - ticker_event_t events[MBED_ARRAY_SIZE(timestamps)] = { 0 }; - - for (size_t i = 0; i < MBED_ARRAY_SIZE(events); ++i) { - ticker_insert_event_us( - &ticker_stub, - &events[i], timestamps[i], (uint32_t) &events[i] - ); - } - - interface_stub.set_interrupt_call = 0; - interface_stub.clear_interrupt_call = 0; - interface_stub.timestamp = timestamps[0]; - - ticker_irq_handler(&ticker_stub); - - TEST_ASSERT_EQUAL(1, interface_stub.clear_interrupt_call); - TEST_ASSERT_EQUAL(1, interface_stub.set_interrupt_call); - TEST_ASSERT_EQUAL_UINT32(MBED_ARRAY_SIZE(timestamps), handler_called); - TEST_ASSERT_EQUAL_UINT32( - timestamps[MBED_ARRAY_SIZE(timestamps) - 1] + TIMESTAMP_MAX_DELTA, - interface_stub.interrupt_timestamp - ); - TEST_ASSERT_NULL(queue_stub.head); - - TEST_ASSERT_EQUAL(0, interface_stub.disable_interrupt_call); -} - -/** - * Given an initialized ticker with two ticker event inserted scheduled from more - * than TIMESTAMP_MAX_DELTA from one another. The interface - * timestamp is equal to the timestamp of the first event. - * When ticker_irq_handler is called. - * Then: - * - The IRQ handler should have been called for the first event. - * - The head of the queue should be set to the event after the first event. - * - The interrupt timestamp in the ticker interface should be scheduled in - * TIMESTAMP_MAX_DELTA. - */ -static void test_irq_handler_multiple_event_single_dequeue_overflow() -{ - const us_timestamp_t timestamps [] = { - 10, - 10 + TIMESTAMP_MAX_DELTA + 1 - }; - - size_t handler_called = 0; - struct irq_handler_stub_t { - static void event_handler(uint32_t id) - { - ++ (*((size_t *) id)); - } - }; - - ticker_set_handler(&ticker_stub, irq_handler_stub_t::event_handler); - interface_stub.set_interrupt_call = 0; - - ticker_event_t events[MBED_ARRAY_SIZE(timestamps)] = { 0 }; - - for (size_t i = 0; i < MBED_ARRAY_SIZE(events); ++i) { - ticker_insert_event_us( - &ticker_stub, - &events[i], timestamps[i], (uint32_t) &handler_called - ); - } - - interface_stub.set_interrupt_call = 0; - interface_stub.clear_interrupt_call = 0; - interface_stub.timestamp = timestamps[0]; - - ticker_irq_handler(&ticker_stub); - - TEST_ASSERT_EQUAL(1, interface_stub.clear_interrupt_call); - TEST_ASSERT_EQUAL(1, interface_stub.set_interrupt_call); - TEST_ASSERT_EQUAL_UINT32(1, handler_called); - TEST_ASSERT_EQUAL_UINT32( - timestamps[0] + TIMESTAMP_MAX_DELTA, - interface_stub.interrupt_timestamp - ); - TEST_ASSERT_EQUAL_PTR(&events[1], queue_stub.head); - - TEST_ASSERT_EQUAL(0, interface_stub.disable_interrupt_call); -} - -/** - * Given an initialized ticker with two ticker event inserted scheduled from less - * than TIMESTAMP_MAX_DELTA from one another. The interface - * timestamp is equal to the timestamp of the first event. - * When ticker_irq_handler is called. - * Then: - * - The IRQ handler should have been called for the first event. - * - The head of the queue should be set to second event. - * - The interrupt timestamp in the ticker interface should be equal to the - * timestamp of the second event. - */ -static void test_irq_handler_multiple_event_single_dequeue() -{ - const us_timestamp_t timestamps [] = { - 10, - 10 + TIMESTAMP_MAX_DELTA - 1 - }; - - size_t handler_called = 0; - struct irq_handler_stub_t { - static void event_handler(uint32_t id) - { - ++ (*((size_t *) id)); - } - }; - - ticker_set_handler(&ticker_stub, irq_handler_stub_t::event_handler); - interface_stub.set_interrupt_call = 0; - - ticker_event_t events[MBED_ARRAY_SIZE(timestamps)] = { 0 }; - - for (size_t i = 0; i < MBED_ARRAY_SIZE(events); ++i) { - ticker_insert_event_us( - &ticker_stub, - &events[i], timestamps[i], (uint32_t) &handler_called - ); - } - - interface_stub.set_interrupt_call = 0; - interface_stub.clear_interrupt_call = 0; - interface_stub.timestamp = timestamps[0]; - - ticker_irq_handler(&ticker_stub); - - TEST_ASSERT_EQUAL(1, interface_stub.clear_interrupt_call); - TEST_ASSERT_EQUAL(1, interface_stub.set_interrupt_call); - TEST_ASSERT_EQUAL_UINT32(1, handler_called); - TEST_ASSERT_EQUAL_UINT32( - timestamps[1], - interface_stub.interrupt_timestamp - ); - TEST_ASSERT_EQUAL_PTR(&events[1], queue_stub.head); - - TEST_ASSERT_EQUAL(0, interface_stub.disable_interrupt_call); -} - -/** - * Given an initialized ticker with multiple ticker event inserted and the - * interface timestamp is equal to the timestamp of the first event. The first - * event to execute will insert an events in the ticker which have to be executed - * immediately. - * When ticker_irq_handler is called. - * Then: - * - The IRQ handler should have been called for the first event and the event - * inserted during irq. - * - The head of the queue should be set correctly. - * - The interrupt timestamp in the ticker interface should be equal to - * timestamp of the head event. - */ -static void test_irq_handler_insert_immediate_in_irq() -{ - static const us_timestamp_t timestamps [] = { - 10, - 10 + TIMESTAMP_MAX_DELTA - 1 - }; - - static const us_timestamp_t expected_timestamp = - ((timestamps[1] - timestamps[0]) / 2) + timestamps[0]; - - struct ctrl_block_t { - bool irq_event_called; - ticker_event_t immediate_event; - size_t handler_called; - }; - - ctrl_block_t ctrl_block = { 0 }; - - struct irq_handler_stub_t { - static void event_handler(uint32_t id) - { - ctrl_block_t *ctrl_block = (ctrl_block_t *) id; - - if (ctrl_block->handler_called == 0) { - ticker_insert_event( - &ticker_stub, - &ctrl_block->immediate_event, expected_timestamp, id - ); - interface_stub.timestamp = expected_timestamp; - } else if (ctrl_block->handler_called > 1) { - TEST_FAIL(); - } - ++ctrl_block->handler_called; - } - }; - - ticker_set_handler(&ticker_stub, irq_handler_stub_t::event_handler); - interface_stub.set_interrupt_call = 0; - - ticker_event_t events[MBED_ARRAY_SIZE(timestamps)] = { 0 }; - - for (size_t i = 0; i < MBED_ARRAY_SIZE(events); ++i) { - ticker_insert_event_us( - &ticker_stub, - &events[i], timestamps[i], (uint32_t) &ctrl_block - ); - } - - interface_stub.set_interrupt_call = 0; - interface_stub.clear_interrupt_call = 0; - interface_stub.timestamp = timestamps[0]; - - ticker_irq_handler(&ticker_stub); - - TEST_ASSERT_EQUAL(1, interface_stub.clear_interrupt_call); - TEST_ASSERT_EQUAL_UINT32(2, ctrl_block.handler_called); - TEST_ASSERT_EQUAL_UINT32( - timestamps[1], - interface_stub.interrupt_timestamp - ); - TEST_ASSERT_EQUAL_PTR(&events[1], queue_stub.head); - - TEST_ASSERT_EQUAL(0, interface_stub.disable_interrupt_call); -} - -/** - * Given an initialized ticker with multiple ticker event inserted and the - * interface timestamp is equal to the timestamp of the first event. The first - * event to execute will insert an events in the ticker which does not have to - * be executed immediately. - * When ticker_irq_handler is called. - * Then: - * - The IRQ handler should have been called for the first event. - * - The head of the queue should be set to the event inserted in IRQ. - * - The interrupt timestamp in the ticker interface should be equal to - * timestamp of the head event. - */ -static void test_irq_handler_insert_non_immediate_in_irq() -{ - static const us_timestamp_t timestamps [] = { - 10, - 10 + TIMESTAMP_MAX_DELTA - 1 - }; - - static const us_timestamp_t expected_timestamp = - ((timestamps[1] - timestamps[0]) / 2) + timestamps[0]; - - struct ctrl_block_t { - bool irq_event_called; - ticker_event_t non_immediate_event; - size_t handler_called; - }; - - ctrl_block_t ctrl_block = { 0 }; - - struct irq_handler_stub_t { - static void event_handler(uint32_t id) - { - ctrl_block_t *ctrl_block = (ctrl_block_t *) id; - - if (ctrl_block->handler_called == 0) { - ticker_insert_event( - &ticker_stub, - &ctrl_block->non_immediate_event, expected_timestamp, id - ); - } else { - TEST_FAIL(); - } - ++ctrl_block->handler_called; - } - }; - - - ticker_set_handler(&ticker_stub, irq_handler_stub_t::event_handler); - interface_stub.set_interrupt_call = 0; - - ticker_event_t events[MBED_ARRAY_SIZE(timestamps)] = { 0 }; - - for (size_t i = 0; i < MBED_ARRAY_SIZE(events); ++i) { - ticker_insert_event_us( - &ticker_stub, - &events[i], timestamps[i], (uint32_t) &ctrl_block - ); - } - - interface_stub.set_interrupt_call = 0; - interface_stub.clear_interrupt_call = 0; - interface_stub.timestamp = timestamps[0]; - - ticker_irq_handler(&ticker_stub); - - TEST_ASSERT_EQUAL(1, interface_stub.clear_interrupt_call); - TEST_ASSERT_EQUAL_UINT32(1, ctrl_block.handler_called); - TEST_ASSERT_EQUAL_UINT32( - expected_timestamp, - interface_stub.interrupt_timestamp - ); - TEST_ASSERT_EQUAL_PTR(&ctrl_block.non_immediate_event, queue_stub.head); - TEST_ASSERT_EQUAL_PTR(&events[1], queue_stub.head->next); - - TEST_ASSERT_EQUAL(0, interface_stub.disable_interrupt_call); -} - -static uint32_t ticker_interface_stub_read_interrupt_time() -{ - ++interface_stub.read_call; - // only if set interrupt call, to test the condition afterwards - if (interface_stub.set_interrupt_call) { - return interface_stub.interrupt_timestamp; - } else { - return interface_stub.timestamp; - } -} - -/** - * Test to insert an event that is already in the past, the fire_interrupt should - * be invoked, instead of set_interrupt - */ -static void test_set_interrupt_past_time() -{ - ticker_set_handler(&ticker_stub, NULL); - - interface_stub.set_interrupt_call = 0; - interface_stub.fire_interrupt_call = 0; - interface_stub.timestamp = 0xFF; - - - // This tests fire now functinality when next_event_timestamp <= present - ticker_event_t event = { 0 }; - const timestamp_t event_timestamp = interface_stub.timestamp; - const uint32_t id_last_event = 0xDEADDEAF; - - ticker_insert_event(&ticker_stub, &event, event_timestamp, id_last_event); - TEST_ASSERT_EQUAL(0, interface_stub.set_interrupt_call); - TEST_ASSERT_EQUAL(1, interface_stub.fire_interrupt_call); -} -/** - * Test to insert an event that is being delayed, set_interrupt is set - * but then event is already in the past, thus fire_interrupt should be invoked right-away - */ -static void test_set_interrupt_past_time_with_delay() -{ - ticker_set_handler(&ticker_stub, NULL); - - interface_stub.set_interrupt_call = 0; - interface_stub.fire_interrupt_call = 0; - interface_stub.timestamp = 0xFF; - - // This tests fire now functionality when present time >= new_match_time - interface_stub.interface.read = ticker_interface_stub_read_interrupt_time; - ticker_event_t event = { 0 }; - const timestamp_t event_timestamp = interface_stub.timestamp + 5; - const uint32_t id_last_event = 0xDEADDEAF; - - ticker_insert_event(&ticker_stub, &event, event_timestamp, id_last_event); - TEST_ASSERT_EQUAL(1, interface_stub.set_interrupt_call); - TEST_ASSERT_EQUAL(1, interface_stub.fire_interrupt_call); -} - -/** - * Convert ticks at a given frequency to time in microseconds - * - * Assert if there is a 64-bit overflow - */ -static uint64_t convert_to_us(uint64_t ticks, uint32_t frequency) -{ - uint64_t scaled_ticks = ticks * 1000000; - // Assert that there was not an overflow - TEST_ASSERT_EQUAL(ticks, scaled_ticks / 1000000); - return scaled_ticks / frequency; -} - -/** - * Given an uninitialized ticker instance and an interface of a - * certain frequency and bit width. - * Then the time returned the ticker should match the cumulative time. - */ -void test_frequencies_and_masks(uint32_t frequency, uint32_t bits) -{ - const uint32_t bitmask = ((uint64_t)1 << bits) - 1; - - ticker_set_handler(&ticker_stub, NULL); - uint64_t ticks = 0; - - // Single tick - ticks += 1; - interface_stub.timestamp = ticks & bitmask; - TEST_ASSERT_EQUAL_UINT32(convert_to_us(ticks, frequency), ticker_read(&ticker_stub)); - TEST_ASSERT_EQUAL_UINT64(convert_to_us(ticks, frequency), ticker_read_us(&ticker_stub)); - - // Run until the loop before 64-bit overflow (worst case with frequency=1hz, bits=32) - for (unsigned int k = 0; k < 4294; k++) { - - // Largest value possible tick - ticks += ((uint64_t)1 << bits) - 1; - interface_stub.timestamp = ticks & bitmask; - TEST_ASSERT_EQUAL_UINT32(convert_to_us(ticks, frequency), ticker_read(&ticker_stub)); - TEST_ASSERT_EQUAL_UINT64(convert_to_us(ticks, frequency), ticker_read_us(&ticker_stub)); - } -} - -/** - * Given an uninitialized ticker_data instance. - * When the ticker is initialized - * Then: - * - The internal ticker timestamp should be zero - * - interrupt should be scheduled in current (timestamp + - * TIMESTAMP_MAX_DELTA_BITS(bitwidth)) % modval - * - The queue should not contains any event - */ -static void test_ticker_max_value() -{ - for (int bitwidth = 8; bitwidth <= 32; bitwidth++) { - const uint64_t modval = 1ULL << bitwidth; - - // setup of the stub - reset_ticker_stub(); - interface_info_stub.bits = bitwidth; - interface_stub.timestamp = 0xBA; - - ticker_set_handler(&ticker_stub, NULL); - - TEST_ASSERT_EQUAL_UINT64(0, queue_stub.present_time); - TEST_ASSERT_EQUAL(1, interface_stub.set_interrupt_call); - TEST_ASSERT_EQUAL_UINT32( - (interface_stub.timestamp + TIMESTAMP_MAX_DELTA_BITS(bitwidth)) % modval, - interface_stub.interrupt_timestamp - ); - TEST_ASSERT_EQUAL_PTR(NULL, queue_stub.head); - TEST_ASSERT_EQUAL(0, interface_stub.disable_interrupt_call); - } -} - -/** - * Check that _ticker_match_interval_passed correctly detects matches - * - * Brute force test that _ticker_match_interval_passed returns the correct match value - * for all cominations of values within a small range. - */ -static void test_match_interval_passed() -{ - - for (int modval = 1; modval <= 5; modval++) { - for (int prev = 0; prev < modval; prev++) { - for (int cur = 0; cur < modval; cur++) { - for (int match = 0; match < modval; match++) { - uint32_t delta = (cur - prev) % modval; - uint32_t delta_to_match = (match - prev) % modval; - bool match_expected = false; - if (delta_to_match) { - match_expected = delta >= delta_to_match; - } - - // Sanity checks - if (prev == cur) { - // No time has passed - TEST_ASSERT_EQUAL(false, match_expected); - } else if (match == prev) { - // Match can't occur without an overflow occurring - TEST_ASSERT_EQUAL(false, match_expected); - } else if (cur == match) { - // All other cases where cur == match a match should be expected - TEST_ASSERT_EQUAL(true, match_expected); - } - - // Actual test - TEST_ASSERT_EQUAL(match_expected, _ticker_match_interval_passed(prev, cur, match)); - } - } - } - } -} - -typedef struct { - timestamp_t prev; - timestamp_t cur; - timestamp_t match; - bool result; -} match_interval_entry_t; - -/** - * Check that _ticker_match_interval_passed correctly detects matches - * - * Use a table of pre-computed values to check that _ticker_match_interval_passed - * returns the correct match value. - */ -static void test_match_interval_passed_table() -{ - static const match_interval_entry_t test_values[] = { - /* prev, cur, match, result */ - {0x00000000, 0x00000000, 0x00000000, false}, - {0x00000000, 0x00000000, 0xffffffff, false}, - {0x00000000, 0x00000000, 0x00000001, false}, - {0x00000000, 0xffffffff, 0x00000000, false}, - {0x00000000, 0x00000001, 0x00000000, false}, - {0xffffffff, 0x00000000, 0x00000000, true}, - {0x00000001, 0x00000000, 0x00000000, true}, - {0x00005555, 0x00005555, 0x00005555, false}, - {0x00005555, 0x00005555, 0x00005554, false}, - {0x00005555, 0x00005555, 0x00005556, false}, - {0x00005555, 0x00005554, 0x00005555, false}, - {0x00005555, 0x00005556, 0x00005555, false}, - {0x00005554, 0x00005555, 0x00005555, true}, - {0x00005556, 0x00005555, 0x00005555, true}, - {0xffffffff, 0xffffffff, 0xffffffff, false}, - {0xffffffff, 0xffffffff, 0xfffffffe, false}, - {0xffffffff, 0xffffffff, 0x00000000, false}, - {0xffffffff, 0xfffffffe, 0xffffffff, false}, - {0xffffffff, 0x00000000, 0xffffffff, false}, - {0xfffffffe, 0xffffffff, 0xffffffff, true}, - {0x00000000, 0xffffffff, 0xffffffff, true}, - }; - for (int i = 0; i < MBED_ARRAY_SIZE(test_values); i++) { - const uint32_t prev = test_values[i].prev; - const uint32_t cur = test_values[i].cur; - const uint32_t match = test_values[i].match; - const uint32_t result = test_values[i].result; - TEST_ASSERT_EQUAL(result, _ticker_match_interval_passed(prev, cur, match)); - } -} - -/** - * Check that suspend and resume work as expected - * - * Check the following - * -time does not change while suspended - * -restricted interface functions are not called - * -scheduling resumes correctly - */ -static void test_suspend_resume() -{ - ticker_set_handler(&ticker_stub, NULL); - - interface_stub.timestamp = 1000; - us_timestamp_t start = ticker_read_us(&ticker_stub); - TEST_ASSERT_EQUAL(1000, start); - - /* Reset call count */ - interface_stub.init_call = 0; - interface_stub.read_call = 0; - interface_stub.set_interrupt_call = 0; - - /* Suspend the ticker */ - ticker_suspend(&ticker_stub); - const timestamp_t suspend_time = queue_stub.present_time; - - - /* Simulate time passing */ - interface_stub.timestamp = 1500; - us_timestamp_t next = ticker_read_us(&ticker_stub); - - /* Time should not have passed and no calls to interface should have been made */ - TEST_ASSERT_EQUAL(start, next); - TEST_ASSERT_EQUAL(0, interface_stub.init_call); - TEST_ASSERT_EQUAL(0, interface_stub.read_call); - TEST_ASSERT_EQUAL(0, interface_stub.disable_interrupt_call); - TEST_ASSERT_EQUAL(0, interface_stub.clear_interrupt_call); - TEST_ASSERT_EQUAL(0, interface_stub.set_interrupt_call); - TEST_ASSERT_EQUAL(0, interface_stub.fire_interrupt_call); - - - /* Simulate a reinit (time reset to 0) */ - interface_stub.timestamp = 0; - next = ticker_read_us(&ticker_stub); - - /* Time should not have passed and no calls to interface should have been made */ - TEST_ASSERT_EQUAL(start, next); - TEST_ASSERT_EQUAL(0, interface_stub.init_call); - TEST_ASSERT_EQUAL(0, interface_stub.read_call); - TEST_ASSERT_EQUAL(0, interface_stub.disable_interrupt_call); - TEST_ASSERT_EQUAL(0, interface_stub.clear_interrupt_call); - TEST_ASSERT_EQUAL(0, interface_stub.set_interrupt_call); - TEST_ASSERT_EQUAL(0, interface_stub.fire_interrupt_call); - - - /* Insert an event in the past and future */ - ticker_event_t event_past = { 0 }; - const timestamp_t event_past_timestamp = suspend_time - 10; - ticker_insert_event_us(&ticker_stub, &event_past, event_past_timestamp, 0); - - ticker_event_t event_future = { 0 }; - const timestamp_t event_future_timestamp = suspend_time + 10; - ticker_insert_event_us(&ticker_stub, &event_future, event_future_timestamp, 0); - - TEST_ASSERT_EQUAL(0, interface_stub.init_call); - TEST_ASSERT_EQUAL(0, interface_stub.read_call); - TEST_ASSERT_EQUAL(0, interface_stub.disable_interrupt_call); - TEST_ASSERT_EQUAL(0, interface_stub.clear_interrupt_call); - TEST_ASSERT_EQUAL(0, interface_stub.set_interrupt_call); - TEST_ASSERT_EQUAL(0, interface_stub.fire_interrupt_call); - - /* Resume and verify everything starts again */ - ticker_resume(&ticker_stub); - TEST_ASSERT_EQUAL(suspend_time, queue_stub.present_time); - TEST_ASSERT_EQUAL(1, interface_stub.fire_interrupt_call); -} - -static const case_t cases[] = { - MAKE_TEST_CASE("ticker initialization", test_ticker_initialization), - MAKE_TEST_CASE( - "ticker multiple initialization", test_ticker_re_initialization - ), - MAKE_TEST_CASE("ticker read", test_ticker_read), - MAKE_TEST_CASE("ticker read overflow", test_ticker_read_overflow), - MAKE_TEST_CASE( - "legacy insert event outside overflow range", - test_legacy_insert_event_outside_overflow_range - ), - MAKE_TEST_CASE( - "legacy insert event in overflow range", - test_legacy_insert_event_in_overflow_range - ), - MAKE_TEST_CASE( - "legacy insert event overflow", test_legacy_insert_event_overflow - ), - MAKE_TEST_CASE( - "legacy insert event head", test_legacy_insert_event_head - ), - MAKE_TEST_CASE( - "legacy insert event tail", test_legacy_insert_event_tail - ), - MAKE_TEST_CASE( - "legacy insert event multiple overflow", - test_legacy_insert_event_multiple_overflow - ), - MAKE_TEST_CASE( - "test_legacy_insert_event_multiple_random", - test_legacy_insert_event_multiple_random - ), - MAKE_TEST_CASE( - "test_insert_event_us_outside_overflow_range", - test_insert_event_us_outside_overflow_range - ), - MAKE_TEST_CASE( - "test_insert_event_us_in_overflow_range", - test_insert_event_us_in_overflow_range - ), - MAKE_TEST_CASE( - "test_insert_event_us_underflow", test_insert_event_us_underflow - ), - MAKE_TEST_CASE("test_insert_event_us_head", test_insert_event_us_head), - MAKE_TEST_CASE("test_insert_event_us_tail", test_insert_event_us_tail), - MAKE_TEST_CASE( - "test_insert_event_us_multiple_random", - test_insert_event_us_multiple_random - ), - MAKE_TEST_CASE("test_remove_event_tail", test_remove_event_tail), - MAKE_TEST_CASE("test_remove_event_head", test_remove_event_head), - MAKE_TEST_CASE("test_remove_event_invalid", test_remove_event_invalid), - MAKE_TEST_CASE("test_remove_random", test_remove_random), - MAKE_TEST_CASE("update overflow guard", test_overflow_event_update), - MAKE_TEST_CASE( - "update overflow guard in case of spurious interrupt", - test_overflow_event_update_when_spurious_interrupt - ), - MAKE_TEST_CASE( - "test_irq_handler_single_event", test_irq_handler_single_event - ), - MAKE_TEST_CASE( - "test_irq_handler_single_event_spurious", - test_irq_handler_single_event_spurious - ), - MAKE_TEST_CASE( - "test_irq_handler_multiple_event_multiple_dequeue", - test_irq_handler_multiple_event_multiple_dequeue - ), - MAKE_TEST_CASE( - "test_irq_handler_multiple_event_single_dequeue_overflow", - test_irq_handler_multiple_event_single_dequeue_overflow - ), - MAKE_TEST_CASE( - "test_irq_handler_multiple_event_single_dequeue", - test_irq_handler_multiple_event_single_dequeue - ), - MAKE_TEST_CASE( - "test_irq_handler_insert_immediate_in_irq", - test_irq_handler_insert_immediate_in_irq - ), - MAKE_TEST_CASE( - "test_irq_handler_insert_non_immediate_in_irq", - test_irq_handler_insert_non_immediate_in_irq - ), - MAKE_TEST_CASE( - "test_set_interrupt_past_time", - test_set_interrupt_past_time - ), - MAKE_TEST_CASE( - "test_set_interrupt_past_time_with_delay", - test_set_interrupt_past_time_with_delay - ), - MAKE_TEST_CASE( - "test_frequencies_and_masks", - test_over_frequency_and_width - ), - MAKE_TEST_CASE( - "test_ticker_max_value", - test_ticker_max_value - ), - MAKE_TEST_CASE( - "test_match_interval_passed", - test_match_interval_passed - ), - MAKE_TEST_CASE( - "test_match_interval_passed_table", - test_match_interval_passed_table - ), - MAKE_TEST_CASE( - "test_suspend_resume", - test_suspend_resume - ) -}; - -static utest::v1::status_t greentea_test_setup(const size_t number_of_cases) -{ - GREENTEA_SETUP(60, "default_auto"); - return verbose_test_setup_handler(number_of_cases); -} - -int main() -{ - Specification specification(greentea_test_setup, cases, greentea_test_teardown_handler); - return !Harness::run(specification); -} diff --git a/TESTS/mbed_hal/trng/base64b/base64b.cpp b/TESTS/mbed_hal/trng/base64b/base64b.cpp deleted file mode 100644 index 9b8525c..0000000 --- a/TESTS/mbed_hal/trng/base64b/base64b.cpp +++ /dev/null @@ -1,197 +0,0 @@ -/* -* Copyright (c) 2018 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. -*/ - -#include "base64b.h" - -using namespace std; - -static char IntToBase64Char(uint8_t intVal) -{ - const char *base64Digits = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; - return base64Digits[intVal & 0x3F]; -} - -#define BASE_64_PAD 0xFF -static base64_result_e Base64CharToInt(char base64, uint8_t *intVal) -{ - if (NULL == intVal) { - return BASE64_INVALID_PARAMETER; - } - - if ((base64 >= 'A') && (base64 <= 'Z')) { - *intVal = base64 - 'A' ; - } else if ((base64 >= 'a') && (base64 <= 'z')) { - *intVal = base64 - 'a' + 26; - } else if ((base64 >= '0') && (base64 <= '9')) { - *intVal = base64 - '0' + 52; - } else if (base64 == '+') { - *intVal = 62; - } else if (base64 == '/') { - *intVal = 63; - } else if (base64 == '=') { - *intVal = BASE_64_PAD; - } else { - return BASE64_ERROR; - } - - return BASE64_SUCCESS; -} - -base64_result_e trng_DecodeNBase64(const char *string, - uint32_t stringMaxSize, - void *buffer, - uint32_t bufferSize, - uint32_t *lengthWritten, - uint32_t *charsProcessed) -{ - base64_result_e result = BASE64_SUCCESS; - uint32_t bitOffset = 0; - uint8_t *writePtr = (uint8_t *)buffer; - uint8_t *bufferEnd = (uint8_t *)buffer + bufferSize; - uint8_t tempVal = 0; - uint32_t currPos = 0; - uint32_t localBytesWritten = 0; - uint32_t localCharsProcessed = 0; - bool isEndOfString = false; - - if ((NULL == string) || (NULL == buffer) || (bufferSize == 0)) { - return BASE64_INVALID_PARAMETER; - } - - *writePtr = 0; - while ((currPos < stringMaxSize) && - (string[currPos] != 0) && - (writePtr < bufferEnd) && - (!isEndOfString)) { - uint8_t val; - - if (string[currPos] == 0) { - break; - } - - result = Base64CharToInt(string[currPos++], &val); - if (result != BASE64_SUCCESS) { - break; - } - - if (val != BASE_64_PAD) { - if (bitOffset <= 2) { - tempVal |= val << (2 - bitOffset); - if (bitOffset == 2) { - *writePtr++ = tempVal; - tempVal = 0; - } - } else { - *writePtr++ = (uint8_t)(tempVal | (val >> (bitOffset - 2))); - tempVal = (uint8_t)(val << (10 - bitOffset)); - } - } else { // found BASE_64_PAD - // At most two pad characters may occur at the end of the encoded stream - if (bitOffset == 2) { - isEndOfString = true; // The last padding byte has been processed. - } else if (bitOffset != 4) { - return BASE64_ERROR; // Incorrect padding - } - } - - bitOffset = (bitOffset + 6) & 0x7; - if (bitOffset == 0) { - localBytesWritten = (uint32_t)(writePtr - (uint8_t *)buffer); - localCharsProcessed = currPos; - } - } - if (charsProcessed == NULL) { - localBytesWritten = (uint32_t)(writePtr - (uint8_t *)buffer); - } else { - *charsProcessed = localCharsProcessed; - } - if (lengthWritten != NULL) { - *lengthWritten = localBytesWritten; - } else if (bufferSize != localBytesWritten) { - return BASE64_BUFFER_TOO_SMALL; - } - - // Check if additional bytes should have been processed but buffer isn't sufficient. - if ((result == BASE64_SUCCESS) && - (!isEndOfString) && - (currPos < stringMaxSize) && - (string[currPos] != 0) && - (string[currPos] != '=')) { - return BASE64_BUFFER_TOO_SMALL; - } - - if (result != BASE64_SUCCESS) { - return result; - } - - return BASE64_SUCCESS; -} - -base64_result_e trng_EncodeBase64(const void *buffer, uint32_t bufferSize, char *string, uint32_t stringSize) -{ - uint32_t bitOffset = 0; - - const uint8_t *readPtr = (const uint8_t *)buffer; - const uint8_t *bufferEnd = (const uint8_t *)buffer + bufferSize; - - char *writePtr = string; - char *stringEnd = string + stringSize - 1; - - if ((NULL == string) || (NULL == buffer) || (stringSize == 0)) { - return BASE64_INVALID_PARAMETER; - } - - stringSize--; - while (readPtr < bufferEnd && writePtr < stringEnd) { - uint8_t tempVal = 0; - switch (bitOffset) { - case 0: - *writePtr++ = IntToBase64Char(*readPtr >> 2); // take upper 6 bits - break; - case 6: - tempVal = *readPtr++ << 4; - if (readPtr < bufferEnd) { - tempVal |= *readPtr >> 4; - } - *writePtr++ = IntToBase64Char(tempVal); - break; - case 4: - tempVal = *readPtr++ << 2; - if (readPtr < bufferEnd) { - tempVal |= *readPtr >> 6; - } - *writePtr++ = IntToBase64Char(tempVal); - break; - case 2: - *writePtr++ = IntToBase64Char(*readPtr++); - break; - default: - return BASE64_ERROR; // we should never reach this code. - } - bitOffset = (bitOffset + 6) & 0x7; - } - while (bitOffset > 0 && writePtr < stringEnd) { - *writePtr++ = '='; - bitOffset = (bitOffset + 6) & 0x7; - } - *writePtr = 0; - - if ((readPtr < bufferEnd) || (bitOffset != 0)) { - return (BASE64_BUFFER_TOO_SMALL); - } - - return (BASE64_SUCCESS); -} diff --git a/TESTS/mbed_hal/trng/base64b/base64b.h b/TESTS/mbed_hal/trng/base64b/base64b.h deleted file mode 100644 index cbb6b85..0000000 --- a/TESTS/mbed_hal/trng/base64b/base64b.h +++ /dev/null @@ -1,32 +0,0 @@ -/* -* Copyright (c) 2018 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. -*/ - -#include -#include -#include - -typedef enum { - BASE64_SUCCESS = 0, - BASE64_INVALID_PARAMETER = 1, - BASE64_BUFFER_TOO_SMALL = 2, - BASE64_ERROR = 3, -} base64_result_e; - -base64_result_e trng_EncodeBase64(const void *buffer, uint32_t bufferSize, char *string, uint32_t stringSize); -base64_result_e trng_DecodeNBase64(const char *string, uint32_t stringMaxSize, void *buffer, uint32_t bufferSize, - uint32_t *lengthWritten, uint32_t *charsProcessed); - - diff --git a/TESTS/mbed_hal/trng/main.cpp b/TESTS/mbed_hal/trng/main.cpp deleted file mode 100644 index 40147e8..0000000 --- a/TESTS/mbed_hal/trng/main.cpp +++ /dev/null @@ -1,259 +0,0 @@ -/* -* Copyright (c) 2018-2020 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. -*/ - -/* -* The test is based on the assumption that trng will generate random data, random so -* there will not be any similar patterns in it, that kind of data will be impossible to -* compress, if compression will occur the test will result in failure. -* -* The test is composed out of three parts: -* the first, generate a trng buffer and try to compress it, at the end of first part -* we will reset the device. -* In second part we will generate a trng buffer with a different buffer size and try to -* compress it. -* In the third part we will again generate a trng buffer to see that the same trng output -* is not generated as the stored trng buffer from part one (before reseting), the new trng data will -* be concatenated to the trng data from the first part and then try to compress it -* together, if there are similar patterns the compression will succeed. -* -* We need to store and load the first part data before and after reset, the mechanism -* we will use is the mbed greentea platform for sending and receving the data from the device -* to the host running the test and back, the problem with this mechanism is that it doesn't -* handle well certain characters, especially non ASCII ones, so we use the base64 algorithm -* to ensure all characters will be transmitted correctly. -*/ - -#include "greentea-client/test_env.h" -#include "unity/unity.h" -#include "utest/utest.h" -#include "hal/trng_api.h" -#include "base64b.h" -#include "pithy.h" -#include -#include -#include "mbedtls/config.h" -#include "mbedtls/platform.h" - -#if !DEVICE_TRNG -#error [NOT_SUPPORTED] TRNG API not supported for this target -#else - -#define MSG_VALUE_DUMMY "0" -#define MSG_VALUE_LEN 64 -#define MSG_KEY_LEN 32 - -#define BUFFER_LEN (MSG_VALUE_LEN/2) - -#define MSG_TRNG_READY "ready" -#define MSG_TRNG_BUFFER "buffer" -#define MSG_TRNG_EXIT "exit" - -#define MSG_TRNG_TEST_STEP1 "check_step1" -#define MSG_TRNG_TEST_STEP2 "check_step2" -#define MSG_TRNG_TEST_SUITE_ENDED "Test_suite_ended" - -#define RESULT_SUCCESS 0 - -using namespace utest::v1; - -static int fill_buffer_trng(uint8_t *buffer, trng_t *trng_obj, size_t trng_len) -{ - size_t temp_size = 0, output_length = 0; - int trng_res = 0; - uint8_t *temp_in_buf = buffer; - - trng_init(trng_obj); - memset(buffer, 0, BUFFER_LEN); - - while (true) { - trng_res = trng_get_bytes(trng_obj, temp_in_buf, trng_len - temp_size, &output_length); - TEST_ASSERT_EQUAL_INT_MESSAGE(0, trng_res, "trng_get_bytes error!"); - temp_size += output_length; - temp_in_buf += output_length; - if (temp_size >= trng_len) { - break; - } - } - - temp_in_buf = NULL; - trng_free(trng_obj); - return 0; -} - -void print_array(uint8_t *buffer, size_t size) -{ - for (size_t i = 0; i < size; i++) { - utest_printf("%02x", buffer[i]); - } - utest_printf("\n"); -} - -static void compress_and_compare(char *key, char *value) -{ - trng_t trng_obj; - uint8_t *out_comp_buf, *buffer; - uint8_t *input_buf, *temp_buf; - size_t comp_sz = 0; - unsigned int result = 0; - -#define OUT_COMP_BUF_SIZE ((BUFFER_LEN * 5) + 32) -#define TEMP_BUF_SIZE (BUFFER_LEN * 2) - - out_comp_buf = new uint8_t[OUT_COMP_BUF_SIZE]; - buffer = new uint8_t[BUFFER_LEN]; - temp_buf = new uint8_t[BUFFER_LEN * 2]; - input_buf = new uint8_t[BUFFER_LEN * 4]; - - /*At the begining of step 2 load trng buffer from step 1*/ - if (strcmp(key, MSG_TRNG_TEST_STEP2) == 0) { - /*Using base64 to decode data sent from host*/ - uint32_t lengthWritten = 0; - uint32_t charsProcessed = 0; - result = trng_DecodeNBase64((const char *)value, - MSG_VALUE_LEN, - buffer, - BUFFER_LEN, - &lengthWritten, - &charsProcessed); - TEST_ASSERT_EQUAL(0, result); - memcpy(input_buf, buffer, BUFFER_LEN); - } - - if (strcmp(key, MSG_TRNG_TEST_STEP1) == 0) { - /*Fill buffer with trng values*/ - result = fill_buffer_trng(buffer, &trng_obj, BUFFER_LEN); - TEST_ASSERT_EQUAL(0, result); - memcpy(input_buf, buffer, BUFFER_LEN); - } - /*pithy_Compress will try to compress the random data, if it succeeded it means the data is not really random*/ - else if (strcmp(key, MSG_TRNG_TEST_STEP2) == 0) { - - comp_sz = pithy_Compress((char *)buffer, - BUFFER_LEN, - (char *)out_comp_buf, - OUT_COMP_BUF_SIZE, - 9); - if (comp_sz <= BUFFER_LEN) { - print_array(buffer, BUFFER_LEN); - } - TEST_ASSERT_MESSAGE(comp_sz > BUFFER_LEN, - "TRNG_TEST_STEP1: trng_get_bytes was able to compress thus not random"); - - /*pithy_Compress will try to compress the random data with a different buffer size*/ - result = fill_buffer_trng(temp_buf, &trng_obj, TEMP_BUF_SIZE); - TEST_ASSERT_EQUAL(0, result); - - comp_sz = pithy_Compress((char *)temp_buf, - TEMP_BUF_SIZE, - (char *)out_comp_buf, - OUT_COMP_BUF_SIZE, - 9); - if (comp_sz <= TEMP_BUF_SIZE) { - print_array(temp_buf, TEMP_BUF_SIZE); - } - TEST_ASSERT_MESSAGE(comp_sz > TEMP_BUF_SIZE, - "TRNG_TEST_STEP2: trng_get_bytes was able to compress thus not random"); - - memcpy(input_buf + BUFFER_LEN, temp_buf, TEMP_BUF_SIZE); - /*pithy_Compress will try to compress the random data from before reset concatenated with new random data*/ - comp_sz = pithy_Compress((char *)input_buf, - TEMP_BUF_SIZE + BUFFER_LEN, - (char *)out_comp_buf, - OUT_COMP_BUF_SIZE, - 9); - if (comp_sz <= TEMP_BUF_SIZE + BUFFER_LEN) { - print_array(input_buf, TEMP_BUF_SIZE + BUFFER_LEN); - } - TEST_ASSERT_MESSAGE(comp_sz > TEMP_BUF_SIZE + BUFFER_LEN, - "TRNG_TEST_STEP3: concatenated buffer after reset was able to compress thus not random"); - - greentea_send_kv(MSG_TRNG_TEST_SUITE_ENDED, MSG_VALUE_DUMMY); - } - - /*At the end of step 1 store trng buffer and reset the device*/ - if (strcmp(key, MSG_TRNG_TEST_STEP1) == 0) { - int result = 0; - /*Using base64 to encode data sending from host*/ - result = trng_EncodeBase64(buffer, - BUFFER_LEN, - (char *)out_comp_buf, - OUT_COMP_BUF_SIZE); - TEST_ASSERT_EQUAL(RESULT_SUCCESS, result); - - greentea_send_kv(MSG_TRNG_BUFFER, (const char *)out_comp_buf); - } - - delete[] out_comp_buf; - delete[] buffer; - delete[] input_buf; - delete[] temp_buf; -} - -/*This method call first and second steps, it directs by the key received from the host*/ -void trng_test() -{ - greentea_send_kv(MSG_TRNG_READY, MSG_VALUE_DUMMY); - - char key[MSG_KEY_LEN + 1] = { }; - char *value = new char[MSG_VALUE_LEN + 1]; - do { - memset(key, 0, MSG_KEY_LEN + 1); - memset(value, 0, MSG_VALUE_LEN + 1); - - greentea_parse_kv(key, value, MSG_KEY_LEN, MSG_VALUE_LEN); - - if (strcmp(key, MSG_TRNG_TEST_STEP1) == 0) { - /*create trng data buffer and try to compress it, store it for later checks*/ - compress_and_compare(key, value); - } - - if (strcmp(key, MSG_TRNG_TEST_STEP2) == 0) { - /*create another trng data buffer and concatenate it to the stored trng data buffer - try to compress them both*/ - compress_and_compare(key, value); - } - } while (strcmp(key, MSG_TRNG_EXIT) != 0); - - delete[] value; -} - -Case cases[] = { - Case("TRNG: trng_test", trng_test), -}; - -utest::v1::status_t greentea_test_setup(const size_t number_of_cases) -{ - GREENTEA_SETUP(100, "trng_reset"); - return greentea_test_setup_handler(number_of_cases); -} - -Specification specification(greentea_test_setup, cases, greentea_test_teardown_handler); - -int main() -{ - int ret = 0; -#if defined(MBEDTLS_PLATFORM_C) - ret = mbedtls_platform_setup(NULL); -#endif /* MBEDTLS_PLATFORM_C */ - ret = !Harness::run(specification); -#if defined(MBEDTLS_PLATFORM_C) - mbedtls_platform_teardown(NULL); -#endif /* MBEDTLS_PLATFORM_C */ - return ret; -} - -#endif // !DEVICE_TRNG - diff --git a/TESTS/mbed_hal/trng/pithy/pithy.c b/TESTS/mbed_hal/trng/pithy/pithy.c deleted file mode 100644 index d0581d8..0000000 --- a/TESTS/mbed_hal/trng/pithy/pithy.c +++ /dev/null @@ -1,796 +0,0 @@ -// -// pithy.c -// http://github.com/johnezang/pithy -// Licensed under the terms of the BSD License, as specified below. -// -// SPDX-License-Identifier: BSD-3-Clause - -/* - Copyright (c) 2011, John Engelhart - - All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - * Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - - * Neither the name of the Zang Industries nor the names of its - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED - TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - -#include -#include -#include -#include - -#if defined(__arm__) && defined(__ARM_NEON__) -#include -#endif - -#include "pithy.h" - -#define kBlockLog 20ul -#define kBlockSize ((size_t)(1 << kBlockLog)) - -// The maximum size that can be compressed while still allowing for the worst case compression expansion. -#define PITHY_UNCOMPRESSED_MAX_LENGTH 0xdb6db6bfu // 0xdb6db6bf == 3681400511, or 3510.857 Mbytes. - -typedef const char *pithy_hashOffset_t; - -enum { - PITHY_LITERAL = 0, - PITHY_COPY_1_BYTE_OFFSET = 1, - PITHY_COPY_2_BYTE_OFFSET = 2, - PITHY_COPY_3_BYTE_OFFSET = 3 -}; - - -#if defined (__GNUC__) && (__GNUC__ >= 3) -#define PITHY_ATTRIBUTES(attr, ...) __attribute__((attr, ##__VA_ARGS__)) -#define PITHY_EXPECTED(cond, expect) __builtin_expect((long)(cond), (expect)) -#define PITHY_EXPECT_T(cond) PITHY_EXPECTED(cond, 1u) -#define PITHY_EXPECT_F(cond) PITHY_EXPECTED(cond, 0u) -#define PITHY_PREFETCH(ptr) __builtin_prefetch(ptr) -#else // defined (__GNUC__) && (__GNUC__ >= 3) -#define PITHY_ATTRIBUTES(attr, ...) -#define PITHY_EXPECTED(cond, expect) (cond) -#define PITHY_EXPECT_T(cond) (cond) -#define PITHY_EXPECT_F(cond) (cond) -#define PITHY_PREFETCH(ptr) -#endif // defined (__GNUC__) && (__GNUC__ >= 3) - -#define PITHY_STATIC_INLINE static inline PITHY_ATTRIBUTES(always_inline) -#define PITHY_ALIGNED(x) PITHY_ATTRIBUTES(aligned(x)) - -#if defined(NS_BLOCK_ASSERTIONS) && !defined(NDEBUG) -#define NDEBUG -#endif - -#ifdef NDEBUG -#define DCHECK(condition) -#else -#define DCHECK(condition) do { \ - if(PITHY_EXPECT_F(!(condition))) { \ - fprintf(stderr, "%s / %s @ %ld: Invalid parameter not satisfying: %s", \ - __FILE__, __PRETTY_FUNCTION__, (long)__LINE__, #condition); fflush(stderr); \ - abort(); \ - } \ - } while(0) -#endif - -PITHY_STATIC_INLINE const char *pithy_Parse32WithLimit(const char *p, const char *l, size_t *OUTPUT); -PITHY_STATIC_INLINE char *pithy_Encode32(char *ptr, uint32_t v); - -PITHY_STATIC_INLINE uint32_t pithy_GetUint32AtOffset(uint64_t v, uint32_t offset); -PITHY_STATIC_INLINE uint32_t pithy_HashBytes(uint32_t bytes, uint32_t shift); -PITHY_STATIC_INLINE size_t pithy_FindMatchLength(const char *s1, const char *s2, const char *s2_limit); -PITHY_STATIC_INLINE char *pithy_EmitLiteral(char *op, const char *literal, size_t len, int allow_fast_path); -PITHY_STATIC_INLINE char *pithy_EmitCopyGreaterThan63(char *op, size_t offset, size_t len); -PITHY_STATIC_INLINE char *pithy_EmitCopyLessThan63(char *op, size_t offset, size_t len); -PITHY_STATIC_INLINE char *pithy_EmitCopy(char *op, size_t offset, size_t len); - -PITHY_STATIC_INLINE uint16_t pithy_Load16(const void *p) { uint16_t t; memcpy(&t, p, sizeof(t)); return (t); } -PITHY_STATIC_INLINE uint32_t pithy_Load32(const void *p) { uint32_t t; memcpy(&t, p, sizeof(t)); return (t); } -PITHY_STATIC_INLINE uint64_t pithy_Load64(const void *p) { uint64_t t; memcpy(&t, p, sizeof(t)); return (t); } -PITHY_STATIC_INLINE void pithy_Store16(void *p, uint16_t v) { memcpy(p, &v, sizeof(v)); } -PITHY_STATIC_INLINE void pithy_Store32(void *p, uint32_t v) { memcpy(p, &v, sizeof(v)); } -PITHY_STATIC_INLINE void pithy_Store64(void *p, uint64_t v) { memcpy(p, &v, sizeof(v)); } - -#define pithy_Move64(dst,src) pithy_Store64(dst, pithy_Load64(src)); -#define pithy_Move128(dst,src) pithy_Move64(dst, src); pithy_Move64(dst + 8ul, src + 8ul); - -#ifdef __BIG_ENDIAN__ - -#ifdef _MSC_VER -#include -#define pithy_bswap_16(x) _byteswap_ushort(x) -#define pithy_bswap_32(x) _byteswap_ulong(x) -#define pithy_bswap_64(x) _byteswap_uint64(x) - -#elif defined(__APPLE__) - -// Mac OS X / Darwin features -#include -#define pithy_bswap_16(x) OSSwapInt16(x) -#define pithy_bswap_32(x) OSSwapInt32(x) -#define pithy_bswap_64(x) OSSwapInt64(x) -#else -#include -#endif - -#endif // __BIG_ENDIAN__ - -// Conversion functions. -#ifdef __BIG_ENDIAN__ -#define pithy_FromHost16(x) ((uint16_t)pithy_bswap_16(x)) -#define pithy_ToHost16(x) ((uint16_t)pithy_bswap_16(x)) -#define pithy_FromHost32(x) ((uint32_t)pithy_bswap_32(x)) -#define pithy_ToHost32(x) ((uint32_t)pithy_bswap_32(x)) -#define pithy_IsLittleEndian() (0) - -#else // !defined(__BIG_ENDIAN__) -#define pithy_FromHost16(x) ((uint16_t)(x)) -#define pithy_ToHost16(x) ((uint16_t)(x)) -#define pithy_FromHost32(x) ((uint32_t)(x)) -#define pithy_ToHost32(x) ((uint32_t)(x)) -#define pithy_IsLittleEndian() (1) - -#endif // !defined(__BIG_ENDIAN__) - -#define pithy_LoadHost16(p) pithy_ToHost16(pithy_Load16((const void *)(p))) -#define pithy_StoreHost16(p, v) pithy_Store16((void *)(p), pithy_FromHost16(v)) -#define pithy_LoadHost32(p) pithy_ToHost32(pithy_Load32((p))) -#define pithy_StoreHost32(p, v) pithy_Store32((p), pithy_FromHost32(v)) - -PITHY_STATIC_INLINE void pithy_StoreHost24(char *p, uint32_t v) -{ - *p++ = (v & 0xffu); - *p++ = ((v >> 8) & 0xffu); - *p++ = ((v >> 16) & 0xffu); -} - -#if defined (__GNUC__) && (__GNUC__ >= 3) - -#define pithy_Log2Floor(n) ({typeof(n) _n = (n); _n == 0 ? (int)-1 : (int)(31 ^ __builtin_clz(_n));}) -#define pithy_FindLSBSetNonZero32(n) ((int)__builtin_ctz((uint32_t)(n))) -#define pithy_FindLSBSetNonZero64(n) ((int)__builtin_ctzll((uint64_t)(n))) -#define pithy_FindMSBSetNonZero32(n) ((int)__builtin_clz((uint32_t)(n))) -#define pithy_FindMSBSetNonZero64(n) ((int)__builtin_clzll((uint64_t)(n))) - -#else // Portable versions, !GNUC || GNUC < 3 - -PITHY_STATIC_INLINE int pithy_Log2Floor(uint32_t n) -{ - if (n == 0u) { - return (-1); - } - int i = 0, log = 0; - uint32_t value = n; - for (i = 4; i >= 0; --i) { - int shift = (1 << i); - uint32_t x = value >> shift; - if (x != 0u) { - value = x; - log += shift; - } - } - DCHECK(value == 1); - return (log); -} - -PITHY_STATIC_INLINE int pithy_FindLSBSetNonZero32(uint32_t n) -{ - int i = 0, rc = 31, shift = 0; - for (i = 4, shift = 1 << 4; i >= 0; --i) { - const uint32_t x = n << shift; - if (x != 0u) { - n = x; - rc -= shift; - } - shift >>= 1; - } - return (rc); -} - -PITHY_STATIC_INLINE int pithy_FindLSBSetNonZero64(uint64_t n) -{ - const uint32_t bottomBits = n; - if (bottomBits == 0u) { - return (32 + pithy_FindLSBSetNonZero32((n >> 32))); - } else { - return (pithy_FindLSBSetNonZero32(bottomBits)); - } -} - -PITHY_STATIC_INLINE int pithy_FindMSBSetNonZero32(uint32_t n) -{ - int i; - uint32_t x, rc = 32, shift = 1 << 4; - for (i = 3; i >= 0; --i) { - x = n >> shift; - if (x != 0) { - rc -= shift; - n = x; - } - shift >>= 1; - } - x = n >> shift; - return (rc - ((x != 0) ? 2 : n)); -} - -PITHY_STATIC_INLINE int pithy_FindMSBSetNonZero64(uint64_t n) -{ - const uint32_t upperBits = n >> 32; - if (upperBits == 0u) { - return (32 + pithy_FindMSBSetNonZero32((n))); - } else { - return (pithy_FindMSBSetNonZero32(upperBits)); - } -} - -#endif // End portable versions. - -PITHY_STATIC_INLINE const char *pithy_Parse32WithLimit(const char *p, const char *l, size_t *resultOut) -{ - const unsigned char *ptr = (const unsigned char *)p, *limit = (const unsigned char *)l; - size_t resultShift = 0ul, result = 0ul; - uint32_t encodedByte = 0u; - - for (resultShift = 0ul; resultShift <= 28ul; resultShift += 7ul) { - if (ptr >= limit) { - return (NULL); - } - encodedByte = *(ptr++); - result |= (encodedByte & 127u) << resultShift; - if (encodedByte < ((resultShift == 28ul) ? 16u : 128u)) { - goto done; - } - } - return (NULL); -done: - *resultOut = result; - return ((const char *)ptr); -} - -PITHY_STATIC_INLINE char *pithy_Encode32(char *sptr, uint32_t v) -{ - unsigned char *ptr = (unsigned char *)sptr; - if (v < (1u << 7)) { - *(ptr++) = v; - } else if (v < (1u << 14)) { - *(ptr++) = v | 0x80u; - *(ptr++) = (v >> 7); - } else if (v < (1u << 21)) { - *(ptr++) = v | 0x80u; - *(ptr++) = (v >> 7) | 0x80u; - *(ptr++) = (v >> 14); - } else if (v < (1u << 28)) { - *(ptr++) = v | 0x80u; - *(ptr++) = (v >> 7) | 0x80u; - *(ptr++) = (v >> 14) | 0x80u; - *(ptr++) = (v >> 21); - } else { - *(ptr++) = v | 0x80u; - *(ptr++) = (v >> 7) | 0x80u; - *(ptr++) = (v >> 14) | 0x80u; - *(ptr++) = (v >> 21) | 0x80u; - *(ptr++) = (v >> 28); - } - return ((char *)ptr); -} - - -PITHY_STATIC_INLINE uint32_t pithy_GetUint32AtOffset(uint64_t v, uint32_t offset) -{ - DCHECK(offset <= 4); - return (v >> (pithy_IsLittleEndian() ? (8u * offset) : (32u - (8u * offset)))); -} - - -PITHY_STATIC_INLINE uint32_t pithy_HashBytes(uint32_t bytes, uint32_t shift) -{ - uint32_t kMul = 0x1e35a7bdU; - return ((bytes * kMul) >> shift); -} - - -PITHY_STATIC_INLINE size_t pithy_FindMatchLength(const char *s1, const char *s2, const char *s2_limit) -{ - DCHECK(s2_limit >= s2); - const char *ms1 = s1, *ms2 = s2; - -#if defined(__LP64__) - while (PITHY_EXPECT_T(ms2 < (s2_limit - 8ul))) { - uint64_t x = pithy_Load64(ms1) ^ pithy_Load64(ms2); - if (PITHY_EXPECT_F(x == 0ul)) { - ms1 += 8ul; - ms2 += 8ul; - } else { - return ((ms1 - s1) + ((unsigned int)(pithy_IsLittleEndian() ? (pithy_FindLSBSetNonZero64(x) >> 3) : - (pithy_FindMSBSetNonZero64(x) >> 3)))); - } - } -#else - while (PITHY_EXPECT_T(ms2 < (s2_limit - 4u ))) { - uint32_t x = pithy_Load32(ms1) ^ pithy_Load32(ms2); - if (PITHY_EXPECT_F(x == 0u)) { - ms1 += 4u; - ms2 += 4u; - } else { - return ((ms1 - s1) + ((unsigned int)(pithy_IsLittleEndian() ? - (pithy_FindLSBSetNonZero32(x) >> 3) : (pithy_FindMSBSetNonZero32(x) >> 3)))); - } - } -#endif - while (PITHY_EXPECT_T(ms2 < s2_limit)) { - if (PITHY_EXPECT_T(*ms1 == *ms2)) { - ms1++; - ms2++; - } else { - return (ms1 - s1); - } - } - return (ms1 - s1); -} - - -PITHY_STATIC_INLINE char *pithy_EmitLiteral(char *op, const char *literal, size_t len, int allow_fast_path) -{ - int n = len - 1l; - if (PITHY_EXPECT_T(n < 60l)) { - *op++ = PITHY_LITERAL | (n << 2); - if (PITHY_EXPECT_T(allow_fast_path) && PITHY_EXPECT_T(len <= 16ul)) { - pithy_Move128(op, literal); - return (op + len); - } - } else { - char *base = op; - int count = 0; - op++; - while (n > 0l) { - *op++ = n & 0xff; - n >>= 8; - count++; - } - DCHECK((count >= 1) && (count <= 4)); - *base = PITHY_LITERAL | ((59 + count) << 2); - } - memcpy(op, literal, len); - return (op + len); -} - -PITHY_STATIC_INLINE char *pithy_EmitCopyGreaterThan63(char *op, size_t offset, size_t len) -{ - DCHECK((len < 65536ul) && (len >= 63ul) && (offset < kBlockSize)); - if (PITHY_EXPECT_T(offset < 65536ul)) { - if (PITHY_EXPECT_T(len < (256ul + 63ul))) { - *op++ = PITHY_COPY_2_BYTE_OFFSET | (62 << 2); - pithy_StoreHost16(op, offset); - op += 2ul; - *op++ = (len - 63ul); - } else { - *op++ = PITHY_COPY_2_BYTE_OFFSET | (63 << 2); - pithy_StoreHost16(op, offset); - op += 2ul; - pithy_StoreHost16(op, len); - op += 2ul; - } - } else { - if (PITHY_EXPECT_T(len < (256ul + 63ul))) { - *op++ = PITHY_COPY_3_BYTE_OFFSET | (62 << 2); - pithy_StoreHost24(op, offset); - op += 3ul; - *op++ = (len - 63ul); - } else { - *op++ = PITHY_COPY_3_BYTE_OFFSET | (63 << 2); - pithy_StoreHost24(op, offset); - op += 3ul; - pithy_StoreHost16(op, len); - op += 2ul; - } - } - return (op); -} - -PITHY_STATIC_INLINE char *pithy_EmitCopyLessThan63(char *op, size_t offset, size_t len) -{ - DCHECK((len < 63ul) && (len >= 4ul) && (offset < kBlockSize)); - if (PITHY_EXPECT_T(len < 12ul) && PITHY_EXPECT_T(offset < 2048ul)) { - int lenMinus4 = len - 4l; - DCHECK(lenMinus4 < 8l); - *op++ = PITHY_COPY_1_BYTE_OFFSET | (lenMinus4 << 2) | ((offset >> 8) << 5); - *op++ = offset & 0xff; - } else { - if (PITHY_EXPECT_T(offset < 65536ul)) { - *op++ = PITHY_COPY_2_BYTE_OFFSET | ((len - 1ul) << 2); - pithy_StoreHost16(op, offset); - op += 2ul; - } else { - *op++ = PITHY_COPY_3_BYTE_OFFSET | ((len - 1ul) << 2); - pithy_StoreHost24(op, offset); - op += 3ul; - } - } - return (op); -} - -PITHY_STATIC_INLINE char *pithy_EmitCopy(char *op, size_t offset, size_t len) -{ - while (PITHY_EXPECT_F(len >= 63ul)) { - op = pithy_EmitCopyGreaterThan63(op, offset, (len >= 65539ul) ? 65535ul : len); - len -= (len >= 65539ul) ? 65535ul : len; - } - DCHECK((len > 0ul) ? ((len >= 4ul) && (len < 63ul)) : 1); - if ( PITHY_EXPECT_T(len > 0ul)) { - op = pithy_EmitCopyLessThan63(op, offset, len); - len -= len; - } - return (op); -} - -size_t pithy_MaxCompressedLength(size_t inputLength) -{ - return ((inputLength >= PITHY_UNCOMPRESSED_MAX_LENGTH) ? 0ul : 32ul + inputLength + (inputLength / 6ul)); -} - -size_t pithy_Compress(const char *uncompressed, - size_t uncompressedLength, - char *compressedOut, - size_t compressedOutLength, - int compressionLevel) -{ - - if ((pithy_MaxCompressedLength(uncompressedLength) > compressedOutLength) || - (uncompressedLength >= PITHY_UNCOMPRESSED_MAX_LENGTH) || - (uncompressedLength == 0ul)) { - return (0ul); - } - - char *compressedPtr = compressedOut; - - size_t hashTableSize = 0x100ul, maxHashTableSize = 1 << (12ul + (((compressionLevel < 0) ? 0 : - (compressionLevel > 9) ? 9 : compressionLevel) / 2ul)); - while ((hashTableSize < maxHashTableSize) && (hashTableSize < uncompressedLength)) { - hashTableSize <<= 1; - } - pithy_hashOffset_t stackHashTable[hashTableSize], *heapHashTable = NULL, *hashTable = stackHashTable; - if ((sizeof(pithy_hashOffset_t) * hashTableSize) >= (1024ul * 128ul)) { - if ((heapHashTable = malloc(sizeof(pithy_hashOffset_t) * hashTableSize)) == NULL) { - return (0ul); - } - hashTable = heapHashTable; - } - size_t x = 0ul; - for (x = 0ul; x < hashTableSize; x++) { - hashTable[x] = uncompressed; - } - -#ifndef NDEBUG - char *const compressedOutEnd = compressedOut + compressedOutLength; -#endif - compressedPtr = pithy_Encode32(compressedPtr, uncompressedLength); - DCHECK(compressedPtr <= compressedOutEnd); - { - const char *uncompressedPtr = uncompressed; - const char *uncompressedEnd = uncompressed + uncompressedLength; - const char *nextEmitUncompressedPtr = uncompressedPtr; - DCHECK((hashTableSize & (hashTableSize - 1l)) == 0); - const int shift = 32 - pithy_Log2Floor(hashTableSize); - DCHECK((UINT32_MAX >> shift) == (hashTableSize - 1l)); - size_t skip = 32ul; - - if (PITHY_EXPECT_T(uncompressedLength >= 15ul)) { - const char *uncompressedEndLimit = uncompressed + uncompressedLength - 15ul; - uint32_t uncompressedBytes; - uint32_t nextUncompressedBytes = pithy_Load32(++uncompressedPtr); - uint32_t nextUncompressedBytesHash = pithy_HashBytes(nextUncompressedBytes, shift); - - while (1) { - DCHECK(nextEmitUncompressedPtr < uncompressedPtr); - const char *nextUncompressedPtr = uncompressedPtr, *matchCandidatePtr = NULL; - - skip = (((skip - 32ul) * 184ul) >> 8) + 32ul; - - do { - uncompressedPtr = nextUncompressedPtr; - uncompressedBytes = nextUncompressedBytes; - uint32_t uncompressedBytesHash = nextUncompressedBytesHash; - DCHECK(uncompressedBytesHash == pithy_HashBytes(uncompressedBytes, shift)); - size_t skipBytesBetweenHashLookups = skip >> 5; - skip += ((skip * 7ul) >> 11) + 1ul; - nextUncompressedPtr = uncompressedPtr + skipBytesBetweenHashLookups; - if (PITHY_EXPECT_F(nextUncompressedPtr > uncompressedEndLimit)) { - goto emit_remainder; - } - nextUncompressedBytes = pithy_Load32(nextUncompressedPtr); - nextUncompressedBytesHash = pithy_HashBytes(nextUncompressedBytes, shift); - matchCandidatePtr = hashTable[uncompressedBytesHash]; - DCHECK((matchCandidatePtr >= uncompressed) && (matchCandidatePtr < uncompressedPtr)); - hashTable[uncompressedBytesHash] = uncompressedPtr; - } while ((PITHY_EXPECT_T(uncompressedBytes != pithy_Load32(matchCandidatePtr))) || - PITHY_EXPECT_F((uncompressedPtr - matchCandidatePtr) >= ((int)(kBlockSize - 2ul)))); - - DCHECK((nextEmitUncompressedPtr + 16ul) <= uncompressedEnd); - compressedPtr = pithy_EmitLiteral(compressedPtr, - nextEmitUncompressedPtr, - uncompressedPtr - nextEmitUncompressedPtr, - 1); - DCHECK(compressedPtr <= compressedOutEnd); - uint64_t uncompressedBytes64 = 0ul; - - do { - if (compressionLevel > 2) { - DCHECK((uncompressedPtr + 5ul) <= uncompressedEnd); - uncompressedBytes64 = pithy_Load64((uint64_t*)uncompressedPtr + 1ul); - hashTable[pithy_HashBytes(pithy_GetUint32AtOffset(uncompressedBytes64, 0u), shift)] = - uncompressedPtr + 1ul; - if (compressionLevel > 4) { - hashTable[pithy_HashBytes(pithy_GetUint32AtOffset(uncompressedBytes64, 1u), shift)] = - uncompressedPtr + 2ul; - } - } - - DCHECK((matchCandidatePtr >= uncompressed) && - (matchCandidatePtr <= uncompressedPtr) && - ((matchCandidatePtr + 4ul) <= uncompressedEnd) && - ((uncompressedPtr + 4ul) <= uncompressedEnd)); - - size_t matchCandidateLength = 4ul + pithy_FindMatchLength(matchCandidatePtr + 4ul, - uncompressedPtr + 4ul, - uncompressedEnd); - DCHECK(((matchCandidatePtr + matchCandidateLength) >= uncompressed) && - ((matchCandidatePtr + matchCandidateLength) <= uncompressedEnd)); - DCHECK(0 == memcmp(uncompressedPtr, matchCandidatePtr, matchCandidateLength)); - compressedPtr = pithy_EmitCopy(compressedPtr, - uncompressedPtr - matchCandidatePtr, - matchCandidateLength); - DCHECK(compressedPtr <= compressedOutEnd); - uncompressedPtr += matchCandidateLength; - DCHECK(uncompressedPtr <= uncompressedEnd); - nextEmitUncompressedPtr = uncompressedPtr; - if (PITHY_EXPECT_F(uncompressedPtr >= uncompressedEndLimit)) { - goto emit_remainder; - } - - DCHECK(((uncompressedPtr - 3ul) >= uncompressed) && (uncompressedPtr <= uncompressedEnd)); - - uncompressedBytes64 = pithy_Load64((uint64_t*)uncompressedPtr - 3ul); - - if (compressionLevel > 0) { - if (compressionLevel > 8) { - hashTable[pithy_HashBytes(pithy_GetUint32AtOffset(uncompressedBytes64, 0u), shift)] = - uncompressedPtr - 3ul; - } - if (compressionLevel > 6) { - hashTable[pithy_HashBytes(pithy_GetUint32AtOffset(uncompressedBytes64, 1u), shift)] = - uncompressedPtr - 2ul; - } - hashTable[pithy_HashBytes(pithy_GetUint32AtOffset(uncompressedBytes64, 2u), shift)] = - uncompressedPtr - 1ul; - } - - uncompressedBytes = pithy_GetUint32AtOffset(uncompressedBytes64, 3u); - uint32_t uncompressedBytesHash = pithy_HashBytes(uncompressedBytes, shift); - matchCandidatePtr = hashTable[uncompressedBytesHash]; - DCHECK((matchCandidatePtr >= uncompressed) && (matchCandidatePtr < uncompressedPtr)); - hashTable[uncompressedBytesHash] = uncompressedPtr; - } while (PITHY_EXPECT_F(uncompressedBytes == pithy_Load32(matchCandidatePtr)) && - PITHY_EXPECT_T((uncompressedPtr - matchCandidatePtr) < ((int)(kBlockSize - 2ul)))); - - nextUncompressedBytes = pithy_GetUint32AtOffset(uncompressedBytes64, 4u); - nextUncompressedBytesHash = pithy_HashBytes(nextUncompressedBytes, shift); - uncompressedPtr++; - } - } - -emit_remainder: - if (nextEmitUncompressedPtr < uncompressedEnd) { - compressedPtr = pithy_EmitLiteral(compressedPtr, - nextEmitUncompressedPtr, - uncompressedEnd - nextEmitUncompressedPtr, - 0); - } - } - - pithy_Store32(compressedPtr, 0); - compressedPtr += 4; - - DCHECK((size_t)(compressedPtr - compressedOut) <= compressedOutLength); - if (heapHashTable != NULL) { - free(heapHashTable); - heapHashTable = NULL; - hashTable = NULL; - } - return (compressedPtr - compressedOut); -} - - -static const uint32_t pithy_wordmask[] = { - 0u, 0xffu, 0xffffu, 0xffffffu, 0xffffffffu -}; - - -static const uint16_t pithy_charTable[256] = { - 0x0001, 0x0804, 0x1001, 0x1801, 0x0002, 0x0805, 0x1002, 0x1802, - 0x0003, 0x0806, 0x1003, 0x1803, 0x0004, 0x0807, 0x1004, 0x1804, - 0x0005, 0x0808, 0x1005, 0x1805, 0x0006, 0x0809, 0x1006, 0x1806, - 0x0007, 0x080a, 0x1007, 0x1807, 0x0008, 0x080b, 0x1008, 0x1808, - 0x0009, 0x0904, 0x1009, 0x1809, 0x000a, 0x0905, 0x100a, 0x180a, - 0x000b, 0x0906, 0x100b, 0x180b, 0x000c, 0x0907, 0x100c, 0x180c, - 0x000d, 0x0908, 0x100d, 0x180d, 0x000e, 0x0909, 0x100e, 0x180e, - 0x000f, 0x090a, 0x100f, 0x180f, 0x0010, 0x090b, 0x1010, 0x1810, - 0x0011, 0x0a04, 0x1011, 0x1811, 0x0012, 0x0a05, 0x1012, 0x1812, - 0x0013, 0x0a06, 0x1013, 0x1813, 0x0014, 0x0a07, 0x1014, 0x1814, - 0x0015, 0x0a08, 0x1015, 0x1815, 0x0016, 0x0a09, 0x1016, 0x1816, - 0x0017, 0x0a0a, 0x1017, 0x1817, 0x0018, 0x0a0b, 0x1018, 0x1818, - 0x0019, 0x0b04, 0x1019, 0x1819, 0x001a, 0x0b05, 0x101a, 0x181a, - 0x001b, 0x0b06, 0x101b, 0x181b, 0x001c, 0x0b07, 0x101c, 0x181c, - 0x001d, 0x0b08, 0x101d, 0x181d, 0x001e, 0x0b09, 0x101e, 0x181e, - 0x001f, 0x0b0a, 0x101f, 0x181f, 0x0020, 0x0b0b, 0x1020, 0x1820, - 0x0021, 0x0c04, 0x1021, 0x1821, 0x0022, 0x0c05, 0x1022, 0x1822, - 0x0023, 0x0c06, 0x1023, 0x1823, 0x0024, 0x0c07, 0x1024, 0x1824, - 0x0025, 0x0c08, 0x1025, 0x1825, 0x0026, 0x0c09, 0x1026, 0x1826, - 0x0027, 0x0c0a, 0x1027, 0x1827, 0x0028, 0x0c0b, 0x1028, 0x1828, - 0x0029, 0x0d04, 0x1029, 0x1829, 0x002a, 0x0d05, 0x102a, 0x182a, - 0x002b, 0x0d06, 0x102b, 0x182b, 0x002c, 0x0d07, 0x102c, 0x182c, - 0x002d, 0x0d08, 0x102d, 0x182d, 0x002e, 0x0d09, 0x102e, 0x182e, - 0x002f, 0x0d0a, 0x102f, 0x182f, 0x0030, 0x0d0b, 0x1030, 0x1830, - 0x0031, 0x0e04, 0x1031, 0x1831, 0x0032, 0x0e05, 0x1032, 0x1832, - 0x0033, 0x0e06, 0x1033, 0x1833, 0x0034, 0x0e07, 0x1034, 0x1834, - 0x0035, 0x0e08, 0x1035, 0x1835, 0x0036, 0x0e09, 0x1036, 0x1836, - 0x0037, 0x0e0a, 0x1037, 0x1837, 0x0038, 0x0e0b, 0x1038, 0x1838, - 0x0039, 0x0f04, 0x1039, 0x1839, 0x003a, 0x0f05, 0x103a, 0x183a, - 0x003b, 0x0f06, 0x103b, 0x183b, 0x003c, 0x0f07, 0x103c, 0x183c, - 0x0801, 0x0f08, 0x103d, 0x183d, 0x1001, 0x0f09, 0x103e, 0x183e, - 0x1801, 0x0f0a, 0x103f, 0x183f, 0x2001, 0x0f0b, 0x1040, 0x1840 -}; - - -int pithy_GetDecompressedLength(const char *compressed, size_t compressedLength, size_t *decompressedOutLengthResult) -{ - const char *compressedEnd = compressed + compressedLength; - size_t decompressedLength = 0ul; - if (pithy_Parse32WithLimit(compressed, compressedEnd, &decompressedLength) != NULL) { - *decompressedOutLengthResult = decompressedLength; - return (1); - } else { - return (0); - } -} - - -int pithy_Decompress(const char *compressed, size_t compressedLength, char *decompressedOut, - size_t decompressedOutLength) -{ - const char *nextCompressedPtr = NULL, *compressedEnd = (compressed + compressedLength); - size_t parsedDecompressedLength = 0ul; - if (((nextCompressedPtr = pithy_Parse32WithLimit(compressed, compressedEnd, &parsedDecompressedLength)) == NULL) || - (parsedDecompressedLength > decompressedOutLength)) { - return (0); - } - - char *decompressedPtr = decompressedOut, *decompressedEnd = decompressedOut + parsedDecompressedLength; - - while (1) { - const char *compressedPtr = nextCompressedPtr; - DCHECK(compressedPtr <= compressedEnd); - if (PITHY_EXPECT_F(compressedPtr >= compressedEnd)) { - break; - } - - const unsigned char c = *((const unsigned char *)(compressedPtr++)); - const unsigned char cLowerBits = (c & 0x3u); - const int spaceLeft = (decompressedEnd - decompressedPtr); - - if ((cLowerBits == PITHY_LITERAL)) { - size_t literalLength = (c >> 2) + 1; - if (PITHY_EXPECT_T(literalLength <= 16ul) && PITHY_EXPECT_T((compressedEnd - compressedPtr) >= 16l) && - PITHY_EXPECT_T(spaceLeft >= 16l)) { - pithy_Move128(decompressedPtr, compressedPtr); - } else { - if (PITHY_EXPECT_F(literalLength > 60)) { - if (PITHY_EXPECT_F((compressedPtr + 4) > compressedEnd)) { - break; - } - size_t literalLengthBytes = literalLength - 60; - literalLength = (pithy_LoadHost32(compressedPtr) & pithy_wordmask[literalLengthBytes]) + 1; - compressedPtr += literalLengthBytes; - } - if (PITHY_EXPECT_F(spaceLeft < (int)literalLength) || - PITHY_EXPECT_F((compressedPtr + literalLength) > compressedEnd)) { - break; - } - memcpy(decompressedPtr, compressedPtr, literalLength); - } - nextCompressedPtr = compressedPtr + literalLength; - decompressedPtr += literalLength; - } else { - const uint32_t entry = pithy_charTable[c]; - const size_t trailer = pithy_LoadHost32(compressedPtr) & pithy_wordmask[cLowerBits]; - size_t length = entry & 0xffu; - const size_t copyOffset = ((entry & 0x700u) + trailer); - - compressedPtr += cLowerBits; - - DCHECK((compressedPtr <= compressedEnd) && (copyOffset > 0ul) && (spaceLeft > 0l) && (length > 0ul)); - - if (PITHY_EXPECT_F((decompressedPtr - decompressedOut) <= ((int)copyOffset - 1l))) { - break; - } - if (PITHY_EXPECT_T(length <= 16ul) && - PITHY_EXPECT_T(copyOffset >= 16ul) && - PITHY_EXPECT_T(spaceLeft >= 16l)) { - pithy_Move128(decompressedPtr, decompressedPtr - copyOffset); - } else { - if (PITHY_EXPECT_F(length >= 63ul)) { - if (PITHY_EXPECT_T(length == 63ul)) { - if (PITHY_EXPECT_F((compressedPtr + 1) > compressedEnd)) { - break; - } - length = (*((unsigned char *)compressedPtr++)) + 63ul; - } else { - if (PITHY_EXPECT_F((compressedPtr + 2) > compressedEnd)) { - break; - } - length = pithy_LoadHost16(compressedPtr); - compressedPtr += 2ul; - } - } - - char *copyFrom = decompressedPtr - copyOffset, *copyTo = decompressedPtr; - int copyLength = (int)length; - - if (PITHY_EXPECT_F(copyLength > 256l) && PITHY_EXPECT_T(copyOffset > (size_t)copyLength)) { - if (PITHY_EXPECT_F(spaceLeft < copyLength)) { - break; - } - memcpy(copyTo, copyFrom, copyLength); - } else { - if (PITHY_EXPECT_T(spaceLeft >= (copyLength + 24)) && PITHY_EXPECT_T(copyLength > 0l)) { - while ((copyTo - copyFrom) < 16l) { - pithy_Move128(copyTo, copyFrom); - copyLength -= copyTo - copyFrom; - copyTo += copyTo - copyFrom; - } - while (copyLength > 0l) { - pithy_Move128(copyTo, copyFrom); - copyFrom += 16l; - copyTo += 16l; - copyLength -= 16l; - } - } else { - if (PITHY_EXPECT_F(spaceLeft < copyLength) || PITHY_EXPECT_F(copyLength <= 0l)) { - break; - } - do { - *copyTo++ = *copyFrom++; - } while (--copyLength > 0l); - } - } - } - nextCompressedPtr = compressedPtr; - decompressedPtr += length; - } - } - - return (decompressedPtr == decompressedEnd); -} diff --git a/TESTS/mbed_hal/trng/pithy/pithy.h b/TESTS/mbed_hal/trng/pithy/pithy.h deleted file mode 100644 index 056ae1a..0000000 --- a/TESTS/mbed_hal/trng/pithy/pithy.h +++ /dev/null @@ -1,64 +0,0 @@ -// -// pithy.h -// http://github.com/johnezang/pithy -// Licensed under the terms of the BSD License, as specified below. -// -// SPDX-License-Identifier: BSD-3-Clause - -/* - Copyright (c) 2011, John Engelhart - - All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - * Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - - * Neither the name of the Zang Industries nor the names of its - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED - TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -#ifndef _PITHY_H_ -#define _PITHY_H_ - -// compressionLevel >= 0 && compressionLevel <= 9. Values out side this range will be clamped to this range. -size_t pithy_Compress (const char *uncompressed, size_t uncompressedLength, char *compressedOut, - size_t compressedOutLength, int compressionLevel); -int pithy_Decompress(const char *compressed, size_t compressedLength, char *decompressedOut, - size_t decompressedOutLength); - -size_t pithy_MaxCompressedLength(size_t inputLength); -int pithy_GetDecompressedLength(const char *compressed, size_t compressedLength, - size_t *decompressedOutLengthResult); - -#endif // _PITHY_H_ - -#ifdef __cplusplus -} // extern "C" -#endif diff --git a/TESTS/mbed_hal/us_ticker/main.cpp b/TESTS/mbed_hal/us_ticker/main.cpp deleted file mode 100644 index 976b38f..0000000 --- a/TESTS/mbed_hal/us_ticker/main.cpp +++ /dev/null @@ -1,72 +0,0 @@ -/* mbed Microcontroller Library - * Copyright (c) 2017 ARM Limited - * 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. - */ -#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 -#else - -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); - - switch (p_ticker_info->bits) { - case 32: - TEST_ASSERT(p_ticker_info->frequency <= 100000000); - break; - - default: - TEST_ASSERT(p_ticker_info->frequency <= 8000000); - break; - } - - TEST_ASSERT(p_ticker_info->bits >= 16); - -#ifdef US_TICKER_PERIOD_NUM - TEST_ASSERT_UINT32_WITHIN(1, 1000000 * US_TICKER_PERIOD_DEN / US_TICKER_PERIOD_NUM, p_ticker_info->frequency); - TEST_ASSERT_EQUAL_UINT32(US_TICKER_MASK, ((uint64_t)1 << p_ticker_info->bits) - 1); -#endif -} - -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); -} - -#endif // !DEVICE_USTICKER diff --git a/TESTS/mbed_hal/us_ticker/us_ticker_api_tests.h b/TESTS/mbed_hal/us_ticker/us_ticker_api_tests.h deleted file mode 100644 index 4cfe203..0000000 --- a/TESTS/mbed_hal/us_ticker/us_ticker_api_tests.h +++ /dev/null @@ -1,51 +0,0 @@ -/* mbed Microcontroller Library - * Copyright (c) 2017-2017 ARM Limited - * 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. - */ - -/** \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: - * - counter frequency is between 250KHz and 8MHz for counters which are less than 32 bits wide - * - counter frequency is up to 100MHz for counters which are 32 bits wide - * - the counter is at least 16 bits wide. - */ -void us_ticker_info_test(void); - - -/**@}*/ - -#ifdef __cplusplus -} -#endif - -#endif - -/**@}*/ diff --git a/TESTS/mbed_hal/watchdog/main.cpp b/TESTS/mbed_hal/watchdog/main.cpp deleted file mode 100644 index 683e360..0000000 --- a/TESTS/mbed_hal/watchdog/main.cpp +++ /dev/null @@ -1,273 +0,0 @@ -/* - * Copyright (c) 2018-2019 Arm Limited and affiliates. - * 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. - */ -#if !DEVICE_WATCHDOG -#error [NOT_SUPPORTED] Watchdog not supported for this target -#else - -#include "greentea-client/test_env.h" -#include "hal/watchdog_api.h" -#include "mbed_wait_api.h" -#include "unity/unity.h" -#include "utest/utest.h" -#include "watchdog_api_tests.h" -#include "mbed.h" - -#include - -/* The shortest timeout value, this test suite is able to handle correctly. */ -#define WDG_MIN_TIMEOUT_MS 50UL - -// Do not set watchdog timeout shorter than WDG_MIN_TIMEOUT_MS, as it may -// cause the host-test-runner return 'TIMEOUT' instead of 'FAIL' / 'PASS' -// if watchdog performs reset during test suite teardown. -#define WDG_TIMEOUT_MS 100UL - -#define MSG_VALUE_DUMMY "0" -#define MSG_VALUE_LEN 24 -#define MSG_KEY_LEN 24 - -#define MSG_KEY_DEVICE_READY "ready" -#define MSG_KEY_START_CASE "start_case" -#define MSG_KEY_DEVICE_RESET "reset_on_case_teardown" - -/* To prevent a loss of Greentea data, the serial buffers have to be flushed - * before the UART peripheral shutdown. The UART shutdown happens when the - * device is entering the deepsleep mode or performing a reset. - * - * With the current API, it is not possible to check if the hardware buffers - * are empty. However, it is possible to determine the time required for the - * buffers to flush. - * - * Assuming the biggest Tx FIFO of 128 bytes (as for CY8CPROTO_062_4343W) - * and a default UART config (9600, 8N1), flushing the Tx FIFO wold take: - * (1 start_bit + 8 data_bits + 1 stop_bit) * 128 * 1000 / 9600 = 133.3 ms. - * To be on the safe side, set the wait time to 150 ms. - */ -#define SERIAL_FLUSH_TIME_MS 150 - -int CASE_INDEX_START; -int CASE_INDEX_CURRENT; -bool CASE_IGNORED = false; - -using utest::v1::Case; -using utest::v1::Specification; -using utest::v1::Harness; - -const watchdog_config_t WDG_CONFIG_DEFAULT = { .timeout_ms = WDG_TIMEOUT_MS }; - -void test_max_timeout_is_valid() -{ - TEST_ASSERT(hal_watchdog_get_platform_features().max_timeout > 1UL); -} - -void test_restart_is_possible() -{ - watchdog_features_t features = hal_watchdog_get_platform_features(); - if (!features.disable_watchdog) { - CASE_IGNORED = true; - TEST_IGNORE_MESSAGE("Disabling watchdog not supported for this platform"); - return; - } - TEST_ASSERT(features.update_config); -} - -void test_stop() -{ - watchdog_features_t features = hal_watchdog_get_platform_features(); - if (!features.disable_watchdog) { - TEST_ASSERT_EQUAL(WATCHDOG_STATUS_NOT_SUPPORTED, hal_watchdog_stop()); - CASE_IGNORED = true; - TEST_IGNORE_MESSAGE("Disabling watchdog not supported for this platform"); - return; - } - - TEST_ASSERT_EQUAL(WATCHDOG_STATUS_OK, hal_watchdog_stop()); - - TEST_ASSERT_EQUAL(WATCHDOG_STATUS_OK, hal_watchdog_init(&WDG_CONFIG_DEFAULT)); - TEST_ASSERT_EQUAL(WATCHDOG_STATUS_OK, hal_watchdog_stop()); - // Make sure that a disabled watchdog does not reset the core. - ThisThread::sleep_for(2 * WDG_TIMEOUT_MS); // Watchdog should fire before twice the timeout value. - - TEST_ASSERT_EQUAL(WATCHDOG_STATUS_OK, hal_watchdog_stop()); -} - -void test_update_config() -{ - watchdog_features_t features = hal_watchdog_get_platform_features(); - if (!features.update_config) { - CASE_IGNORED = true; - TEST_IGNORE_MESSAGE("Updating watchdog config not supported for this platform"); - return; - } - - watchdog_config_t config = WDG_CONFIG_DEFAULT; - uint32_t timeouts[] = { - features.max_timeout / 4, - features.max_timeout / 8, - features.max_timeout / 16 - }; - int num_timeouts = sizeof timeouts / sizeof timeouts[0]; - - for (size_t i = 0; i < num_timeouts; i++) { - if (timeouts[i] < WDG_MIN_TIMEOUT_MS) { - CASE_IGNORED = true; - TEST_IGNORE_MESSAGE("Requested timeout value is too short -- ignoring test case."); - return; - } - - config.timeout_ms = timeouts[i]; - TEST_ASSERT_EQUAL(WATCHDOG_STATUS_OK, hal_watchdog_init(&config)); - uint32_t reload_value = hal_watchdog_get_reload_value(); - // The watchdog should trigger at, or after the timeout value. - TEST_ASSERT(reload_value >= timeouts[i]); - // The watchdog should trigger before twice the timeout value. - TEST_ASSERT(reload_value < 2 * timeouts[i]); - } -} - -utest::v1::status_t case_setup_sync_on_reset(const Case *const source, const size_t index_of_case) -{ - CASE_INDEX_CURRENT = index_of_case; - CASE_IGNORED = false; - return utest::v1::greentea_case_setup_handler(source, index_of_case); -} - -utest::v1::status_t case_teardown_sync_on_reset(const Case *const source, const size_t passed, const size_t failed, - const utest::v1::failure_t failure) -{ - if (CASE_IGNORED) { - return utest::v1::greentea_case_teardown_handler(source, passed, failed, failure); - } - // Start kicking the watchdog during teardown. - hal_watchdog_kick(); - Ticker wdg_kicking_ticker; - wdg_kicking_ticker.attach_us(mbed::callback(hal_watchdog_kick), 20000); - utest::v1::status_t status = utest::v1::greentea_case_teardown_handler(source, passed, failed, failure); - if (failed) { - /* Return immediately and skip the device reset, if the test case failed. - * Provided that the device won't be restarted by other means (i.e. watchdog timer), - * this should allow the test suite to finish in a defined manner - * and report failure to host. - * In case of watchdog reset during test suite teardown, the loss of serial - * connection is possible, so the host-test-runner may return 'TIMEOUT' - * instead of 'FAIL'. - */ - return status; - } - greentea_send_kv(MSG_KEY_DEVICE_RESET, CASE_INDEX_START + CASE_INDEX_CURRENT); - utest_printf("The device will now restart.\n"); - ThisThread::sleep_for(SERIAL_FLUSH_TIME_MS); // Wait for the serial buffers to flush. - NVIC_SystemReset(); - return status; // Reset is instant so this line won't be reached. -} - -utest::v1::status_t case_teardown_wdg_stop_or_reset(const Case *const source, const size_t passed, const size_t failed, - const utest::v1::failure_t failure) -{ - if (CASE_IGNORED) { - return utest::v1::greentea_case_teardown_handler(source, passed, failed, failure); - } - watchdog_features_t features = hal_watchdog_get_platform_features(); - if (features.disable_watchdog) { - hal_watchdog_stop(); - return utest::v1::greentea_case_teardown_handler(source, passed, failed, failure); - } - - return case_teardown_sync_on_reset(source, passed, failed, failure); -} - -template -void test_init() -{ - if (timeout_ms < WDG_MIN_TIMEOUT_MS) { - CASE_IGNORED = true; - TEST_IGNORE_MESSAGE("Requested timeout value is too short -- ignoring test case."); - return; - } - watchdog_config_t config = { .timeout_ms = timeout_ms }; - TEST_ASSERT_EQUAL(WATCHDOG_STATUS_OK, hal_watchdog_init(&config)); - uint32_t reload_value = hal_watchdog_get_reload_value(); - // The watchdog should trigger at, or after the timeout value. - TEST_ASSERT(reload_value >= timeout_ms); - // The watchdog should trigger before twice the timeout value. - TEST_ASSERT(reload_value < 2 * timeout_ms); -} - -void test_init_max_timeout() -{ - watchdog_features_t features = hal_watchdog_get_platform_features(); - watchdog_config_t config = { .timeout_ms = features.max_timeout }; - TEST_ASSERT_EQUAL(WATCHDOG_STATUS_OK, hal_watchdog_init(&config)); - // The watchdog should trigger at, or after the timeout value. - TEST_ASSERT(hal_watchdog_get_reload_value() >= features.max_timeout); -} - -int testsuite_setup_sync_on_reset(const size_t number_of_cases) -{ - GREENTEA_SETUP(45, "sync_on_reset"); - utest::v1::status_t status = utest::v1::greentea_test_setup_handler(number_of_cases); - if (status != utest::v1::STATUS_CONTINUE) { - return status; - } - - char key[MSG_KEY_LEN + 1] = { }; - char value[MSG_VALUE_LEN + 1] = { }; - - greentea_send_kv(MSG_KEY_DEVICE_READY, MSG_VALUE_DUMMY); - greentea_parse_kv(key, value, MSG_KEY_LEN, MSG_VALUE_LEN); - - if (strcmp(key, MSG_KEY_START_CASE) != 0) { - utest_printf("Invalid message key.\n"); - return utest::v1::STATUS_ABORT; - } - - char *tailptr = NULL; - CASE_INDEX_START = (int) strtol(value, &tailptr, 10); - if (*tailptr != '\0' || CASE_INDEX_START < 0) { - utest_printf("Invalid start case index received from host\n"); - return utest::v1::STATUS_ABORT; - } - - utest_printf("Starting with test case index %i of all %i defined test cases.\n", CASE_INDEX_START, number_of_cases); - return CASE_INDEX_START; -} - -Case cases[] = { - Case("Platform feature max_timeout is valid", test_max_timeout_is_valid), - Case("Stopped watchdog can be started again", test_restart_is_possible), - Case("Watchdog can be stopped", test_stop), - - Case("Update config with multiple init calls", - (utest::v1::case_setup_handler_t) case_setup_sync_on_reset, - test_update_config, - (utest::v1::case_teardown_handler_t) case_teardown_wdg_stop_or_reset), - - Case("Init, 100 ms", (utest::v1::case_setup_handler_t) case_setup_sync_on_reset, - test_init<100UL>, (utest::v1::case_teardown_handler_t) case_teardown_sync_on_reset), - Case("Init, max_timeout", (utest::v1::case_setup_handler_t) case_setup_sync_on_reset, - test_init_max_timeout, (utest::v1::case_teardown_handler_t) case_teardown_sync_on_reset), -}; - -Specification specification((utest::v1::test_setup_handler_t) testsuite_setup_sync_on_reset, cases); - -int main() -{ - // Harness will start with a test case index provided by host script. - return !Harness::run(specification); -} - -#endif // !DEVICE_WATCHDOG \ No newline at end of file diff --git a/TESTS/mbed_hal/watchdog/watchdog_api_tests.h b/TESTS/mbed_hal/watchdog/watchdog_api_tests.h deleted file mode 100644 index 15e8d5e..0000000 --- a/TESTS/mbed_hal/watchdog/watchdog_api_tests.h +++ /dev/null @@ -1,103 +0,0 @@ -/* - * Copyright (c) 2018-2019 Arm Limited and affiliates. - * 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. - */ - -/** - * @addtogroup hal_watchdog_tests - * @{ - */ - -#ifndef MBED_HAL_WATCHDOG_API_TESTS_H -#define MBED_HAL_WATCHDOG_API_TESTS_H - -#if DEVICE_WATCHDOG - -/** Test max_timeout validity - * - * Given a device supporting Watchdog HAL API, - * when @a hal_watchdog_get_platform_features() is called, - * then max_timeout member of returned watchdog_features_t struct is greater than 1. - */ -void test_max_timeout_is_valid(); - -/** Test Watchdog features if a stopped Watchdog can be started again - * - * Given a device supporting Watchdog HAL API, - * when the device supports the @a disable_watchdog feature, - * then the device also supports @a update_config feature. - */ -void test_restart_is_possible(); - -/** Test Watchdog stop - * - * Given a device without a support for the @a disable_watchdog feature, - * when @a hal_watchdog_stop() is called, - * then WATCHDOG_STATUS_NOT_SUPPORTED is returned. - * - * Otherwise, given the device with @a disable_watchdog feature support: - * - * Given the Watchdog is *NOT* running, - * when @a hal_watchdog_stop() is called, - * then WATCHDOG_STATUS_OK is returned. - * - * Given the Watchdog is running, - * when @a hal_watchdog_stop() is called before the timeout expires, - * then WATCHDOG_STATUS_OK is returned and the device is not restarted. - * - * Given the Watchdog is *NOT* running (it has already been stopped), - * when @a hal_watchdog_stop() is called, - * then WATCHDOG_STATUS_OK is returned. - */ -void test_stop(); - -/** Test Watchdog init multiple times - * - * Given a set of unique timeout values, - * when @a config.timeout_ms is set to each of these values (T), - * then, for every value T, @a hal_watchdog_init() returns @a WATCHDOG_STATUS_OK - * and @a hal_watchdog_get_reload_value() returns a reload value R - * and T <= R < 2 * T. - */ -void test_update_config(); - -/** Test Watchdog init with a valid config - * - * Given @a config.timeout_ms is set to T ms, - * which is within supported Watchdog timeout range, - * when @a hal_watchdog_init() is called, - * then @a WATCHDOG_STATUS_OK is returned - * and @a hal_watchdog_get_reload_value() returns a reload value R - * and T <= R < 2 * T. - */ -template -void test_init(); - -/** Test Watchdog init with a max_timeout - * - * Given @a config.timeout_ms is set to max_timeout, - * which is a value returned by @a hal_watchdog_get_platform_features(), - * when @a hal_watchdog_init() is called, - * then @a WATCHDOG_STATUS_OK is returned - * and @a hal_watchdog_get_reload_value() returns max_timeout. - */ -void test_init_max_timeout(); - -#endif - -#endif - -/** @}*/ - diff --git a/TESTS/mbed_hal/watchdog_reset/main.cpp b/TESTS/mbed_hal/watchdog_reset/main.cpp deleted file mode 100644 index 4d9b794..0000000 --- a/TESTS/mbed_hal/watchdog_reset/main.cpp +++ /dev/null @@ -1,332 +0,0 @@ -/* - * Copyright (c) 2018-2019 Arm Limited and affiliates. - * 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. - */ -#if !DEVICE_WATCHDOG -#error [NOT_SUPPORTED] Watchdog not supported for this target -#else - -#include "greentea-client/test_env.h" -#include "utest/utest.h" -#include "unity/unity.h" -#include "hal/watchdog_api.h" -#include "watchdog_reset_tests.h" -#include "mbed.h" - -#define TIMEOUT_MS 100UL - -/* This value is used to calculate the time to kick the watchdog. - * Given the watchdog timeout is set to TIMEOUT_MS, the kick will be performed - * with a delay of (TIMEOUT_MS - KICK_ADVANCE_MS), after the init. - * - * It is common for the watchdog peripheral to use a low precision clock source, - * e.g. the LSI RC acts as a clock source for the IWDG on ST targets. - * According to the ST spec, the 37 kHz LSI is guaranteed to have a frequency - * around 37-38 kHz, but the actual frequency range guaranteed by the production - * tests is 26 kHz up to 56 kHz. - * Bearing that in mind, a 100 ms timeout value may actually last as long as 142 ms - * and as short as 66 ms. - * The value of 35 ms is used to cover the worst case scenario (66 ms). - */ -#define KICK_ADVANCE_MS 35UL - -#define MSG_VALUE_DUMMY "0" -#define CASE_DATA_INVALID 0xffffffffUL -#define CASE_DATA_PHASE2_OK 0xfffffffeUL - -#define MSG_VALUE_LEN 24 -#define MSG_KEY_LEN 24 - -#define MSG_KEY_DEVICE_READY "ready" -#define MSG_KEY_START_CASE "start_case" -#define MSG_KEY_DEVICE_RESET "dev_reset" - -/* To prevent a loss of Greentea data, the serial buffers have to be flushed - * before the UART peripheral shutdown. The UART shutdown happens when the - * device is entering the deepsleep mode or performing a reset. - * - * With the current API, it is not possible to check if the hardware buffers - * are empty. However, it is possible to determine the time required for the - * buffers to flush. - * - * Assuming the biggest Tx FIFO of 128 bytes (as for CY8CPROTO_062_4343W) - * and a default UART config (9600, 8N1), flushing the Tx FIFO wold take: - * (1 start_bit + 8 data_bits + 1 stop_bit) * 128 * 1000 / 9600 = 133.3 ms. - * To be on the safe side, set the wait time to 150 ms. - */ -#define SERIAL_FLUSH_TIME_MS 150 - -#define TIMEOUT_US (1000 * (TIMEOUT_MS)) -#define KICK_ADVANCE_US (1000 * (KICK_ADVANCE_MS)) -#define SERIAL_FLUSH_TIME_US (1000 * (SERIAL_FLUSH_TIME_MS)) - -using utest::v1::Case; -using utest::v1::Specification; -using utest::v1::Harness; - -struct testcase_data { - int index; - int start_index; - uint32_t received_data; -}; - -testcase_data current_case; - -Ticker wdg_kicking_ticker; - -bool send_reset_notification(testcase_data *tcdata, uint32_t delay_ms) -{ - char msg_value[12]; - int str_len = snprintf(msg_value, sizeof msg_value, "%02x,%08lx", tcdata->start_index + tcdata->index, delay_ms); - if (str_len < 0) { - utest_printf("Failed to compose a value string to be sent to host."); - return false; - } - greentea_send_kv(MSG_KEY_DEVICE_RESET, msg_value); - return true; -} - -void test_simple_reset() -{ - // Phase 2. -- verify the test results. - // Verify if this test case passed based on data received from host. - if (current_case.received_data != CASE_DATA_INVALID) { - TEST_ASSERT_EQUAL(CASE_DATA_PHASE2_OK, current_case.received_data); - current_case.received_data = CASE_DATA_INVALID; - return; - } - - // Phase 1. -- run the test code. - // Init the watchdog and wait for a device reset. - watchdog_config_t config = { TIMEOUT_MS }; - if (send_reset_notification(¤t_case, 2 * TIMEOUT_MS + SERIAL_FLUSH_TIME_MS) == false) { - TEST_ASSERT_MESSAGE(0, "Dev-host communication error."); - return; - } - wait_us(SERIAL_FLUSH_TIME_US); // Wait for the serial buffers to flush. - TEST_ASSERT_EQUAL(WATCHDOG_STATUS_OK, hal_watchdog_init(&config)); - // Watchdog should fire before twice the timeout value. - wait_us(2 * TIMEOUT_US); // Device reset expected. - - // Watchdog reset should have occurred during a wait above. - - hal_watchdog_kick(); - wdg_kicking_ticker.attach_us(mbed::callback(hal_watchdog_kick), 20000); // For testsuite failure handling. - TEST_ASSERT_MESSAGE(0, "Watchdog did not reset the device as expected."); -} - -#if DEVICE_SLEEP -void test_sleep_reset() -{ - // Phase 2. -- verify the test results. - if (current_case.received_data != CASE_DATA_INVALID) { - TEST_ASSERT_EQUAL(CASE_DATA_PHASE2_OK, current_case.received_data); - current_case.received_data = CASE_DATA_INVALID; - return; - } - - // Phase 1. -- run the test code. - watchdog_config_t config = { TIMEOUT_MS }; - if (send_reset_notification(¤t_case, 2 * TIMEOUT_MS + SERIAL_FLUSH_TIME_MS) == false) { - TEST_ASSERT_MESSAGE(0, "Dev-host communication error."); - return; - } - wait_us(SERIAL_FLUSH_TIME_US); // Wait for the serial buffers to flush. - TEST_ASSERT_EQUAL(WATCHDOG_STATUS_OK, hal_watchdog_init(&config)); - sleep_manager_lock_deep_sleep(); - if (sleep_manager_can_deep_sleep()) { - TEST_ASSERT_MESSAGE(0, "Deepsleep should be disallowed."); - return; - } - // Watchdog should fire before twice the timeout value. - ThisThread::sleep_for(2 * TIMEOUT_MS); // Device reset expected. - sleep_manager_unlock_deep_sleep(); - - // Watchdog reset should have occurred during the sleep above. - - hal_watchdog_kick(); - wdg_kicking_ticker.attach_us(mbed::callback(hal_watchdog_kick), 20000); // For testsuite failure handling. - TEST_ASSERT_MESSAGE(0, "Watchdog did not reset the device as expected."); -} - -#if DEVICE_LPTICKER -void test_deepsleep_reset() -{ - // Phase 2. -- verify the test results. - if (current_case.received_data != CASE_DATA_INVALID) { - TEST_ASSERT_EQUAL(CASE_DATA_PHASE2_OK, current_case.received_data); - current_case.received_data = CASE_DATA_INVALID; - return; - } - - // Phase 1. -- run the test code. - watchdog_config_t config = { TIMEOUT_MS }; - if (send_reset_notification(¤t_case, 2 * TIMEOUT_MS + SERIAL_FLUSH_TIME_MS) == false) { - TEST_ASSERT_MESSAGE(0, "Dev-host communication error."); - return; - } - wait_us(SERIAL_FLUSH_TIME_US); // Wait for the serial buffers to flush. - wait_us(SERIAL_FLUSH_TIME_US); // Wait for the serial buffers to flush. - TEST_ASSERT_EQUAL(WATCHDOG_STATUS_OK, hal_watchdog_init(&config)); - if (!sleep_manager_can_deep_sleep()) { - TEST_ASSERT_MESSAGE(0, "Deepsleep should be allowed."); - } - - // The Watchdog reset is allowed to be delayed up to twice the timeout - // value when the deepsleep mode is active. - // To make the test less sensitive to clock/wait accuracy, add 20% extra - // (making tha whole deepsleep wait equal to 2.2 * timeout). - ThisThread::sleep_for(220 * TIMEOUT_MS / 100); // Device reset expected. - - // Watchdog reset should have occurred during the deepsleep above. - - hal_watchdog_kick(); - wdg_kicking_ticker.attach_us(mbed::callback(hal_watchdog_kick), 20000); // For testsuite failure handling. - TEST_ASSERT_MESSAGE(0, "Watchdog did not reset the device as expected."); -} -#endif -#endif - -void test_restart_reset() -{ - watchdog_features_t features = hal_watchdog_get_platform_features(); - if (!features.disable_watchdog) { - TEST_IGNORE_MESSAGE("Disabling Watchdog not supported for this platform"); - return; - } - - // Phase 2. -- verify the test results. - if (current_case.received_data != CASE_DATA_INVALID) { - TEST_ASSERT_EQUAL(CASE_DATA_PHASE2_OK, current_case.received_data); - current_case.received_data = CASE_DATA_INVALID; - return; - } - - // Phase 1. -- run the test code. - watchdog_config_t config = { TIMEOUT_MS }; - TEST_ASSERT_EQUAL(WATCHDOG_STATUS_OK, hal_watchdog_init(&config)); - wait_us(TIMEOUT_US / 2); - TEST_ASSERT_EQUAL(WATCHDOG_STATUS_OK, hal_watchdog_stop()); - // Check that stopping the Watchdog prevents a device reset. - // The watchdog should trigger at, or after the timeout value. - // The watchdog should trigger before twice the timeout value. - wait_us(TIMEOUT_US / 2 + TIMEOUT_US); - - if (send_reset_notification(¤t_case, 2 * TIMEOUT_MS + SERIAL_FLUSH_TIME_MS) == false) { - TEST_ASSERT_MESSAGE(0, "Dev-host communication error."); - return; - } - wait_us(SERIAL_FLUSH_TIME_US); // Wait for the serial buffers to flush. - TEST_ASSERT_EQUAL(WATCHDOG_STATUS_OK, hal_watchdog_init(&config)); - // Watchdog should fire before twice the timeout value. - wait_us(2 * TIMEOUT_US); // Device reset expected. - - // Watchdog reset should have occurred during a wait above. - - hal_watchdog_kick(); - wdg_kicking_ticker.attach_us(mbed::callback(hal_watchdog_kick), 20000); // For testsuite failure handling. - TEST_ASSERT_MESSAGE(0, "Watchdog did not reset the device as expected."); -} - -void test_kick_reset() -{ - // Phase 2. -- verify the test results. - if (current_case.received_data != CASE_DATA_INVALID) { - TEST_ASSERT_EQUAL(CASE_DATA_PHASE2_OK, current_case.received_data); - current_case.received_data = CASE_DATA_INVALID; - return; - } - - // Phase 1. -- run the test code. - watchdog_config_t config = { TIMEOUT_MS }; - TEST_ASSERT_EQUAL(WATCHDOG_STATUS_OK, hal_watchdog_init(&config)); - for (int i = 3; i; i--) { - // The reset is prevented as long as the watchdog is kicked - // anytime before the timeout. - wait_us(TIMEOUT_US - KICK_ADVANCE_US); - hal_watchdog_kick(); - } - if (send_reset_notification(¤t_case, 2 * TIMEOUT_MS + SERIAL_FLUSH_TIME_MS) == false) { - TEST_ASSERT_MESSAGE(0, "Dev-host communication error."); - return; - } - wait_us(SERIAL_FLUSH_TIME_US); // Wait for the serial buffers to flush. - // Watchdog should fire before twice the timeout value. - wait_us(2 * TIMEOUT_US); // Device reset expected. - - // Watchdog reset should have occurred during a wait above. - - hal_watchdog_kick(); - wdg_kicking_ticker.attach_us(mbed::callback(hal_watchdog_kick), 20000); // For testsuite failure handling. - TEST_ASSERT_MESSAGE(0, "Watchdog did not reset the device as expected."); -} - -utest::v1::status_t case_setup(const Case *const source, const size_t index_of_case) -{ - current_case.index = index_of_case; - return utest::v1::greentea_case_setup_handler(source, index_of_case); -} - -int testsuite_setup(const size_t number_of_cases) -{ - GREENTEA_SETUP(90, "watchdog_reset"); - utest::v1::status_t status = utest::v1::greentea_test_setup_handler(number_of_cases); - if (status != utest::v1::STATUS_CONTINUE) { - return status; - } - - char key[MSG_KEY_LEN + 1] = { }; - char value[MSG_VALUE_LEN + 1] = { }; - - greentea_send_kv(MSG_KEY_DEVICE_READY, MSG_VALUE_DUMMY); - greentea_parse_kv(key, value, MSG_KEY_LEN, MSG_VALUE_LEN); - - if (strcmp(key, MSG_KEY_START_CASE) != 0) { - utest_printf("Invalid message key.\n"); - return utest::v1::STATUS_ABORT; - } - - int num_args = sscanf(value, "%02x,%08lx", &(current_case.start_index), &(current_case.received_data)); - if (num_args == 0 || num_args == EOF) { - utest_printf("Invalid data received from host\n"); - return utest::v1::STATUS_ABORT; - } - - utest_printf("This test suite is composed of %i test cases. Starting at index %i.\n", number_of_cases, - current_case.start_index); - return current_case.start_index; -} - -Case cases[] = { - Case("Watchdog reset", case_setup, test_simple_reset), -#if DEVICE_SLEEP - Case("Watchdog reset in sleep mode", case_setup, test_sleep_reset), -#if DEVICE_LPTICKER - Case("Watchdog reset in deepsleep mode", case_setup, test_deepsleep_reset), -#endif -#endif - Case("Watchdog started again", case_setup, test_restart_reset), - Case("Kicking the Watchdog prevents reset", case_setup, test_kick_reset), -}; - -Specification specification((utest::v1::test_setup_handler_t) testsuite_setup, cases); - -int main() -{ - // Harness will start with a test case index provided by host script. - return !Harness::run(specification); -} - -#endif // !DEVICE_WATCHDOG diff --git a/TESTS/mbed_hal/watchdog_reset/watchdog_reset_tests.h b/TESTS/mbed_hal/watchdog_reset/watchdog_reset_tests.h deleted file mode 100644 index 1833913..0000000 --- a/TESTS/mbed_hal/watchdog_reset/watchdog_reset_tests.h +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright (c) 2018-2019 Arm Limited and affiliates. - * 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. - */ - -/** - * @addtogroup hal_watchdog_tests - * @{ - */ - -#ifndef MBED_HAL_WATCHDOG_RESET_TESTS_H -#define MBED_HAL_WATCHDOG_RESET_TESTS_H - -#if DEVICE_WATCHDOG - -/** Test watchdog reset - * - * Given a device with a watchdog started, - * when a watchdog timeout expires, - * then the device is restarted. - */ -void test_simple_reset(); - -/** Test watchdog reset in sleep mode - * - * Given a device with a watchdog started, - * when the watchdog timeout expires while the device is in sleep mode, - * then the device is restarted. - */ -void test_sleep_reset(); - -/** Test watchdog reset in deepsleep mode - * - * Given a device with a watchdog started, - * when the watchdog timeout expires while the device is in deepsleep mode, - * then the device is restarted. - */ -void test_deepsleep_reset(); - -/** Test watchdog reset after watchdog restart - * - * Given a device with a watchdog started, - * when the watchdog is stopped before its timeout expires, - * then the device is not restarted. - * When the watchdog is started again and its timeout expires, - * then the device is restarted. - */ -void test_restart_reset(); - -/** Test watchdog kick - * - * Given a device with a watchdog started, - * when the watchdog is kicked before its timeout expires, - * then the device restart is prevented. - * When the watchdog is *NOT* kicked again before next timeout expires, - * then the device is restarted. - */ -void test_kick_reset(); - -#endif - -#endif - -/** @}*/ - diff --git a/TESTS/mbed_hal/watchdog_timing/main.cpp b/TESTS/mbed_hal/watchdog_timing/main.cpp deleted file mode 100644 index 23d5993..0000000 --- a/TESTS/mbed_hal/watchdog_timing/main.cpp +++ /dev/null @@ -1,227 +0,0 @@ -/* - * Copyright (c) 2018-2019 Arm Limited and affiliates. - * 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. - */ -#if !DEVICE_WATCHDOG -#error [NOT_SUPPORTED] Watchdog not supported for this target -#else - -#include "greentea-client/test_env.h" -#include "hal/watchdog_api.h" -#include "unity/unity.h" -#include "us_ticker_api.h" -#include "utest/utest.h" -#include "watchdog_timing_tests.h" -#include "mbed.h" - -#define TIMEOUT_LOWER_LIMIT_MS 1000ULL - -// A window to allow to process watchdog kick before timeout occurs. -#define TIME_WINDOW_MS 2UL - -#define MSG_VALUE_DUMMY "0" -#define CASE_DATA_INVALID 0xffffffffUL -#define CASE_DATA_PHASE2_OK 0xfffffffeUL - -#define MSG_VALUE_LEN 24 -#define MSG_KEY_LEN 24 - -#define MSG_KEY_DEVICE_READY "ready" -#define MSG_KEY_START_CASE "start_case" -#define MSG_KEY_HEARTBEAT "hb" -#define MSG_KEY_DEVICE_RESET "dev_reset" - -using utest::v1::Case; -using utest::v1::Specification; -using utest::v1::Harness; - -struct testcase_data { - int index; - int start_index; - uint32_t received_data; -}; - -testcase_data current_case; - -bool send_reset_notification(testcase_data *tcdata, uint32_t delay_ms) -{ - char msg_value[12]; - int str_len = snprintf(msg_value, sizeof msg_value, "%02x,%08lx", tcdata->start_index + tcdata->index, delay_ms); - if (str_len < 0) { - utest_printf("Failed to compose a value string to be sent to host."); - return false; - } - greentea_send_kv(MSG_KEY_DEVICE_RESET, msg_value); - return true; -} - -template -void test_timing() -{ - watchdog_features_t features = hal_watchdog_get_platform_features(); - if (timeout_ms > features.max_timeout) { - TEST_IGNORE_MESSAGE("Requested timeout value not supported for this target -- ignoring test case."); - return; - } - - // Phase 2. -- verify the test results. - // Verify the heartbeat time span sent by host is within given range: - // 1. The watchdog should trigger at, or after the timeout value. - // 2. The watchdog should trigger before twice the timeout value. - if (current_case.received_data != CASE_DATA_INVALID) { - // Provided the watchdog works as expected, the last timestamp received - // by the host will always be before the expected reset time. Because - // of that, the constraint no 1. is not verified. - TEST_ASSERT(current_case.received_data > 0); - TEST_ASSERT(current_case.received_data < 2 * timeout_ms); - current_case.received_data = CASE_DATA_INVALID; - return; - } - - // Phase 1. -- run the test code. - // Send heartbeat messages to host until the watchdeg resets the device. - const ticker_data_t *const us_ticker = get_us_ticker_data(); - us_timestamp_t current_ts, next_ts, expected_reset_ts, divider, ts_increment; - char msg_value[12]; - - watchdog_config_t config = { timeout_ms }; - TEST_ASSERT_EQUAL(WATCHDOG_STATUS_OK, hal_watchdog_init(&config)); - next_ts = ticker_read_us(us_ticker); - expected_reset_ts = next_ts + 1000ULL * timeout_ms; - - divider = 0x2ULL; - while (1) { - current_ts = ticker_read_us(us_ticker); - if (current_ts < next_ts) { - continue; - } - - int str_len = snprintf(msg_value, sizeof msg_value, "%02x,%08lx", current_case.start_index + current_case.index, - (uint32_t) current_ts); - if (str_len < 0) { - utest_printf("Failed to compose a value string to be sent to host."); - return; - } - greentea_send_kv(MSG_KEY_HEARTBEAT, msg_value); - - // The closer to expected reset, the smaller heartbeat time difference. - // This should reduce measurement error present for heartbeat with - // equal periods. - ts_increment = (1000ULL * timeout_ms / divider); - next_ts += ts_increment; - - if (current_ts <= expected_reset_ts) { - divider <<= 1; - } else if (divider > 0x2ULL) { - divider >>= 1; - } - } -} - -void test_timeout_lower_limit() -{ - watchdog_features_t features = hal_watchdog_get_platform_features(); - if (TIMEOUT_LOWER_LIMIT_MS > features.max_timeout) { - TEST_IGNORE_MESSAGE("Requested timeout value not supported for this target -- ignoring test case."); - return; - } - - // Phase 2. -- verify the test results. - if (current_case.received_data != CASE_DATA_INVALID) { - TEST_ASSERT_EQUAL(CASE_DATA_PHASE2_OK, current_case.received_data); - current_case.received_data = CASE_DATA_INVALID; - return; - } - - // Phase 1. -- run the test code. - watchdog_config_t config = { TIMEOUT_LOWER_LIMIT_MS }; - uint32_t sleep_time_ms = (TIMEOUT_LOWER_LIMIT_MS * features.clock_typical_frequency / features.clock_max_frequency) - TIME_WINDOW_MS; - TEST_ASSERT_EQUAL(WATCHDOG_STATUS_OK, hal_watchdog_init(&config)); - - // Kick watchdog before timeout. - // Watchdog should not trigger before timeout * clock accuracy. - // If device restarts while waiting for the kick, test fails. - - wait_us(sleep_time_ms * 1000); - hal_watchdog_kick(); - - if (send_reset_notification(¤t_case, 2 * TIMEOUT_LOWER_LIMIT_MS) == false) { - TEST_ASSERT_MESSAGE(0, "Dev-host communication error."); - return; - } - hal_watchdog_kick(); - - // Watchdog should fire before twice the timeout value. - wait_us(2 * TIMEOUT_LOWER_LIMIT_MS * 1000); - - // Watchdog reset should have occurred during that wait() above; - - hal_watchdog_kick(); // Just to buy some time for testsuite failure handling. - TEST_ASSERT_MESSAGE(0, "Watchdog did not reset the device as expected."); -} - -utest::v1::status_t case_setup(const Case *const source, const size_t index_of_case) -{ - current_case.index = index_of_case; - return utest::v1::greentea_case_setup_handler(source, index_of_case); -} - -int testsuite_setup(const size_t number_of_cases) -{ - GREENTEA_SETUP(90, "watchdog_reset"); - utest::v1::status_t status = utest::v1::greentea_test_setup_handler(number_of_cases); - if (status != utest::v1::STATUS_CONTINUE) { - return status; - } - - char key[MSG_KEY_LEN + 1] = { }; - char value[MSG_VALUE_LEN + 1] = { }; - - greentea_send_kv(MSG_KEY_DEVICE_READY, MSG_VALUE_DUMMY); - greentea_parse_kv(key, value, MSG_KEY_LEN, MSG_VALUE_LEN); - - if (strcmp(key, MSG_KEY_START_CASE) != 0) { - utest_printf("Invalid message key.\n"); - return utest::v1::STATUS_ABORT; - } - - int num_args = sscanf(value, "%02x,%08lx", &(current_case.start_index), &(current_case.received_data)); - if (num_args == 0 || num_args == EOF) { - utest_printf("Invalid data received from host\n"); - return utest::v1::STATUS_ABORT; - } - - utest_printf("This test suite is composed of %i test cases. Starting at index %i.\n", number_of_cases, - current_case.start_index); - return current_case.start_index; -} - -Case cases[] = { - Case("Timing, 200 ms", case_setup, test_timing<200UL>), - Case("Timing, 500 ms", case_setup, test_timing<500UL>), - Case("Timing, 1000 ms", case_setup, test_timing<1000UL>), - Case("Timing, 3000 ms", case_setup, test_timing<3000UL>), - Case("timeout accuracy", case_setup, test_timeout_lower_limit) -}; - -Specification specification((utest::v1::test_setup_handler_t) testsuite_setup, cases); - -int main() -{ - // Harness will start with a test case index provided by host script. - return !Harness::run(specification); -} - -#endif // !DEVICE_WATCHDOG diff --git a/TESTS/mbed_hal/watchdog_timing/watchdog_timing_tests.h b/TESTS/mbed_hal/watchdog_timing/watchdog_timing_tests.h deleted file mode 100644 index d6b5ec3..0000000 --- a/TESTS/mbed_hal/watchdog_timing/watchdog_timing_tests.h +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright (c) 2018-2019 Arm Limited and affiliates. - * 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. - */ - -/** - * @addtogroup hal_watchdog_tests - * @{ - */ - -#ifndef MBED_HAL_WATCHDOG_TIMING_TESTS_H -#define MBED_HAL_WATCHDOG_TIMING_TESTS_H - -#if DEVICE_WATCHDOG - -/** Test watchdog timing accuracy - * - * Phase 1. - * Given a watchdog timer started with a timeout value of X ms, - * when the time of X ms elapses, - * then the device is restarted by the watchdog. - * - * Phase 2. - * Given a device restarted by the watchdog timer, - * when the device receives time measurement T from the host, - * then X <= T < 2 * X. - */ -template -void test_timing(); - -/** Test Watchdog timeout - * - * Given a device with a Watchdog started, - * when the Watchdog timeout doesn't expire, - * then the device restart is not performed. - * When the Watchdog timeout does expire, - * then the device is restarted after the timeout and before twice the timeout value. - */ -void test_timeout_lower_limit(); - -#endif - -#endif - -/** @}*/ - diff --git a/TESTS/mbed_hal_fpga_ci_test_shield/README.md b/TESTS/mbed_hal_fpga_ci_test_shield/README.md deleted file mode 100644 index c15471f..0000000 --- a/TESTS/mbed_hal_fpga_ci_test_shield/README.md +++ /dev/null @@ -1,51 +0,0 @@ -# Testing with FPGA CI TEST shield - -## Setup - -![30% center](fpga_test_shield.jpg) - -``` -mbed test -n tests*fpga* --app-config tests/configs/fpga.json -``` - -FPGA_CI_TEST_SHIELD needed macro -and specific test capabilities per target -are defined in: -https://github.com/ARMmbed/mbed-os/blob/master/TESTS/configs/fpga.json - - - -## MBED-OS - -Tested from factor is defined by MBED_CONF_TARGET_DEFAULT_FORM_FACTOR -"default-form-factor" default value is null. - -When "default-form-factor" is not set, ARDUINO form factor is used. - -Default ff_arduino_pins is defined in: -https://github.com/ARMmbed/mbed-os/blob/master/hal/mbed_pinmap_default.cpp#L28-L32 - -Default ff_arduino_names is defined in: -https://github.com/ARMmbed/mbed-os/blob/master/hal/mbed_pinmap_default.cpp#L34-L38 - -Default empty_gpio_pinmap is defined in: -https://github.com/ARMmbed/mbed-os/blob/master/hal/mbed_gpio.c#L89-L114 - -Some pins are restricted: -https://github.com/ARMmbed/mbed-os/blob/master/hal/mbed_pinmap_default.cpp#L69-L73 - -Some peripherals are restricted: -https://github.com/ARMmbed/mbed-os/blob/master/hal/mbed_pinmap_default.cpp#L94-L100 - - -## Known issues - - -## LINKS - -https://github.com/ARMmbed/fpga-ci-test-shield - -https://github.com/ARMmbed/fpga-ci-test-shield-updater - -https://github.com/ARMmbed/fpga-ci-test-shield-terminal - diff --git a/TESTS/mbed_hal_fpga_ci_test_shield/analogin/analogin_fpga_test.h b/TESTS/mbed_hal_fpga_ci_test_shield/analogin/analogin_fpga_test.h deleted file mode 100644 index 6150e32..0000000 --- a/TESTS/mbed_hal_fpga_ci_test_shield/analogin/analogin_fpga_test.h +++ /dev/null @@ -1,60 +0,0 @@ -/* mbed Microcontroller Library - * Copyright (c) 2019 ARM Limited - * 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. - */ - -/** \addtogroup hal_analogin_tests */ -/** @{*/ - -#ifndef MBED_FPGA_ANALOG_IN_TEST_H -#define MBED_FPGA_ANALOG_IN_TEST_H - -#if DEVICE_ANALOGIN - -#ifdef __cplusplus -extern "C" { -#endif - -/** Test that the alalogin can be initialized using all possible analogin pins. - * - * Given board provides analogin support. - * When analogin is initialized using valid analogin pin. - * Then the operation is successfull. - * - */ -void fpga_analogin_init_test(PinName pin); - -/** Test that analogin correctly interprets given input voltage. - * - * Given board provides analogin support. - * When 0.0/3.3 V is provided to analogin pin. - * Then analogin_read returns 0.0/1.0, - * analogin_read_u16 returns 0/65535. - * - */ -void fpga_analogin_test(PinName pin); - - -/**@}*/ - -#ifdef __cplusplus -} -#endif - -#endif - -#endif - -/**@}*/ diff --git a/TESTS/mbed_hal_fpga_ci_test_shield/analogin/main.cpp b/TESTS/mbed_hal_fpga_ci_test_shield/analogin/main.cpp deleted file mode 100644 index 57b4459..0000000 --- a/TESTS/mbed_hal_fpga_ci_test_shield/analogin/main.cpp +++ /dev/null @@ -1,109 +0,0 @@ -/* - * Copyright (c) 2019, Arm Limited and affiliates. - * 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. - */ - -#if !DEVICE_ANALOGIN -#error [NOT_SUPPORTED] Analog in not supported for this target -#elif !COMPONENT_FPGA_CI_TEST_SHIELD -#error [NOT_SUPPORTED] FPGA CI Test Shield is needed to run this test -#elif !defined(TARGET_FF_ARDUINO) && !defined(MBED_CONF_TARGET_DEFAULT_FORM_FACTOR) -#error [NOT_SUPPORTED] Test not supported for this form factor -#else - -#include "utest/utest.h" -#include "unity/unity.h" -#include "greentea-client/test_env.h" -#include "mbed.h" -#include "pinmap.h" -#include "hal/static_pinmap.h" -#include "test_utils.h" -#include "MbedTester.h" -#include "analogin_fpga_test.h" - -using namespace utest::v1; - -#define analogin_debug_printf(...) - -#define DELTA_FLOAT (0.1f) // 10% -#define DELTA_U16 (2*3277) // 10% - -const PinList *form_factor = pinmap_ff_default_pins(); -const PinList *restricted = pinmap_restricted_pins(); - -MbedTester tester(form_factor, restricted); - -void fpga_analogin_init_test(PinName pin) -{ - analogin_t analogin; - - analogin_init(&analogin, pin); - analogin_free(&analogin); -} - -template -void fpga_analogin_test(PinName pin) -{ - tester.reset(); - tester.pin_map_set(pin, MbedTester::LogicalPinGPIO0); - tester.select_peripheral(MbedTester::PeripheralGPIO); - - /* Test analog input */ - - analogin_t analogin; - - if (init_direct) { - const PinMap pinmap = get_analogin_pinmap(pin); - analogin_init_direct(&analogin, &pinmap); - } else { - analogin_init(&analogin, pin); - } - - tester.gpio_write(MbedTester::LogicalPinGPIO0, 1, true); - TEST_ASSERT_FLOAT_WITHIN(DELTA_FLOAT, 1.0f, analogin_read(&analogin)); - TEST_ASSERT_UINT16_WITHIN(DELTA_U16, 65535, analogin_read_u16(&analogin)); - - tester.gpio_write(MbedTester::LogicalPinGPIO0, 0, true); - TEST_ASSERT_FLOAT_WITHIN(DELTA_FLOAT, 0.0f, analogin_read(&analogin)); - TEST_ASSERT_UINT16_WITHIN(DELTA_U16, 0, analogin_read_u16(&analogin)); - - /* Set gpio back to Hi-Z */ - tester.gpio_write(MbedTester::LogicalPinGPIO0, 0, false); - - analogin_free(&analogin); -} - -Case cases[] = { - // This will be run for all pins - Case("AnalogIn - init test", all_ports), - // This will be run for single pin - Case("AnalogIn - read test", all_ports>), - Case("AnalogIn (direct init) - read test", all_ports>), -}; - -utest::v1::status_t greentea_test_setup(const size_t number_of_cases) -{ - GREENTEA_SETUP(120, "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); -} - -#endif /* !DEVICE_ANALOGIN */ diff --git a/TESTS/mbed_hal_fpga_ci_test_shield/fpga_test_shield.jpg b/TESTS/mbed_hal_fpga_ci_test_shield/fpga_test_shield.jpg deleted file mode 100644 index fe7b7ca..0000000 --- a/TESTS/mbed_hal_fpga_ci_test_shield/fpga_test_shield.jpg +++ /dev/null Binary files differ diff --git a/TESTS/mbed_hal_fpga_ci_test_shield/gpio/gpio_fpga_test.h b/TESTS/mbed_hal_fpga_ci_test_shield/gpio/gpio_fpga_test.h deleted file mode 100644 index 34f817b..0000000 --- a/TESTS/mbed_hal_fpga_ci_test_shield/gpio/gpio_fpga_test.h +++ /dev/null @@ -1,69 +0,0 @@ -/* mbed Microcontroller Library - * Copyright (c) 2019-2020 ARM Limited - * 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. - */ - -/** \addtogroup hal_gpio_tests */ -/** @{*/ - -#ifndef MBED_FPGA_GPIO_TEST_H -#define MBED_FPGA_GPIO_TEST_H - -#ifdef __cplusplus -extern "C" { -#endif - -/* Test basic input & output operations. - * - * Given a GPIO instance initialized with a generic gpio_init() function, - * when basic input and output operations are performed, - * then all operations succeed. - */ -void fpga_test_basic_input_output(PinName pin); - -/* Test input pull modes. - * - * Given a GPIO instance configured with an input pull mode, - * when basic input operations are performed, - * then all operations succeed. - */ -void fpga_test_input_pull_modes(PinName pin); - -/* Test explicit input initialization. - * - * Given a GPIO instance, - * when additional parameters are passed to the input init function, - * then the GPIO is correctly initialized as an input. - */ -void fpga_test_explicit_input(PinName pin); - -/* Test explicit output initialization. - * - * Given a GPIO instance, - * when additional parameters are passed to the output init function, - * then the GPIO is correctly initialized as an output. - */ -void fpga_test_explicit_output(PinName pin); - -/**@}*/ - -#ifdef __cplusplus -} -#endif - -#endif - - -/**@}*/ diff --git a/TESTS/mbed_hal_fpga_ci_test_shield/gpio/main.cpp b/TESTS/mbed_hal_fpga_ci_test_shield/gpio/main.cpp deleted file mode 100644 index aaec083..0000000 --- a/TESTS/mbed_hal_fpga_ci_test_shield/gpio/main.cpp +++ /dev/null @@ -1,328 +0,0 @@ -/* - * Copyright (c) 2019-2020, Arm Limited and affiliates. - * 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. - */ - -#if !COMPONENT_FPGA_CI_TEST_SHIELD -#error [NOT_SUPPORTED] FPGA CI Test Shield is needed to run this test -#elif !defined(TARGET_FF_ARDUINO) && !defined(MBED_CONF_TARGET_DEFAULT_FORM_FACTOR) -#error [NOT_SUPPORTED] Test not supported for this form factor -#else - -#include "utest/utest.h" -#include "unity/unity.h" -#include "greentea-client/test_env.h" -#include "mbed.h" -#include "MbedTester.h" -#include "pinmap.h" -#include "test_utils.h" -#include "gpio_fpga_test.h" - -using namespace utest::v1; - -// This delay is used when reading a floating input that has an internal pull-up -// or pull-down resistor. The voltage response is much slower when the input -// is not driven externally. -#define HI_Z_READ_DELAY_US 5 - -MbedTester tester(DefaultFormFactor::pins(), DefaultFormFactor::restricted_pins()); - -/* Test basic input & output operations. - * - * Given a GPIO instance initialized with a generic gpio_init() function, - * when basic input and output operations are performed, - * then all operations succeed. - */ -void fpga_test_basic_input_output(PinName pin) -{ - // Reset everything and set all tester pins to hi-Z. - tester.reset(); - - // Map pins for test. - tester.pin_map_set(pin, MbedTester::LogicalPinGPIO0); - - // Select GPIO0. - tester.select_peripheral(MbedTester::PeripheralGPIO); - - gpio_t gpio; - // Initialize GPIO pin with a generic init fun. - gpio_init(&gpio, NC); - // Test gpio_is_connected() returned value. - TEST_ASSERT_EQUAL_INT(0, gpio_is_connected(&gpio)); - gpio_free(&gpio); - gpio_init(&gpio, pin); - TEST_ASSERT_NOT_EQUAL(0, gpio_is_connected(&gpio)); - - // Test GPIO used as an input. - gpio_dir(&gpio, PIN_INPUT); - tester.gpio_write(MbedTester::LogicalPinGPIO0, 1, true); - TEST_ASSERT_EQUAL_INT(1, gpio_read(&gpio)); - tester.gpio_write(MbedTester::LogicalPinGPIO0, 0, true); - TEST_ASSERT_EQUAL_INT(0, gpio_read(&gpio)); - tester.gpio_write(MbedTester::LogicalPinGPIO0, 1, true); - TEST_ASSERT_EQUAL_INT(1, gpio_read(&gpio)); - - // Test GPIO used as an output. - tester.gpio_write(MbedTester::LogicalPinGPIO0, 0, false); - gpio_dir(&gpio, PIN_OUTPUT); - gpio_write(&gpio, 0); - TEST_ASSERT_EQUAL_INT(0, tester.gpio_read(MbedTester::LogicalPinGPIO0)); - gpio_write(&gpio, 1); - TEST_ASSERT_EQUAL_INT(1, tester.gpio_read(MbedTester::LogicalPinGPIO0)); - gpio_write(&gpio, 0); - TEST_ASSERT_EQUAL_INT(0, tester.gpio_read(MbedTester::LogicalPinGPIO0)); - - gpio_free(&gpio); -} - -/* Test input pull modes. - * - * Given a GPIO instance configured with an input pull mode, - * when basic input operations are performed, - * then all operations succeed. - */ -void fpga_test_input_pull_modes(PinName pin) -{ - // Reset everything and set all tester pins to hi-Z. - tester.reset(); - - // Map pins for test. - tester.pin_map_set(pin, MbedTester::LogicalPinGPIO0); - - // Select GPIO0. - tester.select_peripheral(MbedTester::PeripheralGPIO); - - gpio_t gpio; - // Initialize GPIO pin with a generic init fun. - gpio_init(&gpio, pin); - TEST_ASSERT_NOT_EQUAL(0, gpio_is_connected(&gpio)); - gpio_dir(&gpio, PIN_INPUT); - gpio_capabilities_t gcap = {}; - gpio_get_capabilities(&gpio, &gcap); - - // Test input, pull-up mode. - if (gcap.pull_up) { - gpio_mode(&gpio, PullUp); - tester.gpio_write(MbedTester::LogicalPinGPIO0, 0, false); - wait_us(HI_Z_READ_DELAY_US); - TEST_ASSERT_EQUAL_INT(1, gpio_read(&gpio)); // hi-Z, pulled up - tester.gpio_write(MbedTester::LogicalPinGPIO0, 0, true); - TEST_ASSERT_EQUAL_INT(0, gpio_read(&gpio)); - tester.gpio_write(MbedTester::LogicalPinGPIO0, 1, true); - TEST_ASSERT_EQUAL_INT(1, gpio_read(&gpio)); - tester.gpio_write(MbedTester::LogicalPinGPIO0, 0, true); - TEST_ASSERT_EQUAL_INT(0, gpio_read(&gpio)); - tester.gpio_write(MbedTester::LogicalPinGPIO0, 0, false); - wait_us(HI_Z_READ_DELAY_US); - TEST_ASSERT_EQUAL_INT(1, gpio_read(&gpio)); // hi-Z, pulled up - } else { - utest_printf("skipped PullUp,"); - } - - // Test input, pull-down mode. - if (gcap.pull_down) { - gpio_mode(&gpio, PullDown); - tester.gpio_write(MbedTester::LogicalPinGPIO0, 0, false); - wait_us(HI_Z_READ_DELAY_US); - TEST_ASSERT_EQUAL_INT(0, gpio_read(&gpio)); // hi-Z, pulled down - tester.gpio_write(MbedTester::LogicalPinGPIO0, 1, true); - TEST_ASSERT_EQUAL_INT(1, gpio_read(&gpio)); - tester.gpio_write(MbedTester::LogicalPinGPIO0, 0, true); - TEST_ASSERT_EQUAL_INT(0, gpio_read(&gpio)); - tester.gpio_write(MbedTester::LogicalPinGPIO0, 1, true); - TEST_ASSERT_EQUAL_INT(1, gpio_read(&gpio)); - tester.gpio_write(MbedTester::LogicalPinGPIO0, 0, false); - wait_us(HI_Z_READ_DELAY_US); - TEST_ASSERT_EQUAL_INT(0, gpio_read(&gpio)); // hi-Z, pulled down - } else { - utest_printf("skipped PullDown,"); - } - - // Test input, pull-none mode. - if (gcap.pull_none) { - gpio_mode(&gpio, PullNone); - tester.gpio_write(MbedTester::LogicalPinGPIO0, 1, true); - TEST_ASSERT_EQUAL_INT(1, gpio_read(&gpio)); - tester.gpio_write(MbedTester::LogicalPinGPIO0, 0, true); - TEST_ASSERT_EQUAL_INT(0, gpio_read(&gpio)); - tester.gpio_write(MbedTester::LogicalPinGPIO0, 1, true); - TEST_ASSERT_EQUAL_INT(1, gpio_read(&gpio)); - } else { - utest_printf("skipped PullNone,"); - } - - gpio_free(&gpio); -} - -/* Test explicit input initialization. - * - * Given a GPIO instance, - * when additional parameters are passed to the input init function, - * then the GPIO is correctly initialized as an input. - */ -void fpga_test_explicit_input(PinName pin) -{ - // Reset everything and set all tester pins to hi-Z. - tester.reset(); - - // Map pins for test. - tester.pin_map_set(pin, MbedTester::LogicalPinGPIO0); - - // Select GPIO0. - tester.select_peripheral(MbedTester::PeripheralGPIO); - - gpio_t gpio; - gpio_init(&gpio, pin); - gpio_capabilities_t gcap = {}; - gpio_get_capabilities(&gpio, &gcap); - gpio_free(&gpio); - - // Initialize GPIO pin as an input, pull-up mode. - if (gcap.pull_up) { - memset(&gpio, 0, sizeof gpio); - gpio_init_in_ex(&gpio, pin, PullUp); - TEST_ASSERT_NOT_EQUAL(0, gpio_is_connected(&gpio)); - tester.gpio_write(MbedTester::LogicalPinGPIO0, 0, false); - wait_us(HI_Z_READ_DELAY_US); - TEST_ASSERT_EQUAL_INT(1, gpio_read(&gpio)); // hi-Z, pulled up - gpio_free(&gpio); - } else { - utest_printf("skipped PullUp,"); - } - - // Initialize GPIO pin as an input, pull-down mode. - if (gcap.pull_down) { - memset(&gpio, 0, sizeof gpio); - gpio_init_in_ex(&gpio, pin, PullDown); - TEST_ASSERT_NOT_EQUAL(0, gpio_is_connected(&gpio)); - tester.gpio_write(MbedTester::LogicalPinGPIO0, 0, false); - wait_us(HI_Z_READ_DELAY_US); - TEST_ASSERT_EQUAL_INT(0, gpio_read(&gpio)); // hi-Z, pulled down - gpio_free(&gpio); - } else { - utest_printf("skipped PullDown,"); - } - - // Initialize GPIO pin as an input, pull-up mode. - if (gcap.pull_up) { - memset(&gpio, 0, sizeof gpio); - gpio_init_inout(&gpio, pin, PIN_INPUT, PullUp, 0); - TEST_ASSERT_NOT_EQUAL(0, gpio_is_connected(&gpio)); - tester.gpio_write(MbedTester::LogicalPinGPIO0, 0, false); - wait_us(HI_Z_READ_DELAY_US); - TEST_ASSERT_EQUAL_INT(1, gpio_read(&gpio)); // hi-Z, pulled up - gpio_free(&gpio); - } else { - utest_printf("skipped PullUp,"); - } - - // Initialize GPIO pin as an input, pull-down mode. - if (gcap.pull_down) { - memset(&gpio, 0, sizeof gpio); - gpio_init_inout(&gpio, pin, PIN_INPUT, PullDown, 0); - TEST_ASSERT_NOT_EQUAL(0, gpio_is_connected(&gpio)); - tester.gpio_write(MbedTester::LogicalPinGPIO0, 0, false); - wait_us(HI_Z_READ_DELAY_US); - TEST_ASSERT_EQUAL_INT(0, gpio_read(&gpio)); // hi-Z, pulled down - gpio_free(&gpio); - } else { - utest_printf("skipped PullDown,"); - } -} - -/* Test explicit output initialization. - * - * Given a GPIO instance, - * when additional parameters are passed to the output init function, - * then the GPIO is correctly initialized as an output. - */ -void fpga_test_explicit_output(PinName pin) -{ - // Reset everything and set all tester pins to hi-Z. - tester.reset(); - - // Map pins for test. - tester.pin_map_set(pin, MbedTester::LogicalPinGPIO0); - - // Select GPIO0. - tester.select_peripheral(MbedTester::PeripheralGPIO); - - gpio_t gpio; - gpio_init(&gpio, pin); - gpio_capabilities_t gcap = {}; - gpio_get_capabilities(&gpio, &gcap); - gpio_free(&gpio); - - // Initialize GPIO pin as an output, output value = 0. - memset(&gpio, 0, sizeof gpio); - gpio_init_out(&gpio, pin); - TEST_ASSERT_NOT_EQUAL(0, gpio_is_connected(&gpio)); - TEST_ASSERT_EQUAL_INT(0, tester.gpio_read(MbedTester::LogicalPinGPIO0)); - gpio_free(&gpio); - - // Initialize GPIO pin as an output, output value = 1. - memset(&gpio, 0, sizeof gpio); - gpio_init_out_ex(&gpio, pin, 1); - TEST_ASSERT_NOT_EQUAL(0, gpio_is_connected(&gpio)); - TEST_ASSERT_EQUAL_INT(1, tester.gpio_read(MbedTester::LogicalPinGPIO0)); - gpio_free(&gpio); - - // Initialize GPIO pin as an output, output value = 0. - memset(&gpio, 0, sizeof gpio); - gpio_init_out_ex(&gpio, pin, 0); - TEST_ASSERT_NOT_EQUAL(0, gpio_is_connected(&gpio)); - TEST_ASSERT_EQUAL_INT(0, tester.gpio_read(MbedTester::LogicalPinGPIO0)); - gpio_free(&gpio); - - // Initialize GPIO pin as an output, output value = 1. - if (gcap.pull_none) { - memset(&gpio, 0, sizeof gpio); - gpio_init_inout(&gpio, pin, PIN_OUTPUT, PullNone, 1); - TEST_ASSERT_NOT_EQUAL(0, gpio_is_connected(&gpio)); - TEST_ASSERT_EQUAL_INT(1, tester.gpio_read(MbedTester::LogicalPinGPIO0)); - gpio_free(&gpio); - - // Initialize GPIO pin as an output, output value = 0. - memset(&gpio, 0, sizeof gpio); - gpio_init_inout(&gpio, pin, PIN_OUTPUT, PullNone, 0); - TEST_ASSERT_NOT_EQUAL(0, gpio_is_connected(&gpio)); - TEST_ASSERT_EQUAL_INT(0, tester.gpio_read(MbedTester::LogicalPinGPIO0)); - gpio_free(&gpio); - } else { - utest_printf("skipped gpio_init_inout,"); - } -} - -Case cases[] = { - Case("basic input & output", all_ports), - Case("input pull modes", all_ports), - Case("explicit init, input", all_ports), - Case("explicit init, output", all_ports), -}; - -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); -} - -#endif /* !COMPONENT_FPGA_CI_TEST_SHIELD */ diff --git a/TESTS/mbed_hal_fpga_ci_test_shield/gpio_irq/gpio_irq_fpga_test.h b/TESTS/mbed_hal_fpga_ci_test_shield/gpio_irq/gpio_irq_fpga_test.h deleted file mode 100644 index 793022a..0000000 --- a/TESTS/mbed_hal_fpga_ci_test_shield/gpio_irq/gpio_irq_fpga_test.h +++ /dev/null @@ -1,58 +0,0 @@ -/* mbed Microcontroller Library - * Copyright (c) 2019 ARM Limited - * 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. - */ - -/** \addtogroup hal_gpioirq_tests */ -/** @{*/ - -#ifndef MBED_FPGA_GPIO_IRQ_TEST_H -#define MBED_FPGA_GPIO_IRQ_TEST_H - -#if DEVICE_INTERRUPTIN - -#ifdef __cplusplus -extern "C" { -#endif - -/** Test that the GPIO IRQ can be initialized/de-initialized using all possible - * GPIO IRQ pins. - * - * Given board provides GPIO IRQ support. - * When GPIO IRQ is initialized (and then de-initialized) using valid GPIO IRQ pin. - * Then the operation is successfull. - * - */ -void fpga_gpio_irq_test(PinName pin); - -/** Test that the gpio interrupt is generated correctly. - * - * Given board provides interrupt-in feature. - * When gpio interrupt is configured to fire on rasing/falling/both edge(s). - * Then on rasing/falling/any edge registered interrupt handler is called. - * - */ -void fpga_gpio_irq_init_free_test(PinName pin); - -/**@}*/ - -#ifdef __cplusplus -} -#endif - -#endif - -#endif -/**@}*/ diff --git a/TESTS/mbed_hal_fpga_ci_test_shield/gpio_irq/main.cpp b/TESTS/mbed_hal_fpga_ci_test_shield/gpio_irq/main.cpp deleted file mode 100644 index 98b4935..0000000 --- a/TESTS/mbed_hal_fpga_ci_test_shield/gpio_irq/main.cpp +++ /dev/null @@ -1,283 +0,0 @@ -/* - * Copyright (c) 2019, Arm Limited and affiliates. - * 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. - */ - -#if !DEVICE_INTERRUPTIN -#error [NOT_SUPPORTED] test not supported -#elif !COMPONENT_FPGA_CI_TEST_SHIELD -#error [NOT_SUPPORTED] FPGA CI Test Shield is needed to run this test -#elif !defined(TARGET_FF_ARDUINO) && !defined(MBED_CONF_TARGET_DEFAULT_FORM_FACTOR) -#error [NOT_SUPPORTED] Test not supported for this form factor -#else - -#include "utest/utest.h" -#include "unity/unity.h" -#include "greentea-client/test_env.h" -#include "mbed.h" -#include "MbedTester.h" -#include "pinmap.h" -#include "gpio_irq_fpga_test.h" - -using namespace utest::v1; - -#include "MbedTester.h" -#include "pinmap.h" -#include "test_utils.h" - -MbedTester tester(DefaultFormFactor::pins(), DefaultFormFactor::restricted_pins()); - -static volatile uint32_t call_counter; -void test_gpio_irq_handler(uint32_t id, gpio_irq_event event) -{ - call_counter++; -} - -#define WAIT() wait_us(10) - -void fpga_gpio_irq_test(PinName pin) -{ - // Reset everything and set all tester pins to hi-Z. - tester.reset(); - - // Map pins for test. - tester.pin_map_set(pin, MbedTester::LogicalPinGPIO0); - - // Select GPIO0. - tester.select_peripheral(MbedTester::PeripheralGPIO); - - gpio_t gpio; - // configure pin as input - gpio_init_in(&gpio, pin); - - gpio_irq_t gpio_irq; - uint32_t id = 123; - TEST_ASSERT_EQUAL(0, gpio_irq_init(&gpio_irq, pin, test_gpio_irq_handler, id)); - - gpio_irq_set(&gpio_irq, IRQ_RISE, true); - gpio_irq_enable(&gpio_irq); - - tester.gpio_write(MbedTester::LogicalPinGPIO0, 0, true); - WAIT(); - - // test irq on rising edge - call_counter = 0; - tester.gpio_write(MbedTester::LogicalPinGPIO0, 1, true); - WAIT(); - TEST_ASSERT_EQUAL(1, call_counter); - - tester.gpio_write(MbedTester::LogicalPinGPIO0, 0, true); - WAIT(); - TEST_ASSERT_EQUAL(1, call_counter); - - tester.gpio_write(MbedTester::LogicalPinGPIO0, 1, true); - WAIT(); - TEST_ASSERT_EQUAL(2, call_counter); - - tester.gpio_write(MbedTester::LogicalPinGPIO0, 0, true); - WAIT(); - TEST_ASSERT_EQUAL(2, call_counter); - - gpio_irq_disable(&gpio_irq); - - call_counter = 0; - tester.gpio_write(MbedTester::LogicalPinGPIO0, 1, true); - WAIT(); - TEST_ASSERT_EQUAL(0, call_counter); - - tester.gpio_write(MbedTester::LogicalPinGPIO0, 0, true); - WAIT(); - TEST_ASSERT_EQUAL(0, call_counter); - - tester.gpio_write(MbedTester::LogicalPinGPIO0, 1, true); - WAIT(); - TEST_ASSERT_EQUAL(0, call_counter); - - tester.gpio_write(MbedTester::LogicalPinGPIO0, 0, true); - WAIT(); - TEST_ASSERT_EQUAL(0, call_counter); - - gpio_irq_enable(&gpio_irq); - - call_counter = 0; - tester.gpio_write(MbedTester::LogicalPinGPIO0, 1, true); - WAIT(); - TEST_ASSERT_EQUAL(1, call_counter); - - tester.gpio_write(MbedTester::LogicalPinGPIO0, 0, true); - WAIT(); - TEST_ASSERT_EQUAL(1, call_counter); - - tester.gpio_write(MbedTester::LogicalPinGPIO0, 1, true); - WAIT(); - TEST_ASSERT_EQUAL(2, call_counter); - - tester.gpio_write(MbedTester::LogicalPinGPIO0, 0, true); - WAIT(); - TEST_ASSERT_EQUAL(2, call_counter); - - // test irq on both rising and falling edge - gpio_irq_set(&gpio_irq, IRQ_FALL, true); - - tester.gpio_write(MbedTester::LogicalPinGPIO0, 1, true); - WAIT(); - - call_counter = 0; - tester.gpio_write(MbedTester::LogicalPinGPIO0, 0, true); - WAIT(); - TEST_ASSERT_EQUAL(1, call_counter); - - tester.gpio_write(MbedTester::LogicalPinGPIO0, 1, true); - WAIT(); - TEST_ASSERT_EQUAL(2, call_counter); - - tester.gpio_write(MbedTester::LogicalPinGPIO0, 0, true); - WAIT(); - TEST_ASSERT_EQUAL(3, call_counter); - - tester.gpio_write(MbedTester::LogicalPinGPIO0, 1, true); - WAIT(); - TEST_ASSERT_EQUAL(4, call_counter); - - gpio_irq_disable(&gpio_irq); - - call_counter = 0; - tester.gpio_write(MbedTester::LogicalPinGPIO0, 0, true); - WAIT(); - TEST_ASSERT_EQUAL(0, call_counter); - - tester.gpio_write(MbedTester::LogicalPinGPIO0, 1, true); - WAIT(); - TEST_ASSERT_EQUAL(0, call_counter); - - tester.gpio_write(MbedTester::LogicalPinGPIO0, 0, true); - WAIT(); - TEST_ASSERT_EQUAL(0, call_counter); - - tester.gpio_write(MbedTester::LogicalPinGPIO0, 1, true); - WAIT(); - TEST_ASSERT_EQUAL(0, call_counter); - - gpio_irq_enable(&gpio_irq); - - call_counter = 0; - tester.gpio_write(MbedTester::LogicalPinGPIO0, 0, true); - WAIT(); - TEST_ASSERT_EQUAL(1, call_counter); - - tester.gpio_write(MbedTester::LogicalPinGPIO0, 1, true); - WAIT(); - TEST_ASSERT_EQUAL(2, call_counter); - - tester.gpio_write(MbedTester::LogicalPinGPIO0, 0, true); - WAIT(); - TEST_ASSERT_EQUAL(3, call_counter); - - tester.gpio_write(MbedTester::LogicalPinGPIO0, 1, true); - WAIT(); - TEST_ASSERT_EQUAL(4, call_counter); - - // test irq on falling edge - gpio_irq_set(&gpio_irq, IRQ_RISE, false); - - tester.gpio_write(MbedTester::LogicalPinGPIO0, 1, true); - WAIT(); - - call_counter = 0; - tester.gpio_write(MbedTester::LogicalPinGPIO0, 0, true); - WAIT(); - TEST_ASSERT_EQUAL(1, call_counter); - - tester.gpio_write(MbedTester::LogicalPinGPIO0, 1, true); - WAIT(); - TEST_ASSERT_EQUAL(1, call_counter); - - tester.gpio_write(MbedTester::LogicalPinGPIO0, 0, true); - WAIT(); - TEST_ASSERT_EQUAL(2, call_counter); - - tester.gpio_write(MbedTester::LogicalPinGPIO0, 1, true); - WAIT(); - TEST_ASSERT_EQUAL(2, call_counter); - - gpio_irq_disable(&gpio_irq); - - call_counter = 0; - tester.gpio_write(MbedTester::LogicalPinGPIO0, 0, true); - WAIT(); - TEST_ASSERT_EQUAL(0, call_counter); - - tester.gpio_write(MbedTester::LogicalPinGPIO0, 1, true); - WAIT(); - TEST_ASSERT_EQUAL(0, call_counter); - - tester.gpio_write(MbedTester::LogicalPinGPIO0, 0, true); - WAIT(); - TEST_ASSERT_EQUAL(0, call_counter); - - tester.gpio_write(MbedTester::LogicalPinGPIO0, 1, true); - WAIT(); - TEST_ASSERT_EQUAL(0, call_counter); - - gpio_irq_enable(&gpio_irq); - - call_counter = 0; - tester.gpio_write(MbedTester::LogicalPinGPIO0, 0, true); - WAIT(); - TEST_ASSERT_EQUAL(1, call_counter); - - tester.gpio_write(MbedTester::LogicalPinGPIO0, 1, true); - WAIT(); - TEST_ASSERT_EQUAL(1, call_counter); - - tester.gpio_write(MbedTester::LogicalPinGPIO0, 0, true); - WAIT(); - TEST_ASSERT_EQUAL(2, call_counter); - - tester.gpio_write(MbedTester::LogicalPinGPIO0, 1, true); - WAIT(); - TEST_ASSERT_EQUAL(2, call_counter); - - gpio_irq_free(&gpio_irq); -} - -void fpga_gpio_irq_init_free_test(PinName pin) -{ - gpio_t gpio; - gpio_irq_t gpio_irq; - gpio_init_in(&gpio, pin); - TEST_ASSERT_EQUAL(0, gpio_irq_init(&gpio_irq, pin, test_gpio_irq_handler, 123)); - gpio_irq_free(&gpio_irq); -} - -Case cases[] = { - Case("init/free", all_ports), - Case("rising & falling edge", all_ports), -}; - -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); -} - -#endif /* !DEVICE_INTERRUPTIN */ diff --git a/TESTS/mbed_hal_fpga_ci_test_shield/i2c/i2c_fpga_test.h b/TESTS/mbed_hal_fpga_ci_test_shield/i2c/i2c_fpga_test.h deleted file mode 100644 index 9734eb4..0000000 --- a/TESTS/mbed_hal_fpga_ci_test_shield/i2c/i2c_fpga_test.h +++ /dev/null @@ -1,86 +0,0 @@ -/* mbed Microcontroller Library - * Copyright (c) 2019 ARM Limited - * 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. - */ - -/** \addtogroup hal_GeneralI2C_tests */ -/** @{*/ - -#ifndef MBED_FPGA_I2C_TEST_H -#define MBED_FPGA_I2C_TEST_H - -#if DEVICE_I2C - -#ifdef __cplusplus -extern "C" { -#endif - -/** Test that the i2c-master can be initialized/de-initialized using all possible - * i2c pins. - * - * Given board provides i2c-master support. - * When i2c-master is initialized (and then de-initialized) using valid set of i2c pins. - * Then the operation is successfull. - * - */ -void fpga_test_i2c_init_free(PinName sda, PinName scl); - -/** Test that I2C master is able to read data from I2C bus using i2c_byte_read. - * - * Given board provides I2C master support. - * When I2C master reads data from I2C bus using i2c_byte_read. - * Then data is successfully read. - * - */ -void fpga_i2c_test_byte_read(PinName sda, PinName scl); - -/** Test that I2C master is able to write data to I2C bus using i2c_byte_write. - * - * Given board provides I2C master support. - * When I2C master writes data to the I2C bus using i2c_byte_write. - * Then data is successfully transmitted. - * - */ -void fpga_i2c_test_byte_write(PinName sda, PinName scl); - -/** Test that I2C master is able to read data from I2C bus using i2c_read. - * - * Given board provides I2C master support. - * When I2C master reads data from I2C bus using i2c_read. - * Then data is successfully read. - * - */ -void fpga_i2c_test_read(PinName sda, PinName scl); - -/** Test that I2C master is able to write data to I2C bus using i2c_write. - * - * Given board provides I2C master support. - * When I2C master writes data to the I2C bus using i2c_write. - * Then data is successfully transmitted. - * - */ -void fpga_i2c_test_write(PinName sda, PinName scl); - -/**@}*/ - -#ifdef __cplusplus -} -#endif - -#endif - -#endif - -/**@}*/ diff --git a/TESTS/mbed_hal_fpga_ci_test_shield/i2c/main.cpp b/TESTS/mbed_hal_fpga_ci_test_shield/i2c/main.cpp deleted file mode 100644 index 62030ec..0000000 --- a/TESTS/mbed_hal_fpga_ci_test_shield/i2c/main.cpp +++ /dev/null @@ -1,471 +0,0 @@ -/* - * Copyright (c) 2019, Arm Limited and affiliates. - * 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. - */ - -#if !DEVICE_I2C -#error [NOT_SUPPORTED] I2C not supported for this target -#elif !COMPONENT_FPGA_CI_TEST_SHIELD -#error [NOT_SUPPORTED] FPGA CI Test Shield is needed to run this test -#elif !defined(TARGET_FF_ARDUINO) && !defined(MBED_CONF_TARGET_DEFAULT_FORM_FACTOR) -#error [NOT_SUPPORTED] Test not supported for this form factor -#else - -#include "utest/utest.h" -#include "unity/unity.h" -#include "greentea-client/test_env.h" -#include "mbed.h" -#include "i2c_api.h" -#include "pinmap.h" -#include "hal/static_pinmap.h" -#include "test_utils.h" -#include "I2CTester.h" -#include "i2c_fpga_test.h" - -using namespace utest::v1; - -#define NACK 0 -#define ACK 1 -#define TIMEOUT 2 -#define I2C_DEV_ADDR 0x98//default i2c slave address on FPGA is 0x98 until modified -const int TRANSFER_COUNT = 300; - -I2CTester tester(DefaultFormFactor::pins(), DefaultFormFactor::restricted_pins()); - -void fpga_test_i2c_init_free(PinName sda, PinName scl) -{ - i2c_t obj = {}; - memset(&obj, 0, sizeof(obj)); - i2c_init(&obj, sda, scl); - i2c_frequency(&obj, 100000); - - i2c_free(&obj); -} - -template -void fpga_i2c_test_write(PinName sda, PinName scl) -{ - // Remap pins for test - tester.reset(); - tester.pin_map_set(sda, MbedTester::LogicalPinI2CSda); - tester.pin_map_set(scl, MbedTester::LogicalPinI2CScl); - - tester.pin_set_pull(sda, MbedTester::PullUp); - tester.pin_set_pull(scl, MbedTester::PullUp); - - // Initialize mbed I2C pins - i2c_t i2c; - memset(&i2c, 0, sizeof(i2c)); - if (init_direct) { -#if STATIC_PINMAP_READY - const i2c_pinmap_t pinmap = get_i2c_pinmap(sda, scl); - i2c_init_direct(&i2c, &pinmap); -#else - //skip this test case if static pinmap is not supported - return; -#endif - } else { - i2c_init(&i2c, sda, scl); - } - i2c_frequency(&i2c, 100000); - - // Reset tester stats and select I2C - tester.peripherals_reset(); - tester.select_peripheral(I2CTester::PeripheralI2C); - - // Data out and in buffers and initialization - uint8_t data_out[TRANSFER_COUNT]; - for (int i = 0; i < TRANSFER_COUNT; i++) { - data_out[i] = i & 0xFF; - } - uint8_t data_in[TRANSFER_COUNT]; - for (int i = 0; i < TRANSFER_COUNT; i++) { - data_in[i] = 0; - } - - int num_writes; - int num_reads; - int num_acks; - int num_nacks; - int num_starts; - int num_stops; - uint32_t checksum; - int num_dev_addr_matches; - int ack_nack;//0 if NACK was received, 1 if ACK was received, 2 for timeout - - // Reset tester stats and select I2C - tester.peripherals_reset(); - tester.select_peripheral(MbedTester::PeripheralI2C); - - // Write data for I2C complete transaction - // Will write 0-(TRANSFER_COUNT-1) to FPGA, checksum must match checksum calculated in parallel on FPGA - num_dev_addr_matches = 0; - num_writes = 0; - num_reads = 0; - num_starts = 0; - num_stops = 0; - num_acks = 0; - num_nacks = 0; - checksum = 0; - - num_writes = i2c_write(&i2c, I2C_DEV_ADDR, (char *)data_out, TRANSFER_COUNT, true); //transaction ends with a stop condition - num_acks = num_writes + 1; - num_starts += 1; - num_stops += 1; - num_dev_addr_matches += 1; - - for (int i = 0; i < TRANSFER_COUNT; i++) { - checksum += data_out[i]; - } - - // Verify that the transfer was successful - TEST_ASSERT_EQUAL(num_dev_addr_matches, tester.num_dev_addr_matches()); - TEST_ASSERT_EQUAL(TRANSFER_COUNT, num_writes); - TEST_ASSERT_EQUAL(num_writes + 1, tester.transfer_count()); - TEST_ASSERT_EQUAL(num_starts, tester.num_starts()); - TEST_ASSERT_EQUAL(num_stops, tester.num_stops()); - TEST_ASSERT_EQUAL(num_acks, tester.num_acks()); - TEST_ASSERT_EQUAL(num_nacks, tester.num_nacks()); - TEST_ASSERT_EQUAL(checksum, tester.get_receive_checksum()); - TEST_ASSERT_EQUAL(0, tester.state_num()); - TEST_ASSERT_EQUAL(data_out[TRANSFER_COUNT - 4], tester.get_prev_to_slave_4()); - TEST_ASSERT_EQUAL(data_out[TRANSFER_COUNT - 3], tester.get_prev_to_slave_3()); - TEST_ASSERT_EQUAL(data_out[TRANSFER_COUNT - 2], tester.get_prev_to_slave_2()); - TEST_ASSERT_EQUAL(data_out[TRANSFER_COUNT - 1], tester.get_prev_to_slave_1()); - TEST_ASSERT_EQUAL(num_writes, tester.num_writes()); - TEST_ASSERT_EQUAL(num_reads, tester.num_reads()); - - tester.reset(); - tester.pin_set_pull(sda, MbedTester::PullNone); - tester.pin_set_pull(scl, MbedTester::PullNone); - i2c_free(&i2c); -} - -template -void fpga_i2c_test_read(PinName sda, PinName scl) -{ - // Remap pins for test - tester.reset(); - tester.pin_map_set(sda, MbedTester::LogicalPinI2CSda); - tester.pin_map_set(scl, MbedTester::LogicalPinI2CScl); - - tester.pin_set_pull(sda, MbedTester::PullUp); - tester.pin_set_pull(scl, MbedTester::PullUp); - - // Initialize mbed I2C pins - i2c_t i2c; - memset(&i2c, 0, sizeof(i2c)); - if (init_direct) { - const i2c_pinmap_t pinmap = get_i2c_pinmap(sda, scl); - i2c_init_direct(&i2c, &pinmap); - } else { - i2c_init(&i2c, sda, scl); - } - i2c_frequency(&i2c, 100000); - - // Reset tester stats and select I2C - tester.peripherals_reset(); - tester.select_peripheral(I2CTester::PeripheralI2C); - - // Data out and in buffers and initialization - uint8_t data_out[TRANSFER_COUNT]; - for (int i = 0; i < TRANSFER_COUNT; i++) { - data_out[i] = i & 0xFF; - } - uint8_t data_in[TRANSFER_COUNT]; - for (int i = 0; i < TRANSFER_COUNT; i++) { - data_in[i] = 0; - } - - int num_writes; - int num_reads; - int num_acks; - int num_nacks; - int num_starts; - int num_stops; - uint32_t checksum; - int num_dev_addr_matches; - int ack_nack;//0 if NACK was received, 1 if ACK was received, 2 for timeout - - // Reset tester stats and select I2C - tester.peripherals_reset(); - tester.select_peripheral(MbedTester::PeripheralI2C); - - // Read data for I2C complete transaction - // Will read bytes, checksum must match checksum calculated in parallel on FPGA - num_dev_addr_matches = 0; - num_writes = 0; - num_reads = 0; - num_starts = 0; - num_stops = 0; - num_acks = 0; - num_nacks = 0; - checksum = 0; - - num_reads = i2c_read(&i2c, (I2C_DEV_ADDR | 1), (char *)data_in, TRANSFER_COUNT, true); //transaction ends with a stop condition - num_starts += 1; - num_stops += 1; - num_acks += 1; - num_acks += TRANSFER_COUNT - 1; - num_nacks += 1; - num_dev_addr_matches += 1; - - for (int i = 0; i < TRANSFER_COUNT; i++) { - checksum += data_in[i]; - } - - // Verify that the transfer was successful - TEST_ASSERT_EQUAL(num_dev_addr_matches, tester.num_dev_addr_matches()); - TEST_ASSERT_EQUAL(TRANSFER_COUNT, num_reads); - TEST_ASSERT_EQUAL(num_reads + 1, tester.transfer_count()); - TEST_ASSERT_EQUAL(num_starts, tester.num_starts()); - TEST_ASSERT_EQUAL(num_stops, tester.num_stops()); - TEST_ASSERT_EQUAL(num_acks, tester.num_acks()); - TEST_ASSERT_EQUAL(num_nacks, tester.num_nacks()); - TEST_ASSERT_EQUAL(checksum, tester.get_send_checksum()); - TEST_ASSERT_EQUAL(0, tester.state_num()); - TEST_ASSERT_EQUAL(((TRANSFER_COUNT + 1) & 0xFF), tester.get_next_from_slave()); - TEST_ASSERT_EQUAL(num_writes, tester.num_writes()); - TEST_ASSERT_EQUAL(num_reads, tester.num_reads()); - - tester.reset(); - tester.pin_set_pull(sda, MbedTester::PullNone); - tester.pin_set_pull(scl, MbedTester::PullNone); - i2c_free(&i2c); -} - -void fpga_i2c_test_byte_write(PinName sda, PinName scl) -{ - // Remap pins for test - tester.reset(); - tester.pin_map_set(sda, MbedTester::LogicalPinI2CSda); - tester.pin_map_set(scl, MbedTester::LogicalPinI2CScl); - - tester.pin_set_pull(sda, MbedTester::PullUp); - tester.pin_set_pull(scl, MbedTester::PullUp); - - // Initialize mbed I2C pins - i2c_t i2c; - memset(&i2c, 0, sizeof(i2c)); - i2c_init(&i2c, sda, scl); - i2c_frequency(&i2c, 100000); - - // Reset tester stats and select I2C - tester.peripherals_reset(); - tester.select_peripheral(I2CTester::PeripheralI2C); - - // Data out and in buffers and initialization - uint8_t data_out[TRANSFER_COUNT]; - for (int i = 0; i < TRANSFER_COUNT; i++) { - data_out[i] = i & 0xFF; - } - uint8_t data_in[TRANSFER_COUNT]; - for (int i = 0; i < TRANSFER_COUNT; i++) { - data_in[i] = 0; - } - - int num_writes; - int num_reads; - int num_acks; - int num_nacks; - int num_starts; - int num_stops; - uint32_t checksum; - int num_dev_addr_matches; - int ack_nack;//0 if NACK was received, 1 if ACK was received, 2 for timeout - - // Reset tester stats and select I2C - tester.peripherals_reset(); - tester.select_peripheral(MbedTester::PeripheralI2C); - - // Write data for I2C single byte transfers - // Will write 0-(TRANSFER_COUNT-1) to FPGA, checksum must match checksum calculated in parallel on FPGA - num_dev_addr_matches = 0; - num_writes = 0; - num_reads = 0; - num_starts = 0; - num_stops = 0; - num_acks = 0; - num_nacks = 0; - checksum = 0; - - i2c_start(&i2c);//start condition - num_starts += 1; - i2c_byte_write(&i2c, I2C_DEV_ADDR);//send device address - num_dev_addr_matches += 1; - num_acks += 1; - for (int i = 0; i < TRANSFER_COUNT; i++) { - ack_nack = i2c_byte_write(&i2c, data_out[i]);//send data - if (ack_nack == ACK) { - num_acks += 1; - } else if (ack_nack == NACK) { - num_nacks += 1; - } else { - printf("Timeout error\n\r"); - } - checksum += data_out[i]; - num_writes += 1; - } - i2c_stop(&i2c); - num_stops += 1; - - // Verify that the transfer was successful - TEST_ASSERT_EQUAL(num_dev_addr_matches, tester.num_dev_addr_matches()); - TEST_ASSERT_EQUAL(TRANSFER_COUNT, num_writes); - TEST_ASSERT_EQUAL(num_writes + 1, tester.transfer_count()); - TEST_ASSERT_EQUAL(num_starts, tester.num_starts()); - TEST_ASSERT_EQUAL(num_stops, tester.num_stops()); - TEST_ASSERT_EQUAL(num_acks, tester.num_acks()); - TEST_ASSERT_EQUAL(num_nacks, tester.num_nacks()); - TEST_ASSERT_EQUAL(checksum, tester.get_receive_checksum()); - TEST_ASSERT_EQUAL(0, tester.state_num()); - TEST_ASSERT_EQUAL(data_out[TRANSFER_COUNT - 4], tester.get_prev_to_slave_4()); - TEST_ASSERT_EQUAL(data_out[TRANSFER_COUNT - 3], tester.get_prev_to_slave_3()); - TEST_ASSERT_EQUAL(data_out[TRANSFER_COUNT - 2], tester.get_prev_to_slave_2()); - TEST_ASSERT_EQUAL(data_out[TRANSFER_COUNT - 1], tester.get_prev_to_slave_1()); - TEST_ASSERT_EQUAL(num_writes, tester.num_writes()); - TEST_ASSERT_EQUAL(num_reads, tester.num_reads()); - - tester.reset(); - tester.pin_set_pull(sda, MbedTester::PullNone); - tester.pin_set_pull(scl, MbedTester::PullNone); - i2c_free(&i2c); -} - -void fpga_i2c_test_byte_read(PinName sda, PinName scl) -{ - // Remap pins for test - tester.reset(); - tester.pin_map_set(sda, MbedTester::LogicalPinI2CSda); - tester.pin_map_set(scl, MbedTester::LogicalPinI2CScl); - - tester.pin_set_pull(sda, MbedTester::PullUp); - tester.pin_set_pull(scl, MbedTester::PullUp); - - // Initialize mbed I2C pins - i2c_t i2c; - memset(&i2c, 0, sizeof(i2c)); - i2c_init(&i2c, sda, scl); - i2c_frequency(&i2c, 100000); - - // Reset tester stats and select I2C - tester.peripherals_reset(); - tester.select_peripheral(I2CTester::PeripheralI2C); - - // Data out and in buffers and initialization - uint8_t data_out[TRANSFER_COUNT]; - for (int i = 0; i < TRANSFER_COUNT; i++) { - data_out[i] = i & 0xFF; - } - uint8_t data_in[TRANSFER_COUNT]; - for (int i = 0; i < TRANSFER_COUNT; i++) { - data_in[i] = 0; - } - - int num_writes; - int num_reads; - int num_acks; - int num_nacks; - int num_starts; - int num_stops; - uint32_t checksum; - int num_dev_addr_matches; - int ack_nack;//0 if NACK was received, 1 if ACK was received, 2 for timeout - - // Reset tester stats and select I2C - tester.peripherals_reset(); - tester.select_peripheral(MbedTester::PeripheralI2C); - tester.set_next_from_slave(0); - for (int i = 0; i < TRANSFER_COUNT; i++) { - data_in[i] = 0; - } - - // Read data for I2C single byte transfers - // Will read bytes, checksum must match checksum calculated in parallel on FPGA - num_dev_addr_matches = 0; - num_writes = 0; - num_reads = 0; - num_starts = 0; - num_stops = 0; - num_acks = 0; - num_nacks = 0; - checksum = 0; - - i2c_start(&i2c);//start condition - num_starts += 1; - i2c_byte_write(&i2c, (I2C_DEV_ADDR | 1));//send device address for reading - num_dev_addr_matches += 1; - num_acks += 1; - for (int i = 0; i < TRANSFER_COUNT; i++) { - if (num_reads == (TRANSFER_COUNT - 1)) { - data_in[i] = i2c_byte_read(&i2c, 1);//send NACK - checksum += data_in[i]; - num_reads += 1; - num_nacks += 1; - } else { - data_in[i] = i2c_byte_read(&i2c, 0);//send ACK - checksum += data_in[i]; - num_reads += 1; - num_acks += 1; - } - } - - i2c_stop(&i2c); - num_stops += 1; - - // Verify that the transfer was successful - TEST_ASSERT_EQUAL(num_dev_addr_matches, tester.num_dev_addr_matches()); - TEST_ASSERT_EQUAL(TRANSFER_COUNT, num_reads); - TEST_ASSERT_EQUAL(num_reads + 1, tester.transfer_count()); - TEST_ASSERT_EQUAL(num_starts, tester.num_starts()); - TEST_ASSERT_EQUAL(num_stops, tester.num_stops()); - TEST_ASSERT_EQUAL(num_acks, tester.num_acks()); - TEST_ASSERT_EQUAL(num_nacks, tester.num_nacks()); - TEST_ASSERT_EQUAL(checksum, tester.get_send_checksum()); - TEST_ASSERT_EQUAL(0, tester.state_num()); - TEST_ASSERT_EQUAL(((TRANSFER_COUNT) & 0xFF), tester.get_next_from_slave()); - TEST_ASSERT_EQUAL(num_writes, tester.num_writes()); - TEST_ASSERT_EQUAL(num_reads, tester.num_reads()); - - tester.reset(); - tester.pin_set_pull(sda, MbedTester::PullNone); - tester.pin_set_pull(scl, MbedTester::PullNone); - i2c_free(&i2c); -} - -Case cases[] = { - Case("i2c - init/free test all pins", all_ports), - Case("i2c - test write i2c API", all_peripherals>), - Case("i2c (direct init) - test write i2c API", all_peripherals>), - Case("i2c - test read i2c API", all_peripherals>), - Case("i2c (direct init) - test read i2c API", all_peripherals>), - Case("i2c - test single byte write i2c API", all_peripherals), - Case("i2c - test single byte read i2c API", all_peripherals) -}; - -utest::v1::status_t greentea_test_setup(const size_t number_of_cases) -{ - GREENTEA_SETUP(30, "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); -} - -#endif /* !DEVICE_I2C */ diff --git a/TESTS/mbed_hal_fpga_ci_test_shield/pwm/main.cpp b/TESTS/mbed_hal_fpga_ci_test_shield/pwm/main.cpp deleted file mode 100644 index 7124fce..0000000 --- a/TESTS/mbed_hal_fpga_ci_test_shield/pwm/main.cpp +++ /dev/null @@ -1,239 +0,0 @@ -/* - * Copyright (c) 2019, Arm Limited and affiliates. - * 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. - */ - -#if !DEVICE_PWMOUT -#error [NOT_SUPPORTED] PWM not supported for this target -#elif !COMPONENT_FPGA_CI_TEST_SHIELD -#error [NOT_SUPPORTED] FPGA CI Test Shield is needed to run this test -#elif !defined(TARGET_FF_ARDUINO) && !defined(MBED_CONF_TARGET_DEFAULT_FORM_FACTOR) -#error [NOT_SUPPORTED] Test not supported for this form factor -#else - -#include "utest/utest.h" -#include "unity/unity.h" -#include "greentea-client/test_env.h" -#include "mbed.h" -#include "MbedTester.h" -#include "pinmap.h" -#include "hal/static_pinmap.h" -#include "test_utils.h" -#include "pwm_fpga_test.h" - -using namespace utest::v1; - -#define pwm_debug_printf(...) - -typedef enum { - PERIOD_WRITE, - PERIOD_MS_WRITE, - PERIOD_US_WRITE, - PERIOD_PULSEWIDTH, - PERIOD_PULSEWIDTH_MS, - PERIOD_PULSEWIDTH_US -} pwm_api_test_t; - -#define NUM_OF_PERIODS 10 -#define US_PER_SEC 1000000 -#define US_PER_MS 1000 -#define MS_PER_SEC 1000 - -#define DELTA_FACTOR 20 // 5% delta - -#define PERIOD_US(PERIOD_MS) (((PERIOD_MS) * US_PER_MS)) -#define PERIOD_FLOAT(PERIOD_MS) (((float)(PERIOD_MS) / US_PER_MS)) -#define FILL_FLOAT(PRC) ((float)(PRC) / 100) -#define PULSE_HIGH_US(PERIOD_US, PRC) ((uint32_t)((PERIOD_US) * FILL_FLOAT(PRC))) -#define PULSE_LOW_US(PERIOD_US, PRC) ((uint32_t)((PERIOD_US) * (1.0f - FILL_FLOAT(PRC)))) - - -MbedTester tester(DefaultFormFactor::pins(), DefaultFormFactor::restricted_pins()); - - -void fpga_pwm_init_free(PinName pin) -{ - pwmout_t pwm_out; - - pwm_debug_printf("PWM init/free test on pin=%s (%i)\r\n", pinmap_ff_default_pin_to_string(pin), pin); - - pwmout_init(&pwm_out, pin); - pwmout_free(&pwm_out); -} - - -void fpga_pwm_period_fill_test(PinName pin, uint32_t period_ms, uint32_t fill_prc, pwm_api_test_t api_test, bool init_direct) -{ - pwm_debug_printf("PWM test on pin = %s (%i)\r\n", pinmap_ff_default_pin_to_string(pin), pin); - pwm_debug_printf("Testing period = %lu ms, duty-cycle = %lu %%\r\n", period_ms, fill_prc); - pwm_debug_printf("Testing APIs = %d\r\n", (int)api_test); - - tester.reset(); - MbedTester::LogicalPin logical_pin = (MbedTester::LogicalPin)(MbedTester::LogicalPinIOMetrics0); - tester.pin_map_set(pin, logical_pin); - - pwmout_t pwm_out; - - if (init_direct) { - const PinMap pinmap = get_pwm_pinmap(pin); - pwmout_init_direct(&pwm_out, &pinmap); - } else { - pwmout_init(&pwm_out, pin); - } - - core_util_critical_section_enter(); - - switch (api_test) { - case PERIOD_WRITE: - pwmout_period(&pwm_out, PERIOD_FLOAT(period_ms)); - pwmout_write(&pwm_out, FILL_FLOAT(fill_prc)); - break; - - case PERIOD_MS_WRITE: - pwmout_period_ms(&pwm_out, (int)period_ms); - pwmout_write(&pwm_out, FILL_FLOAT(fill_prc)); - break; - - case PERIOD_US_WRITE: - pwmout_period_us(&pwm_out, PERIOD_US(period_ms)); - pwmout_write(&pwm_out, FILL_FLOAT(fill_prc)); - break; - - case PERIOD_PULSEWIDTH: - pwmout_period(&pwm_out, PERIOD_FLOAT(period_ms)); - pwmout_pulsewidth(&pwm_out, (float)PULSE_HIGH_US(PERIOD_US(period_ms), fill_prc) / US_PER_SEC); - break; - - case PERIOD_PULSEWIDTH_MS: - pwmout_period(&pwm_out, PERIOD_FLOAT(period_ms)); - pwmout_pulsewidth_ms(&pwm_out, (int)PULSE_HIGH_US(PERIOD_US(period_ms), fill_prc) / MS_PER_SEC); - break; - - case PERIOD_PULSEWIDTH_US: - pwmout_period(&pwm_out, PERIOD_FLOAT(period_ms)); - pwmout_pulsewidth_us(&pwm_out, (int)PULSE_HIGH_US(PERIOD_US(period_ms), fill_prc)); - break; - } - - // wait_us is safe to call as this test disable the IRQs on execution. - wait_us(PERIOD_US(period_ms)); - - tester.io_metrics_start(); - - wait_us(NUM_OF_PERIODS * PERIOD_US(period_ms)); - - tester.io_metrics_stop(); - core_util_critical_section_exit(); - - const uint32_t expected_low_pulse_us = PULSE_LOW_US(PERIOD_US(period_ms), fill_prc); - const uint32_t expected_high_pulse_us = PULSE_HIGH_US(PERIOD_US(period_ms), fill_prc); - const uint32_t delta_low_pulse = (expected_low_pulse_us / DELTA_FACTOR); - const uint32_t delta_high_pulse = (expected_high_pulse_us / DELTA_FACTOR); - - pwm_debug_printf("Minimum pulse low %lu us\r\n", tester.io_metrics_min_pulse_low(logical_pin) / 100); - pwm_debug_printf("Minimum pulse high %lu us\r\n", tester.io_metrics_min_pulse_high(logical_pin) / 100); - pwm_debug_printf("Maximum pulse low %lu us\r\n", tester.io_metrics_max_pulse_low(logical_pin) / 100); - pwm_debug_printf("Maximum pulse high %lu us\r\n", tester.io_metrics_max_pulse_high(logical_pin) / 100); - pwm_debug_printf("Rising edges %lu\r\n", tester.io_metrics_rising_edges(logical_pin)); - pwm_debug_printf("Falling edges %lu\r\n", tester.io_metrics_falling_edges(logical_pin)); - - TEST_ASSERT_FLOAT_WITHIN(FILL_FLOAT(fill_prc) / DELTA_FACTOR, FILL_FLOAT(fill_prc), pwmout_read(&pwm_out)); - - TEST_ASSERT_UINT32_WITHIN(delta_low_pulse, expected_low_pulse_us, tester.io_metrics_min_pulse_low(logical_pin) / 100); - TEST_ASSERT_UINT32_WITHIN(delta_low_pulse, expected_low_pulse_us, tester.io_metrics_max_pulse_low(logical_pin) / 100); - TEST_ASSERT_UINT32_WITHIN(delta_high_pulse, expected_high_pulse_us, tester.io_metrics_min_pulse_high(logical_pin) / 100); - TEST_ASSERT_UINT32_WITHIN(delta_high_pulse, expected_high_pulse_us, tester.io_metrics_max_pulse_high(logical_pin) / 100); - - TEST_ASSERT_UINT32_WITHIN(1, NUM_OF_PERIODS, tester.io_metrics_rising_edges(logical_pin)); - TEST_ASSERT_UINT32_WITHIN(1, NUM_OF_PERIODS, tester.io_metrics_falling_edges(logical_pin)); - - pwmout_free(&pwm_out); -} - -template -void fpga_pwm_period_fill_test(PinName pin) -{ - fpga_pwm_period_fill_test(pin, period_ms, fill_prc, api_test, init_direct); -} - - -Case cases[] = { - // This will be run for all pins - Case("PWM - init/free test", all_ports), - - // This will be run for single pin - Case("PWM - period: 10 ms, fill: 10%, api: period/write", one_peripheral >), - Case("PWM (direct init) - period: 10 ms, fill: 10%, api: period/write", one_peripheral >), - - Case("PWM - period: 10 ms, fill: 10%, api: period_ms/write", one_peripheral >), - Case("PWM - period: 10 ms, fill: 10%, api: period_us/write", one_peripheral >), - Case("PWM - period: 10 ms, fill: 10%, api: period/pulse_width", one_peripheral >), - Case("PWM - period: 10 ms, fill: 10%, api: period/pulse_width_ms", one_peripheral >), - Case("PWM - period: 10 ms, fill: 10%, api: period/pulse_width_us", one_peripheral >), - - Case("PWM - period: 10 ms, fill: 50%, api: period/write", one_peripheral >), - Case("PWM - period: 10 ms, fill: 50%, api: period_ms/write", one_peripheral >), - Case("PWM - period: 10 ms, fill: 50%, api: period_us/write", one_peripheral >), - Case("PWM - period: 10 ms, fill: 50%, api: period/pulse_width", one_peripheral >), - Case("PWM - period: 10 ms, fill: 50%, api: period/pulse_width_ms", one_peripheral >), - Case("PWM - period: 10 ms, fill: 50%, api: period/pulse_width_us", one_peripheral >), - - Case("PWM - period: 10 ms, fill: 90%, api: period/write", one_peripheral >), - Case("PWM - period: 10 ms, fill: 90%, api: period_ms/write", one_peripheral >), - Case("PWM - period: 10 ms, fill: 90%, api: period_us/write", one_peripheral >), - Case("PWM - period: 10 ms, fill: 90%, api: period/pulse_width", one_peripheral >), - Case("PWM - period: 10 ms, fill: 90%, api: period/pulse_width_ms", one_peripheral >), - Case("PWM - period: 10 ms, fill: 90%, api: period/pulse_width_us", one_peripheral >), - - Case("PWM - period: 30 ms, fill: 10%, api: period/write", one_peripheral >), - Case("PWM - period: 30 ms, fill: 10%, api: period_ms/write", one_peripheral >), - Case("PWM - period: 30 ms, fill: 10%, api: period_us/write", one_peripheral >), - Case("PWM - period: 30 ms, fill: 10%, api: period/pulse_width", one_peripheral >), - Case("PWM - period: 30 ms, fill: 10%, api: period/pulse_width_ms", one_peripheral >), - Case("PWM - period: 30 ms, fill: 10%, api: period/pulse_width_us", one_peripheral >), - - Case("PWM - period: 30 ms, fill: 50%, api: period/write", one_peripheral >), - Case("PWM - period: 30 ms, fill: 50%, api: period_ms/write", one_peripheral >), - Case("PWM - period: 30 ms, fill: 50%, api: period_us/write", one_peripheral >), - Case("PWM - period: 30 ms, fill: 50%, api: period/pulse_width", one_peripheral >), - Case("PWM - period: 30 ms, fill: 50%, api: period/pulse_width_ms", one_peripheral >), - Case("PWM - period: 30 ms, fill: 50%, api: period/pulse_width_us", one_peripheral >), - - Case("PWM - period: 30 ms, fill: 90%, api: period/write", one_peripheral >), - Case("PWM - period: 30 ms, fill: 90%, api: period_ms/write", one_peripheral >), - Case("PWM - period: 30 ms, fill: 90%, api: period_us/write", one_peripheral >), - Case("PWM - period: 30 ms, fill: 90%, api: period/pulse_width", one_peripheral >), - Case("PWM - period: 30 ms, fill: 90%, api: period/pulse_width_ms", one_peripheral >), - Case("PWM - period: 30 ms, fill: 90%, api: period/pulse_width_us", one_peripheral >) -}; - -utest::v1::status_t greentea_test_setup(const size_t number_of_cases) -{ -#ifdef FPGA_FORCE_ALL_PORTS - GREENTEA_SETUP(300, "default_auto"); -#else - GREENTEA_SETUP(120, "default_auto"); -#endif - return greentea_test_setup_handler(number_of_cases); -} - -Specification specification(greentea_test_setup, cases, greentea_test_teardown_handler); - -int main() -{ - Harness::run(specification); -} - -#endif /* !DEVICE_PWMOUT */ diff --git a/TESTS/mbed_hal_fpga_ci_test_shield/pwm/pwm_fpga_test.h b/TESTS/mbed_hal_fpga_ci_test_shield/pwm/pwm_fpga_test.h deleted file mode 100644 index 26b5708..0000000 --- a/TESTS/mbed_hal_fpga_ci_test_shield/pwm/pwm_fpga_test.h +++ /dev/null @@ -1,61 +0,0 @@ -/* mbed Microcontroller Library - * Copyright (c) 2019 ARM Limited - * 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. - */ - -/** \addtogroup hal_pwmout_tests */ -/** @{*/ - -#ifndef MBED_FPGA_PWM_TEST_H -#define MBED_FPGA_PWM_TEST_H - -#if DEVICE_PWM - -#ifdef __cplusplus -extern "C" { -#endif - -/** Test that the PWM can be initialized/de-initialized using all possible - * PWM pins. - * - * Given board provides PWM support. - * When PWM is initialized (and then de-initialized) using valid PWM pin. - * Then the operation is successfull. - * - */ -void fpga_pwm_init_free(PinName pin); - -/** Test that pwmout_period, pwmout_period_ms, pwmout_period_us functions sets the - * PWM period correctly and pwmout_write, pwmout_pulsewidth, pwmout_pulsewidth_ms, - * pwmout_pulsewidth_us functions sets the pulse width correctly. - * - * Given board provides PWM support. - * When PWM period/width is set using pwmout_period, pwmout_period_ms, pwmout_period_us/pwmout_write, pwmout_pulsewidth, pwmout_pulsewidth_ms, pwmout_pulsewidth_us - * Then the valid PWM puswidth and period is on output. - * - */ -void fpga_pwm_period_fill_test(PinName pin); - -/**@}*/ - -#ifdef __cplusplus -} -#endif - -#endif - -#endif - -/**@}*/ diff --git a/TESTS/mbed_hal_fpga_ci_test_shield/spi/main.cpp b/TESTS/mbed_hal_fpga_ci_test_shield/spi/main.cpp deleted file mode 100644 index f933b25..0000000 --- a/TESTS/mbed_hal_fpga_ci_test_shield/spi/main.cpp +++ /dev/null @@ -1,436 +0,0 @@ -/* - * Copyright (c) 2019, Arm Limited and affiliates. - * 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. - */ - -#if !DEVICE_SPI -#error [NOT_SUPPORTED] SPI not supported for this target -#elif !COMPONENT_FPGA_CI_TEST_SHIELD -#error [NOT_SUPPORTED] FPGA CI Test Shield is needed to run this test -#elif !defined(TARGET_FF_ARDUINO) && !defined(MBED_CONF_TARGET_DEFAULT_FORM_FACTOR) -#error [NOT_SUPPORTED] Test not supported for this form factor -#else - -#include "utest/utest.h" -#include "unity/unity.h" -#include "greentea-client/test_env.h" -#include "mbed.h" -#include "SPIMasterTester.h" -#include "pinmap.h" -#include "hal/static_pinmap.h" -#include "test_utils.h" -#include "spi_fpga_test.h" - -using namespace utest::v1; - -typedef enum { - TRANSFER_SPI_MASTER_WRITE_SYNC, - TRANSFER_SPI_MASTER_BLOCK_WRITE_SYNC, - TRANSFER_SPI_MASTER_TRANSFER_ASYNC -} transfer_type_t; - -typedef enum { - BUFFERS_COMMON, // common case rx/tx buffers are defined and have the same size - BUFFERS_TX_GT_RX, // tx buffer length is greater than rx buffer length - BUFFERS_TX_LT_RX, // tx buffer length is less than rx buffer length - BUFFERS_TX_ONE_SYM, // one symbol only is transmitted in both directions -} test_buffers_t; - -#define FREQ_200_KHZ (200000ull) -#define FREQ_500_KHZ (500000) -#define FREQ_1_MHZ (1000000) -#define FREQ_2_MHZ (2000000) -#define FREQ_10_MHZ (10000000ull) -#define FREQ_MIN ((uint32_t)0) -#define FREQ_MAX ((uint32_t)-1) -#define FILL_SYM (0xF5F5F5F5) -#define DUMMY_SYM (0xD5D5D5D5) - -#define SS_ASSERT (0) -#define SS_DEASSERT (!(SS_ASSERT)) - -#define TEST_CAPABILITY_BIT(MASK, CAP) ((1 << CAP) & (MASK)) - -const int TRANSFER_COUNT = 300; -SPIMasterTester tester(DefaultFormFactor::pins(), DefaultFormFactor::restricted_pins()); - -spi_t spi; -static volatile bool async_trasfer_done; - -#if DEVICE_SPI_ASYNCH -void spi_async_handler() -{ - int event = spi_irq_handler_asynch(&spi); - - if (event & SPI_EVENT_COMPLETE) { - async_trasfer_done = true; - } -} -#endif - -/* Function finds SS pin for manual SS handling. */ -static PinName find_ss_pin(PinName mosi, PinName miso, PinName sclk) -{ - const PinList *ff_pins_list = pinmap_ff_default_pins(); - const PinList *restricted_pins_list = pinmap_restricted_pins(); - uint32_t cs_pin_idx; - - for (cs_pin_idx = 0; cs_pin_idx < ff_pins_list->count; cs_pin_idx++) { - if (ff_pins_list->pins[cs_pin_idx] == mosi || - ff_pins_list->pins[cs_pin_idx] == miso || - ff_pins_list->pins[cs_pin_idx] == sclk) { - continue; - } - - bool restricted_pin = false; - for (uint32_t i = 0; i < restricted_pins_list->count ; i++) { - if (ff_pins_list->pins[cs_pin_idx] == restricted_pins_list->pins[i]) { - restricted_pin = true; - } - } - - if (restricted_pin) { - continue; - } else { - break; - } - } - - PinName ssel = (cs_pin_idx == ff_pins_list->count ? NC : ff_pins_list->pins[cs_pin_idx]); - - TEST_ASSERT_MESSAGE(ssel != NC, "Unable to find pin for Chip Select"); - - return ssel; -} - -/* Function handles ss line if ss is specified. */ -static void handle_ss(DigitalOut *ss, bool select) -{ - if (ss) { - if (select) { - *ss = SS_ASSERT; - } else { - *ss = SS_DEASSERT; - } - } -} - -/* Auxiliary function to check platform capabilities against test case. */ -static bool check_capabilities(const spi_capabilities_t *capabilities, SPITester::SpiMode spi_mode, uint32_t sym_size, transfer_type_t transfer_type, uint32_t frequency, test_buffers_t test_buffers) -{ - // Symbol size - if (!TEST_CAPABILITY_BIT(capabilities->word_length, (sym_size - 1))) { - utest_printf("\n skipped. "); - return false; - } - - // SPI clock mode - if (!TEST_CAPABILITY_BIT(capabilities->clk_modes, spi_mode)) { - utest_printf("\n skipped. "); - return false; - } - - // Frequency - if (frequency != FREQ_MAX && frequency != FREQ_MIN && frequency < capabilities->minimum_frequency && frequency > capabilities->maximum_frequency) { - utest_printf("\n skipped. "); - return false; - } - - // Async mode - if (transfer_type == TRANSFER_SPI_MASTER_TRANSFER_ASYNC && capabilities->async_mode == false) { - utest_printf("\n skipped. "); - return false; - } - - if ((test_buffers == BUFFERS_TX_GT_RX || test_buffers == BUFFERS_TX_LT_RX) && capabilities->tx_rx_buffers_equal_length == true) { - utest_printf("\n skipped. "); - return false; - } - - return true; -} - -void fpga_spi_test_init_free(PinName mosi, PinName miso, PinName sclk, PinName ssel) -{ - spi_init(&spi, mosi, miso, sclk, ssel); - spi_format(&spi, 8, 0, 0); - spi_frequency(&spi, 1000000); - spi_free(&spi); -} - -void fpga_spi_test_init_free_cs_nc(PinName mosi, PinName miso, PinName sclk) -{ - spi_init(&spi, mosi, miso, sclk, NC); - spi_format(&spi, 8, 0, 0); - spi_frequency(&spi, 1000000); - spi_free(&spi); -} - -void fpga_spi_test_init_free_cs_nc_miso_nc_mosi_nc(PinName mosi, PinName miso, PinName sclk) -{ - utest_printf("\nTesting: MOSI = NC. "); - - spi_init(&spi, NC, miso, sclk, NC); - spi_format(&spi, 8, 0, 0); - spi_frequency(&spi, 1000000); - spi_free(&spi); - - utest_printf("Testing: MISO = NC. "); - - spi_init(&spi, mosi, NC, sclk, NC); - spi_format(&spi, 8, 0, 0); - spi_frequency(&spi, 1000000); - spi_free(&spi); -} - - -void fpga_spi_test_common(PinName mosi, PinName miso, PinName sclk, PinName ssel, SPITester::SpiMode spi_mode, uint32_t sym_size, transfer_type_t transfer_type, uint32_t frequency, test_buffers_t test_buffers, bool auto_ss, bool init_direct) -{ - spi_capabilities_t capabilities; - uint32_t freq = frequency; - uint32_t tx_cnt = TRANSFER_COUNT; - uint32_t rx_cnt = TRANSFER_COUNT; - uint8_t fill_symbol = (uint8_t)FILL_SYM; - PinName ss_pin = (auto_ss ? ssel : NC); - DigitalOut *ss = NULL; - - spi_get_capabilities(ssel, false, &capabilities); - - if (check_capabilities(&capabilities, spi_mode, sym_size, transfer_type, frequency, test_buffers) == false) { - return; - } - - uint32_t sym_mask = ((1 << sym_size) - 1); - - switch (frequency) { - case (FREQ_MIN): - freq = capabilities.minimum_frequency; - break; - case (FREQ_MAX): - freq = capabilities.maximum_frequency; - break; - default: - break; - } - - switch (test_buffers) { - case (BUFFERS_COMMON): - // nothing to change - break; - case (BUFFERS_TX_GT_RX): - rx_cnt /= 2; - break; - case (BUFFERS_TX_LT_RX): - tx_cnt /= 2; - break; - case (BUFFERS_TX_ONE_SYM): - tx_cnt = 1; - rx_cnt = 1; - break; - - default: - break; - } - - // Remap pins for test - tester.reset(); - tester.pin_map_set(mosi, MbedTester::LogicalPinSPIMosi); - tester.pin_map_set(miso, MbedTester::LogicalPinSPIMiso); - tester.pin_map_set(sclk, MbedTester::LogicalPinSPISclk); - tester.pin_map_set(ssel, MbedTester::LogicalPinSPISsel); - - // Manually handle SS pin - if (!auto_ss) { - ss = new DigitalOut(ssel, SS_DEASSERT); - } - - if (init_direct) { - const spi_pinmap_t pinmap = get_spi_pinmap(mosi, miso, sclk, ss_pin); - spi_init_direct(&spi, &pinmap); - } else { - spi_init(&spi, mosi, miso, sclk, ss_pin); - } - - spi_format(&spi, sym_size, spi_mode, 0); - spi_frequency(&spi, freq); - - // Configure spi_slave module - tester.set_mode(spi_mode); - tester.set_bit_order(SPITester::MSBFirst); - tester.set_sym_size(sym_size); - - // Reset tester stats and select SPI - tester.peripherals_reset(); - tester.select_peripheral(SPITester::PeripheralSPI); - - uint32_t checksum = 0; - uint32_t sym_count = TRANSFER_COUNT; - int result = 0; - uint8_t tx_buf[TRANSFER_COUNT] = {0}; - uint8_t rx_buf[TRANSFER_COUNT] = {0}; - - // Send and receive test data - switch (transfer_type) { - case TRANSFER_SPI_MASTER_WRITE_SYNC: - handle_ss(ss, true); - for (int i = 0; i < TRANSFER_COUNT; i++) { - uint32_t data = spi_master_write(&spi, (0 - i) & sym_mask); - TEST_ASSERT_EQUAL(i & sym_mask, data); - checksum += (0 - i) & sym_mask; - } - handle_ss(ss, false); - break; - - case TRANSFER_SPI_MASTER_BLOCK_WRITE_SYNC: - for (int i = 0; i < TRANSFER_COUNT; i++) { - tx_buf[i] = (0 - i) & sym_mask; - rx_buf[i] = 0xFF; - - switch (test_buffers) { - case (BUFFERS_COMMON): - case (BUFFERS_TX_GT_RX): - checksum += ((0 - i) & sym_mask); - break; - case (BUFFERS_TX_LT_RX): - if (i < tx_cnt) { - checksum += ((0 - i) & sym_mask); - } else { - checksum += (fill_symbol & sym_mask); - } - break; - case (BUFFERS_TX_ONE_SYM): - tx_buf[0] = 0xAA; - checksum = 0xAA; - sym_count = 1; - break; - default: - break; - } - } - - handle_ss(ss, true); - result = spi_master_block_write(&spi, (const char *)tx_buf, tx_cnt, (char *)rx_buf, rx_cnt, 0xF5); - handle_ss(ss, false); - - for (int i = 0; i < rx_cnt; i++) { - TEST_ASSERT_EQUAL(i & sym_mask, rx_buf[i]); - } - - for (int i = rx_cnt; i < TRANSFER_COUNT; i++) { - TEST_ASSERT_EQUAL(0xFF, rx_buf[i]); - } - - TEST_ASSERT_EQUAL(sym_count, result); - break; - -#if DEVICE_SPI_ASYNCH - case TRANSFER_SPI_MASTER_TRANSFER_ASYNC: - for (int i = 0; i < TRANSFER_COUNT; i++) { - tx_buf[i] = (0 - i) & sym_mask; - checksum += (0 - i) & sym_mask; - rx_buf[i] = 0xAA; - } - - async_trasfer_done = false; - - handle_ss(ss, true); - spi_master_transfer(&spi, tx_buf, TRANSFER_COUNT, rx_buf, TRANSFER_COUNT, 8, (uint32_t)spi_async_handler, SPI_EVENT_COMPLETE, DMA_USAGE_NEVER); - - while (!async_trasfer_done); - handle_ss(ss, false); - - for (int i = 0; i < TRANSFER_COUNT; i++) { - TEST_ASSERT_EQUAL(i & sym_mask, rx_buf[i]); - } - - break; -#endif - default: - TEST_ASSERT_MESSAGE(0, "Unsupported transfer type."); - break; - - } - - // Verify that the transfer was successful - TEST_ASSERT_EQUAL(sym_count, tester.get_transfer_count()); - TEST_ASSERT_EQUAL(checksum, tester.get_receive_checksum()); - - spi_free(&spi); - tester.reset(); -} - -template -void fpga_spi_test_common(PinName mosi, PinName miso, PinName sclk, PinName ssel) -{ - fpga_spi_test_common(mosi, miso, sclk, ssel, spi_mode, sym_size, transfer_type, frequency, test_buffers, auto_ss, init_direct); -} - -template -void fpga_spi_test_common_no_ss(PinName mosi, PinName miso, PinName sclk) -{ - PinName ssel = find_ss_pin(mosi, miso, sclk); - - fpga_spi_test_common(mosi, miso, sclk, ssel, spi_mode, sym_size, transfer_type, frequency, test_buffers, auto_ss, init_direct); -} - -Case cases[] = { - // This will be run for all pins - Case("SPI - init/free test all pins", all_ports), - Case("SPI - init/free test all pins (CS == NC)", all_ports), - Case("SPI - init/free test all pins (CS == NC, MISO/MOSI == NC)", one_peripheral), - - // This will be run for all peripherals - Case("SPI - basic test", all_peripherals >), - Case("SPI - basic test (direct init)", all_peripherals >), - - // This will be run for single pin configuration - Case("SPI - mode testing (MODE_1)", one_peripheral >), - Case("SPI - mode testing (MODE_2)", one_peripheral >), - Case("SPI - mode testing (MODE_3)", one_peripheral >), - Case("SPI - symbol size testing (4)", one_peripheral >), - Case("SPI - symbol size testing (12)", one_peripheral >), - Case("SPI - symbol size testing (16)", one_peripheral >), - Case("SPI - symbol size testing (24)", one_peripheral >), - Case("SPI - symbol size testing (32)", one_peripheral >), - Case("SPI - buffers tx > rx", one_peripheral >), - Case("SPI - buffers tx < rx", one_peripheral >), - Case("SPI - frequency testing (200 kHz)", one_peripheral >), - Case("SPI - frequency testing (2 MHz)", one_peripheral >), - Case("SPI - frequency testing (capabilities min)", one_peripheral >), - Case("SPI - frequency testing (capabilities max)", one_peripheral >), - Case("SPI - block write", one_peripheral >), - Case("SPI - block write(one sym)", one_peripheral >), - Case("SPI - hardware ss handling", one_peripheral >), - Case("SPI - hardware ss handling(block)", one_peripheral >), -#if DEVICE_SPI_ASYNCH - Case("SPI - async mode (sw ss)", one_peripheral >), - Case("SPI - async mode (hw ss)", one_peripheral >) -#endif -}; - -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); -} - -#endif /* !DEVICE_SPI */ diff --git a/TESTS/mbed_hal_fpga_ci_test_shield/spi/spi_fpga_test.h b/TESTS/mbed_hal_fpga_ci_test_shield/spi/spi_fpga_test.h deleted file mode 100644 index 14a2306..0000000 --- a/TESTS/mbed_hal_fpga_ci_test_shield/spi/spi_fpga_test.h +++ /dev/null @@ -1,68 +0,0 @@ -/* mbed Microcontroller Library - * Copyright (c) 2019 ARM Limited - * 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. - */ - -/** \addtogroup hal_GeneralSPI_tests */ -/** @{*/ - -#ifndef MBED_FPGA_SPI_TEST_H -#define MBED_FPGA_SPI_TEST_H - -#if DEVICE_SPI - -#ifdef __cplusplus -extern "C" { -#endif - -/** Test that the spi-Master can be initialized/de-initialized using all possible - * SPI pins. - * - * Given board provides SPI-Master support. - * When SPI-Master is initialized (and then de-initialized) using valid set of SPI pins. - * Then the operation is successfull. - * - */ -void fpga_spi_test_init_free(PinName mosi, PinName miso, PinName sclk, PinName ssel); - -/** Test that the SPI-Master transfer can be performed in various configurations (SSEL handled by hardware). - * - * Given board provides SPI-Master support. - * When SPI transmission is performed using different settings. - * Then data is successfully transferred. - * - */ -void fpga_spi_test_common(PinName mosi, PinName miso, PinName sclk, PinName ssel); - -/** Test that the SPI-Master transfer can be performed in various configurations (SSEL handled manually). - * - * Given board provides SPI-Master support. - * When SPI transmission is performed using different settings. - * Then data is successfully transferred. - * - */ -void fpga_spi_test_common_no_ss(PinName mosi, PinName miso, PinName sclk); - -/**@}*/ - -#ifdef __cplusplus -} -#endif - -#endif - -#endif - -/**@}*/ diff --git a/TESTS/mbed_hal_fpga_ci_test_shield/uart/main.cpp b/TESTS/mbed_hal_fpga_ci_test_shield/uart/main.cpp deleted file mode 100644 index 4315cc8..0000000 --- a/TESTS/mbed_hal_fpga_ci_test_shield/uart/main.cpp +++ /dev/null @@ -1,425 +0,0 @@ -/* - * Copyright (c) 2019, Arm Limited and affiliates. - * 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. - */ - -#if !DEVICE_SERIAL -#error [NOT_SUPPORTED] SERIAL not supported for this target -#elif !COMPONENT_FPGA_CI_TEST_SHIELD -#error [NOT_SUPPORTED] FPGA CI Test Shield is needed to run this test -#elif !defined(TARGET_FF_ARDUINO) && !defined(MBED_CONF_TARGET_DEFAULT_FORM_FACTOR) -#error [NOT_SUPPORTED] Test not supported for this form factor -#else - -#include "utest/utest.h" -#include "unity/unity.h" -#include "greentea-client/test_env.h" -#include "platform/mbed_critical.h" -#include -#include "hal/serial_api.h" -#include "UARTTester.h" -#include "pinmap.h" -#include "test_utils.h" -#include "us_ticker_api.h" -#include "uart_fpga_test.h" -#include "hal/static_pinmap.h" - - -using namespace utest::v1; - -#define PUTC_REPS 16 -#define GETC_REPS 16 - -// In the UART RX test, the request for the FPGA to start sending data is sent -// first. Then the execution is blocked at serial_getc() call. Since the DUT -// is not ready to receive UART data instantly after the request, the start of -// the actual transmission has to be dalyed. -// A measured delay for NUCLEO_F070RB is 193 us. -#define TX_START_DELAY_NS 250000 - -UARTTester tester(DefaultFormFactor::pins(), DefaultFormFactor::restricted_pins()); - -typedef struct { - serial_t *ser; - int *rx_buff; - uint32_t rx_cnt; - int *tx_buff; - uint32_t tx_cnt; -} serial_test_data_t; - -static void test_irq_handler(uint32_t id, SerialIrq event) -{ - serial_test_data_t *td = (serial_test_data_t *)id; - int c = 0x01; // arbitrary, non-zero value - if (event == RxIrq) { - c = serial_getc(td->ser); - core_util_critical_section_enter(); - if (td->rx_cnt < GETC_REPS) { - td->rx_buff[td->rx_cnt] = c; - td->rx_cnt++; - } - core_util_critical_section_exit(); - } else if (event == TxIrq) { - core_util_critical_section_enter(); - if (td->tx_cnt < PUTC_REPS) { - c = td->tx_buff[td->tx_cnt]; - td->tx_cnt++; - } - core_util_critical_section_exit(); - // Send either one of tx_buff[] values or 0x01. - serial_putc(td->ser, c); - } -} - -static void uart_test_common(int baudrate, int data_bits, SerialParity parity, int stop_bits, bool init_direct, PinName tx, PinName rx, PinName cts, PinName rts) -{ - // The FPGA CI shield only supports None, Odd & Even. - // Forced parity is not supported on many targets - MBED_ASSERT(parity != ParityForced1 && parity != ParityForced0); - -// See TESTS/configs/fpga.json to check which target supports what -#if defined(UART_9BITS_NOT_SUPPORTED) - if (data_bits == 9) { - utest_printf(" UART_9BITS_NOT_SUPPORTED set ... "); - return; - } -#endif - -#if defined(UART_9BITS_PARITY_NOT_SUPPORTED) - if ((data_bits == 9) && (parity != ParityNone)) { - utest_printf(" UART_9BITS_PARITY_NOT_SUPPORTED set ... "); - return; - } -#endif - -#if defined(UART_7BITS_NOT_SUPPORTED) - if (data_bits == 7) { - utest_printf(" UART_7BITS_NOT_SUPPORTED set ... "); - return; - } -#endif - -#if defined(UART_7BITS_PARITY_NONE_NOT_SUPPORTED) - if ((data_bits == 7) && (parity == ParityNone)) { - utest_printf(" UART_7BITS_PARITY_NONE_NOT_SUPPORTED set ... "); - return; - } -#endif - - // Limit the actual TX & RX chars to 8 bits for this test. - int test_buff_bits = data_bits < 8 ? data_bits : 8; - - // start_bit + data_bits + parity_bit + stop_bits - int packet_bits = 1 + data_bits + stop_bits + (parity == ParityNone ? 0 : 1); - us_timestamp_t packet_tx_time = 1000000 * packet_bits / baudrate; - const ticker_data_t *const us_ticker = get_us_ticker_data(); - - bool use_flow_control = (cts != NC && rts != NC) ? true : false; - - // Remap pins for test - tester.reset(); - tester.pin_map_set(tx, MbedTester::LogicalPinUARTRx); - tester.pin_map_set(rx, MbedTester::LogicalPinUARTTx); - if (use_flow_control) { - tester.pin_map_set(cts, MbedTester::LogicalPinUARTRts); - tester.pin_map_set(rts, MbedTester::LogicalPinUARTCts); - } - - // Initialize mbed UART pins - serial_t serial; - if (init_direct) { - const serial_pinmap_t pinmap = get_uart_pinmap(tx, rx); - serial_init_direct(&serial, &pinmap); - } else { - serial_init(&serial, tx, rx); - } - serial_baud(&serial, baudrate); - serial_format(&serial, data_bits, parity, stop_bits); -#if DEVICE_SERIAL_FC - if (use_flow_control) { - if (init_direct) { -#if STATIC_PINMAP_READY - const serial_fc_pinmap_t pinmap = get_uart_fc_pinmap(rts, cts); - serial_set_flow_control_direct(&serial, FlowControlRTSCTS, &pinmap); -#else - //skip this test case if static pinmap is not supported - // Cleanup uart to be able execute next test case - serial_free(&serial); - tester.reset(); - return; -#endif - } else { - serial_set_flow_control(&serial, FlowControlRTSCTS, rts, cts); - } - } else { - serial_set_flow_control(&serial, FlowControlNone, NC, NC); - } -#endif - - // Reset tester stats and select UART - tester.peripherals_reset(); - tester.select_peripheral(MbedTester::PeripheralUART); - - // Configure UART module - tester.set_baud((uint32_t)baudrate); - tester.set_bits((uint8_t)data_bits); - tester.set_stops((uint8_t)stop_bits); - switch (parity) { - case ParityOdd: - tester.set_parity(true, true); - break; - case ParityEven: - tester.set_parity(true, false); - break; - case ParityNone: - default: - tester.set_parity(false, false); - break; - } - if (use_flow_control) { - tester.cts_deassert_delay(0); - } - - int rx_buff[GETC_REPS] = {}; - int tx_buff[PUTC_REPS] = {}; - volatile serial_test_data_t td = { - &serial, - rx_buff, - 0, - tx_buff, - 0 - }; - uint32_t checksum = 0; - - // DUT TX / FPGA RX - int tx_val; - tester.rx_start(); - for (uint32_t reps = 1; reps <= PUTC_REPS; reps++) { - tx_val = rand() % (1 << test_buff_bits); - checksum += tx_val; - serial_putc(&serial, tx_val); - us_timestamp_t end_ts = ticker_read_us(us_ticker) + 2 * packet_tx_time; - while (tester.rx_get_count() != reps && ticker_read_us(us_ticker) <= end_ts) { - // Wait (no longer than twice the time of one packet transfer) for - // the FPGA to receive data and update the byte counter. - } - TEST_ASSERT_EQUAL_UINT32(reps, tester.rx_get_count()); - TEST_ASSERT_EQUAL(0, tester.rx_get_parity_errors()); - TEST_ASSERT_EQUAL(0, tester.rx_get_stop_errors()); - TEST_ASSERT_EQUAL(0, tester.rx_get_framing_errors()); - TEST_ASSERT_EQUAL_UINT32(checksum, tester.rx_get_checksum()); - TEST_ASSERT_EQUAL(tx_val, tester.rx_get_data()); - } - tester.rx_stop(); - - // DUT RX / FPGA TX - // serial_getc() may return 16-bit as well as 8-bit value cast to an int. - // Use a random initial value, but make sure it is low enouth, - // so the FPGA will not overflow 8 bits when incrementing it. - uint16_t tester_buff = rand() % ((1 << test_buff_bits) - GETC_REPS); - tester.tx_set_next(tester_buff); - tester.tx_set_count(GETC_REPS); - if (!use_flow_control) { - tester.tx_set_delay(TX_START_DELAY_NS); - } - tester.tx_start(use_flow_control); - for (int i = 0; i < GETC_REPS; i++) { - rx_buff[i] = serial_getc(&serial); - } - tester.tx_stop(); - for (int i = 0; i < GETC_REPS; tester_buff++, i++) { - TEST_ASSERT_EQUAL(tester_buff, rx_buff[i]); - } - - serial_irq_handler(&serial, test_irq_handler, (uint32_t) &td); - - // DUT TX (IRQ) / FPGA RX - tx_val = rand() % ((1 << test_buff_bits) - PUTC_REPS); - for (size_t i = 0; i < PUTC_REPS; tx_val++, i++) { - td.tx_buff[i] = tx_val; - checksum += tx_val; - } - - tester.rx_start(); - core_util_critical_section_enter(); - td.tx_cnt = 0; - // Enable only the TX IRQ. - serial_irq_set(&serial, TxIrq, 1); - core_util_critical_section_exit(); - while (core_util_atomic_load_u32(&td.tx_cnt) != PUTC_REPS) { - // Wait until the last byte is written to UART TX reg. - }; - core_util_critical_section_enter(); - serial_irq_set(&serial, TxIrq, 0); - core_util_critical_section_exit(); - us_timestamp_t end_ts = ticker_read_us(us_ticker) + 2 * packet_tx_time; - while (ticker_read_us(us_ticker) <= end_ts) { - // Wait twice the time of one packet transfer for the FPGA - // to receive and process data. - }; - tester.rx_stop(); - TEST_ASSERT_EQUAL_UINT32(2 * PUTC_REPS, tester.rx_get_count()); - TEST_ASSERT_EQUAL(0, tester.rx_get_parity_errors()); - TEST_ASSERT_EQUAL(0, tester.rx_get_stop_errors()); - TEST_ASSERT_EQUAL(0, tester.rx_get_framing_errors()); - TEST_ASSERT_EQUAL_UINT32(checksum, tester.rx_get_checksum()); - TEST_ASSERT_EQUAL(tx_val - 1, tester.rx_get_data()); - - // DUT RX (IRQ) / FPGA TX - // serial_getc() may return 16-bit as well as 8-bit value cast to an int. - // Use a random initial value, but make sure it is low enouth, - // so the FPGA will not overflow 8 bits when incrementing it. - tester_buff = rand() % ((1 << test_buff_bits) - GETC_REPS); - tester.tx_set_next(tester_buff); - tester.tx_set_count(GETC_REPS); - if (!use_flow_control) { - tester.tx_set_delay(TX_START_DELAY_NS); - } - core_util_critical_section_enter(); - // Enable only the RX IRQ. - serial_irq_set(&serial, RxIrq, 1); - core_util_critical_section_exit(); - tester.rx_start(); - tester.tx_start(use_flow_control); - while (core_util_atomic_load_u32(&td.rx_cnt) != GETC_REPS) { - // Wait until the last byte is received to UART RX reg. - }; - core_util_critical_section_enter(); - serial_irq_set(&serial, RxIrq, 0); - core_util_critical_section_exit(); - tester.tx_stop(); - tester.rx_stop(); - for (int i = 0; i < GETC_REPS; tester_buff++, i++) { - TEST_ASSERT_EQUAL(tester_buff, td.rx_buff[i]); - } - - // Make sure TX IRQ was disabled during the last RX test. - TEST_ASSERT_EQUAL_UINT32(checksum, tester.rx_get_checksum()); - TEST_ASSERT_EQUAL_UINT32(2 * PUTC_REPS, tester.rx_get_count()); - - // Cleanup - serial_free(&serial); - tester.reset(); -} - -void fpga_uart_init_free_test(PinName tx, PinName rx, PinName cts, PinName rts) -{ - bool use_flow_control = (cts != NC && rts != NC) ? true : false; - serial_t serial; - serial_init(&serial, tx, rx); - serial_baud(&serial, 9600); - serial_format(&serial, 8, ParityNone, 1); -#if DEVICE_SERIAL_FC - if (use_flow_control) { - serial_set_flow_control(&serial, FlowControlRTSCTS, rts, cts); - } -#endif - serial_free(&serial); -} - -void fpga_uart_init_free_test_no_fc(PinName tx, PinName rx) -{ - fpga_uart_init_free_test(tx, rx); -} - -template -void fpga_uart_test_common(PinName tx, PinName rx, PinName cts, PinName rts) -{ - uart_test_common(BAUDRATE, DATA_BITS, PARITY, STOP_BITS, INIT_DIRECT, tx, rx, cts, rts); -} - -template -void fpga_uart_test_common_no_fc(PinName tx, PinName rx) -{ - uart_test_common(BAUDRATE, DATA_BITS, PARITY, STOP_BITS, INIT_DIRECT, tx, rx); -} - -Case cases[] = { - // Every set of pins from every peripheral. - Case("init/free, FC off", all_ports), - - // One set of pins from every peripheral. - Case("basic, 9600, 8N1, FC off", all_peripherals >), - Case("basic (direct init), 9600, 8N1, FC off", all_peripherals >), - - // same test with 7 and 9 bits data length - Case("basic, 9600, 7N1, FC off", all_peripherals >), - Case("basic, 9600, 9N1, FC off", all_peripherals >), - - // One set of pins from one peripheral. - // baudrate - Case("19200, 8N1, FC off", one_peripheral >), - Case("38400, 8N1, FC off", one_peripheral >), - Case("115200, 8N1, FC off", one_peripheral >), - // stop bits -#if !defined(UART_TWO_STOP_BITS_NOT_SUPPORTED) - Case("9600, 8N2, FC off", one_peripheral >), -#endif - -#if DEVICE_SERIAL_FC - // Every set of pins from every peripheral. - Case("init/free, FC on", all_ports), - - // One set of pins from every peripheral. - Case("basic, 9600, 8N1, FC on", all_peripherals >), - Case("basic (direct init), 9600, 8N1, FC on", all_peripherals >), - - // same test with 7 and 9 bits data length - Case("basic, 9600, 7N1, FC on", all_peripherals >), - Case("basic, 9600, 9N1, FC on", all_peripherals >), - - // One set of pins from one peripheral. - // baudrate - Case("19200, 8N1, FC on", one_peripheral >), - Case("38400, 8N1, FC on", one_peripheral >), - Case("115200, 8N1, FC on", one_peripheral >), - // data bits: not tested (some platforms support 8 bits only) - // parity -#if !defined(UART_ODD_PARITY_NOT_SUPPORTED) - Case("9600, 8O1, FC on", one_peripheral >), - - // same test with 7 and 9 bits data length - Case("9600, 7O1, FC on", one_peripheral >), - Case("9600, 9O1, FC on", one_peripheral >), -#endif - Case("9600, 8E1, FC on", one_peripheral >), - - // same test with 7 and 9 bits data length - Case("9600, 7E1, FC on", one_peripheral >), - Case("9600, 9E1, FC on", one_peripheral >), - - // stop bits -#if !defined(UART_TWO_STOP_BITS_NOT_SUPPORTED) - Case("9600, 8N2, FC on", one_peripheral >), -#endif -#endif - -}; - -utest::v1::status_t greentea_test_setup(const size_t number_of_cases) -{ - GREENTEA_SETUP(240, "default_auto"); - srand((unsigned) ticker_read_us(get_us_ticker_data())); - return greentea_test_setup_handler(number_of_cases); -} - -Specification specification(greentea_test_setup, cases, greentea_test_teardown_handler); - -int main() -{ - Harness::run(specification); -} - -#endif /* !DEVICE_SERIAL */ diff --git a/TESTS/mbed_hal_fpga_ci_test_shield/uart/uart_fpga_test.h b/TESTS/mbed_hal_fpga_ci_test_shield/uart/uart_fpga_test.h deleted file mode 100644 index 3c3915d..0000000 --- a/TESTS/mbed_hal_fpga_ci_test_shield/uart/uart_fpga_test.h +++ /dev/null @@ -1,81 +0,0 @@ -/* mbed Microcontroller Library - * Copyright (c) 2019 ARM Limited - * 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. - */ - -/** \addtogroup hal_GeneralSerial_tests */ -/** @{*/ - -#ifndef MBED_FPGA_UART_TEST_H -#define MBED_FPGA_UART_TEST_H - -#if DEVICE_SERIAL - -#ifdef __cplusplus -extern "C" { -#endif - -/** Test that the uart can be initialized/de-initialized using all possible - * uart pins (flow control enabled). - * - * Given board provides uart support with flow control. - * When uart is initialized (and then de-initialized) using valid set of uart pins. - * Then the operation is successfull. - * - */ -void fpga_uart_init_free_test(PinName tx, PinName rx, PinName cts = NC, PinName rts = NC); - -/** Test that the uart can be initialized/de-initialized using all possible - * uart pins (flow control disabled). - * - * Given board provides uart support without flow control. - * When uart is initialized (and then de-initialized) using valid set of uart pins. - * Then the operation is successfull. - * - */ -void fpga_uart_init_free_test_no_fc(PinName tx, PinName rx); - -/** Test that the uart transfer can be performed in various configurations (flow control enabled). - * - * Given board provides uart support with flow control. - * When uart transmission is performed using different settings. - * Then data is successfully transfered. - * - */ -void fpga_uart_test_common(PinName tx, PinName rx, PinName cts = NC, PinName rts = NC); - -/** Test that the uart transfer can be performed in various configurations (flow control disabled). - * - * Given board provides uart support without flow control. - * When uart transmission is performed using different settings. - * Then data is successfully transfered. - * - */ -void fpga_uart_test_common_no_fc(PinName tx, PinName rx); - -/* Common test function. */ -static void uart_test_common(int baudrate, int data_bits, SerialParity parity, int stop_bits, bool init_direct, PinName tx, PinName rx, PinName cts = NC, PinName rts = NC); - -/**@}*/ - -#ifdef __cplusplus -} -#endif - -#endif - -#endif - -/**@}*/ diff --git a/UNITTESTS/CMakeLists.txt b/UNITTESTS/CMakeLists.txt index 598c76e..d149c3c 100644 --- a/UNITTESTS/CMakeLists.txt +++ b/UNITTESTS/CMakeLists.txt @@ -126,6 +126,7 @@ "${PROJECT_SOURCE_DIR}/../drivers/include/drivers" "${PROJECT_SOURCE_DIR}/../drivers/include/drivers/internal" "${PROJECT_SOURCE_DIR}/../hal" + "${PROJECT_SOURCE_DIR}/../hal/include" "${PROJECT_SOURCE_DIR}/../events/include" "${PROJECT_SOURCE_DIR}/../events/include/events/internal" "${PROJECT_SOURCE_DIR}/../events/source" diff --git a/UNITTESTS/stubs/us_ticker_stub.cpp b/UNITTESTS/stubs/us_ticker_stub.cpp index 69c96ac..b451424 100644 --- a/UNITTESTS/stubs/us_ticker_stub.cpp +++ b/UNITTESTS/stubs/us_ticker_stub.cpp @@ -17,7 +17,7 @@ #include "stdlib.h" -#include "us_ticker_api.h" +#include "hal/us_ticker_api.h" const ticker_data_t *get_us_ticker_data(void) { diff --git a/UNITTESTS/stubs/watchdog_api_stub.c b/UNITTESTS/stubs/watchdog_api_stub.c index 78e0802..f6c061f 100644 --- a/UNITTESTS/stubs/watchdog_api_stub.c +++ b/UNITTESTS/stubs/watchdog_api_stub.c @@ -14,7 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -#include "watchdog_api.h" +#include "hal/watchdog_api.h" #if DEVICE_WATCHDOG diff --git a/UNITTESTS/target_h/PinNames.h b/UNITTESTS/target_h/PinNames.h index 745ddda..92fa9fb 100644 --- a/UNITTESTS/target_h/PinNames.h +++ b/UNITTESTS/target_h/PinNames.h @@ -47,6 +47,6 @@ #ifdef __cplusplus } #endif -#include "pinmap.h" +#include "hal/pinmap.h" #endif diff --git a/hal/LowPowerTickerWrapper.cpp b/hal/LowPowerTickerWrapper.cpp deleted file mode 100644 index 0f03a41..0000000 --- a/hal/LowPowerTickerWrapper.cpp +++ /dev/null @@ -1,318 +0,0 @@ -/* mbed Microcontroller Library - * Copyright (c) 2018 ARM Limited - * 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. - */ -#include "hal/LowPowerTickerWrapper.h" -#include "platform/Callback.h" - -using namespace mbed::chrono; - -LowPowerTickerWrapper::LowPowerTickerWrapper(const ticker_data_t *data, const ticker_interface_t *interface, uint32_t min_cycles_between_writes, uint32_t min_cycles_until_match) - : _intf(data->interface), _min_count_between_writes(min_cycles_between_writes + 1), _min_count_until_match(min_cycles_until_match + 1), _suspended(false) -{ - core_util_critical_section_enter(); - - this->data.interface = interface; - this->data.queue = data->queue; - _reset(); - - core_util_critical_section_exit(); -} - -void LowPowerTickerWrapper::irq_handler(ticker_irq_handler_type handler) -{ - core_util_critical_section_enter(); - - // This code no longer filters out early interrupts. Instead it - // passes them through to the next layer and ignores further interrupts - // until the next call to set_interrrupt or fire_interrupt (when not suspended). - // This is to ensure that the device doesn't get stuck in sleep due to an - // early low power ticker interrupt that was ignored. - if (_pending_fire_now || _pending_match || _suspended) { - _timeout.detach(); - _pending_timeout = false; - _pending_match = false; - _pending_fire_now = false; - if (handler) { - handler(&data); - } - } else { - // Spurious interrupt - _intf->clear_interrupt(); - } - - core_util_critical_section_exit(); -} - -void LowPowerTickerWrapper::suspend() -{ - core_util_critical_section_enter(); - - // Wait until rescheduling is allowed - while (!_set_interrupt_allowed) { - timestamp_t current = _intf->read(); - if (((current - _last_actual_set_interrupt) & _mask) >= _min_count_between_writes) { - _set_interrupt_allowed = true; - } - } - - _reset(); - _suspended = true; - - core_util_critical_section_exit(); -} - -void LowPowerTickerWrapper::resume() -{ - core_util_critical_section_enter(); - - // Wait until rescheduling is allowed - while (!_set_interrupt_allowed) { - timestamp_t current = _intf->read(); - if (((current - _last_actual_set_interrupt) & _mask) >= _min_count_between_writes) { - _set_interrupt_allowed = true; - } - } - - _suspended = false; - - core_util_critical_section_exit(); -} - -bool LowPowerTickerWrapper::timeout_pending() -{ - core_util_critical_section_enter(); - - bool pending = _pending_timeout; - - core_util_critical_section_exit(); - return pending; -} - -void LowPowerTickerWrapper::init() -{ - core_util_critical_section_enter(); - - _reset(); - _intf->init(); - - core_util_critical_section_exit(); -} - -void LowPowerTickerWrapper::free() -{ - core_util_critical_section_enter(); - - _reset(); - _intf->free(); - - core_util_critical_section_exit(); -} - -uint32_t LowPowerTickerWrapper::read() -{ - core_util_critical_section_enter(); - - timestamp_t current = _intf->read(); - if (!_suspended && _match_check(current)) { - _intf->fire_interrupt(); - } - - core_util_critical_section_exit(); - return current; -} - -void LowPowerTickerWrapper::set_interrupt(timestamp_t timestamp) -{ - core_util_critical_section_enter(); - - _last_set_interrupt = _intf->read(); - _cur_match_time = timestamp; - _pending_match = true; - if (!_suspended) { - _schedule_match(_last_set_interrupt); - } else { - _intf->set_interrupt(timestamp); - _last_actual_set_interrupt = _last_set_interrupt; - _set_interrupt_allowed = false; - } - - core_util_critical_section_exit(); -} - -void LowPowerTickerWrapper::disable_interrupt() -{ - core_util_critical_section_enter(); - - _intf->disable_interrupt(); - - core_util_critical_section_exit(); -} - -void LowPowerTickerWrapper::clear_interrupt() -{ - core_util_critical_section_enter(); - - _intf->clear_interrupt(); - - core_util_critical_section_exit(); -} - -void LowPowerTickerWrapper::fire_interrupt() -{ - core_util_critical_section_enter(); - - _pending_fire_now = 1; - _intf->fire_interrupt(); - - core_util_critical_section_exit(); -} - -const ticker_info_t *LowPowerTickerWrapper::get_info() -{ - - core_util_critical_section_enter(); - - const ticker_info_t *info = _intf->get_info(); - - core_util_critical_section_exit(); - return info; -} - -void LowPowerTickerWrapper::_reset() -{ - MBED_ASSERT(core_util_in_critical_section()); - - _timeout.detach(); - _pending_timeout = false; - _pending_match = false; - _pending_fire_now = false; - _set_interrupt_allowed = true; - _cur_match_time = 0; - _last_set_interrupt = 0; - _last_actual_set_interrupt = 0; - - const ticker_info_t *info = _intf->get_info(); - if (info->bits >= 32) { - _mask = 0xffffffff; - } else { - _mask = ((uint64_t)1 << info->bits) - 1; - } - - // Round us_per_tick up - _us_per_tick = (1000000 + info->frequency - 1) / info->frequency; -} - -void LowPowerTickerWrapper::_timeout_handler() -{ - core_util_critical_section_enter(); - _pending_timeout = false; - - timestamp_t current = _intf->read(); - /* Add extra check for '_last_set_interrupt == _cur_match_time' - * - * When '_last_set_interrupt == _cur_match_time', _ticker_match_interval_passed sees it as - * one-round interval rather than just-pass, so add extra check for it. In rare cases, we - * may trap in _timeout_handler/_schedule_match loop. This check can break it. - */ - if ((_last_set_interrupt == _cur_match_time) || - _ticker_match_interval_passed(_last_set_interrupt, current, _cur_match_time)) { - _intf->fire_interrupt(); - } else { - _schedule_match(current); - } - - core_util_critical_section_exit(); -} - -bool LowPowerTickerWrapper::_match_check(timestamp_t current) -{ - MBED_ASSERT(core_util_in_critical_section()); - - if (!_pending_match) { - return false; - } - /* Add extra check for '_last_set_interrupt == _cur_match_time' as above */ - return (_last_set_interrupt == _cur_match_time) || - _ticker_match_interval_passed(_last_set_interrupt, current, _cur_match_time); -} - -microseconds_u32 LowPowerTickerWrapper::_lp_ticks_to_us(uint32_t ticks) -{ - MBED_ASSERT(core_util_in_critical_section()); - - // Add 4 microseconds to round up the micro second ticker time (which has a frequency of at least 250KHz - 4us period) - return microseconds_u32(_us_per_tick * ticks + 4); -} - -void LowPowerTickerWrapper::_schedule_match(timestamp_t current) -{ - MBED_ASSERT(core_util_in_critical_section()); - - // Check if _intf->set_interrupt is allowed - if (!_set_interrupt_allowed) { - if (((current - _last_actual_set_interrupt) & _mask) >= _min_count_between_writes) { - _set_interrupt_allowed = true; - } - } - - uint32_t cycles_until_match = (_cur_match_time - current) & _mask; - bool too_close = cycles_until_match < _min_count_until_match; - - if (!_set_interrupt_allowed) { - - // Can't use _intf->set_interrupt so use microsecond Timeout instead - - // Speed optimization - if a timer has already been scheduled - // then don't schedule it again. - if (!_pending_timeout) { - uint32_t ticks = cycles_until_match < _min_count_until_match ? cycles_until_match : _min_count_until_match; - _timeout.attach(mbed::callback(this, &LowPowerTickerWrapper::_timeout_handler), _lp_ticks_to_us(ticks)); - _pending_timeout = true; - } - return; - } - - if (!too_close) { - - // Schedule LP ticker - _intf->set_interrupt(_cur_match_time); - current = _intf->read(); - _last_actual_set_interrupt = current; - _set_interrupt_allowed = false; - - // Check for overflow - uint32_t new_cycles_until_match = (_cur_match_time - current) & _mask; - if (new_cycles_until_match > cycles_until_match) { - // Overflow so fire now - _intf->fire_interrupt(); - return; - } - - // Update variables with new time - cycles_until_match = new_cycles_until_match; - too_close = cycles_until_match < _min_count_until_match; - } - - if (too_close) { - - // Low power ticker incremented to less than _min_count_until_match - // so low power ticker may not fire. Use Timeout to ensure it does fire. - uint32_t ticks = cycles_until_match < _min_count_until_match ? cycles_until_match : _min_count_until_match; - _timeout.attach(mbed::callback(this, &LowPowerTickerWrapper::_timeout_handler), _lp_ticks_to_us(ticks)); - _pending_timeout = true; - return; - } -} diff --git a/hal/LowPowerTickerWrapper.h b/hal/LowPowerTickerWrapper.h deleted file mode 100644 index a709d14..0000000 --- a/hal/LowPowerTickerWrapper.h +++ /dev/null @@ -1,246 +0,0 @@ - -/** \addtogroup hal */ -/** @{*/ -/* mbed Microcontroller Library - * Copyright (c) 2018-2019 ARM Limited - * 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. - */ -#ifndef MBED_LOW_POWER_TICKER_WRAPPER_H -#define MBED_LOW_POWER_TICKER_WRAPPER_H - -#include "device.h" - -#include "hal/ticker_api.h" -#include "hal/us_ticker_api.h" -#include "drivers/Timeout.h" - -#include "platform/mbed_chrono.h" -#include "platform/mbed_critical.h" - - -class LowPowerTickerWrapper { -public: - - - /** - * Create a new wrapped low power ticker object - * - * @param data Low power ticker data to wrap - * @param interface new ticker interface functions - * @param min_cycles_between_writes The number of whole low power clock periods - * which must complete before subsequent calls to set_interrupt - * @param min_cycles_until_match The minimum number of whole low power clock periods - * from the current time for which the match timestamp passed to set_interrupt is - * guaranteed to fire. - * - * N = min_cycles_between_writes - * - * 0 1 N - 1 N N + 1 N + 2 N + 3 - * |-------|------...------|-------|-------|-------|-------| - * ^ ^ - * | | - * set_interrupt Next set_interrupt allowed - * - * N = min_cycles_until_match - * - * 0 1 N - 1 N N + 1 N + 2 N + 3 - * |-------|------...------|-------|-------|-------|-------| - * ^ ^ - * | | - * set_interrupt Earliest match timestamp allowed - * - * - */ - - LowPowerTickerWrapper(const ticker_data_t *data, const ticker_interface_t *interface, uint32_t min_cycles_between_writes, uint32_t min_cycles_until_match); - - /** - * Interrupt handler called by the underlying driver/hardware - * - * @param handler The callback which would normally be called by the underlying driver/hardware - */ - void irq_handler(ticker_irq_handler_type handler); - - /** - * Suspend wrapper operation and pass through interrupts. - * - * This stops to wrapper layer from using the microsecond ticker. - * This should be called before using the low power ticker APIs directly. - * - * @warning: Make sure to suspend the LP ticker first (call ticker_suspend()), - * otherwise the behavior is undefined. - */ - void suspend(); - - /** - * Resume wrapper operation and filter interrupts normally - */ - void resume(); - - /** - * Check if a Timeout object is being used - * - * @return true if Timeout is used for scheduling false otherwise - */ - bool timeout_pending(); - - /* - * Implementation of ticker_init - */ - void init(); - - /* - * Implementation of free - */ - void free(); - - /* - * Implementation of read - */ - uint32_t read(); - - /* - * Implementation of set_interrupt - */ - void set_interrupt(timestamp_t timestamp); - - /* - * Implementation of disable_interrupt - */ - void disable_interrupt(); - - /* - * Implementation of clear_interrupt - */ - void clear_interrupt(); - - /* - * Implementation of fire_interrupt - */ - void fire_interrupt(); - - /* - * Implementation of get_info - */ - const ticker_info_t *get_info(); - - ticker_data_t data; - -private: - mbed::Timeout _timeout; - const ticker_interface_t *const _intf; - - /* - * The number of low power clock cycles which must pass between subsequent - * calls to intf->set_interrupt - */ - const uint32_t _min_count_between_writes; - - /* - * The minimum number of low power clock cycles in the future that - * a match value can be set to and still fire - */ - const uint32_t _min_count_until_match; - - /* - * Flag to indicate if the timer is suspended - */ - bool _suspended; - - /* - * _cur_match_time is valid and Timeout is scheduled to fire - */ - bool _pending_timeout; - - /* - * set_interrupt has been called and _cur_match_time is valid - */ - bool _pending_match; - - /* - * The function LowPowerTickerWrapper::fire_interrupt has been called - * and an interrupt is expected. - */ - bool _pending_fire_now; - - /* - * It is safe to call intf->set_interrupt - */ - bool _set_interrupt_allowed; - - /* - * Last value written by LowPowerTickerWrapper::set_interrupt - */ - timestamp_t _cur_match_time; - - /* - * Time of last call to LowPowerTickerWrapper::set_interrupt - */ - uint32_t _last_set_interrupt; - - /* - * Time of last call to intf->set_interrupt - */ - uint32_t _last_actual_set_interrupt; - - /* - * Mask of valid bits from intf->read() - */ - uint32_t _mask; - - /* - * Microsecond per low power tick (rounded up) - */ - uint32_t _us_per_tick; - - - void _reset(); - - /** - * Set the low power ticker match time when hardware is ready - * - * This event is scheduled to set the lp timer after the previous write - * has taken effect and it is safe to write a new value without blocking. - * If the time has already passed then this function fires and interrupt - * immediately. - */ - void _timeout_handler(); - - /* - * Check match time has passed - */ - bool _match_check(timestamp_t current); - - /* - * Convert low power ticks to approximate microseconds - * - * This value is always larger or equal to exact value. - */ - mbed::chrono::microseconds_u32 _lp_ticks_to_us(uint32_t); - - /* - * Schedule a match interrupt to fire at the correct time - * - * @param current The current low power ticker time - */ - void _schedule_match(timestamp_t current); - -}; - -#endif - -/** @}*/ - - diff --git a/hal/analogin_api.h b/hal/analogin_api.h deleted file mode 100644 index d172607..0000000 --- a/hal/analogin_api.h +++ /dev/null @@ -1,120 +0,0 @@ - -/** \addtogroup hal */ -/** @{*/ -/* mbed Microcontroller Library - * Copyright (c) 2006-2013 ARM Limited - * 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. - */ -#ifndef MBED_ANALOGIN_API_H -#define MBED_ANALOGIN_API_H - -#include "device.h" -#include "pinmap.h" - -#if DEVICE_ANALOGIN - -#ifdef __cplusplus -extern "C" { -#endif - -/** Analogin hal structure. analogin_s is declared in the target's hal - */ -typedef struct analogin_s analogin_t; - -/** - * \defgroup hal_analogin Analogin hal functions - * - * # Defined behaviour - * * The function ::analogin_init initializes the analogin_t control structure - * * The function ::analogin_free returns the pin owned by the Analogin object to its reset state - * * The function ::analogin_read reads the input voltage, represented as a float in the range [0.0 (GND), 1.0 (VCC)] - * * The function ::analogin_read_u16 reads the value from analogin pin, represented as an unsigned 16bit value [0.0 (GND), MAX_UINT16 (VCC)] - * * The accuracy of the ADC is +/- 10% - * * The ADC operations ::analogin_read, ::analogin_read_u16 take less than 20us to complete - * - * # Undefined behaviour - * - * * ::analogin_init is called with invalid pin (which does not support analog input function) - * * Calling ::analogin_read, ::analogin_read_u16 before ::analogin_init - * @{ - */ - -/** - * \defgroup hal_analogin_tests Analogin hal tests - * The Analogin HAL tests ensure driver conformance to defined behaviour. - * - * To run the Analogin hal tests use the command: - * - * mbed test -t -m -n tests-mbed_hal_fpga_ci_test_shield-analogin - * - */ - -/** Initialize the analogin peripheral - * - * Configures the pin used by analogin. - * @param obj The analogin object to initialize - * @param pinmap pointer to structure which holds static pinmap - */ -void analogin_init_direct(analogin_t *obj, const PinMap *pinmap); - -/** Initialize the analogin peripheral - * - * Configures the pin used by analogin. - * @param obj The analogin object to initialize - * @param pin The analogin pin name - */ -void analogin_init(analogin_t *obj, PinName pin); - -/** Release the analogin peripheral - * - * Releases the pin used by analogin. - * @param obj The analogin object to initialize - */ -void analogin_free(analogin_t *obj); - -/** Read the input voltage, represented as a float in the range [0.0, 1.0] - * - * @param obj The analogin object - * @return A floating value representing the current input voltage - */ -float analogin_read(analogin_t *obj); - -/** Read the value from analogin pin, represented as an unsigned 16bit value - * - * @param obj The analogin object - * @return An unsigned 16bit value representing the current input voltage - */ -uint16_t analogin_read_u16(analogin_t *obj); - -/** Get the pins that support analogin - * - * Return a PinMap array of pins that support analogin. The - * array is terminated with {NC, NC, 0}. - * - * @return PinMap array - */ -const PinMap *analogin_pinmap(void); - -/**@}*/ - -#ifdef __cplusplus -} -#endif - -#endif - -#endif - -/** @}*/ diff --git a/hal/analogout_api.h b/hal/analogout_api.h deleted file mode 100644 index 4212907..0000000 --- a/hal/analogout_api.h +++ /dev/null @@ -1,136 +0,0 @@ - -/** \addtogroup hal */ -/** @{*/ -/* mbed Microcontroller Library - * Copyright (c) 2006-2013 ARM Limited - * 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. - */ -#ifndef MBED_ANALOGOUT_API_H -#define MBED_ANALOGOUT_API_H - -#include "device.h" -#include "pinmap.h" - -#if DEVICE_ANALOGOUT - -#ifdef __cplusplus -extern "C" { -#endif - -/** Analogout hal structure. dac_s is declared in the target's hal - */ -typedef struct dac_s dac_t; - -/** - * \defgroup hal_analogout Analogout hal functions - * - * # Defined behaviour - * * The function ::analogout_init initializes the dac_t control structure - * * The function ::analogout_write sets the output voltage, specified as a percentage (float) in range [0.0 (GND), 1.0 (VCC)] - * * The function ::analogout_write_u16 sets the output voltage, specified as unsigned 16-bit value [0 (GND), MAX_UINT16 (VCC)] - * * The function ::analogout_read reads the current voltage value on the pin and returns a floating-point value representing the current voltage in range [0.0 (GND), 1.0 (VCC)] - * * The function ::analogout_read_u16 reads the current voltage value on the pin and returns the output voltage, specified as unsigned 16-bit value [0 (GND), MAX_UINT16 (VCC)] - * * The accuracy of the DAC is +/- 10% - * * The DAC operations ::analogout_write, ::analogout_write_u16, ::analogout_read, ::analogout_read_u16 take less than 20us to complete - * * The function ::analogout_free releases the analogout object - * - * # Undefined behaviour - * - * * ::analogout_init is called with invalid pin (which does not support analog output function) - * * Calling other functions before ::analogout_init - * @{ - */ - -/** - * \defgroup hal_analogin_tests Analogout hal tests - * The Analogout HAL tests ensure driver conformance to defined behaviour. - * - * To run the Analogout hal tests use the command: - * - * mbed test -t -m -n tests-mbed_hal_fpga_ci_test_shield-analogout - * - */ - -/** Initialize the analogout peripheral - * - * Configures the pin used by analogout. - * @param obj The analogout object to initialize - * @param pinmap pointer to structure which holds static pinmap - */ -void analogout_init_direct(dac_t *obj, const PinMap *pinmap); - -/** Initialize the analogout peripheral - * - * Configures the pin used by analogout. - * @param obj The analogout object to initialize - * @param pin The analogout pin name - */ -void analogout_init(dac_t *obj, PinName pin); - -/** Release the analogout object - * - * @param obj The analogout object - */ -void analogout_free(dac_t *obj); - -/** Set the output voltage, specified as a percentage (float) - * - * @param obj The analogin object - * @param value The floating-point output voltage to be set - */ -void analogout_write(dac_t *obj, float value); - -/** Set the output voltage, specified as unsigned 16-bit - * - * @param obj The analogin object - * @param value The unsigned 16-bit output voltage to be set - */ -void analogout_write_u16(dac_t *obj, uint16_t value); - -/** Read the current voltage value on the pin - * - * @param obj The analogin object - * @return A floating-point value representing the current voltage on the pin, - * measured as a percentage - */ -float analogout_read(dac_t *obj); - -/** Read the current voltage value on the pin, as a normalized unsigned 16bit value - * - * @param obj The analogin object - * @return An unsigned 16-bit value representing the current voltage on the pin - */ -uint16_t analogout_read_u16(dac_t *obj); - -/** Get the pins that support analogout - * - * Return a PinMap array of pins that support analogout. The - * array is terminated with {NC, NC, 0}. - * - * @return PinMap array - */ -const PinMap *analogout_pinmap(void); - -/**@}*/ - -#ifdef __cplusplus -} -#endif - -#endif - -#endif - -/** @}*/ diff --git a/hal/buffer.h b/hal/buffer.h deleted file mode 100644 index a68b940..0000000 --- a/hal/buffer.h +++ /dev/null @@ -1,36 +0,0 @@ - -/** \addtogroup hal */ -/** @{*/ -/* mbed Microcontroller Library - * Copyright (c) 2014-2015 ARM Limited - * 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. - */ -#ifndef MBED_BUFFER_H -#define MBED_BUFFER_H - -#include - -/** Generic buffer structure - */ -typedef struct buffer_s { - void *buffer; /**< the pointer to a buffer */ - size_t length; /**< the buffer length */ - size_t pos; /**< actual buffer position */ - uint8_t width; /**< The buffer unit width (8, 16, 32, 64), used for proper *buffer casting */ -} buffer_t; - -#endif - -/** @}*/ diff --git a/hal/can_api.h b/hal/can_api.h deleted file mode 100644 index 9774d12..0000000 --- a/hal/can_api.h +++ /dev/null @@ -1,116 +0,0 @@ - -/** \addtogroup hal */ -/** @{*/ -/* mbed Microcontroller Library - * Copyright (c) 2006-2016 ARM Limited - * 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. - */ -#ifndef MBED_CAN_API_H -#define MBED_CAN_API_H - -#include "device.h" -#include "pinmap.h" - -#if DEVICE_CAN - -#include "PinNames.h" -#include "PeripheralNames.h" -#include "hal/can_helper.h" - -#ifdef __cplusplus -extern "C" { -#endif - -typedef enum { - IRQ_RX, - IRQ_TX, - IRQ_ERROR, - IRQ_OVERRUN, - IRQ_WAKEUP, - IRQ_PASSIVE, - IRQ_ARB, - IRQ_BUS, - IRQ_READY -} CanIrqType; - - -typedef enum { - MODE_RESET, - MODE_NORMAL, - MODE_SILENT, - MODE_TEST_LOCAL, - MODE_TEST_GLOBAL, - MODE_TEST_SILENT -} CanMode; - -typedef struct { - int peripheral; - PinName rd_pin; - int rd_function; - PinName td_pin; - int td_function; -} can_pinmap_t; - -typedef void (*can_irq_handler)(uint32_t id, CanIrqType type); - -typedef struct can_s can_t; - -void can_init(can_t *obj, PinName rd, PinName td); -void can_init_direct(can_t *obj, const can_pinmap_t *pinmap); -void can_init_freq(can_t *obj, PinName rd, PinName td, int hz); -void can_init_freq_direct(can_t *obj, const can_pinmap_t *pinmap, int hz); -void can_free(can_t *obj); -int can_frequency(can_t *obj, int hz); - -void can_irq_init(can_t *obj, can_irq_handler handler, uint32_t id); -void can_irq_free(can_t *obj); -void can_irq_set(can_t *obj, CanIrqType irq, uint32_t enable); - -int can_write(can_t *obj, CAN_Message, int cc); -int can_read(can_t *obj, CAN_Message *msg, int handle); -int can_mode(can_t *obj, CanMode mode); -int can_filter(can_t *obj, uint32_t id, uint32_t mask, CANFormat format, int32_t handle); -void can_reset(can_t *obj); -unsigned char can_rderror(can_t *obj); -unsigned char can_tderror(can_t *obj); -void can_monitor(can_t *obj, int silent); - -/** Get the pins that support CAN RD - * - * Return a PinMap array of pins that support CAN RD. The - * array is terminated with {NC, NC, 0}. - * - * @return PinMap array - */ -const PinMap *can_rd_pinmap(void); - -/** Get the pins that support CAN TD - * - * Return a PinMap array of pins that support CAN TD. The - * array is terminated with {NC, NC, 0}. - * - * @return PinMap array - */ -const PinMap *can_td_pinmap(void); - -#ifdef __cplusplus -} -#endif - -#endif // MBED_CAN_API_H - -#endif - -/** @}*/ diff --git a/hal/can_helper.h b/hal/can_helper.h deleted file mode 100644 index 3f56f16..0000000 --- a/hal/can_helper.h +++ /dev/null @@ -1,78 +0,0 @@ - -/** \addtogroup hal */ -/** @{*/ -/* mbed Microcontroller Library - * Copyright (c) 2006-2013 ARM Limited - * 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. - */ -#ifndef MBED_CAN_HELPER_H -#define MBED_CAN_HELPER_H - -#if DEVICE_CAN - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * - * \enum CANFormat - * - * \brief Values that represent CAN Format -**/ -enum CANFormat { - CANStandard = 0, - CANExtended = 1, - CANAny = 2 -}; -typedef enum CANFormat CANFormat; - -/** - * - * \enum CANType - * - * \brief Values that represent CAN Type -**/ -enum CANType { - CANData = 0, - CANRemote = 1 -}; -typedef enum CANType CANType; - -/** - * - * \struct CAN_Message - * - * \brief Holder for single CAN message. - * -**/ -struct CAN_Message { - unsigned int id; // 29 bit identifier - unsigned char data[8]; // Data field - unsigned char len; // Length of data field in bytes - CANFormat format; // Format ::CANFormat - CANType type; // Type ::CANType -}; -typedef struct CAN_Message CAN_Message; - -#ifdef __cplusplus -} -#endif - -#endif - -#endif // MBED_CAN_HELPER_H - -/** @}*/ diff --git a/hal/crc_api.h b/hal/crc_api.h deleted file mode 100644 index e59b678..0000000 --- a/hal/crc_api.h +++ /dev/null @@ -1,233 +0,0 @@ -/** \addtogroup hal */ -/** @{*/ -/* mbed Microcontroller Library - * Copyright (c) 2018 ARM Limited - * 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. - */ -#ifndef MBED_CRC_HAL_API_H -#define MBED_CRC_HAL_API_H - -#include -#include -#include - -/** CRC Polynomial value - * - * Different polynomial values supported - */ -typedef enum crc_polynomial { - POLY_7BIT_SD = 0x09, ///< x7+x3+1 - POLY_8BIT_CCITT = 0x07, ///< x8+x2+x+1 - POLY_16BIT_CCITT = 0x1021, ///< x16+x12+x5+1 - POLY_16BIT_IBM = 0x8005, ///< x16+x15+x2+1 - POLY_32BIT_ANSI = 0x04C11DB7 ///< x32+x26+x23+x22+x16+x12+x11+x10+x8+x7+x5+x4+x2+x+1 -} crc_polynomial_t; - -typedef struct crc_mbed_config { - /** CRC Polynomial. Example polynomial: x^8+x^5+x+1 -> width = 8, polynomial = 0010_0011 = 0x21 */ - uint32_t polynomial; - /** CRC Bit Width */ - uint32_t width; - /** Initial seed value for the computation. */ - uint32_t initial_xor; - /** Final xor value for the computation. */ - uint32_t final_xor; - /** Reflect bits on input. */ - bool reflect_in; - /** Reflect bits in final result before returning. */ - bool reflect_out; -} crc_mbed_config_t; - -#if DEVICE_CRC - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * \defgroup hal_crc Hardware CRC - * - * The Hardware CRC HAL API provides a low-level interface to the Hardware CRC - * module of a target platform. - * - * # Defined behaviour - * - * * Macro HAL_CRC_IS_SUPPORTED() evaluates true if platform supports hardware - * CRC for the given polynomial/width - verified by test ::crc_is_supported_test. - * * Macro HAL_CRC_IS_SUPPORTED() evaluates false if platform does not support hardware - * CRC for the given polynomial/width - verified by test ::crc_is_supported_test. - * * If CRC module does not support any of the following settings: initial_xor, final_xor - * reflect_in, reflect_out, then these operations must be handled by the driver - * - Verified by test ::crc_calc_single_test. - * * Platform which supports hardware CRC must be able to handle at least one of the predefined - * polynomial/width configurations that can be constructed in the MbedCRC class: POLY_8BIT_CCITT, - * POLY_7BIT_SD, POLY_16BIT_CCITT, POLY_16BIT_IBM, POLY_32BIT_ANSI - * - verified by test ::crc_is_supported_test, ::crc_calc_single_test. - * * Function hal_crc_compute_partial_start() configures CRC module with the given configuration - * - Verified by test ::crc_calc_single_test. - * * Calling hal_crc_compute_partial_start() without finalising the - * CRC calculation overrides the current configuration - Verified by test ::crc_reconfigure_test. - * * Function hal_crc_compute_partial() writes data to the CRC module - verified by test ::crc_calc_single_test. - * * Function hal_crc_compute_partial() can be call multiple times in succession in order to - * provide additional data to CRC module - verified by test ::crc_calc_multi_test. - * * Function hal_crc_compute_partial() does nothing if pointer to buffer is undefined or - * data length is equal to 0 - verified by test ::crc_compute_partial_invalid_param_test. - * * Function hal_crc_get_result() returns the checksum result from the CRC module - * - verified by tests ::crc_calc_single_test, ::crc_calc_multi_test, ::crc_reconfigure_test. - * - * # Undefined behaviour - * - * * Calling hal_crc_compute_partial_start() function with invalid (unsupported) polynomial. - * * Calling hal_crc_compute_partial() or hal_crc_get_result() functions before hal_crc_compute_partial_start(). - * * Calling hal_crc_get_result() function multiple times. - * - * # Non-functional requirements - * - * * CRC configuration provides the following settings: - * * polynomial - CRC Polynomial, - * * width - CRC bit width, - * * initial_xor - seed value for the computation, - * * final_xor - final xor value for the computation, - * * reflect_in - reflect bits on input, - * * reflect_out - reflect bits in final result before returning. - * - * # Potential bugs - * - * # Macros - * - * Platform support for particular CRC polynomials is indicated by the - * macro HAL_CRC_IS_SUPPORTED(polynomial, width), which must be defined - * in device.h, or a file included from there. - * - * The macro must evaluate to a constant boolean expression when given - * constant parameters. - * - * The current platform must support the given polynomial with all possible - * other config parameters if the macro evaluates to true. These are: - * reflect in, reflect out, initial xor and final xor. If any of these settings - * of these settings cannot be configured, the polynomial is not supported. - * - * Example: - * - * #define HAL_CRC_IS_SUPPORTED(polynomial, width) \ - * ((width) == 16 || ((width) == 32 && (polynomial) == POLY_32BIT_ANSI) - * @{ - */ - -/** - * \defgroup hal_crc_tests crc hal tests - * The crc HAL tests ensure driver conformance to defined behaviour. - * - * To run the crc hal tests use the command: - * - * mbed test -t -m -n tests-mbed_hal-crc* - * - */ - -/** Initialize the hardware CRC module with the given polynomial - * - * After calling this function, the CRC HAL module is ready to receive data - * using the hal_crc_compute_partial() function. The CRC module on the board - * is configured internally with the specified configuration and is ready - * to receive data. - * - * The platform configures itself based on the default configuration - * parameters of the input polynomial. - * - * This function must be called before calling hal_crc_compute_partial(). - * - * This function must be called with a valid polynomial supported by the - * platform. The polynomial must be checked for support using the - * HAL_CRC_IS_SUPPORTED() macro. - * - * Calling hal_crc_compute_partial_start() multiple times without finalizing the - * CRC calculation with hal_crc_get_result() overrides the current - * configuration and state, and the intermediate result of the computation is - * lost. - * - * This function is not thread safe. A CRC calculation must not be started from - * two different threads or contexts at the same time; calling this function - * from two different contexts may lead to configurations being overwritten and - * results being lost. - * - * \param config Contains CRC configuration parameters for initializing the - * hardware CRC module. For example, polynomial and initial seed - * values. - */ -void hal_crc_compute_partial_start(const crc_mbed_config_t *config); - -/** Writes data to the current CRC module. - * - * Writes input data buffer bytes to the CRC data register. The CRC module - * must interpret the data as an array of bytes. - * - * The final transformations are not applied to the data; the CRC module must - * retain the intermediate result so that additional calls to this function - * can be made, appending the additional data to the calculation. - * - * To obtain the final result of the CRC calculation, hal_crc_get_result() is - * called to apply the final transformations to the data. - * - * If the function is passed an undefined pointer, or the size of the buffer is - * specified to be 0, this function does nothing and returns. - * - * This function can be called multiple times in succession. This can be used - * to calculate the CRC result of streamed data. - * - * This function is not thread safe. There is only one instance of the CRC - * module active at a time. Calling this function from multiple contexts - * appends different data to the same, single instance of the module, which causes an - * erroneous value to be calculated. - * - * \param data Input data stream to be written into the CRC calculation - * \param size Size of the data stream in bytes - */ -void hal_crc_compute_partial(const uint8_t *data, const size_t size); - -/* Reads the checksum result from the CRC module. - * - * Reads the final checksum result for the final checksum value. The returned - * value is cast as an unsigned 32-bit integer. The actual size of the returned - * result depends on the polynomial used to configure the CRC module. - * - * Additional transformations that are used in the default configuration of the - * input polynomial are applied to the result before it is returned from this - * function. These transformations include: the final xor being appended to the - * calculation, and the result being reflected if required. - * - * Calling this function multiple times is undefined. The first call to this - * function returns the final result of the CRC calculation. The return - * value on successive calls is undefined because the contents of the register after - * accessing them is platform-specific. - * - * This function is not thread safe. There is only one instance of the CRC - * module active at a time. Calling this function from multiple contexts may - * return incorrect data or affect the current state of the module. - * - * \return The final CRC checksum after the reflections and final calculations - * have been applied. - */ -uint32_t hal_crc_get_result(void); - -/**@}*/ - -#ifdef __cplusplus -} -#endif - -#endif // DEVICE_CRC -#endif // MBED_CRC_HAL_API_H - -/**@}*/ diff --git a/hal/critical_section_api.h b/hal/critical_section_api.h deleted file mode 100644 index 8c6ac59..0000000 --- a/hal/critical_section_api.h +++ /dev/null @@ -1,108 +0,0 @@ -/** \addtogroup hal */ -/** @{*/ -/* mbed Microcontroller Library - * Copyright (c) 2006-2017 ARM Limited - * 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. - */ -#ifndef MBED_CRITICAL_SECTION_API_H -#define MBED_CRITICAL_SECTION_API_H - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * \defgroup hal_critical Critical Section HAL functions - * @{ - */ - -/** - * Mark the start of a critical section - * - * This function will be called by core_util_critical_section_enter() each time - * the application requests to enter a critical section. The purpose of the - * critical section is to ensure mutual-exclusion synchronisation of the - * processor by preventing any change in processor control, the default - * behaviour requires storing the state of interrupts in the system before - * disabling them. - * - * The critical section code supports nesting. When a thread has entered a - * critical section it can make additional calls to - * core_util_critical_section_enter() without deadlocking itself. The critical - * section driver API tracks the number of nested calls to the critical section. - * The critical section will only be exited when - * core_util_critical_section_exit() has been called once for each time it - * entered the critical section. - * - * On the first call to enter a critical section this function MUST store the - * state of any interrupts or other application settings it will modify to - * facilitate the critical section. - * - * Each successive call to enter the critical section MUST ignore storing or - * modifying any application state. - * - * The default implementation of this function which will save the current state - * of interrupts before disabling them. This implementation can be found in - * mbed_critical_section_api.c. This behaviour is can be overridden on a per - * platform basis by providing a different implementation within the correct - * targets directory. - */ -void hal_critical_section_enter(void); - - -/** Mark the end of a critical section. - * - * The purpose of this function is to restore any state that was modified upon - * entering the critical section, allowing other threads or interrupts to change - * the processor control. - * - * This function will be called once by core_util_critical_section_exit() per - * critical section on last call to exit. When called, the application MUST - * restore the saved interrupt/application state that was saved when entering - * the critical section. - * - * There is a default implementation of this function, it will restore the state - * of interrupts that were previously saved when hal_critical_section_enter was - * first called, this implementation can be found in - * mbed_critical_section_api.c. This behaviour is overridable by providing a - * different function implementation within the correct targets directory. - */ -void hal_critical_section_exit(void); - - -/** Determine if the application is currently running in a critical section - * - * The purpose of this function is to inform the caller whether or not the - * application is running in a critical section. This is done by checking if - * the current interrupt state has been saved in the underlying implementation, - * this could also be done by checking the state of the interrupts at the time - * of calling. - * - * @return True if running in a critical section, false if not. - */ -bool hal_in_critical_section(void); - - -/**@}*/ - -#ifdef __cplusplus -} -#endif - -#endif // MBED_CRITICAL_SECTION_API_H - -/** @}*/ diff --git a/hal/dma_api.h b/hal/dma_api.h deleted file mode 100644 index 864439e..0000000 --- a/hal/dma_api.h +++ /dev/null @@ -1,51 +0,0 @@ - -/** \addtogroup hal */ -/** @{*/ -/* mbed Microcontroller Library - * Copyright (c) 2014-2015 ARM Limited - * 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. - */ -#ifndef MBED_DMA_API_H -#define MBED_DMA_API_H - -#include - -#define DMA_ERROR_OUT_OF_CHANNELS (-1) - -typedef enum { - DMA_USAGE_NEVER, - DMA_USAGE_OPPORTUNISTIC, - DMA_USAGE_ALWAYS, - DMA_USAGE_TEMPORARY_ALLOCATED, - DMA_USAGE_ALLOCATED -} DMAUsage; - -#ifdef __cplusplus -extern "C" { -#endif - -void dma_init(void); - -int dma_channel_allocate(uint32_t capabilities); - -int dma_channel_free(int channelid); - -#ifdef __cplusplus -} -#endif - -#endif - -/** @}*/ diff --git a/hal/flash_api.h b/hal/flash_api.h deleted file mode 100644 index e98c806..0000000 --- a/hal/flash_api.h +++ /dev/null @@ -1,138 +0,0 @@ -/** \addtogroup hal */ -/** @{*/ - -/* mbed Microcontroller Library - * Copyright (c) 2017 ARM Limited - * 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. - */ -#ifndef MBED_FLASH_API_H -#define MBED_FLASH_API_H - -#include "device.h" -#include - -#if DEVICE_FLASH - -#define MBED_FLASH_INVALID_SIZE 0xFFFFFFFF - -typedef struct flash_s flash_t; - -#if TARGET_FLASH_CMSIS_ALGO -#include "flash_data.h" -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * \defgroup flash_hal Flash HAL API - * @{ - */ - -/** Initialize the flash peripheral and the flash_t object - * - * @param obj The flash object - * @return 0 for success, -1 for error - */ -int32_t flash_init(flash_t *obj); - -/** Uninitialize the flash peripheral and the flash_t object - * - * @param obj The flash object - * @return 0 for success, -1 for error - */ -int32_t flash_free(flash_t *obj); - -/** Erase one sector starting at defined address - * - * The address should be at sector boundary. This function does not do any check for address alignments - * @param obj The flash object - * @param address The sector starting address - * @return 0 for success, -1 for error - */ -int32_t flash_erase_sector(flash_t *obj, uint32_t address); - -/** Read data starting at defined address - * - * This function has a WEAK implementation using memcpy for backwards compatibility. - * @param obj The flash object - * @param address Address to begin reading from - * @param data The buffer to read data into - * @param size The number of bytes to read - * @return 0 for success, -1 for error - */ -int32_t flash_read(flash_t *obj, uint32_t address, uint8_t *data, uint32_t size); - -/** Program pages starting at defined address - * - * The pages should not cross multiple sectors. - * This function does not do any check for address alignments or if size is aligned to a page size. - * @param obj The flash object - * @param address The sector starting address - * @param data The data buffer to be programmed - * @param size The number of bytes to program - * @return 0 for success, -1 for error - */ -int32_t flash_program_page(flash_t *obj, uint32_t address, const uint8_t *data, uint32_t size); - -/** Get sector size - * - * @param obj The flash object - * @param address The sector starting address - * @return The size of a sector - */ -uint32_t flash_get_sector_size(const flash_t *obj, uint32_t address); - -/** Get page size - * - * The page size defines the writable page size - * @param obj The flash object - * @return The size of a page - */ -uint32_t flash_get_page_size(const flash_t *obj); - -/** Get start address for the flash region - * - * @param obj The flash object - * @return The start address for the flash region - */ -uint32_t flash_get_start_address(const flash_t *obj); - -/** Get the flash region size - * - * @param obj The flash object - * @return The flash region size - */ -uint32_t flash_get_size(const flash_t *obj); - -/** Get the flash erase value - * - * @param obj The flash object - * @return The flash erase value - */ -uint8_t flash_get_erase_value(const flash_t *obj); - -/**@}*/ - -#ifdef __cplusplus -} -#endif - -#endif - -#endif - -/** @}*/ diff --git a/hal/gpio_api.h b/hal/gpio_api.h deleted file mode 100644 index c4f4d17..0000000 --- a/hal/gpio_api.h +++ /dev/null @@ -1,201 +0,0 @@ - -/** \addtogroup hal */ -/** @{*/ -/* mbed Microcontroller Library - * Copyright (c) 2006-2020 ARM Limited - * 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. - */ -#ifndef MBED_GPIO_API_H -#define MBED_GPIO_API_H - -#include -#include "device.h" -#include "pinmap.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * \defgroup hal_gpio GPIO HAL functions - * - * # Defined behavior - * * ::gpio_init and other init functions can be called with NC or a valid PinName for the target - Verified by ::gpio_nc_test - * * ::gpio_is_connected can be used to test whether a gpio_t object was initialized with NC - Verified by ::gpio_nc_test - * * ::gpio_init initializes the GPIO pin - * * ::gpio_free returns the pin owned by the GPIO object to its reset state - * * ::gpio_mode sets the mode of the given pin - * * ::gpio_dir sets the direction of the given pin - * * ::gpio_write sets the gpio output value - * * ::gpio_read reads the input value - * * ::gpio_init_in inits the input pin and sets mode to PullDefault - * * ::gpio_init_in_ex inits the input pin and sets the mode - * * ::gpio_init_out inits the pin as an output, with predefined output value 0 - * * ::gpio_init_out_ex inits the pin as an output and sets the output value - * * ::gpio_init_inout inits the pin to be input/output and set pin mode and value - * * The GPIO operations ::gpio_write, ::gpio_read take less than 20us to complete - * * The function ::gpio_get_capabilities fills the given - * `gpio_capabilities_t` instance according to pin capabilities. - * - * # Undefined behavior - * * Calling any ::gpio_mode, ::gpio_dir, ::gpio_write or ::gpio_read on a gpio_t object that was initialized - * with NC. - * * Calling ::gpio_set with NC. - * - * @{ - */ - -/** - * \defgroup hal_gpio_tests GPIO HAL tests - * The GPIO HAL tests ensure driver conformance to defined behaviour. - * - * To run the GPIO hal tests use the command: - * - * mbed test -t -m -n tests-mbed_hal_fpga_ci_test_shield-gpio,tests-mbed_hal-gpio - * - */ - -/** GPIO capabilities for a given pin - */ -typedef struct { - uint8_t pull_none : 1; - uint8_t pull_down : 1; - uint8_t pull_up : 1; -} gpio_capabilities_t; - -/** Set the given pin as GPIO - * - * @param pin The pin to be set as GPIO - * @return The GPIO port mask for this pin - **/ -uint32_t gpio_set(PinName pin); - -/** Checks if gpio object is connected (pin was not initialized with NC) - * @param obj The GPIO object - * @return 0 if object was initialized with NC - * @return non-zero if object was initialized with a valid PinName - **/ -int gpio_is_connected(const gpio_t *obj); - -/** Initialize the GPIO pin - * - * @param obj The GPIO object to initialize - * @param pin The GPIO pin to initialize (may be NC) - */ -void gpio_init(gpio_t *obj, PinName pin); - -/** Releases the GPIO pin - * - * @param obj The GPIO object to release - */ -void gpio_free(gpio_t *obj); - -/** Set the input pin mode - * - * @param obj The GPIO object (must be connected) - * @param mode The pin mode to be set - */ -void gpio_mode(gpio_t *obj, PinMode mode); - -/** Set the pin direction - * - * @param obj The GPIO object (must be connected) - * @param direction The pin direction to be set - */ -void gpio_dir(gpio_t *obj, PinDirection direction); - -/** Set the output value - * - * @param obj The GPIO object (must be connected) - * @param value The value to be set - */ -void gpio_write(gpio_t *obj, int value); - -/** Read the input value - * - * @param obj The GPIO object (must be connected) - * @return An integer value 1 or 0 - */ -int gpio_read(gpio_t *obj); - -// the following functions are generic and implemented in the common gpio.c file -// TODO: fix, will be moved to the common gpio header file - -/** Init the input pin and set mode to PullDefault - * - * @param gpio The GPIO object - * @param pin The pin name (may be NC) - */ -void gpio_init_in(gpio_t *gpio, PinName pin); - -/** Init the input pin and set the mode - * - * @param gpio The GPIO object - * @param pin The pin name (may be NC) - * @param mode The pin mode to be set - */ -void gpio_init_in_ex(gpio_t *gpio, PinName pin, PinMode mode); - -/** Init the output pin as an output, with predefined output value 0 - * - * @param gpio The GPIO object - * @param pin The pin name (may be NC) - * @return An integer value 1 or 0 - */ -void gpio_init_out(gpio_t *gpio, PinName pin); - -/** Init the pin as an output and set the output value - * - * @param gpio The GPIO object - * @param pin The pin name (may be NC) - * @param value The value to be set - */ -void gpio_init_out_ex(gpio_t *gpio, PinName pin, int value); - -/** Init the pin to be in/out - * - * @param gpio The GPIO object - * @param pin The pin name (may be NC) - * @param direction The pin direction to be set - * @param mode The pin mode to be set - * @param value The value to be set for an output pin - */ -void gpio_init_inout(gpio_t *gpio, PinName pin, PinDirection direction, PinMode mode, int value); - -/** Fill the given gpio_capabilities_t instance according to pin capabilities. - */ -void gpio_get_capabilities(gpio_t *gpio, gpio_capabilities_t *cap); - -/** Get the pins that support all GPIO tests - * - * Return a PinMap array of pins that support GPIO. The - * array is terminated with {NC, NC, 0}. - * - * Targets should override the weak implementation of this - * function to provide the actual pinmap for GPIO testing. - * - * @return PinMap array - */ -const PinMap *gpio_pinmap(void); - -/**@}*/ - -#ifdef __cplusplus -} -#endif - -#endif - -/** @}*/ diff --git a/hal/gpio_irq_api.h b/hal/gpio_irq_api.h deleted file mode 100644 index e08b049..0000000 --- a/hal/gpio_irq_api.h +++ /dev/null @@ -1,133 +0,0 @@ - -/** \addtogroup hal */ -/** @{*/ -/* mbed Microcontroller Library - * Copyright (c) 2006-2013 ARM Limited - * 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. - */ -#ifndef MBED_GPIO_IRQ_API_H -#define MBED_GPIO_IRQ_API_H - -#include "device.h" -#include "pinmap.h" - -#if DEVICE_INTERRUPTIN - -#ifdef __cplusplus -extern "C" { -#endif - -/** GPIO IRQ events - */ -typedef enum { - IRQ_NONE, - IRQ_RISE, - IRQ_FALL -} gpio_irq_event; - -/** GPIO IRQ HAL structure. gpio_irq_s is declared in the target's HAL - */ -typedef struct gpio_irq_s gpio_irq_t; - -typedef void (*gpio_irq_handler)(uint32_t id, gpio_irq_event event); - -/** - * \defgroup hal_gpioirq GPIO IRQ HAL functions - * - * # Defined behavior - * * ::gpio_irq_init initializes the GPIO IRQ pin - * * ::gpio_irq_init attaches the interrupt handler - * * ::gpio_irq_free releases the GPIO IRQ pin - * * ::gpio_irq_set enables/disables pin IRQ event - * * ::gpio_irq_enable enables GPIO IRQ - * * ::gpio_irq_disable disables GPIO IRQ - * - * # Undefined behavior - * * Calling other function before ::gpio_irq_init - * - * @{ - */ - -/** - * \defgroup hal_gpioirq_tests GPIO IRQ HAL tests - * The GPIO IRQ HAL tests ensure driver conformance to defined behaviour. - * - * To run the GPIO IRQ hal tests use the command: - * - * mbed test -t -m -n tests-mbed_hal_fpga_ci_test_shield-gpio_irq - * - */ - -/** Initialize the GPIO IRQ pin - * - * @param obj The GPIO object to initialize - * @param pin The GPIO pin name - * @param handler The handler to be attached to GPIO IRQ - * @param id The object ID (id != 0, 0 is reserved) - * @return -1 if pin is NC, 0 otherwise - */ -int gpio_irq_init(gpio_irq_t *obj, PinName pin, gpio_irq_handler handler, uint32_t id); - -/** Release the GPIO IRQ PIN - * - * @param obj The gpio object - */ -void gpio_irq_free(gpio_irq_t *obj); - -/** Enable/disable pin IRQ event - * - * @param obj The GPIO object - * @param event The GPIO IRQ event - * @param enable The enable flag - */ -void gpio_irq_set(gpio_irq_t *obj, gpio_irq_event event, uint32_t enable); - -/** Enable GPIO IRQ - * - * This is target dependent, as it might enable the entire port or just a pin - * @param obj The GPIO object - */ -void gpio_irq_enable(gpio_irq_t *obj); - -/** Disable GPIO IRQ - * - * This is target dependent, as it might disable the entire port or just a pin - * @param obj The GPIO object - */ -void gpio_irq_disable(gpio_irq_t *obj); - -/** Get the pins that support all GPIO IRQ tests - * - * Return a PinMap array of pins that support GPIO IRQ. - * The array is terminated with {NC, NC, 0}. - * - * Targets should override the weak implementation of this - * function to provide the actual pinmap for GPIO IRQ testing. - * - * @return PinMap array - */ -const PinMap *gpio_irq_pinmap(void); - -/**@}*/ - -#ifdef __cplusplus -} -#endif - -#endif - -#endif - -/** @}*/ diff --git a/hal/i2c_api.h b/hal/i2c_api.h deleted file mode 100644 index 9a71985..0000000 --- a/hal/i2c_api.h +++ /dev/null @@ -1,378 +0,0 @@ - -/** \addtogroup hal */ -/** @{*/ -/* mbed Microcontroller Library - * Copyright (c) 2006-2015 ARM Limited - * 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. - */ -#ifndef MBED_I2C_API_H -#define MBED_I2C_API_H - -#include "device.h" -#include "pinmap.h" -#include "hal/buffer.h" - -#if DEVICE_I2C_ASYNCH -#include "hal/dma_api.h" -#endif - -#if DEVICE_I2C - -/** - * @defgroup hal_I2CEvents I2C Events Macros - * - * @{ - */ -#define I2C_EVENT_ERROR (1 << 1) -#define I2C_EVENT_ERROR_NO_SLAVE (1 << 2) -#define I2C_EVENT_TRANSFER_COMPLETE (1 << 3) -#define I2C_EVENT_TRANSFER_EARLY_NACK (1 << 4) -#define I2C_EVENT_ALL (I2C_EVENT_ERROR | I2C_EVENT_TRANSFER_COMPLETE | I2C_EVENT_ERROR_NO_SLAVE | I2C_EVENT_TRANSFER_EARLY_NACK) - -/**@}*/ - -#if DEVICE_I2C_ASYNCH -/** Asynch I2C HAL structure - */ -typedef struct { - struct i2c_s i2c; /**< Target specific I2C structure */ - struct buffer_s tx_buff; /**< Tx buffer */ - struct buffer_s rx_buff; /**< Rx buffer */ -} i2c_t; - -#else -/** Non-asynch I2C HAL structure - */ -typedef struct i2c_s i2c_t; - -#endif - -enum { - I2C_ERROR_NO_SLAVE = -1, - I2C_ERROR_BUS_BUSY = -2 -}; - -typedef struct { - int peripheral; - PinName sda_pin; - int sda_function; - PinName scl_pin; - int scl_function; -} i2c_pinmap_t; - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * \defgroup hal_GeneralI2C I2C Configuration Functions - * - * # Defined behavior - * * ::i2c_init initializes i2c_t control structure - * * ::i2c_init configures the pins used by I2C - * * ::i2c_free returns the pins owned by the I2C object to their reset state - * * ::i2c_frequency configure the I2C frequency - * * ::i2c_start sends START command - * * ::i2c_read reads `length` bytes from the I2C slave specified by `address` to the `data` buffer - * * ::i2c_read reads generates a stop condition on the bus at the end of the transfer if `stop` parameter is non-zero - * * ::i2c_read reads returns the number of symbols received from the bus - * * ::i2c_write writes `length` bytes to the I2C slave specified by `address` from the `data` buffer - * * ::i2c_write generates a stop condition on the bus at the end of the transfer if `stop` parameter is non-zero - * * ::i2c_write returns zero on success, error code otherwise - * * ::i2c_reset resets the I2C peripheral - * * ::i2c_byte_read reads and return one byte from the specfied I2C slave - * * ::i2c_byte_read uses `last` parameter to inform the slave that all bytes have been read - * * ::i2c_byte_write writes one byte to the specified I2C slave - * * ::i2c_byte_write returns 0 if NAK was received, 1 if ACK was received, 2 for timeout - * * ::i2c_slave_mode enables/disables I2S slave mode - * * ::i2c_slave_receive returns: 1 - read addresses, 2 - write to all slaves, 3 write addressed, 0 - the slave has not been addressed - * * ::i2c_slave_read reads `length` bytes from the I2C master to the `data` buffer - * * ::i2c_slave_read returns non-zero if a value is available, 0 otherwise - * * ::i2c_slave_write writes `length` bytes to the I2C master from the `data` buffer - * * ::i2c_slave_write returns non-zero if a value is available, 0 otherwise - * * ::i2c_slave_address configures I2C slave address - * * ::i2c_transfer_asynch starts I2C asynchronous transfer - * * ::i2c_transfer_asynch writes `tx_length` bytes to the I2C slave specified by `address` from the `tx` buffer - * * ::i2c_transfer_asynch reads `rx_length` bytes from the I2C slave specified by `address` to the `rx` buffer - * * ::i2c_transfer_asynch generates a stop condition on the bus at the end of the transfer if `stop` parameter is non-zero - * * The callback given to ::i2c_transfer_asynch is invoked when the transfer completes - * * ::i2c_transfer_asynch specifies the logical OR of events to be registered - * * The ::i2c_transfer_asynch function may use the `DMAUsage` hint to select the appropriate async algorithm - * * ::i2c_irq_handler_asynch returns event flags if a transfer termination condition was met, otherwise returns 0. - * * ::i2c_active returns non-zero if the I2C module is active or 0 if it is not - * * ::i2c_abort_asynch aborts an on-going async transfer - * - * # Undefined behavior - * * Calling ::i2c_init multiple times on the same `i2c_t` - * * Calling any function other than ::i2c_init on a non-initialized `i2c_t` - * * Initialising the `I2C` peripheral with invalid `SDA` and `SCL` pins. - * * Passing pins that cannot be on the same peripheral - * * Passing an invalid pointer as `obj` to any function - * * Use of a `null` pointer as an argument to any function. - * * Initialising the peripheral in slave mode if slave mode is not supported - * * Operating the peripheral in slave mode without first specifying and address using ::i2c_slave_address - * * Setting an address using i2c_slave_address after initialising the peripheral in master mode - * * Setting an address to an `I2C` reserved value - * * Specifying an invalid address when calling any `read` or `write` functions - * * Setting the length of the transfer or receive buffers to larger than the buffers are - * * Passing an invalid pointer as `handler` - * * Calling ::i2c_abort_async when no transfer is currently in progress - * - * - * @{ - */ - -/** - * \defgroup hal_GeneralI2C_tests I2C hal tests - * The I2C HAL tests ensure driver conformance to defined behaviour. - * - * To run the I2C hal tests use the command: - * - * mbed test -t -m -n tests-mbed_hal_fpga_ci_test_shield-i2c - * - */ - -/** Initialize the I2C peripheral. It sets the default parameters for I2C - * peripheral, and configures its specifieds pins. - * - * @param obj The I2C object - * @param pinmap Pinmap pointer to structure which holds static pinmap - */ -void i2c_init_direct(i2c_t *obj, const i2c_pinmap_t *pinmap); - -/** Initialize the I2C peripheral. It sets the default parameters for I2C - * peripheral, and configures its specifieds pins. - * - * @param obj The I2C object - * @param sda The sda pin - * @param scl The scl pin - */ -void i2c_init(i2c_t *obj, PinName sda, PinName scl); - -/** Release a I2C object - * - * Return the pins owned by the I2C object to their reset state - * @param obj The I2C object to deinitialize - */ -void i2c_free(i2c_t *obj); - -/** Configure the I2C frequency - * - * @param obj The I2C object - * @param hz Frequency in Hz - */ -void i2c_frequency(i2c_t *obj, int hz); - -/** Send START command - * - * @param obj The I2C object - */ -int i2c_start(i2c_t *obj); - -/** Send STOP command - * - * @param obj The I2C object - */ -int i2c_stop(i2c_t *obj); - -/** Blocking reading data - * - * @param obj The I2C object - * @param address 7-bit address (last bit is 1) - * @param data The buffer for receiving - * @param length Number of bytes to read - * @param stop Stop to be generated after the transfer is done - * @return Number of read bytes - */ -int i2c_read(i2c_t *obj, int address, char *data, int length, int stop); - -/** Blocking sending data - * - * @param obj The I2C object - * @param address 7-bit address (last bit is 0) - * @param data The buffer for sending - * @param length Number of bytes to write - * @param stop Stop to be generated after the transfer is done - * @return - * zero or non-zero - Number of written bytes - * negative - I2C_ERROR_XXX status - */ -int i2c_write(i2c_t *obj, int address, const char *data, int length, int stop); - -/** Reset I2C peripheral. TODO: The action here. Most of the implementation sends stop() - * - * @param obj The I2C object - */ -void i2c_reset(i2c_t *obj); - -/** Read one byte - * - * @param obj The I2C object - * @param last Acknoledge - * @return The read byte - */ -int i2c_byte_read(i2c_t *obj, int last); - -/** Write one byte - * - * @param obj The I2C object - * @param data Byte to be written - * @return 0 if NAK was received, 1 if ACK was received, 2 for timeout. - */ -int i2c_byte_write(i2c_t *obj, int data); - -/** Get the pins that support I2C SDA - * - * Return a PinMap array of pins that support I2C SDA in - * master mode. The array is terminated with {NC, NC, 0}. - * - * @return PinMap array - */ -const PinMap *i2c_master_sda_pinmap(void); - -/** Get the pins that support I2C SCL - * - * Return a PinMap array of pins that support I2C SCL in - * master mode. The array is terminated with {NC, NC, 0}. - * - * @return PinMap array - */ -const PinMap *i2c_master_scl_pinmap(void); - -/** Get the pins that support I2C SDA - * - * Return a PinMap array of pins that support I2C SDA in - * slave mode. The array is terminated with {NC, NC, 0}. - * - * @return PinMap array - */ -const PinMap *i2c_slave_sda_pinmap(void); - -/** Get the pins that support I2C SCL - * - * Return a PinMap array of pins that support I2C SCL in - * slave mode. The array is terminated with {NC, NC, 0}. - * - * @return PinMap array - */ -const PinMap *i2c_slave_scl_pinmap(void); - -/**@}*/ - -#if DEVICE_I2CSLAVE - -/** - * \defgroup SynchI2C Synchronous I2C Hardware Abstraction Layer for slave - * @{ - */ - -/** Configure I2C as slave or master. - * @param obj The I2C object - * @param enable_slave Enable i2c hardware so you can receive events with ::i2c_slave_receive - * @return non-zero if a value is available - */ -void i2c_slave_mode(i2c_t *obj, int enable_slave); - -/** Check to see if the I2C slave has been addressed. - * @param obj The I2C object - * @return The status - 1 - read addresses, 2 - write to all slaves, - * 3 write addressed, 0 - the slave has not been addressed - */ -int i2c_slave_receive(i2c_t *obj); - -/** Configure I2C as slave or master. - * @param obj The I2C object - * @param data The buffer for receiving - * @param length Number of bytes to read - * @return non-zero if a value is available - */ -int i2c_slave_read(i2c_t *obj, char *data, int length); - -/** Configure I2C as slave or master. - * @param obj The I2C object - * @param data The buffer for sending - * @param length Number of bytes to write - * @return non-zero if a value is available - */ -int i2c_slave_write(i2c_t *obj, const char *data, int length); - -/** Configure I2C address. - * @param obj The I2C object - * @param idx Currently not used - * @param address The address to be set - * @param mask Currently not used - */ -void i2c_slave_address(i2c_t *obj, int idx, uint32_t address, uint32_t mask); - -#endif - -/**@}*/ - -#if DEVICE_I2C_ASYNCH - -/** - * \defgroup hal_AsynchI2C Asynchronous I2C Hardware Abstraction Layer - * @{ - */ - -/** Start I2C asynchronous transfer - * - * @param obj The I2C object - * @param tx The transmit buffer - * @param tx_length The number of bytes to transmit - * @param rx The receive buffer - * @param rx_length The number of bytes to receive - * @param address The address to be set - 7bit or 9bit - * @param stop If true, stop will be generated after the transfer is done - * @param handler The I2C IRQ handler to be set - * @param event Event mask for the transfer. See \ref hal_I2CEvents - * @param hint DMA hint usage - */ -void i2c_transfer_asynch(i2c_t *obj, const void *tx, size_t tx_length, void *rx, size_t rx_length, uint32_t address, uint32_t stop, uint32_t handler, uint32_t event, DMAUsage hint); - -/** The asynchronous IRQ handler - * - * @param obj The I2C object which holds the transfer information - * @return Event flags if a transfer termination condition was met, otherwise return 0. - */ -uint32_t i2c_irq_handler_asynch(i2c_t *obj); - -/** Attempts to determine if the I2C peripheral is already in use - * - * @param obj The I2C object - * @return Non-zero if the I2C module is active or zero if it is not - */ -uint8_t i2c_active(i2c_t *obj); - -/** Abort asynchronous transfer - * - * This function does not perform any check - that should happen in upper layers. - * @param obj The I2C object - */ -void i2c_abort_asynch(i2c_t *obj); - -#endif - -/**@}*/ - -#ifdef __cplusplus -} -#endif - -#endif - -#endif - -/** @}*/ diff --git a/hal/include/hal/LowPowerTickerWrapper.h b/hal/include/hal/LowPowerTickerWrapper.h new file mode 100644 index 0000000..a709d14 --- /dev/null +++ b/hal/include/hal/LowPowerTickerWrapper.h @@ -0,0 +1,246 @@ + +/** \addtogroup hal */ +/** @{*/ +/* mbed Microcontroller Library + * Copyright (c) 2018-2019 ARM Limited + * 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. + */ +#ifndef MBED_LOW_POWER_TICKER_WRAPPER_H +#define MBED_LOW_POWER_TICKER_WRAPPER_H + +#include "device.h" + +#include "hal/ticker_api.h" +#include "hal/us_ticker_api.h" +#include "drivers/Timeout.h" + +#include "platform/mbed_chrono.h" +#include "platform/mbed_critical.h" + + +class LowPowerTickerWrapper { +public: + + + /** + * Create a new wrapped low power ticker object + * + * @param data Low power ticker data to wrap + * @param interface new ticker interface functions + * @param min_cycles_between_writes The number of whole low power clock periods + * which must complete before subsequent calls to set_interrupt + * @param min_cycles_until_match The minimum number of whole low power clock periods + * from the current time for which the match timestamp passed to set_interrupt is + * guaranteed to fire. + * + * N = min_cycles_between_writes + * + * 0 1 N - 1 N N + 1 N + 2 N + 3 + * |-------|------...------|-------|-------|-------|-------| + * ^ ^ + * | | + * set_interrupt Next set_interrupt allowed + * + * N = min_cycles_until_match + * + * 0 1 N - 1 N N + 1 N + 2 N + 3 + * |-------|------...------|-------|-------|-------|-------| + * ^ ^ + * | | + * set_interrupt Earliest match timestamp allowed + * + * + */ + + LowPowerTickerWrapper(const ticker_data_t *data, const ticker_interface_t *interface, uint32_t min_cycles_between_writes, uint32_t min_cycles_until_match); + + /** + * Interrupt handler called by the underlying driver/hardware + * + * @param handler The callback which would normally be called by the underlying driver/hardware + */ + void irq_handler(ticker_irq_handler_type handler); + + /** + * Suspend wrapper operation and pass through interrupts. + * + * This stops to wrapper layer from using the microsecond ticker. + * This should be called before using the low power ticker APIs directly. + * + * @warning: Make sure to suspend the LP ticker first (call ticker_suspend()), + * otherwise the behavior is undefined. + */ + void suspend(); + + /** + * Resume wrapper operation and filter interrupts normally + */ + void resume(); + + /** + * Check if a Timeout object is being used + * + * @return true if Timeout is used for scheduling false otherwise + */ + bool timeout_pending(); + + /* + * Implementation of ticker_init + */ + void init(); + + /* + * Implementation of free + */ + void free(); + + /* + * Implementation of read + */ + uint32_t read(); + + /* + * Implementation of set_interrupt + */ + void set_interrupt(timestamp_t timestamp); + + /* + * Implementation of disable_interrupt + */ + void disable_interrupt(); + + /* + * Implementation of clear_interrupt + */ + void clear_interrupt(); + + /* + * Implementation of fire_interrupt + */ + void fire_interrupt(); + + /* + * Implementation of get_info + */ + const ticker_info_t *get_info(); + + ticker_data_t data; + +private: + mbed::Timeout _timeout; + const ticker_interface_t *const _intf; + + /* + * The number of low power clock cycles which must pass between subsequent + * calls to intf->set_interrupt + */ + const uint32_t _min_count_between_writes; + + /* + * The minimum number of low power clock cycles in the future that + * a match value can be set to and still fire + */ + const uint32_t _min_count_until_match; + + /* + * Flag to indicate if the timer is suspended + */ + bool _suspended; + + /* + * _cur_match_time is valid and Timeout is scheduled to fire + */ + bool _pending_timeout; + + /* + * set_interrupt has been called and _cur_match_time is valid + */ + bool _pending_match; + + /* + * The function LowPowerTickerWrapper::fire_interrupt has been called + * and an interrupt is expected. + */ + bool _pending_fire_now; + + /* + * It is safe to call intf->set_interrupt + */ + bool _set_interrupt_allowed; + + /* + * Last value written by LowPowerTickerWrapper::set_interrupt + */ + timestamp_t _cur_match_time; + + /* + * Time of last call to LowPowerTickerWrapper::set_interrupt + */ + uint32_t _last_set_interrupt; + + /* + * Time of last call to intf->set_interrupt + */ + uint32_t _last_actual_set_interrupt; + + /* + * Mask of valid bits from intf->read() + */ + uint32_t _mask; + + /* + * Microsecond per low power tick (rounded up) + */ + uint32_t _us_per_tick; + + + void _reset(); + + /** + * Set the low power ticker match time when hardware is ready + * + * This event is scheduled to set the lp timer after the previous write + * has taken effect and it is safe to write a new value without blocking. + * If the time has already passed then this function fires and interrupt + * immediately. + */ + void _timeout_handler(); + + /* + * Check match time has passed + */ + bool _match_check(timestamp_t current); + + /* + * Convert low power ticks to approximate microseconds + * + * This value is always larger or equal to exact value. + */ + mbed::chrono::microseconds_u32 _lp_ticks_to_us(uint32_t); + + /* + * Schedule a match interrupt to fire at the correct time + * + * @param current The current low power ticker time + */ + void _schedule_match(timestamp_t current); + +}; + +#endif + +/** @}*/ + + diff --git a/hal/include/hal/analogin_api.h b/hal/include/hal/analogin_api.h new file mode 100644 index 0000000..d172607 --- /dev/null +++ b/hal/include/hal/analogin_api.h @@ -0,0 +1,120 @@ + +/** \addtogroup hal */ +/** @{*/ +/* mbed Microcontroller Library + * Copyright (c) 2006-2013 ARM Limited + * 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. + */ +#ifndef MBED_ANALOGIN_API_H +#define MBED_ANALOGIN_API_H + +#include "device.h" +#include "pinmap.h" + +#if DEVICE_ANALOGIN + +#ifdef __cplusplus +extern "C" { +#endif + +/** Analogin hal structure. analogin_s is declared in the target's hal + */ +typedef struct analogin_s analogin_t; + +/** + * \defgroup hal_analogin Analogin hal functions + * + * # Defined behaviour + * * The function ::analogin_init initializes the analogin_t control structure + * * The function ::analogin_free returns the pin owned by the Analogin object to its reset state + * * The function ::analogin_read reads the input voltage, represented as a float in the range [0.0 (GND), 1.0 (VCC)] + * * The function ::analogin_read_u16 reads the value from analogin pin, represented as an unsigned 16bit value [0.0 (GND), MAX_UINT16 (VCC)] + * * The accuracy of the ADC is +/- 10% + * * The ADC operations ::analogin_read, ::analogin_read_u16 take less than 20us to complete + * + * # Undefined behaviour + * + * * ::analogin_init is called with invalid pin (which does not support analog input function) + * * Calling ::analogin_read, ::analogin_read_u16 before ::analogin_init + * @{ + */ + +/** + * \defgroup hal_analogin_tests Analogin hal tests + * The Analogin HAL tests ensure driver conformance to defined behaviour. + * + * To run the Analogin hal tests use the command: + * + * mbed test -t -m -n tests-mbed_hal_fpga_ci_test_shield-analogin + * + */ + +/** Initialize the analogin peripheral + * + * Configures the pin used by analogin. + * @param obj The analogin object to initialize + * @param pinmap pointer to structure which holds static pinmap + */ +void analogin_init_direct(analogin_t *obj, const PinMap *pinmap); + +/** Initialize the analogin peripheral + * + * Configures the pin used by analogin. + * @param obj The analogin object to initialize + * @param pin The analogin pin name + */ +void analogin_init(analogin_t *obj, PinName pin); + +/** Release the analogin peripheral + * + * Releases the pin used by analogin. + * @param obj The analogin object to initialize + */ +void analogin_free(analogin_t *obj); + +/** Read the input voltage, represented as a float in the range [0.0, 1.0] + * + * @param obj The analogin object + * @return A floating value representing the current input voltage + */ +float analogin_read(analogin_t *obj); + +/** Read the value from analogin pin, represented as an unsigned 16bit value + * + * @param obj The analogin object + * @return An unsigned 16bit value representing the current input voltage + */ +uint16_t analogin_read_u16(analogin_t *obj); + +/** Get the pins that support analogin + * + * Return a PinMap array of pins that support analogin. The + * array is terminated with {NC, NC, 0}. + * + * @return PinMap array + */ +const PinMap *analogin_pinmap(void); + +/**@}*/ + +#ifdef __cplusplus +} +#endif + +#endif + +#endif + +/** @}*/ diff --git a/hal/include/hal/analogout_api.h b/hal/include/hal/analogout_api.h new file mode 100644 index 0000000..4212907 --- /dev/null +++ b/hal/include/hal/analogout_api.h @@ -0,0 +1,136 @@ + +/** \addtogroup hal */ +/** @{*/ +/* mbed Microcontroller Library + * Copyright (c) 2006-2013 ARM Limited + * 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. + */ +#ifndef MBED_ANALOGOUT_API_H +#define MBED_ANALOGOUT_API_H + +#include "device.h" +#include "pinmap.h" + +#if DEVICE_ANALOGOUT + +#ifdef __cplusplus +extern "C" { +#endif + +/** Analogout hal structure. dac_s is declared in the target's hal + */ +typedef struct dac_s dac_t; + +/** + * \defgroup hal_analogout Analogout hal functions + * + * # Defined behaviour + * * The function ::analogout_init initializes the dac_t control structure + * * The function ::analogout_write sets the output voltage, specified as a percentage (float) in range [0.0 (GND), 1.0 (VCC)] + * * The function ::analogout_write_u16 sets the output voltage, specified as unsigned 16-bit value [0 (GND), MAX_UINT16 (VCC)] + * * The function ::analogout_read reads the current voltage value on the pin and returns a floating-point value representing the current voltage in range [0.0 (GND), 1.0 (VCC)] + * * The function ::analogout_read_u16 reads the current voltage value on the pin and returns the output voltage, specified as unsigned 16-bit value [0 (GND), MAX_UINT16 (VCC)] + * * The accuracy of the DAC is +/- 10% + * * The DAC operations ::analogout_write, ::analogout_write_u16, ::analogout_read, ::analogout_read_u16 take less than 20us to complete + * * The function ::analogout_free releases the analogout object + * + * # Undefined behaviour + * + * * ::analogout_init is called with invalid pin (which does not support analog output function) + * * Calling other functions before ::analogout_init + * @{ + */ + +/** + * \defgroup hal_analogin_tests Analogout hal tests + * The Analogout HAL tests ensure driver conformance to defined behaviour. + * + * To run the Analogout hal tests use the command: + * + * mbed test -t -m -n tests-mbed_hal_fpga_ci_test_shield-analogout + * + */ + +/** Initialize the analogout peripheral + * + * Configures the pin used by analogout. + * @param obj The analogout object to initialize + * @param pinmap pointer to structure which holds static pinmap + */ +void analogout_init_direct(dac_t *obj, const PinMap *pinmap); + +/** Initialize the analogout peripheral + * + * Configures the pin used by analogout. + * @param obj The analogout object to initialize + * @param pin The analogout pin name + */ +void analogout_init(dac_t *obj, PinName pin); + +/** Release the analogout object + * + * @param obj The analogout object + */ +void analogout_free(dac_t *obj); + +/** Set the output voltage, specified as a percentage (float) + * + * @param obj The analogin object + * @param value The floating-point output voltage to be set + */ +void analogout_write(dac_t *obj, float value); + +/** Set the output voltage, specified as unsigned 16-bit + * + * @param obj The analogin object + * @param value The unsigned 16-bit output voltage to be set + */ +void analogout_write_u16(dac_t *obj, uint16_t value); + +/** Read the current voltage value on the pin + * + * @param obj The analogin object + * @return A floating-point value representing the current voltage on the pin, + * measured as a percentage + */ +float analogout_read(dac_t *obj); + +/** Read the current voltage value on the pin, as a normalized unsigned 16bit value + * + * @param obj The analogin object + * @return An unsigned 16-bit value representing the current voltage on the pin + */ +uint16_t analogout_read_u16(dac_t *obj); + +/** Get the pins that support analogout + * + * Return a PinMap array of pins that support analogout. The + * array is terminated with {NC, NC, 0}. + * + * @return PinMap array + */ +const PinMap *analogout_pinmap(void); + +/**@}*/ + +#ifdef __cplusplus +} +#endif + +#endif + +#endif + +/** @}*/ diff --git a/hal/include/hal/buffer.h b/hal/include/hal/buffer.h new file mode 100644 index 0000000..a68b940 --- /dev/null +++ b/hal/include/hal/buffer.h @@ -0,0 +1,36 @@ + +/** \addtogroup hal */ +/** @{*/ +/* mbed Microcontroller Library + * Copyright (c) 2014-2015 ARM Limited + * 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. + */ +#ifndef MBED_BUFFER_H +#define MBED_BUFFER_H + +#include + +/** Generic buffer structure + */ +typedef struct buffer_s { + void *buffer; /**< the pointer to a buffer */ + size_t length; /**< the buffer length */ + size_t pos; /**< actual buffer position */ + uint8_t width; /**< The buffer unit width (8, 16, 32, 64), used for proper *buffer casting */ +} buffer_t; + +#endif + +/** @}*/ diff --git a/hal/include/hal/can_api.h b/hal/include/hal/can_api.h new file mode 100644 index 0000000..9774d12 --- /dev/null +++ b/hal/include/hal/can_api.h @@ -0,0 +1,116 @@ + +/** \addtogroup hal */ +/** @{*/ +/* mbed Microcontroller Library + * Copyright (c) 2006-2016 ARM Limited + * 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. + */ +#ifndef MBED_CAN_API_H +#define MBED_CAN_API_H + +#include "device.h" +#include "pinmap.h" + +#if DEVICE_CAN + +#include "PinNames.h" +#include "PeripheralNames.h" +#include "hal/can_helper.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum { + IRQ_RX, + IRQ_TX, + IRQ_ERROR, + IRQ_OVERRUN, + IRQ_WAKEUP, + IRQ_PASSIVE, + IRQ_ARB, + IRQ_BUS, + IRQ_READY +} CanIrqType; + + +typedef enum { + MODE_RESET, + MODE_NORMAL, + MODE_SILENT, + MODE_TEST_LOCAL, + MODE_TEST_GLOBAL, + MODE_TEST_SILENT +} CanMode; + +typedef struct { + int peripheral; + PinName rd_pin; + int rd_function; + PinName td_pin; + int td_function; +} can_pinmap_t; + +typedef void (*can_irq_handler)(uint32_t id, CanIrqType type); + +typedef struct can_s can_t; + +void can_init(can_t *obj, PinName rd, PinName td); +void can_init_direct(can_t *obj, const can_pinmap_t *pinmap); +void can_init_freq(can_t *obj, PinName rd, PinName td, int hz); +void can_init_freq_direct(can_t *obj, const can_pinmap_t *pinmap, int hz); +void can_free(can_t *obj); +int can_frequency(can_t *obj, int hz); + +void can_irq_init(can_t *obj, can_irq_handler handler, uint32_t id); +void can_irq_free(can_t *obj); +void can_irq_set(can_t *obj, CanIrqType irq, uint32_t enable); + +int can_write(can_t *obj, CAN_Message, int cc); +int can_read(can_t *obj, CAN_Message *msg, int handle); +int can_mode(can_t *obj, CanMode mode); +int can_filter(can_t *obj, uint32_t id, uint32_t mask, CANFormat format, int32_t handle); +void can_reset(can_t *obj); +unsigned char can_rderror(can_t *obj); +unsigned char can_tderror(can_t *obj); +void can_monitor(can_t *obj, int silent); + +/** Get the pins that support CAN RD + * + * Return a PinMap array of pins that support CAN RD. The + * array is terminated with {NC, NC, 0}. + * + * @return PinMap array + */ +const PinMap *can_rd_pinmap(void); + +/** Get the pins that support CAN TD + * + * Return a PinMap array of pins that support CAN TD. The + * array is terminated with {NC, NC, 0}. + * + * @return PinMap array + */ +const PinMap *can_td_pinmap(void); + +#ifdef __cplusplus +} +#endif + +#endif // MBED_CAN_API_H + +#endif + +/** @}*/ diff --git a/hal/include/hal/can_helper.h b/hal/include/hal/can_helper.h new file mode 100644 index 0000000..3f56f16 --- /dev/null +++ b/hal/include/hal/can_helper.h @@ -0,0 +1,78 @@ + +/** \addtogroup hal */ +/** @{*/ +/* mbed Microcontroller Library + * Copyright (c) 2006-2013 ARM Limited + * 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. + */ +#ifndef MBED_CAN_HELPER_H +#define MBED_CAN_HELPER_H + +#if DEVICE_CAN + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * + * \enum CANFormat + * + * \brief Values that represent CAN Format +**/ +enum CANFormat { + CANStandard = 0, + CANExtended = 1, + CANAny = 2 +}; +typedef enum CANFormat CANFormat; + +/** + * + * \enum CANType + * + * \brief Values that represent CAN Type +**/ +enum CANType { + CANData = 0, + CANRemote = 1 +}; +typedef enum CANType CANType; + +/** + * + * \struct CAN_Message + * + * \brief Holder for single CAN message. + * +**/ +struct CAN_Message { + unsigned int id; // 29 bit identifier + unsigned char data[8]; // Data field + unsigned char len; // Length of data field in bytes + CANFormat format; // Format ::CANFormat + CANType type; // Type ::CANType +}; +typedef struct CAN_Message CAN_Message; + +#ifdef __cplusplus +} +#endif + +#endif + +#endif // MBED_CAN_HELPER_H + +/** @}*/ diff --git a/hal/include/hal/crc_api.h b/hal/include/hal/crc_api.h new file mode 100644 index 0000000..e59b678 --- /dev/null +++ b/hal/include/hal/crc_api.h @@ -0,0 +1,233 @@ +/** \addtogroup hal */ +/** @{*/ +/* mbed Microcontroller Library + * Copyright (c) 2018 ARM Limited + * 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. + */ +#ifndef MBED_CRC_HAL_API_H +#define MBED_CRC_HAL_API_H + +#include +#include +#include + +/** CRC Polynomial value + * + * Different polynomial values supported + */ +typedef enum crc_polynomial { + POLY_7BIT_SD = 0x09, ///< x7+x3+1 + POLY_8BIT_CCITT = 0x07, ///< x8+x2+x+1 + POLY_16BIT_CCITT = 0x1021, ///< x16+x12+x5+1 + POLY_16BIT_IBM = 0x8005, ///< x16+x15+x2+1 + POLY_32BIT_ANSI = 0x04C11DB7 ///< x32+x26+x23+x22+x16+x12+x11+x10+x8+x7+x5+x4+x2+x+1 +} crc_polynomial_t; + +typedef struct crc_mbed_config { + /** CRC Polynomial. Example polynomial: x^8+x^5+x+1 -> width = 8, polynomial = 0010_0011 = 0x21 */ + uint32_t polynomial; + /** CRC Bit Width */ + uint32_t width; + /** Initial seed value for the computation. */ + uint32_t initial_xor; + /** Final xor value for the computation. */ + uint32_t final_xor; + /** Reflect bits on input. */ + bool reflect_in; + /** Reflect bits in final result before returning. */ + bool reflect_out; +} crc_mbed_config_t; + +#if DEVICE_CRC + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \defgroup hal_crc Hardware CRC + * + * The Hardware CRC HAL API provides a low-level interface to the Hardware CRC + * module of a target platform. + * + * # Defined behaviour + * + * * Macro HAL_CRC_IS_SUPPORTED() evaluates true if platform supports hardware + * CRC for the given polynomial/width - verified by test ::crc_is_supported_test. + * * Macro HAL_CRC_IS_SUPPORTED() evaluates false if platform does not support hardware + * CRC for the given polynomial/width - verified by test ::crc_is_supported_test. + * * If CRC module does not support any of the following settings: initial_xor, final_xor + * reflect_in, reflect_out, then these operations must be handled by the driver + * - Verified by test ::crc_calc_single_test. + * * Platform which supports hardware CRC must be able to handle at least one of the predefined + * polynomial/width configurations that can be constructed in the MbedCRC class: POLY_8BIT_CCITT, + * POLY_7BIT_SD, POLY_16BIT_CCITT, POLY_16BIT_IBM, POLY_32BIT_ANSI + * - verified by test ::crc_is_supported_test, ::crc_calc_single_test. + * * Function hal_crc_compute_partial_start() configures CRC module with the given configuration + * - Verified by test ::crc_calc_single_test. + * * Calling hal_crc_compute_partial_start() without finalising the + * CRC calculation overrides the current configuration - Verified by test ::crc_reconfigure_test. + * * Function hal_crc_compute_partial() writes data to the CRC module - verified by test ::crc_calc_single_test. + * * Function hal_crc_compute_partial() can be call multiple times in succession in order to + * provide additional data to CRC module - verified by test ::crc_calc_multi_test. + * * Function hal_crc_compute_partial() does nothing if pointer to buffer is undefined or + * data length is equal to 0 - verified by test ::crc_compute_partial_invalid_param_test. + * * Function hal_crc_get_result() returns the checksum result from the CRC module + * - verified by tests ::crc_calc_single_test, ::crc_calc_multi_test, ::crc_reconfigure_test. + * + * # Undefined behaviour + * + * * Calling hal_crc_compute_partial_start() function with invalid (unsupported) polynomial. + * * Calling hal_crc_compute_partial() or hal_crc_get_result() functions before hal_crc_compute_partial_start(). + * * Calling hal_crc_get_result() function multiple times. + * + * # Non-functional requirements + * + * * CRC configuration provides the following settings: + * * polynomial - CRC Polynomial, + * * width - CRC bit width, + * * initial_xor - seed value for the computation, + * * final_xor - final xor value for the computation, + * * reflect_in - reflect bits on input, + * * reflect_out - reflect bits in final result before returning. + * + * # Potential bugs + * + * # Macros + * + * Platform support for particular CRC polynomials is indicated by the + * macro HAL_CRC_IS_SUPPORTED(polynomial, width), which must be defined + * in device.h, or a file included from there. + * + * The macro must evaluate to a constant boolean expression when given + * constant parameters. + * + * The current platform must support the given polynomial with all possible + * other config parameters if the macro evaluates to true. These are: + * reflect in, reflect out, initial xor and final xor. If any of these settings + * of these settings cannot be configured, the polynomial is not supported. + * + * Example: + * + * #define HAL_CRC_IS_SUPPORTED(polynomial, width) \ + * ((width) == 16 || ((width) == 32 && (polynomial) == POLY_32BIT_ANSI) + * @{ + */ + +/** + * \defgroup hal_crc_tests crc hal tests + * The crc HAL tests ensure driver conformance to defined behaviour. + * + * To run the crc hal tests use the command: + * + * mbed test -t -m -n tests-mbed_hal-crc* + * + */ + +/** Initialize the hardware CRC module with the given polynomial + * + * After calling this function, the CRC HAL module is ready to receive data + * using the hal_crc_compute_partial() function. The CRC module on the board + * is configured internally with the specified configuration and is ready + * to receive data. + * + * The platform configures itself based on the default configuration + * parameters of the input polynomial. + * + * This function must be called before calling hal_crc_compute_partial(). + * + * This function must be called with a valid polynomial supported by the + * platform. The polynomial must be checked for support using the + * HAL_CRC_IS_SUPPORTED() macro. + * + * Calling hal_crc_compute_partial_start() multiple times without finalizing the + * CRC calculation with hal_crc_get_result() overrides the current + * configuration and state, and the intermediate result of the computation is + * lost. + * + * This function is not thread safe. A CRC calculation must not be started from + * two different threads or contexts at the same time; calling this function + * from two different contexts may lead to configurations being overwritten and + * results being lost. + * + * \param config Contains CRC configuration parameters for initializing the + * hardware CRC module. For example, polynomial and initial seed + * values. + */ +void hal_crc_compute_partial_start(const crc_mbed_config_t *config); + +/** Writes data to the current CRC module. + * + * Writes input data buffer bytes to the CRC data register. The CRC module + * must interpret the data as an array of bytes. + * + * The final transformations are not applied to the data; the CRC module must + * retain the intermediate result so that additional calls to this function + * can be made, appending the additional data to the calculation. + * + * To obtain the final result of the CRC calculation, hal_crc_get_result() is + * called to apply the final transformations to the data. + * + * If the function is passed an undefined pointer, or the size of the buffer is + * specified to be 0, this function does nothing and returns. + * + * This function can be called multiple times in succession. This can be used + * to calculate the CRC result of streamed data. + * + * This function is not thread safe. There is only one instance of the CRC + * module active at a time. Calling this function from multiple contexts + * appends different data to the same, single instance of the module, which causes an + * erroneous value to be calculated. + * + * \param data Input data stream to be written into the CRC calculation + * \param size Size of the data stream in bytes + */ +void hal_crc_compute_partial(const uint8_t *data, const size_t size); + +/* Reads the checksum result from the CRC module. + * + * Reads the final checksum result for the final checksum value. The returned + * value is cast as an unsigned 32-bit integer. The actual size of the returned + * result depends on the polynomial used to configure the CRC module. + * + * Additional transformations that are used in the default configuration of the + * input polynomial are applied to the result before it is returned from this + * function. These transformations include: the final xor being appended to the + * calculation, and the result being reflected if required. + * + * Calling this function multiple times is undefined. The first call to this + * function returns the final result of the CRC calculation. The return + * value on successive calls is undefined because the contents of the register after + * accessing them is platform-specific. + * + * This function is not thread safe. There is only one instance of the CRC + * module active at a time. Calling this function from multiple contexts may + * return incorrect data or affect the current state of the module. + * + * \return The final CRC checksum after the reflections and final calculations + * have been applied. + */ +uint32_t hal_crc_get_result(void); + +/**@}*/ + +#ifdef __cplusplus +} +#endif + +#endif // DEVICE_CRC +#endif // MBED_CRC_HAL_API_H + +/**@}*/ diff --git a/hal/include/hal/critical_section_api.h b/hal/include/hal/critical_section_api.h new file mode 100644 index 0000000..8c6ac59 --- /dev/null +++ b/hal/include/hal/critical_section_api.h @@ -0,0 +1,108 @@ +/** \addtogroup hal */ +/** @{*/ +/* mbed Microcontroller Library + * Copyright (c) 2006-2017 ARM Limited + * 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. + */ +#ifndef MBED_CRITICAL_SECTION_API_H +#define MBED_CRITICAL_SECTION_API_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \defgroup hal_critical Critical Section HAL functions + * @{ + */ + +/** + * Mark the start of a critical section + * + * This function will be called by core_util_critical_section_enter() each time + * the application requests to enter a critical section. The purpose of the + * critical section is to ensure mutual-exclusion synchronisation of the + * processor by preventing any change in processor control, the default + * behaviour requires storing the state of interrupts in the system before + * disabling them. + * + * The critical section code supports nesting. When a thread has entered a + * critical section it can make additional calls to + * core_util_critical_section_enter() without deadlocking itself. The critical + * section driver API tracks the number of nested calls to the critical section. + * The critical section will only be exited when + * core_util_critical_section_exit() has been called once for each time it + * entered the critical section. + * + * On the first call to enter a critical section this function MUST store the + * state of any interrupts or other application settings it will modify to + * facilitate the critical section. + * + * Each successive call to enter the critical section MUST ignore storing or + * modifying any application state. + * + * The default implementation of this function which will save the current state + * of interrupts before disabling them. This implementation can be found in + * mbed_critical_section_api.c. This behaviour is can be overridden on a per + * platform basis by providing a different implementation within the correct + * targets directory. + */ +void hal_critical_section_enter(void); + + +/** Mark the end of a critical section. + * + * The purpose of this function is to restore any state that was modified upon + * entering the critical section, allowing other threads or interrupts to change + * the processor control. + * + * This function will be called once by core_util_critical_section_exit() per + * critical section on last call to exit. When called, the application MUST + * restore the saved interrupt/application state that was saved when entering + * the critical section. + * + * There is a default implementation of this function, it will restore the state + * of interrupts that were previously saved when hal_critical_section_enter was + * first called, this implementation can be found in + * mbed_critical_section_api.c. This behaviour is overridable by providing a + * different function implementation within the correct targets directory. + */ +void hal_critical_section_exit(void); + + +/** Determine if the application is currently running in a critical section + * + * The purpose of this function is to inform the caller whether or not the + * application is running in a critical section. This is done by checking if + * the current interrupt state has been saved in the underlying implementation, + * this could also be done by checking the state of the interrupts at the time + * of calling. + * + * @return True if running in a critical section, false if not. + */ +bool hal_in_critical_section(void); + + +/**@}*/ + +#ifdef __cplusplus +} +#endif + +#endif // MBED_CRITICAL_SECTION_API_H + +/** @}*/ diff --git a/hal/include/hal/dma_api.h b/hal/include/hal/dma_api.h new file mode 100644 index 0000000..864439e --- /dev/null +++ b/hal/include/hal/dma_api.h @@ -0,0 +1,51 @@ + +/** \addtogroup hal */ +/** @{*/ +/* mbed Microcontroller Library + * Copyright (c) 2014-2015 ARM Limited + * 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. + */ +#ifndef MBED_DMA_API_H +#define MBED_DMA_API_H + +#include + +#define DMA_ERROR_OUT_OF_CHANNELS (-1) + +typedef enum { + DMA_USAGE_NEVER, + DMA_USAGE_OPPORTUNISTIC, + DMA_USAGE_ALWAYS, + DMA_USAGE_TEMPORARY_ALLOCATED, + DMA_USAGE_ALLOCATED +} DMAUsage; + +#ifdef __cplusplus +extern "C" { +#endif + +void dma_init(void); + +int dma_channel_allocate(uint32_t capabilities); + +int dma_channel_free(int channelid); + +#ifdef __cplusplus +} +#endif + +#endif + +/** @}*/ diff --git a/hal/include/hal/flash_api.h b/hal/include/hal/flash_api.h new file mode 100644 index 0000000..e98c806 --- /dev/null +++ b/hal/include/hal/flash_api.h @@ -0,0 +1,138 @@ +/** \addtogroup hal */ +/** @{*/ + +/* mbed Microcontroller Library + * Copyright (c) 2017 ARM Limited + * 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. + */ +#ifndef MBED_FLASH_API_H +#define MBED_FLASH_API_H + +#include "device.h" +#include + +#if DEVICE_FLASH + +#define MBED_FLASH_INVALID_SIZE 0xFFFFFFFF + +typedef struct flash_s flash_t; + +#if TARGET_FLASH_CMSIS_ALGO +#include "flash_data.h" +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \defgroup flash_hal Flash HAL API + * @{ + */ + +/** Initialize the flash peripheral and the flash_t object + * + * @param obj The flash object + * @return 0 for success, -1 for error + */ +int32_t flash_init(flash_t *obj); + +/** Uninitialize the flash peripheral and the flash_t object + * + * @param obj The flash object + * @return 0 for success, -1 for error + */ +int32_t flash_free(flash_t *obj); + +/** Erase one sector starting at defined address + * + * The address should be at sector boundary. This function does not do any check for address alignments + * @param obj The flash object + * @param address The sector starting address + * @return 0 for success, -1 for error + */ +int32_t flash_erase_sector(flash_t *obj, uint32_t address); + +/** Read data starting at defined address + * + * This function has a WEAK implementation using memcpy for backwards compatibility. + * @param obj The flash object + * @param address Address to begin reading from + * @param data The buffer to read data into + * @param size The number of bytes to read + * @return 0 for success, -1 for error + */ +int32_t flash_read(flash_t *obj, uint32_t address, uint8_t *data, uint32_t size); + +/** Program pages starting at defined address + * + * The pages should not cross multiple sectors. + * This function does not do any check for address alignments or if size is aligned to a page size. + * @param obj The flash object + * @param address The sector starting address + * @param data The data buffer to be programmed + * @param size The number of bytes to program + * @return 0 for success, -1 for error + */ +int32_t flash_program_page(flash_t *obj, uint32_t address, const uint8_t *data, uint32_t size); + +/** Get sector size + * + * @param obj The flash object + * @param address The sector starting address + * @return The size of a sector + */ +uint32_t flash_get_sector_size(const flash_t *obj, uint32_t address); + +/** Get page size + * + * The page size defines the writable page size + * @param obj The flash object + * @return The size of a page + */ +uint32_t flash_get_page_size(const flash_t *obj); + +/** Get start address for the flash region + * + * @param obj The flash object + * @return The start address for the flash region + */ +uint32_t flash_get_start_address(const flash_t *obj); + +/** Get the flash region size + * + * @param obj The flash object + * @return The flash region size + */ +uint32_t flash_get_size(const flash_t *obj); + +/** Get the flash erase value + * + * @param obj The flash object + * @return The flash erase value + */ +uint8_t flash_get_erase_value(const flash_t *obj); + +/**@}*/ + +#ifdef __cplusplus +} +#endif + +#endif + +#endif + +/** @}*/ diff --git a/hal/include/hal/gpio_api.h b/hal/include/hal/gpio_api.h new file mode 100644 index 0000000..c4f4d17 --- /dev/null +++ b/hal/include/hal/gpio_api.h @@ -0,0 +1,201 @@ + +/** \addtogroup hal */ +/** @{*/ +/* mbed Microcontroller Library + * Copyright (c) 2006-2020 ARM Limited + * 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. + */ +#ifndef MBED_GPIO_API_H +#define MBED_GPIO_API_H + +#include +#include "device.h" +#include "pinmap.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \defgroup hal_gpio GPIO HAL functions + * + * # Defined behavior + * * ::gpio_init and other init functions can be called with NC or a valid PinName for the target - Verified by ::gpio_nc_test + * * ::gpio_is_connected can be used to test whether a gpio_t object was initialized with NC - Verified by ::gpio_nc_test + * * ::gpio_init initializes the GPIO pin + * * ::gpio_free returns the pin owned by the GPIO object to its reset state + * * ::gpio_mode sets the mode of the given pin + * * ::gpio_dir sets the direction of the given pin + * * ::gpio_write sets the gpio output value + * * ::gpio_read reads the input value + * * ::gpio_init_in inits the input pin and sets mode to PullDefault + * * ::gpio_init_in_ex inits the input pin and sets the mode + * * ::gpio_init_out inits the pin as an output, with predefined output value 0 + * * ::gpio_init_out_ex inits the pin as an output and sets the output value + * * ::gpio_init_inout inits the pin to be input/output and set pin mode and value + * * The GPIO operations ::gpio_write, ::gpio_read take less than 20us to complete + * * The function ::gpio_get_capabilities fills the given + * `gpio_capabilities_t` instance according to pin capabilities. + * + * # Undefined behavior + * * Calling any ::gpio_mode, ::gpio_dir, ::gpio_write or ::gpio_read on a gpio_t object that was initialized + * with NC. + * * Calling ::gpio_set with NC. + * + * @{ + */ + +/** + * \defgroup hal_gpio_tests GPIO HAL tests + * The GPIO HAL tests ensure driver conformance to defined behaviour. + * + * To run the GPIO hal tests use the command: + * + * mbed test -t -m -n tests-mbed_hal_fpga_ci_test_shield-gpio,tests-mbed_hal-gpio + * + */ + +/** GPIO capabilities for a given pin + */ +typedef struct { + uint8_t pull_none : 1; + uint8_t pull_down : 1; + uint8_t pull_up : 1; +} gpio_capabilities_t; + +/** Set the given pin as GPIO + * + * @param pin The pin to be set as GPIO + * @return The GPIO port mask for this pin + **/ +uint32_t gpio_set(PinName pin); + +/** Checks if gpio object is connected (pin was not initialized with NC) + * @param obj The GPIO object + * @return 0 if object was initialized with NC + * @return non-zero if object was initialized with a valid PinName + **/ +int gpio_is_connected(const gpio_t *obj); + +/** Initialize the GPIO pin + * + * @param obj The GPIO object to initialize + * @param pin The GPIO pin to initialize (may be NC) + */ +void gpio_init(gpio_t *obj, PinName pin); + +/** Releases the GPIO pin + * + * @param obj The GPIO object to release + */ +void gpio_free(gpio_t *obj); + +/** Set the input pin mode + * + * @param obj The GPIO object (must be connected) + * @param mode The pin mode to be set + */ +void gpio_mode(gpio_t *obj, PinMode mode); + +/** Set the pin direction + * + * @param obj The GPIO object (must be connected) + * @param direction The pin direction to be set + */ +void gpio_dir(gpio_t *obj, PinDirection direction); + +/** Set the output value + * + * @param obj The GPIO object (must be connected) + * @param value The value to be set + */ +void gpio_write(gpio_t *obj, int value); + +/** Read the input value + * + * @param obj The GPIO object (must be connected) + * @return An integer value 1 or 0 + */ +int gpio_read(gpio_t *obj); + +// the following functions are generic and implemented in the common gpio.c file +// TODO: fix, will be moved to the common gpio header file + +/** Init the input pin and set mode to PullDefault + * + * @param gpio The GPIO object + * @param pin The pin name (may be NC) + */ +void gpio_init_in(gpio_t *gpio, PinName pin); + +/** Init the input pin and set the mode + * + * @param gpio The GPIO object + * @param pin The pin name (may be NC) + * @param mode The pin mode to be set + */ +void gpio_init_in_ex(gpio_t *gpio, PinName pin, PinMode mode); + +/** Init the output pin as an output, with predefined output value 0 + * + * @param gpio The GPIO object + * @param pin The pin name (may be NC) + * @return An integer value 1 or 0 + */ +void gpio_init_out(gpio_t *gpio, PinName pin); + +/** Init the pin as an output and set the output value + * + * @param gpio The GPIO object + * @param pin The pin name (may be NC) + * @param value The value to be set + */ +void gpio_init_out_ex(gpio_t *gpio, PinName pin, int value); + +/** Init the pin to be in/out + * + * @param gpio The GPIO object + * @param pin The pin name (may be NC) + * @param direction The pin direction to be set + * @param mode The pin mode to be set + * @param value The value to be set for an output pin + */ +void gpio_init_inout(gpio_t *gpio, PinName pin, PinDirection direction, PinMode mode, int value); + +/** Fill the given gpio_capabilities_t instance according to pin capabilities. + */ +void gpio_get_capabilities(gpio_t *gpio, gpio_capabilities_t *cap); + +/** Get the pins that support all GPIO tests + * + * Return a PinMap array of pins that support GPIO. The + * array is terminated with {NC, NC, 0}. + * + * Targets should override the weak implementation of this + * function to provide the actual pinmap for GPIO testing. + * + * @return PinMap array + */ +const PinMap *gpio_pinmap(void); + +/**@}*/ + +#ifdef __cplusplus +} +#endif + +#endif + +/** @}*/ diff --git a/hal/include/hal/gpio_irq_api.h b/hal/include/hal/gpio_irq_api.h new file mode 100644 index 0000000..e08b049 --- /dev/null +++ b/hal/include/hal/gpio_irq_api.h @@ -0,0 +1,133 @@ + +/** \addtogroup hal */ +/** @{*/ +/* mbed Microcontroller Library + * Copyright (c) 2006-2013 ARM Limited + * 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. + */ +#ifndef MBED_GPIO_IRQ_API_H +#define MBED_GPIO_IRQ_API_H + +#include "device.h" +#include "pinmap.h" + +#if DEVICE_INTERRUPTIN + +#ifdef __cplusplus +extern "C" { +#endif + +/** GPIO IRQ events + */ +typedef enum { + IRQ_NONE, + IRQ_RISE, + IRQ_FALL +} gpio_irq_event; + +/** GPIO IRQ HAL structure. gpio_irq_s is declared in the target's HAL + */ +typedef struct gpio_irq_s gpio_irq_t; + +typedef void (*gpio_irq_handler)(uint32_t id, gpio_irq_event event); + +/** + * \defgroup hal_gpioirq GPIO IRQ HAL functions + * + * # Defined behavior + * * ::gpio_irq_init initializes the GPIO IRQ pin + * * ::gpio_irq_init attaches the interrupt handler + * * ::gpio_irq_free releases the GPIO IRQ pin + * * ::gpio_irq_set enables/disables pin IRQ event + * * ::gpio_irq_enable enables GPIO IRQ + * * ::gpio_irq_disable disables GPIO IRQ + * + * # Undefined behavior + * * Calling other function before ::gpio_irq_init + * + * @{ + */ + +/** + * \defgroup hal_gpioirq_tests GPIO IRQ HAL tests + * The GPIO IRQ HAL tests ensure driver conformance to defined behaviour. + * + * To run the GPIO IRQ hal tests use the command: + * + * mbed test -t -m -n tests-mbed_hal_fpga_ci_test_shield-gpio_irq + * + */ + +/** Initialize the GPIO IRQ pin + * + * @param obj The GPIO object to initialize + * @param pin The GPIO pin name + * @param handler The handler to be attached to GPIO IRQ + * @param id The object ID (id != 0, 0 is reserved) + * @return -1 if pin is NC, 0 otherwise + */ +int gpio_irq_init(gpio_irq_t *obj, PinName pin, gpio_irq_handler handler, uint32_t id); + +/** Release the GPIO IRQ PIN + * + * @param obj The gpio object + */ +void gpio_irq_free(gpio_irq_t *obj); + +/** Enable/disable pin IRQ event + * + * @param obj The GPIO object + * @param event The GPIO IRQ event + * @param enable The enable flag + */ +void gpio_irq_set(gpio_irq_t *obj, gpio_irq_event event, uint32_t enable); + +/** Enable GPIO IRQ + * + * This is target dependent, as it might enable the entire port or just a pin + * @param obj The GPIO object + */ +void gpio_irq_enable(gpio_irq_t *obj); + +/** Disable GPIO IRQ + * + * This is target dependent, as it might disable the entire port or just a pin + * @param obj The GPIO object + */ +void gpio_irq_disable(gpio_irq_t *obj); + +/** Get the pins that support all GPIO IRQ tests + * + * Return a PinMap array of pins that support GPIO IRQ. + * The array is terminated with {NC, NC, 0}. + * + * Targets should override the weak implementation of this + * function to provide the actual pinmap for GPIO IRQ testing. + * + * @return PinMap array + */ +const PinMap *gpio_irq_pinmap(void); + +/**@}*/ + +#ifdef __cplusplus +} +#endif + +#endif + +#endif + +/** @}*/ diff --git a/hal/include/hal/i2c_api.h b/hal/include/hal/i2c_api.h new file mode 100644 index 0000000..9a71985 --- /dev/null +++ b/hal/include/hal/i2c_api.h @@ -0,0 +1,378 @@ + +/** \addtogroup hal */ +/** @{*/ +/* mbed Microcontroller Library + * Copyright (c) 2006-2015 ARM Limited + * 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. + */ +#ifndef MBED_I2C_API_H +#define MBED_I2C_API_H + +#include "device.h" +#include "pinmap.h" +#include "hal/buffer.h" + +#if DEVICE_I2C_ASYNCH +#include "hal/dma_api.h" +#endif + +#if DEVICE_I2C + +/** + * @defgroup hal_I2CEvents I2C Events Macros + * + * @{ + */ +#define I2C_EVENT_ERROR (1 << 1) +#define I2C_EVENT_ERROR_NO_SLAVE (1 << 2) +#define I2C_EVENT_TRANSFER_COMPLETE (1 << 3) +#define I2C_EVENT_TRANSFER_EARLY_NACK (1 << 4) +#define I2C_EVENT_ALL (I2C_EVENT_ERROR | I2C_EVENT_TRANSFER_COMPLETE | I2C_EVENT_ERROR_NO_SLAVE | I2C_EVENT_TRANSFER_EARLY_NACK) + +/**@}*/ + +#if DEVICE_I2C_ASYNCH +/** Asynch I2C HAL structure + */ +typedef struct { + struct i2c_s i2c; /**< Target specific I2C structure */ + struct buffer_s tx_buff; /**< Tx buffer */ + struct buffer_s rx_buff; /**< Rx buffer */ +} i2c_t; + +#else +/** Non-asynch I2C HAL structure + */ +typedef struct i2c_s i2c_t; + +#endif + +enum { + I2C_ERROR_NO_SLAVE = -1, + I2C_ERROR_BUS_BUSY = -2 +}; + +typedef struct { + int peripheral; + PinName sda_pin; + int sda_function; + PinName scl_pin; + int scl_function; +} i2c_pinmap_t; + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \defgroup hal_GeneralI2C I2C Configuration Functions + * + * # Defined behavior + * * ::i2c_init initializes i2c_t control structure + * * ::i2c_init configures the pins used by I2C + * * ::i2c_free returns the pins owned by the I2C object to their reset state + * * ::i2c_frequency configure the I2C frequency + * * ::i2c_start sends START command + * * ::i2c_read reads `length` bytes from the I2C slave specified by `address` to the `data` buffer + * * ::i2c_read reads generates a stop condition on the bus at the end of the transfer if `stop` parameter is non-zero + * * ::i2c_read reads returns the number of symbols received from the bus + * * ::i2c_write writes `length` bytes to the I2C slave specified by `address` from the `data` buffer + * * ::i2c_write generates a stop condition on the bus at the end of the transfer if `stop` parameter is non-zero + * * ::i2c_write returns zero on success, error code otherwise + * * ::i2c_reset resets the I2C peripheral + * * ::i2c_byte_read reads and return one byte from the specfied I2C slave + * * ::i2c_byte_read uses `last` parameter to inform the slave that all bytes have been read + * * ::i2c_byte_write writes one byte to the specified I2C slave + * * ::i2c_byte_write returns 0 if NAK was received, 1 if ACK was received, 2 for timeout + * * ::i2c_slave_mode enables/disables I2S slave mode + * * ::i2c_slave_receive returns: 1 - read addresses, 2 - write to all slaves, 3 write addressed, 0 - the slave has not been addressed + * * ::i2c_slave_read reads `length` bytes from the I2C master to the `data` buffer + * * ::i2c_slave_read returns non-zero if a value is available, 0 otherwise + * * ::i2c_slave_write writes `length` bytes to the I2C master from the `data` buffer + * * ::i2c_slave_write returns non-zero if a value is available, 0 otherwise + * * ::i2c_slave_address configures I2C slave address + * * ::i2c_transfer_asynch starts I2C asynchronous transfer + * * ::i2c_transfer_asynch writes `tx_length` bytes to the I2C slave specified by `address` from the `tx` buffer + * * ::i2c_transfer_asynch reads `rx_length` bytes from the I2C slave specified by `address` to the `rx` buffer + * * ::i2c_transfer_asynch generates a stop condition on the bus at the end of the transfer if `stop` parameter is non-zero + * * The callback given to ::i2c_transfer_asynch is invoked when the transfer completes + * * ::i2c_transfer_asynch specifies the logical OR of events to be registered + * * The ::i2c_transfer_asynch function may use the `DMAUsage` hint to select the appropriate async algorithm + * * ::i2c_irq_handler_asynch returns event flags if a transfer termination condition was met, otherwise returns 0. + * * ::i2c_active returns non-zero if the I2C module is active or 0 if it is not + * * ::i2c_abort_asynch aborts an on-going async transfer + * + * # Undefined behavior + * * Calling ::i2c_init multiple times on the same `i2c_t` + * * Calling any function other than ::i2c_init on a non-initialized `i2c_t` + * * Initialising the `I2C` peripheral with invalid `SDA` and `SCL` pins. + * * Passing pins that cannot be on the same peripheral + * * Passing an invalid pointer as `obj` to any function + * * Use of a `null` pointer as an argument to any function. + * * Initialising the peripheral in slave mode if slave mode is not supported + * * Operating the peripheral in slave mode without first specifying and address using ::i2c_slave_address + * * Setting an address using i2c_slave_address after initialising the peripheral in master mode + * * Setting an address to an `I2C` reserved value + * * Specifying an invalid address when calling any `read` or `write` functions + * * Setting the length of the transfer or receive buffers to larger than the buffers are + * * Passing an invalid pointer as `handler` + * * Calling ::i2c_abort_async when no transfer is currently in progress + * + * + * @{ + */ + +/** + * \defgroup hal_GeneralI2C_tests I2C hal tests + * The I2C HAL tests ensure driver conformance to defined behaviour. + * + * To run the I2C hal tests use the command: + * + * mbed test -t -m -n tests-mbed_hal_fpga_ci_test_shield-i2c + * + */ + +/** Initialize the I2C peripheral. It sets the default parameters for I2C + * peripheral, and configures its specifieds pins. + * + * @param obj The I2C object + * @param pinmap Pinmap pointer to structure which holds static pinmap + */ +void i2c_init_direct(i2c_t *obj, const i2c_pinmap_t *pinmap); + +/** Initialize the I2C peripheral. It sets the default parameters for I2C + * peripheral, and configures its specifieds pins. + * + * @param obj The I2C object + * @param sda The sda pin + * @param scl The scl pin + */ +void i2c_init(i2c_t *obj, PinName sda, PinName scl); + +/** Release a I2C object + * + * Return the pins owned by the I2C object to their reset state + * @param obj The I2C object to deinitialize + */ +void i2c_free(i2c_t *obj); + +/** Configure the I2C frequency + * + * @param obj The I2C object + * @param hz Frequency in Hz + */ +void i2c_frequency(i2c_t *obj, int hz); + +/** Send START command + * + * @param obj The I2C object + */ +int i2c_start(i2c_t *obj); + +/** Send STOP command + * + * @param obj The I2C object + */ +int i2c_stop(i2c_t *obj); + +/** Blocking reading data + * + * @param obj The I2C object + * @param address 7-bit address (last bit is 1) + * @param data The buffer for receiving + * @param length Number of bytes to read + * @param stop Stop to be generated after the transfer is done + * @return Number of read bytes + */ +int i2c_read(i2c_t *obj, int address, char *data, int length, int stop); + +/** Blocking sending data + * + * @param obj The I2C object + * @param address 7-bit address (last bit is 0) + * @param data The buffer for sending + * @param length Number of bytes to write + * @param stop Stop to be generated after the transfer is done + * @return + * zero or non-zero - Number of written bytes + * negative - I2C_ERROR_XXX status + */ +int i2c_write(i2c_t *obj, int address, const char *data, int length, int stop); + +/** Reset I2C peripheral. TODO: The action here. Most of the implementation sends stop() + * + * @param obj The I2C object + */ +void i2c_reset(i2c_t *obj); + +/** Read one byte + * + * @param obj The I2C object + * @param last Acknoledge + * @return The read byte + */ +int i2c_byte_read(i2c_t *obj, int last); + +/** Write one byte + * + * @param obj The I2C object + * @param data Byte to be written + * @return 0 if NAK was received, 1 if ACK was received, 2 for timeout. + */ +int i2c_byte_write(i2c_t *obj, int data); + +/** Get the pins that support I2C SDA + * + * Return a PinMap array of pins that support I2C SDA in + * master mode. The array is terminated with {NC, NC, 0}. + * + * @return PinMap array + */ +const PinMap *i2c_master_sda_pinmap(void); + +/** Get the pins that support I2C SCL + * + * Return a PinMap array of pins that support I2C SCL in + * master mode. The array is terminated with {NC, NC, 0}. + * + * @return PinMap array + */ +const PinMap *i2c_master_scl_pinmap(void); + +/** Get the pins that support I2C SDA + * + * Return a PinMap array of pins that support I2C SDA in + * slave mode. The array is terminated with {NC, NC, 0}. + * + * @return PinMap array + */ +const PinMap *i2c_slave_sda_pinmap(void); + +/** Get the pins that support I2C SCL + * + * Return a PinMap array of pins that support I2C SCL in + * slave mode. The array is terminated with {NC, NC, 0}. + * + * @return PinMap array + */ +const PinMap *i2c_slave_scl_pinmap(void); + +/**@}*/ + +#if DEVICE_I2CSLAVE + +/** + * \defgroup SynchI2C Synchronous I2C Hardware Abstraction Layer for slave + * @{ + */ + +/** Configure I2C as slave or master. + * @param obj The I2C object + * @param enable_slave Enable i2c hardware so you can receive events with ::i2c_slave_receive + * @return non-zero if a value is available + */ +void i2c_slave_mode(i2c_t *obj, int enable_slave); + +/** Check to see if the I2C slave has been addressed. + * @param obj The I2C object + * @return The status - 1 - read addresses, 2 - write to all slaves, + * 3 write addressed, 0 - the slave has not been addressed + */ +int i2c_slave_receive(i2c_t *obj); + +/** Configure I2C as slave or master. + * @param obj The I2C object + * @param data The buffer for receiving + * @param length Number of bytes to read + * @return non-zero if a value is available + */ +int i2c_slave_read(i2c_t *obj, char *data, int length); + +/** Configure I2C as slave or master. + * @param obj The I2C object + * @param data The buffer for sending + * @param length Number of bytes to write + * @return non-zero if a value is available + */ +int i2c_slave_write(i2c_t *obj, const char *data, int length); + +/** Configure I2C address. + * @param obj The I2C object + * @param idx Currently not used + * @param address The address to be set + * @param mask Currently not used + */ +void i2c_slave_address(i2c_t *obj, int idx, uint32_t address, uint32_t mask); + +#endif + +/**@}*/ + +#if DEVICE_I2C_ASYNCH + +/** + * \defgroup hal_AsynchI2C Asynchronous I2C Hardware Abstraction Layer + * @{ + */ + +/** Start I2C asynchronous transfer + * + * @param obj The I2C object + * @param tx The transmit buffer + * @param tx_length The number of bytes to transmit + * @param rx The receive buffer + * @param rx_length The number of bytes to receive + * @param address The address to be set - 7bit or 9bit + * @param stop If true, stop will be generated after the transfer is done + * @param handler The I2C IRQ handler to be set + * @param event Event mask for the transfer. See \ref hal_I2CEvents + * @param hint DMA hint usage + */ +void i2c_transfer_asynch(i2c_t *obj, const void *tx, size_t tx_length, void *rx, size_t rx_length, uint32_t address, uint32_t stop, uint32_t handler, uint32_t event, DMAUsage hint); + +/** The asynchronous IRQ handler + * + * @param obj The I2C object which holds the transfer information + * @return Event flags if a transfer termination condition was met, otherwise return 0. + */ +uint32_t i2c_irq_handler_asynch(i2c_t *obj); + +/** Attempts to determine if the I2C peripheral is already in use + * + * @param obj The I2C object + * @return Non-zero if the I2C module is active or zero if it is not + */ +uint8_t i2c_active(i2c_t *obj); + +/** Abort asynchronous transfer + * + * This function does not perform any check - that should happen in upper layers. + * @param obj The I2C object + */ +void i2c_abort_asynch(i2c_t *obj); + +#endif + +/**@}*/ + +#ifdef __cplusplus +} +#endif + +#endif + +#endif + +/** @}*/ diff --git a/hal/include/hal/itm_api.h b/hal/include/hal/itm_api.h new file mode 100644 index 0000000..897f6fa --- /dev/null +++ b/hal/include/hal/itm_api.h @@ -0,0 +1,103 @@ +/** \addtogroup hal */ +/** @{*/ +/* mbed Microcontroller Library + * Copyright (c) 2017 ARM Limited + * 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. + */ + +#ifndef MBED_ITM_API_H +#define MBED_ITM_API_H + +#if DEVICE_ITM + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \defgroup itm_hal Instrumented Trace Macrocell HAL API + * @{ + */ + +enum { + ITM_PORT_SWO = 0 +}; + +/** + * @brief Target specific initialization function. + * This function is responsible for initializing and configuring + * the debug clock for the ITM and setting up the SWO pin for + * debug output. + * + * The only Cortex-M register that should be modified is the clock + * prescaler in TPI->ACPR. + * + * The generic mbed_itm_init initialization function will setup: + * + * ITM->LAR + * ITM->TPR + * ITM->TCR + * ITM->TER + * TPI->SPPR + * TPI->FFCR + * DWT->CTRL + * + * for SWO output on stimulus port 0. + */ +void itm_init(void); + +/** + * @brief Initialization function for both generic registers and target specific clock and pin. + */ +void mbed_itm_init(void); + +/** + * @brief Send data over ITM stimulus port. + * + * @param[in] port The stimulus port to send data over. + * @param[in] data The 32-bit data to send. + * + * The data is written as a single 32-bit write to the port. + * + * @return value of data sent. + */ +uint32_t mbed_itm_send(uint32_t port, uint32_t data); + +/** + * @brief Send a block of data over ITM stimulus port. + * + * @param[in] port The stimulus port to send data over. + * @param[in] data The block of data to send. + * @param[in] len The number of bytes of data to send. + * + * The data is written using multiple appropriately-sized port accesses for + * efficient transfer. + */ +void mbed_itm_send_block(uint32_t port, const void *data, size_t len); + +/**@}*/ + +#ifdef __cplusplus +} +#endif + +#endif + +#endif /* MBED_ITM_API_H */ + +/**@}*/ diff --git a/hal/include/hal/lp_ticker_api.h b/hal/include/hal/lp_ticker_api.h new file mode 100644 index 0000000..aecaf8a --- /dev/null +++ b/hal/include/hal/lp_ticker_api.h @@ -0,0 +1,248 @@ + +/** \addtogroup hal */ +/** @{*/ +/* mbed Microcontroller Library + * Copyright (c) 2015 ARM Limited + * 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. + */ +#ifndef MBED_LPTICKER_API_H +#define MBED_LPTICKER_API_H + +#include "device.h" + +#if DEVICE_LPTICKER + +#include "hal/ticker_api.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \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 -m -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 + * + * @param ticker_irq_handler IRQ handler to be connected + * + * @return previous 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 + * + */ +ticker_irq_handler_type set_lp_ticker_irq_handler(ticker_irq_handler_type ticker_irq_handler); + +/** Get low power ticker's data + * + * @return The low power ticker data + */ +const ticker_data_t *get_lp_ticker_data(void); + +/** The wrapper for ticker_irq_handler, to pass lp ticker's data + * + */ +void lp_ticker_irq_handler(void); + +/* HAL lp ticker */ + +/** 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); + +/** Deinitialize the lower power ticker + * + * 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 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. + * + * 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); + +/**@}*/ + +#ifdef __cplusplus +} +#endif + +#endif + +#endif + +/** @}*/ diff --git a/hal/include/hal/mbed_lp_ticker_wrapper.h b/hal/include/hal/mbed_lp_ticker_wrapper.h new file mode 100644 index 0000000..3493abe --- /dev/null +++ b/hal/include/hal/mbed_lp_ticker_wrapper.h @@ -0,0 +1,82 @@ + +/** \addtogroup hal */ +/** @{*/ +/* mbed Microcontroller Library + * Copyright (c) 2018 ARM Limited + * 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. + */ +#ifndef MBED_LP_TICKER_WRAPPER_H +#define MBED_LP_TICKER_WRAPPER_H + +#include "device.h" + +#if DEVICE_LPTICKER + +#include "hal/ticker_api.h" +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef void (*ticker_irq_handler_type)(const ticker_data_t *const); + +/** + * Interrupt handler for the wrapped lp ticker + * + * @param handler the function which would normally be called by the + * lp ticker handler when it is not wrapped + */ +void lp_ticker_wrapper_irq_handler(ticker_irq_handler_type handler); + +/** + * Get wrapped lp ticker data + * + * @param data hardware low power ticker object + * @return wrapped low power ticker object + */ +const ticker_data_t *get_lp_ticker_wrapper_data(const ticker_data_t *data); + +/** + * Suspend the wrapper layer code + * + * Pass through all interrupts to the low power ticker and stop using + * the microsecond ticker. + * + * @warning: Make sure to suspend the LP ticker first (call ticker_suspend()), + * otherwise the behavior is undefined. + */ +void lp_ticker_wrapper_suspend(void); + +/** + * Resume the wrapper layer code + * + * Resume operation of the wrapper layer. Interrupts will be filtered + * as normal and the microsecond timer will be used for interrupts scheduled + * too quickly back-to-back. + */ +void lp_ticker_wrapper_resume(void); + +/**@}*/ + +#ifdef __cplusplus +} +#endif + +#endif + +#endif + +/** @}*/ diff --git a/hal/include/hal/mpu_api.h b/hal/include/hal/mpu_api.h new file mode 100644 index 0000000..95ee8fc --- /dev/null +++ b/hal/include/hal/mpu_api.h @@ -0,0 +1,123 @@ + +/** \addtogroup hal */ +/** @{*/ +/* mbed Microcontroller Library + * Copyright (c) 2018-2018 ARM Limited + * 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. + */ +#ifndef MBED_MPU_API_H +#define MBED_MPU_API_H + +#include "device.h" +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#if DEVICE_MPU + +/** + * \defgroup hal_mpu MPU hal + * + * The MPU hal provides a simple MPU API to enhance device security by preventing + * execution from ram. + * + * # Defined behavior + * * The function ::mbed_mpu_init is safe to call repeatedly - Verified by ::mpu_init_test + * * The function ::mbed_mpu_free disables MPU protection - Verified by ::mpu_free_test + * * Execution from RAM results in a fault when execute never is enabled. + * This RAM includes heap, stack, data and zero init - Verified by ::mpu_fault_test_data, + * ::mpu_fault_test_bss, ::mpu_fault_test_stack and ::mpu_fault_test_heap. + * * Writing to ROM results in a fault when write never is enabled - Not verified + * + * # Undefined behavior + * * Calling any function other than ::mbed_mpu_init before the initialization of the MPU. + * + * @see hal_mpu_tests + * + * @{ + */ + +/** + * \defgroup hal_mpu_tests MPU hal tests + * The MPU test validates proper implementation of the MPU hal. + * + * To run the MPU hal tests use the command: + * + * mbed test -t -m -n tests-mbed_hal-mpu* + */ + + +/** + * Initialize the MPU + * + * Initialize or re-initialize the memory protection unit. + * After initialization or re-initialization, ROM and RAM protection + * are both enabled. + */ +void mbed_mpu_init(void); + +/** + * Enable or disable ROM MPU protection + * + * This function is used to mark all of ROM as read and execute only. + * When enabled writes to ROM cause a fault. + * + * By default writes to ROM are disabled. + * + * @param enable true to disable writes to ROM, false otherwise + */ +void mbed_mpu_enable_rom_wn(bool enable); + +/** + * Enable or disable ram MPU protection + * + * This function is used to mark all of RAM as execute never. + * When enabled code is only allowed to execute from flash. + * + * By default execution from RAM is disabled. + * + * @param enable true to disable execution from RAM, false otherwise + */ +void mbed_mpu_enable_ram_xn(bool enable); + +/** Deinitialize the MPU + * + * Powerdown the MPU in preparation for powerdown, reset or jumping to another application. + */ +void mbed_mpu_free(void); + +/**@}*/ + +#else + +#define mbed_mpu_init() + +#define mbed_mpu_enable_rom_wn(enable) (void)enable + +#define mbed_mpu_enable_ram_xn(enable) (void)enable + +#define mbed_mpu_free() + +#endif + +#ifdef __cplusplus +} +#endif + +#endif + +/** @}*/ diff --git a/hal/include/hal/pinmap.h b/hal/include/hal/pinmap.h new file mode 100644 index 0000000..f3af23b --- /dev/null +++ b/hal/include/hal/pinmap.h @@ -0,0 +1,260 @@ + +/** \addtogroup hal */ +/** @{*/ +/* mbed Microcontroller Library + * Copyright (c) 2006-2013 ARM Limited + * 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. + */ +#ifndef MBED_PINMAP_H +#define MBED_PINMAP_H + +#include "PinNames.h" +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct { + PinName pin; + int peripheral; + int function; +} PinMap; + +typedef struct { + uint32_t count; + const PinName *pins; +} PinList; + +typedef struct { + uint32_t count; + const int *peripheral; +} PeripheralList; + +void pin_function(PinName pin, int function); +void pin_mode(PinName pin, PinMode mode); + +uint32_t pinmap_peripheral(PinName pin, const PinMap *map); +uint32_t pinmap_function(PinName pin, const PinMap *map); +uint32_t pinmap_merge(uint32_t a, uint32_t b); +void pinmap_pinout(PinName pin, const PinMap *map); +uint32_t pinmap_find_peripheral(PinName pin, const PinMap *map); +uint32_t pinmap_find_function(PinName pin, const PinMap *map); + +/** + * Find a combination of pins suitable for use given the constraints + * + * This function finds pins which meet these specific properties: + * - The pin is part of the form factor + * - The pin is not in the restricted list + * - The pin is contained within the respective pinmap + * - The pin belongs to the given peripheral + * - Each pin found is distinct; in the example below + * mosi and miso will never be assigned the same pin + * + * Example: + * @code + * #include "mbed.h" + * #include "pinmap.h" + * + * int main() + * { + * int per = spi_master_cs_pinmap()->peripheral; + * const PinList *pins_ff = pinmap_ff_default_pins(); + * const PinList *pins_avoid = pinmap_restricted_pins(); + * PinName mosi = NC; + * PinName miso = NC; + * PinName sclk = NC; + * PinName ssel = NC; + * const PinMap *maps[] = { + * spi_master_mosi_pinmap(), + * spi_master_miso_pinmap(), + * spi_master_clk_pinmap(), + * spi_master_cs_pinmap() + * }; + * PinName *pins[] = { + * &mosi, + * &miso, + * &sclk, + * &ssel + * }; + * if (pinmap_find_peripheral_pins(pins_ff, pins_avoid, per, maps, pins, sizeof(maps) / sizeof(maps[0]))) { + * printf("Found SPI pins to test instance %i with:\n" + * " mosi=%s\n" + * " miso=%s\n" + * " sclk=%s\n" + * " ssel=%s\n", per, + * pinmap_ff_default_pin_to_string(mosi), + * pinmap_ff_default_pin_to_string(miso), + * pinmap_ff_default_pin_to_string(sclk), + * pinmap_ff_default_pin_to_string(ssel)); + * } else { + * printf("Could not find SPI combination to test %i\n", per); + * } + * return 0; + * } + * @endcode + * + * @param whitelist List of pins to choose from + * @param blacklist List of pins which cannot be used + * @param per Peripheral to which the pins belong + * @param maps An array of pin maps to select from + * @param pins An array of pins to find. Pins already set to a value will be + * left unchanged. Only pins initialized to NC will be updated by this function + * @param count The size of maps and pins + * @return true if a suitable combination of pins was found and + * written to the pins array, otherwise false + */ +bool pinmap_find_peripheral_pins(const PinList *whitelist, const PinList *blacklist, int per, const PinMap *const *maps, PinName **pins, uint32_t count); + +/** + * Check if the pin is in the list + * + * @param list pin list to check + * @param pin pin to check for in the list + * @return true if the pin is in the list, false otherwise + */ +bool pinmap_list_has_pin(const PinList *list, PinName pin); + +/** + * Check if the peripheral is in the list + * + * @param list peripheral list to check + * @param peripheral peripheral to check for in the list + * @return true if the peripheral is in the list, false otherwise + */ +bool pinmap_list_has_peripheral(const PeripheralList *list, int peripheral); + +/** + * Get the pin list of pins to avoid during testing + * + * The restricted pin list is used to indicate to testing + * that a pin should be skipped due to some caveat about it. + * For example, using USBRX and USBTX during tests will interfere + * with the test runner and should be avoided. + * + * Targets should override the weak implementation of this + * function if they have additional pins which should be + * skipped during testing. + * + * @return Pointer to a pin list of pins to avoid + */ +const PinList *pinmap_restricted_pins(void); + +/** + * Get the pin list of peripherals per interface to avoid during testing + * + * The restricted peripheral list is used to indicate to testing + * that a peripheral should be skipped due to some caveat about it. + * For example, using the USB serial port during tests will interfere + * with the test runner and should be avoided. + * + * Targets should override the weak implementation of this + * function if they have peripherals which should be + * skipped during testing. + * + * @note Restricting peripheral is at the moment available for UART + * interface only as only STDIO UART must be skipped because it is + * used by Mbed. + * Restricting peripherals for other interfaces should be added + * in the future if required. + * + * @return Pointer to a peripheral list of peripheral to avoid + */ +#if DEVICE_SERIAL +const PeripheralList *pinmap_uart_restricted_peripherals(void); +#endif + +/** + * Get the pin list of pins to avoid during GPIO/GPIO_IRQ testing + * + * The GPIO restricted pin list is used to indicate to testing + * that a pin should be skipped due to some caveat about it. + * + * Targets should override the weak implementation of this + * function if they have peripherals which should be + * skipped during testing. + * + * @note This is special case only for GPIO/GPIO_IRQ tests because + * targets do not provide pin-maps for GPIO. + * + * @return Pointer to a peripheral list of peripheral to avoid + */ +const PinList *pinmap_gpio_restricted_pins(void); + +#ifdef TARGET_FF_ARDUINO + +/** + * Get the pin list of the Arduino form factor + * + * @return Pointer to the Arduino pin list + */ +const PinList *pinmap_ff_arduino_pins(void); + +/** + * Get the string representation of a form factor pin + * + * @param pin Pin to get a string for + * @return String representing the form factor pin + */ +const char *pinmap_ff_arduino_pin_to_string(PinName pin); + +/* Default to arduino form factor if unspecified */ +#ifndef MBED_CONF_TARGET_DEFAULT_FORM_FACTOR +#define MBED_CONF_TARGET_DEFAULT_FORM_FACTOR arduino +#endif + +#endif + +#ifdef MBED_CONF_TARGET_DEFAULT_FORM_FACTOR + +#define PINMAP_DEFAULT_PINS_(name) pinmap_ff_ ## name ## _pins +#define PINMAP_DEFAULT_PIN_TO_STRING_(name) pinmap_ff_ ## name ## _pin_to_string +#define PINMAP_DEFAULT_PINS(name) PINMAP_DEFAULT_PINS_(name) +#define PINMAP_DEFAULT_PIN_TO_STRING(name) PINMAP_DEFAULT_PIN_TO_STRING_(name) +#define pinmap_ff_default_pins PINMAP_DEFAULT_PINS(MBED_CONF_TARGET_DEFAULT_FORM_FACTOR) +#define pinmap_ff_default_pin_to_string PINMAP_DEFAULT_PIN_TO_STRING(MBED_CONF_TARGET_DEFAULT_FORM_FACTOR) + +/** + * Get the pin list of the default form factor + * + * This is an alias to whichever form factor is set + * to be the default. + * + * @return Pointer to the default pin list + */ +const PinList *pinmap_ff_default_pins(void); + +/** + * Get the string representation of a form factor pin + * + * This is an alias to whichever form factor is set + * to be the default. + * + * @param pin Pin to get a string for + * @return String representing the form factor pin + */ +const char *pinmap_ff_default_pin_to_string(PinName pin); + +#endif + +#ifdef __cplusplus +} +#endif + +#endif + +/** @}*/ diff --git a/hal/include/hal/port_api.h b/hal/include/hal/port_api.h new file mode 100644 index 0000000..48bd0d2 --- /dev/null +++ b/hal/include/hal/port_api.h @@ -0,0 +1,94 @@ + +/** \addtogroup hal */ +/** @{*/ +/* mbed Microcontroller Library + * Copyright (c) 2006-2013 ARM Limited + * 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. + */ +#ifndef MBED_PORTMAP_H +#define MBED_PORTMAP_H + +#include "device.h" + +#if DEVICE_PORTIN || DEVICE_PORTOUT + +#ifdef __cplusplus +extern "C" { +#endif + +/** Port HAL structure. port_s is declared in the target's HAL + */ +typedef struct port_s port_t; + +/** + * \defgroup hal_port Port HAL functions + * @{ + */ + +/** Get the pin name from the port's pin number + * + * @param port The port name + * @param pin_n The pin number within the specified port + * @return The pin name for the port's pin number + */ +PinName port_pin(PortName port, int pin_n); + +/** Initilize the port + * + * @param obj The port object to initialize + * @param port The port name + * @param mask The bitmask to identify which bits in the port should be included (0 - ignore) + * @param dir The port direction + */ +void port_init(port_t *obj, PortName port, int mask, PinDirection dir); + +/** Set the input port mode + * + * @param obj The port object + * @param mode THe port mode to be set + */ +void port_mode(port_t *obj, PinMode mode); + +/** Set port direction (in/out) + * + * @param obj The port object + * @param dir The port direction to be set + */ +void port_dir(port_t *obj, PinDirection dir); + +/** Write value to the port + * + * @param obj The port object + * @param value The value to be set + */ +void port_write(port_t *obj, int value); + +/** Read the current value on the port + * + * @param obj The port object + * @return An integer with each bit corresponding to an associated port pin setting + */ +int port_read(port_t *obj); + +/**@}*/ + +#ifdef __cplusplus +} +#endif +#endif + +#endif + +/** @}*/ diff --git a/hal/include/hal/pwmout_api.h b/hal/include/hal/pwmout_api.h new file mode 100644 index 0000000..977f7c6 --- /dev/null +++ b/hal/include/hal/pwmout_api.h @@ -0,0 +1,168 @@ + +/** \addtogroup hal */ +/** @{*/ +/* mbed Microcontroller Library + * Copyright (c) 2006-2013 ARM Limited + * 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. + */ +#ifndef MBED_PWMOUT_API_H +#define MBED_PWMOUT_API_H + +#include "device.h" +#include "pinmap.h" + +#if DEVICE_PWMOUT + +#ifdef __cplusplus +extern "C" { +#endif + +/** Pwmout hal structure. pwmout_s is declared in the target's hal + */ +typedef struct pwmout_s pwmout_t; + +/** + * \defgroup hal_pwmout Pwmout hal functions + * + * # Defined behavior + * * ::pwmout_init initializes the pwmout_t control structure + * * ::pwmout_free deinitializes the pwmout object + * * ::pwmout_write sets the output duty-cycle in range <0.0f, 1.0f> + * * ::pwmout_read returns the current float-point output duty-cycle in range <0.0f, 1.0f> + * * ::pwmout_period sets the PWM period specified in seconds, keeping the duty cycle the same + * * ::pwmout_period_ms sets the PWM period specified in miliseconds, keeping the duty cycle the same + * * ::pwmout_period_us sets the PWM period specified in microseconds, keeping the duty cycle the same + * * ::pwmout_pulsewidth sets the PWM pulsewidth specified in seconds, keeping the period the same + * * ::pwmout_pulsewidth_ms sets the PWM pulsewidth specified in miliseconds, keeping the period the same + * * ::pwmout_pulsewidth_us sets the PWM pulsewidth specified in microseconds, keeping the period the same + * * The accuracy of the PWM is +/- 10% + * * The PWM operations ::pwmout_write, ::pwmout_read, ::pwmout_read, ::pwmout_period_ms, ::pwmout_period_us + * ::pwmout_pulsewidth, ::pwmout_pulsewidth_ms, ::pwmout_pulsewidth_us take less than 20us to complete + * + * # Undefined behavior + * * Calling other function before ::pwmout_init + * * Calling ::pwmout_init with NC as pwmout pin + * + * @{ + */ + +/** + * \defgroup hal_pwmout_tests GPIO IRQ HAL tests + * The Pwmout HAL tests ensure driver conformance to defined behaviour. + * + * To run the Pwmout hal tests use the command: + * + * mbed test -t -m -n tests-mbed_hal_fpga_ci_test_shield-pwm + * + */ + +/** Initialize the pwm out peripheral and configure the pin + * + * @param obj The pwmout object to initialize + * @param pinmap pointer to structure which holds static pinmap + */ +void pwmout_init_direct(pwmout_t *obj, const PinMap *pinmap); + +/** Initialize the pwm out peripheral and configure the pin + * + * @param obj The pwmout object to initialize + * @param pin The pwmout pin to initialize + */ +void pwmout_init(pwmout_t *obj, PinName pin); + +/** Deinitialize the pwmout object + * + * @param obj The pwmout object + */ +void pwmout_free(pwmout_t *obj); + +/** Set the output duty-cycle in range <0.0f, 1.0f> + * + * Value 0.0f represents 0 percentage, 1.0f represents 100 percent. + * @param obj The pwmout object + * @param percent The floating-point percentage number + */ +void pwmout_write(pwmout_t *obj, float percent); + +/** Read the current float-point output duty-cycle + * + * @param obj The pwmout object + * @return A floating-point output duty-cycle + */ +float pwmout_read(pwmout_t *obj); + +/** Set the PWM period specified in seconds, keeping the duty cycle the same + * + * Periods smaller than microseconds (the lowest resolution) are set to zero. + * @param obj The pwmout object + * @param seconds The floating-point seconds period + */ +void pwmout_period(pwmout_t *obj, float seconds); + +/** Set the PWM period specified in miliseconds, keeping the duty cycle the same + * + * @param obj The pwmout object + * @param ms The milisecond period + */ +void pwmout_period_ms(pwmout_t *obj, int ms); + +/** Set the PWM period specified in microseconds, keeping the duty cycle the same + * + * @param obj The pwmout object + * @param us The microsecond period + */ +void pwmout_period_us(pwmout_t *obj, int us); + +/** Set the PWM pulsewidth specified in seconds, keeping the period the same. + * + * @param obj The pwmout object + * @param seconds The floating-point pulsewidth in seconds + */ +void pwmout_pulsewidth(pwmout_t *obj, float seconds); + +/** Set the PWM pulsewidth specified in miliseconds, keeping the period the same. + * + * @param obj The pwmout object + * @param ms The floating-point pulsewidth in miliseconds + */ +void pwmout_pulsewidth_ms(pwmout_t *obj, int ms); + +/** Set the PWM pulsewidth specified in microseconds, keeping the period the same. + * + * @param obj The pwmout object + * @param us The floating-point pulsewidth in microseconds + */ +void pwmout_pulsewidth_us(pwmout_t *obj, int us); + +/** Get the pins that support PWM + * + * Return a PinMap array of pins that support PWM. + * The array is terminated with {NC, NC, 0}. + * + * @return PinMap array + */ +const PinMap *pwmout_pinmap(void); + +/**@}*/ + +#ifdef __cplusplus +} +#endif + +#endif + +#endif + +/** @}*/ diff --git a/hal/include/hal/qspi_api.h b/hal/include/hal/qspi_api.h new file mode 100644 index 0000000..f753de2 --- /dev/null +++ b/hal/include/hal/qspi_api.h @@ -0,0 +1,282 @@ + +/** \addtogroup hal */ +/** @{*/ +/* mbed Microcontroller Library + * Copyright (c) 2017 ARM Limited + * 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. + */ +#ifndef MBED_QSPI_API_H +#define MBED_QSPI_API_H + +#include "device.h" +#include "pinmap.h" +#include + +#if DEVICE_QSPI + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \defgroup hal_qspi QSPI HAL + * @{ + */ + +/** QSPI HAL object + */ +typedef struct qspi_s qspi_t; + +typedef struct { + int peripheral; + PinName data0_pin; + int data0_function; + PinName data1_pin; + int data1_function; + PinName data2_pin; + int data2_function; + PinName data3_pin; + int data3_function; + PinName sclk_pin; + int sclk_function; + PinName ssel_pin; + int ssel_function; +} qspi_pinmap_t; + +/** QSPI Bus width + * + * Some parts of commands provide variable bus width + */ +typedef enum qspi_bus_width { + QSPI_CFG_BUS_SINGLE, + QSPI_CFG_BUS_DUAL, + QSPI_CFG_BUS_QUAD, +} qspi_bus_width_t; + +/** Address size in bits + */ +typedef enum qspi_address_size { + QSPI_CFG_ADDR_SIZE_8, + QSPI_CFG_ADDR_SIZE_16, + QSPI_CFG_ADDR_SIZE_24, + QSPI_CFG_ADDR_SIZE_32, +} qspi_address_size_t; + +/** Alternative size in bits + */ +typedef uint8_t qspi_alt_size_t; + +// The following defines are provided for backwards compatibilty. New code should explicitly +// specify the required number of alt bits. +#define QSPI_CFG_ALT_SIZE_8 8u +#define QSPI_CFG_ALT_SIZE_16 16u +#define QSPI_CFG_ALT_SIZE_24 24u +#define QSPI_CFG_ALT_SIZE_32 32u + +/** QSPI command + * + * Defines a frame format. It consists of instruction, address, alternative, dummy count and data + */ +typedef struct qspi_command { + struct { + qspi_bus_width_t bus_width; /**< Bus width for the instruction >*/ + uint8_t value; /**< Instruction value >*/ + bool disabled; /**< Instruction phase skipped if disabled is set to true >*/ + } instruction; + struct { + qspi_bus_width_t bus_width; /**< Bus width for the address >*/ + qspi_address_size_t size; /**< Address size >*/ + uint32_t value; /**< Address value >*/ + bool disabled; /**< Address phase skipped if disabled is set to true >*/ + } address; + struct { + qspi_bus_width_t bus_width; /**< Bus width for alternative >*/ + qspi_alt_size_t size; /**< Alternative size >*/ + uint32_t value; /**< Alternative value >*/ + bool disabled; /**< Alternative phase skipped if disabled is set to true >*/ + } alt; + uint8_t dummy_count; /**< Dummy cycles count >*/ + struct { + qspi_bus_width_t bus_width; /**< Bus width for data >*/ + } data; +} qspi_command_t; + +/** QSPI return status + */ +typedef enum qspi_status { + QSPI_STATUS_ERROR = -1, /**< Generic error >*/ + QSPI_STATUS_INVALID_PARAMETER = -2, /**< The parameter is invalid >*/ + QSPI_STATUS_OK = 0, /**< Function executed sucessfully >*/ +} qspi_status_t; + +/** Initialize QSPI peripheral. + * + * It should initialize QSPI pins (io0-io3, sclk and ssel), set frequency, clock polarity and phase mode. The clock for the peripheral should be enabled + * + * @param obj QSPI object + * @param io0 Data pin 0 + * @param io1 Data pin 1 + * @param io2 Data pin 2 + * @param io3 Data pin 3 + * @param sclk The clock pin + * @param ssel The chip select pin + * @param hz The bus frequency + * @param mode Clock polarity and phase mode (0 - 3) + * @return QSPI_STATUS_OK if initialisation successfully executed + QSPI_STATUS_INVALID_PARAMETER if invalid parameter found + QSPI_STATUS_ERROR otherwise + */ +qspi_status_t qspi_init(qspi_t *obj, PinName io0, PinName io1, PinName io2, PinName io3, PinName sclk, PinName ssel, uint32_t hz, uint8_t mode); + +/** Initialize QSPI peripheral. + * + * It should initialize QSPI pins (io0-io3, sclk and ssel), set frequency, clock polarity and phase mode. The clock for the peripheral should be enabled + * + * @param obj QSPI object + * @param pinmap pointer to structure which holds static pinmap + * @param hz The bus frequency + * @param mode Clock polarity and phase mode (0 - 3) + * @return QSPI_STATUS_OK if initialisation successfully executed + QSPI_STATUS_INVALID_PARAMETER if invalid parameter found + QSPI_STATUS_ERROR otherwise + */ +qspi_status_t qspi_init_direct(qspi_t *obj, const qspi_pinmap_t *pinmap, uint32_t hz, uint8_t mode); + +/** Deinitilize QSPI peripheral + * + * It should release pins that are associated with the QSPI object, and disable clocks for QSPI peripheral module that was associated with the object + * + * @param obj QSPI object + * @return QSPI_STATUS_OK if deinitialisation successfully executed + QSPI_STATUS_INVALID_PARAMETER if invalid parameter found + QSPI_STATUS_ERROR otherwise + */ +qspi_status_t qspi_free(qspi_t *obj); + +/** Set the QSPI baud rate + * + * Actual frequency may differ from the desired frequency due to available dividers and the bus clock + * Configures the QSPI peripheral's baud rate + * @param obj The SPI object to configure + * @param hz The baud rate in Hz + * @return QSPI_STATUS_OK if frequency was set + QSPI_STATUS_INVALID_PARAMETER if invalid parameter found + QSPI_STATUS_ERROR otherwise + */ +qspi_status_t qspi_frequency(qspi_t *obj, int hz); + +/** Send a command and block of data + * + * @param obj QSPI object + * @param command QSPI command + * @param data TX buffer + * @param[in,out] length in - TX buffer length in bytes, out - number of bytes written + * @return QSPI_STATUS_OK if the data has been succesfully sent + QSPI_STATUS_INVALID_PARAMETER if invalid parameter found + QSPI_STATUS_ERROR otherwise + */ +qspi_status_t qspi_write(qspi_t *obj, const qspi_command_t *command, const void *data, size_t *length); + +/** Send a command (and optionally data) and get the response. Can be used to send/receive device specific commands + * + * @param obj QSPI object + * @param command QSPI command + * @param tx_data TX buffer + * @param tx_size TX buffer length in bytes + * @param rx_data RX buffer + * @param rx_size RX buffer length in bytes + * @return QSPI_STATUS_OK if the data has been succesfully sent + QSPI_STATUS_INVALID_PARAMETER if invalid parameter found + QSPI_STATUS_ERROR otherwise + */ +qspi_status_t qspi_command_transfer(qspi_t *obj, const qspi_command_t *command, const void *tx_data, size_t tx_size, void *rx_data, size_t rx_size); + +/** Receive a command and block of data + * + * @param obj QSPI object + * @param command QSPI command + * @param data RX buffer + * @param[in,out] length in - RX buffer length in bytes, out - number of bytes read + * @return QSPI_STATUS_OK if data has been succesfully received + QSPI_STATUS_INVALID_PARAMETER if invalid parameter found + QSPI_STATUS_ERROR otherwise + */ +qspi_status_t qspi_read(qspi_t *obj, const qspi_command_t *command, void *data, size_t *length); + +/** Get the pins that support QSPI SCLK + * + * Return a PinMap array of pins that support QSPI SCLK in + * master mode. The array is terminated with {NC, NC, 0}. + * + * @return PinMap array + */ +const PinMap *qspi_master_sclk_pinmap(void); + +/** Get the pins that support QSPI SSEL + * + * Return a PinMap array of pins that support QSPI SSEL in + * master mode. The array is terminated with {NC, NC, 0}. + * + * @return PinMap array + */ +const PinMap *qspi_master_ssel_pinmap(void); + +/** Get the pins that support QSPI DATA0 + * + * Return a PinMap array of pins that support QSPI DATA0 in + * master mode. The array is terminated with {NC, NC, 0}. + * + * @return PinMap array + */ +const PinMap *qspi_master_data0_pinmap(void); + +/** Get the pins that support QSPI DATA1 + * + * Return a PinMap array of pins that support QSPI DATA1 in + * master mode. The array is terminated with {NC, NC, 0}. + * + * @return PinMap array + */ +const PinMap *qspi_master_data1_pinmap(void); + +/** Get the pins that support QSPI DATA2 + * + * Return a PinMap array of pins that support QSPI DATA2 in + * master mode. The array is terminated with {NC, NC, 0}. + * + * @return PinMap array + */ +const PinMap *qspi_master_data2_pinmap(void); + +/** Get the pins that support QSPI DATA3 + * + * Return a PinMap array of pins that support QSPI DATA3 in + * master mode. The array is terminated with {NC, NC, 0}. + * + * @return PinMap array + */ +const PinMap *qspi_master_data3_pinmap(void); + +/**@}*/ + +#ifdef __cplusplus +} +#endif + +#endif + +#endif + +/** @}*/ diff --git a/hal/include/hal/reset_reason_api.h b/hal/include/hal/reset_reason_api.h new file mode 100644 index 0000000..23bb402 --- /dev/null +++ b/hal/include/hal/reset_reason_api.h @@ -0,0 +1,162 @@ +/** \addtogroup hal */ +/** @{*/ +/* + * Copyright (c) 2018-2019 Arm Limited and affiliates. + * 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. + */ +#ifndef MBED_RESET_REASON_API_H +#define MBED_RESET_REASON_API_H + +#if DEVICE_RESET_REASON + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \defgroup hal_reset_reason ResetReason HAL API + * Low-level interface to the ResetReason of a target. + * + * This module provides a platform-independent method of checking the cause + * of the last system reset. + * + * # Defined behavior + * * The function ::hal_reset_reason_clear clears the ResetReason registers + * for the next system boot. + * * By the time the user calls ::hal_reset_reason_get to read the value, + * some other part of the application may have cleared the value. Therefore, + * though there may have been a reset reason in the registers when the system + * started, the reason may not be available when the user comes to check it. + * * The function ::hal_reset_reason_get_capabilities fills the given + * `reset_reason_capabilities_t` instance. + * + * # Undefined behavior + * * There is no guarantee that the function ::hal_reset_reason_get will + * return the same value when you call it repeatedly. Store the value for later + * use instead of calling the function repeatedly. + * * The function ::hal_reset_reason_clear may not clear the ResetReason + * register in time for the next system boot. + * + * # Notes + * * The contents of the targets ResetReason register may be cleared by some + * subsystem before it first gets called. This returns a ::RESET_REASON_UNKNOWN + * value to the user. To avoid this, the user should call the ResetReason API + * as early as possible at boot time. + * * If the target doesn't support clearing reset registers, + * ::hal_reset_reason_get seems to erroneously return a reset reason even after + * clearing. + * + * @{ + */ + +/** + * \defgroup hal_reset_reason_tests ResetReason HAL tests + * Greentea tests for the ResetReason HAL. + * + * To run the ResetReason HAL tests, use the command: + * + * mbed test -t -m -n tests-mbed_hal-reset_reason + * + */ + +/** Definitions of different reset reasons + */ +typedef enum { + RESET_REASON_POWER_ON, /**< Set when power is initially applied to the board. The power-on-reset circuit causes a POWER_ON reset when this occurs */ + RESET_REASON_PIN_RESET, /**< Set when a reset is triggered by the hardware pin on the board */ + RESET_REASON_BROWN_OUT, /**< Triggered when the voltage drops below the low voltage detect (LVD) threshold; the system is held in a reset until the voltage rises above the threshold */ + RESET_REASON_SOFTWARE, /**< Set during software reset, typically triggered by writing the SYSRESETREQ bit in the Application Interrupt and Reset Control register */ + RESET_REASON_WATCHDOG, /**< Set when a running watchdog timer fails to be refreshed */ + RESET_REASON_LOCKUP, /**< Set when the core is locked because of an unrecoverable exception */ + RESET_REASON_WAKE_LOW_POWER, /**< Set when waking from deep sleep mode */ + RESET_REASON_ACCESS_ERROR, /**< Umbrella value that encompasses any access related reset */ + RESET_REASON_BOOT_ERROR, /**< Umbrella value that encompasses any boot related reset */ + RESET_REASON_MULTIPLE, /**< Set if multiple reset reasons are set within the board. Occurs when the reset reason registers aren't cleared between resets */ + RESET_REASON_PLATFORM, /**< Platform specific reset reason not captured in this enum */ + RESET_REASON_UNKNOWN /**< Unknown or unreadable reset reason **/ +} reset_reason_t; + +/** Reset reason capabilities of the platform + */ +typedef struct { + uint32_t reasons; /**< Supported reset reasons. Each bit represents a corresponding reset_reason_t value.**/ +} reset_reason_capabilities_t; + +/** Fetch the reset reason for the last system reset. + * + * This function must return the contents of the system reset reason registers + * cast to an appropriate platform independent reset reason. If multiple reset + * reasons are set, this function should return ::RESET_REASON_MULTIPLE. If the + * reset reason does not match any existing platform independent value, this + * function should return ::RESET_REASON_PLATFORM. If no reset reason can be + * determined, this function should return ::RESET_REASON_UNKNOWN. + * + * This function is not idempotent; there is no guarantee the system + * reset reason will not be cleared between calls to this function altering the + * return value between calls. + * + * Note: Some platforms contain reset reason registers that persist through + * system resets. If the registers haven't been cleared before calling this + * function, multiple reasons may be set within the registers. If multiple reset + * reasons are detected, this function returns ::RESET_REASON_MULTIPLE. + * + * @return enum containing the last reset reason for the board. + */ +reset_reason_t hal_reset_reason_get(void); + + +/** Fetch the raw platform specific reset reason register value. + * + * This function must return the raw contents of the system reset reason + * registers cast to a uint32_t value. If the platform contains reset reasons + * that span multiple registers/addresses, the value should be concatenated into + * the return type. + * + * This function is not idempotent; there is no guarantee the system + * reset reason will not be cleared between calls to this function altering the + * return value between calls. + * + * @return value containing the reset reason register for the given platform. + * If the platform contains reset reasons across multiple registers, they + * will be concatenated here. + */ +uint32_t hal_reset_reason_get_raw(void); + +/** Clear the reset reason from registers. + * + * Reset the value of the reset status registers. The reset reason persists + * between system resets on certain platforms, so the registers should be cleared + * before the system resets. Failing to do so may make it difficult to determine + * the cause of any subsequent system resets. + */ +void hal_reset_reason_clear(void); + +/** Fill the given reset_reason_capabilities_t instance according to platform capabilities. + */ +void hal_reset_reason_get_capabilities(reset_reason_capabilities_t *cap); + +/**@}*/ + +#ifdef __cplusplus +} +#endif + +#endif // DEVICE_RESET_REASON + +#endif // MBED_RESET_REASON_API_H + +/** @}*/ diff --git a/hal/include/hal/rtc_api.h b/hal/include/hal/rtc_api.h new file mode 100644 index 0000000..5685f88 --- /dev/null +++ b/hal/include/hal/rtc_api.h @@ -0,0 +1,188 @@ +/* mbed Microcontroller Library + * Copyright (c) 2006-2013 ARM Limited + * 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. + */ + +/** \addtogroup hal */ +/** @{*/ + +#ifndef MBED_RTC_API_H +#define MBED_RTC_API_H + +#include "device.h" + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \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 -m -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 + * + * 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); + +/** Check if the RTC has the time set and is counting + * + * @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 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); + +/** Write the current time in seconds to the RTC peripheral + * + * @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); + +/**@}*/ + +#ifdef __cplusplus +} +#endif + +#endif + +/** @}*/ diff --git a/hal/include/hal/serial_api.h b/hal/include/hal/serial_api.h new file mode 100644 index 0000000..78a1ee8 --- /dev/null +++ b/hal/include/hal/serial_api.h @@ -0,0 +1,466 @@ + +/** \addtogroup hal */ +/** @{*/ +/* mbed Microcontroller Library + * Copyright (c) 2006-2013 ARM Limited + * 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. + */ +#ifndef MBED_SERIAL_API_H +#define MBED_SERIAL_API_H + +#include "device.h" +#include "pinmap.h" +#include "hal/buffer.h" +#include "hal/dma_api.h" + +#if DEVICE_SERIAL + +#define SERIAL_EVENT_TX_SHIFT (2) +#define SERIAL_EVENT_RX_SHIFT (8) + +#define SERIAL_EVENT_TX_MASK (0x00FC) +#define SERIAL_EVENT_RX_MASK (0x3F00) + +#define SERIAL_EVENT_ERROR (1 << 1) + +/** + * @defgroup SerialTXEvents Serial TX Events Macros + * + * @{ + */ +#define SERIAL_EVENT_TX_COMPLETE (1 << (SERIAL_EVENT_TX_SHIFT + 0)) +#define SERIAL_EVENT_TX_ALL (SERIAL_EVENT_TX_COMPLETE) +/**@}*/ + +/** + * @defgroup SerialRXEvents Serial RX Events Macros + * + * @{ + */ +#define SERIAL_EVENT_RX_COMPLETE (1 << (SERIAL_EVENT_RX_SHIFT + 0)) +#define SERIAL_EVENT_RX_OVERRUN_ERROR (1 << (SERIAL_EVENT_RX_SHIFT + 1)) +#define SERIAL_EVENT_RX_FRAMING_ERROR (1 << (SERIAL_EVENT_RX_SHIFT + 2)) +#define SERIAL_EVENT_RX_PARITY_ERROR (1 << (SERIAL_EVENT_RX_SHIFT + 3)) +#define SERIAL_EVENT_RX_OVERFLOW (1 << (SERIAL_EVENT_RX_SHIFT + 4)) +#define SERIAL_EVENT_RX_CHARACTER_MATCH (1 << (SERIAL_EVENT_RX_SHIFT + 5)) +#define SERIAL_EVENT_RX_ALL (SERIAL_EVENT_RX_OVERFLOW | SERIAL_EVENT_RX_PARITY_ERROR | \ + SERIAL_EVENT_RX_FRAMING_ERROR | SERIAL_EVENT_RX_OVERRUN_ERROR | \ + SERIAL_EVENT_RX_COMPLETE | SERIAL_EVENT_RX_CHARACTER_MATCH) +/**@}*/ + +#define SERIAL_RESERVED_CHAR_MATCH (255) + +typedef enum { + ParityNone = 0, + ParityOdd = 1, + ParityEven = 2, + ParityForced1 = 3, + ParityForced0 = 4 +} SerialParity; + +/** Serial interrupt sources + */ +typedef enum { + RxIrq, /**< Receive Data Register Full */ + TxIrq /**< Transmit Data Register Empty */ +} SerialIrq; + +typedef enum { + FlowControlNone, + FlowControlRTS, + FlowControlCTS, + FlowControlRTSCTS +} FlowControl; + +typedef void (*uart_irq_handler)(uint32_t id, SerialIrq event); + +#if DEVICE_SERIAL_ASYNCH +/** Asynch serial HAL structure + */ +typedef struct { + struct serial_s serial; /**< Target specific serial structure */ + struct buffer_s tx_buff; /**< TX buffer */ + struct buffer_s rx_buff; /**< RX buffer */ + uint8_t char_match; /**< Character to be matched */ + uint8_t char_found; /**< State of the matched character */ +} serial_t; + +#else +/** Non-asynch serial HAL structure + */ +typedef struct serial_s serial_t; + +#endif + +typedef struct { + int peripheral; + PinName tx_pin; + int tx_function; + PinName rx_pin; + int rx_function; + bool stdio_config; +} serial_pinmap_t; + +typedef struct { + int peripheral; + PinName tx_flow_pin; + int tx_flow_function; + PinName rx_flow_pin; + int rx_flow_function; +} serial_fc_pinmap_t; + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \defgroup hal_GeneralSerial Serial Configuration Functions + * + * # Defined behavior + * * ::serial_init initializes the ::serial_t + * * ::serial_init sets the default parameters for serial peripheral (9600 bps, 8N1 format) + * * ::serial_init configures the specified pins + * * ::serial_free releases the serial peripheral + * * ::serial_baud configures the baud rate + * * at least 9600 bps the baud rate must be supported + * * ::serial_format configures the transmission format (number of bits, parity and the number of stop bits) + * * at least 8N1 format must be supported + * * ::serial_irq_handler registers the interrupt handler which will be invoked when the interrupt fires. + * * ::serial_irq_set enables or disables the serial RX or TX IRQ. + * * If `RxIrq` is enabled by ::serial_irq_set, ::serial_irq_handler will be invoked whenever + * Receive Data Register Full IRQ is generated. + * * If `TxIrq` is enabled by ::serial_irq_set, ::serial_irq_handler will be invoked whenever + * Transmit Data Register Empty IRQ is generated. + * * If the interrupt condition holds true, when the interrupt is enabled with ::serial_irq_set, + * the ::serial_irq_handler is called instantly. + * * ::serial_getc returns the character from serial buffer. + * * ::serial_getc is a blocking call (waits for the character). + * * ::serial_putc sends a character. + * * ::serial_putc is a blocking call (waits for a peripheral to be available). + * * ::serial_readable returns non-zero value if a character can be read, 0 otherwise. + * * ::serial_writable returns non-zero value if a character can be written, 0 otherwise. + * * ::serial_clear clears the ::serial_t RX/TX buffers + * * ::serial_break_set sets the break signal. + * * ::serial_break_clear clears the break signal. + * * ::serial_pinout_tx configures the TX pin as an output (to be used in half-duplex mode). + * * ::serial_set_flow_control configures serial flow control. + * * ::serial_set_flow_control sets flow control in the hardware if a serial peripheral supports it, + * otherwise software emulation is used. + * * ::serial_tx_asynch starts the serial asynchronous transfer. + * * ::serial_tx_asynch writes `tx_length` bytes from the `tx` to the bus. + * * ::serial_tx_asynch must support 8 data bits + * * The callback given to ::serial_tx_asynch is invoked when the transfer completes. + * * ::serial_tx_asynch specifies the logical OR of events to be registered. + * * The ::serial_tx_asynch function may use the `DMAUsage` hint to select the appropriate async algorithm. + * * ::serial_rx_asynch starts the serial asynchronous transfer. + * * ::serial_rx_asynch reads `rx_length` bytes to the `rx` buffer. + * * ::serial_rx_asynch must support 8 data bits + * * The callback given to ::serial_rx_asynch is invoked when the transfer completes. + * * ::serial_rx_asynch specifies the logical OR of events to be registered. + * * The ::serial_rx_asynch function may use the `DMAUsage` hint to select the appropriate async algorithm. + * * ::serial_rx_asynch specifies a character in range 0-254 to be matched, 255 is a reserved value. + * * If SERIAL_EVENT_RX_CHARACTER_MATCH event is not registered, the `char_match` is ignored. + * * The SERIAL_EVENT_RX_CHARACTER_MATCH event is set in the callback when SERIAL_EVENT_RX_CHARACTER_MATCH event is + * registered AND `char_match` is present in the received data. + * * ::serial_tx_active returns non-zero if the TX transaction is ongoing, 0 otherwise. + * * ::serial_rx_active returns non-zero if the RX transaction is ongoing, 0 otherwise. + * * ::serial_irq_handler_asynch returns event flags if a transfer termination condition was met, otherwise returns 0. + * * ::serial_irq_handler_asynch takes no longer than one packet transfer time (packet_bits / baudrate) to execute. + * * ::serial_tx_abort_asynch aborts the ongoing TX transaction. + * * ::serial_tx_abort_asynch disables the enabled interupt for TX. + * * ::serial_tx_abort_asynch flushes the TX hardware buffer if TX FIFO is used. + * * ::serial_rx_abort_asynch aborts the ongoing RX transaction. + * * ::serial_rx_abort_asynch disables the enabled interupt for RX. + * * ::serial_rx_abort_asynch flushes the TX hardware buffer if RX FIFO is used. + * * Correct operation guaranteed when interrupt latency is shorter than one packet transfer time (packet_bits / baudrate) + * if the flow control is not used. + * * Correct operation guaranteed regardless of interrupt latency if the flow control is used. + * + * # Undefined behavior + * * Calling ::serial_init multiple times on the same `serial_t` without ::serial_free. + * * Passing invalid pin to ::serial_init, ::serial_pinout_tx. + * * Calling any function other than ::serial_init on am uninitialized or freed `serial_t`. + * * Passing an invalid pointer as `obj` to any function. + * * Passing an invalid pointer as `handler` to ::serial_irq_handler, ::serial_tx_asynch, ::serial_rx_asynch. + * * Calling ::serial_tx_abort while no async TX transfer is being processed. + * * Calling ::serial_rx_abort while no async RX transfer is being processed. + * * Devices behavior is undefined when the interrupt latency is longer than one packet transfer time + * (packet_bits / baudrate) if the flow control is not used. + * @{ + */ + +/** + * \defgroup hal_GeneralSerial_tests Serial hal tests + * The Serial HAL tests ensure driver conformance to defined behavior. + * + * To run the Serial hal tests use the command: + * + * mbed test -t -m -n tests-mbed_hal_fpga_ci_test_shield-uart + * + */ + +/** Initialize the serial peripheral. It sets the default parameters for serial + * peripheral, and configures its specifieds pins. + * + * @param obj The serial object + * @param tx The TX pin name + * @param rx The RX pin name + */ +void serial_init(serial_t *obj, PinName tx, PinName rx); + +/** Initialize the serial peripheral. It sets the default parameters for serial + * peripheral, and configures its specifieds pins. + * + * @param obj The serial object + * @param pinmap pointer to structure which holds static pinmap + */ +void serial_init_direct(serial_t *obj, const serial_pinmap_t *pinmap); + + +/** Release the serial peripheral, not currently invoked. It requires further + * resource management. + * + * @param obj The serial object + */ +void serial_free(serial_t *obj); + +/** Configure the baud rate + * + * @param obj The serial object + * @param baudrate The baud rate to be configured + */ +void serial_baud(serial_t *obj, int baudrate); + +/** Configure the format. Set the number of bits, parity and the number of stop bits + * + * @param obj The serial object + * @param data_bits The number of data bits + * @param parity The parity + * @param stop_bits The number of stop bits + */ +void serial_format(serial_t *obj, int data_bits, SerialParity parity, int stop_bits); + +/** The serial interrupt handler registration + * + * @param obj The serial object + * @param handler The interrupt handler which will be invoked when the interrupt fires + * @param id The SerialBase object + */ +void serial_irq_handler(serial_t *obj, uart_irq_handler handler, uint32_t id); + +/** Configure serial interrupt. This function is used for word-approach + * + * @param obj The serial object + * @param irq The serial IRQ type (RX or TX) + * @param enable Set to non-zero to enable events, or zero to disable them + */ +void serial_irq_set(serial_t *obj, SerialIrq irq, uint32_t enable); + +/** Get character. This is a blocking call, waiting for a character + * + * @param obj The serial object + */ +int serial_getc(serial_t *obj); + +/** Send a character. This is a blocking call, waiting for a peripheral to be available + * for writing + * + * @param obj The serial object + * @param c The character to be sent + */ +void serial_putc(serial_t *obj, int c); + +/** Check if the serial peripheral is readable + * + * @param obj The serial object + * @return Non-zero value if a character can be read, 0 if nothing to read + */ +int serial_readable(serial_t *obj); + +/** Check if the serial peripheral is writable + * + * @param obj The serial object + * @return Non-zero value if a character can be written, 0 otherwise. + */ +int serial_writable(serial_t *obj); + +/** Clear the serial peripheral + * + * @param obj The serial object + */ +void serial_clear(serial_t *obj); + +/** Set the break + * + * @param obj The serial object + */ +void serial_break_set(serial_t *obj); + +/** Clear the break + * + * @param obj The serial object + */ +void serial_break_clear(serial_t *obj); + +/** Configure the TX pin for UART function. + * + * @param tx The pin name used for TX + */ +void serial_pinout_tx(PinName tx); + +#if DEVICE_SERIAL_FC +/** Configure the serial for the flow control. It sets flow control in the hardware + * if a serial peripheral supports it, otherwise software emulation is used. + * + * @param obj The serial object + * @param type The type of the flow control. Look at the available FlowControl types. + * @param rxflow The TX pin name + * @param txflow The RX pin name + */ +void serial_set_flow_control(serial_t *obj, FlowControl type, PinName rxflow, PinName txflow); + +/** Configure the serial for the flow control. It sets flow control in the hardware + * if a serial peripheral supports it, otherwise software emulation is used. + * + * @param obj The serial object + * @param type The type of the flow control. Look at the available FlowControl types. + * @param pinmap Pointer to structure which holds static pinmap + */ +void serial_set_flow_control_direct(serial_t *obj, FlowControl type, const serial_fc_pinmap_t *pinmap); +#endif + +/** Get the pins that support Serial TX + * + * Return a PinMap array of pins that support Serial TX. The + * array is terminated with {NC, NC, 0}. + * + * @return PinMap array + */ +const PinMap *serial_tx_pinmap(void); + +/** Get the pins that support Serial RX + * + * Return a PinMap array of pins that support Serial RX. The + * array is terminated with {NC, NC, 0}. + * + * @return PinMap array + */ +const PinMap *serial_rx_pinmap(void); + +#if DEVICE_SERIAL_FC +/** Get the pins that support Serial CTS + * + * Return a PinMap array of pins that support Serial CTS. The + * array is terminated with {NC, NC, 0}. + * + * @return PinMap array + */ +const PinMap *serial_cts_pinmap(void); + +/** Get the pins that support Serial RTS + * + * Return a PinMap array of pins that support Serial RTS. The + * array is terminated with {NC, NC, 0}. + * + * @return PinMap array + */ +const PinMap *serial_rts_pinmap(void); +#endif + +#if DEVICE_SERIAL_ASYNCH + +/**@}*/ + +/** + * \defgroup hal_AsynchSerial Asynchronous Serial Hardware Abstraction Layer + * @{ + */ + +/** Begin asynchronous TX transfer. The used buffer is specified in the serial object, + * tx_buff + * + * @param obj The serial object + * @param tx The transmit buffer + * @param tx_length The number of bytes to transmit + * @param tx_width Deprecated argument + * @param handler The serial handler + * @param event The logical OR of events to be registered + * @param hint A suggestion for how to use DMA with this transfer + * @return Returns number of data transfered, otherwise returns 0 + */ +int serial_tx_asynch(serial_t *obj, const void *tx, size_t tx_length, uint8_t tx_width, uint32_t handler, uint32_t event, DMAUsage hint); + +/** Begin asynchronous RX transfer (enable interrupt for data collecting) + * The used buffer is specified in the serial object - rx_buff + * + * @param obj The serial object + * @param rx The receive buffer + * @param rx_length The number of bytes to receive + * @param rx_width Deprecated argument + * @param handler The serial handler + * @param event The logical OR of events to be registered + * @param char_match A character in range 0-254 to be matched + * @param hint A suggestion for how to use DMA with this transfer + */ +void serial_rx_asynch(serial_t *obj, void *rx, size_t rx_length, uint8_t rx_width, uint32_t handler, uint32_t event, uint8_t char_match, DMAUsage hint); + +/** Attempts to determine if the serial peripheral is already in use for TX + * + * @param obj The serial object + * @return Non-zero if the RX transaction is ongoing, 0 otherwise + */ +uint8_t serial_tx_active(serial_t *obj); + +/** Attempts to determine if the serial peripheral is already in use for RX + * + * @param obj The serial object + * @return Non-zero if the RX transaction is ongoing, 0 otherwise + */ +uint8_t serial_rx_active(serial_t *obj); + +/** The asynchronous TX and RX handler. + * + * @param obj The serial object + * @return Returns event flags if an RX transfer termination condition was met; otherwise returns 0 + */ +int serial_irq_handler_asynch(serial_t *obj); + +/** Abort the ongoing TX transaction. It disables the enabled interupt for TX and + * flushes the TX hardware buffer if TX FIFO is used + * + * @param obj The serial object + */ +void serial_tx_abort_asynch(serial_t *obj); + +/** Abort the ongoing RX transaction. It disables the enabled interrupt for RX and + * flushes the RX hardware buffer if RX FIFO is used + * + * @param obj The serial object + */ +void serial_rx_abort_asynch(serial_t *obj); + +/**@}*/ + +#endif + +#ifdef __cplusplus +} +#endif + +#endif + +#endif + +/** @}*/ diff --git a/hal/include/hal/sleep_api.h b/hal/include/hal/sleep_api.h new file mode 100644 index 0000000..1dd2d0d --- /dev/null +++ b/hal/include/hal/sleep_api.h @@ -0,0 +1,103 @@ + +/** \addtogroup hal */ +/** @{*/ +/* mbed Microcontroller Library + * Copyright (c) 2006-2013 ARM Limited + * 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. + */ +#ifndef MBED_SLEEP_API_H +#define MBED_SLEEP_API_H + +#include "device.h" + +#if DEVICE_SLEEP + +#ifdef __cplusplus +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 -m -n tests-mbed_hal-sleep* + * + */ + +/** Send the microcontroller to sleep + * + * 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. + * + * 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 high frequency clocks. + * All state is still maintained. + * + * The processor can only be woken up by low power ticker, RTC, an external interrupt on a pin or a watchdog timer. + * + * The wake-up time shall be less than 10 ms. + */ +void hal_deepsleep(void); + +/**@}*/ + +#ifdef __cplusplus +} +#endif + +#endif + +#endif + +/**@}*/ diff --git a/hal/include/hal/spi_api.h b/hal/include/hal/spi_api.h new file mode 100644 index 0000000..f67b6ef --- /dev/null +++ b/hal/include/hal/spi_api.h @@ -0,0 +1,427 @@ + +/** \addtogroup hal */ +/** @{*/ +/* mbed Microcontroller Library + * Copyright (c) 2006-2013 ARM Limited + * 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. + */ +#ifndef MBED_SPI_API_H +#define MBED_SPI_API_H + +#include "device.h" +#include "pinmap.h" +#include "hal/dma_api.h" +#include "hal/buffer.h" + +#if DEVICE_SPI + +#define SPI_EVENT_ERROR (1 << 1) +#define SPI_EVENT_COMPLETE (1 << 2) +#define SPI_EVENT_RX_OVERFLOW (1 << 3) +#define SPI_EVENT_ALL (SPI_EVENT_ERROR | SPI_EVENT_COMPLETE | SPI_EVENT_RX_OVERFLOW) + +#define SPI_EVENT_INTERNAL_TRANSFER_COMPLETE (1 << 30) // Internal flag to report that an event occurred + +#define SPI_FILL_WORD (0xFFFF) +#define SPI_FILL_CHAR (0xFF) + +#if DEVICE_SPI_ASYNCH +/** Asynch SPI HAL structure + */ +typedef struct { + struct spi_s spi; /**< Target specific SPI structure */ + struct buffer_s tx_buff; /**< Tx buffer */ + struct buffer_s rx_buff; /**< Rx buffer */ +} spi_t; + +#else +/** Non-asynch SPI HAL structure + */ +typedef struct spi_s spi_t; + +#endif + +typedef struct { + int peripheral; + PinName mosi_pin; + int mosi_function; + PinName miso_pin; + int miso_function; + PinName sclk_pin; + int sclk_function; + PinName ssel_pin; + int ssel_function; +} spi_pinmap_t; + +/** + * Describes the capabilities of a SPI peripherals + */ +typedef struct { + /** Minimum frequency supported must be set by target device and it will be assessed during + * testing. + */ + uint32_t minimum_frequency; + /** Maximum frequency supported must be set by target device and it will be assessed during + * testing. + */ + uint32_t maximum_frequency; + /** Each bit represents the corresponding word length. lsb => 1bit, msb => 32bit. */ + uint32_t word_length; + uint16_t slave_delay_between_symbols_ns; /**< specifies required number of ns between transmission of successive symbols in slave mode. */ + uint8_t clk_modes; /**< specifies supported modes from spi_mode_t. Each bit represents the corresponding mode. */ + bool support_slave_mode; /**< If true, the device can handle SPI slave mode using hardware management on the specified ssel pin. */ + bool hw_cs_handle; /**< If true, in SPI master mode Chip Select can be handled by hardware. */ + bool async_mode; /**< If true, in async mode is supported. */ + bool tx_rx_buffers_equal_length; /**< If true, rx and tx buffers must have the same length. */ +} spi_capabilities_t; + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \defgroup hal_GeneralSPI SPI Configuration Functions + * + * # Defined behavior + * * ::spi_init initializes the spi_t control structure + * * ::spi_init configures the pins used by SPI - Verified by ::fpga_spi_test_init_free, ::fpga_spi_test_common_no_ss and ::fpga_spi_test_common + * * ::spi_get_capabilities() fills the given `spi_capabilities_t` instance - Verified by ::fpga_spi_test_common_no_ss and ::fpga_spi_test_common + * * ::spi_get_capabilities() should consider the `ssel` pin when evaluation the `support_slave_mode` and `hw_cs_handle` capability - TBD (basic test) + * * ::spi_get_capabilities(): if the given `ssel` pin cannot be managed by hardware, `support_slave_mode` and `hw_cs_handle` should be false - TBD (basic test) + * * At least a symbol width of 8bit must be supported - Verified by ::fpga_spi_test_common_no_ss and ::fpga_spi_test_common + * * The supported frequency range must include the range [0.2..2] MHz - Verified by ::fpga_spi_test_common_no_ss and ::fpga_spi_test_common + * * ::spi_free returns the pins owned by the SPI object to their reset state - Verified by ::fpga_spi_test_init_free + * * ::spi_format sets the number of bits per frame - Verified by ::fpga_spi_test_common_no_ss and ::fpga_spi_test_common + * * ::spi_format configures clock polarity and phase - Verified by ::fpga_spi_test_common_no_ss and ::fpga_spi_test_common + * * ::spi_format configures master/slave mode - Verified by ::fpga_spi_test_common_no_ss and ::fpga_spi_test_common; slave mode - TBD + * * ::spi_frequency sets the SPI baud rate - Verified by ::fpga_spi_test_common_no_ss and ::fpga_spi_test_common + * * ::spi_master_write writes a symbol out in master mode and receives a symbol - Verified by ::fpga_spi_test_common_no_ss and ::fpga_spi_test_common + * * ::spi_master_block_write writes `tx_length` words to the bus - Verified by ::fpga_spi_test_common_no_ss and ::fpga_spi_test_common + * * ::spi_master_block_write reads `rx_length` words from the bus - Verified by ::fpga_spi_test_common_no_ss and ::fpga_spi_test_common + * * ::spi_master_block_write returns the maximum of tx_length and rx_length - Verified by ::fpga_spi_test_common_no_ss and ::fpga_spi_test_common + * * ::spi_master_block_write specifies the write_fill which is default data transmitted while performing a read - Verified by ::fpga_spi_test_common_no_ss and ::fpga_spi_test_common + * * ::spi_get_module returns the SPI module number - TBD (basic test) + * * ::spi_slave_read returns a received value out of the SPI receive buffer in slave mode - TBD (SPI slave test) + * * ::spi_slave_read blocks until a value is available - TBD (SPI slave test) + * * ::spi_slave_write writes a value to the SPI peripheral in slave mode - TBD (SPI slave test) + * * ::spi_slave_write blocks until the SPI peripheral can be written to - TBD (SPI slave test) + * * ::spi_busy returns non-zero if the peripheral is currently transmitting, 0 otherwise - TBD (basic test) + * * ::spi_master_transfer starts the SPI asynchronous transfer - Verified by ::fpga_spi_test_common_no_ss and ::fpga_spi_test_common + * * ::spi_master_transfer writes `tx_len` words to the bus - Verified by ::fpga_spi_test_common_no_ss and ::fpga_spi_test_common + * * ::spi_master_transfer reads `rx_len` words from the bus - Verified by ::fpga_spi_test_common_no_ss and ::fpga_spi_test_common + * * ::spi_master_transfer specifies the bit width of buffer words - Verified by ::fpga_spi_test_common_no_ss and ::fpga_spi_test_common + * * The callback given to ::spi_master_transfer is invoked when the transfer completes (with a success or an error) - Verified by ::fpga_spi_test_common_no_ss and ::fpga_spi_test_common + * * ::spi_master_transfer specifies the logical OR of events to be registered - Verified by ::fpga_spi_test_common_no_ss and ::fpga_spi_test_common + * * The ::spi_master_transfer function may use the `DMAUsage` hint to select the appropriate async algorithm - Not testable + * * ::spi_irq_handler_asynch reads the received values out of the RX FIFO - Verified by ::fpga_spi_test_common_no_ss and ::fpga_spi_test_common + * * ::spi_irq_handler_asynch writes values into the TX FIFO - Verified by ::fpga_spi_test_common_no_ss and ::fpga_spi_test_common + * * ::spi_irq_handler_asynch checks for transfer termination conditions, such as buffer overflows or transfer complete - Verified by ::fpga_spi_test_common_no_ss and ::fpga_spi_test_common + * * ::spi_irq_handler_asynch returns event flags if a transfer termination condition was met, otherwise 0 - Verified by ::fpga_spi_test_common_no_ss and ::fpga_spi_test_common + * * ::spi_abort_asynch aborts an on-going async transfer - TBD (basic test) + * * ::spi_active returns non-zero if the SPI port is active or zero if it is not - TBD (basic test) + * + * # Undefined behavior + * * Calling ::spi_init multiple times on the same `spi_t` without ::spi_free + * * Calling any function other than ::spi_init on a non-initialized or freed `spi_t` + * * Passing pins that cannot be on the same peripheral + * * Passing an invalid pointer as `obj` to any function + * * Passing an invalid pointer as `handler` to ::spi_master_transfer + * * Calling ::spi_abort while no async transfer is being processed (no transfer or a synchronous transfer) + * + * @{ + */ + +/** + * \defgroup hal_GeneralSPI_tests SPI hal tests + * The SPI HAL tests ensure driver conformance to defined behaviour. + * + * To run the SPI hal tests use the command: + * + * mbed test -t -m -n tests-mbed_hal_fpga_ci_test_shield-spi + * + */ + +#ifdef DEVICE_SPI_COUNT +/** + * Returns a variant of the SPIName enum uniquely identifying a SPI peripheral of the device. + * @param[in] mosi The pin to use for MOSI + * @param[in] miso The pin to use for MISO + * @param[in] sclk The pin to use for SCLK + * @return An SPI peripheral identifier + */ +SPIName spi_get_peripheral_name(PinName mosi, PinName miso, PinName mclk); +#endif + +/** + * Fills the given spi_capabilities_t structure with the capabilities of the given peripheral. + */ +void spi_get_capabilities(PinName ssel, bool slave, spi_capabilities_t *cap); + +/** Initialize the SPI peripheral + * + * Configures the pins used by SPI, sets a default format and frequency, and enables the peripheral + * @param[out] obj The SPI object to initialize + * @param[in] pinmap pointer to structure which holds static pinmap + */ +void spi_init_direct(spi_t *obj, const spi_pinmap_t *pinmap); + +/** Initialize the SPI peripheral + * + * Configures the pins used by SPI, sets a default format and frequency, and enables the peripheral + * @param[out] obj The SPI object to initialize + * @param[in] mosi The pin to use for MOSI + * @param[in] miso The pin to use for MISO + * @param[in] sclk The pin to use for SCLK + * @param[in] ssel The pin to use for SSEL + */ +void spi_init(spi_t *obj, PinName mosi, PinName miso, PinName sclk, PinName ssel); + +/** Release a SPI object + * + * TODO: spi_free is currently unimplemented + * This will require reference counting at the C++ level to be safe + * + * Return the pins owned by the SPI object to their reset state + * Disable the SPI peripheral + * Disable the SPI clock + * @param[in] obj The SPI object to deinitialize + */ +void spi_free(spi_t *obj); + +/** Configure the SPI format + * + * Set the number of bits per frame, configure clock polarity and phase, shift order and master/slave mode. + * The default bit order is MSB. + * @param[in,out] obj The SPI object to configure + * @param[in] bits The number of bits per frame + * @param[in] mode The SPI mode (clock polarity, phase, and shift direction) + * @param[in] slave Zero for master mode or non-zero for slave mode + */ +void spi_format(spi_t *obj, int bits, int mode, int slave); + +/** Set the SPI baud rate + * + * Actual frequency may differ from the desired frequency due to available dividers and bus clock + * Configures the SPI peripheral's baud rate + * @param[in,out] obj The SPI object to configure + * @param[in] hz The baud rate in Hz + */ +void spi_frequency(spi_t *obj, int hz); + +/**@}*/ +/** + * \defgroup SynchSPI Synchronous SPI Hardware Abstraction Layer + * @{ + */ + +/** Write a byte out in master mode and receive a value + * + * @param[in] obj The SPI peripheral to use for sending + * @param[in] value The value to send + * @return Returns the value received during send + */ +int spi_master_write(spi_t *obj, int value); + +/** Write a block out in master mode and receive a value + * + * The total number of bytes sent and received will be the maximum of + * tx_length and rx_length. The bytes written will be padded with the + * value 0xff. + * + * @param[in] obj The SPI peripheral to use for sending + * @param[in] tx_buffer Pointer to the byte-array of data to write to the device + * @param[in] tx_length Number of bytes to write, may be zero + * @param[in] rx_buffer Pointer to the byte-array of data to read from the device + * @param[in] rx_length Number of bytes to read, may be zero + * @param[in] write_fill Default data transmitted while performing a read + * @returns + * The number of bytes written and read from the device. This is + * maximum of tx_length and rx_length. + */ +int spi_master_block_write(spi_t *obj, const char *tx_buffer, int tx_length, char *rx_buffer, int rx_length, char write_fill); + +/** Check if a value is available to read + * + * @param[in] obj The SPI peripheral to check + * @return non-zero if a value is available + */ +int spi_slave_receive(spi_t *obj); + +/** Get a received value out of the SPI receive buffer in slave mode + * + * Blocks until a value is available + * @param[in] obj The SPI peripheral to read + * @return The value received + */ +int spi_slave_read(spi_t *obj); + +/** Write a value to the SPI peripheral in slave mode + * + * Blocks until the SPI peripheral can be written to + * @param[in] obj The SPI peripheral to write + * @param[in] value The value to write + */ +void spi_slave_write(spi_t *obj, int value); + +/** Checks if the specified SPI peripheral is in use + * + * @param[in] obj The SPI peripheral to check + * @return non-zero if the peripheral is currently transmitting + */ +int spi_busy(spi_t *obj); + +/** Get the module number + * + * @param[in] obj The SPI peripheral to check + * @return The module number + */ +uint8_t spi_get_module(spi_t *obj); + +/** Get the pins that support SPI MOSI + * + * Return a PinMap array of pins that support SPI MOSI in + * master mode. The array is terminated with {NC, NC, 0}. + * + * @return PinMap array + */ +const PinMap *spi_master_mosi_pinmap(void); + +/** Get the pins that support SPI MISO + * + * Return a PinMap array of pins that support SPI MISO in + * master mode. The array is terminated with {NC, NC, 0}. + * + * @return PinMap array + */ +const PinMap *spi_master_miso_pinmap(void); + +/** Get the pins that support SPI CLK + * + * Return a PinMap array of pins that support SPI CLK in + * master mode. The array is terminated with {NC, NC, 0}. + * + * @return PinMap array + */ +const PinMap *spi_master_clk_pinmap(void); + +/** Get the pins that support SPI CS + * + * Return a PinMap array of pins that support SPI CS in + * master mode. The array is terminated with {NC, NC, 0}. + * + * @return PinMap array + */ +const PinMap *spi_master_cs_pinmap(void); + +/** Get the pins that support SPI MOSI + * + * Return a PinMap array of pins that support SPI MOSI in + * slave mode. The array is terminated with {NC, NC, 0}. + * + * @return PinMap array + */ +const PinMap *spi_slave_mosi_pinmap(void); + +/** Get the pins that support SPI MISO + * + * Return a PinMap array of pins that support SPI MISO in + * slave mode. The array is terminated with {NC, NC, 0}. + * + * @return PinMap array + */ +const PinMap *spi_slave_miso_pinmap(void); + +/** Get the pins that support SPI CLK + * + * Return a PinMap array of pins that support SPI CLK in + * slave mode. The array is terminated with {NC, NC, 0}. + * + * @return PinMap array + */ +const PinMap *spi_slave_clk_pinmap(void); + +/** Get the pins that support SPI CS + * + * Return a PinMap array of pins that support SPI CS in + * slave mode. The array is terminated with {NC, NC, 0}. + * + * @return PinMap array + */ +const PinMap *spi_slave_cs_pinmap(void); + +/**@}*/ + +#if DEVICE_SPI_ASYNCH +/** + * \defgroup AsynchSPI Asynchronous SPI Hardware Abstraction Layer + * @{ + */ + +/** Begin the SPI transfer. Buffer pointers and lengths are specified in tx_buff and rx_buff + * + * @param[in] obj The SPI object that holds the transfer information + * @param[in] tx The transmit buffer + * @param[in] tx_length The number of bytes to transmit + * @param[in] rx The receive buffer + * @param[in] rx_length The number of bytes to receive + * @param[in] bit_width The bit width of buffer words + * @param[in] event The logical OR of events to be registered + * @param[in] handler SPI interrupt handler + * @param[in] hint A suggestion for how to use DMA with this transfer + */ +void spi_master_transfer(spi_t *obj, const void *tx, size_t tx_length, void *rx, size_t rx_length, uint8_t bit_width, uint32_t handler, uint32_t event, DMAUsage hint); + +/** The asynchronous IRQ handler + * + * Reads the received values out of the RX FIFO, writes values into the TX FIFO and checks for transfer termination + * conditions, such as buffer overflows or transfer complete. + * @param[in] obj The SPI object that holds the transfer information + * @return Event flags if a transfer termination condition was met; otherwise 0. + */ +uint32_t spi_irq_handler_asynch(spi_t *obj); + +/** Attempts to determine if the SPI peripheral is already in use + * + * If a temporary DMA channel has been allocated, peripheral is in use. + * If a permanent DMA channel has been allocated, check if the DMA channel is in use. If not, proceed as though no DMA + * channel were allocated. + * If no DMA channel is allocated, check whether tx and rx buffers have been assigned. For each assigned buffer, check + * if the corresponding buffer position is less than the buffer length. If buffers do not indicate activity, check if + * there are any bytes in the FIFOs. + * @param[in] obj The SPI object to check for activity + * @return Non-zero if the SPI port is active or zero if it is not. + */ +uint8_t spi_active(spi_t *obj); + +/** Abort an SPI transfer + * + * @param obj The SPI peripheral to stop + */ +void spi_abort_asynch(spi_t *obj); + + +#endif + +/**@}*/ + +#ifdef __cplusplus +} +#endif // __cplusplus + +#endif // SPI_DEVICE + +#endif // MBED_SPI_API_H + +/** @}*/ diff --git a/hal/include/hal/static_pinmap.h b/hal/include/hal/static_pinmap.h new file mode 100644 index 0000000..fafed9c --- /dev/null +++ b/hal/include/hal/static_pinmap.h @@ -0,0 +1,363 @@ +/* mbed Microcontroller Library + * Copyright (c) 2018-2019 ARM Limited + * 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. + */ +#ifndef STATIC_PINMAP_H +#define STATIC_PINMAP_H + +#include "PinNames.h" +#include "spi_api.h" +#include "pwmout_api.h" +#include "analogin_api.h" +#include "analogout_api.h" +#include "i2c_api.h" +#include "serial_api.h" +#include "qspi_api.h" +#include "can_api.h" +#include + +#if STATIC_PINMAP_READY +#include "PeripheralPinMaps.h" + + +#if defined(DEVICE_PWMOUT) && defined(PINMAP_PWM) +MSTD_CONSTEXPR_FN_14 PinMap get_pwm_pinmap(const PinName pin) +{ + for (const PinMap &pinmap : PINMAP_PWM) { + if (pinmap.pin == pin) { + return {pin, pinmap.peripheral, pinmap.function}; + } + } + return {NC, (int) NC, (int) NC}; +} +#endif // DEVICE_PWMOUT + +#if defined(DEVICE_ANALOGIN) && defined(PINMAP_ANALOGIN) +MSTD_CONSTEXPR_FN_14 PinMap get_analogin_pinmap(const PinName pin) +{ + for (const PinMap &pinmap : PINMAP_ANALOGIN) { + if (pinmap.pin == pin) { + return {pin, pinmap.peripheral, pinmap.function}; + } + } + +#if PINMAP_ANALOGIN_INTERNAL + for (const PinMap &pinmap : PINMAP_ANALOGIN_INTERNAL) { + if (pinmap.pin == pin) { + return {pin, pinmap.peripheral, pinmap.function}; + } + } +#endif + + return {NC, (int) NC, (int) NC}; +} +#endif // DEVICE_ANALOGIN + +#if defined(DEVICE_ANALOGOUT) && defined(PINMAP_ANALOGOUT) +MSTD_CONSTEXPR_FN_14 PinMap get_analogout_pinmap(const PinName pin) +{ + for (const PinMap &pinmap : PINMAP_ANALOGOUT) { + if (pinmap.pin == pin) { + return {pin, pinmap.peripheral, pinmap.function}; + } + } + return {NC, (int) NC, (int) NC}; +} +#endif // DEVICE_ANALOGOUT + +#if defined(DEVICE_I2C) && defined(PINMAP_I2C_SDA) && defined(PINMAP_I2C_SCL) +MSTD_CONSTEXPR_FN_14 i2c_pinmap_t get_i2c_pinmap(const PinName sda, const PinName scl) +{ + const PinMap *sda_map = nullptr; + for (const PinMap &pinmap : PINMAP_I2C_SDA) { + if (pinmap.pin == sda) { + sda_map = &pinmap; + break; + } + } + + const PinMap *scl_map = nullptr; + for (const PinMap &pinmap : PINMAP_I2C_SCL) { + if (pinmap.pin == scl) { + scl_map = &pinmap; + break; + } + } + + if (!sda_map || !scl_map || sda_map->peripheral != scl_map->peripheral) { + return {(int) NC, NC, (int) NC, NC, (int) NC}; + } + + return {sda_map->peripheral, sda_map->pin, sda_map->function, scl_map->pin, scl_map->function}; +} +#endif //DEVICE_I2C + +#if defined(DEVICE_SERIAL) && defined(PINMAP_UART_TX) && defined(PINMAP_UART_RX) +MSTD_CONSTEXPR_FN_14 serial_pinmap_t get_uart_pinmap(const PinName tx, const PinName rx) +{ + const PinMap *tx_map = nullptr; + for (const PinMap &pinmap : PINMAP_UART_TX) { + if (pinmap.pin == tx) { + tx_map = &pinmap; + break; + } + } + + const PinMap *rx_map = nullptr; + for (const PinMap &pinmap : PINMAP_UART_RX) { + if (pinmap.pin == rx) { + rx_map = &pinmap; + break; + } + } + + if (!tx_map || !rx_map || rx_map->peripheral != tx_map->peripheral) { + return {(int) NC, NC, (int) NC, NC, (int) NC, false}; + } + + if (tx_map->pin == STDIO_UART_TX && rx_map->pin == STDIO_UART_RX) { + return {tx_map->peripheral, tx_map->pin, tx_map->function, rx_map->pin, rx_map->function, true}; + } else { + return {tx_map->peripheral, tx_map->pin, tx_map->function, rx_map->pin, rx_map->function, false}; + } +} + +#if defined(DEVICE_SERIAL_FC) && defined(PINMAP_UART_RTS) && defined(PINMAP_UART_CTS) +MSTD_CONSTEXPR_FN_14 serial_fc_pinmap_t get_uart_fc_pinmap(const PinName rxflow, const PinName txflow) +{ + const PinMap *rts_map = nullptr; + for (const PinMap &pinmap : PINMAP_UART_RTS) { + if (pinmap.pin == rxflow) { + rts_map = &pinmap; + break; + } + } + + const PinMap *cts_map = nullptr; + for (const PinMap &pinmap : PINMAP_UART_CTS) { + if (pinmap.pin == txflow) { + cts_map = &pinmap; + break; + } + } + + if ((!rts_map || !cts_map) || (rts_map->peripheral != cts_map->peripheral)) { + return {(int) NC, NC, (int) NC, NC, (int) NC}; + } + + return {cts_map->peripheral, cts_map->pin, cts_map->function, rts_map->pin, rts_map->function}; +} +#endif // DEVICE_SERIAL_FC +#endif // DEVICE_SERIAL + +#if defined(DEVICE_SPI) && defined(PINMAP_SPI_MOSI) && defined(PINMAP_SPI_MISO) && defined(PINMAP_SPI_SCLK) && defined(PINMAP_SPI_SSEL) +MSTD_CONSTEXPR_FN_14 spi_pinmap_t get_spi_pinmap(const PinName mosi, const PinName miso, const PinName sclk, const PinName ssel) +{ + const PinMap *mosi_map = nullptr; + for (const PinMap &pinmap : PINMAP_SPI_MOSI) { + if (pinmap.pin == mosi) { + mosi_map = &pinmap; + break; + } + } + + const PinMap *miso_map = nullptr; + for (const PinMap &pinmap : PINMAP_SPI_MISO) { + if (pinmap.pin == miso) { + miso_map = &pinmap; + break; + } + } + + const PinMap *sclk_map = nullptr; + for (const PinMap &pinmap : PINMAP_SPI_SCLK) { + if (pinmap.pin == sclk) { + sclk_map = &pinmap; + break; + } + } + + const PinMap *ssel_map = nullptr; + for (const PinMap &pinmap : PINMAP_SPI_SSEL) { + if (pinmap.pin == ssel) { + ssel_map = &pinmap; + break; + } + } + + if ((!mosi_map || !miso_map || !sclk_map || !ssel_map) || + (mosi_map->peripheral != miso_map->peripheral || mosi_map->peripheral != sclk_map->peripheral) || + (ssel_map->pin != NC && mosi_map->peripheral != ssel_map->peripheral)) { + return {(int) NC, NC, (int) NC, NC, (int) NC, NC, (int) NC, NC, (int) NC}; + } + + return {mosi_map->peripheral, mosi_map->pin, mosi_map->function, miso_map->pin, miso_map->function, sclk_map->pin, sclk_map->function, ssel_map->pin, ssel_map->function}; +} +#endif // DEVICE_SPI + +#if defined(DEVICE_CAN) && defined(PINMAP_CAN_RD) && defined(PINMAP_CAN_TD) +MSTD_CONSTEXPR_FN_14 can_pinmap_t get_can_pinmap(const PinName rd, const PinName td) +{ + const PinMap *rd_map = nullptr; + for (const PinMap &pinmap : PINMAP_CAN_RD) { + if (pinmap.pin == rd) { + rd_map = &pinmap; + break; + } + } + + const PinMap *td_map = nullptr; + for (const PinMap &pinmap : PINMAP_CAN_TD) { + if (pinmap.pin == td) { + td_map = &pinmap; + break; + } + } + + if (!rd_map || !td_map || rd_map->peripheral != td_map->peripheral) { + return {(int) NC, NC, (int) NC, NC, (int) NC}; + } + + return {rd_map->peripheral, rd_map->pin, rd_map->function, td_map->pin, td_map->function}; +} +#endif //DEVICE_CAN + +#if defined(DEVICE_QSPI) && defined(PINMAP_QSPI_DATA0) && defined(PINMAP_QSPI_DATA1) && defined(PINMAP_QSPI_DATA2) && defined(PINMAP_QSPI_DATA3) && defined(PINMAP_QSPI_SCLK) && defined(PINMAP_QSPI_SSEL) +MSTD_CONSTEXPR_FN_14 qspi_pinmap_t get_qspi_pinmap(const PinName data0, const PinName data1, const PinName data2, const PinName data3, const PinName sclk, const PinName ssel) +{ + const PinMap *data0_map = nullptr; + for (const PinMap &pinmap : PINMAP_QSPI_DATA0) { + if (pinmap.pin == data0) { + data0_map = &pinmap; + break; + } + } + + const PinMap *data1_map = nullptr; + for (const PinMap &pinmap : PINMAP_QSPI_DATA1) { + if (pinmap.pin == data1) { + data1_map = &pinmap; + break; + } + } + + const PinMap *data2_map = nullptr; + for (const PinMap &pinmap : PINMAP_QSPI_DATA2) { + if (pinmap.pin == data2) { + data2_map = &pinmap; + break; + } + } + + const PinMap *data3_map = nullptr; + for (const PinMap &pinmap : PINMAP_QSPI_DATA3) { + if (pinmap.pin == data3) { + data3_map = &pinmap; + break; + } + } + + const PinMap *sclk_map = nullptr; + for (const PinMap &pinmap : PINMAP_QSPI_SCLK) { + if (pinmap.pin == sclk) { + sclk_map = &pinmap; + break; + } + } + + const PinMap *ssel_map = nullptr; + for (const PinMap &pinmap : PINMAP_QSPI_SSEL) { + if (pinmap.pin == ssel) { + ssel_map = &pinmap; + break; + } + } + + if (!data0_map || !data1_map || !data2_map || !data3_map || !sclk_map || !ssel_map || data0_map->peripheral != data1_map->peripheral || data0_map->peripheral != data2_map->peripheral || data0_map->peripheral != data3_map->peripheral || data0_map->peripheral != sclk_map->peripheral || data0_map->peripheral != ssel_map->peripheral) { + return {(int) NC, NC, (int) NC, NC, (int) NC, NC, (int) NC, NC, (int) NC}; + } + + return {data0_map->peripheral, data0_map->pin, data0_map->function, data1_map->pin, data1_map->function, data2_map->pin, data2_map->function, data3_map->pin, data3_map->function, sclk_map->pin, sclk_map->function, ssel_map->pin, ssel_map->function}; +} +#endif //DEVICE_QSPI + +#else // STATIC_PINMAP_READY + +#if DEVICE_PWMOUT +MSTD_CONSTEXPR_FN_14 PinMap get_pwm_pinmap(const PinName pin) +{ + return {pin, (int) NC, (int) NC}; +} +#endif // DEVICE_PWMOUT + +#if DEVICE_ANALOGIN +MSTD_CONSTEXPR_FN_14 PinMap get_analogin_pinmap(const PinName pin) +{ + return {pin, (int) NC, (int) NC}; +} +#endif // DEVICE_ANALOGIN + +#if DEVICE_ANALOGOUT +MSTD_CONSTEXPR_FN_14 PinMap get_analogout_pinmap(const PinName pin) +{ + return {pin, (int) NC, (int) NC}; +} +#endif // DEVICE_ANALOGOUT + +#if DEVICE_I2C +MSTD_CONSTEXPR_FN_14 i2c_pinmap_t get_i2c_pinmap(const PinName sda, const PinName scl) +{ + return {(int) NC, sda, (int) NC, scl, (int) NC}; +} +#endif //DEVICE_I2C + +#if DEVICE_SERIAL +MSTD_CONSTEXPR_FN_14 serial_pinmap_t get_uart_pinmap(const PinName tx, const PinName rx) +{ + return {(int) NC, tx, (int) NC, rx, (int) NC, false}; +} + +#if DEVICE_SERIAL_FC +MSTD_CONSTEXPR_FN_14 serial_fc_pinmap_t get_uart_fc_pinmap(const PinName rxflow, const PinName txflow) +{ + return {(int) NC, txflow, (int) NC, rxflow, (int) NC}; +} +#endif // DEVICE_SERIAL_FC +#endif // DEVICE_SERIAL + +#if DEVICE_SPI +MSTD_CONSTEXPR_FN_14 spi_pinmap_t get_spi_pinmap(const PinName mosi, const PinName miso, const PinName sclk, const PinName ssel) +{ + return {(int) NC, mosi, (int) NC, miso, (int) NC, sclk, (int) NC, ssel, (int) NC}; +} +#endif // DEVICE_SERIAL + +#if DEVICE_CAN +MSTD_CONSTEXPR_FN_14 can_pinmap_t get_can_pinmap(const PinName rd, const PinName td) +{ + return {(int) NC, rd, (int) NC, td, (int) NC}; +} +#endif //DEVICE_CAN + +#if DEVICE_QSPI +MSTD_CONSTEXPR_FN_14 qspi_pinmap_t get_qspi_pinmap(const PinName data0, const PinName data1, const PinName data2, const PinName data3, const PinName sclk, const PinName ssel) +{ + return {(int) NC, data0, (int) NC, data1, (int) NC, data2, (int) NC, data3, (int) NC, sclk, (int) NC, ssel, (int) NC}; +} +#endif //DEVICE_QSPI + +#endif // STATIC_PINMAP_READY + +#endif // STATIC_PINMAP_H diff --git a/hal/include/hal/ticker_api.h b/hal/include/hal/ticker_api.h new file mode 100644 index 0000000..28017fe --- /dev/null +++ b/hal/include/hal/ticker_api.h @@ -0,0 +1,240 @@ + +/** \addtogroup hal */ +/** @{*/ +/* mbed Microcontroller Library + * Copyright (c) 2015 ARM Limited + * 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. + */ +#ifndef MBED_TICKER_API_H +#define MBED_TICKER_API_H + +#include +#include +#include "device.h" + +/** + * Legacy format representing a timestamp in us. + * Given it is modeled as a 32 bit integer, this type can represent timestamp + * up to 4294 seconds (71 minutes). + * Prefer using us_timestamp_t which store timestamp as 64 bits integer. + */ +typedef uint32_t timestamp_t; + +/** + * A us timestamp stored in a 64 bit integer. + * Can store timestamp up to 584810 years. + */ +typedef uint64_t us_timestamp_t; + +/** Ticker's event structure + */ +typedef struct ticker_event_s { + us_timestamp_t timestamp; /**< Event's timestamp */ + uint32_t id; /**< TimerEvent object */ + struct ticker_event_s *next; /**< Next event in the queue */ +} ticker_event_t; + +typedef void (*ticker_event_handler)(uint32_t id); + +/** Information about the ticker implementation + */ +typedef struct { + uint32_t frequency; /**< Frequency in Hz this ticker runs at */ + uint32_t bits; /**< Number of bits this ticker supports */ +} ticker_info_t; + + +/** Ticker's interface structure - required API for a ticker + */ +typedef struct { + void (*init)(void); /**< Init function */ + uint32_t (*read)(void); /**< Read function */ + void (*disable_interrupt)(void); /**< Disable interrupt function */ + void (*clear_interrupt)(void); /**< Clear interrupt function */ + void (*set_interrupt)(timestamp_t timestamp); /**< Set interrupt function */ + void (*fire_interrupt)(void); /**< Fire interrupt right-away */ + void (*free)(void); /**< Disable function */ + const ticker_info_t *(*get_info)(void); /**< Return info about this ticker's implementation */ + bool runs_in_deep_sleep; /**< Whether ticker operates in deep sleep */ +} ticker_interface_t; + +/** Ticker's event queue structure + */ +typedef struct { + ticker_event_handler event_handler; /**< Event handler */ + ticker_event_t *head; /**< A pointer to head */ + uint32_t frequency; /**< Frequency of the timer in Hz */ + uint32_t bitmask; /**< Mask to be applied to time values read */ + uint32_t max_delta; /**< Largest delta in ticks that can be used when scheduling */ + uint64_t max_delta_us; /**< Largest delta in us that can be used when scheduling */ + uint32_t tick_last_read; /**< Last tick read */ + 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 */ + bool dispatching; /**< The function ticker_irq_handler is dispatching */ + bool suspended; /**< Indicate if the instance is suspended */ + 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 + */ +typedef struct { + const ticker_interface_t *interface; /**< Ticker's interface */ + ticker_event_queue_t *queue; /**< Ticker's event queue */ +} ticker_data_t; + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \defgroup hal_ticker Ticker HAL functions + * @{ + */ + +/** Initialize a ticker and set the event handler + * + * @param ticker The ticker object. + * @param handler A handler to be set + */ +void ticker_set_handler(const ticker_data_t *const ticker, ticker_event_handler handler); + +/** IRQ handler that goes through the events to trigger overdue events. + * + * @param ticker The ticker object. + */ +void ticker_irq_handler(const ticker_data_t *const ticker); + +/** Remove an event from the queue + * + * @param ticker The ticker object. + * @param obj The event object to be removed from the queue + */ +void ticker_remove_event(const ticker_data_t *const ticker, ticker_event_t *obj); + +/** Insert an event to the queue + * + * The event will be executed in timestamp - ticker_read(). + * + * @warning This function does not consider timestamp in the past. If an event + * is inserted with a timestamp less than the current timestamp then the event + * will be executed in timestamp - ticker_read() us. + * The internal counter wrap very quickly it is hard to decide weither an + * event is in the past or in 1 hour. + * + * @note prefer the use of ticker_insert_event_us which allows registration of + * absolute timestamp. + * + * @param ticker The ticker object. + * @param obj The event object to be inserted to the queue + * @param timestamp The event's timestamp + * @param id The event object + */ +void ticker_insert_event(const ticker_data_t *const ticker, ticker_event_t *obj, timestamp_t timestamp, uint32_t id); + +/** Insert an event to the queue + * + * The event will be executed in timestamp - ticker_read_us() us. + * + * @note If an event is inserted with a timestamp less than the current + * timestamp then the event will be scheduled immediately resulting in + * an instant call to event handler. + * + * @param ticker The ticker object. + * @param obj The event object to be inserted to the queue + * @param timestamp The event's timestamp + * @param id The event object + */ +void ticker_insert_event_us(const ticker_data_t *const ticker, ticker_event_t *obj, us_timestamp_t timestamp, uint32_t id); + +/** Read the current (relative) ticker's timestamp + * + * @warning Return a relative timestamp because the counter wrap every 4294 + * seconds. + * + * @param ticker The ticker object. + * @return The current timestamp + */ +timestamp_t ticker_read(const ticker_data_t *const ticker); + +/** Read the current (absolute) ticker's timestamp + * + * @warning Return an absolute timestamp counting from the initialization of the + * ticker. + * + * @param ticker The ticker object. + * @return The current timestamp + */ +us_timestamp_t ticker_read_us(const ticker_data_t *const ticker); + +/** Read the next event's timestamp + * + * @param ticker The ticker object. + * @param timestamp The timestamp object. + * @return 1 if timestamp is pending event, 0 if there's no event pending + */ +int ticker_get_next_timestamp(const ticker_data_t *const ticker, timestamp_t *timestamp); + +/** Read the next event's timestamp + * + * @param ticker The ticker object. + * @param timestamp The timestamp object. + * @return 1 if timestamp is pending event, 0 if there's no event pending + */ +int ticker_get_next_timestamp_us(const ticker_data_t *const ticker, us_timestamp_t *timestamp); + +/** Suspend this ticker + * + * When suspended reads will always return the same time and no + * events will be dispatched. When suspended the common layer + * will only ever call the interface function clear_interrupt() + * and that is only if ticker_irq_handler is called. + * + * + * @param ticker The ticker object. + */ +void ticker_suspend(const ticker_data_t *const ticker); + +/** Resume this ticker + * + * When resumed the ticker will ignore any time that has passed + * and continue counting up where it left off. + * + * @param ticker The ticker object. + */ +void ticker_resume(const ticker_data_t *const ticker); + +/* Private functions + * + * @cond PRIVATE + * + */ + +int _ticker_match_interval_passed(timestamp_t prev_tick, timestamp_t cur_tick, timestamp_t match_tick); + +/* + * @endcond PRIVATE + * + */ + +/**@}*/ + +#ifdef __cplusplus +} +#endif + +#endif + +/** @}*/ diff --git a/hal/include/hal/trng_api.h b/hal/include/hal/trng_api.h new file mode 100644 index 0000000..34780d6 --- /dev/null +++ b/hal/include/hal/trng_api.h @@ -0,0 +1,73 @@ + +/** \addtogroup hal */ +/** @{*/ +/* mbed Microcontroller Library + * Copyright (c) 2016 ARM Limited + * 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. + */ +#ifndef MBED_TRNG_API_H +#define MBED_TRNG_API_H + +#include +#include "device.h" + +#if defined(DEVICE_TRNG) || defined(FEATURE_PSA) + +/** TRNG HAL structure. trng_s is declared in the target's HAL + */ +typedef struct trng_s trng_t; + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \defgroup hal_trng TRNG hal functions + * @{ + */ + +/** Initialize the TRNG peripheral + * + * @param obj The TRNG object + */ +void trng_init(trng_t *obj); + +/** Deinitialize the TRNG peripheral + * + * @param obj The TRNG object + */ +void trng_free(trng_t *obj); + +/** Get random data from TRNG peripheral + * + * @param obj The TRNG object + * @param output The pointer to an output array + * @param length The size of output data, to avoid buffer overwrite + * @param output_length The length of generated data + * @return 0 success, -1 fail + */ +int trng_get_bytes(trng_t *obj, uint8_t *output, size_t length, size_t *output_length); + +/**@}*/ + +#ifdef __cplusplus +} +#endif + +#endif + +#endif + +/** @}*/ diff --git a/hal/include/hal/us_ticker_api.h b/hal/include/hal/us_ticker_api.h new file mode 100644 index 0000000..ecfa712 --- /dev/null +++ b/hal/include/hal/us_ticker_api.h @@ -0,0 +1,319 @@ + +/** \addtogroup hal */ +/** @{*/ +/* mbed Microcontroller Library + * Copyright (c) 2006-2015 ARM Limited + * 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. + */ +#ifndef MBED_US_TICKER_API_H +#define MBED_US_TICKER_API_H + +#include +#include "hal/ticker_api.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \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 for counters which are less than 32 bits wide - Verified by test ::us_ticker_info_test + * * Has a reported frequency up to 100MHz for counters which are 32 bits wide - 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 + * + * # Compile-time optimization macros + * + * To permit compile-time optimization, particularly of wait_us, the following macros should + * be defined by a target's device.h: + * + * US_TICKER_PERIOD_NUM, US_TICKER_PERIOD_DEN: These denote the ratio (numerator, denominator) + * of the ticker period to a microsecond. For example, an 8MHz ticker would have NUM = 1, DEN = 8; + * a 1MHz ticker would have NUM = 1, DEN = 1; a 250kHz ticker would have NUM = 4, DEN = 1. + * Both numerator and denominator must be 16 bits or less. + * + * US_TICKER_MASK: The value mask for the ticker - eg 0x07FFFFFF for a 27-bit ticker. + * + * If any are defined, all 3 must be defined, and the macros are checked for consistency with + * us_ticker_get_info by test ::us_ticker_info_test. + + * @{ + */ + +/** + * \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 -m -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 + * * The ticker operations ticker_init and ticker_read are atomic. + * + * # 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 -m -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 + * + * @param ticker_irq_handler IRQ handler to be connected + * + * @return previous 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 + * + */ +ticker_irq_handler_type set_us_ticker_irq_handler(ticker_irq_handler_type ticker_irq_handler); + +/** Get ticker's data + * + * @return The microsecond ticker data + */ +const ticker_data_t *get_us_ticker_data(void); + + +/** The wrapper for ticker_irq_handler, to pass us ticker's data + * + */ +void us_ticker_irq_handler(void); + +/* HAL us ticker */ + +/** 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. + * + * Pseudo Code: + * @code + * uint32_t us_ticker_free() + * { + * // Disable timer + * TIMER_CTRL &= ~TIMER_CTRL_ENABLE_Msk; + * + * // Disable the compare interrupt + * TIMER_CTRL &= ~TIMER_CTRL_COMPARE_ENABLE_Msk; + * + * // Disable timer interrupt + * NVIC_DisableIRQ(TIMER_IRQn); + * + * // Disable clock gate so processor cannot read TIMER registers + * POWER_CTRL &= ~POWER_CTRL_TIMER_Msk; + * } + * @endcode + * + */ +void us_ticker_free(void); + +/** Read the current counter + * + * 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 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); + +/**@}*/ + +#ifdef __cplusplus +} +#endif + +#endif + +/** @}*/ diff --git a/hal/include/hal/watchdog_api.h b/hal/include/hal/watchdog_api.h new file mode 100644 index 0000000..2223611 --- /dev/null +++ b/hal/include/hal/watchdog_api.h @@ -0,0 +1,188 @@ +/** \addtogroup hal */ +/** @{*/ + +/* + * Copyright (c) 2018-2019 Arm Limited and affiliates. + * 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. + */ + +#ifndef MBED_WATCHDOG_API_H +#define MBED_WATCHDOG_API_H + +#if DEVICE_WATCHDOG + +#include +#include + +/** + * \defgroup hal_watchdog Watchdog HAL API + * Low-level interface to the Independent Watchdog Timer of a target. + * + * This module provides platform independent access to the system watchdog timer + * which is an embedded peripheral that will reset the system in the case of + * system failures or malfunctions. + * + * The watchdog timer initializes a system timer with a time period specified in + * the configuration. This timer counts down and triggers a system reset when it + * wraps. To prevent the system reset the timer must be continually + * kicked/refreshed by calling ::hal_watchdog_kick which will reset the countdown + * to the user specified reset value. + * + * # Defined behavior + * * Sleep and debug modes don't stop the watchdog timer from counting down. + * * The function ::hal_watchdog_init is safe to call repeatedly. The + * function's implementation must not do anything if ::hal_watchdog_init has + * already initialized the hardware watchdog timer. + * * Maximum supported timeout is `UINT32_MAX` milliseconds; minimum timeout + * is 1 millisecond. + * * The uncalibrated watchdog should trigger at or after the timeout value + * multiplied by the frequency accuracy ratio of its oscillator (typical_frequency / max_frequency). + * * The calibrated watchdog should trigger at or after the timeout value. + * * The watchdog should trigger before twice the timeout value. + * + * # Undefined behavior + * * Calling any function other than ::hal_watchdog_init or + * ::hal_watchdog_get_platform_features before you have initialized the watchdog. + * + * # Notes + * * A software reset may not stop the watchdog timer; the behavior is platform specific. + * + * @{ + */ + +/** + * \defgroup hal_watchdog_tests Watchdog HAL tests + * Greentea tests for the Watchdog HAL. + * + * To run the Watchdog HAL tests use the command: + * + * mbed test -t -m -n tests-mbed_hal-watchdog* + * + */ + +/** Watchdog configuration. + */ +typedef struct { + /** + * Refresh value for the watchdog in milliseconds. The maximum value of this + * setting is platform dependent, to find the maximum value for the current + * platform call hal_watchdog_get_features() and check the timeout value + * member. The minimum valid value for this setting is 1. Attempting to + * initialize the watchdog with a timeout of 0 ms returns + * WATCHDOG_STATUS_INVALID_ARGUMENT. + */ + uint32_t timeout_ms; +} watchdog_config_t; + +/** Watchdog features. + */ +typedef struct { + /** + * Maximum timeout value for the watchdog in milliseconds. + */ + uint32_t max_timeout; + /** + * You can update the watchdog configuration after the watchdog has started. + */ + bool update_config; + /** + * You can stop the watchdog after it starts without a reset. + */ + bool disable_watchdog; + /** + * Typical frequency of not calibrated watchdog clock in Hz. + */ + uint32_t clock_typical_frequency; + /** + * Maximum frequency of not calibrated watchdog clock in Hz. + */ + uint32_t clock_max_frequency; +} watchdog_features_t; + + +/** Status of a watchdog operation. +*/ +typedef enum { + WATCHDOG_STATUS_OK, /**< Operation successful. **/ + WATCHDOG_STATUS_NOT_SUPPORTED, /**< Operation not supported. **/ + WATCHDOG_STATUS_INVALID_ARGUMENT /**< Invalid argument. **/ +} watchdog_status_t; + +#ifdef __cplusplus +extern "C" { +#endif + +/** Initialize and start a watchdog timer with the given configuration. + * + * If the watchdog timer is configured and starts successfully, this + * function returns ::WATCHDOG_STATUS_OK. + * + * If the timeout specified is outside the range supported by the platform, + * it returns ::WATCHDOG_STATUS_INVALID_ARGUMENT. + * + * @param[in] config Configuration settings for the watchdog timer + * + * @return ::WATCHDOG_STATUS_OK if the watchdog is configured correctly and + * has started. Otherwise a status indicating the fault. + */ +watchdog_status_t hal_watchdog_init(const watchdog_config_t *config); + +/** Refreshes the watchdog timer. + * + * Call this function periodically before the watchdog times out. + * Otherwise, the system resets. + * + * If a watchdog is not running, this function does nothing. + */ +void hal_watchdog_kick(void); + +/** Stops the watchdog timer. + * + * Calling this function disables any running watchdog + * timers if the current platform supports them. + * + * @return Returns ::WATCHDOG_STATUS_OK if the watchdog timer was succesfully + * stopped, or if the timer was never started. Returns + * ::WATCHDOG_STATUS_NOT_SUPPORTED if the watchdog cannot be disabled on + * the current platform. + */ +watchdog_status_t hal_watchdog_stop(void); + +/** Get the watchdog timer refresh value. + * + * This function returns the configured refresh timeout of the watchdog timer. + * + * @return Reload value for the watchdog timer in milliseconds. + */ +uint32_t hal_watchdog_get_reload_value(void); + +/** Get information on the current platforms supported watchdog functionality. + * + * @return watchdog_feature_t indicating supported watchdog features on the + * current platform + */ +watchdog_features_t hal_watchdog_get_platform_features(void); + +/**@}*/ + +#ifdef __cplusplus +} +#endif + +#endif // DEVICE_WATCHDOG + +#endif // MBED_WATCHDOG_API_H + +/** @}*/ diff --git a/hal/itm_api.h b/hal/itm_api.h deleted file mode 100644 index 897f6fa..0000000 --- a/hal/itm_api.h +++ /dev/null @@ -1,103 +0,0 @@ -/** \addtogroup hal */ -/** @{*/ -/* mbed Microcontroller Library - * Copyright (c) 2017 ARM Limited - * 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. - */ - -#ifndef MBED_ITM_API_H -#define MBED_ITM_API_H - -#if DEVICE_ITM - -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * \defgroup itm_hal Instrumented Trace Macrocell HAL API - * @{ - */ - -enum { - ITM_PORT_SWO = 0 -}; - -/** - * @brief Target specific initialization function. - * This function is responsible for initializing and configuring - * the debug clock for the ITM and setting up the SWO pin for - * debug output. - * - * The only Cortex-M register that should be modified is the clock - * prescaler in TPI->ACPR. - * - * The generic mbed_itm_init initialization function will setup: - * - * ITM->LAR - * ITM->TPR - * ITM->TCR - * ITM->TER - * TPI->SPPR - * TPI->FFCR - * DWT->CTRL - * - * for SWO output on stimulus port 0. - */ -void itm_init(void); - -/** - * @brief Initialization function for both generic registers and target specific clock and pin. - */ -void mbed_itm_init(void); - -/** - * @brief Send data over ITM stimulus port. - * - * @param[in] port The stimulus port to send data over. - * @param[in] data The 32-bit data to send. - * - * The data is written as a single 32-bit write to the port. - * - * @return value of data sent. - */ -uint32_t mbed_itm_send(uint32_t port, uint32_t data); - -/** - * @brief Send a block of data over ITM stimulus port. - * - * @param[in] port The stimulus port to send data over. - * @param[in] data The block of data to send. - * @param[in] len The number of bytes of data to send. - * - * The data is written using multiple appropriately-sized port accesses for - * efficient transfer. - */ -void mbed_itm_send_block(uint32_t port, const void *data, size_t len); - -/**@}*/ - -#ifdef __cplusplus -} -#endif - -#endif - -#endif /* MBED_ITM_API_H */ - -/**@}*/ diff --git a/hal/lp_ticker_api.h b/hal/lp_ticker_api.h deleted file mode 100644 index aecaf8a..0000000 --- a/hal/lp_ticker_api.h +++ /dev/null @@ -1,248 +0,0 @@ - -/** \addtogroup hal */ -/** @{*/ -/* mbed Microcontroller Library - * Copyright (c) 2015 ARM Limited - * 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. - */ -#ifndef MBED_LPTICKER_API_H -#define MBED_LPTICKER_API_H - -#include "device.h" - -#if DEVICE_LPTICKER - -#include "hal/ticker_api.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * \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 -m -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 - * - * @param ticker_irq_handler IRQ handler to be connected - * - * @return previous 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 - * - */ -ticker_irq_handler_type set_lp_ticker_irq_handler(ticker_irq_handler_type ticker_irq_handler); - -/** Get low power ticker's data - * - * @return The low power ticker data - */ -const ticker_data_t *get_lp_ticker_data(void); - -/** The wrapper for ticker_irq_handler, to pass lp ticker's data - * - */ -void lp_ticker_irq_handler(void); - -/* HAL lp ticker */ - -/** 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); - -/** Deinitialize the lower power ticker - * - * 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 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. - * - * 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); - -/**@}*/ - -#ifdef __cplusplus -} -#endif - -#endif - -#endif - -/** @}*/ diff --git a/hal/mbed_compat.c b/hal/mbed_compat.c deleted file mode 100644 index 1c58414..0000000 --- a/hal/mbed_compat.c +++ /dev/null @@ -1,106 +0,0 @@ -/* mbed Microcontroller Library - * Copyright (c) 2019 ARM Limited - * 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. - */ - -#include "analogin_api.h" -#include "i2c_api.h" -#include "spi_api.h" -#include "gpio_api.h" -#include "reset_reason_api.h" -#include "mbed_toolchain.h" - -// To be re-implemented in the target layer if required -MBED_WEAK void gpio_free(gpio_t *obj) -{ - // Do nothing -} - -#if DEVICE_I2C -// To be re-implemented in the target layer if required -MBED_WEAK void i2c_free(i2c_t *obj) -{ - // Do nothing -} -#endif - -#if DEVICE_ANALOGIN -// To be re-implemented in the target layer if required -MBED_WEAK void analogin_free(analogin_t *obj) -{ - // Do nothing -} -#endif - -#if DEVICE_SPI -// Default SPI capabilities. If specific target has different capabilities this function needs to be re-implemented. -MBED_WEAK void spi_get_capabilities(PinName ssel, bool slave, spi_capabilities_t *cap) -{ - if (slave) { - cap->minimum_frequency = 200000; // 200 kHz - cap->maximum_frequency = 2000000; // 2 MHz - cap->word_length = 0x00008080; // 8 and 16 bit symbols - cap->support_slave_mode = false; // to be determined later based on ssel - cap->hw_cs_handle = false; // irrelevant in slave mode - cap->slave_delay_between_symbols_ns = 2500; // 2.5 us - cap->clk_modes = 0x0f; // all clock modes - cap->tx_rx_buffers_equal_length = true; // rx buffer size must be equal tx buffer size -#if DEVICE_SPI_ASYNCH - cap->async_mode = true; -#else - cap->async_mode = false; -#endif - } else { - cap->minimum_frequency = 200000; // 200 kHz - cap->maximum_frequency = 2000000; // 2 MHz - cap->word_length = 0x00008080; // 8 and 16 bit symbols - cap->support_slave_mode = false; // to be determined later based on ssel - cap->hw_cs_handle = false; // to be determined later based on ssel - cap->slave_delay_between_symbols_ns = 0; // irrelevant in master mode - cap->clk_modes = 0x0f; // all clock modes - cap->tx_rx_buffers_equal_length = true; // rx buffer size must be equal tx buffer size -#if DEVICE_SPI_ASYNCH - cap->async_mode = true; -#else - cap->async_mode = false; -#endif - } - - // check if given ssel pin is in the cs pinmap - const PinMap *cs_pins = spi_master_cs_pinmap(); - while (cs_pins->pin != NC) { - if (cs_pins->pin == ssel) { -#if DEVICE_SPISLAVE - cap->support_slave_mode = true; -#endif - cap->hw_cs_handle = true; - break; - } - cs_pins++; - } -} - -#endif - -#if DEVICE_RESET_REASON -// To be re-implemented in the target layer if required -MBED_WEAK void hal_reset_reason_get_capabilities(reset_reason_capabilities_t *cap) -{ - cap->reasons = (1 << RESET_REASON_PIN_RESET) | (1 << RESET_REASON_SOFTWARE); -#if DEVICE_WATCHDOG - cap->reasons |= 1 << RESET_REASON_WATCHDOG; -#endif -} -#endif diff --git a/hal/mbed_critical_section_api.c b/hal/mbed_critical_section_api.c deleted file mode 100644 index d9bbc7b..0000000 --- a/hal/mbed_critical_section_api.c +++ /dev/null @@ -1,66 +0,0 @@ -/* mbed Microcontroller Library - * Copyright (c) 2017 ARM Limited - * 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. - */ -#include "cmsis.h" -#include "hal/critical_section_api.h" -#include "platform/mbed_assert.h" -#include "platform/mbed_toolchain.h" - -#include - -static bool critical_interrupts_enabled = false; -static bool state_saved = false; - -static bool are_interrupts_enabled(void) -{ -#if defined(__CORTEX_A9) - return ((__get_CPSR() & 0x80) == 0); -#else - return ((__get_PRIMASK() & 0x1) == 0); -#endif -} - - -MBED_WEAK void hal_critical_section_enter(void) -{ - const bool interrupt_state = are_interrupts_enabled(); - - __disable_irq(); - - if (state_saved == true) { - return; - } - - critical_interrupts_enabled = interrupt_state; - state_saved = true; -} - -MBED_WEAK void hal_critical_section_exit(void) -{ - // Interrupts must be disabled on invoking an exit from a critical section - MBED_ASSERT(!are_interrupts_enabled()); - state_saved = false; - - // Restore the IRQs to their state prior to entering the critical section - if (critical_interrupts_enabled == true) { - __enable_irq(); - } -} - -MBED_WEAK bool hal_in_critical_section(void) -{ - return (state_saved == true); -} diff --git a/hal/mbed_flash_api.c b/hal/mbed_flash_api.c deleted file mode 100644 index a5d009b..0000000 --- a/hal/mbed_flash_api.c +++ /dev/null @@ -1,31 +0,0 @@ -/* mbed Microcontroller Library - * Copyright (c) 2017 ARM Limited - * 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. - */ - -#include "hal/flash_api.h" - -#if DEVICE_FLASH - -#include "platform/mbed_toolchain.h" -#include - -MBED_WEAK int32_t flash_read(flash_t *obj, uint32_t address, uint8_t *data, uint32_t size) -{ - memcpy(data, (const void *)address, size); - return 0; -} - -#endif diff --git a/hal/mbed_gpio.c b/hal/mbed_gpio.c deleted file mode 100644 index 7659cff..0000000 --- a/hal/mbed_gpio.c +++ /dev/null @@ -1,128 +0,0 @@ -/* mbed Microcontroller Library - * Copyright (c) 2006-2020 ARM Limited - * 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. - */ -#include "hal/gpio_api.h" -#include "platform/mbed_toolchain.h" - -static inline void _gpio_init_in(gpio_t *gpio, PinName pin, PinMode mode) -{ - gpio_init(gpio, pin); - if (pin != NC) { - gpio_dir(gpio, PIN_INPUT); - gpio_mode(gpio, mode); - } -} - -static inline void _gpio_init_out(gpio_t *gpio, PinName pin, PinMode mode, int value) -{ - gpio_init(gpio, pin); - if (pin != NC) { - gpio_write(gpio, value); - gpio_dir(gpio, PIN_OUTPUT); - gpio_mode(gpio, mode); - } -} - -void gpio_init_in(gpio_t *gpio, PinName pin) -{ - gpio_init_in_ex(gpio, pin, PullDefault); -} - -void gpio_init_in_ex(gpio_t *gpio, PinName pin, PinMode mode) -{ - _gpio_init_in(gpio, pin, mode); -} - -void gpio_init_out(gpio_t *gpio, PinName pin) -{ - gpio_init_out_ex(gpio, pin, 0); -} - -void gpio_init_out_ex(gpio_t *gpio, PinName pin, int value) -{ - _gpio_init_out(gpio, pin, PullNone, value); -} - -void gpio_init_inout(gpio_t *gpio, PinName pin, PinDirection direction, PinMode mode, int value) -{ - if (direction == PIN_INPUT) { - _gpio_init_in(gpio, pin, mode); - if (pin != NC) { - gpio_write(gpio, value); // we prepare the value in case it is switched later - } - } else { - _gpio_init_out(gpio, pin, mode, value); - } -} - -// To be re-implemented in the target layer if required. -MBED_WEAK void gpio_get_capabilities(gpio_t *gpio, gpio_capabilities_t *cap) -{ - (void)gpio; // By default, every pin supports all basic input pull modes. - cap->pull_none = 1; - cap->pull_down = 1; - cap->pull_up = 1; -} - -#ifdef TARGET_FF_ARDUINO - -typedef enum { - DEFAULT_GPIO = 0, -} DefaultGPIOPeripheralName; - -MBED_WEAK const PinMap *gpio_pinmap() -{ - // Targets should override this weak implementation to provide correct data. - static const PinMap empty_gpio_pinmap[] = { - {D0, DEFAULT_GPIO, 0}, - {D1, DEFAULT_GPIO, 0}, - {D2, DEFAULT_GPIO, 0}, - {D3, DEFAULT_GPIO, 0}, - {D4, DEFAULT_GPIO, 0}, - {D5, DEFAULT_GPIO, 0}, - {D6, DEFAULT_GPIO, 0}, - {D7, DEFAULT_GPIO, 0}, - {D8, DEFAULT_GPIO, 0}, - {D9, DEFAULT_GPIO, 0}, - {D10, DEFAULT_GPIO, 0}, - {D11, DEFAULT_GPIO, 0}, - {D12, DEFAULT_GPIO, 0}, - {D13, DEFAULT_GPIO, 0}, - {D14, DEFAULT_GPIO, 0}, - {D15, DEFAULT_GPIO, 0}, - {A0, DEFAULT_GPIO, 0}, - {A1, DEFAULT_GPIO, 0}, - {A2, DEFAULT_GPIO, 0}, - {A3, DEFAULT_GPIO, 0}, - {A4, DEFAULT_GPIO, 0}, - {A5, DEFAULT_GPIO, 0}, - - {NC, NC, 0}, - }; - return empty_gpio_pinmap; -} - -#else - -MBED_WEAK const PinMap *gpio_pinmap() -{ - static const PinMap empty_gpio_pinmap[] = { - {NC, NC, 0}, - }; - return empty_gpio_pinmap; -} - -#endif diff --git a/hal/mbed_gpio_irq.c b/hal/mbed_gpio_irq.c deleted file mode 100644 index b8c6e86..0000000 --- a/hal/mbed_gpio_irq.c +++ /dev/null @@ -1,31 +0,0 @@ -/* mbed Microcontroller Library - * Copyright (c) 2019 ARM Limited - * 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. - */ -#include "hal/gpio_irq_api.h" - -#if DEVICE_INTERRUPTIN - -#include "platform/mbed_toolchain.h" -#include "hal/gpio_api.h" - -MBED_WEAK const PinMap *gpio_irq_pinmap() -{ - // Targets should override this weak implementation to provide correct data. - // By default, this is exactly the same as GPIO PinMap. - return gpio_pinmap(); -} - -#endif diff --git a/hal/mbed_itm_api.c b/hal/mbed_itm_api.c deleted file mode 100644 index 46d7e3d..0000000 --- a/hal/mbed_itm_api.c +++ /dev/null @@ -1,134 +0,0 @@ -/* mbed Microcontroller Library - * Copyright (c) 2017 ARM Limited - * 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. - */ - -#if DEVICE_ITM - -#include "hal/itm_api.h" -#include "cmsis.h" - -#include - -#ifndef ITM_STIM_FIFOREADY_Msk -#define ITM_STIM_FIFOREADY_Msk 1 -#endif - -#define ITM_ENABLE_WRITE 0xC5ACCE55 - -#define SWO_NRZ 0x02 -#define SWO_STIMULUS_PORT 0x01 - -void mbed_itm_init(void) -{ - static bool do_init = true; - - if (do_init) { - do_init = false; - - itm_init(); - - /* Enable write access to ITM registers. */ - ITM->LAR = ITM_ENABLE_WRITE; - - /* Trace Port Interface Selected Pin Protocol Register. */ - TPI->SPPR = (SWO_NRZ << TPI_SPPR_TXMODE_Pos); - - /* Trace Port Interface Formatter and Flush Control Register */ - TPI->FFCR = (1 << TPI_FFCR_TrigIn_Pos); - - /* Data Watchpoint and Trace Control Register */ - DWT->CTRL = (1 << DWT_CTRL_CYCTAP_Pos) | - (0xF << DWT_CTRL_POSTINIT_Pos) | - (0xF << DWT_CTRL_POSTPRESET_Pos) | - (1 << DWT_CTRL_CYCCNTENA_Pos); - - /* Trace Privilege Register. - * Disable access to trace channel configuration from non-privileged mode. - */ - ITM->TPR = 0x0; - - /* Trace Control Register */ - ITM->TCR = (1 << ITM_TCR_TraceBusID_Pos) | - (1 << ITM_TCR_DWTENA_Pos) | - (1 << ITM_TCR_SYNCENA_Pos) | - (1 << ITM_TCR_ITMENA_Pos); - - /* Trace Enable Register */ - ITM->TER = SWO_STIMULUS_PORT; - } -} - -static void itm_out8(uint32_t port, uint8_t data) -{ - /* Wait until port is available */ - while ((ITM->PORT[port].u32 & ITM_STIM_FIFOREADY_Msk) == 0) { - __NOP(); - } - - /* write data to port */ - ITM->PORT[port].u8 = data; -} - -static void itm_out32(uint32_t port, uint32_t data) -{ - /* Wait until port is available */ - while ((ITM->PORT[port].u32 & ITM_STIM_FIFOREADY_Msk) == 0) { - __NOP(); - } - - /* write data to port */ - ITM->PORT[port].u32 = data; -} - -uint32_t mbed_itm_send(uint32_t port, uint32_t data) -{ - /* Check if ITM and port is enabled */ - if (((ITM->TCR & ITM_TCR_ITMENA_Msk) != 0UL) && /* ITM enabled */ - ((ITM->TER & (1UL << port)) != 0UL)) { /* ITM Port enabled */ - itm_out32(port, data); - } - - return data; -} - -void mbed_itm_send_block(uint32_t port, const void *data, size_t len) -{ - const char *ptr = data; - - /* Check if ITM and port is enabled */ - if (((ITM->TCR & ITM_TCR_ITMENA_Msk) != 0UL) && /* ITM enabled */ - ((ITM->TER & (1UL << port)) != 0UL)) { /* ITM Port enabled */ - /* Output single byte at a time until data is aligned */ - while ((((uintptr_t) ptr) & 3) && len != 0) { - itm_out8(port, *ptr++); - len--; - } - - /* Output bulk of data one word at a time */ - while (len >= 4) { - itm_out32(port, *(const uint32_t *) ptr); - ptr += 4; - len -= 4; - } - - /* Output any trailing bytes */ - while (len != 0) { - itm_out8(port, *ptr++); - len--; - } - } -} -#endif // DEVICE_ITM diff --git a/hal/mbed_lp_ticker_api.c b/hal/mbed_lp_ticker_api.c deleted file mode 100644 index b1b2d96..0000000 --- a/hal/mbed_lp_ticker_api.c +++ /dev/null @@ -1,72 +0,0 @@ -/* mbed Microcontroller Library - * Copyright (c) 2015 ARM Limited - * 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. - */ -#include "hal/lp_ticker_api.h" -#include "hal/mbed_lp_ticker_wrapper.h" - -#if DEVICE_LPTICKER - -static ticker_event_queue_t events = { 0 }; - -static ticker_irq_handler_type irq_handler = ticker_irq_handler; - -static const ticker_interface_t lp_interface = { - .init = lp_ticker_init, - .read = lp_ticker_read, - .disable_interrupt = lp_ticker_disable_interrupt, - .clear_interrupt = lp_ticker_clear_interrupt, - .set_interrupt = lp_ticker_set_interrupt, - .fire_interrupt = lp_ticker_fire_interrupt, - .get_info = lp_ticker_get_info, - .free = lp_ticker_free, - .runs_in_deep_sleep = true, -}; - -static const ticker_data_t lp_data = { - .interface = &lp_interface, - .queue = &events, -}; - -const ticker_data_t *get_lp_ticker_data(void) -{ -#if LPTICKER_DELAY_TICKS > 0 - return get_lp_ticker_wrapper_data(&lp_data); -#else - return &lp_data; -#endif -} - -ticker_irq_handler_type set_lp_ticker_irq_handler(ticker_irq_handler_type ticker_irq_handler) -{ - ticker_irq_handler_type prev_irq_handler = irq_handler; - - irq_handler = ticker_irq_handler; - - return prev_irq_handler; -} - -void lp_ticker_irq_handler(void) -{ -#if LPTICKER_DELAY_TICKS > 0 - lp_ticker_wrapper_irq_handler(irq_handler); -#else - if (irq_handler) { - irq_handler(&lp_data); - } -#endif -} - -#endif diff --git a/hal/mbed_lp_ticker_wrapper.cpp b/hal/mbed_lp_ticker_wrapper.cpp deleted file mode 100644 index e388355..0000000 --- a/hal/mbed_lp_ticker_wrapper.cpp +++ /dev/null @@ -1,129 +0,0 @@ -/* mbed Microcontroller Library - * Copyright (c) 2018 ARM Limited - * 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. - */ -#include "hal/mbed_lp_ticker_wrapper.h" - -#if DEVICE_LPTICKER && (LPTICKER_DELAY_TICKS > 0) - -#include "hal/LowPowerTickerWrapper.h" -#include "platform/mbed_critical.h" - -// Do not use SingletonPtr since this must be initialized in a critical section -static LowPowerTickerWrapper *ticker_wrapper; -static uint64_t ticker_wrapper_data[(sizeof(LowPowerTickerWrapper) + 7) / 8]; -static bool init = false; - -static void lp_ticker_wrapper_init() -{ - ticker_wrapper->init(); -} - -static uint32_t lp_ticker_wrapper_read() -{ - return ticker_wrapper->read(); -} - -static void lp_ticker_wrapper_set_interrupt(timestamp_t timestamp) -{ - ticker_wrapper->set_interrupt(timestamp); -} - -static void lp_ticker_wrapper_disable_interrupt() -{ - ticker_wrapper->disable_interrupt(); -} - -static void lp_ticker_wrapper_clear_interrupt() -{ - ticker_wrapper->clear_interrupt(); -} - -static void lp_ticker_wrapper_fire_interrupt() -{ - ticker_wrapper->fire_interrupt(); -} - -static const ticker_info_t *lp_ticker_wrapper_get_info() -{ - return ticker_wrapper->get_info(); -} - -static void lp_ticker_wrapper_free() -{ - ticker_wrapper->free(); -} - -static const ticker_interface_t lp_interface = { - lp_ticker_wrapper_init, - lp_ticker_wrapper_read, - lp_ticker_wrapper_disable_interrupt, - lp_ticker_wrapper_clear_interrupt, - lp_ticker_wrapper_set_interrupt, - lp_ticker_wrapper_fire_interrupt, - lp_ticker_wrapper_free, - lp_ticker_wrapper_get_info, - true -}; - -void lp_ticker_wrapper_irq_handler(ticker_irq_handler_type handler) -{ - core_util_critical_section_enter(); - - if (!init) { - // Force ticker to initialize - get_lp_ticker_data(); - } - - ticker_wrapper->irq_handler(handler); - - core_util_critical_section_exit(); -} - -const ticker_data_t *get_lp_ticker_wrapper_data(const ticker_data_t *data) -{ - core_util_critical_section_enter(); - - if (!init) { - ticker_wrapper = new (ticker_wrapper_data) LowPowerTickerWrapper(data, &lp_interface, LPTICKER_DELAY_TICKS, LPTICKER_DELAY_TICKS); - init = true; - } - - core_util_critical_section_exit(); - - return &ticker_wrapper->data; -} - -void lp_ticker_wrapper_suspend() -{ - if (!init) { - // Force ticker to initialize - get_lp_ticker_data(); - } - - ticker_wrapper->suspend(); -} - -void lp_ticker_wrapper_resume() -{ - if (!init) { - // Force ticker to initialize - get_lp_ticker_data(); - } - - ticker_wrapper->resume(); -} - -#endif diff --git a/hal/mbed_lp_ticker_wrapper.h b/hal/mbed_lp_ticker_wrapper.h deleted file mode 100644 index 3493abe..0000000 --- a/hal/mbed_lp_ticker_wrapper.h +++ /dev/null @@ -1,82 +0,0 @@ - -/** \addtogroup hal */ -/** @{*/ -/* mbed Microcontroller Library - * Copyright (c) 2018 ARM Limited - * 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. - */ -#ifndef MBED_LP_TICKER_WRAPPER_H -#define MBED_LP_TICKER_WRAPPER_H - -#include "device.h" - -#if DEVICE_LPTICKER - -#include "hal/ticker_api.h" -#include - -#ifdef __cplusplus -extern "C" { -#endif - -typedef void (*ticker_irq_handler_type)(const ticker_data_t *const); - -/** - * Interrupt handler for the wrapped lp ticker - * - * @param handler the function which would normally be called by the - * lp ticker handler when it is not wrapped - */ -void lp_ticker_wrapper_irq_handler(ticker_irq_handler_type handler); - -/** - * Get wrapped lp ticker data - * - * @param data hardware low power ticker object - * @return wrapped low power ticker object - */ -const ticker_data_t *get_lp_ticker_wrapper_data(const ticker_data_t *data); - -/** - * Suspend the wrapper layer code - * - * Pass through all interrupts to the low power ticker and stop using - * the microsecond ticker. - * - * @warning: Make sure to suspend the LP ticker first (call ticker_suspend()), - * otherwise the behavior is undefined. - */ -void lp_ticker_wrapper_suspend(void); - -/** - * Resume the wrapper layer code - * - * Resume operation of the wrapper layer. Interrupts will be filtered - * as normal and the microsecond timer will be used for interrupts scheduled - * too quickly back-to-back. - */ -void lp_ticker_wrapper_resume(void); - -/**@}*/ - -#ifdef __cplusplus -} -#endif - -#endif - -#endif - -/** @}*/ diff --git a/hal/mbed_pinmap_common.c b/hal/mbed_pinmap_common.c deleted file mode 100644 index f47cb1a..0000000 --- a/hal/mbed_pinmap_common.c +++ /dev/null @@ -1,188 +0,0 @@ -/* mbed Microcontroller Library - * Copyright (c) 2006-2013 ARM Limited - * 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. - */ -#include "hal/pinmap.h" -#include "platform/mbed_error.h" - -void pinmap_pinout(PinName pin, const PinMap *map) -{ - if (pin == NC) { - return; - } - - while (map->pin != NC) { - if (map->pin == pin) { - pin_function(pin, map->function); - - pin_mode(pin, PullNone); - return; - } - map++; - } - MBED_ERROR1(MBED_MAKE_ERROR(MBED_MODULE_PLATFORM, MBED_ERROR_CODE_PINMAP_INVALID), "could not pinout", pin); -} - -uint32_t pinmap_merge(uint32_t a, uint32_t b) -{ - // both are the same (inc both NC) - if (a == b) { - return a; - } - - // one (or both) is not connected - if (a == (uint32_t)NC) { - return b; - } - if (b == (uint32_t)NC) { - return a; - } - - // mis-match error case - MBED_ERROR1(MBED_MAKE_ERROR(MBED_MODULE_PLATFORM, MBED_ERROR_CODE_PINMAP_INVALID), "pinmap mis-match", a); -} - -uint32_t pinmap_find_peripheral(PinName pin, const PinMap *map) -{ - while (map->pin != NC) { - if (map->pin == pin) { - return map->peripheral; - } - map++; - } - return (uint32_t)NC; -} - -uint32_t pinmap_peripheral(PinName pin, const PinMap *map) -{ - uint32_t peripheral = (uint32_t)NC; - - if (pin == (PinName)NC) { - return (uint32_t)NC; - } - peripheral = pinmap_find_peripheral(pin, map); - if ((uint32_t)NC == peripheral) { // no mapping available - MBED_ERROR1(MBED_MAKE_ERROR(MBED_MODULE_PLATFORM, MBED_ERROR_CODE_PINMAP_INVALID), "pinmap not found for peripheral", pin); - } - return peripheral; -} - -uint32_t pinmap_find_function(PinName pin, const PinMap *map) -{ - while (map->pin != NC) { - if (map->pin == pin) { - return map->function; - } - map++; - } - return (uint32_t)NC; -} - -uint32_t pinmap_function(PinName pin, const PinMap *map) -{ - uint32_t function = (uint32_t)NC; - - if (pin == (PinName)NC) { - return (uint32_t)NC; - } - function = pinmap_find_function(pin, map); - if ((uint32_t)NC == function) { // no mapping available - MBED_ERROR1(MBED_MAKE_ERROR(MBED_MODULE_PLATFORM, MBED_ERROR_CODE_PINMAP_INVALID), "pinmap not found for function", pin); - } - return function; -} - -bool pinmap_find_peripheral_pins(const PinList *whitelist, const PinList *blacklist, int per, const PinMap *const *maps, PinName **pins, uint32_t count) -{ - /* - * This function uses recursion to find a suitable set of pins which meet the requirements. - * Recursion is at max the number of pinmaps passed in - the 'count' parameter. Because of this - * there is no risk of a stack overflow due to unbounded recursion. - * - * Below is a psuedo code example of this function's operation when finding a set of 4 pins. - * The recursion depth is indicated by the number in front. - * - * 1. Given 4 maps and a peripheral find 4 suitable pins - * 2. Given 4 maps, a peripheral and 1 pin find 3 suitable pins - * 3. Given 4 maps, a peripheral and 2 pins find 2 suitable pins - * 4. Given 4 maps, a peripheral and 3 pins find 1 suitable pin - * 4. Return success if all pins are found, return failure if there are no suitable pins, otherwise choose the next pin and retry - * 3. Return success if all pins are found, return failure if there are no suitable pins, otherwise choose the next pin and retry - * 2. Return success if all pins are found, return failure if there are no suitable pins, otherwise choose the next pin and retry - * 1. Return success if all pins are found, return failure if there are no suitable pins, otherwise choose the next pin and retry - * - */ - - for (uint32_t i = 0; i < count; i++) { - const PinMap *map = maps[i]; - PinName *pin = pins[i]; - if (*pin == NC) { - for (; map->pin != NC; map++) { - if (map->peripheral != per) { - continue; - } - if (!pinmap_list_has_pin(whitelist, map->pin)) { - // Not part of this form factor - continue; - } - if (pinmap_list_has_pin(blacklist, map->pin)) { - // Restricted pin - continue; - } - bool already_in_use = false; - for (uint32_t j = 0; j < count; j++) { - if (j == i) { - // Don't compare with self - continue; - } - if (map->pin == *pins[j]) { - already_in_use = true; - break; - } - } - if (already_in_use) { - continue; - } - *pin = map->pin; - if (pinmap_find_peripheral_pins(whitelist, blacklist, per, maps, pins, count)) { - return true; - } - } - *pin = NC; - return false; - } - } - return true; -} - -bool pinmap_list_has_pin(const PinList *list, PinName pin) -{ - for (uint32_t i = 0; i < list->count; i++) { - if (list->pins[i] == pin) { - return true; - } - } - return false; -} - -bool pinmap_list_has_peripheral(const PeripheralList *list, int peripheral) -{ - for (uint32_t i = 0; i < list->count; i++) { - if (list->peripheral[i] == peripheral) { - return true; - } - } - return false; -} diff --git a/hal/mbed_pinmap_default.cpp b/hal/mbed_pinmap_default.cpp deleted file mode 100644 index 45ac316..0000000 --- a/hal/mbed_pinmap_default.cpp +++ /dev/null @@ -1,108 +0,0 @@ -/* mbed Microcontroller Library - * Copyright (c) 2019 ARM Limited - * 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. - */ - -#include -#include "hal/pinmap.h" -#include "platform/mbed_toolchain.h" -#include "platform/mbed_assert.h" -#include "device.h" -#include "hal/serial_api.h" - -//*** Common form factors *** -#ifdef TARGET_FF_ARDUINO - -static const PinName ff_arduino_pins[] = { - D0, D1, D2, D3, D4, D5, D6, D7, - D8, D9, D10, D11, D12, D13, D14, D15, - A0, A1, A2, A3, A4, A5 -}; - -static const char *ff_arduino_names[] = { - "D0", "D1", "D2", "D3", "D4", "D5", "D6", "D7", - "D8", "D9", "D10", "D11", "D12", "D13", "D14", "D15", - "A0", "A1", "A2", "A3", "A4", "A5" -}; - -static const PinList ff_arduino_list = { - sizeof(ff_arduino_pins) / sizeof(ff_arduino_pins[0]), - ff_arduino_pins -}; - -MBED_STATIC_ASSERT(sizeof(ff_arduino_pins) / sizeof(ff_arduino_pins[0]) == sizeof(ff_arduino_names) / sizeof(ff_arduino_names[0]), - "Arrays must have the same length"); - -const PinList *pinmap_ff_arduino_pins() -{ - return &ff_arduino_list; -} - -const char *pinmap_ff_arduino_pin_to_string(PinName pin) -{ - if (pin == NC) { - return "NC"; - } - for (size_t i = 0; i < ff_arduino_list.count; i++) { - if (ff_arduino_list.pins[i] == pin) { - return ff_arduino_names[i]; - } - } - return "Unknown"; -} - -#endif - -//*** Default restricted pins *** -MBED_WEAK const PinList *pinmap_restricted_pins() -{ - static const PinName pins[] = { - USBTX, USBRX - }; - static const PinList pin_list = { - sizeof(pins) / sizeof(pins[0]), - pins - }; - return &pin_list; -} - -//*** Default restricted gpio pins *** -// GPIO pins are special case because there are no pin-maps for GPIO -MBED_WEAK const PinList *pinmap_gpio_restricted_pins() -{ - static const PinList pin_list = { - 0, - 0 - }; - return &pin_list; -} - -//*** Default restricted peripherals *** -#if DEVICE_SERIAL -MBED_WEAK const PeripheralList *pinmap_uart_restricted_peripherals() -{ - static const int stdio_uart = pinmap_peripheral(STDIO_UART_TX, serial_tx_pinmap()); - - static const int peripherals[] = { - stdio_uart - }; - - static const PeripheralList peripheral_list = { - sizeof peripherals / sizeof peripherals[0], - peripherals - }; - return &peripheral_list; -} -#endif diff --git a/hal/mbed_ticker_api.c b/hal/mbed_ticker_api.c deleted file mode 100644 index 5f36365..0000000 --- a/hal/mbed_ticker_api.c +++ /dev/null @@ -1,507 +0,0 @@ -/* mbed Microcontroller Library - * Copyright (c) 2015 ARM Limited - * 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. - */ -#include -#include -#include "hal/ticker_api.h" -#include "platform/mbed_critical.h" -#include "platform/mbed_assert.h" -#include "platform/mbed_error.h" - -static void schedule_interrupt(const ticker_data_t *const ticker); -static void update_present_time(const ticker_data_t *const ticker); - -/* - * Initialize a ticker instance. - */ -static void initialize(const ticker_data_t *ticker) -{ - // return if the queue has already been initialized, in that case the - // interface used by the queue is already initialized. - if (ticker->queue->initialized) { - return; - } - if (ticker->queue->suspended) { - return; - } - - ticker->interface->init(); - - const ticker_info_t *info = ticker->interface->get_info(); - uint32_t frequency = info->frequency; - if (info->frequency == 0) { -#if MBED_TRAP_ERRORS_ENABLED - MBED_ERROR( - MBED_MAKE_ERROR( - MBED_MODULE_HAL, - MBED_ERROR_CODE_NOT_READY - ), - "Ticker frequency is zero" - ); -#else - frequency = 1000000; -#endif // MBED_TRAP_ERRORS_ENABLED - } - - uint8_t frequency_shifts = 0; - for (uint8_t i = 31; i > 0; --i) { - if ((1U << i) == frequency) { - frequency_shifts = i; - break; - } - } - - uint32_t bits = info->bits; - if ((info->bits > 32) || (info->bits < 4)) { -#if MBED_TRAP_ERRORS_ENABLED - MBED_ERROR( - MBED_MAKE_ERROR( - MBED_MODULE_HAL, - MBED_ERROR_CODE_INVALID_SIZE - ), - "Ticker number of bit is greater than 32 or less than 4 bits" - ); -#else - bits = 32; -#endif // MBED_TRAP_ERRORS_ENABLED - } - uint32_t max_delta = 0x7 << (bits - 4); // 7/16th - uint64_t max_delta_us = - ((uint64_t)max_delta * 1000000 + frequency - 1) / frequency; - - ticker->queue->event_handler = NULL; - ticker->queue->head = NULL; - 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; - ticker->queue->present_time = 0; - ticker->queue->dispatching = false; - ticker->queue->suspended = false; - ticker->queue->initialized = true; - - update_present_time(ticker); - schedule_interrupt(ticker); -} - -/** - * Set the event handler function of a ticker instance. - */ -static void set_handler(const ticker_data_t *const ticker, ticker_event_handler handler) -{ - ticker->queue->event_handler = handler; -} - -/* - * Convert a 32 bit timestamp into a 64 bit timestamp. - * - * A 64 bit timestamp is used as the point of time of reference while the - * timestamp to convert is relative to this point of time. - * - * The lower 32 bits of the timestamp returned will be equal to the timestamp to - * convert. - * - * If the timestamp to convert is less than the lower 32 bits of the time - * reference then the timestamp to convert is seen as an overflowed value and - * the upper 32 bit of the timestamp returned will be equal to the upper 32 bit - * of the reference point + 1. - * Otherwise, the upper 32 bit returned will be equal to the upper 32 bit of the - * reference point. - * - * @param ref: The 64 bit timestamp of reference. - * @param timestamp: The timestamp to convert. - */ -static us_timestamp_t convert_timestamp(us_timestamp_t ref, timestamp_t timestamp) -{ - bool overflow = timestamp < ((timestamp_t) ref) ? true : false; - - us_timestamp_t result = (ref & ~((us_timestamp_t)UINT32_MAX)) | timestamp; - if (overflow) { - result += (1ULL << 32); - } - - return result; -} - -/** - * Update the present timestamp value of a ticker. - */ -static void update_present_time(const ticker_data_t *const ticker) -{ - ticker_event_queue_t *queue = ticker->queue; - if (queue->suspended) { - return; - } - uint32_t ticker_time = ticker->interface->read(); - if (ticker_time == ticker->queue->tick_last_read) { - // No work to do - return; - } - - uint64_t elapsed_ticks = (ticker_time - queue->tick_last_read) & queue->bitmask; - queue->tick_last_read = ticker_time; - - uint64_t elapsed_us; - if (1000000 == queue->frequency) { - // Optimized for 1MHz - - elapsed_us = elapsed_ticks; - } 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 >> queue->frequency_shifts; - - // Update remainder - 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; - } - } else { - // General case - - uint64_t us_x_ticks = elapsed_ticks * 1000000; - elapsed_us = us_x_ticks / queue->frequency; - - // Update remainder - queue->tick_remainder += us_x_ticks - elapsed_us * queue->frequency; - if (queue->tick_remainder >= queue->frequency) { - elapsed_us += 1; - queue->tick_remainder -= queue->frequency; - } - } - - // Update current time - queue->present_time += elapsed_us; -} - -/** - * Given the absolute timestamp compute the hal tick timestamp rounded up. - */ -static timestamp_t compute_tick_round_up(const ticker_data_t *const ticker, us_timestamp_t timestamp) -{ - ticker_event_queue_t *queue = ticker->queue; - us_timestamp_t delta_us = timestamp - queue->present_time; - - timestamp_t delta = ticker->queue->max_delta; - if (delta_us <= ticker->queue->max_delta_us) { - // Checking max_delta_us ensures the operation will not overflow - - if (1000000 == queue->frequency) { - // Optimized for 1MHz - - delta = delta_us; - if (delta > ticker->queue->max_delta) { - delta = ticker->queue->max_delta; - } - } else if (0 != queue->frequency_shifts) { - // Optimized frequencies divisible by 2 - - delta = ((delta_us << ticker->queue->frequency_shifts) + 1000000 - 1) / 1000000; - if (delta > ticker->queue->max_delta) { - delta = ticker->queue->max_delta; - } - } else { - // General case - - delta = (delta_us * queue->frequency + 1000000 - 1) / 1000000; - if (delta > ticker->queue->max_delta) { - delta = ticker->queue->max_delta; - } - } - } - return (queue->tick_last_read + delta) & queue->bitmask; -} - -/** - * Return 1 if the tick has incremented to or past match_tick, otherwise 0. - */ -int _ticker_match_interval_passed(timestamp_t prev_tick, timestamp_t cur_tick, timestamp_t match_tick) -{ - if (match_tick > prev_tick) { - return (cur_tick >= match_tick) || (cur_tick < prev_tick); - } else { - return (cur_tick < prev_tick) && (cur_tick >= match_tick); - } -} - -/** - * Compute the time when the interrupt has to be triggered and schedule it. - * - * If there is no event in the queue or the next event to execute is in more - * than ticker.queue.max_delta ticks from now then the ticker irq will be - * scheduled in ticker.queue.max_delta ticks. Otherwise the irq will be - * scheduled to happen when the running counter reach the timestamp of the - * first event in the queue. - * - * @note If there is no event in the queue then the interrupt is scheduled to - * in ticker.queue.max_delta. This is necessary to keep track - * of the timer overflow. - */ -static void schedule_interrupt(const ticker_data_t *const ticker) -{ - ticker_event_queue_t *queue = ticker->queue; - if (queue->suspended || ticker->queue->dispatching) { - // Don't schedule the next interrupt until dispatching is - // finished. This prevents repeated calls to interface->set_interrupt - return; - } - - update_present_time(ticker); - - if (ticker->queue->head) { - us_timestamp_t present = ticker->queue->present_time; - us_timestamp_t match_time = ticker->queue->head->timestamp; - - // if the event at the head of the queue is in the past then schedule - // it immediately. - if (match_time <= present) { - ticker->interface->fire_interrupt(); - return; - } - - timestamp_t match_tick = compute_tick_round_up(ticker, match_time); - - // The same tick should never occur since match_tick is rounded up. - // If the same tick is returned scheduling will not work correctly. - MBED_ASSERT(match_tick != queue->tick_last_read); - - ticker->interface->set_interrupt(match_tick); - timestamp_t cur_tick = ticker->interface->read(); - - if (_ticker_match_interval_passed(queue->tick_last_read, cur_tick, match_tick)) { - ticker->interface->fire_interrupt(); - } - } else { - uint32_t match_tick = - (queue->tick_last_read + queue->max_delta) & queue->bitmask; - ticker->interface->set_interrupt(match_tick); - } -} - -void ticker_set_handler(const ticker_data_t *const ticker, ticker_event_handler handler) -{ - initialize(ticker); - - core_util_critical_section_enter(); - set_handler(ticker, handler); - core_util_critical_section_exit(); -} - -void ticker_irq_handler(const ticker_data_t *const ticker) -{ - core_util_critical_section_enter(); - - ticker->interface->clear_interrupt(); - if (ticker->queue->suspended) { - core_util_critical_section_exit(); - return; - } - - /* Go through all the pending TimerEvents */ - ticker->queue->dispatching = true; - while (1) { - if (ticker->queue->head == NULL) { - break; - } - - // update the current timestamp used by the queue - update_present_time(ticker); - - if (ticker->queue->head->timestamp <= ticker->queue->present_time) { - // This event was in the past: - // point to the following one and execute its handler - ticker_event_t *p = ticker->queue->head; - ticker->queue->head = ticker->queue->head->next; - if (ticker->queue->event_handler != NULL) { - (*ticker->queue->event_handler)(p->id); // NOTE: the handler can set new events - } - /* Note: We continue back to examining the head because calling the - * event handler may have altered the chain of pending events. */ - } else { - break; - } - } - ticker->queue->dispatching = false; - - schedule_interrupt(ticker); - - core_util_critical_section_exit(); -} - -void ticker_insert_event(const ticker_data_t *const ticker, ticker_event_t *obj, timestamp_t timestamp, uint32_t id) -{ - core_util_critical_section_enter(); - - // update the current timestamp - update_present_time(ticker); - us_timestamp_t absolute_timestamp = convert_timestamp( - ticker->queue->present_time, - timestamp - ); - - // defer to ticker_insert_event_us - ticker_insert_event_us( - ticker, - obj, absolute_timestamp, id - ); - - core_util_critical_section_exit(); -} - -void ticker_insert_event_us(const ticker_data_t *const ticker, ticker_event_t *obj, us_timestamp_t timestamp, uint32_t id) -{ - core_util_critical_section_enter(); - - // update the current timestamp - update_present_time(ticker); - - // initialise our data - obj->timestamp = timestamp; - obj->id = id; - - /* Go through the list until we either reach the end, or find - an element this should come before (which is possibly the - head). */ - ticker_event_t *prev = NULL, *p = ticker->queue->head; - while (p != NULL) { - /* check if we come before p */ - if (timestamp < p->timestamp) { - break; - } - /* go to the next element */ - prev = p; - p = p->next; - } - - /* if we're at the end p will be NULL, which is correct */ - obj->next = p; - - /* if prev is NULL we're at the head */ - if (prev == NULL) { - ticker->queue->head = obj; - } else { - prev->next = obj; - } - - if (prev == NULL || timestamp <= ticker->queue->present_time) { - schedule_interrupt(ticker); - } - - core_util_critical_section_exit(); -} - -void ticker_remove_event(const ticker_data_t *const ticker, ticker_event_t *obj) -{ - core_util_critical_section_enter(); - - // remove this object from the list - if (ticker->queue->head == obj) { - // first in the list, so just drop me - ticker->queue->head = obj->next; - schedule_interrupt(ticker); - } else { - // find the object before me, then drop me - ticker_event_t *p = ticker->queue->head; - while (p != NULL) { - if (p->next == obj) { - p->next = obj->next; - break; - } - p = p->next; - } - } - - core_util_critical_section_exit(); -} - -timestamp_t ticker_read(const ticker_data_t *const ticker) -{ - return ticker_read_us(ticker); -} - -us_timestamp_t ticker_read_us(const ticker_data_t *const ticker) -{ - us_timestamp_t ret; - - initialize(ticker); - - core_util_critical_section_enter(); - update_present_time(ticker); - ret = ticker->queue->present_time; - core_util_critical_section_exit(); - - return ret; -} - -int ticker_get_next_timestamp(const ticker_data_t *const data, timestamp_t *timestamp) -{ - int ret = 0; - - /* if head is NULL, there are no pending events */ - core_util_critical_section_enter(); - if (data->queue->head != NULL) { - *timestamp = data->queue->head->timestamp; - ret = 1; - } - core_util_critical_section_exit(); - - return ret; -} - -int ticker_get_next_timestamp_us(const ticker_data_t *const data, us_timestamp_t *timestamp) -{ - int ret = 0; - - /* if head is NULL, there are no pending events */ - core_util_critical_section_enter(); - if (data->queue->head != NULL) { - *timestamp = data->queue->head->timestamp; - ret = 1; - } - core_util_critical_section_exit(); - - return ret; -} - -void ticker_suspend(const ticker_data_t *const ticker) -{ - core_util_critical_section_enter(); - - ticker->queue->suspended = true; - - core_util_critical_section_exit(); -} - -void ticker_resume(const ticker_data_t *const ticker) -{ - core_util_critical_section_enter(); - - ticker->queue->suspended = false; - if (ticker->queue->initialized) { - ticker->queue->tick_last_read = ticker->interface->read(); - - update_present_time(ticker); - schedule_interrupt(ticker); - } else { - initialize(ticker); - } - - core_util_critical_section_exit(); -} diff --git a/hal/mbed_us_ticker_api.c b/hal/mbed_us_ticker_api.c deleted file mode 100644 index 777a5e4..0000000 --- a/hal/mbed_us_ticker_api.c +++ /dev/null @@ -1,112 +0,0 @@ -/* mbed Microcontroller Library - * Copyright (c) 2015 ARM Limited - * 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. - */ - -#include -#include "platform/mbed_atomic.h" -#include "hal/us_ticker_api.h" - -#if DEVICE_USTICKER - -static ticker_event_queue_t events = { 0 }; - -static ticker_irq_handler_type irq_handler = ticker_irq_handler; - -#if MBED_CONF_TARGET_INIT_US_TICKER_AT_BOOT - -// If we are initializing at boot, we want the timer to be -// always-on, so we block any attempt to free it. We do need -// to pass through init(), as that needs to reset pending -// interrupts. -static void block_us_ticker_free() -{ -} - -#else // MBED_CONF_TARGET_INIT_US_TICKER_AT_BOOT - -bool _us_ticker_initialized; - -// If we are not initializing at boot, we want to track -// whether the timer has been initialized. This permits -// a fast path for wait_us. -static void note_us_ticker_init() -{ - us_ticker_init(); - core_util_atomic_store_bool(&_us_ticker_initialized, true); -} - -static void note_us_ticker_free() -{ - core_util_atomic_store_bool(&_us_ticker_initialized, false); - us_ticker_free(); -} - -#endif // MBED_CONF_TARGET_INIT_US_TICKER_AT_BOOT - -static const ticker_interface_t us_interface = { -#if MBED_CONF_TARGET_INIT_US_TICKER_AT_BOOT - .init = us_ticker_init, -#else - .init = note_us_ticker_init, -#endif - .read = us_ticker_read, - .disable_interrupt = us_ticker_disable_interrupt, - .clear_interrupt = us_ticker_clear_interrupt, - .set_interrupt = us_ticker_set_interrupt, - .fire_interrupt = us_ticker_fire_interrupt, - .get_info = us_ticker_get_info, -#if MBED_CONF_TARGET_INIT_US_TICKER_AT_BOOT - .free = block_us_ticker_free, -#else - .free = note_us_ticker_free, -#endif - .runs_in_deep_sleep = false, -}; - -static const ticker_data_t us_data = { - .interface = &us_interface, - .queue = &events -}; - -const ticker_data_t *get_us_ticker_data(void) -{ - return &us_data; -} - -ticker_irq_handler_type set_us_ticker_irq_handler(ticker_irq_handler_type ticker_irq_handler) -{ - ticker_irq_handler_type prev_irq_handler = irq_handler; - - irq_handler = ticker_irq_handler; - - return prev_irq_handler; -} - -void us_ticker_irq_handler(void) -{ - if (irq_handler) { - irq_handler(&us_data); - } -} - -#else - -const ticker_data_t *get_us_ticker_data(void) -{ - return NULL; -} - -#endif // DEVICE_USTICKER diff --git a/hal/mpu/mbed_mpu_v7m.c b/hal/mpu/mbed_mpu_v7m.c deleted file mode 100644 index d804063..0000000 --- a/hal/mpu/mbed_mpu_v7m.c +++ /dev/null @@ -1,238 +0,0 @@ -/* mbed Microcontroller Library - * Copyright (c) 2018 ARM Limited - * 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. - */ -#include "hal/mpu_api.h" -#include "platform/mbed_assert.h" -#include "cmsis.h" - -#if ((__ARM_ARCH_7M__ == 1U) || (__ARM_ARCH_7EM__ == 1U) || (__ARM_ARCH_6M__ == 1U)) && \ - defined (__MPU_PRESENT) && (__MPU_PRESENT == 1U) && \ - !defined(MBED_MPU_CUSTOM) - -#if !DEVICE_MPU -#error "Device has v7m MPU but it is not enabled. Add 'MPU' to device_has in targets.json" -#endif - -#ifdef MBED_CONF_TARGET_MPU_ROM_END -#define MBED_MPU_ROM_END MBED_CONF_TARGET_MPU_ROM_END -#else -#define MBED_MPU_ROM_END (0x10000000 - 1) -#endif -#define MBED_MPU_RAM_START (MBED_MPU_ROM_END + 1) - -MBED_STATIC_ASSERT( - MBED_MPU_ROM_END == 0x04000000 - 1 || - MBED_MPU_ROM_END == 0x08000000 - 1 || - MBED_MPU_ROM_END == 0x0C000000 - 1 || - MBED_MPU_ROM_END == 0x10000000 - 1 || - MBED_MPU_ROM_END == 0x14000000 - 1 || - MBED_MPU_ROM_END == 0x18000000 - 1 || - MBED_MPU_ROM_END == 0x1C000000 - 1 || - MBED_MPU_ROM_END == 0x20000000 - 1, - "Unsupported value for MBED_MPU_ROM_END"); - -void mbed_mpu_init() -{ - // Flush memory writes before configuring the MPU. - __DMB(); - - const uint32_t regions = (MPU->TYPE & MPU_TYPE_DREGION_Msk) >> MPU_TYPE_DREGION_Pos; - - // Our MPU setup requires 3 or 4 regions - if this assert is hit, remove - // a region by setting MPU_ROM_END to 0x1fffffff, or remove MPU from device_has -#if MBED_MPU_RAM_START == 0x20000000 - MBED_ASSERT(regions >= 3); -#else - MBED_ASSERT(regions >= 4); -#endif - - // Disable the MCU - MPU->CTRL = 0; - - // Reset all mapping - for (uint32_t i = 0; i < regions; i++) { - ARM_MPU_ClrRegion(i); - } - - /* - * ARMv6m and ARMv7-M memory map: - * - * Start End Name Executable by default Mbed MPU protection - * 0x00000000 - 0x1FFFFFFF Code Yes Write disabled for first portion and execute disabled for the rest - * 0x20000000 - 0x3FFFFFFF SRAM Yes Execute disabled - * 0x40000000 - 0x5FFFFFFF Peripheral No - * 0x60000000 - 0x7FFFFFFF RAM Yes Execute disabled - * 0x80000000 - 0x9FFFFFFF RAM Yes Execute disabled - * 0xA0000000 - 0xBFFFFFFF Device No - * 0xC0000000 - 0xDFFFFFFF Device No - * 0xE0000000 - 0xFFFFFFFF System No - */ - - // Select region 0 and use it for the WT read-only rom region - // - Code 0x00000000 to MBED_MPU_ROM_END - ARM_MPU_SetRegion( - ARM_MPU_RBAR( - 0, // Region - 0x00000000), // Base - ARM_MPU_RASR( - 0, // DisableExec - ARM_MPU_AP_RO, // AccessPermission - 0, // TypeExtField - 0, // IsShareable - 1, // IsCacheable - 0, // IsBufferable - // SubRegionDisable - based on where ROM ends - ((MBED_MPU_ROM_END >= 0x00000000) ? 0 : (1 << 0)) | // 0 to enable, 1 << n to disable - ((MBED_MPU_ROM_END >= 0x04000000) ? 0 : (1 << 1)) | - ((MBED_MPU_ROM_END >= 0x08000000) ? 0 : (1 << 2)) | - ((MBED_MPU_ROM_END >= 0x0C000000) ? 0 : (1 << 3)) | - ((MBED_MPU_ROM_END >= 0x10000000) ? 0 : (1 << 4)) | - ((MBED_MPU_ROM_END >= 0x14000000) ? 0 : (1 << 5)) | - ((MBED_MPU_ROM_END >= 0x18000000) ? 0 : (1 << 6)) | - ((MBED_MPU_ROM_END >= 0x1C000000) ? 0 : (1 << 7)), - ARM_MPU_REGION_SIZE_512MB) // Size - ); - -#if MBED_MPU_RAM_START < 0x20000000 - // Select region 3 and use it for a WT ram region in the Code area - // - Code MBED_MPU_ROM_END + 1 to 0x1FFFFFFF - ARM_MPU_SetRegion( - ARM_MPU_RBAR( - 3, // Region - 0x00000000), // Base - ARM_MPU_RASR( - 1, // DisableExec - ARM_MPU_AP_FULL, // AccessPermission - 0, // TypeExtField - 0, // IsShareable - 1, // IsCacheable - 0, // IsBufferable - // SubRegionDisable - based on where RAM starts - ((MBED_MPU_RAM_START <= 0x04000000) ? 0 : (1 << 0)) | // 0 to enable, 1 << n to disable - ((MBED_MPU_RAM_START <= 0x08000000) ? 0 : (1 << 1)) | - ((MBED_MPU_RAM_START <= 0x0C000000) ? 0 : (1 << 2)) | - ((MBED_MPU_RAM_START <= 0x10000000) ? 0 : (1 << 3)) | - ((MBED_MPU_RAM_START <= 0x14000000) ? 0 : (1 << 4)) | - ((MBED_MPU_RAM_START <= 0x18000000) ? 0 : (1 << 5)) | - ((MBED_MPU_RAM_START <= 0x1C000000) ? 0 : (1 << 6)) | - ((MBED_MPU_RAM_START <= 0x20000000) ? 0 : (1 << 7)), - ARM_MPU_REGION_SIZE_512MB) // Size - ); -#define LAST_RAM_REGION 3 -#else -#define LAST_RAM_REGION 2 -#endif - - // Select region 1 and use it for WBWA ram regions - // - SRAM 0x20000000 to 0x3FFFFFFF - // - RAM 0x60000000 to 0x7FFFFFFF - ARM_MPU_SetRegion( - ARM_MPU_RBAR( - 1, // Region - 0x00000000), // Base - ARM_MPU_RASR( - 1, // DisableExec - ARM_MPU_AP_FULL, // AccessPermission - 1, // TypeExtField - 0, // IsShareable - 1, // IsCacheable - 1, // IsBufferable - // SubRegionDisable - (1 << 0) | // Disable Sub-region - (0 << 1) | // Enable Sub-region SRAM 0x20000000 - 0x3FFFFFFF - (1 << 2) | // Disable Sub-region - (0 << 3) | // Enable Sub-region RAM 0x60000000 - 0x7FFFFFFF - (1 << 4) | // Disable Sub-region - (1 << 5) | // Disable Sub-region - (1 << 6) | // Disable Sub-region - (1 << 7), // Disable Sub-region - ARM_MPU_REGION_SIZE_4GB) // Size - ); - - // Select region 2 and use it for the WT ram region - // - RAM 0x80000000 to 0x9FFFFFFF - ARM_MPU_SetRegion( - ARM_MPU_RBAR( - 2, // Region - 0x80000000), // Base - ARM_MPU_RASR( - 1, // DisableExec - ARM_MPU_AP_FULL, // AccessPermission - 0, // TypeExtField - 0, // IsShareable - 1, // IsCacheable - 0, // IsBufferable - 0U, // SubRegionDisable - ARM_MPU_REGION_SIZE_512MB) // Size - ); - - // Enable the MPU - MPU->CTRL = - (1 << MPU_CTRL_PRIVDEFENA_Pos) | // Use the default memory map for unmapped addresses - (1 << MPU_CTRL_HFNMIENA_Pos) | // Keep MPU turned on for faults - (1 << MPU_CTRL_ENABLE_Pos); // Enable MPU - - // Ensure changes take effect - __DSB(); - __ISB(); -} - -void mbed_mpu_free() -{ - // Flush memory writes before configuring the MPU. - __DMB(); - - // Disable the MPU - MPU->CTRL = 0; - - // Ensure changes take effect - __DSB(); - __ISB(); -} - -static void enable_region(bool enable, uint32_t region) -{ - MPU->RNR = region; - MPU->RASR = (MPU->RASR & ~MPU_RASR_ENABLE_Msk) | (enable << MPU_RASR_ENABLE_Pos); -} - -void mbed_mpu_enable_rom_wn(bool enable) -{ - // Flush memory writes before configuring the MPU. - __DMB(); - - enable_region(enable, 0); - - // Ensure changes take effect - __DSB(); - __ISB(); -} - -void mbed_mpu_enable_ram_xn(bool enable) -{ - // Flush memory writes before configuring the MPU. - __DMB(); - - for (uint32_t region = 1; region <= LAST_RAM_REGION; region++) { - enable_region(enable, region); - } - - // Ensure changes take effect - __DSB(); - __ISB(); -} - -#endif diff --git a/hal/mpu/mbed_mpu_v8m.c b/hal/mpu/mbed_mpu_v8m.c deleted file mode 100644 index ccdbd59..0000000 --- a/hal/mpu/mbed_mpu_v8m.c +++ /dev/null @@ -1,212 +0,0 @@ -/* mbed Microcontroller Library - * Copyright (c) 2018 ARM Limited - * 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. - */ -#include "hal/mpu_api.h" -#include "platform/mbed_assert.h" -#include "cmsis.h" - -#if ((__ARM_ARCH_8M_BASE__ == 1U) || (__ARM_ARCH_8M_MAIN__ == 1U)) && \ - defined (__MPU_PRESENT) && (__MPU_PRESENT == 1U) && \ - !defined(MBED_MPU_CUSTOM) - -#if !DEVICE_MPU -#error "Device has v8m MPU but it is not enabled. Add 'MPU' to device_has in targets.json" -#endif - -#ifdef MBED_CONF_TARGET_MPU_ROM_END -#define MBED_MPU_ROM_END MBED_CONF_TARGET_MPU_ROM_END -#else -#define MBED_MPU_ROM_END (0x10000000 - 1) -#endif -#define MBED_MPU_RAM_START (MBED_MPU_ROM_END + 1) - -MBED_STATIC_ASSERT(MBED_MPU_ROM_END <= 0x20000000 - 1, - "Unsupported value for MBED_MPU_ROM_END"); - -void mbed_mpu_init() -{ - // Flush memory writes before configuring the MPU. - __DMB(); - - const uint32_t regions = (MPU->TYPE & MPU_TYPE_DREGION_Msk) >> MPU_TYPE_DREGION_Pos; - - // Our MPU setup requires 4 or 5 regions - if this assert is hit, remove - // a region by setting MPU_ROM_END to 0x1fffffff, or remove MPU from device_has -#if MBED_MPU_RAM_START == 0x20000000 - MBED_ASSERT(regions >= 4); -#else - MBED_ASSERT(regions >= 5); -#endif - - // Disable the MCU - MPU->CTRL = 0; - - // Reset all mapping - for (uint32_t i = 0; i < regions; i++) { - ARM_MPU_ClrRegion(i); - } - - /* - * ARMv8-M memory map: - * - * Start End Name Executable by default Default cache Mbed MPU protection - * 0x00000000 - 0x1FFFFFFF Code Yes WT, WA Write disabled for first portion and execute disabled for the rest - * 0x20000000 - 0x3FFFFFFF SRAM Yes WB, WA, RA Execute disabled - * 0x40000000 - 0x5FFFFFFF Peripheral No - * 0x60000000 - 0x7FFFFFFF RAM Yes WB, WA, RA Execute disabled - * 0x80000000 - 0x9FFFFFFF RAM Yes WT, RA Execute disabled - * 0xA0000000 - 0xBFFFFFFF Device No - * 0xC0000000 - 0xDFFFFFFF Device No - * 0xE0000000 - 0xFFFFFFFF System No - */ - - const uint8_t WTRA = ARM_MPU_ATTR_MEMORY_(1, 0, 1, 0); // Non-transient, Write-Through, Read-allocate, Not Write-allocate - const uint8_t WBWARA = ARM_MPU_ATTR_MEMORY_(1, 1, 1, 1); // Non-transient, Write-Back, Read-allocate, Write-allocate - enum { - AttrIndex_WTRA, - AttrIndex_WBWARA, - }; - - ARM_MPU_SetMemAttr(AttrIndex_WTRA, ARM_MPU_ATTR(WTRA, WTRA)); - ARM_MPU_SetMemAttr(AttrIndex_WBWARA, ARM_MPU_ATTR(WBWARA, WBWARA)); - - ARM_MPU_SetRegion( - 0, // Region - ARM_MPU_RBAR( - 0x00000000, // Base - ARM_MPU_SH_NON, // Non-shareable - 1, // Read-Only - 1, // Non-Privileged - 0), // Execute Never disabled - ARM_MPU_RLAR( - MBED_MPU_ROM_END, // Limit - AttrIndex_WTRA) // Attribute index - Write-Through, Read-allocate - ); - -#if MBED_MPU_RAM_START != 0x20000000 - ARM_MPU_SetRegion( - 4, // Region - ARM_MPU_RBAR( - MBED_MPU_RAM_START, // Base - ARM_MPU_SH_NON, // Non-shareable - 0, // Read-Write - 1, // Non-Privileged - 1), // Execute Never enabled - ARM_MPU_RLAR( - 0x1FFFFFFF, // Limit - AttrIndex_WTRA) // Attribute index - Write-Through, Read-allocate - ); -#define LAST_RAM_REGION 4 -#else -#define LAST_RAM_REGION 3 -#endif - - ARM_MPU_SetRegion( - 1, // Region - ARM_MPU_RBAR( - 0x20000000, // Base - ARM_MPU_SH_NON, // Non-shareable - 0, // Read-Write - 1, // Non-Privileged - 1), // Execute Never enabled - ARM_MPU_RLAR( - 0x3FFFFFFF, // Limit - AttrIndex_WBWARA) // Attribute index - Write-Back, Write-allocate - ); - - ARM_MPU_SetRegion( - 2, // Region - ARM_MPU_RBAR( - 0x60000000, // Base - ARM_MPU_SH_NON, // Non-shareable - 0, // Read-Write - 1, // Non-Privileged - 1), // Execute Never enabled - ARM_MPU_RLAR( - 0x7FFFFFFF, // Limit - AttrIndex_WBWARA) // Attribute index - Write-Back, Write-allocate - ); - - ARM_MPU_SetRegion( - 3, // Region - ARM_MPU_RBAR( - 0x80000000, // Base - ARM_MPU_SH_NON, // Non-shareable - 0, // Read-Write - 1, // Non-Privileged - 1), // Execute Never enabled - ARM_MPU_RLAR( - 0x9FFFFFFF, // Limit - AttrIndex_WTRA) // Attribute index - Write-Through, Read-allocate - ); - - // Enable the MPU - MPU->CTRL = - (1 << MPU_CTRL_PRIVDEFENA_Pos) | // Use the default memory map for unmapped addresses - (1 << MPU_CTRL_HFNMIENA_Pos) | // Keep MPU turned on for faults - (1 << MPU_CTRL_ENABLE_Pos); // Enable MPU - - // Ensure changes take effect - __DSB(); - __ISB(); -} - -void mbed_mpu_free() -{ - // Flush memory writes before configuring the MPU. - __DMB(); - - // Disable the MCU - MPU->CTRL = 0; - - // Ensure changes take effect - __DSB(); - __ISB(); -} - -static void enable_region(bool enable, uint32_t region) -{ - MPU->RNR = region; - MPU->RLAR = (MPU->RLAR & ~MPU_RLAR_EN_Msk) | (enable << MPU_RLAR_EN_Pos); -} - -void mbed_mpu_enable_rom_wn(bool enable) -{ - // Flush memory writes before configuring the MPU. - __DMB(); - - enable_region(enable, 0); - - // Ensure changes take effect - __DSB(); - __ISB(); -} - -void mbed_mpu_enable_ram_xn(bool enable) -{ - // Flush memory writes before configuring the MPU. - __DMB(); - - for (uint32_t region = 1; region <= LAST_RAM_REGION; region++) { - enable_region(enable, region); - } - - // Ensure changes take effect - __DSB(); - __ISB(); -} - -#endif diff --git a/hal/mpu_api.h b/hal/mpu_api.h deleted file mode 100644 index 95ee8fc..0000000 --- a/hal/mpu_api.h +++ /dev/null @@ -1,123 +0,0 @@ - -/** \addtogroup hal */ -/** @{*/ -/* mbed Microcontroller Library - * Copyright (c) 2018-2018 ARM Limited - * 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. - */ -#ifndef MBED_MPU_API_H -#define MBED_MPU_API_H - -#include "device.h" -#include - -#ifdef __cplusplus -extern "C" { -#endif - -#if DEVICE_MPU - -/** - * \defgroup hal_mpu MPU hal - * - * The MPU hal provides a simple MPU API to enhance device security by preventing - * execution from ram. - * - * # Defined behavior - * * The function ::mbed_mpu_init is safe to call repeatedly - Verified by ::mpu_init_test - * * The function ::mbed_mpu_free disables MPU protection - Verified by ::mpu_free_test - * * Execution from RAM results in a fault when execute never is enabled. - * This RAM includes heap, stack, data and zero init - Verified by ::mpu_fault_test_data, - * ::mpu_fault_test_bss, ::mpu_fault_test_stack and ::mpu_fault_test_heap. - * * Writing to ROM results in a fault when write never is enabled - Not verified - * - * # Undefined behavior - * * Calling any function other than ::mbed_mpu_init before the initialization of the MPU. - * - * @see hal_mpu_tests - * - * @{ - */ - -/** - * \defgroup hal_mpu_tests MPU hal tests - * The MPU test validates proper implementation of the MPU hal. - * - * To run the MPU hal tests use the command: - * - * mbed test -t -m -n tests-mbed_hal-mpu* - */ - - -/** - * Initialize the MPU - * - * Initialize or re-initialize the memory protection unit. - * After initialization or re-initialization, ROM and RAM protection - * are both enabled. - */ -void mbed_mpu_init(void); - -/** - * Enable or disable ROM MPU protection - * - * This function is used to mark all of ROM as read and execute only. - * When enabled writes to ROM cause a fault. - * - * By default writes to ROM are disabled. - * - * @param enable true to disable writes to ROM, false otherwise - */ -void mbed_mpu_enable_rom_wn(bool enable); - -/** - * Enable or disable ram MPU protection - * - * This function is used to mark all of RAM as execute never. - * When enabled code is only allowed to execute from flash. - * - * By default execution from RAM is disabled. - * - * @param enable true to disable execution from RAM, false otherwise - */ -void mbed_mpu_enable_ram_xn(bool enable); - -/** Deinitialize the MPU - * - * Powerdown the MPU in preparation for powerdown, reset or jumping to another application. - */ -void mbed_mpu_free(void); - -/**@}*/ - -#else - -#define mbed_mpu_init() - -#define mbed_mpu_enable_rom_wn(enable) (void)enable - -#define mbed_mpu_enable_ram_xn(enable) (void)enable - -#define mbed_mpu_free() - -#endif - -#ifdef __cplusplus -} -#endif - -#endif - -/** @}*/ diff --git a/hal/pinmap.h b/hal/pinmap.h deleted file mode 100644 index f3af23b..0000000 --- a/hal/pinmap.h +++ /dev/null @@ -1,260 +0,0 @@ - -/** \addtogroup hal */ -/** @{*/ -/* mbed Microcontroller Library - * Copyright (c) 2006-2013 ARM Limited - * 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. - */ -#ifndef MBED_PINMAP_H -#define MBED_PINMAP_H - -#include "PinNames.h" -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct { - PinName pin; - int peripheral; - int function; -} PinMap; - -typedef struct { - uint32_t count; - const PinName *pins; -} PinList; - -typedef struct { - uint32_t count; - const int *peripheral; -} PeripheralList; - -void pin_function(PinName pin, int function); -void pin_mode(PinName pin, PinMode mode); - -uint32_t pinmap_peripheral(PinName pin, const PinMap *map); -uint32_t pinmap_function(PinName pin, const PinMap *map); -uint32_t pinmap_merge(uint32_t a, uint32_t b); -void pinmap_pinout(PinName pin, const PinMap *map); -uint32_t pinmap_find_peripheral(PinName pin, const PinMap *map); -uint32_t pinmap_find_function(PinName pin, const PinMap *map); - -/** - * Find a combination of pins suitable for use given the constraints - * - * This function finds pins which meet these specific properties: - * - The pin is part of the form factor - * - The pin is not in the restricted list - * - The pin is contained within the respective pinmap - * - The pin belongs to the given peripheral - * - Each pin found is distinct; in the example below - * mosi and miso will never be assigned the same pin - * - * Example: - * @code - * #include "mbed.h" - * #include "pinmap.h" - * - * int main() - * { - * int per = spi_master_cs_pinmap()->peripheral; - * const PinList *pins_ff = pinmap_ff_default_pins(); - * const PinList *pins_avoid = pinmap_restricted_pins(); - * PinName mosi = NC; - * PinName miso = NC; - * PinName sclk = NC; - * PinName ssel = NC; - * const PinMap *maps[] = { - * spi_master_mosi_pinmap(), - * spi_master_miso_pinmap(), - * spi_master_clk_pinmap(), - * spi_master_cs_pinmap() - * }; - * PinName *pins[] = { - * &mosi, - * &miso, - * &sclk, - * &ssel - * }; - * if (pinmap_find_peripheral_pins(pins_ff, pins_avoid, per, maps, pins, sizeof(maps) / sizeof(maps[0]))) { - * printf("Found SPI pins to test instance %i with:\n" - * " mosi=%s\n" - * " miso=%s\n" - * " sclk=%s\n" - * " ssel=%s\n", per, - * pinmap_ff_default_pin_to_string(mosi), - * pinmap_ff_default_pin_to_string(miso), - * pinmap_ff_default_pin_to_string(sclk), - * pinmap_ff_default_pin_to_string(ssel)); - * } else { - * printf("Could not find SPI combination to test %i\n", per); - * } - * return 0; - * } - * @endcode - * - * @param whitelist List of pins to choose from - * @param blacklist List of pins which cannot be used - * @param per Peripheral to which the pins belong - * @param maps An array of pin maps to select from - * @param pins An array of pins to find. Pins already set to a value will be - * left unchanged. Only pins initialized to NC will be updated by this function - * @param count The size of maps and pins - * @return true if a suitable combination of pins was found and - * written to the pins array, otherwise false - */ -bool pinmap_find_peripheral_pins(const PinList *whitelist, const PinList *blacklist, int per, const PinMap *const *maps, PinName **pins, uint32_t count); - -/** - * Check if the pin is in the list - * - * @param list pin list to check - * @param pin pin to check for in the list - * @return true if the pin is in the list, false otherwise - */ -bool pinmap_list_has_pin(const PinList *list, PinName pin); - -/** - * Check if the peripheral is in the list - * - * @param list peripheral list to check - * @param peripheral peripheral to check for in the list - * @return true if the peripheral is in the list, false otherwise - */ -bool pinmap_list_has_peripheral(const PeripheralList *list, int peripheral); - -/** - * Get the pin list of pins to avoid during testing - * - * The restricted pin list is used to indicate to testing - * that a pin should be skipped due to some caveat about it. - * For example, using USBRX and USBTX during tests will interfere - * with the test runner and should be avoided. - * - * Targets should override the weak implementation of this - * function if they have additional pins which should be - * skipped during testing. - * - * @return Pointer to a pin list of pins to avoid - */ -const PinList *pinmap_restricted_pins(void); - -/** - * Get the pin list of peripherals per interface to avoid during testing - * - * The restricted peripheral list is used to indicate to testing - * that a peripheral should be skipped due to some caveat about it. - * For example, using the USB serial port during tests will interfere - * with the test runner and should be avoided. - * - * Targets should override the weak implementation of this - * function if they have peripherals which should be - * skipped during testing. - * - * @note Restricting peripheral is at the moment available for UART - * interface only as only STDIO UART must be skipped because it is - * used by Mbed. - * Restricting peripherals for other interfaces should be added - * in the future if required. - * - * @return Pointer to a peripheral list of peripheral to avoid - */ -#if DEVICE_SERIAL -const PeripheralList *pinmap_uart_restricted_peripherals(void); -#endif - -/** - * Get the pin list of pins to avoid during GPIO/GPIO_IRQ testing - * - * The GPIO restricted pin list is used to indicate to testing - * that a pin should be skipped due to some caveat about it. - * - * Targets should override the weak implementation of this - * function if they have peripherals which should be - * skipped during testing. - * - * @note This is special case only for GPIO/GPIO_IRQ tests because - * targets do not provide pin-maps for GPIO. - * - * @return Pointer to a peripheral list of peripheral to avoid - */ -const PinList *pinmap_gpio_restricted_pins(void); - -#ifdef TARGET_FF_ARDUINO - -/** - * Get the pin list of the Arduino form factor - * - * @return Pointer to the Arduino pin list - */ -const PinList *pinmap_ff_arduino_pins(void); - -/** - * Get the string representation of a form factor pin - * - * @param pin Pin to get a string for - * @return String representing the form factor pin - */ -const char *pinmap_ff_arduino_pin_to_string(PinName pin); - -/* Default to arduino form factor if unspecified */ -#ifndef MBED_CONF_TARGET_DEFAULT_FORM_FACTOR -#define MBED_CONF_TARGET_DEFAULT_FORM_FACTOR arduino -#endif - -#endif - -#ifdef MBED_CONF_TARGET_DEFAULT_FORM_FACTOR - -#define PINMAP_DEFAULT_PINS_(name) pinmap_ff_ ## name ## _pins -#define PINMAP_DEFAULT_PIN_TO_STRING_(name) pinmap_ff_ ## name ## _pin_to_string -#define PINMAP_DEFAULT_PINS(name) PINMAP_DEFAULT_PINS_(name) -#define PINMAP_DEFAULT_PIN_TO_STRING(name) PINMAP_DEFAULT_PIN_TO_STRING_(name) -#define pinmap_ff_default_pins PINMAP_DEFAULT_PINS(MBED_CONF_TARGET_DEFAULT_FORM_FACTOR) -#define pinmap_ff_default_pin_to_string PINMAP_DEFAULT_PIN_TO_STRING(MBED_CONF_TARGET_DEFAULT_FORM_FACTOR) - -/** - * Get the pin list of the default form factor - * - * This is an alias to whichever form factor is set - * to be the default. - * - * @return Pointer to the default pin list - */ -const PinList *pinmap_ff_default_pins(void); - -/** - * Get the string representation of a form factor pin - * - * This is an alias to whichever form factor is set - * to be the default. - * - * @param pin Pin to get a string for - * @return String representing the form factor pin - */ -const char *pinmap_ff_default_pin_to_string(PinName pin); - -#endif - -#ifdef __cplusplus -} -#endif - -#endif - -/** @}*/ diff --git a/hal/port_api.h b/hal/port_api.h deleted file mode 100644 index 48bd0d2..0000000 --- a/hal/port_api.h +++ /dev/null @@ -1,94 +0,0 @@ - -/** \addtogroup hal */ -/** @{*/ -/* mbed Microcontroller Library - * Copyright (c) 2006-2013 ARM Limited - * 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. - */ -#ifndef MBED_PORTMAP_H -#define MBED_PORTMAP_H - -#include "device.h" - -#if DEVICE_PORTIN || DEVICE_PORTOUT - -#ifdef __cplusplus -extern "C" { -#endif - -/** Port HAL structure. port_s is declared in the target's HAL - */ -typedef struct port_s port_t; - -/** - * \defgroup hal_port Port HAL functions - * @{ - */ - -/** Get the pin name from the port's pin number - * - * @param port The port name - * @param pin_n The pin number within the specified port - * @return The pin name for the port's pin number - */ -PinName port_pin(PortName port, int pin_n); - -/** Initilize the port - * - * @param obj The port object to initialize - * @param port The port name - * @param mask The bitmask to identify which bits in the port should be included (0 - ignore) - * @param dir The port direction - */ -void port_init(port_t *obj, PortName port, int mask, PinDirection dir); - -/** Set the input port mode - * - * @param obj The port object - * @param mode THe port mode to be set - */ -void port_mode(port_t *obj, PinMode mode); - -/** Set port direction (in/out) - * - * @param obj The port object - * @param dir The port direction to be set - */ -void port_dir(port_t *obj, PinDirection dir); - -/** Write value to the port - * - * @param obj The port object - * @param value The value to be set - */ -void port_write(port_t *obj, int value); - -/** Read the current value on the port - * - * @param obj The port object - * @return An integer with each bit corresponding to an associated port pin setting - */ -int port_read(port_t *obj); - -/**@}*/ - -#ifdef __cplusplus -} -#endif -#endif - -#endif - -/** @}*/ diff --git a/hal/pwmout_api.h b/hal/pwmout_api.h deleted file mode 100644 index 977f7c6..0000000 --- a/hal/pwmout_api.h +++ /dev/null @@ -1,168 +0,0 @@ - -/** \addtogroup hal */ -/** @{*/ -/* mbed Microcontroller Library - * Copyright (c) 2006-2013 ARM Limited - * 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. - */ -#ifndef MBED_PWMOUT_API_H -#define MBED_PWMOUT_API_H - -#include "device.h" -#include "pinmap.h" - -#if DEVICE_PWMOUT - -#ifdef __cplusplus -extern "C" { -#endif - -/** Pwmout hal structure. pwmout_s is declared in the target's hal - */ -typedef struct pwmout_s pwmout_t; - -/** - * \defgroup hal_pwmout Pwmout hal functions - * - * # Defined behavior - * * ::pwmout_init initializes the pwmout_t control structure - * * ::pwmout_free deinitializes the pwmout object - * * ::pwmout_write sets the output duty-cycle in range <0.0f, 1.0f> - * * ::pwmout_read returns the current float-point output duty-cycle in range <0.0f, 1.0f> - * * ::pwmout_period sets the PWM period specified in seconds, keeping the duty cycle the same - * * ::pwmout_period_ms sets the PWM period specified in miliseconds, keeping the duty cycle the same - * * ::pwmout_period_us sets the PWM period specified in microseconds, keeping the duty cycle the same - * * ::pwmout_pulsewidth sets the PWM pulsewidth specified in seconds, keeping the period the same - * * ::pwmout_pulsewidth_ms sets the PWM pulsewidth specified in miliseconds, keeping the period the same - * * ::pwmout_pulsewidth_us sets the PWM pulsewidth specified in microseconds, keeping the period the same - * * The accuracy of the PWM is +/- 10% - * * The PWM operations ::pwmout_write, ::pwmout_read, ::pwmout_read, ::pwmout_period_ms, ::pwmout_period_us - * ::pwmout_pulsewidth, ::pwmout_pulsewidth_ms, ::pwmout_pulsewidth_us take less than 20us to complete - * - * # Undefined behavior - * * Calling other function before ::pwmout_init - * * Calling ::pwmout_init with NC as pwmout pin - * - * @{ - */ - -/** - * \defgroup hal_pwmout_tests GPIO IRQ HAL tests - * The Pwmout HAL tests ensure driver conformance to defined behaviour. - * - * To run the Pwmout hal tests use the command: - * - * mbed test -t -m -n tests-mbed_hal_fpga_ci_test_shield-pwm - * - */ - -/** Initialize the pwm out peripheral and configure the pin - * - * @param obj The pwmout object to initialize - * @param pinmap pointer to structure which holds static pinmap - */ -void pwmout_init_direct(pwmout_t *obj, const PinMap *pinmap); - -/** Initialize the pwm out peripheral and configure the pin - * - * @param obj The pwmout object to initialize - * @param pin The pwmout pin to initialize - */ -void pwmout_init(pwmout_t *obj, PinName pin); - -/** Deinitialize the pwmout object - * - * @param obj The pwmout object - */ -void pwmout_free(pwmout_t *obj); - -/** Set the output duty-cycle in range <0.0f, 1.0f> - * - * Value 0.0f represents 0 percentage, 1.0f represents 100 percent. - * @param obj The pwmout object - * @param percent The floating-point percentage number - */ -void pwmout_write(pwmout_t *obj, float percent); - -/** Read the current float-point output duty-cycle - * - * @param obj The pwmout object - * @return A floating-point output duty-cycle - */ -float pwmout_read(pwmout_t *obj); - -/** Set the PWM period specified in seconds, keeping the duty cycle the same - * - * Periods smaller than microseconds (the lowest resolution) are set to zero. - * @param obj The pwmout object - * @param seconds The floating-point seconds period - */ -void pwmout_period(pwmout_t *obj, float seconds); - -/** Set the PWM period specified in miliseconds, keeping the duty cycle the same - * - * @param obj The pwmout object - * @param ms The milisecond period - */ -void pwmout_period_ms(pwmout_t *obj, int ms); - -/** Set the PWM period specified in microseconds, keeping the duty cycle the same - * - * @param obj The pwmout object - * @param us The microsecond period - */ -void pwmout_period_us(pwmout_t *obj, int us); - -/** Set the PWM pulsewidth specified in seconds, keeping the period the same. - * - * @param obj The pwmout object - * @param seconds The floating-point pulsewidth in seconds - */ -void pwmout_pulsewidth(pwmout_t *obj, float seconds); - -/** Set the PWM pulsewidth specified in miliseconds, keeping the period the same. - * - * @param obj The pwmout object - * @param ms The floating-point pulsewidth in miliseconds - */ -void pwmout_pulsewidth_ms(pwmout_t *obj, int ms); - -/** Set the PWM pulsewidth specified in microseconds, keeping the period the same. - * - * @param obj The pwmout object - * @param us The floating-point pulsewidth in microseconds - */ -void pwmout_pulsewidth_us(pwmout_t *obj, int us); - -/** Get the pins that support PWM - * - * Return a PinMap array of pins that support PWM. - * The array is terminated with {NC, NC, 0}. - * - * @return PinMap array - */ -const PinMap *pwmout_pinmap(void); - -/**@}*/ - -#ifdef __cplusplus -} -#endif - -#endif - -#endif - -/** @}*/ diff --git a/hal/qspi_api.h b/hal/qspi_api.h deleted file mode 100644 index f753de2..0000000 --- a/hal/qspi_api.h +++ /dev/null @@ -1,282 +0,0 @@ - -/** \addtogroup hal */ -/** @{*/ -/* mbed Microcontroller Library - * Copyright (c) 2017 ARM Limited - * 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. - */ -#ifndef MBED_QSPI_API_H -#define MBED_QSPI_API_H - -#include "device.h" -#include "pinmap.h" -#include - -#if DEVICE_QSPI - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * \defgroup hal_qspi QSPI HAL - * @{ - */ - -/** QSPI HAL object - */ -typedef struct qspi_s qspi_t; - -typedef struct { - int peripheral; - PinName data0_pin; - int data0_function; - PinName data1_pin; - int data1_function; - PinName data2_pin; - int data2_function; - PinName data3_pin; - int data3_function; - PinName sclk_pin; - int sclk_function; - PinName ssel_pin; - int ssel_function; -} qspi_pinmap_t; - -/** QSPI Bus width - * - * Some parts of commands provide variable bus width - */ -typedef enum qspi_bus_width { - QSPI_CFG_BUS_SINGLE, - QSPI_CFG_BUS_DUAL, - QSPI_CFG_BUS_QUAD, -} qspi_bus_width_t; - -/** Address size in bits - */ -typedef enum qspi_address_size { - QSPI_CFG_ADDR_SIZE_8, - QSPI_CFG_ADDR_SIZE_16, - QSPI_CFG_ADDR_SIZE_24, - QSPI_CFG_ADDR_SIZE_32, -} qspi_address_size_t; - -/** Alternative size in bits - */ -typedef uint8_t qspi_alt_size_t; - -// The following defines are provided for backwards compatibilty. New code should explicitly -// specify the required number of alt bits. -#define QSPI_CFG_ALT_SIZE_8 8u -#define QSPI_CFG_ALT_SIZE_16 16u -#define QSPI_CFG_ALT_SIZE_24 24u -#define QSPI_CFG_ALT_SIZE_32 32u - -/** QSPI command - * - * Defines a frame format. It consists of instruction, address, alternative, dummy count and data - */ -typedef struct qspi_command { - struct { - qspi_bus_width_t bus_width; /**< Bus width for the instruction >*/ - uint8_t value; /**< Instruction value >*/ - bool disabled; /**< Instruction phase skipped if disabled is set to true >*/ - } instruction; - struct { - qspi_bus_width_t bus_width; /**< Bus width for the address >*/ - qspi_address_size_t size; /**< Address size >*/ - uint32_t value; /**< Address value >*/ - bool disabled; /**< Address phase skipped if disabled is set to true >*/ - } address; - struct { - qspi_bus_width_t bus_width; /**< Bus width for alternative >*/ - qspi_alt_size_t size; /**< Alternative size >*/ - uint32_t value; /**< Alternative value >*/ - bool disabled; /**< Alternative phase skipped if disabled is set to true >*/ - } alt; - uint8_t dummy_count; /**< Dummy cycles count >*/ - struct { - qspi_bus_width_t bus_width; /**< Bus width for data >*/ - } data; -} qspi_command_t; - -/** QSPI return status - */ -typedef enum qspi_status { - QSPI_STATUS_ERROR = -1, /**< Generic error >*/ - QSPI_STATUS_INVALID_PARAMETER = -2, /**< The parameter is invalid >*/ - QSPI_STATUS_OK = 0, /**< Function executed sucessfully >*/ -} qspi_status_t; - -/** Initialize QSPI peripheral. - * - * It should initialize QSPI pins (io0-io3, sclk and ssel), set frequency, clock polarity and phase mode. The clock for the peripheral should be enabled - * - * @param obj QSPI object - * @param io0 Data pin 0 - * @param io1 Data pin 1 - * @param io2 Data pin 2 - * @param io3 Data pin 3 - * @param sclk The clock pin - * @param ssel The chip select pin - * @param hz The bus frequency - * @param mode Clock polarity and phase mode (0 - 3) - * @return QSPI_STATUS_OK if initialisation successfully executed - QSPI_STATUS_INVALID_PARAMETER if invalid parameter found - QSPI_STATUS_ERROR otherwise - */ -qspi_status_t qspi_init(qspi_t *obj, PinName io0, PinName io1, PinName io2, PinName io3, PinName sclk, PinName ssel, uint32_t hz, uint8_t mode); - -/** Initialize QSPI peripheral. - * - * It should initialize QSPI pins (io0-io3, sclk and ssel), set frequency, clock polarity and phase mode. The clock for the peripheral should be enabled - * - * @param obj QSPI object - * @param pinmap pointer to structure which holds static pinmap - * @param hz The bus frequency - * @param mode Clock polarity and phase mode (0 - 3) - * @return QSPI_STATUS_OK if initialisation successfully executed - QSPI_STATUS_INVALID_PARAMETER if invalid parameter found - QSPI_STATUS_ERROR otherwise - */ -qspi_status_t qspi_init_direct(qspi_t *obj, const qspi_pinmap_t *pinmap, uint32_t hz, uint8_t mode); - -/** Deinitilize QSPI peripheral - * - * It should release pins that are associated with the QSPI object, and disable clocks for QSPI peripheral module that was associated with the object - * - * @param obj QSPI object - * @return QSPI_STATUS_OK if deinitialisation successfully executed - QSPI_STATUS_INVALID_PARAMETER if invalid parameter found - QSPI_STATUS_ERROR otherwise - */ -qspi_status_t qspi_free(qspi_t *obj); - -/** Set the QSPI baud rate - * - * Actual frequency may differ from the desired frequency due to available dividers and the bus clock - * Configures the QSPI peripheral's baud rate - * @param obj The SPI object to configure - * @param hz The baud rate in Hz - * @return QSPI_STATUS_OK if frequency was set - QSPI_STATUS_INVALID_PARAMETER if invalid parameter found - QSPI_STATUS_ERROR otherwise - */ -qspi_status_t qspi_frequency(qspi_t *obj, int hz); - -/** Send a command and block of data - * - * @param obj QSPI object - * @param command QSPI command - * @param data TX buffer - * @param[in,out] length in - TX buffer length in bytes, out - number of bytes written - * @return QSPI_STATUS_OK if the data has been succesfully sent - QSPI_STATUS_INVALID_PARAMETER if invalid parameter found - QSPI_STATUS_ERROR otherwise - */ -qspi_status_t qspi_write(qspi_t *obj, const qspi_command_t *command, const void *data, size_t *length); - -/** Send a command (and optionally data) and get the response. Can be used to send/receive device specific commands - * - * @param obj QSPI object - * @param command QSPI command - * @param tx_data TX buffer - * @param tx_size TX buffer length in bytes - * @param rx_data RX buffer - * @param rx_size RX buffer length in bytes - * @return QSPI_STATUS_OK if the data has been succesfully sent - QSPI_STATUS_INVALID_PARAMETER if invalid parameter found - QSPI_STATUS_ERROR otherwise - */ -qspi_status_t qspi_command_transfer(qspi_t *obj, const qspi_command_t *command, const void *tx_data, size_t tx_size, void *rx_data, size_t rx_size); - -/** Receive a command and block of data - * - * @param obj QSPI object - * @param command QSPI command - * @param data RX buffer - * @param[in,out] length in - RX buffer length in bytes, out - number of bytes read - * @return QSPI_STATUS_OK if data has been succesfully received - QSPI_STATUS_INVALID_PARAMETER if invalid parameter found - QSPI_STATUS_ERROR otherwise - */ -qspi_status_t qspi_read(qspi_t *obj, const qspi_command_t *command, void *data, size_t *length); - -/** Get the pins that support QSPI SCLK - * - * Return a PinMap array of pins that support QSPI SCLK in - * master mode. The array is terminated with {NC, NC, 0}. - * - * @return PinMap array - */ -const PinMap *qspi_master_sclk_pinmap(void); - -/** Get the pins that support QSPI SSEL - * - * Return a PinMap array of pins that support QSPI SSEL in - * master mode. The array is terminated with {NC, NC, 0}. - * - * @return PinMap array - */ -const PinMap *qspi_master_ssel_pinmap(void); - -/** Get the pins that support QSPI DATA0 - * - * Return a PinMap array of pins that support QSPI DATA0 in - * master mode. The array is terminated with {NC, NC, 0}. - * - * @return PinMap array - */ -const PinMap *qspi_master_data0_pinmap(void); - -/** Get the pins that support QSPI DATA1 - * - * Return a PinMap array of pins that support QSPI DATA1 in - * master mode. The array is terminated with {NC, NC, 0}. - * - * @return PinMap array - */ -const PinMap *qspi_master_data1_pinmap(void); - -/** Get the pins that support QSPI DATA2 - * - * Return a PinMap array of pins that support QSPI DATA2 in - * master mode. The array is terminated with {NC, NC, 0}. - * - * @return PinMap array - */ -const PinMap *qspi_master_data2_pinmap(void); - -/** Get the pins that support QSPI DATA3 - * - * Return a PinMap array of pins that support QSPI DATA3 in - * master mode. The array is terminated with {NC, NC, 0}. - * - * @return PinMap array - */ -const PinMap *qspi_master_data3_pinmap(void); - -/**@}*/ - -#ifdef __cplusplus -} -#endif - -#endif - -#endif - -/** @}*/ diff --git a/hal/reset_reason_api.h b/hal/reset_reason_api.h deleted file mode 100644 index 23bb402..0000000 --- a/hal/reset_reason_api.h +++ /dev/null @@ -1,162 +0,0 @@ -/** \addtogroup hal */ -/** @{*/ -/* - * Copyright (c) 2018-2019 Arm Limited and affiliates. - * 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. - */ -#ifndef MBED_RESET_REASON_API_H -#define MBED_RESET_REASON_API_H - -#if DEVICE_RESET_REASON - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * \defgroup hal_reset_reason ResetReason HAL API - * Low-level interface to the ResetReason of a target. - * - * This module provides a platform-independent method of checking the cause - * of the last system reset. - * - * # Defined behavior - * * The function ::hal_reset_reason_clear clears the ResetReason registers - * for the next system boot. - * * By the time the user calls ::hal_reset_reason_get to read the value, - * some other part of the application may have cleared the value. Therefore, - * though there may have been a reset reason in the registers when the system - * started, the reason may not be available when the user comes to check it. - * * The function ::hal_reset_reason_get_capabilities fills the given - * `reset_reason_capabilities_t` instance. - * - * # Undefined behavior - * * There is no guarantee that the function ::hal_reset_reason_get will - * return the same value when you call it repeatedly. Store the value for later - * use instead of calling the function repeatedly. - * * The function ::hal_reset_reason_clear may not clear the ResetReason - * register in time for the next system boot. - * - * # Notes - * * The contents of the targets ResetReason register may be cleared by some - * subsystem before it first gets called. This returns a ::RESET_REASON_UNKNOWN - * value to the user. To avoid this, the user should call the ResetReason API - * as early as possible at boot time. - * * If the target doesn't support clearing reset registers, - * ::hal_reset_reason_get seems to erroneously return a reset reason even after - * clearing. - * - * @{ - */ - -/** - * \defgroup hal_reset_reason_tests ResetReason HAL tests - * Greentea tests for the ResetReason HAL. - * - * To run the ResetReason HAL tests, use the command: - * - * mbed test -t -m -n tests-mbed_hal-reset_reason - * - */ - -/** Definitions of different reset reasons - */ -typedef enum { - RESET_REASON_POWER_ON, /**< Set when power is initially applied to the board. The power-on-reset circuit causes a POWER_ON reset when this occurs */ - RESET_REASON_PIN_RESET, /**< Set when a reset is triggered by the hardware pin on the board */ - RESET_REASON_BROWN_OUT, /**< Triggered when the voltage drops below the low voltage detect (LVD) threshold; the system is held in a reset until the voltage rises above the threshold */ - RESET_REASON_SOFTWARE, /**< Set during software reset, typically triggered by writing the SYSRESETREQ bit in the Application Interrupt and Reset Control register */ - RESET_REASON_WATCHDOG, /**< Set when a running watchdog timer fails to be refreshed */ - RESET_REASON_LOCKUP, /**< Set when the core is locked because of an unrecoverable exception */ - RESET_REASON_WAKE_LOW_POWER, /**< Set when waking from deep sleep mode */ - RESET_REASON_ACCESS_ERROR, /**< Umbrella value that encompasses any access related reset */ - RESET_REASON_BOOT_ERROR, /**< Umbrella value that encompasses any boot related reset */ - RESET_REASON_MULTIPLE, /**< Set if multiple reset reasons are set within the board. Occurs when the reset reason registers aren't cleared between resets */ - RESET_REASON_PLATFORM, /**< Platform specific reset reason not captured in this enum */ - RESET_REASON_UNKNOWN /**< Unknown or unreadable reset reason **/ -} reset_reason_t; - -/** Reset reason capabilities of the platform - */ -typedef struct { - uint32_t reasons; /**< Supported reset reasons. Each bit represents a corresponding reset_reason_t value.**/ -} reset_reason_capabilities_t; - -/** Fetch the reset reason for the last system reset. - * - * This function must return the contents of the system reset reason registers - * cast to an appropriate platform independent reset reason. If multiple reset - * reasons are set, this function should return ::RESET_REASON_MULTIPLE. If the - * reset reason does not match any existing platform independent value, this - * function should return ::RESET_REASON_PLATFORM. If no reset reason can be - * determined, this function should return ::RESET_REASON_UNKNOWN. - * - * This function is not idempotent; there is no guarantee the system - * reset reason will not be cleared between calls to this function altering the - * return value between calls. - * - * Note: Some platforms contain reset reason registers that persist through - * system resets. If the registers haven't been cleared before calling this - * function, multiple reasons may be set within the registers. If multiple reset - * reasons are detected, this function returns ::RESET_REASON_MULTIPLE. - * - * @return enum containing the last reset reason for the board. - */ -reset_reason_t hal_reset_reason_get(void); - - -/** Fetch the raw platform specific reset reason register value. - * - * This function must return the raw contents of the system reset reason - * registers cast to a uint32_t value. If the platform contains reset reasons - * that span multiple registers/addresses, the value should be concatenated into - * the return type. - * - * This function is not idempotent; there is no guarantee the system - * reset reason will not be cleared between calls to this function altering the - * return value between calls. - * - * @return value containing the reset reason register for the given platform. - * If the platform contains reset reasons across multiple registers, they - * will be concatenated here. - */ -uint32_t hal_reset_reason_get_raw(void); - -/** Clear the reset reason from registers. - * - * Reset the value of the reset status registers. The reset reason persists - * between system resets on certain platforms, so the registers should be cleared - * before the system resets. Failing to do so may make it difficult to determine - * the cause of any subsequent system resets. - */ -void hal_reset_reason_clear(void); - -/** Fill the given reset_reason_capabilities_t instance according to platform capabilities. - */ -void hal_reset_reason_get_capabilities(reset_reason_capabilities_t *cap); - -/**@}*/ - -#ifdef __cplusplus -} -#endif - -#endif // DEVICE_RESET_REASON - -#endif // MBED_RESET_REASON_API_H - -/** @}*/ diff --git a/hal/rtc_api.h b/hal/rtc_api.h deleted file mode 100644 index 5685f88..0000000 --- a/hal/rtc_api.h +++ /dev/null @@ -1,188 +0,0 @@ -/* mbed Microcontroller Library - * Copyright (c) 2006-2013 ARM Limited - * 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. - */ - -/** \addtogroup hal */ -/** @{*/ - -#ifndef MBED_RTC_API_H -#define MBED_RTC_API_H - -#include "device.h" - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * \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 -m -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 - * - * 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); - -/** Check if the RTC has the time set and is counting - * - * @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 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); - -/** Write the current time in seconds to the RTC peripheral - * - * @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); - -/**@}*/ - -#ifdef __cplusplus -} -#endif - -#endif - -/** @}*/ diff --git a/hal/serial_api.h b/hal/serial_api.h deleted file mode 100644 index 78a1ee8..0000000 --- a/hal/serial_api.h +++ /dev/null @@ -1,466 +0,0 @@ - -/** \addtogroup hal */ -/** @{*/ -/* mbed Microcontroller Library - * Copyright (c) 2006-2013 ARM Limited - * 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. - */ -#ifndef MBED_SERIAL_API_H -#define MBED_SERIAL_API_H - -#include "device.h" -#include "pinmap.h" -#include "hal/buffer.h" -#include "hal/dma_api.h" - -#if DEVICE_SERIAL - -#define SERIAL_EVENT_TX_SHIFT (2) -#define SERIAL_EVENT_RX_SHIFT (8) - -#define SERIAL_EVENT_TX_MASK (0x00FC) -#define SERIAL_EVENT_RX_MASK (0x3F00) - -#define SERIAL_EVENT_ERROR (1 << 1) - -/** - * @defgroup SerialTXEvents Serial TX Events Macros - * - * @{ - */ -#define SERIAL_EVENT_TX_COMPLETE (1 << (SERIAL_EVENT_TX_SHIFT + 0)) -#define SERIAL_EVENT_TX_ALL (SERIAL_EVENT_TX_COMPLETE) -/**@}*/ - -/** - * @defgroup SerialRXEvents Serial RX Events Macros - * - * @{ - */ -#define SERIAL_EVENT_RX_COMPLETE (1 << (SERIAL_EVENT_RX_SHIFT + 0)) -#define SERIAL_EVENT_RX_OVERRUN_ERROR (1 << (SERIAL_EVENT_RX_SHIFT + 1)) -#define SERIAL_EVENT_RX_FRAMING_ERROR (1 << (SERIAL_EVENT_RX_SHIFT + 2)) -#define SERIAL_EVENT_RX_PARITY_ERROR (1 << (SERIAL_EVENT_RX_SHIFT + 3)) -#define SERIAL_EVENT_RX_OVERFLOW (1 << (SERIAL_EVENT_RX_SHIFT + 4)) -#define SERIAL_EVENT_RX_CHARACTER_MATCH (1 << (SERIAL_EVENT_RX_SHIFT + 5)) -#define SERIAL_EVENT_RX_ALL (SERIAL_EVENT_RX_OVERFLOW | SERIAL_EVENT_RX_PARITY_ERROR | \ - SERIAL_EVENT_RX_FRAMING_ERROR | SERIAL_EVENT_RX_OVERRUN_ERROR | \ - SERIAL_EVENT_RX_COMPLETE | SERIAL_EVENT_RX_CHARACTER_MATCH) -/**@}*/ - -#define SERIAL_RESERVED_CHAR_MATCH (255) - -typedef enum { - ParityNone = 0, - ParityOdd = 1, - ParityEven = 2, - ParityForced1 = 3, - ParityForced0 = 4 -} SerialParity; - -/** Serial interrupt sources - */ -typedef enum { - RxIrq, /**< Receive Data Register Full */ - TxIrq /**< Transmit Data Register Empty */ -} SerialIrq; - -typedef enum { - FlowControlNone, - FlowControlRTS, - FlowControlCTS, - FlowControlRTSCTS -} FlowControl; - -typedef void (*uart_irq_handler)(uint32_t id, SerialIrq event); - -#if DEVICE_SERIAL_ASYNCH -/** Asynch serial HAL structure - */ -typedef struct { - struct serial_s serial; /**< Target specific serial structure */ - struct buffer_s tx_buff; /**< TX buffer */ - struct buffer_s rx_buff; /**< RX buffer */ - uint8_t char_match; /**< Character to be matched */ - uint8_t char_found; /**< State of the matched character */ -} serial_t; - -#else -/** Non-asynch serial HAL structure - */ -typedef struct serial_s serial_t; - -#endif - -typedef struct { - int peripheral; - PinName tx_pin; - int tx_function; - PinName rx_pin; - int rx_function; - bool stdio_config; -} serial_pinmap_t; - -typedef struct { - int peripheral; - PinName tx_flow_pin; - int tx_flow_function; - PinName rx_flow_pin; - int rx_flow_function; -} serial_fc_pinmap_t; - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * \defgroup hal_GeneralSerial Serial Configuration Functions - * - * # Defined behavior - * * ::serial_init initializes the ::serial_t - * * ::serial_init sets the default parameters for serial peripheral (9600 bps, 8N1 format) - * * ::serial_init configures the specified pins - * * ::serial_free releases the serial peripheral - * * ::serial_baud configures the baud rate - * * at least 9600 bps the baud rate must be supported - * * ::serial_format configures the transmission format (number of bits, parity and the number of stop bits) - * * at least 8N1 format must be supported - * * ::serial_irq_handler registers the interrupt handler which will be invoked when the interrupt fires. - * * ::serial_irq_set enables or disables the serial RX or TX IRQ. - * * If `RxIrq` is enabled by ::serial_irq_set, ::serial_irq_handler will be invoked whenever - * Receive Data Register Full IRQ is generated. - * * If `TxIrq` is enabled by ::serial_irq_set, ::serial_irq_handler will be invoked whenever - * Transmit Data Register Empty IRQ is generated. - * * If the interrupt condition holds true, when the interrupt is enabled with ::serial_irq_set, - * the ::serial_irq_handler is called instantly. - * * ::serial_getc returns the character from serial buffer. - * * ::serial_getc is a blocking call (waits for the character). - * * ::serial_putc sends a character. - * * ::serial_putc is a blocking call (waits for a peripheral to be available). - * * ::serial_readable returns non-zero value if a character can be read, 0 otherwise. - * * ::serial_writable returns non-zero value if a character can be written, 0 otherwise. - * * ::serial_clear clears the ::serial_t RX/TX buffers - * * ::serial_break_set sets the break signal. - * * ::serial_break_clear clears the break signal. - * * ::serial_pinout_tx configures the TX pin as an output (to be used in half-duplex mode). - * * ::serial_set_flow_control configures serial flow control. - * * ::serial_set_flow_control sets flow control in the hardware if a serial peripheral supports it, - * otherwise software emulation is used. - * * ::serial_tx_asynch starts the serial asynchronous transfer. - * * ::serial_tx_asynch writes `tx_length` bytes from the `tx` to the bus. - * * ::serial_tx_asynch must support 8 data bits - * * The callback given to ::serial_tx_asynch is invoked when the transfer completes. - * * ::serial_tx_asynch specifies the logical OR of events to be registered. - * * The ::serial_tx_asynch function may use the `DMAUsage` hint to select the appropriate async algorithm. - * * ::serial_rx_asynch starts the serial asynchronous transfer. - * * ::serial_rx_asynch reads `rx_length` bytes to the `rx` buffer. - * * ::serial_rx_asynch must support 8 data bits - * * The callback given to ::serial_rx_asynch is invoked when the transfer completes. - * * ::serial_rx_asynch specifies the logical OR of events to be registered. - * * The ::serial_rx_asynch function may use the `DMAUsage` hint to select the appropriate async algorithm. - * * ::serial_rx_asynch specifies a character in range 0-254 to be matched, 255 is a reserved value. - * * If SERIAL_EVENT_RX_CHARACTER_MATCH event is not registered, the `char_match` is ignored. - * * The SERIAL_EVENT_RX_CHARACTER_MATCH event is set in the callback when SERIAL_EVENT_RX_CHARACTER_MATCH event is - * registered AND `char_match` is present in the received data. - * * ::serial_tx_active returns non-zero if the TX transaction is ongoing, 0 otherwise. - * * ::serial_rx_active returns non-zero if the RX transaction is ongoing, 0 otherwise. - * * ::serial_irq_handler_asynch returns event flags if a transfer termination condition was met, otherwise returns 0. - * * ::serial_irq_handler_asynch takes no longer than one packet transfer time (packet_bits / baudrate) to execute. - * * ::serial_tx_abort_asynch aborts the ongoing TX transaction. - * * ::serial_tx_abort_asynch disables the enabled interupt for TX. - * * ::serial_tx_abort_asynch flushes the TX hardware buffer if TX FIFO is used. - * * ::serial_rx_abort_asynch aborts the ongoing RX transaction. - * * ::serial_rx_abort_asynch disables the enabled interupt for RX. - * * ::serial_rx_abort_asynch flushes the TX hardware buffer if RX FIFO is used. - * * Correct operation guaranteed when interrupt latency is shorter than one packet transfer time (packet_bits / baudrate) - * if the flow control is not used. - * * Correct operation guaranteed regardless of interrupt latency if the flow control is used. - * - * # Undefined behavior - * * Calling ::serial_init multiple times on the same `serial_t` without ::serial_free. - * * Passing invalid pin to ::serial_init, ::serial_pinout_tx. - * * Calling any function other than ::serial_init on am uninitialized or freed `serial_t`. - * * Passing an invalid pointer as `obj` to any function. - * * Passing an invalid pointer as `handler` to ::serial_irq_handler, ::serial_tx_asynch, ::serial_rx_asynch. - * * Calling ::serial_tx_abort while no async TX transfer is being processed. - * * Calling ::serial_rx_abort while no async RX transfer is being processed. - * * Devices behavior is undefined when the interrupt latency is longer than one packet transfer time - * (packet_bits / baudrate) if the flow control is not used. - * @{ - */ - -/** - * \defgroup hal_GeneralSerial_tests Serial hal tests - * The Serial HAL tests ensure driver conformance to defined behavior. - * - * To run the Serial hal tests use the command: - * - * mbed test -t -m -n tests-mbed_hal_fpga_ci_test_shield-uart - * - */ - -/** Initialize the serial peripheral. It sets the default parameters for serial - * peripheral, and configures its specifieds pins. - * - * @param obj The serial object - * @param tx The TX pin name - * @param rx The RX pin name - */ -void serial_init(serial_t *obj, PinName tx, PinName rx); - -/** Initialize the serial peripheral. It sets the default parameters for serial - * peripheral, and configures its specifieds pins. - * - * @param obj The serial object - * @param pinmap pointer to structure which holds static pinmap - */ -void serial_init_direct(serial_t *obj, const serial_pinmap_t *pinmap); - - -/** Release the serial peripheral, not currently invoked. It requires further - * resource management. - * - * @param obj The serial object - */ -void serial_free(serial_t *obj); - -/** Configure the baud rate - * - * @param obj The serial object - * @param baudrate The baud rate to be configured - */ -void serial_baud(serial_t *obj, int baudrate); - -/** Configure the format. Set the number of bits, parity and the number of stop bits - * - * @param obj The serial object - * @param data_bits The number of data bits - * @param parity The parity - * @param stop_bits The number of stop bits - */ -void serial_format(serial_t *obj, int data_bits, SerialParity parity, int stop_bits); - -/** The serial interrupt handler registration - * - * @param obj The serial object - * @param handler The interrupt handler which will be invoked when the interrupt fires - * @param id The SerialBase object - */ -void serial_irq_handler(serial_t *obj, uart_irq_handler handler, uint32_t id); - -/** Configure serial interrupt. This function is used for word-approach - * - * @param obj The serial object - * @param irq The serial IRQ type (RX or TX) - * @param enable Set to non-zero to enable events, or zero to disable them - */ -void serial_irq_set(serial_t *obj, SerialIrq irq, uint32_t enable); - -/** Get character. This is a blocking call, waiting for a character - * - * @param obj The serial object - */ -int serial_getc(serial_t *obj); - -/** Send a character. This is a blocking call, waiting for a peripheral to be available - * for writing - * - * @param obj The serial object - * @param c The character to be sent - */ -void serial_putc(serial_t *obj, int c); - -/** Check if the serial peripheral is readable - * - * @param obj The serial object - * @return Non-zero value if a character can be read, 0 if nothing to read - */ -int serial_readable(serial_t *obj); - -/** Check if the serial peripheral is writable - * - * @param obj The serial object - * @return Non-zero value if a character can be written, 0 otherwise. - */ -int serial_writable(serial_t *obj); - -/** Clear the serial peripheral - * - * @param obj The serial object - */ -void serial_clear(serial_t *obj); - -/** Set the break - * - * @param obj The serial object - */ -void serial_break_set(serial_t *obj); - -/** Clear the break - * - * @param obj The serial object - */ -void serial_break_clear(serial_t *obj); - -/** Configure the TX pin for UART function. - * - * @param tx The pin name used for TX - */ -void serial_pinout_tx(PinName tx); - -#if DEVICE_SERIAL_FC -/** Configure the serial for the flow control. It sets flow control in the hardware - * if a serial peripheral supports it, otherwise software emulation is used. - * - * @param obj The serial object - * @param type The type of the flow control. Look at the available FlowControl types. - * @param rxflow The TX pin name - * @param txflow The RX pin name - */ -void serial_set_flow_control(serial_t *obj, FlowControl type, PinName rxflow, PinName txflow); - -/** Configure the serial for the flow control. It sets flow control in the hardware - * if a serial peripheral supports it, otherwise software emulation is used. - * - * @param obj The serial object - * @param type The type of the flow control. Look at the available FlowControl types. - * @param pinmap Pointer to structure which holds static pinmap - */ -void serial_set_flow_control_direct(serial_t *obj, FlowControl type, const serial_fc_pinmap_t *pinmap); -#endif - -/** Get the pins that support Serial TX - * - * Return a PinMap array of pins that support Serial TX. The - * array is terminated with {NC, NC, 0}. - * - * @return PinMap array - */ -const PinMap *serial_tx_pinmap(void); - -/** Get the pins that support Serial RX - * - * Return a PinMap array of pins that support Serial RX. The - * array is terminated with {NC, NC, 0}. - * - * @return PinMap array - */ -const PinMap *serial_rx_pinmap(void); - -#if DEVICE_SERIAL_FC -/** Get the pins that support Serial CTS - * - * Return a PinMap array of pins that support Serial CTS. The - * array is terminated with {NC, NC, 0}. - * - * @return PinMap array - */ -const PinMap *serial_cts_pinmap(void); - -/** Get the pins that support Serial RTS - * - * Return a PinMap array of pins that support Serial RTS. The - * array is terminated with {NC, NC, 0}. - * - * @return PinMap array - */ -const PinMap *serial_rts_pinmap(void); -#endif - -#if DEVICE_SERIAL_ASYNCH - -/**@}*/ - -/** - * \defgroup hal_AsynchSerial Asynchronous Serial Hardware Abstraction Layer - * @{ - */ - -/** Begin asynchronous TX transfer. The used buffer is specified in the serial object, - * tx_buff - * - * @param obj The serial object - * @param tx The transmit buffer - * @param tx_length The number of bytes to transmit - * @param tx_width Deprecated argument - * @param handler The serial handler - * @param event The logical OR of events to be registered - * @param hint A suggestion for how to use DMA with this transfer - * @return Returns number of data transfered, otherwise returns 0 - */ -int serial_tx_asynch(serial_t *obj, const void *tx, size_t tx_length, uint8_t tx_width, uint32_t handler, uint32_t event, DMAUsage hint); - -/** Begin asynchronous RX transfer (enable interrupt for data collecting) - * The used buffer is specified in the serial object - rx_buff - * - * @param obj The serial object - * @param rx The receive buffer - * @param rx_length The number of bytes to receive - * @param rx_width Deprecated argument - * @param handler The serial handler - * @param event The logical OR of events to be registered - * @param char_match A character in range 0-254 to be matched - * @param hint A suggestion for how to use DMA with this transfer - */ -void serial_rx_asynch(serial_t *obj, void *rx, size_t rx_length, uint8_t rx_width, uint32_t handler, uint32_t event, uint8_t char_match, DMAUsage hint); - -/** Attempts to determine if the serial peripheral is already in use for TX - * - * @param obj The serial object - * @return Non-zero if the RX transaction is ongoing, 0 otherwise - */ -uint8_t serial_tx_active(serial_t *obj); - -/** Attempts to determine if the serial peripheral is already in use for RX - * - * @param obj The serial object - * @return Non-zero if the RX transaction is ongoing, 0 otherwise - */ -uint8_t serial_rx_active(serial_t *obj); - -/** The asynchronous TX and RX handler. - * - * @param obj The serial object - * @return Returns event flags if an RX transfer termination condition was met; otherwise returns 0 - */ -int serial_irq_handler_asynch(serial_t *obj); - -/** Abort the ongoing TX transaction. It disables the enabled interupt for TX and - * flushes the TX hardware buffer if TX FIFO is used - * - * @param obj The serial object - */ -void serial_tx_abort_asynch(serial_t *obj); - -/** Abort the ongoing RX transaction. It disables the enabled interrupt for RX and - * flushes the RX hardware buffer if RX FIFO is used - * - * @param obj The serial object - */ -void serial_rx_abort_asynch(serial_t *obj); - -/**@}*/ - -#endif - -#ifdef __cplusplus -} -#endif - -#endif - -#endif - -/** @}*/ diff --git a/hal/sleep_api.h b/hal/sleep_api.h deleted file mode 100644 index 1dd2d0d..0000000 --- a/hal/sleep_api.h +++ /dev/null @@ -1,103 +0,0 @@ - -/** \addtogroup hal */ -/** @{*/ -/* mbed Microcontroller Library - * Copyright (c) 2006-2013 ARM Limited - * 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. - */ -#ifndef MBED_SLEEP_API_H -#define MBED_SLEEP_API_H - -#include "device.h" - -#if DEVICE_SLEEP - -#ifdef __cplusplus -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 -m -n tests-mbed_hal-sleep* - * - */ - -/** Send the microcontroller to sleep - * - * 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. - * - * 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 high frequency clocks. - * All state is still maintained. - * - * The processor can only be woken up by low power ticker, RTC, an external interrupt on a pin or a watchdog timer. - * - * The wake-up time shall be less than 10 ms. - */ -void hal_deepsleep(void); - -/**@}*/ - -#ifdef __cplusplus -} -#endif - -#endif - -#endif - -/**@}*/ diff --git a/hal/source/LowPowerTickerWrapper.cpp b/hal/source/LowPowerTickerWrapper.cpp new file mode 100644 index 0000000..0f03a41 --- /dev/null +++ b/hal/source/LowPowerTickerWrapper.cpp @@ -0,0 +1,318 @@ +/* mbed Microcontroller Library + * Copyright (c) 2018 ARM Limited + * 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. + */ +#include "hal/LowPowerTickerWrapper.h" +#include "platform/Callback.h" + +using namespace mbed::chrono; + +LowPowerTickerWrapper::LowPowerTickerWrapper(const ticker_data_t *data, const ticker_interface_t *interface, uint32_t min_cycles_between_writes, uint32_t min_cycles_until_match) + : _intf(data->interface), _min_count_between_writes(min_cycles_between_writes + 1), _min_count_until_match(min_cycles_until_match + 1), _suspended(false) +{ + core_util_critical_section_enter(); + + this->data.interface = interface; + this->data.queue = data->queue; + _reset(); + + core_util_critical_section_exit(); +} + +void LowPowerTickerWrapper::irq_handler(ticker_irq_handler_type handler) +{ + core_util_critical_section_enter(); + + // This code no longer filters out early interrupts. Instead it + // passes them through to the next layer and ignores further interrupts + // until the next call to set_interrrupt or fire_interrupt (when not suspended). + // This is to ensure that the device doesn't get stuck in sleep due to an + // early low power ticker interrupt that was ignored. + if (_pending_fire_now || _pending_match || _suspended) { + _timeout.detach(); + _pending_timeout = false; + _pending_match = false; + _pending_fire_now = false; + if (handler) { + handler(&data); + } + } else { + // Spurious interrupt + _intf->clear_interrupt(); + } + + core_util_critical_section_exit(); +} + +void LowPowerTickerWrapper::suspend() +{ + core_util_critical_section_enter(); + + // Wait until rescheduling is allowed + while (!_set_interrupt_allowed) { + timestamp_t current = _intf->read(); + if (((current - _last_actual_set_interrupt) & _mask) >= _min_count_between_writes) { + _set_interrupt_allowed = true; + } + } + + _reset(); + _suspended = true; + + core_util_critical_section_exit(); +} + +void LowPowerTickerWrapper::resume() +{ + core_util_critical_section_enter(); + + // Wait until rescheduling is allowed + while (!_set_interrupt_allowed) { + timestamp_t current = _intf->read(); + if (((current - _last_actual_set_interrupt) & _mask) >= _min_count_between_writes) { + _set_interrupt_allowed = true; + } + } + + _suspended = false; + + core_util_critical_section_exit(); +} + +bool LowPowerTickerWrapper::timeout_pending() +{ + core_util_critical_section_enter(); + + bool pending = _pending_timeout; + + core_util_critical_section_exit(); + return pending; +} + +void LowPowerTickerWrapper::init() +{ + core_util_critical_section_enter(); + + _reset(); + _intf->init(); + + core_util_critical_section_exit(); +} + +void LowPowerTickerWrapper::free() +{ + core_util_critical_section_enter(); + + _reset(); + _intf->free(); + + core_util_critical_section_exit(); +} + +uint32_t LowPowerTickerWrapper::read() +{ + core_util_critical_section_enter(); + + timestamp_t current = _intf->read(); + if (!_suspended && _match_check(current)) { + _intf->fire_interrupt(); + } + + core_util_critical_section_exit(); + return current; +} + +void LowPowerTickerWrapper::set_interrupt(timestamp_t timestamp) +{ + core_util_critical_section_enter(); + + _last_set_interrupt = _intf->read(); + _cur_match_time = timestamp; + _pending_match = true; + if (!_suspended) { + _schedule_match(_last_set_interrupt); + } else { + _intf->set_interrupt(timestamp); + _last_actual_set_interrupt = _last_set_interrupt; + _set_interrupt_allowed = false; + } + + core_util_critical_section_exit(); +} + +void LowPowerTickerWrapper::disable_interrupt() +{ + core_util_critical_section_enter(); + + _intf->disable_interrupt(); + + core_util_critical_section_exit(); +} + +void LowPowerTickerWrapper::clear_interrupt() +{ + core_util_critical_section_enter(); + + _intf->clear_interrupt(); + + core_util_critical_section_exit(); +} + +void LowPowerTickerWrapper::fire_interrupt() +{ + core_util_critical_section_enter(); + + _pending_fire_now = 1; + _intf->fire_interrupt(); + + core_util_critical_section_exit(); +} + +const ticker_info_t *LowPowerTickerWrapper::get_info() +{ + + core_util_critical_section_enter(); + + const ticker_info_t *info = _intf->get_info(); + + core_util_critical_section_exit(); + return info; +} + +void LowPowerTickerWrapper::_reset() +{ + MBED_ASSERT(core_util_in_critical_section()); + + _timeout.detach(); + _pending_timeout = false; + _pending_match = false; + _pending_fire_now = false; + _set_interrupt_allowed = true; + _cur_match_time = 0; + _last_set_interrupt = 0; + _last_actual_set_interrupt = 0; + + const ticker_info_t *info = _intf->get_info(); + if (info->bits >= 32) { + _mask = 0xffffffff; + } else { + _mask = ((uint64_t)1 << info->bits) - 1; + } + + // Round us_per_tick up + _us_per_tick = (1000000 + info->frequency - 1) / info->frequency; +} + +void LowPowerTickerWrapper::_timeout_handler() +{ + core_util_critical_section_enter(); + _pending_timeout = false; + + timestamp_t current = _intf->read(); + /* Add extra check for '_last_set_interrupt == _cur_match_time' + * + * When '_last_set_interrupt == _cur_match_time', _ticker_match_interval_passed sees it as + * one-round interval rather than just-pass, so add extra check for it. In rare cases, we + * may trap in _timeout_handler/_schedule_match loop. This check can break it. + */ + if ((_last_set_interrupt == _cur_match_time) || + _ticker_match_interval_passed(_last_set_interrupt, current, _cur_match_time)) { + _intf->fire_interrupt(); + } else { + _schedule_match(current); + } + + core_util_critical_section_exit(); +} + +bool LowPowerTickerWrapper::_match_check(timestamp_t current) +{ + MBED_ASSERT(core_util_in_critical_section()); + + if (!_pending_match) { + return false; + } + /* Add extra check for '_last_set_interrupt == _cur_match_time' as above */ + return (_last_set_interrupt == _cur_match_time) || + _ticker_match_interval_passed(_last_set_interrupt, current, _cur_match_time); +} + +microseconds_u32 LowPowerTickerWrapper::_lp_ticks_to_us(uint32_t ticks) +{ + MBED_ASSERT(core_util_in_critical_section()); + + // Add 4 microseconds to round up the micro second ticker time (which has a frequency of at least 250KHz - 4us period) + return microseconds_u32(_us_per_tick * ticks + 4); +} + +void LowPowerTickerWrapper::_schedule_match(timestamp_t current) +{ + MBED_ASSERT(core_util_in_critical_section()); + + // Check if _intf->set_interrupt is allowed + if (!_set_interrupt_allowed) { + if (((current - _last_actual_set_interrupt) & _mask) >= _min_count_between_writes) { + _set_interrupt_allowed = true; + } + } + + uint32_t cycles_until_match = (_cur_match_time - current) & _mask; + bool too_close = cycles_until_match < _min_count_until_match; + + if (!_set_interrupt_allowed) { + + // Can't use _intf->set_interrupt so use microsecond Timeout instead + + // Speed optimization - if a timer has already been scheduled + // then don't schedule it again. + if (!_pending_timeout) { + uint32_t ticks = cycles_until_match < _min_count_until_match ? cycles_until_match : _min_count_until_match; + _timeout.attach(mbed::callback(this, &LowPowerTickerWrapper::_timeout_handler), _lp_ticks_to_us(ticks)); + _pending_timeout = true; + } + return; + } + + if (!too_close) { + + // Schedule LP ticker + _intf->set_interrupt(_cur_match_time); + current = _intf->read(); + _last_actual_set_interrupt = current; + _set_interrupt_allowed = false; + + // Check for overflow + uint32_t new_cycles_until_match = (_cur_match_time - current) & _mask; + if (new_cycles_until_match > cycles_until_match) { + // Overflow so fire now + _intf->fire_interrupt(); + return; + } + + // Update variables with new time + cycles_until_match = new_cycles_until_match; + too_close = cycles_until_match < _min_count_until_match; + } + + if (too_close) { + + // Low power ticker incremented to less than _min_count_until_match + // so low power ticker may not fire. Use Timeout to ensure it does fire. + uint32_t ticks = cycles_until_match < _min_count_until_match ? cycles_until_match : _min_count_until_match; + _timeout.attach(mbed::callback(this, &LowPowerTickerWrapper::_timeout_handler), _lp_ticks_to_us(ticks)); + _pending_timeout = true; + return; + } +} diff --git a/hal/source/mbed_compat.c b/hal/source/mbed_compat.c new file mode 100644 index 0000000..1c58414 --- /dev/null +++ b/hal/source/mbed_compat.c @@ -0,0 +1,106 @@ +/* mbed Microcontroller Library + * Copyright (c) 2019 ARM Limited + * 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. + */ + +#include "analogin_api.h" +#include "i2c_api.h" +#include "spi_api.h" +#include "gpio_api.h" +#include "reset_reason_api.h" +#include "mbed_toolchain.h" + +// To be re-implemented in the target layer if required +MBED_WEAK void gpio_free(gpio_t *obj) +{ + // Do nothing +} + +#if DEVICE_I2C +// To be re-implemented in the target layer if required +MBED_WEAK void i2c_free(i2c_t *obj) +{ + // Do nothing +} +#endif + +#if DEVICE_ANALOGIN +// To be re-implemented in the target layer if required +MBED_WEAK void analogin_free(analogin_t *obj) +{ + // Do nothing +} +#endif + +#if DEVICE_SPI +// Default SPI capabilities. If specific target has different capabilities this function needs to be re-implemented. +MBED_WEAK void spi_get_capabilities(PinName ssel, bool slave, spi_capabilities_t *cap) +{ + if (slave) { + cap->minimum_frequency = 200000; // 200 kHz + cap->maximum_frequency = 2000000; // 2 MHz + cap->word_length = 0x00008080; // 8 and 16 bit symbols + cap->support_slave_mode = false; // to be determined later based on ssel + cap->hw_cs_handle = false; // irrelevant in slave mode + cap->slave_delay_between_symbols_ns = 2500; // 2.5 us + cap->clk_modes = 0x0f; // all clock modes + cap->tx_rx_buffers_equal_length = true; // rx buffer size must be equal tx buffer size +#if DEVICE_SPI_ASYNCH + cap->async_mode = true; +#else + cap->async_mode = false; +#endif + } else { + cap->minimum_frequency = 200000; // 200 kHz + cap->maximum_frequency = 2000000; // 2 MHz + cap->word_length = 0x00008080; // 8 and 16 bit symbols + cap->support_slave_mode = false; // to be determined later based on ssel + cap->hw_cs_handle = false; // to be determined later based on ssel + cap->slave_delay_between_symbols_ns = 0; // irrelevant in master mode + cap->clk_modes = 0x0f; // all clock modes + cap->tx_rx_buffers_equal_length = true; // rx buffer size must be equal tx buffer size +#if DEVICE_SPI_ASYNCH + cap->async_mode = true; +#else + cap->async_mode = false; +#endif + } + + // check if given ssel pin is in the cs pinmap + const PinMap *cs_pins = spi_master_cs_pinmap(); + while (cs_pins->pin != NC) { + if (cs_pins->pin == ssel) { +#if DEVICE_SPISLAVE + cap->support_slave_mode = true; +#endif + cap->hw_cs_handle = true; + break; + } + cs_pins++; + } +} + +#endif + +#if DEVICE_RESET_REASON +// To be re-implemented in the target layer if required +MBED_WEAK void hal_reset_reason_get_capabilities(reset_reason_capabilities_t *cap) +{ + cap->reasons = (1 << RESET_REASON_PIN_RESET) | (1 << RESET_REASON_SOFTWARE); +#if DEVICE_WATCHDOG + cap->reasons |= 1 << RESET_REASON_WATCHDOG; +#endif +} +#endif diff --git a/hal/source/mbed_critical_section_api.c b/hal/source/mbed_critical_section_api.c new file mode 100644 index 0000000..d9bbc7b --- /dev/null +++ b/hal/source/mbed_critical_section_api.c @@ -0,0 +1,66 @@ +/* mbed Microcontroller Library + * Copyright (c) 2017 ARM Limited + * 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. + */ +#include "cmsis.h" +#include "hal/critical_section_api.h" +#include "platform/mbed_assert.h" +#include "platform/mbed_toolchain.h" + +#include + +static bool critical_interrupts_enabled = false; +static bool state_saved = false; + +static bool are_interrupts_enabled(void) +{ +#if defined(__CORTEX_A9) + return ((__get_CPSR() & 0x80) == 0); +#else + return ((__get_PRIMASK() & 0x1) == 0); +#endif +} + + +MBED_WEAK void hal_critical_section_enter(void) +{ + const bool interrupt_state = are_interrupts_enabled(); + + __disable_irq(); + + if (state_saved == true) { + return; + } + + critical_interrupts_enabled = interrupt_state; + state_saved = true; +} + +MBED_WEAK void hal_critical_section_exit(void) +{ + // Interrupts must be disabled on invoking an exit from a critical section + MBED_ASSERT(!are_interrupts_enabled()); + state_saved = false; + + // Restore the IRQs to their state prior to entering the critical section + if (critical_interrupts_enabled == true) { + __enable_irq(); + } +} + +MBED_WEAK bool hal_in_critical_section(void) +{ + return (state_saved == true); +} diff --git a/hal/source/mbed_flash_api.c b/hal/source/mbed_flash_api.c new file mode 100644 index 0000000..a5d009b --- /dev/null +++ b/hal/source/mbed_flash_api.c @@ -0,0 +1,31 @@ +/* mbed Microcontroller Library + * Copyright (c) 2017 ARM Limited + * 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. + */ + +#include "hal/flash_api.h" + +#if DEVICE_FLASH + +#include "platform/mbed_toolchain.h" +#include + +MBED_WEAK int32_t flash_read(flash_t *obj, uint32_t address, uint8_t *data, uint32_t size) +{ + memcpy(data, (const void *)address, size); + return 0; +} + +#endif diff --git a/hal/source/mbed_gpio.c b/hal/source/mbed_gpio.c new file mode 100644 index 0000000..7659cff --- /dev/null +++ b/hal/source/mbed_gpio.c @@ -0,0 +1,128 @@ +/* mbed Microcontroller Library + * Copyright (c) 2006-2020 ARM Limited + * 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. + */ +#include "hal/gpio_api.h" +#include "platform/mbed_toolchain.h" + +static inline void _gpio_init_in(gpio_t *gpio, PinName pin, PinMode mode) +{ + gpio_init(gpio, pin); + if (pin != NC) { + gpio_dir(gpio, PIN_INPUT); + gpio_mode(gpio, mode); + } +} + +static inline void _gpio_init_out(gpio_t *gpio, PinName pin, PinMode mode, int value) +{ + gpio_init(gpio, pin); + if (pin != NC) { + gpio_write(gpio, value); + gpio_dir(gpio, PIN_OUTPUT); + gpio_mode(gpio, mode); + } +} + +void gpio_init_in(gpio_t *gpio, PinName pin) +{ + gpio_init_in_ex(gpio, pin, PullDefault); +} + +void gpio_init_in_ex(gpio_t *gpio, PinName pin, PinMode mode) +{ + _gpio_init_in(gpio, pin, mode); +} + +void gpio_init_out(gpio_t *gpio, PinName pin) +{ + gpio_init_out_ex(gpio, pin, 0); +} + +void gpio_init_out_ex(gpio_t *gpio, PinName pin, int value) +{ + _gpio_init_out(gpio, pin, PullNone, value); +} + +void gpio_init_inout(gpio_t *gpio, PinName pin, PinDirection direction, PinMode mode, int value) +{ + if (direction == PIN_INPUT) { + _gpio_init_in(gpio, pin, mode); + if (pin != NC) { + gpio_write(gpio, value); // we prepare the value in case it is switched later + } + } else { + _gpio_init_out(gpio, pin, mode, value); + } +} + +// To be re-implemented in the target layer if required. +MBED_WEAK void gpio_get_capabilities(gpio_t *gpio, gpio_capabilities_t *cap) +{ + (void)gpio; // By default, every pin supports all basic input pull modes. + cap->pull_none = 1; + cap->pull_down = 1; + cap->pull_up = 1; +} + +#ifdef TARGET_FF_ARDUINO + +typedef enum { + DEFAULT_GPIO = 0, +} DefaultGPIOPeripheralName; + +MBED_WEAK const PinMap *gpio_pinmap() +{ + // Targets should override this weak implementation to provide correct data. + static const PinMap empty_gpio_pinmap[] = { + {D0, DEFAULT_GPIO, 0}, + {D1, DEFAULT_GPIO, 0}, + {D2, DEFAULT_GPIO, 0}, + {D3, DEFAULT_GPIO, 0}, + {D4, DEFAULT_GPIO, 0}, + {D5, DEFAULT_GPIO, 0}, + {D6, DEFAULT_GPIO, 0}, + {D7, DEFAULT_GPIO, 0}, + {D8, DEFAULT_GPIO, 0}, + {D9, DEFAULT_GPIO, 0}, + {D10, DEFAULT_GPIO, 0}, + {D11, DEFAULT_GPIO, 0}, + {D12, DEFAULT_GPIO, 0}, + {D13, DEFAULT_GPIO, 0}, + {D14, DEFAULT_GPIO, 0}, + {D15, DEFAULT_GPIO, 0}, + {A0, DEFAULT_GPIO, 0}, + {A1, DEFAULT_GPIO, 0}, + {A2, DEFAULT_GPIO, 0}, + {A3, DEFAULT_GPIO, 0}, + {A4, DEFAULT_GPIO, 0}, + {A5, DEFAULT_GPIO, 0}, + + {NC, NC, 0}, + }; + return empty_gpio_pinmap; +} + +#else + +MBED_WEAK const PinMap *gpio_pinmap() +{ + static const PinMap empty_gpio_pinmap[] = { + {NC, NC, 0}, + }; + return empty_gpio_pinmap; +} + +#endif diff --git a/hal/source/mbed_gpio_irq.c b/hal/source/mbed_gpio_irq.c new file mode 100644 index 0000000..b8c6e86 --- /dev/null +++ b/hal/source/mbed_gpio_irq.c @@ -0,0 +1,31 @@ +/* mbed Microcontroller Library + * Copyright (c) 2019 ARM Limited + * 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. + */ +#include "hal/gpio_irq_api.h" + +#if DEVICE_INTERRUPTIN + +#include "platform/mbed_toolchain.h" +#include "hal/gpio_api.h" + +MBED_WEAK const PinMap *gpio_irq_pinmap() +{ + // Targets should override this weak implementation to provide correct data. + // By default, this is exactly the same as GPIO PinMap. + return gpio_pinmap(); +} + +#endif diff --git a/hal/source/mbed_itm_api.c b/hal/source/mbed_itm_api.c new file mode 100644 index 0000000..46d7e3d --- /dev/null +++ b/hal/source/mbed_itm_api.c @@ -0,0 +1,134 @@ +/* mbed Microcontroller Library + * Copyright (c) 2017 ARM Limited + * 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. + */ + +#if DEVICE_ITM + +#include "hal/itm_api.h" +#include "cmsis.h" + +#include + +#ifndef ITM_STIM_FIFOREADY_Msk +#define ITM_STIM_FIFOREADY_Msk 1 +#endif + +#define ITM_ENABLE_WRITE 0xC5ACCE55 + +#define SWO_NRZ 0x02 +#define SWO_STIMULUS_PORT 0x01 + +void mbed_itm_init(void) +{ + static bool do_init = true; + + if (do_init) { + do_init = false; + + itm_init(); + + /* Enable write access to ITM registers. */ + ITM->LAR = ITM_ENABLE_WRITE; + + /* Trace Port Interface Selected Pin Protocol Register. */ + TPI->SPPR = (SWO_NRZ << TPI_SPPR_TXMODE_Pos); + + /* Trace Port Interface Formatter and Flush Control Register */ + TPI->FFCR = (1 << TPI_FFCR_TrigIn_Pos); + + /* Data Watchpoint and Trace Control Register */ + DWT->CTRL = (1 << DWT_CTRL_CYCTAP_Pos) | + (0xF << DWT_CTRL_POSTINIT_Pos) | + (0xF << DWT_CTRL_POSTPRESET_Pos) | + (1 << DWT_CTRL_CYCCNTENA_Pos); + + /* Trace Privilege Register. + * Disable access to trace channel configuration from non-privileged mode. + */ + ITM->TPR = 0x0; + + /* Trace Control Register */ + ITM->TCR = (1 << ITM_TCR_TraceBusID_Pos) | + (1 << ITM_TCR_DWTENA_Pos) | + (1 << ITM_TCR_SYNCENA_Pos) | + (1 << ITM_TCR_ITMENA_Pos); + + /* Trace Enable Register */ + ITM->TER = SWO_STIMULUS_PORT; + } +} + +static void itm_out8(uint32_t port, uint8_t data) +{ + /* Wait until port is available */ + while ((ITM->PORT[port].u32 & ITM_STIM_FIFOREADY_Msk) == 0) { + __NOP(); + } + + /* write data to port */ + ITM->PORT[port].u8 = data; +} + +static void itm_out32(uint32_t port, uint32_t data) +{ + /* Wait until port is available */ + while ((ITM->PORT[port].u32 & ITM_STIM_FIFOREADY_Msk) == 0) { + __NOP(); + } + + /* write data to port */ + ITM->PORT[port].u32 = data; +} + +uint32_t mbed_itm_send(uint32_t port, uint32_t data) +{ + /* Check if ITM and port is enabled */ + if (((ITM->TCR & ITM_TCR_ITMENA_Msk) != 0UL) && /* ITM enabled */ + ((ITM->TER & (1UL << port)) != 0UL)) { /* ITM Port enabled */ + itm_out32(port, data); + } + + return data; +} + +void mbed_itm_send_block(uint32_t port, const void *data, size_t len) +{ + const char *ptr = data; + + /* Check if ITM and port is enabled */ + if (((ITM->TCR & ITM_TCR_ITMENA_Msk) != 0UL) && /* ITM enabled */ + ((ITM->TER & (1UL << port)) != 0UL)) { /* ITM Port enabled */ + /* Output single byte at a time until data is aligned */ + while ((((uintptr_t) ptr) & 3) && len != 0) { + itm_out8(port, *ptr++); + len--; + } + + /* Output bulk of data one word at a time */ + while (len >= 4) { + itm_out32(port, *(const uint32_t *) ptr); + ptr += 4; + len -= 4; + } + + /* Output any trailing bytes */ + while (len != 0) { + itm_out8(port, *ptr++); + len--; + } + } +} +#endif // DEVICE_ITM diff --git a/hal/source/mbed_lp_ticker_api.c b/hal/source/mbed_lp_ticker_api.c new file mode 100644 index 0000000..b1b2d96 --- /dev/null +++ b/hal/source/mbed_lp_ticker_api.c @@ -0,0 +1,72 @@ +/* mbed Microcontroller Library + * Copyright (c) 2015 ARM Limited + * 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. + */ +#include "hal/lp_ticker_api.h" +#include "hal/mbed_lp_ticker_wrapper.h" + +#if DEVICE_LPTICKER + +static ticker_event_queue_t events = { 0 }; + +static ticker_irq_handler_type irq_handler = ticker_irq_handler; + +static const ticker_interface_t lp_interface = { + .init = lp_ticker_init, + .read = lp_ticker_read, + .disable_interrupt = lp_ticker_disable_interrupt, + .clear_interrupt = lp_ticker_clear_interrupt, + .set_interrupt = lp_ticker_set_interrupt, + .fire_interrupt = lp_ticker_fire_interrupt, + .get_info = lp_ticker_get_info, + .free = lp_ticker_free, + .runs_in_deep_sleep = true, +}; + +static const ticker_data_t lp_data = { + .interface = &lp_interface, + .queue = &events, +}; + +const ticker_data_t *get_lp_ticker_data(void) +{ +#if LPTICKER_DELAY_TICKS > 0 + return get_lp_ticker_wrapper_data(&lp_data); +#else + return &lp_data; +#endif +} + +ticker_irq_handler_type set_lp_ticker_irq_handler(ticker_irq_handler_type ticker_irq_handler) +{ + ticker_irq_handler_type prev_irq_handler = irq_handler; + + irq_handler = ticker_irq_handler; + + return prev_irq_handler; +} + +void lp_ticker_irq_handler(void) +{ +#if LPTICKER_DELAY_TICKS > 0 + lp_ticker_wrapper_irq_handler(irq_handler); +#else + if (irq_handler) { + irq_handler(&lp_data); + } +#endif +} + +#endif diff --git a/hal/source/mbed_lp_ticker_wrapper.cpp b/hal/source/mbed_lp_ticker_wrapper.cpp new file mode 100644 index 0000000..e388355 --- /dev/null +++ b/hal/source/mbed_lp_ticker_wrapper.cpp @@ -0,0 +1,129 @@ +/* mbed Microcontroller Library + * Copyright (c) 2018 ARM Limited + * 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. + */ +#include "hal/mbed_lp_ticker_wrapper.h" + +#if DEVICE_LPTICKER && (LPTICKER_DELAY_TICKS > 0) + +#include "hal/LowPowerTickerWrapper.h" +#include "platform/mbed_critical.h" + +// Do not use SingletonPtr since this must be initialized in a critical section +static LowPowerTickerWrapper *ticker_wrapper; +static uint64_t ticker_wrapper_data[(sizeof(LowPowerTickerWrapper) + 7) / 8]; +static bool init = false; + +static void lp_ticker_wrapper_init() +{ + ticker_wrapper->init(); +} + +static uint32_t lp_ticker_wrapper_read() +{ + return ticker_wrapper->read(); +} + +static void lp_ticker_wrapper_set_interrupt(timestamp_t timestamp) +{ + ticker_wrapper->set_interrupt(timestamp); +} + +static void lp_ticker_wrapper_disable_interrupt() +{ + ticker_wrapper->disable_interrupt(); +} + +static void lp_ticker_wrapper_clear_interrupt() +{ + ticker_wrapper->clear_interrupt(); +} + +static void lp_ticker_wrapper_fire_interrupt() +{ + ticker_wrapper->fire_interrupt(); +} + +static const ticker_info_t *lp_ticker_wrapper_get_info() +{ + return ticker_wrapper->get_info(); +} + +static void lp_ticker_wrapper_free() +{ + ticker_wrapper->free(); +} + +static const ticker_interface_t lp_interface = { + lp_ticker_wrapper_init, + lp_ticker_wrapper_read, + lp_ticker_wrapper_disable_interrupt, + lp_ticker_wrapper_clear_interrupt, + lp_ticker_wrapper_set_interrupt, + lp_ticker_wrapper_fire_interrupt, + lp_ticker_wrapper_free, + lp_ticker_wrapper_get_info, + true +}; + +void lp_ticker_wrapper_irq_handler(ticker_irq_handler_type handler) +{ + core_util_critical_section_enter(); + + if (!init) { + // Force ticker to initialize + get_lp_ticker_data(); + } + + ticker_wrapper->irq_handler(handler); + + core_util_critical_section_exit(); +} + +const ticker_data_t *get_lp_ticker_wrapper_data(const ticker_data_t *data) +{ + core_util_critical_section_enter(); + + if (!init) { + ticker_wrapper = new (ticker_wrapper_data) LowPowerTickerWrapper(data, &lp_interface, LPTICKER_DELAY_TICKS, LPTICKER_DELAY_TICKS); + init = true; + } + + core_util_critical_section_exit(); + + return &ticker_wrapper->data; +} + +void lp_ticker_wrapper_suspend() +{ + if (!init) { + // Force ticker to initialize + get_lp_ticker_data(); + } + + ticker_wrapper->suspend(); +} + +void lp_ticker_wrapper_resume() +{ + if (!init) { + // Force ticker to initialize + get_lp_ticker_data(); + } + + ticker_wrapper->resume(); +} + +#endif diff --git a/hal/source/mbed_pinmap_common.c b/hal/source/mbed_pinmap_common.c new file mode 100644 index 0000000..f47cb1a --- /dev/null +++ b/hal/source/mbed_pinmap_common.c @@ -0,0 +1,188 @@ +/* mbed Microcontroller Library + * Copyright (c) 2006-2013 ARM Limited + * 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. + */ +#include "hal/pinmap.h" +#include "platform/mbed_error.h" + +void pinmap_pinout(PinName pin, const PinMap *map) +{ + if (pin == NC) { + return; + } + + while (map->pin != NC) { + if (map->pin == pin) { + pin_function(pin, map->function); + + pin_mode(pin, PullNone); + return; + } + map++; + } + MBED_ERROR1(MBED_MAKE_ERROR(MBED_MODULE_PLATFORM, MBED_ERROR_CODE_PINMAP_INVALID), "could not pinout", pin); +} + +uint32_t pinmap_merge(uint32_t a, uint32_t b) +{ + // both are the same (inc both NC) + if (a == b) { + return a; + } + + // one (or both) is not connected + if (a == (uint32_t)NC) { + return b; + } + if (b == (uint32_t)NC) { + return a; + } + + // mis-match error case + MBED_ERROR1(MBED_MAKE_ERROR(MBED_MODULE_PLATFORM, MBED_ERROR_CODE_PINMAP_INVALID), "pinmap mis-match", a); +} + +uint32_t pinmap_find_peripheral(PinName pin, const PinMap *map) +{ + while (map->pin != NC) { + if (map->pin == pin) { + return map->peripheral; + } + map++; + } + return (uint32_t)NC; +} + +uint32_t pinmap_peripheral(PinName pin, const PinMap *map) +{ + uint32_t peripheral = (uint32_t)NC; + + if (pin == (PinName)NC) { + return (uint32_t)NC; + } + peripheral = pinmap_find_peripheral(pin, map); + if ((uint32_t)NC == peripheral) { // no mapping available + MBED_ERROR1(MBED_MAKE_ERROR(MBED_MODULE_PLATFORM, MBED_ERROR_CODE_PINMAP_INVALID), "pinmap not found for peripheral", pin); + } + return peripheral; +} + +uint32_t pinmap_find_function(PinName pin, const PinMap *map) +{ + while (map->pin != NC) { + if (map->pin == pin) { + return map->function; + } + map++; + } + return (uint32_t)NC; +} + +uint32_t pinmap_function(PinName pin, const PinMap *map) +{ + uint32_t function = (uint32_t)NC; + + if (pin == (PinName)NC) { + return (uint32_t)NC; + } + function = pinmap_find_function(pin, map); + if ((uint32_t)NC == function) { // no mapping available + MBED_ERROR1(MBED_MAKE_ERROR(MBED_MODULE_PLATFORM, MBED_ERROR_CODE_PINMAP_INVALID), "pinmap not found for function", pin); + } + return function; +} + +bool pinmap_find_peripheral_pins(const PinList *whitelist, const PinList *blacklist, int per, const PinMap *const *maps, PinName **pins, uint32_t count) +{ + /* + * This function uses recursion to find a suitable set of pins which meet the requirements. + * Recursion is at max the number of pinmaps passed in - the 'count' parameter. Because of this + * there is no risk of a stack overflow due to unbounded recursion. + * + * Below is a psuedo code example of this function's operation when finding a set of 4 pins. + * The recursion depth is indicated by the number in front. + * + * 1. Given 4 maps and a peripheral find 4 suitable pins + * 2. Given 4 maps, a peripheral and 1 pin find 3 suitable pins + * 3. Given 4 maps, a peripheral and 2 pins find 2 suitable pins + * 4. Given 4 maps, a peripheral and 3 pins find 1 suitable pin + * 4. Return success if all pins are found, return failure if there are no suitable pins, otherwise choose the next pin and retry + * 3. Return success if all pins are found, return failure if there are no suitable pins, otherwise choose the next pin and retry + * 2. Return success if all pins are found, return failure if there are no suitable pins, otherwise choose the next pin and retry + * 1. Return success if all pins are found, return failure if there are no suitable pins, otherwise choose the next pin and retry + * + */ + + for (uint32_t i = 0; i < count; i++) { + const PinMap *map = maps[i]; + PinName *pin = pins[i]; + if (*pin == NC) { + for (; map->pin != NC; map++) { + if (map->peripheral != per) { + continue; + } + if (!pinmap_list_has_pin(whitelist, map->pin)) { + // Not part of this form factor + continue; + } + if (pinmap_list_has_pin(blacklist, map->pin)) { + // Restricted pin + continue; + } + bool already_in_use = false; + for (uint32_t j = 0; j < count; j++) { + if (j == i) { + // Don't compare with self + continue; + } + if (map->pin == *pins[j]) { + already_in_use = true; + break; + } + } + if (already_in_use) { + continue; + } + *pin = map->pin; + if (pinmap_find_peripheral_pins(whitelist, blacklist, per, maps, pins, count)) { + return true; + } + } + *pin = NC; + return false; + } + } + return true; +} + +bool pinmap_list_has_pin(const PinList *list, PinName pin) +{ + for (uint32_t i = 0; i < list->count; i++) { + if (list->pins[i] == pin) { + return true; + } + } + return false; +} + +bool pinmap_list_has_peripheral(const PeripheralList *list, int peripheral) +{ + for (uint32_t i = 0; i < list->count; i++) { + if (list->peripheral[i] == peripheral) { + return true; + } + } + return false; +} diff --git a/hal/source/mbed_pinmap_default.cpp b/hal/source/mbed_pinmap_default.cpp new file mode 100644 index 0000000..45ac316 --- /dev/null +++ b/hal/source/mbed_pinmap_default.cpp @@ -0,0 +1,108 @@ +/* mbed Microcontroller Library + * Copyright (c) 2019 ARM Limited + * 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. + */ + +#include +#include "hal/pinmap.h" +#include "platform/mbed_toolchain.h" +#include "platform/mbed_assert.h" +#include "device.h" +#include "hal/serial_api.h" + +//*** Common form factors *** +#ifdef TARGET_FF_ARDUINO + +static const PinName ff_arduino_pins[] = { + D0, D1, D2, D3, D4, D5, D6, D7, + D8, D9, D10, D11, D12, D13, D14, D15, + A0, A1, A2, A3, A4, A5 +}; + +static const char *ff_arduino_names[] = { + "D0", "D1", "D2", "D3", "D4", "D5", "D6", "D7", + "D8", "D9", "D10", "D11", "D12", "D13", "D14", "D15", + "A0", "A1", "A2", "A3", "A4", "A5" +}; + +static const PinList ff_arduino_list = { + sizeof(ff_arduino_pins) / sizeof(ff_arduino_pins[0]), + ff_arduino_pins +}; + +MBED_STATIC_ASSERT(sizeof(ff_arduino_pins) / sizeof(ff_arduino_pins[0]) == sizeof(ff_arduino_names) / sizeof(ff_arduino_names[0]), + "Arrays must have the same length"); + +const PinList *pinmap_ff_arduino_pins() +{ + return &ff_arduino_list; +} + +const char *pinmap_ff_arduino_pin_to_string(PinName pin) +{ + if (pin == NC) { + return "NC"; + } + for (size_t i = 0; i < ff_arduino_list.count; i++) { + if (ff_arduino_list.pins[i] == pin) { + return ff_arduino_names[i]; + } + } + return "Unknown"; +} + +#endif + +//*** Default restricted pins *** +MBED_WEAK const PinList *pinmap_restricted_pins() +{ + static const PinName pins[] = { + USBTX, USBRX + }; + static const PinList pin_list = { + sizeof(pins) / sizeof(pins[0]), + pins + }; + return &pin_list; +} + +//*** Default restricted gpio pins *** +// GPIO pins are special case because there are no pin-maps for GPIO +MBED_WEAK const PinList *pinmap_gpio_restricted_pins() +{ + static const PinList pin_list = { + 0, + 0 + }; + return &pin_list; +} + +//*** Default restricted peripherals *** +#if DEVICE_SERIAL +MBED_WEAK const PeripheralList *pinmap_uart_restricted_peripherals() +{ + static const int stdio_uart = pinmap_peripheral(STDIO_UART_TX, serial_tx_pinmap()); + + static const int peripherals[] = { + stdio_uart + }; + + static const PeripheralList peripheral_list = { + sizeof peripherals / sizeof peripherals[0], + peripherals + }; + return &peripheral_list; +} +#endif diff --git a/hal/source/mbed_ticker_api.c b/hal/source/mbed_ticker_api.c new file mode 100644 index 0000000..5f36365 --- /dev/null +++ b/hal/source/mbed_ticker_api.c @@ -0,0 +1,507 @@ +/* mbed Microcontroller Library + * Copyright (c) 2015 ARM Limited + * 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. + */ +#include +#include +#include "hal/ticker_api.h" +#include "platform/mbed_critical.h" +#include "platform/mbed_assert.h" +#include "platform/mbed_error.h" + +static void schedule_interrupt(const ticker_data_t *const ticker); +static void update_present_time(const ticker_data_t *const ticker); + +/* + * Initialize a ticker instance. + */ +static void initialize(const ticker_data_t *ticker) +{ + // return if the queue has already been initialized, in that case the + // interface used by the queue is already initialized. + if (ticker->queue->initialized) { + return; + } + if (ticker->queue->suspended) { + return; + } + + ticker->interface->init(); + + const ticker_info_t *info = ticker->interface->get_info(); + uint32_t frequency = info->frequency; + if (info->frequency == 0) { +#if MBED_TRAP_ERRORS_ENABLED + MBED_ERROR( + MBED_MAKE_ERROR( + MBED_MODULE_HAL, + MBED_ERROR_CODE_NOT_READY + ), + "Ticker frequency is zero" + ); +#else + frequency = 1000000; +#endif // MBED_TRAP_ERRORS_ENABLED + } + + uint8_t frequency_shifts = 0; + for (uint8_t i = 31; i > 0; --i) { + if ((1U << i) == frequency) { + frequency_shifts = i; + break; + } + } + + uint32_t bits = info->bits; + if ((info->bits > 32) || (info->bits < 4)) { +#if MBED_TRAP_ERRORS_ENABLED + MBED_ERROR( + MBED_MAKE_ERROR( + MBED_MODULE_HAL, + MBED_ERROR_CODE_INVALID_SIZE + ), + "Ticker number of bit is greater than 32 or less than 4 bits" + ); +#else + bits = 32; +#endif // MBED_TRAP_ERRORS_ENABLED + } + uint32_t max_delta = 0x7 << (bits - 4); // 7/16th + uint64_t max_delta_us = + ((uint64_t)max_delta * 1000000 + frequency - 1) / frequency; + + ticker->queue->event_handler = NULL; + ticker->queue->head = NULL; + 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; + ticker->queue->present_time = 0; + ticker->queue->dispatching = false; + ticker->queue->suspended = false; + ticker->queue->initialized = true; + + update_present_time(ticker); + schedule_interrupt(ticker); +} + +/** + * Set the event handler function of a ticker instance. + */ +static void set_handler(const ticker_data_t *const ticker, ticker_event_handler handler) +{ + ticker->queue->event_handler = handler; +} + +/* + * Convert a 32 bit timestamp into a 64 bit timestamp. + * + * A 64 bit timestamp is used as the point of time of reference while the + * timestamp to convert is relative to this point of time. + * + * The lower 32 bits of the timestamp returned will be equal to the timestamp to + * convert. + * + * If the timestamp to convert is less than the lower 32 bits of the time + * reference then the timestamp to convert is seen as an overflowed value and + * the upper 32 bit of the timestamp returned will be equal to the upper 32 bit + * of the reference point + 1. + * Otherwise, the upper 32 bit returned will be equal to the upper 32 bit of the + * reference point. + * + * @param ref: The 64 bit timestamp of reference. + * @param timestamp: The timestamp to convert. + */ +static us_timestamp_t convert_timestamp(us_timestamp_t ref, timestamp_t timestamp) +{ + bool overflow = timestamp < ((timestamp_t) ref) ? true : false; + + us_timestamp_t result = (ref & ~((us_timestamp_t)UINT32_MAX)) | timestamp; + if (overflow) { + result += (1ULL << 32); + } + + return result; +} + +/** + * Update the present timestamp value of a ticker. + */ +static void update_present_time(const ticker_data_t *const ticker) +{ + ticker_event_queue_t *queue = ticker->queue; + if (queue->suspended) { + return; + } + uint32_t ticker_time = ticker->interface->read(); + if (ticker_time == ticker->queue->tick_last_read) { + // No work to do + return; + } + + uint64_t elapsed_ticks = (ticker_time - queue->tick_last_read) & queue->bitmask; + queue->tick_last_read = ticker_time; + + uint64_t elapsed_us; + if (1000000 == queue->frequency) { + // Optimized for 1MHz + + elapsed_us = elapsed_ticks; + } 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 >> queue->frequency_shifts; + + // Update remainder + 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; + } + } else { + // General case + + uint64_t us_x_ticks = elapsed_ticks * 1000000; + elapsed_us = us_x_ticks / queue->frequency; + + // Update remainder + queue->tick_remainder += us_x_ticks - elapsed_us * queue->frequency; + if (queue->tick_remainder >= queue->frequency) { + elapsed_us += 1; + queue->tick_remainder -= queue->frequency; + } + } + + // Update current time + queue->present_time += elapsed_us; +} + +/** + * Given the absolute timestamp compute the hal tick timestamp rounded up. + */ +static timestamp_t compute_tick_round_up(const ticker_data_t *const ticker, us_timestamp_t timestamp) +{ + ticker_event_queue_t *queue = ticker->queue; + us_timestamp_t delta_us = timestamp - queue->present_time; + + timestamp_t delta = ticker->queue->max_delta; + if (delta_us <= ticker->queue->max_delta_us) { + // Checking max_delta_us ensures the operation will not overflow + + if (1000000 == queue->frequency) { + // Optimized for 1MHz + + delta = delta_us; + if (delta > ticker->queue->max_delta) { + delta = ticker->queue->max_delta; + } + } else if (0 != queue->frequency_shifts) { + // Optimized frequencies divisible by 2 + + delta = ((delta_us << ticker->queue->frequency_shifts) + 1000000 - 1) / 1000000; + if (delta > ticker->queue->max_delta) { + delta = ticker->queue->max_delta; + } + } else { + // General case + + delta = (delta_us * queue->frequency + 1000000 - 1) / 1000000; + if (delta > ticker->queue->max_delta) { + delta = ticker->queue->max_delta; + } + } + } + return (queue->tick_last_read + delta) & queue->bitmask; +} + +/** + * Return 1 if the tick has incremented to or past match_tick, otherwise 0. + */ +int _ticker_match_interval_passed(timestamp_t prev_tick, timestamp_t cur_tick, timestamp_t match_tick) +{ + if (match_tick > prev_tick) { + return (cur_tick >= match_tick) || (cur_tick < prev_tick); + } else { + return (cur_tick < prev_tick) && (cur_tick >= match_tick); + } +} + +/** + * Compute the time when the interrupt has to be triggered and schedule it. + * + * If there is no event in the queue or the next event to execute is in more + * than ticker.queue.max_delta ticks from now then the ticker irq will be + * scheduled in ticker.queue.max_delta ticks. Otherwise the irq will be + * scheduled to happen when the running counter reach the timestamp of the + * first event in the queue. + * + * @note If there is no event in the queue then the interrupt is scheduled to + * in ticker.queue.max_delta. This is necessary to keep track + * of the timer overflow. + */ +static void schedule_interrupt(const ticker_data_t *const ticker) +{ + ticker_event_queue_t *queue = ticker->queue; + if (queue->suspended || ticker->queue->dispatching) { + // Don't schedule the next interrupt until dispatching is + // finished. This prevents repeated calls to interface->set_interrupt + return; + } + + update_present_time(ticker); + + if (ticker->queue->head) { + us_timestamp_t present = ticker->queue->present_time; + us_timestamp_t match_time = ticker->queue->head->timestamp; + + // if the event at the head of the queue is in the past then schedule + // it immediately. + if (match_time <= present) { + ticker->interface->fire_interrupt(); + return; + } + + timestamp_t match_tick = compute_tick_round_up(ticker, match_time); + + // The same tick should never occur since match_tick is rounded up. + // If the same tick is returned scheduling will not work correctly. + MBED_ASSERT(match_tick != queue->tick_last_read); + + ticker->interface->set_interrupt(match_tick); + timestamp_t cur_tick = ticker->interface->read(); + + if (_ticker_match_interval_passed(queue->tick_last_read, cur_tick, match_tick)) { + ticker->interface->fire_interrupt(); + } + } else { + uint32_t match_tick = + (queue->tick_last_read + queue->max_delta) & queue->bitmask; + ticker->interface->set_interrupt(match_tick); + } +} + +void ticker_set_handler(const ticker_data_t *const ticker, ticker_event_handler handler) +{ + initialize(ticker); + + core_util_critical_section_enter(); + set_handler(ticker, handler); + core_util_critical_section_exit(); +} + +void ticker_irq_handler(const ticker_data_t *const ticker) +{ + core_util_critical_section_enter(); + + ticker->interface->clear_interrupt(); + if (ticker->queue->suspended) { + core_util_critical_section_exit(); + return; + } + + /* Go through all the pending TimerEvents */ + ticker->queue->dispatching = true; + while (1) { + if (ticker->queue->head == NULL) { + break; + } + + // update the current timestamp used by the queue + update_present_time(ticker); + + if (ticker->queue->head->timestamp <= ticker->queue->present_time) { + // This event was in the past: + // point to the following one and execute its handler + ticker_event_t *p = ticker->queue->head; + ticker->queue->head = ticker->queue->head->next; + if (ticker->queue->event_handler != NULL) { + (*ticker->queue->event_handler)(p->id); // NOTE: the handler can set new events + } + /* Note: We continue back to examining the head because calling the + * event handler may have altered the chain of pending events. */ + } else { + break; + } + } + ticker->queue->dispatching = false; + + schedule_interrupt(ticker); + + core_util_critical_section_exit(); +} + +void ticker_insert_event(const ticker_data_t *const ticker, ticker_event_t *obj, timestamp_t timestamp, uint32_t id) +{ + core_util_critical_section_enter(); + + // update the current timestamp + update_present_time(ticker); + us_timestamp_t absolute_timestamp = convert_timestamp( + ticker->queue->present_time, + timestamp + ); + + // defer to ticker_insert_event_us + ticker_insert_event_us( + ticker, + obj, absolute_timestamp, id + ); + + core_util_critical_section_exit(); +} + +void ticker_insert_event_us(const ticker_data_t *const ticker, ticker_event_t *obj, us_timestamp_t timestamp, uint32_t id) +{ + core_util_critical_section_enter(); + + // update the current timestamp + update_present_time(ticker); + + // initialise our data + obj->timestamp = timestamp; + obj->id = id; + + /* Go through the list until we either reach the end, or find + an element this should come before (which is possibly the + head). */ + ticker_event_t *prev = NULL, *p = ticker->queue->head; + while (p != NULL) { + /* check if we come before p */ + if (timestamp < p->timestamp) { + break; + } + /* go to the next element */ + prev = p; + p = p->next; + } + + /* if we're at the end p will be NULL, which is correct */ + obj->next = p; + + /* if prev is NULL we're at the head */ + if (prev == NULL) { + ticker->queue->head = obj; + } else { + prev->next = obj; + } + + if (prev == NULL || timestamp <= ticker->queue->present_time) { + schedule_interrupt(ticker); + } + + core_util_critical_section_exit(); +} + +void ticker_remove_event(const ticker_data_t *const ticker, ticker_event_t *obj) +{ + core_util_critical_section_enter(); + + // remove this object from the list + if (ticker->queue->head == obj) { + // first in the list, so just drop me + ticker->queue->head = obj->next; + schedule_interrupt(ticker); + } else { + // find the object before me, then drop me + ticker_event_t *p = ticker->queue->head; + while (p != NULL) { + if (p->next == obj) { + p->next = obj->next; + break; + } + p = p->next; + } + } + + core_util_critical_section_exit(); +} + +timestamp_t ticker_read(const ticker_data_t *const ticker) +{ + return ticker_read_us(ticker); +} + +us_timestamp_t ticker_read_us(const ticker_data_t *const ticker) +{ + us_timestamp_t ret; + + initialize(ticker); + + core_util_critical_section_enter(); + update_present_time(ticker); + ret = ticker->queue->present_time; + core_util_critical_section_exit(); + + return ret; +} + +int ticker_get_next_timestamp(const ticker_data_t *const data, timestamp_t *timestamp) +{ + int ret = 0; + + /* if head is NULL, there are no pending events */ + core_util_critical_section_enter(); + if (data->queue->head != NULL) { + *timestamp = data->queue->head->timestamp; + ret = 1; + } + core_util_critical_section_exit(); + + return ret; +} + +int ticker_get_next_timestamp_us(const ticker_data_t *const data, us_timestamp_t *timestamp) +{ + int ret = 0; + + /* if head is NULL, there are no pending events */ + core_util_critical_section_enter(); + if (data->queue->head != NULL) { + *timestamp = data->queue->head->timestamp; + ret = 1; + } + core_util_critical_section_exit(); + + return ret; +} + +void ticker_suspend(const ticker_data_t *const ticker) +{ + core_util_critical_section_enter(); + + ticker->queue->suspended = true; + + core_util_critical_section_exit(); +} + +void ticker_resume(const ticker_data_t *const ticker) +{ + core_util_critical_section_enter(); + + ticker->queue->suspended = false; + if (ticker->queue->initialized) { + ticker->queue->tick_last_read = ticker->interface->read(); + + update_present_time(ticker); + schedule_interrupt(ticker); + } else { + initialize(ticker); + } + + core_util_critical_section_exit(); +} diff --git a/hal/source/mbed_us_ticker_api.c b/hal/source/mbed_us_ticker_api.c new file mode 100644 index 0000000..777a5e4 --- /dev/null +++ b/hal/source/mbed_us_ticker_api.c @@ -0,0 +1,112 @@ +/* mbed Microcontroller Library + * Copyright (c) 2015 ARM Limited + * 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. + */ + +#include +#include "platform/mbed_atomic.h" +#include "hal/us_ticker_api.h" + +#if DEVICE_USTICKER + +static ticker_event_queue_t events = { 0 }; + +static ticker_irq_handler_type irq_handler = ticker_irq_handler; + +#if MBED_CONF_TARGET_INIT_US_TICKER_AT_BOOT + +// If we are initializing at boot, we want the timer to be +// always-on, so we block any attempt to free it. We do need +// to pass through init(), as that needs to reset pending +// interrupts. +static void block_us_ticker_free() +{ +} + +#else // MBED_CONF_TARGET_INIT_US_TICKER_AT_BOOT + +bool _us_ticker_initialized; + +// If we are not initializing at boot, we want to track +// whether the timer has been initialized. This permits +// a fast path for wait_us. +static void note_us_ticker_init() +{ + us_ticker_init(); + core_util_atomic_store_bool(&_us_ticker_initialized, true); +} + +static void note_us_ticker_free() +{ + core_util_atomic_store_bool(&_us_ticker_initialized, false); + us_ticker_free(); +} + +#endif // MBED_CONF_TARGET_INIT_US_TICKER_AT_BOOT + +static const ticker_interface_t us_interface = { +#if MBED_CONF_TARGET_INIT_US_TICKER_AT_BOOT + .init = us_ticker_init, +#else + .init = note_us_ticker_init, +#endif + .read = us_ticker_read, + .disable_interrupt = us_ticker_disable_interrupt, + .clear_interrupt = us_ticker_clear_interrupt, + .set_interrupt = us_ticker_set_interrupt, + .fire_interrupt = us_ticker_fire_interrupt, + .get_info = us_ticker_get_info, +#if MBED_CONF_TARGET_INIT_US_TICKER_AT_BOOT + .free = block_us_ticker_free, +#else + .free = note_us_ticker_free, +#endif + .runs_in_deep_sleep = false, +}; + +static const ticker_data_t us_data = { + .interface = &us_interface, + .queue = &events +}; + +const ticker_data_t *get_us_ticker_data(void) +{ + return &us_data; +} + +ticker_irq_handler_type set_us_ticker_irq_handler(ticker_irq_handler_type ticker_irq_handler) +{ + ticker_irq_handler_type prev_irq_handler = irq_handler; + + irq_handler = ticker_irq_handler; + + return prev_irq_handler; +} + +void us_ticker_irq_handler(void) +{ + if (irq_handler) { + irq_handler(&us_data); + } +} + +#else + +const ticker_data_t *get_us_ticker_data(void) +{ + return NULL; +} + +#endif // DEVICE_USTICKER diff --git a/hal/source/mpu/mbed_mpu_v7m.c b/hal/source/mpu/mbed_mpu_v7m.c new file mode 100644 index 0000000..d804063 --- /dev/null +++ b/hal/source/mpu/mbed_mpu_v7m.c @@ -0,0 +1,238 @@ +/* mbed Microcontroller Library + * Copyright (c) 2018 ARM Limited + * 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. + */ +#include "hal/mpu_api.h" +#include "platform/mbed_assert.h" +#include "cmsis.h" + +#if ((__ARM_ARCH_7M__ == 1U) || (__ARM_ARCH_7EM__ == 1U) || (__ARM_ARCH_6M__ == 1U)) && \ + defined (__MPU_PRESENT) && (__MPU_PRESENT == 1U) && \ + !defined(MBED_MPU_CUSTOM) + +#if !DEVICE_MPU +#error "Device has v7m MPU but it is not enabled. Add 'MPU' to device_has in targets.json" +#endif + +#ifdef MBED_CONF_TARGET_MPU_ROM_END +#define MBED_MPU_ROM_END MBED_CONF_TARGET_MPU_ROM_END +#else +#define MBED_MPU_ROM_END (0x10000000 - 1) +#endif +#define MBED_MPU_RAM_START (MBED_MPU_ROM_END + 1) + +MBED_STATIC_ASSERT( + MBED_MPU_ROM_END == 0x04000000 - 1 || + MBED_MPU_ROM_END == 0x08000000 - 1 || + MBED_MPU_ROM_END == 0x0C000000 - 1 || + MBED_MPU_ROM_END == 0x10000000 - 1 || + MBED_MPU_ROM_END == 0x14000000 - 1 || + MBED_MPU_ROM_END == 0x18000000 - 1 || + MBED_MPU_ROM_END == 0x1C000000 - 1 || + MBED_MPU_ROM_END == 0x20000000 - 1, + "Unsupported value for MBED_MPU_ROM_END"); + +void mbed_mpu_init() +{ + // Flush memory writes before configuring the MPU. + __DMB(); + + const uint32_t regions = (MPU->TYPE & MPU_TYPE_DREGION_Msk) >> MPU_TYPE_DREGION_Pos; + + // Our MPU setup requires 3 or 4 regions - if this assert is hit, remove + // a region by setting MPU_ROM_END to 0x1fffffff, or remove MPU from device_has +#if MBED_MPU_RAM_START == 0x20000000 + MBED_ASSERT(regions >= 3); +#else + MBED_ASSERT(regions >= 4); +#endif + + // Disable the MCU + MPU->CTRL = 0; + + // Reset all mapping + for (uint32_t i = 0; i < regions; i++) { + ARM_MPU_ClrRegion(i); + } + + /* + * ARMv6m and ARMv7-M memory map: + * + * Start End Name Executable by default Mbed MPU protection + * 0x00000000 - 0x1FFFFFFF Code Yes Write disabled for first portion and execute disabled for the rest + * 0x20000000 - 0x3FFFFFFF SRAM Yes Execute disabled + * 0x40000000 - 0x5FFFFFFF Peripheral No + * 0x60000000 - 0x7FFFFFFF RAM Yes Execute disabled + * 0x80000000 - 0x9FFFFFFF RAM Yes Execute disabled + * 0xA0000000 - 0xBFFFFFFF Device No + * 0xC0000000 - 0xDFFFFFFF Device No + * 0xE0000000 - 0xFFFFFFFF System No + */ + + // Select region 0 and use it for the WT read-only rom region + // - Code 0x00000000 to MBED_MPU_ROM_END + ARM_MPU_SetRegion( + ARM_MPU_RBAR( + 0, // Region + 0x00000000), // Base + ARM_MPU_RASR( + 0, // DisableExec + ARM_MPU_AP_RO, // AccessPermission + 0, // TypeExtField + 0, // IsShareable + 1, // IsCacheable + 0, // IsBufferable + // SubRegionDisable - based on where ROM ends + ((MBED_MPU_ROM_END >= 0x00000000) ? 0 : (1 << 0)) | // 0 to enable, 1 << n to disable + ((MBED_MPU_ROM_END >= 0x04000000) ? 0 : (1 << 1)) | + ((MBED_MPU_ROM_END >= 0x08000000) ? 0 : (1 << 2)) | + ((MBED_MPU_ROM_END >= 0x0C000000) ? 0 : (1 << 3)) | + ((MBED_MPU_ROM_END >= 0x10000000) ? 0 : (1 << 4)) | + ((MBED_MPU_ROM_END >= 0x14000000) ? 0 : (1 << 5)) | + ((MBED_MPU_ROM_END >= 0x18000000) ? 0 : (1 << 6)) | + ((MBED_MPU_ROM_END >= 0x1C000000) ? 0 : (1 << 7)), + ARM_MPU_REGION_SIZE_512MB) // Size + ); + +#if MBED_MPU_RAM_START < 0x20000000 + // Select region 3 and use it for a WT ram region in the Code area + // - Code MBED_MPU_ROM_END + 1 to 0x1FFFFFFF + ARM_MPU_SetRegion( + ARM_MPU_RBAR( + 3, // Region + 0x00000000), // Base + ARM_MPU_RASR( + 1, // DisableExec + ARM_MPU_AP_FULL, // AccessPermission + 0, // TypeExtField + 0, // IsShareable + 1, // IsCacheable + 0, // IsBufferable + // SubRegionDisable - based on where RAM starts + ((MBED_MPU_RAM_START <= 0x04000000) ? 0 : (1 << 0)) | // 0 to enable, 1 << n to disable + ((MBED_MPU_RAM_START <= 0x08000000) ? 0 : (1 << 1)) | + ((MBED_MPU_RAM_START <= 0x0C000000) ? 0 : (1 << 2)) | + ((MBED_MPU_RAM_START <= 0x10000000) ? 0 : (1 << 3)) | + ((MBED_MPU_RAM_START <= 0x14000000) ? 0 : (1 << 4)) | + ((MBED_MPU_RAM_START <= 0x18000000) ? 0 : (1 << 5)) | + ((MBED_MPU_RAM_START <= 0x1C000000) ? 0 : (1 << 6)) | + ((MBED_MPU_RAM_START <= 0x20000000) ? 0 : (1 << 7)), + ARM_MPU_REGION_SIZE_512MB) // Size + ); +#define LAST_RAM_REGION 3 +#else +#define LAST_RAM_REGION 2 +#endif + + // Select region 1 and use it for WBWA ram regions + // - SRAM 0x20000000 to 0x3FFFFFFF + // - RAM 0x60000000 to 0x7FFFFFFF + ARM_MPU_SetRegion( + ARM_MPU_RBAR( + 1, // Region + 0x00000000), // Base + ARM_MPU_RASR( + 1, // DisableExec + ARM_MPU_AP_FULL, // AccessPermission + 1, // TypeExtField + 0, // IsShareable + 1, // IsCacheable + 1, // IsBufferable + // SubRegionDisable + (1 << 0) | // Disable Sub-region + (0 << 1) | // Enable Sub-region SRAM 0x20000000 - 0x3FFFFFFF + (1 << 2) | // Disable Sub-region + (0 << 3) | // Enable Sub-region RAM 0x60000000 - 0x7FFFFFFF + (1 << 4) | // Disable Sub-region + (1 << 5) | // Disable Sub-region + (1 << 6) | // Disable Sub-region + (1 << 7), // Disable Sub-region + ARM_MPU_REGION_SIZE_4GB) // Size + ); + + // Select region 2 and use it for the WT ram region + // - RAM 0x80000000 to 0x9FFFFFFF + ARM_MPU_SetRegion( + ARM_MPU_RBAR( + 2, // Region + 0x80000000), // Base + ARM_MPU_RASR( + 1, // DisableExec + ARM_MPU_AP_FULL, // AccessPermission + 0, // TypeExtField + 0, // IsShareable + 1, // IsCacheable + 0, // IsBufferable + 0U, // SubRegionDisable + ARM_MPU_REGION_SIZE_512MB) // Size + ); + + // Enable the MPU + MPU->CTRL = + (1 << MPU_CTRL_PRIVDEFENA_Pos) | // Use the default memory map for unmapped addresses + (1 << MPU_CTRL_HFNMIENA_Pos) | // Keep MPU turned on for faults + (1 << MPU_CTRL_ENABLE_Pos); // Enable MPU + + // Ensure changes take effect + __DSB(); + __ISB(); +} + +void mbed_mpu_free() +{ + // Flush memory writes before configuring the MPU. + __DMB(); + + // Disable the MPU + MPU->CTRL = 0; + + // Ensure changes take effect + __DSB(); + __ISB(); +} + +static void enable_region(bool enable, uint32_t region) +{ + MPU->RNR = region; + MPU->RASR = (MPU->RASR & ~MPU_RASR_ENABLE_Msk) | (enable << MPU_RASR_ENABLE_Pos); +} + +void mbed_mpu_enable_rom_wn(bool enable) +{ + // Flush memory writes before configuring the MPU. + __DMB(); + + enable_region(enable, 0); + + // Ensure changes take effect + __DSB(); + __ISB(); +} + +void mbed_mpu_enable_ram_xn(bool enable) +{ + // Flush memory writes before configuring the MPU. + __DMB(); + + for (uint32_t region = 1; region <= LAST_RAM_REGION; region++) { + enable_region(enable, region); + } + + // Ensure changes take effect + __DSB(); + __ISB(); +} + +#endif diff --git a/hal/source/mpu/mbed_mpu_v8m.c b/hal/source/mpu/mbed_mpu_v8m.c new file mode 100644 index 0000000..ccdbd59 --- /dev/null +++ b/hal/source/mpu/mbed_mpu_v8m.c @@ -0,0 +1,212 @@ +/* mbed Microcontroller Library + * Copyright (c) 2018 ARM Limited + * 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. + */ +#include "hal/mpu_api.h" +#include "platform/mbed_assert.h" +#include "cmsis.h" + +#if ((__ARM_ARCH_8M_BASE__ == 1U) || (__ARM_ARCH_8M_MAIN__ == 1U)) && \ + defined (__MPU_PRESENT) && (__MPU_PRESENT == 1U) && \ + !defined(MBED_MPU_CUSTOM) + +#if !DEVICE_MPU +#error "Device has v8m MPU but it is not enabled. Add 'MPU' to device_has in targets.json" +#endif + +#ifdef MBED_CONF_TARGET_MPU_ROM_END +#define MBED_MPU_ROM_END MBED_CONF_TARGET_MPU_ROM_END +#else +#define MBED_MPU_ROM_END (0x10000000 - 1) +#endif +#define MBED_MPU_RAM_START (MBED_MPU_ROM_END + 1) + +MBED_STATIC_ASSERT(MBED_MPU_ROM_END <= 0x20000000 - 1, + "Unsupported value for MBED_MPU_ROM_END"); + +void mbed_mpu_init() +{ + // Flush memory writes before configuring the MPU. + __DMB(); + + const uint32_t regions = (MPU->TYPE & MPU_TYPE_DREGION_Msk) >> MPU_TYPE_DREGION_Pos; + + // Our MPU setup requires 4 or 5 regions - if this assert is hit, remove + // a region by setting MPU_ROM_END to 0x1fffffff, or remove MPU from device_has +#if MBED_MPU_RAM_START == 0x20000000 + MBED_ASSERT(regions >= 4); +#else + MBED_ASSERT(regions >= 5); +#endif + + // Disable the MCU + MPU->CTRL = 0; + + // Reset all mapping + for (uint32_t i = 0; i < regions; i++) { + ARM_MPU_ClrRegion(i); + } + + /* + * ARMv8-M memory map: + * + * Start End Name Executable by default Default cache Mbed MPU protection + * 0x00000000 - 0x1FFFFFFF Code Yes WT, WA Write disabled for first portion and execute disabled for the rest + * 0x20000000 - 0x3FFFFFFF SRAM Yes WB, WA, RA Execute disabled + * 0x40000000 - 0x5FFFFFFF Peripheral No + * 0x60000000 - 0x7FFFFFFF RAM Yes WB, WA, RA Execute disabled + * 0x80000000 - 0x9FFFFFFF RAM Yes WT, RA Execute disabled + * 0xA0000000 - 0xBFFFFFFF Device No + * 0xC0000000 - 0xDFFFFFFF Device No + * 0xE0000000 - 0xFFFFFFFF System No + */ + + const uint8_t WTRA = ARM_MPU_ATTR_MEMORY_(1, 0, 1, 0); // Non-transient, Write-Through, Read-allocate, Not Write-allocate + const uint8_t WBWARA = ARM_MPU_ATTR_MEMORY_(1, 1, 1, 1); // Non-transient, Write-Back, Read-allocate, Write-allocate + enum { + AttrIndex_WTRA, + AttrIndex_WBWARA, + }; + + ARM_MPU_SetMemAttr(AttrIndex_WTRA, ARM_MPU_ATTR(WTRA, WTRA)); + ARM_MPU_SetMemAttr(AttrIndex_WBWARA, ARM_MPU_ATTR(WBWARA, WBWARA)); + + ARM_MPU_SetRegion( + 0, // Region + ARM_MPU_RBAR( + 0x00000000, // Base + ARM_MPU_SH_NON, // Non-shareable + 1, // Read-Only + 1, // Non-Privileged + 0), // Execute Never disabled + ARM_MPU_RLAR( + MBED_MPU_ROM_END, // Limit + AttrIndex_WTRA) // Attribute index - Write-Through, Read-allocate + ); + +#if MBED_MPU_RAM_START != 0x20000000 + ARM_MPU_SetRegion( + 4, // Region + ARM_MPU_RBAR( + MBED_MPU_RAM_START, // Base + ARM_MPU_SH_NON, // Non-shareable + 0, // Read-Write + 1, // Non-Privileged + 1), // Execute Never enabled + ARM_MPU_RLAR( + 0x1FFFFFFF, // Limit + AttrIndex_WTRA) // Attribute index - Write-Through, Read-allocate + ); +#define LAST_RAM_REGION 4 +#else +#define LAST_RAM_REGION 3 +#endif + + ARM_MPU_SetRegion( + 1, // Region + ARM_MPU_RBAR( + 0x20000000, // Base + ARM_MPU_SH_NON, // Non-shareable + 0, // Read-Write + 1, // Non-Privileged + 1), // Execute Never enabled + ARM_MPU_RLAR( + 0x3FFFFFFF, // Limit + AttrIndex_WBWARA) // Attribute index - Write-Back, Write-allocate + ); + + ARM_MPU_SetRegion( + 2, // Region + ARM_MPU_RBAR( + 0x60000000, // Base + ARM_MPU_SH_NON, // Non-shareable + 0, // Read-Write + 1, // Non-Privileged + 1), // Execute Never enabled + ARM_MPU_RLAR( + 0x7FFFFFFF, // Limit + AttrIndex_WBWARA) // Attribute index - Write-Back, Write-allocate + ); + + ARM_MPU_SetRegion( + 3, // Region + ARM_MPU_RBAR( + 0x80000000, // Base + ARM_MPU_SH_NON, // Non-shareable + 0, // Read-Write + 1, // Non-Privileged + 1), // Execute Never enabled + ARM_MPU_RLAR( + 0x9FFFFFFF, // Limit + AttrIndex_WTRA) // Attribute index - Write-Through, Read-allocate + ); + + // Enable the MPU + MPU->CTRL = + (1 << MPU_CTRL_PRIVDEFENA_Pos) | // Use the default memory map for unmapped addresses + (1 << MPU_CTRL_HFNMIENA_Pos) | // Keep MPU turned on for faults + (1 << MPU_CTRL_ENABLE_Pos); // Enable MPU + + // Ensure changes take effect + __DSB(); + __ISB(); +} + +void mbed_mpu_free() +{ + // Flush memory writes before configuring the MPU. + __DMB(); + + // Disable the MCU + MPU->CTRL = 0; + + // Ensure changes take effect + __DSB(); + __ISB(); +} + +static void enable_region(bool enable, uint32_t region) +{ + MPU->RNR = region; + MPU->RLAR = (MPU->RLAR & ~MPU_RLAR_EN_Msk) | (enable << MPU_RLAR_EN_Pos); +} + +void mbed_mpu_enable_rom_wn(bool enable) +{ + // Flush memory writes before configuring the MPU. + __DMB(); + + enable_region(enable, 0); + + // Ensure changes take effect + __DSB(); + __ISB(); +} + +void mbed_mpu_enable_ram_xn(bool enable) +{ + // Flush memory writes before configuring the MPU. + __DMB(); + + for (uint32_t region = 1; region <= LAST_RAM_REGION; region++) { + enable_region(enable, region); + } + + // Ensure changes take effect + __DSB(); + __ISB(); +} + +#endif diff --git a/hal/source/static_pinmap.cpp b/hal/source/static_pinmap.cpp new file mode 100644 index 0000000..ba1f958 --- /dev/null +++ b/hal/source/static_pinmap.cpp @@ -0,0 +1,96 @@ +/* mbed Microcontroller Library + * Copyright (c) 2006-2019 ARM Limited + * 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. + */ + +#include "mbed_error.h" +#include "static_pinmap.h" + + +/* + * This file provides default definitions of xxx_direct() functions for peripherals. + * in all cases standard init function is called, which won't give any ROM memory savings. + * + */ + +#if DEVICE_SPI +MBED_WEAK void spi_init_direct(spi_t *obj, const spi_pinmap_t *pinmap) +{ + spi_init(obj, pinmap->mosi_pin, pinmap->miso_pin, pinmap->sclk_pin, pinmap->ssel_pin); +} +#endif + +#if DEVICE_PWMOUT +MBED_WEAK void pwmout_init_direct(pwmout_t *obj, const PinMap *pinmap) +{ + pwmout_init(obj, pinmap->pin); +} +#endif + +#if DEVICE_ANALOGIN +MBED_WEAK void analogin_init_direct(analogin_t *obj, const PinMap *pinmap) +{ + analogin_init(obj, pinmap->pin); +} +#endif + +#if DEVICE_ANALOGOUT +MBED_WEAK void analogout_init_direct(dac_t *obj, const PinMap *pinmap) +{ + analogout_init(obj, pinmap->pin); +} +#endif + +#if DEVICE_I2C +MBED_WEAK void i2c_init_direct(i2c_t *obj, const i2c_pinmap_t *pinmap) +{ + i2c_init(obj, pinmap->sda_pin, pinmap->scl_pin); +} +#endif + +#if DEVICE_SERIAL +MBED_WEAK void serial_init_direct(serial_t *obj, const serial_pinmap_t *pinmap) +{ + serial_init(obj, pinmap->tx_pin, pinmap->rx_pin); +} + +#if DEVICE_SERIAL_FC +MBED_WEAK void serial_set_flow_control_direct(serial_t *obj, FlowControl type, const serial_fc_pinmap_t *pinmap) +{ + serial_set_flow_control(obj, type, pinmap->rx_flow_pin, pinmap->tx_flow_pin); +} +#endif + +#if DEVICE_CAN +MBED_WEAK void can_init_freq_direct(can_t *obj, const can_pinmap_t *pinmap, int hz) +{ + can_init_freq(obj, pinmap->rd_pin, pinmap->td_pin, hz); +} + +MBED_WEAK void can_init_direct(can_t *obj, const can_pinmap_t *pinmap) +{ + can_init(obj, pinmap->rd_pin, pinmap->td_pin); +} + +#endif + +#if DEVICE_QSPI +MBED_WEAK qspi_status_t qspi_init_direct(qspi_t *obj, const qspi_pinmap_t *pinmap, uint32_t hz, uint8_t mode) +{ + return qspi_init(obj, pinmap->data0_pin, pinmap->data1_pin, pinmap->data2_pin, pinmap->data3_pin, pinmap->sclk_pin, pinmap->ssel_pin, hz, mode); +} +#endif + +#endif diff --git a/hal/spi_api.h b/hal/spi_api.h deleted file mode 100644 index f67b6ef..0000000 --- a/hal/spi_api.h +++ /dev/null @@ -1,427 +0,0 @@ - -/** \addtogroup hal */ -/** @{*/ -/* mbed Microcontroller Library - * Copyright (c) 2006-2013 ARM Limited - * 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. - */ -#ifndef MBED_SPI_API_H -#define MBED_SPI_API_H - -#include "device.h" -#include "pinmap.h" -#include "hal/dma_api.h" -#include "hal/buffer.h" - -#if DEVICE_SPI - -#define SPI_EVENT_ERROR (1 << 1) -#define SPI_EVENT_COMPLETE (1 << 2) -#define SPI_EVENT_RX_OVERFLOW (1 << 3) -#define SPI_EVENT_ALL (SPI_EVENT_ERROR | SPI_EVENT_COMPLETE | SPI_EVENT_RX_OVERFLOW) - -#define SPI_EVENT_INTERNAL_TRANSFER_COMPLETE (1 << 30) // Internal flag to report that an event occurred - -#define SPI_FILL_WORD (0xFFFF) -#define SPI_FILL_CHAR (0xFF) - -#if DEVICE_SPI_ASYNCH -/** Asynch SPI HAL structure - */ -typedef struct { - struct spi_s spi; /**< Target specific SPI structure */ - struct buffer_s tx_buff; /**< Tx buffer */ - struct buffer_s rx_buff; /**< Rx buffer */ -} spi_t; - -#else -/** Non-asynch SPI HAL structure - */ -typedef struct spi_s spi_t; - -#endif - -typedef struct { - int peripheral; - PinName mosi_pin; - int mosi_function; - PinName miso_pin; - int miso_function; - PinName sclk_pin; - int sclk_function; - PinName ssel_pin; - int ssel_function; -} spi_pinmap_t; - -/** - * Describes the capabilities of a SPI peripherals - */ -typedef struct { - /** Minimum frequency supported must be set by target device and it will be assessed during - * testing. - */ - uint32_t minimum_frequency; - /** Maximum frequency supported must be set by target device and it will be assessed during - * testing. - */ - uint32_t maximum_frequency; - /** Each bit represents the corresponding word length. lsb => 1bit, msb => 32bit. */ - uint32_t word_length; - uint16_t slave_delay_between_symbols_ns; /**< specifies required number of ns between transmission of successive symbols in slave mode. */ - uint8_t clk_modes; /**< specifies supported modes from spi_mode_t. Each bit represents the corresponding mode. */ - bool support_slave_mode; /**< If true, the device can handle SPI slave mode using hardware management on the specified ssel pin. */ - bool hw_cs_handle; /**< If true, in SPI master mode Chip Select can be handled by hardware. */ - bool async_mode; /**< If true, in async mode is supported. */ - bool tx_rx_buffers_equal_length; /**< If true, rx and tx buffers must have the same length. */ -} spi_capabilities_t; - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * \defgroup hal_GeneralSPI SPI Configuration Functions - * - * # Defined behavior - * * ::spi_init initializes the spi_t control structure - * * ::spi_init configures the pins used by SPI - Verified by ::fpga_spi_test_init_free, ::fpga_spi_test_common_no_ss and ::fpga_spi_test_common - * * ::spi_get_capabilities() fills the given `spi_capabilities_t` instance - Verified by ::fpga_spi_test_common_no_ss and ::fpga_spi_test_common - * * ::spi_get_capabilities() should consider the `ssel` pin when evaluation the `support_slave_mode` and `hw_cs_handle` capability - TBD (basic test) - * * ::spi_get_capabilities(): if the given `ssel` pin cannot be managed by hardware, `support_slave_mode` and `hw_cs_handle` should be false - TBD (basic test) - * * At least a symbol width of 8bit must be supported - Verified by ::fpga_spi_test_common_no_ss and ::fpga_spi_test_common - * * The supported frequency range must include the range [0.2..2] MHz - Verified by ::fpga_spi_test_common_no_ss and ::fpga_spi_test_common - * * ::spi_free returns the pins owned by the SPI object to their reset state - Verified by ::fpga_spi_test_init_free - * * ::spi_format sets the number of bits per frame - Verified by ::fpga_spi_test_common_no_ss and ::fpga_spi_test_common - * * ::spi_format configures clock polarity and phase - Verified by ::fpga_spi_test_common_no_ss and ::fpga_spi_test_common - * * ::spi_format configures master/slave mode - Verified by ::fpga_spi_test_common_no_ss and ::fpga_spi_test_common; slave mode - TBD - * * ::spi_frequency sets the SPI baud rate - Verified by ::fpga_spi_test_common_no_ss and ::fpga_spi_test_common - * * ::spi_master_write writes a symbol out in master mode and receives a symbol - Verified by ::fpga_spi_test_common_no_ss and ::fpga_spi_test_common - * * ::spi_master_block_write writes `tx_length` words to the bus - Verified by ::fpga_spi_test_common_no_ss and ::fpga_spi_test_common - * * ::spi_master_block_write reads `rx_length` words from the bus - Verified by ::fpga_spi_test_common_no_ss and ::fpga_spi_test_common - * * ::spi_master_block_write returns the maximum of tx_length and rx_length - Verified by ::fpga_spi_test_common_no_ss and ::fpga_spi_test_common - * * ::spi_master_block_write specifies the write_fill which is default data transmitted while performing a read - Verified by ::fpga_spi_test_common_no_ss and ::fpga_spi_test_common - * * ::spi_get_module returns the SPI module number - TBD (basic test) - * * ::spi_slave_read returns a received value out of the SPI receive buffer in slave mode - TBD (SPI slave test) - * * ::spi_slave_read blocks until a value is available - TBD (SPI slave test) - * * ::spi_slave_write writes a value to the SPI peripheral in slave mode - TBD (SPI slave test) - * * ::spi_slave_write blocks until the SPI peripheral can be written to - TBD (SPI slave test) - * * ::spi_busy returns non-zero if the peripheral is currently transmitting, 0 otherwise - TBD (basic test) - * * ::spi_master_transfer starts the SPI asynchronous transfer - Verified by ::fpga_spi_test_common_no_ss and ::fpga_spi_test_common - * * ::spi_master_transfer writes `tx_len` words to the bus - Verified by ::fpga_spi_test_common_no_ss and ::fpga_spi_test_common - * * ::spi_master_transfer reads `rx_len` words from the bus - Verified by ::fpga_spi_test_common_no_ss and ::fpga_spi_test_common - * * ::spi_master_transfer specifies the bit width of buffer words - Verified by ::fpga_spi_test_common_no_ss and ::fpga_spi_test_common - * * The callback given to ::spi_master_transfer is invoked when the transfer completes (with a success or an error) - Verified by ::fpga_spi_test_common_no_ss and ::fpga_spi_test_common - * * ::spi_master_transfer specifies the logical OR of events to be registered - Verified by ::fpga_spi_test_common_no_ss and ::fpga_spi_test_common - * * The ::spi_master_transfer function may use the `DMAUsage` hint to select the appropriate async algorithm - Not testable - * * ::spi_irq_handler_asynch reads the received values out of the RX FIFO - Verified by ::fpga_spi_test_common_no_ss and ::fpga_spi_test_common - * * ::spi_irq_handler_asynch writes values into the TX FIFO - Verified by ::fpga_spi_test_common_no_ss and ::fpga_spi_test_common - * * ::spi_irq_handler_asynch checks for transfer termination conditions, such as buffer overflows or transfer complete - Verified by ::fpga_spi_test_common_no_ss and ::fpga_spi_test_common - * * ::spi_irq_handler_asynch returns event flags if a transfer termination condition was met, otherwise 0 - Verified by ::fpga_spi_test_common_no_ss and ::fpga_spi_test_common - * * ::spi_abort_asynch aborts an on-going async transfer - TBD (basic test) - * * ::spi_active returns non-zero if the SPI port is active or zero if it is not - TBD (basic test) - * - * # Undefined behavior - * * Calling ::spi_init multiple times on the same `spi_t` without ::spi_free - * * Calling any function other than ::spi_init on a non-initialized or freed `spi_t` - * * Passing pins that cannot be on the same peripheral - * * Passing an invalid pointer as `obj` to any function - * * Passing an invalid pointer as `handler` to ::spi_master_transfer - * * Calling ::spi_abort while no async transfer is being processed (no transfer or a synchronous transfer) - * - * @{ - */ - -/** - * \defgroup hal_GeneralSPI_tests SPI hal tests - * The SPI HAL tests ensure driver conformance to defined behaviour. - * - * To run the SPI hal tests use the command: - * - * mbed test -t -m -n tests-mbed_hal_fpga_ci_test_shield-spi - * - */ - -#ifdef DEVICE_SPI_COUNT -/** - * Returns a variant of the SPIName enum uniquely identifying a SPI peripheral of the device. - * @param[in] mosi The pin to use for MOSI - * @param[in] miso The pin to use for MISO - * @param[in] sclk The pin to use for SCLK - * @return An SPI peripheral identifier - */ -SPIName spi_get_peripheral_name(PinName mosi, PinName miso, PinName mclk); -#endif - -/** - * Fills the given spi_capabilities_t structure with the capabilities of the given peripheral. - */ -void spi_get_capabilities(PinName ssel, bool slave, spi_capabilities_t *cap); - -/** Initialize the SPI peripheral - * - * Configures the pins used by SPI, sets a default format and frequency, and enables the peripheral - * @param[out] obj The SPI object to initialize - * @param[in] pinmap pointer to structure which holds static pinmap - */ -void spi_init_direct(spi_t *obj, const spi_pinmap_t *pinmap); - -/** Initialize the SPI peripheral - * - * Configures the pins used by SPI, sets a default format and frequency, and enables the peripheral - * @param[out] obj The SPI object to initialize - * @param[in] mosi The pin to use for MOSI - * @param[in] miso The pin to use for MISO - * @param[in] sclk The pin to use for SCLK - * @param[in] ssel The pin to use for SSEL - */ -void spi_init(spi_t *obj, PinName mosi, PinName miso, PinName sclk, PinName ssel); - -/** Release a SPI object - * - * TODO: spi_free is currently unimplemented - * This will require reference counting at the C++ level to be safe - * - * Return the pins owned by the SPI object to their reset state - * Disable the SPI peripheral - * Disable the SPI clock - * @param[in] obj The SPI object to deinitialize - */ -void spi_free(spi_t *obj); - -/** Configure the SPI format - * - * Set the number of bits per frame, configure clock polarity and phase, shift order and master/slave mode. - * The default bit order is MSB. - * @param[in,out] obj The SPI object to configure - * @param[in] bits The number of bits per frame - * @param[in] mode The SPI mode (clock polarity, phase, and shift direction) - * @param[in] slave Zero for master mode or non-zero for slave mode - */ -void spi_format(spi_t *obj, int bits, int mode, int slave); - -/** Set the SPI baud rate - * - * Actual frequency may differ from the desired frequency due to available dividers and bus clock - * Configures the SPI peripheral's baud rate - * @param[in,out] obj The SPI object to configure - * @param[in] hz The baud rate in Hz - */ -void spi_frequency(spi_t *obj, int hz); - -/**@}*/ -/** - * \defgroup SynchSPI Synchronous SPI Hardware Abstraction Layer - * @{ - */ - -/** Write a byte out in master mode and receive a value - * - * @param[in] obj The SPI peripheral to use for sending - * @param[in] value The value to send - * @return Returns the value received during send - */ -int spi_master_write(spi_t *obj, int value); - -/** Write a block out in master mode and receive a value - * - * The total number of bytes sent and received will be the maximum of - * tx_length and rx_length. The bytes written will be padded with the - * value 0xff. - * - * @param[in] obj The SPI peripheral to use for sending - * @param[in] tx_buffer Pointer to the byte-array of data to write to the device - * @param[in] tx_length Number of bytes to write, may be zero - * @param[in] rx_buffer Pointer to the byte-array of data to read from the device - * @param[in] rx_length Number of bytes to read, may be zero - * @param[in] write_fill Default data transmitted while performing a read - * @returns - * The number of bytes written and read from the device. This is - * maximum of tx_length and rx_length. - */ -int spi_master_block_write(spi_t *obj, const char *tx_buffer, int tx_length, char *rx_buffer, int rx_length, char write_fill); - -/** Check if a value is available to read - * - * @param[in] obj The SPI peripheral to check - * @return non-zero if a value is available - */ -int spi_slave_receive(spi_t *obj); - -/** Get a received value out of the SPI receive buffer in slave mode - * - * Blocks until a value is available - * @param[in] obj The SPI peripheral to read - * @return The value received - */ -int spi_slave_read(spi_t *obj); - -/** Write a value to the SPI peripheral in slave mode - * - * Blocks until the SPI peripheral can be written to - * @param[in] obj The SPI peripheral to write - * @param[in] value The value to write - */ -void spi_slave_write(spi_t *obj, int value); - -/** Checks if the specified SPI peripheral is in use - * - * @param[in] obj The SPI peripheral to check - * @return non-zero if the peripheral is currently transmitting - */ -int spi_busy(spi_t *obj); - -/** Get the module number - * - * @param[in] obj The SPI peripheral to check - * @return The module number - */ -uint8_t spi_get_module(spi_t *obj); - -/** Get the pins that support SPI MOSI - * - * Return a PinMap array of pins that support SPI MOSI in - * master mode. The array is terminated with {NC, NC, 0}. - * - * @return PinMap array - */ -const PinMap *spi_master_mosi_pinmap(void); - -/** Get the pins that support SPI MISO - * - * Return a PinMap array of pins that support SPI MISO in - * master mode. The array is terminated with {NC, NC, 0}. - * - * @return PinMap array - */ -const PinMap *spi_master_miso_pinmap(void); - -/** Get the pins that support SPI CLK - * - * Return a PinMap array of pins that support SPI CLK in - * master mode. The array is terminated with {NC, NC, 0}. - * - * @return PinMap array - */ -const PinMap *spi_master_clk_pinmap(void); - -/** Get the pins that support SPI CS - * - * Return a PinMap array of pins that support SPI CS in - * master mode. The array is terminated with {NC, NC, 0}. - * - * @return PinMap array - */ -const PinMap *spi_master_cs_pinmap(void); - -/** Get the pins that support SPI MOSI - * - * Return a PinMap array of pins that support SPI MOSI in - * slave mode. The array is terminated with {NC, NC, 0}. - * - * @return PinMap array - */ -const PinMap *spi_slave_mosi_pinmap(void); - -/** Get the pins that support SPI MISO - * - * Return a PinMap array of pins that support SPI MISO in - * slave mode. The array is terminated with {NC, NC, 0}. - * - * @return PinMap array - */ -const PinMap *spi_slave_miso_pinmap(void); - -/** Get the pins that support SPI CLK - * - * Return a PinMap array of pins that support SPI CLK in - * slave mode. The array is terminated with {NC, NC, 0}. - * - * @return PinMap array - */ -const PinMap *spi_slave_clk_pinmap(void); - -/** Get the pins that support SPI CS - * - * Return a PinMap array of pins that support SPI CS in - * slave mode. The array is terminated with {NC, NC, 0}. - * - * @return PinMap array - */ -const PinMap *spi_slave_cs_pinmap(void); - -/**@}*/ - -#if DEVICE_SPI_ASYNCH -/** - * \defgroup AsynchSPI Asynchronous SPI Hardware Abstraction Layer - * @{ - */ - -/** Begin the SPI transfer. Buffer pointers and lengths are specified in tx_buff and rx_buff - * - * @param[in] obj The SPI object that holds the transfer information - * @param[in] tx The transmit buffer - * @param[in] tx_length The number of bytes to transmit - * @param[in] rx The receive buffer - * @param[in] rx_length The number of bytes to receive - * @param[in] bit_width The bit width of buffer words - * @param[in] event The logical OR of events to be registered - * @param[in] handler SPI interrupt handler - * @param[in] hint A suggestion for how to use DMA with this transfer - */ -void spi_master_transfer(spi_t *obj, const void *tx, size_t tx_length, void *rx, size_t rx_length, uint8_t bit_width, uint32_t handler, uint32_t event, DMAUsage hint); - -/** The asynchronous IRQ handler - * - * Reads the received values out of the RX FIFO, writes values into the TX FIFO and checks for transfer termination - * conditions, such as buffer overflows or transfer complete. - * @param[in] obj The SPI object that holds the transfer information - * @return Event flags if a transfer termination condition was met; otherwise 0. - */ -uint32_t spi_irq_handler_asynch(spi_t *obj); - -/** Attempts to determine if the SPI peripheral is already in use - * - * If a temporary DMA channel has been allocated, peripheral is in use. - * If a permanent DMA channel has been allocated, check if the DMA channel is in use. If not, proceed as though no DMA - * channel were allocated. - * If no DMA channel is allocated, check whether tx and rx buffers have been assigned. For each assigned buffer, check - * if the corresponding buffer position is less than the buffer length. If buffers do not indicate activity, check if - * there are any bytes in the FIFOs. - * @param[in] obj The SPI object to check for activity - * @return Non-zero if the SPI port is active or zero if it is not. - */ -uint8_t spi_active(spi_t *obj); - -/** Abort an SPI transfer - * - * @param obj The SPI peripheral to stop - */ -void spi_abort_asynch(spi_t *obj); - - -#endif - -/**@}*/ - -#ifdef __cplusplus -} -#endif // __cplusplus - -#endif // SPI_DEVICE - -#endif // MBED_SPI_API_H - -/** @}*/ diff --git a/hal/static_pinmap.cpp b/hal/static_pinmap.cpp deleted file mode 100644 index ba1f958..0000000 --- a/hal/static_pinmap.cpp +++ /dev/null @@ -1,96 +0,0 @@ -/* mbed Microcontroller Library - * Copyright (c) 2006-2019 ARM Limited - * 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. - */ - -#include "mbed_error.h" -#include "static_pinmap.h" - - -/* - * This file provides default definitions of xxx_direct() functions for peripherals. - * in all cases standard init function is called, which won't give any ROM memory savings. - * - */ - -#if DEVICE_SPI -MBED_WEAK void spi_init_direct(spi_t *obj, const spi_pinmap_t *pinmap) -{ - spi_init(obj, pinmap->mosi_pin, pinmap->miso_pin, pinmap->sclk_pin, pinmap->ssel_pin); -} -#endif - -#if DEVICE_PWMOUT -MBED_WEAK void pwmout_init_direct(pwmout_t *obj, const PinMap *pinmap) -{ - pwmout_init(obj, pinmap->pin); -} -#endif - -#if DEVICE_ANALOGIN -MBED_WEAK void analogin_init_direct(analogin_t *obj, const PinMap *pinmap) -{ - analogin_init(obj, pinmap->pin); -} -#endif - -#if DEVICE_ANALOGOUT -MBED_WEAK void analogout_init_direct(dac_t *obj, const PinMap *pinmap) -{ - analogout_init(obj, pinmap->pin); -} -#endif - -#if DEVICE_I2C -MBED_WEAK void i2c_init_direct(i2c_t *obj, const i2c_pinmap_t *pinmap) -{ - i2c_init(obj, pinmap->sda_pin, pinmap->scl_pin); -} -#endif - -#if DEVICE_SERIAL -MBED_WEAK void serial_init_direct(serial_t *obj, const serial_pinmap_t *pinmap) -{ - serial_init(obj, pinmap->tx_pin, pinmap->rx_pin); -} - -#if DEVICE_SERIAL_FC -MBED_WEAK void serial_set_flow_control_direct(serial_t *obj, FlowControl type, const serial_fc_pinmap_t *pinmap) -{ - serial_set_flow_control(obj, type, pinmap->rx_flow_pin, pinmap->tx_flow_pin); -} -#endif - -#if DEVICE_CAN -MBED_WEAK void can_init_freq_direct(can_t *obj, const can_pinmap_t *pinmap, int hz) -{ - can_init_freq(obj, pinmap->rd_pin, pinmap->td_pin, hz); -} - -MBED_WEAK void can_init_direct(can_t *obj, const can_pinmap_t *pinmap) -{ - can_init(obj, pinmap->rd_pin, pinmap->td_pin); -} - -#endif - -#if DEVICE_QSPI -MBED_WEAK qspi_status_t qspi_init_direct(qspi_t *obj, const qspi_pinmap_t *pinmap, uint32_t hz, uint8_t mode) -{ - return qspi_init(obj, pinmap->data0_pin, pinmap->data1_pin, pinmap->data2_pin, pinmap->data3_pin, pinmap->sclk_pin, pinmap->ssel_pin, hz, mode); -} -#endif - -#endif diff --git a/hal/static_pinmap.h b/hal/static_pinmap.h deleted file mode 100644 index fafed9c..0000000 --- a/hal/static_pinmap.h +++ /dev/null @@ -1,363 +0,0 @@ -/* mbed Microcontroller Library - * Copyright (c) 2018-2019 ARM Limited - * 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. - */ -#ifndef STATIC_PINMAP_H -#define STATIC_PINMAP_H - -#include "PinNames.h" -#include "spi_api.h" -#include "pwmout_api.h" -#include "analogin_api.h" -#include "analogout_api.h" -#include "i2c_api.h" -#include "serial_api.h" -#include "qspi_api.h" -#include "can_api.h" -#include - -#if STATIC_PINMAP_READY -#include "PeripheralPinMaps.h" - - -#if defined(DEVICE_PWMOUT) && defined(PINMAP_PWM) -MSTD_CONSTEXPR_FN_14 PinMap get_pwm_pinmap(const PinName pin) -{ - for (const PinMap &pinmap : PINMAP_PWM) { - if (pinmap.pin == pin) { - return {pin, pinmap.peripheral, pinmap.function}; - } - } - return {NC, (int) NC, (int) NC}; -} -#endif // DEVICE_PWMOUT - -#if defined(DEVICE_ANALOGIN) && defined(PINMAP_ANALOGIN) -MSTD_CONSTEXPR_FN_14 PinMap get_analogin_pinmap(const PinName pin) -{ - for (const PinMap &pinmap : PINMAP_ANALOGIN) { - if (pinmap.pin == pin) { - return {pin, pinmap.peripheral, pinmap.function}; - } - } - -#if PINMAP_ANALOGIN_INTERNAL - for (const PinMap &pinmap : PINMAP_ANALOGIN_INTERNAL) { - if (pinmap.pin == pin) { - return {pin, pinmap.peripheral, pinmap.function}; - } - } -#endif - - return {NC, (int) NC, (int) NC}; -} -#endif // DEVICE_ANALOGIN - -#if defined(DEVICE_ANALOGOUT) && defined(PINMAP_ANALOGOUT) -MSTD_CONSTEXPR_FN_14 PinMap get_analogout_pinmap(const PinName pin) -{ - for (const PinMap &pinmap : PINMAP_ANALOGOUT) { - if (pinmap.pin == pin) { - return {pin, pinmap.peripheral, pinmap.function}; - } - } - return {NC, (int) NC, (int) NC}; -} -#endif // DEVICE_ANALOGOUT - -#if defined(DEVICE_I2C) && defined(PINMAP_I2C_SDA) && defined(PINMAP_I2C_SCL) -MSTD_CONSTEXPR_FN_14 i2c_pinmap_t get_i2c_pinmap(const PinName sda, const PinName scl) -{ - const PinMap *sda_map = nullptr; - for (const PinMap &pinmap : PINMAP_I2C_SDA) { - if (pinmap.pin == sda) { - sda_map = &pinmap; - break; - } - } - - const PinMap *scl_map = nullptr; - for (const PinMap &pinmap : PINMAP_I2C_SCL) { - if (pinmap.pin == scl) { - scl_map = &pinmap; - break; - } - } - - if (!sda_map || !scl_map || sda_map->peripheral != scl_map->peripheral) { - return {(int) NC, NC, (int) NC, NC, (int) NC}; - } - - return {sda_map->peripheral, sda_map->pin, sda_map->function, scl_map->pin, scl_map->function}; -} -#endif //DEVICE_I2C - -#if defined(DEVICE_SERIAL) && defined(PINMAP_UART_TX) && defined(PINMAP_UART_RX) -MSTD_CONSTEXPR_FN_14 serial_pinmap_t get_uart_pinmap(const PinName tx, const PinName rx) -{ - const PinMap *tx_map = nullptr; - for (const PinMap &pinmap : PINMAP_UART_TX) { - if (pinmap.pin == tx) { - tx_map = &pinmap; - break; - } - } - - const PinMap *rx_map = nullptr; - for (const PinMap &pinmap : PINMAP_UART_RX) { - if (pinmap.pin == rx) { - rx_map = &pinmap; - break; - } - } - - if (!tx_map || !rx_map || rx_map->peripheral != tx_map->peripheral) { - return {(int) NC, NC, (int) NC, NC, (int) NC, false}; - } - - if (tx_map->pin == STDIO_UART_TX && rx_map->pin == STDIO_UART_RX) { - return {tx_map->peripheral, tx_map->pin, tx_map->function, rx_map->pin, rx_map->function, true}; - } else { - return {tx_map->peripheral, tx_map->pin, tx_map->function, rx_map->pin, rx_map->function, false}; - } -} - -#if defined(DEVICE_SERIAL_FC) && defined(PINMAP_UART_RTS) && defined(PINMAP_UART_CTS) -MSTD_CONSTEXPR_FN_14 serial_fc_pinmap_t get_uart_fc_pinmap(const PinName rxflow, const PinName txflow) -{ - const PinMap *rts_map = nullptr; - for (const PinMap &pinmap : PINMAP_UART_RTS) { - if (pinmap.pin == rxflow) { - rts_map = &pinmap; - break; - } - } - - const PinMap *cts_map = nullptr; - for (const PinMap &pinmap : PINMAP_UART_CTS) { - if (pinmap.pin == txflow) { - cts_map = &pinmap; - break; - } - } - - if ((!rts_map || !cts_map) || (rts_map->peripheral != cts_map->peripheral)) { - return {(int) NC, NC, (int) NC, NC, (int) NC}; - } - - return {cts_map->peripheral, cts_map->pin, cts_map->function, rts_map->pin, rts_map->function}; -} -#endif // DEVICE_SERIAL_FC -#endif // DEVICE_SERIAL - -#if defined(DEVICE_SPI) && defined(PINMAP_SPI_MOSI) && defined(PINMAP_SPI_MISO) && defined(PINMAP_SPI_SCLK) && defined(PINMAP_SPI_SSEL) -MSTD_CONSTEXPR_FN_14 spi_pinmap_t get_spi_pinmap(const PinName mosi, const PinName miso, const PinName sclk, const PinName ssel) -{ - const PinMap *mosi_map = nullptr; - for (const PinMap &pinmap : PINMAP_SPI_MOSI) { - if (pinmap.pin == mosi) { - mosi_map = &pinmap; - break; - } - } - - const PinMap *miso_map = nullptr; - for (const PinMap &pinmap : PINMAP_SPI_MISO) { - if (pinmap.pin == miso) { - miso_map = &pinmap; - break; - } - } - - const PinMap *sclk_map = nullptr; - for (const PinMap &pinmap : PINMAP_SPI_SCLK) { - if (pinmap.pin == sclk) { - sclk_map = &pinmap; - break; - } - } - - const PinMap *ssel_map = nullptr; - for (const PinMap &pinmap : PINMAP_SPI_SSEL) { - if (pinmap.pin == ssel) { - ssel_map = &pinmap; - break; - } - } - - if ((!mosi_map || !miso_map || !sclk_map || !ssel_map) || - (mosi_map->peripheral != miso_map->peripheral || mosi_map->peripheral != sclk_map->peripheral) || - (ssel_map->pin != NC && mosi_map->peripheral != ssel_map->peripheral)) { - return {(int) NC, NC, (int) NC, NC, (int) NC, NC, (int) NC, NC, (int) NC}; - } - - return {mosi_map->peripheral, mosi_map->pin, mosi_map->function, miso_map->pin, miso_map->function, sclk_map->pin, sclk_map->function, ssel_map->pin, ssel_map->function}; -} -#endif // DEVICE_SPI - -#if defined(DEVICE_CAN) && defined(PINMAP_CAN_RD) && defined(PINMAP_CAN_TD) -MSTD_CONSTEXPR_FN_14 can_pinmap_t get_can_pinmap(const PinName rd, const PinName td) -{ - const PinMap *rd_map = nullptr; - for (const PinMap &pinmap : PINMAP_CAN_RD) { - if (pinmap.pin == rd) { - rd_map = &pinmap; - break; - } - } - - const PinMap *td_map = nullptr; - for (const PinMap &pinmap : PINMAP_CAN_TD) { - if (pinmap.pin == td) { - td_map = &pinmap; - break; - } - } - - if (!rd_map || !td_map || rd_map->peripheral != td_map->peripheral) { - return {(int) NC, NC, (int) NC, NC, (int) NC}; - } - - return {rd_map->peripheral, rd_map->pin, rd_map->function, td_map->pin, td_map->function}; -} -#endif //DEVICE_CAN - -#if defined(DEVICE_QSPI) && defined(PINMAP_QSPI_DATA0) && defined(PINMAP_QSPI_DATA1) && defined(PINMAP_QSPI_DATA2) && defined(PINMAP_QSPI_DATA3) && defined(PINMAP_QSPI_SCLK) && defined(PINMAP_QSPI_SSEL) -MSTD_CONSTEXPR_FN_14 qspi_pinmap_t get_qspi_pinmap(const PinName data0, const PinName data1, const PinName data2, const PinName data3, const PinName sclk, const PinName ssel) -{ - const PinMap *data0_map = nullptr; - for (const PinMap &pinmap : PINMAP_QSPI_DATA0) { - if (pinmap.pin == data0) { - data0_map = &pinmap; - break; - } - } - - const PinMap *data1_map = nullptr; - for (const PinMap &pinmap : PINMAP_QSPI_DATA1) { - if (pinmap.pin == data1) { - data1_map = &pinmap; - break; - } - } - - const PinMap *data2_map = nullptr; - for (const PinMap &pinmap : PINMAP_QSPI_DATA2) { - if (pinmap.pin == data2) { - data2_map = &pinmap; - break; - } - } - - const PinMap *data3_map = nullptr; - for (const PinMap &pinmap : PINMAP_QSPI_DATA3) { - if (pinmap.pin == data3) { - data3_map = &pinmap; - break; - } - } - - const PinMap *sclk_map = nullptr; - for (const PinMap &pinmap : PINMAP_QSPI_SCLK) { - if (pinmap.pin == sclk) { - sclk_map = &pinmap; - break; - } - } - - const PinMap *ssel_map = nullptr; - for (const PinMap &pinmap : PINMAP_QSPI_SSEL) { - if (pinmap.pin == ssel) { - ssel_map = &pinmap; - break; - } - } - - if (!data0_map || !data1_map || !data2_map || !data3_map || !sclk_map || !ssel_map || data0_map->peripheral != data1_map->peripheral || data0_map->peripheral != data2_map->peripheral || data0_map->peripheral != data3_map->peripheral || data0_map->peripheral != sclk_map->peripheral || data0_map->peripheral != ssel_map->peripheral) { - return {(int) NC, NC, (int) NC, NC, (int) NC, NC, (int) NC, NC, (int) NC}; - } - - return {data0_map->peripheral, data0_map->pin, data0_map->function, data1_map->pin, data1_map->function, data2_map->pin, data2_map->function, data3_map->pin, data3_map->function, sclk_map->pin, sclk_map->function, ssel_map->pin, ssel_map->function}; -} -#endif //DEVICE_QSPI - -#else // STATIC_PINMAP_READY - -#if DEVICE_PWMOUT -MSTD_CONSTEXPR_FN_14 PinMap get_pwm_pinmap(const PinName pin) -{ - return {pin, (int) NC, (int) NC}; -} -#endif // DEVICE_PWMOUT - -#if DEVICE_ANALOGIN -MSTD_CONSTEXPR_FN_14 PinMap get_analogin_pinmap(const PinName pin) -{ - return {pin, (int) NC, (int) NC}; -} -#endif // DEVICE_ANALOGIN - -#if DEVICE_ANALOGOUT -MSTD_CONSTEXPR_FN_14 PinMap get_analogout_pinmap(const PinName pin) -{ - return {pin, (int) NC, (int) NC}; -} -#endif // DEVICE_ANALOGOUT - -#if DEVICE_I2C -MSTD_CONSTEXPR_FN_14 i2c_pinmap_t get_i2c_pinmap(const PinName sda, const PinName scl) -{ - return {(int) NC, sda, (int) NC, scl, (int) NC}; -} -#endif //DEVICE_I2C - -#if DEVICE_SERIAL -MSTD_CONSTEXPR_FN_14 serial_pinmap_t get_uart_pinmap(const PinName tx, const PinName rx) -{ - return {(int) NC, tx, (int) NC, rx, (int) NC, false}; -} - -#if DEVICE_SERIAL_FC -MSTD_CONSTEXPR_FN_14 serial_fc_pinmap_t get_uart_fc_pinmap(const PinName rxflow, const PinName txflow) -{ - return {(int) NC, txflow, (int) NC, rxflow, (int) NC}; -} -#endif // DEVICE_SERIAL_FC -#endif // DEVICE_SERIAL - -#if DEVICE_SPI -MSTD_CONSTEXPR_FN_14 spi_pinmap_t get_spi_pinmap(const PinName mosi, const PinName miso, const PinName sclk, const PinName ssel) -{ - return {(int) NC, mosi, (int) NC, miso, (int) NC, sclk, (int) NC, ssel, (int) NC}; -} -#endif // DEVICE_SERIAL - -#if DEVICE_CAN -MSTD_CONSTEXPR_FN_14 can_pinmap_t get_can_pinmap(const PinName rd, const PinName td) -{ - return {(int) NC, rd, (int) NC, td, (int) NC}; -} -#endif //DEVICE_CAN - -#if DEVICE_QSPI -MSTD_CONSTEXPR_FN_14 qspi_pinmap_t get_qspi_pinmap(const PinName data0, const PinName data1, const PinName data2, const PinName data3, const PinName sclk, const PinName ssel) -{ - return {(int) NC, data0, (int) NC, data1, (int) NC, data2, (int) NC, data3, (int) NC, sclk, (int) NC, ssel, (int) NC}; -} -#endif //DEVICE_QSPI - -#endif // STATIC_PINMAP_READY - -#endif // STATIC_PINMAP_H diff --git a/hal/tests/TESTS/host_tests/reset_reason.py b/hal/tests/TESTS/host_tests/reset_reason.py new file mode 100644 index 0000000..4e33606 --- /dev/null +++ b/hal/tests/TESTS/host_tests/reset_reason.py @@ -0,0 +1,181 @@ +""" +Copyright (c) 2018-2019 Arm Limited and affiliates. +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. +""" +import time +from mbed_host_tests import BaseHostTest + +DEFAULT_SYNC_DELAY = 4.0 + +MSG_VALUE_WATCHDOG_PRESENT = 1 +MSG_VALUE_DUMMY = '0' +MSG_VALUE_RESET_REASON_GET = 'get' +MSG_VALUE_RESET_REASON_CLEAR = 'clear' +MSG_VALUE_DEVICE_RESET_NVIC = 'nvic' +MSG_VALUE_DEVICE_RESET_WATCHDOG = 'watchdog' + +MSG_KEY_DEVICE_READY = 'ready' +MSG_KEY_RESET_REASON_RAW = 'reason_raw' +MSG_KEY_RESET_REASON = 'reason' +MSG_KEY_DEVICE_RESET = 'reset' +MSG_KEY_SYNC = '__sync' +MSG_KEY_RESET_COMPLETE = 'reset_complete' + +RESET_REASONS = { + 'POWER_ON': '0', + 'PIN_RESET': '1', + 'BROWN_OUT': '2', + 'SOFTWARE': '3', + 'WATCHDOG': '4', + 'LOCKUP': '5', + 'WAKE_LOW_POWER': '6', + 'ACCESS_ERROR': '7', + 'BOOT_ERROR': '8', + 'MULTIPLE': '9', + 'PLATFORM': '10', + 'UNKNOWN': '11' +} + + +def raise_if_different(expected, actual, text=''): + """Raise a RuntimeError if actual is different than expected.""" + if expected != actual: + raise RuntimeError('{}Got {!r}, expected {!r}' + .format(text, actual, expected)) + + +class ResetReasonTest(BaseHostTest): + """Test for the Reset Reason HAL API. + + Given a device supporting a Reset Reason API. + When the device is restarted using various methods. + Then the device returns a correct reset reason for every restart. + """ + + def __init__(self): + super(ResetReasonTest, self).__init__() + self.device_reasons = None + self.device_has_watchdog = None + self.raw_reset_reasons = set() + self.sync_delay = DEFAULT_SYNC_DELAY + self.test_steps_sequence = self.test_steps() + # Advance the coroutine to it's first yield statement. + self.test_steps_sequence.send(None) + + def setup(self): + sync_delay = self.get_config_item('forced_reset_timeout') + self.sync_delay = sync_delay if sync_delay is not None else DEFAULT_SYNC_DELAY + self.register_callback(MSG_KEY_DEVICE_READY, self.cb_device_ready) + self.register_callback(MSG_KEY_RESET_REASON_RAW, self.cb_reset_reason_raw) + self.register_callback(MSG_KEY_RESET_REASON, self.cb_reset_reason) + self.register_callback(MSG_KEY_DEVICE_RESET, self.cb_reset_reason) + self.register_callback(MSG_KEY_RESET_COMPLETE, self.cb_reset_reason) + + def cb_device_ready(self, key, value, timestamp): + """Request a raw value of the reset_reason register. + + Additionally, save the device's reset_reason capabilities + and the watchdog status on the first call. + """ + if self.device_reasons is None: + reasons, wdg_status = (int(i, base=16) for i in value.split(',')) + self.device_has_watchdog = (wdg_status == MSG_VALUE_WATCHDOG_PRESENT) + self.device_reasons = [k for k, v in RESET_REASONS.items() if (reasons & 1 << int(v))] + self.send_kv(MSG_KEY_RESET_REASON_RAW, MSG_VALUE_RESET_REASON_GET) + + def cb_reset_reason_raw(self, key, value, timestamp): + """Verify that the raw reset_reason register value is unique. + + Fail the test suite if the raw reset_reason value is not unique. + Request a platform independent reset_reason otherwise. + """ + if value in self.raw_reset_reasons: + self.log('TEST FAILED: The raw reset reason is not unique. ' + '{!r} is already present in {!r}.' + .format(value, self.raw_reset_reasons)) + self.notify_complete(False) + else: + self.raw_reset_reasons.add(value) + self.send_kv(MSG_KEY_RESET_REASON, MSG_VALUE_RESET_REASON_GET) + + def cb_reset_reason(self, key, value, timestamp): + """Feed the test_steps coroutine with reset_reason value. + + Pass the test suite if the coroutine yields True. + Fail the test suite if the iterator stops or raises a RuntimeError. + """ + try: + if self.test_steps_sequence.send(value): + self.notify_complete(True) + except (StopIteration, RuntimeError) as exc: + self.log('TEST FAILED: {}'.format(exc)) + self.notify_complete(False) + + def test_steps(self): + """Generate a sequence of test steps. + + This coroutine calls yield to wait for the input from the device + (the reset_reason). If the device gives the wrong response, the + generator raises a RuntimeError exception and fails the test. + """ + # Ignore the first reason. + __ignored_reset_reason = yield + self.raw_reset_reasons.clear() + self.send_kv(MSG_KEY_RESET_REASON, MSG_VALUE_RESET_REASON_CLEAR) + __ignored_clear_ack = yield + + # Request a NVIC_SystemReset() call. + expected_reason = 'SOFTWARE' + if expected_reason not in self.device_reasons: + self.log('Skipping the {} reset reason -- not supported.'.format(expected_reason)) + else: + # Request a NVIC_SystemReset() call. + self.send_kv(MSG_KEY_DEVICE_RESET, MSG_VALUE_DEVICE_RESET_NVIC) + __ignored_reset_ack = yield + time.sleep(self.sync_delay) + self.send_kv(MSG_KEY_SYNC, MSG_VALUE_DUMMY) + reset_reason = yield + raise_if_different(RESET_REASONS[expected_reason], reset_reason, 'Wrong reset reason. ') + self.send_kv(MSG_KEY_RESET_REASON, MSG_VALUE_RESET_REASON_CLEAR) + __ignored_clear_ack = yield + + # Reset the device using DAP. + expected_reason = 'PIN_RESET' + if expected_reason not in self.device_reasons: + self.log('Skipping the {} reset reason -- not supported.'.format(expected_reason)) + else: + self.reset() + __ignored_reset_ack = yield # 'reset_complete' + time.sleep(self.sync_delay) + self.send_kv(MSG_KEY_SYNC, MSG_VALUE_DUMMY) + reset_reason = yield + raise_if_different(RESET_REASONS[expected_reason], reset_reason, 'Wrong reset reason. ') + self.send_kv(MSG_KEY_RESET_REASON, MSG_VALUE_RESET_REASON_CLEAR) + __ignored_clear_ack = yield + + # Start a watchdog timer and wait for it to reset the device. + expected_reason = 'WATCHDOG' + if expected_reason not in self.device_reasons or not self.device_has_watchdog: + self.log('Skipping the {} reset reason -- not supported.'.format(expected_reason)) + else: + self.send_kv(MSG_KEY_DEVICE_RESET, MSG_VALUE_DEVICE_RESET_WATCHDOG) + __ignored_reset_ack = yield + time.sleep(self.sync_delay) + self.send_kv(MSG_KEY_SYNC, MSG_VALUE_DUMMY) + reset_reason = yield + raise_if_different(RESET_REASONS[expected_reason], reset_reason, 'Wrong reset reason. ') + + # The sequence is correct -- test passed. + yield True diff --git a/hal/tests/TESTS/host_tests/rtc_calc_auto.py b/hal/tests/TESTS/host_tests/rtc_calc_auto.py new file mode 100644 index 0000000..419c43d --- /dev/null +++ b/hal/tests/TESTS/host_tests/rtc_calc_auto.py @@ -0,0 +1,140 @@ +""" +Copyright (c) 2011-2020, Arm Limited and affiliates +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. +""" + +from mbed_host_tests import BaseHostTest +import time +import calendar +import datetime + +class RTC_time_calc_test(BaseHostTest): + """ + This is the host part of the test to verify if: + - _rtc_mktime function converts a calendar time into time since UNIX epoch as a time_t, + - _rtc_localtime function converts a given time in seconds since epoch into calendar time. + + The same algoritm to generate next calendar time to be tested is used by both parts of the test. + We will check if correct time since UNIX epoch is calculated for the first and the last day + of each month and across valid years. + + Mbed part of the test sends calculated time since UNIX epoch. + This part validates given value and responds to indicate pass or fail. + Additionally it sends also encoded day of week and day of year which + will be needed to verify _rtc_localtime. + + Support for both types of RTC devices is provided: + - RTCs which handles all leap years in the mentioned year range correctly. Leap year is determined by checking if + the year counter value is divisible by 400, 100, and 4. No problem here. + - RTCs which handles leap years correctly up to 2100. The RTC does a simple bit comparison to see if the two + lowest order bits of the year counter are zero. In this case 2100 year will be considered + incorrectly as a leap year, so the last valid point in time will be 28.02.2100 23:59:59 and next day will be + 29.02.2100 (invalid). So after 28.02.2100 the day counter will be off by a day. + + """ + + edge_date = datetime.datetime(2100, 2, 28, 0, 0, 0) + + # Test the following years: + # - first - 1970 + # - example not leap year (not divisible by 4) + # - example leap year (divisible by 4 and by 100 and by 400) + # - example leap year (divisible by 4 and not by 100) + # - example not leap year (divisible by 4 and by 100) + # - last fully supported - 2105 + years = [1970, 1971, 2000, 2096, 2100, 2105] + year_id = 0 + + + + full_leap_year_support = False + + RTC_FULL_LEAP_YEAR_SUPPORT = 0 + RTC_PARTIAL_LEAP_YEAR_SUPPORT = 1 + + def _set_leap_year_support(self, key, value, timestamp): + if (int(value) == self.RTC_FULL_LEAP_YEAR_SUPPORT): + self.full_leap_year_support = True + else: + self.full_leap_year_support = False + + self.first = True + self.date = datetime.datetime(1970, 1, 1, 23, 0, 0) + self.year_id = 0 + + def _verify_timestamp(self, key, value, timestamp): + # week day in python is counted from sunday(0) and on mbed side week day is counted from monday(0). + # year day in python is counted from 1 and on mbed side year day is counted from 0. + week_day = ((self.date.timetuple().tm_wday + 1) % 7) + year_day = self.date.timetuple().tm_yday - 1 + + # Fix for RTC which not have full leap year support. + if (not self.full_leap_year_support): + if self.date >= self.edge_date: + # After 28.02.2100 we should be one day off - add this day and store original + date_org = self.date + self.date += datetime.timedelta(days = 1) + + # Adjust week day. + week_day = ((self.date.timetuple().tm_wday + 1) % 7) + + # Adjust year day. + if (self.date.year == 2100): + year_day = self.date.timetuple().tm_yday - 1 + else: + year_day = date_org.timetuple().tm_yday - 1 + + # Last day in year + if (self.date.month == 1 and self.date.day == 1): + if (self.date.year == 2101): + # Exception for year 2100 - ivalid handled by RTC without full leap year support + year_day = 365 + else: + year_day = date_org.timetuple().tm_yday - 1 + + t = (self.date.year , self.date.month, self.date.day, self.date.hour, self.date.minute, self.date.second, 0, 0, 0) + + expected_timestamp = calendar.timegm(t) + actual_timestamp = int(value) & 0xffffffff # convert to unsigned int + + # encode week day and year day in the response + response = (week_day << 16) | year_day + + if (actual_timestamp == expected_timestamp): + # response contains encoded week day and year day + self.send_kv("passed", str(response)) + else: + self.send_kv("failed", 0) + print("expected = %d, result = %d" % (expected_timestamp , actual_timestamp)) + + # calculate next date + if (self.first): + days_range = calendar.monthrange(self.date.year, self.date.month) + self.date = self.date.replace(day = days_range[1], minute = 59, second = 59) + self.first = not self.first + else: + self.date += datetime.timedelta(days = 1) + if (self.date.month == 1): + self.year_id += 1 + if (len(self.years) == self.year_id): + # All years were processed, no need to calc next date + return + self.date = self.date.replace(year = self.years[self.year_id]) + self.date = self.date.replace(day = 1, minute = 0, second = 0) + self.first = not self.first + + def setup(self): + self.register_callback('timestamp', self._verify_timestamp) + self.register_callback('leap_year_setup', self._set_leap_year_support) diff --git a/hal/tests/TESTS/host_tests/rtc_reset.py b/hal/tests/TESTS/host_tests/rtc_reset.py new file mode 100644 index 0000000..acdb4cc --- /dev/null +++ b/hal/tests/TESTS/host_tests/rtc_reset.py @@ -0,0 +1,145 @@ +""" +mbed SDK +Copyright (c) 2017-2017 ARM Limited +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. +""" +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 = 1537789823 # GMT: Monday, 24 September 2018 11:50:23 + 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() + next(generator) + + 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 + diff --git a/hal/tests/TESTS/host_tests/sync_on_reset.py b/hal/tests/TESTS/host_tests/sync_on_reset.py new file mode 100644 index 0000000..1d509ca --- /dev/null +++ b/hal/tests/TESTS/host_tests/sync_on_reset.py @@ -0,0 +1,74 @@ +""" +Copyright (c) 2018-2019 Arm Limited and affiliates. + +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. +""" +import time +from mbed_host_tests import BaseHostTest + +DEFAULT_SYNC_DELAY = 4.0 + +MSG_VALUE_DUMMY = '0' +MSG_KEY_DEVICE_READY = 'ready' +MSG_KEY_START_CASE = 'start_case' +MSG_KEY_DEVICE_RESET = 'reset_on_case_teardown' +MSG_KEY_SYNC = '__sync' + + +class SyncOnReset(BaseHostTest): + """Host side test that handles device reset during case teardown. + + Given a device that performs a reset during a test case teardown. + When the device notifies the host about the reset. + Then the host: + * keeps track of the test case index of the current test suite, + * performs a dev-host handshake, + * advances the test suite to next test case. + + Note: + Developed for a watchdog test, so that it can be run on devices that + do not support watchdog timeout updates after the initial setup. + As a solution, after testing watchdog with one set of settings, the + device performs a reset and notifies the host with the test case number, + so that the test suite may be advanced once the device boots again. + """ + + def __init__(self): + super(SyncOnReset, self).__init__() + self.test_case_num = 0 + self.sync_delay = DEFAULT_SYNC_DELAY + + def setup(self): + sync_delay = self.get_config_item('forced_reset_timeout') + self.sync_delay = sync_delay if sync_delay is not None else DEFAULT_SYNC_DELAY + self.register_callback(MSG_KEY_DEVICE_READY, self.cb_device_ready) + self.register_callback(MSG_KEY_DEVICE_RESET, self.cb_device_reset) + + def cb_device_ready(self, key, value, timestamp): + """Advance the device test suite to the next test case.""" + self.send_kv(MSG_KEY_START_CASE, self.test_case_num) + + def cb_device_reset(self, key, value, timestamp): + """Wait for the device to boot and perform a handshake. + + Additionally, keep track of the last test case number. + """ + try: + self.test_case_num = int(value) + except ValueError: + pass + self.test_case_num += 1 + time.sleep(self.sync_delay) + self.send_kv(MSG_KEY_SYNC, MSG_VALUE_DUMMY) diff --git a/hal/tests/TESTS/host_tests/system_reset.py b/hal/tests/TESTS/host_tests/system_reset.py new file mode 100644 index 0000000..13d2309 --- /dev/null +++ b/hal/tests/TESTS/host_tests/system_reset.py @@ -0,0 +1,76 @@ +""" +Copyright (c) 2018 ARM Limited +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. +""" +import time +from mbed_host_tests import BaseHostTest +from mbed_host_tests.host_tests_runner.host_test_default import DefaultTestSelector + +DEFAULT_CYCLE_PERIOD = 1.0 + +MSG_VALUE_DUMMY = '0' + +MSG_KEY_DEVICE_READY = 'ready' +MSG_KEY_DEVICE_RESET = 'reset' +MSG_KEY_SYNC = '__sync' + +class SystemResetTest(BaseHostTest): + """Test for the system_reset API. + + Given a device running code + When the device is restarted using @a system_reset() + Then the device is restarted + """ + + def __init__(self): + super(SystemResetTest, self).__init__() + self.reset = False + self.test_steps_sequence = self.test_steps() + # Advance the coroutine to it's first yield statement. + self.test_steps_sequence.send(None) + + def setup(self): + self.register_callback(MSG_KEY_DEVICE_READY, self.cb_device_ready) + + def cb_device_ready(self, key, value, timestamp): + """Acknowledge device rebooted correctly and feed the test execution + """ + self.reset = True + + try: + if self.test_steps_sequence.send(value): + self.notify_complete(True) + except (StopIteration, RuntimeError) as exc: + self.notify_complete(False) + + def test_steps(self): + """Reset the device and check the status + """ + system_reset = yield + self.reset = False + + wait_after_reset = self.get_config_item('forced_reset_timeout') + wait_after_reset = wait_after_reset if wait_after_reset is not None else DEFAULT_CYCLE_PERIOD + + self.send_kv(MSG_KEY_DEVICE_RESET, MSG_VALUE_DUMMY) + time.sleep(wait_after_reset) + self.send_kv(MSG_KEY_SYNC, MSG_VALUE_DUMMY) + + system_reset = yield + if self.reset == False: + raise RuntimeError('Platform did not reset as expected.') + + # The sequence is correct -- test passed. + yield True diff --git a/hal/tests/TESTS/host_tests/timing_drift_auto.py b/hal/tests/TESTS/host_tests/timing_drift_auto.py new file mode 100644 index 0000000..65ac90a --- /dev/null +++ b/hal/tests/TESTS/host_tests/timing_drift_auto.py @@ -0,0 +1,136 @@ +""" +mbed SDK +Copyright (c) 2011-2013 ARM Limited +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. +""" + +from mbed_host_tests import BaseHostTest +import time + + +class TimingDriftSync(BaseHostTest): + """ + This works as master-slave fashion + 1) Device says its booted up and ready to run the test, wait for host to respond + 2) Host sends the message to get the device current time i.e base time + + # + # * + # * | + #<---* DUT<- base_time | - round_trip_base_time ------ + # * | | + # * - | + # - | + # | | + # | | + # | - measurement_stretch | - nominal_time + # | | + # | | + # - | + # * - | + # * | | + #<---* DUT <-final_time | - round_trip_final_time------ + # * | + # * - + # + # + # As we increase the measurement_stretch, the error because of transport delay diminishes. + # The values of measurement_stretch is propotional to round_trip_base_time(transport delays) + # by factor time_measurement_multiplier.This multiplier is used is 80 to tolerate 2 sec of + # transport delay and test time ~ 180 secs + # + # Failure in timing can occur if we are ticking too fast or we are ticking too slow, hence we have + # min_range and max_range. if we cross on either side tests would be marked fail. The range is a function of + # tolerance/acceptable drift currently its 5%. + # + + """ + __result = None + mega = 1000000.0 + max_measurement_time = 180 + + # this value is obtained for measurements when there is 0 transport delay and we want accurancy of 5% + time_measurement_multiplier = 80 + + def _callback_timing_drift_check_start(self, key, value, timestamp): + self.round_trip_base_start = timestamp + self.send_kv("base_time", 0) + + def _callback_base_time(self, key, value, timestamp): + self.round_trip_base_end = timestamp + self.device_time_base = float(value) + self.round_trip_base_time = self.round_trip_base_end - self.round_trip_base_start + + self.log("Device base time {}".format(value)) + measurement_stretch = (self.round_trip_base_time * self.time_measurement_multiplier) + 5 + + if measurement_stretch > self.max_measurement_time: + self.log("Time required {} to determine device timer is too high due to transport delay, skipping".format(measurement_stretch)) + else: + self.log("sleeping for {} to measure drift accurately".format(measurement_stretch)) + time.sleep(measurement_stretch) + self.round_trip_final_start = time.time() + self.send_kv("final_time", 0) + + def _callback_final_time(self, key, value, timestamp): + self.round_trip_final_end = timestamp + self.device_time_final = float(value) + self.round_trip_final_time = self.round_trip_final_end - self.round_trip_final_start + self.log("Device final time {} ".format(value)) + + # compute the test results and send to device + results = "pass" if self.compute_parameter() else "fail" + self.send_kv(results, "0") + + def setup(self): + self.register_callback('timing_drift_check_start', self._callback_timing_drift_check_start) + self.register_callback('base_time', self._callback_base_time) + self.register_callback('final_time', self._callback_final_time) + + def compute_parameter(self, failure_criteria=0.05): + t_max = self.round_trip_final_end - self.round_trip_base_start + t_min = self.round_trip_final_start - self.round_trip_base_end + t_max_hi = t_max * (1 + failure_criteria) + t_max_lo = t_max * (1 - failure_criteria) + t_min_hi = t_min * (1 + failure_criteria) + t_min_lo = t_min * (1 - failure_criteria) + device_time = (self.device_time_final - self.device_time_base) / self.mega + + self.log("Compute host events") + self.log("Transport delay 0: {}".format(self.round_trip_base_time)) + self.log("Transport delay 1: {}".format(self.round_trip_final_time)) + self.log("DUT base time : {}".format(self.device_time_base)) + self.log("DUT end time : {}".format(self.device_time_final)) + + self.log("min_pass : {} , max_pass : {} for {}%%".format(t_max_lo, t_min_hi, failure_criteria * 100)) + self.log("min_inconclusive : {} , max_inconclusive : {}".format(t_min_lo, t_max_hi)) + self.log("Time reported by device: {}".format(device_time)) + + if t_max_lo <= device_time <= t_min_hi: + self.log("Test passed !!!") + self.__result = True + elif t_min_lo <= device_time <= t_max_hi: + self.log("Test inconclusive due to transport delay, retrying") + self.__result = False + else: + self.log("Time outside of passing range. Timing drift seems to be present !!!") + self.__result = False + return self.__result + + def result(self): + return self.__result + + def teardown(self): + pass diff --git a/hal/tests/TESTS/host_tests/trng_reset.py b/hal/tests/TESTS/host_tests/trng_reset.py new file mode 100644 index 0000000..7e8878e --- /dev/null +++ b/hal/tests/TESTS/host_tests/trng_reset.py @@ -0,0 +1,147 @@ +""" +Copyright (c) 2018-2020, Arm Limited and affiliates +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 script is the host script for trng test sequence, it send the +step signaling sequence and receive and transmit data to the device after +reset if necesarry (default loading and storing mechanism while reseting the device +is KVStore, in case KVStore isn't enabled we'll use current infrastructure, +for more details see main.cpp file) +""" + +import time +from mbed_host_tests import BaseHostTest +from mbed_host_tests.host_tests_runner.host_test_default import DefaultTestSelector +from time import sleep + +DEFAULT_CYCLE_PERIOD = 1.0 +MSG_VALUE_DUMMY = '0' +MSG_TRNG_READY = 'ready' +MSG_TRNG_BUFFER = 'buffer' +MSG_TRNG_TEST_STEP1 = 'check_step1' +MSG_TRNG_TEST_STEP2 = 'check_step2' +MSG_KEY_SYNC = '__sync' +MSG_KEY_RESET_COMPLETE = 'reset_complete' +MSG_KEY_TEST_SUITE_ENDED = 'Test_suite_ended' +MSG_KEY_EXIT = 'exit' + +class TRNGResetTest(BaseHostTest): + """Test for the TRNG API. + """ + + def __init__(self): + super(TRNGResetTest, self).__init__() + self.did_reset = False + self.ready = False + self.suite_ended = False + self.buffer = 0 + self.test_steps_sequence = self.test_steps() + # Advance the coroutine to it's first yield statement. + self.test_steps_sequence.send(None) + + #define callback functions for msg handling + def setup(self): + self.register_callback(MSG_TRNG_READY, self.cb_device_ready) + self.register_callback(MSG_TRNG_BUFFER, self.cb_trng_buffer) + self.register_callback(MSG_KEY_TEST_SUITE_ENDED, self.cb_device_test_suit_ended) + self.register_callback(MSG_KEY_RESET_COMPLETE, self.cb_reset_complete) + + #receive sent data from device before reset + def cb_trng_buffer(self, key, value, timestamp): + """Acknowledge device rebooted correctly and feed the test execution + """ + self.buffer = value + + try: + if self.test_steps_sequence.send(value): + self.notify_complete(True) + except (StopIteration, RuntimeError) as exc: + self.notify_complete(False) + + def cb_device_ready(self, key, value, timestamp): + """Acknowledge device rebooted correctly and feed the test execution + """ + self.ready = True + + try: + if self.test_steps_sequence.send(value): + self.notify_complete(True) + except (StopIteration, RuntimeError) as exc: + self.notify_complete(False) + + def cb_reset_complete(self, key, value, timestamp): + """Acknowledge reset complete + """ + self.did_reset = True + + try: + if self.test_steps_sequence.send(value): + self.notify_complete(True) + except (StopIteration, RuntimeError) as exc: + self.notify_complete(False) + + def cb_device_test_suit_ended(self, key, value, timestamp): + """Acknowledge device finished a test step correctly and feed the test execution + """ + self.suite_ended = True + + try: + if self.test_steps_sequence.send(value): + self.notify_complete(True) + except (StopIteration, RuntimeError) as exc: + self.notify_complete(False) + + #define test steps and actions + def test_steps(self): + """Test step 1 + """ + wait_for_communication = yield + + self.ready = False + self.did_reset = False + self.suite_ended = False + self.send_kv(MSG_TRNG_TEST_STEP1, MSG_VALUE_DUMMY) + wait_for_communication = yield + if self.buffer == 0: + raise RuntimeError('Phase 1: No buffer received.') + + self.reset() + + """Test step 2 (After reset) + """ + wait_for_communication = yield + if self.did_reset == False: + raise RuntimeError('Phase 1: Platform did not reset as expected.') + + self.send_kv(MSG_KEY_SYNC, MSG_VALUE_DUMMY) + + wait_for_communication = yield + + if self.ready == False: + raise RuntimeError('Phase 1: Platform not ready as expected.') + + self.send_kv(MSG_TRNG_TEST_STEP2, self.buffer) + + wait_for_communication = yield + + if self.suite_ended == False: + raise RuntimeError('Test failed.') + + self.send_kv(MSG_KEY_EXIT, MSG_VALUE_DUMMY) + + # The sequence is correct -- test passed. + yield diff --git a/hal/tests/TESTS/host_tests/watchdog_reset.py b/hal/tests/TESTS/host_tests/watchdog_reset.py new file mode 100644 index 0000000..3f79188 --- /dev/null +++ b/hal/tests/TESTS/host_tests/watchdog_reset.py @@ -0,0 +1,145 @@ +""" +Copyright (c) 2018-2019 Arm Limited and affiliates. +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. +""" +import collections +import threading +from mbed_host_tests import BaseHostTest + +TestCaseData = collections.namedtuple('TestCaseData', ['index', 'data_to_send']) + +DEFAULT_SYNC_DELAY = 4.0 +MAX_HB_PERIOD = 2.5 # [s] Max expected heartbeat period. + +MSG_VALUE_DUMMY = '0' +CASE_DATA_INVALID = 0xffffffff +CASE_DATA_PHASE2_OK = 0xfffffffe +CASE_DATA_INSUFF_HB = 0x0 + +MSG_KEY_SYNC = '__sync' +MSG_KEY_DEVICE_READY = 'ready' +MSG_KEY_START_CASE = 'start_case' +MSG_KEY_DEVICE_RESET = 'dev_reset' +MSG_KEY_HEARTBEAT = 'hb' + + +class WatchdogReset(BaseHostTest): + """Host side test that handles device reset. + + Given a device with a watchdog timer started. + When the device notifies the host about an incoming reset. + Then the host: + * keeps track of the test case index of the current test suite, + * performs a dev-host handshake. + """ + + def __init__(self): + super(WatchdogReset, self).__init__() + self.current_case = TestCaseData(0, CASE_DATA_INVALID) + self.__handshake_timer = None + self.sync_delay = DEFAULT_SYNC_DELAY + self.drop_heartbeat_messages = True + self.hb_timestamps_us = [] + + def handshake_timer_start(self, seconds=1.0, pre_sync_fun=None): + """Start a new handshake timer.""" + + def timer_handler(): + """Perform a dev-host handshake by sending a sync message.""" + if pre_sync_fun is not None: + pre_sync_fun() + self.send_kv(MSG_KEY_SYNC, MSG_VALUE_DUMMY) + + self.__handshake_timer = threading.Timer(seconds, timer_handler) + self.__handshake_timer.start() + + def handshake_timer_cancel(self): + """Cancel the current handshake timer.""" + try: + self.__handshake_timer.cancel() + except AttributeError: + pass + finally: + self.__handshake_timer = None + + def heartbeat_timeout_handler(self): + """Handler for the heartbeat timeout. + + Compute the time span of the last heartbeat sequence. + Set self.current_case.data_to_send to CASE_DATA_INVALID if no heartbeat was received. + Set self.current_case.data_to_send to CASE_DATA_INSUFF_HB if only one heartbeat was + received. + """ + self.drop_heartbeat_messages = True + dev_data = CASE_DATA_INVALID + if len(self.hb_timestamps_us) == 1: + dev_data = CASE_DATA_INSUFF_HB + self.log('Not enough heartbeats received.') + elif len(self.hb_timestamps_us) >= 2: + dev_data = int(round(0.001 * (self.hb_timestamps_us[-1] - self.hb_timestamps_us[0]))) + self.log('Heartbeat time span was {} ms.'.format(dev_data)) + self.current_case = TestCaseData(self.current_case.index, dev_data) + + def setup(self): + sync_delay = self.get_config_item('forced_reset_timeout') + self.sync_delay = sync_delay if sync_delay is not None else DEFAULT_SYNC_DELAY + self.register_callback(MSG_KEY_DEVICE_READY, self.cb_device_ready) + self.register_callback(MSG_KEY_DEVICE_RESET, self.cb_device_reset) + self.register_callback(MSG_KEY_HEARTBEAT, self.cb_heartbeat) + + def teardown(self): + self.handshake_timer_cancel() + + def cb_device_ready(self, key, value, timestamp): + """Advance the device test suite to a proper test case. + + Additionally, send test case data to the device. + """ + self.handshake_timer_cancel() + msg_value = '{0.index:02x},{0.data_to_send:08x}'.format(self.current_case) + self.send_kv(MSG_KEY_START_CASE, msg_value) + self.drop_heartbeat_messages = False + self.hb_timestamps_us = [] + + def cb_device_reset(self, key, value, timestamp): + """Keep track of the test case number. + + Also set a new handshake timeout, so when the device gets + restarted by the watchdog, the communication will be restored + by the __handshake_timer. + """ + self.handshake_timer_cancel() + case_num, dev_reset_delay_ms = (int(i, base=16) for i in value.split(',')) + self.current_case = TestCaseData(case_num, CASE_DATA_PHASE2_OK) + self.handshake_timer_start(self.sync_delay + dev_reset_delay_ms / 1000.0) + + def cb_heartbeat(self, key, value, timestamp): + """Save the timestamp of a heartbeat message. + + Additionally, keep track of the test case number. + + Also each heartbeat sets a new timeout, so when the device gets + restarted by the watchdog, the communication will be restored + by the __handshake_timer. + """ + if self.drop_heartbeat_messages: + return + self.handshake_timer_cancel() + case_num, timestamp_us = (int(i, base=16) for i in value.split(',')) + self.current_case = TestCaseData(case_num, CASE_DATA_INVALID) + self.hb_timestamps_us.append(timestamp_us) + self.handshake_timer_start( + seconds=(MAX_HB_PERIOD + self.sync_delay), + pre_sync_fun=self.heartbeat_timeout_handler) diff --git a/hal/tests/TESTS/mbed_hal/common_tickers/main.cpp b/hal/tests/TESTS/mbed_hal/common_tickers/main.cpp new file mode 100644 index 0000000..442eb01 --- /dev/null +++ b/hal/tests/TESTS/mbed_hal/common_tickers/main.cpp @@ -0,0 +1,634 @@ +/* mbed Microcontroller Library + * Copyright (c) 2017 ARM Limited + * 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. + */ + +#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" +#include "hal/mbed_lp_ticker_wrapper.h" + +#ifdef MBED_CONF_RTOS_PRESENT +#ifdef __cplusplus +extern "C" { +#endif +#include "os_tick.h" +#ifdef __cplusplus +} +#endif // __cplusplus +#endif + +#if !DEVICE_USTICKER +#error [NOT_SUPPORTED] test not supported +#else + +#define US_PER_S 1000000 + +#define FORCE_OVERFLOW_TEST (false) +#define TICKER_INT_VAL 500 +#define TICKER_DELTA 10 + +#define LP_TICKER_OVERFLOW_DELTA1 0 // this will allow to detect that ticker counter rollovers to 0 +#define LP_TICKER_OVERFLOW_DELTA2 0 +#define US_TICKER_OVERFLOW_DELTA1 50 +#define US_TICKER_OVERFLOW_DELTA2 60 + +#define TICKER_100_TICKS 100 +#define TICKER_500_TICKS 500 + +#define MAX_FUNC_EXEC_TIME_US 20 +#define DELTA_FUNC_EXEC_TIME_US 5 +#define NUM_OF_CALLS 100 + +#define NUM_OF_CYCLES 100000 + +#define US_TICKER_OV_LIMIT 35000 +#define LP_TICKER_OV_LIMIT 4000 + +#define TICKS_TO_US(ticks, freq) ((uint32_t) ((uint64_t)ticks * US_PER_S /freq)) + +using namespace utest::v1; + +volatile int intFlag = 0; +const ticker_interface_t *intf; +ticker_irq_handler_type prev_irq_handler; +/* Some targets might fail overflow test uncertainly due to getting trapped in busy + * intf->read() loop. In the loop, some ticker values wouldn't get caught in time + * because of: + * 1. Lower CPU clock + * 2. Compiled code with worse performance + * 3. Interrupt at that time + * + * We fix it by checking small ticker value range rather than one exact ticker point + * in near overflow check. + */ +unsigned int ticker_overflow_delta1; +unsigned int ticker_overflow_delta2; + +/* Auxiliary function to count ticker ticks elapsed during execution of N cycles of empty while loop. + * Parameter is used to disable compiler optimisation. */ +MBED_NOINLINE +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 (core_util_is_isr_active()) { + intFlag++; + } +} + +void wait_cycles(volatile unsigned int cycles) +{ + while (cycles--); +} + +/* Auxiliary function to determine how long ticker function are executed. + * This function returns number of us between and + * taking into account counter roll-over, counter size and frequency. + */ +uint32_t diff_us(uint32_t start_ticks, uint32_t stop_ticks, const ticker_info_t *info) +{ + uint32_t counter_mask = ((1 << info->bits) - 1); + + uint32_t diff_ticks = ((stop_ticks - start_ticks) & counter_mask); + + return (uint32_t)((uint64_t) diff_ticks * US_PER_S / info->frequency); +} + +/* 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, 400, 500, 600, 700, 800, 900, 1000, 1100, 1200 }; + uint8_t run_count = 0; + const ticker_info_t *p_ticker_info = intf->get_info(); + + overflow_protect(); + + for (uint32_t i = 0; i < (sizeof(ticker_timeout) / sizeof(uint32_t)); i++) { + + /* Skip timeout if less than max allowed execution time of set_interrupt() - 20 us */ + if (TICKS_TO_US(ticker_timeout[i], p_ticker_info->frequency) < (MAX_FUNC_EXEC_TIME_US + DELTA_FUNC_EXEC_TIME_US)) { + continue; + } + + run_count++; + 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); + } + + /* At least 3 sub test cases must be executed. */ + TEST_ASSERT_MESSAGE(run_count >= 3, "At least 3 sub test cases must be executed"); +} + +/* 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_delta2) && + intf->read() <= (max_count - ticker_overflow_delta1)) { + /* Just wait. */ + } + + /* Now we are near/at the overflow point. Detect rollover. */ + while (intf->read() > ticker_overflow_delta1); + + 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_delta1); + 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; + const uint32_t repeat_count = 20; + const uint32_t max_inc_val = 100; + + uint32_t base_tick_count = count_ticks(num_of_cycles, 1); + uint32_t next_tick_count = base_tick_count; + uint32_t inc_val = 0; + uint32_t repeat_cnt = 0; + + while (inc_val < max_inc_val) { + next_tick_count = count_ticks(num_of_cycles + inc_val, 1); + + if (next_tick_count == base_tick_count) { + + /* Same tick count, so repeat 20 times and than + * increase num of cycles by 1. + */ + if (repeat_cnt == repeat_count) { + inc_val++; + repeat_cnt = 0; + } + + repeat_cnt++; + } else { + /* Check if we got 1 tick diff. */ + if (next_tick_count - base_tick_count == 1 || + base_tick_count - next_tick_count == 1) { + break; + } + + /* 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; + repeat_cnt = 0; + base_tick_count = count_ticks(num_of_cycles, 1); + } + } + + /* 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) +{ + int counter = NUM_OF_CALLS; + uint32_t start; + uint32_t stop; + + const ticker_info_t *us_ticker_info = get_us_ticker_data()->interface->get_info(); + + /* ---- Test ticker_read function. ---- */ + start = us_ticker_read(); + while (counter--) { + intf->read(); + } + stop = us_ticker_read(); + + TEST_ASSERT(diff_us(start, stop, us_ticker_info) < (NUM_OF_CALLS * (MAX_FUNC_EXEC_TIME_US + DELTA_FUNC_EXEC_TIME_US))); + + /* ---- Test ticker_clear_interrupt function. ---- */ + counter = NUM_OF_CALLS; + start = us_ticker_read(); + while (counter--) { + intf->clear_interrupt(); + } + stop = us_ticker_read(); + + TEST_ASSERT(diff_us(start, stop, us_ticker_info) < (NUM_OF_CALLS * (MAX_FUNC_EXEC_TIME_US + DELTA_FUNC_EXEC_TIME_US))); + + /* ---- Test ticker_set_interrupt function. ---- */ + counter = NUM_OF_CALLS; + start = us_ticker_read(); + while (counter--) { + intf->set_interrupt(0); + } + stop = us_ticker_read(); + + TEST_ASSERT(diff_us(start, stop, us_ticker_info) < (NUM_OF_CALLS * (MAX_FUNC_EXEC_TIME_US + DELTA_FUNC_EXEC_TIME_US))); + + /* ---- Test fire_interrupt function. ---- */ + counter = NUM_OF_CALLS; + /* Disable ticker interrupt which would interfere with speed test */ + core_util_critical_section_enter(); + start = us_ticker_read(); + while (counter--) { + intf->fire_interrupt(); + } + stop = us_ticker_read(); + core_util_critical_section_exit(); + + TEST_ASSERT(diff_us(start, stop, us_ticker_info) < (NUM_OF_CALLS * (MAX_FUNC_EXEC_TIME_US + DELTA_FUNC_EXEC_TIME_US))); + + /* ---- Test disable_interrupt function. ---- */ + counter = NUM_OF_CALLS; + start = us_ticker_read(); + while (counter--) { + intf->disable_interrupt(); + } + stop = us_ticker_read(); + + TEST_ASSERT(diff_us(start, stop, us_ticker_info) < (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; + +#ifdef MBED_CONF_RTOS_PRESENT + /* OS, common ticker and low power ticker wrapper + * may make use of us ticker so suspend them for this test */ + osKernelSuspend(); +#endif +#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->init(); + + prev_irq_handler = set_us_ticker_irq_handler(ticker_event_handler_stub); + + ticker_overflow_delta1 = US_TICKER_OVERFLOW_DELTA1; + ticker_overflow_delta2 = US_TICKER_OVERFLOW_DELTA2; + + 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; + + ticker_resume(get_us_ticker_data()); +#if DEVICE_LPTICKER && (LPTICKER_DELAY_TICKS > 0) + lp_ticker_wrapper_resume(); + ticker_resume(get_lp_ticker_data()); +#endif +#ifdef MBED_CONF_RTOS_PRESENT + osKernelResume(0); +#endif + + 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; + +#ifdef MBED_CONF_RTOS_PRESENT + /* OS and common ticker may make use of lp ticker so suspend them for this test */ + osKernelSuspend(); +#endif + ticker_suspend(get_lp_ticker_data()); + + intf->init(); + + prev_irq_handler = set_lp_ticker_irq_handler(ticker_event_handler_stub); + + ticker_overflow_delta1 = LP_TICKER_OVERFLOW_DELTA1; + ticker_overflow_delta2 = LP_TICKER_OVERFLOW_DELTA2; + + 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; + + ticker_resume(get_lp_ticker_data()); +#ifdef MBED_CONF_RTOS_PRESENT + osKernelResume(0); +#endif + + return greentea_case_teardown_handler(source, passed, failed, reason); +} +#endif + +utest::v1::status_t test_setup(const size_t number_of_cases) +{ + GREENTEA_SETUP(80, "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); +} +#endif // !DEVICE_USTICKER diff --git a/hal/tests/TESTS/mbed_hal/common_tickers/ticker_api_tests.h b/hal/tests/TESTS/mbed_hal/common_tickers/ticker_api_tests.h new file mode 100644 index 0000000..d7e0a84 --- /dev/null +++ b/hal/tests/TESTS/mbed_hal/common_tickers/ticker_api_tests.h @@ -0,0 +1,130 @@ +/* mbed Microcontroller Library + * Copyright (c) 2017-2017 ARM Limited + * 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. + */ + +/** \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 + +/**@}*/ diff --git a/hal/tests/TESTS/mbed_hal/common_tickers_freq/main.cpp b/hal/tests/TESTS/mbed_hal/common_tickers_freq/main.cpp new file mode 100644 index 0000000..fb4a886 --- /dev/null +++ b/hal/tests/TESTS/mbed_hal/common_tickers_freq/main.cpp @@ -0,0 +1,215 @@ +/* + * 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] UsTicker need to be enabled for this test +#else + +#if defined(SKIP_TIME_DRIFT_TESTS) +#error [NOT_SUPPORTED] timing accuracy tests skipped +#endif // defined(SKIP_TIME_DRIFT_TESTS) + +#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) +{ +#ifdef MBED_CONF_RTOS_PRESENT + /* Suspend RTOS Kernel so the timers are not in use. */ + osKernelSuspend(); +#endif + + 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) +{ +#ifdef MBED_CONF_RTOS_PRESENT + osKernelResume(0); +#endif + + greentea_test_teardown_handler(passed, failed, failure); +} + +Specification specification(greentea_test_setup, cases, greentea_test_teardown); + +int main() +{ + Harness::run(specification); +} + +#endif // !DEVICE_USTICKER diff --git a/hal/tests/TESTS/mbed_hal/common_tickers_freq/ticker_api_test_freq.h b/hal/tests/TESTS/mbed_hal/common_tickers_freq/ticker_api_test_freq.h new file mode 100644 index 0000000..8390044 --- /dev/null +++ b/hal/tests/TESTS/mbed_hal/common_tickers_freq/ticker_api_test_freq.h @@ -0,0 +1,48 @@ +/* mbed Microcontroller Library + * Copyright (c) 2017-2017 ARM Limited + * 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. + */ + +/** \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 + +/**@}*/ diff --git a/hal/tests/TESTS/mbed_hal/crc/crc_api_tests.h b/hal/tests/TESTS/mbed_hal/crc/crc_api_tests.h new file mode 100644 index 0000000..cedd4e1 --- /dev/null +++ b/hal/tests/TESTS/mbed_hal/crc/crc_api_tests.h @@ -0,0 +1,115 @@ +/* mbed Microcontroller Library + * Copyright (c) 2018 ARM Limited + * 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. + */ + +/** \addtogroup hal_crc_tests */ +/** @{*/ + +#ifndef MBED_CRC_API_TESTS_H +#define MBED_CRC_API_TESTS_H + +#include "device.h" + +#if DEVICE_CRC + +#ifdef __cplusplus +extern "C" { +#endif + +/** Test that hal_crc_is_supported() function returns true if given polynomial/width + * is supported, false otherwise (at least one predefined polynomial/width must be supported). + * + * Given is platform with hardware CRC support. + * + * When given polynomial/width is supported. + * Then hal_crc_is_supported() function returns true. + * + * When given polynomial/width is not supported. + * Then hal_crc_is_supported() function returns false. + * + * Note: + * At least one predefined polynomial/width config must be supported. + * + */ +void crc_is_supported_test(); + +/** Test that CRC module can be successfully configured, fed with data and the result can + * be successfully obtained. + * + * Given is platform with hardware CRC support. + * + * When hal_crc_compute_partial_start() function is called. + * Then it configures CRC module with the given polynomial. + * + * When hal_crc_compute_partial() function is called with valid buffer and data length. + * Then it feeds CRC module with data. + * + * When hal_crc_get_result() function is called. + * Then CRC value for the given data is returned. + * + */ +void crc_calc_single_test(); + +/** Test that hal_crc_compute_partial() function can be call multiple times in + * succession in order to provide additional data to CRC module. + * + * Given is platform with hardware CRC support and CRC module is configured. + * When hal_crc_compute_partial() function is called multiple times. + * Then each call provides additional data to CRC module. + * + */ +void crc_calc_multi_test(); + +/** Test that calling hal_crc_compute_partial_start() without finalising the + * CRC calculation overrides the current configuration and partial result. + * + * Given is platform with hardware CRC support. + * When CRC module has been configured and fed with data and reconfigured (without reading the result). + * Then the configuration has been overwritten and the new data can be successfully processed. + * + */ +void crc_reconfigure_test(); + +/** Test that hal_crc_compute_partial() does nothing if pointer to buffer is undefined or + * data length is equal to 0. + * + * Given is platform with hardware CRC support. + * When hal_crc_compute_partial() is called with invalid parameters. + * Then no data is provided to CRC module and no exception is generated. + * + */ +void crc_compute_partial_invalid_param_test(); + +/** Test that hal_crc_is_supported() returns false if pointer to the config structure is undefined. + * + * Given is platform with hardware CRC support. + * When hal_crc_is_supported() is called with invalid parameter. + * Then function returns false. + * + */ +void crc_is_supported_invalid_param_test(); + +/**@}*/ + +#ifdef __cplusplus +} +#endif + +#endif + +#endif + +/**@}*/ diff --git a/hal/tests/TESTS/mbed_hal/crc/main.cpp b/hal/tests/TESTS/mbed_hal/crc/main.cpp new file mode 100644 index 0000000..58ac7d2 --- /dev/null +++ b/hal/tests/TESTS/mbed_hal/crc/main.cpp @@ -0,0 +1,284 @@ +/* mbed Microcontroller Library + * Copyright (c) 2018 ARM Limited + * 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. + */ +#include "utest/utest.h" +#include "unity/unity.h" +#include "greentea-client/test_env.h" +#include "mbed.h" +#include "math.h" +#include "crc_api.h" + +#if !DEVICE_CRC +#error [NOT_SUPPORTED] CRC not supported for this target +#else + +using namespace utest::v1; + +#define POLY_8BIT_MAXIM 0x31 + +#define UNSUPPORTED (-1) +#define POL_CNT (2) + +const uint8_t input_data[] = "123456789"; + +typedef struct { + const crc_mbed_config config_data; + uint32_t expected_result; + +} TEST_CASE; + +/* We will allocate test case array on stack since memory limits on some boards + * like NUCLEO_F070RB. */ +static TEST_CASE *test_cases; +static uint32_t test_cases_size; + +/* Test that hal_crc_is_supported() function returns true if given polynomial + * is supported, false otherwise (at least one polynomial from the predefined list must be supported). */ +void crc_is_supported_test() +{ + /* Check if at least one crc polynomial/config is supported. */ + uint32_t num_of_supported_polynomials = 0; + + for (unsigned int i = 0; i < (test_cases_size / sizeof(TEST_CASE)); i++) { + if (HAL_CRC_IS_SUPPORTED(test_cases[i].config_data.polynomial, test_cases[i].config_data.width)) { + + num_of_supported_polynomials++; + } + } + + TEST_ASSERT(num_of_supported_polynomials > 0); +} + +/* Test that CRC module can be successfully configured, fed with data and the result can + * be successfully obtained. */ +void crc_calc_single_test() +{ + for (unsigned int i = 0; i < (test_cases_size / sizeof(TEST_CASE)); i++) { + if (HAL_CRC_IS_SUPPORTED(test_cases[i].config_data.polynomial, test_cases[i].config_data.width)) { + + hal_crc_compute_partial_start(&test_cases[i].config_data); + hal_crc_compute_partial((uint8_t *) input_data, strlen((const char *) input_data)); + const uint32_t crc = hal_crc_get_result(); + + TEST_ASSERT_EQUAL(test_cases[i].expected_result, crc); + } + } +} + +/* Test that hal_crc_compute_partial() function can be call multiple times in + * succession in order to provide additional data to CRC module. */ +void crc_calc_multi_test() +{ + for (unsigned int i = 0; i < (test_cases_size / sizeof(TEST_CASE)); i++) { + if (HAL_CRC_IS_SUPPORTED(test_cases[i].config_data.polynomial, test_cases[i].config_data.width)) { + + const uint32_t first_part_bytes = 3; + const uint32_t second_part_bytes = 1; + const uint32_t third_part_bytes = strlen((const char *) input_data) - first_part_bytes + - second_part_bytes; + + hal_crc_compute_partial_start(&test_cases[i].config_data); + hal_crc_compute_partial((uint8_t *) input_data, first_part_bytes); + hal_crc_compute_partial((uint8_t *)(input_data + first_part_bytes), second_part_bytes); + hal_crc_compute_partial((uint8_t *)(input_data + first_part_bytes + second_part_bytes), + third_part_bytes); + const uint32_t crc = hal_crc_get_result(); + + TEST_ASSERT_EQUAL(test_cases[i].expected_result, crc); + } + } +} + +/* Test that calling hal_crc_compute_partial_start() without finalising the + * CRC calculation overrides the current configuration. */ +void crc_reconfigure_test() +{ + int pol_idx[POL_CNT] = + { UNSUPPORTED, UNSUPPORTED }; + int pol_cnt = 0; + const uint8_t dummy_input_data[] = "abcdefghijklmnopqrstuvwxyz"; + + /* At least one configuration must be supported. If two are supported, then + * re-initialize CRC module using different config. */ + for (unsigned int i = 0; i < (test_cases_size / sizeof(TEST_CASE)); i++) { + + /* Find two supported polynomials if possible. */ + if (HAL_CRC_IS_SUPPORTED(test_cases[i].config_data.polynomial, test_cases[i].config_data.width)) { + if (pol_cnt == 0) { + pol_idx[pol_cnt] = i; + pol_cnt++; + } else if (test_cases[pol_idx[0]].config_data.polynomial != test_cases[i].config_data.polynomial) { + pol_idx[pol_cnt] = i; + pol_cnt++; + } + + if (pol_cnt == POL_CNT) { + break; + } + } + } + + pol_cnt = 0; + + /* Init CRC module and provide some data, but do not read the result. */ + hal_crc_compute_partial_start(&test_cases[pol_idx[pol_cnt]].config_data); + hal_crc_compute_partial((uint8_t *) dummy_input_data, strlen((const char *) dummy_input_data)); + + /* Change index only if more than one supported polynomial has been found. */ + if (pol_idx[POL_CNT - 1] != UNSUPPORTED) { + pol_cnt++; + } + + /* Now re-init CRC module and provide new data and check the result. */ + hal_crc_compute_partial_start(&test_cases[pol_idx[pol_cnt]].config_data); + hal_crc_compute_partial((uint8_t *) input_data, strlen((const char *) input_data)); + const uint32_t crc = hal_crc_get_result(); + + TEST_ASSERT_EQUAL(test_cases[pol_idx[pol_cnt]].expected_result, crc); +} + +/* Test that hal_crc_compute_partial() does nothing if pointer to buffer is undefined or + * data length is equal to 0. */ +void crc_compute_partial_invalid_param_test() +{ + uint32_t crc = 0; + + /* At least one polynomial must be supported. */ + for (unsigned int i = 0; i < (test_cases_size / sizeof(TEST_CASE)); i++) { + if (HAL_CRC_IS_SUPPORTED(test_cases[i].config_data.polynomial, test_cases[i].config_data.width)) { + + hal_crc_compute_partial_start(&test_cases[i].config_data); + + /* Call hal_crc_compute_partial() with invalid parameters. */ + hal_crc_compute_partial((uint8_t *) NULL, strlen((const char *) input_data)); + hal_crc_compute_partial((uint8_t *) input_data, 0); + + /* Now use valid parameters. */ + hal_crc_compute_partial((uint8_t *) input_data, + strlen((const char *) input_data)); + + crc = hal_crc_get_result(); + + TEST_ASSERT_EQUAL(test_cases[i].expected_result, crc); + + break; + } + } +} + +Case cases[] = { + Case("test: supported polynomials.", crc_is_supported_test), + Case("test: CRC calculation - single input.", crc_calc_single_test), + Case("test: CRC calculation - multi input.", crc_calc_multi_test), + Case("test: re-configure without getting the result.", crc_reconfigure_test), + Case("test: hal_crc_compute_partial() - invalid parameters.", crc_compute_partial_invalid_param_test), +}; + +utest::v1::status_t greentea_test_setup(const size_t number_of_cases) +{ + GREENTEA_SETUP(30, "default_auto"); + return greentea_test_setup_handler(number_of_cases); +} + +Specification specification(greentea_test_setup, cases, greentea_test_teardown_handler); + +int main() +{ + // *INDENT-OFF* + TEST_CASE local_test_cases[] = { + /* Predefined polynomials. */ + { {POLY_7BIT_SD , 7, 0x00000000, 0x00000000, false, false}, 0x75 }, + { {POLY_7BIT_SD , 7, 0x0000007F, 0x00000000, false, false}, 0x50 }, + { {POLY_7BIT_SD , 7, 0x0000002B, 0x00000000, false, false}, 0x3A }, + { {POLY_7BIT_SD , 7, 0x00000000, 0x0000007F, false, false}, 0x0A }, + { {POLY_7BIT_SD , 7, 0x00000000, 0x0000002B, false, false}, 0x5E }, + { {POLY_7BIT_SD , 7, 0x00000000, 0x00000000, true , false}, 0x52 }, + { {POLY_7BIT_SD , 7, 0x00000000, 0x00000000, false, true }, 0x57 }, + { {POLY_7BIT_SD , 7, 0x0000002B, 0x00000000, true , false}, 0x1D }, + { {POLY_7BIT_SD , 7, 0x0000002B, 0x00000000, false, true }, 0x2E }, + { {POLY_7BIT_SD , 7, 0x0000002B, 0x00000000, true , true }, 0x5C }, + { {POLY_7BIT_SD , 7, 0x00000000, 0x0000002B, false, true }, 0x7C }, + + { {POLY_8BIT_CCITT , 8, 0x00000000, 0x00000000, false, false}, 0xF4 }, + { {POLY_8BIT_CCITT , 8, 0x000000FF, 0x00000000, false, false}, 0xFB }, + { {POLY_8BIT_CCITT , 8, 0x000000AB, 0x00000000, false, false}, 0x87 }, + { {POLY_8BIT_CCITT , 8, 0x00000000, 0x000000FF, false, false}, 0x0B }, + { {POLY_8BIT_CCITT , 8, 0x00000000, 0x000000AB, false, false}, 0x5F }, + { {POLY_8BIT_CCITT , 8, 0x00000000, 0x00000000, true , false}, 0x04 }, + { {POLY_8BIT_CCITT , 8, 0x00000000, 0x00000000, false, true }, 0x2F }, + { {POLY_8BIT_CCITT , 8, 0x000000AB, 0x00000000, true, false}, 0x77 }, + { {POLY_8BIT_CCITT , 8, 0x000000AB, 0x00000000, false, true }, 0xE1 }, + { {POLY_8BIT_CCITT , 8, 0x000000AB, 0x00000000, true, true }, 0xEE }, + { {POLY_8BIT_CCITT , 8, 0x00000000, 0x000000AB, false, true }, 0x84 }, + + { {POLY_16BIT_CCITT , 16, 0x00000000, 0x00000000, false, false}, 0x31C3 }, + { {POLY_16BIT_CCITT , 16, 0x0000FFFF, 0x00000000, false, false}, 0x29B1 }, + { {POLY_16BIT_CCITT , 16, 0x0000ABAB, 0x00000000, false, false}, 0x7D70 }, + { {POLY_16BIT_CCITT , 16, 0x00000000, 0x0000FFFF, false, false}, 0xCE3C }, + { {POLY_16BIT_CCITT , 16, 0x00000000, 0x0000ABAB, false, false}, 0x9A68 }, + { {POLY_16BIT_CCITT , 16, 0x00000000, 0x00000000, true , false}, 0x9184 }, + { {POLY_16BIT_CCITT , 16, 0x00000000, 0x00000000, false, true }, 0xC38C }, + { {POLY_16BIT_CCITT , 16, 0x0000ABAB, 0x00000000, true, false}, 0xDD37 }, + { {POLY_16BIT_CCITT , 16, 0x0000ABAB, 0x00000000, false, true }, 0x0EBE }, + { {POLY_16BIT_CCITT , 16, 0x0000ABAB, 0x00000000, true, true }, 0xECBB }, + { {POLY_16BIT_CCITT , 16, 0x00000000, 0x0000ABAB, false, true }, 0x6827 }, + + { {POLY_16BIT_IBM , 16, 0x00000000, 0x00000000, false, false}, 0xFEE8 }, + { {POLY_16BIT_IBM , 16, 0x0000FFFF, 0x00000000, false, false}, 0xAEE7 }, + { {POLY_16BIT_IBM , 16, 0x0000ABAB, 0x00000000, false, false}, 0x0887 }, + { {POLY_16BIT_IBM , 16, 0x00000000, 0x0000FFFF, false, false}, 0x0117 }, + { {POLY_16BIT_IBM , 16, 0x00000000, 0x0000ABAB, false, false}, 0x5543 }, + { {POLY_16BIT_IBM , 16, 0x00000000, 0x00000000, true , false}, 0xBCDD }, + { {POLY_16BIT_IBM , 16, 0x00000000, 0x00000000, false, true }, 0x177F }, + { {POLY_16BIT_IBM , 16, 0x0000ABAB, 0x00000000, true, false}, 0x4AB2 }, + { {POLY_16BIT_IBM , 16, 0x0000ABAB, 0x00000000, false, true }, 0xE110 }, + { {POLY_16BIT_IBM , 16, 0x0000ABAB, 0x00000000, true, true }, 0x4D52 }, + { {POLY_16BIT_IBM , 16, 0x00000000, 0x0000ABAB, false, true }, 0xBCD4 }, + + { {POLY_32BIT_ANSI , 32, 0x00000000, 0x00000000, false, false}, 0x89A1897F }, + { {POLY_32BIT_ANSI , 32, 0xFFFFFFFF, 0x00000000, false, false}, 0x0376E6E7 }, + { {POLY_32BIT_ANSI , 32, 0xABABABAB, 0x00000000, false, false}, 0x871A2FAA }, + { {POLY_32BIT_ANSI , 32, 0x00000000, 0xFFFFFFFF, false, false}, 0x765E7680 }, + { {POLY_32BIT_ANSI , 32, 0x00000000, 0xABABABAB, false, false}, 0x220A22D4 }, + { {POLY_32BIT_ANSI , 32, 0x00000000, 0x00000000, true , false}, 0x11B4BFB4 }, + { {POLY_32BIT_ANSI , 32, 0x00000000, 0x00000000, false, true }, 0xFE918591 }, + { {POLY_32BIT_ANSI , 32, 0xABABABAB, 0x00000000, true, false}, 0x1F0F1961 }, + { {POLY_32BIT_ANSI , 32, 0xABABABAB, 0x00000000, false, true }, 0x55F458E1 }, + { {POLY_32BIT_ANSI , 32, 0xABABABAB, 0x00000000, true, true }, 0x8698F0F8 }, + { {POLY_32BIT_ANSI , 32, 0x00000000, 0xABABABAB, false, true }, 0x553A2E3A }, + + /* Not-predefined polynomials. */ + { {POLY_8BIT_MAXIM , 8, 0x00000000, 0x00000000, false, false}, 0xA2 }, + { {POLY_8BIT_MAXIM , 8, 0x000000FF, 0x00000000, false, false}, 0xF7 }, + { {POLY_8BIT_MAXIM , 8, 0x000000AB, 0x00000000, false, false}, 0x71 }, + { {POLY_8BIT_MAXIM , 8, 0x00000000, 0x000000FF, false, false}, 0x5D }, + { {POLY_8BIT_MAXIM , 8, 0x00000000, 0x000000AB, false, false}, 0x09 }, + { {POLY_8BIT_MAXIM , 8, 0x00000000, 0x00000000, true , false}, 0x85 }, + { {POLY_8BIT_MAXIM , 8, 0x00000000, 0x00000000, false, true }, 0x45 }, + { {POLY_8BIT_MAXIM , 8, 0x000000AB, 0x00000000, true, false}, 0x56 }, + { {POLY_8BIT_MAXIM , 8, 0x000000AB, 0x00000000, false, true }, 0x8E }, + { {POLY_8BIT_MAXIM , 8, 0x000000AB, 0x00000000, true, true }, 0x6A }, + { {POLY_8BIT_MAXIM , 8, 0x00000000, 0x000000AB, false, true }, 0xEE }, + }; + // *INDENT-ON* + + test_cases = local_test_cases; + test_cases_size = sizeof(local_test_cases); + + Harness::run(specification); +} + +#endif // !DEVICE_CRC diff --git a/hal/tests/TESTS/mbed_hal/critical_section/critical_section_test.h b/hal/tests/TESTS/mbed_hal/critical_section/critical_section_test.h new file mode 100644 index 0000000..d3b882a --- /dev/null +++ b/hal/tests/TESTS/mbed_hal/critical_section/critical_section_test.h @@ -0,0 +1,55 @@ +/* mbed Microcontroller Library + * Copyright (c) 2018 ARM Limited + * 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. + */ + +/** \addtogroup hal_critical + * @{ + * \defgroup hal_critical_test Tests + * Tests definitions of the HAL Critical module. + * @{ + */ + +#ifndef MBED_CRITICAL_SECTION_TEST_H +#define MBED_CRITICAL_SECTION_TEST_H + +/** Template for HAL critical section tests + * + * Test critical section + * Given a critical section HAL mechanism + * When before critical section + * Then interrupts are enabled + * When inside critical section + * Then interrupts are disabled + * When after critical section + * Then interrupts are enabled again + * + * Test critical section - nested lock + * Given a critical section HAL mechanism + * When before critical section + * Then interrupts are enabled + * When inside nested critical section + * Then interrupts are disabled + * When after nested critical section + * Then interrupts are enabled again + * + */ +template +void test_critical_section(); + +/**@}*/ +/**@}*/ + +#endif // MBED_CRITICAL_SECTION_TEST_H diff --git a/hal/tests/TESTS/mbed_hal/critical_section/main.cpp b/hal/tests/TESTS/mbed_hal/critical_section/main.cpp new file mode 100644 index 0000000..0741b0f --- /dev/null +++ b/hal/tests/TESTS/mbed_hal/critical_section/main.cpp @@ -0,0 +1,76 @@ +/* mbed Microcontroller Library + * Copyright (c) 2018 ARM Limited + * 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. + */ +#include "critical_section_test.h" +#include "hal/critical_section_api.h" +#include "utest/utest.h" +#include "unity/unity.h" +#include "greentea-client/test_env.h" +#include "mbed.h" +#include "cmsis.h" +#if defined(TARGET_NRF5x) // for all NRF5x targets +#include "nrf_nvic.h" // for __NRF_NVIC_APP_IRQS_0 / __NRF_NVIC_APP_IRQS_1 +#endif + +using utest::v1::Case; + +bool test_are_interrupts_enabled(void) +{ +#if defined(__CORTEX_A9) + return ((__get_CPSR() & 0x80) == 0); +#else + return ((__get_PRIMASK() & 0x1) == 0); +#endif + +} + + +template +void test_critical_section() +{ + TEST_ASSERT_FALSE(hal_in_critical_section()); + TEST_ASSERT_TRUE(test_are_interrupts_enabled()); + + for (int i = 0; i < N; i++) { + hal_critical_section_enter(); + TEST_ASSERT_TRUE(hal_in_critical_section()); + TEST_ASSERT_FALSE(test_are_interrupts_enabled()); + } + + // assumed to be called once (according API) + hal_critical_section_exit(); + + TEST_ASSERT_FALSE(hal_in_critical_section()); + TEST_ASSERT_TRUE(test_are_interrupts_enabled()); +} + +Case cases[] = { + Case("Test critical section single lock", test_critical_section<1>), + Case("Test critical section nested lock", test_critical_section<10>) +}; + +utest::v1::status_t greentea_test_setup(const size_t number_of_cases) +{ + GREENTEA_SETUP(10, "default_auto"); + return utest::v1::greentea_test_setup_handler(number_of_cases); +} + +utest::v1::Specification specification(greentea_test_setup, cases); + +int main() +{ + return !utest::v1::Harness::run(specification); +} diff --git a/hal/tests/TESTS/mbed_hal/flash/functional_tests/main.cpp b/hal/tests/TESTS/mbed_hal/flash/functional_tests/main.cpp new file mode 100644 index 0000000..b6dcc5d --- /dev/null +++ b/hal/tests/TESTS/mbed_hal/flash/functional_tests/main.cpp @@ -0,0 +1,273 @@ +/* mbed Microcontroller Library + * Copyright (c) 2017 ARM Limited + * 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. + */ + +#if !DEVICE_FLASH +#error [NOT_SUPPORTED] Flash API not supported for this target +#else + +#include "utest/utest.h" +#include "unity/unity.h" +#include "greentea-client/test_env.h" +#include "platform/mbed_mpu_mgmt.h" + +#include "mbed.h" +#include "flash_api.h" + +using namespace utest::v1; + +#define TEST_CYCLES 10000000 + +#define ALLOWED_DRIFT_PPM (1000000/5000) //0.5% + +/* + return values to be checked are documented at: + http://arm-software.github.io/CMSIS_5/Pack/html/algorithmFunc.html#Verify +*/ + +#ifndef ALIGN_DOWN +#define ALIGN_DOWN(x, a) ((x)& ~((a) - 1)) +#endif + +static int timer_diff_start; + +static void erase_range(flash_t *flash, uint32_t addr, uint32_t size) +{ + while (size > 0) { + uint32_t sector_size = flash_get_sector_size(flash, addr); + TEST_ASSERT_NOT_EQUAL(0, sector_size); + int32_t ret = flash_erase_sector(flash, addr); + TEST_ASSERT_EQUAL_INT32(0, ret); + addr += sector_size; + size = size > sector_size ? size - sector_size : 0; + } +} +#if defined (__ICCARM__) +MBED_NOINLINE +static void delay_loop(uint32_t count) +{ + __asm volatile( + "loop: \n" + " SUBS %0, %0, #1 \n" + " BCS.n loop\n" + : "+r"(count) + : + : "cc" + ); +} +#elif defined ( __GNUC__ ) || defined(__ARMCC_VERSION) +MBED_NOINLINE +static void delay_loop(uint32_t count) +{ + __asm__ volatile( + "%=:\n\t" +#if defined(__thumb__) && !defined(__thumb2__) && !defined(__ARMCC_VERSION) + "SUB %0, #1\n\t" +#else + "SUBS %0, %0, #1\n\t" +#endif + "BCS %=b\n\t" + : "+l"(count) + : + : "cc" + ); +} +#endif + +MBED_NOINLINE +static int time_cpu_cycles(uint32_t cycles) +{ + Timer timer; + + core_util_critical_section_enter(); + + timer.start(); + + delay_loop(cycles); + + timer.stop(); + + core_util_critical_section_exit(); + + return timer.read_us(); +} + +void flash_init_test() +{ + timer_diff_start = time_cpu_cycles(TEST_CYCLES); + + flash_t test_flash; + int32_t ret = flash_init(&test_flash); + TEST_ASSERT_EQUAL_INT32(0, ret); + ret = flash_free(&test_flash); + TEST_ASSERT_EQUAL_INT32(0, ret); +} + +void flash_mapping_alignment_test() +{ + flash_t test_flash; + int32_t ret = flash_init(&test_flash); + TEST_ASSERT_EQUAL_INT32(0, ret); + + const uint32_t page_size = flash_get_page_size(&test_flash); + const uint32_t flash_start = flash_get_start_address(&test_flash); + const uint32_t flash_size = flash_get_size(&test_flash); + TEST_ASSERT_TRUE(page_size != 0UL); + + uint32_t sector_size = flash_get_sector_size(&test_flash, flash_start); + for (uint32_t offset = 0; offset < flash_size; offset += sector_size) { + const uint32_t sector_start = flash_start + offset; + sector_size = flash_get_sector_size(&test_flash, sector_start); + const uint32_t sector_end = sector_start + sector_size - 1; + const uint32_t end_sector_size = flash_get_sector_size(&test_flash, sector_end); + + // Sector size must be a valid value + TEST_ASSERT_NOT_EQUAL(MBED_FLASH_INVALID_SIZE, sector_size); + // Sector size must be greater than zero + TEST_ASSERT_NOT_EQUAL(0, sector_size); + // All flash sectors must be a multiple of page size + TEST_ASSERT_EQUAL(0, sector_size % page_size); + // Sector address must be a multiple of sector size + TEST_ASSERT_EQUAL(0, sector_start % sector_size); + // All address in a sector must return the same sector size + TEST_ASSERT_EQUAL(sector_size, end_sector_size); + } + + // Make sure unmapped flash is reported correctly + TEST_ASSERT_EQUAL(MBED_FLASH_INVALID_SIZE, flash_get_sector_size(&test_flash, flash_start - 1)); + TEST_ASSERT_EQUAL(MBED_FLASH_INVALID_SIZE, flash_get_sector_size(&test_flash, flash_start + flash_size)); + + ret = flash_free(&test_flash); + TEST_ASSERT_EQUAL_INT32(0, ret); +} + +void flash_erase_sector_test() +{ + flash_t test_flash; + int32_t ret = flash_init(&test_flash); + TEST_ASSERT_EQUAL_INT32(0, ret); + + uint32_t addr_after_last = flash_get_start_address(&test_flash) + flash_get_size(&test_flash); + uint32_t last_sector_size = flash_get_sector_size(&test_flash, addr_after_last - 1); + uint32_t last_sector = addr_after_last - last_sector_size; + TEST_ASSERT_EQUAL_INT32(0, last_sector % last_sector_size); + + utest_printf("ROM ends at 0x%lx, test starts at 0x%lx\n", FLASHIAP_APP_ROM_END_ADDR, last_sector); + TEST_SKIP_UNLESS_MESSAGE(last_sector >= FLASHIAP_APP_ROM_END_ADDR, "Test skipped. Test region overlaps code."); + + ret = flash_erase_sector(&test_flash, last_sector); + TEST_ASSERT_EQUAL_INT32(0, ret); + + ret = flash_free(&test_flash); + TEST_ASSERT_EQUAL_INT32(0, ret); +} + +// Erase sector, write one page, erase sector and write new data +void flash_program_page_test() +{ + flash_t test_flash; + int32_t ret = flash_init(&test_flash); + TEST_ASSERT_EQUAL_INT32(0, ret); + + uint32_t test_size = flash_get_page_size(&test_flash); + uint8_t *data = new uint8_t[test_size]; + uint8_t *data_flashed = new uint8_t[test_size]; + for (uint32_t i = 0; i < test_size; i++) { + data[i] = 0xCE; + } + + // the one before the last page in the system + uint32_t address = flash_get_start_address(&test_flash) + flash_get_size(&test_flash) - (2 * test_size); + + // sector size might not be same as page size + uint32_t erase_sector_boundary = ALIGN_DOWN(address, flash_get_sector_size(&test_flash, address)); + utest_printf("ROM ends at 0x%lx, test starts at 0x%lx\n", FLASHIAP_APP_ROM_END_ADDR, erase_sector_boundary); + TEST_SKIP_UNLESS_MESSAGE(erase_sector_boundary >= FLASHIAP_APP_ROM_END_ADDR, "Test skipped. Test region overlaps code."); + + ret = flash_erase_sector(&test_flash, erase_sector_boundary); + TEST_ASSERT_EQUAL_INT32(0, ret); + + ret = flash_program_page(&test_flash, address, data, test_size); + TEST_ASSERT_EQUAL_INT32(0, ret); + + ret = flash_read(&test_flash, address, data_flashed, test_size); + TEST_ASSERT_EQUAL_INT32(0, ret); + TEST_ASSERT_EQUAL_UINT8_ARRAY(data, data_flashed, test_size); + + // sector size might not be same as page size + erase_sector_boundary = ALIGN_DOWN(address, flash_get_sector_size(&test_flash, address)); + ret = flash_erase_sector(&test_flash, erase_sector_boundary); + TEST_ASSERT_EQUAL_INT32(0, ret); + + // write another data to be certain we are re-flashing + for (uint32_t i = 0; i < test_size; i++) { + data[i] = 0xAC; + } + ret = flash_program_page(&test_flash, address, data, test_size); + TEST_ASSERT_EQUAL_INT32(0, ret); + + ret = flash_read(&test_flash, address, data_flashed, test_size); + TEST_ASSERT_EQUAL_INT32(0, ret); + TEST_ASSERT_EQUAL_UINT8_ARRAY(data, data_flashed, test_size); + + ret = flash_free(&test_flash); + TEST_ASSERT_EQUAL_INT32(0, ret); + delete[] data; + delete[] data_flashed; +} + +// check the execution speed at the start and end of the test to make sure +// cache settings weren't changed +void flash_clock_and_cache_test() +{ + const int timer_diff_end = time_cpu_cycles(TEST_CYCLES); + const int acceptable_range = timer_diff_start / (ALLOWED_DRIFT_PPM); + TEST_ASSERT_UINT32_WITHIN(acceptable_range, timer_diff_start, timer_diff_end); +} + +Case cases[] = { + Case("Flash - init", flash_init_test), + Case("Flash - mapping alignment", flash_mapping_alignment_test), + Case("Flash - erase sector", flash_erase_sector_test), + Case("Flash - program page", flash_program_page_test), + Case("Flash - clock and cache test", flash_clock_and_cache_test), +}; + +utest::v1::status_t greentea_test_setup(const size_t number_of_cases) +{ + mbed_mpu_manager_lock_ram_execution(); + mbed_mpu_manager_lock_rom_write(); + + GREENTEA_SETUP(20, "default_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) +{ + mbed_mpu_manager_unlock_ram_execution(); + mbed_mpu_manager_unlock_rom_write(); + + greentea_test_teardown_handler(passed, failed, failure); +} + +Specification specification(greentea_test_setup, cases, greentea_test_teardown); + +int main() +{ + Harness::run(specification); +} + +#endif !DEVICE_FLASH diff --git a/hal/tests/TESTS/mbed_hal/gpio/main.cpp b/hal/tests/TESTS/mbed_hal/gpio/main.cpp new file mode 100644 index 0000000..2281957 --- /dev/null +++ b/hal/tests/TESTS/mbed_hal/gpio/main.cpp @@ -0,0 +1,57 @@ +/* mbed Microcontroller Library + * Copyright (c) 2019 ARM Limited + * 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. + */ + +#include "utest/utest.h" +#include "unity/unity.h" +#include "greentea-client/test_env.h" + +using namespace utest::v1; + +#include "PinNames.h" +#include "gpio_api.h" + +static void gpio_nc_test() +{ + gpio_t nc_obj; + gpio_init(&nc_obj, NC); + TEST_ASSERT_FALSE(gpio_is_connected(&nc_obj)); + + gpio_t led_obj; + gpio_init(&led_obj, LED1); + if (LED1 == NC) { + TEST_ASSERT_FALSE(gpio_is_connected(&led_obj)); + } else { + TEST_ASSERT_TRUE(gpio_is_connected(&led_obj)); + } +} + +Case cases[] = { + Case("gpio NC test", gpio_nc_test) +}; + +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); +} diff --git a/hal/tests/TESTS/mbed_hal/lp_ticker/lp_ticker_api_tests.h b/hal/tests/TESTS/mbed_hal/lp_ticker/lp_ticker_api_tests.h new file mode 100644 index 0000000..0fbb3a5 --- /dev/null +++ b/hal/tests/TESTS/mbed_hal/lp_ticker/lp_ticker_api_tests.h @@ -0,0 +1,63 @@ +/* mbed Microcontroller Library + * Copyright (c) 2017-2017 ARM Limited + * 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. + */ + +/** \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 + +/**@}*/ diff --git a/hal/tests/TESTS/mbed_hal/lp_ticker/main.cpp b/hal/tests/TESTS/mbed_hal/lp_ticker/main.cpp new file mode 100644 index 0000000..7331edf --- /dev/null +++ b/hal/tests/TESTS/mbed_hal/lp_ticker/main.cpp @@ -0,0 +1,214 @@ +/* mbed Microcontroller Library + * Copyright (c) 2017 ARM Limited + * 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. + */ + +#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" +#include "hal/mbed_lp_ticker_wrapper.h" +#include "hal/us_ticker_api.h" + +#if !DEVICE_LPTICKER +#error [NOT_SUPPORTED] Low power timer not supported for this target +#else + +using namespace utest::v1; + +volatile int intFlag = 0; + +ticker_irq_handler_type prev_handler; + +#define US_PER_MS 1000 + +#define TICKER_GLITCH_TEST_TICKS 1000 + +#define TICKER_INT_VAL 500 +#define TICKER_DELTA 10 + +#define LP_TICKER_OV_LIMIT 4000 + +/* To prevent a loss of Greentea data, the serial buffers have to be flushed + * before the UART peripheral shutdown. The UART shutdown happens when the + * device is entering the deepsleep mode or performing a reset. + * + * With the current API, it is not possible to check if the hardware buffers + * are empty. However, it is possible to determine the time required for the + * buffers to flush. + * + * Assuming the biggest Tx FIFO of 128 bytes (as for CY8CPROTO_062_4343W) + * and a default UART config (9600, 8N1), flushing the Tx FIFO wold take: + * (1 start_bit + 8 data_bits + 1 stop_bit) * 128 * 1000 / 9600 = 133.3 ms. + * To be on the safe side, set the wait time to 150 ms. + */ +#define SERIAL_FLUSH_TIME_MS 150 + +void busy_wait_ms(int ms) +{ + const ticker_data_t *const ticker = get_us_ticker_data(); + uint32_t start = ticker_read(ticker); + while ((ticker_read(ticker) - start) < (uint32_t)(ms * US_PER_MS)); +} + +/* 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() +{ + uint32_t time_window; + + time_window = LP_TICKER_OV_LIMIT; + + const uint32_t ticks_now = lp_ticker_read(); + const ticker_info_t *p_ticker_info = lp_ticker_get_info(); + + 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 (core_util_is_isr_active()) { + intFlag++; + } + + /* Clear and disable ticker interrupt. */ + lp_ticker_clear_interrupt(); + lp_ticker_disable_interrupt(); +} + +/* 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 +/* Test that the ticker continues operating in deep sleep mode. */ +void lp_ticker_deepsleep_test() +{ + intFlag = 0; + + lp_ticker_init(); + + /* Give some time Green Tea to finish UART transmission before entering + * deep-sleep mode. + */ + busy_wait_ms(SERIAL_FLUSH_TIME_MS); + + overflow_protect(); + + 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_test_check()); + + 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; + } +} + +#if DEVICE_LPTICKER +utest::v1::status_t lp_ticker_deepsleep_test_setup_handler(const Case *const source, const size_t index_of_case) +{ +#ifdef MBED_CONF_RTOS_PRESENT + /* disable everything using the lp ticker for this test */ + osKernelSuspend(); +#endif + ticker_suspend(get_lp_ticker_data()); +#if DEVICE_LPTICKER && (LPTICKER_DELAY_TICKS > 0) + lp_ticker_wrapper_suspend(); +#endif + 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_deepsleep_test_teardown_handler(const Case *const source, const size_t passed, const size_t failed, + const failure_t reason) +{ + set_lp_ticker_irq_handler(prev_handler); +#if DEVICE_LPTICKER && (LPTICKER_DELAY_TICKS > 0) + lp_ticker_wrapper_resume(); +#endif + ticker_resume(get_lp_ticker_data()); +#ifdef MBED_CONF_RTOS_PRESENT + osKernelResume(0); +#endif + return greentea_case_teardown_handler(source, passed, failed, reason); +} +#endif + +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("lp ticker info test", lp_ticker_info_test), +#if DEVICE_SLEEP + Case("lp ticker sleep test", lp_ticker_deepsleep_test_setup_handler, lp_ticker_deepsleep_test, lp_ticker_deepsleep_test_teardown_handler), +#endif + Case("lp ticker glitch test", lp_ticker_glitch_test) +}; + +Specification specification(test_setup, cases); + +int main() +{ + return !Harness::run(specification); +} + +#endif // !DEVICE_LPTICKER diff --git a/hal/tests/TESTS/mbed_hal/minimum_requirements/main.cpp b/hal/tests/TESTS/mbed_hal/minimum_requirements/main.cpp new file mode 100644 index 0000000..3e58adf --- /dev/null +++ b/hal/tests/TESTS/mbed_hal/minimum_requirements/main.cpp @@ -0,0 +1,73 @@ +/* mbed Microcontroller Library + * Copyright (c) 2017 ARM Limited + * 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. + */ + +#include "utest/utest.h" +#include "unity/unity.h" +#include "greentea-client/test_env.h" + +#include "mbed.h" + +using namespace utest::v1; + +/** + * This test is intended to gate devices that do not have enough RAM to run + * Mbed os. Devices passing this test should have enough RAM to run all + * other Mbed OS tests. + * + * If your device does not pass this test, then you should determine the + * cause of high memory usage and fix it. If you cannot free enough memory, + * then you should turn off Mbed OS support for this device. + */ + +#define MIN_HEAP_SIZE 2048 +#define MIN_DATA_SIZE 2048 + +volatile uint8_t test_buffer[MIN_DATA_SIZE]; + +static void minimum_heap_test() +{ + void *mem = malloc(MIN_HEAP_SIZE); + TEST_ASSERT_NOT_EQUAL(NULL, mem); + free(mem); +} + +static void minimum_data_test() +{ + // Use test buffer so it is not optimized away + for (int i = 0; i < MIN_DATA_SIZE; i++) { + test_buffer[i] = i & 0xFF; + } +} + + +utest::v1::status_t greentea_test_setup(const size_t number_of_cases) +{ + GREENTEA_SETUP(30, "default_auto"); + return greentea_test_setup_handler(number_of_cases); +} + +Case cases[] = { + Case("Minimum heap test", minimum_heap_test), + Case("Minimum data test", minimum_data_test), +}; + +Specification specification(greentea_test_setup, cases, greentea_test_teardown_handler); + +int main() +{ + Harness::run(specification); +} diff --git a/hal/tests/TESTS/mbed_hal/mpu/main.cpp b/hal/tests/TESTS/mbed_hal/mpu/main.cpp new file mode 100644 index 0000000..fe79ccb --- /dev/null +++ b/hal/tests/TESTS/mbed_hal/mpu/main.cpp @@ -0,0 +1,202 @@ +/* mbed Microcontroller Library + * Copyright (c) 2017 ARM Limited + * 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. + */ + +#include "utest/utest.h" +#include "unity/unity.h" +#include "greentea-client/test_env.h" + +#include "cmsis.h" +#include + +#include "mpu_api.h" +#include "mpu_test.h" + +#if !DEVICE_MPU +#error [NOT_SUPPORTED] MPU API not supported for this target +#else + +using namespace utest::v1; + +#define HARDFAULT_IRQn ((IRQn_Type)-13) +#define MEMFAULT_IRQn ((IRQn_Type)-12) + +// Assembly return instruction: bx lr +#define ASM_BX_LR 0x4770 + +volatile uint32_t fault_count; +uint32_t real_hard_fault_handler; +uint32_t real_mem_fault_handler; + +static volatile uint16_t data_function = ASM_BX_LR; +static volatile uint16_t bss_function; + +static void clear_caches() +{ +#if defined(__CORTEX_M7) + /* Data cache clean and invalid */ + SCB_CleanInvalidateDCache(); + + /* Instruction cache invalid */ + SCB_InvalidateICache(); +#endif + + __ISB(); + __DSB(); + +} + +static void call_mem(const volatile uint16_t *mem_function) +{ + // or the address with 1 to ensure the thumb bit is set + ((void (*)())((uint32_t)mem_function | 1))(); +} + +static void hard_fault_handler_test() +{ + fault_count++; + mbed_mpu_enable_ram_xn(false); +} + +static void mpu_fault_test(const volatile uint16_t *mem_function) +{ + // Verify that the mpu causes faults when executing ram after init + fault_count = 0; + mbed_mpu_init(); + call_mem(mem_function); + TEST_ASSERT_EQUAL(1, fault_count); + + // Verify that the mpu can be turned off + fault_count = 0; + mbed_mpu_enable_ram_xn(false); + call_mem(mem_function); + TEST_ASSERT_EQUAL(0, fault_count); + + // Verify that the mpu can be turned back on + fault_count = 0; + mbed_mpu_enable_ram_xn(true); + call_mem(mem_function); + TEST_ASSERT_EQUAL(1, fault_count); + + // Verify that free turns off the mpu + fault_count = 0; + mbed_mpu_free(); + call_mem(mem_function); + TEST_ASSERT_EQUAL(0, fault_count); +} + +void mpu_init_test() +{ + for (int i = 0; i < 10; i++) { + mbed_mpu_init(); + } + + mbed_mpu_free(); +} + +void mpu_free_test() +{ + mbed_mpu_init(); + + // Enable the MPU + mbed_mpu_enable_ram_xn(true); + + // Free and ensure execution from RAM is allowed + mbed_mpu_free(); + + call_mem(&data_function); +} + +void mpu_fault_test_data() +{ + mpu_fault_test(&data_function); +} + +void mpu_fault_test_bss() +{ + bss_function = ASM_BX_LR; + clear_caches(); + mpu_fault_test(&bss_function); +} + +void mpu_fault_test_stack() +{ + uint16_t stack_function; + + stack_function = ASM_BX_LR; + clear_caches(); + mpu_fault_test(&stack_function); +} + +void mpu_fault_test_heap() +{ + uint16_t *heap_function = (uint16_t *)malloc(2); + + TEST_ASSERT_NOT_EQUAL(NULL, heap_function); + *heap_function = ASM_BX_LR; + clear_caches(); + mpu_fault_test(heap_function); + + free(heap_function); +} + +utest::v1::status_t fault_override_setup(const Case *const source, const size_t index_of_case) +{ + // Save old fault handlers and replace it with a new one + real_hard_fault_handler = NVIC_GetVector(HARDFAULT_IRQn); + real_mem_fault_handler = NVIC_GetVector(MEMFAULT_IRQn); + NVIC_SetVector(HARDFAULT_IRQn, (uint32_t)&hard_fault_handler_test); + NVIC_SetVector(MEMFAULT_IRQn, (uint32_t)&hard_fault_handler_test); + + return greentea_case_setup_handler(source, index_of_case); +} + +utest::v1::status_t fault_override_teardown(const Case *const source, const size_t passed, const size_t failed, + const failure_t reason) +{ + // Restore real fault handlers + NVIC_SetVector(HARDFAULT_IRQn, real_hard_fault_handler); + NVIC_SetVector(MEMFAULT_IRQn, real_mem_fault_handler); + + return greentea_case_teardown_handler(source, passed, failed, reason); +} + +Case cases[] = { + Case("MPU - init", fault_override_setup, mpu_init_test, fault_override_teardown), + Case("MPU - free", fault_override_setup, mpu_free_test, fault_override_teardown), +#if !((__ARM_ARCH_8M_BASE__ == 1U) || (__ARM_ARCH_8M_MAIN__ == 1U)) + // Skip fault tests for ARMv8-M until a fault handler hook is provided + Case("MPU - data fault", fault_override_setup, mpu_fault_test_data, fault_override_teardown), + Case("MPU - bss fault", fault_override_setup, mpu_fault_test_bss, fault_override_teardown), + Case("MPU - stack fault", fault_override_setup, mpu_fault_test_stack, fault_override_teardown), + Case("MPU - heap fault", fault_override_setup, mpu_fault_test_heap, fault_override_teardown) +#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); +} + +#endif // !DEVICE_MPU diff --git a/hal/tests/TESTS/mbed_hal/mpu/mpu_test.h b/hal/tests/TESTS/mbed_hal/mpu/mpu_test.h new file mode 100644 index 0000000..0a916ca --- /dev/null +++ b/hal/tests/TESTS/mbed_hal/mpu/mpu_test.h @@ -0,0 +1,95 @@ +/* mbed Microcontroller Library + * Copyright (c) 2018-2018 ARM Limited + * 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. + */ + +/** \addtogroup hal_mpu_tests + * @{ + */ + +#ifndef MBED_MPU_TEST_H +#define MBED_MPU_TEST_H + +#if DEVICE_MPU + +#ifdef __cplusplus +extern "C" { +#endif + +/** Test that ::mbed_mpu_init can be called multiple times. + * + * Given board provides MPU. + * When ::mbed_mpu_init is called multiple times. + * Then ::mbed_mpu_init are successfully performed (no exception is generated). + * + */ +void mpu_init_test(void); + +/** Test that ::mbed_mpu_free disables the MPU + * + * Given board provides MPU. + * When ::mbed_mpu_free is called. + * Then execution from RAM is allowed. + * + */ +void mpu_free_test(void); + +/** Test that MPU protection works for global data + * + * Given board provides MPU. + * When RAM execution is disabled with a call to ::mbed_mpu_enable_ram_xn. + * Then execution from global initialized data results in a fault. + * + */ +void mpu_fault_test_data(void); + +/** Test that MPU protection works for zero initialized data + * + * Given board provides MPU. + * When RAM execution is disabled with a call to ::mbed_mpu_enable_ram_xn. + * Then execution from global uninitialized data results in a fault. + * + */ +void mpu_fault_test_bss(void); + +/** Test that MPU protection works for the stack + * + * Given board provides MPU. + * When RAM execution is disabled with a call to ::mbed_mpu_enable_ram_xn. + * Then execution from stack memory results in a fault. + * + */ +void mpu_fault_test_stack(void); + +/** Test that MPU protection works for the heap + * + * Given board provides MPU. + * When RAM execution is disabled with a call to ::mbed_mpu_enable_ram_xn. + * Then execution from heap memory results in a fault. + * + */ +void mpu_fault_test_heap(void); + +/**@}*/ + +#ifdef __cplusplus +} +#endif + +#endif + +#endif + +/** @}*/ diff --git a/hal/tests/TESTS/mbed_hal/pinmap/main.cpp b/hal/tests/TESTS/mbed_hal/pinmap/main.cpp new file mode 100644 index 0000000..1b87414 --- /dev/null +++ b/hal/tests/TESTS/mbed_hal/pinmap/main.cpp @@ -0,0 +1,128 @@ +/* mbed Microcontroller Library + * Copyright (c) 2019 ARM Limited + * 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. + */ + +#include "utest/utest.h" +#include "unity/unity.h" +#include "greentea-client/test_env.h" + +using namespace utest::v1; + +#include "analogin_api.h" +#include "analogout_api.h" +#include "can_api.h" +#include "i2c_api.h" +#include "pwmout_api.h" +#include "qspi_api.h" +#include "serial_api.h" +#include "spi_api.h" + +#define PINMAP_TEST_ENTRY(function) {function, #function} + +typedef const PinMap *(*get_pinmap_func_t)(void); +typedef struct { + get_pinmap_func_t function; + const char *name; +} pinmap_info_t; + +const pinmap_info_t pinmap_functions[] = { +#if DEVICE_ANALOGIN + PINMAP_TEST_ENTRY(analogin_pinmap), +#endif +#if DEVICE_ANALOGOUT + PINMAP_TEST_ENTRY(analogout_pinmap), +#endif +#if DEVICE_CAN + PINMAP_TEST_ENTRY(can_rd_pinmap), + PINMAP_TEST_ENTRY(can_td_pinmap), +#endif +#if DEVICE_I2C + PINMAP_TEST_ENTRY(i2c_master_sda_pinmap), + PINMAP_TEST_ENTRY(i2c_master_scl_pinmap), +#if DEVICE_I2CSLAVE + PINMAP_TEST_ENTRY(i2c_slave_sda_pinmap), + PINMAP_TEST_ENTRY(i2c_slave_scl_pinmap), +#endif +#endif +#if DEVICE_PWMOUT + PINMAP_TEST_ENTRY(pwmout_pinmap), +#endif +#if DEVICE_QSPI + PINMAP_TEST_ENTRY(qspi_master_sclk_pinmap), + PINMAP_TEST_ENTRY(qspi_master_ssel_pinmap), + PINMAP_TEST_ENTRY(qspi_master_data0_pinmap), + PINMAP_TEST_ENTRY(qspi_master_data1_pinmap), + PINMAP_TEST_ENTRY(qspi_master_data2_pinmap), + PINMAP_TEST_ENTRY(qspi_master_data3_pinmap), +#endif +#if DEVICE_SERIAL + PINMAP_TEST_ENTRY(serial_tx_pinmap), + PINMAP_TEST_ENTRY(serial_rx_pinmap), +#if DEVICE_SERIAL_FC + PINMAP_TEST_ENTRY(serial_cts_pinmap), + PINMAP_TEST_ENTRY(serial_rts_pinmap), +#endif +#endif +#if DEVICE_SPI + PINMAP_TEST_ENTRY(spi_master_mosi_pinmap), + PINMAP_TEST_ENTRY(spi_master_miso_pinmap), + PINMAP_TEST_ENTRY(spi_master_clk_pinmap), + PINMAP_TEST_ENTRY(spi_master_cs_pinmap), +#if DEVICE_SPISLAVE + PINMAP_TEST_ENTRY(spi_slave_mosi_pinmap), + PINMAP_TEST_ENTRY(spi_slave_miso_pinmap), + PINMAP_TEST_ENTRY(spi_slave_clk_pinmap), + PINMAP_TEST_ENTRY(spi_slave_cs_pinmap), +#endif +#endif + {NULL, NULL} +}; + +void pinmap_validation() +{ + for (size_t i = 0; i < sizeof(pinmap_functions) / sizeof(pinmap_functions[0]) - 1; i++) { + printf("Testing pinmap %s\r\n", pinmap_functions[i].name); + + get_pinmap_func_t function = pinmap_functions[i].function; + TEST_ASSERT_NOT_EQUAL(NULL, function); + + const PinMap *map = function(); + TEST_ASSERT_NOT_EQUAL(NULL, map); + + while (map->pin != NC) { + map++; + } + + TEST_ASSERT_EQUAL(NC, map->peripheral); + } +} + +Case cases[] = { + Case("pinmap - validation", pinmap_validation) +}; + +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); +} diff --git a/hal/tests/TESTS/mbed_hal/qspi/flash_configs/MT25Q_config.h b/hal/tests/TESTS/mbed_hal/qspi/flash_configs/MT25Q_config.h new file mode 100644 index 0000000..ff3d064 --- /dev/null +++ b/hal/tests/TESTS/mbed_hal/qspi/flash_configs/MT25Q_config.h @@ -0,0 +1,250 @@ +/* mbed Microcontroller Library + * Copyright (c) 2018 ARM Limited + * 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. + */ +#ifndef MBED_QSPI_FLASH_MT25Q_H +#define MBED_QSPI_FLASH_MT25Q_H +#define QSPI_FLASH_CHIP_STRING "Micron MT25Q" +// Command for reading status register +#define QSPI_CMD_RDSR 0x05 +// Command for reading configuration register 0 (NONVOLATILE CONFIGURATION REGISTER) +#define QSPI_CMD_RDCR0 0xB5 +// Command for reading configuration register 1 (VOLATILE CONFIGURATION REGISTER) +#define QSPI_CMD_RDCR1 0x85 +// Command for reading configuration register 2 (ENHANCED VOLATILE CONFIGURATION REGISTER) +#define QSPI_CMD_RDCR2 0x65 +// Command for writing status register +#define QSPI_CMD_WRSR 0x01 +// Command for writing configuration register 0 (NONVOLATILE CONFIGURATION REGISTER) +#define QSPI_CMD_WRCR0 0xB1 +// Command for writing configuration register 1 (VOLATILE CONFIGURATION REGISTER) +#define QSPI_CMD_WRCR1 0x81 +// Command for writing configuration register 2 (ENHANCED VOLATILE CONFIGURATION REGISTER) +#define QSPI_CMD_WRCR2 0x61 +// Command for setting Reset Enable +#define QSPI_CMD_RSTEN 0x66 +// Command for setting Reset +#define QSPI_CMD_RST 0x99 +// Command for setting write enable +#define QSPI_CMD_WREN 0x06 +// Command for setting write disable +#define QSPI_CMD_WRDI 0x04 +// WRSR operations max time [us] (datasheet max time + 15%) +#define QSPI_WRSR_MAX_TIME 9200 // 8ms +// general wait max time [us] +#define QSPI_WAIT_MAX_TIME 100000 // 100ms +// Commands for writing (page programming) +#define QSPI_CMD_WRITE_1IO 0x02 // 1-1-1 mode +#define QSPI_CMD_WRITE_1I2O 0xA2 // 1-1-2 mode +#define QSPI_CMD_WRITE_2IO 0xD2 // 1-2-2 mode +#define QSPI_CMD_WRITE_1I4O 0x32 // 1-1-4 mode +#define QSPI_CMD_WRITE_4IO 0x38 // 1-4-4 mode +#define QSPI_CMD_WRITE_DPI 0xD2 // 2-2-2 mode +#define QSPI_CMD_WRITE_QPI 0x38 // 4-4-4 mode +// write operations max time [us] (datasheet max time + 15%) +#define QSPI_PAGE_PROG_MAX_TIME 2070 // 1.8ms +#define QSPI_PAGE_SIZE 256 // 256B +#define QSPI_SECTOR_SIZE 4096 // 4kB +#define QSPI_SECTOR_COUNT 4096 // for 128Mb chip +// Commands for reading +#define QSPI_CMD_READ_1IO_FAST 0x0B // 1-1-1 mode +#define QSPI_CMD_READ_1IO 0x03 // 1-1-1 mode +#define QSPI_CMD_READ_1I2O 0x3B // 1-1-2 mode +#define QSPI_CMD_READ_2IO 0xBB // 1-2-2 mode +#define QSPI_CMD_READ_DPI 0xBB // 2-2-2 mode +#define QSPI_CMD_READ_1I4O 0x6B // 1-1-4 mode +#define QSPI_CMD_READ_4IO 0xEB // 1-4-4 mode +#define QSPI_CMD_READ_QPI 0xEB // 4-4-4 mode +#define QSPI_READ_1IO_DUMMY_CYCLE 0 // 1-1-1 mode +#define QSPI_READ_FAST_DUMMY_CYCLE 8 // 1-1-1 mode +#define QSPI_READ_1I2O_DUMMY_CYCLE 8 // 1-1-2 mode +#define QSPI_READ_2IO_DUMMY_CYCLE 8 // 1-2-2 mode +#define QSPI_READ_DPI_DUMMY_CYCLE 8 // 2-2-2 mode +#define QSPI_READ_1I4O_DUMMY_CYCLE 8 // 1-1-4 mode +#define QSPI_READ_4IO_DUMMY_CYCLE 10 // 1-4-4 mode +#define QSPI_READ_QPI_DUMMY_CYCLE 10 // 4-4-4 mode +// Commands for erasing +#define QSPI_CMD_ERASE_SECTOR 0x20 // 4kB +#define QSPI_CMD_ERASE_BLOCK_32 0x52 // 32kB +#define QSPI_CMD_ERASE_BLOCK_64 0xD8 // 64kB +#define QSPI_CMD_ERASE_CHIP 0x60 // or 0xC7 +// erase operations max time [us] (datasheet max time + 15%) +#define QSPI_ERASE_SECTOR_MAX_TIME 460000 // 0.4s +#define QSPI_ERASE_BLOCK_32_MAX_TIME 1150000 // 1s +#define QSPI_ERASE_BLOCK_64_MAX_TIME 1150000 // 1s +// max frequency for basic rw operation +#define QSPI_COMMON_MAX_FREQUENCY 50000000 +#define QSPI_STATUS_REG_SIZE 1 +#define QSPI_CONFIG_REG_0_SIZE 2 +#define QSPI_CONFIG_REG_1_SIZE 1 +#define QSPI_CONFIG_REG_2_SIZE 1 +#define QSPI_MAX_REG_SIZE 2 +// status register +#define STATUS_BIT_WIP (1 << 0) // write in progress bit +#define STATUS_BIT_WEL (1 << 1) // write enable latch +#define STATUS_BIT_BP0 (1 << 2) // Block protect +#define STATUS_BIT_BP1 (1 << 3) // Block protect +#define STATUS_BIT_BP2 (1 << 4) // Block protect +#define STATUS_BIT_BP_TB (1 << 5) // Block protect top/bottom +#define STATUS_BIT_BP3 (1 << 6) // Block protect +#define STATUS_BIT_SRWD (1 << 7) // status register write protect +// configuration register 0 (Nonvolatile Configuration Register) +// bit 0, 1 reserved +#define CONFIG0_BIT_DE (1 << 2) // Dual Enable 0 = Enabled / 1 = Disabled +#define CONFIG0_BIT_QE (1 << 3) // Quad Enable 0 = Enabled / 1 = Disabled +#define CONFIG0_BIT_RH (1 << 4) // Reset/hold +#define CONFIG0_BIT_DTR (1 << 5) // Double transfer rate protocol +#define CONFIG0_BIT_ODS0 (1 << 6) // Output driver strength +#define CONFIG0_BIT_ODS1 (1 << 7) // Output driver strength +#define CONFIG0_BIT_ODS2 (1 << 8) // Output driver strength +#define CONFIG0_BIT_XIP_MODE0 (1 << 9) // XIP mode at power-on reset +#define CONFIG0_BIT_XIP_MODE1 (1 << 10) // XIP mode at power-on reset +#define CONFIG0_BIT_XIP_MODE2 (1 << 11) // XIP mode at power-on reset +#define CONFIG0_BIT_DCYCLE0 (1 << 12) // Dummy Cycle +#define CONFIG0_BIT_DCYCLE1 (1 << 13) // Dummy Cycle +#define CONFIG0_BIT_DCYCLE2 (1 << 14) // Dummy Cycle +#define CONFIG0_BIT_DCYCLE3 (1 << 15) // Dummy Cycle +// configuration register 1 (Volatile Configuration Register) +// bit 2, reserved +#define CONFIG1_BIT_WRAP0 (1 << 0) // Output data wrap +#define CONFIG1_BIT_WRAP1 (1 << 1) // Output data wrap +#define CONFIG1_BIT_XIP (1 << 3) // 0 = Enable / 1 = Disable (default) +#define CONFIG1_BIT_DCYCLE0 (1 << 4) // Number of dummy clock cycles +#define CONFIG1_BIT_DCYCLE1 (1 << 5) // Number of dummy clock cycles +#define CONFIG1_BIT_DCYCLE2 (1 << 6) // Number of dummy clock cycles +#define CONFIG1_BIT_DCYCLE3 (1 << 7) // Number of dummy clock cycles +// configuration register 2 (Enhanced Volatile Configuration Register) +// bit 3, reserved +#define CONFIG2_BIT_ODS0 (1 << 0) // Output driver strength 111 = 30 Ohms (Default) +#define CONFIG2_BIT_ODS1 (1 << 1) // Output driver strength +#define CONFIG2_BIT_ODS2 (1 << 2) // Output driver strength +#define CONFIG2_BIT_RH (1 << 4) // Reset/hold +#define CONFIG2_BIT_DTR (1 << 5) // Double transfer rate protocol +#define CONFIG2_BIT_DE (1 << 6) // Dual I/O protocol 0 = Enabled / 1 = Disabled (Default, extended SPI protocol) +#define CONFIG2_BIT_QE (1 << 7) // Quad I/O protocol 0 = Enabled / 1 = Disabled (Default, extended SPI protocol) +#define DUAL_ENABLE() \ + \ + uint8_t reg_data[QSPI_CONFIG_REG_2_SIZE]; \ + \ + memset(reg_data, 0, QSPI_CONFIG_REG_2_SIZE); \ + if (read_register(QSPI_CMD_RDCR2, reg_data, \ + QSPI_CONFIG_REG_2_SIZE, qspi) != QSPI_STATUS_OK) { \ + return QSPI_STATUS_ERROR; \ + } \ + if (write_enable(qspi) != QSPI_STATUS_OK) { \ + return QSPI_STATUS_ERROR; \ + } \ + \ + reg_data[0] = reg_data[0] & ~(CONFIG2_BIT_DE); \ + if (write_register(QSPI_CMD_WRCR2, reg_data, \ + QSPI_CONFIG_REG_2_SIZE, qspi) != QSPI_STATUS_OK) { \ + return QSPI_STATUS_ERROR; \ + } \ + qspi.cmd.configure(MODE_2_2_2, ADDR_SIZE_24, ALT_SIZE_8); \ + WAIT_FOR(WRSR_MAX_TIME, qspi); \ + memset(reg_data, 0, QSPI_CONFIG_REG_2_SIZE); \ + if (read_register(QSPI_CMD_RDCR2, reg_data, \ + QSPI_CONFIG_REG_2_SIZE, qspi) != QSPI_STATUS_OK) { \ + return QSPI_STATUS_ERROR; \ + } \ + \ + return ((reg_data[0] & (CONFIG2_BIT_DE)) == 0 ? \ + QSPI_STATUS_OK : QSPI_STATUS_ERROR) +#define DUAL_DISABLE() \ + \ + uint8_t reg_data[QSPI_CONFIG_REG_2_SIZE]; \ + \ + memset(reg_data, 0, QSPI_CONFIG_REG_2_SIZE); \ + if (read_register(QSPI_CMD_RDCR2, reg_data, \ + QSPI_CONFIG_REG_2_SIZE, qspi) != QSPI_STATUS_OK) { \ + return QSPI_STATUS_ERROR; \ + } \ + if (write_enable(qspi) != QSPI_STATUS_OK) { \ + return QSPI_STATUS_ERROR; \ + } \ + \ + reg_data[0] = reg_data[0] | (CONFIG2_BIT_DE); \ + if (write_register(QSPI_CMD_WRCR2, reg_data, \ + QSPI_CONFIG_REG_2_SIZE, qspi) != QSPI_STATUS_OK) { \ + return QSPI_STATUS_ERROR; \ + } \ + qspi.cmd.configure(MODE_1_1_1, ADDR_SIZE_24, ALT_SIZE_8); \ + WAIT_FOR(WRSR_MAX_TIME, qspi); \ + memset(reg_data, 0, QSPI_CONFIG_REG_2_SIZE); \ + if (read_register(QSPI_CMD_RDCR2, reg_data, \ + QSPI_CONFIG_REG_2_SIZE, qspi) != QSPI_STATUS_OK) { \ + return QSPI_STATUS_ERROR; \ + } \ + \ + return ((reg_data[0] & CONFIG2_BIT_DE) != 1 ? \ + QSPI_STATUS_OK : QSPI_STATUS_ERROR) +#define QUAD_ENABLE() \ + \ + uint8_t reg_data[QSPI_CONFIG_REG_2_SIZE]; \ + \ + memset(reg_data, 0, QSPI_CONFIG_REG_2_SIZE); \ + if (read_register(QSPI_CMD_RDCR2, reg_data, \ + QSPI_CONFIG_REG_2_SIZE, qspi) != QSPI_STATUS_OK) { \ + return QSPI_STATUS_ERROR; \ + } \ + if (write_enable(qspi) != QSPI_STATUS_OK) { \ + return QSPI_STATUS_ERROR; \ + } \ + \ + reg_data[0] = reg_data[0] & ~(CONFIG2_BIT_QE); \ + if (write_register(QSPI_CMD_WRCR2, reg_data, \ + QSPI_CONFIG_REG_2_SIZE, qspi) != QSPI_STATUS_OK) { \ + return QSPI_STATUS_ERROR; \ + } \ + qspi.cmd.configure(MODE_4_4_4, ADDR_SIZE_24, ALT_SIZE_8); \ + WAIT_FOR(WRSR_MAX_TIME, qspi); \ + memset(reg_data, 0, QSPI_CONFIG_REG_2_SIZE); \ + if (read_register(QSPI_CMD_RDCR2, reg_data, \ + QSPI_CONFIG_REG_2_SIZE, qspi) != QSPI_STATUS_OK) { \ + return QSPI_STATUS_ERROR; \ + } \ + \ + return ((reg_data[0] & (CONFIG2_BIT_QE)) == 0 ? \ + QSPI_STATUS_OK : QSPI_STATUS_ERROR) +#define QUAD_DISABLE() \ + \ + uint8_t reg_data[QSPI_CONFIG_REG_2_SIZE]; \ + \ + memset(reg_data, 0, QSPI_CONFIG_REG_2_SIZE); \ + if (read_register(QSPI_CMD_RDCR2, reg_data, \ + QSPI_CONFIG_REG_2_SIZE, qspi) != QSPI_STATUS_OK) { \ + return QSPI_STATUS_ERROR; \ + } \ + if (write_enable(qspi) != QSPI_STATUS_OK) { \ + return QSPI_STATUS_ERROR; \ + } \ + \ + reg_data[0] = reg_data[0] | (CONFIG2_BIT_QE); \ + if (write_register(QSPI_CMD_WRCR2, reg_data, \ + QSPI_CONFIG_REG_2_SIZE, qspi) != QSPI_STATUS_OK) { \ + return QSPI_STATUS_ERROR; \ + } \ + qspi.cmd.configure(MODE_1_1_1, ADDR_SIZE_24, ALT_SIZE_8); \ + WAIT_FOR(WRSR_MAX_TIME, qspi); \ + memset(reg_data, 0, QSPI_CONFIG_REG_2_SIZE); \ + if (read_register(QSPI_CMD_RDCR2, reg_data, \ + QSPI_CONFIG_REG_2_SIZE, qspi) != QSPI_STATUS_OK) { \ + return QSPI_STATUS_ERROR; \ + } \ + \ + return ((reg_data[0] & CONFIG2_BIT_QE) != 1 ? \ + QSPI_STATUS_OK : QSPI_STATUS_ERROR) +#endif // MBED_QSPI_FLASH_MT25Q_H + diff --git a/hal/tests/TESTS/mbed_hal/qspi/flash_configs/MX25L51245G_config.h b/hal/tests/TESTS/mbed_hal/qspi/flash_configs/MX25L51245G_config.h new file mode 100644 index 0000000..6f50ed8 --- /dev/null +++ b/hal/tests/TESTS/mbed_hal/qspi/flash_configs/MX25L51245G_config.h @@ -0,0 +1,107 @@ +/* mbed Microcontroller Library + * Copyright (c) 2018-2018 ARM Limited + * 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. + */ +#ifndef MBED_QSPI_FLASH_MX25L51245G_H +#define MBED_QSPI_FLASH_MX25L51245G_H + + +#define QSPI_FLASH_CHIP_STRING "macronix MX25L51245G" + +// Command for reading status register +#define QSPI_CMD_RDSR 0x05 +// Command for reading configuration register +#define QSPI_CMD_RDCR0 0x15 +// Command for writing status/configuration register +#define QSPI_CMD_WRSR 0x01 +// Command for reading security register +#define QSPI_CMD_RDSCUR 0x2B + +// Command for setting Reset Enable +#define QSPI_CMD_RSTEN 0x66 +// Command for setting Reset +#define QSPI_CMD_RST 0x99 + +// Command for setting write enable +#define QSPI_CMD_WREN 0x06 +// Command for setting write disable +#define QSPI_CMD_WRDI 0x04 + +// WRSR operations max time [us] (datasheet max time + 15%) +#define QSPI_WRSR_MAX_TIME 34500 // 30ms +// general wait max time [us] +#define QSPI_WAIT_MAX_TIME 100000 // 100ms + + +// Commands for writing (page programming) +#define QSPI_CMD_WRITE_1IO 0x02 // 1-1-1 mode +#define QSPI_CMD_WRITE_4IO 0x38 // 1-4-4 mode + +// write operations max time [us] (datasheet max time + 15%) +#define QSPI_PAGE_PROG_MAX_TIME 11500 // 10ms + +#define QSPI_PAGE_SIZE 256 // 256B +#define QSPI_SECTOR_SIZE 4096 // 4kB +#define QSPI_SECTOR_COUNT 2048 // + +// Commands for reading +#define QSPI_CMD_READ_1IO_FAST 0x0B // 1-1-1 mode +#define QSPI_CMD_READ_1IO 0x03 // 1-1-1 mode +#define QSPI_CMD_READ_2IO 0xBB // 1-2-2 mode +#define QSPI_CMD_READ_1I2O 0x3B // 1-1-2 mode +#define QSPI_CMD_READ_4IO 0xEB // 1-4-4 mode +#define QSPI_CMD_READ_1I4O 0x6B // 1-1-4 mode + +#define QSPI_READ_1IO_DUMMY_CYCLE 0 +#define QSPI_READ_FAST_DUMMY_CYCLE 8 +#define QSPI_READ_2IO_DUMMY_CYCLE 4 +#define QSPI_READ_1I2O_DUMMY_CYCLE 8 +#define QSPI_READ_4IO_DUMMY_CYCLE 6 +#define QSPI_READ_1I4O_DUMMY_CYCLE 8 + +// Commands for erasing +#define QSPI_CMD_ERASE_SECTOR 0x20 // 4kB +#define QSPI_CMD_ERASE_BLOCK_32 0x52 // 32kB +#define QSPI_CMD_ERASE_BLOCK_64 0xD8 // 64kB +#define QSPI_CMD_ERASE_CHIP 0x60 // or 0xC7 + +// erase operations max time [us] (datasheet max time + 15%) +#define QSPI_ERASE_SECTOR_MAX_TIME 480000 // 400 ms +#define QSPI_ERASE_BLOCK_32_MAX_TIME 1200000 // 1s +#define QSPI_ERASE_BLOCK_64_MAX_TIME 2400000 // 2s + +// max frequency for basic rw operation (for fast mode) +#define QSPI_COMMON_MAX_FREQUENCY 32000000 + +#define QSPI_STATUS_REG_SIZE 1 +#define QSPI_CONFIG_REG_0_SIZE 2 +#define QSPI_SECURITY_REG_SIZE 1 +#define QSPI_MAX_REG_SIZE 2 + +// status register +#define STATUS_BIT_WIP (1 << 0) // write in progress bit +#define STATUS_BIT_WEL (1 << 1) // write enable latch +#define STATUS_BIT_BP0 (1 << 2) // +#define STATUS_BIT_BP1 (1 << 3) // +#define STATUS_BIT_BP2 (1 << 4) // +#define STATUS_BIT_BP3 (1 << 5) // +#define STATUS_BIT_QE (1 << 6) // Quad Enable +#define STATUS_BIT_SRWD (1 << 7) // status register write protect + +// configuration register 0 +// bit 0, 1, 2, 4, 5, 7 reserved +#define CONFIG0_BIT_TB (1 << 3) // Top/Bottom area protect + +#endif // MBED_QSPI_FLASH_MX25L51245G_H diff --git a/hal/tests/TESTS/mbed_hal/qspi/flash_configs/MX25LM51245G_config.h b/hal/tests/TESTS/mbed_hal/qspi/flash_configs/MX25LM51245G_config.h new file mode 100644 index 0000000..6957b8f --- /dev/null +++ b/hal/tests/TESTS/mbed_hal/qspi/flash_configs/MX25LM51245G_config.h @@ -0,0 +1,96 @@ +/* mbed Microcontroller Library + * Copyright (c) 2018-2018 ARM Limited + * 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. + */ +#ifndef MBED_QSPI_FLASH_MX25LM51245G_H +#define MBED_QSPI_FLASH_MX25LM51245G_H + + +#define QSPI_FLASH_CHIP_STRING "macronix MX25LM51245G" + +// Command for reading status register +#define QSPI_CMD_RDSR 0x05 +// Command for reading configuration register +#define QSPI_CMD_RDCR0 0x15 +#define QSPI_CMD_RDCR1 0x71 +// Command for writing status/configuration register +#define QSPI_CMD_WRSR 0x01 +// Command for reading security register +#define QSPI_CMD_RDSCUR 0x2B + +// Command for setting Reset Enable +#define QSPI_CMD_RSTEN 0x66 +// Command for setting Reset +#define QSPI_CMD_RST 0x99 + +// Command for setting write enable +#define QSPI_CMD_WREN 0x06 +// Command for setting write disable +#define QSPI_CMD_WRDI 0x04 + +// WRSR operations max time [us] (datasheet max time + 15%) +#define QSPI_WRSR_MAX_TIME 34500 // 30ms +// general wait max time [us] +#define QSPI_WAIT_MAX_TIME 100000 // 100ms + + +// Commands for writing (page programming) +// Only single/octal mode supported with this memory +// So only single 1-1-1 mode in this QSPI config +#define QSPI_CMD_WRITE_1IO 0x02 // 1-1-1 mode +// write operations max time [us] (datasheet max time + 15%) +#define QSPI_PAGE_PROG_MAX_TIME 11500 // 10ms + +#define QSPI_PAGE_SIZE 256 // 256B +#define QSPI_SECTOR_SIZE 4096 // 4kB +#define QSPI_SECTOR_COUNT 131072 // 512MB / QSPI_SECTOR_SIZE + +// Commands for reading +// Only single/octal mode supported with this memory +// So only single 1-1-1 mode in this QSPI config +#define QSPI_CMD_READ_1IO_FAST 0x0B // 1-1-1 mode +#define QSPI_CMD_READ_1IO 0x03 // 1-1-1 mode + +#define QSPI_READ_1IO_DUMMY_CYCLE 0 +#define QSPI_READ_FAST_DUMMY_CYCLE 8 + +// Commands for erasing +#define QSPI_CMD_ERASE_SECTOR 0x20 // 4kB +//#define QSPI_CMD_ERASE_BLOCK_32 // not supported +#define QSPI_CMD_ERASE_BLOCK_64 0xD8 // 64kB +#define QSPI_CMD_ERASE_CHIP 0x60 // or 0xC7 + +// erase operations max time [us] (datasheet max time + 15%) +#define QSPI_ERASE_SECTOR_MAX_TIME 480000 // 400 ms +#define QSPI_ERASE_BLOCK_64_MAX_TIME 2400000 // 2s + +// max frequency for basic rw operation (for fast mode) +#define QSPI_COMMON_MAX_FREQUENCY 66000000 + +#define QSPI_STATUS_REG_SIZE 1 +#define QSPI_CONFIG_REG_0_SIZE 1 +#define QSPI_CONFIG_REG_1_SIZE 12 +#define QSPI_SECURITY_REG_SIZE 1 +#define QSPI_MAX_REG_SIZE 12 + +// status register +#define STATUS_BIT_WIP (1 << 0) // write in progress bit +#define STATUS_BIT_WEL (1 << 1) // write enable latch +#define STATUS_BIT_BP0 (1 << 2) // +#define STATUS_BIT_BP1 (1 << 3) // +#define STATUS_BIT_BP2 (1 << 4) // +#define STATUS_BIT_BP3 (1 << 5) // + +#endif // MBED_QSPI_FLASH_MX25LM51245G_H diff --git a/hal/tests/TESTS/mbed_hal/qspi/flash_configs/MX25RXX35F_config.h b/hal/tests/TESTS/mbed_hal/qspi/flash_configs/MX25RXX35F_config.h new file mode 100644 index 0000000..0119c4f --- /dev/null +++ b/hal/tests/TESTS/mbed_hal/qspi/flash_configs/MX25RXX35F_config.h @@ -0,0 +1,255 @@ +/* mbed Microcontroller Library + * Copyright (c) 2018-2018 ARM Limited + * 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. + */ +#ifndef MBED_QSPI_FLASH_MX25RXX35F_H +#define MBED_QSPI_FLASH_MX25RXX35F_H + + +#define QSPI_FLASH_CHIP_STRING "macronix MX25RXX35F" + +// Command for reading status register +#define QSPI_CMD_RDSR 0x05 +// Command for reading configuration register +#define QSPI_CMD_RDCR0 0x15 +// Command for writing status/configuration register +#define QSPI_CMD_WRSR 0x01 +// Command for reading security register +#define QSPI_CMD_RDSCUR 0x2B + +// Command for setting Reset Enable +#define QSPI_CMD_RSTEN 0x66 +// Command for setting Reset +#define QSPI_CMD_RST 0x99 + +// Command for setting write enable +#define QSPI_CMD_WREN 0x06 +// Command for setting write disable +#define QSPI_CMD_WRDI 0x04 + +// WRSR operations max time [us] (datasheet max time + 15%) +#define QSPI_WRSR_MAX_TIME 34500 // 30ms +// general wait max time [us] +#define QSPI_WAIT_MAX_TIME 100000 // 100ms + + +// Commands for writing (page programming) +#define QSPI_CMD_WRITE_1IO 0x02 // 1-1-1 mode +#define QSPI_CMD_WRITE_4IO 0x38 // 1-4-4 mode + +// write operations max time [us] (datasheet max time + 15%) +#define QSPI_PAGE_PROG_MAX_TIME 11500 // 10ms + +#define QSPI_PAGE_SIZE 256 // 256B +#define QSPI_SECTOR_SIZE 4096 // 4kB +#define QSPI_SECTOR_COUNT 32 // adjusted to MX25R1035F smallest one from MX25RXX35F family + +// Commands for reading +#define QSPI_CMD_READ_1IO_FAST 0x0B // 1-1-1 mode +#define QSPI_CMD_READ_1IO 0x03 // 1-1-1 mode +#define QSPI_CMD_READ_2IO 0xBB // 1-2-2 mode +#define QSPI_CMD_READ_1I2O 0x3B // 1-1-2 mode +#define QSPI_CMD_READ_4IO 0xEB // 1-4-4 mode +#define QSPI_CMD_READ_1I4O 0x6B // 1-1-4 mode + +#define QSPI_READ_1IO_DUMMY_CYCLE 0 +#define QSPI_READ_FAST_DUMMY_CYCLE 8 +#define QSPI_READ_2IO_DUMMY_CYCLE 4 +#define QSPI_READ_1I2O_DUMMY_CYCLE 8 +#define QSPI_READ_4IO_DUMMY_CYCLE 6 +#define QSPI_READ_1I4O_DUMMY_CYCLE 8 + +// Commands for erasing +#define QSPI_CMD_ERASE_SECTOR 0x20 // 4kB +#define QSPI_CMD_ERASE_BLOCK_32 0x52 // 32kB +#define QSPI_CMD_ERASE_BLOCK_64 0xD8 // 64kB +#define QSPI_CMD_ERASE_CHIP 0x60 // or 0xC7 + +// erase operations max time [us] (datasheet max time + 15%) +#define QSPI_ERASE_SECTOR_MAX_TIME 276000 // 240 ms +#define QSPI_ERASE_BLOCK_32_MAX_TIME 3450000 // 3s +#define QSPI_ERASE_BLOCK_64_MAX_TIME 4025000 // 3.5s + +// max frequency for basic rw operation (for fast mode) +#define QSPI_COMMON_MAX_FREQUENCY 32000000 + +#define QSPI_STATUS_REG_SIZE 1 +#define QSPI_CONFIG_REG_0_SIZE 2 +#define QSPI_SECURITY_REG_SIZE 1 +#define QSPI_MAX_REG_SIZE 2 + +// status register +#define STATUS_BIT_WIP (1 << 0) // write in progress bit +#define STATUS_BIT_WEL (1 << 1) // write enable latch +#define STATUS_BIT_BP0 (1 << 2) // +#define STATUS_BIT_BP1 (1 << 3) // +#define STATUS_BIT_BP2 (1 << 4) // +#define STATUS_BIT_BP3 (1 << 5) // +#define STATUS_BIT_QE (1 << 6) // Quad Enable +#define STATUS_BIT_SRWD (1 << 7) // status register write protect + +// configuration register 0 +// bit 0, 1, 2, 4, 5, 7 reserved +#define CONFIG0_BIT_TB (1 << 3) // Top/Bottom area protect +#define CONFIG0_BIT_DC (1 << 6) // Dummy Cycle + +// configuration register 1 +// bit 0, 2, 3, 4, 5, 6, 7 reserved +#define CONFIG1_BIT_LH (1 << 1) // 0 = Ultra Low power mode, 1 = High performance mode + + + +#define EXTENDED_SPI_ENABLE() \ + \ + const int32_t reg_size = QSPI_STATUS_REG_SIZE + QSPI_CONFIG_REG_0_SIZE; \ + uint8_t reg_data[reg_size] = { 0 }; \ + \ + if (read_register(STATUS_REG, reg_data, \ + QSPI_STATUS_REG_SIZE, qspi) != QSPI_STATUS_OK) { \ + return QSPI_STATUS_ERROR; \ + } \ + if (read_register(CONFIG_REG0, reg_data + QSPI_STATUS_REG_SIZE, \ + QSPI_CONFIG_REG_0_SIZE, qspi) != QSPI_STATUS_OK) { \ + return QSPI_STATUS_ERROR; \ + } \ + \ + if (write_enable(qspi) != QSPI_STATUS_OK) { \ + return QSPI_STATUS_ERROR; \ + } \ + \ + reg_data[0] = STATUS_BIT_QE; \ + if (write_register(QSPI_CMD_WRSR, reg_data, \ + reg_size, qspi) != QSPI_STATUS_OK) { \ + return QSPI_STATUS_ERROR; \ + } \ + WAIT_FOR(WRSR_MAX_TIME, qspi); \ + \ + memset(reg_data, 0, QSPI_STATUS_REG_SIZE); \ + if (read_register(STATUS_REG, reg_data, \ + QSPI_STATUS_REG_SIZE, qspi) != QSPI_STATUS_OK) { \ + return QSPI_STATUS_ERROR; \ + } \ + \ + return ((reg_data[0] & STATUS_BIT_QE) != 0 ? \ + QSPI_STATUS_OK : QSPI_STATUS_ERROR) + + + +#define EXTENDED_SPI_DISABLE() \ + \ + const int32_t reg_size = QSPI_STATUS_REG_SIZE + QSPI_CONFIG_REG_0_SIZE; \ + uint8_t reg_data[reg_size] = { 0 }; \ + \ + if (read_register(STATUS_REG, reg_data, \ + QSPI_STATUS_REG_SIZE, qspi) != QSPI_STATUS_OK) { \ + return QSPI_STATUS_ERROR; \ + } \ + if (read_register(CONFIG_REG0, reg_data + QSPI_STATUS_REG_SIZE, \ + QSPI_CONFIG_REG_0_SIZE, qspi) != QSPI_STATUS_OK) { \ + return QSPI_STATUS_ERROR; \ + } \ + \ + if (write_enable(qspi) != QSPI_STATUS_OK) { \ + return QSPI_STATUS_ERROR; \ + } \ + \ + reg_data[0] &= ~(STATUS_BIT_QE); \ + \ + if (write_register(QSPI_CMD_WRSR, reg_data, \ + reg_size, qspi) != QSPI_STATUS_OK) { \ + return QSPI_STATUS_ERROR; \ + } \ + WAIT_FOR(WRSR_MAX_TIME, qspi); \ + \ + reg_data[0] = 0; \ + if (read_register(STATUS_REG, reg_data, \ + QSPI_STATUS_REG_SIZE, qspi) != QSPI_STATUS_OK) { \ + return QSPI_STATUS_ERROR; \ + } \ + \ + return ((reg_data[0] & STATUS_BIT_QE) == 0 ? \ + QSPI_STATUS_OK : QSPI_STATUS_ERROR) + + + +#define FAST_MODE_ENABLE() \ + \ + const int32_t reg_size = QSPI_STATUS_REG_SIZE + QSPI_CONFIG_REG_0_SIZE; \ + uint8_t reg_data[reg_size]; \ + \ + if (read_register(STATUS_REG, reg_data, \ + QSPI_STATUS_REG_SIZE, qspi) != QSPI_STATUS_OK) { \ + return QSPI_STATUS_ERROR; \ + } \ + if (read_register(CONFIG_REG0, reg_data + QSPI_STATUS_REG_SIZE, \ + QSPI_CONFIG_REG_0_SIZE, qspi) != QSPI_STATUS_OK) { \ + return QSPI_STATUS_ERROR; \ + } \ + \ + if (write_enable(qspi) != QSPI_STATUS_OK) { \ + return QSPI_STATUS_ERROR; \ + } \ + \ + reg_data[2] |= CONFIG1_BIT_LH; \ + if (write_register(QSPI_CMD_WRSR, reg_data, \ + reg_size, qspi) != QSPI_STATUS_OK) { \ + return QSPI_STATUS_ERROR; \ + } \ + WAIT_FOR(WRSR_MAX_TIME, qspi); \ + \ + if (read_register(CONFIG_REG0, reg_data, \ + QSPI_CONFIG_REG_0_SIZE, qspi) != QSPI_STATUS_OK) { \ + return QSPI_STATUS_ERROR; \ + } \ + \ + return ((reg_data[1] & CONFIG1_BIT_LH) != 0 ? \ + QSPI_STATUS_OK : QSPI_STATUS_ERROR) + + +#define FAST_MODE_DISABLE() \ + \ + const int32_t reg_size = QSPI_STATUS_REG_SIZE + QSPI_CONFIG_REG_0_SIZE; \ + uint8_t reg_data[reg_size]; \ + \ + if (read_register(STATUS_REG, reg_data, \ + QSPI_STATUS_REG_SIZE, qspi) != QSPI_STATUS_OK) { \ + return QSPI_STATUS_ERROR; \ + } \ + if (read_register(CONFIG_REG0, reg_data + QSPI_STATUS_REG_SIZE, \ + QSPI_CONFIG_REG_0_SIZE, qspi) != QSPI_STATUS_OK) { \ + return QSPI_STATUS_ERROR; \ + } \ + \ + if (write_enable(qspi) != QSPI_STATUS_OK) { \ + return QSPI_STATUS_ERROR; \ + } \ + \ + reg_data[2] &= ~(CONFIG1_BIT_LH); \ + if (write_register(QSPI_CMD_WRSR, reg_data, \ + reg_size, qspi) != QSPI_STATUS_OK) { \ + return QSPI_STATUS_ERROR; \ + } \ + WAIT_FOR(WRSR_MAX_TIME, qspi); \ + \ + if (read_register(CONFIG_REG0, reg_data, \ + QSPI_CONFIG_REG_0_SIZE, qspi) != QSPI_STATUS_OK) { \ + return QSPI_STATUS_ERROR; \ + } \ + \ + return ((reg_data[1] & CONFIG1_BIT_LH) == 0 ? \ + QSPI_STATUS_OK : QSPI_STATUS_ERROR) + + +#endif // MBED_QSPI_FLASH_MX25RXX35F_H diff --git a/hal/tests/TESTS/mbed_hal/qspi/flash_configs/N25Q128A_config.h b/hal/tests/TESTS/mbed_hal/qspi/flash_configs/N25Q128A_config.h new file mode 100644 index 0000000..30c3bc2 --- /dev/null +++ b/hal/tests/TESTS/mbed_hal/qspi/flash_configs/N25Q128A_config.h @@ -0,0 +1,283 @@ +/* mbed Microcontroller Library + * Copyright (c) 2018-2018 ARM Limited + * 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. + */ +#ifndef MBED_QSPI_FLASH_N25Q128A_H +#define MBED_QSPI_FLASH_N25Q128A_H + + +#define QSPI_FLASH_CHIP_STRING "Micron N25Q128A" + +// Command for reading status register +#define QSPI_CMD_RDSR 0x05 +// Command for reading configuration register 0 (NONVOLATILE CONFIGURATION REGISTER) +#define QSPI_CMD_RDCR0 0xB5 +// Command for reading configuration register 1 (VOLATILE CONFIGURATION REGISTER) +#define QSPI_CMD_RDCR1 0x85 +// Command for reading configuration register 2 (ENHANCED VOLATILE CONFIGURATION REGISTER) +#define QSPI_CMD_RDCR2 0x65 +// Command for writing status +#define QSPI_CMD_WRSR 0x01 +// Command for writing configuration register 0 (NONVOLATILE CONFIGURATION REGISTER) +#define QSPI_CMD_WRCR0 0xB1 +// Command for writing configuration register 1 (VOLATILE CONFIGURATION REGISTER) +#define QSPI_CMD_WRCR1 0x81 +// Command for writing configuration register 2 (ENHANCED VOLATILE CONFIGURATION REGISTER) +#define QSPI_CMD_WRCR2 0x61 +// Command for reading security register +#define QSPI_CMD_RDSCUR 0x2B + +// Command for setting Reset Enable +#define QSPI_CMD_RSTEN 0x66 +// Command for setting Reset +#define QSPI_CMD_RST 0x99 + +// Command for setting write enable +#define QSPI_CMD_WREN 0x06 +// Command for setting write disable +#define QSPI_CMD_WRDI 0x04 + +// WRSR operations max time [us] (datasheet max time + 15%) +#define QSPI_WRSR_MAX_TIME 9200 // 8ms +// general wait max time [us] +#define QSPI_WAIT_MAX_TIME 100000 // 100ms + + +// Commands for writing (page programming) +#define QSPI_CMD_WRITE_1IO 0x02 // 1-1-1 mode +#define QSPI_CMD_WRITE_2IO 0xD2 // 1-2-2 mode +#define QSPI_CMD_WRITE_4IO 0x12 // 1-4-4 mode +#define QSPI_CMD_WRITE_DPI 0xD2 // 2-2-2 mode +#define QSPI_CMD_WRITE_QPI 0x12 // 4-4-4 mode + +// write operations max time [us] (datasheet max time + 15%) +#define QSPI_PAGE_PROG_MAX_TIME 5750 // 5ms + +#define QSPI_PAGE_SIZE 256 // 256B +#define QSPI_SECTOR_SIZE 4096 // 4kB +#define QSPI_SECTOR_COUNT 4096 + +// Commands for reading +#define QSPI_CMD_READ_1IO_FAST 0x0B // 1-1-1 mode +#define QSPI_CMD_READ_1IO 0x03 // 1-1-1 mode +#define QSPI_CMD_READ_2IO 0xBB // 1-2-2 mode +#define QSPI_CMD_READ_DPI 0xBB // 2-2-2 mode +#define QSPI_CMD_READ_1I2O 0x3B // 1-1-2 mode +#define QSPI_CMD_READ_4IO 0xEB // 1-4-4 mode +#define QSPI_CMD_READ_QPI 0xEB // 4-4-4 mode +#define QSPI_CMD_READ_1I4O 0x6B // 1-1-4 mode + + +#define QSPI_READ_1IO_DUMMY_CYCLE 0 +#define QSPI_READ_FAST_DUMMY_CYCLE 8 +// 8 dummy (10 dummy when quad SPI protocol is enabled) +#define QSPI_READ_2IO_DUMMY_CYCLE 8 +#define QSPI_READ_1I2O_DUMMY_CYCLE 8 +#define QSPI_READ_4IO_DUMMY_CYCLE 10 +#define QSPI_READ_1I4O_DUMMY_CYCLE 8 + +// Commands for erasing +#define QSPI_CMD_ERASE_SECTOR 0x20 // 4kB +#define QSPI_CMD_ERASE_BLOCK_32 0x52 // 32kB +#define QSPI_CMD_ERASE_BLOCK_64 0xD8 // 64kB +#define QSPI_CMD_ERASE_CHIP 0x60 // or 0xC7 + +// erase operations max time [us] (datasheet max time + 15%) +#define QSPI_ERASE_SECTOR_MAX_TIME 920000 // 0.8s +#define QSPI_ERASE_BLOCK_32_MAX_TIME 3000000 // 3s +#define QSPI_ERASE_BLOCK_64_MAX_TIME 3500000 // 3.5s + +// max frequency for basic rw operation +#define QSPI_COMMON_MAX_FREQUENCY 50000000 + +#define QSPI_STATUS_REG_SIZE 1 +#define QSPI_CONFIG_REG_0_SIZE 2 +#define QSPI_CONFIG_REG_1_SIZE 1 +#define QSPI_CONFIG_REG_2_SIZE 1 +#define QSPI_MAX_REG_SIZE 2 + +// status register +#define STATUS_BIT_WIP (1 << 0) // write in progress bit +#define STATUS_BIT_WEL (1 << 1) // write enable latch +#define STATUS_BIT_BP0 (1 << 2) // block +#define STATUS_BIT_BP1 (1 << 3) // +#define STATUS_BIT_BP2 (1 << 4) // +#define STATUS_BIT_BP_TB (1 << 5) // Block protect top/bottom +#define STATUS_BIT_BP3 (1 << 6) // +#define STATUS_BIT_SRWD (1 << 7) // status register write protect + +// configuration register 0 (Nonvolatile Configuration Register) +// bit 1, 5, reserved +#define CONFIG0_BIT_LOCK (1 << 0) // Lock nonvolatile configuration register +#define CONFIG0_BIT_DE (1 << 2) // Dual Enable 0 = Enabled / 1 = Disabled +#define CONFIG0_BIT_QE (1 << 3) // Quad Enable 0 = Enabled / 1 = Disabled +#define CONFIG0_BIT_RH (1 << 4) // Reset/hold +#define CONFIG0_BIT_ODS0 (1 << 6) // Output driver strength +#define CONFIG0_BIT_ODS1 (1 << 7) // Output driver strength +#define CONFIG0_BIT_ODS2 (1 << 8) // Output driver strength +#define CONFIG0_BIT_XIP_MODE0 (1 << 9) // XIP mode at power-on reset +#define CONFIG0_BIT_XIP_MODE1 (1 << 10) // XIP mode at power-on reset +#define CONFIG0_BIT_XIP_MODE2 (1 << 11) // XIP mode at power-on reset +#define CONFIG0_BIT_DCYCLE0 (1 << 12) // Dummy Cycle +#define CONFIG0_BIT_DCYCLE1 (1 << 13) // Dummy Cycle +#define CONFIG0_BIT_DCYCLE2 (1 << 14) // Dummy Cycle +#define CONFIG0_BIT_DCYCLE3 (1 << 15) // Dummy Cycle +#define CONFIG0_BITS_DEFAULT 0xFFFF // reg default state + + +// configuration register 1 (Volatile Configuration Register) +// bit 2, reserved +#define CONFIG1_BIT_WRAP0 (1 << 0) // Output data wrap +#define CONFIG1_BIT_WRAP1 (1 << 1) // Output data wrap +#define CONFIG1_BIT_XIP (1 << 3) // 0 = Enable / 1 = Disable (default) +#define CONFIG1_BIT_DCYCLE0 (1 << 4) // Number of dummy clock cycles +#define CONFIG1_BIT_DCYCLE1 (1 << 5) // Number of dummy clock cycles +#define CONFIG1_BIT_DCYCLE2 (1 << 6) // Number of dummy clock cycles +#define CONFIG1_BIT_DCYCLE3 (1 << 7) // Number of dummy clock cycles +#define CONFIG1_BITS_DEFAULT 0xB // reg default state + + +// configuration register 2 (Enhanced Volatile Configuration Register) +// bit 5, reserved +#define CONFIG2_BIT_ODS0 (1 << 0) // Output driver strength 111 = 30 Ohms (Default) +#define CONFIG2_BIT_ODS1 (1 << 1) // Output driver strength +#define CONFIG2_BIT_ODS2 (1 << 2) // Output driver strength +#define CONFIG2_BIT_VPP (1 << 3) // VPP accelerator 1 = Disabled (Default) +#define CONFIG2_BIT_RH (1 << 4) // Reset/hold +#define CONFIG2_BIT_DE (1 << 6) // Dual I/O protocol 0 = Enabled / 1 = Disabled (Default, extended SPI protocol) +#define CONFIG2_BIT_QE (1 << 7) // Quad I/O protocol 0 = Enabled / 1 = Disabled (Default, extended SPI protocol) +#define CONFIG2_BITS_DEFAULT 0xDF // reg default state + + +#define DUAL_ENABLE() \ + \ + uint8_t reg_data[QSPI_CONFIG_REG_2_SIZE]; \ + \ + memset(reg_data, 0, QSPI_CONFIG_REG_2_SIZE); \ + if (read_register(QSPI_CMD_RDCR2, reg_data, \ + QSPI_CONFIG_REG_2_SIZE, qspi) != QSPI_STATUS_OK) { \ + return QSPI_STATUS_ERROR; \ + } \ + if (write_enable(qspi) != QSPI_STATUS_OK) { \ + return QSPI_STATUS_ERROR; \ + } \ + \ + reg_data[0] = reg_data[0] & ~(CONFIG2_BIT_DE); \ + if (write_register(QSPI_CMD_WRCR2, reg_data, \ + QSPI_CONFIG_REG_2_SIZE, qspi) != QSPI_STATUS_OK) { \ + return QSPI_STATUS_ERROR; \ + } \ + qspi.cmd.configure(MODE_2_2_2, ADDR_SIZE_24, ALT_SIZE_8); \ + WAIT_FOR(WRSR_MAX_TIME, qspi); \ + memset(reg_data, 0, QSPI_CONFIG_REG_2_SIZE); \ + if (read_register(QSPI_CMD_RDCR2, reg_data, \ + QSPI_CONFIG_REG_2_SIZE, qspi) != QSPI_STATUS_OK) { \ + return QSPI_STATUS_ERROR; \ + } \ + \ + return ((reg_data[0] & (CONFIG2_BIT_DE)) == 0 ? \ + QSPI_STATUS_OK : QSPI_STATUS_ERROR) + + +#define DUAL_DISABLE() \ + \ + uint8_t reg_data[QSPI_CONFIG_REG_2_SIZE]; \ + \ + memset(reg_data, 0, QSPI_CONFIG_REG_2_SIZE); \ + if (read_register(QSPI_CMD_RDCR2, reg_data, \ + QSPI_CONFIG_REG_2_SIZE, qspi) != QSPI_STATUS_OK) { \ + return QSPI_STATUS_ERROR; \ + } \ + if (write_enable(qspi) != QSPI_STATUS_OK) { \ + return QSPI_STATUS_ERROR; \ + } \ + \ + reg_data[0] = reg_data[0] | (CONFIG2_BIT_DE); \ + if (write_register(QSPI_CMD_WRCR2, reg_data, \ + QSPI_CONFIG_REG_2_SIZE, qspi) != QSPI_STATUS_OK) { \ + return QSPI_STATUS_ERROR; \ + } \ + WAIT_FOR(WRSR_MAX_TIME, qspi); \ + qspi.cmd.configure(MODE_1_1_1, ADDR_SIZE_24, ALT_SIZE_8); \ + memset(reg_data, 0, QSPI_CONFIG_REG_2_SIZE); \ + if (read_register(QSPI_CMD_RDCR2, reg_data, \ + QSPI_CONFIG_REG_2_SIZE, qspi) != QSPI_STATUS_OK) { \ + return QSPI_STATUS_ERROR; \ + } \ + \ + return ((reg_data[0] & CONFIG2_BIT_DE) != 1 ? \ + QSPI_STATUS_OK : QSPI_STATUS_ERROR) + + +#define QUAD_ENABLE() \ + \ + uint8_t reg_data[QSPI_CONFIG_REG_2_SIZE]; \ + \ + memset(reg_data, 0, QSPI_CONFIG_REG_2_SIZE); \ + if (read_register(QSPI_CMD_RDCR2, reg_data, \ + QSPI_CONFIG_REG_2_SIZE, qspi) != QSPI_STATUS_OK) { \ + return QSPI_STATUS_ERROR; \ + } \ + if (write_enable(qspi) != QSPI_STATUS_OK) { \ + return QSPI_STATUS_ERROR; \ + } \ + \ + reg_data[0] = reg_data[0] & ~(CONFIG2_BIT_QE); \ + if (write_register(QSPI_CMD_WRCR2, reg_data, \ + QSPI_CONFIG_REG_2_SIZE, qspi) != QSPI_STATUS_OK) { \ + return QSPI_STATUS_ERROR; \ + } \ + qspi.cmd.configure(MODE_4_4_4, ADDR_SIZE_24, ALT_SIZE_8); \ + WAIT_FOR(WRSR_MAX_TIME, qspi); \ + memset(reg_data, 0, QSPI_CONFIG_REG_2_SIZE); \ + if (read_register(QSPI_CMD_RDCR2, reg_data, \ + QSPI_CONFIG_REG_2_SIZE, qspi) != QSPI_STATUS_OK) { \ + return QSPI_STATUS_ERROR; \ + } \ + \ + return ((reg_data[0] & (CONFIG2_BIT_QE)) == 0 ? \ + QSPI_STATUS_OK : QSPI_STATUS_ERROR) + + +#define QUAD_DISABLE() \ + \ + uint8_t reg_data[QSPI_CONFIG_REG_2_SIZE]; \ + \ + memset(reg_data, 0, QSPI_CONFIG_REG_2_SIZE); \ + if (read_register(QSPI_CMD_RDCR2, reg_data, \ + QSPI_CONFIG_REG_2_SIZE, qspi) != QSPI_STATUS_OK) { \ + return QSPI_STATUS_ERROR; \ + } \ + if (write_enable(qspi) != QSPI_STATUS_OK) { \ + return QSPI_STATUS_ERROR; \ + } \ + \ + reg_data[0] = reg_data[0] | (CONFIG2_BIT_QE); \ + if (write_register(QSPI_CMD_WRCR2, reg_data, \ + QSPI_CONFIG_REG_2_SIZE, qspi) != QSPI_STATUS_OK) { \ + return QSPI_STATUS_ERROR; \ + } \ + WAIT_FOR(WRSR_MAX_TIME, qspi); \ + qspi.cmd.configure(MODE_1_1_1, ADDR_SIZE_24, ALT_SIZE_8); \ + memset(reg_data, 0, QSPI_CONFIG_REG_2_SIZE); \ + if (read_register(QSPI_CMD_RDCR2, reg_data, \ + QSPI_CONFIG_REG_2_SIZE, qspi) != QSPI_STATUS_OK) { \ + return QSPI_STATUS_ERROR; \ + } \ + \ + return ((reg_data[0] & CONFIG2_BIT_QE) != 1 ? \ + QSPI_STATUS_OK : QSPI_STATUS_ERROR) + +#endif // MBED_QSPI_FLASH_N25Q128A_H diff --git a/hal/tests/TESTS/mbed_hal/qspi/flash_configs/NORDIC/EP_AGORA/flash_config.h b/hal/tests/TESTS/mbed_hal/qspi/flash_configs/NORDIC/EP_AGORA/flash_config.h new file mode 100644 index 0000000..8fba66e --- /dev/null +++ b/hal/tests/TESTS/mbed_hal/qspi/flash_configs/NORDIC/EP_AGORA/flash_config.h @@ -0,0 +1,38 @@ +/* mbed Microcontroller Library + * Copyright (c) 2018-2018 ARM Limited + * 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. + */ +#ifndef MBED_QSPI_FLASH_CONFIG_H +#define MBED_QSPI_FLASH_CONFIG_H + +#include "../../W25Q32JV_config.h" + +// NRF doesn't uses read/write opcodes, instead it uses commands id's. +// Before sending it to H/W opcodes are mapped to id's in Mbed hal qspi implementation +// +// for more details see: +// targets\TARGET_NORDIC\TARGET_NRF5x\TARGET_SDK_15_0\modules\nrfx\mdk\nrf52840_bitfields.h +// targets\TARGET_NORDIC\TARGET_NRF5x\qspi_api.c + +// NRF doesn't support read 1IO (opcode 0x03) +#undef QSPI_CMD_READ_1IO +#define QSPI_CMD_READ_1IO QSPI_CMD_READ_1IO_FAST + +#ifdef QSPI_SECTOR_COUNT +#undef QSPI_SECTOR_COUNT +#define QSPI_SECTOR_COUNT 1024 // for W25Q32JV +#endif + +#endif // MBED_QSPI_FLASH_CONFIG_H diff --git a/hal/tests/TESTS/mbed_hal/qspi/flash_configs/NORDIC/NRF52840_DK/flash_config.h b/hal/tests/TESTS/mbed_hal/qspi/flash_configs/NORDIC/NRF52840_DK/flash_config.h new file mode 100644 index 0000000..bda5464 --- /dev/null +++ b/hal/tests/TESTS/mbed_hal/qspi/flash_configs/NORDIC/NRF52840_DK/flash_config.h @@ -0,0 +1,38 @@ +/* mbed Microcontroller Library + * Copyright (c) 2018-2018 ARM Limited + * 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. + */ +#ifndef MBED_QSPI_FLASH_CONFIG_H +#define MBED_QSPI_FLASH_CONFIG_H + +#include "../../MX25RXX35F_config.h" + +// NRF doesn't uses read/write opcodes, instead it uses commands id's. +// Before sending it to H/W opcodes are mapped to id's in Mbed hal qspi implementation +// +// for more details see: +// targets\TARGET_NORDIC\TARGET_NRF5x\TARGET_SDK_14_2\device\nrf52840_bitfields.h +// targets\TARGET_NORDIC\TARGET_NRF5x\qspi_api.c + +// NRF doesn't support read 1IO (opcode 0x03) +#undef QSPI_CMD_READ_1IO +#define QSPI_CMD_READ_1IO QSPI_CMD_READ_1IO_FAST + +#ifdef QSPI_SECTOR_COUNT +#undef QSPI_SECTOR_COUNT +#define QSPI_SECTOR_COUNT 2048 // for MX25R6435F +#endif + +#endif // MBED_QSPI_FLASH_CONFIG_H diff --git a/hal/tests/TESTS/mbed_hal/qspi/flash_configs/NXP/K82F/flash_config.h b/hal/tests/TESTS/mbed_hal/qspi/flash_configs/NXP/K82F/flash_config.h new file mode 100644 index 0000000..f0e25fd --- /dev/null +++ b/hal/tests/TESTS/mbed_hal/qspi/flash_configs/NXP/K82F/flash_config.h @@ -0,0 +1,119 @@ +/* mbed Microcontroller Library + * Copyright (c) 2018-2018 ARM Limited + * 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. + */ +#ifndef MBED_QSPI_FLASH_CONFIG_H +#define MBED_QSPI_FLASH_CONFIG_H + +#include "../../MX25RXX35F_config.h" + +/* Fast mode not supported in MX25U3235F */ +#undef FAST_MODE_ENABLE +#undef FAST_MODE_DISABLE + +#ifdef QSPI_SECTOR_COUNT +#undef QSPI_SECTOR_COUNT +#define QSPI_SECTOR_COUNT 1024 // for MX25U3235F +#endif + +/* The values for MX25U3235F are different, specify this here */ +#undef QSPI_COMMON_MAX_FREQUENCY +#undef QSPI_WRSR_MAX_TIME +#undef QSPI_PAGE_PROG_MAX_TIME +#undef QSPI_ERASE_SECTOR_MAX_TIME +#undef QSPI_ERASE_BLOCK_32_MAX_TIME +#undef QSPI_ERASE_BLOCK_64_MAX_TIME + +/* Implementation of these macros are slightly different for MX25U3235F */ +#undef EXTENDED_SPI_ENABLE +#undef EXTENDED_SPI_DISABLE + +/* Max frequency for basic rw operation in MX25U3235F */ +#define QSPI_COMMON_MAX_FREQUENCY 54000000 + +/* WRSR operations max time [us] (datasheet max time + 15%) */ +#define QSPI_WRSR_MAX_TIME 46000 // 40ms + +/* Write operations max time [us] (datasheet max time + 15%) */ +#define QSPI_PAGE_PROG_MAX_TIME 3450 // 3ms + +/* erase operations max time [us] (datasheet max time + 15%) */ +#define QSPI_ERASE_SECTOR_MAX_TIME 230000 // 200 ms +#define QSPI_ERASE_BLOCK_32_MAX_TIME 1150000 // 1s +#define QSPI_ERASE_BLOCK_64_MAX_TIME 2300000 // 2s + +#define EXTENDED_SPI_ENABLE() \ + \ + const int32_t reg_size = QSPI_STATUS_REG_SIZE; \ + uint8_t reg_data[reg_size] = { 0 }; \ + \ + if (read_register(STATUS_REG, reg_data, \ + QSPI_STATUS_REG_SIZE, qspi) != QSPI_STATUS_OK) { \ + return QSPI_STATUS_ERROR; \ + } \ + if (write_enable(qspi) != QSPI_STATUS_OK) { \ + return QSPI_STATUS_ERROR; \ + } \ + \ + reg_data[0] = STATUS_BIT_QE; \ + if (write_register(QSPI_CMD_WRSR, reg_data, \ + reg_size, qspi) != QSPI_STATUS_OK) { \ + return QSPI_STATUS_ERROR; \ + } \ + WAIT_FOR(WRSR_MAX_TIME, qspi); \ + \ + memset(reg_data, 0, QSPI_STATUS_REG_SIZE); \ + if (read_register(STATUS_REG, reg_data, \ + QSPI_STATUS_REG_SIZE, qspi) != QSPI_STATUS_OK) { \ + return QSPI_STATUS_ERROR; \ + } \ + \ + return ((reg_data[0] & STATUS_BIT_QE) != 0 ? \ + QSPI_STATUS_OK : QSPI_STATUS_ERROR) + + + +#define EXTENDED_SPI_DISABLE() \ + \ + const int32_t reg_size = QSPI_STATUS_REG_SIZE; \ + uint8_t reg_data[reg_size] = { 0 }; \ + \ + if (read_register(STATUS_REG, reg_data, \ + QSPI_STATUS_REG_SIZE, qspi) != QSPI_STATUS_OK) { \ + return QSPI_STATUS_ERROR; \ + } \ + \ + if (write_enable(qspi) != QSPI_STATUS_OK) { \ + return QSPI_STATUS_ERROR; \ + } \ + \ + reg_data[0] &= ~(STATUS_BIT_QE); \ + \ + if (write_register(QSPI_CMD_WRSR, reg_data, \ + reg_size, qspi) != QSPI_STATUS_OK) { \ + return QSPI_STATUS_ERROR; \ + } \ + WAIT_FOR(WRSR_MAX_TIME, qspi); \ + \ + reg_data[0] = 0; \ + if (read_register(STATUS_REG, reg_data, \ + QSPI_STATUS_REG_SIZE, qspi) != QSPI_STATUS_OK) { \ + return QSPI_STATUS_ERROR; \ + } \ + \ + return ((reg_data[0] & STATUS_BIT_QE) == 0 ? \ + QSPI_STATUS_OK : QSPI_STATUS_ERROR) + +#endif // MBED_QSPI_FLASH_CONFIG_H diff --git a/hal/tests/TESTS/mbed_hal/qspi/flash_configs/NXP/LPC546XX/flash_config.h b/hal/tests/TESTS/mbed_hal/qspi/flash_configs/NXP/LPC546XX/flash_config.h new file mode 100644 index 0000000..d0e3541 --- /dev/null +++ b/hal/tests/TESTS/mbed_hal/qspi/flash_configs/NXP/LPC546XX/flash_config.h @@ -0,0 +1,22 @@ +/* mbed Microcontroller Library + * Copyright (c) 2018-2018 ARM Limited + * 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. + */ +#ifndef MBED_QSPI_FLASH_CONFIG_H +#define MBED_QSPI_FLASH_CONFIG_H + +#include "../../MT25Q_config.h" + +#endif // MBED_QSPI_FLASH_CONFIG_H diff --git a/hal/tests/TESTS/mbed_hal/qspi/flash_configs/S25FL128S_config.h b/hal/tests/TESTS/mbed_hal/qspi/flash_configs/S25FL128S_config.h new file mode 100644 index 0000000..01b1050 --- /dev/null +++ b/hal/tests/TESTS/mbed_hal/qspi/flash_configs/S25FL128S_config.h @@ -0,0 +1,191 @@ +/* mbed Microcontroller Library + * Copyright (c) 2018-2018 ARM Limited + * 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. + */ +#ifndef MBED_QSPI_FLASH_S25FL128S_H +#define MBED_QSPI_FLASH_S25FL128S_H + +#define QSPI_FLASH_CHIP_STRING "Cypress S25FL128S" +#define QSPI_FLASH_CYPRESS_S25FL128S + +// Command for reading configuration register +#define QSPI_CMD_RDCR0 0x35 // To read Quad (QE) enable bit +// Command for writing status/configuration register +#define QSPI_CMD_WRSR 0x01 // To write Qual (QE) enable bit +// Command for reading status register +#define QSPI_CMD_RDSR 0x05 // To read WIP bit of status register 1 + + + +// Command for reading security register +#define QSPI_CMD_RDSCUR 0x2B + +// Command for setting Reset Enable +#define QSPI_CMD_RSTEN 0x66 +// Command for setting Reset +#define QSPI_CMD_RST 0xF0 //0x99 + +// Command for setting write enable +#define QSPI_CMD_WREN 0x06 +// Command for setting write disable +#define QSPI_CMD_WRDI 0x04 + +// WRSR operations max time [us] (datasheet max time + 15%) +#define QSPI_WRSR_MAX_TIME 575000 // 575 ms +// general wait max time [us] +#define QSPI_WAIT_MAX_TIME 100000 // 100 ms + + +// Commands for writing (page programming) +#define QSPI_CMD_WRITE_1IO 0x02 // 1-1-1 mode +#define QSPI_CMD_WRITE_1I4O 0x32 // 1-1-4 mode // 1-4-4 is not supported by S25FL512S + +// write operations max time [us] (datasheet max time + 15%) +#define QSPI_PAGE_PROG_MAX_TIME 800 // 800 us + +#define QSPI_PAGE_SIZE 512 // 512B +#define QSPI_SECTOR_SIZE 262144 // 256kB +#define QSPI_SECTOR_COUNT 64 // 16 MB + +// Commands for reading +#define QSPI_CMD_READ_1IO_FAST 0x0B // 1-1-1 mode +#define QSPI_CMD_READ_1IO 0x03 // 1-1-1 mode +#define QSPI_CMD_READ_2IO 0xBB // 1-2-2 mode - dual I/O +#define QSPI_CMD_READ_1I2O 0x3B // 1-1-2 mode - dual output +#define QSPI_CMD_READ_4IO 0xEB // 1-4-4 mode - quad I/O +#define QSPI_CMD_READ_1I4O 0x6B // 1-1-4 mode - quad output + +// Alt (mode) value for quad I/O read +#define QSPI_ALT_READ_4IO 0x01 // 1-4-4 mode only + +#define QSPI_READ_1IO_DUMMY_CYCLE 0 +#define QSPI_READ_FAST_DUMMY_CYCLE 8 +#define QSPI_READ_2IO_DUMMY_CYCLE 4 // dual I/O +#define QSPI_READ_1I2O_DUMMY_CYCLE 8 // dual output +#define QSPI_READ_4IO_DUMMY_CYCLE 6 // quad I/O - 2 cycles for Mode or Alt (4 bits per cycle x 2 cycles = 1 byte) + 4 dummy cycles +#define QSPI_READ_1I4O_DUMMY_CYCLE 8 // quad output + +// Commands for erasing +#define QSPI_CMD_ERASE_SECTOR 0xD8 // 256kB +#define QSPI_CMD_ERASE_CHIP 0x60 // or 0xC7 + +// erase operations max time [us] (datasheet max time + 15%) +#define QSPI_ERASE_SECTOR_MAX_TIME 750000 // 1.15*650 ~ 750 ms + +// max frequency for basic rw operation (for fast mode) +#define QSPI_COMMON_MAX_FREQUENCY 50000000 + +#define QSPI_STATUS_REG_SIZE 1 +#define QSPI_CONFIG_REG_0_SIZE 1 +#define QSPI_SECURITY_REG_SIZE 1 +#define QSPI_MAX_REG_SIZE 2 + +// status register +#define STATUS_BIT_WIP (1 << 0) // write in progress bit +#define STATUS_BIT_WEL (1 << 1) // write enable latch +#define STATUS_BIT_BP0 (1 << 2) // +#define STATUS_BIT_BP1 (1 << 3) // +#define STATUS_BIT_BP2 (1 << 4) // +#define STATUS_BIT_BP3 (1 << 5) // +#define STATUS_BIT_QE (1 << 1) // Quad Enable +#define STATUS_BIT_SRWD (1 << 7) // status register write protect + +// configuration register 0 +// bit 0, 1, 2, 4, 5, 7 reserved +#define CONFIG0_BIT_TB (1 << 3) // Top/Bottom area protect +#define CONFIG0_BIT_DC (1 << 6) // Dummy Cycle + +// configuration register 1 +// bit 0, 2, 3, 4, 5, 6, 7 reserved +#define CONFIG1_BIT_LH (1 << 1) // 0 = Ultra Low power mode, 1 = High performance mode + + + +#define EXTENDED_SPI_ENABLE() \ + \ + const int32_t reg_size = QSPI_STATUS_REG_SIZE + QSPI_CONFIG_REG_0_SIZE; \ + uint8_t reg_data[reg_size] = { 0 }; \ + \ + if (read_register(STATUS_REG, reg_data, \ + QSPI_STATUS_REG_SIZE, qspi) != QSPI_STATUS_OK) { \ + return QSPI_STATUS_ERROR; \ + } \ + if (read_register(CONFIG_REG0, reg_data + QSPI_STATUS_REG_SIZE, \ + QSPI_CONFIG_REG_0_SIZE, qspi) != QSPI_STATUS_OK) { \ + return QSPI_STATUS_ERROR; \ + } \ + \ + if (write_enable(qspi) != QSPI_STATUS_OK) { \ + return QSPI_STATUS_ERROR; \ + } \ + \ + reg_data[1] |= STATUS_BIT_QE; \ + if (write_register(QSPI_CMD_WRSR, reg_data, \ + reg_size, qspi) != QSPI_STATUS_OK) { \ + return QSPI_STATUS_ERROR; \ + } \ + \ + WAIT_FOR(WRSR_MAX_TIME, qspi); \ + \ + memset(reg_data, 0, QSPI_STATUS_REG_SIZE); \ + if (read_register(CONFIG_REG0, reg_data, \ + QSPI_STATUS_REG_SIZE, qspi) != QSPI_STATUS_OK) { \ + return QSPI_STATUS_ERROR; \ + } \ + \ + return ((reg_data[0] & STATUS_BIT_QE) != 0 ? \ + QSPI_STATUS_OK : QSPI_STATUS_ERROR) + + + +#define EXTENDED_SPI_DISABLE() \ + \ + const int32_t reg_size = QSPI_STATUS_REG_SIZE + QSPI_CONFIG_REG_0_SIZE; \ + uint8_t reg_data[reg_size] = { 0 }; \ + \ + if (read_register(STATUS_REG, reg_data, \ + QSPI_STATUS_REG_SIZE, qspi) != QSPI_STATUS_OK) { \ + return QSPI_STATUS_ERROR; \ + } \ + \ + if (read_register(CONFIG_REG0, reg_data + QSPI_STATUS_REG_SIZE, \ + QSPI_CONFIG_REG_0_SIZE, qspi) != QSPI_STATUS_OK) { \ + return QSPI_STATUS_ERROR; \ + } \ + \ + if (write_enable(qspi) != QSPI_STATUS_OK) { \ + return QSPI_STATUS_ERROR; \ + } \ + \ + reg_data[1] &= ~(STATUS_BIT_QE); \ + \ + if (write_register(QSPI_CMD_WRSR, reg_data, \ + reg_size, qspi) != QSPI_STATUS_OK) { \ + return QSPI_STATUS_ERROR; \ + } \ + \ + WAIT_FOR(WRSR_MAX_TIME, qspi); \ + \ + reg_data[0] = 0; \ + if (read_register(CONFIG_REG0, reg_data, \ + QSPI_STATUS_REG_SIZE, qspi) != QSPI_STATUS_OK) { \ + return QSPI_STATUS_ERROR; \ + } \ + \ + return ((reg_data[0] & STATUS_BIT_QE) == 0 ? \ + QSPI_STATUS_OK : QSPI_STATUS_ERROR) + + +#endif // MBED_QSPI_FLASH_S25FL128S_H diff --git a/hal/tests/TESTS/mbed_hal/qspi/flash_configs/S25FL512S_config.h b/hal/tests/TESTS/mbed_hal/qspi/flash_configs/S25FL512S_config.h new file mode 100755 index 0000000..4b866c8 --- /dev/null +++ b/hal/tests/TESTS/mbed_hal/qspi/flash_configs/S25FL512S_config.h @@ -0,0 +1,191 @@ +/* mbed Microcontroller Library + * Copyright (c) 2018-2018 ARM Limited + * 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. + */ +#ifndef MBED_QSPI_FLASH_S25FL512S_H +#define MBED_QSPI_FLASH_S25FL512S_H + +#define QSPI_FLASH_CHIP_STRING "Cypress S25FL512S" +#define QSPI_FLASH_CYPRESS_S25FL512S + +// Command for reading configuration register +#define QSPI_CMD_RDCR0 0x35 // To read Quad (QE) enable bit +// Command for writing status/configuration register +#define QSPI_CMD_WRSR 0x01 // To write Qual (QE) enable bit +// Command for reading status register +#define QSPI_CMD_RDSR 0x05 // To read WIP bit of status register 1 + + + +// Command for reading security register +#define QSPI_CMD_RDSCUR 0x2B + +// Command for setting Reset Enable +#define QSPI_CMD_RSTEN 0x66 +// Command for setting Reset +#define QSPI_CMD_RST 0xF0 //0x99 + +// Command for setting write enable +#define QSPI_CMD_WREN 0x06 +// Command for setting write disable +#define QSPI_CMD_WRDI 0x04 + +// WRSR operations max time [us] (datasheet max time + 15%) +#define QSPI_WRSR_MAX_TIME 2300000 // 2.3 seconds +// general wait max time [us] +#define QSPI_WAIT_MAX_TIME 100000 // 100ms + + +// Commands for writing (page programming) +#define QSPI_CMD_WRITE_1IO 0x02 // 1-1-1 mode +#define QSPI_CMD_WRITE_1I4O 0x32 // 1-1-4 mode // 1-4-4 is not supported by S25FL512S + +// write operations max time [us] (datasheet max time + 15%) +#define QSPI_PAGE_PROG_MAX_TIME 1500 // 1.5ms + +#define QSPI_PAGE_SIZE 512 // 512B +#define QSPI_SECTOR_SIZE 262144 // 256kB +#define QSPI_SECTOR_COUNT 256 // 64 MB + +// Commands for reading +#define QSPI_CMD_READ_1IO_FAST 0x0B // 1-1-1 mode +#define QSPI_CMD_READ_1IO 0x03 // 1-1-1 mode +#define QSPI_CMD_READ_2IO 0xBB // 1-2-2 mode - dual I/O +#define QSPI_CMD_READ_1I2O 0x3B // 1-1-2 mode - dual output +#define QSPI_CMD_READ_4IO 0xEB // 1-4-4 mode - quad I/O +#define QSPI_CMD_READ_1I4O 0x6B // 1-1-4 mode - quad output + +// Alt (mode) value for quad I/O read +#define QSPI_ALT_READ_4IO 0x01 // 1-4-4 mode only + +#define QSPI_READ_1IO_DUMMY_CYCLE 0 +#define QSPI_READ_FAST_DUMMY_CYCLE 8 +#define QSPI_READ_2IO_DUMMY_CYCLE 4 // dual I/O +#define QSPI_READ_1I2O_DUMMY_CYCLE 8 // dual output +#define QSPI_READ_4IO_DUMMY_CYCLE 6 // quad I/O - 2 cycles for Mode or Alt (4 bits per cycle x 2 cycles = 1 byte) + 4 dummy cycles +#define QSPI_READ_1I4O_DUMMY_CYCLE 8 // quad output + +// Commands for erasing +#define QSPI_CMD_ERASE_SECTOR 0xD8 // 256kB +#define QSPI_CMD_ERASE_CHIP 0x60 // or 0xC7 + +// erase operations max time [us] (datasheet max time + 15%) +#define QSPI_ERASE_SECTOR_MAX_TIME 2990000 // 1.15*2600 ~ 2900 ms + +// max frequency for basic rw operation (for fast mode) +#define QSPI_COMMON_MAX_FREQUENCY 50000000 + +#define QSPI_STATUS_REG_SIZE 1 +#define QSPI_CONFIG_REG_0_SIZE 1 +#define QSPI_SECURITY_REG_SIZE 1 +#define QSPI_MAX_REG_SIZE 2 + +// status register +#define STATUS_BIT_WIP (1 << 0) // write in progress bit +#define STATUS_BIT_WEL (1 << 1) // write enable latch +#define STATUS_BIT_BP0 (1 << 2) // +#define STATUS_BIT_BP1 (1 << 3) // +#define STATUS_BIT_BP2 (1 << 4) // +#define STATUS_BIT_BP3 (1 << 5) // +#define STATUS_BIT_QE (1 << 1) // Quad Enable +#define STATUS_BIT_SRWD (1 << 7) // status register write protect + +// configuration register 0 +// bit 0, 1, 2, 4, 5, 7 reserved +#define CONFIG0_BIT_TB (1 << 3) // Top/Bottom area protect +#define CONFIG0_BIT_DC (1 << 6) // Dummy Cycle + +// configuration register 1 +// bit 0, 2, 3, 4, 5, 6, 7 reserved +#define CONFIG1_BIT_LH (1 << 1) // 0 = Ultra Low power mode, 1 = High performance mode + + + +#define EXTENDED_SPI_ENABLE() \ + \ + const int32_t reg_size = QSPI_STATUS_REG_SIZE + QSPI_CONFIG_REG_0_SIZE; \ + uint8_t reg_data[reg_size] = { 0 }; \ + \ + if (read_register(STATUS_REG, reg_data, \ + QSPI_STATUS_REG_SIZE, qspi) != QSPI_STATUS_OK) { \ + return QSPI_STATUS_ERROR; \ + } \ + if (read_register(CONFIG_REG0, reg_data + QSPI_STATUS_REG_SIZE, \ + QSPI_CONFIG_REG_0_SIZE, qspi) != QSPI_STATUS_OK) { \ + return QSPI_STATUS_ERROR; \ + } \ + \ + if (write_enable(qspi) != QSPI_STATUS_OK) { \ + return QSPI_STATUS_ERROR; \ + } \ + \ + reg_data[1] |= STATUS_BIT_QE; \ + if (write_register(QSPI_CMD_WRSR, reg_data, \ + reg_size, qspi) != QSPI_STATUS_OK) { \ + return QSPI_STATUS_ERROR; \ + } \ + \ + WAIT_FOR(WRSR_MAX_TIME, qspi); \ + \ + memset(reg_data, 0, QSPI_STATUS_REG_SIZE); \ + if (read_register(CONFIG_REG0, reg_data, \ + QSPI_STATUS_REG_SIZE, qspi) != QSPI_STATUS_OK) { \ + return QSPI_STATUS_ERROR; \ + } \ + \ + return ((reg_data[0] & STATUS_BIT_QE) != 0 ? \ + QSPI_STATUS_OK : QSPI_STATUS_ERROR) + + + +#define EXTENDED_SPI_DISABLE() \ + \ + const int32_t reg_size = QSPI_STATUS_REG_SIZE + QSPI_CONFIG_REG_0_SIZE; \ + uint8_t reg_data[reg_size] = { 0 }; \ + \ + if (read_register(STATUS_REG, reg_data, \ + QSPI_STATUS_REG_SIZE, qspi) != QSPI_STATUS_OK) { \ + return QSPI_STATUS_ERROR; \ + } \ + \ + if (read_register(CONFIG_REG0, reg_data + QSPI_STATUS_REG_SIZE, \ + QSPI_CONFIG_REG_0_SIZE, qspi) != QSPI_STATUS_OK) { \ + return QSPI_STATUS_ERROR; \ + } \ + \ + if (write_enable(qspi) != QSPI_STATUS_OK) { \ + return QSPI_STATUS_ERROR; \ + } \ + \ + reg_data[1] &= ~(STATUS_BIT_QE); \ + \ + if (write_register(QSPI_CMD_WRSR, reg_data, \ + reg_size, qspi) != QSPI_STATUS_OK) { \ + return QSPI_STATUS_ERROR; \ + } \ + \ + WAIT_FOR(WRSR_MAX_TIME, qspi); \ + \ + reg_data[0] = 0; \ + if (read_register(CONFIG_REG0, reg_data, \ + QSPI_STATUS_REG_SIZE, qspi) != QSPI_STATUS_OK) { \ + return QSPI_STATUS_ERROR; \ + } \ + \ + return ((reg_data[0] & STATUS_BIT_QE) == 0 ? \ + QSPI_STATUS_OK : QSPI_STATUS_ERROR) + + +#endif // MBED_QSPI_FLASH_S25FL512S_H diff --git a/hal/tests/TESTS/mbed_hal/qspi/flash_configs/S25FS512S_config.h b/hal/tests/TESTS/mbed_hal/qspi/flash_configs/S25FS512S_config.h new file mode 100644 index 0000000..6be35f5 --- /dev/null +++ b/hal/tests/TESTS/mbed_hal/qspi/flash_configs/S25FS512S_config.h @@ -0,0 +1,191 @@ +/* mbed Microcontroller Library + * Copyright (c) 2018-2018 ARM Limited + * 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. + */ +#ifndef MBED_QSPI_FLASH_S25FS512S_H +#define MBED_QSPI_FLASH_S25FS512S_H + +#define QSPI_FLASH_CHIP_STRING "Cypress S25FS512S" +#define QSPI_FLASH_CYPRESS_S25FS512S + +// Command for reading configuration register +#define QSPI_CMD_RDCR0 0x35 // To read Quad (QE) enable bit +// Command for writing status/configuration register +#define QSPI_CMD_WRSR 0x01 // To write Qual (QE) enable bit +// Command for reading status register +#define QSPI_CMD_RDSR 0x05 // To read WIP bit of status register 1 + + + +// Command for reading security register +#define QSPI_CMD_RDSCUR 0x2B + +// Command for setting Reset Enable +#define QSPI_CMD_RSTEN 0x66 +// Command for setting Reset +#define QSPI_CMD_RST 0xF0 //0x99 + +// Command for setting write enable +#define QSPI_CMD_WREN 0x06 +// Command for setting write disable +#define QSPI_CMD_WRDI 0x04 + +// WRSR operations max time [us] (datasheet max time + 15%) +#define QSPI_WRSR_MAX_TIME 2300000 // 2.3 seconds +// general wait max time [us] +#define QSPI_WAIT_MAX_TIME 100000 // 100ms + + +// Commands for writing (page programming) +#define QSPI_CMD_WRITE_1IO 0x02 // 1-1-1 mode +#define QSPI_CMD_WRITE_1I4O 0x32 // 1-1-4 mode // 1-4-4 is not supported by S25FS512S + +// write operations max time [us] (datasheet max time + 15%) +#define QSPI_PAGE_PROG_MAX_TIME 2300 // 2.3ms + +#define QSPI_PAGE_SIZE 256 // 256B +#define QSPI_SECTOR_SIZE 262144 // 256kB +#define QSPI_SECTOR_COUNT 256 // 64 MB + +// Commands for reading +#define QSPI_CMD_READ_1IO_FAST 0x0B // 1-1-1 mode +#define QSPI_CMD_READ_1IO 0x03 // 1-1-1 mode +#define QSPI_CMD_READ_2IO 0xBB // 1-2-2 mode - dual I/O +#define QSPI_CMD_READ_1I2O 0x3B // 1-1-2 mode - dual output +#define QSPI_CMD_READ_4IO 0xEB // 1-4-4 mode - quad I/O +#define QSPI_CMD_READ_1I4O 0x6B // 1-1-4 mode - quad output + +// Alt (mode) value for quad I/O read +#define QSPI_ALT_READ_4IO 0x01 // 1-4-4 mode only + +#define QSPI_READ_1IO_DUMMY_CYCLE 0 +#define QSPI_READ_FAST_DUMMY_CYCLE 8 +#define QSPI_READ_2IO_DUMMY_CYCLE 4 // dual I/O +#define QSPI_READ_1I2O_DUMMY_CYCLE 8 // dual output +#define QSPI_READ_4IO_DUMMY_CYCLE 6 // quad I/O - 2 cycles for Mode or Alt (4 bits per cycle x 2 cycles = 1 byte) + 4 dummy cycles +#define QSPI_READ_1I4O_DUMMY_CYCLE 8 // quad output + +// Commands for erasing +#define QSPI_CMD_ERASE_SECTOR 0xD8 // 256kB +#define QSPI_CMD_ERASE_CHIP 0x60 // or 0xC7 + +// erase operations max time [us] (datasheet max time + 15%) +#define QSPI_ERASE_SECTOR_MAX_TIME 850000 // 1.15*725 ~ 850 ms + +// max frequency for basic rw operation (for fast mode) +#define QSPI_COMMON_MAX_FREQUENCY 50000000 + +#define QSPI_STATUS_REG_SIZE 1 +#define QSPI_CONFIG_REG_0_SIZE 1 +#define QSPI_SECURITY_REG_SIZE 1 +#define QSPI_MAX_REG_SIZE 2 + +// status register +#define STATUS_BIT_WIP (1 << 0) // write in progress bit +#define STATUS_BIT_WEL (1 << 1) // write enable latch +#define STATUS_BIT_BP0 (1 << 2) // +#define STATUS_BIT_BP1 (1 << 3) // +#define STATUS_BIT_BP2 (1 << 4) // +#define STATUS_BIT_BP3 (1 << 5) // +#define STATUS_BIT_QE (1 << 1) // Quad Enable +#define STATUS_BIT_SRWD (1 << 7) // status register write protect + +// configuration register 0 +// bit 0, 1, 2, 4, 5, 7 reserved +#define CONFIG0_BIT_TB (1 << 3) // Top/Bottom area protect +#define CONFIG0_BIT_DC (1 << 6) // Dummy Cycle + +// configuration register 1 +// bit 0, 2, 3, 4, 5, 6, 7 reserved +#define CONFIG1_BIT_LH (1 << 1) // 0 = Ultra Low power mode, 1 = High performance mode + + + +#define EXTENDED_SPI_ENABLE() \ + \ + const int32_t reg_size = QSPI_STATUS_REG_SIZE + QSPI_CONFIG_REG_0_SIZE; \ + uint8_t reg_data[reg_size] = { 0 }; \ + \ + if (read_register(STATUS_REG, reg_data, \ + QSPI_STATUS_REG_SIZE, qspi) != QSPI_STATUS_OK) { \ + return QSPI_STATUS_ERROR; \ + } \ + if (read_register(CONFIG_REG0, reg_data + QSPI_STATUS_REG_SIZE, \ + QSPI_CONFIG_REG_0_SIZE, qspi) != QSPI_STATUS_OK) { \ + return QSPI_STATUS_ERROR; \ + } \ + \ + if (write_enable(qspi) != QSPI_STATUS_OK) { \ + return QSPI_STATUS_ERROR; \ + } \ + \ + reg_data[1] |= STATUS_BIT_QE; \ + if (write_register(QSPI_CMD_WRSR, reg_data, \ + reg_size, qspi) != QSPI_STATUS_OK) { \ + return QSPI_STATUS_ERROR; \ + } \ + \ + WAIT_FOR(WRSR_MAX_TIME, qspi); \ + \ + memset(reg_data, 0, QSPI_STATUS_REG_SIZE); \ + if (read_register(CONFIG_REG0, reg_data, \ + QSPI_STATUS_REG_SIZE, qspi) != QSPI_STATUS_OK) { \ + return QSPI_STATUS_ERROR; \ + } \ + \ + return ((reg_data[0] & STATUS_BIT_QE) != 0 ? \ + QSPI_STATUS_OK : QSPI_STATUS_ERROR) + + + +#define EXTENDED_SPI_DISABLE() \ + \ + const int32_t reg_size = QSPI_STATUS_REG_SIZE + QSPI_CONFIG_REG_0_SIZE; \ + uint8_t reg_data[reg_size] = { 0 }; \ + \ + if (read_register(STATUS_REG, reg_data, \ + QSPI_STATUS_REG_SIZE, qspi) != QSPI_STATUS_OK) { \ + return QSPI_STATUS_ERROR; \ + } \ + \ + if (read_register(CONFIG_REG0, reg_data + QSPI_STATUS_REG_SIZE, \ + QSPI_CONFIG_REG_0_SIZE, qspi) != QSPI_STATUS_OK) { \ + return QSPI_STATUS_ERROR; \ + } \ + \ + if (write_enable(qspi) != QSPI_STATUS_OK) { \ + return QSPI_STATUS_ERROR; \ + } \ + \ + reg_data[1] &= ~(STATUS_BIT_QE); \ + \ + if (write_register(QSPI_CMD_WRSR, reg_data, \ + reg_size, qspi) != QSPI_STATUS_OK) { \ + return QSPI_STATUS_ERROR; \ + } \ + \ + WAIT_FOR(WRSR_MAX_TIME, qspi); \ + \ + reg_data[0] = 0; \ + if (read_register(CONFIG_REG0, reg_data, \ + QSPI_STATUS_REG_SIZE, qspi) != QSPI_STATUS_OK) { \ + return QSPI_STATUS_ERROR; \ + } \ + \ + return ((reg_data[0] & STATUS_BIT_QE) == 0 ? \ + QSPI_STATUS_OK : QSPI_STATUS_ERROR) + + +#endif // MBED_QSPI_FLASH_S25FS512S_H diff --git a/hal/tests/TESTS/mbed_hal/qspi/flash_configs/SiliconLabs/EFM32GG11_STK3701/flash_config.h b/hal/tests/TESTS/mbed_hal/qspi/flash_configs/SiliconLabs/EFM32GG11_STK3701/flash_config.h new file mode 100644 index 0000000..5ff3dde --- /dev/null +++ b/hal/tests/TESTS/mbed_hal/qspi/flash_configs/SiliconLabs/EFM32GG11_STK3701/flash_config.h @@ -0,0 +1,29 @@ +/* mbed Microcontroller Library + * Copyright (c) 2018-2018 ARM Limited + * 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. + */ +#ifndef MBED_QSPI_FLASH_CONFIG_H +#define MBED_QSPI_FLASH_CONFIG_H + +#include "../../MX25RXX35F_config.h" + +#ifdef QSPI_SECTOR_COUNT +#undef QSPI_SECTOR_COUNT +#define QSPI_SECTOR_COUNT 1024 // for MX25R3235F +#endif + +#define QSPI_MIN_FREQUENCY 2000000 + +#endif // MBED_QSPI_FLASH_CONFIG_H diff --git a/hal/tests/TESTS/mbed_hal/qspi/flash_configs/W25Q32JV_config.h b/hal/tests/TESTS/mbed_hal/qspi/flash_configs/W25Q32JV_config.h new file mode 100644 index 0000000..3ab306b --- /dev/null +++ b/hal/tests/TESTS/mbed_hal/qspi/flash_configs/W25Q32JV_config.h @@ -0,0 +1,185 @@ +/* mbed Microcontroller Library + * Copyright (c) 2018-2018 ARM Limited + * 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. + */ +#ifndef MBED_QSPI_FLASH_W25Q32JV_H +#define MBED_QSPI_FLASH_W25Q32JV_H + + +#define QSPI_FLASH_CHIP_STRING "Winbond W25Q32JV" + +// Command for reading status register +#define QSPI_CMD_RDSR 0x05 +// Command for reading configuration register +#define QSPI_CMD_RDCR0 0x35 +#define QSPI_CMD_RDCR1 0x15 +// Command for writing status/configuration register +#define QSPI_CMD_WRSR 0x01 +// Command for writing configuration register +#define QSPI_CMD_WRCR0 0x31 +#define QSPI_CMD_WRCR1 0x11 +// Command for reading security register +#define QSPI_CMD_RDSCUR 0x48 + +// Command for setting Reset Enable +#define QSPI_CMD_RSTEN 0x66 +// Command for setting Reset +#define QSPI_CMD_RST 0x99 + +// Command for setting write enable +#define QSPI_CMD_WREN 0x06 +// Command for setting write disable +#define QSPI_CMD_WRDI 0x04 + +// WRSR operations max time [us] (datasheet max time + 15%) +#define QSPI_WRSR_MAX_TIME 34500 // 30ms +// general wait max time [us] +#define QSPI_WAIT_MAX_TIME 100000 // 100ms + + +// Commands for writing (page programming) +#define QSPI_CMD_WRITE_1IO 0x02 // 1-1-1 mode + +// write operations max time [us] (datasheet max time + 15%) +#define QSPI_PAGE_PROG_MAX_TIME 11500 // 10ms + +#define QSPI_PAGE_SIZE 256 // 256B +#define QSPI_SECTOR_SIZE 4096 // 4kB +#define QSPI_SECTOR_COUNT 1024 + +// Commands for reading +#define QSPI_CMD_READ_1IO_FAST 0x0B // 1-1-1 mode +#define QSPI_CMD_READ_1IO 0x03 // 1-1-1 mode +#define QSPI_CMD_READ_2IO 0xBB // 1-2-2 mode +#define QSPI_CMD_READ_1I2O 0x3B // 1-1-2 mode +#define QSPI_CMD_READ_4IO 0xEB // 1-4-4 mode +#define QSPI_CMD_READ_1I4O 0x6B // 1-1-4 mode + +#define QSPI_READ_1IO_DUMMY_CYCLE 0 +#define QSPI_READ_FAST_DUMMY_CYCLE 8 +#define QSPI_READ_2IO_DUMMY_CYCLE 4 +#define QSPI_READ_1I2O_DUMMY_CYCLE 8 +#define QSPI_READ_4IO_DUMMY_CYCLE 6 +#define QSPI_READ_1I4O_DUMMY_CYCLE 8 + +// Commands for erasing +#define QSPI_CMD_ERASE_SECTOR 0x20 // 4kB +#define QSPI_CMD_ERASE_BLOCK_32 0x52 // 32kB +#define QSPI_CMD_ERASE_BLOCK_64 0xD8 // 64kB +#define QSPI_CMD_ERASE_CHIP 0x60 // or 0xC7 + +// erase operations max time [us] (datasheet max time + 15%) +#define QSPI_ERASE_SECTOR_MAX_TIME 480000 // 400 ms +#define QSPI_ERASE_BLOCK_32_MAX_TIME 3450000 // 3s +#define QSPI_ERASE_BLOCK_64_MAX_TIME 4025000 // 3.5s + +// max frequency for basic rw operation (for fast mode) +#define QSPI_COMMON_MAX_FREQUENCY 32000000 + +#define QSPI_STATUS_REG_SIZE 1 +#define QSPI_CONFIG_REG_0_SIZE 1 +#define QSPI_CONFIG_REG_1_SIZE 1 + +#define QSPI_SECURITY_REG_SIZE 1 +#define QSPI_MAX_REG_SIZE 1 + +// status register +#define STATUS_BIT_WIP (1 << 0) // write in progress bit +#define STATUS_BIT_WEL (1 << 1) // write enable latch +#define STATUS_BIT_BP0 (1 << 2) // block protect 0 +#define STATUS_BIT_BP1 (1 << 3) // block protect 1 +#define STATUS_BIT_BP2 (1 << 4) // block protect 2 +#define STATUS_BIT_BP_TB (1 << 5) // block protect top/bottom +#define STATUS_BIT_SP (1 << 6) // sector protect +#define STATUS_BIT_SRWD (1 << 7) // status register protect + +// configuration register 0 +// bit 2 reserved +#define CONFIG0_BIT_SRL (1 << 0) // status register lock +#define CONFIG0_BIT_QE (1 << 1) // quad enable +#define CONFIG0_BIT_LB1 (1 << 3) // security register lock 1 +#define CONFIG0_BIT_LB2 (1 << 4) // security register lock 2 +#define CONFIG0_BIT_LB3 (1 << 5) // security register lock 3 +#define CONFIG0_BIT_CMP (1 << 6) // complement protect +#define CONFIG0_BIT_SUS (1 << 7) // suspend status + +// configuration register 1 +// bits 0, 1, 3, 4, 7 reserved +#define CONFIG1_BIT_WPS (1 << 2) // write protect selection +#define CONFIG1_BIT_DRV2 (1 << 5) // output driver strength 2 +#define CONFIG1_BIT_DRV1 (1 << 6) // output driver strength 1 + + + +#define QUAD_ENABLE() \ + \ + uint8_t reg_data[QSPI_CONFIG_REG_0_SIZE]; \ + \ + memset(reg_data, 0, QSPI_CONFIG_REG_0_SIZE); \ + if (read_register(QSPI_CMD_RDCR0, reg_data, \ + QSPI_CONFIG_REG_0_SIZE, qspi) != QSPI_STATUS_OK) { \ + return QSPI_STATUS_ERROR; \ + } \ + if (write_enable(qspi) != QSPI_STATUS_OK) { \ + return QSPI_STATUS_ERROR; \ + } \ + \ + reg_data[0] = reg_data[0] & ~(CONFIG0_BIT_QE); \ + if (write_register(QSPI_CMD_WRCR0, reg_data, \ + QSPI_CONFIG_REG_0_SIZE, qspi) != QSPI_STATUS_OK) { \ + return QSPI_STATUS_ERROR; \ + } \ + qspi.cmd.configure(MODE_4_4_4, ADDR_SIZE_24, ALT_SIZE_8); \ + WAIT_FOR(WRSR_MAX_TIME, qspi); \ + memset(reg_data, 0, QSPI_CONFIG_REG_0_SIZE); \ + if (read_register(QSPI_CMD_RDCR0, reg_data, \ + QSPI_CONFIG_REG_0_SIZE, qspi) != QSPI_STATUS_OK) { \ + return QSPI_STATUS_ERROR; \ + } \ + \ + return ((reg_data[0] & (CONFIG0_BIT_QE)) == 0 ? \ + QSPI_STATUS_OK : QSPI_STATUS_ERROR) + + +#define QUAD_DISABLE() \ + \ + uint8_t reg_data[QSPI_CONFIG_REG_0_SIZE]; \ + \ + memset(reg_data, 0, QSPI_CONFIG_REG_0_SIZE); \ + if (read_register(QSPI_CMD_RDCR0, reg_data, \ + QSPI_CONFIG_REG_0_SIZE, qspi) != QSPI_STATUS_OK) { \ + return QSPI_STATUS_ERROR; \ + } \ + if (write_enable(qspi) != QSPI_STATUS_OK) { \ + return QSPI_STATUS_ERROR; \ + } \ + \ + reg_data[0] = reg_data[0] | (CONFIG0_BIT_QE); \ + if (write_register(QSPI_CMD_WRCR0, reg_data, \ + QSPI_CONFIG_REG_0_SIZE, qspi) != QSPI_STATUS_OK) { \ + return QSPI_STATUS_ERROR; \ + } \ + WAIT_FOR(WRSR_MAX_TIME, qspi); \ + qspi.cmd.configure(MODE_1_1_1, ADDR_SIZE_24, ALT_SIZE_8); \ + memset(reg_data, 0, QSPI_CONFIG_REG_0_SIZE); \ + if (read_register(QSPI_CMD_RDCR0, reg_data, \ + QSPI_CONFIG_REG_0_SIZE, qspi) != QSPI_STATUS_OK) { \ + return QSPI_STATUS_ERROR; \ + } \ + \ + return ((reg_data[0] & CONFIG0_BIT_QE) != 1 ? \ + QSPI_STATUS_OK : QSPI_STATUS_ERROR) + +#endif // MBED_QSPI_FLASH_W25Q32JV_H diff --git a/hal/tests/TESTS/mbed_hal/qspi/flash_configs/flash_configs.h b/hal/tests/TESTS/mbed_hal/qspi/flash_configs/flash_configs.h new file mode 100644 index 0000000..cca4212 --- /dev/null +++ b/hal/tests/TESTS/mbed_hal/qspi/flash_configs/flash_configs.h @@ -0,0 +1,83 @@ +/* mbed Microcontroller Library + * Copyright (c) 2018-2018 ARM Limited + * 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. + */ + +#ifndef MBED_FLASH_CONFIGS_H +#define MBED_FLASH_CONFIGS_H + +#if defined(TARGET_MX25R6435F) +#include "MX25RXX35F_config.h" + +#elif defined(TARGET_DISCO_L476VG) +#include "N25Q128A_config.h" // N25Q128A13EF840E +/* See STM32L476 Errata Sheet, it is not possible to use Dual-/Quad-mode for the command phase */ +#undef QSPI_CMD_READ_DPI +#undef QSPI_CMD_READ_QPI +#undef QSPI_CMD_WRITE_DPI +#undef QSPI_CMD_WRITE_QPI + +#elif defined(TARGET_N25Q128A) +#include "N25Q128A_config.h" + +#elif defined(TARGET_MX25L51245G) +#include "MX25L51245G_config.h" + +#elif defined(TARGET_MX25LM51245G) +#include "MX25LM51245G_config.h" + +#elif defined(TARGET_RHOMBIO_L476DMW1K) +#include "MT25Q_config.h" // MT25QL128ABA1EW7 +/* See STM32L476 Errata Sheet, it is not possible to use Dual-/Quad-mode for the command phase */ +#undef QSPI_CMD_READ_DPI +#undef QSPI_CMD_READ_QPI +#undef QSPI_CMD_WRITE_DPI +#undef QSPI_CMD_WRITE_QPI + +#elif defined(TARGET_NRF52840) +#if TARGET_EP_AGORA +#include "NORDIC/EP_AGORA/flash_config.h" +#else +#include "NORDIC/NRF52840_DK/flash_config.h" +#endif + +#elif defined(TARGET_EFM32GG11_STK3701) +#include "SiliconLabs/EFM32GG11_STK3701/flash_config.h" + +#elif defined(TARGET_K82F) +#include "NXP/K82F/flash_config.h" + +#elif defined(TARGET_LPC546XX) +#include "NXP/LPC546XX/flash_config.h" + +#elif( defined(TARGET_CY8CKIT_062_BLE) || \ + defined(TARGET_CY8CKIT_062_WIFI_BT) || \ + defined(TARGET_CY8CKIT_062S2_43012) || \ + defined(TARGET_CY8CKIT_062S2_4343W) || \ + defined(TARGET_CY8CKIT_064S2_4343W) || \ + defined(TARGET_CY8CKIT_064B0S2_4343W) || \ + defined(TARGET_CY8CPROTO_062_4343W) || \ + defined(TARGET_CY8CPROTO_062S2_43012) || \ + defined(TARGET_CY8CPROTO_062S3_4343W) || \ + defined(TARGET_CYW9P62S1_43438EVB_01) || \ + defined(TARGET_CYSBSYSKIT_01)) +#include "S25FL512S_config.h" + +#elif defined(TARGET_CYW9P62S1_43012EVB_01) +#include "S25FS512S_config.h" + +#endif + +#endif // MBED_FLASH_CONFIGS_H diff --git a/hal/tests/TESTS/mbed_hal/qspi/main.cpp b/hal/tests/TESTS/mbed_hal/qspi/main.cpp new file mode 100644 index 0000000..4259f61 --- /dev/null +++ b/hal/tests/TESTS/mbed_hal/qspi/main.cpp @@ -0,0 +1,628 @@ +/* mbed Microcontroller Library + * Copyright (c) 2018-2018 ARM Limited + * 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. + */ + +#if !DEVICE_QSPI +#error [NOT_SUPPORTED] QSPI not supported for this target +#else + +#include "utest/utest.h" +#include "unity/unity.h" +#include "greentea-client/test_env.h" +#include "qspi_test.h" +#include "qspi_test_utils.h" + +#include "mbed.h" +#include "qspi_api.h" +#include "hal/us_ticker_api.h" + + +#if !defined(QSPI_FLASH_CHIP_STRING) +#error [NOT_SUPPORTED] QSPI test not supported for this target +#else + +using namespace utest::v1; + +// uncomment to enable verbose mode +//#define QSPI_TEST_LOG_DATA +//#define QSPI_TEST_LOG_FLASH_TIME +//#define QSPI_TEST_LOG_FLASH_STATUS + + + +#ifndef QSPI_MIN_FREQUENCY +#define QSPI_MIN_FREQUENCY 1000000 +#endif + +// max write size is usually page size +#define DATA_SIZE_256 (QSPI_PAGE_SIZE) +#define DATA_SIZE_1024 (QSPI_PAGE_SIZE * 4) + +uint8_t tx_buf[DATA_SIZE_1024]; +uint8_t rx_buf[DATA_SIZE_1024]; + + +// write address should be page aligned +#define TEST_FLASH_ADDRESS 0x0 + +#define TEST_REPEAT_SINGLE 1 +#define TEST_REPEAT_MULTIPLE 4 + +// write block of data in single write operation +#define WRITE_SINGLE 1 +// write block of data in adjacent locations in multiple write operations +#define WRITE_MULTIPLE 4 + +// read block of data in single read operation +#define READ_SINGLE 1 +// read block of data in adjacent locations in multiple read operations +#define READ_MULTIPLE 4 + + +// some target defines QSPI pins as integers thus conversion needed +#define QPIN_0 static_cast(MBED_CONF_DRIVERS_QSPI_IO0) +#define QPIN_1 static_cast(MBED_CONF_DRIVERS_QSPI_IO1) +#define QPIN_2 static_cast(MBED_CONF_DRIVERS_QSPI_IO2) +#define QPIN_3 static_cast(MBED_CONF_DRIVERS_QSPI_IO3) +#define QSCK static_cast(MBED_CONF_DRIVERS_QSPI_SCK) +#define QCSN static_cast(MBED_CONF_DRIVERS_QSPI_CSN) + + +static uint32_t gen_flash_address() +{ + srand(ticker_read(get_us_ticker_data())); + uint32_t address = (((uint32_t)rand()) % QSPI_SECTOR_COUNT) * QSPI_SECTOR_SIZE; + address &= 0xFFFFFF; // Ensure address is within 24 bits so as to not have to deal with 4-byte addressing + return address; +} + +static void log_data(const char *str, uint8_t *data, uint32_t size) +{ + utest_printf("%s: ", str); + for (uint32_t j = 0; j < size; j++) { + utest_printf("%02X ", data[j]); + } + utest_printf("\r\n"); +} + + +static void _qspi_write_read_test(Qspi &qspi, qspi_bus_width_t write_inst_width, qspi_bus_width_t write_addr_width, + qspi_bus_width_t write_data_width, qspi_bus_width_t write_alt_width, uint32_t write_cmd, + qspi_address_size_t write_addr_size, qspi_alt_size_t write_alt_size, + uint32_t write_count, qspi_bus_width_t read_inst_width, qspi_bus_width_t read_addr_width, + qspi_bus_width_t read_data_width, qspi_bus_width_t read_alt_width, uint32_t read_cmd, + int read_dummy_cycles, qspi_address_size_t read_addr_size, qspi_alt_size_t read_alt_size, + uint32_t read_count, uint32_t test_count, uint32_t data_size, + uint32_t flash_addr) +{ + qspi_status_t ret = QSPI_STATUS_OK; + + Timer timer; + int erase_time = 0, write_time = 0, read_time = 0; + size_t buf_len = data_size; + + for (uint32_t tc = 0; tc < test_count; tc++) { + + srand(ticker_read(get_us_ticker_data())); + for (uint32_t i = 0; i < data_size; i++) { + tx_buf[i] = (uint8_t)(rand() & 0xFF); + } + + ret = write_enable(qspi); + TEST_ASSERT_EQUAL(QSPI_STATUS_OK, ret); + + timer.reset(); + timer.start(); + + ret = erase(SECTOR_ERASE, flash_addr, qspi); + TEST_ASSERT_EQUAL(QSPI_STATUS_OK, ret); + WAIT_FOR(SECTOR_ERASE_MAX_TIME, qspi); + + timer.stop(); + erase_time = timer.read_us(); + + // switching to extended-SPI/DPI/QPI mode here for write operation + // for DPI/QPI qspi.cmd is automatically switched to 2_2_2/4_4_4 mode + ret = mode_enable(qspi, write_inst_width, write_addr_width, write_data_width); + TEST_ASSERT_EQUAL(QSPI_STATUS_OK, ret); + + const uint32_t write_size = data_size / write_count; + for (uint32_t wc = 0, write_start = flash_addr; wc < write_count; wc++, write_start += write_size) { + ret = write_enable(qspi); + TEST_ASSERT_EQUAL(QSPI_STATUS_OK, ret); + + timer.reset(); + timer.start(); + + buf_len = write_size; + qspi.cmd.configure(write_inst_width, write_addr_width, write_data_width, write_alt_width, write_addr_size, write_alt_size); + qspi.cmd.build(write_cmd, write_start); + ret = qspi_write(&qspi.handle, qspi.cmd.get(), tx_buf + wc * write_size, &buf_len); + TEST_ASSERT_EQUAL(QSPI_STATUS_OK, ret); + TEST_ASSERT_EQUAL(write_size, buf_len); + + if (is_extended_mode(write_inst_width, write_addr_width, write_data_width)) { + // on some flash chips in extended-SPI mode, control commands works only in 1-1-1 mode + // so switching back to 1-1-1 mode + qspi.cmd.configure(MODE_1_1_1, ADDR_SIZE_24, ALT_SIZE_8); + } + + WAIT_FOR(PAGE_PROG_MAX_TIME, qspi); + + timer.stop(); + write_time = timer.read_us(); + } + + // switching back to single channel SPI + ret = mode_disable(qspi, write_inst_width, write_addr_width, write_data_width); + TEST_ASSERT_EQUAL(QSPI_STATUS_OK, ret); + + // switching to extended-SPI/DPI/QPI mode here for read operation + // for DPI/QPI qspi.cmd is automatically switched to 2_2_2/4_4_4 mode + ret = mode_enable(qspi, read_inst_width, read_addr_width, read_data_width); + TEST_ASSERT_EQUAL(QSPI_STATUS_OK, ret); + + memset(rx_buf, 0, sizeof(rx_buf)); + const uint32_t read_size = data_size / read_count; + qspi.cmd.configure(read_inst_width, read_addr_width, read_data_width, read_alt_width, read_addr_size, read_alt_size, read_dummy_cycles); + for (uint32_t rc = 0, read_start = flash_addr; rc < read_count; rc++, read_start += read_size) { + timer.reset(); + timer.start(); + + buf_len = read_size; + qspi.cmd.build(read_cmd, read_start); + ret = qspi_read(&qspi.handle, qspi.cmd.get(), rx_buf + rc * read_size, &buf_len); + TEST_ASSERT_EQUAL(QSPI_STATUS_OK, ret); + TEST_ASSERT_EQUAL(read_size, buf_len); + + timer.stop(); + read_time = timer.read_us(); + } + qspi.cmd.set_dummy_cycles(0); + + if (is_extended_mode(read_inst_width, read_addr_width, read_data_width)) { + // on some flash chips in extended-SPI mode, control commands works only in 1-1-1 mode + // so switching back to 1-1-1 mode + qspi.cmd.configure(MODE_1_1_1, ADDR_SIZE_24, ALT_SIZE_8); + } + + // switching back to single channel SPI + ret = mode_disable(qspi, read_inst_width, read_addr_width, read_data_width); + TEST_ASSERT_EQUAL(QSPI_STATUS_OK, ret); + + for (uint32_t i = 0; i < data_size; i++) { + if (tx_buf[i] != rx_buf[i]) { + log_data("tx data", tx_buf, data_size); + log_data("rx data", rx_buf, data_size); + utest_printf("erase/write/read time: %d/%d/%d [us]\r\n", erase_time, write_time, read_time); + TEST_ASSERT_EQUAL(tx_buf[i], rx_buf[i]); + } + } + +#ifdef QSPI_TEST_LOG_FLASH_TIME + utest_printf("erase/write/read time: %d/%d/%d [us]\r\n", erase_time, write_time, read_time); +#endif + +#ifdef QSPI_TEST_LOG_DATA + log_data("tx data", tx_buf, data_size); + log_data("rx data", rx_buf, data_size); + utest_printf("rx/tx data match\r\n"); +#endif + } +} + + +template < qspi_bus_width_t write_inst_width, + qspi_bus_width_t write_addr_width, + qspi_bus_width_t write_data_width, + qspi_bus_width_t write_alt_width, + unsigned int write_cmd, + qspi_address_size_t write_addr_size, + qspi_alt_size_t write_alt_size, + uint32_t write_count, + qspi_bus_width_t read_inst_width, + qspi_bus_width_t read_addr_width, + qspi_bus_width_t read_data_width, + qspi_bus_width_t read_alt_width, + unsigned int read_cmd, + int read_dummy_cycles, + qspi_address_size_t read_addr_size, + qspi_alt_size_t read_alt_size, + int frequency, + uint32_t read_count, + uint32_t test_count, + uint32_t data_size, + uint32_t flash_addr> +void qspi_write_read_test(void) +{ + qspi_status_t ret; + Qspi qspi; + + uint32_t addr = flash_addr; + if (addr == 0) { + // if no specified address selected, use random one to extend flash life + addr = gen_flash_address(); + } + + qspi_init(&qspi.handle, QPIN_0, QPIN_1, QPIN_2, QPIN_3, QSCK, QCSN, QSPI_COMMON_MAX_FREQUENCY, 0); + + ret = qspi_frequency(&qspi.handle, frequency); + TEST_ASSERT_EQUAL(QSPI_STATUS_OK, ret); + + qspi.cmd.configure(MODE_1_1_1, ADDR_SIZE_24, ALT_SIZE_8); + flash_init(qspi); + + // switch memory to high performance mode (if available) + ret = fast_mode_enable(qspi); + TEST_ASSERT_EQUAL(QSPI_STATUS_OK, ret); + +#ifdef QSPI_TEST_LOG_FLASH_STATUS + log_register(STATUS_REG, QSPI_STATUS_REG_SIZE, qspi, "Status register"); + log_register(CONFIG_REG0, QSPI_CONFIG_REG_0_SIZE, qspi, "Config register 0"); +#ifdef CONFIG_REG1 + log_register(CONFIG_REG1, QSPI_CONFIG_REG_1_SIZE, qspi, "Config register 1"); +#endif +#ifdef CONFIG_REG2 + log_register(CONFIG_REG2, QSPI_CONFIG_REG_2_SIZE, qspi, "Config register 2"); +#endif +#endif + + _qspi_write_read_test(qspi, write_inst_width, write_addr_width, write_data_width, write_alt_width, write_cmd, + write_addr_size, write_alt_size, write_count, read_inst_width, + read_addr_width, read_data_width, read_alt_width, read_cmd, read_dummy_cycles, + read_addr_size, read_alt_size, read_count, test_count, + data_size, addr); + + ret = fast_mode_disable(qspi); + TEST_ASSERT_EQUAL(QSPI_STATUS_OK, ret); + + qspi_free(&qspi.handle); +} + + +void qspi_init_free_test(void) +{ + Qspi qspi; + qspi_status_t ret; + + ret = qspi_init(&qspi.handle, QPIN_0, QPIN_1, QPIN_2, QPIN_3, QSCK, QCSN, QSPI_COMMON_MAX_FREQUENCY, 0); + TEST_ASSERT_EQUAL(QSPI_STATUS_OK, ret); + ret = qspi_free(&qspi.handle); + TEST_ASSERT_EQUAL(QSPI_STATUS_OK, ret); + + + ret = qspi_init(&qspi.handle, QPIN_0, QPIN_1, QPIN_2, QPIN_3, QSCK, QCSN, QSPI_COMMON_MAX_FREQUENCY, 0); + TEST_ASSERT_EQUAL(QSPI_STATUS_OK, ret); + ret = qspi_free(&qspi.handle); + TEST_ASSERT_EQUAL(QSPI_STATUS_OK, ret); + + + ret = qspi_init(&qspi.handle, QPIN_0, QPIN_1, QPIN_2, QPIN_3, QSCK, QCSN, QSPI_COMMON_MAX_FREQUENCY, 0); + TEST_ASSERT_EQUAL(QSPI_STATUS_OK, ret); + ret = qspi_free(&qspi.handle); + TEST_ASSERT_EQUAL(QSPI_STATUS_OK, ret); + + + ret = qspi_init(&qspi.handle, QPIN_0, QPIN_1, QPIN_2, QPIN_3, QSCK, QCSN, QSPI_COMMON_MAX_FREQUENCY, 0); + TEST_ASSERT_EQUAL(QSPI_STATUS_OK, ret); + + // check if the memory is working properly + qspi.cmd.configure(MODE_1_1_1, ADDR_SIZE_24, ALT_SIZE_8); + flash_init(qspi); + +#ifdef QSPI_TEST_LOG_FLASH_STATUS + log_register(STATUS_REG, QSPI_STATUS_REG_SIZE, qspi, "Status register"); + log_register(CONFIG_REG0, QSPI_CONFIG_REG_0_SIZE, qspi, "Config register 0"); +#ifdef CONFIG_REG1 + log_register(CONFIG_REG1, QSPI_CONFIG_REG_1_SIZE, qspi, "Config register 1"); +#endif +#ifdef CONFIG_REG2 + log_register(CONFIG_REG2, QSPI_CONFIG_REG_2_SIZE, qspi, "Config register 2"); +#endif +#endif + + _qspi_write_read_test(qspi, WRITE_1_1_1, ADDR_SIZE_24, ALT_SIZE_8, WRITE_SINGLE, READ_1_1_1, ADDR_SIZE_24, ALT_SIZE_8, READ_SINGLE, TEST_REPEAT_SINGLE, DATA_SIZE_256, TEST_FLASH_ADDRESS); + qspi_free(&qspi.handle); +} + + +void qspi_frequency_test(void) +{ + Qspi qspi; + qspi_status_t ret; + int freq = QSPI_COMMON_MAX_FREQUENCY; + + ret = qspi_init(&qspi.handle, QPIN_0, QPIN_1, QPIN_2, QPIN_3, QSCK, QCSN, freq, 0); + TEST_ASSERT_EQUAL(QSPI_STATUS_OK, ret); + + while (ret == QSPI_STATUS_OK && freq >= QSPI_MIN_FREQUENCY) { + // check if the memory is working properly + qspi.cmd.configure(MODE_1_1_1, ADDR_SIZE_24, ALT_SIZE_8); + ret = qspi_frequency(&qspi.handle, freq); + flash_init(qspi); + _qspi_write_read_test(qspi, WRITE_1_1_1, ADDR_SIZE_24, ALT_SIZE_8, WRITE_SINGLE, READ_1_1_1, ADDR_SIZE_24, ALT_SIZE_8, READ_SINGLE, TEST_REPEAT_SINGLE, DATA_SIZE_256, TEST_FLASH_ADDRESS); + + utest_printf("frequency setting %d [Hz] - OK\r\n", freq); + + freq /= 2; + } + + qspi_free(&qspi.handle); +} + + +void qspi_memory_id_test() +{ + utest_printf("*** %s memory config loaded ***\r\n", QSPI_FLASH_CHIP_STRING); +} + + +Case cases[] = { + Case("qspi memory id test", qspi_memory_id_test), + Case("qspi init/free test", qspi_init_free_test), + Case("qspi frequency setting test", qspi_frequency_test), + // read/x1 write/x1 - read/write block of data in single write/read operation + // read/x4 write/x4 - read/write block of data in adjacent locations in multiple write/read operations + // repeat/xN - test repeat count (new data pattern each time) + // 1-1-1 - single channel SPI + // 1-1-2 - Dual data (extended SPI) + // 1-2-2 - Dual I/O (extended SPI) + // 1-1-4 - Quad data (extended SPI) + // 1-4-4 - Quad I/O (extended SPI) + // 2-2-2 - DPI (multi-channel SPI) + // 4-4-4 - QPI (multi-channel SPI) + Case("qspi write(1-1-1)/x1 read(1-1-1)/x1 repeat/x1 test", qspi_write_read_test), + Case("qspi write(1-1-1)/x4 read(1-1-1)/x1 repeat/x1 test", qspi_write_read_test), + Case("qspi write(1-1-1)/x1 read(1-1-1)/x4 repeat/x1 test", qspi_write_read_test), + Case("qspi write(1-1-1)/x1 read(1-1-1)/x1 repeat/x4 test", qspi_write_read_test), +#ifdef READ_1_1_2 + Case("qspi write(1-1-1)/x1 read(1-1-2)/x1 repeat/x1 test", qspi_write_read_test), + Case("qspi write(1-1-1)/x4 read(1-1-2)/x1 repeat/x1 test", qspi_write_read_test), + Case("qspi write(1-1-1)/x1 read(1-1-2)/x4 repeat/x1 test", qspi_write_read_test), + Case("qspi write(1-1-1)/x1 read(1-1-2)/x1 repeat/x4 test", qspi_write_read_test), +#endif +#ifdef READ_1_2_2 + Case("qspi write(1-1-1)/x1 read(1-2-2)/x1 repeat/x1 test", qspi_write_read_test), + Case("qspi write(1-1-1)/x4 read(1-2-2)/x1 repeat/x1 test", qspi_write_read_test), + Case("qspi write(1-1-1)/x1 read(1-2-2)/x4 repeat/x1 test", qspi_write_read_test), + Case("qspi write(1-1-1)/x1 read(1-2-2)/x1 repeat/x4 test", qspi_write_read_test), +#endif +#ifdef READ_2_2_2 + Case("qspi write(1-1-1)/x1 read(2-2-2)/x1 repeat/x1 test", qspi_write_read_test), + Case("qspi write(1-1-1)/x4 read(2-2-2)/x1 repeat/x1 test", qspi_write_read_test), + Case("qspi write(1-1-1)/x1 read(2-2-2)/x4 repeat/x1 test", qspi_write_read_test), + Case("qspi write(1-1-1)/x1 read(2-2-2)/x1 repeat/x4 test", qspi_write_read_test), +#endif +#ifdef READ_1_1_4 + Case("qspi write(1-1-1)/x1 read(1-1-4)/x1 repeat/x1 test", qspi_write_read_test), + Case("qspi write(1-1-1)/x4 read(1-1-4)/x1 repeat/x1 test", qspi_write_read_test), + Case("qspi write(1-1-1)/x1 read(1-1-4)/x4 repeat/x1 test", qspi_write_read_test), + Case("qspi write(1-1-1)/x1 read(1-1-4)/x1 repeat/x4 test", qspi_write_read_test), +#endif +#ifdef READ_1_4_4 + Case("qspi write(1-1-1)/x1 read(1-4-4)/x1 repeat/x1 test", qspi_write_read_test), + Case("qspi write(1-1-1)/x4 read(1-4-4)/x1 repeat/x1 test", qspi_write_read_test), + Case("qspi write(1-1-1)/x1 read(1-4-4)/x4 repeat/x1 test", qspi_write_read_test), + Case("qspi write(1-1-1)/x1 read(1-4-4)/x1 repeat/x4 test", qspi_write_read_test), +#endif +#ifdef READ_4_4_4 + Case("qspi write(1-1-1)/x1 read(4-4-4)/x1 repeat/x1 test", qspi_write_read_test), + Case("qspi write(1-1-1)/x4 read(4-4-4)/x1 repeat/x1 test", qspi_write_read_test), + Case("qspi write(1-1-1)/x1 read(4-4-4)/x4 repeat/x1 test", qspi_write_read_test), + Case("qspi write(1-1-1)/x1 read(4-4-4)/x1 repeat/x4 test", qspi_write_read_test), +#endif + +#ifdef WRITE_1_2_2 + Case("qspi write(1-2-2)/x1 read(1-1-1)/x1 repeat/x1 test", qspi_write_read_test), + Case("qspi write(1-2-2)/x4 read(1-1-1)/x1 repeat/x1 test", qspi_write_read_test), + Case("qspi write(1-2-2)/x1 read(1-1-1)/x4 repeat/x1 test", qspi_write_read_test), + Case("qspi write(1-2-2)/x1 read(1-1-1)/x1 repeat/x4 test", qspi_write_read_test), + Case("qspi write(1-2-2)/x1 read(1-1-2)/x1 repeat/x1 test", qspi_write_read_test), + Case("qspi write(1-2-2)/x4 read(1-1-2)/x1 repeat/x1 test", qspi_write_read_test), + Case("qspi write(1-2-2)/x1 read(1-1-2)/x4 repeat/x1 test", qspi_write_read_test), + Case("qspi write(1-2-2)/x1 read(1-1-2)/x1 repeat/x4 test", qspi_write_read_test), + Case("qspi write(1-2-2)/x1 read(1-2-2)/x1 repeat/x1 test", qspi_write_read_test), + Case("qspi write(1-2-2)/x4 read(1-2-2)/x1 repeat/x1 test", qspi_write_read_test), + Case("qspi write(1-2-2)/x1 read(1-2-2)/x4 repeat/x1 test", qspi_write_read_test), + Case("qspi write(1-2-2)/x1 read(1-2-2)/x1 repeat/x4 test", qspi_write_read_test), +#ifdef READ_2_2_2 + Case("qspi write(1-2-2)/x1 read(2-2-2)/x1 repeat/x1 test", qspi_write_read_test), + Case("qspi write(1-2-2)/x4 read(2-2-2)/x1 repeat/x1 test", qspi_write_read_test), + Case("qspi write(1-2-2)/x1 read(2-2-2)/x4 repeat/x1 test", qspi_write_read_test), + Case("qspi write(1-2-2)/x1 read(2-2-2)/x1 repeat/x4 test", qspi_write_read_test), +#endif +#ifdef READ_1_1_4 + Case("qspi write(1-2-2)/x1 read(1-1-4)/x1 repeat/x1 test", qspi_write_read_test), + Case("qspi write(1-2-2)/x4 read(1-1-4)/x1 repeat/x1 test", qspi_write_read_test), + Case("qspi write(1-2-2)/x1 read(1-1-4)/x4 repeat/x1 test", qspi_write_read_test), + Case("qspi write(1-2-2)/x1 read(1-1-4)/x1 repeat/x4 test", qspi_write_read_test), +#endif + Case("qspi write(1-2-2)/x1 read(1-4-4)/x1 repeat/x1 test", qspi_write_read_test), + Case("qspi write(1-2-2)/x4 read(1-4-4)/x1 repeat/x1 test", qspi_write_read_test), + Case("qspi write(1-2-2)/x1 read(1-4-4)/x4 repeat/x1 test", qspi_write_read_test), + Case("qspi write(1-2-2)/x1 read(1-4-4)/x1 repeat/x4 test", qspi_write_read_test), +#ifdef READ_4_4_4 + Case("qspi write(1-2-2)/x1 read(4-4-4)/x1 repeat/x1 test", qspi_write_read_test), + Case("qspi write(1-2-2)/x4 read(4-4-4)/x1 repeat/x1 test", qspi_write_read_test), + Case("qspi write(1-2-2)/x1 read(4-4-4)/x4 repeat/x1 test", qspi_write_read_test), + Case("qspi write(1-2-2)/x1 read(4-4-4)/x1 repeat/x4 test", qspi_write_read_test), +#endif +#endif + +#ifdef WRITE_2_2_2 + Case("qspi write(2-2-2)/x1 read(1-1-1)/x1 repeat/x1 test", qspi_write_read_test), + Case("qspi write(2-2-2)/x4 read(1-1-1)/x1 repeat/x1 test", qspi_write_read_test), + Case("qspi write(2-2-2)/x1 read(1-1-1)/x4 repeat/x1 test", qspi_write_read_test), + Case("qspi write(2-2-2)/x1 read(1-1-1)/x1 repeat/x4 test", qspi_write_read_test), + Case("qspi write(2-2-2)/x1 read(1-1-2)/x1 repeat/x1 test", qspi_write_read_test), + Case("qspi write(2-2-2)/x4 read(1-1-2)/x1 repeat/x1 test", qspi_write_read_test), + Case("qspi write(2-2-2)/x1 read(1-1-2)/x4 repeat/x1 test", qspi_write_read_test), + Case("qspi write(2-2-2)/x1 read(1-1-2)/x1 repeat/x4 test", qspi_write_read_test), + Case("qspi write(2-2-2)/x1 read(1-2-2)/x1 repeat/x1 test", qspi_write_read_test), + Case("qspi write(2-2-2)/x4 read(1-2-2)/x1 repeat/x1 test", qspi_write_read_test), + Case("qspi write(2-2-2)/x1 read(1-2-2)/x4 repeat/x1 test", qspi_write_read_test), + Case("qspi write(2-2-2)/x1 read(1-2-2)/x1 repeat/x4 test", qspi_write_read_test), +#ifdef READ_2_2_2 + Case("qspi write(2-2-2)/x1 read(2-2-2)/x1 repeat/x1 test", qspi_write_read_test), + Case("qspi write(2-2-2)/x4 read(2-2-2)/x1 repeat/x1 test", qspi_write_read_test), + Case("qspi write(2-2-2)/x1 read(2-2-2)/x4 repeat/x1 test", qspi_write_read_test), + Case("qspi write(2-2-2)/x1 read(2-2-2)/x1 repeat/x4 test", qspi_write_read_test), +#endif +#ifdef READ_1_1_4 + Case("qspi write(2-2-2)/x1 read(1-1-4)/x1 repeat/x1 test", qspi_write_read_test), + Case("qspi write(2-2-2)/x4 read(1-1-4)/x1 repeat/x1 test", qspi_write_read_test), + Case("qspi write(2-2-2)/x1 read(1-1-4)/x4 repeat/x1 test", qspi_write_read_test), + Case("qspi write(2-2-2)/x1 read(1-1-4)/x1 repeat/x4 test", qspi_write_read_test), +#endif + Case("qspi write(2-2-2)/x1 read(1-4-4)/x1 repeat/x1 test", qspi_write_read_test), + Case("qspi write(2-2-2)/x4 read(1-4-4)/x1 repeat/x1 test", qspi_write_read_test), + Case("qspi write(2-2-2)/x1 read(1-4-4)/x4 repeat/x1 test", qspi_write_read_test), + Case("qspi write(2-2-2)/x1 read(1-4-4)/x1 repeat/x4 test", qspi_write_read_test), +#ifdef READ_4_4_4 + Case("qspi write(2-2-2)/x1 read(4-4-4)/x1 repeat/x1 test", qspi_write_read_test), + Case("qspi write(2-2-2)/x4 read(4-4-4)/x1 repeat/x1 test", qspi_write_read_test), + Case("qspi write(2-2-2)/x1 read(4-4-4)/x4 repeat/x1 test", qspi_write_read_test), + Case("qspi write(2-2-2)/x1 read(4-4-4)/x1 repeat/x4 test", qspi_write_read_test), +#endif +#endif + +#ifdef WRITE_1_1_4 + Case("qspi write(1-1-4)/x1 read(1-1-1)/x1 repeat/x1 test", qspi_write_read_test), + Case("qspi write(1-1-4)/x4 read(1-1-1)/x1 repeat/x1 test", qspi_write_read_test), + Case("qspi write(1-1-4)/x1 read(1-1-1)/x4 repeat/x1 test", qspi_write_read_test), + Case("qspi write(1-1-4)/x1 read(1-1-1)/x1 repeat/x4 test", qspi_write_read_test), + Case("qspi write(1-1-4)/x1 read(1-1-2)/x1 repeat/x1 test", qspi_write_read_test), + Case("qspi write(1-1-4)/x4 read(1-1-2)/x1 repeat/x1 test", qspi_write_read_test), + Case("qspi write(1-1-4)/x1 read(1-1-2)/x4 repeat/x1 test", qspi_write_read_test), + Case("qspi write(1-1-4)/x1 read(1-1-2)/x1 repeat/x4 test", qspi_write_read_test), + Case("qspi write(1-1-4)/x1 read(1-2-2)/x1 repeat/x1 test", qspi_write_read_test), + Case("qspi write(1-1-4)/x4 read(1-2-2)/x1 repeat/x1 test", qspi_write_read_test), + Case("qspi write(1-1-4)/x1 read(1-2-2)/x4 repeat/x1 test", qspi_write_read_test), + Case("qspi write(1-1-4)/x1 read(1-2-2)/x1 repeat/x4 test", qspi_write_read_test), +#ifdef READ_2_2_2 + Case("qspi write(1-1-4)/x1 read(2-2-2)/x1 repeat/x1 test", qspi_write_read_test), + Case("qspi write(1-1-4)/x4 read(2-2-2)/x1 repeat/x1 test", qspi_write_read_test), + Case("qspi write(1-1-4)/x1 read(2-2-2)/x4 repeat/x1 test", qspi_write_read_test), + Case("qspi write(1-1-4)/x1 read(2-2-2)/x1 repeat/x4 test", qspi_write_read_test), +#endif +#ifdef READ_1_1_4 + Case("qspi write(1-1-4)/x1 read(1-1-4)/x1 repeat/x1 test", qspi_write_read_test), + Case("qspi write(1-1-4)/x4 read(1-1-4)/x1 repeat/x1 test", qspi_write_read_test), + Case("qspi write(1-1-4)/x1 read(1-1-4)/x4 repeat/x1 test", qspi_write_read_test), + Case("qspi write(1-1-4)/x1 read(1-1-4)/x1 repeat/x4 test", qspi_write_read_test), +#endif + Case("qspi write(1-1-4)/x1 read(1-4-4)/x1 repeat/x1 test", qspi_write_read_test), + Case("qspi write(1-1-4)/x4 read(1-4-4)/x1 repeat/x1 test", qspi_write_read_test), + Case("qspi write(1-1-4)/x1 read(1-4-4)/x4 repeat/x1 test", qspi_write_read_test), + Case("qspi write(1-1-4)/x1 read(1-4-4)/x1 repeat/x4 test", qspi_write_read_test), +#ifdef READ_4_4_4 + Case("qspi write(1-1-4)/x1 read(4-4-4)/x1 repeat/x1 test", qspi_write_read_test), + Case("qspi write(1-1-4)/x4 read(4-4-4)/x1 repeat/x1 test", qspi_write_read_test), + Case("qspi write(1-1-4)/x1 read(4-4-4)/x4 repeat/x1 test", qspi_write_read_test), + Case("qspi write(1-1-4)/x1 read(4-4-4)/x1 repeat/x4 test", qspi_write_read_test), +#endif +#endif + +#ifdef WRITE_1_4_4 + Case("qspi write(1-4-4)/x1 read(1-1-1)/x1 repeat/x1 test", qspi_write_read_test), + Case("qspi write(1-4-4)/x4 read(1-1-1)/x1 repeat/x1 test", qspi_write_read_test), + Case("qspi write(1-4-4)/x1 read(1-1-1)/x4 repeat/x1 test", qspi_write_read_test), + Case("qspi write(1-4-4)/x1 read(1-1-1)/x1 repeat/x4 test", qspi_write_read_test), + Case("qspi write(1-4-4)/x1 read(1-1-2)/x1 repeat/x1 test", qspi_write_read_test), + Case("qspi write(1-4-4)/x4 read(1-1-2)/x1 repeat/x1 test", qspi_write_read_test), + Case("qspi write(1-4-4)/x1 read(1-1-2)/x4 repeat/x1 test", qspi_write_read_test), + Case("qspi write(1-4-4)/x1 read(1-1-2)/x1 repeat/x4 test", qspi_write_read_test), + Case("qspi write(1-4-4)/x1 read(1-2-2)/x1 repeat/x1 test", qspi_write_read_test), + Case("qspi write(1-4-4)/x4 read(1-2-2)/x1 repeat/x1 test", qspi_write_read_test), + Case("qspi write(1-4-4)/x1 read(1-2-2)/x4 repeat/x1 test", qspi_write_read_test), + Case("qspi write(1-4-4)/x1 read(1-2-2)/x1 repeat/x4 test", qspi_write_read_test), +#ifdef READ_2_2_2 + Case("qspi write(1-4-4)/x1 read(2-2-2)/x1 repeat/x1 test", qspi_write_read_test), + Case("qspi write(1-4-4)/x4 read(2-2-2)/x1 repeat/x1 test", qspi_write_read_test), + Case("qspi write(1-4-4)/x1 read(2-2-2)/x4 repeat/x1 test", qspi_write_read_test), + Case("qspi write(1-4-4)/x1 read(2-2-2)/x1 repeat/x4 test", qspi_write_read_test), +#endif +#ifdef READ_1_1_4 + Case("qspi write(1-4-4)/x1 read(1-1-4)/x1 repeat/x1 test", qspi_write_read_test), + Case("qspi write(1-4-4)/x4 read(1-1-4)/x1 repeat/x1 test", qspi_write_read_test), + Case("qspi write(1-4-4)/x1 read(1-1-4)/x4 repeat/x1 test", qspi_write_read_test), + Case("qspi write(1-4-4)/x1 read(1-1-4)/x1 repeat/x4 test", qspi_write_read_test), +#endif + Case("qspi write(1-4-4)/x1 read(1-4-4)/x1 repeat/x1 test", qspi_write_read_test), + Case("qspi write(1-4-4)/x4 read(1-4-4)/x1 repeat/x1 test", qspi_write_read_test), + Case("qspi write(1-4-4)/x1 read(1-4-4)/x4 repeat/x1 test", qspi_write_read_test), + Case("qspi write(1-4-4)/x1 read(1-4-4)/x1 repeat/x4 test", qspi_write_read_test), +#ifdef READ_4_4_4 + Case("qspi write(1-4-4)/x1 read(4-4-4)/x1 repeat/x1 test", qspi_write_read_test), + Case("qspi write(1-4-4)/x4 read(4-4-4)/x1 repeat/x1 test", qspi_write_read_test), + Case("qspi write(1-4-4)/x1 read(4-4-4)/x4 repeat/x1 test", qspi_write_read_test), + Case("qspi write(1-4-4)/x1 read(4-4-4)/x1 repeat/x4 test", qspi_write_read_test), +#endif +#endif + +#ifdef WRITE_4_4_4 + Case("qspi write(4-4-4)/x1 read(1-1-1)/x1 repeat/x1 test", qspi_write_read_test), + Case("qspi write(4-4-4)/x4 read(1-1-1)/x1 repeat/x1 test", qspi_write_read_test), + Case("qspi write(4-4-4)/x1 read(1-1-1)/x4 repeat/x1 test", qspi_write_read_test), + Case("qspi write(4-4-4)/x1 read(1-1-1)/x1 repeat/x4 test", qspi_write_read_test), + Case("qspi write(4-4-4)/x1 read(1-1-2)/x1 repeat/x1 test", qspi_write_read_test), + Case("qspi write(4-4-4)/x4 read(1-1-2)/x1 repeat/x1 test", qspi_write_read_test), + Case("qspi write(4-4-4)/x1 read(1-1-2)/x4 repeat/x1 test", qspi_write_read_test), + Case("qspi write(4-4-4)/x1 read(1-1-2)/x1 repeat/x4 test", qspi_write_read_test), + Case("qspi write(4-4-4)/x1 read(1-2-2)/x1 repeat/x1 test", qspi_write_read_test), + Case("qspi write(4-4-4)/x4 read(1-2-2)/x1 repeat/x1 test", qspi_write_read_test), + Case("qspi write(4-4-4)/x1 read(1-2-2)/x4 repeat/x1 test", qspi_write_read_test), + Case("qspi write(4-4-4)/x1 read(1-2-2)/x1 repeat/x4 test", qspi_write_read_test), +#ifdef READ_2_2_2 + Case("qspi write(4-4-4)/x1 read(2-2-2)/x1 repeat/x1 test", qspi_write_read_test), + Case("qspi write(4-4-4)/x4 read(2-2-2)/x1 repeat/x1 test", qspi_write_read_test), + Case("qspi write(4-4-4)/x1 read(2-2-2)/x4 repeat/x1 test", qspi_write_read_test), + Case("qspi write(4-4-4)/x1 read(2-2-2)/x1 repeat/x4 test", qspi_write_read_test), +#endif +#ifdef READ_1_1_4 + Case("qspi write(4-4-4)/x1 read(1-1-4)/x1 repeat/x1 test", qspi_write_read_test), + Case("qspi write(4-4-4)/x4 read(1-1-4)/x1 repeat/x1 test", qspi_write_read_test), + Case("qspi write(4-4-4)/x1 read(1-1-4)/x4 repeat/x1 test", qspi_write_read_test), + Case("qspi write(4-4-4)/x1 read(1-1-4)/x1 repeat/x4 test", qspi_write_read_test), +#endif + Case("qspi write(4-4-4)/x1 read(1-4-4)/x1 repeat/x1 test", qspi_write_read_test), + Case("qspi write(4-4-4)/x4 read(1-4-4)/x1 repeat/x1 test", qspi_write_read_test), + Case("qspi write(4-4-4)/x1 read(1-4-4)/x4 repeat/x1 test", qspi_write_read_test), + Case("qspi write(4-4-4)/x1 read(1-4-4)/x1 repeat/x4 test", qspi_write_read_test), +#ifdef READ_4_4_4 + Case("qspi write(4-4-4)/x1 read(4-4-4)/x1 repeat/x1 test", qspi_write_read_test), + Case("qspi write(4-4-4)/x4 read(4-4-4)/x1 repeat/x1 test", qspi_write_read_test), + Case("qspi write(4-4-4)/x1 read(4-4-4)/x4 repeat/x1 test", qspi_write_read_test), + Case("qspi write(4-4-4)/x1 read(4-4-4)/x1 repeat/x4 test", qspi_write_read_test), +#endif +#endif +}; + +utest::v1::status_t greentea_test_setup(const size_t number_of_cases) +{ + GREENTEA_SETUP(180, "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); +} + +#endif // !defined(QSPI_FLASH_CHIP_STRING) +#endif // !DEVICE_QSPI diff --git a/hal/tests/TESTS/mbed_hal/qspi/qspi_test.h b/hal/tests/TESTS/mbed_hal/qspi/qspi_test.h new file mode 100644 index 0000000..61c3dc7 --- /dev/null +++ b/hal/tests/TESTS/mbed_hal/qspi/qspi_test.h @@ -0,0 +1,102 @@ +/* mbed Microcontroller Library + * Copyright (c) 2018-2018 ARM Limited + * 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. + */ + +/** \addtogroup hal_qspi + * @{ + * \defgroup hal_qspi_tests Tests + * QSPI tests of the HAL. + * @{ + */ +#ifndef MBED_QSPI_TEST_H +#define MBED_QSPI_TEST_H + +#include "qspi_api.h" +#include "qspi_test_utils.h" + + +#if DEVICE_QSPI + +/** Test that qspi_init/qspi_free can be called multiple times. + * + * Given board provides QSPI. + * When qspi_init/qspi_free is called multiple times. + * Then qspi_init/qspi_free are successfully performed (no exception is generated). + * + */ +void qspi_init_free_test(void); + +/** Test qspi frequency setting. + * + * Given board provides QSPI, with QSPI already initialized. + * When set QSPI frequency. + * Then freguency setting is successfully performed (no exception is generated). + * + */ +void qspi_frequency_test(void); + +/** Template for write/read tests + * + * Test single write/read operation of a block of data to/from the specific memory address + * Given board provides QSPI, with QSPI already initialized. + * When perform write and then read operations. + * Then data is successfully written and then read (no exception is generated) and the read data is valid. + * + * Test multiple write/read operation of a block of data to/from the same specific memory address + * Given board provides QSPI, with QSPI already initialized. + * When perform write and then read operations. + * Then data is successfully written and then read (no exception is generated) and the read data is valid. + * + * Test multiple adjacent write and single read operation of a block of data to/from the specific memory address + * Given board provides QSPI, with QSPI already initialized. + * When perform write and then read operations. + * Then data is successfully written and then read (no exception is generated) and the read data is valid. + * + * Test single write and multiple adjacent read operation of a block of data to/from the specific memory address + * Given board provides QSPI, with QSPI already initialized. + * When perform write and then read operations. + * Then data is successfully written and then read (no exception is generated) and the read data is valid. + * + */ +template < qspi_bus_width_t write_inst_width, + qspi_bus_width_t write_addr_width, + qspi_bus_width_t write_data_width, + qspi_bus_width_t write_alt_width, + unsigned int write_cmd, + qspi_address_size_t write_addr_size, + qspi_alt_size_t write_alt_size, + uint32_t write_count, + qspi_bus_width_t read_inst_width, + qspi_bus_width_t read_addr_width, + qspi_bus_width_t read_data_width, + qspi_bus_width_t read_alt_width, + unsigned int read_cmd, + int read_dummy_cycles, + qspi_address_size_t read_addr_size, + qspi_alt_size_t read_alt_size, + int frequency, + uint32_t read_count, + uint32_t test_count, + uint32_t data_size, + uint32_t flash_addr> +void qspi_write_read_test(void); + +#endif + +#endif + +/** @}*/ +/** @}*/ diff --git a/hal/tests/TESTS/mbed_hal/qspi/qspi_test_utils.cpp b/hal/tests/TESTS/mbed_hal/qspi/qspi_test_utils.cpp new file mode 100644 index 0000000..4c69f92 --- /dev/null +++ b/hal/tests/TESTS/mbed_hal/qspi/qspi_test_utils.cpp @@ -0,0 +1,332 @@ +/* mbed Microcontroller Library + * Copyright (c) 2018-2018 ARM Limited + * 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. + */ + +#include "utest/utest.h" + +#include "hal/qspi_api.h" +#include "hal/us_ticker_api.h" +#include "qspi_test_utils.h" + +#include "unity/unity.h" + +#include // for memset + +#include "flash_configs/flash_configs.h" +#include "mbed.h" + +static qspi_status_t extended_enable(Qspi &qspi); +static qspi_status_t extended_disable(Qspi &qspi); +static qspi_status_t dual_enable(Qspi &qspi); +static qspi_status_t dual_disable(Qspi &qspi); +static qspi_status_t quad_enable(Qspi &qspi); +static qspi_status_t quad_disable(Qspi &qspi); + +void QspiCommand::configure(qspi_bus_width_t inst_width, qspi_bus_width_t addr_width, + qspi_bus_width_t data_width, qspi_bus_width_t alt_width, + qspi_address_size_t addr_size, qspi_alt_size_t alt_size, + int dummy_cycles) +{ + memset(&_cmd, 0, sizeof(qspi_command_t)); + _cmd.instruction.disabled = _cmd.address.disabled = _cmd.alt.disabled = true; + + _cmd.instruction.bus_width = inst_width; + _cmd.address.bus_width = addr_width; + _cmd.address.size = addr_size; + _cmd.alt.bus_width = alt_width; + _cmd.alt.size = alt_size; + _cmd.data.bus_width = data_width; + _cmd.dummy_count = dummy_cycles; +} + +void QspiCommand::set_dummy_cycles(int dummy_cycles) +{ + _cmd.dummy_count = dummy_cycles; +} + +void QspiCommand::build(int instruction, int address, int alt) +{ + _cmd.instruction.disabled = (instruction == QSPI_NO_INST); + if (!_cmd.instruction.disabled) { + _cmd.instruction.value = instruction; + } + + _cmd.address.disabled = (address == QSPI_NONE); + if (!_cmd.address.disabled) { + _cmd.address.value = address; + } + + _cmd.alt.disabled = (alt == QSPI_NONE); + if (!_cmd.alt.disabled) { + _cmd.alt.value = alt; + } +} + +qspi_command_t *QspiCommand::get() +{ + return &_cmd; +} + + +qspi_status_t read_register(uint32_t cmd, uint8_t *buf, uint32_t size, Qspi &q) +{ + q.cmd.build(cmd); + return qspi_command_transfer(&q.handle, q.cmd.get(), NULL, 0, buf, size); +} + +qspi_status_t write_register(uint32_t cmd, uint8_t *buf, uint32_t size, Qspi &q) +{ + q.cmd.build(cmd); + return qspi_command_transfer(&q.handle, q.cmd.get(), buf, size, NULL, 0); +} + + +QspiStatus flash_wait_for(uint32_t time_us, Qspi &qspi) +{ + uint8_t reg[QSPI_STATUS_REG_SIZE]; + qspi_status_t ret; + uint32_t curr_time; + + const ticker_data_t *const ticker = get_us_ticker_data(); + const uint32_t start = ticker_read(ticker); + + memset(reg, 255, QSPI_STATUS_REG_SIZE); + do { + ret = read_register(STATUS_REG, reg, QSPI_STATUS_REG_SIZE, qspi); + curr_time = ticker_read(ticker); + } while (((reg[0] & STATUS_BIT_WIP) != 0) && ((curr_time - start) < time_us)); + + if (((reg[0] & STATUS_BIT_WIP) == 0) && (ret == QSPI_STATUS_OK)) { + return sOK; + } else if (ret != QSPI_STATUS_OK) { + return sError; + } else if ((curr_time - start) >= time_us) { + return sTimeout; + } + return sUnknown; +} + +void flash_init(Qspi &qspi) +{ + uint8_t status[QSPI_STATUS_REG_SIZE]; + qspi_status_t ret; + + qspi.cmd.build(QSPI_CMD_RDSR); + ret = qspi_command_transfer(&qspi.handle, qspi.cmd.get(), NULL, 0, status, QSPI_STATUS_REG_SIZE); + TEST_ASSERT_EQUAL(QSPI_STATUS_OK, ret); + + // Only do reset enable if device needs it + if (QSPI_CMD_RSTEN != 0) { + qspi.cmd.build(QSPI_CMD_RSTEN); + ret = qspi_command_transfer(&qspi.handle, qspi.cmd.get(), NULL, 0, NULL, 0); + TEST_ASSERT_EQUAL(QSPI_STATUS_OK, ret); + + WAIT_FOR(WRSR_MAX_TIME, qspi); + } + + qspi.cmd.build(QSPI_CMD_RST); + ret = qspi_command_transfer(&qspi.handle, qspi.cmd.get(), NULL, 0, NULL, 0); + TEST_ASSERT_EQUAL(QSPI_STATUS_OK, ret); + + WAIT_FOR(WAIT_MAX_TIME, qspi); + + // Zero out status register to attempt to clear block protection bits + uint8_t blanks[QSPI_STATUS_REG_SIZE] = {0}; + + qspi.cmd.build(QSPI_CMD_WREN); + ret = qspi_command_transfer(&qspi.handle, qspi.cmd.get(), NULL, 0, NULL, 0); + TEST_ASSERT_EQUAL(QSPI_STATUS_OK, ret); + + qspi.cmd.build(QSPI_CMD_WRSR); + ret = qspi_command_transfer(&qspi.handle, qspi.cmd.get(), blanks, 1, NULL, 0); + TEST_ASSERT_EQUAL(QSPI_STATUS_OK, ret); + + WAIT_FOR(WRSR_MAX_TIME, qspi); +} + + +qspi_status_t write_enable(Qspi &qspi) +{ + uint8_t reg[QSPI_STATUS_REG_SIZE]; + qspi.cmd.build(QSPI_CMD_WREN); + + if (qspi_command_transfer(&qspi.handle, qspi.cmd.get(), NULL, 0, NULL, 0) != QSPI_STATUS_OK) { + return QSPI_STATUS_ERROR; + } + WAIT_FOR(WRSR_MAX_TIME, qspi); + + memset(reg, 0, QSPI_STATUS_REG_SIZE); + if (read_register(STATUS_REG, reg, QSPI_STATUS_REG_SIZE, qspi) != QSPI_STATUS_OK) { + return QSPI_STATUS_ERROR; + } + + return ((reg[0] & STATUS_BIT_WEL) != 0 ? QSPI_STATUS_OK : QSPI_STATUS_ERROR); +} + +qspi_status_t write_disable(Qspi &qspi) +{ + uint8_t reg[QSPI_STATUS_REG_SIZE]; + qspi.cmd.build(QSPI_CMD_WRDI); + + if (qspi_command_transfer(&qspi.handle, qspi.cmd.get(), NULL, 0, NULL, 0) != QSPI_STATUS_OK) { + return QSPI_STATUS_ERROR; + } + WAIT_FOR(WRSR_MAX_TIME, qspi); + + memset(reg, 0, QSPI_STATUS_REG_SIZE); + if (read_register(STATUS_REG, reg, QSPI_STATUS_REG_SIZE, qspi) != QSPI_STATUS_OK) { + return QSPI_STATUS_ERROR; + } + + return ((reg[0] & STATUS_BIT_WEL) == 0 ? QSPI_STATUS_OK : QSPI_STATUS_ERROR); +} + +void log_register(uint32_t cmd, uint32_t reg_size, Qspi &qspi, const char *str) +{ + qspi_status_t ret; + static uint8_t reg[QSPI_MAX_REG_SIZE]; + + ret = read_register(cmd, reg, reg_size, qspi); + TEST_ASSERT_EQUAL(QSPI_STATUS_OK, ret); + + for (uint32_t j = 0; j < reg_size; j++) { + utest_printf("%s byte %u (MSB first): ", str != NULL ? str : "", j); + for (int i = 0; i < 8; i++) { + utest_printf("%s ", ((reg[j] & (1 << (7 - i))) & 0xFF) == 0 ? "0" : "1"); + } + utest_printf("\r\n"); + } +} + +qspi_status_t erase(uint32_t erase_cmd, uint32_t flash_addr, Qspi &qspi) +{ + qspi.cmd.build(erase_cmd, flash_addr); + return qspi_command_transfer(&qspi.handle, qspi.cmd.get(), NULL, 0, NULL, 0); +} + +qspi_status_t mode_enable(Qspi &qspi, qspi_bus_width_t inst_width, qspi_bus_width_t addr_width, qspi_bus_width_t data_width) +{ + if (is_extended_mode(inst_width, addr_width, data_width)) { + return extended_enable(qspi); + } else if (is_dual_mode(inst_width, addr_width, data_width)) { + return dual_enable(qspi); + } else if (is_quad_mode(inst_width, addr_width, data_width)) { + return quad_enable(qspi); + } else { + return QSPI_STATUS_OK; + } +} + +qspi_status_t mode_disable(Qspi &qspi, qspi_bus_width_t inst_width, qspi_bus_width_t addr_width, qspi_bus_width_t data_width) +{ + if (is_extended_mode(inst_width, addr_width, data_width)) { + return extended_disable(qspi); + } else if (is_dual_mode(inst_width, addr_width, data_width)) { + return dual_disable(qspi); + } else if (is_quad_mode(inst_width, addr_width, data_width)) { + return quad_disable(qspi); + } else { + return QSPI_STATUS_OK; + } +} + +static qspi_status_t extended_enable(Qspi &qspi) +{ +#ifdef EXTENDED_SPI_ENABLE + EXTENDED_SPI_ENABLE(); +#else + return QSPI_STATUS_OK; +#endif +} + +static qspi_status_t extended_disable(Qspi &qspi) +{ +#ifdef EXTENDED_SPI_DISABLE + EXTENDED_SPI_DISABLE(); +#else + return QSPI_STATUS_OK; +#endif +} + +static qspi_status_t dual_enable(Qspi &qspi) +{ +#ifdef DUAL_ENABLE + DUAL_ENABLE(); +#else + return QSPI_STATUS_OK; +#endif +} + +static qspi_status_t dual_disable(Qspi &qspi) +{ +#ifdef DUAL_DISABLE + DUAL_DISABLE(); +#else + return QSPI_STATUS_OK; +#endif + +} + +static qspi_status_t quad_enable(Qspi &qspi) +{ +#ifdef QUAD_ENABLE + QUAD_ENABLE(); +#else + return QSPI_STATUS_OK; +#endif +} + +static qspi_status_t quad_disable(Qspi &qspi) +{ +#ifdef QUAD_DISABLE + QUAD_DISABLE(); +#else + return QSPI_STATUS_OK; +#endif +} + +qspi_status_t fast_mode_enable(Qspi &qspi) +{ +#ifdef FAST_MODE_ENABLE + FAST_MODE_ENABLE(); +#else + return QSPI_STATUS_OK; +#endif +} + +qspi_status_t fast_mode_disable(Qspi &qspi) +{ +#ifdef FAST_MODE_DISABLE + FAST_MODE_DISABLE(); +#else + return QSPI_STATUS_OK; +#endif +} + +bool is_extended_mode(qspi_bus_width_t inst_width, qspi_bus_width_t addr_width, qspi_bus_width_t data_width) +{ + return (inst_width == QSPI_CFG_BUS_SINGLE) && ((addr_width != QSPI_CFG_BUS_SINGLE) || (data_width != QSPI_CFG_BUS_SINGLE)); +} + +bool is_dual_mode(qspi_bus_width_t inst_width, qspi_bus_width_t addr_width, qspi_bus_width_t data_width) +{ + return (inst_width == QSPI_CFG_BUS_DUAL) && (addr_width == QSPI_CFG_BUS_DUAL) && (data_width == QSPI_CFG_BUS_DUAL); +} + +bool is_quad_mode(qspi_bus_width_t inst_width, qspi_bus_width_t addr_width, qspi_bus_width_t data_width) +{ + return (inst_width == QSPI_CFG_BUS_QUAD) && (addr_width == QSPI_CFG_BUS_QUAD) && (data_width == QSPI_CFG_BUS_QUAD); +} diff --git a/hal/tests/TESTS/mbed_hal/qspi/qspi_test_utils.h b/hal/tests/TESTS/mbed_hal/qspi/qspi_test_utils.h new file mode 100644 index 0000000..1e2efc9 --- /dev/null +++ b/hal/tests/TESTS/mbed_hal/qspi/qspi_test_utils.h @@ -0,0 +1,170 @@ +/* mbed Microcontroller Library + * Copyright (c) 2018-2018 ARM Limited + * 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. + */ +#ifndef MBED_QSPI_TEST_UTILS_H +#define MBED_QSPI_TEST_UTILS_H + +#include "flash_configs/flash_configs.h" +#include "unity/unity.h" + +#define QSPI_NONE (-1) + +enum QspiStatus { + sOK, + sError, + sTimeout, + sUnknown +}; + +class QspiCommand { +public: + void configure(qspi_bus_width_t inst_width, qspi_bus_width_t addr_width, qspi_bus_width_t data_width, + qspi_bus_width_t alt_width, qspi_address_size_t addr_size, qspi_alt_size_t alt_size, + int dummy_cycles = 0); + + void set_dummy_cycles(int dummy_cycles); + + void build(int instruction, int address = QSPI_NONE, int alt = QSPI_NONE); + + qspi_command_t *get(); + +private: + qspi_command_t _cmd; +}; + +struct Qspi { + qspi_t handle; + QspiCommand cmd; +}; + +// MODE_Command_Address_Data_Alt +#define MODE_1_1_1 QSPI_CFG_BUS_SINGLE, QSPI_CFG_BUS_SINGLE, QSPI_CFG_BUS_SINGLE, QSPI_CFG_BUS_SINGLE +#define MODE_1_1_2 QSPI_CFG_BUS_SINGLE, QSPI_CFG_BUS_SINGLE, QSPI_CFG_BUS_DUAL, QSPI_CFG_BUS_DUAL +#define MODE_1_2_2 QSPI_CFG_BUS_SINGLE, QSPI_CFG_BUS_DUAL, QSPI_CFG_BUS_DUAL, QSPI_CFG_BUS_DUAL +#define MODE_2_2_2 QSPI_CFG_BUS_DUAL, QSPI_CFG_BUS_DUAL, QSPI_CFG_BUS_DUAL, QSPI_CFG_BUS_DUAL +#define MODE_1_1_4 QSPI_CFG_BUS_SINGLE, QSPI_CFG_BUS_SINGLE, QSPI_CFG_BUS_QUAD, QSPI_CFG_BUS_QUAD +#define MODE_1_4_4 QSPI_CFG_BUS_SINGLE, QSPI_CFG_BUS_QUAD, QSPI_CFG_BUS_QUAD, QSPI_CFG_BUS_QUAD +#define MODE_4_4_4 QSPI_CFG_BUS_QUAD, QSPI_CFG_BUS_QUAD, QSPI_CFG_BUS_QUAD, QSPI_CFG_BUS_QUAD + +#define WRITE_1_1_1 MODE_1_1_1, QSPI_CMD_WRITE_1IO +#ifdef QSPI_CMD_WRITE_2IO +#define WRITE_1_2_2 MODE_1_2_2, QSPI_CMD_WRITE_2IO +#endif +#ifdef QSPI_CMD_WRITE_1I4O // Quad page program - command: 0x32 +#define WRITE_1_1_4 MODE_1_1_4, QSPI_CMD_WRITE_1I4O +#endif +#ifdef QSPI_CMD_WRITE_4IO +#define WRITE_1_4_4 MODE_1_4_4, QSPI_CMD_WRITE_4IO +#endif +#ifdef QSPI_CMD_WRITE_DPI +#define WRITE_2_2_2 MODE_2_2_2, QSPI_CMD_WRITE_DPI +#endif +#ifdef QSPI_CMD_WRITE_QPI +#define WRITE_4_4_4 MODE_4_4_4, QSPI_CMD_WRITE_QPI +#endif + + +#define READ_1_1_1 MODE_1_1_1, QSPI_CMD_READ_1IO, QSPI_READ_1IO_DUMMY_CYCLE +#ifdef QSPI_CMD_READ_1I2O +#define READ_1_1_2 MODE_1_1_2, QSPI_CMD_READ_1I2O, QSPI_READ_1I2O_DUMMY_CYCLE +#endif +#ifdef QSPI_CMD_READ_2IO +#define READ_1_2_2 MODE_1_2_2, QSPI_CMD_READ_2IO, QSPI_READ_2IO_DUMMY_CYCLE +#endif +#ifdef QSPI_CMD_READ_1I4O +#define READ_1_1_4 MODE_1_1_4, QSPI_CMD_READ_1I4O, QSPI_READ_1I4O_DUMMY_CYCLE +#endif +#ifdef QSPI_CMD_READ_4IO +#define READ_1_4_4 MODE_1_4_4, QSPI_CMD_READ_4IO, QSPI_READ_4IO_DUMMY_CYCLE +#endif + +#ifdef QSPI_CMD_READ_DPI +#define READ_2_2_2 MODE_2_2_2, QSPI_CMD_READ_DPI, QSPI_READ_2IO_DUMMY_CYCLE +#endif +#ifdef QSPI_CMD_READ_QPI +#define READ_4_4_4 MODE_4_4_4, QSPI_CMD_READ_QPI, QSPI_READ_4IO_DUMMY_CYCLE +#endif + +#define ADDR_SIZE_8 QSPI_CFG_ADDR_SIZE_8 +#define ADDR_SIZE_16 QSPI_CFG_ADDR_SIZE_16 +#define ADDR_SIZE_24 QSPI_CFG_ADDR_SIZE_24 +#define ADDR_SIZE_32 QSPI_CFG_ADDR_SIZE_32 + +#define ALT_SIZE_8 QSPI_CFG_ALT_SIZE_8 +#define ALT_SIZE_16 QSPI_CFG_ALT_SIZE_16 +#define ALT_SIZE_24 QSPI_CFG_ALT_SIZE_24 +#define ALT_SIZE_32 QSPI_CFG_ALT_SIZE_32 + +#define STATUS_REG QSPI_CMD_RDSR +#define CONFIG_REG0 QSPI_CMD_RDCR0 +#ifdef QSPI_CMD_RDCR1 +#define CONFIG_REG1 QSPI_CMD_RDCR1 +#endif +#ifdef QSPI_CMD_RDCR2 +#define CONFIG_REG2 QSPI_CMD_RDCR2 +#endif +#define SECURITY_REG QSPI_CMD_RDSCUR + +#ifndef QSPI_CONFIG_REG_1_SIZE +#define QSPI_CONFIG_REG_1_SIZE 0 +#endif + +#ifndef QSPI_CONFIG_REG_2_SIZE +#define QSPI_CONFIG_REG_2_SIZE 0 +#endif + + +#define SECTOR_ERASE QSPI_CMD_ERASE_SECTOR +#define BLOCK_ERASE QSPI_CMD_ERASE_BLOCK_64 + + +#define SECTOR_ERASE_MAX_TIME QSPI_ERASE_SECTOR_MAX_TIME +#define BLOCK32_ERASE_MAX_TIME QSPI_ERASE_BLOCK_32_MAX_TIME +#define BLOCK64_ERASE_MAX_TIME QSPI_ERASE_BLOCK_64_MAX_TIME +#define PAGE_PROG_MAX_TIME QSPI_PAGE_PROG_MAX_TIME +#define WRSR_MAX_TIME QSPI_WRSR_MAX_TIME +#define WAIT_MAX_TIME QSPI_WAIT_MAX_TIME + + + +qspi_status_t read_register(uint32_t cmd, uint8_t *buf, uint32_t size, Qspi &q); +qspi_status_t write_register(uint32_t cmd, uint8_t *buf, uint32_t size, Qspi &q); + +QspiStatus flash_wait_for(uint32_t time_us, Qspi &qspi); + +void flash_init(Qspi &qspi); + +qspi_status_t write_enable(Qspi &qspi); +qspi_status_t write_disable(Qspi &qspi); + +void log_register(uint32_t cmd, uint32_t reg_size, Qspi &qspi, const char *str = NULL); + +qspi_status_t mode_enable(Qspi &qspi, qspi_bus_width_t inst_width, qspi_bus_width_t addr_width, qspi_bus_width_t data_width); +qspi_status_t mode_disable(Qspi &qspi, qspi_bus_width_t inst_width, qspi_bus_width_t addr_width, qspi_bus_width_t data_width); + +qspi_status_t fast_mode_enable(Qspi &qspi); +qspi_status_t fast_mode_disable(Qspi &qspi); + +qspi_status_t erase(uint32_t erase_cmd, uint32_t flash_addr, Qspi &qspi); + +bool is_extended_mode(qspi_bus_width_t inst_width, qspi_bus_width_t addr_width, qspi_bus_width_t data_width); +bool is_dual_mode(qspi_bus_width_t inst_width, qspi_bus_width_t addr_width, qspi_bus_width_t data_width); +bool is_quad_mode(qspi_bus_width_t inst_width, qspi_bus_width_t addr_width, qspi_bus_width_t data_width); + +#define WAIT_FOR(timeout, q) TEST_ASSERT_EQUAL_MESSAGE(sOK, flash_wait_for(timeout, q), "flash_wait_for failed!!!") + + +#endif // MBED_QSPI_TEST_UTILS_H diff --git a/hal/tests/TESTS/mbed_hal/reset_reason/main.cpp b/hal/tests/TESTS/mbed_hal/reset_reason/main.cpp new file mode 100644 index 0000000..f449963 --- /dev/null +++ b/hal/tests/TESTS/mbed_hal/reset_reason/main.cpp @@ -0,0 +1,161 @@ +/* + * Copyright (c) 2018-2019 Arm Limited and affiliates. + * 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. + */ +#if !DEVICE_RESET_REASON +#error [NOT_SUPPORTED] Reset reason API not supported for this target +#else + +#include "greentea-client/test_env.h" +#include "unity/unity.h" +#include "hal/reset_reason_api.h" +#include "reset_reason_api_tests.h" +#include "mbed.h" + +#if DEVICE_WATCHDOG +# include "hal/watchdog_api.h" +# define MSG_VALUE_WATCHDOG_STATUS 1 +# define WDG_TIMEOUT_MS 50UL +#else +# define MSG_VALUE_WATCHDOG_STATUS 0 +#endif + +#define MSG_VALUE_DUMMY "0" +#define MSG_VALUE_RESET_REASON_GET "get" +#define MSG_VALUE_RESET_REASON_CLEAR "clear" +#define MSG_VALUE_RESET_REASON_CLEAR_ACK "cleared" +#define MSG_VALUE_DEVICE_RESET_ACK "ack" +#define MSG_VALUE_DEVICE_RESET_NVIC "nvic" +#define MSG_VALUE_DEVICE_RESET_WATCHDOG "watchdog" +#define MSG_VALUE_LEN 16 +#define MSG_KEY_LEN 16 + +#define MSG_KEY_DEVICE_READY "ready" +#define MSG_KEY_RESET_REASON_RAW "reason_raw" +#define MSG_KEY_RESET_REASON "reason" +#define MSG_KEY_DEVICE_RESET "reset" + +/* To prevent a loss of Greentea data, the serial buffers have to be flushed + * before the UART peripheral shutdown. The UART shutdown happens when the + * device is entering the deepsleep mode or performing a reset. + * + * With the current API, it is not possible to check if the hardware buffers + * are empty. However, it is possible to determine the time required for the + * buffers to flush. + * + * Assuming the biggest Tx FIFO of 128 bytes (as for CY8CPROTO_062_4343W) + * and a default UART config (9600, 8N1), flushing the Tx FIFO wold take: + * (1 start_bit + 8 data_bits + 1 stop_bit) * 128 * 1000 / 9600 = 133.3 ms. + * To be on the safe side, set the wait time to 150 ms. + */ +#define SERIAL_FLUSH_TIME_MS 150 + +typedef enum { + CMD_STATUS_CONTINUE, + CMD_STATUS_ERROR +} cmd_status_t; + +static cmd_status_t handle_command(const char *key, const char *value) +{ + if (strcmp(key, MSG_KEY_RESET_REASON_RAW) == 0) { + uint32_t raw_reason = hal_reset_reason_get_raw(); + char raw_reason_hex_str[9] = { }; + int raw_reason_hex_str_len = snprintf(raw_reason_hex_str, + sizeof raw_reason_hex_str, "%08lx", raw_reason); + + if (raw_reason_hex_str_len < 0) { + TEST_ASSERT_MESSAGE(0, "Failed to compose raw reset reason hex string."); + return CMD_STATUS_ERROR; + } + + greentea_send_kv(MSG_KEY_RESET_REASON_RAW, raw_reason_hex_str); + return CMD_STATUS_CONTINUE; + } + + if (strcmp(key, MSG_KEY_RESET_REASON) == 0 && strcmp(value, MSG_VALUE_RESET_REASON_GET) == 0) { + int reason = (int) hal_reset_reason_get(); + greentea_send_kv(MSG_KEY_RESET_REASON, reason); + return CMD_STATUS_CONTINUE; + } + + if (strcmp(key, MSG_KEY_RESET_REASON) == 0 && strcmp(value, MSG_VALUE_RESET_REASON_CLEAR) == 0) { + hal_reset_reason_clear(); + greentea_send_kv(MSG_KEY_RESET_REASON, MSG_VALUE_RESET_REASON_CLEAR_ACK); + return CMD_STATUS_CONTINUE; + } + + if (strcmp(key, MSG_KEY_DEVICE_RESET) == 0 && strcmp(value, MSG_VALUE_DEVICE_RESET_NVIC) == 0) { + greentea_send_kv(MSG_KEY_DEVICE_RESET, MSG_VALUE_DEVICE_RESET_ACK); + ThisThread::sleep_for(SERIAL_FLUSH_TIME_MS); // Wait for the serial buffers to flush. + NVIC_SystemReset(); + TEST_ASSERT_MESSAGE(0, "NVIC_SystemReset did not reset the device as expected."); + return CMD_STATUS_ERROR; + } + +#if DEVICE_WATCHDOG + if (strcmp(key, MSG_KEY_DEVICE_RESET) == 0 && strcmp(value, MSG_VALUE_DEVICE_RESET_WATCHDOG) == 0) { + greentea_send_kv(MSG_KEY_DEVICE_RESET, MSG_VALUE_DEVICE_RESET_ACK); + ThisThread::sleep_for(SERIAL_FLUSH_TIME_MS); // Wait for the serial buffers to flush. + watchdog_config_t config = { .timeout_ms = WDG_TIMEOUT_MS }; + if (hal_watchdog_init(&config) != WATCHDOG_STATUS_OK) { + TEST_ASSERT_MESSAGE(0, "hal_watchdog_init() error."); + return CMD_STATUS_ERROR; + } + ThisThread::sleep_for(2 * WDG_TIMEOUT_MS); // Watchdog should fire before twice the timeout value. + TEST_ASSERT_MESSAGE(0, "Watchdog did not reset the device as expected."); + return CMD_STATUS_ERROR; + } +#endif + + TEST_ASSERT_MESSAGE(0, "Invalid message key."); + return CMD_STATUS_ERROR; +} + +void test_reset_reason() +{ + reset_reason_capabilities_t rrcap = {}; + hal_reset_reason_get_capabilities(&rrcap); + char msg_value[11]; + int str_len = snprintf(msg_value, sizeof msg_value, "%08lx,%01x", rrcap.reasons, MSG_VALUE_WATCHDOG_STATUS); + if (str_len < 0) { + printf("Failed to compose a value string to be sent to host."); + GREENTEA_TESTSUITE_RESULT(0); + return; + } + + // Report readiness, capabilities and watchdog status. + greentea_send_kv(MSG_KEY_DEVICE_READY, msg_value); + + cmd_status_t cmd_status = CMD_STATUS_CONTINUE; + static char _key[MSG_KEY_LEN + 1] = { }; + static char _value[MSG_VALUE_LEN + 1] = { }; + + // Let the host side decide what to do and just handle the commands. + while (CMD_STATUS_CONTINUE == cmd_status) { + memset(_key, 0, sizeof _key); + memset(_value, 0, sizeof _value); + greentea_parse_kv(_key, _value, MSG_KEY_LEN, MSG_VALUE_LEN); + cmd_status = handle_command(_key, _value); + } +} + +int main() +{ + GREENTEA_SETUP(90, "reset_reason"); + test_reset_reason(); // The result of this test suite is reported by the host side. + GREENTEA_TESTSUITE_RESULT(0); // Fail on any error. +} + +#endif //!DEVICE_RESET_REASON diff --git a/hal/tests/TESTS/mbed_hal/reset_reason/reset_reason_api_tests.h b/hal/tests/TESTS/mbed_hal/reset_reason/reset_reason_api_tests.h new file mode 100644 index 0000000..80df8e0 --- /dev/null +++ b/hal/tests/TESTS/mbed_hal/reset_reason/reset_reason_api_tests.h @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2018-2019 Arm Limited and affiliates. + * 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. + */ + +/** + * @addtogroup hal_reset_reason_tests + * @{ + */ + +#ifndef MBED_HAL_RESET_REASON_API_TESTS_H +#define MBED_HAL_RESET_REASON_API_TESTS_H + +#if DEVICE_RESET_REASON + +#ifdef __cplusplus +extern "C" { +#endif + +/** Test the Reset Reason HAL API + * + * Given a device supporting a Reset Reason API, + * when the device is restarted, + * then the device returns a correct reset reason for every restart. + */ +void test_reset_reason(); + +#ifdef __cplusplus +} +#endif + +#endif + +#endif + +/** @}*/ + diff --git a/hal/tests/TESTS/mbed_hal/rtc/main.cpp b/hal/tests/TESTS/mbed_hal/rtc/main.cpp new file mode 100644 index 0000000..179bb3d --- /dev/null +++ b/hal/tests/TESTS/mbed_hal/rtc/main.cpp @@ -0,0 +1,261 @@ +/* mbed Microcontroller Library + * Copyright (c) 2017 ARM Limited + * 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. + */ + +#if !DEVICE_RTC +#error [NOT_SUPPORTED] RTC API not supported for this target +#else + +#include "utest/utest.h" +#include "unity/unity.h" +#include "greentea-client/test_env.h" +#include "rtc_test.h" + +#include "mbed.h" +#include "drivers/RealTimeClock.h" +#include "rtc_api.h" +#include +#include + +using namespace utest::v1; +using namespace std::chrono; + +static constexpr auto WAIT_TIME = 4s; +static constexpr auto WAIT_TOLERANCE = 1s; + +#define TEST_ASSERT_DURATION_WITHIN(delta, expected, actual) \ + do { \ + using ct = std::common_type_t; \ + TEST_ASSERT_INT_WITHIN(ct(delta).count(), ct(expected).count(), ct(actual).count()); \ + } while (0) + +#if DEVICE_LPTICKER +mstd::atomic_bool expired; + +void set_flag_true(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 auto start = RealTimeClock::time_point(100s); + 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 ThisThread::sleep_for() function for now. + */ + ThisThread::sleep_for(10ms); + + RealTimeClock::init(); + + if (deepsleep_mode == false) { + sleep_manager_lock_deep_sleep(); + } + + RealTimeClock::write(start); + + timeout.attach(set_flag_true, 4s); + + TEST_ASSERT(sleep_manager_can_deep_sleep_test_check() == deepsleep_mode); + + while (!expired) { + sleep(); + } + + const auto stop = RealTimeClock::now(); + + TEST_ASSERT_DURATION_WITHIN(1s, 4s, stop - start); + + timeout.detach(); + + if (deepsleep_mode == false) { + sleep_manager_unlock_deep_sleep(); + } + + RealTimeClock::free(); +} +#endif + +/* Test that ::rtc_init can be called multiple times. */ +void rtc_init_test() +{ + for (int i = 0; i < 10; i++) { + RealTimeClock::init(); + } + + RealTimeClock::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 auto start = RealTimeClock::time_point(100s); + RealTimeClock::init(); + RealTimeClock::write(start); + RealTimeClock::free(); + + ThisThread::sleep_for(WAIT_TIME); + + RealTimeClock::init(); + const auto stop = RealTimeClock::now(); + const bool enabled = RealTimeClock::isenabled(); + RealTimeClock::free(); + + TEST_ASSERT_TRUE(enabled); + TEST_ASSERT_DURATION_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 auto start = RealTimeClock::time_point(0xffffes); + RealTimeClock::init(); + + RealTimeClock::write(start); + auto last = start; + while (last < start + 4s) { + const auto cur = RealTimeClock::now(); + TEST_ASSERT(cur >= last); + last = cur; + } + + RealTimeClock::free(); +} + +/* Test that the RTC correctly handles different time values. */ +void rtc_range_test() +{ + static const RealTimeClock::time_point starts[] = { + RealTimeClock::time_point{0x00000000s}, + RealTimeClock::time_point{0xEFFFFFFFs}, + RealTimeClock::time_point{0x00001000s}, + RealTimeClock::time_point{0x00010000s}, + }; + + RealTimeClock::init(); + for (const auto &start : starts) { + RealTimeClock::write(start); + ThisThread::sleep_for(WAIT_TIME); + const auto stop = RealTimeClock::now(); + TEST_ASSERT_DURATION_WITHIN(WAIT_TOLERANCE, WAIT_TIME, stop - start); + } + RealTimeClock::free(); +} + +/* Test that the RTC accuracy is at least 10%. */ +void rtc_accuracy_test() +{ + Timer timer1; + + const auto start = RealTimeClock::time_point(100s); + RealTimeClock::init(); + RealTimeClock::write(start); + + timer1.start(); + while (RealTimeClock::now() < (start + 10s)) { + /* Just wait. */ + } + timer1.stop(); + + /* RTC accuracy is at least 10%. */ + TEST_ASSERT_DURATION_WITHIN(1s, 10s, timer1.elapsed_time()); +} + +/* Test that ::rtc_write/::rtc_read functions provides availability to set/get RTC time. */ +void rtc_write_read_test() +{ + RealTimeClock::init(); + + /* NB: IAR compilation issue with "auto init_val = RealTimeClock::time_point(100s)" */ + for (auto init_val = RealTimeClock::time_point(seconds(100)); init_val < RealTimeClock::time_point(400s); init_val += 100s) { + core_util_critical_section_enter(); + + RealTimeClock::write(init_val); + const auto read_val = RealTimeClock::now(); + + 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(init_val == read_val); + } + + RealTimeClock::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. + */ + + RealTimeClock::init(); + RealTimeClock::write(RealTimeClock::time_point(0s)); + TEST_ASSERT_TRUE(RealTimeClock::isenabled()); + RealTimeClock::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); +} + +#endif // !DEVICE_RTC diff --git a/hal/tests/TESTS/mbed_hal/rtc/rtc_test.h b/hal/tests/TESTS/mbed_hal/rtc/rtc_test.h new file mode 100644 index 0000000..eb75995 --- /dev/null +++ b/hal/tests/TESTS/mbed_hal/rtc/rtc_test.h @@ -0,0 +1,116 @@ +/* mbed Microcontroller Library + * Copyright (c) 2017-2017 ARM Limited + * 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. + */ + +/** \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 + +/** @}*/ diff --git a/hal/tests/TESTS/mbed_hal/rtc_reset/main.cpp b/hal/tests/TESTS/mbed_hal/rtc_reset/main.cpp new file mode 100644 index 0000000..ca01b1b --- /dev/null +++ b/hal/tests/TESTS/mbed_hal/rtc_reset/main.cpp @@ -0,0 +1,105 @@ +/* mbed Microcontroller Library + * Copyright (c) 2017 ARM Limited + * 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. + */ + +#if !DEVICE_RTC +#error [NOT_SUPPORTED] RTC API not supported for this target +#else + +#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(); +} + +#endif // !DEVICE_RTC diff --git a/hal/tests/TESTS/mbed_hal/rtc_reset/rtc_reset_test.h b/hal/tests/TESTS/mbed_hal/rtc_reset/rtc_reset_test.h new file mode 100644 index 0000000..66dfc53 --- /dev/null +++ b/hal/tests/TESTS/mbed_hal/rtc_reset/rtc_reset_test.h @@ -0,0 +1,50 @@ +/* mbed Microcontroller Library + * Copyright (c) 2017-2017 ARM Limited + * 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. + */ + +/** \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 + +/** @}*/ diff --git a/hal/tests/TESTS/mbed_hal/rtc_time/main.cpp b/hal/tests/TESTS/mbed_hal/rtc_time/main.cpp new file mode 100644 index 0000000..c4c47b3 --- /dev/null +++ b/hal/tests/TESTS/mbed_hal/rtc_time/main.cpp @@ -0,0 +1,221 @@ +/* mbed Microcontroller Library + * Copyright (c) 2017 ARM Limited + * 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. + */ + +#include "utest/utest.h" +#include "unity/unity.h" +#include "greentea-client/test_env.h" + +#include "mbed.h" +#include "mbed_mktime.h" + +#define LAST_VALID_YEAR 206 + +using namespace utest::v1; + +/* Regular is_leap_year, see platform/mbed_mktime.c for the optimised version. */ +bool is_leap_year(int year) +{ + year = 1900 + year; + if (year % 4) { + return false; + } else if (year % 100) { + return true; + } else if (year % 400) { + return false; + } + return true; +} + +/* Test the optimised version of _rtc_is_leap_year() against the generic version. + * + * Note: This test case is designed for both types of RTC devices: + * - RTC devices which handle correctly leap years in whole range (1970 - 2106). + * - RTC devices which does not handle correctly leap years in whole range (1970 - 2106). + * This RTC devices uses simpler leap year detection and incorrectly treat 2100 as a leap year. + * rtc_leap_year_support variable specifies which device is tested. + * + * Given is year in valid range. + * When _rtc_is_leap_year() function is called. + * Then _rtc_is_leap_year() returns true if given year is a leap year; false otherwise. + */ +template +void test_is_leap_year() +{ + for (int i = 70; i <= LAST_VALID_YEAR; ++i) { + bool expected = is_leap_year(i); + + /* Add exception for year 2100. */ + if (rtc_leap_year_support == RTC_4_YEAR_LEAP_YEAR_SUPPORT && i == 200) { + expected = true; + } + + bool actual_value = _rtc_is_leap_year(i, rtc_leap_year_support); + + if (expected != actual_value) { + printf("Leap year failed with i = %d\r\n", i); + } + TEST_ASSERT_EQUAL(expected, actual_value); + } +} + +/* Structure to test border values for _rtc_maketime(). */ +typedef struct { + struct tm timeinfo; + time_t exp_seconds; // if result is false then exp_seconds is irrelevant + bool result; +} test_mk_time_struct; + +/* Test boundary values for _rtc_maketime(). + * + * Note: This test case is designed for both types of RTC devices: + * - RTC devices which handle correctly leap years in whole range (1970 - 2106). + * - RTC devices which does not handle correctly leap years in whole range (1970 - 2106). + * This RTC devices uses simpler leap year detection and incorrectly treat 2100 as a leap year. + * rtc_leap_year_support variable specifies which device is tested. + * + * Given is boundary calendar time. + * When _rtc_maketime() function is called to convert the calendar time into timestamp. + * Then if given calendar time is valid function returns true and conversion result, otherwise returns false. + */ +template +void test_mk_time_boundary() +{ + test_mk_time_struct *pTestCases; + + /* Array which contains data to test boundary values for the RTC devices which handles correctly leap years in + * whole range (1970 - 2106). + * Expected range: the 1st of January 1970 at 00:00:00 (seconds: 0) to the 7th of February 2106 at 06:28:15 (seconds: UINT_MAX). + */ + test_mk_time_struct test_mk_time_arr_full[] = { + {{ 0, 0, 0, 1, 0, 70, 0, 0, 0 }, (time_t) 0, true}, // valid lower bound - the 1st of January 1970 at 00:00:00 + {{ 59, 59, 23, 31, 11, 59, 0, 0, 0 }, (time_t) 0, false }, // invalid lower bound - the 31st of December 1969 at 23:59:59 + + {{ 15, 28, 6, 7, 1, 206, 0, 0, 0 }, (time_t)(UINT_MAX), true }, // valid upper bound - the 7th of February 2106 at 06:28:15 + {{ 16, 28, 6, 7, 1, 206, 0, 0, 0 }, (time_t) 0, false }, // invalid upper bound - the 7th of February 2106 at 06:28:16 + }; + + /* Array which contains data to test boundary values for the RTC devices which does not handle correctly leap years in + * whole range (1970 - 2106). On this platforms we will be one day off after 28.02.2100 since 2100 year will be + * incorrectly treated as a leap year. + * Expected range: the 1st of January 1970 at 00:00:00 (seconds: 0) to the 6th of February 2106 at 06:28:15 (seconds: UINT_MAX). + */ + test_mk_time_struct test_mk_time_arr_partial[] = { + {{ 0, 0, 0, 1, 0, 70, 0, 0, 0 }, (time_t) 0, true}, // valid lower bound - the 1st of January 1970 at 00:00:00 + {{ 59, 59, 23, 31, 11, 59, 0, 0, 0 }, (time_t) 0, false }, // invalid lower bound - the 31st of December 1969 at 23:59:59 + + {{ 15, 28, 6, 6, 1, 206, 0, 0, 0 }, (time_t)(UINT_MAX), true }, // valid upper bound - the 6th of February 2106 at 06:28:15 + {{ 16, 28, 6, 6, 1, 206, 0, 0, 0 }, (time_t) 0, false }, // invalid upper bound - the 6th of February 2106 at 06:28:16 + }; + + /* Select array with test cases. */ + if (rtc_leap_year_support == RTC_FULL_LEAP_YEAR_SUPPORT) { + pTestCases = test_mk_time_arr_full; + } else { + pTestCases = test_mk_time_arr_partial; + } + + for (int i = 0; i < (sizeof(test_mk_time_arr_full) / (sizeof(test_mk_time_struct))); i++) { + time_t seconds; + bool result = _rtc_maketime(&pTestCases[i].timeinfo, &seconds, rtc_leap_year_support); + + TEST_ASSERT_EQUAL(pTestCases[i].result, result); + + /* If the result is false, then we have conversion error - skip checking seconds. */ + if (pTestCases[i].result) { + TEST_ASSERT_EQUAL_UINT32(pTestCases[i].exp_seconds, seconds); + } + } +} + +/* Test _rtc_maketime() function - call with invalid parameters. + * + * Given is _rtc_maketime() function. + * When _rtc_maketime() function is called with invalid parameter. + * Then _rtc_maketime() function returns false. + */ +void test_mk_time_invalid_param() +{ + time_t seconds; + struct tm timeinfo; + + TEST_ASSERT_EQUAL(false, _rtc_maketime(NULL, &seconds, RTC_FULL_LEAP_YEAR_SUPPORT)); + TEST_ASSERT_EQUAL(false, _rtc_maketime(NULL, &seconds, RTC_4_YEAR_LEAP_YEAR_SUPPORT)); + TEST_ASSERT_EQUAL(false, _rtc_maketime(&timeinfo, NULL, RTC_FULL_LEAP_YEAR_SUPPORT)); + TEST_ASSERT_EQUAL(false, _rtc_maketime(&timeinfo, NULL, RTC_4_YEAR_LEAP_YEAR_SUPPORT)); +} + +/* Test _rtc_localtime() function - call with invalid parameters. + * + * Given is _rtc_localtime() function. + * When _rtc_localtime() function is called with invalid parameter. + * Then _rtc_localtime() function returns false. + */ +void test_local_time_invalid_param() +{ + TEST_ASSERT_EQUAL(false, _rtc_localtime(1, NULL, RTC_FULL_LEAP_YEAR_SUPPORT)); + TEST_ASSERT_EQUAL(false, _rtc_localtime(1, NULL, RTC_4_YEAR_LEAP_YEAR_SUPPORT)); +} + +/* Test set_time() function called a few seconds apart. + * + * Given is set_time() function. + * When set_time() is used to set the system time two times. + * Then if the value returned from time() is always correct return true, otherwise return false. + */ +#define NEW_TIME 15 +void test_set_time_twice() +{ + time_t current_time; + + /* Set the time to NEW_TIME and check it */ + set_time(NEW_TIME); + current_time = time(NULL); + TEST_ASSERT_EQUAL(true, (current_time == NEW_TIME)); + + /* Wait 2 seconds */ + ThisThread::sleep_for(2000); + + /* set the time to NEW_TIME again and check it */ + set_time(NEW_TIME); + current_time = time(NULL); + TEST_ASSERT_EQUAL(true, (current_time == NEW_TIME)); +} + +Case cases[] = { + Case("test is leap year - RTC leap years full support", test_is_leap_year), + Case("test is leap year - RTC leap years partial support", test_is_leap_year), + Case("test make time boundary values - RTC leap years full support", test_mk_time_boundary), + Case("test make time boundary values - RTC leap years partial support", test_mk_time_boundary), + Case("test make time - invalid param", test_mk_time_invalid_param), + Case("test local time - invalid param", test_local_time_invalid_param), +#if DEVICE_RTC || DEVICE_LPTICKER + Case("test set_time twice", test_set_time_twice), +#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() +{ + return Harness::run(specification); +} diff --git a/hal/tests/TESTS/mbed_hal/rtc_time_conv/main.cpp b/hal/tests/TESTS/mbed_hal/rtc_time_conv/main.cpp new file mode 100644 index 0000000..0a71654 --- /dev/null +++ b/hal/tests/TESTS/mbed_hal/rtc_time_conv/main.cpp @@ -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: + * - _rtc_maketime() function converts a calendar time into time since UNIX epoch as a time_t, + * - _rtc_localtime() function converts a given time in seconds since epoch into calendar time. + */ + +#include "mbed.h" +#include "greentea-client/test_env.h" +#include "utest/utest.h" +#include "unity/unity.h" +#include "mbed_mktime.h" + +#define LAST_VALID_YEAR 206 + +using namespace utest::v1; + +static rtc_leap_year_support_t rtc_leap_year_support; + +/* + * regular is_leap_year, see platform/mbed_mktime.c for the optimised version + */ +bool is_leap_year(int year) +{ + year = 1900 + year; + if (year % 4) { + return false; + } else if (year % 100) { + return true; + } else if (year % 400) { + return false; + } + return true; +} + +struct tm make_time_info(int year, int month, int day, int hours, int minutes, int seconds) +{ + struct tm timeinfo = { + seconds, // tm_sec + minutes, // tm_min + hours, // tm_hour + day, // tm_mday + month, // tm_mon + year, // tm_year + 0, // tm_wday + 0, // tm_yday + 0, // tm_isdst + }; + return timeinfo; +} + +/* Test _rtc_maketime() and _rtc_localtime() across wide range + * + * Note: This test functions handles both types of RTC devices: + * - devices which supports full leap years support in range 1970 - 2106. + * - devices which supports parial leap years support and incorrectly treats 2100 year as a leap year. + * + * Given is valid calendar time. + * When _rtc_maketime() is used to generate timestamp from calendar time and _rtc_localtime() is used to convert + * timestamp to calendar time. + * Then both operations gives valid results. + */ +void test_case_mktime_localtime() +{ + char _key[11] = + { }; + char _value[128] = + { }; + + size_t years[] = {70, 71, 100, 196, 200, 205}; + + /* Inform host part of the test about tested RTC type. */ + greentea_send_kv("leap_year_setup", rtc_leap_year_support); + + /* Check the first and last last day of each month. */ + for (size_t year_id = 0; year_id < (sizeof(years) / sizeof(size_t)) ; ++year_id) { + for (size_t month = 0; month < 12; ++month) { + for (size_t dayid = 0; dayid < 2; ++dayid) { + + size_t year = years[year_id]; + + size_t day = 0; + /* Test the first and the last day of each month: + * day 0 - first, + * day 1 - last + * */ + switch (dayid) { + case 0: + day = 1; + break; + + case 1: + day = 31; + + if (month == 3 || month == 5 || month == 8 || month == 10) { + day = 30; + } + + if (month == 1) { + day = 28; + } + + if (month == 1 && is_leap_year(year)) { + day = 29; + } + + /* Additional conditions for RTCs with partial leap year support. */ + if (month == 1 && year == 200 && rtc_leap_year_support == RTC_4_YEAR_LEAP_YEAR_SUPPORT) { + day = 29; + } + + break; + + default: + break; + } + + tm time_info = make_time_info(year, month, day, 23, dayid ? 59 : 0, dayid ? 59 : 0); + + time_t actual_timestamp; + + TEST_ASSERT_TRUE(_rtc_maketime(&time_info, &actual_timestamp, rtc_leap_year_support)); + + greentea_send_kv("timestamp", (int) actual_timestamp); + + greentea_parse_kv(_key, _value, sizeof(_key), sizeof(_value)); + + TEST_ASSERT_EQUAL_STRING("passed", _key); + + /* Response which indicates success contains encoded week day + * and year day needed to verify _rtc_localtime(). + * Use validated timestamp to generate and validate calendar time. + */ + + unsigned int buf = (unsigned int) strtol(_value, NULL, 10); + + time_info.tm_wday = ((buf >> 16) & 0x0000FFFF); + time_info.tm_yday = (buf & 0x0000FFFF); + + tm actual_time_info; + + bool result = _rtc_localtime((time_t) actual_timestamp, &actual_time_info, rtc_leap_year_support); + + TEST_ASSERT_TRUE(result); + TEST_ASSERT_EQUAL_UINT32_MESSAGE(time_info.tm_sec, actual_time_info.tm_sec, "invalid seconds"); + TEST_ASSERT_EQUAL_UINT32_MESSAGE(time_info.tm_min, actual_time_info.tm_min, "invalid minutes"); + TEST_ASSERT_EQUAL_UINT32_MESSAGE(time_info.tm_hour, actual_time_info.tm_hour, "invalid hours"); + TEST_ASSERT_EQUAL_UINT32_MESSAGE(time_info.tm_mday, actual_time_info.tm_mday, "invalid day"); + TEST_ASSERT_EQUAL_UINT32_MESSAGE(time_info.tm_mon, actual_time_info.tm_mon, "invalid month"); + TEST_ASSERT_EQUAL_UINT32_MESSAGE(time_info.tm_year, actual_time_info.tm_year, "invalid year"); + TEST_ASSERT_EQUAL_UINT32_MESSAGE(time_info.tm_wday, actual_time_info.tm_wday, "invalid weekday"); + TEST_ASSERT_EQUAL_UINT32_MESSAGE(time_info.tm_yday, actual_time_info.tm_yday, "invalid year day"); + } + } + } +} + +utest::v1::status_t full_leap_year_case_setup_handler_t(const Case *const source, const size_t index_of_case) +{ + rtc_leap_year_support = RTC_FULL_LEAP_YEAR_SUPPORT; + + return greentea_case_setup_handler(source, index_of_case); +} + +utest::v1::status_t partial_leap_year_case_setup_handler_t(const Case *const source, const size_t index_of_case) +{ + rtc_leap_year_support = RTC_4_YEAR_LEAP_YEAR_SUPPORT; + + return greentea_case_setup_handler(source, index_of_case); +} + +utest::v1::status_t 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("test make time and local time - RTC leap years full support", full_leap_year_case_setup_handler_t, test_case_mktime_localtime, teardown_handler_t), + Case("test make time and local time - RTC leap years partial support", partial_leap_year_case_setup_handler_t, test_case_mktime_localtime, teardown_handler_t), +}; + +utest::v1::status_t greentea_test_setup(const size_t number_of_cases) +{ + GREENTEA_SETUP(300, "rtc_calc_auto"); + return greentea_test_setup_handler(number_of_cases); +} + +Specification specification(greentea_test_setup, cases, greentea_test_teardown_handler); + +int main() +{ + Harness::run(specification); +} diff --git a/hal/tests/TESTS/mbed_hal/sleep/main.cpp b/hal/tests/TESTS/mbed_hal/sleep/main.cpp new file mode 100644 index 0000000..c0a21d8 --- /dev/null +++ b/hal/tests/TESTS/mbed_hal/sleep/main.cpp @@ -0,0 +1,268 @@ +/* mbed Microcontroller Library + * Copyright (c) 2017 ARM Limited + * 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. + */ +#if !DEVICE_SLEEP +#error [NOT_SUPPORTED] sleep not supported for this target +#else + +#include "mbed.h" + +#include "utest/utest.h" +#include "unity/unity.h" +#include "greentea-client/test_env.h" +#include "mbed_lp_ticker_wrapper.h" +#include "hal/us_ticker_api.h" + +#include "sleep_test_utils.h" +#include "sleep_api_tests.h" + +using namespace utest::v1; + +static char info[512] = {0}; + +/* 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 */ +#if defined(MBED_CPU_STATS_ENABLED) +/* extra 25us for stats computation (for more details see MBED_CPU_STATS_ENABLED) */ +static const uint32_t sleep_mode_delta_us = (10 + 4 + 5 + 25); +#else +static const uint32_t sleep_mode_delta_us = (10 + 4 + 5); +#endif + +/* 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); + +/* 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() +{ + 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) { + /* Give some time Green Tea to finish UART transmission before entering + * sleep mode. + */ + busy_wait_ms(SERIAL_FLUSH_TIME_MS); + + /* note: us_ticker_read() operates on ticks. */ + const timestamp_t start_timestamp = us_ticker_read(); + const timestamp_t next_match_timestamp = overflow_protect(start_timestamp + us_to_ticks(i, ticker_freq), + ticker_width); + + us_ticker_set_interrupt(next_match_timestamp); + + sleep(); + + const unsigned int wakeup_timestamp = us_ticker_read(); + + sprintf(info, "Delta ticks: %u, Ticker width: %u, Expected wake up tick: %d, Actual wake up tick: %d, delay ticks: %d, wake up after ticks: %d", + us_to_ticks(sleep_mode_delta_us, ticker_freq), ticker_width, next_match_timestamp, wakeup_timestamp, us_to_ticks(i, ticker_freq), wakeup_timestamp - start_timestamp); + + TEST_ASSERT_MESSAGE(compare_timestamps(us_to_ticks(sleep_mode_delta_us, ticker_freq), + ticker_width, next_match_timestamp, wakeup_timestamp), info); + } + + set_us_ticker_irq_handler(us_ticker_irq_handler_org); + + sleep_manager_unlock_deep_sleep(); + TEST_ASSERT_TRUE(sleep_manager_can_deep_sleep()); +} + +#if 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); + + 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) { + /* Give some time Green Tea to finish UART transmission before entering + * deep-sleep mode. + */ + busy_wait_ms(SERIAL_FLUSH_TIME_MS); + + /* note: lp_ticker_read() operates on ticks. */ + const timestamp_t start_timestamp = lp_ticker_read(); + const timestamp_t next_match_timestamp = overflow_protect(start_timestamp + us_to_ticks(i, ticker_freq), ticker_width); + + lp_ticker_set_interrupt(next_match_timestamp); + + /* On some targets like STM family boards with LPTIM enabled there is a required delay (~100 us) before we are able to + reprogram LPTIM_COMPARE register back to back. This is handled by the low level lp ticker wrapper which uses LPTIM_CMPOK interrupt. + CMPOK fires when LPTIM_COMPARE register can be safely reprogrammed again. During this period deep-sleep is locked. + This means that on these platforms we have additional interrupt (CMPOK) fired always ~100 us after programming lp ticker. + Since this interrupt wakes-up the board from the sleep we need to go to sleep after CMPOK is handled. */ + TEST_ASSERT_TRUE(sleep_manager_can_deep_sleep_test_check()); + + sleep(); + + /* On some targets like STM family boards with LPTIM enabled an interrupt is triggered on counter rollover. + We need special handling for cases when next_match_timestamp < start_timestamp (interrupt is to be fired after rollover). + In such case after first wake-up we need to reset interrupt and go back to sleep waiting for the valid one. + NOTE: Above comment (CMPOK) applies also here.*/ +#if MBED_CONF_TARGET_LPTICKER_LPTIM + if ((next_match_timestamp < start_timestamp) && lp_ticker_read() < next_match_timestamp) { + lp_ticker_set_interrupt(next_match_timestamp); + wait_ns(200000); + sleep(); + } +#endif + + const timestamp_t wakeup_timestamp = lp_ticker_read(); + + sprintf(info, "Delta ticks: %u, Ticker width: %u, Expected wake up tick: %d, Actual wake up tick: %d, delay ticks: %d, wake up after ticks: %d", + us_to_ticks(deepsleep_mode_delta_us, ticker_freq), ticker_width, next_match_timestamp, wakeup_timestamp, us_to_ticks(i, ticker_freq), wakeup_timestamp - start_timestamp); + + TEST_ASSERT_MESSAGE(compare_timestamps(us_to_ticks(deepsleep_mode_delta_us, ticker_freq), ticker_width, + next_match_timestamp, wakeup_timestamp), info); + } + + 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. + */ + busy_wait_ms(SERIAL_FLUSH_TIME_MS); + + TEST_ASSERT_TRUE_MESSAGE(sleep_manager_can_deep_sleep(), "deep sleep should not be locked"); + + const timestamp_t wakeup_time = lp_ticker_read() + us_to_ticks(20000, lp_ticker_freq); + lp_ticker_set_interrupt(wakeup_time); + + /* Wait for CMPOK */ + TEST_ASSERT_TRUE(sleep_manager_can_deep_sleep_test_check()); + + const unsigned int us_ticks_before_sleep = us_ticker_read(); + + 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)); + + sprintf(info, "Delta ticks: %u, Ticker width: %u, Expected wake up tick: %d, Actual wake up tick: %d", + us_to_ticks(deepsleep_mode_delta_us, lp_ticker_freq), lp_ticker_width, wakeup_time, lp_ticks_after_sleep); + + /* Check if we have woken-up after expected time. */ + TEST_ASSERT_MESSAGE(compare_timestamps(us_to_ticks(deepsleep_mode_delta_us, lp_ticker_freq), lp_ticker_width, + wakeup_time, lp_ticks_after_sleep), info); +} + +#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"); + /* Suspend RTOS Kernel to enable sleep modes. */ +#if defined(MBED_CONF_RTOS_PRESENT) + osKernelSuspend(); +#endif +#if DEVICE_LPTICKER + ticker_suspend(get_lp_ticker_data()); +#if DEVICE_LPTICKER && (LPTICKER_DELAY_TICKS > 0) + lp_ticker_wrapper_suspend(); +#endif +#endif + ticker_suspend(get_us_ticker_data()); + + us_ticker_init(); +#if DEVICE_LPTICKER + lp_ticker_init(); +#endif + + return greentea_test_setup_handler(number_of_cases); +} + +void greentea_test_teardown(const size_t passed, const size_t failed, const failure_t failure) +{ + ticker_resume(get_us_ticker_data()); +#if DEVICE_LPTICKER +#if DEVICE_LPTICKER && (LPTICKER_DELAY_TICKS > 0) + lp_ticker_wrapper_resume(); +#endif + ticker_resume(get_lp_ticker_data()); +#endif +#if defined(MBED_CONF_RTOS_PRESENT) + osKernelResume(0); +#endif + greentea_test_teardown_handler(passed, failed, failure); +} + +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); + +int main() +{ + Harness::run(specification); +} + +#endif // !DEVICE_SLEEP diff --git a/hal/tests/TESTS/mbed_hal/sleep/sleep_api_tests.h b/hal/tests/TESTS/mbed_hal/sleep/sleep_api_tests.h new file mode 100644 index 0000000..2e056af --- /dev/null +++ b/hal/tests/TESTS/mbed_hal/sleep/sleep_api_tests.h @@ -0,0 +1,70 @@ +/* mbed Microcontroller Library + * Copyright (c) 2017 ARM Limited + * 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. + */ + +/** \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 + +/**@}*/ diff --git a/hal/tests/TESTS/mbed_hal/sleep/sleep_test_utils.h b/hal/tests/TESTS/mbed_hal/sleep/sleep_test_utils.h new file mode 100644 index 0000000..e9e3de7 --- /dev/null +++ b/hal/tests/TESTS/mbed_hal/sleep/sleep_test_utils.h @@ -0,0 +1,118 @@ +/* mbed Microcontroller Library + * Copyright (c) 2017 ARM Limited + * 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. + */ + +/** + * @addtogroup hal_sleep + * @{ + * @defgroup hal_sleep_test_util Tests + * Tests of the sleep HAL. + * @{ + */ + +#ifndef MBED_SLEEP_TEST_UTILS_H +#define MBED_SLEEP_TEST_UTILS_H + +#include "hal/ticker_api.h" +#include "hal/us_ticker_api.h" +#include "hal/lp_ticker_api.h" + +/* To prevent a loss of Greentea data, the serial buffers have to be flushed + * before the UART peripheral shutdown. The UART shutdown happens when the + * device is entering the deepsleep mode or performing a reset. + * + * With the current API, it is not possible to check if the hardware buffers + * are empty. However, it is possible to determine the time required for the + * buffers to flush. + * + * Assuming the biggest Tx FIFO of 128 bytes (as for CY8CPROTO_062_4343W) + * and a default UART config (9600, 8N1), flushing the Tx FIFO wold take: + * (1 start_bit + 8 data_bits + 1 stop_bit) * 128 * 1000 / 9600 = 133.3 ms. + * To be on the safe side, set the wait time to 150 ms. + */ +#define SERIAL_FLUSH_TIME_MS 150 + +#define US_PER_S 1000000 + +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 busy_wait_ms(int ms) +{ + const ticker_info_t *info = us_ticker_get_info(); + uint32_t mask = (1 << info->bits) - 1; + int delay = (int)((uint64_t) ms * info->frequency / 1000); + + uint32_t prev = us_ticker_read(); + while (delay > 0) { + uint32_t next = us_ticker_read(); + delay -= (next - prev) & mask; + prev = next; + } +} + +void us_ticker_isr(const ticker_data_t *const ticker_data) +{ + us_ticker_clear_interrupt(); +} + +#if DEVICE_LPTICKER +void lp_ticker_isr(const ticker_data_t *const ticker_data) +{ + lp_ticker_clear_interrupt(); +} +#endif + +#endif + +/** @}*/ +/** @}*/ diff --git a/hal/tests/TESTS/mbed_hal/sleep_manager/main.cpp b/hal/tests/TESTS/mbed_hal/sleep_manager/main.cpp new file mode 100644 index 0000000..09a0ad1 --- /dev/null +++ b/hal/tests/TESTS/mbed_hal/sleep_manager/main.cpp @@ -0,0 +1,346 @@ +/* mbed Microcontroller Library + * Copyright (c) 2017 ARM Limited + * 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. + */ +#include "utest/utest.h" +#include "unity/unity.h" +#include "greentea-client/test_env.h" +#include +#include "mbed.h" +#include "mbed_lp_ticker_wrapper.h" +#include "hal/us_ticker_api.h" +#include "../sleep/sleep_test_utils.h" +#include "sleep_manager_api_tests.h" + +#if !DEVICE_SLEEP +#error [NOT_SUPPORTED] test not supported +#else + +#define SLEEP_DURATION_US 20000ULL +#define DEEP_SLEEP_TEST_CHECK_WAIT_US 2000 +// As sleep_manager_can_deep_sleep_test_check() is based on wait_ns +// and wait_ns can be up to 40% slower, use a 50% delta here. +#define DEEP_SLEEP_TEST_CHECK_WAIT_DELTA_US 1000 + +using utest::v1::Case; +using utest::v1::Specification; +using utest::v1::Harness; + +#if DEVICE_LPTICKER +/* Make sure there are enough ticks to cope with more than SLEEP_DURATION_US sleep + * without hitting the wrap-around. + */ +void wraparound_lp_protect(void) +{ + const uint32_t ticks_now = get_lp_ticker_data()->interface->read(); + const ticker_info_t *p_ticker_info = get_lp_ticker_data()->interface->get_info(); + + const uint32_t max_count = ((1 << p_ticker_info->bits) - 1); + const uint32_t delta_ticks = us_to_ticks(SLEEP_DURATION_US * 1.5, p_ticker_info->frequency); + + if (ticks_now < (max_count - delta_ticks)) { + return; + } + + while (get_lp_ticker_data()->interface->read() > (max_count - delta_ticks)); +} +#endif + +void test_lock_unlock() +{ + TEST_ASSERT_TRUE(sleep_manager_can_deep_sleep()); + + sleep_manager_lock_deep_sleep(); + TEST_ASSERT_FALSE(sleep_manager_can_deep_sleep()); + + sleep_manager_unlock_deep_sleep(); + TEST_ASSERT_TRUE(sleep_manager_can_deep_sleep()); +} + +void test_lock_eq_ushrt_max() +{ + uint32_t lock_count = 0; + while (lock_count < USHRT_MAX) { + sleep_manager_lock_deep_sleep(); + lock_count++; + TEST_ASSERT_FALSE(sleep_manager_can_deep_sleep()); + } + while (lock_count > 1) { + sleep_manager_unlock_deep_sleep(); + lock_count--; + TEST_ASSERT_FALSE(sleep_manager_can_deep_sleep()); + } + sleep_manager_unlock_deep_sleep(); + TEST_ASSERT_TRUE(sleep_manager_can_deep_sleep()); +} + +utest::v1::status_t testcase_setup(const Case *const source, const size_t index_of_case) +{ + // Suspend the RTOS kernel scheduler to prevent interference with duration of sleep. +#if defined(MBED_CONF_RTOS_PRESENT) + osKernelSuspend(); +#endif +#if DEVICE_LPTICKER + ticker_suspend(get_lp_ticker_data()); +#if (LPTICKER_DELAY_TICKS > 0) + // Suspend the low power ticker wrapper to prevent interference with deep sleep lock. + lp_ticker_wrapper_suspend(); +#endif +#endif + ticker_suspend(get_us_ticker_data()); + // Make sure HAL tickers are initialized. + us_ticker_init(); +#if DEVICE_LPTICKER + lp_ticker_init(); +#endif + return utest::v1::greentea_case_setup_handler(source, index_of_case); +} + +utest::v1::status_t testcase_teardown(const Case *const source, const size_t passed, const size_t failed, + const utest::v1::failure_t failure) +{ + ticker_resume(get_us_ticker_data()); +#if DEVICE_LPTICKER +#if (LPTICKER_DELAY_TICKS > 0) + lp_ticker_wrapper_resume(); +#endif + ticker_resume(get_lp_ticker_data()); +#endif +#if defined(MBED_CONF_RTOS_PRESENT) + osKernelResume(0); +#endif + return utest::v1::greentea_case_teardown_handler(source, passed, failed, failure); +} + +#if DEVICE_LPTICKER +#if DEVICE_USTICKER +/* This test is based on the fact that the high-speed clocks are turned off + * in deep sleep mode but remain on in the ordinary sleep mode. Low-speed + * clocks stay on for both sleep and deep sleep modes. + * + * The type of sleep that was actually used by sleep_manager_sleep_auto() + * can be detected by comparing times measured by us and lp tickers. + */ +void test_sleep_auto() +{ + const ticker_info_t *us_ticker_info = get_us_ticker_data()->interface->get_info(); + const unsigned us_ticker_mask = ((1 << us_ticker_info->bits) - 1); + const ticker_irq_handler_type us_ticker_irq_handler_org = set_us_ticker_irq_handler(us_ticker_isr); + const ticker_info_t *lp_ticker_info = get_lp_ticker_data()->interface->get_info(); + const unsigned lp_ticker_mask = ((1 << lp_ticker_info->bits) - 1); + const ticker_irq_handler_type lp_ticker_irq_handler_org = set_lp_ticker_irq_handler(lp_ticker_isr); + uint32_t us_ts1, us_ts2, lp_ts1, lp_ts2, us_diff1, us_diff2, lp_diff1, lp_diff2; + + /* Let's avoid the Lp ticker wrap-around case */ + wraparound_lp_protect(); + uint32_t lp_wakeup_ts_raw = lp_ticker_read() + us_to_ticks(SLEEP_DURATION_US, lp_ticker_info->frequency); + timestamp_t lp_wakeup_ts = overflow_protect(lp_wakeup_ts_raw, lp_ticker_info->bits); + lp_ticker_set_interrupt(lp_wakeup_ts); + + /* Some targets may need an interrupt short time after LPTIM interrupt is + * set and forbid deep_sleep during that period. Let this period pass */ + TEST_ASSERT_TRUE(sleep_manager_can_deep_sleep_test_check()); + + sleep_manager_lock_deep_sleep(); + + us_ts1 = us_ticker_read(); + lp_ts1 = lp_ticker_read(); + + sleep_manager_sleep_auto(); + + us_ts2 = us_ticker_read(); + lp_ts2 = lp_ticker_read(); + + us_diff1 = ticks_to_us((us_ts1 <= us_ts2) ? (us_ts2 - us_ts1) : (us_ticker_mask - us_ts1 + us_ts2 + 1), us_ticker_info->frequency); + lp_diff1 = ticks_to_us((lp_ts1 <= lp_ts2) ? (lp_ts2 - lp_ts1) : (lp_ticker_mask - lp_ts1 + lp_ts2 + 1), lp_ticker_info->frequency); + + // Deep sleep locked -- ordinary sleep mode used: + // * us_ticker powered ON, + // * lp_ticker powered ON, + // so both should increment equally. + + // Verify us and lp tickers incremented equally, with 10% tolerance. + TEST_ASSERT_UINT64_WITHIN_MESSAGE( + SLEEP_DURATION_US / 10ULL, lp_diff1, us_diff1, + "Deep sleep mode locked, but still used"); + + sleep_manager_unlock_deep_sleep(); + TEST_ASSERT_TRUE(sleep_manager_can_deep_sleep()); + + // Wait for hardware serial buffers to flush. + busy_wait_ms(SERIAL_FLUSH_TIME_MS); + + /* Let's avoid the Lp ticker wrap-around case */ + wraparound_lp_protect(); + lp_wakeup_ts_raw = lp_ticker_read() + us_to_ticks(SLEEP_DURATION_US, lp_ticker_info->frequency); + lp_wakeup_ts = overflow_protect(lp_wakeup_ts_raw, lp_ticker_info->bits); + lp_ticker_set_interrupt(lp_wakeup_ts); + + /* Some targets may need an interrupt short time after LPTIM interrupt is + * set and forbid deep_sleep during that period. Let this period pass */ + TEST_ASSERT_TRUE(sleep_manager_can_deep_sleep_test_check()); + + us_ts1 = us_ticker_read(); + lp_ts1 = lp_ticker_read(); + + sleep_manager_sleep_auto(); + + us_ts2 = us_ticker_read(); + lp_ts2 = lp_ticker_read(); + + us_diff2 = ticks_to_us((us_ts1 <= us_ts2) ? (us_ts2 - us_ts1) : (us_ticker_mask - us_ts1 + us_ts2 + 1), us_ticker_info->frequency); + lp_diff2 = ticks_to_us((lp_ts1 <= lp_ts2) ? (lp_ts2 - lp_ts1) : (lp_ticker_mask - lp_ts1 + lp_ts2 + 1), lp_ticker_info->frequency); + + // Deep sleep unlocked -- deep sleep mode used: + // * us_ticker powered OFF, + // * lp_ticker powered ON. + // The us_ticker increment represents only the code execution time + // and should be much shorter than both: + // 1. current lp_ticker increment, + // 2. previous us_ticker increment (locked sleep test above) + + // Verify that the current us_ticker increment: + // 1. is at most 10% of lp_ticker increment + // 2. is at most 10% of previous us_ticker increment. + TEST_ASSERT_MESSAGE(us_diff2 < lp_diff2 / 10ULL, "Deep sleep mode unlocked, but not used"); + TEST_ASSERT_MESSAGE(us_diff2 < us_diff1 / 10ULL, "Deep sleep mode unlocked, but not used"); + + set_us_ticker_irq_handler(us_ticker_irq_handler_org); + set_lp_ticker_irq_handler(lp_ticker_irq_handler_org); +} +#endif + +#define US_PER_S 1000000 + +uint32_t diff_us(uint32_t start_ticks, uint32_t stop_ticks, const ticker_info_t *info) +{ + uint32_t counter_mask = ((1 << info->bits) - 1); + + uint32_t diff_ticks = ((stop_ticks - start_ticks) & counter_mask); + + return (uint32_t)((uint64_t) diff_ticks * US_PER_S / info->frequency); +} + +volatile bool unlock_deep_sleep = false; + +void ticker_event_handler_stub(const ticker_data_t *const ticker) +{ + lp_ticker_clear_interrupt(); + if (unlock_deep_sleep) { + sleep_manager_unlock_deep_sleep_internal(); + unlock_deep_sleep = false; + } +} + +ticker_irq_handler_type prev_irq_handler; + +void test_lock_unlock_test_check() +{ + prev_irq_handler = set_lp_ticker_irq_handler(ticker_event_handler_stub); + + for (int i = 0; i < 1000; i++) { + + wraparound_lp_protect(); + + const ticker_info_t *p_ticker_info = get_lp_ticker_data()->interface->get_info(); + + // Use LowPowerTimer instead of Timer to prevent deep sleep lock. + us_timestamp_t exec_time_unlocked, exec_time_locked; + uint32_t start, stop; + + // Deep sleep unlocked: + // * sleep_manager_can_deep_sleep() returns true, + // * sleep_manager_can_deep_sleep_test_check() returns true instantly. + TEST_ASSERT_TRUE(sleep_manager_can_deep_sleep()); + start = lp_ticker_read(); + TEST_ASSERT_TRUE(sleep_manager_can_deep_sleep_test_check()); + stop = lp_ticker_read(); + exec_time_unlocked = diff_us(start, stop, p_ticker_info); + + // Deep sleep locked: + // * sleep_manager_can_deep_sleep() returns false, + // * sleep_manager_can_deep_sleep_test_check() returns false with 2 ms delay. + sleep_manager_lock_deep_sleep(); + TEST_ASSERT_FALSE(sleep_manager_can_deep_sleep()); + start = lp_ticker_read(); + TEST_ASSERT_FALSE(sleep_manager_can_deep_sleep_test_check()); + stop = lp_ticker_read(); + exec_time_locked = diff_us(start, stop, p_ticker_info); + TEST_ASSERT_UINT64_WITHIN(DEEP_SLEEP_TEST_CHECK_WAIT_DELTA_US, DEEP_SLEEP_TEST_CHECK_WAIT_US, + exec_time_locked - exec_time_unlocked); + + // Deep sleep unlocked with a 1 ms delay: + // * sleep_manager_can_deep_sleep() returns false, + // * sleep_manager_can_deep_sleep_test_check() returns true with a 1 ms delay, + // * sleep_manager_can_deep_sleep() returns true when checked again. + unlock_deep_sleep = true; + /* Let's avoid the Lp ticker wrap-around case */ + wraparound_lp_protect(); + start = lp_ticker_read(); + uint32_t lp_wakeup_ts_raw = start + us_to_ticks(DEEP_SLEEP_TEST_CHECK_WAIT_US / 2, p_ticker_info->frequency); + timestamp_t lp_wakeup_ts = overflow_protect(lp_wakeup_ts_raw, p_ticker_info->bits); + lp_ticker_set_interrupt(lp_wakeup_ts); + + // Extra wait after setting interrupt to handle CMPOK + wait_ns(100000); + TEST_ASSERT_FALSE(sleep_manager_can_deep_sleep()); + TEST_ASSERT_TRUE(sleep_manager_can_deep_sleep_test_check()); + stop = lp_ticker_read(); + TEST_ASSERT(diff_us(start, stop, p_ticker_info) > 0UL); + TEST_ASSERT(diff_us(start, stop, p_ticker_info) < DEEP_SLEEP_TEST_CHECK_WAIT_US); + TEST_ASSERT_TRUE(sleep_manager_can_deep_sleep()); + } + + set_lp_ticker_irq_handler(prev_irq_handler); +} +#endif + +utest::v1::status_t testsuite_setup(const size_t number_of_cases) +{ + GREENTEA_SETUP(15, "default_auto"); + return utest::v1::greentea_test_setup_handler(number_of_cases); +} + +Case cases[] = { + Case("deep sleep lock/unlock", + (utest::v1::case_setup_handler_t) testcase_setup, + test_lock_unlock, + (utest::v1::case_teardown_handler_t) testcase_teardown), + Case("deep sleep locked USHRT_MAX times", + (utest::v1::case_setup_handler_t) testcase_setup, + test_lock_eq_ushrt_max, + (utest::v1::case_teardown_handler_t) testcase_teardown), +#if DEVICE_LPTICKER +#if DEVICE_USTICKER + Case("sleep_auto calls sleep/deep sleep based on lock", + (utest::v1::case_setup_handler_t) testcase_setup, + test_sleep_auto, + (utest::v1::case_teardown_handler_t) testcase_teardown), +#endif + Case("deep sleep lock/unlock test_check", + (utest::v1::case_setup_handler_t) testcase_setup, + test_lock_unlock_test_check, + (utest::v1::case_teardown_handler_t) testcase_teardown) +#endif +}; + +Specification specification(testsuite_setup, cases); + +int main() +{ + return !Harness::run(specification); +} + +#endif // !DEVICE_SLEEP diff --git a/hal/tests/TESTS/mbed_hal/sleep_manager/sleep_manager_api_tests.h b/hal/tests/TESTS/mbed_hal/sleep_manager/sleep_manager_api_tests.h new file mode 100644 index 0000000..dc353d0 --- /dev/null +++ b/hal/tests/TESTS/mbed_hal/sleep_manager/sleep_manager_api_tests.h @@ -0,0 +1,87 @@ +/* mbed Microcontroller Library + * Copyright (c) 2018 ARM Limited + * 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. + */ + +/** + * @addtogroup hal_sleep_manager_tests + * @{ + */ + +#ifndef MBED_HAL_SLEEP_MANAGER_API_TESTS_H +#define MBED_HAL_SLEEP_MANAGER_API_TESTS_H + +#if DEVICE_SLEEP + +/** Test lock/unlock + * + * Given no prior calls to lock/unlock + * When the deep sleep status is checked + * Then the deep sleep is allowed + * + * When the lock function is called + * Then the deep sleep is not allowed + * + * When the unlock function is called + * Then the deep sleep is allowed again + */ +void test_lock_unlock(); + +/** Test lock USHRT_MAX times + * + * Given a device with sleep mode support + * When deep sleep mode is locked USHRT_MAX times + * Then the deep sleep mode is locked + * + * When unlock is called repeatedly + * Then deep sleep mode stays locked until the number + * of unlock calls is equal to number of lock calls + */ +void test_lock_eq_ushrt_max(); + +/** Test sleep_auto calls sleep and deep sleep based on lock + * + * Given a device with sleep mode support + * When the deep sleep mode is locked + * Then sleep_auto uses sleep mode + * + * When the deep sleep mode is unlocked + * Then sleep_auto uses deep sleep mode + */ +void test_sleep_auto(); + +/** Test lock/unlock test_check fun + * + * Given the deep sleep has not been locked + * When the deep sleep status is checked + * Then sleep_manager_can_deep_sleep() returns true + * and sleep_manager_can_deep_sleep_test_check() returns true instantly. + * + * When the deep sleep mode is locked + * Then sleep_manager_can_deep_sleep() returns false + * and sleep_manager_can_deep_sleep_test_check() returns false with 2 ms delay. + * + * When the deep sleep mode is unlocked with a 1 ms delay + * Then sleep_manager_can_deep_sleep() returns false + * and sleep_manager_can_deep_sleep_test_check() returns true with 1 ms delay + * and sleep_manager_can_deep_sleep() returns true when checked again. + */ +void test_lock_unlock_test_check(); + +#endif + +#endif + +/** @}*/ diff --git a/hal/tests/TESTS/mbed_hal/sleep_manager_racecondition/main.cpp b/hal/tests/TESTS/mbed_hal/sleep_manager_racecondition/main.cpp new file mode 100644 index 0000000..034b41c --- /dev/null +++ b/hal/tests/TESTS/mbed_hal/sleep_manager_racecondition/main.cpp @@ -0,0 +1,109 @@ +/* mbed Microcontroller Library + * Copyright (c) 2017 ARM Limited + * 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. + */ +#include "utest/utest.h" +#include "unity/unity.h" +#include "greentea-client/test_env.h" +#include "mbed.h" +#include "sleep_manager_api_racecondition_tests.h" + +#if !DEVICE_SLEEP || !DEVICE_USTICKER +#error [NOT_SUPPORTED] test not supported +#else + +using namespace utest::v1; + +#define TEST_STACK_SIZE 256 +#if defined(MBED_CONF_RTOS_PRESENT) +void sleep_manager_locking_thread_test() +{ + for (uint32_t i = 0; i < 100; i++) { + sleep_manager_lock_deep_sleep(); + ThisThread::sleep_for(25); + sleep_manager_unlock_deep_sleep(); + } +} + +void sleep_manager_multithread_test() +{ + { + Callback cb(sleep_manager_locking_thread_test); + Thread t1(osPriorityNormal, TEST_STACK_SIZE); + Thread t2(osPriorityNormal, TEST_STACK_SIZE); + + t1.start(callback(cb)); + ThisThread::sleep_for(25); + t2.start(callback(cb)); + + // Wait for the threads to finish + t1.join(); + t2.join(); + } + + bool deep_sleep_allowed = sleep_manager_can_deep_sleep_test_check(); + TEST_ASSERT_TRUE_MESSAGE(deep_sleep_allowed, "Deep sleep should be allowed"); +} +#endif + +void sleep_manager_locking_irq_test() +{ + sleep_manager_lock_deep_sleep(); + sleep_manager_unlock_deep_sleep(); +} + +void sleep_manager_irq_test() +{ + { + Ticker ticker1; + Timer timer; + + ticker1.attach_us(&sleep_manager_locking_irq_test, 1000); + + // run this for 10 seconds + timer.start(); + int start = timer.read(); + int end = start + 10; + while (timer.read() < end) { + sleep_manager_locking_irq_test(); + } + timer.stop(); + } + + bool deep_sleep_allowed = sleep_manager_can_deep_sleep_test_check(); + TEST_ASSERT_TRUE_MESSAGE(deep_sleep_allowed, "Deep sleep should be allowed"); +} + +utest::v1::status_t greentea_test_setup(const size_t number_of_cases) +{ + GREENTEA_SETUP(30, "default_auto"); + return greentea_test_setup_handler(number_of_cases); +} + +Case cases[] = { +#if defined(MBED_CONF_RTOS_PRESENT) + Case("deep sleep lock/unlock is thread safe", sleep_manager_multithread_test), +#endif + Case("deep sleep lock/unlock is IRQ safe", sleep_manager_irq_test), +}; + +Specification specification(greentea_test_setup, cases, greentea_test_teardown_handler); + +int main() +{ + Harness::run(specification); +} + +#endif // !DEVICE_SLEEP || !DEVICE_USTICKER diff --git a/hal/tests/TESTS/mbed_hal/sleep_manager_racecondition/sleep_manager_api_racecondition_tests.h b/hal/tests/TESTS/mbed_hal/sleep_manager_racecondition/sleep_manager_api_racecondition_tests.h new file mode 100644 index 0000000..5af8c6a --- /dev/null +++ b/hal/tests/TESTS/mbed_hal/sleep_manager_racecondition/sleep_manager_api_racecondition_tests.h @@ -0,0 +1,44 @@ +/* mbed Microcontroller Library + * Copyright (c) 2018 ARM Limited + * 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. + */ + +/** + * @addtogroup hal_sleep_manager_tests + * @{ + */ + +#ifndef MBED_HAL_SLEEP_MANAGER_API_RACECONDITION_TESTS_H +#define MBED_HAL_SLEEP_MANAGER_API_RACECONDITION_TESTS_H + +/** Test lock/unlock is thread safe + * + * Given a device with sleep mode support + * When multiple threads are using the sleep manager API + * Then lock/unlock calls are thread safe + */ +void sleep_manager_multithread_test(); + +/** Test lock/unlock is IRQ safe + * + * Given a device with sleep mode support + * When the sleep manager API is used from IRQ and the main thread concurrently + * Then lock/unlock calls are IRQ safe + */ +void sleep_manager_irq_test(); + +#endif + +/** @}*/ diff --git a/hal/tests/TESTS/mbed_hal/stack_size_unification/main.cpp b/hal/tests/TESTS/mbed_hal/stack_size_unification/main.cpp new file mode 100644 index 0000000..23c84a4 --- /dev/null +++ b/hal/tests/TESTS/mbed_hal/stack_size_unification/main.cpp @@ -0,0 +1,78 @@ +/* mbed Microcontroller Library + * Copyright (c) 2019-2019 ARM Limited + * + * 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. + */ +#include "mbed.h" +#include "greentea-client/test_env.h" +#include "unity.h" +#include "utest.h" + +#ifdef TARGET_RENESAS +#error [NOT_SUPPORTED] Cortex-A target not supported for this test +#else + +using namespace utest::v1; + +#ifdef MBED_CONF_RTOS_PRESENT +extern osThreadAttr_t _main_thread_attr; +#endif +extern uint32_t mbed_stack_isr_size; + +#define EXPECTED_ISR_STACK_SIZE (MBED_CONF_TARGET_BOOT_STACK_SIZE) + +#define EXPECTED_MAIN_THREAD_STACK_SIZE (MBED_CONF_RTOS_MAIN_THREAD_STACK_SIZE) + +#define EXPECTED_USER_THREAD_DEFAULT_STACK_SIZE (MBED_CONF_RTOS_THREAD_STACK_SIZE) + +#if ((MBED_RAM_SIZE - MBED_BOOT_STACK_SIZE) <= (EXPECTED_MAIN_THREAD_STACK_SIZE + EXPECTED_ISR_STACK_SIZE)) +#error [NOT_SUPPORTED] Insufficient stack for staci_size_unification tests +#endif + + +/* Test sizes of ISR stack, main thread stack, default user thread stack. + * + * On some platforms with lower RAM size (e.g. NUCLEO_F070RB - 16 KB RAM) it is impossible + * to create thread with default stack size to check its size, that is why we will + * check only macro which specifies default user thread stack. + * + */ +void stack_size_unification_test() +{ + TEST_ASSERT_EQUAL(EXPECTED_ISR_STACK_SIZE, mbed_stack_isr_size); +#ifdef MBED_CONF_RTOS_PRESENT + TEST_ASSERT_EQUAL(EXPECTED_MAIN_THREAD_STACK_SIZE, _main_thread_attr.stack_size); + TEST_ASSERT_EQUAL(EXPECTED_USER_THREAD_DEFAULT_STACK_SIZE, OS_STACK_SIZE); +#endif +} + +utest::v1::status_t test_setup(const size_t number_of_cases) +{ + GREENTEA_SETUP(10, "default_auto"); + return verbose_test_setup_handler(number_of_cases); +} + +Case cases[] = { + Case("Stack size unification test", stack_size_unification_test) +}; + +Specification specification(test_setup, cases); + +int main() +{ + return !Harness::run(specification); +} + +#endif // TARGET_RENESAS diff --git a/hal/tests/TESTS/mbed_hal/stack_size_unification/stack_size_unification.h b/hal/tests/TESTS/mbed_hal/stack_size_unification/stack_size_unification.h new file mode 100644 index 0000000..2c038a9 --- /dev/null +++ b/hal/tests/TESTS/mbed_hal/stack_size_unification/stack_size_unification.h @@ -0,0 +1,51 @@ +/* mbed Microcontroller Library + * Copyright (c) 2019-2019 ARM Limited + * + * 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. + */ + +/** \addtogroup hal_rtc_tests + * @{ + */ + +#ifndef MBED_STACK_SIZE_UNIFICATION_H +#define MBED_STACK_SIZE_UNIFICATION_H + +#ifdef __cplusplus +extern "C" { +#endif + +/** Test sizes of ISR stack, main thread stack, default user thread stack. + * + * Given is Mbed OS configuration. + * When ISR stack, main thread stack, default user thread stack sizes are defined. + * Then ISR stack size is equal to 1 KB, + * main thread stack size is equal to 4 KB, + * default user thread stack size is equal to 4 KB. + * + * NOTE: + * It is impossible to verify RTOS-less thread stack size since all tests are build with RTOS. + */ +void stack_size_unification_test(void); + +/**@}*/ + +#ifdef __cplusplus +} +#endif + +#endif + +/** @}*/ diff --git a/hal/tests/TESTS/mbed_hal/ticker/main.cpp b/hal/tests/TESTS/mbed_hal/ticker/main.cpp new file mode 100644 index 0000000..a8db500 --- /dev/null +++ b/hal/tests/TESTS/mbed_hal/ticker/main.cpp @@ -0,0 +1,2473 @@ +/* mbed Microcontroller Library + * Copyright (c) 2017 ARM Limited + * 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. + */ + +#define __STDC_LIMIT_MACROS +#include +#include + +#include "utest/utest.h" +#include "unity/unity.h" +#include "greentea-client/test_env.h" + +#include "mbed.h" +#include "ticker_api.h" + +using namespace utest::v1; + +#define MBED_ARRAY_SIZE(array) (sizeof(array)/sizeof(array[0])) + +#define TIMESTAMP_MAX_DELTA_BITS(bits) ((uint64_t)(0x7 << ((bits) - 4))) +#define TIMESTAMP_MAX_DELTA TIMESTAMP_MAX_DELTA_BITS(32) + +struct ticker_interface_stub_t { + ticker_interface_t interface; + bool initialized; + bool interrupt_flag; + timestamp_t timestamp ; + timestamp_t interrupt_timestamp; + unsigned int init_call; + unsigned int read_call; + unsigned int disable_interrupt_call; + unsigned int clear_interrupt_call; + unsigned int set_interrupt_call; + unsigned int fire_interrupt_call; + unsigned int get_info_call; +}; + +static ticker_interface_stub_t interface_stub = { 0 }; +static ticker_info_t interface_info_stub = { 0 }; + +static void ticker_interface_stub_init() +{ + ++interface_stub.init_call; + interface_stub.initialized = true; +} + +static uint32_t ticker_interface_stub_read() +{ + ++interface_stub.read_call; + return interface_stub.timestamp; +} + +static void ticker_interface_stub_disable_interrupt() +{ + ++interface_stub.disable_interrupt_call; +} + +static void ticker_interface_stub_clear_interrupt() +{ + ++interface_stub.clear_interrupt_call; + interface_stub.interrupt_flag = false; +} + +static void ticker_interface_stub_set_interrupt(timestamp_t timestamp) +{ + ++interface_stub.set_interrupt_call; + interface_stub.interrupt_timestamp = timestamp; +} + +static void ticker_interface_stub_fire_interrupt() +{ + ++interface_stub.fire_interrupt_call; +} + +static const ticker_info_t *ticker_interface_stub_get_info() +{ + ++interface_stub.get_info_call; + return &interface_info_stub; +} + +static void reset_ticker_interface_stub() +{ + interface_stub.interface.init = ticker_interface_stub_init; + interface_stub.interface.read = ticker_interface_stub_read; + interface_stub.interface.disable_interrupt = + ticker_interface_stub_disable_interrupt; + interface_stub.interface.clear_interrupt = + ticker_interface_stub_clear_interrupt; + interface_stub.interface.set_interrupt = ticker_interface_stub_set_interrupt; + interface_stub.interface.fire_interrupt = ticker_interface_stub_fire_interrupt; + interface_stub.interface.get_info = ticker_interface_stub_get_info; + interface_stub.initialized = false; + interface_stub.interrupt_flag = false; + interface_stub.timestamp = 0; + interface_stub.interrupt_timestamp = 0; + interface_stub.init_call = 0; + interface_stub.read_call = 0; + interface_stub.disable_interrupt_call = 0; + interface_stub.clear_interrupt_call = 0; + interface_stub.set_interrupt_call = 0; + interface_stub.fire_interrupt_call = 0; + + interface_info_stub.frequency = 1000000; + interface_info_stub.bits = 32; +} + +// stub of the event queue +static ticker_event_queue_t queue_stub = { + /* event handler */ NULL, + /* head */ NULL, + /* timestamp */ 0, + /* initialized */ false +}; + +static void reset_queue_stub() +{ + queue_stub.event_handler = NULL; + queue_stub.head = NULL, + queue_stub.tick_last_read = 0; + queue_stub.tick_remainder = 0; + queue_stub.frequency = 0; + queue_stub.bitmask = 0; + queue_stub.max_delta = 0; + queue_stub.max_delta_us = 0; + queue_stub.present_time = 0; + queue_stub.initialized = false; +} + +// stub of the ticker +static ticker_data_t ticker_stub = { + /* interface */ &interface_stub.interface, + /* queue */ &queue_stub +}; + +static void reset_ticker_stub() +{ + reset_queue_stub(); + reset_ticker_interface_stub(); +} + +const uint32_t test_frequencies[] = { + 1, + 32768, // 2^15 + 1000000, + 0xFFFFFFFF // 2^32 - 1 +}; + +const uint32_t test_bitwidths[] = { + 32, + 31, + 16, + 8 +}; + +template < void (F)(uint32_t a, uint32_t b)> +static void test_over_frequency_and_width(void) +{ + for (unsigned int i = 0; i < MBED_ARRAY_SIZE(test_frequencies); i++) { + for (unsigned int j = 0; j < MBED_ARRAY_SIZE(test_bitwidths); j++) { + reset_ticker_stub(); + interface_info_stub.frequency = test_frequencies[i]; + interface_info_stub.bits = test_bitwidths[j]; + + F(test_frequencies[i], test_bitwidths[j]); + } + } +} + +static utest::v1::status_t case_setup_handler( + const Case *const source, const size_t index_of_case +) +{ + utest::v1::status_t status = greentea_case_setup_handler(source, index_of_case); + reset_ticker_stub(); + return status; +} + +static utest::v1::status_t case_teardown_handler( + const Case *const source, const size_t passed, const size_t failed, const failure_t reason +) +{ + reset_ticker_stub(); + utest::v1::status_t status = greentea_case_teardown_handler( + source, passed, failed, reason + ); + return status; +} + +static utest::v1::status_t greentea_failure_handler( + const Case *const source, const failure_t reason +) +{ + utest::v1::status_t status = greentea_case_failure_abort_handler( + source, reason + ); + return status; +} + +#define MAKE_TEST_CASE(description, handler) \ + { \ + description, \ + handler, \ + NULL, \ + NULL, \ + case_setup_handler, \ + case_teardown_handler, \ + greentea_failure_handler \ + } + +/** + * Given an unitialized ticker_data instance. + * When the ticker is initialized + * Then: + * - The ticker interface should be initialized + * - The queue handler should be set to the handler provided in parameter + * - The internal ticker timestamp should be zero + * - interrupt should be scheduled in current timestamp + + * TIMESTAMP_MAX_DELTA + * - The queue should not contains any event + */ +static void test_ticker_initialization() +{ + ticker_event_handler dummy_handler = (ticker_event_handler)0xDEADBEEF; + + // setup of the stub + interface_stub.timestamp = 0xFEEDBABE; + + ticker_set_handler(&ticker_stub, dummy_handler); + + TEST_ASSERT_TRUE(interface_stub.initialized); + TEST_ASSERT_EQUAL_PTR(dummy_handler, queue_stub.event_handler); + TEST_ASSERT_EQUAL_UINT64(0, queue_stub.present_time); + TEST_ASSERT_EQUAL(1, interface_stub.set_interrupt_call); + TEST_ASSERT_EQUAL_UINT32( + interface_stub.timestamp + TIMESTAMP_MAX_DELTA, + interface_stub.interrupt_timestamp + ); + TEST_ASSERT_EQUAL_PTR(NULL, queue_stub.head); + TEST_ASSERT_EQUAL(0, interface_stub.disable_interrupt_call); +} + +/** + * Given an initialized ticker_data instance. + * When the ticker handler is set to a new value + * Then: + * - The ticker interface initialization function should not be called. + * - The queue handler should be set to the new handler. + * - The events in the queue should remains the same. + */ +static void test_ticker_re_initialization() +{ + ticker_event_handler dummy_handler = (ticker_event_handler) 0xDEADBEEF; + ticker_event_handler expected_handler = (ticker_event_handler) 0xFEEDDEAF; + + ticker_event_t first_event = { 0 }; + ticker_event_t second_event = { 0 }; + ticker_event_t third_event = { 0 }; + + first_event.next = &second_event; + second_event.next = &third_event; + + // initialize the ticker and put few events in the queue. + ticker_set_handler(&ticker_stub, dummy_handler); + // simulate insertion, it shouldn't affect the queue behaviour for this test + queue_stub.head = &first_event; + interface_stub.init_call = 0; + + ticker_set_handler(&ticker_stub, expected_handler); + + TEST_ASSERT_TRUE(interface_stub.initialized); + TEST_ASSERT_EQUAL(0, interface_stub.init_call); + TEST_ASSERT_EQUAL(expected_handler, queue_stub.event_handler); + TEST_ASSERT_EQUAL(&first_event, queue_stub.head); + TEST_ASSERT_EQUAL(&second_event, queue_stub.head->next); + TEST_ASSERT_EQUAL(&third_event, queue_stub.head->next->next); + TEST_ASSERT_EQUAL(NULL, queue_stub.head->next->next->next); + TEST_ASSERT_EQUAL(0, interface_stub.disable_interrupt_call); +} + +/** + * Given an initialized ticker_data instance. + * When the ticker is read + * Then it should return the value present in the ticker interface + */ +static void test_ticker_read() +{ + ticker_set_handler(&ticker_stub, NULL); + + timestamp_t timestamps[] = { + 0xA, + 0xAA, + 0xAAA, + 0xAAAA, + 0xAAAAA, + 0xAAAAAA, + 0xAAAAAAA, + 0xAAAAAAAA + }; + + for (size_t i = 0; i < MBED_ARRAY_SIZE(timestamps); ++i) { + interface_stub.timestamp = timestamps[i]; + TEST_ASSERT_EQUAL_UINT32(timestamps[i], ticker_read(&ticker_stub)); + TEST_ASSERT_EQUAL_UINT64(timestamps[i], ticker_read_us(&ticker_stub)); + } + + TEST_ASSERT_EQUAL(0, interface_stub.disable_interrupt_call); +} + +/** + * Given an initialized ticker_data instance. + * When the ticker is read and the value read is less than the previous + * value read. + * Then: + * - ticker_read should return the value read in the ticker interface + * - ticker_read_us should return a value where: + * + lower 8 bytes should be equal to the value in the ticker interface + * + upper 8 bytes should be equal to the previous value of upper 8 bytes + * plus one. + */ +static void test_ticker_read_overflow() +{ + const timestamp_t timestamps[] = { + 0xAAAAAAAA, + 0xAAAAAAA, + 0xAAAAAA, + 0xAAAAA, + 0xAAAA, + 0xAAA, + 0xAA, + 0xA + }; + + ticker_set_handler(&ticker_stub, NULL); + + uint32_t upper_bytes_begin = ticker_read_us(&ticker_stub) >> 32; + + for (size_t i = 0; i < MBED_ARRAY_SIZE(timestamps); ++i) { + interface_stub.timestamp = timestamps[i]; + TEST_ASSERT_EQUAL_UINT32(timestamps[i], ticker_read(&ticker_stub)); + TEST_ASSERT_EQUAL_UINT32(timestamps[i], ticker_read_us(&ticker_stub)); + TEST_ASSERT_EQUAL_UINT64( + upper_bytes_begin + i, ticker_read_us(&ticker_stub) >> 32 + ); + } + + TEST_ASSERT_EQUAL(0, interface_stub.disable_interrupt_call); +} + +/** + * Given an initialized ticker without user registered events. + * When an event is inserted with ticker_insert_event and the timestamp passed + * in parameter is in range [ticker_timestamp : ticker_timestamp + + * TIMESTAMP_MAX_DELTA[. + * Then + * - The event should be in the queue + * - The interrupt timestamp should be equal to the timestamp of the event + * - The timestamp of the event should reflect the timestamp requested. + * - The id of the event should be equal to the id passed in parameter. + */ +static void test_legacy_insert_event_outside_overflow_range() +{ + ticker_set_handler(&ticker_stub, NULL); + interface_stub.set_interrupt_call = 0; + + // test the end of the range + ticker_event_t last_event = { 0 }; + const timestamp_t timestamp_last_event = + interface_stub.timestamp + TIMESTAMP_MAX_DELTA; + const uint32_t id_last_event = 0xDEADDEAF; + + ticker_insert_event( + &ticker_stub, + &last_event, timestamp_last_event, id_last_event + ); + + TEST_ASSERT_EQUAL_PTR(&last_event, queue_stub.head); + TEST_ASSERT_EQUAL(1, interface_stub.set_interrupt_call); + TEST_ASSERT_EQUAL_UINT32( + timestamp_last_event, interface_stub.interrupt_timestamp + ); + TEST_ASSERT_EQUAL_PTR(NULL, queue_stub.head->next); + TEST_ASSERT_EQUAL_UINT32(timestamp_last_event, last_event.timestamp); + TEST_ASSERT_EQUAL_UINT32(id_last_event, last_event.id); + + // test the beginning of the range + ticker_event_t first_event = { 0 }; + const timestamp_t timestamp_first_event = interface_stub.timestamp + 1; + const uint32_t id_first_event = 0xAAAAAAAA; + + ticker_insert_event( + &ticker_stub, + &first_event, timestamp_first_event, id_first_event + ); + + TEST_ASSERT_EQUAL_PTR(&first_event, queue_stub.head); + TEST_ASSERT_EQUAL(2, interface_stub.set_interrupt_call); + TEST_ASSERT_EQUAL_UINT32( + timestamp_first_event, interface_stub.interrupt_timestamp + ); + TEST_ASSERT_EQUAL_PTR(&last_event, queue_stub.head->next); + TEST_ASSERT_EQUAL_UINT32( + timestamp_first_event, first_event.timestamp + ); + TEST_ASSERT_EQUAL_UINT32(id_first_event, first_event.id); + + TEST_ASSERT_EQUAL(0, interface_stub.disable_interrupt_call); +} + +/** + * Given an initialized ticker without user registered events. + * When an event is inserted with ticker_insert_event and a timestamp in the + * range [ticker_timestamp + TIMESTAMP_MAX_DELTA + 1 : + * ticker_timestamp + UINT32MAX [ + * Then + * - The event should be in the queue + * - The interrupt timestamp should be equal to + * TIMESTAMP_MAX_DELTA + * - The timestamp of the event should reflect the timestamp requested. + * - The id of the event should be equal to the id passed in parameter. + */ +static void test_legacy_insert_event_in_overflow_range() +{ + ticker_set_handler(&ticker_stub, NULL); + interface_stub.set_interrupt_call = 0; + + // test the end of the range + ticker_event_t last_event = { 0 }; + const timestamp_t timestamp_last_event = + interface_stub.timestamp + UINT32_MAX; + const uint32_t id_last_event = 0xDEADDEAF; + + ticker_insert_event( + &ticker_stub, + &last_event, timestamp_last_event, id_last_event + ); + + TEST_ASSERT_EQUAL_PTR(&last_event, queue_stub.head); + TEST_ASSERT_EQUAL(1, interface_stub.set_interrupt_call); + TEST_ASSERT_EQUAL_UINT32( + interface_stub.timestamp + TIMESTAMP_MAX_DELTA, + interface_stub.interrupt_timestamp + ); + TEST_ASSERT_EQUAL_PTR(NULL, queue_stub.head->next); + TEST_ASSERT_EQUAL_UINT32(timestamp_last_event, last_event.timestamp); + TEST_ASSERT_EQUAL_UINT32(id_last_event, last_event.id); + + // test the beginning of the range + ++interface_stub.timestamp; + + ticker_event_t first_event = { 0 }; + const timestamp_t timestamp_first_event = + interface_stub.timestamp + TIMESTAMP_MAX_DELTA + 1; + const uint32_t id_first_event = 0xAAAAAAAA; + + ticker_insert_event( + &ticker_stub, + &first_event, timestamp_first_event, id_first_event + ); + + TEST_ASSERT_EQUAL_PTR(&first_event, queue_stub.head); + TEST_ASSERT_EQUAL(2, interface_stub.set_interrupt_call); + TEST_ASSERT_EQUAL_UINT32( + interface_stub.timestamp + TIMESTAMP_MAX_DELTA, + interface_stub.interrupt_timestamp + ); + TEST_ASSERT_EQUAL_PTR(&last_event, queue_stub.head->next); + TEST_ASSERT_EQUAL_UINT32( + timestamp_first_event, first_event.timestamp + ); + TEST_ASSERT_EQUAL_UINT32(id_first_event, first_event.id); + + TEST_ASSERT_EQUAL(0, interface_stub.disable_interrupt_call); +} + +/** + * Given an initialized ticker without user registered events. + * When an event is inserted with ticker_insert_event and the timestamp in + * parameter is less than the current timestamp value. + * Then + * - The event should be in the queue + * - The timestamp of the event should reflect the timestamp requested: + * + lower 8 bytes should be equal to the timestamp in input. + * + upper 8 bytes should be equal to the upper of the upper 8 bytes of the + * timestamp state stored in the queue plus one. + * - The id of the event should be equal to the id passed in parameter. + */ +static void test_legacy_insert_event_overflow() +{ + ticker_set_handler(&ticker_stub, NULL); + interface_stub.set_interrupt_call = 0; + + interface_stub.timestamp = 0x20000000; + ticker_read(&ticker_stub); + + ticker_event_t event = { 0 }; + const timestamp_t expected_timestamp = + interface_stub.timestamp + + TIMESTAMP_MAX_DELTA + + 1; + const us_timestamp_t expected_us_timestamp = + (((queue_stub.present_time >> 32) + 1) << 32) | expected_timestamp; + const uint32_t expected_id = 0xDEADDEAF; + + ticker_insert_event( + &ticker_stub, + &event, expected_timestamp, expected_id + ); + + TEST_ASSERT_EQUAL_PTR(&event, queue_stub.head); + TEST_ASSERT_EQUAL(1, interface_stub.set_interrupt_call); + TEST_ASSERT_EQUAL_UINT32( + interface_stub.timestamp + TIMESTAMP_MAX_DELTA, + interface_stub.interrupt_timestamp + ); + TEST_ASSERT_EQUAL_PTR(NULL, queue_stub.head->next); + TEST_ASSERT_EQUAL_UINT32(expected_us_timestamp, event.timestamp); + TEST_ASSERT_EQUAL_UINT32(expected_id, event.id); + + TEST_ASSERT_EQUAL(0, interface_stub.disable_interrupt_call); +} + +/** + * Given an initialized ticker. + * When an event is inserted with ticker_insert_event and a timestamp less than + * the one for the next scheduled timestamp. + * Then + * - The event inserted should be the first in the queue + * - The interrupt timestamp should be equal to the timestamp of the event or + * TIMESTAMP_MAX_DELTA if in the overflow range. + * - The timestamp of the event should reflect the timestamp requested. + * - The id of the event should be equal to the id passed in parameter. + * - Events in the queue should remained ordered by timestamp. + */ +static void test_legacy_insert_event_head() +{ + ticker_set_handler(&ticker_stub, NULL); + interface_stub.set_interrupt_call = 0; + + const timestamp_t timestamps[] = { + UINT32_MAX, + TIMESTAMP_MAX_DELTA + 1, + TIMESTAMP_MAX_DELTA, + TIMESTAMP_MAX_DELTA / 2, + TIMESTAMP_MAX_DELTA / 4, + TIMESTAMP_MAX_DELTA / 8, + TIMESTAMP_MAX_DELTA / 16, + }; + ticker_event_t events[MBED_ARRAY_SIZE(timestamps)] = { 0 }; + + for (size_t i = 0; i < MBED_ARRAY_SIZE(events); ++i) { + ticker_insert_event( + &ticker_stub, + &events[i], timestamps[i], i + ); + + TEST_ASSERT_EQUAL_PTR(&events[i], queue_stub.head); + TEST_ASSERT_EQUAL(i + 1, interface_stub.set_interrupt_call); + if (timestamps[i] < TIMESTAMP_MAX_DELTA) { + TEST_ASSERT_EQUAL_UINT32( + timestamps[i], + interface_stub.interrupt_timestamp + ); + } else { + TEST_ASSERT_EQUAL_UINT32( + TIMESTAMP_MAX_DELTA, + interface_stub.interrupt_timestamp + ); + } + + TEST_ASSERT_EQUAL_UINT32( + timestamps[i], events[i].timestamp + ); + TEST_ASSERT_EQUAL_UINT32(i, events[i].id); + + ticker_event_t *e = &events[i]; + while (e) { + TEST_ASSERT_EQUAL_UINT32(timestamps[e->id], e->timestamp); + if (e->next) { + TEST_ASSERT_TRUE(e->id > e->next->id); + TEST_ASSERT_TRUE(e->timestamp < e->next->timestamp); + } else { + TEST_ASSERT_EQUAL_UINT32(0, e->id); + } + e = e->next; + } + } + + TEST_ASSERT_EQUAL(0, interface_stub.disable_interrupt_call); +} + +/** + * Given an initialized ticker. + * When an event is inserted with ticker_insert_event and its timestamp is bigger + * than the one of the last event in the queue. + * Then + * - The event inserted should be the last in the queue + * - The interrupt timestamp should remains equal to the interrupt timestamp + * of the head event . + * - The timestamp of the event should reflect the timestamp requested. + * - The id of the event should be equal to the id passed in parameter. + * - Events in the queue should remained ordered by timestamp. + */ +static void test_legacy_insert_event_tail() +{ + ticker_set_handler(&ticker_stub, NULL); + interface_stub.set_interrupt_call = 0; + + const timestamp_t timestamps[] = { + 0xA, + 0xAA, + 0xAAA, + 0xAAAA, + 0xAAAAA, + 0xAAAAAA, + 0xAAAAAAA, + 0xAAAAAAAA, + }; + ticker_event_t events[MBED_ARRAY_SIZE(timestamps)] = { 0 }; + + for (size_t i = 0; i < MBED_ARRAY_SIZE(events); ++i) { + ticker_insert_event( + &ticker_stub, + &events[i], timestamps[i], i + ); + + TEST_ASSERT_EQUAL_PTR(&events[0], queue_stub.head); + TEST_ASSERT_EQUAL_UINT32( + timestamps[0], interface_stub.interrupt_timestamp + ); + + TEST_ASSERT_EQUAL_UINT32(timestamps[i], events[i].timestamp); + TEST_ASSERT_EQUAL_UINT32(i, events[i].id); + + ticker_event_t *e = queue_stub.head; + while (e) { + TEST_ASSERT_EQUAL_UINT32(timestamps[e->id], e->timestamp); + if (e->next) { + TEST_ASSERT_TRUE(e->id < e->next->id); + TEST_ASSERT_TRUE(e->timestamp < e->next->timestamp); + } else { + TEST_ASSERT_EQUAL_UINT32(&events[i], e); + } + e = e->next; + } + } + + TEST_ASSERT_EQUAL(0, interface_stub.disable_interrupt_call); +} + +/** + * Given an initialized ticker. + * When an event is inserted with ticker_insert_event and a timestamp less + * than the current timestamp in the interface and less than the relative + * timestamp of the next event to execute. + * Then + * - The event inserted should be after the head + * - The interrupt timestamp should remains equal to the interrupt timestamp + * of the head event . + * - The timestamp of the event should reflect the timestamp requested (overflow) + * - The id of the event should be equal to the id passed in parameter. + * - Events in the queue should remained ordered by timestamp. + */ +static void test_legacy_insert_event_multiple_overflow() +{ + ticker_set_handler(&ticker_stub, NULL); + interface_stub.set_interrupt_call = 0; + + const timestamp_t timestamps[] = { + 0xA, + 0xAA, + 0xAAA, + 0xAAAA, + 0xAAAAA, + 0xAAAAAA, + 0xAAAAAAA, + 0xAAAAAAAA + }; + ticker_event_t events[MBED_ARRAY_SIZE(timestamps)] = { 0 }; + + ticker_event_t ref_event; + timestamp_t ref_event_timestamp = 0xCCCCCCCC; + ticker_insert_event( + &ticker_stub, + &ref_event, ref_event_timestamp, 0xDEADBEEF + ); + + timestamp_t last_timestamp_to_insert = + timestamps[MBED_ARRAY_SIZE(timestamps) - 1]; + interface_stub.timestamp = + last_timestamp_to_insert + + ((ref_event_timestamp - last_timestamp_to_insert) / 2); + ticker_irq_handler(&ticker_stub); + + for (size_t i = 0; i < MBED_ARRAY_SIZE(events); ++i) { + ticker_insert_event( + &ticker_stub, + &events[i], timestamps[i], i + ); + + TEST_ASSERT_EQUAL_PTR(&ref_event, queue_stub.head); + TEST_ASSERT_EQUAL_PTR(&events[0], queue_stub.head->next); + TEST_ASSERT_EQUAL_UINT32( + ref_event_timestamp, interface_stub.interrupt_timestamp + ); + + TEST_ASSERT_EQUAL_UINT32(timestamps[i], events[i].timestamp); + TEST_ASSERT_EQUAL_UINT32(i, events[i].id); + + ticker_event_t *e = queue_stub.head->next; + while (e) { + TEST_ASSERT_EQUAL_UINT32(timestamps[e->id], e->timestamp); + if (e->next) { + TEST_ASSERT_TRUE(e->id < e->next->id); + TEST_ASSERT_TRUE(e->timestamp < e->next->timestamp); + } else { + TEST_ASSERT_EQUAL_UINT32(&events[i], e); + } + e = e->next; + } + } + + TEST_ASSERT_EQUAL(0, interface_stub.disable_interrupt_call); +} + +/** + * Given an initialized ticker. + * When an event is inserted with ticker_insert_event. + * Then + * - The event inserted should be at the correct position in the queue + * - The event queue should remain ordered by timestamp + * - The interrupt timestamp should be equal to the interrupt timestamp + * of the head event or TIMESTAMP_MAX_DELTA if the + * timestamp is in the overflow range. + * - The timestamp of the event should reflect the timestamp requested (overflow) + * - The id of the event should be equal to the id passed in parameter. + * - Events in the queue should remained ordered by timestamp. + */ +static void test_legacy_insert_event_multiple_random() +{ + ticker_set_handler(&ticker_stub, NULL); + interface_stub.set_interrupt_call = 0; + + const timestamp_t ref_timestamp = UINT32_MAX / 2; + interface_stub.timestamp = ref_timestamp; + + // insert first event at the head of the queue + ticker_event_t first_event; + const timestamp_t first_event_timestamp = + ref_timestamp + TIMESTAMP_MAX_DELTA + 100; + + ticker_insert_event( + &ticker_stub, + &first_event, first_event_timestamp, (uint32_t) &first_event + ); + + TEST_ASSERT_EQUAL_PTR(&first_event, queue_stub.head); + TEST_ASSERT_EQUAL_PTR(NULL, first_event.next); + TEST_ASSERT_EQUAL_UINT32( + ref_timestamp + TIMESTAMP_MAX_DELTA, interface_stub.interrupt_timestamp + ); + TEST_ASSERT_EQUAL_UINT32(first_event_timestamp, first_event.timestamp); + TEST_ASSERT_EQUAL_UINT64( + first_event.timestamp, + first_event_timestamp + + ((first_event_timestamp < ref_timestamp) ? (1ULL << 32) : 0) + ); + TEST_ASSERT_EQUAL_UINT32((uint32_t) &first_event, first_event.id); + + // insert second event at the tail of the queue + ticker_event_t second_event; + const timestamp_t second_event_timestamp = first_event_timestamp + 1; + + ticker_insert_event( + &ticker_stub, + &second_event, second_event_timestamp, (uint32_t) &second_event + ); + + TEST_ASSERT_EQUAL_PTR(&first_event, queue_stub.head); + TEST_ASSERT_EQUAL_PTR(&second_event, first_event.next); + TEST_ASSERT_EQUAL_PTR(NULL, second_event.next); + TEST_ASSERT_EQUAL_UINT32( + ref_timestamp + TIMESTAMP_MAX_DELTA, interface_stub.interrupt_timestamp + ); + TEST_ASSERT_EQUAL_UINT32(second_event_timestamp, second_event.timestamp); + TEST_ASSERT_EQUAL_UINT64( + second_event.timestamp, + second_event_timestamp + + ((second_event_timestamp < ref_timestamp) ? (1ULL << 32) : 0) + ); + TEST_ASSERT_EQUAL_UINT32((uint32_t) &second_event, second_event.id); + + + // insert third event at the head of the queue out the overflow zone + ticker_event_t third_event; + const timestamp_t third_event_timestamp = + ref_timestamp + TIMESTAMP_MAX_DELTA - 100; + + ticker_insert_event( + &ticker_stub, + &third_event, third_event_timestamp, (uint32_t) &third_event + ); + + TEST_ASSERT_EQUAL_PTR(&third_event, queue_stub.head); + TEST_ASSERT_EQUAL_PTR(&first_event, third_event.next); + TEST_ASSERT_EQUAL_PTR(&second_event, first_event.next); + TEST_ASSERT_EQUAL_PTR(NULL, second_event.next); + TEST_ASSERT_EQUAL_UINT32( + third_event_timestamp, interface_stub.interrupt_timestamp + ); + TEST_ASSERT_EQUAL_UINT32(third_event_timestamp, third_event.timestamp); + TEST_ASSERT_EQUAL_UINT64( + third_event.timestamp, + third_event_timestamp + + ((third_event_timestamp < ref_timestamp) ? (1ULL << 32) : 0) + ); + TEST_ASSERT_EQUAL_UINT32((uint32_t) &third_event, third_event.id); + + // insert fourth event right after the third event + ticker_event_t fourth_event; + const timestamp_t fourth_event_timestamp = third_event_timestamp + 50; + + ticker_insert_event( + &ticker_stub, + &fourth_event, fourth_event_timestamp, (uint32_t) &fourth_event + ); + + TEST_ASSERT_EQUAL_PTR(&third_event, queue_stub.head); + TEST_ASSERT_EQUAL_PTR(&fourth_event, third_event.next); + TEST_ASSERT_EQUAL_PTR(&first_event, fourth_event.next); + TEST_ASSERT_EQUAL_PTR(&second_event, first_event.next); + TEST_ASSERT_EQUAL_PTR(NULL, second_event.next); + TEST_ASSERT_EQUAL_UINT32( + third_event_timestamp, interface_stub.interrupt_timestamp + ); + TEST_ASSERT_EQUAL_UINT32(fourth_event_timestamp, fourth_event.timestamp); + TEST_ASSERT_EQUAL_UINT64( + fourth_event.timestamp, + fourth_event_timestamp + + ((fourth_event_timestamp < ref_timestamp) ? (1ULL << 32) : 0) + ); + TEST_ASSERT_EQUAL_UINT32((uint32_t) &fourth_event, fourth_event.id); + + TEST_ASSERT_EQUAL(0, interface_stub.disable_interrupt_call); +} + +/** + * Given an initialized ticker without user registered events. + * When an event is inserted with ticker_insert_event_us and the timestamp passed + * in parameter is in range [ticker_timestamp : ticker_timestamp + + * TIMESTAMP_MAX_DELTA[. + * Then + * - The event should be in the queue + * - The interrupt timestamp should be equal to the lower 8 bytes of the event. + * - The timestamp of the event should be equal to the timestamp requested. + * - The id of the event should be equal to the id passed in parameter. + */ +static void test_insert_event_us_outside_overflow_range() +{ + ticker_set_handler(&ticker_stub, NULL); + interface_stub.set_interrupt_call = 0; + interface_stub.timestamp = 0xAAAAAAAA; + queue_stub.tick_last_read = interface_stub.timestamp; + queue_stub.present_time = 10ULL << 32 | interface_stub.timestamp; + + // test the end of the range + ticker_event_t last_event = { 0 }; + const us_timestamp_t timestamp_last_event = + queue_stub.present_time + TIMESTAMP_MAX_DELTA; + const uint32_t id_last_event = 0xDEADDEAF; + + ticker_insert_event_us( + &ticker_stub, + &last_event, timestamp_last_event, id_last_event + ); + + TEST_ASSERT_EQUAL_PTR(&last_event, queue_stub.head); + TEST_ASSERT_EQUAL(1, interface_stub.set_interrupt_call); + TEST_ASSERT_EQUAL_UINT32( + timestamp_last_event, interface_stub.interrupt_timestamp + ); + TEST_ASSERT_EQUAL_PTR(NULL, queue_stub.head->next); + TEST_ASSERT_EQUAL_UINT64(timestamp_last_event, last_event.timestamp); + TEST_ASSERT_EQUAL_UINT32(id_last_event, last_event.id); + + // test the beginning of the range + ticker_event_t first_event = { 0 }; + const us_timestamp_t timestamp_first_event = queue_stub.present_time + 1; + const uint32_t id_first_event = 0xAAAAAAAA; + + ticker_insert_event_us( + &ticker_stub, + &first_event, timestamp_first_event, id_first_event + ); + + TEST_ASSERT_EQUAL_PTR(&first_event, queue_stub.head); + TEST_ASSERT_EQUAL(2, interface_stub.set_interrupt_call); + TEST_ASSERT_EQUAL_UINT32( + timestamp_first_event, interface_stub.interrupt_timestamp + ); + TEST_ASSERT_EQUAL_PTR(&last_event, queue_stub.head->next); + TEST_ASSERT_EQUAL_UINT64( + timestamp_first_event, first_event.timestamp + ); + TEST_ASSERT_EQUAL_UINT32(id_first_event, first_event.id); + + TEST_ASSERT_EQUAL(0, interface_stub.disable_interrupt_call); +} + +/** + * Given an initialized ticker without user registered events. + * When an event is inserted with ticker_insert_event_us and a timestamp in the + * range [ticker_timestamp + TIMESTAMP_MAX_DELTA + 1 : UINT64_MAX [ + * Then + * - The event should be in the queue + * - The interrupt timestamp should be equal to TIMESTAMP_MAX_DELTA + * - The timestamp of the event should be equal to the timestamp in parameter. + * - The id of the event should be equal to the id passed in parameter. + */ +static void test_insert_event_us_in_overflow_range() +{ + ticker_set_handler(&ticker_stub, NULL); + interface_stub.set_interrupt_call = 0; + interface_stub.timestamp = 0xAAAAAAAA; + queue_stub.tick_last_read = interface_stub.timestamp; + queue_stub.present_time = 10ULL << 32 | interface_stub.timestamp; + + // test the end of the range + ticker_event_t last_event = { 0 }; + const us_timestamp_t timestamp_last_event = UINT64_MAX; + const uint32_t id_last_event = 0xDEADDEAF; + + ticker_insert_event_us( + &ticker_stub, + &last_event, timestamp_last_event, id_last_event + ); + + TEST_ASSERT_EQUAL_PTR(&last_event, queue_stub.head); + TEST_ASSERT_EQUAL(1, interface_stub.set_interrupt_call); + TEST_ASSERT_EQUAL_UINT32( + interface_stub.timestamp + TIMESTAMP_MAX_DELTA, + interface_stub.interrupt_timestamp + ); + TEST_ASSERT_EQUAL_PTR(NULL, queue_stub.head->next); + TEST_ASSERT_EQUAL_UINT64(timestamp_last_event, last_event.timestamp); + TEST_ASSERT_EQUAL_UINT32(id_last_event, last_event.id); + + // test the beginning of the range + ++interface_stub.timestamp; + ++queue_stub.present_time; + + ticker_event_t first_event = { 0 }; + const us_timestamp_t timestamp_first_event = + queue_stub.present_time + TIMESTAMP_MAX_DELTA + 1; + uint32_t id_first_event = 0xAAAAAAAA; + + ticker_insert_event_us(&ticker_stub, + &first_event, timestamp_first_event, id_first_event + ); + + TEST_ASSERT_EQUAL_PTR(&first_event, queue_stub.head); + TEST_ASSERT_EQUAL(2, interface_stub.set_interrupt_call); + TEST_ASSERT_EQUAL_UINT32( + interface_stub.timestamp + TIMESTAMP_MAX_DELTA, + interface_stub.interrupt_timestamp + ); + TEST_ASSERT_EQUAL_PTR(&last_event, queue_stub.head->next); + TEST_ASSERT_EQUAL_UINT64(timestamp_first_event, first_event.timestamp); + TEST_ASSERT_EQUAL_UINT32(id_first_event, first_event.id); + + TEST_ASSERT_EQUAL(0, interface_stub.disable_interrupt_call); +} + +/** + * Given an initialized ticker without user registered events. + * When an event is inserted with ticker_insert_event_us and a timestamp less + * than timestamp value in the ticker interface. + * Then + * - The event should be in the queue + * - The interrupt timestamp should be set to interface_stub.timestamp so it + * is scheduled immediately. + */ +static void test_insert_event_us_underflow() +{ + ticker_set_handler(&ticker_stub, NULL); + interface_stub.set_interrupt_call = 0; + + interface_stub.timestamp = 0xAAAAAAAA; + queue_stub.tick_last_read = interface_stub.timestamp; + queue_stub.present_time = 10ULL << 32 | interface_stub.timestamp; + + // test the end of the range + ticker_event_t event = { 0 }; + const timestamp_t expected_timestamp = queue_stub.present_time - 1; + const uint32_t expected_id = 0xDEADDEAF; + + ticker_insert_event_us( + &ticker_stub, + &event, expected_timestamp, expected_id + ); + + TEST_ASSERT_EQUAL_PTR(&event, queue_stub.head); + TEST_ASSERT_EQUAL(1, interface_stub.fire_interrupt_call); + + TEST_ASSERT_EQUAL(0, interface_stub.disable_interrupt_call); +} + +/** + * Given an initialized ticker. + * When an event is inserted with ticker_insert_event_us and a timestamp less + * than the one for the next scheduled timestamp. + * Then + * - The event inserted should be the first in the queue + * - The interrupt timestamp should be equal to the timestamp of the event or + * TIMESTAMP_MAX_DELTA if in the overflow range. + * - The timestamp of the event should be equal to the timestamp in parameter. + * - The id of the event should be equal to the id passed in parameter. + * - Events in the queue should remained ordered by timestamp. + */ +static void test_insert_event_us_head() +{ + ticker_set_handler(&ticker_stub, NULL); + interface_stub.set_interrupt_call = 0; + interface_stub.timestamp = 0xAAAAAAAA; + queue_stub.tick_last_read = interface_stub.timestamp; + queue_stub.present_time = 10ULL << 32 | interface_stub.timestamp; + + const us_timestamp_t timestamps[] = { + UINT64_MAX, + queue_stub.present_time + TIMESTAMP_MAX_DELTA + 1, + queue_stub.present_time + TIMESTAMP_MAX_DELTA, + queue_stub.present_time + (TIMESTAMP_MAX_DELTA / 2), + queue_stub.present_time + (TIMESTAMP_MAX_DELTA / 4), + queue_stub.present_time + (TIMESTAMP_MAX_DELTA / 8), + queue_stub.present_time + (TIMESTAMP_MAX_DELTA / 16), + }; + ticker_event_t events[MBED_ARRAY_SIZE(timestamps)] = { 0 }; + + for (size_t i = 0; i < MBED_ARRAY_SIZE(events); ++i) { + ticker_insert_event_us( + &ticker_stub, + &events[i], timestamps[i], i + ); + + TEST_ASSERT_EQUAL_PTR(&events[i], queue_stub.head); + if ((timestamps[i] - queue_stub.present_time) < TIMESTAMP_MAX_DELTA) { + TEST_ASSERT_EQUAL_UINT32( + timestamps[i], + interface_stub.interrupt_timestamp + ); + } else { + TEST_ASSERT_EQUAL_UINT32( + queue_stub.present_time + TIMESTAMP_MAX_DELTA, + interface_stub.interrupt_timestamp + ); + } + + TEST_ASSERT_EQUAL_UINT64(timestamps[i], events[i].timestamp); + TEST_ASSERT_EQUAL_UINT32(i, events[i].id); + + ticker_event_t *e = &events[i]; + while (e) { + TEST_ASSERT_EQUAL_UINT32(timestamps[e->id], e->timestamp); + if (e->next) { + TEST_ASSERT_TRUE(e->id > e->next->id); + TEST_ASSERT_TRUE(e->timestamp < e->next->timestamp); + } else { + TEST_ASSERT_EQUAL_UINT32(0, e->id); + } + e = e->next; + } + } + + TEST_ASSERT_EQUAL(0, interface_stub.disable_interrupt_call); +} + +/** + * Given an initialized ticker. + * When an event is inserted with ticker_insert_event_us and its timestamp is + * bigger than the one of the last event in the queue. + * Then + * - The event inserted should be the last in the queue + * - The interrupt timestamp should remains equal to the interrupt timestamp + * of the head event . + * - The timestamp of the event should reflect the timestamp requested. + * - The id of the event should be equal to the id passed in parameter. + * - Events in the queue should remained ordered by timestamp. + */ +static void test_insert_event_us_tail() +{ + ticker_set_handler(&ticker_stub, NULL); + interface_stub.set_interrupt_call = 0; + + const us_timestamp_t timestamps[] = { + 0xA, + (1ULL << 32), + (2ULL << 32), + (4ULL << 32), + (8ULL << 32), + (16ULL << 32), + (32ULL << 32), + (64ULL << 32), + }; + ticker_event_t events[MBED_ARRAY_SIZE(timestamps)] = { 0 }; + + for (size_t i = 0; i < MBED_ARRAY_SIZE(events); ++i) { + ticker_insert_event_us( + &ticker_stub, + &events[i], timestamps[i], i + ); + + TEST_ASSERT_EQUAL_PTR(&events[0], queue_stub.head); + TEST_ASSERT_EQUAL_UINT32( + timestamps[0], interface_stub.interrupt_timestamp + ); + TEST_ASSERT_EQUAL_UINT64(timestamps[i], events[i].timestamp); + TEST_ASSERT_EQUAL_UINT32(i, events[i].id); + + ticker_event_t *e = queue_stub.head; + while (e) { + TEST_ASSERT_EQUAL_UINT32(timestamps[e->id], e->timestamp); + if (e->next) { + TEST_ASSERT_TRUE(e->id < e->next->id); + TEST_ASSERT_TRUE(e->timestamp < e->next->timestamp); + } else { + TEST_ASSERT_EQUAL_UINT32(&events[i], e); + } + e = e->next; + } + } + + TEST_ASSERT_EQUAL(0, interface_stub.disable_interrupt_call); +} + +/** + * Given an initialized ticker. + * When an event is inserted with ticker_insert_event_us. + * Then + * - The event inserted should be at the correct position in the queue + * - The event queue should remain ordered by timestamp + * - The interrupt timestamp should be equal to the interrupt timestamp + * of the head event or TIMESTAMP_MAX_DELTA if the + * timestamp is in the overflow range. + * - The timestamp of the event should be equal to the timestamp parameter. + * - The id of the event should be equal to the id passed in parameter. + * - Events in the queue should remained ordered by timestamp. + */ +static void test_insert_event_us_multiple_random() +{ + ticker_set_handler(&ticker_stub, NULL); + interface_stub.set_interrupt_call = 0; + + const timestamp_t ref_timestamp = UINT32_MAX / 2; + interface_stub.timestamp = ref_timestamp; + + // insert first event at the head of the queue + ticker_event_t first_event; + const us_timestamp_t first_event_timestamp = + ref_timestamp + TIMESTAMP_MAX_DELTA + 100; + + ticker_insert_event_us( + &ticker_stub, + &first_event, first_event_timestamp, (uint32_t) &first_event + ); + + TEST_ASSERT_EQUAL_PTR(&first_event, queue_stub.head); + TEST_ASSERT_EQUAL_PTR(NULL, first_event.next); + TEST_ASSERT_EQUAL_UINT32( + ref_timestamp + TIMESTAMP_MAX_DELTA, interface_stub.interrupt_timestamp + ); + TEST_ASSERT_EQUAL_UINT64(first_event.timestamp, first_event_timestamp); + TEST_ASSERT_EQUAL_UINT32((uint32_t) &first_event, first_event.id); + + // insert second event at the tail of the queue + ticker_event_t second_event; + const us_timestamp_t second_event_timestamp = first_event_timestamp + 1; + + ticker_insert_event_us( + &ticker_stub, + &second_event, second_event_timestamp, (uint32_t) &second_event + ); + + TEST_ASSERT_EQUAL_PTR(&first_event, queue_stub.head); + TEST_ASSERT_EQUAL_PTR(&second_event, first_event.next); + TEST_ASSERT_EQUAL_PTR(NULL, second_event.next); + TEST_ASSERT_EQUAL_UINT32( + ref_timestamp + TIMESTAMP_MAX_DELTA, interface_stub.interrupt_timestamp + ); + TEST_ASSERT_EQUAL_UINT64(second_event_timestamp, second_event.timestamp); + TEST_ASSERT_EQUAL_UINT32((uint32_t) &second_event, second_event.id); + + + // insert third event at the head of the queue out the overflow zone + ticker_event_t third_event; + const us_timestamp_t third_event_timestamp = + ref_timestamp + TIMESTAMP_MAX_DELTA - 100; + + ticker_insert_event_us( + &ticker_stub, + &third_event, third_event_timestamp, (uint32_t) &third_event + ); + + TEST_ASSERT_EQUAL_PTR(&third_event, queue_stub.head); + TEST_ASSERT_EQUAL_PTR(&first_event, third_event.next); + TEST_ASSERT_EQUAL_PTR(&second_event, first_event.next); + TEST_ASSERT_EQUAL_PTR(NULL, second_event.next); + TEST_ASSERT_EQUAL_UINT32( + third_event_timestamp, interface_stub.interrupt_timestamp + ); + TEST_ASSERT_EQUAL_UINT64(third_event_timestamp, third_event.timestamp); + TEST_ASSERT_EQUAL_UINT32((uint32_t) &third_event, third_event.id); + + // insert fourth event right after the third event + ticker_event_t fourth_event; + const us_timestamp_t fourth_event_timestamp = third_event_timestamp + 50; + + ticker_insert_event_us( + &ticker_stub, + &fourth_event, fourth_event_timestamp, (uint32_t) &fourth_event + ); + + TEST_ASSERT_EQUAL_PTR(&third_event, queue_stub.head); + TEST_ASSERT_EQUAL_PTR(&fourth_event, third_event.next); + TEST_ASSERT_EQUAL_PTR(&first_event, fourth_event.next); + TEST_ASSERT_EQUAL_PTR(&second_event, first_event.next); + TEST_ASSERT_EQUAL_PTR(NULL, second_event.next); + TEST_ASSERT_EQUAL_UINT32( + third_event_timestamp, interface_stub.interrupt_timestamp + ); + TEST_ASSERT_EQUAL_UINT64(fourth_event_timestamp, fourth_event.timestamp); + TEST_ASSERT_EQUAL_UINT32((uint32_t) &fourth_event, fourth_event.id); + + TEST_ASSERT_EQUAL(0, interface_stub.disable_interrupt_call); +} + +/** + * Given an initialized ticker with multiple events registered. + * When the event at the tail of the queue is removed from the queue. + * Then: + * - The event should not be in the queue. + * - The events in the queue should remain ordered + * - The interrupt timestamp should be unchanged. + */ +static void test_remove_event_tail() +{ + ticker_set_handler(&ticker_stub, NULL); + const us_timestamp_t timestamps[] = { + 0xA, + (1ULL << 32), + (2ULL << 32), + (4ULL << 32), + (8ULL << 32), + (16ULL << 32), + (32ULL << 32), + (64ULL << 32), + }; + ticker_event_t events[MBED_ARRAY_SIZE(timestamps)] = { 0 }; + + for (size_t i = 0; i < MBED_ARRAY_SIZE(events); ++i) { + ticker_insert_event_us( + &ticker_stub, + &events[i], timestamps[i], i + ); + } + + for (ssize_t i = MBED_ARRAY_SIZE(events) - 1; i >= 0; --i) { + ticker_remove_event(&ticker_stub, &events[i]); + + ticker_event_t *e = queue_stub.head; + size_t event_count = 0; + while (e) { + TEST_ASSERT_NOT_EQUAL(e, &events[i]); + if (e->next) { + TEST_ASSERT_TRUE(e->timestamp <= e->next->timestamp); + } + e = e->next; + ++event_count; + } + + TEST_ASSERT_EQUAL(i, event_count); + + if (i != 0) { + TEST_ASSERT_EQUAL( + timestamps[0], + interface_stub.interrupt_timestamp + ); + } else { + TEST_ASSERT_EQUAL( + interface_stub.timestamp + TIMESTAMP_MAX_DELTA, + interface_stub.interrupt_timestamp + ); + } + } + + TEST_ASSERT_EQUAL(0, interface_stub.disable_interrupt_call); +} + +/** + * Given an initialized ticker with multiple events registered. + * When the event at the head of the queue is removed from the queue. + * Then: + * - The event should not be in the queue. + * - The event at the head of the queue should be the equal to the one + * after the event removed. + * - The interrupt timestamp should be equal to the interrupt timestamp + * of the head event or TIMESTAMP_MAX_DELTA if the + * timestamp is in the overflow range. + */ +static void test_remove_event_head() +{ + ticker_set_handler(&ticker_stub, NULL); + const us_timestamp_t timestamps[] = { + TIMESTAMP_MAX_DELTA / 8, + TIMESTAMP_MAX_DELTA / 4, + TIMESTAMP_MAX_DELTA / 2, + TIMESTAMP_MAX_DELTA - 1, + TIMESTAMP_MAX_DELTA, + TIMESTAMP_MAX_DELTA + 1, + (1ULL << 32) | TIMESTAMP_MAX_DELTA, + UINT64_MAX + }; + ticker_event_t events[MBED_ARRAY_SIZE(timestamps)] = { 0 }; + + for (size_t i = 0; i < MBED_ARRAY_SIZE(events); ++i) { + ticker_insert_event_us(&ticker_stub, + &events[i], timestamps[i], i + ); + } + + for (size_t i = 0; i < MBED_ARRAY_SIZE(events); ++i) { + ticker_remove_event(&ticker_stub, &events[i]); + + ticker_event_t *e = queue_stub.head; + size_t event_count = 0; + while (e) { + TEST_ASSERT_NOT_EQUAL(e, &events[i]); + if (e->next) { + TEST_ASSERT_TRUE(e->timestamp <= e->next->timestamp); + } + e = e->next; + ++event_count; + } + + TEST_ASSERT_EQUAL(MBED_ARRAY_SIZE(events) - i - 1, event_count); + + if (event_count) { + TEST_ASSERT_EQUAL( + std::min( + timestamps[i + 1], + interface_stub.timestamp + TIMESTAMP_MAX_DELTA + ), + interface_stub.interrupt_timestamp + ); + } else { + TEST_ASSERT_EQUAL( + interface_stub.timestamp + TIMESTAMP_MAX_DELTA, + interface_stub.interrupt_timestamp + ); + } + + } + + TEST_ASSERT_EQUAL(0, interface_stub.disable_interrupt_call); +} + +/** + * Given an initialized ticker with multiple events registered. + * When an event not in the queue is attempted to be removed. + * Then the queue should remains identical as before. + */ +static void test_remove_event_invalid() +{ + ticker_set_handler(&ticker_stub, NULL); + const us_timestamp_t timestamps[] = { + TIMESTAMP_MAX_DELTA / 8, + TIMESTAMP_MAX_DELTA / 4, + TIMESTAMP_MAX_DELTA / 2, + TIMESTAMP_MAX_DELTA - 1, + TIMESTAMP_MAX_DELTA, + TIMESTAMP_MAX_DELTA + 1, + (1ULL << 32) | TIMESTAMP_MAX_DELTA, + UINT64_MAX + }; + ticker_event_t events[MBED_ARRAY_SIZE(timestamps)] = { 0 }; + + for (size_t i = 0; i < MBED_ARRAY_SIZE(events); ++i) { + ticker_insert_event_us( + &ticker_stub, + &events[i], timestamps[i], i + ); + } + + ticker_event_t invalid_event; + ticker_remove_event(&ticker_stub, &invalid_event); + + TEST_ASSERT_EQUAL(&events[0], queue_stub.head); + + ticker_event_t *e = queue_stub.head; + size_t event_count = 0; + while (e) { + TEST_ASSERT_EQUAL(e, &events[event_count]); + e = e->next; + ++event_count; + } + TEST_ASSERT_EQUAL(MBED_ARRAY_SIZE(events), event_count); +} + +/** + * Given an initialized ticker with multiple events inserted. + * When an event is remoced + * Then: + * - the event should not be in the queue + * - the queue should remain ordered + * - the interrupt timestamp should be set to either head->timestamp or + * TIMESTAMP_MAX_DELTA depending on the distance between the current time + * ans the timestamp of the event at the head of the queue. + */ +static void test_remove_random() +{ + ticker_set_handler(&ticker_stub, NULL); + interface_stub.set_interrupt_call = 0; + + const timestamp_t ref_timestamp = UINT32_MAX / 2; + interface_stub.timestamp = ref_timestamp; + + // insert all events + ticker_event_t first_event; + const us_timestamp_t first_event_timestamp = + ref_timestamp + TIMESTAMP_MAX_DELTA + 100; + + ticker_insert_event_us( + &ticker_stub, + &first_event, first_event_timestamp, (uint32_t) &first_event + ); + + + ticker_event_t second_event; + const us_timestamp_t second_event_timestamp = first_event_timestamp + 1; + + ticker_insert_event_us( + &ticker_stub, + &second_event, second_event_timestamp, (uint32_t) &second_event + ); + + ticker_event_t third_event; + const us_timestamp_t third_event_timestamp = + ref_timestamp + TIMESTAMP_MAX_DELTA - 100; + + ticker_insert_event_us( + &ticker_stub, + &third_event, third_event_timestamp, (uint32_t) &third_event + ); + + ticker_event_t fourth_event; + const us_timestamp_t fourth_event_timestamp = third_event_timestamp + 50; + + ticker_insert_event_us( + &ticker_stub, + &fourth_event, fourth_event_timestamp, (uint32_t) &fourth_event + ); + + // test that the queue is in the correct state + TEST_ASSERT_EQUAL_PTR(&third_event, queue_stub.head); + TEST_ASSERT_EQUAL_PTR(&fourth_event, third_event.next); + TEST_ASSERT_EQUAL_PTR(&first_event, fourth_event.next); + TEST_ASSERT_EQUAL_PTR(&second_event, first_event.next); + TEST_ASSERT_EQUAL_PTR(NULL, second_event.next); + TEST_ASSERT_EQUAL_UINT32( + third_event_timestamp, interface_stub.interrupt_timestamp + ); + TEST_ASSERT_EQUAL_UINT64(fourth_event_timestamp, fourth_event.timestamp); + TEST_ASSERT_EQUAL_UINT32((uint32_t) &fourth_event, fourth_event.id); + + // remove fourth event + ticker_remove_event(&ticker_stub, &fourth_event); + + TEST_ASSERT_EQUAL_PTR(&third_event, queue_stub.head); + TEST_ASSERT_EQUAL_PTR(&first_event, third_event.next); + TEST_ASSERT_EQUAL_PTR(&second_event, first_event.next); + TEST_ASSERT_EQUAL_PTR(NULL, second_event.next); + TEST_ASSERT_EQUAL_UINT32( + third_event_timestamp, interface_stub.interrupt_timestamp + ); + TEST_ASSERT_EQUAL_UINT64(third_event_timestamp, third_event.timestamp); + TEST_ASSERT_EQUAL_UINT32((uint32_t) &third_event, third_event.id); + + // remove third event + ticker_remove_event(&ticker_stub, &third_event); + + TEST_ASSERT_EQUAL_PTR(&first_event, queue_stub.head); + TEST_ASSERT_EQUAL_PTR(&second_event, first_event.next); + TEST_ASSERT_EQUAL_PTR(NULL, second_event.next); + TEST_ASSERT_EQUAL_UINT32( + ref_timestamp + TIMESTAMP_MAX_DELTA, interface_stub.interrupt_timestamp + ); + TEST_ASSERT_EQUAL_UINT64(second_event_timestamp, second_event.timestamp); + TEST_ASSERT_EQUAL_UINT32((uint32_t) &second_event, second_event.id); + + // remove second event + ticker_remove_event(&ticker_stub, &second_event); + + TEST_ASSERT_EQUAL_PTR(&first_event, queue_stub.head); + TEST_ASSERT_EQUAL_PTR(NULL, first_event.next); + TEST_ASSERT_EQUAL_UINT32( + ref_timestamp + TIMESTAMP_MAX_DELTA, interface_stub.interrupt_timestamp + ); + TEST_ASSERT_EQUAL_UINT64(first_event.timestamp, first_event_timestamp); + TEST_ASSERT_EQUAL_UINT32((uint32_t) &first_event, first_event.id); + + // remove first event + ticker_remove_event(&ticker_stub, &first_event); + + TEST_ASSERT_EQUAL_PTR(NULL, queue_stub.head); + TEST_ASSERT_EQUAL_PTR(NULL, first_event.next); + TEST_ASSERT_EQUAL_UINT32( + ref_timestamp + TIMESTAMP_MAX_DELTA, interface_stub.interrupt_timestamp + ); + + TEST_ASSERT_EQUAL(0, interface_stub.disable_interrupt_call); +} + +/** + * Given an initialized ticker without user registered events and a ticker + * interface timestamp equal or bigger than the one registered by the overflow + * event. + * When the interrupt handler is called. + * Then: + * - The interrupt timestamp should be updated to the timestamp of the ticker + * interface plus TIMESTAMP_MAX_DELTA. + * - The irq handler registered should not be called. + */ +static void test_overflow_event_update() +{ + static uint32_t handler_call = 0; + struct irq_handler_stub_t { + static void event_handler(uint32_t id) + { + ++handler_call; + } + }; + handler_call = 0; + + ticker_set_handler(&ticker_stub, irq_handler_stub_t::event_handler); + interface_stub.set_interrupt_call = 0; + + for (size_t i = 0; i < 8; ++i) { + us_timestamp_t previous_timestamp = queue_stub.present_time; + timestamp_t interface_timestamp = + previous_timestamp + (TIMESTAMP_MAX_DELTA + i * 100); + interface_stub.timestamp = interface_timestamp; + + ticker_irq_handler(&ticker_stub); + TEST_ASSERT_EQUAL(i + 1, interface_stub.clear_interrupt_call); + + TEST_ASSERT_EQUAL(i + 1, interface_stub.set_interrupt_call); + TEST_ASSERT_EQUAL_UINT32( + interface_timestamp + TIMESTAMP_MAX_DELTA, + interface_stub.interrupt_timestamp + ); + TEST_ASSERT_EQUAL(0, handler_call); + } + + TEST_ASSERT_EQUAL(0, interface_stub.disable_interrupt_call); +} + +/** + * Given an initialized ticker without user registered events and a ticker + * interface timestamp less than the one registered to handle overflow. + * When the interrupt handler is called. + * Then: + * - The interrupt timestamp should be updated to the timestamp of the ticker + * interface plus TIMESTAMP_MAX_DELTA. + * - The irq handler registered should not be called. + */ +static void test_overflow_event_update_when_spurious_interrupt() +{ + static uint32_t handler_call = 0; + struct irq_handler_stub_t { + static void event_handler(uint32_t id) + { + ++handler_call; + } + }; + handler_call = 0; + + ticker_set_handler(&ticker_stub, irq_handler_stub_t::event_handler); + interface_stub.set_interrupt_call = 0; + + for (size_t i = 0; i < 8; ++i) { + us_timestamp_t previous_timestamp = queue_stub.present_time; + timestamp_t interface_timestamp = + previous_timestamp + (TIMESTAMP_MAX_DELTA / (2 + i)); + interface_stub.timestamp = interface_timestamp; + + ticker_irq_handler(&ticker_stub); + + TEST_ASSERT_EQUAL(i + 1, interface_stub.clear_interrupt_call); + TEST_ASSERT_EQUAL(i + 1, interface_stub.set_interrupt_call); + TEST_ASSERT_EQUAL_UINT32( + interface_timestamp + TIMESTAMP_MAX_DELTA, + interface_stub.interrupt_timestamp + ); + TEST_ASSERT_EQUAL(0, handler_call); + } + + TEST_ASSERT_EQUAL(0, interface_stub.disable_interrupt_call); +} + +/** + * Given an initialized ticker with a single ticker event inserted and a ticker + * interface timestamp bigger than the one set for interrupt. + * When ticker_irq_handler is called. + * Then: + * - The IRQ handler should be called with the id of the event at the head of + * the queue. + * - The event at the head of the queue should be replaced by the next event. + * - The interrupt timestamp in the ticker interface should be set to the + * value of the interface timestamp + TIMESTAMP_MAX_DELTA + */ +static void test_irq_handler_single_event() +{ + static const timestamp_t event_timestamp = 0xAAAAAAAA; + static const timestamp_t interface_timestamp_after_irq = event_timestamp + 100; + + uint32_t handler_call = 0; + struct irq_handler_stub_t { + static void event_handler(uint32_t id) + { + ++ (*((uint32_t *) id)); + interface_stub.timestamp = interface_timestamp_after_irq; + } + }; + + ticker_set_handler(&ticker_stub, irq_handler_stub_t::event_handler); + interface_stub.set_interrupt_call = 0; + + ticker_event_t e; + ticker_insert_event(&ticker_stub, &e, event_timestamp, (uint32_t) &handler_call); + + interface_stub.timestamp = event_timestamp; + interface_stub.set_interrupt_call = 0; + + ticker_irq_handler(&ticker_stub); + + TEST_ASSERT_EQUAL(1, interface_stub.clear_interrupt_call); + TEST_ASSERT_EQUAL(1, interface_stub.set_interrupt_call); + TEST_ASSERT_EQUAL(1, handler_call); + TEST_ASSERT_EQUAL_UINT32( + interface_timestamp_after_irq + TIMESTAMP_MAX_DELTA, + interface_stub.interrupt_timestamp + ); + + TEST_ASSERT_NULL(queue_stub.head); + + TEST_ASSERT_EQUAL(0, interface_stub.disable_interrupt_call); +} + +/** + * Given an initialized ticker with at least a ticker event inserted and a ticker + * interface timestamp less than the one set for interrupt. + * When ticker_irq_handler is called. + * Then: + * - The IRQ handler should not be called. + * - The event at the head of the queue should remains the same. + * - The interrupt timestamp in the ticker interface should be set to the + * value of the event timestamp + */ +static void test_irq_handler_single_event_spurious() +{ + struct irq_handler_stub_t { + static void event_handler(uint32_t id) + { + TEST_FAIL(); + } + }; + + ticker_set_handler(&ticker_stub, irq_handler_stub_t::event_handler); + interface_stub.set_interrupt_call = 0; + + const us_timestamp_t timestamps [] = { + UINT32_MAX, + TIMESTAMP_MAX_DELTA + 1, + TIMESTAMP_MAX_DELTA, + TIMESTAMP_MAX_DELTA - 1 + }; + + ticker_event_t events[MBED_ARRAY_SIZE(timestamps)] = { 0 }; + + for (size_t i = 0; i < MBED_ARRAY_SIZE(events); ++i) { + ticker_insert_event_us( + &ticker_stub, + &events[i], timestamps[i], timestamps[i] + ); + interface_stub.set_interrupt_call = 0; + interface_stub.clear_interrupt_call = 0; + + ticker_irq_handler(&ticker_stub); + + TEST_ASSERT_EQUAL(1, interface_stub.clear_interrupt_call); + TEST_ASSERT_EQUAL(1, interface_stub.set_interrupt_call); + TEST_ASSERT_EQUAL_UINT32( + std::min(timestamps[i], TIMESTAMP_MAX_DELTA), + interface_stub.interrupt_timestamp + ); + } + + TEST_ASSERT_EQUAL(0, interface_stub.disable_interrupt_call); +} + +/** + * Given an initialized ticker with multiple ticker event inserted, its + * interface timestamp at greater than the timestamp of the next schedule event + * and all event execution time taking at least the time befor ethe next event. + * When ticker_irq_handler is called. + * Then: + * - The IRQ handler should have been called for every event. + * - The head of the queue should be set to NULL. + * - The interrupt timestamp in the ticker interface should be scheduled in + * TIMESTAMP_MAX_DELTAs + */ +static void test_irq_handler_multiple_event_multiple_dequeue() +{ + const us_timestamp_t timestamps [] = { + 10, + 10 + TIMESTAMP_MAX_DELTA - 1, + 10 + TIMESTAMP_MAX_DELTA, + 10 + TIMESTAMP_MAX_DELTA + 1, + UINT32_MAX + }; + + static size_t handler_called = 0; + struct irq_handler_stub_t { + static void event_handler(uint32_t id) + { + ++handler_called; + ticker_event_t *e = (ticker_event_t *) id; + if (e->next) { + interface_stub.timestamp = e->next->timestamp; + } + } + }; + handler_called = 0; + + ticker_set_handler(&ticker_stub, irq_handler_stub_t::event_handler); + interface_stub.set_interrupt_call = 0; + + ticker_event_t events[MBED_ARRAY_SIZE(timestamps)] = { 0 }; + + for (size_t i = 0; i < MBED_ARRAY_SIZE(events); ++i) { + ticker_insert_event_us( + &ticker_stub, + &events[i], timestamps[i], (uint32_t) &events[i] + ); + } + + interface_stub.set_interrupt_call = 0; + interface_stub.clear_interrupt_call = 0; + interface_stub.timestamp = timestamps[0]; + + ticker_irq_handler(&ticker_stub); + + TEST_ASSERT_EQUAL(1, interface_stub.clear_interrupt_call); + TEST_ASSERT_EQUAL(1, interface_stub.set_interrupt_call); + TEST_ASSERT_EQUAL_UINT32(MBED_ARRAY_SIZE(timestamps), handler_called); + TEST_ASSERT_EQUAL_UINT32( + timestamps[MBED_ARRAY_SIZE(timestamps) - 1] + TIMESTAMP_MAX_DELTA, + interface_stub.interrupt_timestamp + ); + TEST_ASSERT_NULL(queue_stub.head); + + TEST_ASSERT_EQUAL(0, interface_stub.disable_interrupt_call); +} + +/** + * Given an initialized ticker with two ticker event inserted scheduled from more + * than TIMESTAMP_MAX_DELTA from one another. The interface + * timestamp is equal to the timestamp of the first event. + * When ticker_irq_handler is called. + * Then: + * - The IRQ handler should have been called for the first event. + * - The head of the queue should be set to the event after the first event. + * - The interrupt timestamp in the ticker interface should be scheduled in + * TIMESTAMP_MAX_DELTA. + */ +static void test_irq_handler_multiple_event_single_dequeue_overflow() +{ + const us_timestamp_t timestamps [] = { + 10, + 10 + TIMESTAMP_MAX_DELTA + 1 + }; + + size_t handler_called = 0; + struct irq_handler_stub_t { + static void event_handler(uint32_t id) + { + ++ (*((size_t *) id)); + } + }; + + ticker_set_handler(&ticker_stub, irq_handler_stub_t::event_handler); + interface_stub.set_interrupt_call = 0; + + ticker_event_t events[MBED_ARRAY_SIZE(timestamps)] = { 0 }; + + for (size_t i = 0; i < MBED_ARRAY_SIZE(events); ++i) { + ticker_insert_event_us( + &ticker_stub, + &events[i], timestamps[i], (uint32_t) &handler_called + ); + } + + interface_stub.set_interrupt_call = 0; + interface_stub.clear_interrupt_call = 0; + interface_stub.timestamp = timestamps[0]; + + ticker_irq_handler(&ticker_stub); + + TEST_ASSERT_EQUAL(1, interface_stub.clear_interrupt_call); + TEST_ASSERT_EQUAL(1, interface_stub.set_interrupt_call); + TEST_ASSERT_EQUAL_UINT32(1, handler_called); + TEST_ASSERT_EQUAL_UINT32( + timestamps[0] + TIMESTAMP_MAX_DELTA, + interface_stub.interrupt_timestamp + ); + TEST_ASSERT_EQUAL_PTR(&events[1], queue_stub.head); + + TEST_ASSERT_EQUAL(0, interface_stub.disable_interrupt_call); +} + +/** + * Given an initialized ticker with two ticker event inserted scheduled from less + * than TIMESTAMP_MAX_DELTA from one another. The interface + * timestamp is equal to the timestamp of the first event. + * When ticker_irq_handler is called. + * Then: + * - The IRQ handler should have been called for the first event. + * - The head of the queue should be set to second event. + * - The interrupt timestamp in the ticker interface should be equal to the + * timestamp of the second event. + */ +static void test_irq_handler_multiple_event_single_dequeue() +{ + const us_timestamp_t timestamps [] = { + 10, + 10 + TIMESTAMP_MAX_DELTA - 1 + }; + + size_t handler_called = 0; + struct irq_handler_stub_t { + static void event_handler(uint32_t id) + { + ++ (*((size_t *) id)); + } + }; + + ticker_set_handler(&ticker_stub, irq_handler_stub_t::event_handler); + interface_stub.set_interrupt_call = 0; + + ticker_event_t events[MBED_ARRAY_SIZE(timestamps)] = { 0 }; + + for (size_t i = 0; i < MBED_ARRAY_SIZE(events); ++i) { + ticker_insert_event_us( + &ticker_stub, + &events[i], timestamps[i], (uint32_t) &handler_called + ); + } + + interface_stub.set_interrupt_call = 0; + interface_stub.clear_interrupt_call = 0; + interface_stub.timestamp = timestamps[0]; + + ticker_irq_handler(&ticker_stub); + + TEST_ASSERT_EQUAL(1, interface_stub.clear_interrupt_call); + TEST_ASSERT_EQUAL(1, interface_stub.set_interrupt_call); + TEST_ASSERT_EQUAL_UINT32(1, handler_called); + TEST_ASSERT_EQUAL_UINT32( + timestamps[1], + interface_stub.interrupt_timestamp + ); + TEST_ASSERT_EQUAL_PTR(&events[1], queue_stub.head); + + TEST_ASSERT_EQUAL(0, interface_stub.disable_interrupt_call); +} + +/** + * Given an initialized ticker with multiple ticker event inserted and the + * interface timestamp is equal to the timestamp of the first event. The first + * event to execute will insert an events in the ticker which have to be executed + * immediately. + * When ticker_irq_handler is called. + * Then: + * - The IRQ handler should have been called for the first event and the event + * inserted during irq. + * - The head of the queue should be set correctly. + * - The interrupt timestamp in the ticker interface should be equal to + * timestamp of the head event. + */ +static void test_irq_handler_insert_immediate_in_irq() +{ + static const us_timestamp_t timestamps [] = { + 10, + 10 + TIMESTAMP_MAX_DELTA - 1 + }; + + static const us_timestamp_t expected_timestamp = + ((timestamps[1] - timestamps[0]) / 2) + timestamps[0]; + + struct ctrl_block_t { + bool irq_event_called; + ticker_event_t immediate_event; + size_t handler_called; + }; + + ctrl_block_t ctrl_block = { 0 }; + + struct irq_handler_stub_t { + static void event_handler(uint32_t id) + { + ctrl_block_t *ctrl_block = (ctrl_block_t *) id; + + if (ctrl_block->handler_called == 0) { + ticker_insert_event( + &ticker_stub, + &ctrl_block->immediate_event, expected_timestamp, id + ); + interface_stub.timestamp = expected_timestamp; + } else if (ctrl_block->handler_called > 1) { + TEST_FAIL(); + } + ++ctrl_block->handler_called; + } + }; + + ticker_set_handler(&ticker_stub, irq_handler_stub_t::event_handler); + interface_stub.set_interrupt_call = 0; + + ticker_event_t events[MBED_ARRAY_SIZE(timestamps)] = { 0 }; + + for (size_t i = 0; i < MBED_ARRAY_SIZE(events); ++i) { + ticker_insert_event_us( + &ticker_stub, + &events[i], timestamps[i], (uint32_t) &ctrl_block + ); + } + + interface_stub.set_interrupt_call = 0; + interface_stub.clear_interrupt_call = 0; + interface_stub.timestamp = timestamps[0]; + + ticker_irq_handler(&ticker_stub); + + TEST_ASSERT_EQUAL(1, interface_stub.clear_interrupt_call); + TEST_ASSERT_EQUAL_UINT32(2, ctrl_block.handler_called); + TEST_ASSERT_EQUAL_UINT32( + timestamps[1], + interface_stub.interrupt_timestamp + ); + TEST_ASSERT_EQUAL_PTR(&events[1], queue_stub.head); + + TEST_ASSERT_EQUAL(0, interface_stub.disable_interrupt_call); +} + +/** + * Given an initialized ticker with multiple ticker event inserted and the + * interface timestamp is equal to the timestamp of the first event. The first + * event to execute will insert an events in the ticker which does not have to + * be executed immediately. + * When ticker_irq_handler is called. + * Then: + * - The IRQ handler should have been called for the first event. + * - The head of the queue should be set to the event inserted in IRQ. + * - The interrupt timestamp in the ticker interface should be equal to + * timestamp of the head event. + */ +static void test_irq_handler_insert_non_immediate_in_irq() +{ + static const us_timestamp_t timestamps [] = { + 10, + 10 + TIMESTAMP_MAX_DELTA - 1 + }; + + static const us_timestamp_t expected_timestamp = + ((timestamps[1] - timestamps[0]) / 2) + timestamps[0]; + + struct ctrl_block_t { + bool irq_event_called; + ticker_event_t non_immediate_event; + size_t handler_called; + }; + + ctrl_block_t ctrl_block = { 0 }; + + struct irq_handler_stub_t { + static void event_handler(uint32_t id) + { + ctrl_block_t *ctrl_block = (ctrl_block_t *) id; + + if (ctrl_block->handler_called == 0) { + ticker_insert_event( + &ticker_stub, + &ctrl_block->non_immediate_event, expected_timestamp, id + ); + } else { + TEST_FAIL(); + } + ++ctrl_block->handler_called; + } + }; + + + ticker_set_handler(&ticker_stub, irq_handler_stub_t::event_handler); + interface_stub.set_interrupt_call = 0; + + ticker_event_t events[MBED_ARRAY_SIZE(timestamps)] = { 0 }; + + for (size_t i = 0; i < MBED_ARRAY_SIZE(events); ++i) { + ticker_insert_event_us( + &ticker_stub, + &events[i], timestamps[i], (uint32_t) &ctrl_block + ); + } + + interface_stub.set_interrupt_call = 0; + interface_stub.clear_interrupt_call = 0; + interface_stub.timestamp = timestamps[0]; + + ticker_irq_handler(&ticker_stub); + + TEST_ASSERT_EQUAL(1, interface_stub.clear_interrupt_call); + TEST_ASSERT_EQUAL_UINT32(1, ctrl_block.handler_called); + TEST_ASSERT_EQUAL_UINT32( + expected_timestamp, + interface_stub.interrupt_timestamp + ); + TEST_ASSERT_EQUAL_PTR(&ctrl_block.non_immediate_event, queue_stub.head); + TEST_ASSERT_EQUAL_PTR(&events[1], queue_stub.head->next); + + TEST_ASSERT_EQUAL(0, interface_stub.disable_interrupt_call); +} + +static uint32_t ticker_interface_stub_read_interrupt_time() +{ + ++interface_stub.read_call; + // only if set interrupt call, to test the condition afterwards + if (interface_stub.set_interrupt_call) { + return interface_stub.interrupt_timestamp; + } else { + return interface_stub.timestamp; + } +} + +/** + * Test to insert an event that is already in the past, the fire_interrupt should + * be invoked, instead of set_interrupt + */ +static void test_set_interrupt_past_time() +{ + ticker_set_handler(&ticker_stub, NULL); + + interface_stub.set_interrupt_call = 0; + interface_stub.fire_interrupt_call = 0; + interface_stub.timestamp = 0xFF; + + + // This tests fire now functinality when next_event_timestamp <= present + ticker_event_t event = { 0 }; + const timestamp_t event_timestamp = interface_stub.timestamp; + const uint32_t id_last_event = 0xDEADDEAF; + + ticker_insert_event(&ticker_stub, &event, event_timestamp, id_last_event); + TEST_ASSERT_EQUAL(0, interface_stub.set_interrupt_call); + TEST_ASSERT_EQUAL(1, interface_stub.fire_interrupt_call); +} +/** + * Test to insert an event that is being delayed, set_interrupt is set + * but then event is already in the past, thus fire_interrupt should be invoked right-away + */ +static void test_set_interrupt_past_time_with_delay() +{ + ticker_set_handler(&ticker_stub, NULL); + + interface_stub.set_interrupt_call = 0; + interface_stub.fire_interrupt_call = 0; + interface_stub.timestamp = 0xFF; + + // This tests fire now functionality when present time >= new_match_time + interface_stub.interface.read = ticker_interface_stub_read_interrupt_time; + ticker_event_t event = { 0 }; + const timestamp_t event_timestamp = interface_stub.timestamp + 5; + const uint32_t id_last_event = 0xDEADDEAF; + + ticker_insert_event(&ticker_stub, &event, event_timestamp, id_last_event); + TEST_ASSERT_EQUAL(1, interface_stub.set_interrupt_call); + TEST_ASSERT_EQUAL(1, interface_stub.fire_interrupt_call); +} + +/** + * Convert ticks at a given frequency to time in microseconds + * + * Assert if there is a 64-bit overflow + */ +static uint64_t convert_to_us(uint64_t ticks, uint32_t frequency) +{ + uint64_t scaled_ticks = ticks * 1000000; + // Assert that there was not an overflow + TEST_ASSERT_EQUAL(ticks, scaled_ticks / 1000000); + return scaled_ticks / frequency; +} + +/** + * Given an uninitialized ticker instance and an interface of a + * certain frequency and bit width. + * Then the time returned the ticker should match the cumulative time. + */ +void test_frequencies_and_masks(uint32_t frequency, uint32_t bits) +{ + const uint32_t bitmask = ((uint64_t)1 << bits) - 1; + + ticker_set_handler(&ticker_stub, NULL); + uint64_t ticks = 0; + + // Single tick + ticks += 1; + interface_stub.timestamp = ticks & bitmask; + TEST_ASSERT_EQUAL_UINT32(convert_to_us(ticks, frequency), ticker_read(&ticker_stub)); + TEST_ASSERT_EQUAL_UINT64(convert_to_us(ticks, frequency), ticker_read_us(&ticker_stub)); + + // Run until the loop before 64-bit overflow (worst case with frequency=1hz, bits=32) + for (unsigned int k = 0; k < 4294; k++) { + + // Largest value possible tick + ticks += ((uint64_t)1 << bits) - 1; + interface_stub.timestamp = ticks & bitmask; + TEST_ASSERT_EQUAL_UINT32(convert_to_us(ticks, frequency), ticker_read(&ticker_stub)); + TEST_ASSERT_EQUAL_UINT64(convert_to_us(ticks, frequency), ticker_read_us(&ticker_stub)); + } +} + +/** + * Given an uninitialized ticker_data instance. + * When the ticker is initialized + * Then: + * - The internal ticker timestamp should be zero + * - interrupt should be scheduled in current (timestamp + + * TIMESTAMP_MAX_DELTA_BITS(bitwidth)) % modval + * - The queue should not contains any event + */ +static void test_ticker_max_value() +{ + for (int bitwidth = 8; bitwidth <= 32; bitwidth++) { + const uint64_t modval = 1ULL << bitwidth; + + // setup of the stub + reset_ticker_stub(); + interface_info_stub.bits = bitwidth; + interface_stub.timestamp = 0xBA; + + ticker_set_handler(&ticker_stub, NULL); + + TEST_ASSERT_EQUAL_UINT64(0, queue_stub.present_time); + TEST_ASSERT_EQUAL(1, interface_stub.set_interrupt_call); + TEST_ASSERT_EQUAL_UINT32( + (interface_stub.timestamp + TIMESTAMP_MAX_DELTA_BITS(bitwidth)) % modval, + interface_stub.interrupt_timestamp + ); + TEST_ASSERT_EQUAL_PTR(NULL, queue_stub.head); + TEST_ASSERT_EQUAL(0, interface_stub.disable_interrupt_call); + } +} + +/** + * Check that _ticker_match_interval_passed correctly detects matches + * + * Brute force test that _ticker_match_interval_passed returns the correct match value + * for all cominations of values within a small range. + */ +static void test_match_interval_passed() +{ + + for (int modval = 1; modval <= 5; modval++) { + for (int prev = 0; prev < modval; prev++) { + for (int cur = 0; cur < modval; cur++) { + for (int match = 0; match < modval; match++) { + uint32_t delta = (cur - prev) % modval; + uint32_t delta_to_match = (match - prev) % modval; + bool match_expected = false; + if (delta_to_match) { + match_expected = delta >= delta_to_match; + } + + // Sanity checks + if (prev == cur) { + // No time has passed + TEST_ASSERT_EQUAL(false, match_expected); + } else if (match == prev) { + // Match can't occur without an overflow occurring + TEST_ASSERT_EQUAL(false, match_expected); + } else if (cur == match) { + // All other cases where cur == match a match should be expected + TEST_ASSERT_EQUAL(true, match_expected); + } + + // Actual test + TEST_ASSERT_EQUAL(match_expected, _ticker_match_interval_passed(prev, cur, match)); + } + } + } + } +} + +typedef struct { + timestamp_t prev; + timestamp_t cur; + timestamp_t match; + bool result; +} match_interval_entry_t; + +/** + * Check that _ticker_match_interval_passed correctly detects matches + * + * Use a table of pre-computed values to check that _ticker_match_interval_passed + * returns the correct match value. + */ +static void test_match_interval_passed_table() +{ + static const match_interval_entry_t test_values[] = { + /* prev, cur, match, result */ + {0x00000000, 0x00000000, 0x00000000, false}, + {0x00000000, 0x00000000, 0xffffffff, false}, + {0x00000000, 0x00000000, 0x00000001, false}, + {0x00000000, 0xffffffff, 0x00000000, false}, + {0x00000000, 0x00000001, 0x00000000, false}, + {0xffffffff, 0x00000000, 0x00000000, true}, + {0x00000001, 0x00000000, 0x00000000, true}, + {0x00005555, 0x00005555, 0x00005555, false}, + {0x00005555, 0x00005555, 0x00005554, false}, + {0x00005555, 0x00005555, 0x00005556, false}, + {0x00005555, 0x00005554, 0x00005555, false}, + {0x00005555, 0x00005556, 0x00005555, false}, + {0x00005554, 0x00005555, 0x00005555, true}, + {0x00005556, 0x00005555, 0x00005555, true}, + {0xffffffff, 0xffffffff, 0xffffffff, false}, + {0xffffffff, 0xffffffff, 0xfffffffe, false}, + {0xffffffff, 0xffffffff, 0x00000000, false}, + {0xffffffff, 0xfffffffe, 0xffffffff, false}, + {0xffffffff, 0x00000000, 0xffffffff, false}, + {0xfffffffe, 0xffffffff, 0xffffffff, true}, + {0x00000000, 0xffffffff, 0xffffffff, true}, + }; + for (int i = 0; i < MBED_ARRAY_SIZE(test_values); i++) { + const uint32_t prev = test_values[i].prev; + const uint32_t cur = test_values[i].cur; + const uint32_t match = test_values[i].match; + const uint32_t result = test_values[i].result; + TEST_ASSERT_EQUAL(result, _ticker_match_interval_passed(prev, cur, match)); + } +} + +/** + * Check that suspend and resume work as expected + * + * Check the following + * -time does not change while suspended + * -restricted interface functions are not called + * -scheduling resumes correctly + */ +static void test_suspend_resume() +{ + ticker_set_handler(&ticker_stub, NULL); + + interface_stub.timestamp = 1000; + us_timestamp_t start = ticker_read_us(&ticker_stub); + TEST_ASSERT_EQUAL(1000, start); + + /* Reset call count */ + interface_stub.init_call = 0; + interface_stub.read_call = 0; + interface_stub.set_interrupt_call = 0; + + /* Suspend the ticker */ + ticker_suspend(&ticker_stub); + const timestamp_t suspend_time = queue_stub.present_time; + + + /* Simulate time passing */ + interface_stub.timestamp = 1500; + us_timestamp_t next = ticker_read_us(&ticker_stub); + + /* Time should not have passed and no calls to interface should have been made */ + TEST_ASSERT_EQUAL(start, next); + TEST_ASSERT_EQUAL(0, interface_stub.init_call); + TEST_ASSERT_EQUAL(0, interface_stub.read_call); + TEST_ASSERT_EQUAL(0, interface_stub.disable_interrupt_call); + TEST_ASSERT_EQUAL(0, interface_stub.clear_interrupt_call); + TEST_ASSERT_EQUAL(0, interface_stub.set_interrupt_call); + TEST_ASSERT_EQUAL(0, interface_stub.fire_interrupt_call); + + + /* Simulate a reinit (time reset to 0) */ + interface_stub.timestamp = 0; + next = ticker_read_us(&ticker_stub); + + /* Time should not have passed and no calls to interface should have been made */ + TEST_ASSERT_EQUAL(start, next); + TEST_ASSERT_EQUAL(0, interface_stub.init_call); + TEST_ASSERT_EQUAL(0, interface_stub.read_call); + TEST_ASSERT_EQUAL(0, interface_stub.disable_interrupt_call); + TEST_ASSERT_EQUAL(0, interface_stub.clear_interrupt_call); + TEST_ASSERT_EQUAL(0, interface_stub.set_interrupt_call); + TEST_ASSERT_EQUAL(0, interface_stub.fire_interrupt_call); + + + /* Insert an event in the past and future */ + ticker_event_t event_past = { 0 }; + const timestamp_t event_past_timestamp = suspend_time - 10; + ticker_insert_event_us(&ticker_stub, &event_past, event_past_timestamp, 0); + + ticker_event_t event_future = { 0 }; + const timestamp_t event_future_timestamp = suspend_time + 10; + ticker_insert_event_us(&ticker_stub, &event_future, event_future_timestamp, 0); + + TEST_ASSERT_EQUAL(0, interface_stub.init_call); + TEST_ASSERT_EQUAL(0, interface_stub.read_call); + TEST_ASSERT_EQUAL(0, interface_stub.disable_interrupt_call); + TEST_ASSERT_EQUAL(0, interface_stub.clear_interrupt_call); + TEST_ASSERT_EQUAL(0, interface_stub.set_interrupt_call); + TEST_ASSERT_EQUAL(0, interface_stub.fire_interrupt_call); + + /* Resume and verify everything starts again */ + ticker_resume(&ticker_stub); + TEST_ASSERT_EQUAL(suspend_time, queue_stub.present_time); + TEST_ASSERT_EQUAL(1, interface_stub.fire_interrupt_call); +} + +static const case_t cases[] = { + MAKE_TEST_CASE("ticker initialization", test_ticker_initialization), + MAKE_TEST_CASE( + "ticker multiple initialization", test_ticker_re_initialization + ), + MAKE_TEST_CASE("ticker read", test_ticker_read), + MAKE_TEST_CASE("ticker read overflow", test_ticker_read_overflow), + MAKE_TEST_CASE( + "legacy insert event outside overflow range", + test_legacy_insert_event_outside_overflow_range + ), + MAKE_TEST_CASE( + "legacy insert event in overflow range", + test_legacy_insert_event_in_overflow_range + ), + MAKE_TEST_CASE( + "legacy insert event overflow", test_legacy_insert_event_overflow + ), + MAKE_TEST_CASE( + "legacy insert event head", test_legacy_insert_event_head + ), + MAKE_TEST_CASE( + "legacy insert event tail", test_legacy_insert_event_tail + ), + MAKE_TEST_CASE( + "legacy insert event multiple overflow", + test_legacy_insert_event_multiple_overflow + ), + MAKE_TEST_CASE( + "test_legacy_insert_event_multiple_random", + test_legacy_insert_event_multiple_random + ), + MAKE_TEST_CASE( + "test_insert_event_us_outside_overflow_range", + test_insert_event_us_outside_overflow_range + ), + MAKE_TEST_CASE( + "test_insert_event_us_in_overflow_range", + test_insert_event_us_in_overflow_range + ), + MAKE_TEST_CASE( + "test_insert_event_us_underflow", test_insert_event_us_underflow + ), + MAKE_TEST_CASE("test_insert_event_us_head", test_insert_event_us_head), + MAKE_TEST_CASE("test_insert_event_us_tail", test_insert_event_us_tail), + MAKE_TEST_CASE( + "test_insert_event_us_multiple_random", + test_insert_event_us_multiple_random + ), + MAKE_TEST_CASE("test_remove_event_tail", test_remove_event_tail), + MAKE_TEST_CASE("test_remove_event_head", test_remove_event_head), + MAKE_TEST_CASE("test_remove_event_invalid", test_remove_event_invalid), + MAKE_TEST_CASE("test_remove_random", test_remove_random), + MAKE_TEST_CASE("update overflow guard", test_overflow_event_update), + MAKE_TEST_CASE( + "update overflow guard in case of spurious interrupt", + test_overflow_event_update_when_spurious_interrupt + ), + MAKE_TEST_CASE( + "test_irq_handler_single_event", test_irq_handler_single_event + ), + MAKE_TEST_CASE( + "test_irq_handler_single_event_spurious", + test_irq_handler_single_event_spurious + ), + MAKE_TEST_CASE( + "test_irq_handler_multiple_event_multiple_dequeue", + test_irq_handler_multiple_event_multiple_dequeue + ), + MAKE_TEST_CASE( + "test_irq_handler_multiple_event_single_dequeue_overflow", + test_irq_handler_multiple_event_single_dequeue_overflow + ), + MAKE_TEST_CASE( + "test_irq_handler_multiple_event_single_dequeue", + test_irq_handler_multiple_event_single_dequeue + ), + MAKE_TEST_CASE( + "test_irq_handler_insert_immediate_in_irq", + test_irq_handler_insert_immediate_in_irq + ), + MAKE_TEST_CASE( + "test_irq_handler_insert_non_immediate_in_irq", + test_irq_handler_insert_non_immediate_in_irq + ), + MAKE_TEST_CASE( + "test_set_interrupt_past_time", + test_set_interrupt_past_time + ), + MAKE_TEST_CASE( + "test_set_interrupt_past_time_with_delay", + test_set_interrupt_past_time_with_delay + ), + MAKE_TEST_CASE( + "test_frequencies_and_masks", + test_over_frequency_and_width + ), + MAKE_TEST_CASE( + "test_ticker_max_value", + test_ticker_max_value + ), + MAKE_TEST_CASE( + "test_match_interval_passed", + test_match_interval_passed + ), + MAKE_TEST_CASE( + "test_match_interval_passed_table", + test_match_interval_passed_table + ), + MAKE_TEST_CASE( + "test_suspend_resume", + test_suspend_resume + ) +}; + +static utest::v1::status_t greentea_test_setup(const size_t number_of_cases) +{ + GREENTEA_SETUP(60, "default_auto"); + return verbose_test_setup_handler(number_of_cases); +} + +int main() +{ + Specification specification(greentea_test_setup, cases, greentea_test_teardown_handler); + return !Harness::run(specification); +} diff --git a/hal/tests/TESTS/mbed_hal/trng/base64b/base64b.cpp b/hal/tests/TESTS/mbed_hal/trng/base64b/base64b.cpp new file mode 100644 index 0000000..9b8525c --- /dev/null +++ b/hal/tests/TESTS/mbed_hal/trng/base64b/base64b.cpp @@ -0,0 +1,197 @@ +/* +* Copyright (c) 2018 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. +*/ + +#include "base64b.h" + +using namespace std; + +static char IntToBase64Char(uint8_t intVal) +{ + const char *base64Digits = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + return base64Digits[intVal & 0x3F]; +} + +#define BASE_64_PAD 0xFF +static base64_result_e Base64CharToInt(char base64, uint8_t *intVal) +{ + if (NULL == intVal) { + return BASE64_INVALID_PARAMETER; + } + + if ((base64 >= 'A') && (base64 <= 'Z')) { + *intVal = base64 - 'A' ; + } else if ((base64 >= 'a') && (base64 <= 'z')) { + *intVal = base64 - 'a' + 26; + } else if ((base64 >= '0') && (base64 <= '9')) { + *intVal = base64 - '0' + 52; + } else if (base64 == '+') { + *intVal = 62; + } else if (base64 == '/') { + *intVal = 63; + } else if (base64 == '=') { + *intVal = BASE_64_PAD; + } else { + return BASE64_ERROR; + } + + return BASE64_SUCCESS; +} + +base64_result_e trng_DecodeNBase64(const char *string, + uint32_t stringMaxSize, + void *buffer, + uint32_t bufferSize, + uint32_t *lengthWritten, + uint32_t *charsProcessed) +{ + base64_result_e result = BASE64_SUCCESS; + uint32_t bitOffset = 0; + uint8_t *writePtr = (uint8_t *)buffer; + uint8_t *bufferEnd = (uint8_t *)buffer + bufferSize; + uint8_t tempVal = 0; + uint32_t currPos = 0; + uint32_t localBytesWritten = 0; + uint32_t localCharsProcessed = 0; + bool isEndOfString = false; + + if ((NULL == string) || (NULL == buffer) || (bufferSize == 0)) { + return BASE64_INVALID_PARAMETER; + } + + *writePtr = 0; + while ((currPos < stringMaxSize) && + (string[currPos] != 0) && + (writePtr < bufferEnd) && + (!isEndOfString)) { + uint8_t val; + + if (string[currPos] == 0) { + break; + } + + result = Base64CharToInt(string[currPos++], &val); + if (result != BASE64_SUCCESS) { + break; + } + + if (val != BASE_64_PAD) { + if (bitOffset <= 2) { + tempVal |= val << (2 - bitOffset); + if (bitOffset == 2) { + *writePtr++ = tempVal; + tempVal = 0; + } + } else { + *writePtr++ = (uint8_t)(tempVal | (val >> (bitOffset - 2))); + tempVal = (uint8_t)(val << (10 - bitOffset)); + } + } else { // found BASE_64_PAD + // At most two pad characters may occur at the end of the encoded stream + if (bitOffset == 2) { + isEndOfString = true; // The last padding byte has been processed. + } else if (bitOffset != 4) { + return BASE64_ERROR; // Incorrect padding + } + } + + bitOffset = (bitOffset + 6) & 0x7; + if (bitOffset == 0) { + localBytesWritten = (uint32_t)(writePtr - (uint8_t *)buffer); + localCharsProcessed = currPos; + } + } + if (charsProcessed == NULL) { + localBytesWritten = (uint32_t)(writePtr - (uint8_t *)buffer); + } else { + *charsProcessed = localCharsProcessed; + } + if (lengthWritten != NULL) { + *lengthWritten = localBytesWritten; + } else if (bufferSize != localBytesWritten) { + return BASE64_BUFFER_TOO_SMALL; + } + + // Check if additional bytes should have been processed but buffer isn't sufficient. + if ((result == BASE64_SUCCESS) && + (!isEndOfString) && + (currPos < stringMaxSize) && + (string[currPos] != 0) && + (string[currPos] != '=')) { + return BASE64_BUFFER_TOO_SMALL; + } + + if (result != BASE64_SUCCESS) { + return result; + } + + return BASE64_SUCCESS; +} + +base64_result_e trng_EncodeBase64(const void *buffer, uint32_t bufferSize, char *string, uint32_t stringSize) +{ + uint32_t bitOffset = 0; + + const uint8_t *readPtr = (const uint8_t *)buffer; + const uint8_t *bufferEnd = (const uint8_t *)buffer + bufferSize; + + char *writePtr = string; + char *stringEnd = string + stringSize - 1; + + if ((NULL == string) || (NULL == buffer) || (stringSize == 0)) { + return BASE64_INVALID_PARAMETER; + } + + stringSize--; + while (readPtr < bufferEnd && writePtr < stringEnd) { + uint8_t tempVal = 0; + switch (bitOffset) { + case 0: + *writePtr++ = IntToBase64Char(*readPtr >> 2); // take upper 6 bits + break; + case 6: + tempVal = *readPtr++ << 4; + if (readPtr < bufferEnd) { + tempVal |= *readPtr >> 4; + } + *writePtr++ = IntToBase64Char(tempVal); + break; + case 4: + tempVal = *readPtr++ << 2; + if (readPtr < bufferEnd) { + tempVal |= *readPtr >> 6; + } + *writePtr++ = IntToBase64Char(tempVal); + break; + case 2: + *writePtr++ = IntToBase64Char(*readPtr++); + break; + default: + return BASE64_ERROR; // we should never reach this code. + } + bitOffset = (bitOffset + 6) & 0x7; + } + while (bitOffset > 0 && writePtr < stringEnd) { + *writePtr++ = '='; + bitOffset = (bitOffset + 6) & 0x7; + } + *writePtr = 0; + + if ((readPtr < bufferEnd) || (bitOffset != 0)) { + return (BASE64_BUFFER_TOO_SMALL); + } + + return (BASE64_SUCCESS); +} diff --git a/hal/tests/TESTS/mbed_hal/trng/base64b/base64b.h b/hal/tests/TESTS/mbed_hal/trng/base64b/base64b.h new file mode 100644 index 0000000..cbb6b85 --- /dev/null +++ b/hal/tests/TESTS/mbed_hal/trng/base64b/base64b.h @@ -0,0 +1,32 @@ +/* +* Copyright (c) 2018 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. +*/ + +#include +#include +#include + +typedef enum { + BASE64_SUCCESS = 0, + BASE64_INVALID_PARAMETER = 1, + BASE64_BUFFER_TOO_SMALL = 2, + BASE64_ERROR = 3, +} base64_result_e; + +base64_result_e trng_EncodeBase64(const void *buffer, uint32_t bufferSize, char *string, uint32_t stringSize); +base64_result_e trng_DecodeNBase64(const char *string, uint32_t stringMaxSize, void *buffer, uint32_t bufferSize, + uint32_t *lengthWritten, uint32_t *charsProcessed); + + diff --git a/hal/tests/TESTS/mbed_hal/trng/main.cpp b/hal/tests/TESTS/mbed_hal/trng/main.cpp new file mode 100644 index 0000000..40147e8 --- /dev/null +++ b/hal/tests/TESTS/mbed_hal/trng/main.cpp @@ -0,0 +1,259 @@ +/* +* Copyright (c) 2018-2020 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. +*/ + +/* +* The test is based on the assumption that trng will generate random data, random so +* there will not be any similar patterns in it, that kind of data will be impossible to +* compress, if compression will occur the test will result in failure. +* +* The test is composed out of three parts: +* the first, generate a trng buffer and try to compress it, at the end of first part +* we will reset the device. +* In second part we will generate a trng buffer with a different buffer size and try to +* compress it. +* In the third part we will again generate a trng buffer to see that the same trng output +* is not generated as the stored trng buffer from part one (before reseting), the new trng data will +* be concatenated to the trng data from the first part and then try to compress it +* together, if there are similar patterns the compression will succeed. +* +* We need to store and load the first part data before and after reset, the mechanism +* we will use is the mbed greentea platform for sending and receving the data from the device +* to the host running the test and back, the problem with this mechanism is that it doesn't +* handle well certain characters, especially non ASCII ones, so we use the base64 algorithm +* to ensure all characters will be transmitted correctly. +*/ + +#include "greentea-client/test_env.h" +#include "unity/unity.h" +#include "utest/utest.h" +#include "hal/trng_api.h" +#include "base64b.h" +#include "pithy.h" +#include +#include +#include "mbedtls/config.h" +#include "mbedtls/platform.h" + +#if !DEVICE_TRNG +#error [NOT_SUPPORTED] TRNG API not supported for this target +#else + +#define MSG_VALUE_DUMMY "0" +#define MSG_VALUE_LEN 64 +#define MSG_KEY_LEN 32 + +#define BUFFER_LEN (MSG_VALUE_LEN/2) + +#define MSG_TRNG_READY "ready" +#define MSG_TRNG_BUFFER "buffer" +#define MSG_TRNG_EXIT "exit" + +#define MSG_TRNG_TEST_STEP1 "check_step1" +#define MSG_TRNG_TEST_STEP2 "check_step2" +#define MSG_TRNG_TEST_SUITE_ENDED "Test_suite_ended" + +#define RESULT_SUCCESS 0 + +using namespace utest::v1; + +static int fill_buffer_trng(uint8_t *buffer, trng_t *trng_obj, size_t trng_len) +{ + size_t temp_size = 0, output_length = 0; + int trng_res = 0; + uint8_t *temp_in_buf = buffer; + + trng_init(trng_obj); + memset(buffer, 0, BUFFER_LEN); + + while (true) { + trng_res = trng_get_bytes(trng_obj, temp_in_buf, trng_len - temp_size, &output_length); + TEST_ASSERT_EQUAL_INT_MESSAGE(0, trng_res, "trng_get_bytes error!"); + temp_size += output_length; + temp_in_buf += output_length; + if (temp_size >= trng_len) { + break; + } + } + + temp_in_buf = NULL; + trng_free(trng_obj); + return 0; +} + +void print_array(uint8_t *buffer, size_t size) +{ + for (size_t i = 0; i < size; i++) { + utest_printf("%02x", buffer[i]); + } + utest_printf("\n"); +} + +static void compress_and_compare(char *key, char *value) +{ + trng_t trng_obj; + uint8_t *out_comp_buf, *buffer; + uint8_t *input_buf, *temp_buf; + size_t comp_sz = 0; + unsigned int result = 0; + +#define OUT_COMP_BUF_SIZE ((BUFFER_LEN * 5) + 32) +#define TEMP_BUF_SIZE (BUFFER_LEN * 2) + + out_comp_buf = new uint8_t[OUT_COMP_BUF_SIZE]; + buffer = new uint8_t[BUFFER_LEN]; + temp_buf = new uint8_t[BUFFER_LEN * 2]; + input_buf = new uint8_t[BUFFER_LEN * 4]; + + /*At the begining of step 2 load trng buffer from step 1*/ + if (strcmp(key, MSG_TRNG_TEST_STEP2) == 0) { + /*Using base64 to decode data sent from host*/ + uint32_t lengthWritten = 0; + uint32_t charsProcessed = 0; + result = trng_DecodeNBase64((const char *)value, + MSG_VALUE_LEN, + buffer, + BUFFER_LEN, + &lengthWritten, + &charsProcessed); + TEST_ASSERT_EQUAL(0, result); + memcpy(input_buf, buffer, BUFFER_LEN); + } + + if (strcmp(key, MSG_TRNG_TEST_STEP1) == 0) { + /*Fill buffer with trng values*/ + result = fill_buffer_trng(buffer, &trng_obj, BUFFER_LEN); + TEST_ASSERT_EQUAL(0, result); + memcpy(input_buf, buffer, BUFFER_LEN); + } + /*pithy_Compress will try to compress the random data, if it succeeded it means the data is not really random*/ + else if (strcmp(key, MSG_TRNG_TEST_STEP2) == 0) { + + comp_sz = pithy_Compress((char *)buffer, + BUFFER_LEN, + (char *)out_comp_buf, + OUT_COMP_BUF_SIZE, + 9); + if (comp_sz <= BUFFER_LEN) { + print_array(buffer, BUFFER_LEN); + } + TEST_ASSERT_MESSAGE(comp_sz > BUFFER_LEN, + "TRNG_TEST_STEP1: trng_get_bytes was able to compress thus not random"); + + /*pithy_Compress will try to compress the random data with a different buffer size*/ + result = fill_buffer_trng(temp_buf, &trng_obj, TEMP_BUF_SIZE); + TEST_ASSERT_EQUAL(0, result); + + comp_sz = pithy_Compress((char *)temp_buf, + TEMP_BUF_SIZE, + (char *)out_comp_buf, + OUT_COMP_BUF_SIZE, + 9); + if (comp_sz <= TEMP_BUF_SIZE) { + print_array(temp_buf, TEMP_BUF_SIZE); + } + TEST_ASSERT_MESSAGE(comp_sz > TEMP_BUF_SIZE, + "TRNG_TEST_STEP2: trng_get_bytes was able to compress thus not random"); + + memcpy(input_buf + BUFFER_LEN, temp_buf, TEMP_BUF_SIZE); + /*pithy_Compress will try to compress the random data from before reset concatenated with new random data*/ + comp_sz = pithy_Compress((char *)input_buf, + TEMP_BUF_SIZE + BUFFER_LEN, + (char *)out_comp_buf, + OUT_COMP_BUF_SIZE, + 9); + if (comp_sz <= TEMP_BUF_SIZE + BUFFER_LEN) { + print_array(input_buf, TEMP_BUF_SIZE + BUFFER_LEN); + } + TEST_ASSERT_MESSAGE(comp_sz > TEMP_BUF_SIZE + BUFFER_LEN, + "TRNG_TEST_STEP3: concatenated buffer after reset was able to compress thus not random"); + + greentea_send_kv(MSG_TRNG_TEST_SUITE_ENDED, MSG_VALUE_DUMMY); + } + + /*At the end of step 1 store trng buffer and reset the device*/ + if (strcmp(key, MSG_TRNG_TEST_STEP1) == 0) { + int result = 0; + /*Using base64 to encode data sending from host*/ + result = trng_EncodeBase64(buffer, + BUFFER_LEN, + (char *)out_comp_buf, + OUT_COMP_BUF_SIZE); + TEST_ASSERT_EQUAL(RESULT_SUCCESS, result); + + greentea_send_kv(MSG_TRNG_BUFFER, (const char *)out_comp_buf); + } + + delete[] out_comp_buf; + delete[] buffer; + delete[] input_buf; + delete[] temp_buf; +} + +/*This method call first and second steps, it directs by the key received from the host*/ +void trng_test() +{ + greentea_send_kv(MSG_TRNG_READY, MSG_VALUE_DUMMY); + + char key[MSG_KEY_LEN + 1] = { }; + char *value = new char[MSG_VALUE_LEN + 1]; + do { + memset(key, 0, MSG_KEY_LEN + 1); + memset(value, 0, MSG_VALUE_LEN + 1); + + greentea_parse_kv(key, value, MSG_KEY_LEN, MSG_VALUE_LEN); + + if (strcmp(key, MSG_TRNG_TEST_STEP1) == 0) { + /*create trng data buffer and try to compress it, store it for later checks*/ + compress_and_compare(key, value); + } + + if (strcmp(key, MSG_TRNG_TEST_STEP2) == 0) { + /*create another trng data buffer and concatenate it to the stored trng data buffer + try to compress them both*/ + compress_and_compare(key, value); + } + } while (strcmp(key, MSG_TRNG_EXIT) != 0); + + delete[] value; +} + +Case cases[] = { + Case("TRNG: trng_test", trng_test), +}; + +utest::v1::status_t greentea_test_setup(const size_t number_of_cases) +{ + GREENTEA_SETUP(100, "trng_reset"); + return greentea_test_setup_handler(number_of_cases); +} + +Specification specification(greentea_test_setup, cases, greentea_test_teardown_handler); + +int main() +{ + int ret = 0; +#if defined(MBEDTLS_PLATFORM_C) + ret = mbedtls_platform_setup(NULL); +#endif /* MBEDTLS_PLATFORM_C */ + ret = !Harness::run(specification); +#if defined(MBEDTLS_PLATFORM_C) + mbedtls_platform_teardown(NULL); +#endif /* MBEDTLS_PLATFORM_C */ + return ret; +} + +#endif // !DEVICE_TRNG + diff --git a/hal/tests/TESTS/mbed_hal/trng/pithy/pithy.c b/hal/tests/TESTS/mbed_hal/trng/pithy/pithy.c new file mode 100644 index 0000000..d0581d8 --- /dev/null +++ b/hal/tests/TESTS/mbed_hal/trng/pithy/pithy.c @@ -0,0 +1,796 @@ +// +// pithy.c +// http://github.com/johnezang/pithy +// Licensed under the terms of the BSD License, as specified below. +// +// SPDX-License-Identifier: BSD-3-Clause + +/* + Copyright (c) 2011, John Engelhart + + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + * Neither the name of the Zang Industries nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include +#include +#include +#include + +#if defined(__arm__) && defined(__ARM_NEON__) +#include +#endif + +#include "pithy.h" + +#define kBlockLog 20ul +#define kBlockSize ((size_t)(1 << kBlockLog)) + +// The maximum size that can be compressed while still allowing for the worst case compression expansion. +#define PITHY_UNCOMPRESSED_MAX_LENGTH 0xdb6db6bfu // 0xdb6db6bf == 3681400511, or 3510.857 Mbytes. + +typedef const char *pithy_hashOffset_t; + +enum { + PITHY_LITERAL = 0, + PITHY_COPY_1_BYTE_OFFSET = 1, + PITHY_COPY_2_BYTE_OFFSET = 2, + PITHY_COPY_3_BYTE_OFFSET = 3 +}; + + +#if defined (__GNUC__) && (__GNUC__ >= 3) +#define PITHY_ATTRIBUTES(attr, ...) __attribute__((attr, ##__VA_ARGS__)) +#define PITHY_EXPECTED(cond, expect) __builtin_expect((long)(cond), (expect)) +#define PITHY_EXPECT_T(cond) PITHY_EXPECTED(cond, 1u) +#define PITHY_EXPECT_F(cond) PITHY_EXPECTED(cond, 0u) +#define PITHY_PREFETCH(ptr) __builtin_prefetch(ptr) +#else // defined (__GNUC__) && (__GNUC__ >= 3) +#define PITHY_ATTRIBUTES(attr, ...) +#define PITHY_EXPECTED(cond, expect) (cond) +#define PITHY_EXPECT_T(cond) (cond) +#define PITHY_EXPECT_F(cond) (cond) +#define PITHY_PREFETCH(ptr) +#endif // defined (__GNUC__) && (__GNUC__ >= 3) + +#define PITHY_STATIC_INLINE static inline PITHY_ATTRIBUTES(always_inline) +#define PITHY_ALIGNED(x) PITHY_ATTRIBUTES(aligned(x)) + +#if defined(NS_BLOCK_ASSERTIONS) && !defined(NDEBUG) +#define NDEBUG +#endif + +#ifdef NDEBUG +#define DCHECK(condition) +#else +#define DCHECK(condition) do { \ + if(PITHY_EXPECT_F(!(condition))) { \ + fprintf(stderr, "%s / %s @ %ld: Invalid parameter not satisfying: %s", \ + __FILE__, __PRETTY_FUNCTION__, (long)__LINE__, #condition); fflush(stderr); \ + abort(); \ + } \ + } while(0) +#endif + +PITHY_STATIC_INLINE const char *pithy_Parse32WithLimit(const char *p, const char *l, size_t *OUTPUT); +PITHY_STATIC_INLINE char *pithy_Encode32(char *ptr, uint32_t v); + +PITHY_STATIC_INLINE uint32_t pithy_GetUint32AtOffset(uint64_t v, uint32_t offset); +PITHY_STATIC_INLINE uint32_t pithy_HashBytes(uint32_t bytes, uint32_t shift); +PITHY_STATIC_INLINE size_t pithy_FindMatchLength(const char *s1, const char *s2, const char *s2_limit); +PITHY_STATIC_INLINE char *pithy_EmitLiteral(char *op, const char *literal, size_t len, int allow_fast_path); +PITHY_STATIC_INLINE char *pithy_EmitCopyGreaterThan63(char *op, size_t offset, size_t len); +PITHY_STATIC_INLINE char *pithy_EmitCopyLessThan63(char *op, size_t offset, size_t len); +PITHY_STATIC_INLINE char *pithy_EmitCopy(char *op, size_t offset, size_t len); + +PITHY_STATIC_INLINE uint16_t pithy_Load16(const void *p) { uint16_t t; memcpy(&t, p, sizeof(t)); return (t); } +PITHY_STATIC_INLINE uint32_t pithy_Load32(const void *p) { uint32_t t; memcpy(&t, p, sizeof(t)); return (t); } +PITHY_STATIC_INLINE uint64_t pithy_Load64(const void *p) { uint64_t t; memcpy(&t, p, sizeof(t)); return (t); } +PITHY_STATIC_INLINE void pithy_Store16(void *p, uint16_t v) { memcpy(p, &v, sizeof(v)); } +PITHY_STATIC_INLINE void pithy_Store32(void *p, uint32_t v) { memcpy(p, &v, sizeof(v)); } +PITHY_STATIC_INLINE void pithy_Store64(void *p, uint64_t v) { memcpy(p, &v, sizeof(v)); } + +#define pithy_Move64(dst,src) pithy_Store64(dst, pithy_Load64(src)); +#define pithy_Move128(dst,src) pithy_Move64(dst, src); pithy_Move64(dst + 8ul, src + 8ul); + +#ifdef __BIG_ENDIAN__ + +#ifdef _MSC_VER +#include +#define pithy_bswap_16(x) _byteswap_ushort(x) +#define pithy_bswap_32(x) _byteswap_ulong(x) +#define pithy_bswap_64(x) _byteswap_uint64(x) + +#elif defined(__APPLE__) + +// Mac OS X / Darwin features +#include +#define pithy_bswap_16(x) OSSwapInt16(x) +#define pithy_bswap_32(x) OSSwapInt32(x) +#define pithy_bswap_64(x) OSSwapInt64(x) +#else +#include +#endif + +#endif // __BIG_ENDIAN__ + +// Conversion functions. +#ifdef __BIG_ENDIAN__ +#define pithy_FromHost16(x) ((uint16_t)pithy_bswap_16(x)) +#define pithy_ToHost16(x) ((uint16_t)pithy_bswap_16(x)) +#define pithy_FromHost32(x) ((uint32_t)pithy_bswap_32(x)) +#define pithy_ToHost32(x) ((uint32_t)pithy_bswap_32(x)) +#define pithy_IsLittleEndian() (0) + +#else // !defined(__BIG_ENDIAN__) +#define pithy_FromHost16(x) ((uint16_t)(x)) +#define pithy_ToHost16(x) ((uint16_t)(x)) +#define pithy_FromHost32(x) ((uint32_t)(x)) +#define pithy_ToHost32(x) ((uint32_t)(x)) +#define pithy_IsLittleEndian() (1) + +#endif // !defined(__BIG_ENDIAN__) + +#define pithy_LoadHost16(p) pithy_ToHost16(pithy_Load16((const void *)(p))) +#define pithy_StoreHost16(p, v) pithy_Store16((void *)(p), pithy_FromHost16(v)) +#define pithy_LoadHost32(p) pithy_ToHost32(pithy_Load32((p))) +#define pithy_StoreHost32(p, v) pithy_Store32((p), pithy_FromHost32(v)) + +PITHY_STATIC_INLINE void pithy_StoreHost24(char *p, uint32_t v) +{ + *p++ = (v & 0xffu); + *p++ = ((v >> 8) & 0xffu); + *p++ = ((v >> 16) & 0xffu); +} + +#if defined (__GNUC__) && (__GNUC__ >= 3) + +#define pithy_Log2Floor(n) ({typeof(n) _n = (n); _n == 0 ? (int)-1 : (int)(31 ^ __builtin_clz(_n));}) +#define pithy_FindLSBSetNonZero32(n) ((int)__builtin_ctz((uint32_t)(n))) +#define pithy_FindLSBSetNonZero64(n) ((int)__builtin_ctzll((uint64_t)(n))) +#define pithy_FindMSBSetNonZero32(n) ((int)__builtin_clz((uint32_t)(n))) +#define pithy_FindMSBSetNonZero64(n) ((int)__builtin_clzll((uint64_t)(n))) + +#else // Portable versions, !GNUC || GNUC < 3 + +PITHY_STATIC_INLINE int pithy_Log2Floor(uint32_t n) +{ + if (n == 0u) { + return (-1); + } + int i = 0, log = 0; + uint32_t value = n; + for (i = 4; i >= 0; --i) { + int shift = (1 << i); + uint32_t x = value >> shift; + if (x != 0u) { + value = x; + log += shift; + } + } + DCHECK(value == 1); + return (log); +} + +PITHY_STATIC_INLINE int pithy_FindLSBSetNonZero32(uint32_t n) +{ + int i = 0, rc = 31, shift = 0; + for (i = 4, shift = 1 << 4; i >= 0; --i) { + const uint32_t x = n << shift; + if (x != 0u) { + n = x; + rc -= shift; + } + shift >>= 1; + } + return (rc); +} + +PITHY_STATIC_INLINE int pithy_FindLSBSetNonZero64(uint64_t n) +{ + const uint32_t bottomBits = n; + if (bottomBits == 0u) { + return (32 + pithy_FindLSBSetNonZero32((n >> 32))); + } else { + return (pithy_FindLSBSetNonZero32(bottomBits)); + } +} + +PITHY_STATIC_INLINE int pithy_FindMSBSetNonZero32(uint32_t n) +{ + int i; + uint32_t x, rc = 32, shift = 1 << 4; + for (i = 3; i >= 0; --i) { + x = n >> shift; + if (x != 0) { + rc -= shift; + n = x; + } + shift >>= 1; + } + x = n >> shift; + return (rc - ((x != 0) ? 2 : n)); +} + +PITHY_STATIC_INLINE int pithy_FindMSBSetNonZero64(uint64_t n) +{ + const uint32_t upperBits = n >> 32; + if (upperBits == 0u) { + return (32 + pithy_FindMSBSetNonZero32((n))); + } else { + return (pithy_FindMSBSetNonZero32(upperBits)); + } +} + +#endif // End portable versions. + +PITHY_STATIC_INLINE const char *pithy_Parse32WithLimit(const char *p, const char *l, size_t *resultOut) +{ + const unsigned char *ptr = (const unsigned char *)p, *limit = (const unsigned char *)l; + size_t resultShift = 0ul, result = 0ul; + uint32_t encodedByte = 0u; + + for (resultShift = 0ul; resultShift <= 28ul; resultShift += 7ul) { + if (ptr >= limit) { + return (NULL); + } + encodedByte = *(ptr++); + result |= (encodedByte & 127u) << resultShift; + if (encodedByte < ((resultShift == 28ul) ? 16u : 128u)) { + goto done; + } + } + return (NULL); +done: + *resultOut = result; + return ((const char *)ptr); +} + +PITHY_STATIC_INLINE char *pithy_Encode32(char *sptr, uint32_t v) +{ + unsigned char *ptr = (unsigned char *)sptr; + if (v < (1u << 7)) { + *(ptr++) = v; + } else if (v < (1u << 14)) { + *(ptr++) = v | 0x80u; + *(ptr++) = (v >> 7); + } else if (v < (1u << 21)) { + *(ptr++) = v | 0x80u; + *(ptr++) = (v >> 7) | 0x80u; + *(ptr++) = (v >> 14); + } else if (v < (1u << 28)) { + *(ptr++) = v | 0x80u; + *(ptr++) = (v >> 7) | 0x80u; + *(ptr++) = (v >> 14) | 0x80u; + *(ptr++) = (v >> 21); + } else { + *(ptr++) = v | 0x80u; + *(ptr++) = (v >> 7) | 0x80u; + *(ptr++) = (v >> 14) | 0x80u; + *(ptr++) = (v >> 21) | 0x80u; + *(ptr++) = (v >> 28); + } + return ((char *)ptr); +} + + +PITHY_STATIC_INLINE uint32_t pithy_GetUint32AtOffset(uint64_t v, uint32_t offset) +{ + DCHECK(offset <= 4); + return (v >> (pithy_IsLittleEndian() ? (8u * offset) : (32u - (8u * offset)))); +} + + +PITHY_STATIC_INLINE uint32_t pithy_HashBytes(uint32_t bytes, uint32_t shift) +{ + uint32_t kMul = 0x1e35a7bdU; + return ((bytes * kMul) >> shift); +} + + +PITHY_STATIC_INLINE size_t pithy_FindMatchLength(const char *s1, const char *s2, const char *s2_limit) +{ + DCHECK(s2_limit >= s2); + const char *ms1 = s1, *ms2 = s2; + +#if defined(__LP64__) + while (PITHY_EXPECT_T(ms2 < (s2_limit - 8ul))) { + uint64_t x = pithy_Load64(ms1) ^ pithy_Load64(ms2); + if (PITHY_EXPECT_F(x == 0ul)) { + ms1 += 8ul; + ms2 += 8ul; + } else { + return ((ms1 - s1) + ((unsigned int)(pithy_IsLittleEndian() ? (pithy_FindLSBSetNonZero64(x) >> 3) : + (pithy_FindMSBSetNonZero64(x) >> 3)))); + } + } +#else + while (PITHY_EXPECT_T(ms2 < (s2_limit - 4u ))) { + uint32_t x = pithy_Load32(ms1) ^ pithy_Load32(ms2); + if (PITHY_EXPECT_F(x == 0u)) { + ms1 += 4u; + ms2 += 4u; + } else { + return ((ms1 - s1) + ((unsigned int)(pithy_IsLittleEndian() ? + (pithy_FindLSBSetNonZero32(x) >> 3) : (pithy_FindMSBSetNonZero32(x) >> 3)))); + } + } +#endif + while (PITHY_EXPECT_T(ms2 < s2_limit)) { + if (PITHY_EXPECT_T(*ms1 == *ms2)) { + ms1++; + ms2++; + } else { + return (ms1 - s1); + } + } + return (ms1 - s1); +} + + +PITHY_STATIC_INLINE char *pithy_EmitLiteral(char *op, const char *literal, size_t len, int allow_fast_path) +{ + int n = len - 1l; + if (PITHY_EXPECT_T(n < 60l)) { + *op++ = PITHY_LITERAL | (n << 2); + if (PITHY_EXPECT_T(allow_fast_path) && PITHY_EXPECT_T(len <= 16ul)) { + pithy_Move128(op, literal); + return (op + len); + } + } else { + char *base = op; + int count = 0; + op++; + while (n > 0l) { + *op++ = n & 0xff; + n >>= 8; + count++; + } + DCHECK((count >= 1) && (count <= 4)); + *base = PITHY_LITERAL | ((59 + count) << 2); + } + memcpy(op, literal, len); + return (op + len); +} + +PITHY_STATIC_INLINE char *pithy_EmitCopyGreaterThan63(char *op, size_t offset, size_t len) +{ + DCHECK((len < 65536ul) && (len >= 63ul) && (offset < kBlockSize)); + if (PITHY_EXPECT_T(offset < 65536ul)) { + if (PITHY_EXPECT_T(len < (256ul + 63ul))) { + *op++ = PITHY_COPY_2_BYTE_OFFSET | (62 << 2); + pithy_StoreHost16(op, offset); + op += 2ul; + *op++ = (len - 63ul); + } else { + *op++ = PITHY_COPY_2_BYTE_OFFSET | (63 << 2); + pithy_StoreHost16(op, offset); + op += 2ul; + pithy_StoreHost16(op, len); + op += 2ul; + } + } else { + if (PITHY_EXPECT_T(len < (256ul + 63ul))) { + *op++ = PITHY_COPY_3_BYTE_OFFSET | (62 << 2); + pithy_StoreHost24(op, offset); + op += 3ul; + *op++ = (len - 63ul); + } else { + *op++ = PITHY_COPY_3_BYTE_OFFSET | (63 << 2); + pithy_StoreHost24(op, offset); + op += 3ul; + pithy_StoreHost16(op, len); + op += 2ul; + } + } + return (op); +} + +PITHY_STATIC_INLINE char *pithy_EmitCopyLessThan63(char *op, size_t offset, size_t len) +{ + DCHECK((len < 63ul) && (len >= 4ul) && (offset < kBlockSize)); + if (PITHY_EXPECT_T(len < 12ul) && PITHY_EXPECT_T(offset < 2048ul)) { + int lenMinus4 = len - 4l; + DCHECK(lenMinus4 < 8l); + *op++ = PITHY_COPY_1_BYTE_OFFSET | (lenMinus4 << 2) | ((offset >> 8) << 5); + *op++ = offset & 0xff; + } else { + if (PITHY_EXPECT_T(offset < 65536ul)) { + *op++ = PITHY_COPY_2_BYTE_OFFSET | ((len - 1ul) << 2); + pithy_StoreHost16(op, offset); + op += 2ul; + } else { + *op++ = PITHY_COPY_3_BYTE_OFFSET | ((len - 1ul) << 2); + pithy_StoreHost24(op, offset); + op += 3ul; + } + } + return (op); +} + +PITHY_STATIC_INLINE char *pithy_EmitCopy(char *op, size_t offset, size_t len) +{ + while (PITHY_EXPECT_F(len >= 63ul)) { + op = pithy_EmitCopyGreaterThan63(op, offset, (len >= 65539ul) ? 65535ul : len); + len -= (len >= 65539ul) ? 65535ul : len; + } + DCHECK((len > 0ul) ? ((len >= 4ul) && (len < 63ul)) : 1); + if ( PITHY_EXPECT_T(len > 0ul)) { + op = pithy_EmitCopyLessThan63(op, offset, len); + len -= len; + } + return (op); +} + +size_t pithy_MaxCompressedLength(size_t inputLength) +{ + return ((inputLength >= PITHY_UNCOMPRESSED_MAX_LENGTH) ? 0ul : 32ul + inputLength + (inputLength / 6ul)); +} + +size_t pithy_Compress(const char *uncompressed, + size_t uncompressedLength, + char *compressedOut, + size_t compressedOutLength, + int compressionLevel) +{ + + if ((pithy_MaxCompressedLength(uncompressedLength) > compressedOutLength) || + (uncompressedLength >= PITHY_UNCOMPRESSED_MAX_LENGTH) || + (uncompressedLength == 0ul)) { + return (0ul); + } + + char *compressedPtr = compressedOut; + + size_t hashTableSize = 0x100ul, maxHashTableSize = 1 << (12ul + (((compressionLevel < 0) ? 0 : + (compressionLevel > 9) ? 9 : compressionLevel) / 2ul)); + while ((hashTableSize < maxHashTableSize) && (hashTableSize < uncompressedLength)) { + hashTableSize <<= 1; + } + pithy_hashOffset_t stackHashTable[hashTableSize], *heapHashTable = NULL, *hashTable = stackHashTable; + if ((sizeof(pithy_hashOffset_t) * hashTableSize) >= (1024ul * 128ul)) { + if ((heapHashTable = malloc(sizeof(pithy_hashOffset_t) * hashTableSize)) == NULL) { + return (0ul); + } + hashTable = heapHashTable; + } + size_t x = 0ul; + for (x = 0ul; x < hashTableSize; x++) { + hashTable[x] = uncompressed; + } + +#ifndef NDEBUG + char *const compressedOutEnd = compressedOut + compressedOutLength; +#endif + compressedPtr = pithy_Encode32(compressedPtr, uncompressedLength); + DCHECK(compressedPtr <= compressedOutEnd); + { + const char *uncompressedPtr = uncompressed; + const char *uncompressedEnd = uncompressed + uncompressedLength; + const char *nextEmitUncompressedPtr = uncompressedPtr; + DCHECK((hashTableSize & (hashTableSize - 1l)) == 0); + const int shift = 32 - pithy_Log2Floor(hashTableSize); + DCHECK((UINT32_MAX >> shift) == (hashTableSize - 1l)); + size_t skip = 32ul; + + if (PITHY_EXPECT_T(uncompressedLength >= 15ul)) { + const char *uncompressedEndLimit = uncompressed + uncompressedLength - 15ul; + uint32_t uncompressedBytes; + uint32_t nextUncompressedBytes = pithy_Load32(++uncompressedPtr); + uint32_t nextUncompressedBytesHash = pithy_HashBytes(nextUncompressedBytes, shift); + + while (1) { + DCHECK(nextEmitUncompressedPtr < uncompressedPtr); + const char *nextUncompressedPtr = uncompressedPtr, *matchCandidatePtr = NULL; + + skip = (((skip - 32ul) * 184ul) >> 8) + 32ul; + + do { + uncompressedPtr = nextUncompressedPtr; + uncompressedBytes = nextUncompressedBytes; + uint32_t uncompressedBytesHash = nextUncompressedBytesHash; + DCHECK(uncompressedBytesHash == pithy_HashBytes(uncompressedBytes, shift)); + size_t skipBytesBetweenHashLookups = skip >> 5; + skip += ((skip * 7ul) >> 11) + 1ul; + nextUncompressedPtr = uncompressedPtr + skipBytesBetweenHashLookups; + if (PITHY_EXPECT_F(nextUncompressedPtr > uncompressedEndLimit)) { + goto emit_remainder; + } + nextUncompressedBytes = pithy_Load32(nextUncompressedPtr); + nextUncompressedBytesHash = pithy_HashBytes(nextUncompressedBytes, shift); + matchCandidatePtr = hashTable[uncompressedBytesHash]; + DCHECK((matchCandidatePtr >= uncompressed) && (matchCandidatePtr < uncompressedPtr)); + hashTable[uncompressedBytesHash] = uncompressedPtr; + } while ((PITHY_EXPECT_T(uncompressedBytes != pithy_Load32(matchCandidatePtr))) || + PITHY_EXPECT_F((uncompressedPtr - matchCandidatePtr) >= ((int)(kBlockSize - 2ul)))); + + DCHECK((nextEmitUncompressedPtr + 16ul) <= uncompressedEnd); + compressedPtr = pithy_EmitLiteral(compressedPtr, + nextEmitUncompressedPtr, + uncompressedPtr - nextEmitUncompressedPtr, + 1); + DCHECK(compressedPtr <= compressedOutEnd); + uint64_t uncompressedBytes64 = 0ul; + + do { + if (compressionLevel > 2) { + DCHECK((uncompressedPtr + 5ul) <= uncompressedEnd); + uncompressedBytes64 = pithy_Load64((uint64_t*)uncompressedPtr + 1ul); + hashTable[pithy_HashBytes(pithy_GetUint32AtOffset(uncompressedBytes64, 0u), shift)] = + uncompressedPtr + 1ul; + if (compressionLevel > 4) { + hashTable[pithy_HashBytes(pithy_GetUint32AtOffset(uncompressedBytes64, 1u), shift)] = + uncompressedPtr + 2ul; + } + } + + DCHECK((matchCandidatePtr >= uncompressed) && + (matchCandidatePtr <= uncompressedPtr) && + ((matchCandidatePtr + 4ul) <= uncompressedEnd) && + ((uncompressedPtr + 4ul) <= uncompressedEnd)); + + size_t matchCandidateLength = 4ul + pithy_FindMatchLength(matchCandidatePtr + 4ul, + uncompressedPtr + 4ul, + uncompressedEnd); + DCHECK(((matchCandidatePtr + matchCandidateLength) >= uncompressed) && + ((matchCandidatePtr + matchCandidateLength) <= uncompressedEnd)); + DCHECK(0 == memcmp(uncompressedPtr, matchCandidatePtr, matchCandidateLength)); + compressedPtr = pithy_EmitCopy(compressedPtr, + uncompressedPtr - matchCandidatePtr, + matchCandidateLength); + DCHECK(compressedPtr <= compressedOutEnd); + uncompressedPtr += matchCandidateLength; + DCHECK(uncompressedPtr <= uncompressedEnd); + nextEmitUncompressedPtr = uncompressedPtr; + if (PITHY_EXPECT_F(uncompressedPtr >= uncompressedEndLimit)) { + goto emit_remainder; + } + + DCHECK(((uncompressedPtr - 3ul) >= uncompressed) && (uncompressedPtr <= uncompressedEnd)); + + uncompressedBytes64 = pithy_Load64((uint64_t*)uncompressedPtr - 3ul); + + if (compressionLevel > 0) { + if (compressionLevel > 8) { + hashTable[pithy_HashBytes(pithy_GetUint32AtOffset(uncompressedBytes64, 0u), shift)] = + uncompressedPtr - 3ul; + } + if (compressionLevel > 6) { + hashTable[pithy_HashBytes(pithy_GetUint32AtOffset(uncompressedBytes64, 1u), shift)] = + uncompressedPtr - 2ul; + } + hashTable[pithy_HashBytes(pithy_GetUint32AtOffset(uncompressedBytes64, 2u), shift)] = + uncompressedPtr - 1ul; + } + + uncompressedBytes = pithy_GetUint32AtOffset(uncompressedBytes64, 3u); + uint32_t uncompressedBytesHash = pithy_HashBytes(uncompressedBytes, shift); + matchCandidatePtr = hashTable[uncompressedBytesHash]; + DCHECK((matchCandidatePtr >= uncompressed) && (matchCandidatePtr < uncompressedPtr)); + hashTable[uncompressedBytesHash] = uncompressedPtr; + } while (PITHY_EXPECT_F(uncompressedBytes == pithy_Load32(matchCandidatePtr)) && + PITHY_EXPECT_T((uncompressedPtr - matchCandidatePtr) < ((int)(kBlockSize - 2ul)))); + + nextUncompressedBytes = pithy_GetUint32AtOffset(uncompressedBytes64, 4u); + nextUncompressedBytesHash = pithy_HashBytes(nextUncompressedBytes, shift); + uncompressedPtr++; + } + } + +emit_remainder: + if (nextEmitUncompressedPtr < uncompressedEnd) { + compressedPtr = pithy_EmitLiteral(compressedPtr, + nextEmitUncompressedPtr, + uncompressedEnd - nextEmitUncompressedPtr, + 0); + } + } + + pithy_Store32(compressedPtr, 0); + compressedPtr += 4; + + DCHECK((size_t)(compressedPtr - compressedOut) <= compressedOutLength); + if (heapHashTable != NULL) { + free(heapHashTable); + heapHashTable = NULL; + hashTable = NULL; + } + return (compressedPtr - compressedOut); +} + + +static const uint32_t pithy_wordmask[] = { + 0u, 0xffu, 0xffffu, 0xffffffu, 0xffffffffu +}; + + +static const uint16_t pithy_charTable[256] = { + 0x0001, 0x0804, 0x1001, 0x1801, 0x0002, 0x0805, 0x1002, 0x1802, + 0x0003, 0x0806, 0x1003, 0x1803, 0x0004, 0x0807, 0x1004, 0x1804, + 0x0005, 0x0808, 0x1005, 0x1805, 0x0006, 0x0809, 0x1006, 0x1806, + 0x0007, 0x080a, 0x1007, 0x1807, 0x0008, 0x080b, 0x1008, 0x1808, + 0x0009, 0x0904, 0x1009, 0x1809, 0x000a, 0x0905, 0x100a, 0x180a, + 0x000b, 0x0906, 0x100b, 0x180b, 0x000c, 0x0907, 0x100c, 0x180c, + 0x000d, 0x0908, 0x100d, 0x180d, 0x000e, 0x0909, 0x100e, 0x180e, + 0x000f, 0x090a, 0x100f, 0x180f, 0x0010, 0x090b, 0x1010, 0x1810, + 0x0011, 0x0a04, 0x1011, 0x1811, 0x0012, 0x0a05, 0x1012, 0x1812, + 0x0013, 0x0a06, 0x1013, 0x1813, 0x0014, 0x0a07, 0x1014, 0x1814, + 0x0015, 0x0a08, 0x1015, 0x1815, 0x0016, 0x0a09, 0x1016, 0x1816, + 0x0017, 0x0a0a, 0x1017, 0x1817, 0x0018, 0x0a0b, 0x1018, 0x1818, + 0x0019, 0x0b04, 0x1019, 0x1819, 0x001a, 0x0b05, 0x101a, 0x181a, + 0x001b, 0x0b06, 0x101b, 0x181b, 0x001c, 0x0b07, 0x101c, 0x181c, + 0x001d, 0x0b08, 0x101d, 0x181d, 0x001e, 0x0b09, 0x101e, 0x181e, + 0x001f, 0x0b0a, 0x101f, 0x181f, 0x0020, 0x0b0b, 0x1020, 0x1820, + 0x0021, 0x0c04, 0x1021, 0x1821, 0x0022, 0x0c05, 0x1022, 0x1822, + 0x0023, 0x0c06, 0x1023, 0x1823, 0x0024, 0x0c07, 0x1024, 0x1824, + 0x0025, 0x0c08, 0x1025, 0x1825, 0x0026, 0x0c09, 0x1026, 0x1826, + 0x0027, 0x0c0a, 0x1027, 0x1827, 0x0028, 0x0c0b, 0x1028, 0x1828, + 0x0029, 0x0d04, 0x1029, 0x1829, 0x002a, 0x0d05, 0x102a, 0x182a, + 0x002b, 0x0d06, 0x102b, 0x182b, 0x002c, 0x0d07, 0x102c, 0x182c, + 0x002d, 0x0d08, 0x102d, 0x182d, 0x002e, 0x0d09, 0x102e, 0x182e, + 0x002f, 0x0d0a, 0x102f, 0x182f, 0x0030, 0x0d0b, 0x1030, 0x1830, + 0x0031, 0x0e04, 0x1031, 0x1831, 0x0032, 0x0e05, 0x1032, 0x1832, + 0x0033, 0x0e06, 0x1033, 0x1833, 0x0034, 0x0e07, 0x1034, 0x1834, + 0x0035, 0x0e08, 0x1035, 0x1835, 0x0036, 0x0e09, 0x1036, 0x1836, + 0x0037, 0x0e0a, 0x1037, 0x1837, 0x0038, 0x0e0b, 0x1038, 0x1838, + 0x0039, 0x0f04, 0x1039, 0x1839, 0x003a, 0x0f05, 0x103a, 0x183a, + 0x003b, 0x0f06, 0x103b, 0x183b, 0x003c, 0x0f07, 0x103c, 0x183c, + 0x0801, 0x0f08, 0x103d, 0x183d, 0x1001, 0x0f09, 0x103e, 0x183e, + 0x1801, 0x0f0a, 0x103f, 0x183f, 0x2001, 0x0f0b, 0x1040, 0x1840 +}; + + +int pithy_GetDecompressedLength(const char *compressed, size_t compressedLength, size_t *decompressedOutLengthResult) +{ + const char *compressedEnd = compressed + compressedLength; + size_t decompressedLength = 0ul; + if (pithy_Parse32WithLimit(compressed, compressedEnd, &decompressedLength) != NULL) { + *decompressedOutLengthResult = decompressedLength; + return (1); + } else { + return (0); + } +} + + +int pithy_Decompress(const char *compressed, size_t compressedLength, char *decompressedOut, + size_t decompressedOutLength) +{ + const char *nextCompressedPtr = NULL, *compressedEnd = (compressed + compressedLength); + size_t parsedDecompressedLength = 0ul; + if (((nextCompressedPtr = pithy_Parse32WithLimit(compressed, compressedEnd, &parsedDecompressedLength)) == NULL) || + (parsedDecompressedLength > decompressedOutLength)) { + return (0); + } + + char *decompressedPtr = decompressedOut, *decompressedEnd = decompressedOut + parsedDecompressedLength; + + while (1) { + const char *compressedPtr = nextCompressedPtr; + DCHECK(compressedPtr <= compressedEnd); + if (PITHY_EXPECT_F(compressedPtr >= compressedEnd)) { + break; + } + + const unsigned char c = *((const unsigned char *)(compressedPtr++)); + const unsigned char cLowerBits = (c & 0x3u); + const int spaceLeft = (decompressedEnd - decompressedPtr); + + if ((cLowerBits == PITHY_LITERAL)) { + size_t literalLength = (c >> 2) + 1; + if (PITHY_EXPECT_T(literalLength <= 16ul) && PITHY_EXPECT_T((compressedEnd - compressedPtr) >= 16l) && + PITHY_EXPECT_T(spaceLeft >= 16l)) { + pithy_Move128(decompressedPtr, compressedPtr); + } else { + if (PITHY_EXPECT_F(literalLength > 60)) { + if (PITHY_EXPECT_F((compressedPtr + 4) > compressedEnd)) { + break; + } + size_t literalLengthBytes = literalLength - 60; + literalLength = (pithy_LoadHost32(compressedPtr) & pithy_wordmask[literalLengthBytes]) + 1; + compressedPtr += literalLengthBytes; + } + if (PITHY_EXPECT_F(spaceLeft < (int)literalLength) || + PITHY_EXPECT_F((compressedPtr + literalLength) > compressedEnd)) { + break; + } + memcpy(decompressedPtr, compressedPtr, literalLength); + } + nextCompressedPtr = compressedPtr + literalLength; + decompressedPtr += literalLength; + } else { + const uint32_t entry = pithy_charTable[c]; + const size_t trailer = pithy_LoadHost32(compressedPtr) & pithy_wordmask[cLowerBits]; + size_t length = entry & 0xffu; + const size_t copyOffset = ((entry & 0x700u) + trailer); + + compressedPtr += cLowerBits; + + DCHECK((compressedPtr <= compressedEnd) && (copyOffset > 0ul) && (spaceLeft > 0l) && (length > 0ul)); + + if (PITHY_EXPECT_F((decompressedPtr - decompressedOut) <= ((int)copyOffset - 1l))) { + break; + } + if (PITHY_EXPECT_T(length <= 16ul) && + PITHY_EXPECT_T(copyOffset >= 16ul) && + PITHY_EXPECT_T(spaceLeft >= 16l)) { + pithy_Move128(decompressedPtr, decompressedPtr - copyOffset); + } else { + if (PITHY_EXPECT_F(length >= 63ul)) { + if (PITHY_EXPECT_T(length == 63ul)) { + if (PITHY_EXPECT_F((compressedPtr + 1) > compressedEnd)) { + break; + } + length = (*((unsigned char *)compressedPtr++)) + 63ul; + } else { + if (PITHY_EXPECT_F((compressedPtr + 2) > compressedEnd)) { + break; + } + length = pithy_LoadHost16(compressedPtr); + compressedPtr += 2ul; + } + } + + char *copyFrom = decompressedPtr - copyOffset, *copyTo = decompressedPtr; + int copyLength = (int)length; + + if (PITHY_EXPECT_F(copyLength > 256l) && PITHY_EXPECT_T(copyOffset > (size_t)copyLength)) { + if (PITHY_EXPECT_F(spaceLeft < copyLength)) { + break; + } + memcpy(copyTo, copyFrom, copyLength); + } else { + if (PITHY_EXPECT_T(spaceLeft >= (copyLength + 24)) && PITHY_EXPECT_T(copyLength > 0l)) { + while ((copyTo - copyFrom) < 16l) { + pithy_Move128(copyTo, copyFrom); + copyLength -= copyTo - copyFrom; + copyTo += copyTo - copyFrom; + } + while (copyLength > 0l) { + pithy_Move128(copyTo, copyFrom); + copyFrom += 16l; + copyTo += 16l; + copyLength -= 16l; + } + } else { + if (PITHY_EXPECT_F(spaceLeft < copyLength) || PITHY_EXPECT_F(copyLength <= 0l)) { + break; + } + do { + *copyTo++ = *copyFrom++; + } while (--copyLength > 0l); + } + } + } + nextCompressedPtr = compressedPtr; + decompressedPtr += length; + } + } + + return (decompressedPtr == decompressedEnd); +} diff --git a/hal/tests/TESTS/mbed_hal/trng/pithy/pithy.h b/hal/tests/TESTS/mbed_hal/trng/pithy/pithy.h new file mode 100644 index 0000000..056ae1a --- /dev/null +++ b/hal/tests/TESTS/mbed_hal/trng/pithy/pithy.h @@ -0,0 +1,64 @@ +// +// pithy.h +// http://github.com/johnezang/pithy +// Licensed under the terms of the BSD License, as specified below. +// +// SPDX-License-Identifier: BSD-3-Clause + +/* + Copyright (c) 2011, John Engelhart + + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + * Neither the name of the Zang Industries nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef _PITHY_H_ +#define _PITHY_H_ + +// compressionLevel >= 0 && compressionLevel <= 9. Values out side this range will be clamped to this range. +size_t pithy_Compress (const char *uncompressed, size_t uncompressedLength, char *compressedOut, + size_t compressedOutLength, int compressionLevel); +int pithy_Decompress(const char *compressed, size_t compressedLength, char *decompressedOut, + size_t decompressedOutLength); + +size_t pithy_MaxCompressedLength(size_t inputLength); +int pithy_GetDecompressedLength(const char *compressed, size_t compressedLength, + size_t *decompressedOutLengthResult); + +#endif // _PITHY_H_ + +#ifdef __cplusplus +} // extern "C" +#endif diff --git a/hal/tests/TESTS/mbed_hal/us_ticker/main.cpp b/hal/tests/TESTS/mbed_hal/us_ticker/main.cpp new file mode 100644 index 0000000..976b38f --- /dev/null +++ b/hal/tests/TESTS/mbed_hal/us_ticker/main.cpp @@ -0,0 +1,72 @@ +/* mbed Microcontroller Library + * Copyright (c) 2017 ARM Limited + * 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. + */ +#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 +#else + +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); + + switch (p_ticker_info->bits) { + case 32: + TEST_ASSERT(p_ticker_info->frequency <= 100000000); + break; + + default: + TEST_ASSERT(p_ticker_info->frequency <= 8000000); + break; + } + + TEST_ASSERT(p_ticker_info->bits >= 16); + +#ifdef US_TICKER_PERIOD_NUM + TEST_ASSERT_UINT32_WITHIN(1, 1000000 * US_TICKER_PERIOD_DEN / US_TICKER_PERIOD_NUM, p_ticker_info->frequency); + TEST_ASSERT_EQUAL_UINT32(US_TICKER_MASK, ((uint64_t)1 << p_ticker_info->bits) - 1); +#endif +} + +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); +} + +#endif // !DEVICE_USTICKER diff --git a/hal/tests/TESTS/mbed_hal/us_ticker/us_ticker_api_tests.h b/hal/tests/TESTS/mbed_hal/us_ticker/us_ticker_api_tests.h new file mode 100644 index 0000000..4cfe203 --- /dev/null +++ b/hal/tests/TESTS/mbed_hal/us_ticker/us_ticker_api_tests.h @@ -0,0 +1,51 @@ +/* mbed Microcontroller Library + * Copyright (c) 2017-2017 ARM Limited + * 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. + */ + +/** \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: + * - counter frequency is between 250KHz and 8MHz for counters which are less than 32 bits wide + * - counter frequency is up to 100MHz for counters which are 32 bits wide + * - the counter is at least 16 bits wide. + */ +void us_ticker_info_test(void); + + +/**@}*/ + +#ifdef __cplusplus +} +#endif + +#endif + +/**@}*/ diff --git a/hal/tests/TESTS/mbed_hal/watchdog/main.cpp b/hal/tests/TESTS/mbed_hal/watchdog/main.cpp new file mode 100644 index 0000000..683e360 --- /dev/null +++ b/hal/tests/TESTS/mbed_hal/watchdog/main.cpp @@ -0,0 +1,273 @@ +/* + * Copyright (c) 2018-2019 Arm Limited and affiliates. + * 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. + */ +#if !DEVICE_WATCHDOG +#error [NOT_SUPPORTED] Watchdog not supported for this target +#else + +#include "greentea-client/test_env.h" +#include "hal/watchdog_api.h" +#include "mbed_wait_api.h" +#include "unity/unity.h" +#include "utest/utest.h" +#include "watchdog_api_tests.h" +#include "mbed.h" + +#include + +/* The shortest timeout value, this test suite is able to handle correctly. */ +#define WDG_MIN_TIMEOUT_MS 50UL + +// Do not set watchdog timeout shorter than WDG_MIN_TIMEOUT_MS, as it may +// cause the host-test-runner return 'TIMEOUT' instead of 'FAIL' / 'PASS' +// if watchdog performs reset during test suite teardown. +#define WDG_TIMEOUT_MS 100UL + +#define MSG_VALUE_DUMMY "0" +#define MSG_VALUE_LEN 24 +#define MSG_KEY_LEN 24 + +#define MSG_KEY_DEVICE_READY "ready" +#define MSG_KEY_START_CASE "start_case" +#define MSG_KEY_DEVICE_RESET "reset_on_case_teardown" + +/* To prevent a loss of Greentea data, the serial buffers have to be flushed + * before the UART peripheral shutdown. The UART shutdown happens when the + * device is entering the deepsleep mode or performing a reset. + * + * With the current API, it is not possible to check if the hardware buffers + * are empty. However, it is possible to determine the time required for the + * buffers to flush. + * + * Assuming the biggest Tx FIFO of 128 bytes (as for CY8CPROTO_062_4343W) + * and a default UART config (9600, 8N1), flushing the Tx FIFO wold take: + * (1 start_bit + 8 data_bits + 1 stop_bit) * 128 * 1000 / 9600 = 133.3 ms. + * To be on the safe side, set the wait time to 150 ms. + */ +#define SERIAL_FLUSH_TIME_MS 150 + +int CASE_INDEX_START; +int CASE_INDEX_CURRENT; +bool CASE_IGNORED = false; + +using utest::v1::Case; +using utest::v1::Specification; +using utest::v1::Harness; + +const watchdog_config_t WDG_CONFIG_DEFAULT = { .timeout_ms = WDG_TIMEOUT_MS }; + +void test_max_timeout_is_valid() +{ + TEST_ASSERT(hal_watchdog_get_platform_features().max_timeout > 1UL); +} + +void test_restart_is_possible() +{ + watchdog_features_t features = hal_watchdog_get_platform_features(); + if (!features.disable_watchdog) { + CASE_IGNORED = true; + TEST_IGNORE_MESSAGE("Disabling watchdog not supported for this platform"); + return; + } + TEST_ASSERT(features.update_config); +} + +void test_stop() +{ + watchdog_features_t features = hal_watchdog_get_platform_features(); + if (!features.disable_watchdog) { + TEST_ASSERT_EQUAL(WATCHDOG_STATUS_NOT_SUPPORTED, hal_watchdog_stop()); + CASE_IGNORED = true; + TEST_IGNORE_MESSAGE("Disabling watchdog not supported for this platform"); + return; + } + + TEST_ASSERT_EQUAL(WATCHDOG_STATUS_OK, hal_watchdog_stop()); + + TEST_ASSERT_EQUAL(WATCHDOG_STATUS_OK, hal_watchdog_init(&WDG_CONFIG_DEFAULT)); + TEST_ASSERT_EQUAL(WATCHDOG_STATUS_OK, hal_watchdog_stop()); + // Make sure that a disabled watchdog does not reset the core. + ThisThread::sleep_for(2 * WDG_TIMEOUT_MS); // Watchdog should fire before twice the timeout value. + + TEST_ASSERT_EQUAL(WATCHDOG_STATUS_OK, hal_watchdog_stop()); +} + +void test_update_config() +{ + watchdog_features_t features = hal_watchdog_get_platform_features(); + if (!features.update_config) { + CASE_IGNORED = true; + TEST_IGNORE_MESSAGE("Updating watchdog config not supported for this platform"); + return; + } + + watchdog_config_t config = WDG_CONFIG_DEFAULT; + uint32_t timeouts[] = { + features.max_timeout / 4, + features.max_timeout / 8, + features.max_timeout / 16 + }; + int num_timeouts = sizeof timeouts / sizeof timeouts[0]; + + for (size_t i = 0; i < num_timeouts; i++) { + if (timeouts[i] < WDG_MIN_TIMEOUT_MS) { + CASE_IGNORED = true; + TEST_IGNORE_MESSAGE("Requested timeout value is too short -- ignoring test case."); + return; + } + + config.timeout_ms = timeouts[i]; + TEST_ASSERT_EQUAL(WATCHDOG_STATUS_OK, hal_watchdog_init(&config)); + uint32_t reload_value = hal_watchdog_get_reload_value(); + // The watchdog should trigger at, or after the timeout value. + TEST_ASSERT(reload_value >= timeouts[i]); + // The watchdog should trigger before twice the timeout value. + TEST_ASSERT(reload_value < 2 * timeouts[i]); + } +} + +utest::v1::status_t case_setup_sync_on_reset(const Case *const source, const size_t index_of_case) +{ + CASE_INDEX_CURRENT = index_of_case; + CASE_IGNORED = false; + return utest::v1::greentea_case_setup_handler(source, index_of_case); +} + +utest::v1::status_t case_teardown_sync_on_reset(const Case *const source, const size_t passed, const size_t failed, + const utest::v1::failure_t failure) +{ + if (CASE_IGNORED) { + return utest::v1::greentea_case_teardown_handler(source, passed, failed, failure); + } + // Start kicking the watchdog during teardown. + hal_watchdog_kick(); + Ticker wdg_kicking_ticker; + wdg_kicking_ticker.attach_us(mbed::callback(hal_watchdog_kick), 20000); + utest::v1::status_t status = utest::v1::greentea_case_teardown_handler(source, passed, failed, failure); + if (failed) { + /* Return immediately and skip the device reset, if the test case failed. + * Provided that the device won't be restarted by other means (i.e. watchdog timer), + * this should allow the test suite to finish in a defined manner + * and report failure to host. + * In case of watchdog reset during test suite teardown, the loss of serial + * connection is possible, so the host-test-runner may return 'TIMEOUT' + * instead of 'FAIL'. + */ + return status; + } + greentea_send_kv(MSG_KEY_DEVICE_RESET, CASE_INDEX_START + CASE_INDEX_CURRENT); + utest_printf("The device will now restart.\n"); + ThisThread::sleep_for(SERIAL_FLUSH_TIME_MS); // Wait for the serial buffers to flush. + NVIC_SystemReset(); + return status; // Reset is instant so this line won't be reached. +} + +utest::v1::status_t case_teardown_wdg_stop_or_reset(const Case *const source, const size_t passed, const size_t failed, + const utest::v1::failure_t failure) +{ + if (CASE_IGNORED) { + return utest::v1::greentea_case_teardown_handler(source, passed, failed, failure); + } + watchdog_features_t features = hal_watchdog_get_platform_features(); + if (features.disable_watchdog) { + hal_watchdog_stop(); + return utest::v1::greentea_case_teardown_handler(source, passed, failed, failure); + } + + return case_teardown_sync_on_reset(source, passed, failed, failure); +} + +template +void test_init() +{ + if (timeout_ms < WDG_MIN_TIMEOUT_MS) { + CASE_IGNORED = true; + TEST_IGNORE_MESSAGE("Requested timeout value is too short -- ignoring test case."); + return; + } + watchdog_config_t config = { .timeout_ms = timeout_ms }; + TEST_ASSERT_EQUAL(WATCHDOG_STATUS_OK, hal_watchdog_init(&config)); + uint32_t reload_value = hal_watchdog_get_reload_value(); + // The watchdog should trigger at, or after the timeout value. + TEST_ASSERT(reload_value >= timeout_ms); + // The watchdog should trigger before twice the timeout value. + TEST_ASSERT(reload_value < 2 * timeout_ms); +} + +void test_init_max_timeout() +{ + watchdog_features_t features = hal_watchdog_get_platform_features(); + watchdog_config_t config = { .timeout_ms = features.max_timeout }; + TEST_ASSERT_EQUAL(WATCHDOG_STATUS_OK, hal_watchdog_init(&config)); + // The watchdog should trigger at, or after the timeout value. + TEST_ASSERT(hal_watchdog_get_reload_value() >= features.max_timeout); +} + +int testsuite_setup_sync_on_reset(const size_t number_of_cases) +{ + GREENTEA_SETUP(45, "sync_on_reset"); + utest::v1::status_t status = utest::v1::greentea_test_setup_handler(number_of_cases); + if (status != utest::v1::STATUS_CONTINUE) { + return status; + } + + char key[MSG_KEY_LEN + 1] = { }; + char value[MSG_VALUE_LEN + 1] = { }; + + greentea_send_kv(MSG_KEY_DEVICE_READY, MSG_VALUE_DUMMY); + greentea_parse_kv(key, value, MSG_KEY_LEN, MSG_VALUE_LEN); + + if (strcmp(key, MSG_KEY_START_CASE) != 0) { + utest_printf("Invalid message key.\n"); + return utest::v1::STATUS_ABORT; + } + + char *tailptr = NULL; + CASE_INDEX_START = (int) strtol(value, &tailptr, 10); + if (*tailptr != '\0' || CASE_INDEX_START < 0) { + utest_printf("Invalid start case index received from host\n"); + return utest::v1::STATUS_ABORT; + } + + utest_printf("Starting with test case index %i of all %i defined test cases.\n", CASE_INDEX_START, number_of_cases); + return CASE_INDEX_START; +} + +Case cases[] = { + Case("Platform feature max_timeout is valid", test_max_timeout_is_valid), + Case("Stopped watchdog can be started again", test_restart_is_possible), + Case("Watchdog can be stopped", test_stop), + + Case("Update config with multiple init calls", + (utest::v1::case_setup_handler_t) case_setup_sync_on_reset, + test_update_config, + (utest::v1::case_teardown_handler_t) case_teardown_wdg_stop_or_reset), + + Case("Init, 100 ms", (utest::v1::case_setup_handler_t) case_setup_sync_on_reset, + test_init<100UL>, (utest::v1::case_teardown_handler_t) case_teardown_sync_on_reset), + Case("Init, max_timeout", (utest::v1::case_setup_handler_t) case_setup_sync_on_reset, + test_init_max_timeout, (utest::v1::case_teardown_handler_t) case_teardown_sync_on_reset), +}; + +Specification specification((utest::v1::test_setup_handler_t) testsuite_setup_sync_on_reset, cases); + +int main() +{ + // Harness will start with a test case index provided by host script. + return !Harness::run(specification); +} + +#endif // !DEVICE_WATCHDOG \ No newline at end of file diff --git a/hal/tests/TESTS/mbed_hal/watchdog/watchdog_api_tests.h b/hal/tests/TESTS/mbed_hal/watchdog/watchdog_api_tests.h new file mode 100644 index 0000000..15e8d5e --- /dev/null +++ b/hal/tests/TESTS/mbed_hal/watchdog/watchdog_api_tests.h @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2018-2019 Arm Limited and affiliates. + * 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. + */ + +/** + * @addtogroup hal_watchdog_tests + * @{ + */ + +#ifndef MBED_HAL_WATCHDOG_API_TESTS_H +#define MBED_HAL_WATCHDOG_API_TESTS_H + +#if DEVICE_WATCHDOG + +/** Test max_timeout validity + * + * Given a device supporting Watchdog HAL API, + * when @a hal_watchdog_get_platform_features() is called, + * then max_timeout member of returned watchdog_features_t struct is greater than 1. + */ +void test_max_timeout_is_valid(); + +/** Test Watchdog features if a stopped Watchdog can be started again + * + * Given a device supporting Watchdog HAL API, + * when the device supports the @a disable_watchdog feature, + * then the device also supports @a update_config feature. + */ +void test_restart_is_possible(); + +/** Test Watchdog stop + * + * Given a device without a support for the @a disable_watchdog feature, + * when @a hal_watchdog_stop() is called, + * then WATCHDOG_STATUS_NOT_SUPPORTED is returned. + * + * Otherwise, given the device with @a disable_watchdog feature support: + * + * Given the Watchdog is *NOT* running, + * when @a hal_watchdog_stop() is called, + * then WATCHDOG_STATUS_OK is returned. + * + * Given the Watchdog is running, + * when @a hal_watchdog_stop() is called before the timeout expires, + * then WATCHDOG_STATUS_OK is returned and the device is not restarted. + * + * Given the Watchdog is *NOT* running (it has already been stopped), + * when @a hal_watchdog_stop() is called, + * then WATCHDOG_STATUS_OK is returned. + */ +void test_stop(); + +/** Test Watchdog init multiple times + * + * Given a set of unique timeout values, + * when @a config.timeout_ms is set to each of these values (T), + * then, for every value T, @a hal_watchdog_init() returns @a WATCHDOG_STATUS_OK + * and @a hal_watchdog_get_reload_value() returns a reload value R + * and T <= R < 2 * T. + */ +void test_update_config(); + +/** Test Watchdog init with a valid config + * + * Given @a config.timeout_ms is set to T ms, + * which is within supported Watchdog timeout range, + * when @a hal_watchdog_init() is called, + * then @a WATCHDOG_STATUS_OK is returned + * and @a hal_watchdog_get_reload_value() returns a reload value R + * and T <= R < 2 * T. + */ +template +void test_init(); + +/** Test Watchdog init with a max_timeout + * + * Given @a config.timeout_ms is set to max_timeout, + * which is a value returned by @a hal_watchdog_get_platform_features(), + * when @a hal_watchdog_init() is called, + * then @a WATCHDOG_STATUS_OK is returned + * and @a hal_watchdog_get_reload_value() returns max_timeout. + */ +void test_init_max_timeout(); + +#endif + +#endif + +/** @}*/ + diff --git a/hal/tests/TESTS/mbed_hal/watchdog_reset/main.cpp b/hal/tests/TESTS/mbed_hal/watchdog_reset/main.cpp new file mode 100644 index 0000000..4d9b794 --- /dev/null +++ b/hal/tests/TESTS/mbed_hal/watchdog_reset/main.cpp @@ -0,0 +1,332 @@ +/* + * Copyright (c) 2018-2019 Arm Limited and affiliates. + * 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. + */ +#if !DEVICE_WATCHDOG +#error [NOT_SUPPORTED] Watchdog not supported for this target +#else + +#include "greentea-client/test_env.h" +#include "utest/utest.h" +#include "unity/unity.h" +#include "hal/watchdog_api.h" +#include "watchdog_reset_tests.h" +#include "mbed.h" + +#define TIMEOUT_MS 100UL + +/* This value is used to calculate the time to kick the watchdog. + * Given the watchdog timeout is set to TIMEOUT_MS, the kick will be performed + * with a delay of (TIMEOUT_MS - KICK_ADVANCE_MS), after the init. + * + * It is common for the watchdog peripheral to use a low precision clock source, + * e.g. the LSI RC acts as a clock source for the IWDG on ST targets. + * According to the ST spec, the 37 kHz LSI is guaranteed to have a frequency + * around 37-38 kHz, but the actual frequency range guaranteed by the production + * tests is 26 kHz up to 56 kHz. + * Bearing that in mind, a 100 ms timeout value may actually last as long as 142 ms + * and as short as 66 ms. + * The value of 35 ms is used to cover the worst case scenario (66 ms). + */ +#define KICK_ADVANCE_MS 35UL + +#define MSG_VALUE_DUMMY "0" +#define CASE_DATA_INVALID 0xffffffffUL +#define CASE_DATA_PHASE2_OK 0xfffffffeUL + +#define MSG_VALUE_LEN 24 +#define MSG_KEY_LEN 24 + +#define MSG_KEY_DEVICE_READY "ready" +#define MSG_KEY_START_CASE "start_case" +#define MSG_KEY_DEVICE_RESET "dev_reset" + +/* To prevent a loss of Greentea data, the serial buffers have to be flushed + * before the UART peripheral shutdown. The UART shutdown happens when the + * device is entering the deepsleep mode or performing a reset. + * + * With the current API, it is not possible to check if the hardware buffers + * are empty. However, it is possible to determine the time required for the + * buffers to flush. + * + * Assuming the biggest Tx FIFO of 128 bytes (as for CY8CPROTO_062_4343W) + * and a default UART config (9600, 8N1), flushing the Tx FIFO wold take: + * (1 start_bit + 8 data_bits + 1 stop_bit) * 128 * 1000 / 9600 = 133.3 ms. + * To be on the safe side, set the wait time to 150 ms. + */ +#define SERIAL_FLUSH_TIME_MS 150 + +#define TIMEOUT_US (1000 * (TIMEOUT_MS)) +#define KICK_ADVANCE_US (1000 * (KICK_ADVANCE_MS)) +#define SERIAL_FLUSH_TIME_US (1000 * (SERIAL_FLUSH_TIME_MS)) + +using utest::v1::Case; +using utest::v1::Specification; +using utest::v1::Harness; + +struct testcase_data { + int index; + int start_index; + uint32_t received_data; +}; + +testcase_data current_case; + +Ticker wdg_kicking_ticker; + +bool send_reset_notification(testcase_data *tcdata, uint32_t delay_ms) +{ + char msg_value[12]; + int str_len = snprintf(msg_value, sizeof msg_value, "%02x,%08lx", tcdata->start_index + tcdata->index, delay_ms); + if (str_len < 0) { + utest_printf("Failed to compose a value string to be sent to host."); + return false; + } + greentea_send_kv(MSG_KEY_DEVICE_RESET, msg_value); + return true; +} + +void test_simple_reset() +{ + // Phase 2. -- verify the test results. + // Verify if this test case passed based on data received from host. + if (current_case.received_data != CASE_DATA_INVALID) { + TEST_ASSERT_EQUAL(CASE_DATA_PHASE2_OK, current_case.received_data); + current_case.received_data = CASE_DATA_INVALID; + return; + } + + // Phase 1. -- run the test code. + // Init the watchdog and wait for a device reset. + watchdog_config_t config = { TIMEOUT_MS }; + if (send_reset_notification(¤t_case, 2 * TIMEOUT_MS + SERIAL_FLUSH_TIME_MS) == false) { + TEST_ASSERT_MESSAGE(0, "Dev-host communication error."); + return; + } + wait_us(SERIAL_FLUSH_TIME_US); // Wait for the serial buffers to flush. + TEST_ASSERT_EQUAL(WATCHDOG_STATUS_OK, hal_watchdog_init(&config)); + // Watchdog should fire before twice the timeout value. + wait_us(2 * TIMEOUT_US); // Device reset expected. + + // Watchdog reset should have occurred during a wait above. + + hal_watchdog_kick(); + wdg_kicking_ticker.attach_us(mbed::callback(hal_watchdog_kick), 20000); // For testsuite failure handling. + TEST_ASSERT_MESSAGE(0, "Watchdog did not reset the device as expected."); +} + +#if DEVICE_SLEEP +void test_sleep_reset() +{ + // Phase 2. -- verify the test results. + if (current_case.received_data != CASE_DATA_INVALID) { + TEST_ASSERT_EQUAL(CASE_DATA_PHASE2_OK, current_case.received_data); + current_case.received_data = CASE_DATA_INVALID; + return; + } + + // Phase 1. -- run the test code. + watchdog_config_t config = { TIMEOUT_MS }; + if (send_reset_notification(¤t_case, 2 * TIMEOUT_MS + SERIAL_FLUSH_TIME_MS) == false) { + TEST_ASSERT_MESSAGE(0, "Dev-host communication error."); + return; + } + wait_us(SERIAL_FLUSH_TIME_US); // Wait for the serial buffers to flush. + TEST_ASSERT_EQUAL(WATCHDOG_STATUS_OK, hal_watchdog_init(&config)); + sleep_manager_lock_deep_sleep(); + if (sleep_manager_can_deep_sleep()) { + TEST_ASSERT_MESSAGE(0, "Deepsleep should be disallowed."); + return; + } + // Watchdog should fire before twice the timeout value. + ThisThread::sleep_for(2 * TIMEOUT_MS); // Device reset expected. + sleep_manager_unlock_deep_sleep(); + + // Watchdog reset should have occurred during the sleep above. + + hal_watchdog_kick(); + wdg_kicking_ticker.attach_us(mbed::callback(hal_watchdog_kick), 20000); // For testsuite failure handling. + TEST_ASSERT_MESSAGE(0, "Watchdog did not reset the device as expected."); +} + +#if DEVICE_LPTICKER +void test_deepsleep_reset() +{ + // Phase 2. -- verify the test results. + if (current_case.received_data != CASE_DATA_INVALID) { + TEST_ASSERT_EQUAL(CASE_DATA_PHASE2_OK, current_case.received_data); + current_case.received_data = CASE_DATA_INVALID; + return; + } + + // Phase 1. -- run the test code. + watchdog_config_t config = { TIMEOUT_MS }; + if (send_reset_notification(¤t_case, 2 * TIMEOUT_MS + SERIAL_FLUSH_TIME_MS) == false) { + TEST_ASSERT_MESSAGE(0, "Dev-host communication error."); + return; + } + wait_us(SERIAL_FLUSH_TIME_US); // Wait for the serial buffers to flush. + wait_us(SERIAL_FLUSH_TIME_US); // Wait for the serial buffers to flush. + TEST_ASSERT_EQUAL(WATCHDOG_STATUS_OK, hal_watchdog_init(&config)); + if (!sleep_manager_can_deep_sleep()) { + TEST_ASSERT_MESSAGE(0, "Deepsleep should be allowed."); + } + + // The Watchdog reset is allowed to be delayed up to twice the timeout + // value when the deepsleep mode is active. + // To make the test less sensitive to clock/wait accuracy, add 20% extra + // (making tha whole deepsleep wait equal to 2.2 * timeout). + ThisThread::sleep_for(220 * TIMEOUT_MS / 100); // Device reset expected. + + // Watchdog reset should have occurred during the deepsleep above. + + hal_watchdog_kick(); + wdg_kicking_ticker.attach_us(mbed::callback(hal_watchdog_kick), 20000); // For testsuite failure handling. + TEST_ASSERT_MESSAGE(0, "Watchdog did not reset the device as expected."); +} +#endif +#endif + +void test_restart_reset() +{ + watchdog_features_t features = hal_watchdog_get_platform_features(); + if (!features.disable_watchdog) { + TEST_IGNORE_MESSAGE("Disabling Watchdog not supported for this platform"); + return; + } + + // Phase 2. -- verify the test results. + if (current_case.received_data != CASE_DATA_INVALID) { + TEST_ASSERT_EQUAL(CASE_DATA_PHASE2_OK, current_case.received_data); + current_case.received_data = CASE_DATA_INVALID; + return; + } + + // Phase 1. -- run the test code. + watchdog_config_t config = { TIMEOUT_MS }; + TEST_ASSERT_EQUAL(WATCHDOG_STATUS_OK, hal_watchdog_init(&config)); + wait_us(TIMEOUT_US / 2); + TEST_ASSERT_EQUAL(WATCHDOG_STATUS_OK, hal_watchdog_stop()); + // Check that stopping the Watchdog prevents a device reset. + // The watchdog should trigger at, or after the timeout value. + // The watchdog should trigger before twice the timeout value. + wait_us(TIMEOUT_US / 2 + TIMEOUT_US); + + if (send_reset_notification(¤t_case, 2 * TIMEOUT_MS + SERIAL_FLUSH_TIME_MS) == false) { + TEST_ASSERT_MESSAGE(0, "Dev-host communication error."); + return; + } + wait_us(SERIAL_FLUSH_TIME_US); // Wait for the serial buffers to flush. + TEST_ASSERT_EQUAL(WATCHDOG_STATUS_OK, hal_watchdog_init(&config)); + // Watchdog should fire before twice the timeout value. + wait_us(2 * TIMEOUT_US); // Device reset expected. + + // Watchdog reset should have occurred during a wait above. + + hal_watchdog_kick(); + wdg_kicking_ticker.attach_us(mbed::callback(hal_watchdog_kick), 20000); // For testsuite failure handling. + TEST_ASSERT_MESSAGE(0, "Watchdog did not reset the device as expected."); +} + +void test_kick_reset() +{ + // Phase 2. -- verify the test results. + if (current_case.received_data != CASE_DATA_INVALID) { + TEST_ASSERT_EQUAL(CASE_DATA_PHASE2_OK, current_case.received_data); + current_case.received_data = CASE_DATA_INVALID; + return; + } + + // Phase 1. -- run the test code. + watchdog_config_t config = { TIMEOUT_MS }; + TEST_ASSERT_EQUAL(WATCHDOG_STATUS_OK, hal_watchdog_init(&config)); + for (int i = 3; i; i--) { + // The reset is prevented as long as the watchdog is kicked + // anytime before the timeout. + wait_us(TIMEOUT_US - KICK_ADVANCE_US); + hal_watchdog_kick(); + } + if (send_reset_notification(¤t_case, 2 * TIMEOUT_MS + SERIAL_FLUSH_TIME_MS) == false) { + TEST_ASSERT_MESSAGE(0, "Dev-host communication error."); + return; + } + wait_us(SERIAL_FLUSH_TIME_US); // Wait for the serial buffers to flush. + // Watchdog should fire before twice the timeout value. + wait_us(2 * TIMEOUT_US); // Device reset expected. + + // Watchdog reset should have occurred during a wait above. + + hal_watchdog_kick(); + wdg_kicking_ticker.attach_us(mbed::callback(hal_watchdog_kick), 20000); // For testsuite failure handling. + TEST_ASSERT_MESSAGE(0, "Watchdog did not reset the device as expected."); +} + +utest::v1::status_t case_setup(const Case *const source, const size_t index_of_case) +{ + current_case.index = index_of_case; + return utest::v1::greentea_case_setup_handler(source, index_of_case); +} + +int testsuite_setup(const size_t number_of_cases) +{ + GREENTEA_SETUP(90, "watchdog_reset"); + utest::v1::status_t status = utest::v1::greentea_test_setup_handler(number_of_cases); + if (status != utest::v1::STATUS_CONTINUE) { + return status; + } + + char key[MSG_KEY_LEN + 1] = { }; + char value[MSG_VALUE_LEN + 1] = { }; + + greentea_send_kv(MSG_KEY_DEVICE_READY, MSG_VALUE_DUMMY); + greentea_parse_kv(key, value, MSG_KEY_LEN, MSG_VALUE_LEN); + + if (strcmp(key, MSG_KEY_START_CASE) != 0) { + utest_printf("Invalid message key.\n"); + return utest::v1::STATUS_ABORT; + } + + int num_args = sscanf(value, "%02x,%08lx", &(current_case.start_index), &(current_case.received_data)); + if (num_args == 0 || num_args == EOF) { + utest_printf("Invalid data received from host\n"); + return utest::v1::STATUS_ABORT; + } + + utest_printf("This test suite is composed of %i test cases. Starting at index %i.\n", number_of_cases, + current_case.start_index); + return current_case.start_index; +} + +Case cases[] = { + Case("Watchdog reset", case_setup, test_simple_reset), +#if DEVICE_SLEEP + Case("Watchdog reset in sleep mode", case_setup, test_sleep_reset), +#if DEVICE_LPTICKER + Case("Watchdog reset in deepsleep mode", case_setup, test_deepsleep_reset), +#endif +#endif + Case("Watchdog started again", case_setup, test_restart_reset), + Case("Kicking the Watchdog prevents reset", case_setup, test_kick_reset), +}; + +Specification specification((utest::v1::test_setup_handler_t) testsuite_setup, cases); + +int main() +{ + // Harness will start with a test case index provided by host script. + return !Harness::run(specification); +} + +#endif // !DEVICE_WATCHDOG diff --git a/hal/tests/TESTS/mbed_hal/watchdog_reset/watchdog_reset_tests.h b/hal/tests/TESTS/mbed_hal/watchdog_reset/watchdog_reset_tests.h new file mode 100644 index 0000000..1833913 --- /dev/null +++ b/hal/tests/TESTS/mbed_hal/watchdog_reset/watchdog_reset_tests.h @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2018-2019 Arm Limited and affiliates. + * 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. + */ + +/** + * @addtogroup hal_watchdog_tests + * @{ + */ + +#ifndef MBED_HAL_WATCHDOG_RESET_TESTS_H +#define MBED_HAL_WATCHDOG_RESET_TESTS_H + +#if DEVICE_WATCHDOG + +/** Test watchdog reset + * + * Given a device with a watchdog started, + * when a watchdog timeout expires, + * then the device is restarted. + */ +void test_simple_reset(); + +/** Test watchdog reset in sleep mode + * + * Given a device with a watchdog started, + * when the watchdog timeout expires while the device is in sleep mode, + * then the device is restarted. + */ +void test_sleep_reset(); + +/** Test watchdog reset in deepsleep mode + * + * Given a device with a watchdog started, + * when the watchdog timeout expires while the device is in deepsleep mode, + * then the device is restarted. + */ +void test_deepsleep_reset(); + +/** Test watchdog reset after watchdog restart + * + * Given a device with a watchdog started, + * when the watchdog is stopped before its timeout expires, + * then the device is not restarted. + * When the watchdog is started again and its timeout expires, + * then the device is restarted. + */ +void test_restart_reset(); + +/** Test watchdog kick + * + * Given a device with a watchdog started, + * when the watchdog is kicked before its timeout expires, + * then the device restart is prevented. + * When the watchdog is *NOT* kicked again before next timeout expires, + * then the device is restarted. + */ +void test_kick_reset(); + +#endif + +#endif + +/** @}*/ + diff --git a/hal/tests/TESTS/mbed_hal/watchdog_timing/main.cpp b/hal/tests/TESTS/mbed_hal/watchdog_timing/main.cpp new file mode 100644 index 0000000..23d5993 --- /dev/null +++ b/hal/tests/TESTS/mbed_hal/watchdog_timing/main.cpp @@ -0,0 +1,227 @@ +/* + * Copyright (c) 2018-2019 Arm Limited and affiliates. + * 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. + */ +#if !DEVICE_WATCHDOG +#error [NOT_SUPPORTED] Watchdog not supported for this target +#else + +#include "greentea-client/test_env.h" +#include "hal/watchdog_api.h" +#include "unity/unity.h" +#include "us_ticker_api.h" +#include "utest/utest.h" +#include "watchdog_timing_tests.h" +#include "mbed.h" + +#define TIMEOUT_LOWER_LIMIT_MS 1000ULL + +// A window to allow to process watchdog kick before timeout occurs. +#define TIME_WINDOW_MS 2UL + +#define MSG_VALUE_DUMMY "0" +#define CASE_DATA_INVALID 0xffffffffUL +#define CASE_DATA_PHASE2_OK 0xfffffffeUL + +#define MSG_VALUE_LEN 24 +#define MSG_KEY_LEN 24 + +#define MSG_KEY_DEVICE_READY "ready" +#define MSG_KEY_START_CASE "start_case" +#define MSG_KEY_HEARTBEAT "hb" +#define MSG_KEY_DEVICE_RESET "dev_reset" + +using utest::v1::Case; +using utest::v1::Specification; +using utest::v1::Harness; + +struct testcase_data { + int index; + int start_index; + uint32_t received_data; +}; + +testcase_data current_case; + +bool send_reset_notification(testcase_data *tcdata, uint32_t delay_ms) +{ + char msg_value[12]; + int str_len = snprintf(msg_value, sizeof msg_value, "%02x,%08lx", tcdata->start_index + tcdata->index, delay_ms); + if (str_len < 0) { + utest_printf("Failed to compose a value string to be sent to host."); + return false; + } + greentea_send_kv(MSG_KEY_DEVICE_RESET, msg_value); + return true; +} + +template +void test_timing() +{ + watchdog_features_t features = hal_watchdog_get_platform_features(); + if (timeout_ms > features.max_timeout) { + TEST_IGNORE_MESSAGE("Requested timeout value not supported for this target -- ignoring test case."); + return; + } + + // Phase 2. -- verify the test results. + // Verify the heartbeat time span sent by host is within given range: + // 1. The watchdog should trigger at, or after the timeout value. + // 2. The watchdog should trigger before twice the timeout value. + if (current_case.received_data != CASE_DATA_INVALID) { + // Provided the watchdog works as expected, the last timestamp received + // by the host will always be before the expected reset time. Because + // of that, the constraint no 1. is not verified. + TEST_ASSERT(current_case.received_data > 0); + TEST_ASSERT(current_case.received_data < 2 * timeout_ms); + current_case.received_data = CASE_DATA_INVALID; + return; + } + + // Phase 1. -- run the test code. + // Send heartbeat messages to host until the watchdeg resets the device. + const ticker_data_t *const us_ticker = get_us_ticker_data(); + us_timestamp_t current_ts, next_ts, expected_reset_ts, divider, ts_increment; + char msg_value[12]; + + watchdog_config_t config = { timeout_ms }; + TEST_ASSERT_EQUAL(WATCHDOG_STATUS_OK, hal_watchdog_init(&config)); + next_ts = ticker_read_us(us_ticker); + expected_reset_ts = next_ts + 1000ULL * timeout_ms; + + divider = 0x2ULL; + while (1) { + current_ts = ticker_read_us(us_ticker); + if (current_ts < next_ts) { + continue; + } + + int str_len = snprintf(msg_value, sizeof msg_value, "%02x,%08lx", current_case.start_index + current_case.index, + (uint32_t) current_ts); + if (str_len < 0) { + utest_printf("Failed to compose a value string to be sent to host."); + return; + } + greentea_send_kv(MSG_KEY_HEARTBEAT, msg_value); + + // The closer to expected reset, the smaller heartbeat time difference. + // This should reduce measurement error present for heartbeat with + // equal periods. + ts_increment = (1000ULL * timeout_ms / divider); + next_ts += ts_increment; + + if (current_ts <= expected_reset_ts) { + divider <<= 1; + } else if (divider > 0x2ULL) { + divider >>= 1; + } + } +} + +void test_timeout_lower_limit() +{ + watchdog_features_t features = hal_watchdog_get_platform_features(); + if (TIMEOUT_LOWER_LIMIT_MS > features.max_timeout) { + TEST_IGNORE_MESSAGE("Requested timeout value not supported for this target -- ignoring test case."); + return; + } + + // Phase 2. -- verify the test results. + if (current_case.received_data != CASE_DATA_INVALID) { + TEST_ASSERT_EQUAL(CASE_DATA_PHASE2_OK, current_case.received_data); + current_case.received_data = CASE_DATA_INVALID; + return; + } + + // Phase 1. -- run the test code. + watchdog_config_t config = { TIMEOUT_LOWER_LIMIT_MS }; + uint32_t sleep_time_ms = (TIMEOUT_LOWER_LIMIT_MS * features.clock_typical_frequency / features.clock_max_frequency) - TIME_WINDOW_MS; + TEST_ASSERT_EQUAL(WATCHDOG_STATUS_OK, hal_watchdog_init(&config)); + + // Kick watchdog before timeout. + // Watchdog should not trigger before timeout * clock accuracy. + // If device restarts while waiting for the kick, test fails. + + wait_us(sleep_time_ms * 1000); + hal_watchdog_kick(); + + if (send_reset_notification(¤t_case, 2 * TIMEOUT_LOWER_LIMIT_MS) == false) { + TEST_ASSERT_MESSAGE(0, "Dev-host communication error."); + return; + } + hal_watchdog_kick(); + + // Watchdog should fire before twice the timeout value. + wait_us(2 * TIMEOUT_LOWER_LIMIT_MS * 1000); + + // Watchdog reset should have occurred during that wait() above; + + hal_watchdog_kick(); // Just to buy some time for testsuite failure handling. + TEST_ASSERT_MESSAGE(0, "Watchdog did not reset the device as expected."); +} + +utest::v1::status_t case_setup(const Case *const source, const size_t index_of_case) +{ + current_case.index = index_of_case; + return utest::v1::greentea_case_setup_handler(source, index_of_case); +} + +int testsuite_setup(const size_t number_of_cases) +{ + GREENTEA_SETUP(90, "watchdog_reset"); + utest::v1::status_t status = utest::v1::greentea_test_setup_handler(number_of_cases); + if (status != utest::v1::STATUS_CONTINUE) { + return status; + } + + char key[MSG_KEY_LEN + 1] = { }; + char value[MSG_VALUE_LEN + 1] = { }; + + greentea_send_kv(MSG_KEY_DEVICE_READY, MSG_VALUE_DUMMY); + greentea_parse_kv(key, value, MSG_KEY_LEN, MSG_VALUE_LEN); + + if (strcmp(key, MSG_KEY_START_CASE) != 0) { + utest_printf("Invalid message key.\n"); + return utest::v1::STATUS_ABORT; + } + + int num_args = sscanf(value, "%02x,%08lx", &(current_case.start_index), &(current_case.received_data)); + if (num_args == 0 || num_args == EOF) { + utest_printf("Invalid data received from host\n"); + return utest::v1::STATUS_ABORT; + } + + utest_printf("This test suite is composed of %i test cases. Starting at index %i.\n", number_of_cases, + current_case.start_index); + return current_case.start_index; +} + +Case cases[] = { + Case("Timing, 200 ms", case_setup, test_timing<200UL>), + Case("Timing, 500 ms", case_setup, test_timing<500UL>), + Case("Timing, 1000 ms", case_setup, test_timing<1000UL>), + Case("Timing, 3000 ms", case_setup, test_timing<3000UL>), + Case("timeout accuracy", case_setup, test_timeout_lower_limit) +}; + +Specification specification((utest::v1::test_setup_handler_t) testsuite_setup, cases); + +int main() +{ + // Harness will start with a test case index provided by host script. + return !Harness::run(specification); +} + +#endif // !DEVICE_WATCHDOG diff --git a/hal/tests/TESTS/mbed_hal/watchdog_timing/watchdog_timing_tests.h b/hal/tests/TESTS/mbed_hal/watchdog_timing/watchdog_timing_tests.h new file mode 100644 index 0000000..d6b5ec3 --- /dev/null +++ b/hal/tests/TESTS/mbed_hal/watchdog_timing/watchdog_timing_tests.h @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2018-2019 Arm Limited and affiliates. + * 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. + */ + +/** + * @addtogroup hal_watchdog_tests + * @{ + */ + +#ifndef MBED_HAL_WATCHDOG_TIMING_TESTS_H +#define MBED_HAL_WATCHDOG_TIMING_TESTS_H + +#if DEVICE_WATCHDOG + +/** Test watchdog timing accuracy + * + * Phase 1. + * Given a watchdog timer started with a timeout value of X ms, + * when the time of X ms elapses, + * then the device is restarted by the watchdog. + * + * Phase 2. + * Given a device restarted by the watchdog timer, + * when the device receives time measurement T from the host, + * then X <= T < 2 * X. + */ +template +void test_timing(); + +/** Test Watchdog timeout + * + * Given a device with a Watchdog started, + * when the Watchdog timeout doesn't expire, + * then the device restart is not performed. + * When the Watchdog timeout does expire, + * then the device is restarted after the timeout and before twice the timeout value. + */ +void test_timeout_lower_limit(); + +#endif + +#endif + +/** @}*/ + diff --git a/hal/tests/TESTS/mbed_hal_fpga_ci_test_shield/README.md b/hal/tests/TESTS/mbed_hal_fpga_ci_test_shield/README.md new file mode 100644 index 0000000..c15471f --- /dev/null +++ b/hal/tests/TESTS/mbed_hal_fpga_ci_test_shield/README.md @@ -0,0 +1,51 @@ +# Testing with FPGA CI TEST shield + +## Setup + +![30% center](fpga_test_shield.jpg) + +``` +mbed test -n tests*fpga* --app-config tests/configs/fpga.json +``` + +FPGA_CI_TEST_SHIELD needed macro +and specific test capabilities per target +are defined in: +https://github.com/ARMmbed/mbed-os/blob/master/TESTS/configs/fpga.json + + + +## MBED-OS + +Tested from factor is defined by MBED_CONF_TARGET_DEFAULT_FORM_FACTOR +"default-form-factor" default value is null. + +When "default-form-factor" is not set, ARDUINO form factor is used. + +Default ff_arduino_pins is defined in: +https://github.com/ARMmbed/mbed-os/blob/master/hal/mbed_pinmap_default.cpp#L28-L32 + +Default ff_arduino_names is defined in: +https://github.com/ARMmbed/mbed-os/blob/master/hal/mbed_pinmap_default.cpp#L34-L38 + +Default empty_gpio_pinmap is defined in: +https://github.com/ARMmbed/mbed-os/blob/master/hal/mbed_gpio.c#L89-L114 + +Some pins are restricted: +https://github.com/ARMmbed/mbed-os/blob/master/hal/mbed_pinmap_default.cpp#L69-L73 + +Some peripherals are restricted: +https://github.com/ARMmbed/mbed-os/blob/master/hal/mbed_pinmap_default.cpp#L94-L100 + + +## Known issues + + +## LINKS + +https://github.com/ARMmbed/fpga-ci-test-shield + +https://github.com/ARMmbed/fpga-ci-test-shield-updater + +https://github.com/ARMmbed/fpga-ci-test-shield-terminal + diff --git a/hal/tests/TESTS/mbed_hal_fpga_ci_test_shield/analogin/analogin_fpga_test.h b/hal/tests/TESTS/mbed_hal_fpga_ci_test_shield/analogin/analogin_fpga_test.h new file mode 100644 index 0000000..6150e32 --- /dev/null +++ b/hal/tests/TESTS/mbed_hal_fpga_ci_test_shield/analogin/analogin_fpga_test.h @@ -0,0 +1,60 @@ +/* mbed Microcontroller Library + * Copyright (c) 2019 ARM Limited + * 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. + */ + +/** \addtogroup hal_analogin_tests */ +/** @{*/ + +#ifndef MBED_FPGA_ANALOG_IN_TEST_H +#define MBED_FPGA_ANALOG_IN_TEST_H + +#if DEVICE_ANALOGIN + +#ifdef __cplusplus +extern "C" { +#endif + +/** Test that the alalogin can be initialized using all possible analogin pins. + * + * Given board provides analogin support. + * When analogin is initialized using valid analogin pin. + * Then the operation is successfull. + * + */ +void fpga_analogin_init_test(PinName pin); + +/** Test that analogin correctly interprets given input voltage. + * + * Given board provides analogin support. + * When 0.0/3.3 V is provided to analogin pin. + * Then analogin_read returns 0.0/1.0, + * analogin_read_u16 returns 0/65535. + * + */ +void fpga_analogin_test(PinName pin); + + +/**@}*/ + +#ifdef __cplusplus +} +#endif + +#endif + +#endif + +/**@}*/ diff --git a/hal/tests/TESTS/mbed_hal_fpga_ci_test_shield/analogin/main.cpp b/hal/tests/TESTS/mbed_hal_fpga_ci_test_shield/analogin/main.cpp new file mode 100644 index 0000000..57b4459 --- /dev/null +++ b/hal/tests/TESTS/mbed_hal_fpga_ci_test_shield/analogin/main.cpp @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2019, Arm Limited and affiliates. + * 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. + */ + +#if !DEVICE_ANALOGIN +#error [NOT_SUPPORTED] Analog in not supported for this target +#elif !COMPONENT_FPGA_CI_TEST_SHIELD +#error [NOT_SUPPORTED] FPGA CI Test Shield is needed to run this test +#elif !defined(TARGET_FF_ARDUINO) && !defined(MBED_CONF_TARGET_DEFAULT_FORM_FACTOR) +#error [NOT_SUPPORTED] Test not supported for this form factor +#else + +#include "utest/utest.h" +#include "unity/unity.h" +#include "greentea-client/test_env.h" +#include "mbed.h" +#include "pinmap.h" +#include "hal/static_pinmap.h" +#include "test_utils.h" +#include "MbedTester.h" +#include "analogin_fpga_test.h" + +using namespace utest::v1; + +#define analogin_debug_printf(...) + +#define DELTA_FLOAT (0.1f) // 10% +#define DELTA_U16 (2*3277) // 10% + +const PinList *form_factor = pinmap_ff_default_pins(); +const PinList *restricted = pinmap_restricted_pins(); + +MbedTester tester(form_factor, restricted); + +void fpga_analogin_init_test(PinName pin) +{ + analogin_t analogin; + + analogin_init(&analogin, pin); + analogin_free(&analogin); +} + +template +void fpga_analogin_test(PinName pin) +{ + tester.reset(); + tester.pin_map_set(pin, MbedTester::LogicalPinGPIO0); + tester.select_peripheral(MbedTester::PeripheralGPIO); + + /* Test analog input */ + + analogin_t analogin; + + if (init_direct) { + const PinMap pinmap = get_analogin_pinmap(pin); + analogin_init_direct(&analogin, &pinmap); + } else { + analogin_init(&analogin, pin); + } + + tester.gpio_write(MbedTester::LogicalPinGPIO0, 1, true); + TEST_ASSERT_FLOAT_WITHIN(DELTA_FLOAT, 1.0f, analogin_read(&analogin)); + TEST_ASSERT_UINT16_WITHIN(DELTA_U16, 65535, analogin_read_u16(&analogin)); + + tester.gpio_write(MbedTester::LogicalPinGPIO0, 0, true); + TEST_ASSERT_FLOAT_WITHIN(DELTA_FLOAT, 0.0f, analogin_read(&analogin)); + TEST_ASSERT_UINT16_WITHIN(DELTA_U16, 0, analogin_read_u16(&analogin)); + + /* Set gpio back to Hi-Z */ + tester.gpio_write(MbedTester::LogicalPinGPIO0, 0, false); + + analogin_free(&analogin); +} + +Case cases[] = { + // This will be run for all pins + Case("AnalogIn - init test", all_ports), + // This will be run for single pin + Case("AnalogIn - read test", all_ports>), + Case("AnalogIn (direct init) - read test", all_ports>), +}; + +utest::v1::status_t greentea_test_setup(const size_t number_of_cases) +{ + GREENTEA_SETUP(120, "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); +} + +#endif /* !DEVICE_ANALOGIN */ diff --git a/hal/tests/TESTS/mbed_hal_fpga_ci_test_shield/fpga_test_shield.jpg b/hal/tests/TESTS/mbed_hal_fpga_ci_test_shield/fpga_test_shield.jpg new file mode 100644 index 0000000..fe7b7ca --- /dev/null +++ b/hal/tests/TESTS/mbed_hal_fpga_ci_test_shield/fpga_test_shield.jpg Binary files differ diff --git a/hal/tests/TESTS/mbed_hal_fpga_ci_test_shield/gpio/gpio_fpga_test.h b/hal/tests/TESTS/mbed_hal_fpga_ci_test_shield/gpio/gpio_fpga_test.h new file mode 100644 index 0000000..34f817b --- /dev/null +++ b/hal/tests/TESTS/mbed_hal_fpga_ci_test_shield/gpio/gpio_fpga_test.h @@ -0,0 +1,69 @@ +/* mbed Microcontroller Library + * Copyright (c) 2019-2020 ARM Limited + * 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. + */ + +/** \addtogroup hal_gpio_tests */ +/** @{*/ + +#ifndef MBED_FPGA_GPIO_TEST_H +#define MBED_FPGA_GPIO_TEST_H + +#ifdef __cplusplus +extern "C" { +#endif + +/* Test basic input & output operations. + * + * Given a GPIO instance initialized with a generic gpio_init() function, + * when basic input and output operations are performed, + * then all operations succeed. + */ +void fpga_test_basic_input_output(PinName pin); + +/* Test input pull modes. + * + * Given a GPIO instance configured with an input pull mode, + * when basic input operations are performed, + * then all operations succeed. + */ +void fpga_test_input_pull_modes(PinName pin); + +/* Test explicit input initialization. + * + * Given a GPIO instance, + * when additional parameters are passed to the input init function, + * then the GPIO is correctly initialized as an input. + */ +void fpga_test_explicit_input(PinName pin); + +/* Test explicit output initialization. + * + * Given a GPIO instance, + * when additional parameters are passed to the output init function, + * then the GPIO is correctly initialized as an output. + */ +void fpga_test_explicit_output(PinName pin); + +/**@}*/ + +#ifdef __cplusplus +} +#endif + +#endif + + +/**@}*/ diff --git a/hal/tests/TESTS/mbed_hal_fpga_ci_test_shield/gpio/main.cpp b/hal/tests/TESTS/mbed_hal_fpga_ci_test_shield/gpio/main.cpp new file mode 100644 index 0000000..aaec083 --- /dev/null +++ b/hal/tests/TESTS/mbed_hal_fpga_ci_test_shield/gpio/main.cpp @@ -0,0 +1,328 @@ +/* + * Copyright (c) 2019-2020, Arm Limited and affiliates. + * 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. + */ + +#if !COMPONENT_FPGA_CI_TEST_SHIELD +#error [NOT_SUPPORTED] FPGA CI Test Shield is needed to run this test +#elif !defined(TARGET_FF_ARDUINO) && !defined(MBED_CONF_TARGET_DEFAULT_FORM_FACTOR) +#error [NOT_SUPPORTED] Test not supported for this form factor +#else + +#include "utest/utest.h" +#include "unity/unity.h" +#include "greentea-client/test_env.h" +#include "mbed.h" +#include "MbedTester.h" +#include "pinmap.h" +#include "test_utils.h" +#include "gpio_fpga_test.h" + +using namespace utest::v1; + +// This delay is used when reading a floating input that has an internal pull-up +// or pull-down resistor. The voltage response is much slower when the input +// is not driven externally. +#define HI_Z_READ_DELAY_US 5 + +MbedTester tester(DefaultFormFactor::pins(), DefaultFormFactor::restricted_pins()); + +/* Test basic input & output operations. + * + * Given a GPIO instance initialized with a generic gpio_init() function, + * when basic input and output operations are performed, + * then all operations succeed. + */ +void fpga_test_basic_input_output(PinName pin) +{ + // Reset everything and set all tester pins to hi-Z. + tester.reset(); + + // Map pins for test. + tester.pin_map_set(pin, MbedTester::LogicalPinGPIO0); + + // Select GPIO0. + tester.select_peripheral(MbedTester::PeripheralGPIO); + + gpio_t gpio; + // Initialize GPIO pin with a generic init fun. + gpio_init(&gpio, NC); + // Test gpio_is_connected() returned value. + TEST_ASSERT_EQUAL_INT(0, gpio_is_connected(&gpio)); + gpio_free(&gpio); + gpio_init(&gpio, pin); + TEST_ASSERT_NOT_EQUAL(0, gpio_is_connected(&gpio)); + + // Test GPIO used as an input. + gpio_dir(&gpio, PIN_INPUT); + tester.gpio_write(MbedTester::LogicalPinGPIO0, 1, true); + TEST_ASSERT_EQUAL_INT(1, gpio_read(&gpio)); + tester.gpio_write(MbedTester::LogicalPinGPIO0, 0, true); + TEST_ASSERT_EQUAL_INT(0, gpio_read(&gpio)); + tester.gpio_write(MbedTester::LogicalPinGPIO0, 1, true); + TEST_ASSERT_EQUAL_INT(1, gpio_read(&gpio)); + + // Test GPIO used as an output. + tester.gpio_write(MbedTester::LogicalPinGPIO0, 0, false); + gpio_dir(&gpio, PIN_OUTPUT); + gpio_write(&gpio, 0); + TEST_ASSERT_EQUAL_INT(0, tester.gpio_read(MbedTester::LogicalPinGPIO0)); + gpio_write(&gpio, 1); + TEST_ASSERT_EQUAL_INT(1, tester.gpio_read(MbedTester::LogicalPinGPIO0)); + gpio_write(&gpio, 0); + TEST_ASSERT_EQUAL_INT(0, tester.gpio_read(MbedTester::LogicalPinGPIO0)); + + gpio_free(&gpio); +} + +/* Test input pull modes. + * + * Given a GPIO instance configured with an input pull mode, + * when basic input operations are performed, + * then all operations succeed. + */ +void fpga_test_input_pull_modes(PinName pin) +{ + // Reset everything and set all tester pins to hi-Z. + tester.reset(); + + // Map pins for test. + tester.pin_map_set(pin, MbedTester::LogicalPinGPIO0); + + // Select GPIO0. + tester.select_peripheral(MbedTester::PeripheralGPIO); + + gpio_t gpio; + // Initialize GPIO pin with a generic init fun. + gpio_init(&gpio, pin); + TEST_ASSERT_NOT_EQUAL(0, gpio_is_connected(&gpio)); + gpio_dir(&gpio, PIN_INPUT); + gpio_capabilities_t gcap = {}; + gpio_get_capabilities(&gpio, &gcap); + + // Test input, pull-up mode. + if (gcap.pull_up) { + gpio_mode(&gpio, PullUp); + tester.gpio_write(MbedTester::LogicalPinGPIO0, 0, false); + wait_us(HI_Z_READ_DELAY_US); + TEST_ASSERT_EQUAL_INT(1, gpio_read(&gpio)); // hi-Z, pulled up + tester.gpio_write(MbedTester::LogicalPinGPIO0, 0, true); + TEST_ASSERT_EQUAL_INT(0, gpio_read(&gpio)); + tester.gpio_write(MbedTester::LogicalPinGPIO0, 1, true); + TEST_ASSERT_EQUAL_INT(1, gpio_read(&gpio)); + tester.gpio_write(MbedTester::LogicalPinGPIO0, 0, true); + TEST_ASSERT_EQUAL_INT(0, gpio_read(&gpio)); + tester.gpio_write(MbedTester::LogicalPinGPIO0, 0, false); + wait_us(HI_Z_READ_DELAY_US); + TEST_ASSERT_EQUAL_INT(1, gpio_read(&gpio)); // hi-Z, pulled up + } else { + utest_printf("skipped PullUp,"); + } + + // Test input, pull-down mode. + if (gcap.pull_down) { + gpio_mode(&gpio, PullDown); + tester.gpio_write(MbedTester::LogicalPinGPIO0, 0, false); + wait_us(HI_Z_READ_DELAY_US); + TEST_ASSERT_EQUAL_INT(0, gpio_read(&gpio)); // hi-Z, pulled down + tester.gpio_write(MbedTester::LogicalPinGPIO0, 1, true); + TEST_ASSERT_EQUAL_INT(1, gpio_read(&gpio)); + tester.gpio_write(MbedTester::LogicalPinGPIO0, 0, true); + TEST_ASSERT_EQUAL_INT(0, gpio_read(&gpio)); + tester.gpio_write(MbedTester::LogicalPinGPIO0, 1, true); + TEST_ASSERT_EQUAL_INT(1, gpio_read(&gpio)); + tester.gpio_write(MbedTester::LogicalPinGPIO0, 0, false); + wait_us(HI_Z_READ_DELAY_US); + TEST_ASSERT_EQUAL_INT(0, gpio_read(&gpio)); // hi-Z, pulled down + } else { + utest_printf("skipped PullDown,"); + } + + // Test input, pull-none mode. + if (gcap.pull_none) { + gpio_mode(&gpio, PullNone); + tester.gpio_write(MbedTester::LogicalPinGPIO0, 1, true); + TEST_ASSERT_EQUAL_INT(1, gpio_read(&gpio)); + tester.gpio_write(MbedTester::LogicalPinGPIO0, 0, true); + TEST_ASSERT_EQUAL_INT(0, gpio_read(&gpio)); + tester.gpio_write(MbedTester::LogicalPinGPIO0, 1, true); + TEST_ASSERT_EQUAL_INT(1, gpio_read(&gpio)); + } else { + utest_printf("skipped PullNone,"); + } + + gpio_free(&gpio); +} + +/* Test explicit input initialization. + * + * Given a GPIO instance, + * when additional parameters are passed to the input init function, + * then the GPIO is correctly initialized as an input. + */ +void fpga_test_explicit_input(PinName pin) +{ + // Reset everything and set all tester pins to hi-Z. + tester.reset(); + + // Map pins for test. + tester.pin_map_set(pin, MbedTester::LogicalPinGPIO0); + + // Select GPIO0. + tester.select_peripheral(MbedTester::PeripheralGPIO); + + gpio_t gpio; + gpio_init(&gpio, pin); + gpio_capabilities_t gcap = {}; + gpio_get_capabilities(&gpio, &gcap); + gpio_free(&gpio); + + // Initialize GPIO pin as an input, pull-up mode. + if (gcap.pull_up) { + memset(&gpio, 0, sizeof gpio); + gpio_init_in_ex(&gpio, pin, PullUp); + TEST_ASSERT_NOT_EQUAL(0, gpio_is_connected(&gpio)); + tester.gpio_write(MbedTester::LogicalPinGPIO0, 0, false); + wait_us(HI_Z_READ_DELAY_US); + TEST_ASSERT_EQUAL_INT(1, gpio_read(&gpio)); // hi-Z, pulled up + gpio_free(&gpio); + } else { + utest_printf("skipped PullUp,"); + } + + // Initialize GPIO pin as an input, pull-down mode. + if (gcap.pull_down) { + memset(&gpio, 0, sizeof gpio); + gpio_init_in_ex(&gpio, pin, PullDown); + TEST_ASSERT_NOT_EQUAL(0, gpio_is_connected(&gpio)); + tester.gpio_write(MbedTester::LogicalPinGPIO0, 0, false); + wait_us(HI_Z_READ_DELAY_US); + TEST_ASSERT_EQUAL_INT(0, gpio_read(&gpio)); // hi-Z, pulled down + gpio_free(&gpio); + } else { + utest_printf("skipped PullDown,"); + } + + // Initialize GPIO pin as an input, pull-up mode. + if (gcap.pull_up) { + memset(&gpio, 0, sizeof gpio); + gpio_init_inout(&gpio, pin, PIN_INPUT, PullUp, 0); + TEST_ASSERT_NOT_EQUAL(0, gpio_is_connected(&gpio)); + tester.gpio_write(MbedTester::LogicalPinGPIO0, 0, false); + wait_us(HI_Z_READ_DELAY_US); + TEST_ASSERT_EQUAL_INT(1, gpio_read(&gpio)); // hi-Z, pulled up + gpio_free(&gpio); + } else { + utest_printf("skipped PullUp,"); + } + + // Initialize GPIO pin as an input, pull-down mode. + if (gcap.pull_down) { + memset(&gpio, 0, sizeof gpio); + gpio_init_inout(&gpio, pin, PIN_INPUT, PullDown, 0); + TEST_ASSERT_NOT_EQUAL(0, gpio_is_connected(&gpio)); + tester.gpio_write(MbedTester::LogicalPinGPIO0, 0, false); + wait_us(HI_Z_READ_DELAY_US); + TEST_ASSERT_EQUAL_INT(0, gpio_read(&gpio)); // hi-Z, pulled down + gpio_free(&gpio); + } else { + utest_printf("skipped PullDown,"); + } +} + +/* Test explicit output initialization. + * + * Given a GPIO instance, + * when additional parameters are passed to the output init function, + * then the GPIO is correctly initialized as an output. + */ +void fpga_test_explicit_output(PinName pin) +{ + // Reset everything and set all tester pins to hi-Z. + tester.reset(); + + // Map pins for test. + tester.pin_map_set(pin, MbedTester::LogicalPinGPIO0); + + // Select GPIO0. + tester.select_peripheral(MbedTester::PeripheralGPIO); + + gpio_t gpio; + gpio_init(&gpio, pin); + gpio_capabilities_t gcap = {}; + gpio_get_capabilities(&gpio, &gcap); + gpio_free(&gpio); + + // Initialize GPIO pin as an output, output value = 0. + memset(&gpio, 0, sizeof gpio); + gpio_init_out(&gpio, pin); + TEST_ASSERT_NOT_EQUAL(0, gpio_is_connected(&gpio)); + TEST_ASSERT_EQUAL_INT(0, tester.gpio_read(MbedTester::LogicalPinGPIO0)); + gpio_free(&gpio); + + // Initialize GPIO pin as an output, output value = 1. + memset(&gpio, 0, sizeof gpio); + gpio_init_out_ex(&gpio, pin, 1); + TEST_ASSERT_NOT_EQUAL(0, gpio_is_connected(&gpio)); + TEST_ASSERT_EQUAL_INT(1, tester.gpio_read(MbedTester::LogicalPinGPIO0)); + gpio_free(&gpio); + + // Initialize GPIO pin as an output, output value = 0. + memset(&gpio, 0, sizeof gpio); + gpio_init_out_ex(&gpio, pin, 0); + TEST_ASSERT_NOT_EQUAL(0, gpio_is_connected(&gpio)); + TEST_ASSERT_EQUAL_INT(0, tester.gpio_read(MbedTester::LogicalPinGPIO0)); + gpio_free(&gpio); + + // Initialize GPIO pin as an output, output value = 1. + if (gcap.pull_none) { + memset(&gpio, 0, sizeof gpio); + gpio_init_inout(&gpio, pin, PIN_OUTPUT, PullNone, 1); + TEST_ASSERT_NOT_EQUAL(0, gpio_is_connected(&gpio)); + TEST_ASSERT_EQUAL_INT(1, tester.gpio_read(MbedTester::LogicalPinGPIO0)); + gpio_free(&gpio); + + // Initialize GPIO pin as an output, output value = 0. + memset(&gpio, 0, sizeof gpio); + gpio_init_inout(&gpio, pin, PIN_OUTPUT, PullNone, 0); + TEST_ASSERT_NOT_EQUAL(0, gpio_is_connected(&gpio)); + TEST_ASSERT_EQUAL_INT(0, tester.gpio_read(MbedTester::LogicalPinGPIO0)); + gpio_free(&gpio); + } else { + utest_printf("skipped gpio_init_inout,"); + } +} + +Case cases[] = { + Case("basic input & output", all_ports), + Case("input pull modes", all_ports), + Case("explicit init, input", all_ports), + Case("explicit init, output", all_ports), +}; + +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); +} + +#endif /* !COMPONENT_FPGA_CI_TEST_SHIELD */ diff --git a/hal/tests/TESTS/mbed_hal_fpga_ci_test_shield/gpio_irq/gpio_irq_fpga_test.h b/hal/tests/TESTS/mbed_hal_fpga_ci_test_shield/gpio_irq/gpio_irq_fpga_test.h new file mode 100644 index 0000000..793022a --- /dev/null +++ b/hal/tests/TESTS/mbed_hal_fpga_ci_test_shield/gpio_irq/gpio_irq_fpga_test.h @@ -0,0 +1,58 @@ +/* mbed Microcontroller Library + * Copyright (c) 2019 ARM Limited + * 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. + */ + +/** \addtogroup hal_gpioirq_tests */ +/** @{*/ + +#ifndef MBED_FPGA_GPIO_IRQ_TEST_H +#define MBED_FPGA_GPIO_IRQ_TEST_H + +#if DEVICE_INTERRUPTIN + +#ifdef __cplusplus +extern "C" { +#endif + +/** Test that the GPIO IRQ can be initialized/de-initialized using all possible + * GPIO IRQ pins. + * + * Given board provides GPIO IRQ support. + * When GPIO IRQ is initialized (and then de-initialized) using valid GPIO IRQ pin. + * Then the operation is successfull. + * + */ +void fpga_gpio_irq_test(PinName pin); + +/** Test that the gpio interrupt is generated correctly. + * + * Given board provides interrupt-in feature. + * When gpio interrupt is configured to fire on rasing/falling/both edge(s). + * Then on rasing/falling/any edge registered interrupt handler is called. + * + */ +void fpga_gpio_irq_init_free_test(PinName pin); + +/**@}*/ + +#ifdef __cplusplus +} +#endif + +#endif + +#endif +/**@}*/ diff --git a/hal/tests/TESTS/mbed_hal_fpga_ci_test_shield/gpio_irq/main.cpp b/hal/tests/TESTS/mbed_hal_fpga_ci_test_shield/gpio_irq/main.cpp new file mode 100644 index 0000000..98b4935 --- /dev/null +++ b/hal/tests/TESTS/mbed_hal_fpga_ci_test_shield/gpio_irq/main.cpp @@ -0,0 +1,283 @@ +/* + * Copyright (c) 2019, Arm Limited and affiliates. + * 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. + */ + +#if !DEVICE_INTERRUPTIN +#error [NOT_SUPPORTED] test not supported +#elif !COMPONENT_FPGA_CI_TEST_SHIELD +#error [NOT_SUPPORTED] FPGA CI Test Shield is needed to run this test +#elif !defined(TARGET_FF_ARDUINO) && !defined(MBED_CONF_TARGET_DEFAULT_FORM_FACTOR) +#error [NOT_SUPPORTED] Test not supported for this form factor +#else + +#include "utest/utest.h" +#include "unity/unity.h" +#include "greentea-client/test_env.h" +#include "mbed.h" +#include "MbedTester.h" +#include "pinmap.h" +#include "gpio_irq_fpga_test.h" + +using namespace utest::v1; + +#include "MbedTester.h" +#include "pinmap.h" +#include "test_utils.h" + +MbedTester tester(DefaultFormFactor::pins(), DefaultFormFactor::restricted_pins()); + +static volatile uint32_t call_counter; +void test_gpio_irq_handler(uint32_t id, gpio_irq_event event) +{ + call_counter++; +} + +#define WAIT() wait_us(10) + +void fpga_gpio_irq_test(PinName pin) +{ + // Reset everything and set all tester pins to hi-Z. + tester.reset(); + + // Map pins for test. + tester.pin_map_set(pin, MbedTester::LogicalPinGPIO0); + + // Select GPIO0. + tester.select_peripheral(MbedTester::PeripheralGPIO); + + gpio_t gpio; + // configure pin as input + gpio_init_in(&gpio, pin); + + gpio_irq_t gpio_irq; + uint32_t id = 123; + TEST_ASSERT_EQUAL(0, gpio_irq_init(&gpio_irq, pin, test_gpio_irq_handler, id)); + + gpio_irq_set(&gpio_irq, IRQ_RISE, true); + gpio_irq_enable(&gpio_irq); + + tester.gpio_write(MbedTester::LogicalPinGPIO0, 0, true); + WAIT(); + + // test irq on rising edge + call_counter = 0; + tester.gpio_write(MbedTester::LogicalPinGPIO0, 1, true); + WAIT(); + TEST_ASSERT_EQUAL(1, call_counter); + + tester.gpio_write(MbedTester::LogicalPinGPIO0, 0, true); + WAIT(); + TEST_ASSERT_EQUAL(1, call_counter); + + tester.gpio_write(MbedTester::LogicalPinGPIO0, 1, true); + WAIT(); + TEST_ASSERT_EQUAL(2, call_counter); + + tester.gpio_write(MbedTester::LogicalPinGPIO0, 0, true); + WAIT(); + TEST_ASSERT_EQUAL(2, call_counter); + + gpio_irq_disable(&gpio_irq); + + call_counter = 0; + tester.gpio_write(MbedTester::LogicalPinGPIO0, 1, true); + WAIT(); + TEST_ASSERT_EQUAL(0, call_counter); + + tester.gpio_write(MbedTester::LogicalPinGPIO0, 0, true); + WAIT(); + TEST_ASSERT_EQUAL(0, call_counter); + + tester.gpio_write(MbedTester::LogicalPinGPIO0, 1, true); + WAIT(); + TEST_ASSERT_EQUAL(0, call_counter); + + tester.gpio_write(MbedTester::LogicalPinGPIO0, 0, true); + WAIT(); + TEST_ASSERT_EQUAL(0, call_counter); + + gpio_irq_enable(&gpio_irq); + + call_counter = 0; + tester.gpio_write(MbedTester::LogicalPinGPIO0, 1, true); + WAIT(); + TEST_ASSERT_EQUAL(1, call_counter); + + tester.gpio_write(MbedTester::LogicalPinGPIO0, 0, true); + WAIT(); + TEST_ASSERT_EQUAL(1, call_counter); + + tester.gpio_write(MbedTester::LogicalPinGPIO0, 1, true); + WAIT(); + TEST_ASSERT_EQUAL(2, call_counter); + + tester.gpio_write(MbedTester::LogicalPinGPIO0, 0, true); + WAIT(); + TEST_ASSERT_EQUAL(2, call_counter); + + // test irq on both rising and falling edge + gpio_irq_set(&gpio_irq, IRQ_FALL, true); + + tester.gpio_write(MbedTester::LogicalPinGPIO0, 1, true); + WAIT(); + + call_counter = 0; + tester.gpio_write(MbedTester::LogicalPinGPIO0, 0, true); + WAIT(); + TEST_ASSERT_EQUAL(1, call_counter); + + tester.gpio_write(MbedTester::LogicalPinGPIO0, 1, true); + WAIT(); + TEST_ASSERT_EQUAL(2, call_counter); + + tester.gpio_write(MbedTester::LogicalPinGPIO0, 0, true); + WAIT(); + TEST_ASSERT_EQUAL(3, call_counter); + + tester.gpio_write(MbedTester::LogicalPinGPIO0, 1, true); + WAIT(); + TEST_ASSERT_EQUAL(4, call_counter); + + gpio_irq_disable(&gpio_irq); + + call_counter = 0; + tester.gpio_write(MbedTester::LogicalPinGPIO0, 0, true); + WAIT(); + TEST_ASSERT_EQUAL(0, call_counter); + + tester.gpio_write(MbedTester::LogicalPinGPIO0, 1, true); + WAIT(); + TEST_ASSERT_EQUAL(0, call_counter); + + tester.gpio_write(MbedTester::LogicalPinGPIO0, 0, true); + WAIT(); + TEST_ASSERT_EQUAL(0, call_counter); + + tester.gpio_write(MbedTester::LogicalPinGPIO0, 1, true); + WAIT(); + TEST_ASSERT_EQUAL(0, call_counter); + + gpio_irq_enable(&gpio_irq); + + call_counter = 0; + tester.gpio_write(MbedTester::LogicalPinGPIO0, 0, true); + WAIT(); + TEST_ASSERT_EQUAL(1, call_counter); + + tester.gpio_write(MbedTester::LogicalPinGPIO0, 1, true); + WAIT(); + TEST_ASSERT_EQUAL(2, call_counter); + + tester.gpio_write(MbedTester::LogicalPinGPIO0, 0, true); + WAIT(); + TEST_ASSERT_EQUAL(3, call_counter); + + tester.gpio_write(MbedTester::LogicalPinGPIO0, 1, true); + WAIT(); + TEST_ASSERT_EQUAL(4, call_counter); + + // test irq on falling edge + gpio_irq_set(&gpio_irq, IRQ_RISE, false); + + tester.gpio_write(MbedTester::LogicalPinGPIO0, 1, true); + WAIT(); + + call_counter = 0; + tester.gpio_write(MbedTester::LogicalPinGPIO0, 0, true); + WAIT(); + TEST_ASSERT_EQUAL(1, call_counter); + + tester.gpio_write(MbedTester::LogicalPinGPIO0, 1, true); + WAIT(); + TEST_ASSERT_EQUAL(1, call_counter); + + tester.gpio_write(MbedTester::LogicalPinGPIO0, 0, true); + WAIT(); + TEST_ASSERT_EQUAL(2, call_counter); + + tester.gpio_write(MbedTester::LogicalPinGPIO0, 1, true); + WAIT(); + TEST_ASSERT_EQUAL(2, call_counter); + + gpio_irq_disable(&gpio_irq); + + call_counter = 0; + tester.gpio_write(MbedTester::LogicalPinGPIO0, 0, true); + WAIT(); + TEST_ASSERT_EQUAL(0, call_counter); + + tester.gpio_write(MbedTester::LogicalPinGPIO0, 1, true); + WAIT(); + TEST_ASSERT_EQUAL(0, call_counter); + + tester.gpio_write(MbedTester::LogicalPinGPIO0, 0, true); + WAIT(); + TEST_ASSERT_EQUAL(0, call_counter); + + tester.gpio_write(MbedTester::LogicalPinGPIO0, 1, true); + WAIT(); + TEST_ASSERT_EQUAL(0, call_counter); + + gpio_irq_enable(&gpio_irq); + + call_counter = 0; + tester.gpio_write(MbedTester::LogicalPinGPIO0, 0, true); + WAIT(); + TEST_ASSERT_EQUAL(1, call_counter); + + tester.gpio_write(MbedTester::LogicalPinGPIO0, 1, true); + WAIT(); + TEST_ASSERT_EQUAL(1, call_counter); + + tester.gpio_write(MbedTester::LogicalPinGPIO0, 0, true); + WAIT(); + TEST_ASSERT_EQUAL(2, call_counter); + + tester.gpio_write(MbedTester::LogicalPinGPIO0, 1, true); + WAIT(); + TEST_ASSERT_EQUAL(2, call_counter); + + gpio_irq_free(&gpio_irq); +} + +void fpga_gpio_irq_init_free_test(PinName pin) +{ + gpio_t gpio; + gpio_irq_t gpio_irq; + gpio_init_in(&gpio, pin); + TEST_ASSERT_EQUAL(0, gpio_irq_init(&gpio_irq, pin, test_gpio_irq_handler, 123)); + gpio_irq_free(&gpio_irq); +} + +Case cases[] = { + Case("init/free", all_ports), + Case("rising & falling edge", all_ports), +}; + +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); +} + +#endif /* !DEVICE_INTERRUPTIN */ diff --git a/hal/tests/TESTS/mbed_hal_fpga_ci_test_shield/i2c/i2c_fpga_test.h b/hal/tests/TESTS/mbed_hal_fpga_ci_test_shield/i2c/i2c_fpga_test.h new file mode 100644 index 0000000..9734eb4 --- /dev/null +++ b/hal/tests/TESTS/mbed_hal_fpga_ci_test_shield/i2c/i2c_fpga_test.h @@ -0,0 +1,86 @@ +/* mbed Microcontroller Library + * Copyright (c) 2019 ARM Limited + * 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. + */ + +/** \addtogroup hal_GeneralI2C_tests */ +/** @{*/ + +#ifndef MBED_FPGA_I2C_TEST_H +#define MBED_FPGA_I2C_TEST_H + +#if DEVICE_I2C + +#ifdef __cplusplus +extern "C" { +#endif + +/** Test that the i2c-master can be initialized/de-initialized using all possible + * i2c pins. + * + * Given board provides i2c-master support. + * When i2c-master is initialized (and then de-initialized) using valid set of i2c pins. + * Then the operation is successfull. + * + */ +void fpga_test_i2c_init_free(PinName sda, PinName scl); + +/** Test that I2C master is able to read data from I2C bus using i2c_byte_read. + * + * Given board provides I2C master support. + * When I2C master reads data from I2C bus using i2c_byte_read. + * Then data is successfully read. + * + */ +void fpga_i2c_test_byte_read(PinName sda, PinName scl); + +/** Test that I2C master is able to write data to I2C bus using i2c_byte_write. + * + * Given board provides I2C master support. + * When I2C master writes data to the I2C bus using i2c_byte_write. + * Then data is successfully transmitted. + * + */ +void fpga_i2c_test_byte_write(PinName sda, PinName scl); + +/** Test that I2C master is able to read data from I2C bus using i2c_read. + * + * Given board provides I2C master support. + * When I2C master reads data from I2C bus using i2c_read. + * Then data is successfully read. + * + */ +void fpga_i2c_test_read(PinName sda, PinName scl); + +/** Test that I2C master is able to write data to I2C bus using i2c_write. + * + * Given board provides I2C master support. + * When I2C master writes data to the I2C bus using i2c_write. + * Then data is successfully transmitted. + * + */ +void fpga_i2c_test_write(PinName sda, PinName scl); + +/**@}*/ + +#ifdef __cplusplus +} +#endif + +#endif + +#endif + +/**@}*/ diff --git a/hal/tests/TESTS/mbed_hal_fpga_ci_test_shield/i2c/main.cpp b/hal/tests/TESTS/mbed_hal_fpga_ci_test_shield/i2c/main.cpp new file mode 100644 index 0000000..62030ec --- /dev/null +++ b/hal/tests/TESTS/mbed_hal_fpga_ci_test_shield/i2c/main.cpp @@ -0,0 +1,471 @@ +/* + * Copyright (c) 2019, Arm Limited and affiliates. + * 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. + */ + +#if !DEVICE_I2C +#error [NOT_SUPPORTED] I2C not supported for this target +#elif !COMPONENT_FPGA_CI_TEST_SHIELD +#error [NOT_SUPPORTED] FPGA CI Test Shield is needed to run this test +#elif !defined(TARGET_FF_ARDUINO) && !defined(MBED_CONF_TARGET_DEFAULT_FORM_FACTOR) +#error [NOT_SUPPORTED] Test not supported for this form factor +#else + +#include "utest/utest.h" +#include "unity/unity.h" +#include "greentea-client/test_env.h" +#include "mbed.h" +#include "i2c_api.h" +#include "pinmap.h" +#include "hal/static_pinmap.h" +#include "test_utils.h" +#include "I2CTester.h" +#include "i2c_fpga_test.h" + +using namespace utest::v1; + +#define NACK 0 +#define ACK 1 +#define TIMEOUT 2 +#define I2C_DEV_ADDR 0x98//default i2c slave address on FPGA is 0x98 until modified +const int TRANSFER_COUNT = 300; + +I2CTester tester(DefaultFormFactor::pins(), DefaultFormFactor::restricted_pins()); + +void fpga_test_i2c_init_free(PinName sda, PinName scl) +{ + i2c_t obj = {}; + memset(&obj, 0, sizeof(obj)); + i2c_init(&obj, sda, scl); + i2c_frequency(&obj, 100000); + + i2c_free(&obj); +} + +template +void fpga_i2c_test_write(PinName sda, PinName scl) +{ + // Remap pins for test + tester.reset(); + tester.pin_map_set(sda, MbedTester::LogicalPinI2CSda); + tester.pin_map_set(scl, MbedTester::LogicalPinI2CScl); + + tester.pin_set_pull(sda, MbedTester::PullUp); + tester.pin_set_pull(scl, MbedTester::PullUp); + + // Initialize mbed I2C pins + i2c_t i2c; + memset(&i2c, 0, sizeof(i2c)); + if (init_direct) { +#if STATIC_PINMAP_READY + const i2c_pinmap_t pinmap = get_i2c_pinmap(sda, scl); + i2c_init_direct(&i2c, &pinmap); +#else + //skip this test case if static pinmap is not supported + return; +#endif + } else { + i2c_init(&i2c, sda, scl); + } + i2c_frequency(&i2c, 100000); + + // Reset tester stats and select I2C + tester.peripherals_reset(); + tester.select_peripheral(I2CTester::PeripheralI2C); + + // Data out and in buffers and initialization + uint8_t data_out[TRANSFER_COUNT]; + for (int i = 0; i < TRANSFER_COUNT; i++) { + data_out[i] = i & 0xFF; + } + uint8_t data_in[TRANSFER_COUNT]; + for (int i = 0; i < TRANSFER_COUNT; i++) { + data_in[i] = 0; + } + + int num_writes; + int num_reads; + int num_acks; + int num_nacks; + int num_starts; + int num_stops; + uint32_t checksum; + int num_dev_addr_matches; + int ack_nack;//0 if NACK was received, 1 if ACK was received, 2 for timeout + + // Reset tester stats and select I2C + tester.peripherals_reset(); + tester.select_peripheral(MbedTester::PeripheralI2C); + + // Write data for I2C complete transaction + // Will write 0-(TRANSFER_COUNT-1) to FPGA, checksum must match checksum calculated in parallel on FPGA + num_dev_addr_matches = 0; + num_writes = 0; + num_reads = 0; + num_starts = 0; + num_stops = 0; + num_acks = 0; + num_nacks = 0; + checksum = 0; + + num_writes = i2c_write(&i2c, I2C_DEV_ADDR, (char *)data_out, TRANSFER_COUNT, true); //transaction ends with a stop condition + num_acks = num_writes + 1; + num_starts += 1; + num_stops += 1; + num_dev_addr_matches += 1; + + for (int i = 0; i < TRANSFER_COUNT; i++) { + checksum += data_out[i]; + } + + // Verify that the transfer was successful + TEST_ASSERT_EQUAL(num_dev_addr_matches, tester.num_dev_addr_matches()); + TEST_ASSERT_EQUAL(TRANSFER_COUNT, num_writes); + TEST_ASSERT_EQUAL(num_writes + 1, tester.transfer_count()); + TEST_ASSERT_EQUAL(num_starts, tester.num_starts()); + TEST_ASSERT_EQUAL(num_stops, tester.num_stops()); + TEST_ASSERT_EQUAL(num_acks, tester.num_acks()); + TEST_ASSERT_EQUAL(num_nacks, tester.num_nacks()); + TEST_ASSERT_EQUAL(checksum, tester.get_receive_checksum()); + TEST_ASSERT_EQUAL(0, tester.state_num()); + TEST_ASSERT_EQUAL(data_out[TRANSFER_COUNT - 4], tester.get_prev_to_slave_4()); + TEST_ASSERT_EQUAL(data_out[TRANSFER_COUNT - 3], tester.get_prev_to_slave_3()); + TEST_ASSERT_EQUAL(data_out[TRANSFER_COUNT - 2], tester.get_prev_to_slave_2()); + TEST_ASSERT_EQUAL(data_out[TRANSFER_COUNT - 1], tester.get_prev_to_slave_1()); + TEST_ASSERT_EQUAL(num_writes, tester.num_writes()); + TEST_ASSERT_EQUAL(num_reads, tester.num_reads()); + + tester.reset(); + tester.pin_set_pull(sda, MbedTester::PullNone); + tester.pin_set_pull(scl, MbedTester::PullNone); + i2c_free(&i2c); +} + +template +void fpga_i2c_test_read(PinName sda, PinName scl) +{ + // Remap pins for test + tester.reset(); + tester.pin_map_set(sda, MbedTester::LogicalPinI2CSda); + tester.pin_map_set(scl, MbedTester::LogicalPinI2CScl); + + tester.pin_set_pull(sda, MbedTester::PullUp); + tester.pin_set_pull(scl, MbedTester::PullUp); + + // Initialize mbed I2C pins + i2c_t i2c; + memset(&i2c, 0, sizeof(i2c)); + if (init_direct) { + const i2c_pinmap_t pinmap = get_i2c_pinmap(sda, scl); + i2c_init_direct(&i2c, &pinmap); + } else { + i2c_init(&i2c, sda, scl); + } + i2c_frequency(&i2c, 100000); + + // Reset tester stats and select I2C + tester.peripherals_reset(); + tester.select_peripheral(I2CTester::PeripheralI2C); + + // Data out and in buffers and initialization + uint8_t data_out[TRANSFER_COUNT]; + for (int i = 0; i < TRANSFER_COUNT; i++) { + data_out[i] = i & 0xFF; + } + uint8_t data_in[TRANSFER_COUNT]; + for (int i = 0; i < TRANSFER_COUNT; i++) { + data_in[i] = 0; + } + + int num_writes; + int num_reads; + int num_acks; + int num_nacks; + int num_starts; + int num_stops; + uint32_t checksum; + int num_dev_addr_matches; + int ack_nack;//0 if NACK was received, 1 if ACK was received, 2 for timeout + + // Reset tester stats and select I2C + tester.peripherals_reset(); + tester.select_peripheral(MbedTester::PeripheralI2C); + + // Read data for I2C complete transaction + // Will read bytes, checksum must match checksum calculated in parallel on FPGA + num_dev_addr_matches = 0; + num_writes = 0; + num_reads = 0; + num_starts = 0; + num_stops = 0; + num_acks = 0; + num_nacks = 0; + checksum = 0; + + num_reads = i2c_read(&i2c, (I2C_DEV_ADDR | 1), (char *)data_in, TRANSFER_COUNT, true); //transaction ends with a stop condition + num_starts += 1; + num_stops += 1; + num_acks += 1; + num_acks += TRANSFER_COUNT - 1; + num_nacks += 1; + num_dev_addr_matches += 1; + + for (int i = 0; i < TRANSFER_COUNT; i++) { + checksum += data_in[i]; + } + + // Verify that the transfer was successful + TEST_ASSERT_EQUAL(num_dev_addr_matches, tester.num_dev_addr_matches()); + TEST_ASSERT_EQUAL(TRANSFER_COUNT, num_reads); + TEST_ASSERT_EQUAL(num_reads + 1, tester.transfer_count()); + TEST_ASSERT_EQUAL(num_starts, tester.num_starts()); + TEST_ASSERT_EQUAL(num_stops, tester.num_stops()); + TEST_ASSERT_EQUAL(num_acks, tester.num_acks()); + TEST_ASSERT_EQUAL(num_nacks, tester.num_nacks()); + TEST_ASSERT_EQUAL(checksum, tester.get_send_checksum()); + TEST_ASSERT_EQUAL(0, tester.state_num()); + TEST_ASSERT_EQUAL(((TRANSFER_COUNT + 1) & 0xFF), tester.get_next_from_slave()); + TEST_ASSERT_EQUAL(num_writes, tester.num_writes()); + TEST_ASSERT_EQUAL(num_reads, tester.num_reads()); + + tester.reset(); + tester.pin_set_pull(sda, MbedTester::PullNone); + tester.pin_set_pull(scl, MbedTester::PullNone); + i2c_free(&i2c); +} + +void fpga_i2c_test_byte_write(PinName sda, PinName scl) +{ + // Remap pins for test + tester.reset(); + tester.pin_map_set(sda, MbedTester::LogicalPinI2CSda); + tester.pin_map_set(scl, MbedTester::LogicalPinI2CScl); + + tester.pin_set_pull(sda, MbedTester::PullUp); + tester.pin_set_pull(scl, MbedTester::PullUp); + + // Initialize mbed I2C pins + i2c_t i2c; + memset(&i2c, 0, sizeof(i2c)); + i2c_init(&i2c, sda, scl); + i2c_frequency(&i2c, 100000); + + // Reset tester stats and select I2C + tester.peripherals_reset(); + tester.select_peripheral(I2CTester::PeripheralI2C); + + // Data out and in buffers and initialization + uint8_t data_out[TRANSFER_COUNT]; + for (int i = 0; i < TRANSFER_COUNT; i++) { + data_out[i] = i & 0xFF; + } + uint8_t data_in[TRANSFER_COUNT]; + for (int i = 0; i < TRANSFER_COUNT; i++) { + data_in[i] = 0; + } + + int num_writes; + int num_reads; + int num_acks; + int num_nacks; + int num_starts; + int num_stops; + uint32_t checksum; + int num_dev_addr_matches; + int ack_nack;//0 if NACK was received, 1 if ACK was received, 2 for timeout + + // Reset tester stats and select I2C + tester.peripherals_reset(); + tester.select_peripheral(MbedTester::PeripheralI2C); + + // Write data for I2C single byte transfers + // Will write 0-(TRANSFER_COUNT-1) to FPGA, checksum must match checksum calculated in parallel on FPGA + num_dev_addr_matches = 0; + num_writes = 0; + num_reads = 0; + num_starts = 0; + num_stops = 0; + num_acks = 0; + num_nacks = 0; + checksum = 0; + + i2c_start(&i2c);//start condition + num_starts += 1; + i2c_byte_write(&i2c, I2C_DEV_ADDR);//send device address + num_dev_addr_matches += 1; + num_acks += 1; + for (int i = 0; i < TRANSFER_COUNT; i++) { + ack_nack = i2c_byte_write(&i2c, data_out[i]);//send data + if (ack_nack == ACK) { + num_acks += 1; + } else if (ack_nack == NACK) { + num_nacks += 1; + } else { + printf("Timeout error\n\r"); + } + checksum += data_out[i]; + num_writes += 1; + } + i2c_stop(&i2c); + num_stops += 1; + + // Verify that the transfer was successful + TEST_ASSERT_EQUAL(num_dev_addr_matches, tester.num_dev_addr_matches()); + TEST_ASSERT_EQUAL(TRANSFER_COUNT, num_writes); + TEST_ASSERT_EQUAL(num_writes + 1, tester.transfer_count()); + TEST_ASSERT_EQUAL(num_starts, tester.num_starts()); + TEST_ASSERT_EQUAL(num_stops, tester.num_stops()); + TEST_ASSERT_EQUAL(num_acks, tester.num_acks()); + TEST_ASSERT_EQUAL(num_nacks, tester.num_nacks()); + TEST_ASSERT_EQUAL(checksum, tester.get_receive_checksum()); + TEST_ASSERT_EQUAL(0, tester.state_num()); + TEST_ASSERT_EQUAL(data_out[TRANSFER_COUNT - 4], tester.get_prev_to_slave_4()); + TEST_ASSERT_EQUAL(data_out[TRANSFER_COUNT - 3], tester.get_prev_to_slave_3()); + TEST_ASSERT_EQUAL(data_out[TRANSFER_COUNT - 2], tester.get_prev_to_slave_2()); + TEST_ASSERT_EQUAL(data_out[TRANSFER_COUNT - 1], tester.get_prev_to_slave_1()); + TEST_ASSERT_EQUAL(num_writes, tester.num_writes()); + TEST_ASSERT_EQUAL(num_reads, tester.num_reads()); + + tester.reset(); + tester.pin_set_pull(sda, MbedTester::PullNone); + tester.pin_set_pull(scl, MbedTester::PullNone); + i2c_free(&i2c); +} + +void fpga_i2c_test_byte_read(PinName sda, PinName scl) +{ + // Remap pins for test + tester.reset(); + tester.pin_map_set(sda, MbedTester::LogicalPinI2CSda); + tester.pin_map_set(scl, MbedTester::LogicalPinI2CScl); + + tester.pin_set_pull(sda, MbedTester::PullUp); + tester.pin_set_pull(scl, MbedTester::PullUp); + + // Initialize mbed I2C pins + i2c_t i2c; + memset(&i2c, 0, sizeof(i2c)); + i2c_init(&i2c, sda, scl); + i2c_frequency(&i2c, 100000); + + // Reset tester stats and select I2C + tester.peripherals_reset(); + tester.select_peripheral(I2CTester::PeripheralI2C); + + // Data out and in buffers and initialization + uint8_t data_out[TRANSFER_COUNT]; + for (int i = 0; i < TRANSFER_COUNT; i++) { + data_out[i] = i & 0xFF; + } + uint8_t data_in[TRANSFER_COUNT]; + for (int i = 0; i < TRANSFER_COUNT; i++) { + data_in[i] = 0; + } + + int num_writes; + int num_reads; + int num_acks; + int num_nacks; + int num_starts; + int num_stops; + uint32_t checksum; + int num_dev_addr_matches; + int ack_nack;//0 if NACK was received, 1 if ACK was received, 2 for timeout + + // Reset tester stats and select I2C + tester.peripherals_reset(); + tester.select_peripheral(MbedTester::PeripheralI2C); + tester.set_next_from_slave(0); + for (int i = 0; i < TRANSFER_COUNT; i++) { + data_in[i] = 0; + } + + // Read data for I2C single byte transfers + // Will read bytes, checksum must match checksum calculated in parallel on FPGA + num_dev_addr_matches = 0; + num_writes = 0; + num_reads = 0; + num_starts = 0; + num_stops = 0; + num_acks = 0; + num_nacks = 0; + checksum = 0; + + i2c_start(&i2c);//start condition + num_starts += 1; + i2c_byte_write(&i2c, (I2C_DEV_ADDR | 1));//send device address for reading + num_dev_addr_matches += 1; + num_acks += 1; + for (int i = 0; i < TRANSFER_COUNT; i++) { + if (num_reads == (TRANSFER_COUNT - 1)) { + data_in[i] = i2c_byte_read(&i2c, 1);//send NACK + checksum += data_in[i]; + num_reads += 1; + num_nacks += 1; + } else { + data_in[i] = i2c_byte_read(&i2c, 0);//send ACK + checksum += data_in[i]; + num_reads += 1; + num_acks += 1; + } + } + + i2c_stop(&i2c); + num_stops += 1; + + // Verify that the transfer was successful + TEST_ASSERT_EQUAL(num_dev_addr_matches, tester.num_dev_addr_matches()); + TEST_ASSERT_EQUAL(TRANSFER_COUNT, num_reads); + TEST_ASSERT_EQUAL(num_reads + 1, tester.transfer_count()); + TEST_ASSERT_EQUAL(num_starts, tester.num_starts()); + TEST_ASSERT_EQUAL(num_stops, tester.num_stops()); + TEST_ASSERT_EQUAL(num_acks, tester.num_acks()); + TEST_ASSERT_EQUAL(num_nacks, tester.num_nacks()); + TEST_ASSERT_EQUAL(checksum, tester.get_send_checksum()); + TEST_ASSERT_EQUAL(0, tester.state_num()); + TEST_ASSERT_EQUAL(((TRANSFER_COUNT) & 0xFF), tester.get_next_from_slave()); + TEST_ASSERT_EQUAL(num_writes, tester.num_writes()); + TEST_ASSERT_EQUAL(num_reads, tester.num_reads()); + + tester.reset(); + tester.pin_set_pull(sda, MbedTester::PullNone); + tester.pin_set_pull(scl, MbedTester::PullNone); + i2c_free(&i2c); +} + +Case cases[] = { + Case("i2c - init/free test all pins", all_ports), + Case("i2c - test write i2c API", all_peripherals>), + Case("i2c (direct init) - test write i2c API", all_peripherals>), + Case("i2c - test read i2c API", all_peripherals>), + Case("i2c (direct init) - test read i2c API", all_peripherals>), + Case("i2c - test single byte write i2c API", all_peripherals), + Case("i2c - test single byte read i2c API", all_peripherals) +}; + +utest::v1::status_t greentea_test_setup(const size_t number_of_cases) +{ + GREENTEA_SETUP(30, "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); +} + +#endif /* !DEVICE_I2C */ diff --git a/hal/tests/TESTS/mbed_hal_fpga_ci_test_shield/pwm/main.cpp b/hal/tests/TESTS/mbed_hal_fpga_ci_test_shield/pwm/main.cpp new file mode 100644 index 0000000..7124fce --- /dev/null +++ b/hal/tests/TESTS/mbed_hal_fpga_ci_test_shield/pwm/main.cpp @@ -0,0 +1,239 @@ +/* + * Copyright (c) 2019, Arm Limited and affiliates. + * 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. + */ + +#if !DEVICE_PWMOUT +#error [NOT_SUPPORTED] PWM not supported for this target +#elif !COMPONENT_FPGA_CI_TEST_SHIELD +#error [NOT_SUPPORTED] FPGA CI Test Shield is needed to run this test +#elif !defined(TARGET_FF_ARDUINO) && !defined(MBED_CONF_TARGET_DEFAULT_FORM_FACTOR) +#error [NOT_SUPPORTED] Test not supported for this form factor +#else + +#include "utest/utest.h" +#include "unity/unity.h" +#include "greentea-client/test_env.h" +#include "mbed.h" +#include "MbedTester.h" +#include "pinmap.h" +#include "hal/static_pinmap.h" +#include "test_utils.h" +#include "pwm_fpga_test.h" + +using namespace utest::v1; + +#define pwm_debug_printf(...) + +typedef enum { + PERIOD_WRITE, + PERIOD_MS_WRITE, + PERIOD_US_WRITE, + PERIOD_PULSEWIDTH, + PERIOD_PULSEWIDTH_MS, + PERIOD_PULSEWIDTH_US +} pwm_api_test_t; + +#define NUM_OF_PERIODS 10 +#define US_PER_SEC 1000000 +#define US_PER_MS 1000 +#define MS_PER_SEC 1000 + +#define DELTA_FACTOR 20 // 5% delta + +#define PERIOD_US(PERIOD_MS) (((PERIOD_MS) * US_PER_MS)) +#define PERIOD_FLOAT(PERIOD_MS) (((float)(PERIOD_MS) / US_PER_MS)) +#define FILL_FLOAT(PRC) ((float)(PRC) / 100) +#define PULSE_HIGH_US(PERIOD_US, PRC) ((uint32_t)((PERIOD_US) * FILL_FLOAT(PRC))) +#define PULSE_LOW_US(PERIOD_US, PRC) ((uint32_t)((PERIOD_US) * (1.0f - FILL_FLOAT(PRC)))) + + +MbedTester tester(DefaultFormFactor::pins(), DefaultFormFactor::restricted_pins()); + + +void fpga_pwm_init_free(PinName pin) +{ + pwmout_t pwm_out; + + pwm_debug_printf("PWM init/free test on pin=%s (%i)\r\n", pinmap_ff_default_pin_to_string(pin), pin); + + pwmout_init(&pwm_out, pin); + pwmout_free(&pwm_out); +} + + +void fpga_pwm_period_fill_test(PinName pin, uint32_t period_ms, uint32_t fill_prc, pwm_api_test_t api_test, bool init_direct) +{ + pwm_debug_printf("PWM test on pin = %s (%i)\r\n", pinmap_ff_default_pin_to_string(pin), pin); + pwm_debug_printf("Testing period = %lu ms, duty-cycle = %lu %%\r\n", period_ms, fill_prc); + pwm_debug_printf("Testing APIs = %d\r\n", (int)api_test); + + tester.reset(); + MbedTester::LogicalPin logical_pin = (MbedTester::LogicalPin)(MbedTester::LogicalPinIOMetrics0); + tester.pin_map_set(pin, logical_pin); + + pwmout_t pwm_out; + + if (init_direct) { + const PinMap pinmap = get_pwm_pinmap(pin); + pwmout_init_direct(&pwm_out, &pinmap); + } else { + pwmout_init(&pwm_out, pin); + } + + core_util_critical_section_enter(); + + switch (api_test) { + case PERIOD_WRITE: + pwmout_period(&pwm_out, PERIOD_FLOAT(period_ms)); + pwmout_write(&pwm_out, FILL_FLOAT(fill_prc)); + break; + + case PERIOD_MS_WRITE: + pwmout_period_ms(&pwm_out, (int)period_ms); + pwmout_write(&pwm_out, FILL_FLOAT(fill_prc)); + break; + + case PERIOD_US_WRITE: + pwmout_period_us(&pwm_out, PERIOD_US(period_ms)); + pwmout_write(&pwm_out, FILL_FLOAT(fill_prc)); + break; + + case PERIOD_PULSEWIDTH: + pwmout_period(&pwm_out, PERIOD_FLOAT(period_ms)); + pwmout_pulsewidth(&pwm_out, (float)PULSE_HIGH_US(PERIOD_US(period_ms), fill_prc) / US_PER_SEC); + break; + + case PERIOD_PULSEWIDTH_MS: + pwmout_period(&pwm_out, PERIOD_FLOAT(period_ms)); + pwmout_pulsewidth_ms(&pwm_out, (int)PULSE_HIGH_US(PERIOD_US(period_ms), fill_prc) / MS_PER_SEC); + break; + + case PERIOD_PULSEWIDTH_US: + pwmout_period(&pwm_out, PERIOD_FLOAT(period_ms)); + pwmout_pulsewidth_us(&pwm_out, (int)PULSE_HIGH_US(PERIOD_US(period_ms), fill_prc)); + break; + } + + // wait_us is safe to call as this test disable the IRQs on execution. + wait_us(PERIOD_US(period_ms)); + + tester.io_metrics_start(); + + wait_us(NUM_OF_PERIODS * PERIOD_US(period_ms)); + + tester.io_metrics_stop(); + core_util_critical_section_exit(); + + const uint32_t expected_low_pulse_us = PULSE_LOW_US(PERIOD_US(period_ms), fill_prc); + const uint32_t expected_high_pulse_us = PULSE_HIGH_US(PERIOD_US(period_ms), fill_prc); + const uint32_t delta_low_pulse = (expected_low_pulse_us / DELTA_FACTOR); + const uint32_t delta_high_pulse = (expected_high_pulse_us / DELTA_FACTOR); + + pwm_debug_printf("Minimum pulse low %lu us\r\n", tester.io_metrics_min_pulse_low(logical_pin) / 100); + pwm_debug_printf("Minimum pulse high %lu us\r\n", tester.io_metrics_min_pulse_high(logical_pin) / 100); + pwm_debug_printf("Maximum pulse low %lu us\r\n", tester.io_metrics_max_pulse_low(logical_pin) / 100); + pwm_debug_printf("Maximum pulse high %lu us\r\n", tester.io_metrics_max_pulse_high(logical_pin) / 100); + pwm_debug_printf("Rising edges %lu\r\n", tester.io_metrics_rising_edges(logical_pin)); + pwm_debug_printf("Falling edges %lu\r\n", tester.io_metrics_falling_edges(logical_pin)); + + TEST_ASSERT_FLOAT_WITHIN(FILL_FLOAT(fill_prc) / DELTA_FACTOR, FILL_FLOAT(fill_prc), pwmout_read(&pwm_out)); + + TEST_ASSERT_UINT32_WITHIN(delta_low_pulse, expected_low_pulse_us, tester.io_metrics_min_pulse_low(logical_pin) / 100); + TEST_ASSERT_UINT32_WITHIN(delta_low_pulse, expected_low_pulse_us, tester.io_metrics_max_pulse_low(logical_pin) / 100); + TEST_ASSERT_UINT32_WITHIN(delta_high_pulse, expected_high_pulse_us, tester.io_metrics_min_pulse_high(logical_pin) / 100); + TEST_ASSERT_UINT32_WITHIN(delta_high_pulse, expected_high_pulse_us, tester.io_metrics_max_pulse_high(logical_pin) / 100); + + TEST_ASSERT_UINT32_WITHIN(1, NUM_OF_PERIODS, tester.io_metrics_rising_edges(logical_pin)); + TEST_ASSERT_UINT32_WITHIN(1, NUM_OF_PERIODS, tester.io_metrics_falling_edges(logical_pin)); + + pwmout_free(&pwm_out); +} + +template +void fpga_pwm_period_fill_test(PinName pin) +{ + fpga_pwm_period_fill_test(pin, period_ms, fill_prc, api_test, init_direct); +} + + +Case cases[] = { + // This will be run for all pins + Case("PWM - init/free test", all_ports), + + // This will be run for single pin + Case("PWM - period: 10 ms, fill: 10%, api: period/write", one_peripheral >), + Case("PWM (direct init) - period: 10 ms, fill: 10%, api: period/write", one_peripheral >), + + Case("PWM - period: 10 ms, fill: 10%, api: period_ms/write", one_peripheral >), + Case("PWM - period: 10 ms, fill: 10%, api: period_us/write", one_peripheral >), + Case("PWM - period: 10 ms, fill: 10%, api: period/pulse_width", one_peripheral >), + Case("PWM - period: 10 ms, fill: 10%, api: period/pulse_width_ms", one_peripheral >), + Case("PWM - period: 10 ms, fill: 10%, api: period/pulse_width_us", one_peripheral >), + + Case("PWM - period: 10 ms, fill: 50%, api: period/write", one_peripheral >), + Case("PWM - period: 10 ms, fill: 50%, api: period_ms/write", one_peripheral >), + Case("PWM - period: 10 ms, fill: 50%, api: period_us/write", one_peripheral >), + Case("PWM - period: 10 ms, fill: 50%, api: period/pulse_width", one_peripheral >), + Case("PWM - period: 10 ms, fill: 50%, api: period/pulse_width_ms", one_peripheral >), + Case("PWM - period: 10 ms, fill: 50%, api: period/pulse_width_us", one_peripheral >), + + Case("PWM - period: 10 ms, fill: 90%, api: period/write", one_peripheral >), + Case("PWM - period: 10 ms, fill: 90%, api: period_ms/write", one_peripheral >), + Case("PWM - period: 10 ms, fill: 90%, api: period_us/write", one_peripheral >), + Case("PWM - period: 10 ms, fill: 90%, api: period/pulse_width", one_peripheral >), + Case("PWM - period: 10 ms, fill: 90%, api: period/pulse_width_ms", one_peripheral >), + Case("PWM - period: 10 ms, fill: 90%, api: period/pulse_width_us", one_peripheral >), + + Case("PWM - period: 30 ms, fill: 10%, api: period/write", one_peripheral >), + Case("PWM - period: 30 ms, fill: 10%, api: period_ms/write", one_peripheral >), + Case("PWM - period: 30 ms, fill: 10%, api: period_us/write", one_peripheral >), + Case("PWM - period: 30 ms, fill: 10%, api: period/pulse_width", one_peripheral >), + Case("PWM - period: 30 ms, fill: 10%, api: period/pulse_width_ms", one_peripheral >), + Case("PWM - period: 30 ms, fill: 10%, api: period/pulse_width_us", one_peripheral >), + + Case("PWM - period: 30 ms, fill: 50%, api: period/write", one_peripheral >), + Case("PWM - period: 30 ms, fill: 50%, api: period_ms/write", one_peripheral >), + Case("PWM - period: 30 ms, fill: 50%, api: period_us/write", one_peripheral >), + Case("PWM - period: 30 ms, fill: 50%, api: period/pulse_width", one_peripheral >), + Case("PWM - period: 30 ms, fill: 50%, api: period/pulse_width_ms", one_peripheral >), + Case("PWM - period: 30 ms, fill: 50%, api: period/pulse_width_us", one_peripheral >), + + Case("PWM - period: 30 ms, fill: 90%, api: period/write", one_peripheral >), + Case("PWM - period: 30 ms, fill: 90%, api: period_ms/write", one_peripheral >), + Case("PWM - period: 30 ms, fill: 90%, api: period_us/write", one_peripheral >), + Case("PWM - period: 30 ms, fill: 90%, api: period/pulse_width", one_peripheral >), + Case("PWM - period: 30 ms, fill: 90%, api: period/pulse_width_ms", one_peripheral >), + Case("PWM - period: 30 ms, fill: 90%, api: period/pulse_width_us", one_peripheral >) +}; + +utest::v1::status_t greentea_test_setup(const size_t number_of_cases) +{ +#ifdef FPGA_FORCE_ALL_PORTS + GREENTEA_SETUP(300, "default_auto"); +#else + GREENTEA_SETUP(120, "default_auto"); +#endif + return greentea_test_setup_handler(number_of_cases); +} + +Specification specification(greentea_test_setup, cases, greentea_test_teardown_handler); + +int main() +{ + Harness::run(specification); +} + +#endif /* !DEVICE_PWMOUT */ diff --git a/hal/tests/TESTS/mbed_hal_fpga_ci_test_shield/pwm/pwm_fpga_test.h b/hal/tests/TESTS/mbed_hal_fpga_ci_test_shield/pwm/pwm_fpga_test.h new file mode 100644 index 0000000..26b5708 --- /dev/null +++ b/hal/tests/TESTS/mbed_hal_fpga_ci_test_shield/pwm/pwm_fpga_test.h @@ -0,0 +1,61 @@ +/* mbed Microcontroller Library + * Copyright (c) 2019 ARM Limited + * 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. + */ + +/** \addtogroup hal_pwmout_tests */ +/** @{*/ + +#ifndef MBED_FPGA_PWM_TEST_H +#define MBED_FPGA_PWM_TEST_H + +#if DEVICE_PWM + +#ifdef __cplusplus +extern "C" { +#endif + +/** Test that the PWM can be initialized/de-initialized using all possible + * PWM pins. + * + * Given board provides PWM support. + * When PWM is initialized (and then de-initialized) using valid PWM pin. + * Then the operation is successfull. + * + */ +void fpga_pwm_init_free(PinName pin); + +/** Test that pwmout_period, pwmout_period_ms, pwmout_period_us functions sets the + * PWM period correctly and pwmout_write, pwmout_pulsewidth, pwmout_pulsewidth_ms, + * pwmout_pulsewidth_us functions sets the pulse width correctly. + * + * Given board provides PWM support. + * When PWM period/width is set using pwmout_period, pwmout_period_ms, pwmout_period_us/pwmout_write, pwmout_pulsewidth, pwmout_pulsewidth_ms, pwmout_pulsewidth_us + * Then the valid PWM puswidth and period is on output. + * + */ +void fpga_pwm_period_fill_test(PinName pin); + +/**@}*/ + +#ifdef __cplusplus +} +#endif + +#endif + +#endif + +/**@}*/ diff --git a/hal/tests/TESTS/mbed_hal_fpga_ci_test_shield/spi/main.cpp b/hal/tests/TESTS/mbed_hal_fpga_ci_test_shield/spi/main.cpp new file mode 100644 index 0000000..f933b25 --- /dev/null +++ b/hal/tests/TESTS/mbed_hal_fpga_ci_test_shield/spi/main.cpp @@ -0,0 +1,436 @@ +/* + * Copyright (c) 2019, Arm Limited and affiliates. + * 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. + */ + +#if !DEVICE_SPI +#error [NOT_SUPPORTED] SPI not supported for this target +#elif !COMPONENT_FPGA_CI_TEST_SHIELD +#error [NOT_SUPPORTED] FPGA CI Test Shield is needed to run this test +#elif !defined(TARGET_FF_ARDUINO) && !defined(MBED_CONF_TARGET_DEFAULT_FORM_FACTOR) +#error [NOT_SUPPORTED] Test not supported for this form factor +#else + +#include "utest/utest.h" +#include "unity/unity.h" +#include "greentea-client/test_env.h" +#include "mbed.h" +#include "SPIMasterTester.h" +#include "pinmap.h" +#include "hal/static_pinmap.h" +#include "test_utils.h" +#include "spi_fpga_test.h" + +using namespace utest::v1; + +typedef enum { + TRANSFER_SPI_MASTER_WRITE_SYNC, + TRANSFER_SPI_MASTER_BLOCK_WRITE_SYNC, + TRANSFER_SPI_MASTER_TRANSFER_ASYNC +} transfer_type_t; + +typedef enum { + BUFFERS_COMMON, // common case rx/tx buffers are defined and have the same size + BUFFERS_TX_GT_RX, // tx buffer length is greater than rx buffer length + BUFFERS_TX_LT_RX, // tx buffer length is less than rx buffer length + BUFFERS_TX_ONE_SYM, // one symbol only is transmitted in both directions +} test_buffers_t; + +#define FREQ_200_KHZ (200000ull) +#define FREQ_500_KHZ (500000) +#define FREQ_1_MHZ (1000000) +#define FREQ_2_MHZ (2000000) +#define FREQ_10_MHZ (10000000ull) +#define FREQ_MIN ((uint32_t)0) +#define FREQ_MAX ((uint32_t)-1) +#define FILL_SYM (0xF5F5F5F5) +#define DUMMY_SYM (0xD5D5D5D5) + +#define SS_ASSERT (0) +#define SS_DEASSERT (!(SS_ASSERT)) + +#define TEST_CAPABILITY_BIT(MASK, CAP) ((1 << CAP) & (MASK)) + +const int TRANSFER_COUNT = 300; +SPIMasterTester tester(DefaultFormFactor::pins(), DefaultFormFactor::restricted_pins()); + +spi_t spi; +static volatile bool async_trasfer_done; + +#if DEVICE_SPI_ASYNCH +void spi_async_handler() +{ + int event = spi_irq_handler_asynch(&spi); + + if (event & SPI_EVENT_COMPLETE) { + async_trasfer_done = true; + } +} +#endif + +/* Function finds SS pin for manual SS handling. */ +static PinName find_ss_pin(PinName mosi, PinName miso, PinName sclk) +{ + const PinList *ff_pins_list = pinmap_ff_default_pins(); + const PinList *restricted_pins_list = pinmap_restricted_pins(); + uint32_t cs_pin_idx; + + for (cs_pin_idx = 0; cs_pin_idx < ff_pins_list->count; cs_pin_idx++) { + if (ff_pins_list->pins[cs_pin_idx] == mosi || + ff_pins_list->pins[cs_pin_idx] == miso || + ff_pins_list->pins[cs_pin_idx] == sclk) { + continue; + } + + bool restricted_pin = false; + for (uint32_t i = 0; i < restricted_pins_list->count ; i++) { + if (ff_pins_list->pins[cs_pin_idx] == restricted_pins_list->pins[i]) { + restricted_pin = true; + } + } + + if (restricted_pin) { + continue; + } else { + break; + } + } + + PinName ssel = (cs_pin_idx == ff_pins_list->count ? NC : ff_pins_list->pins[cs_pin_idx]); + + TEST_ASSERT_MESSAGE(ssel != NC, "Unable to find pin for Chip Select"); + + return ssel; +} + +/* Function handles ss line if ss is specified. */ +static void handle_ss(DigitalOut *ss, bool select) +{ + if (ss) { + if (select) { + *ss = SS_ASSERT; + } else { + *ss = SS_DEASSERT; + } + } +} + +/* Auxiliary function to check platform capabilities against test case. */ +static bool check_capabilities(const spi_capabilities_t *capabilities, SPITester::SpiMode spi_mode, uint32_t sym_size, transfer_type_t transfer_type, uint32_t frequency, test_buffers_t test_buffers) +{ + // Symbol size + if (!TEST_CAPABILITY_BIT(capabilities->word_length, (sym_size - 1))) { + utest_printf("\n skipped. "); + return false; + } + + // SPI clock mode + if (!TEST_CAPABILITY_BIT(capabilities->clk_modes, spi_mode)) { + utest_printf("\n skipped. "); + return false; + } + + // Frequency + if (frequency != FREQ_MAX && frequency != FREQ_MIN && frequency < capabilities->minimum_frequency && frequency > capabilities->maximum_frequency) { + utest_printf("\n skipped. "); + return false; + } + + // Async mode + if (transfer_type == TRANSFER_SPI_MASTER_TRANSFER_ASYNC && capabilities->async_mode == false) { + utest_printf("\n skipped. "); + return false; + } + + if ((test_buffers == BUFFERS_TX_GT_RX || test_buffers == BUFFERS_TX_LT_RX) && capabilities->tx_rx_buffers_equal_length == true) { + utest_printf("\n skipped. "); + return false; + } + + return true; +} + +void fpga_spi_test_init_free(PinName mosi, PinName miso, PinName sclk, PinName ssel) +{ + spi_init(&spi, mosi, miso, sclk, ssel); + spi_format(&spi, 8, 0, 0); + spi_frequency(&spi, 1000000); + spi_free(&spi); +} + +void fpga_spi_test_init_free_cs_nc(PinName mosi, PinName miso, PinName sclk) +{ + spi_init(&spi, mosi, miso, sclk, NC); + spi_format(&spi, 8, 0, 0); + spi_frequency(&spi, 1000000); + spi_free(&spi); +} + +void fpga_spi_test_init_free_cs_nc_miso_nc_mosi_nc(PinName mosi, PinName miso, PinName sclk) +{ + utest_printf("\nTesting: MOSI = NC. "); + + spi_init(&spi, NC, miso, sclk, NC); + spi_format(&spi, 8, 0, 0); + spi_frequency(&spi, 1000000); + spi_free(&spi); + + utest_printf("Testing: MISO = NC. "); + + spi_init(&spi, mosi, NC, sclk, NC); + spi_format(&spi, 8, 0, 0); + spi_frequency(&spi, 1000000); + spi_free(&spi); +} + + +void fpga_spi_test_common(PinName mosi, PinName miso, PinName sclk, PinName ssel, SPITester::SpiMode spi_mode, uint32_t sym_size, transfer_type_t transfer_type, uint32_t frequency, test_buffers_t test_buffers, bool auto_ss, bool init_direct) +{ + spi_capabilities_t capabilities; + uint32_t freq = frequency; + uint32_t tx_cnt = TRANSFER_COUNT; + uint32_t rx_cnt = TRANSFER_COUNT; + uint8_t fill_symbol = (uint8_t)FILL_SYM; + PinName ss_pin = (auto_ss ? ssel : NC); + DigitalOut *ss = NULL; + + spi_get_capabilities(ssel, false, &capabilities); + + if (check_capabilities(&capabilities, spi_mode, sym_size, transfer_type, frequency, test_buffers) == false) { + return; + } + + uint32_t sym_mask = ((1 << sym_size) - 1); + + switch (frequency) { + case (FREQ_MIN): + freq = capabilities.minimum_frequency; + break; + case (FREQ_MAX): + freq = capabilities.maximum_frequency; + break; + default: + break; + } + + switch (test_buffers) { + case (BUFFERS_COMMON): + // nothing to change + break; + case (BUFFERS_TX_GT_RX): + rx_cnt /= 2; + break; + case (BUFFERS_TX_LT_RX): + tx_cnt /= 2; + break; + case (BUFFERS_TX_ONE_SYM): + tx_cnt = 1; + rx_cnt = 1; + break; + + default: + break; + } + + // Remap pins for test + tester.reset(); + tester.pin_map_set(mosi, MbedTester::LogicalPinSPIMosi); + tester.pin_map_set(miso, MbedTester::LogicalPinSPIMiso); + tester.pin_map_set(sclk, MbedTester::LogicalPinSPISclk); + tester.pin_map_set(ssel, MbedTester::LogicalPinSPISsel); + + // Manually handle SS pin + if (!auto_ss) { + ss = new DigitalOut(ssel, SS_DEASSERT); + } + + if (init_direct) { + const spi_pinmap_t pinmap = get_spi_pinmap(mosi, miso, sclk, ss_pin); + spi_init_direct(&spi, &pinmap); + } else { + spi_init(&spi, mosi, miso, sclk, ss_pin); + } + + spi_format(&spi, sym_size, spi_mode, 0); + spi_frequency(&spi, freq); + + // Configure spi_slave module + tester.set_mode(spi_mode); + tester.set_bit_order(SPITester::MSBFirst); + tester.set_sym_size(sym_size); + + // Reset tester stats and select SPI + tester.peripherals_reset(); + tester.select_peripheral(SPITester::PeripheralSPI); + + uint32_t checksum = 0; + uint32_t sym_count = TRANSFER_COUNT; + int result = 0; + uint8_t tx_buf[TRANSFER_COUNT] = {0}; + uint8_t rx_buf[TRANSFER_COUNT] = {0}; + + // Send and receive test data + switch (transfer_type) { + case TRANSFER_SPI_MASTER_WRITE_SYNC: + handle_ss(ss, true); + for (int i = 0; i < TRANSFER_COUNT; i++) { + uint32_t data = spi_master_write(&spi, (0 - i) & sym_mask); + TEST_ASSERT_EQUAL(i & sym_mask, data); + checksum += (0 - i) & sym_mask; + } + handle_ss(ss, false); + break; + + case TRANSFER_SPI_MASTER_BLOCK_WRITE_SYNC: + for (int i = 0; i < TRANSFER_COUNT; i++) { + tx_buf[i] = (0 - i) & sym_mask; + rx_buf[i] = 0xFF; + + switch (test_buffers) { + case (BUFFERS_COMMON): + case (BUFFERS_TX_GT_RX): + checksum += ((0 - i) & sym_mask); + break; + case (BUFFERS_TX_LT_RX): + if (i < tx_cnt) { + checksum += ((0 - i) & sym_mask); + } else { + checksum += (fill_symbol & sym_mask); + } + break; + case (BUFFERS_TX_ONE_SYM): + tx_buf[0] = 0xAA; + checksum = 0xAA; + sym_count = 1; + break; + default: + break; + } + } + + handle_ss(ss, true); + result = spi_master_block_write(&spi, (const char *)tx_buf, tx_cnt, (char *)rx_buf, rx_cnt, 0xF5); + handle_ss(ss, false); + + for (int i = 0; i < rx_cnt; i++) { + TEST_ASSERT_EQUAL(i & sym_mask, rx_buf[i]); + } + + for (int i = rx_cnt; i < TRANSFER_COUNT; i++) { + TEST_ASSERT_EQUAL(0xFF, rx_buf[i]); + } + + TEST_ASSERT_EQUAL(sym_count, result); + break; + +#if DEVICE_SPI_ASYNCH + case TRANSFER_SPI_MASTER_TRANSFER_ASYNC: + for (int i = 0; i < TRANSFER_COUNT; i++) { + tx_buf[i] = (0 - i) & sym_mask; + checksum += (0 - i) & sym_mask; + rx_buf[i] = 0xAA; + } + + async_trasfer_done = false; + + handle_ss(ss, true); + spi_master_transfer(&spi, tx_buf, TRANSFER_COUNT, rx_buf, TRANSFER_COUNT, 8, (uint32_t)spi_async_handler, SPI_EVENT_COMPLETE, DMA_USAGE_NEVER); + + while (!async_trasfer_done); + handle_ss(ss, false); + + for (int i = 0; i < TRANSFER_COUNT; i++) { + TEST_ASSERT_EQUAL(i & sym_mask, rx_buf[i]); + } + + break; +#endif + default: + TEST_ASSERT_MESSAGE(0, "Unsupported transfer type."); + break; + + } + + // Verify that the transfer was successful + TEST_ASSERT_EQUAL(sym_count, tester.get_transfer_count()); + TEST_ASSERT_EQUAL(checksum, tester.get_receive_checksum()); + + spi_free(&spi); + tester.reset(); +} + +template +void fpga_spi_test_common(PinName mosi, PinName miso, PinName sclk, PinName ssel) +{ + fpga_spi_test_common(mosi, miso, sclk, ssel, spi_mode, sym_size, transfer_type, frequency, test_buffers, auto_ss, init_direct); +} + +template +void fpga_spi_test_common_no_ss(PinName mosi, PinName miso, PinName sclk) +{ + PinName ssel = find_ss_pin(mosi, miso, sclk); + + fpga_spi_test_common(mosi, miso, sclk, ssel, spi_mode, sym_size, transfer_type, frequency, test_buffers, auto_ss, init_direct); +} + +Case cases[] = { + // This will be run for all pins + Case("SPI - init/free test all pins", all_ports), + Case("SPI - init/free test all pins (CS == NC)", all_ports), + Case("SPI - init/free test all pins (CS == NC, MISO/MOSI == NC)", one_peripheral), + + // This will be run for all peripherals + Case("SPI - basic test", all_peripherals >), + Case("SPI - basic test (direct init)", all_peripherals >), + + // This will be run for single pin configuration + Case("SPI - mode testing (MODE_1)", one_peripheral >), + Case("SPI - mode testing (MODE_2)", one_peripheral >), + Case("SPI - mode testing (MODE_3)", one_peripheral >), + Case("SPI - symbol size testing (4)", one_peripheral >), + Case("SPI - symbol size testing (12)", one_peripheral >), + Case("SPI - symbol size testing (16)", one_peripheral >), + Case("SPI - symbol size testing (24)", one_peripheral >), + Case("SPI - symbol size testing (32)", one_peripheral >), + Case("SPI - buffers tx > rx", one_peripheral >), + Case("SPI - buffers tx < rx", one_peripheral >), + Case("SPI - frequency testing (200 kHz)", one_peripheral >), + Case("SPI - frequency testing (2 MHz)", one_peripheral >), + Case("SPI - frequency testing (capabilities min)", one_peripheral >), + Case("SPI - frequency testing (capabilities max)", one_peripheral >), + Case("SPI - block write", one_peripheral >), + Case("SPI - block write(one sym)", one_peripheral >), + Case("SPI - hardware ss handling", one_peripheral >), + Case("SPI - hardware ss handling(block)", one_peripheral >), +#if DEVICE_SPI_ASYNCH + Case("SPI - async mode (sw ss)", one_peripheral >), + Case("SPI - async mode (hw ss)", one_peripheral >) +#endif +}; + +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); +} + +#endif /* !DEVICE_SPI */ diff --git a/hal/tests/TESTS/mbed_hal_fpga_ci_test_shield/spi/spi_fpga_test.h b/hal/tests/TESTS/mbed_hal_fpga_ci_test_shield/spi/spi_fpga_test.h new file mode 100644 index 0000000..14a2306 --- /dev/null +++ b/hal/tests/TESTS/mbed_hal_fpga_ci_test_shield/spi/spi_fpga_test.h @@ -0,0 +1,68 @@ +/* mbed Microcontroller Library + * Copyright (c) 2019 ARM Limited + * 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. + */ + +/** \addtogroup hal_GeneralSPI_tests */ +/** @{*/ + +#ifndef MBED_FPGA_SPI_TEST_H +#define MBED_FPGA_SPI_TEST_H + +#if DEVICE_SPI + +#ifdef __cplusplus +extern "C" { +#endif + +/** Test that the spi-Master can be initialized/de-initialized using all possible + * SPI pins. + * + * Given board provides SPI-Master support. + * When SPI-Master is initialized (and then de-initialized) using valid set of SPI pins. + * Then the operation is successfull. + * + */ +void fpga_spi_test_init_free(PinName mosi, PinName miso, PinName sclk, PinName ssel); + +/** Test that the SPI-Master transfer can be performed in various configurations (SSEL handled by hardware). + * + * Given board provides SPI-Master support. + * When SPI transmission is performed using different settings. + * Then data is successfully transferred. + * + */ +void fpga_spi_test_common(PinName mosi, PinName miso, PinName sclk, PinName ssel); + +/** Test that the SPI-Master transfer can be performed in various configurations (SSEL handled manually). + * + * Given board provides SPI-Master support. + * When SPI transmission is performed using different settings. + * Then data is successfully transferred. + * + */ +void fpga_spi_test_common_no_ss(PinName mosi, PinName miso, PinName sclk); + +/**@}*/ + +#ifdef __cplusplus +} +#endif + +#endif + +#endif + +/**@}*/ diff --git a/hal/tests/TESTS/mbed_hal_fpga_ci_test_shield/uart/main.cpp b/hal/tests/TESTS/mbed_hal_fpga_ci_test_shield/uart/main.cpp new file mode 100644 index 0000000..4315cc8 --- /dev/null +++ b/hal/tests/TESTS/mbed_hal_fpga_ci_test_shield/uart/main.cpp @@ -0,0 +1,425 @@ +/* + * Copyright (c) 2019, Arm Limited and affiliates. + * 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. + */ + +#if !DEVICE_SERIAL +#error [NOT_SUPPORTED] SERIAL not supported for this target +#elif !COMPONENT_FPGA_CI_TEST_SHIELD +#error [NOT_SUPPORTED] FPGA CI Test Shield is needed to run this test +#elif !defined(TARGET_FF_ARDUINO) && !defined(MBED_CONF_TARGET_DEFAULT_FORM_FACTOR) +#error [NOT_SUPPORTED] Test not supported for this form factor +#else + +#include "utest/utest.h" +#include "unity/unity.h" +#include "greentea-client/test_env.h" +#include "platform/mbed_critical.h" +#include +#include "hal/serial_api.h" +#include "UARTTester.h" +#include "pinmap.h" +#include "test_utils.h" +#include "us_ticker_api.h" +#include "uart_fpga_test.h" +#include "hal/static_pinmap.h" + + +using namespace utest::v1; + +#define PUTC_REPS 16 +#define GETC_REPS 16 + +// In the UART RX test, the request for the FPGA to start sending data is sent +// first. Then the execution is blocked at serial_getc() call. Since the DUT +// is not ready to receive UART data instantly after the request, the start of +// the actual transmission has to be dalyed. +// A measured delay for NUCLEO_F070RB is 193 us. +#define TX_START_DELAY_NS 250000 + +UARTTester tester(DefaultFormFactor::pins(), DefaultFormFactor::restricted_pins()); + +typedef struct { + serial_t *ser; + int *rx_buff; + uint32_t rx_cnt; + int *tx_buff; + uint32_t tx_cnt; +} serial_test_data_t; + +static void test_irq_handler(uint32_t id, SerialIrq event) +{ + serial_test_data_t *td = (serial_test_data_t *)id; + int c = 0x01; // arbitrary, non-zero value + if (event == RxIrq) { + c = serial_getc(td->ser); + core_util_critical_section_enter(); + if (td->rx_cnt < GETC_REPS) { + td->rx_buff[td->rx_cnt] = c; + td->rx_cnt++; + } + core_util_critical_section_exit(); + } else if (event == TxIrq) { + core_util_critical_section_enter(); + if (td->tx_cnt < PUTC_REPS) { + c = td->tx_buff[td->tx_cnt]; + td->tx_cnt++; + } + core_util_critical_section_exit(); + // Send either one of tx_buff[] values or 0x01. + serial_putc(td->ser, c); + } +} + +static void uart_test_common(int baudrate, int data_bits, SerialParity parity, int stop_bits, bool init_direct, PinName tx, PinName rx, PinName cts, PinName rts) +{ + // The FPGA CI shield only supports None, Odd & Even. + // Forced parity is not supported on many targets + MBED_ASSERT(parity != ParityForced1 && parity != ParityForced0); + +// See TESTS/configs/fpga.json to check which target supports what +#if defined(UART_9BITS_NOT_SUPPORTED) + if (data_bits == 9) { + utest_printf(" UART_9BITS_NOT_SUPPORTED set ... "); + return; + } +#endif + +#if defined(UART_9BITS_PARITY_NOT_SUPPORTED) + if ((data_bits == 9) && (parity != ParityNone)) { + utest_printf(" UART_9BITS_PARITY_NOT_SUPPORTED set ... "); + return; + } +#endif + +#if defined(UART_7BITS_NOT_SUPPORTED) + if (data_bits == 7) { + utest_printf(" UART_7BITS_NOT_SUPPORTED set ... "); + return; + } +#endif + +#if defined(UART_7BITS_PARITY_NONE_NOT_SUPPORTED) + if ((data_bits == 7) && (parity == ParityNone)) { + utest_printf(" UART_7BITS_PARITY_NONE_NOT_SUPPORTED set ... "); + return; + } +#endif + + // Limit the actual TX & RX chars to 8 bits for this test. + int test_buff_bits = data_bits < 8 ? data_bits : 8; + + // start_bit + data_bits + parity_bit + stop_bits + int packet_bits = 1 + data_bits + stop_bits + (parity == ParityNone ? 0 : 1); + us_timestamp_t packet_tx_time = 1000000 * packet_bits / baudrate; + const ticker_data_t *const us_ticker = get_us_ticker_data(); + + bool use_flow_control = (cts != NC && rts != NC) ? true : false; + + // Remap pins for test + tester.reset(); + tester.pin_map_set(tx, MbedTester::LogicalPinUARTRx); + tester.pin_map_set(rx, MbedTester::LogicalPinUARTTx); + if (use_flow_control) { + tester.pin_map_set(cts, MbedTester::LogicalPinUARTRts); + tester.pin_map_set(rts, MbedTester::LogicalPinUARTCts); + } + + // Initialize mbed UART pins + serial_t serial; + if (init_direct) { + const serial_pinmap_t pinmap = get_uart_pinmap(tx, rx); + serial_init_direct(&serial, &pinmap); + } else { + serial_init(&serial, tx, rx); + } + serial_baud(&serial, baudrate); + serial_format(&serial, data_bits, parity, stop_bits); +#if DEVICE_SERIAL_FC + if (use_flow_control) { + if (init_direct) { +#if STATIC_PINMAP_READY + const serial_fc_pinmap_t pinmap = get_uart_fc_pinmap(rts, cts); + serial_set_flow_control_direct(&serial, FlowControlRTSCTS, &pinmap); +#else + //skip this test case if static pinmap is not supported + // Cleanup uart to be able execute next test case + serial_free(&serial); + tester.reset(); + return; +#endif + } else { + serial_set_flow_control(&serial, FlowControlRTSCTS, rts, cts); + } + } else { + serial_set_flow_control(&serial, FlowControlNone, NC, NC); + } +#endif + + // Reset tester stats and select UART + tester.peripherals_reset(); + tester.select_peripheral(MbedTester::PeripheralUART); + + // Configure UART module + tester.set_baud((uint32_t)baudrate); + tester.set_bits((uint8_t)data_bits); + tester.set_stops((uint8_t)stop_bits); + switch (parity) { + case ParityOdd: + tester.set_parity(true, true); + break; + case ParityEven: + tester.set_parity(true, false); + break; + case ParityNone: + default: + tester.set_parity(false, false); + break; + } + if (use_flow_control) { + tester.cts_deassert_delay(0); + } + + int rx_buff[GETC_REPS] = {}; + int tx_buff[PUTC_REPS] = {}; + volatile serial_test_data_t td = { + &serial, + rx_buff, + 0, + tx_buff, + 0 + }; + uint32_t checksum = 0; + + // DUT TX / FPGA RX + int tx_val; + tester.rx_start(); + for (uint32_t reps = 1; reps <= PUTC_REPS; reps++) { + tx_val = rand() % (1 << test_buff_bits); + checksum += tx_val; + serial_putc(&serial, tx_val); + us_timestamp_t end_ts = ticker_read_us(us_ticker) + 2 * packet_tx_time; + while (tester.rx_get_count() != reps && ticker_read_us(us_ticker) <= end_ts) { + // Wait (no longer than twice the time of one packet transfer) for + // the FPGA to receive data and update the byte counter. + } + TEST_ASSERT_EQUAL_UINT32(reps, tester.rx_get_count()); + TEST_ASSERT_EQUAL(0, tester.rx_get_parity_errors()); + TEST_ASSERT_EQUAL(0, tester.rx_get_stop_errors()); + TEST_ASSERT_EQUAL(0, tester.rx_get_framing_errors()); + TEST_ASSERT_EQUAL_UINT32(checksum, tester.rx_get_checksum()); + TEST_ASSERT_EQUAL(tx_val, tester.rx_get_data()); + } + tester.rx_stop(); + + // DUT RX / FPGA TX + // serial_getc() may return 16-bit as well as 8-bit value cast to an int. + // Use a random initial value, but make sure it is low enouth, + // so the FPGA will not overflow 8 bits when incrementing it. + uint16_t tester_buff = rand() % ((1 << test_buff_bits) - GETC_REPS); + tester.tx_set_next(tester_buff); + tester.tx_set_count(GETC_REPS); + if (!use_flow_control) { + tester.tx_set_delay(TX_START_DELAY_NS); + } + tester.tx_start(use_flow_control); + for (int i = 0; i < GETC_REPS; i++) { + rx_buff[i] = serial_getc(&serial); + } + tester.tx_stop(); + for (int i = 0; i < GETC_REPS; tester_buff++, i++) { + TEST_ASSERT_EQUAL(tester_buff, rx_buff[i]); + } + + serial_irq_handler(&serial, test_irq_handler, (uint32_t) &td); + + // DUT TX (IRQ) / FPGA RX + tx_val = rand() % ((1 << test_buff_bits) - PUTC_REPS); + for (size_t i = 0; i < PUTC_REPS; tx_val++, i++) { + td.tx_buff[i] = tx_val; + checksum += tx_val; + } + + tester.rx_start(); + core_util_critical_section_enter(); + td.tx_cnt = 0; + // Enable only the TX IRQ. + serial_irq_set(&serial, TxIrq, 1); + core_util_critical_section_exit(); + while (core_util_atomic_load_u32(&td.tx_cnt) != PUTC_REPS) { + // Wait until the last byte is written to UART TX reg. + }; + core_util_critical_section_enter(); + serial_irq_set(&serial, TxIrq, 0); + core_util_critical_section_exit(); + us_timestamp_t end_ts = ticker_read_us(us_ticker) + 2 * packet_tx_time; + while (ticker_read_us(us_ticker) <= end_ts) { + // Wait twice the time of one packet transfer for the FPGA + // to receive and process data. + }; + tester.rx_stop(); + TEST_ASSERT_EQUAL_UINT32(2 * PUTC_REPS, tester.rx_get_count()); + TEST_ASSERT_EQUAL(0, tester.rx_get_parity_errors()); + TEST_ASSERT_EQUAL(0, tester.rx_get_stop_errors()); + TEST_ASSERT_EQUAL(0, tester.rx_get_framing_errors()); + TEST_ASSERT_EQUAL_UINT32(checksum, tester.rx_get_checksum()); + TEST_ASSERT_EQUAL(tx_val - 1, tester.rx_get_data()); + + // DUT RX (IRQ) / FPGA TX + // serial_getc() may return 16-bit as well as 8-bit value cast to an int. + // Use a random initial value, but make sure it is low enouth, + // so the FPGA will not overflow 8 bits when incrementing it. + tester_buff = rand() % ((1 << test_buff_bits) - GETC_REPS); + tester.tx_set_next(tester_buff); + tester.tx_set_count(GETC_REPS); + if (!use_flow_control) { + tester.tx_set_delay(TX_START_DELAY_NS); + } + core_util_critical_section_enter(); + // Enable only the RX IRQ. + serial_irq_set(&serial, RxIrq, 1); + core_util_critical_section_exit(); + tester.rx_start(); + tester.tx_start(use_flow_control); + while (core_util_atomic_load_u32(&td.rx_cnt) != GETC_REPS) { + // Wait until the last byte is received to UART RX reg. + }; + core_util_critical_section_enter(); + serial_irq_set(&serial, RxIrq, 0); + core_util_critical_section_exit(); + tester.tx_stop(); + tester.rx_stop(); + for (int i = 0; i < GETC_REPS; tester_buff++, i++) { + TEST_ASSERT_EQUAL(tester_buff, td.rx_buff[i]); + } + + // Make sure TX IRQ was disabled during the last RX test. + TEST_ASSERT_EQUAL_UINT32(checksum, tester.rx_get_checksum()); + TEST_ASSERT_EQUAL_UINT32(2 * PUTC_REPS, tester.rx_get_count()); + + // Cleanup + serial_free(&serial); + tester.reset(); +} + +void fpga_uart_init_free_test(PinName tx, PinName rx, PinName cts, PinName rts) +{ + bool use_flow_control = (cts != NC && rts != NC) ? true : false; + serial_t serial; + serial_init(&serial, tx, rx); + serial_baud(&serial, 9600); + serial_format(&serial, 8, ParityNone, 1); +#if DEVICE_SERIAL_FC + if (use_flow_control) { + serial_set_flow_control(&serial, FlowControlRTSCTS, rts, cts); + } +#endif + serial_free(&serial); +} + +void fpga_uart_init_free_test_no_fc(PinName tx, PinName rx) +{ + fpga_uart_init_free_test(tx, rx); +} + +template +void fpga_uart_test_common(PinName tx, PinName rx, PinName cts, PinName rts) +{ + uart_test_common(BAUDRATE, DATA_BITS, PARITY, STOP_BITS, INIT_DIRECT, tx, rx, cts, rts); +} + +template +void fpga_uart_test_common_no_fc(PinName tx, PinName rx) +{ + uart_test_common(BAUDRATE, DATA_BITS, PARITY, STOP_BITS, INIT_DIRECT, tx, rx); +} + +Case cases[] = { + // Every set of pins from every peripheral. + Case("init/free, FC off", all_ports), + + // One set of pins from every peripheral. + Case("basic, 9600, 8N1, FC off", all_peripherals >), + Case("basic (direct init), 9600, 8N1, FC off", all_peripherals >), + + // same test with 7 and 9 bits data length + Case("basic, 9600, 7N1, FC off", all_peripherals >), + Case("basic, 9600, 9N1, FC off", all_peripherals >), + + // One set of pins from one peripheral. + // baudrate + Case("19200, 8N1, FC off", one_peripheral >), + Case("38400, 8N1, FC off", one_peripheral >), + Case("115200, 8N1, FC off", one_peripheral >), + // stop bits +#if !defined(UART_TWO_STOP_BITS_NOT_SUPPORTED) + Case("9600, 8N2, FC off", one_peripheral >), +#endif + +#if DEVICE_SERIAL_FC + // Every set of pins from every peripheral. + Case("init/free, FC on", all_ports), + + // One set of pins from every peripheral. + Case("basic, 9600, 8N1, FC on", all_peripherals >), + Case("basic (direct init), 9600, 8N1, FC on", all_peripherals >), + + // same test with 7 and 9 bits data length + Case("basic, 9600, 7N1, FC on", all_peripherals >), + Case("basic, 9600, 9N1, FC on", all_peripherals >), + + // One set of pins from one peripheral. + // baudrate + Case("19200, 8N1, FC on", one_peripheral >), + Case("38400, 8N1, FC on", one_peripheral >), + Case("115200, 8N1, FC on", one_peripheral >), + // data bits: not tested (some platforms support 8 bits only) + // parity +#if !defined(UART_ODD_PARITY_NOT_SUPPORTED) + Case("9600, 8O1, FC on", one_peripheral >), + + // same test with 7 and 9 bits data length + Case("9600, 7O1, FC on", one_peripheral >), + Case("9600, 9O1, FC on", one_peripheral >), +#endif + Case("9600, 8E1, FC on", one_peripheral >), + + // same test with 7 and 9 bits data length + Case("9600, 7E1, FC on", one_peripheral >), + Case("9600, 9E1, FC on", one_peripheral >), + + // stop bits +#if !defined(UART_TWO_STOP_BITS_NOT_SUPPORTED) + Case("9600, 8N2, FC on", one_peripheral >), +#endif +#endif + +}; + +utest::v1::status_t greentea_test_setup(const size_t number_of_cases) +{ + GREENTEA_SETUP(240, "default_auto"); + srand((unsigned) ticker_read_us(get_us_ticker_data())); + return greentea_test_setup_handler(number_of_cases); +} + +Specification specification(greentea_test_setup, cases, greentea_test_teardown_handler); + +int main() +{ + Harness::run(specification); +} + +#endif /* !DEVICE_SERIAL */ diff --git a/hal/tests/TESTS/mbed_hal_fpga_ci_test_shield/uart/uart_fpga_test.h b/hal/tests/TESTS/mbed_hal_fpga_ci_test_shield/uart/uart_fpga_test.h new file mode 100644 index 0000000..3c3915d --- /dev/null +++ b/hal/tests/TESTS/mbed_hal_fpga_ci_test_shield/uart/uart_fpga_test.h @@ -0,0 +1,81 @@ +/* mbed Microcontroller Library + * Copyright (c) 2019 ARM Limited + * 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. + */ + +/** \addtogroup hal_GeneralSerial_tests */ +/** @{*/ + +#ifndef MBED_FPGA_UART_TEST_H +#define MBED_FPGA_UART_TEST_H + +#if DEVICE_SERIAL + +#ifdef __cplusplus +extern "C" { +#endif + +/** Test that the uart can be initialized/de-initialized using all possible + * uart pins (flow control enabled). + * + * Given board provides uart support with flow control. + * When uart is initialized (and then de-initialized) using valid set of uart pins. + * Then the operation is successfull. + * + */ +void fpga_uart_init_free_test(PinName tx, PinName rx, PinName cts = NC, PinName rts = NC); + +/** Test that the uart can be initialized/de-initialized using all possible + * uart pins (flow control disabled). + * + * Given board provides uart support without flow control. + * When uart is initialized (and then de-initialized) using valid set of uart pins. + * Then the operation is successfull. + * + */ +void fpga_uart_init_free_test_no_fc(PinName tx, PinName rx); + +/** Test that the uart transfer can be performed in various configurations (flow control enabled). + * + * Given board provides uart support with flow control. + * When uart transmission is performed using different settings. + * Then data is successfully transfered. + * + */ +void fpga_uart_test_common(PinName tx, PinName rx, PinName cts = NC, PinName rts = NC); + +/** Test that the uart transfer can be performed in various configurations (flow control disabled). + * + * Given board provides uart support without flow control. + * When uart transmission is performed using different settings. + * Then data is successfully transfered. + * + */ +void fpga_uart_test_common_no_fc(PinName tx, PinName rx); + +/* Common test function. */ +static void uart_test_common(int baudrate, int data_bits, SerialParity parity, int stop_bits, bool init_direct, PinName tx, PinName rx, PinName cts = NC, PinName rts = NC); + +/**@}*/ + +#ifdef __cplusplus +} +#endif + +#endif + +#endif + +/**@}*/ diff --git a/hal/ticker_api.h b/hal/ticker_api.h deleted file mode 100644 index 28017fe..0000000 --- a/hal/ticker_api.h +++ /dev/null @@ -1,240 +0,0 @@ - -/** \addtogroup hal */ -/** @{*/ -/* mbed Microcontroller Library - * Copyright (c) 2015 ARM Limited - * 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. - */ -#ifndef MBED_TICKER_API_H -#define MBED_TICKER_API_H - -#include -#include -#include "device.h" - -/** - * Legacy format representing a timestamp in us. - * Given it is modeled as a 32 bit integer, this type can represent timestamp - * up to 4294 seconds (71 minutes). - * Prefer using us_timestamp_t which store timestamp as 64 bits integer. - */ -typedef uint32_t timestamp_t; - -/** - * A us timestamp stored in a 64 bit integer. - * Can store timestamp up to 584810 years. - */ -typedef uint64_t us_timestamp_t; - -/** Ticker's event structure - */ -typedef struct ticker_event_s { - us_timestamp_t timestamp; /**< Event's timestamp */ - uint32_t id; /**< TimerEvent object */ - struct ticker_event_s *next; /**< Next event in the queue */ -} ticker_event_t; - -typedef void (*ticker_event_handler)(uint32_t id); - -/** Information about the ticker implementation - */ -typedef struct { - uint32_t frequency; /**< Frequency in Hz this ticker runs at */ - uint32_t bits; /**< Number of bits this ticker supports */ -} ticker_info_t; - - -/** Ticker's interface structure - required API for a ticker - */ -typedef struct { - void (*init)(void); /**< Init function */ - uint32_t (*read)(void); /**< Read function */ - void (*disable_interrupt)(void); /**< Disable interrupt function */ - void (*clear_interrupt)(void); /**< Clear interrupt function */ - void (*set_interrupt)(timestamp_t timestamp); /**< Set interrupt function */ - void (*fire_interrupt)(void); /**< Fire interrupt right-away */ - void (*free)(void); /**< Disable function */ - const ticker_info_t *(*get_info)(void); /**< Return info about this ticker's implementation */ - bool runs_in_deep_sleep; /**< Whether ticker operates in deep sleep */ -} ticker_interface_t; - -/** Ticker's event queue structure - */ -typedef struct { - ticker_event_handler event_handler; /**< Event handler */ - ticker_event_t *head; /**< A pointer to head */ - uint32_t frequency; /**< Frequency of the timer in Hz */ - uint32_t bitmask; /**< Mask to be applied to time values read */ - uint32_t max_delta; /**< Largest delta in ticks that can be used when scheduling */ - uint64_t max_delta_us; /**< Largest delta in us that can be used when scheduling */ - uint32_t tick_last_read; /**< Last tick read */ - 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 */ - bool dispatching; /**< The function ticker_irq_handler is dispatching */ - bool suspended; /**< Indicate if the instance is suspended */ - 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 - */ -typedef struct { - const ticker_interface_t *interface; /**< Ticker's interface */ - ticker_event_queue_t *queue; /**< Ticker's event queue */ -} ticker_data_t; - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * \defgroup hal_ticker Ticker HAL functions - * @{ - */ - -/** Initialize a ticker and set the event handler - * - * @param ticker The ticker object. - * @param handler A handler to be set - */ -void ticker_set_handler(const ticker_data_t *const ticker, ticker_event_handler handler); - -/** IRQ handler that goes through the events to trigger overdue events. - * - * @param ticker The ticker object. - */ -void ticker_irq_handler(const ticker_data_t *const ticker); - -/** Remove an event from the queue - * - * @param ticker The ticker object. - * @param obj The event object to be removed from the queue - */ -void ticker_remove_event(const ticker_data_t *const ticker, ticker_event_t *obj); - -/** Insert an event to the queue - * - * The event will be executed in timestamp - ticker_read(). - * - * @warning This function does not consider timestamp in the past. If an event - * is inserted with a timestamp less than the current timestamp then the event - * will be executed in timestamp - ticker_read() us. - * The internal counter wrap very quickly it is hard to decide weither an - * event is in the past or in 1 hour. - * - * @note prefer the use of ticker_insert_event_us which allows registration of - * absolute timestamp. - * - * @param ticker The ticker object. - * @param obj The event object to be inserted to the queue - * @param timestamp The event's timestamp - * @param id The event object - */ -void ticker_insert_event(const ticker_data_t *const ticker, ticker_event_t *obj, timestamp_t timestamp, uint32_t id); - -/** Insert an event to the queue - * - * The event will be executed in timestamp - ticker_read_us() us. - * - * @note If an event is inserted with a timestamp less than the current - * timestamp then the event will be scheduled immediately resulting in - * an instant call to event handler. - * - * @param ticker The ticker object. - * @param obj The event object to be inserted to the queue - * @param timestamp The event's timestamp - * @param id The event object - */ -void ticker_insert_event_us(const ticker_data_t *const ticker, ticker_event_t *obj, us_timestamp_t timestamp, uint32_t id); - -/** Read the current (relative) ticker's timestamp - * - * @warning Return a relative timestamp because the counter wrap every 4294 - * seconds. - * - * @param ticker The ticker object. - * @return The current timestamp - */ -timestamp_t ticker_read(const ticker_data_t *const ticker); - -/** Read the current (absolute) ticker's timestamp - * - * @warning Return an absolute timestamp counting from the initialization of the - * ticker. - * - * @param ticker The ticker object. - * @return The current timestamp - */ -us_timestamp_t ticker_read_us(const ticker_data_t *const ticker); - -/** Read the next event's timestamp - * - * @param ticker The ticker object. - * @param timestamp The timestamp object. - * @return 1 if timestamp is pending event, 0 if there's no event pending - */ -int ticker_get_next_timestamp(const ticker_data_t *const ticker, timestamp_t *timestamp); - -/** Read the next event's timestamp - * - * @param ticker The ticker object. - * @param timestamp The timestamp object. - * @return 1 if timestamp is pending event, 0 if there's no event pending - */ -int ticker_get_next_timestamp_us(const ticker_data_t *const ticker, us_timestamp_t *timestamp); - -/** Suspend this ticker - * - * When suspended reads will always return the same time and no - * events will be dispatched. When suspended the common layer - * will only ever call the interface function clear_interrupt() - * and that is only if ticker_irq_handler is called. - * - * - * @param ticker The ticker object. - */ -void ticker_suspend(const ticker_data_t *const ticker); - -/** Resume this ticker - * - * When resumed the ticker will ignore any time that has passed - * and continue counting up where it left off. - * - * @param ticker The ticker object. - */ -void ticker_resume(const ticker_data_t *const ticker); - -/* Private functions - * - * @cond PRIVATE - * - */ - -int _ticker_match_interval_passed(timestamp_t prev_tick, timestamp_t cur_tick, timestamp_t match_tick); - -/* - * @endcond PRIVATE - * - */ - -/**@}*/ - -#ifdef __cplusplus -} -#endif - -#endif - -/** @}*/ diff --git a/hal/trng_api.h b/hal/trng_api.h deleted file mode 100644 index 34780d6..0000000 --- a/hal/trng_api.h +++ /dev/null @@ -1,73 +0,0 @@ - -/** \addtogroup hal */ -/** @{*/ -/* mbed Microcontroller Library - * Copyright (c) 2016 ARM Limited - * 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. - */ -#ifndef MBED_TRNG_API_H -#define MBED_TRNG_API_H - -#include -#include "device.h" - -#if defined(DEVICE_TRNG) || defined(FEATURE_PSA) - -/** TRNG HAL structure. trng_s is declared in the target's HAL - */ -typedef struct trng_s trng_t; - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * \defgroup hal_trng TRNG hal functions - * @{ - */ - -/** Initialize the TRNG peripheral - * - * @param obj The TRNG object - */ -void trng_init(trng_t *obj); - -/** Deinitialize the TRNG peripheral - * - * @param obj The TRNG object - */ -void trng_free(trng_t *obj); - -/** Get random data from TRNG peripheral - * - * @param obj The TRNG object - * @param output The pointer to an output array - * @param length The size of output data, to avoid buffer overwrite - * @param output_length The length of generated data - * @return 0 success, -1 fail - */ -int trng_get_bytes(trng_t *obj, uint8_t *output, size_t length, size_t *output_length); - -/**@}*/ - -#ifdef __cplusplus -} -#endif - -#endif - -#endif - -/** @}*/ diff --git a/hal/us_ticker_api.h b/hal/us_ticker_api.h deleted file mode 100644 index ecfa712..0000000 --- a/hal/us_ticker_api.h +++ /dev/null @@ -1,319 +0,0 @@ - -/** \addtogroup hal */ -/** @{*/ -/* mbed Microcontroller Library - * Copyright (c) 2006-2015 ARM Limited - * 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. - */ -#ifndef MBED_US_TICKER_API_H -#define MBED_US_TICKER_API_H - -#include -#include "hal/ticker_api.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * \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 for counters which are less than 32 bits wide - Verified by test ::us_ticker_info_test - * * Has a reported frequency up to 100MHz for counters which are 32 bits wide - 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 - * - * # Compile-time optimization macros - * - * To permit compile-time optimization, particularly of wait_us, the following macros should - * be defined by a target's device.h: - * - * US_TICKER_PERIOD_NUM, US_TICKER_PERIOD_DEN: These denote the ratio (numerator, denominator) - * of the ticker period to a microsecond. For example, an 8MHz ticker would have NUM = 1, DEN = 8; - * a 1MHz ticker would have NUM = 1, DEN = 1; a 250kHz ticker would have NUM = 4, DEN = 1. - * Both numerator and denominator must be 16 bits or less. - * - * US_TICKER_MASK: The value mask for the ticker - eg 0x07FFFFFF for a 27-bit ticker. - * - * If any are defined, all 3 must be defined, and the macros are checked for consistency with - * us_ticker_get_info by test ::us_ticker_info_test. - - * @{ - */ - -/** - * \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 -m -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 - * * The ticker operations ticker_init and ticker_read are atomic. - * - * # 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 -m -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 - * - * @param ticker_irq_handler IRQ handler to be connected - * - * @return previous 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 - * - */ -ticker_irq_handler_type set_us_ticker_irq_handler(ticker_irq_handler_type ticker_irq_handler); - -/** Get ticker's data - * - * @return The microsecond ticker data - */ -const ticker_data_t *get_us_ticker_data(void); - - -/** The wrapper for ticker_irq_handler, to pass us ticker's data - * - */ -void us_ticker_irq_handler(void); - -/* HAL us ticker */ - -/** 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. - * - * Pseudo Code: - * @code - * uint32_t us_ticker_free() - * { - * // Disable timer - * TIMER_CTRL &= ~TIMER_CTRL_ENABLE_Msk; - * - * // Disable the compare interrupt - * TIMER_CTRL &= ~TIMER_CTRL_COMPARE_ENABLE_Msk; - * - * // Disable timer interrupt - * NVIC_DisableIRQ(TIMER_IRQn); - * - * // Disable clock gate so processor cannot read TIMER registers - * POWER_CTRL &= ~POWER_CTRL_TIMER_Msk; - * } - * @endcode - * - */ -void us_ticker_free(void); - -/** Read the current counter - * - * 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 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); - -/**@}*/ - -#ifdef __cplusplus -} -#endif - -#endif - -/** @}*/ diff --git a/hal/usb/USBPhy.h b/hal/usb/USBPhy.h deleted file mode 100644 index c7c69bb..0000000 --- a/hal/usb/USBPhy.h +++ /dev/null @@ -1,318 +0,0 @@ -/* - * Copyright (c) 2018-2019, Arm Limited and affiliates. - * 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. - */ - -#ifndef USBPHY_H -#define USBPHY_H - -#include "USBPhyTypes.h" -#include "USBPhyEvents.h" - -/** Abstract interface to physical USB hardware - * - * # Defined behavior - * * You can use any endpoint configurations that fit in the parameters - * of the table returned by USBPhy::endpoint_table. - * * You can use all endpoints in any valid endpoint configuration concurrently. - * * The device supports use of at least one control, bulk, interrupt and - * isochronous in each direction at the same time - at least 8 endpoints. - * * USBPhy supports all standard endpoint sizes (wMaxPacketSize). - * * USBPhy can handle an interrupt latency of at least 100ms if the host PC - * is not performing a reset or setting the device's address. - * * USBPhy only sends USBPhyEvents when it is in the initialized state. - * * When unpowered, USBPhy only sends the USBPhyEvents::power event. - * * On USB reset, all endpoints are removed except for endpoint 0. - * * A call to USBPhy::ep0_write results in the call of USBPhyEvents::in when - * the PC reads the data unless a power loss, reset, or a call to - * USBPhy::disconnect occurs first. - * * A call to USBPhy::endpoint_write results in the call of USBPhyEvents::in - * when the pc reads the data unless a power loss, reset, or a call to - * USBPhy::endpoint_abort occurs first. - * * A call to USBPhy::endpoint_read results in the call of USBPhyEvents::out - * when the pc sends data unless a power loss, reset, or a call to - * USBPhy::endpoint_abort occurs first. - * * Endpoint 0 naks all transactions aside from setup packets until - * higher-level code calls one of USBPhy::ep0_read, USBPhy::ep0_write or - * USBPhy::ep0_stall. - * * Endpoint 0 stall automatically clears on reception of a setup packet. - * - * # Undefined behavior - * * Calling USBPhy::endpoint_add or USBPhy::endpoint_remove outside of the - * control requests SetInterface or SetConfiguration. - * * Calling USBPhy::endpoint_remove on an endpoint that has an ongoing read - * or write operation. To avoid undefined behavior, you must abort ongoing - * operations with USBPhy::endpoint_abort. - * * Devices behavior is undefined if latency is greater than 2ms when address - * is being set - see USB spec 9.2.6.3. - * * Devices behavior is undefined if latency is greater than 10ms when a - * reset occurs - see USB spec 7.1.7.5. - * * Calling any of the USBPhy::endpoint_* functions on endpoint 0. - * - * # Notes - * * Make sure USBPhy sends USBPhyEvents in the correct order when multiple - * packets are present. USBPhy must send IN endpoint events before OUT - * endpoint events if both are pending. - * * A host PC may resend setup packets to a USB device if there is noise on - * the USB line. The USBPhy should be able to handle this scenario and - * respond to the setup packet with an ACK. - * * Bidirectional protocols making use of alternating IN and OUT phases - * should not rely on the last ACK an IN transfer to indicate that the - * OUT phase should start. Instead, the OUT phase should be started at - * the same time the last IN transfer is started. This is because the ACK - * to the last in transfer may be dropped if there is noise on the USB - * line. If dropped, it will only be resent on the next IN phase. You can - * find more information on this in section 8.5.3.3 of the USB - * specification. - * - * @ingroup usb_device_core - */ -class USBPhy { -public: - USBPhy() {}; - virtual ~USBPhy() {}; - - /** - * Initialize this USBPhy instance - * - * This function must be called before calling - * any other functions of this class, unless specifically - * noted. - * - * @param events Callback class to handle USB events - */ - virtual void init(USBPhyEvents *events) = 0; - - /** - * Power down this USBPhy instance - * - * Disable interrupts and stop sending events. - */ - virtual void deinit() = 0; - - /** - * Check if USB power is present - * - * Devices which don't support checking the USB power state - * must always return true. - * - * @return true if USB power is present, false otherwise - */ - virtual bool powered() = 0; - - /** - * Make the USB phy visible to the USB host - * - * Enable either the D+ or D- pullup so the host can detect - * the presence of this device. - */ - virtual void connect() = 0; - - /** - * Detach the USB phy - * - * Disable the D+ and D- pullup and stop responding to - * USB traffic. - */ - virtual void disconnect() = 0; - - /** - * Set this device to the configured state - * - * Enable added endpoints if they are not enabled - * already. - */ - virtual void configure() = 0; - - /** - * Leave the configured state - * - * This is a notification to the USBPhy indicating that the device - * is leaving the configured state. The USBPhy can disable all - * endpoints other than endpoint 0. - * - */ - virtual void unconfigure() = 0; - - /** - * Enable the start of frame interrupt - * - * Call USBPhyEvents::sof on every frame. - */ - virtual void sof_enable() = 0; - - /** - * Disable the start of frame interrupt - * - * Stop calling USBPhyEvents::sof. - */ - virtual void sof_disable() = 0; - - /** - * Set the USBPhy's address - * - * @param address This device's USB address - */ - virtual void set_address(uint8_t address) = 0; - - /** - * Wake upstream devices - */ - virtual void remote_wakeup() = 0; - - /** - * Get the endpoint table - * - * This function returns a table which describes the endpoints - * can be used, the functionality of those endpoints and the - * resource cost. - */ - virtual const usb_ep_table_t *endpoint_table() = 0; - - /** - * Set wMaxPacketSize of endpoint 0 - * - * @param max_packet The wMaxPacketSize value for endpoint 0 - * @return The actual size of endpoint 0 - */ - virtual uint32_t ep0_set_max_packet(uint32_t max_packet) = 0; - - /** - * Read the contents of the SETUP packet - * - * @param buffer Buffer to fill with data - * @param size Size of buffer passed in - */ - virtual void ep0_setup_read_result(uint8_t *buffer, uint32_t size) = 0; - - /** - * Start receiving a packet of up to wMaxPacketSize on endpoint 0 - * - * @param data Buffer to fill with the data read - * @param size Size of buffer - */ - virtual void ep0_read(uint8_t *data, uint32_t size) = 0; - - /** - * Read the contents of a received packet - * - * @return Size of data read - */ - virtual uint32_t ep0_read_result() = 0; - - /** - * Write a packet on endpoint 0 - * - * @param buffer Buffer fill with data to send - * @param size Size of data to send - */ - virtual void ep0_write(uint8_t *buffer, uint32_t size) = 0; - - /** - * Protocol stall on endpoint 0 - * - * Stall all IN and OUT packets on endpoint 0 until a setup packet - * is received. - * @note The stall is cleared automatically when a setup packet is received - */ - virtual void ep0_stall() = 0; - - /** - * Configure and enable an endpoint - * - * @param endpoint Endpoint to configure and enable - * @param max_packet The maximum packet size that can be sent or received - * @param type The type of endpoint this should be configured as - - * USB_EP_TYPE_BULK, USB_EP_TYPE_INT or USB_EP_TYPE_ISO - * @note This function cannot be used to configure endpoint 0. That must be done - * with ep0_set_max_packet - */ - virtual bool endpoint_add(usb_ep_t endpoint, uint32_t max_packet, usb_ep_type_t type) = 0; - - /** - * Disable an endpoint - * - * @param endpoint Endpoint to disable - */ - virtual void endpoint_remove(usb_ep_t endpoint) = 0; - - /** - * Perform a functional stall on the given endpoint - * - * Set the HALT feature for this endpoint so that all further - * communication is aborted. - * - * @param endpoint Endpoint to stall - */ - virtual void endpoint_stall(usb_ep_t endpoint) = 0; - - /** - * Un-stall the endpoint - * - * Clear the HALT feature on this endpoint so communication can - * resume. - * - * @param endpoint Endpoint to stall - */ - virtual void endpoint_unstall(usb_ep_t endpoint) = 0; - - /** - * Start a read on the given endpoint - * - * @param endpoint Endpoint to start the read on - * @param data Buffer to fill with data - * @param size Size of the read buffer. This must be at least - * the max packet size for this endpoint. - * @return true if the read was successfully started, false otherwise - */ - virtual bool endpoint_read(usb_ep_t endpoint, uint8_t *data, uint32_t size) = 0; - - /** - * Finish a read on the given endpoint - * - * @param endpoint Endpoint to check - * @return The number of bytes received - */ - virtual uint32_t endpoint_read_result(usb_ep_t endpoint) = 0; - - /** - * Start a write on the given endpoint - * - * @param endpoint Endpoint to write to - * @param data Buffer to write - * @param size Size of data to write - * @return true if the data was prepared for transmit, false otherwise - */ - virtual bool endpoint_write(usb_ep_t endpoint, uint8_t *data, uint32_t size) = 0; - - /** - * Abort the current transfer if it has not yet been sent - * - * @param endpoint Endpoint to abort the transfer on. It is implementation defined - * if this function has an effect on receive endpoints. - */ - virtual void endpoint_abort(usb_ep_t endpoint) = 0; - - /** - * Callback used for performing USB processing - * - * USBPhy processing should be triggered by calling USBPhyEvents::start_process - * and done inside process. All USBPhyEvents callbacks aside from - * USBPhyEvents::start_process must be called in the context of process - */ - virtual void process() = 0; -}; - -#endif diff --git a/hal/usb/USBPhyEvents.h b/hal/usb/USBPhyEvents.h deleted file mode 100644 index 1912646..0000000 --- a/hal/usb/USBPhyEvents.h +++ /dev/null @@ -1,108 +0,0 @@ -/* - * Copyright (c) 2018-2019, Arm Limited and affiliates. - * 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. - */ - -#ifndef USBPHY_EVENTS_H -#define USBPHY_EVENTS_H - -#include "USBPhyTypes.h" - -/** Event handler for USBPhy - * - * This class is the event handler for the USBPhy class. Any events generated - * by USBPhy are passed to this class via the virtual functions. - * - * @ingroup usb_device_core - * - */ -class USBPhyEvents { -public: - USBPhyEvents() {}; - virtual ~USBPhyEvents() {}; - - /** - * Callback called when a bus reset occurs - * @note called in the contex of USBPhy::process - */ - virtual void reset() = 0; - - /** - * Callback called when an endpoint 0 setup packet is received - * @note called in the contex of USBPhy::process - */ - virtual void ep0_setup() = 0; - - /** - * Callback called when an endpoint 0 out packet is received - * @note called in the contex of USBPhy::process - */ - virtual void ep0_out() = 0; - - /** - * Callback called when an endpoint 0 in packet is received - * @note called in the contex of USBPhy::process - */ - virtual void ep0_in() = 0; - - /** - * Callback called USB power is applied or removed - * - * @param powered true if USB power is present, false otherwise - * @note called in the contex of USBPhy::process - */ - virtual void power(bool powered) = 0; - - /** - * Callback called when entering or leaving suspend mode - * - * @param suspended true if entering suspend mode false otherwise - * @note called in the contex of USBPhy::process - */ - virtual void suspend(bool suspended) = 0; - - /** - * Callback called on start of frame - * - * @param frame_number The current frame number - * @note This callback is enabled/disabled by - * calling USBPhy::sof_enable / USBPhy::sof_disable - * @note called in the contex of USBPhy::process - */ - virtual void sof(int frame_number) = 0; - - /** - * Callback called on the reception of an OUT packet - * - * @param endpoint Endpoint which received the OUT packet - * @note called in the contex of USBPhy::process - */ - virtual void out(usb_ep_t endpoint) = 0; - - /** - * Callback called on the transmission of an IN packet - * - * @param endpoint Endpoint which sent the IN packet - * @note called in the contex of USBPhy::process - */ - virtual void in(usb_ep_t endpoint) = 0; - - /** - * Callback called to indicate the USB processing needs to be done - */ - virtual void start_process() = 0; -}; - -#endif diff --git a/hal/usb/USBPhyTypes.h b/hal/usb/USBPhyTypes.h deleted file mode 100644 index f47c91f..0000000 --- a/hal/usb/USBPhyTypes.h +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright (c) 2018-2019, Arm Limited and affiliates. - * 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. - */ - -#ifndef USBPHY_TYPES_H -#define USBPHY_TYPES_H - -#include - -typedef uint8_t usb_ep_t; - -typedef enum { - USB_EP_TYPE_CTRL = 0, - USB_EP_TYPE_ISO = 1, - USB_EP_TYPE_BULK = 2, - USB_EP_TYPE_INT = 3 -} usb_ep_type_t; - -enum { - USB_EP_ATTR_ALLOW_CTRL = 1 << USB_EP_TYPE_CTRL, - USB_EP_ATTR_ALLOW_BULK = 1 << USB_EP_TYPE_BULK, - USB_EP_ATTR_ALLOW_INT = 1 << USB_EP_TYPE_INT, - USB_EP_ATTR_ALLOW_ISO = 1 << USB_EP_TYPE_ISO, - USB_EP_ATTR_ALLOW_ALL = USB_EP_ATTR_ALLOW_CTRL | USB_EP_ATTR_ALLOW_BULK | - USB_EP_ATTR_ALLOW_INT | USB_EP_ATTR_ALLOW_ISO, - - USB_EP_ATTR_DIR_IN = 0 << 4, - USB_EP_ATTR_DIR_OUT = 1 << 4, - USB_EP_ATTR_DIR_IN_OR_OUT = 2 << 4, - USB_EP_ATTR_DIR_IN_AND_OUT = 3 << 4, - USB_EP_ATTR_DIR_MASK = 3 << 4 -}; -typedef uint8_t usb_ep_attr_t; - -struct usb_ep_entry_t { - usb_ep_attr_t attributes; - uint8_t byte_cost; - uint16_t base_cost; -}; - -struct usb_ep_table_t { - uint32_t resources; - usb_ep_entry_t table[16]; -}; - -#endif diff --git a/hal/usb/include/usb/USBPhy.h b/hal/usb/include/usb/USBPhy.h new file mode 100644 index 0000000..c7c69bb --- /dev/null +++ b/hal/usb/include/usb/USBPhy.h @@ -0,0 +1,318 @@ +/* + * Copyright (c) 2018-2019, Arm Limited and affiliates. + * 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. + */ + +#ifndef USBPHY_H +#define USBPHY_H + +#include "USBPhyTypes.h" +#include "USBPhyEvents.h" + +/** Abstract interface to physical USB hardware + * + * # Defined behavior + * * You can use any endpoint configurations that fit in the parameters + * of the table returned by USBPhy::endpoint_table. + * * You can use all endpoints in any valid endpoint configuration concurrently. + * * The device supports use of at least one control, bulk, interrupt and + * isochronous in each direction at the same time - at least 8 endpoints. + * * USBPhy supports all standard endpoint sizes (wMaxPacketSize). + * * USBPhy can handle an interrupt latency of at least 100ms if the host PC + * is not performing a reset or setting the device's address. + * * USBPhy only sends USBPhyEvents when it is in the initialized state. + * * When unpowered, USBPhy only sends the USBPhyEvents::power event. + * * On USB reset, all endpoints are removed except for endpoint 0. + * * A call to USBPhy::ep0_write results in the call of USBPhyEvents::in when + * the PC reads the data unless a power loss, reset, or a call to + * USBPhy::disconnect occurs first. + * * A call to USBPhy::endpoint_write results in the call of USBPhyEvents::in + * when the pc reads the data unless a power loss, reset, or a call to + * USBPhy::endpoint_abort occurs first. + * * A call to USBPhy::endpoint_read results in the call of USBPhyEvents::out + * when the pc sends data unless a power loss, reset, or a call to + * USBPhy::endpoint_abort occurs first. + * * Endpoint 0 naks all transactions aside from setup packets until + * higher-level code calls one of USBPhy::ep0_read, USBPhy::ep0_write or + * USBPhy::ep0_stall. + * * Endpoint 0 stall automatically clears on reception of a setup packet. + * + * # Undefined behavior + * * Calling USBPhy::endpoint_add or USBPhy::endpoint_remove outside of the + * control requests SetInterface or SetConfiguration. + * * Calling USBPhy::endpoint_remove on an endpoint that has an ongoing read + * or write operation. To avoid undefined behavior, you must abort ongoing + * operations with USBPhy::endpoint_abort. + * * Devices behavior is undefined if latency is greater than 2ms when address + * is being set - see USB spec 9.2.6.3. + * * Devices behavior is undefined if latency is greater than 10ms when a + * reset occurs - see USB spec 7.1.7.5. + * * Calling any of the USBPhy::endpoint_* functions on endpoint 0. + * + * # Notes + * * Make sure USBPhy sends USBPhyEvents in the correct order when multiple + * packets are present. USBPhy must send IN endpoint events before OUT + * endpoint events if both are pending. + * * A host PC may resend setup packets to a USB device if there is noise on + * the USB line. The USBPhy should be able to handle this scenario and + * respond to the setup packet with an ACK. + * * Bidirectional protocols making use of alternating IN and OUT phases + * should not rely on the last ACK an IN transfer to indicate that the + * OUT phase should start. Instead, the OUT phase should be started at + * the same time the last IN transfer is started. This is because the ACK + * to the last in transfer may be dropped if there is noise on the USB + * line. If dropped, it will only be resent on the next IN phase. You can + * find more information on this in section 8.5.3.3 of the USB + * specification. + * + * @ingroup usb_device_core + */ +class USBPhy { +public: + USBPhy() {}; + virtual ~USBPhy() {}; + + /** + * Initialize this USBPhy instance + * + * This function must be called before calling + * any other functions of this class, unless specifically + * noted. + * + * @param events Callback class to handle USB events + */ + virtual void init(USBPhyEvents *events) = 0; + + /** + * Power down this USBPhy instance + * + * Disable interrupts and stop sending events. + */ + virtual void deinit() = 0; + + /** + * Check if USB power is present + * + * Devices which don't support checking the USB power state + * must always return true. + * + * @return true if USB power is present, false otherwise + */ + virtual bool powered() = 0; + + /** + * Make the USB phy visible to the USB host + * + * Enable either the D+ or D- pullup so the host can detect + * the presence of this device. + */ + virtual void connect() = 0; + + /** + * Detach the USB phy + * + * Disable the D+ and D- pullup and stop responding to + * USB traffic. + */ + virtual void disconnect() = 0; + + /** + * Set this device to the configured state + * + * Enable added endpoints if they are not enabled + * already. + */ + virtual void configure() = 0; + + /** + * Leave the configured state + * + * This is a notification to the USBPhy indicating that the device + * is leaving the configured state. The USBPhy can disable all + * endpoints other than endpoint 0. + * + */ + virtual void unconfigure() = 0; + + /** + * Enable the start of frame interrupt + * + * Call USBPhyEvents::sof on every frame. + */ + virtual void sof_enable() = 0; + + /** + * Disable the start of frame interrupt + * + * Stop calling USBPhyEvents::sof. + */ + virtual void sof_disable() = 0; + + /** + * Set the USBPhy's address + * + * @param address This device's USB address + */ + virtual void set_address(uint8_t address) = 0; + + /** + * Wake upstream devices + */ + virtual void remote_wakeup() = 0; + + /** + * Get the endpoint table + * + * This function returns a table which describes the endpoints + * can be used, the functionality of those endpoints and the + * resource cost. + */ + virtual const usb_ep_table_t *endpoint_table() = 0; + + /** + * Set wMaxPacketSize of endpoint 0 + * + * @param max_packet The wMaxPacketSize value for endpoint 0 + * @return The actual size of endpoint 0 + */ + virtual uint32_t ep0_set_max_packet(uint32_t max_packet) = 0; + + /** + * Read the contents of the SETUP packet + * + * @param buffer Buffer to fill with data + * @param size Size of buffer passed in + */ + virtual void ep0_setup_read_result(uint8_t *buffer, uint32_t size) = 0; + + /** + * Start receiving a packet of up to wMaxPacketSize on endpoint 0 + * + * @param data Buffer to fill with the data read + * @param size Size of buffer + */ + virtual void ep0_read(uint8_t *data, uint32_t size) = 0; + + /** + * Read the contents of a received packet + * + * @return Size of data read + */ + virtual uint32_t ep0_read_result() = 0; + + /** + * Write a packet on endpoint 0 + * + * @param buffer Buffer fill with data to send + * @param size Size of data to send + */ + virtual void ep0_write(uint8_t *buffer, uint32_t size) = 0; + + /** + * Protocol stall on endpoint 0 + * + * Stall all IN and OUT packets on endpoint 0 until a setup packet + * is received. + * @note The stall is cleared automatically when a setup packet is received + */ + virtual void ep0_stall() = 0; + + /** + * Configure and enable an endpoint + * + * @param endpoint Endpoint to configure and enable + * @param max_packet The maximum packet size that can be sent or received + * @param type The type of endpoint this should be configured as - + * USB_EP_TYPE_BULK, USB_EP_TYPE_INT or USB_EP_TYPE_ISO + * @note This function cannot be used to configure endpoint 0. That must be done + * with ep0_set_max_packet + */ + virtual bool endpoint_add(usb_ep_t endpoint, uint32_t max_packet, usb_ep_type_t type) = 0; + + /** + * Disable an endpoint + * + * @param endpoint Endpoint to disable + */ + virtual void endpoint_remove(usb_ep_t endpoint) = 0; + + /** + * Perform a functional stall on the given endpoint + * + * Set the HALT feature for this endpoint so that all further + * communication is aborted. + * + * @param endpoint Endpoint to stall + */ + virtual void endpoint_stall(usb_ep_t endpoint) = 0; + + /** + * Un-stall the endpoint + * + * Clear the HALT feature on this endpoint so communication can + * resume. + * + * @param endpoint Endpoint to stall + */ + virtual void endpoint_unstall(usb_ep_t endpoint) = 0; + + /** + * Start a read on the given endpoint + * + * @param endpoint Endpoint to start the read on + * @param data Buffer to fill with data + * @param size Size of the read buffer. This must be at least + * the max packet size for this endpoint. + * @return true if the read was successfully started, false otherwise + */ + virtual bool endpoint_read(usb_ep_t endpoint, uint8_t *data, uint32_t size) = 0; + + /** + * Finish a read on the given endpoint + * + * @param endpoint Endpoint to check + * @return The number of bytes received + */ + virtual uint32_t endpoint_read_result(usb_ep_t endpoint) = 0; + + /** + * Start a write on the given endpoint + * + * @param endpoint Endpoint to write to + * @param data Buffer to write + * @param size Size of data to write + * @return true if the data was prepared for transmit, false otherwise + */ + virtual bool endpoint_write(usb_ep_t endpoint, uint8_t *data, uint32_t size) = 0; + + /** + * Abort the current transfer if it has not yet been sent + * + * @param endpoint Endpoint to abort the transfer on. It is implementation defined + * if this function has an effect on receive endpoints. + */ + virtual void endpoint_abort(usb_ep_t endpoint) = 0; + + /** + * Callback used for performing USB processing + * + * USBPhy processing should be triggered by calling USBPhyEvents::start_process + * and done inside process. All USBPhyEvents callbacks aside from + * USBPhyEvents::start_process must be called in the context of process + */ + virtual void process() = 0; +}; + +#endif diff --git a/hal/usb/include/usb/USBPhyEvents.h b/hal/usb/include/usb/USBPhyEvents.h new file mode 100644 index 0000000..1912646 --- /dev/null +++ b/hal/usb/include/usb/USBPhyEvents.h @@ -0,0 +1,108 @@ +/* + * Copyright (c) 2018-2019, Arm Limited and affiliates. + * 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. + */ + +#ifndef USBPHY_EVENTS_H +#define USBPHY_EVENTS_H + +#include "USBPhyTypes.h" + +/** Event handler for USBPhy + * + * This class is the event handler for the USBPhy class. Any events generated + * by USBPhy are passed to this class via the virtual functions. + * + * @ingroup usb_device_core + * + */ +class USBPhyEvents { +public: + USBPhyEvents() {}; + virtual ~USBPhyEvents() {}; + + /** + * Callback called when a bus reset occurs + * @note called in the contex of USBPhy::process + */ + virtual void reset() = 0; + + /** + * Callback called when an endpoint 0 setup packet is received + * @note called in the contex of USBPhy::process + */ + virtual void ep0_setup() = 0; + + /** + * Callback called when an endpoint 0 out packet is received + * @note called in the contex of USBPhy::process + */ + virtual void ep0_out() = 0; + + /** + * Callback called when an endpoint 0 in packet is received + * @note called in the contex of USBPhy::process + */ + virtual void ep0_in() = 0; + + /** + * Callback called USB power is applied or removed + * + * @param powered true if USB power is present, false otherwise + * @note called in the contex of USBPhy::process + */ + virtual void power(bool powered) = 0; + + /** + * Callback called when entering or leaving suspend mode + * + * @param suspended true if entering suspend mode false otherwise + * @note called in the contex of USBPhy::process + */ + virtual void suspend(bool suspended) = 0; + + /** + * Callback called on start of frame + * + * @param frame_number The current frame number + * @note This callback is enabled/disabled by + * calling USBPhy::sof_enable / USBPhy::sof_disable + * @note called in the contex of USBPhy::process + */ + virtual void sof(int frame_number) = 0; + + /** + * Callback called on the reception of an OUT packet + * + * @param endpoint Endpoint which received the OUT packet + * @note called in the contex of USBPhy::process + */ + virtual void out(usb_ep_t endpoint) = 0; + + /** + * Callback called on the transmission of an IN packet + * + * @param endpoint Endpoint which sent the IN packet + * @note called in the contex of USBPhy::process + */ + virtual void in(usb_ep_t endpoint) = 0; + + /** + * Callback called to indicate the USB processing needs to be done + */ + virtual void start_process() = 0; +}; + +#endif diff --git a/hal/usb/include/usb/USBPhyTypes.h b/hal/usb/include/usb/USBPhyTypes.h new file mode 100644 index 0000000..f47c91f --- /dev/null +++ b/hal/usb/include/usb/USBPhyTypes.h @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2018-2019, Arm Limited and affiliates. + * 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. + */ + +#ifndef USBPHY_TYPES_H +#define USBPHY_TYPES_H + +#include + +typedef uint8_t usb_ep_t; + +typedef enum { + USB_EP_TYPE_CTRL = 0, + USB_EP_TYPE_ISO = 1, + USB_EP_TYPE_BULK = 2, + USB_EP_TYPE_INT = 3 +} usb_ep_type_t; + +enum { + USB_EP_ATTR_ALLOW_CTRL = 1 << USB_EP_TYPE_CTRL, + USB_EP_ATTR_ALLOW_BULK = 1 << USB_EP_TYPE_BULK, + USB_EP_ATTR_ALLOW_INT = 1 << USB_EP_TYPE_INT, + USB_EP_ATTR_ALLOW_ISO = 1 << USB_EP_TYPE_ISO, + USB_EP_ATTR_ALLOW_ALL = USB_EP_ATTR_ALLOW_CTRL | USB_EP_ATTR_ALLOW_BULK | + USB_EP_ATTR_ALLOW_INT | USB_EP_ATTR_ALLOW_ISO, + + USB_EP_ATTR_DIR_IN = 0 << 4, + USB_EP_ATTR_DIR_OUT = 1 << 4, + USB_EP_ATTR_DIR_IN_OR_OUT = 2 << 4, + USB_EP_ATTR_DIR_IN_AND_OUT = 3 << 4, + USB_EP_ATTR_DIR_MASK = 3 << 4 +}; +typedef uint8_t usb_ep_attr_t; + +struct usb_ep_entry_t { + usb_ep_attr_t attributes; + uint8_t byte_cost; + uint16_t base_cost; +}; + +struct usb_ep_table_t { + uint32_t resources; + usb_ep_entry_t table[16]; +}; + +#endif diff --git a/hal/usb/include/usb/usb_phy_api.h b/hal/usb/include/usb/usb_phy_api.h new file mode 100644 index 0000000..341ef0e --- /dev/null +++ b/hal/usb/include/usb/usb_phy_api.h @@ -0,0 +1,37 @@ + +/** \addtogroup hal */ +/** @{*/ +/* + * Copyright (c) 2018-2019, Arm Limited and affiliates. + * 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. + */ +#ifndef MBED_USB_PHY_API_H +#define MBED_USB_PHY_API_H + +#include "USBPhy.h" + +/** Return a the USBPhy instance for this hardware + * + * For details on adding support for a USBPhy see the specification in USBPhy.h. + * + * @return A pointer to a USBPhy instance + * @note Calling this function on platforms without a USBPhy will result in an + * error + */ +USBPhy *get_usb_phy(); + +#endif + +/** @}*/ diff --git a/hal/usb/mbed_usb_phy.cpp b/hal/usb/mbed_usb_phy.cpp deleted file mode 100644 index 709e2bc..0000000 --- a/hal/usb/mbed_usb_phy.cpp +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright (c) 2018-2019, Arm Limited and affiliates. - * 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. - */ - -#include -#include "usb_phy_api.h" -#include "mbed_error.h" - -#if !defined(DEVICE_USBDEVICE) || !DEVICE_USBDEVICE - -USBPhy *get_usb_phy() -{ - error("This board does not have a hardware USB driver"); - return NULL; -} - -#endif diff --git a/hal/usb/source/mbed_usb_phy.cpp b/hal/usb/source/mbed_usb_phy.cpp new file mode 100644 index 0000000..709e2bc --- /dev/null +++ b/hal/usb/source/mbed_usb_phy.cpp @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2018-2019, Arm Limited and affiliates. + * 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. + */ + +#include +#include "usb_phy_api.h" +#include "mbed_error.h" + +#if !defined(DEVICE_USBDEVICE) || !DEVICE_USBDEVICE + +USBPhy *get_usb_phy() +{ + error("This board does not have a hardware USB driver"); + return NULL; +} + +#endif diff --git a/hal/usb/usb_phy_api.h b/hal/usb/usb_phy_api.h deleted file mode 100644 index 341ef0e..0000000 --- a/hal/usb/usb_phy_api.h +++ /dev/null @@ -1,37 +0,0 @@ - -/** \addtogroup hal */ -/** @{*/ -/* - * Copyright (c) 2018-2019, Arm Limited and affiliates. - * 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. - */ -#ifndef MBED_USB_PHY_API_H -#define MBED_USB_PHY_API_H - -#include "USBPhy.h" - -/** Return a the USBPhy instance for this hardware - * - * For details on adding support for a USBPhy see the specification in USBPhy.h. - * - * @return A pointer to a USBPhy instance - * @note Calling this function on platforms without a USBPhy will result in an - * error - */ -USBPhy *get_usb_phy(); - -#endif - -/** @}*/ diff --git a/hal/watchdog_api.h b/hal/watchdog_api.h deleted file mode 100644 index 2223611..0000000 --- a/hal/watchdog_api.h +++ /dev/null @@ -1,188 +0,0 @@ -/** \addtogroup hal */ -/** @{*/ - -/* - * Copyright (c) 2018-2019 Arm Limited and affiliates. - * 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. - */ - -#ifndef MBED_WATCHDOG_API_H -#define MBED_WATCHDOG_API_H - -#if DEVICE_WATCHDOG - -#include -#include - -/** - * \defgroup hal_watchdog Watchdog HAL API - * Low-level interface to the Independent Watchdog Timer of a target. - * - * This module provides platform independent access to the system watchdog timer - * which is an embedded peripheral that will reset the system in the case of - * system failures or malfunctions. - * - * The watchdog timer initializes a system timer with a time period specified in - * the configuration. This timer counts down and triggers a system reset when it - * wraps. To prevent the system reset the timer must be continually - * kicked/refreshed by calling ::hal_watchdog_kick which will reset the countdown - * to the user specified reset value. - * - * # Defined behavior - * * Sleep and debug modes don't stop the watchdog timer from counting down. - * * The function ::hal_watchdog_init is safe to call repeatedly. The - * function's implementation must not do anything if ::hal_watchdog_init has - * already initialized the hardware watchdog timer. - * * Maximum supported timeout is `UINT32_MAX` milliseconds; minimum timeout - * is 1 millisecond. - * * The uncalibrated watchdog should trigger at or after the timeout value - * multiplied by the frequency accuracy ratio of its oscillator (typical_frequency / max_frequency). - * * The calibrated watchdog should trigger at or after the timeout value. - * * The watchdog should trigger before twice the timeout value. - * - * # Undefined behavior - * * Calling any function other than ::hal_watchdog_init or - * ::hal_watchdog_get_platform_features before you have initialized the watchdog. - * - * # Notes - * * A software reset may not stop the watchdog timer; the behavior is platform specific. - * - * @{ - */ - -/** - * \defgroup hal_watchdog_tests Watchdog HAL tests - * Greentea tests for the Watchdog HAL. - * - * To run the Watchdog HAL tests use the command: - * - * mbed test -t -m -n tests-mbed_hal-watchdog* - * - */ - -/** Watchdog configuration. - */ -typedef struct { - /** - * Refresh value for the watchdog in milliseconds. The maximum value of this - * setting is platform dependent, to find the maximum value for the current - * platform call hal_watchdog_get_features() and check the timeout value - * member. The minimum valid value for this setting is 1. Attempting to - * initialize the watchdog with a timeout of 0 ms returns - * WATCHDOG_STATUS_INVALID_ARGUMENT. - */ - uint32_t timeout_ms; -} watchdog_config_t; - -/** Watchdog features. - */ -typedef struct { - /** - * Maximum timeout value for the watchdog in milliseconds. - */ - uint32_t max_timeout; - /** - * You can update the watchdog configuration after the watchdog has started. - */ - bool update_config; - /** - * You can stop the watchdog after it starts without a reset. - */ - bool disable_watchdog; - /** - * Typical frequency of not calibrated watchdog clock in Hz. - */ - uint32_t clock_typical_frequency; - /** - * Maximum frequency of not calibrated watchdog clock in Hz. - */ - uint32_t clock_max_frequency; -} watchdog_features_t; - - -/** Status of a watchdog operation. -*/ -typedef enum { - WATCHDOG_STATUS_OK, /**< Operation successful. **/ - WATCHDOG_STATUS_NOT_SUPPORTED, /**< Operation not supported. **/ - WATCHDOG_STATUS_INVALID_ARGUMENT /**< Invalid argument. **/ -} watchdog_status_t; - -#ifdef __cplusplus -extern "C" { -#endif - -/** Initialize and start a watchdog timer with the given configuration. - * - * If the watchdog timer is configured and starts successfully, this - * function returns ::WATCHDOG_STATUS_OK. - * - * If the timeout specified is outside the range supported by the platform, - * it returns ::WATCHDOG_STATUS_INVALID_ARGUMENT. - * - * @param[in] config Configuration settings for the watchdog timer - * - * @return ::WATCHDOG_STATUS_OK if the watchdog is configured correctly and - * has started. Otherwise a status indicating the fault. - */ -watchdog_status_t hal_watchdog_init(const watchdog_config_t *config); - -/** Refreshes the watchdog timer. - * - * Call this function periodically before the watchdog times out. - * Otherwise, the system resets. - * - * If a watchdog is not running, this function does nothing. - */ -void hal_watchdog_kick(void); - -/** Stops the watchdog timer. - * - * Calling this function disables any running watchdog - * timers if the current platform supports them. - * - * @return Returns ::WATCHDOG_STATUS_OK if the watchdog timer was succesfully - * stopped, or if the timer was never started. Returns - * ::WATCHDOG_STATUS_NOT_SUPPORTED if the watchdog cannot be disabled on - * the current platform. - */ -watchdog_status_t hal_watchdog_stop(void); - -/** Get the watchdog timer refresh value. - * - * This function returns the configured refresh timeout of the watchdog timer. - * - * @return Reload value for the watchdog timer in milliseconds. - */ -uint32_t hal_watchdog_get_reload_value(void); - -/** Get information on the current platforms supported watchdog functionality. - * - * @return watchdog_feature_t indicating supported watchdog features on the - * current platform - */ -watchdog_features_t hal_watchdog_get_platform_features(void); - -/**@}*/ - -#ifdef __cplusplus -} -#endif - -#endif // DEVICE_WATCHDOG - -#endif // MBED_WATCHDOG_API_H - -/** @}*/