mirror of https://github.com/ARMmbed/mbed-os.git
Bring FPGA-Test-Shield tests into Mbed-os master.
parent
f18e3364e9
commit
cd0ad518cc
|
|
@ -0,0 +1,166 @@
|
|||
/*
|
||||
* 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
|
||||
#else
|
||||
|
||||
#include "utest/utest.h"
|
||||
#include "unity/unity.h"
|
||||
#include "greentea-client/test_env.h"
|
||||
|
||||
#include "mbed.h"
|
||||
#include "pinmap.h"
|
||||
#include "test_utils.h"
|
||||
#include "MbedTester.h"
|
||||
|
||||
using namespace utest::v1;
|
||||
|
||||
#define analogin_debug_printf(...)
|
||||
|
||||
#define DELTA_FLOAT 0.01f // 1%
|
||||
#define DELTA_U16 655 // 1%
|
||||
|
||||
const PinList *form_factor = pinmap_ff_default_pins();
|
||||
const PinList *restricted = pinmap_restricted_pins();
|
||||
|
||||
MbedTester tester(form_factor, restricted);
|
||||
|
||||
void analogin_init(PinName pin)
|
||||
{
|
||||
analogin_t analogin;
|
||||
|
||||
analogin_init(&analogin, pin);
|
||||
}
|
||||
|
||||
void analogin_test(PinName pin)
|
||||
{
|
||||
tester.reset();
|
||||
tester.pin_map_set(pin, MbedTester::LogicalPinGPIO0);
|
||||
tester.select_peripheral(MbedTester::PeripheralGPIO);
|
||||
|
||||
/* Test analog input */
|
||||
|
||||
analogin_t analogin;
|
||||
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);
|
||||
}
|
||||
|
||||
void analogin_full_test(PinName pin)
|
||||
{
|
||||
/* Test analog input */
|
||||
|
||||
printf("Testing AnalogIn\r\n");
|
||||
|
||||
// Remap pins for test
|
||||
tester.reset();
|
||||
|
||||
// Reset tester stats and select GPIO
|
||||
tester.peripherals_reset();
|
||||
tester.select_peripheral(MbedTester::PeripheralGPIO);
|
||||
|
||||
analogin_t analogin;
|
||||
analogin_init(&analogin, pin);
|
||||
|
||||
//enable analog MUX
|
||||
tester.set_mux_enable(true);
|
||||
|
||||
//set MUX address
|
||||
tester.set_mux_addr(pin);
|
||||
|
||||
float voltage = 0.0;
|
||||
bool enable = true;
|
||||
uint32_t period = 100;
|
||||
uint32_t duty_cycle = 0;
|
||||
//enable FPGA system PWM
|
||||
tester.set_analog_out(voltage, enable);
|
||||
|
||||
TEST_ASSERT_EQUAL(true, tester.get_pwm_enable());
|
||||
TEST_ASSERT_EQUAL(period, tester.get_pwm_period());
|
||||
TEST_ASSERT_EQUAL(duty_cycle, tester.get_pwm_cycles_high());
|
||||
// test duty cycles 0-100% at 1000ns period
|
||||
for (int i = 0; i < 11; i += 1) {
|
||||
voltage = (float)i * 0.1f;
|
||||
duty_cycle = 10 * i;
|
||||
tester.set_analog_out(voltage, enable);
|
||||
wait_us(10);
|
||||
//read analog input
|
||||
//assert pwm duty_cycle is correct based on set analog voltage
|
||||
TEST_ASSERT_EQUAL(duty_cycle, tester.get_pwm_cycles_high());
|
||||
TEST_ASSERT_FLOAT_WITHIN(DELTA_FLOAT, 0.01f * (float)duty_cycle, analogin_read(&analogin));
|
||||
}
|
||||
tester.set_pwm_enable(false);
|
||||
TEST_ASSERT_EQUAL(false, tester.get_pwm_enable());
|
||||
wait_us(10);
|
||||
|
||||
// assert Mbed pin correctly drives AnalogMuxIn
|
||||
tester.pin_map_set(pin, MbedTester::LogicalPinGPIO0);
|
||||
|
||||
tester.gpio_write(MbedTester::LogicalPinGPIO0, 0, true);
|
||||
TEST_ASSERT_EQUAL(0, tester.sys_pin_read(MbedTester::AnalogMuxIn));
|
||||
wait_us(10);
|
||||
tester.gpio_write(MbedTester::LogicalPinGPIO0, 1, true);
|
||||
TEST_ASSERT_EQUAL(1, tester.sys_pin_read(MbedTester::AnalogMuxIn));
|
||||
wait_us(10);
|
||||
tester.gpio_write(MbedTester::LogicalPinGPIO0, 0, true);
|
||||
TEST_ASSERT_EQUAL(0, tester.sys_pin_read(MbedTester::AnalogMuxIn));
|
||||
wait_us(10);
|
||||
tester.gpio_write(MbedTester::LogicalPinGPIO0, 0, false);
|
||||
wait_us(10);
|
||||
tester.set_mux_enable(false);
|
||||
wait_us(10);
|
||||
|
||||
TEST_ASSERT_EQUAL(1, tester.self_test_control_current());//assert control channel still functioning properly
|
||||
}
|
||||
|
||||
Case cases[] = {
|
||||
// This will be run for all pins
|
||||
Case("AnalogIn - init test", all_ports<AnaloginPort, DefaultFormFactor, analogin_init>),
|
||||
#if defined(FULL_TEST_SHIELD)
|
||||
Case("AnalogIn - full test", all_ports<AnaloginPort, DefaultFormFactor, analogin_full_test>),
|
||||
#endif
|
||||
|
||||
// This will be run for single pin
|
||||
Case("AnalogIn - read test", all_ports<AnaloginPort, DefaultFormFactor, analogin_test>),
|
||||
};
|
||||
|
||||
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 */
|
||||
|
|
@ -0,0 +1,126 @@
|
|||
/*
|
||||
* 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_ANALOGOUT
|
||||
#error [NOT_SUPPORTED] Analog out not supported for this target
|
||||
#elif !COMPONENT_FPGA_CI_TEST_SHIELD
|
||||
#error [NOT_SUPPORTED] FPGA CI Test Shield is needed to run this test
|
||||
#else
|
||||
|
||||
#include "utest/utest.h"
|
||||
#include "unity/unity.h"
|
||||
#include "greentea-client/test_env.h"
|
||||
#include <inttypes.h>
|
||||
#include "mbed.h"
|
||||
|
||||
using namespace utest::v1;
|
||||
|
||||
#include "MbedTester.h"
|
||||
#include "pinmap.h"
|
||||
#include "test_utils.h"
|
||||
|
||||
#if !DEVICE_ANALOGOUT
|
||||
#error [NOT_SUPPORTED] Analog out not supported for this target
|
||||
#endif
|
||||
|
||||
#define analogout_debug_printf(...)
|
||||
|
||||
#define DELTA_FLOAT 0.01f // 1%
|
||||
|
||||
const PinList *form_factor = pinmap_ff_default_pins();
|
||||
const PinList *restricted = pinmap_restricted_pins();
|
||||
|
||||
MbedTester tester(form_factor, restricted);
|
||||
|
||||
void analogout_init_free(PinName pin)
|
||||
{
|
||||
dac_t analogout;
|
||||
|
||||
analogout_debug_printf("Analog output init/free test on pin=%s (%i)\r\n", pinmap_ff_default_pin_to_string(pin), pin);
|
||||
|
||||
analogout_init(&analogout, pin);
|
||||
analogout_free(&analogout);
|
||||
}
|
||||
|
||||
void analogout_test(PinName pin)
|
||||
{
|
||||
analogout_debug_printf("Analog input test on pin %s (%i)\r\n", pinmap_ff_default_pin_to_string(pin), pin);
|
||||
|
||||
tester.reset();
|
||||
tester.peripherals_reset();
|
||||
|
||||
/* Test analog input */
|
||||
|
||||
dac_t analogout;
|
||||
analogout_init(&analogout, pin);
|
||||
|
||||
tester.set_sample_adc(true);//begin ADC sampling on the FPGA
|
||||
|
||||
float anin;
|
||||
float i;
|
||||
for (i = 0.0f; i < 0.304f; i += 0.0303f) {//0V-1V, float
|
||||
analogout_write(&analogout, i);
|
||||
anin = tester.get_analog_in();
|
||||
TEST_ASSERT_FLOAT_WITHIN(DELTA_FLOAT, (i * 3.3f), anin);
|
||||
}
|
||||
|
||||
i = 0.0f;
|
||||
for (uint16_t i_d16 = 0; i_d16 < 19851; i_d16 += 1985) {//0V-1V, 16-bit
|
||||
analogout_write_u16(&analogout, i_d16);
|
||||
anin = tester.get_analog_in();
|
||||
TEST_ASSERT_FLOAT_WITHIN(DELTA_FLOAT, (i * 3.3f), anin);
|
||||
i += 0.0303f;
|
||||
}
|
||||
|
||||
analogout_free(&analogout);
|
||||
|
||||
tester.set_sample_adc(false);//stop ADC sampling on the FPGA
|
||||
|
||||
// power analysis
|
||||
// uint64_t sum;
|
||||
// uint32_t samples;
|
||||
// uint64_t cycles;
|
||||
// tester.get_anin_sum_samples_cycles(0, &sum, &samples, &cycles);
|
||||
// printf("ANIN0\r\n");
|
||||
// printf("Sum: %llu\r\n", sum);
|
||||
// printf("Num power samples: %d\r\n", samples);
|
||||
// printf("Num power cycles: %llu\r\n", cycles);
|
||||
// printf("ANIN0 voltage: %.6fV\r\n", tester.get_anin_voltage(0));
|
||||
}
|
||||
|
||||
Case cases[] = {
|
||||
// This will be run for all pins
|
||||
Case("Analogout - init test", all_ports<AnalogoutPort, DefaultFormFactor, analogout_init_free>),
|
||||
|
||||
// This will be run for single pin
|
||||
Case("Analogout - write/read test", all_ports<AnalogoutPort, DefaultFormFactor, analogout_test>),
|
||||
};
|
||||
|
||||
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_ANALOGOUT */
|
||||
|
|
@ -0,0 +1,112 @@
|
|||
/*
|
||||
* 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 !COMPONENT_FPGA_CI_TEST_SHIELD
|
||||
#error [NOT_SUPPORTED] FPGA CI Test Shield is needed to run this test
|
||||
#else
|
||||
|
||||
#include "utest/utest.h"
|
||||
#include "unity/unity.h"
|
||||
#include "greentea-client/test_env.h"
|
||||
#include "mbed.h"
|
||||
|
||||
using namespace utest::v1;
|
||||
|
||||
#include "MbedTester.h"
|
||||
#include "pinmap.h"
|
||||
|
||||
const PinList *form_factor = pinmap_ff_default_pins();
|
||||
const PinList *restricted = pinmap_restricted_pins();
|
||||
MbedTester tester(form_factor, restricted);
|
||||
|
||||
void gpio_inout_test(PinName pin)
|
||||
{
|
||||
gpio_t gpio;
|
||||
gpio_init_inout(&gpio, pin, PIN_OUTPUT, PullNone, 0);
|
||||
TEST_ASSERT_EQUAL(0, tester.gpio_read(MbedTester::LogicalPinGPIO0));
|
||||
|
||||
/* Test GPIO output */
|
||||
|
||||
gpio_write(&gpio, 1);
|
||||
TEST_ASSERT_EQUAL(1, tester.gpio_read(MbedTester::LogicalPinGPIO0));
|
||||
|
||||
gpio_write(&gpio, 0);
|
||||
TEST_ASSERT_EQUAL(0, tester.gpio_read(MbedTester::LogicalPinGPIO0));
|
||||
|
||||
gpio_dir(&gpio, PIN_INPUT);
|
||||
|
||||
/* Test GPIO input */
|
||||
|
||||
tester.gpio_write(MbedTester::LogicalPinGPIO0, 0, true);
|
||||
TEST_ASSERT_EQUAL(0, gpio_read(&gpio));
|
||||
|
||||
tester.gpio_write(MbedTester::LogicalPinGPIO0, 1, true);
|
||||
TEST_ASSERT_EQUAL(1, gpio_read(&gpio));
|
||||
|
||||
/* Set gpio back to Hi-Z */
|
||||
|
||||
tester.gpio_write(MbedTester::LogicalPinGPIO0, 0, false);
|
||||
}
|
||||
|
||||
void gpio_inout_test()
|
||||
{
|
||||
for (int i = 0; i < form_factor->count; i++) {
|
||||
const PinName test_pin = form_factor->pins[i];
|
||||
if (pinmap_list_has_pin(restricted, test_pin)) {
|
||||
printf("Skipping gpio pin %s (%i)\r\n", pinmap_ff_default_pin_to_string(test_pin), test_pin);
|
||||
continue;
|
||||
}
|
||||
tester.pin_map_reset();
|
||||
tester.pin_map_set(test_pin, MbedTester::LogicalPinGPIO0);
|
||||
|
||||
printf("GPIO test on pin %s (%i)\r\n", pinmap_ff_default_pin_to_string(test_pin), test_pin);
|
||||
gpio_inout_test(test_pin);
|
||||
}
|
||||
}
|
||||
|
||||
utest::v1::status_t setup(const Case *const source, const size_t index_of_case)
|
||||
{
|
||||
tester.reset();
|
||||
tester.select_peripheral(MbedTester::PeripheralGPIO);
|
||||
|
||||
return greentea_case_setup_handler(source, index_of_case);
|
||||
}
|
||||
|
||||
utest::v1::status_t teardown(const Case *const source, const size_t passed, const size_t failed,
|
||||
const failure_t reason)
|
||||
{
|
||||
return greentea_case_teardown_handler(source, passed, failed, reason);
|
||||
}
|
||||
|
||||
Case cases[] = {
|
||||
Case("GPIO - inout", setup, gpio_inout_test, teardown),
|
||||
};
|
||||
|
||||
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 */
|
||||
|
|
@ -0,0 +1,294 @@
|
|||
/*
|
||||
* 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
|
||||
#else
|
||||
|
||||
#include "utest/utest.h"
|
||||
#include "unity/unity.h"
|
||||
#include "greentea-client/test_env.h"
|
||||
#include "mbed.h"
|
||||
|
||||
using namespace utest::v1;
|
||||
|
||||
#include "mbed.h"
|
||||
#include "MbedTester.h"
|
||||
#include "pinmap.h"
|
||||
|
||||
static uint32_t call_counter;
|
||||
void test_gpio_irq_handler(uint32_t id, gpio_irq_event event)
|
||||
{
|
||||
call_counter++;
|
||||
}
|
||||
|
||||
const PinList *form_factor = pinmap_ff_default_pins();
|
||||
const PinList *restricted = pinmap_restricted_pins();
|
||||
MbedTester tester(form_factor, restricted);
|
||||
|
||||
#define WAIT() wait_us(10)
|
||||
|
||||
|
||||
void gpio_irq_test(PinName pin)
|
||||
{
|
||||
gpio_t gpio;
|
||||
// configure pin as input
|
||||
gpio_init_in(&gpio, pin);
|
||||
|
||||
gpio_irq_t gpio_irq;
|
||||
uint32_t id = 123;
|
||||
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 gpio_irq_test()
|
||||
{
|
||||
for (uint32_t i = 0; i < form_factor->count; i++) {
|
||||
const PinName test_pin = form_factor->pins[i];
|
||||
if (pinmap_list_has_pin(restricted, test_pin)) {
|
||||
printf("Skipping gpio pin %s (%i)\r\n", pinmap_ff_default_pin_to_string(test_pin), test_pin);
|
||||
continue;
|
||||
}
|
||||
tester.pin_map_reset();
|
||||
tester.pin_map_set(test_pin, MbedTester::LogicalPinGPIO0);
|
||||
|
||||
printf("GPIO irq test on pin %3s (%3i)\r\n", pinmap_ff_default_pin_to_string(test_pin), test_pin);
|
||||
gpio_irq_test(test_pin);
|
||||
}
|
||||
}
|
||||
|
||||
utest::v1::status_t setup(const Case *const source, const size_t index_of_case)
|
||||
{
|
||||
tester.reset();
|
||||
tester.select_peripheral(MbedTester::PeripheralGPIO);
|
||||
|
||||
return greentea_case_setup_handler(source, index_of_case);
|
||||
}
|
||||
|
||||
utest::v1::status_t teardown(const Case *const source, const size_t passed, const size_t failed,
|
||||
const failure_t reason)
|
||||
{
|
||||
return greentea_case_teardown_handler(source, passed, failed, reason);
|
||||
}
|
||||
|
||||
Case cases[] = {
|
||||
Case("GPIO - irq test", setup, gpio_irq_test, teardown)
|
||||
};
|
||||
|
||||
utest::v1::status_t greentea_test_setup(const size_t number_of_cases)
|
||||
{
|
||||
GREENTEA_SETUP(10, "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 */
|
||||
|
|
@ -0,0 +1,328 @@
|
|||
/*
|
||||
* 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(FULL_TEST_SHIELD)
|
||||
#error [NOT_SUPPORTED] The I2C test does not run on prototype hardware
|
||||
#else
|
||||
|
||||
#include "utest/utest.h"
|
||||
#include "unity/unity.h"
|
||||
#include "greentea-client/test_env.h"
|
||||
#include "mbed.h"
|
||||
|
||||
#include "mbed.h"
|
||||
#include "i2c_api.h"
|
||||
#include "pinmap.h"
|
||||
#include "test_utils.h"
|
||||
#include "I2CTester.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 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);
|
||||
}
|
||||
|
||||
void i2c_test_all(PinName sda, PinName scl)
|
||||
{
|
||||
// Remap pins for test
|
||||
tester.reset();
|
||||
tester.pin_map_set(sda, MbedTester::LogicalPinI2CSda);
|
||||
tester.pin_map_set(scl, MbedTester::LogicalPinI2CScl);
|
||||
|
||||
// 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
|
||||
|
||||
printf("I2C complete write transaction test on sda=%s (%i), scl=%s (%i)\r\n",
|
||||
pinmap_ff_default_pin_to_string(sda), sda,
|
||||
pinmap_ff_default_pin_to_string(scl), scl);
|
||||
|
||||
// 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;
|
||||
tester.io_metrics_start();
|
||||
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;
|
||||
tester.io_metrics_stop();
|
||||
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());
|
||||
|
||||
printf(" Pin combination works\r\n");
|
||||
|
||||
printf("I2C complete read transaction test on sda=%s (%i), scl=%s (%i)\r\n",
|
||||
pinmap_ff_default_pin_to_string(sda), sda,
|
||||
pinmap_ff_default_pin_to_string(scl), scl);
|
||||
|
||||
// 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;
|
||||
tester.io_metrics_start();
|
||||
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_dev_addr_matches += 1;
|
||||
tester.io_metrics_stop();
|
||||
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_receive_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());
|
||||
|
||||
printf(" Pin combination works\r\n");
|
||||
|
||||
printf("I2C write single bytes test on sda=%s (%i), scl=%s (%i)\r\n",
|
||||
pinmap_ff_default_pin_to_string(sda), sda,
|
||||
pinmap_ff_default_pin_to_string(scl), scl);
|
||||
|
||||
// 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;
|
||||
tester.io_metrics_start();
|
||||
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;
|
||||
tester.io_metrics_stop();
|
||||
|
||||
// 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());
|
||||
|
||||
printf(" Pin combination works\r\n");
|
||||
|
||||
printf("I2C read single bytes test on sda=%s (%i), scl=%s (%i)\r\n",
|
||||
pinmap_ff_default_pin_to_string(sda), sda,
|
||||
pinmap_ff_default_pin_to_string(scl), scl);
|
||||
|
||||
// Reset tester stats and select I2C
|
||||
tester.peripherals_reset();
|
||||
tester.select_peripheral(MbedTester::PeripheralI2C);
|
||||
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;
|
||||
tester.io_metrics_start();
|
||||
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;
|
||||
} else {
|
||||
data_in[i] = i2c_byte_read(&i2c, 0);//send ACK
|
||||
checksum += data_in[i];
|
||||
num_reads += 1;
|
||||
}
|
||||
}
|
||||
|
||||
i2c_stop(&i2c);
|
||||
num_stops += 1;
|
||||
tester.io_metrics_stop();
|
||||
|
||||
// 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_receive_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());
|
||||
|
||||
printf(" Pin combination works\r\n");
|
||||
|
||||
tester.reset();
|
||||
}
|
||||
|
||||
Case cases[] = {
|
||||
Case("i2c - init/free test all pins", all_ports<I2CPort, DefaultFormFactor, test_i2c_init_free>),
|
||||
Case("i2c - test all i2c APIs", all_peripherals<I2CPort, DefaultFormFactor, i2c_test_all>)
|
||||
// Case("i2c - simple write test all peripherals", all_peripherals<I2CPort, DefaultFormFactor, test_i2c_simple_write>),
|
||||
// Case("i2c - simple read test all peripherals", all_peripherals<I2CPort, DefaultFormFactor, test_i2c_simple_read>),
|
||||
// Case("i2c - XXXXXXX test single pin", one_peripheral<I2CPort, DefaultFormFactor, test_i2c_XXXXXXX>)
|
||||
};
|
||||
|
||||
utest::v1::status_t greentea_test_setup(const size_t number_of_cases)
|
||||
{
|
||||
GREENTEA_SETUP(15, "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 */
|
||||
|
|
@ -0,0 +1,224 @@
|
|||
/*
|
||||
* 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
|
||||
#else
|
||||
|
||||
#include "utest/utest.h"
|
||||
#include "unity/unity.h"
|
||||
#include "greentea-client/test_env.h"
|
||||
#include "mbed.h"
|
||||
|
||||
using namespace utest::v1;
|
||||
|
||||
#include "MbedTester.h"
|
||||
#include "pinmap.h"
|
||||
#include "test_utils.h"
|
||||
|
||||
|
||||
#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 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 pwm_period_fill_test(PinName pin, uint32_t period_ms, uint32_t fill_prc, pwm_api_test_t api_test)
|
||||
{
|
||||
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;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
tester.io_metrics_start();
|
||||
|
||||
wait(NUM_OF_PERIODS * PERIOD_FLOAT(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>
|
||||
void pwm_period_fill_test(PinName pin)
|
||||
{
|
||||
pwm_period_fill_test(pin, period_ms, fill_prc, api_test);
|
||||
}
|
||||
|
||||
|
||||
Case cases[] = {
|
||||
// This will be run for all pins
|
||||
Case("PWM - init/free test", all_ports<PWMPort, DefaultFormFactor, pwm_init_free>),
|
||||
|
||||
// This will be run for single pin
|
||||
Case("PWM - period: 10 ms, fill: 10%, api: period/write", one_peripheral<PWMPort, DefaultFormFactor, pwm_period_fill_test<10, 10, PERIOD_WRITE> >),
|
||||
|
||||
Case("PWM - period: 10 ms, fill: 10%, api: period_ms/write", one_peripheral<PWMPort, DefaultFormFactor, pwm_period_fill_test<10, 10, PERIOD_MS_WRITE> >),
|
||||
Case("PWM - period: 10 ms, fill: 10%, api: period_us/write", one_peripheral<PWMPort, DefaultFormFactor, pwm_period_fill_test<10, 10, PERIOD_US_WRITE> >),
|
||||
Case("PWM - period: 10 ms, fill: 10%, api: period/pulse_width", one_peripheral<PWMPort, DefaultFormFactor, pwm_period_fill_test<10, 10, PERIOD_PULSEWIDTH> >),
|
||||
Case("PWM - period: 10 ms, fill: 10%, api: period/pulse_width_ms", one_peripheral<PWMPort, DefaultFormFactor, pwm_period_fill_test<10, 10, PERIOD_PULSEWIDTH_MS> >),
|
||||
Case("PWM - period: 10 ms, fill: 10%, api: period/pulse_width_us", one_peripheral<PWMPort, DefaultFormFactor, pwm_period_fill_test<10, 10, PERIOD_PULSEWIDTH_US> >),
|
||||
|
||||
Case("PWM - period: 10 ms, fill: 50%, api: period/write", one_peripheral<PWMPort, DefaultFormFactor, pwm_period_fill_test<10, 50, PERIOD_WRITE> >),
|
||||
Case("PWM - period: 10 ms, fill: 50%, api: period_ms/write", one_peripheral<PWMPort, DefaultFormFactor, pwm_period_fill_test<10, 50, PERIOD_MS_WRITE> >),
|
||||
Case("PWM - period: 10 ms, fill: 50%, api: period_us/write", one_peripheral<PWMPort, DefaultFormFactor, pwm_period_fill_test<10, 50, PERIOD_US_WRITE> >),
|
||||
Case("PWM - period: 10 ms, fill: 50%, api: period/pulse_width", one_peripheral<PWMPort, DefaultFormFactor, pwm_period_fill_test<10, 50, PERIOD_PULSEWIDTH> >),
|
||||
Case("PWM - period: 10 ms, fill: 50%, api: period/pulse_width_ms", one_peripheral<PWMPort, DefaultFormFactor, pwm_period_fill_test<10, 50, PERIOD_PULSEWIDTH_MS> >),
|
||||
Case("PWM - period: 10 ms, fill: 50%, api: period/pulse_width_us", one_peripheral<PWMPort, DefaultFormFactor, pwm_period_fill_test<10, 50, PERIOD_PULSEWIDTH_US> >),
|
||||
|
||||
Case("PWM - period: 10 ms, fill: 90%, api: period/write", one_peripheral<PWMPort, DefaultFormFactor, pwm_period_fill_test<10, 90, PERIOD_WRITE> >),
|
||||
Case("PWM - period: 10 ms, fill: 90%, api: period_ms/write", one_peripheral<PWMPort, DefaultFormFactor, pwm_period_fill_test<10, 90, PERIOD_MS_WRITE> >),
|
||||
Case("PWM - period: 10 ms, fill: 90%, api: period_us/write", one_peripheral<PWMPort, DefaultFormFactor, pwm_period_fill_test<10, 90, PERIOD_US_WRITE> >),
|
||||
Case("PWM - period: 10 ms, fill: 90%, api: period/pulse_width", one_peripheral<PWMPort, DefaultFormFactor, pwm_period_fill_test<10, 90, PERIOD_PULSEWIDTH> >),
|
||||
Case("PWM - period: 10 ms, fill: 90%, api: period/pulse_width_ms", one_peripheral<PWMPort, DefaultFormFactor, pwm_period_fill_test<10, 90, PERIOD_PULSEWIDTH_MS> >),
|
||||
Case("PWM - period: 10 ms, fill: 90%, api: period/pulse_width_us", one_peripheral<PWMPort, DefaultFormFactor, pwm_period_fill_test<10, 90, PERIOD_PULSEWIDTH_US> >),
|
||||
|
||||
Case("PWM - period: 50 ms, fill: 10%, api: period/write", one_peripheral<PWMPort, DefaultFormFactor, pwm_period_fill_test<50, 10, PERIOD_WRITE> >),
|
||||
Case("PWM - period: 50 ms, fill: 10%, api: period_ms/write", one_peripheral<PWMPort, DefaultFormFactor, pwm_period_fill_test<50, 10, PERIOD_MS_WRITE> >),
|
||||
Case("PWM - period: 50 ms, fill: 10%, api: period_us/write", one_peripheral<PWMPort, DefaultFormFactor, pwm_period_fill_test<50, 10, PERIOD_US_WRITE> >),
|
||||
Case("PWM - period: 50 ms, fill: 10%, api: period/pulse_width", one_peripheral<PWMPort, DefaultFormFactor, pwm_period_fill_test<50, 10, PERIOD_PULSEWIDTH> >),
|
||||
Case("PWM - period: 50 ms, fill: 10%, api: period/pulse_width_ms", one_peripheral<PWMPort, DefaultFormFactor, pwm_period_fill_test<50, 10, PERIOD_PULSEWIDTH_MS> >),
|
||||
Case("PWM - period: 50 ms, fill: 10%, api: period/pulse_width_us", one_peripheral<PWMPort, DefaultFormFactor, pwm_period_fill_test<50, 10, PERIOD_PULSEWIDTH_US> >),
|
||||
|
||||
Case("PWM - period: 50 ms, fill: 50%, api: period/write", one_peripheral<PWMPort, DefaultFormFactor, pwm_period_fill_test<50, 50, PERIOD_WRITE> >),
|
||||
Case("PWM - period: 50 ms, fill: 50%, api: period_ms/write", one_peripheral<PWMPort, DefaultFormFactor, pwm_period_fill_test<50, 50, PERIOD_MS_WRITE> >),
|
||||
Case("PWM - period: 50 ms, fill: 50%, api: period_us/write", one_peripheral<PWMPort, DefaultFormFactor, pwm_period_fill_test<50, 50, PERIOD_US_WRITE> >),
|
||||
Case("PWM - period: 50 ms, fill: 50%, api: period/pulse_width", one_peripheral<PWMPort, DefaultFormFactor, pwm_period_fill_test<50, 50, PERIOD_PULSEWIDTH> >),
|
||||
Case("PWM - period: 50 ms, fill: 50%, api: period/pulse_width_ms", one_peripheral<PWMPort, DefaultFormFactor, pwm_period_fill_test<50, 50, PERIOD_PULSEWIDTH_MS> >),
|
||||
Case("PWM - period: 50 ms, fill: 50%, api: period/pulse_width_us", one_peripheral<PWMPort, DefaultFormFactor, pwm_period_fill_test<50, 50, PERIOD_PULSEWIDTH_US> >),
|
||||
|
||||
Case("PWM - period: 50 ms, fill: 90%, api: period/write", one_peripheral<PWMPort, DefaultFormFactor, pwm_period_fill_test<50, 90, PERIOD_WRITE> >),
|
||||
Case("PWM - period: 50 ms, fill: 90%, api: period_ms/write", one_peripheral<PWMPort, DefaultFormFactor, pwm_period_fill_test<50, 90, PERIOD_MS_WRITE> >),
|
||||
Case("PWM - period: 50 ms, fill: 90%, api: period_us/write", one_peripheral<PWMPort, DefaultFormFactor, pwm_period_fill_test<50, 90, PERIOD_US_WRITE> >),
|
||||
Case("PWM - period: 50 ms, fill: 90%, api: period/pulse_width", one_peripheral<PWMPort, DefaultFormFactor, pwm_period_fill_test<50, 90, PERIOD_PULSEWIDTH> >),
|
||||
Case("PWM - period: 50 ms, fill: 90%, api: period/pulse_width_ms", one_peripheral<PWMPort, DefaultFormFactor, pwm_period_fill_test<50, 90, PERIOD_PULSEWIDTH_MS> >),
|
||||
Case("PWM - period: 50 ms, fill: 90%, api: period/pulse_width_us", one_peripheral<PWMPort, DefaultFormFactor, pwm_period_fill_test<50, 90, PERIOD_PULSEWIDTH_US> >)
|
||||
};
|
||||
|
||||
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_PWMOUT */
|
||||
|
|
@ -0,0 +1,127 @@
|
|||
/*
|
||||
* 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
|
||||
#else
|
||||
|
||||
#include "utest/utest.h"
|
||||
#include "unity/unity.h"
|
||||
#include "greentea-client/test_env.h"
|
||||
#include "mbed.h"
|
||||
|
||||
using namespace utest::v1;
|
||||
|
||||
#include "SPIMasterTester.h"
|
||||
#include "pinmap.h"
|
||||
#include "test_utils.h"
|
||||
|
||||
|
||||
const int TRANSFER_COUNT = 300;
|
||||
SPIMasterTester tester(DefaultFormFactor::pins(), DefaultFormFactor::restricted_pins());
|
||||
|
||||
|
||||
void spi_test_init_free(PinName mosi, PinName miso, PinName sclk, PinName ssel)
|
||||
{
|
||||
spi_t spi;
|
||||
spi_init(&spi, mosi, miso, sclk, ssel);
|
||||
spi_format(&spi, 8, SPITester::Mode0, 0);
|
||||
spi_frequency(&spi, 1000000);
|
||||
spi_free(&spi);
|
||||
}
|
||||
|
||||
void spi_test_common(PinName mosi, PinName miso, PinName sclk, PinName ssel, SPITester::SpiMode spi_mode, uint32_t sym_size)
|
||||
{
|
||||
uint32_t sym_mask = ((1 << sym_size) - 1);
|
||||
// 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);
|
||||
|
||||
// Initialize mbed SPI pins
|
||||
spi_t spi;
|
||||
spi_init(&spi, mosi, miso, sclk, ssel);
|
||||
spi_format(&spi, sym_size, spi_mode, 0);
|
||||
spi_frequency(&spi, 1000000);
|
||||
|
||||
// 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);
|
||||
|
||||
// Send and receive test data
|
||||
uint32_t checksum = 0;
|
||||
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;
|
||||
}
|
||||
|
||||
// Verify that the transfer was successful
|
||||
TEST_ASSERT_EQUAL(TRANSFER_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>
|
||||
void spi_test_common(PinName mosi, PinName miso, PinName sclk, PinName ssel)
|
||||
{
|
||||
spi_test_common(mosi, miso, sclk, ssel, spi_mode, sym_size);
|
||||
}
|
||||
|
||||
Case cases[] = {
|
||||
// This will be run for all pins
|
||||
Case("SPI - init/free test all pins", all_ports<SPIPort, DefaultFormFactor, spi_test_init_free>),
|
||||
|
||||
// This will be run for all peripherals
|
||||
Case("SPI - basic test", all_peripherals<SPIPort, DefaultFormFactor, spi_test_common<SPITester::Mode0, 8> >),
|
||||
|
||||
// This will be run for single pin configuration
|
||||
Case("SPI - mode testing (MODE_1)", one_peripheral<SPIPort, DefaultFormFactor, spi_test_common<SPITester::Mode1, 8> >),
|
||||
Case("SPI - mode testing (MODE_2)", one_peripheral<SPIPort, DefaultFormFactor, spi_test_common<SPITester::Mode2, 8> >),
|
||||
Case("SPI - mode testing (MODE_3)", one_peripheral<SPIPort, DefaultFormFactor, spi_test_common<SPITester::Mode3, 8> >),
|
||||
|
||||
Case("SPI - symbol size testing (4)", one_peripheral<SPIPort, DefaultFormFactor, spi_test_common<SPITester::Mode0, 4> >),
|
||||
Case("SPI - symbol size testing (12)", one_peripheral<SPIPort, DefaultFormFactor, spi_test_common<SPITester::Mode0, 12> >),
|
||||
Case("SPI - symbol size testing (16)", one_peripheral<SPIPort, DefaultFormFactor, spi_test_common<SPITester::Mode0, 16> >)
|
||||
};
|
||||
|
||||
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 */
|
||||
|
|
@ -0,0 +1,353 @@
|
|||
/*
|
||||
* 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
|
||||
#else
|
||||
|
||||
#include "utest/utest.h"
|
||||
#include "unity/unity.h"
|
||||
#include "greentea-client/test_env.h"
|
||||
|
||||
using namespace utest::v1;
|
||||
|
||||
#include <stdlib.h>
|
||||
#include "UARTTester.h"
|
||||
#include "pinmap.h"
|
||||
#include "test_utils.h"
|
||||
#include "serial_api.h"
|
||||
#include "us_ticker_api.h"
|
||||
|
||||
#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, PinName tx, PinName rx, PinName cts = NC, PinName rts = NC)
|
||||
{
|
||||
// The FPGA CI shield only supports None, Odd & Even.
|
||||
// Forced parity is not supported on Atmel, Freescale, Nordic & STM targets.
|
||||
MBED_ASSERT(parity != ParityForced1 && parity != ParityForced0);
|
||||
|
||||
// STM-specific constraints
|
||||
// Only 7, 8 & 9 data bits.
|
||||
MBED_ASSERT(data_bits >= 7 && data_bits <= 9);
|
||||
// Only Odd or Even parity for 7 data bits.
|
||||
if (data_bits == 7) {
|
||||
MBED_ASSERT(parity != ParityNone);
|
||||
}
|
||||
|
||||
// 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;
|
||||
serial_init(&serial, tx, rx);
|
||||
serial_baud(&serial, baudrate);
|
||||
serial_format(&serial, data_bits, parity, stop_bits);
|
||||
if (use_flow_control) {
|
||||
serial_set_flow_control(&serial, FlowControlRTSCTS, rts, cts);
|
||||
} else {
|
||||
serial_set_flow_control(&serial, FlowControlNone, NC, NC);
|
||||
}
|
||||
|
||||
// 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 test_init_free(PinName tx, PinName rx, PinName cts = NC, PinName rts = NC)
|
||||
{
|
||||
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 (use_flow_control) {
|
||||
serial_set_flow_control(&serial, FlowControlRTSCTS, rts, cts);
|
||||
}
|
||||
serial_free(&serial);
|
||||
}
|
||||
|
||||
void test_init_free_no_fc(PinName tx, PinName rx)
|
||||
{
|
||||
test_init_free(tx, rx);
|
||||
}
|
||||
|
||||
template<int BAUDRATE, int DATA_BITS, SerialParity PARITY, int STOP_BITS>
|
||||
void test_common(PinName tx, PinName rx, PinName cts, PinName rts)
|
||||
{
|
||||
uart_test_common(BAUDRATE, DATA_BITS, PARITY, STOP_BITS, tx, rx, cts, rts);
|
||||
}
|
||||
|
||||
template<int BAUDRATE, int DATA_BITS, SerialParity PARITY, int STOP_BITS>
|
||||
void test_common_no_fc(PinName tx, PinName rx)
|
||||
{
|
||||
uart_test_common(BAUDRATE, DATA_BITS, PARITY, STOP_BITS, tx, rx);
|
||||
}
|
||||
|
||||
Case cases[] = {
|
||||
// Every set of pins from every peripheral.
|
||||
Case("init/free, FC on", all_ports<UARTPort, DefaultFormFactor, test_init_free>),
|
||||
Case("init/free, FC off", all_ports<UARTNoFCPort, DefaultFormFactor, test_init_free_no_fc>),
|
||||
|
||||
// One set of pins from every peripheral.
|
||||
Case("basic, 9600, 8N1, FC on", all_peripherals<UARTPort, DefaultFormFactor, test_common<9600, 8, ParityNone, 1> >),
|
||||
Case("basic, 9600, 8N1, FC off", all_peripherals<UARTNoFCPort, DefaultFormFactor, test_common_no_fc<9600, 8, ParityNone, 1> >),
|
||||
|
||||
// One set of pins from one peripheral.
|
||||
// baudrate
|
||||
Case("19200, 8N1, FC on", one_peripheral<UARTPort, DefaultFormFactor, test_common<19200, 8, ParityNone, 1> >),
|
||||
Case("19200, 8N1, FC off", one_peripheral<UARTNoFCPort, DefaultFormFactor, test_common_no_fc<19200, 8, ParityNone, 1> >),
|
||||
Case("38400, 8N1, FC on", one_peripheral<UARTPort, DefaultFormFactor, test_common<38400, 8, ParityNone, 1> >),
|
||||
Case("38400, 8N1, FC off", one_peripheral<UARTNoFCPort, DefaultFormFactor, test_common_no_fc<38400, 8, ParityNone, 1> >),
|
||||
Case("115200, 8N1, FC on", one_peripheral<UARTPort, DefaultFormFactor, test_common<115200, 8, ParityNone, 1> >),
|
||||
Case("115200, 8N1, FC off", one_peripheral<UARTNoFCPort, DefaultFormFactor, test_common_no_fc<115200, 8, ParityNone, 1> >), // DISCO_L475VG_IOT01A
|
||||
// data bits
|
||||
/* FIXME not supported: K64F
|
||||
Case("9600, 7O1, FC on", one_peripheral<UARTPort, DefaultFormFactor, test_common<9600, 7, ParityOdd, 1> >),
|
||||
Case("9600, 7O1, FC off", one_peripheral<UARTNoFCPort, DefaultFormFactor, test_common_no_fc<9600, 7, ParityOdd, 1> >),
|
||||
Case("9600, 9N1, FC on", one_peripheral<UARTPort, DefaultFormFactor, test_common<9600, 9, ParityNone, 1> >),
|
||||
Case("9600, 9N1, FC off", one_peripheral<UARTNoFCPort, DefaultFormFactor, test_common_no_fc<9600, 9, ParityNone, 1> >),
|
||||
*/
|
||||
// parity
|
||||
Case("9600, 8O1, FC on", one_peripheral<UARTPort, DefaultFormFactor, test_common<9600, 8, ParityOdd, 1> >),
|
||||
/* FIXME not supported: NUCLEO_F429ZI, NUCLEO_F746ZG, NUCLEO_F207ZG
|
||||
Case("9600, 8O1, FC off", one_peripheral<UARTNoFCPort, DefaultFormFactor, test_common_no_fc<9600, 8, ParityOdd, 1> >),
|
||||
*/
|
||||
Case("9600, 8E1, FC on", one_peripheral<UARTPort, DefaultFormFactor, test_common<9600, 8, ParityEven, 1> >),
|
||||
/* FIXME not supported: NUCLEO_F429ZI, NUCLEO_F746ZG, NUCLEO_F207ZG
|
||||
Case("9600, 8E1, FC off", one_peripheral<UARTNoFCPort, DefaultFormFactor, test_common_no_fc<9600, 8, ParityEven, 1> >),
|
||||
*/
|
||||
// stop bits
|
||||
Case("9600, 8N2, FC on", one_peripheral<UARTPort, DefaultFormFactor, test_common<9600, 8, ParityNone, 2> >),
|
||||
Case("9600, 8N2, FC off", one_peripheral<UARTNoFCPort, DefaultFormFactor, test_common_no_fc<9600, 8, ParityNone, 2> >),
|
||||
};
|
||||
|
||||
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 */
|
||||
Loading…
Reference in New Issue