Merge pull request #7941 from OpenNuvoton/nuvoton_fix_gpio_mode_mapping

Nuvoton: Fix GPIO mode mapping
pull/7970/merge
Cruz Monrreal 2018-09-25 13:15:09 -05:00 committed by GitHub
commit 815683c2bd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
20 changed files with 497 additions and 188 deletions

View File

@ -94,15 +94,19 @@ typedef enum {
} PinDirection; } PinDirection;
typedef enum { typedef enum {
/* Input pull mode */
PullNone = 0, PullNone = 0,
PullDown, PullDown,
PullUp, PullUp,
PushPull, /* I/O mode */
InputOnly,
PushPullOutput,
OpenDrain, OpenDrain,
Quasi, QuasiBidirectional,
PullDefault = PullUp, /* Default input pull mode */
PullDefault = PullUp
} PinMode; } PinMode;
typedef enum { typedef enum {

View File

@ -51,6 +51,9 @@ void gpio_init(gpio_t *obj, PinName pin)
} }
obj->mask = gpio_set(pin); obj->mask = gpio_set(pin);
/* Default mode/direction */
obj->mode = PullUp;
obj->direction = PIN_INPUT;
} }
void gpio_mode(gpio_t *obj, PinMode mode) void gpio_mode(gpio_t *obj, PinMode mode)
@ -59,7 +62,44 @@ void gpio_mode(gpio_t *obj, PinMode mode)
return; 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) void gpio_dir(gpio_t *obj, PinDirection direction)
@ -68,24 +108,35 @@ void gpio_dir(gpio_t *obj, PinDirection direction)
return; return;
} }
uint32_t pin_index = NU_PINNAME_TO_PIN(obj->pin); obj->direction = direction;
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 (obj->mode) {
case PullNone:
switch (direction) { case PullDown:
case PIN_INPUT: case PullUp:
mode_intern = GPIO_MODE_INPUT; /* 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; break;
case PIN_OUTPUT: case QuasiBidirectional:
mode_intern = GPIO_MODE_OUTPUT; /* 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; break;
default: default:
return; break;
} }
GPIO_SetMode(gpio_base, 1 << pin_index, mode_intern); pin_mode(obj->pin, obj->mode);
} }

View File

@ -29,8 +29,10 @@ extern "C" {
#endif #endif
typedef struct { typedef struct {
PinName pin; PinName pin;
uint32_t mask; uint32_t mask;
PinDirection direction;
PinMode mode;
} gpio_t; } gpio_t;
static inline void gpio_write(gpio_t *obj, int value) static inline void gpio_write(gpio_t *obj, int value)

View File

@ -43,16 +43,11 @@ void pin_mode(PinName pin, PinMode mode)
uint32_t mode_intern = GPIO_MODE_INPUT; uint32_t mode_intern = GPIO_MODE_INPUT;
switch (mode) { switch (mode) {
case PullUp: case InputOnly:
mode_intern = GPIO_MODE_INPUT; mode_intern = GPIO_MODE_INPUT;
break; break;
case PullDown: case PushPullOutput:
case PullNone:
// NOTE: Not support
return;
case PushPull:
mode_intern = GPIO_MODE_OUTPUT; mode_intern = GPIO_MODE_OUTPUT;
break; break;
@ -60,12 +55,26 @@ void pin_mode(PinName pin, PinMode mode)
mode_intern = GPIO_MODE_OPEN_DRAIN; mode_intern = GPIO_MODE_OPEN_DRAIN;
break; break;
case Quasi: case QuasiBidirectional:
mode_intern = GPIO_MODE_QUASI; mode_intern = GPIO_MODE_QUASI;
break; 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); 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) #if defined (__ARM_FEATURE_CMSE) && (__ARM_FEATURE_CMSE == 3U)

View File

@ -55,15 +55,19 @@ typedef enum {
} PinDirection; } PinDirection;
typedef enum { typedef enum {
/* Input pull mode */
PullNone = 0, PullNone = 0,
PullDown, PullDown,
PullUp, PullUp,
PushPull, /* I/O mode */
InputOnly,
PushPullOutput,
OpenDrain, OpenDrain,
Quasi, QuasiBidirectional,
PullDefault = PullUp, /* Default input pull mode */
PullDefault = PullUp
} PinMode; } PinMode;
typedef enum { typedef enum {

View File

@ -51,6 +51,9 @@ void gpio_init(gpio_t *obj, PinName pin)
} }
obj->mask = gpio_set(pin); obj->mask = gpio_set(pin);
/* Default mode/direction */
obj->mode = PullUp;
obj->direction = PIN_INPUT;
} }
void gpio_mode(gpio_t *obj, PinMode mode) void gpio_mode(gpio_t *obj, PinMode mode)
@ -59,7 +62,44 @@ void gpio_mode(gpio_t *obj, PinMode mode)
return; 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) void gpio_dir(gpio_t *obj, PinDirection direction)
@ -68,24 +108,35 @@ void gpio_dir(gpio_t *obj, PinDirection direction)
return; return;
} }
uint32_t pin_index = NU_PINNAME_TO_PIN(obj->pin); obj->direction = direction;
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 (obj->mode) {
case PullNone:
switch (direction) { case PullDown:
case PIN_INPUT: case PullUp:
mode_intern = GPIO_MODE_INPUT; /* 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; break;
case PIN_OUTPUT: case QuasiBidirectional:
mode_intern = GPIO_MODE_OUTPUT; /* 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; break;
default: default:
return; break;
} }
GPIO_SetMode(gpio_base, 1 << pin_index, mode_intern); pin_mode(obj->pin, obj->mode);
} }

View File

@ -28,8 +28,10 @@ extern "C" {
#endif #endif
typedef struct { typedef struct {
PinName pin; PinName pin;
uint32_t mask; uint32_t mask;
PinDirection direction;
PinMode mode;
} gpio_t; } gpio_t;
static inline void gpio_write(gpio_t *obj, int value) static inline void gpio_write(gpio_t *obj, int value)

View File

@ -57,16 +57,11 @@ void pin_mode(PinName pin, PinMode mode)
uint32_t mode_intern = GPIO_MODE_INPUT; uint32_t mode_intern = GPIO_MODE_INPUT;
switch (mode) { switch (mode) {
case PullUp: case InputOnly:
mode_intern = GPIO_MODE_INPUT; mode_intern = GPIO_MODE_INPUT;
break; break;
case PullDown: case PushPullOutput:
case PullNone:
// NOTE: Not support
return;
case PushPull:
mode_intern = GPIO_MODE_OUTPUT; mode_intern = GPIO_MODE_OUTPUT;
break; break;
@ -74,10 +69,24 @@ void pin_mode(PinName pin, PinMode mode)
mode_intern = GPIO_MODE_OPEN_DRAIN; mode_intern = GPIO_MODE_OPEN_DRAIN;
break; break;
case Quasi: case QuasiBidirectional:
mode_intern = GPIO_MODE_QUASI; mode_intern = GPIO_MODE_QUASI;
break; 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); 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
*/
} }

View File

@ -55,15 +55,19 @@ typedef enum {
} PinDirection; } PinDirection;
typedef enum { typedef enum {
/* Input pull mode */
PullNone = 0, PullNone = 0,
PullDown, PullDown,
PullUp, PullUp,
PushPull, /* I/O mode */
InputOnly,
PushPullOutput,
OpenDrain, OpenDrain,
Quasi, QuasiBidirectional,
PullDefault = PullUp, /* Default input pull mode */
PullDefault = PullUp
} PinMode; } PinMode;
typedef enum { typedef enum {

View File

@ -51,6 +51,9 @@ void gpio_init(gpio_t *obj, PinName pin)
} }
obj->mask = gpio_set(pin); obj->mask = gpio_set(pin);
/* Default mode/direction */
obj->mode = PullUp;
obj->direction = PIN_INPUT;
} }
void gpio_mode(gpio_t *obj, PinMode mode) void gpio_mode(gpio_t *obj, PinMode mode)
@ -59,7 +62,44 @@ void gpio_mode(gpio_t *obj, PinMode mode)
return; 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) void gpio_dir(gpio_t *obj, PinDirection direction)
@ -68,24 +108,35 @@ void gpio_dir(gpio_t *obj, PinDirection direction)
return; return;
} }
uint32_t pin_index = NU_PINNAME_TO_PIN(obj->pin); obj->direction = direction;
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 (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;
switch (direction) { case QuasiBidirectional:
case PIN_INPUT: /* With quasi-bidirectional I/O mode, before digital input function is performed,
mode_intern = GPIO_MODE_INPUT; * the corresponding bit in GPIOx_DOUT must be set to 1. */
break; if (obj->direction == PIN_INPUT) {
gpio_write(obj, 1);
}
break;
case PIN_OUTPUT: case InputOnly:
mode_intern = GPIO_MODE_OUTPUT; case PushPullOutput:
break; /* 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: default:
return; break;
} }
GPIO_SetMode(gpio_base, 1 << pin_index, mode_intern); pin_mode(obj->pin, obj->mode);
} }

View File

@ -28,8 +28,10 @@ extern "C" {
#endif #endif
typedef struct { typedef struct {
PinName pin; PinName pin;
uint32_t mask; uint32_t mask;
PinDirection direction;
PinMode mode;
} gpio_t; } gpio_t;
static inline void gpio_write(gpio_t *obj, int value) static inline void gpio_write(gpio_t *obj, int value)

View File

@ -47,27 +47,36 @@ void pin_mode(PinName pin, PinMode mode)
uint32_t mode_intern = GPIO_MODE_INPUT; uint32_t mode_intern = GPIO_MODE_INPUT;
switch (mode) { switch (mode) {
case PullUp: case InputOnly:
mode_intern = GPIO_MODE_INPUT; mode_intern = GPIO_MODE_INPUT;
break; break;
case PullDown: case PushPullOutput:
case PullNone: mode_intern = GPIO_MODE_OUTPUT;
// NOTE: Not support break;
return;
case PushPull: case OpenDrain:
mode_intern = GPIO_MODE_OUTPUT; mode_intern = GPIO_MODE_OPEN_DRAIN;
break; break;
case OpenDrain: case QuasiBidirectional:
mode_intern = GPIO_MODE_OPEN_DRAIN; mode_intern = GPIO_MODE_QUASI;
break; break;
case Quasi: default:
mode_intern = GPIO_MODE_QUASI; /* H/W doesn't support separate configuration for input pull mode/direction.
break; * 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); 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
*/
} }

View File

@ -55,15 +55,18 @@ typedef enum {
} PinDirection; } PinDirection;
typedef enum { typedef enum {
/* Input pull mode */
PullNone = 0, PullNone = 0,
PullDown, PullDown,
PullUp, PullUp,
PushPull, /* I/O mode */
InputOnly,
PushPullOutput,
OpenDrain, OpenDrain,
Quasi,
PullDefault = PullUp, /* Default input pull mode */
PullDefault = PullUp
} PinMode; } PinMode;
typedef enum { typedef enum {

View File

@ -48,6 +48,9 @@ void gpio_init(gpio_t *obj, PinName pin)
} }
obj->mask = gpio_set(pin); obj->mask = gpio_set(pin);
/* Default mode/direction */
obj->mode = PullUp;
obj->direction = PIN_INPUT;
} }
void gpio_mode(gpio_t *obj, PinMode mode) void gpio_mode(gpio_t *obj, PinMode mode)
@ -56,7 +59,36 @@ void gpio_mode(gpio_t *obj, PinMode mode)
return; 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) void gpio_dir(gpio_t *obj, PinDirection direction)
@ -65,24 +97,27 @@ void gpio_dir(gpio_t *obj, PinDirection direction)
return; return;
} }
uint32_t pin_index = NU_PINNAME_TO_PIN(obj->pin); obj->direction = direction;
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 (obj->mode) {
case PullNone:
switch (direction) { case PullDown:
case PIN_INPUT: case PullUp:
mode_intern = GPIO_PMD_INPUT; /* 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; break;
case PIN_OUTPUT: case InputOnly:
mode_intern = GPIO_PMD_OUTPUT; 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; break;
default: default:
return; break;
} }
GPIO_SetMode(gpio_base, 1 << pin_index, mode_intern); pin_mode(obj->pin, obj->mode);
} }

View File

@ -28,8 +28,10 @@ extern "C" {
#endif #endif
typedef struct { typedef struct {
PinName pin; PinName pin;
uint32_t mask; uint32_t mask;
PinDirection direction;
PinMode mode;
} gpio_t; } gpio_t;
static inline void gpio_write(gpio_t *obj, int value) static inline void gpio_write(gpio_t *obj, int value)

View File

@ -44,19 +44,14 @@ void pin_mode(PinName pin, PinMode mode)
uint32_t port_index = NU_PINNAME_TO_PORT(pin); uint32_t port_index = NU_PINNAME_TO_PORT(pin);
GPIO_T *gpio_base = NU_PORT_BASE(port_index); GPIO_T *gpio_base = NU_PORT_BASE(port_index);
uint32_t mode_intern = GPIO_PMD_INPUT; uint32_t mode_intern;
switch (mode) { switch (mode) {
case PullUp: case InputOnly:
mode_intern = GPIO_PMD_INPUT; mode_intern = GPIO_PMD_INPUT;
break; break;
case PullDown: case PushPullOutput:
case PullNone:
// NOTE: Not support
return;
case PushPull:
mode_intern = GPIO_PMD_OUTPUT; mode_intern = GPIO_PMD_OUTPUT;
break; break;
@ -64,10 +59,20 @@ void pin_mode(PinName pin, PinMode mode)
mode_intern = GPIO_PMD_OPEN_DRAIN; mode_intern = GPIO_PMD_OPEN_DRAIN;
break; break;
case Quasi: default:
// NOTE: Not support /* H/W doesn't support separate configuration for input pull mode/direction.
break; * 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); 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
*/
} }

View File

@ -55,15 +55,19 @@ typedef enum {
} PinDirection; } PinDirection;
typedef enum { typedef enum {
/* Input pull mode */
PullNone = 0, PullNone = 0,
PullDown, PullDown,
PullUp, PullUp,
PushPull, /* I/O mode */
InputOnly,
PushPullOutput,
OpenDrain, OpenDrain,
Quasi, QuasiBidirectional,
PullDefault = PullUp, /* Default input pull mode */
PullDefault = PullUp
} PinMode; } PinMode;
typedef enum { typedef enum {

View File

@ -51,6 +51,9 @@ void gpio_init(gpio_t *obj, PinName pin)
} }
obj->mask = gpio_set(pin); obj->mask = gpio_set(pin);
/* Default mode/direction */
obj->mode = PullUp;
obj->direction = PIN_INPUT;
} }
void gpio_mode(gpio_t *obj, PinMode mode) void gpio_mode(gpio_t *obj, PinMode mode)
@ -59,7 +62,44 @@ void gpio_mode(gpio_t *obj, PinMode mode)
return; 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) void gpio_dir(gpio_t *obj, PinDirection direction)
@ -68,24 +108,35 @@ void gpio_dir(gpio_t *obj, PinDirection direction)
return; return;
} }
uint32_t pin_index = NU_PINNAME_TO_PIN(obj->pin); obj->direction = direction;
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 (obj->mode) {
case PullNone:
switch (direction) { case PullDown:
case PIN_INPUT: case PullUp:
mode_intern = GPIO_MODE_INPUT; /* 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; break;
case PIN_OUTPUT: case QuasiBidirectional:
mode_intern = GPIO_MODE_OUTPUT; /* 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; break;
default: default:
return; break;
} }
GPIO_SetMode(gpio_base, 1 << pin_index, mode_intern); pin_mode(obj->pin, obj->mode);
} }

View File

@ -28,8 +28,10 @@ extern "C" {
#endif #endif
typedef struct { typedef struct {
PinName pin; PinName pin;
uint32_t mask; uint32_t mask;
PinDirection direction;
PinMode mode;
} gpio_t; } gpio_t;
static inline void gpio_write(gpio_t *obj, int value) static inline void gpio_write(gpio_t *obj, int value)

View File

@ -54,19 +54,14 @@ void pin_mode(PinName pin, PinMode mode)
uint32_t port_index = NU_PINNAME_TO_PORT(pin); uint32_t port_index = NU_PINNAME_TO_PORT(pin);
GPIO_T *gpio_base = NU_PORT_BASE(port_index); GPIO_T *gpio_base = NU_PORT_BASE(port_index);
uint32_t mode_intern = GPIO_MODE_INPUT; uint32_t mode_intern;
switch (mode) { switch (mode) {
case PullUp: case InputOnly:
mode_intern = GPIO_MODE_INPUT; mode_intern = GPIO_MODE_INPUT;
break; break;
case PullDown: case PushPullOutput:
case PullNone:
// NOTE: Not support
return;
case PushPull:
mode_intern = GPIO_MODE_OUTPUT; mode_intern = GPIO_MODE_OUTPUT;
break; break;
@ -74,10 +69,24 @@ void pin_mode(PinName pin, PinMode mode)
mode_intern = GPIO_MODE_OPEN_DRAIN; mode_intern = GPIO_MODE_OPEN_DRAIN;
break; break;
case Quasi: case QuasiBidirectional:
mode_intern = GPIO_MODE_QUASI; mode_intern = GPIO_MODE_QUASI;
break; 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); 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
*/
} }