Skip to content

Nuvoton: Fix GPIO mode mapping #7941

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 1 commit into from
Sep 25, 2018
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: 7 additions & 3 deletions targets/TARGET_NUVOTON/TARGET_M2351/PinNames.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
89 changes: 70 additions & 19 deletions targets/TARGET_NUVOTON/TARGET_M2351/gpio_api.c
Original file line number Diff line number Diff line change
Expand Up @@ -51,41 +51,92 @@ 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)
{
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)
{
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);
}
6 changes: 4 additions & 2 deletions targets/TARGET_NUVOTON/TARGET_M2351/gpio_object.h
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
35 changes: 22 additions & 13 deletions targets/TARGET_NUVOTON/TARGET_M2351/pinmap.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
10 changes: 7 additions & 3 deletions targets/TARGET_NUVOTON/TARGET_M451/PinNames.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
89 changes: 70 additions & 19 deletions targets/TARGET_NUVOTON/TARGET_M451/gpio_api.c
Original file line number Diff line number Diff line change
Expand Up @@ -51,41 +51,92 @@ 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)
{
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)
{
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);
}
6 changes: 4 additions & 2 deletions targets/TARGET_NUVOTON/TARGET_M451/gpio_object.h
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
Loading