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/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 + +/**@}*/