From 55328ebdd580e9acb2cc53c67d352debdc1d92bc Mon Sep 17 00:00:00 2001 From: ccli8 Date: Thu, 30 Aug 2018 10:11:48 +0800 Subject: [PATCH] [Nuvoton] Fix pin mode mapping between input pull mode/direction and I/O mode 1. Modify PinMode enum to fully support GPIO I/O modes. 2. Translate input pull mode/direction to I/O mode, where H/W doesn't support separate configuration for input pull mode/direction. 3. Allow for configuring I/O mode in addition to input pull mode. --- .../TARGET_NUVOTON/TARGET_M2351/PinNames.h | 10 ++- .../TARGET_NUVOTON/TARGET_M2351/gpio_api.c | 89 +++++++++++++++---- .../TARGET_NUVOTON/TARGET_M2351/gpio_object.h | 6 +- targets/TARGET_NUVOTON/TARGET_M2351/pinmap.c | 35 +++++--- targets/TARGET_NUVOTON/TARGET_M451/PinNames.h | 10 ++- targets/TARGET_NUVOTON/TARGET_M451/gpio_api.c | 89 +++++++++++++++---- .../TARGET_NUVOTON/TARGET_M451/gpio_object.h | 6 +- targets/TARGET_NUVOTON/TARGET_M451/pinmap.c | 35 +++++--- targets/TARGET_NUVOTON/TARGET_M480/PinNames.h | 10 ++- targets/TARGET_NUVOTON/TARGET_M480/gpio_api.c | 83 +++++++++++++---- .../TARGET_NUVOTON/TARGET_M480/gpio_object.h | 6 +- targets/TARGET_NUVOTON/TARGET_M480/pinmap.c | 41 +++++---- .../TARGET_NUVOTON/TARGET_NANO100/PinNames.h | 9 +- .../TARGET_NUVOTON/TARGET_NANO100/gpio_api.c | 73 +++++++++++---- .../TARGET_NANO100/gpio_object.h | 6 +- .../TARGET_NUVOTON/TARGET_NANO100/pinmap.c | 35 ++++---- .../TARGET_NUVOTON/TARGET_NUC472/PinNames.h | 10 ++- .../TARGET_NUVOTON/TARGET_NUC472/gpio_api.c | 89 +++++++++++++++---- .../TARGET_NUC472/gpio_object.h | 6 +- targets/TARGET_NUVOTON/TARGET_NUC472/pinmap.c | 37 +++++--- 20 files changed, 497 insertions(+), 188 deletions(-) diff --git a/targets/TARGET_NUVOTON/TARGET_M2351/PinNames.h b/targets/TARGET_NUVOTON/TARGET_M2351/PinNames.h index e8a378439d..9855d18300 100644 --- a/targets/TARGET_NUVOTON/TARGET_M2351/PinNames.h +++ b/targets/TARGET_NUVOTON/TARGET_M2351/PinNames.h @@ -94,15 +94,19 @@ typedef enum { } PinDirection; typedef enum { + /* Input pull mode */ PullNone = 0, PullDown, PullUp, - PushPull, + /* I/O mode */ + InputOnly, + PushPullOutput, OpenDrain, - Quasi, + QuasiBidirectional, - PullDefault = PullUp, + /* Default input pull mode */ + PullDefault = PullUp } PinMode; typedef enum { diff --git a/targets/TARGET_NUVOTON/TARGET_M2351/gpio_api.c b/targets/TARGET_NUVOTON/TARGET_M2351/gpio_api.c index 9c83e28a5e..f4057366f5 100644 --- a/targets/TARGET_NUVOTON/TARGET_M2351/gpio_api.c +++ b/targets/TARGET_NUVOTON/TARGET_M2351/gpio_api.c @@ -51,6 +51,9 @@ void gpio_init(gpio_t *obj, PinName pin) } obj->mask = gpio_set(pin); + /* Default mode/direction */ + obj->mode = PullUp; + obj->direction = PIN_INPUT; } void gpio_mode(gpio_t *obj, PinMode mode) @@ -58,8 +61,45 @@ void gpio_mode(gpio_t *obj, PinMode mode) if (obj->pin == (PinName) NC) { return; } - - pin_mode(obj->pin, mode); + + switch (mode) { + case PullNone: + case PullDown: + case PullUp: + /* H/W doesn't support separate configuration for input pull mode/direction. + * We translate to input-only/push-pull output I/O mode dependent on direction. */ + obj->mode = (obj->direction == PIN_INPUT) ? InputOnly : PushPullOutput; + break; + + case QuasiBidirectional: + /* With quasi-bidirectional I/O mode, before digital input function is performed, + * the corresponding bit in GPIOx_DOUT must be set to 1. */ + obj->mode = QuasiBidirectional; + if (obj->direction == PIN_INPUT) { + gpio_write(obj, 1); + } + break; + + case InputOnly: + case PushPullOutput: + /* We may meet contradictory I/O mode/direction configuration. Favor I/O mode + * in the gpio_mode call here. */ + if (mode == InputOnly) { + obj->direction = PIN_INPUT; + obj->mode = InputOnly; + } else { + obj->direction = PIN_OUTPUT; + obj->mode = PushPullOutput; + } + break; + + default: + /* Allow for configuring other I/O modes directly */ + obj->mode = mode; + break; + } + + pin_mode(obj->pin, obj->mode); } void gpio_dir(gpio_t *obj, PinDirection direction) @@ -67,25 +107,36 @@ void gpio_dir(gpio_t *obj, PinDirection direction) if (obj->pin == (PinName) NC) { return; } - - uint32_t pin_index = NU_PINNAME_TO_PIN(obj->pin); - uint32_t port_index = NU_PINNAME_TO_PORT(obj->pin); - GPIO_T *gpio_base = NU_PORT_BASE(port_index); - - uint32_t mode_intern = GPIO_MODE_INPUT; - - switch (direction) { - case PIN_INPUT: - mode_intern = GPIO_MODE_INPUT; - break; - - case PIN_OUTPUT: - mode_intern = GPIO_MODE_OUTPUT; + + obj->direction = direction; + + switch (obj->mode) { + case PullNone: + case PullDown: + case PullUp: + /* H/W doesn't support separate configuration for input pull mode/direction. + * We translate to input-only/push-pull output I/O mode dependent on direction. */ + obj->mode = (obj->direction == PIN_INPUT) ? InputOnly : PushPullOutput; break; + case QuasiBidirectional: + /* With quasi-bidirectional I/O mode, before digital input function is performed, + * the corresponding bit in GPIOx_DOUT must be set to 1. */ + if (obj->direction == PIN_INPUT) { + gpio_write(obj, 1); + } + break; + + case InputOnly: + case PushPullOutput: + /* We may meet contradictory I/O mode/direction configuration. Favor direction + * in the gpio_dir call here. */ + obj->mode = (obj->direction == PIN_INPUT) ? InputOnly : PushPullOutput; + break; + default: - return; + break; } - - GPIO_SetMode(gpio_base, 1 << pin_index, mode_intern); + + pin_mode(obj->pin, obj->mode); } diff --git a/targets/TARGET_NUVOTON/TARGET_M2351/gpio_object.h b/targets/TARGET_NUVOTON/TARGET_M2351/gpio_object.h index 6437ac617b..d8c2e870eb 100644 --- a/targets/TARGET_NUVOTON/TARGET_M2351/gpio_object.h +++ b/targets/TARGET_NUVOTON/TARGET_M2351/gpio_object.h @@ -29,8 +29,10 @@ extern "C" { #endif typedef struct { - PinName pin; - uint32_t mask; + PinName pin; + uint32_t mask; + PinDirection direction; + PinMode mode; } gpio_t; static inline void gpio_write(gpio_t *obj, int value) diff --git a/targets/TARGET_NUVOTON/TARGET_M2351/pinmap.c b/targets/TARGET_NUVOTON/TARGET_M2351/pinmap.c index d72e9e3b43..d1fa0bc383 100644 --- a/targets/TARGET_NUVOTON/TARGET_M2351/pinmap.c +++ b/targets/TARGET_NUVOTON/TARGET_M2351/pinmap.c @@ -41,31 +41,40 @@ void pin_mode(PinName pin, PinMode mode) GPIO_T *gpio_base = NU_PORT_BASE(port_index); uint32_t mode_intern = GPIO_MODE_INPUT; - + switch (mode) { - case PullUp: + case InputOnly: mode_intern = GPIO_MODE_INPUT; break; - - case PullDown: - case PullNone: - // NOTE: Not support - return; - - case PushPull: + + case PushPullOutput: mode_intern = GPIO_MODE_OUTPUT; break; - + case OpenDrain: mode_intern = GPIO_MODE_OPEN_DRAIN; break; - - case Quasi: + + case QuasiBidirectional: mode_intern = GPIO_MODE_QUASI; break; + + default: + /* H/W doesn't support separate configuration for input pull mode/direction. + * We expect upper layer would have translated input pull mode/direction + * to I/O mode */ + return; } - + GPIO_SetMode(gpio_base, 1 << pin_index, mode_intern); + + /* Invalid combinations of PinMode/PinDirection + * + * We assume developer would avoid the following combinations of PinMode/PinDirection + * which are invalid: + * 1. InputOnly/PIN_OUTPUT + * 2. PushPullOutput/PIN_INPUT + */ } #if defined (__ARM_FEATURE_CMSE) && (__ARM_FEATURE_CMSE == 3U) diff --git a/targets/TARGET_NUVOTON/TARGET_M451/PinNames.h b/targets/TARGET_NUVOTON/TARGET_M451/PinNames.h index 4599c86ca9..577ff8d28c 100644 --- a/targets/TARGET_NUVOTON/TARGET_M451/PinNames.h +++ b/targets/TARGET_NUVOTON/TARGET_M451/PinNames.h @@ -55,15 +55,19 @@ typedef enum { } PinDirection; typedef enum { + /* Input pull mode */ PullNone = 0, PullDown, PullUp, - PushPull, + /* I/O mode */ + InputOnly, + PushPullOutput, OpenDrain, - Quasi, + QuasiBidirectional, - PullDefault = PullUp, + /* Default input pull mode */ + PullDefault = PullUp } PinMode; typedef enum { diff --git a/targets/TARGET_NUVOTON/TARGET_M451/gpio_api.c b/targets/TARGET_NUVOTON/TARGET_M451/gpio_api.c index 27589ccc39..f3ce3fe477 100644 --- a/targets/TARGET_NUVOTON/TARGET_M451/gpio_api.c +++ b/targets/TARGET_NUVOTON/TARGET_M451/gpio_api.c @@ -51,6 +51,9 @@ void gpio_init(gpio_t *obj, PinName pin) } obj->mask = gpio_set(pin); + /* Default mode/direction */ + obj->mode = PullUp; + obj->direction = PIN_INPUT; } void gpio_mode(gpio_t *obj, PinMode mode) @@ -58,8 +61,45 @@ void gpio_mode(gpio_t *obj, PinMode mode) if (obj->pin == (PinName) NC) { return; } - - pin_mode(obj->pin, mode); + + switch (mode) { + case PullNone: + case PullDown: + case PullUp: + /* H/W doesn't support separate configuration for input pull mode/direction. + * We translate to input-only/push-pull output I/O mode dependent on direction. */ + obj->mode = (obj->direction == PIN_INPUT) ? InputOnly : PushPullOutput; + break; + + case QuasiBidirectional: + /* With quasi-bidirectional I/O mode, before digital input function is performed, + * the corresponding bit in GPIOx_DOUT must be set to 1. */ + obj->mode = QuasiBidirectional; + if (obj->direction == PIN_INPUT) { + gpio_write(obj, 1); + } + break; + + case InputOnly: + case PushPullOutput: + /* We may meet contradictory I/O mode/direction configuration. Favor I/O mode + * in the gpio_mode call here. */ + if (mode == InputOnly) { + obj->direction = PIN_INPUT; + obj->mode = InputOnly; + } else { + obj->direction = PIN_OUTPUT; + obj->mode = PushPullOutput; + } + break; + + default: + /* Allow for configuring other I/O modes directly */ + obj->mode = mode; + break; + } + + pin_mode(obj->pin, obj->mode); } void gpio_dir(gpio_t *obj, PinDirection direction) @@ -67,25 +107,36 @@ void gpio_dir(gpio_t *obj, PinDirection direction) if (obj->pin == (PinName) NC) { return; } - - uint32_t pin_index = NU_PINNAME_TO_PIN(obj->pin); - uint32_t port_index = NU_PINNAME_TO_PORT(obj->pin); - GPIO_T *gpio_base = NU_PORT_BASE(port_index); - - uint32_t mode_intern = GPIO_MODE_INPUT; - - switch (direction) { - case PIN_INPUT: - mode_intern = GPIO_MODE_INPUT; - break; - - case PIN_OUTPUT: - mode_intern = GPIO_MODE_OUTPUT; + + obj->direction = direction; + + switch (obj->mode) { + case PullNone: + case PullDown: + case PullUp: + /* H/W doesn't support separate configuration for input pull mode/direction. + * We translate to input-only/push-pull output I/O mode dependent on direction. */ + obj->mode = (obj->direction == PIN_INPUT) ? InputOnly : PushPullOutput; break; + case QuasiBidirectional: + /* With quasi-bidirectional I/O mode, before digital input function is performed, + * the corresponding bit in GPIOx_DOUT must be set to 1. */ + if (obj->direction == PIN_INPUT) { + gpio_write(obj, 1); + } + break; + + case InputOnly: + case PushPullOutput: + /* We may meet contradictory I/O mode/direction configuration. Favor direction + * in the gpio_dir call here. */ + obj->mode = (obj->direction == PIN_INPUT) ? InputOnly : PushPullOutput; + break; + default: - return; + break; } - - GPIO_SetMode(gpio_base, 1 << pin_index, mode_intern); + + pin_mode(obj->pin, obj->mode); } diff --git a/targets/TARGET_NUVOTON/TARGET_M451/gpio_object.h b/targets/TARGET_NUVOTON/TARGET_M451/gpio_object.h index 282bae437b..6337fd5cd0 100644 --- a/targets/TARGET_NUVOTON/TARGET_M451/gpio_object.h +++ b/targets/TARGET_NUVOTON/TARGET_M451/gpio_object.h @@ -28,8 +28,10 @@ extern "C" { #endif typedef struct { - PinName pin; - uint32_t mask; + PinName pin; + uint32_t mask; + PinDirection direction; + PinMode mode; } gpio_t; static inline void gpio_write(gpio_t *obj, int value) diff --git a/targets/TARGET_NUVOTON/TARGET_M451/pinmap.c b/targets/TARGET_NUVOTON/TARGET_M451/pinmap.c index 274c07fe25..214f7fc6be 100644 --- a/targets/TARGET_NUVOTON/TARGET_M451/pinmap.c +++ b/targets/TARGET_NUVOTON/TARGET_M451/pinmap.c @@ -55,29 +55,38 @@ void pin_mode(PinName pin, PinMode mode) GPIO_T *gpio_base = NU_PORT_BASE(port_index); uint32_t mode_intern = GPIO_MODE_INPUT; - + switch (mode) { - case PullUp: + case InputOnly: mode_intern = GPIO_MODE_INPUT; break; - - case PullDown: - case PullNone: - // NOTE: Not support - return; - - case PushPull: + + case PushPullOutput: mode_intern = GPIO_MODE_OUTPUT; break; - + case OpenDrain: mode_intern = GPIO_MODE_OPEN_DRAIN; break; - - case Quasi: + + case QuasiBidirectional: mode_intern = GPIO_MODE_QUASI; break; + + default: + /* H/W doesn't support separate configuration for input pull mode/direction. + * We expect upper layer would have translated input pull mode/direction + * to I/O mode */ + return; } - + GPIO_SetMode(gpio_base, 1 << pin_index, mode_intern); + + /* Invalid combinations of PinMode/PinDirection + * + * We assume developer would avoid the following combinations of PinMode/PinDirection + * which are invalid: + * 1. InputOnly/PIN_OUTPUT + * 2. PushPullOutput/PIN_INPUT + */ } diff --git a/targets/TARGET_NUVOTON/TARGET_M480/PinNames.h b/targets/TARGET_NUVOTON/TARGET_M480/PinNames.h index 816d5ece49..e8f1078cdf 100644 --- a/targets/TARGET_NUVOTON/TARGET_M480/PinNames.h +++ b/targets/TARGET_NUVOTON/TARGET_M480/PinNames.h @@ -55,15 +55,19 @@ typedef enum { } PinDirection; typedef enum { + /* Input pull mode */ PullNone = 0, PullDown, PullUp, - PushPull, + /* I/O mode */ + InputOnly, + PushPullOutput, OpenDrain, - Quasi, + QuasiBidirectional, - PullDefault = PullUp, + /* Default input pull mode */ + PullDefault = PullUp } PinMode; typedef enum { diff --git a/targets/TARGET_NUVOTON/TARGET_M480/gpio_api.c b/targets/TARGET_NUVOTON/TARGET_M480/gpio_api.c index 9b7b15503e..e6deff1fa9 100644 --- a/targets/TARGET_NUVOTON/TARGET_M480/gpio_api.c +++ b/targets/TARGET_NUVOTON/TARGET_M480/gpio_api.c @@ -51,6 +51,9 @@ void gpio_init(gpio_t *obj, PinName pin) } obj->mask = gpio_set(pin); + /* Default mode/direction */ + obj->mode = PullUp; + obj->direction = PIN_INPUT; } void gpio_mode(gpio_t *obj, PinMode mode) @@ -59,7 +62,44 @@ void gpio_mode(gpio_t *obj, PinMode mode) return; } - pin_mode(obj->pin, mode); + switch (mode) { + case PullNone: + case PullDown: + case PullUp: + /* H/W doesn't support separate configuration for input pull mode/direction. + * We translate to input-only/push-pull output I/O mode dependent on direction. */ + obj->mode = (obj->direction == PIN_INPUT) ? InputOnly : PushPullOutput; + break; + + case QuasiBidirectional: + /* With quasi-bidirectional I/O mode, before digital input function is performed, + * the corresponding bit in GPIOx_DOUT must be set to 1. */ + obj->mode = QuasiBidirectional; + if (obj->direction == PIN_INPUT) { + gpio_write(obj, 1); + } + break; + + case InputOnly: + case PushPullOutput: + /* We may meet contradictory I/O mode/direction configuration. Favor I/O mode + * in the gpio_mode call here. */ + if (mode == InputOnly) { + obj->direction = PIN_INPUT; + obj->mode = InputOnly; + } else { + obj->direction = PIN_OUTPUT; + obj->mode = PushPullOutput; + } + break; + + default: + /* Allow for configuring other I/O modes directly */ + obj->mode = mode; + break; + } + + pin_mode(obj->pin, obj->mode); } void gpio_dir(gpio_t *obj, PinDirection direction) @@ -68,24 +108,35 @@ void gpio_dir(gpio_t *obj, PinDirection direction) return; } - uint32_t pin_index = NU_PINNAME_TO_PIN(obj->pin); - uint32_t port_index = NU_PINNAME_TO_PORT(obj->pin); - GPIO_T *gpio_base = NU_PORT_BASE(port_index); + obj->direction = direction; - uint32_t mode_intern = GPIO_MODE_INPUT; + switch (obj->mode) { + case PullNone: + case PullDown: + case PullUp: + /* H/W doesn't support separate configuration for input pull mode/direction. + * We translate to input-only/push-pull output I/O mode dependent on direction. */ + obj->mode = (obj->direction == PIN_INPUT) ? InputOnly : PushPullOutput; + break; + + case QuasiBidirectional: + /* With quasi-bidirectional I/O mode, before digital input function is performed, + * the corresponding bit in GPIOx_DOUT must be set to 1. */ + if (obj->direction == PIN_INPUT) { + gpio_write(obj, 1); + } + break; - switch (direction) { - case PIN_INPUT: - mode_intern = GPIO_MODE_INPUT; - break; + case InputOnly: + case PushPullOutput: + /* We may meet contradictory I/O mode/direction configuration. Favor direction + * in the gpio_dir call here. */ + obj->mode = (obj->direction == PIN_INPUT) ? InputOnly : PushPullOutput; + break; - case PIN_OUTPUT: - mode_intern = GPIO_MODE_OUTPUT; - break; - - default: - return; + default: + break; } - GPIO_SetMode(gpio_base, 1 << pin_index, mode_intern); + pin_mode(obj->pin, obj->mode); } diff --git a/targets/TARGET_NUVOTON/TARGET_M480/gpio_object.h b/targets/TARGET_NUVOTON/TARGET_M480/gpio_object.h index d4564d3795..76d079bf7c 100644 --- a/targets/TARGET_NUVOTON/TARGET_M480/gpio_object.h +++ b/targets/TARGET_NUVOTON/TARGET_M480/gpio_object.h @@ -28,8 +28,10 @@ extern "C" { #endif typedef struct { - PinName pin; - uint32_t mask; + PinName pin; + uint32_t mask; + PinDirection direction; + PinMode mode; } gpio_t; static inline void gpio_write(gpio_t *obj, int value) diff --git a/targets/TARGET_NUVOTON/TARGET_M480/pinmap.c b/targets/TARGET_NUVOTON/TARGET_M480/pinmap.c index 3e360a708e..2fe8540f3b 100644 --- a/targets/TARGET_NUVOTON/TARGET_M480/pinmap.c +++ b/targets/TARGET_NUVOTON/TARGET_M480/pinmap.c @@ -47,27 +47,36 @@ void pin_mode(PinName pin, PinMode mode) uint32_t mode_intern = GPIO_MODE_INPUT; switch (mode) { - case PullUp: - mode_intern = GPIO_MODE_INPUT; - break; + case InputOnly: + mode_intern = GPIO_MODE_INPUT; + break; - case PullDown: - case PullNone: - // NOTE: Not support - return; + case PushPullOutput: + mode_intern = GPIO_MODE_OUTPUT; + break; - case PushPull: - mode_intern = GPIO_MODE_OUTPUT; - break; + case OpenDrain: + mode_intern = GPIO_MODE_OPEN_DRAIN; + break; - case OpenDrain: - mode_intern = GPIO_MODE_OPEN_DRAIN; - break; + case QuasiBidirectional: + mode_intern = GPIO_MODE_QUASI; + break; - case Quasi: - mode_intern = GPIO_MODE_QUASI; - break; + default: + /* H/W doesn't support separate configuration for input pull mode/direction. + * We expect upper layer would have translated input pull mode/direction + * to I/O mode */ + return; } GPIO_SetMode(gpio_base, 1 << pin_index, mode_intern); + + /* Invalid combinations of PinMode/PinDirection + * + * We assume developer would avoid the following combinations of PinMode/PinDirection + * which are invalid: + * 1. InputOnly/PIN_OUTPUT + * 2. PushPullOutput/PIN_INPUT + */ } diff --git a/targets/TARGET_NUVOTON/TARGET_NANO100/PinNames.h b/targets/TARGET_NUVOTON/TARGET_NANO100/PinNames.h index b443dabd38..4658f5261b 100644 --- a/targets/TARGET_NUVOTON/TARGET_NANO100/PinNames.h +++ b/targets/TARGET_NUVOTON/TARGET_NANO100/PinNames.h @@ -55,15 +55,18 @@ typedef enum { } PinDirection; typedef enum { + /* Input pull mode */ PullNone = 0, PullDown, PullUp, - PushPull, + /* I/O mode */ + InputOnly, + PushPullOutput, OpenDrain, - Quasi, - PullDefault = PullUp, + /* Default input pull mode */ + PullDefault = PullUp } PinMode; typedef enum { diff --git a/targets/TARGET_NUVOTON/TARGET_NANO100/gpio_api.c b/targets/TARGET_NUVOTON/TARGET_NANO100/gpio_api.c index ac7a896ee2..1398e8198f 100644 --- a/targets/TARGET_NUVOTON/TARGET_NANO100/gpio_api.c +++ b/targets/TARGET_NUVOTON/TARGET_NANO100/gpio_api.c @@ -48,6 +48,9 @@ void gpio_init(gpio_t *obj, PinName pin) } obj->mask = gpio_set(pin); + /* Default mode/direction */ + obj->mode = PullUp; + obj->direction = PIN_INPUT; } void gpio_mode(gpio_t *obj, PinMode mode) @@ -55,8 +58,37 @@ void gpio_mode(gpio_t *obj, PinMode mode) if (obj->pin == (PinName) NC) { return; } - - pin_mode(obj->pin, mode); + + switch (mode) { + case PullNone: + case PullDown: + case PullUp: + /* H/W doesn't support separate configuration for input pull mode/direction. + * We translate to input-only/push-pull output I/O mode dependent on direction. */ + obj->mode = (obj->direction == PIN_INPUT) ? InputOnly : PushPullOutput; + break; + + + case InputOnly: + case PushPullOutput: + /* We may meet contradictory I/O mode/direction configuration. Favor I/O mode + * in the gpio_mode call here. */ + if (mode == InputOnly) { + obj->direction = PIN_INPUT; + obj->mode = InputOnly; + } else { + obj->direction = PIN_OUTPUT; + obj->mode = PushPullOutput; + } + break; + + default: + /* Allow for configuring other I/O modes directly */ + obj->mode = mode; + break; + } + + pin_mode(obj->pin, obj->mode); } void gpio_dir(gpio_t *obj, PinDirection direction) @@ -64,25 +96,28 @@ void gpio_dir(gpio_t *obj, PinDirection direction) if (obj->pin == (PinName) NC) { return; } - - uint32_t pin_index = NU_PINNAME_TO_PIN(obj->pin); - uint32_t port_index = NU_PINNAME_TO_PORT(obj->pin); - GPIO_T *gpio_base = NU_PORT_BASE(port_index); - - uint32_t mode_intern = GPIO_PMD_INPUT; - - switch (direction) { - case PIN_INPUT: - mode_intern = GPIO_PMD_INPUT; + + obj->direction = direction; + + switch (obj->mode) { + case PullNone: + case PullDown: + case PullUp: + /* H/W doesn't support separate configuration for input pull mode/direction. + * We translate to input-only/push-pull output I/O mode dependent on direction. */ + obj->mode = (obj->direction == PIN_INPUT) ? InputOnly : PushPullOutput; break; - - case PIN_OUTPUT: - mode_intern = GPIO_PMD_OUTPUT; + + case InputOnly: + case PushPullOutput: + /* We may meet contradictory I/O mode/direction configuration. Favor direction + * in the gpio_dir call here. */ + obj->mode = (obj->direction == PIN_INPUT) ? InputOnly : PushPullOutput; break; - + default: - return; + break; } - - GPIO_SetMode(gpio_base, 1 << pin_index, mode_intern); + + pin_mode(obj->pin, obj->mode); } diff --git a/targets/TARGET_NUVOTON/TARGET_NANO100/gpio_object.h b/targets/TARGET_NUVOTON/TARGET_NANO100/gpio_object.h index e2458dc87b..957789c5a5 100644 --- a/targets/TARGET_NUVOTON/TARGET_NANO100/gpio_object.h +++ b/targets/TARGET_NUVOTON/TARGET_NANO100/gpio_object.h @@ -28,8 +28,10 @@ extern "C" { #endif typedef struct { - PinName pin; - uint32_t mask; + PinName pin; + uint32_t mask; + PinDirection direction; + PinMode mode; } gpio_t; static inline void gpio_write(gpio_t *obj, int value) diff --git a/targets/TARGET_NUVOTON/TARGET_NANO100/pinmap.c b/targets/TARGET_NUVOTON/TARGET_NANO100/pinmap.c index 59912a59df..137036abc1 100644 --- a/targets/TARGET_NUVOTON/TARGET_NANO100/pinmap.c +++ b/targets/TARGET_NUVOTON/TARGET_NANO100/pinmap.c @@ -44,30 +44,35 @@ void pin_mode(PinName pin, PinMode mode) uint32_t port_index = NU_PINNAME_TO_PORT(pin); GPIO_T *gpio_base = NU_PORT_BASE(port_index); - uint32_t mode_intern = GPIO_PMD_INPUT; - + uint32_t mode_intern; + switch (mode) { - case PullUp: + case InputOnly: mode_intern = GPIO_PMD_INPUT; break; - - case PullDown: - case PullNone: - // NOTE: Not support - return; - - case PushPull: + + case PushPullOutput: mode_intern = GPIO_PMD_OUTPUT; break; - + case OpenDrain: mode_intern = GPIO_PMD_OPEN_DRAIN; break; - case Quasi: - // NOTE: Not support - break; + default: + /* H/W doesn't support separate configuration for input pull mode/direction. + * We expect upper layer would have translated input pull mode/direction + * to I/O mode */ + return; } - + GPIO_SetMode(gpio_base, 1 << pin_index, mode_intern); + + /* Invalid combinations of PinMode/PinDirection + * + * We assume developer would avoid the following combinations of PinMode/PinDirection + * which are invalid: + * 1. InputOnly/PIN_OUTPUT + * 2. PushPullOutput/PIN_INPUT + */ } diff --git a/targets/TARGET_NUVOTON/TARGET_NUC472/PinNames.h b/targets/TARGET_NUVOTON/TARGET_NUC472/PinNames.h index 4beecb4b88..333ada6663 100644 --- a/targets/TARGET_NUVOTON/TARGET_NUC472/PinNames.h +++ b/targets/TARGET_NUVOTON/TARGET_NUC472/PinNames.h @@ -55,15 +55,19 @@ typedef enum { } PinDirection; typedef enum { + /* Input pull mode */ PullNone = 0, PullDown, PullUp, - PushPull, + /* I/O mode */ + InputOnly, + PushPullOutput, OpenDrain, - Quasi, + QuasiBidirectional, - PullDefault = PullUp, + /* Default input pull mode */ + PullDefault = PullUp } PinMode; typedef enum { diff --git a/targets/TARGET_NUVOTON/TARGET_NUC472/gpio_api.c b/targets/TARGET_NUVOTON/TARGET_NUC472/gpio_api.c index 27589ccc39..f3ce3fe477 100644 --- a/targets/TARGET_NUVOTON/TARGET_NUC472/gpio_api.c +++ b/targets/TARGET_NUVOTON/TARGET_NUC472/gpio_api.c @@ -51,6 +51,9 @@ void gpio_init(gpio_t *obj, PinName pin) } obj->mask = gpio_set(pin); + /* Default mode/direction */ + obj->mode = PullUp; + obj->direction = PIN_INPUT; } void gpio_mode(gpio_t *obj, PinMode mode) @@ -58,8 +61,45 @@ void gpio_mode(gpio_t *obj, PinMode mode) if (obj->pin == (PinName) NC) { return; } - - pin_mode(obj->pin, mode); + + switch (mode) { + case PullNone: + case PullDown: + case PullUp: + /* H/W doesn't support separate configuration for input pull mode/direction. + * We translate to input-only/push-pull output I/O mode dependent on direction. */ + obj->mode = (obj->direction == PIN_INPUT) ? InputOnly : PushPullOutput; + break; + + case QuasiBidirectional: + /* With quasi-bidirectional I/O mode, before digital input function is performed, + * the corresponding bit in GPIOx_DOUT must be set to 1. */ + obj->mode = QuasiBidirectional; + if (obj->direction == PIN_INPUT) { + gpio_write(obj, 1); + } + break; + + case InputOnly: + case PushPullOutput: + /* We may meet contradictory I/O mode/direction configuration. Favor I/O mode + * in the gpio_mode call here. */ + if (mode == InputOnly) { + obj->direction = PIN_INPUT; + obj->mode = InputOnly; + } else { + obj->direction = PIN_OUTPUT; + obj->mode = PushPullOutput; + } + break; + + default: + /* Allow for configuring other I/O modes directly */ + obj->mode = mode; + break; + } + + pin_mode(obj->pin, obj->mode); } void gpio_dir(gpio_t *obj, PinDirection direction) @@ -67,25 +107,36 @@ void gpio_dir(gpio_t *obj, PinDirection direction) if (obj->pin == (PinName) NC) { return; } - - uint32_t pin_index = NU_PINNAME_TO_PIN(obj->pin); - uint32_t port_index = NU_PINNAME_TO_PORT(obj->pin); - GPIO_T *gpio_base = NU_PORT_BASE(port_index); - - uint32_t mode_intern = GPIO_MODE_INPUT; - - switch (direction) { - case PIN_INPUT: - mode_intern = GPIO_MODE_INPUT; - break; - - case PIN_OUTPUT: - mode_intern = GPIO_MODE_OUTPUT; + + obj->direction = direction; + + switch (obj->mode) { + case PullNone: + case PullDown: + case PullUp: + /* H/W doesn't support separate configuration for input pull mode/direction. + * We translate to input-only/push-pull output I/O mode dependent on direction. */ + obj->mode = (obj->direction == PIN_INPUT) ? InputOnly : PushPullOutput; break; + case QuasiBidirectional: + /* With quasi-bidirectional I/O mode, before digital input function is performed, + * the corresponding bit in GPIOx_DOUT must be set to 1. */ + if (obj->direction == PIN_INPUT) { + gpio_write(obj, 1); + } + break; + + case InputOnly: + case PushPullOutput: + /* We may meet contradictory I/O mode/direction configuration. Favor direction + * in the gpio_dir call here. */ + obj->mode = (obj->direction == PIN_INPUT) ? InputOnly : PushPullOutput; + break; + default: - return; + break; } - - GPIO_SetMode(gpio_base, 1 << pin_index, mode_intern); + + pin_mode(obj->pin, obj->mode); } diff --git a/targets/TARGET_NUVOTON/TARGET_NUC472/gpio_object.h b/targets/TARGET_NUVOTON/TARGET_NUC472/gpio_object.h index d8894b8d06..719006bf13 100644 --- a/targets/TARGET_NUVOTON/TARGET_NUC472/gpio_object.h +++ b/targets/TARGET_NUVOTON/TARGET_NUC472/gpio_object.h @@ -28,8 +28,10 @@ extern "C" { #endif typedef struct { - PinName pin; - uint32_t mask; + PinName pin; + uint32_t mask; + PinDirection direction; + PinMode mode; } gpio_t; static inline void gpio_write(gpio_t *obj, int value) diff --git a/targets/TARGET_NUVOTON/TARGET_NUC472/pinmap.c b/targets/TARGET_NUVOTON/TARGET_NUC472/pinmap.c index 274c07fe25..d12ca01eea 100644 --- a/targets/TARGET_NUVOTON/TARGET_NUC472/pinmap.c +++ b/targets/TARGET_NUVOTON/TARGET_NUC472/pinmap.c @@ -54,30 +54,39 @@ void pin_mode(PinName pin, PinMode mode) uint32_t port_index = NU_PINNAME_TO_PORT(pin); GPIO_T *gpio_base = NU_PORT_BASE(port_index); - uint32_t mode_intern = GPIO_MODE_INPUT; - + uint32_t mode_intern; + switch (mode) { - case PullUp: + case InputOnly: mode_intern = GPIO_MODE_INPUT; break; - - case PullDown: - case PullNone: - // NOTE: Not support - return; - - case PushPull: + + case PushPullOutput: mode_intern = GPIO_MODE_OUTPUT; break; - + case OpenDrain: mode_intern = GPIO_MODE_OPEN_DRAIN; break; - - case Quasi: + + case QuasiBidirectional: mode_intern = GPIO_MODE_QUASI; break; + + default: + /* H/W doesn't support separate configuration for input pull mode/direction. + * We expect upper layer would have translated input pull mode/direction + * to I/O mode */ + return; } - + GPIO_SetMode(gpio_base, 1 << pin_index, mode_intern); + + /* Invalid combinations of PinMode/PinDirection + * + * We assume developer would avoid the following combinations of PinMode/PinDirection + * which are invalid: + * 1. InputOnly/PIN_OUTPUT + * 2. PushPullOutput/PIN_INPUT + */ }