Skip to content

HAL: Add a get_capabilities() function to GPIO API #12477

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Feb 24, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 9 additions & 1 deletion TESTS/mbed_hal_fpga_ci_test_shield/gpio/gpio_fpga_test.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/* mbed Microcontroller Library
* Copyright (c) 2019 ARM Limited
* Copyright (c) 2019-2020 ARM Limited
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License");
Expand Down Expand Up @@ -33,6 +33,14 @@ extern "C" {
*/
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,
Expand Down
239 changes: 152 additions & 87 deletions TESTS/mbed_hal_fpga_ci_test_shield/gpio/main.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2019, Arm Limited and affiliates.
* Copyright (c) 2019-2020, Arm Limited and affiliates.
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License");
Expand Down Expand Up @@ -56,61 +56,23 @@ void fpga_test_basic_input_output(PinName pin)
// Select GPIO0.
tester.select_peripheral(MbedTester::PeripheralGPIO);

// Initialize GPIO pin with a generic init fun.
gpio_t gpio;
// Test gpio_is_connected() returned value.
// 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));

// Some targets don't support input pull mode.
#if !defined(TARGET_NANO100) && \
!defined(TARGET_NUC472) && \
!defined(TARGET_M451)
// Test GPIO used as an input.
gpio_dir(&gpio, PIN_INPUT);

// Test input, pull-up mode.
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

// Test input, pull-down mode.
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

// Test input, pull-none mode.
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));
#endif

// Test GPIO used as an output.
tester.gpio_write(MbedTester::LogicalPinGPIO0, 0, false);
Expand All @@ -125,6 +87,85 @@ void fpga_test_basic_input_output(PinName pin)
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,
Expand All @@ -143,42 +184,62 @@ void fpga_test_explicit_input(PinName pin)
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.
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);
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.
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);
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.
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);
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.
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);
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.
Expand All @@ -199,6 +260,10 @@ void fpga_test_explicit_output(PinName pin)
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);
Expand All @@ -222,28 +287,28 @@ void fpga_test_explicit_output(PinName pin)
gpio_free(&gpio);

// Initialize GPIO pin as an output, output value = 1.
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);
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("generic init, input & output", all_ports<GPIOPort, DefaultFormFactor, fpga_test_basic_input_output>),
// Some targets don't support input pull mode.
#if !defined(TARGET_NANO100) && \
!defined(TARGET_NUC472) && \
!defined(TARGET_M451)
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>),
#endif
Case("explicit init, output", all_ports<GPIOPort, DefaultFormFactor, fpga_test_explicit_output>),
};

Expand Down
16 changes: 15 additions & 1 deletion hal/gpio_api.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
/** \addtogroup hal */
/** @{*/
/* mbed Microcontroller Library
* Copyright (c) 2006-2013 ARM Limited
* Copyright (c) 2006-2020 ARM Limited
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License");
Expand Down Expand Up @@ -46,6 +46,8 @@ extern "C" {
* * ::gpio_init_out_ex inits the pin as an output and sets the output value
* * ::gpio_init_inout inits the pin to be input/output and set pin mode and value
* * The GPIO operations ::gpio_write, ::gpio_read take less than 20us to complete
* * The function ::gpio_get_capabilities fills the given
* `gpio_capabilities_t` instance according to pin capabilities.
*
* # Undefined behavior
* * Calling any ::gpio_mode, ::gpio_dir, ::gpio_write or ::gpio_read on a gpio_t object that was initialized
Expand All @@ -65,6 +67,14 @@ extern "C" {
*
*/

/** GPIO capabilities for a given pin
*/
typedef struct {
uint8_t pull_none : 1;
uint8_t pull_down : 1;
uint8_t pull_up : 1;
} gpio_capabilities_t;

/** Set the given pin as GPIO
*
* @param pin The pin to be set as GPIO
Expand Down Expand Up @@ -164,6 +174,10 @@ void gpio_init_out_ex(gpio_t *gpio, PinName pin, int value);
*/
void gpio_init_inout(gpio_t *gpio, PinName pin, PinDirection direction, PinMode mode, int value);

/** Fill the given gpio_capabilities_t instance according to pin capabilities.
*/
void gpio_get_capabilities(gpio_t *gpio, gpio_capabilities_t *cap);

/** Get the pins that support all GPIO tests
*
* Return a PinMap array of pins that support GPIO. The
Expand Down
11 changes: 10 additions & 1 deletion hal/mbed_gpio.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/* mbed Microcontroller Library
* Copyright (c) 2006-2013 ARM Limited
* Copyright (c) 2006-2020 ARM Limited
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License");
Expand Down Expand Up @@ -68,6 +68,15 @@ void gpio_init_inout(gpio_t *gpio, PinName pin, PinDirection direction, PinMode
}
}

// To be re-implemented in the target layer if required.
MBED_WEAK void gpio_get_capabilities(gpio_t *gpio, gpio_capabilities_t *cap)
{
(void)gpio; // By default, every pin supports all basic input pull modes.
cap->pull_none = 1;
cap->pull_down = 1;
cap->pull_up = 1;
}

#ifdef TARGET_FF_ARDUINO

typedef enum {
Expand Down
Loading