Import Mbed OS hard-float snapshot

This commit is contained in:
Beslan
2026-06-01 20:15:04 +03:00
commit d3738e2f89
16278 changed files with 10628036 additions and 0 deletions

View File

@@ -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

View File

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

View File

@@ -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<bool init_direct>
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<AnaloginPort, DefaultFormFactor, fpga_analogin_init_test>),
// This will be run for single pin
Case("AnalogIn - read test", all_ports<AnaloginPort, DefaultFormFactor, fpga_analogin_test<false>>),
Case("AnalogIn (direct init) - read test", all_ports<AnaloginPort, DefaultFormFactor, fpga_analogin_test<true>>),
};
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 */

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

View File

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

View File

@@ -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<GPIOPort, DefaultFormFactor, fpga_test_basic_input_output>),
Case("input pull modes", all_ports<GPIOPort, DefaultFormFactor, fpga_test_input_pull_modes>),
Case("explicit init, input", all_ports<GPIOPort, DefaultFormFactor, fpga_test_explicit_input>),
Case("explicit init, output", all_ports<GPIOPort, DefaultFormFactor, fpga_test_explicit_output>),
};
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 */

View File

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

View File

@@ -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<GPIOIRQPort, DefaultFormFactor, fpga_gpio_irq_init_free_test>),
Case("rising & falling edge", all_ports<GPIOIRQPort, DefaultFormFactor, fpga_gpio_irq_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_INTERRUPTIN */

View File

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

View File

@@ -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<bool init_direct>
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<bool init_direct>
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 <TRANSFER_COUNT> 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 <TRANSFER_COUNT> 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<I2CPort, DefaultFormFactor, fpga_test_i2c_init_free>),
Case("i2c - test write i2c API", all_peripherals<I2CPort, DefaultFormFactor, fpga_i2c_test_write<false>>),
Case("i2c (direct init) - test write i2c API", all_peripherals<I2CPort, DefaultFormFactor, fpga_i2c_test_write<true>>),
Case("i2c - test read i2c API", all_peripherals<I2CPort, DefaultFormFactor, fpga_i2c_test_read<false>>),
Case("i2c (direct init) - test read i2c API", all_peripherals<I2CPort, DefaultFormFactor, fpga_i2c_test_read<true>>),
Case("i2c - test single byte write i2c API", all_peripherals<I2CPort, DefaultFormFactor, fpga_i2c_test_byte_write>),
Case("i2c - test single byte read i2c API", all_peripherals<I2CPort, DefaultFormFactor, fpga_i2c_test_byte_read>)
};
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 */

View File

@@ -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<uint32_t period_ms, uint32_t fill_prc, pwm_api_test_t api_test, bool init_direct>
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<PWMPort, DefaultFormFactor, fpga_pwm_init_free>),
// This will be run for single pin
Case("PWM - period: 10 ms, fill: 10%, api: period/write", one_peripheral<PWMPort, DefaultFormFactor, fpga_pwm_period_fill_test<10, 10, PERIOD_WRITE, false> >),
Case("PWM (direct init) - period: 10 ms, fill: 10%, api: period/write", one_peripheral<PWMPort, DefaultFormFactor, fpga_pwm_period_fill_test<10, 10, PERIOD_WRITE, true> >),
Case("PWM - period: 10 ms, fill: 10%, api: period_ms/write", one_peripheral<PWMPort, DefaultFormFactor, fpga_pwm_period_fill_test<10, 10, PERIOD_MS_WRITE, false> >),
Case("PWM - period: 10 ms, fill: 10%, api: period_us/write", one_peripheral<PWMPort, DefaultFormFactor, fpga_pwm_period_fill_test<10, 10, PERIOD_US_WRITE, false> >),
Case("PWM - period: 10 ms, fill: 10%, api: period/pulse_width", one_peripheral<PWMPort, DefaultFormFactor, fpga_pwm_period_fill_test<10, 10, PERIOD_PULSEWIDTH, false> >),
Case("PWM - period: 10 ms, fill: 10%, api: period/pulse_width_ms", one_peripheral<PWMPort, DefaultFormFactor, fpga_pwm_period_fill_test<10, 10, PERIOD_PULSEWIDTH_MS, false> >),
Case("PWM - period: 10 ms, fill: 10%, api: period/pulse_width_us", one_peripheral<PWMPort, DefaultFormFactor, fpga_pwm_period_fill_test<10, 10, PERIOD_PULSEWIDTH_US, false> >),
Case("PWM - period: 10 ms, fill: 50%, api: period/write", one_peripheral<PWMPort, DefaultFormFactor, fpga_pwm_period_fill_test<10, 50, PERIOD_WRITE, false> >),
Case("PWM - period: 10 ms, fill: 50%, api: period_ms/write", one_peripheral<PWMPort, DefaultFormFactor, fpga_pwm_period_fill_test<10, 50, PERIOD_MS_WRITE, false> >),
Case("PWM - period: 10 ms, fill: 50%, api: period_us/write", one_peripheral<PWMPort, DefaultFormFactor, fpga_pwm_period_fill_test<10, 50, PERIOD_US_WRITE, false> >),
Case("PWM - period: 10 ms, fill: 50%, api: period/pulse_width", one_peripheral<PWMPort, DefaultFormFactor, fpga_pwm_period_fill_test<10, 50, PERIOD_PULSEWIDTH, false> >),
Case("PWM - period: 10 ms, fill: 50%, api: period/pulse_width_ms", one_peripheral<PWMPort, DefaultFormFactor, fpga_pwm_period_fill_test<10, 50, PERIOD_PULSEWIDTH_MS, false> >),
Case("PWM - period: 10 ms, fill: 50%, api: period/pulse_width_us", one_peripheral<PWMPort, DefaultFormFactor, fpga_pwm_period_fill_test<10, 50, PERIOD_PULSEWIDTH_US, false> >),
Case("PWM - period: 10 ms, fill: 90%, api: period/write", one_peripheral<PWMPort, DefaultFormFactor, fpga_pwm_period_fill_test<10, 90, PERIOD_WRITE, false> >),
Case("PWM - period: 10 ms, fill: 90%, api: period_ms/write", one_peripheral<PWMPort, DefaultFormFactor, fpga_pwm_period_fill_test<10, 90, PERIOD_MS_WRITE, false> >),
Case("PWM - period: 10 ms, fill: 90%, api: period_us/write", one_peripheral<PWMPort, DefaultFormFactor, fpga_pwm_period_fill_test<10, 90, PERIOD_US_WRITE, false> >),
Case("PWM - period: 10 ms, fill: 90%, api: period/pulse_width", one_peripheral<PWMPort, DefaultFormFactor, fpga_pwm_period_fill_test<10, 90, PERIOD_PULSEWIDTH, false> >),
Case("PWM - period: 10 ms, fill: 90%, api: period/pulse_width_ms", one_peripheral<PWMPort, DefaultFormFactor, fpga_pwm_period_fill_test<10, 90, PERIOD_PULSEWIDTH_MS, false> >),
Case("PWM - period: 10 ms, fill: 90%, api: period/pulse_width_us", one_peripheral<PWMPort, DefaultFormFactor, fpga_pwm_period_fill_test<10, 90, PERIOD_PULSEWIDTH_US, false> >),
Case("PWM - period: 30 ms, fill: 10%, api: period/write", one_peripheral<PWMPort, DefaultFormFactor, fpga_pwm_period_fill_test<30, 10, PERIOD_WRITE, false> >),
Case("PWM - period: 30 ms, fill: 10%, api: period_ms/write", one_peripheral<PWMPort, DefaultFormFactor, fpga_pwm_period_fill_test<30, 10, PERIOD_MS_WRITE, false> >),
Case("PWM - period: 30 ms, fill: 10%, api: period_us/write", one_peripheral<PWMPort, DefaultFormFactor, fpga_pwm_period_fill_test<30, 10, PERIOD_US_WRITE, false> >),
Case("PWM - period: 30 ms, fill: 10%, api: period/pulse_width", one_peripheral<PWMPort, DefaultFormFactor, fpga_pwm_period_fill_test<30, 10, PERIOD_PULSEWIDTH, false> >),
Case("PWM - period: 30 ms, fill: 10%, api: period/pulse_width_ms", one_peripheral<PWMPort, DefaultFormFactor, fpga_pwm_period_fill_test<30, 10, PERIOD_PULSEWIDTH_MS, false> >),
Case("PWM - period: 30 ms, fill: 10%, api: period/pulse_width_us", one_peripheral<PWMPort, DefaultFormFactor, fpga_pwm_period_fill_test<30, 10, PERIOD_PULSEWIDTH_US, false> >),
Case("PWM - period: 30 ms, fill: 50%, api: period/write", one_peripheral<PWMPort, DefaultFormFactor, fpga_pwm_period_fill_test<30, 50, PERIOD_WRITE, false> >),
Case("PWM - period: 30 ms, fill: 50%, api: period_ms/write", one_peripheral<PWMPort, DefaultFormFactor, fpga_pwm_period_fill_test<30, 50, PERIOD_MS_WRITE, false> >),
Case("PWM - period: 30 ms, fill: 50%, api: period_us/write", one_peripheral<PWMPort, DefaultFormFactor, fpga_pwm_period_fill_test<30, 50, PERIOD_US_WRITE, false> >),
Case("PWM - period: 30 ms, fill: 50%, api: period/pulse_width", one_peripheral<PWMPort, DefaultFormFactor, fpga_pwm_period_fill_test<30, 50, PERIOD_PULSEWIDTH, false> >),
Case("PWM - period: 30 ms, fill: 50%, api: period/pulse_width_ms", one_peripheral<PWMPort, DefaultFormFactor, fpga_pwm_period_fill_test<30, 50, PERIOD_PULSEWIDTH_MS, false> >),
Case("PWM - period: 30 ms, fill: 50%, api: period/pulse_width_us", one_peripheral<PWMPort, DefaultFormFactor, fpga_pwm_period_fill_test<30, 50, PERIOD_PULSEWIDTH_US, false> >),
Case("PWM - period: 30 ms, fill: 90%, api: period/write", one_peripheral<PWMPort, DefaultFormFactor, fpga_pwm_period_fill_test<30, 90, PERIOD_WRITE, false> >),
Case("PWM - period: 30 ms, fill: 90%, api: period_ms/write", one_peripheral<PWMPort, DefaultFormFactor, fpga_pwm_period_fill_test<30, 90, PERIOD_MS_WRITE, false> >),
Case("PWM - period: 30 ms, fill: 90%, api: period_us/write", one_peripheral<PWMPort, DefaultFormFactor, fpga_pwm_period_fill_test<30, 90, PERIOD_US_WRITE, false> >),
Case("PWM - period: 30 ms, fill: 90%, api: period/pulse_width", one_peripheral<PWMPort, DefaultFormFactor, fpga_pwm_period_fill_test<30, 90, PERIOD_PULSEWIDTH, false> >),
Case("PWM - period: 30 ms, fill: 90%, api: period/pulse_width_ms", one_peripheral<PWMPort, DefaultFormFactor, fpga_pwm_period_fill_test<30, 90, PERIOD_PULSEWIDTH_MS, false> >),
Case("PWM - period: 30 ms, fill: 90%, api: period/pulse_width_us", one_peripheral<PWMPort, DefaultFormFactor, fpga_pwm_period_fill_test<30, 90, PERIOD_PULSEWIDTH_US, false> >)
};
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 */

View File

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

View File

@@ -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<Specified symbol size is not supported on this platform> skipped. ");
return false;
}
// SPI clock mode
if (!TEST_CAPABILITY_BIT(capabilities->clk_modes, spi_mode)) {
utest_printf("\n<Specified spi clock mode is not supported on this platform> skipped. ");
return false;
}
// Frequency
if (frequency != FREQ_MAX && frequency != FREQ_MIN && frequency < capabilities->minimum_frequency && frequency > capabilities->maximum_frequency) {
utest_printf("\n<Specified frequency is not supported on this platform> skipped. ");
return false;
}
// Async mode
if (transfer_type == TRANSFER_SPI_MASTER_TRANSFER_ASYNC && capabilities->async_mode == false) {
utest_printf("\n<Async mode is not supported on this platform> 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<RX length != TX length is not supported on this platform> 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<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>
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<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>
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<SPIPort, DefaultFormFactor, fpga_spi_test_init_free>),
Case("SPI - init/free test all pins (CS == NC)", all_ports<SPINoCSPort, DefaultFormFactor, fpga_spi_test_init_free_cs_nc>),
Case("SPI - init/free test all pins (CS == NC, MISO/MOSI == NC)", one_peripheral<SPINoCSPort, DefaultFormFactor, fpga_spi_test_init_free_cs_nc_miso_nc_mosi_nc>),
// This will be run for all peripherals
Case("SPI - basic test", all_peripherals<SPINoCSPort, DefaultFormFactor, fpga_spi_test_common_no_ss<SPITester::Mode0, 8, TRANSFER_SPI_MASTER_WRITE_SYNC, FREQ_1_MHZ, BUFFERS_COMMON, false, false> >),
Case("SPI - basic test (direct init)", all_peripherals<SPINoCSPort, DefaultFormFactor, fpga_spi_test_common_no_ss<SPITester::Mode0, 8, TRANSFER_SPI_MASTER_WRITE_SYNC, FREQ_1_MHZ, BUFFERS_COMMON, false, true> >),
// This will be run for single pin configuration
Case("SPI - mode testing (MODE_1)", one_peripheral<SPINoCSPort, DefaultFormFactor, fpga_spi_test_common_no_ss<SPITester::Mode1, 8, TRANSFER_SPI_MASTER_WRITE_SYNC, FREQ_1_MHZ, BUFFERS_COMMON, false, false> >),
Case("SPI - mode testing (MODE_2)", one_peripheral<SPINoCSPort, DefaultFormFactor, fpga_spi_test_common_no_ss<SPITester::Mode2, 8, TRANSFER_SPI_MASTER_WRITE_SYNC, FREQ_1_MHZ, BUFFERS_COMMON, false, false> >),
Case("SPI - mode testing (MODE_3)", one_peripheral<SPINoCSPort, DefaultFormFactor, fpga_spi_test_common_no_ss<SPITester::Mode3, 8, TRANSFER_SPI_MASTER_WRITE_SYNC, FREQ_1_MHZ, BUFFERS_COMMON, false, false> >),
Case("SPI - symbol size testing (4)", one_peripheral<SPINoCSPort, DefaultFormFactor, fpga_spi_test_common_no_ss<SPITester::Mode0, 4, TRANSFER_SPI_MASTER_WRITE_SYNC, FREQ_1_MHZ, BUFFERS_COMMON, false, false> >),
Case("SPI - symbol size testing (12)", one_peripheral<SPINoCSPort, DefaultFormFactor, fpga_spi_test_common_no_ss<SPITester::Mode0, 12, TRANSFER_SPI_MASTER_WRITE_SYNC, FREQ_1_MHZ, BUFFERS_COMMON, false, false> >),
Case("SPI - symbol size testing (16)", one_peripheral<SPINoCSPort, DefaultFormFactor, fpga_spi_test_common_no_ss<SPITester::Mode0, 16, TRANSFER_SPI_MASTER_WRITE_SYNC, FREQ_1_MHZ, BUFFERS_COMMON, false, false> >),
Case("SPI - symbol size testing (24)", one_peripheral<SPINoCSPort, DefaultFormFactor, fpga_spi_test_common_no_ss<SPITester::Mode0, 24, TRANSFER_SPI_MASTER_WRITE_SYNC, FREQ_1_MHZ, BUFFERS_COMMON, false, false> >),
Case("SPI - symbol size testing (32)", one_peripheral<SPINoCSPort, DefaultFormFactor, fpga_spi_test_common_no_ss<SPITester::Mode0, 32, TRANSFER_SPI_MASTER_WRITE_SYNC, FREQ_1_MHZ, BUFFERS_COMMON, false, false> >),
Case("SPI - buffers tx > rx", one_peripheral<SPINoCSPort, DefaultFormFactor, fpga_spi_test_common_no_ss<SPITester::Mode0, 8, TRANSFER_SPI_MASTER_BLOCK_WRITE_SYNC, FREQ_1_MHZ, BUFFERS_TX_GT_RX, false, false> >),
Case("SPI - buffers tx < rx", one_peripheral<SPINoCSPort, DefaultFormFactor, fpga_spi_test_common_no_ss<SPITester::Mode0, 8, TRANSFER_SPI_MASTER_BLOCK_WRITE_SYNC, FREQ_1_MHZ, BUFFERS_TX_LT_RX, false, false> >),
Case("SPI - frequency testing (200 kHz)", one_peripheral<SPINoCSPort, DefaultFormFactor, fpga_spi_test_common_no_ss<SPITester::Mode0, 8, TRANSFER_SPI_MASTER_WRITE_SYNC, FREQ_200_KHZ, BUFFERS_COMMON, false, false> >),
Case("SPI - frequency testing (2 MHz)", one_peripheral<SPINoCSPort, DefaultFormFactor, fpga_spi_test_common_no_ss<SPITester::Mode0, 8, TRANSFER_SPI_MASTER_WRITE_SYNC, FREQ_2_MHZ, BUFFERS_COMMON, false, false> >),
Case("SPI - frequency testing (capabilities min)", one_peripheral<SPINoCSPort, DefaultFormFactor, fpga_spi_test_common_no_ss<SPITester::Mode0, 8, TRANSFER_SPI_MASTER_WRITE_SYNC, FREQ_MIN, BUFFERS_COMMON, false, false> >),
Case("SPI - frequency testing (capabilities max)", one_peripheral<SPINoCSPort, DefaultFormFactor, fpga_spi_test_common_no_ss<SPITester::Mode0, 8, TRANSFER_SPI_MASTER_WRITE_SYNC, FREQ_MAX, BUFFERS_COMMON, false, false> >),
Case("SPI - block write", one_peripheral<SPINoCSPort, DefaultFormFactor, fpga_spi_test_common_no_ss<SPITester::Mode0, 8, TRANSFER_SPI_MASTER_BLOCK_WRITE_SYNC, FREQ_1_MHZ, BUFFERS_COMMON, false, false> >),
Case("SPI - block write(one sym)", one_peripheral<SPINoCSPort, DefaultFormFactor, fpga_spi_test_common_no_ss<SPITester::Mode0, 8, TRANSFER_SPI_MASTER_BLOCK_WRITE_SYNC, FREQ_1_MHZ, BUFFERS_TX_ONE_SYM, false, false> >),
Case("SPI - hardware ss handling", one_peripheral<SPIPort, DefaultFormFactor, fpga_spi_test_common<SPITester::Mode0, 8, TRANSFER_SPI_MASTER_WRITE_SYNC, FREQ_1_MHZ, BUFFERS_COMMON, true, false> >),
Case("SPI - hardware ss handling(block)", one_peripheral<SPIPort, DefaultFormFactor, fpga_spi_test_common<SPITester::Mode0, 8, TRANSFER_SPI_MASTER_BLOCK_WRITE_SYNC, FREQ_1_MHZ, BUFFERS_COMMON, true, false> >),
#if DEVICE_SPI_ASYNCH
Case("SPI - async mode (sw ss)", one_peripheral<SPINoCSPort, DefaultFormFactor, fpga_spi_test_common_no_ss<SPITester::Mode0, 8, TRANSFER_SPI_MASTER_TRANSFER_ASYNC, FREQ_1_MHZ, BUFFERS_COMMON, false, false> >),
Case("SPI - async mode (hw ss)", one_peripheral<SPIPort, DefaultFormFactor, fpga_spi_test_common<SPITester::Mode0, 8, TRANSFER_SPI_MASTER_TRANSFER_ASYNC, FREQ_1_MHZ, BUFFERS_COMMON, true, false> >)
#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 */

View File

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

View File

@@ -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 <stdlib.h>
#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<int BAUDRATE, int DATA_BITS, SerialParity PARITY, int STOP_BITS, bool INIT_DIRECT>
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<int BAUDRATE, int DATA_BITS, SerialParity PARITY, int STOP_BITS, bool INIT_DIRECT>
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<UARTNoFCPort, DefaultFormFactor, fpga_uart_init_free_test_no_fc>),
// One set of pins from every peripheral.
Case("basic, 9600, 8N1, FC off", all_peripherals<UARTNoFCPort, DefaultFormFactor, fpga_uart_test_common_no_fc<9600, 8, ParityNone, 1, false> >),
Case("basic (direct init), 9600, 8N1, FC off", all_peripherals<UARTNoFCPort, DefaultFormFactor, fpga_uart_test_common_no_fc<9600, 8, ParityNone, 1, true> >),
// same test with 7 and 9 bits data length
Case("basic, 9600, 7N1, FC off", all_peripherals<UARTNoFCPort, DefaultFormFactor, fpga_uart_test_common_no_fc<9600, 7, ParityNone, 1, false> >),
Case("basic, 9600, 9N1, FC off", all_peripherals<UARTNoFCPort, DefaultFormFactor, fpga_uart_test_common_no_fc<9600, 9, ParityNone, 1, false> >),
// One set of pins from one peripheral.
// baudrate
Case("19200, 8N1, FC off", one_peripheral<UARTNoFCPort, DefaultFormFactor, fpga_uart_test_common_no_fc<19200, 8, ParityNone, 1, false> >),
Case("38400, 8N1, FC off", one_peripheral<UARTNoFCPort, DefaultFormFactor, fpga_uart_test_common_no_fc<38400, 8, ParityNone, 1, false> >),
Case("115200, 8N1, FC off", one_peripheral<UARTNoFCPort, DefaultFormFactor, fpga_uart_test_common_no_fc<115200, 8, ParityNone, 1, false> >),
// stop bits
#if !defined(UART_TWO_STOP_BITS_NOT_SUPPORTED)
Case("9600, 8N2, FC off", one_peripheral<UARTNoFCPort, DefaultFormFactor, fpga_uart_test_common_no_fc<9600, 8, ParityNone, 2, false> >),
#endif
#if DEVICE_SERIAL_FC
// Every set of pins from every peripheral.
Case("init/free, FC on", all_ports<UARTPort, DefaultFormFactor, fpga_uart_init_free_test>),
// One set of pins from every peripheral.
Case("basic, 9600, 8N1, FC on", all_peripherals<UARTPort, DefaultFormFactor, fpga_uart_test_common<9600, 8, ParityNone, 1, false> >),
Case("basic (direct init), 9600, 8N1, FC on", all_peripherals<UARTPort, DefaultFormFactor, fpga_uart_test_common<9600, 8, ParityNone, 1, true> >),
// same test with 7 and 9 bits data length
Case("basic, 9600, 7N1, FC on", all_peripherals<UARTPort, DefaultFormFactor, fpga_uart_test_common<9600, 7, ParityNone, 1, false> >),
Case("basic, 9600, 9N1, FC on", all_peripherals<UARTPort, DefaultFormFactor, fpga_uart_test_common<9600, 9, ParityNone, 1, false> >),
// One set of pins from one peripheral.
// baudrate
Case("19200, 8N1, FC on", one_peripheral<UARTPort, DefaultFormFactor, fpga_uart_test_common<19200, 8, ParityNone, 1, false> >),
Case("38400, 8N1, FC on", one_peripheral<UARTPort, DefaultFormFactor, fpga_uart_test_common<38400, 8, ParityNone, 1, false> >),
Case("115200, 8N1, FC on", one_peripheral<UARTPort, DefaultFormFactor, fpga_uart_test_common<115200, 8, ParityNone, 1, false> >),
// 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<UARTPort, DefaultFormFactor, fpga_uart_test_common<9600, 8, ParityOdd, 1, false> >),
// same test with 7 and 9 bits data length
Case("9600, 7O1, FC on", one_peripheral<UARTPort, DefaultFormFactor, fpga_uart_test_common<9600, 7, ParityOdd, 1, false> >),
Case("9600, 9O1, FC on", one_peripheral<UARTPort, DefaultFormFactor, fpga_uart_test_common<9600, 9, ParityOdd, 1, false> >),
#endif
Case("9600, 8E1, FC on", one_peripheral<UARTPort, DefaultFormFactor, fpga_uart_test_common<9600, 8, ParityEven, 1, false> >),
// same test with 7 and 9 bits data length
Case("9600, 7E1, FC on", one_peripheral<UARTPort, DefaultFormFactor, fpga_uart_test_common<9600, 7, ParityEven, 1, false> >),
Case("9600, 9E1, FC on", one_peripheral<UARTPort, DefaultFormFactor, fpga_uart_test_common<9600, 9, ParityEven, 1, false> >),
// stop bits
#if !defined(UART_TWO_STOP_BITS_NOT_SUPPORTED)
Case("9600, 8N2, FC on", one_peripheral<UARTPort, DefaultFormFactor, fpga_uart_test_common<9600, 8, ParityNone, 2, false> >),
#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 */

View File

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