Skip to content

Commit 815683c

Browse files
author
Cruz Monrreal
authored
Merge pull request #7941 from OpenNuvoton/nuvoton_fix_gpio_mode_mapping
Nuvoton: Fix GPIO mode mapping
2 parents 3bec1b7 + 55328eb commit 815683c

File tree

20 files changed

+500
-191
lines changed

20 files changed

+500
-191
lines changed

targets/TARGET_NUVOTON/TARGET_M2351/PinNames.h

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -94,15 +94,19 @@ typedef enum {
9494
} PinDirection;
9595

9696
typedef enum {
97+
/* Input pull mode */
9798
PullNone = 0,
9899
PullDown,
99100
PullUp,
100101

101-
PushPull,
102+
/* I/O mode */
103+
InputOnly,
104+
PushPullOutput,
102105
OpenDrain,
103-
Quasi,
106+
QuasiBidirectional,
104107

105-
PullDefault = PullUp,
108+
/* Default input pull mode */
109+
PullDefault = PullUp
106110
} PinMode;
107111

108112
typedef enum {

targets/TARGET_NUVOTON/TARGET_M2351/gpio_api.c

Lines changed: 70 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -51,41 +51,92 @@ void gpio_init(gpio_t *obj, PinName pin)
5151
}
5252

5353
obj->mask = gpio_set(pin);
54+
/* Default mode/direction */
55+
obj->mode = PullUp;
56+
obj->direction = PIN_INPUT;
5457
}
5558

5659
void gpio_mode(gpio_t *obj, PinMode mode)
5760
{
5861
if (obj->pin == (PinName) NC) {
5962
return;
6063
}
61-
62-
pin_mode(obj->pin, mode);
64+
65+
switch (mode) {
66+
case PullNone:
67+
case PullDown:
68+
case PullUp:
69+
/* H/W doesn't support separate configuration for input pull mode/direction.
70+
* We translate to input-only/push-pull output I/O mode dependent on direction. */
71+
obj->mode = (obj->direction == PIN_INPUT) ? InputOnly : PushPullOutput;
72+
break;
73+
74+
case QuasiBidirectional:
75+
/* With quasi-bidirectional I/O mode, before digital input function is performed,
76+
* the corresponding bit in GPIOx_DOUT must be set to 1. */
77+
obj->mode = QuasiBidirectional;
78+
if (obj->direction == PIN_INPUT) {
79+
gpio_write(obj, 1);
80+
}
81+
break;
82+
83+
case InputOnly:
84+
case PushPullOutput:
85+
/* We may meet contradictory I/O mode/direction configuration. Favor I/O mode
86+
* in the gpio_mode call here. */
87+
if (mode == InputOnly) {
88+
obj->direction = PIN_INPUT;
89+
obj->mode = InputOnly;
90+
} else {
91+
obj->direction = PIN_OUTPUT;
92+
obj->mode = PushPullOutput;
93+
}
94+
break;
95+
96+
default:
97+
/* Allow for configuring other I/O modes directly */
98+
obj->mode = mode;
99+
break;
100+
}
101+
102+
pin_mode(obj->pin, obj->mode);
63103
}
64104

65105
void gpio_dir(gpio_t *obj, PinDirection direction)
66106
{
67107
if (obj->pin == (PinName) NC) {
68108
return;
69109
}
70-
71-
uint32_t pin_index = NU_PINNAME_TO_PIN(obj->pin);
72-
uint32_t port_index = NU_PINNAME_TO_PORT(obj->pin);
73-
GPIO_T *gpio_base = NU_PORT_BASE(port_index);
74-
75-
uint32_t mode_intern = GPIO_MODE_INPUT;
76-
77-
switch (direction) {
78-
case PIN_INPUT:
79-
mode_intern = GPIO_MODE_INPUT;
80-
break;
81-
82-
case PIN_OUTPUT:
83-
mode_intern = GPIO_MODE_OUTPUT;
110+
111+
obj->direction = direction;
112+
113+
switch (obj->mode) {
114+
case PullNone:
115+
case PullDown:
116+
case PullUp:
117+
/* H/W doesn't support separate configuration for input pull mode/direction.
118+
* We translate to input-only/push-pull output I/O mode dependent on direction. */
119+
obj->mode = (obj->direction == PIN_INPUT) ? InputOnly : PushPullOutput;
84120
break;
85121

122+
case QuasiBidirectional:
123+
/* With quasi-bidirectional I/O mode, before digital input function is performed,
124+
* the corresponding bit in GPIOx_DOUT must be set to 1. */
125+
if (obj->direction == PIN_INPUT) {
126+
gpio_write(obj, 1);
127+
}
128+
break;
129+
130+
case InputOnly:
131+
case PushPullOutput:
132+
/* We may meet contradictory I/O mode/direction configuration. Favor direction
133+
* in the gpio_dir call here. */
134+
obj->mode = (obj->direction == PIN_INPUT) ? InputOnly : PushPullOutput;
135+
break;
136+
86137
default:
87-
return;
138+
break;
88139
}
89-
90-
GPIO_SetMode(gpio_base, 1 << pin_index, mode_intern);
140+
141+
pin_mode(obj->pin, obj->mode);
91142
}

targets/TARGET_NUVOTON/TARGET_M2351/gpio_object.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,10 @@ extern "C" {
2929
#endif
3030

3131
typedef struct {
32-
PinName pin;
33-
uint32_t mask;
32+
PinName pin;
33+
uint32_t mask;
34+
PinDirection direction;
35+
PinMode mode;
3436
} gpio_t;
3537

3638
static inline void gpio_write(gpio_t *obj, int value)

targets/TARGET_NUVOTON/TARGET_M2351/pinmap.c

Lines changed: 22 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -41,31 +41,40 @@ void pin_mode(PinName pin, PinMode mode)
4141
GPIO_T *gpio_base = NU_PORT_BASE(port_index);
4242

4343
uint32_t mode_intern = GPIO_MODE_INPUT;
44-
44+
4545
switch (mode) {
46-
case PullUp:
46+
case InputOnly:
4747
mode_intern = GPIO_MODE_INPUT;
4848
break;
49-
50-
case PullDown:
51-
case PullNone:
52-
// NOTE: Not support
53-
return;
54-
55-
case PushPull:
49+
50+
case PushPullOutput:
5651
mode_intern = GPIO_MODE_OUTPUT;
5752
break;
58-
53+
5954
case OpenDrain:
6055
mode_intern = GPIO_MODE_OPEN_DRAIN;
6156
break;
62-
63-
case Quasi:
57+
58+
case QuasiBidirectional:
6459
mode_intern = GPIO_MODE_QUASI;
6560
break;
61+
62+
default:
63+
/* H/W doesn't support separate configuration for input pull mode/direction.
64+
* We expect upper layer would have translated input pull mode/direction
65+
* to I/O mode */
66+
return;
6667
}
67-
68+
6869
GPIO_SetMode(gpio_base, 1 << pin_index, mode_intern);
70+
71+
/* Invalid combinations of PinMode/PinDirection
72+
*
73+
* We assume developer would avoid the following combinations of PinMode/PinDirection
74+
* which are invalid:
75+
* 1. InputOnly/PIN_OUTPUT
76+
* 2. PushPullOutput/PIN_INPUT
77+
*/
6978
}
7079

7180
#if defined (__ARM_FEATURE_CMSE) && (__ARM_FEATURE_CMSE == 3U)

targets/TARGET_NUVOTON/TARGET_M451/PinNames.h

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -55,15 +55,19 @@ typedef enum {
5555
} PinDirection;
5656

5757
typedef enum {
58+
/* Input pull mode */
5859
PullNone = 0,
5960
PullDown,
6061
PullUp,
6162

62-
PushPull,
63+
/* I/O mode */
64+
InputOnly,
65+
PushPullOutput,
6366
OpenDrain,
64-
Quasi,
67+
QuasiBidirectional,
6568

66-
PullDefault = PullUp,
69+
/* Default input pull mode */
70+
PullDefault = PullUp
6771
} PinMode;
6872

6973
typedef enum {

targets/TARGET_NUVOTON/TARGET_M451/gpio_api.c

Lines changed: 70 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -51,41 +51,92 @@ void gpio_init(gpio_t *obj, PinName pin)
5151
}
5252

5353
obj->mask = gpio_set(pin);
54+
/* Default mode/direction */
55+
obj->mode = PullUp;
56+
obj->direction = PIN_INPUT;
5457
}
5558

5659
void gpio_mode(gpio_t *obj, PinMode mode)
5760
{
5861
if (obj->pin == (PinName) NC) {
5962
return;
6063
}
61-
62-
pin_mode(obj->pin, mode);
64+
65+
switch (mode) {
66+
case PullNone:
67+
case PullDown:
68+
case PullUp:
69+
/* H/W doesn't support separate configuration for input pull mode/direction.
70+
* We translate to input-only/push-pull output I/O mode dependent on direction. */
71+
obj->mode = (obj->direction == PIN_INPUT) ? InputOnly : PushPullOutput;
72+
break;
73+
74+
case QuasiBidirectional:
75+
/* With quasi-bidirectional I/O mode, before digital input function is performed,
76+
* the corresponding bit in GPIOx_DOUT must be set to 1. */
77+
obj->mode = QuasiBidirectional;
78+
if (obj->direction == PIN_INPUT) {
79+
gpio_write(obj, 1);
80+
}
81+
break;
82+
83+
case InputOnly:
84+
case PushPullOutput:
85+
/* We may meet contradictory I/O mode/direction configuration. Favor I/O mode
86+
* in the gpio_mode call here. */
87+
if (mode == InputOnly) {
88+
obj->direction = PIN_INPUT;
89+
obj->mode = InputOnly;
90+
} else {
91+
obj->direction = PIN_OUTPUT;
92+
obj->mode = PushPullOutput;
93+
}
94+
break;
95+
96+
default:
97+
/* Allow for configuring other I/O modes directly */
98+
obj->mode = mode;
99+
break;
100+
}
101+
102+
pin_mode(obj->pin, obj->mode);
63103
}
64104

65105
void gpio_dir(gpio_t *obj, PinDirection direction)
66106
{
67107
if (obj->pin == (PinName) NC) {
68108
return;
69109
}
70-
71-
uint32_t pin_index = NU_PINNAME_TO_PIN(obj->pin);
72-
uint32_t port_index = NU_PINNAME_TO_PORT(obj->pin);
73-
GPIO_T *gpio_base = NU_PORT_BASE(port_index);
74-
75-
uint32_t mode_intern = GPIO_MODE_INPUT;
76-
77-
switch (direction) {
78-
case PIN_INPUT:
79-
mode_intern = GPIO_MODE_INPUT;
80-
break;
81-
82-
case PIN_OUTPUT:
83-
mode_intern = GPIO_MODE_OUTPUT;
110+
111+
obj->direction = direction;
112+
113+
switch (obj->mode) {
114+
case PullNone:
115+
case PullDown:
116+
case PullUp:
117+
/* H/W doesn't support separate configuration for input pull mode/direction.
118+
* We translate to input-only/push-pull output I/O mode dependent on direction. */
119+
obj->mode = (obj->direction == PIN_INPUT) ? InputOnly : PushPullOutput;
84120
break;
85121

122+
case QuasiBidirectional:
123+
/* With quasi-bidirectional I/O mode, before digital input function is performed,
124+
* the corresponding bit in GPIOx_DOUT must be set to 1. */
125+
if (obj->direction == PIN_INPUT) {
126+
gpio_write(obj, 1);
127+
}
128+
break;
129+
130+
case InputOnly:
131+
case PushPullOutput:
132+
/* We may meet contradictory I/O mode/direction configuration. Favor direction
133+
* in the gpio_dir call here. */
134+
obj->mode = (obj->direction == PIN_INPUT) ? InputOnly : PushPullOutput;
135+
break;
136+
86137
default:
87-
return;
138+
break;
88139
}
89-
90-
GPIO_SetMode(gpio_base, 1 << pin_index, mode_intern);
140+
141+
pin_mode(obj->pin, obj->mode);
91142
}

targets/TARGET_NUVOTON/TARGET_M451/gpio_object.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,10 @@ extern "C" {
2828
#endif
2929

3030
typedef struct {
31-
PinName pin;
32-
uint32_t mask;
31+
PinName pin;
32+
uint32_t mask;
33+
PinDirection direction;
34+
PinMode mode;
3335
} gpio_t;
3436

3537
static inline void gpio_write(gpio_t *obj, int value)

0 commit comments

Comments
 (0)