diff --git a/TESTS/mbed_hal/gpio/main.cpp b/TESTS/mbed_hal/gpio/main.cpp new file mode 100644 index 00000000000..2281957b2f4 --- /dev/null +++ b/TESTS/mbed_hal/gpio/main.cpp @@ -0,0 +1,57 @@ +/* mbed Microcontroller Library + * Copyright (c) 2019 ARM Limited + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "utest/utest.h" +#include "unity/unity.h" +#include "greentea-client/test_env.h" + +using namespace utest::v1; + +#include "PinNames.h" +#include "gpio_api.h" + +static void gpio_nc_test() +{ + gpio_t nc_obj; + gpio_init(&nc_obj, NC); + TEST_ASSERT_FALSE(gpio_is_connected(&nc_obj)); + + gpio_t led_obj; + gpio_init(&led_obj, LED1); + if (LED1 == NC) { + TEST_ASSERT_FALSE(gpio_is_connected(&led_obj)); + } else { + TEST_ASSERT_TRUE(gpio_is_connected(&led_obj)); + } +} + +Case cases[] = { + Case("gpio NC test", gpio_nc_test) +}; + +utest::v1::status_t greentea_test_setup(const size_t number_of_cases) +{ + GREENTEA_SETUP(20, "default_auto"); + return greentea_test_setup_handler(number_of_cases); +} + +Specification specification(greentea_test_setup, cases, greentea_test_teardown_handler); + +int main() +{ + Harness::run(specification); +} diff --git a/hal/gpio_api.h b/hal/gpio_api.h index 51156acd23f..503e682a6f5 100644 --- a/hal/gpio_api.h +++ b/hal/gpio_api.h @@ -29,6 +29,16 @@ extern "C" { /** * \defgroup hal_gpio GPIO HAL functions + * + * # Defined behavior + * * ::gpio_init and other init functions can be called with NC or a valid PinName for the target - Verified by ::gpio_nc_test + * * ::gpio_is_connected can be used to test whether a gpio_t object was initialized with NC - Verified by ::gpio_nc_test + * + * # Undefined behavior + * * Calling any ::gpio_mode, ::gpio_dir, ::gpio_write or ::gpio_read on a gpio_t object that was initialized + * with NC. + * * Calling ::gpio_set with NC. + * * @{ */ @@ -38,43 +48,45 @@ extern "C" { * @return The GPIO port mask for this pin **/ uint32_t gpio_set(PinName pin); -/* Checks if gpio object is connected (pin was not initialized with NC) - * @param pin The pin to be set as GPIO - * @return 0 if port is initialized with NC + +/** Checks if gpio object is connected (pin was not initialized with NC) + * @param obj The GPIO object + * @return 0 if object was initialized with NC + * @return non-zero if object was initialized with a valid PinName **/ int gpio_is_connected(const gpio_t *obj); /** Initialize the GPIO pin * * @param obj The GPIO object to initialize - * @param pin The GPIO pin to initialize + * @param pin The GPIO pin to initialize (may be NC) */ void gpio_init(gpio_t *obj, PinName pin); /** Set the input pin mode * - * @param obj The GPIO object + * @param obj The GPIO object (must be connected) * @param mode The pin mode to be set */ void gpio_mode(gpio_t *obj, PinMode mode); /** Set the pin direction * - * @param obj The GPIO object + * @param obj The GPIO object (must be connected) * @param direction The pin direction to be set */ void gpio_dir(gpio_t *obj, PinDirection direction); /** Set the output value * - * @param obj The GPIO object + * @param obj The GPIO object (must be connected) * @param value The value to be set */ void gpio_write(gpio_t *obj, int value); /** Read the input value * - * @param obj The GPIO object + * @param obj The GPIO object (must be connected) * @return An integer value 1 or 0 */ int gpio_read(gpio_t *obj); @@ -85,14 +97,14 @@ int gpio_read(gpio_t *obj); /** Init the input pin and set mode to PullDefault * * @param gpio The GPIO object - * @param pin The pin name + * @param pin The pin name (may be NC) */ void gpio_init_in(gpio_t *gpio, PinName pin); /** Init the input pin and set the mode * * @param gpio The GPIO object - * @param pin The pin name + * @param pin The pin name (may be NC) * @param mode The pin mode to be set */ void gpio_init_in_ex(gpio_t *gpio, PinName pin, PinMode mode); @@ -100,7 +112,7 @@ void gpio_init_in_ex(gpio_t *gpio, PinName pin, PinMode mode); /** Init the output pin as an output, with predefined output value 0 * * @param gpio The GPIO object - * @param pin The pin name + * @param pin The pin name (may be NC) * @return An integer value 1 or 0 */ void gpio_init_out(gpio_t *gpio, PinName pin); @@ -108,7 +120,7 @@ void gpio_init_out(gpio_t *gpio, PinName pin); /** Init the pin as an output and set the output value * * @param gpio The GPIO object - * @param pin The pin name + * @param pin The pin name (may be NC) * @param value The value to be set */ void gpio_init_out_ex(gpio_t *gpio, PinName pin, int value); @@ -116,7 +128,7 @@ void gpio_init_out_ex(gpio_t *gpio, PinName pin, int value); /** Init the pin to be in/out * * @param gpio The GPIO object - * @param pin The pin name + * @param pin The pin name (may be NC) * @param direction The pin direction to be set * @param mode The pin mode to be set * @param value The value to be set for an output pin diff --git a/targets/TARGET_ARM_FM/TARGET_FVP_MPS2/gpio_api.c b/targets/TARGET_ARM_FM/TARGET_FVP_MPS2/gpio_api.c index 2da2b84e53e..5cfdd573c70 100644 --- a/targets/TARGET_ARM_FM/TARGET_FVP_MPS2/gpio_api.c +++ b/targets/TARGET_ARM_FM/TARGET_FVP_MPS2/gpio_api.c @@ -27,11 +27,11 @@ uint32_t gpio_set(PinName pin) // with the object created for the pin void gpio_init(gpio_t *obj, PinName pin) { + obj->pin = pin; if (pin == NC) { return; } else { int pin_value = 0; - obj->pin = pin; if (pin <= 15) { pin_value = pin; } else if (pin >= 16 && pin <= 31) { diff --git a/targets/TARGET_ARM_SSG/TARGET_CM3DS_MPS2/gpio_api.c b/targets/TARGET_ARM_SSG/TARGET_CM3DS_MPS2/gpio_api.c index 46a95c4abfd..2458569ae79 100644 --- a/targets/TARGET_ARM_SSG/TARGET_CM3DS_MPS2/gpio_api.c +++ b/targets/TARGET_ARM_SSG/TARGET_CM3DS_MPS2/gpio_api.c @@ -101,6 +101,13 @@ void gpio_init(gpio_t *obj, PinName pin) { struct arm_gpio_dev_t *gpio_dev; + if (pin == NC) { + obj->pin_number = NC; + obj->gpio_dev = NULL; + obj->mps2_io_dev = NULL; + return; + } + if (pin >= EXP0 && pin <= EXP51) { /* GPIO pins */ switch (GPIO_DEV_NUMBER(pin)) { diff --git a/targets/TARGET_ARM_SSG/TARGET_IOTSS/gpio_api.c b/targets/TARGET_ARM_SSG/TARGET_IOTSS/gpio_api.c index b80fcbacd17..2a87bb2dda6 100644 --- a/targets/TARGET_ARM_SSG/TARGET_IOTSS/gpio_api.c +++ b/targets/TARGET_ARM_SSG/TARGET_IOTSS/gpio_api.c @@ -25,10 +25,10 @@ uint32_t gpio_set(PinName pin) { // this links the board control bits for each pin // with the object created for the pin void gpio_init(gpio_t *obj, PinName pin) { + obj->pin = pin; if(pin == NC){ return;} else { int pin_value = 0; - obj->pin = pin; if(pin <=15){ pin_value = pin; }else if (pin >= 16 && pin <= 31){ diff --git a/targets/TARGET_Atmel/TARGET_SAM_CortexM0P/gpio_api.c b/targets/TARGET_Atmel/TARGET_SAM_CortexM0P/gpio_api.c index 2706e3cfb36..66bf6ca4cc2 100644 --- a/targets/TARGET_Atmel/TARGET_SAM_CortexM0P/gpio_api.c +++ b/targets/TARGET_Atmel/TARGET_SAM_CortexM0P/gpio_api.c @@ -28,7 +28,6 @@ uint32_t gpio_set(PinName pin) void gpio_init(gpio_t *obj, PinName pin) { - MBED_ASSERT(pin != (PinName)NC); struct port_config pin_conf; PortGroup *const port_base = (PortGroup*)port_get_group_from_gpio_pin(pin); diff --git a/targets/TARGET_Atmel/TARGET_SAM_CortexM4/gpio_api.c b/targets/TARGET_Atmel/TARGET_SAM_CortexM4/gpio_api.c index bb1af212582..b6613e4d1c9 100644 --- a/targets/TARGET_Atmel/TARGET_SAM_CortexM4/gpio_api.c +++ b/targets/TARGET_Atmel/TARGET_SAM_CortexM4/gpio_api.c @@ -30,13 +30,15 @@ uint32_t gpio_set(PinName pin) void gpio_init(gpio_t *obj, PinName pin) { - MBED_ASSERT(pin != (PinName)NC); if (g_sys_init == 0) { sysclk_init(); system_board_init(); g_sys_init = 1; } obj->pin = pin; + if (pin == NC) { + return; + } ioport_set_pin_dir(pin, IOPORT_DIR_INPUT); ioport_set_pin_mode(pin, IOPORT_MODE_PULLUP); diff --git a/targets/TARGET_Realtek/TARGET_AMEBA/TARGET_MCU_RTL8195A/gpio_api.c b/targets/TARGET_Realtek/TARGET_AMEBA/TARGET_MCU_RTL8195A/gpio_api.c index cf81673e18e..56285489a2e 100644 --- a/targets/TARGET_Realtek/TARGET_AMEBA/TARGET_MCU_RTL8195A/gpio_api.c +++ b/targets/TARGET_Realtek/TARGET_AMEBA/TARGET_MCU_RTL8195A/gpio_api.c @@ -83,10 +83,11 @@ void gpio_init(gpio_t *obj, PinName pin) { uint32_t pin_name; + obj->pin = pin; + if (pin == (PinName)NC) return; - obj->pin = pin; obj->mode = PullNone; obj->direction = PIN_INPUT; pin_name = gpio_set(pin); // get the IP pin name diff --git a/targets/TARGET_TT/TARGET_TT_M3HQ/gpio_api.c b/targets/TARGET_TT/TARGET_TT_M3HQ/gpio_api.c index ae96d4ae601..a800f57e2ed 100644 --- a/targets/TARGET_TT/TARGET_TT_M3HQ/gpio_api.c +++ b/targets/TARGET_TT/TARGET_TT_M3HQ/gpio_api.c @@ -36,9 +36,11 @@ void gpio_init(gpio_t *obj, PinName pin) { // Store above pin mask, pin name into GPIO object obj->pin = pin; - obj->mask = gpio_set(pin); - obj->port = (PortName) (pin >> 3); - TSB_CG->FSYSENA |= (1<<(obj->port)); + if (pin != NC) { + obj->mask = gpio_set(pin); + obj->port = (PortName) (pin >> 3); + TSB_CG->FSYSENA |= (1<<(obj->port)); + } } void gpio_mode(gpio_t *obj, PinMode mode) diff --git a/targets/TARGET_TT/TARGET_TT_M4G9/gpio_api.c b/targets/TARGET_TT/TARGET_TT_M4G9/gpio_api.c index 2e7603750b4..c30f3f1f450 100644 --- a/targets/TARGET_TT/TARGET_TT_M4G9/gpio_api.c +++ b/targets/TARGET_TT/TARGET_TT_M4G9/gpio_api.c @@ -61,11 +61,13 @@ void gpio_init(gpio_t *obj, PinName pin) { // Store above pin mask, pin name into GPIO object obj->pin = pin; - obj->pin_num = PIN_POS(pin); - obj->mask = gpio_set(pin); - obj->port = (PortName) PIN_PORT(pin); - //Enable clock for particular port - TSB_CG->FSYSMENB |= (1 << ((obj->port) + 2)); + if (pin != NC) { + obj->pin_num = PIN_POS(pin); + obj->mask = gpio_set(pin); + obj->port = (PortName) PIN_PORT(pin); + //Enable clock for particular port + TSB_CG->FSYSMENB |= (1 << ((obj->port) + 2)); + } } void gpio_mode(gpio_t *obj, PinMode mode) diff --git a/targets/TARGET_WIZNET/TARGET_W7500x/gpio_api.c b/targets/TARGET_WIZNET/TARGET_W7500x/gpio_api.c index d40f2f01c71..9747c01b2d9 100644 --- a/targets/TARGET_WIZNET/TARGET_W7500x/gpio_api.c +++ b/targets/TARGET_WIZNET/TARGET_W7500x/gpio_api.c @@ -45,13 +45,13 @@ uint32_t gpio_set(PinName pin) void gpio_init(gpio_t *obj, PinName pin) { + obj->pin = pin; if (pin == (PinName)NC) { return; } obj->port_num = WIZ_PORT(pin); obj->pin_index = WIZ_PIN_INDEX(pin); - obj->pin = pin; GPIO_TypeDef *gpio = (GPIO_TypeDef *)Get_GPIO_BaseAddress(obj->port_num); obj->reg_data_in = &gpio->DATA; } diff --git a/targets/TARGET_ublox/TARGET_HI2110/gpio_api.c b/targets/TARGET_ublox/TARGET_HI2110/gpio_api.c index 7024631750a..0406d2a0262 100644 --- a/targets/TARGET_ublox/TARGET_HI2110/gpio_api.c +++ b/targets/TARGET_ublox/TARGET_HI2110/gpio_api.c @@ -36,13 +36,13 @@ void gpio_init(gpio_t *obj, PinName pin) { + obj->pin = pin; if (pin == (PinName)NC) { return; } MBED_ASSERT (pin < NUM_PINS); - obj->pin = pin; obj->mask = (1ul << pin); obj->reg_set = &GPIO_OUT_BITSET;