1 /*
2 * Copyright (c) 2019 Piotr Mienkowski
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7
8 #include <limits.h>
9 #include <zephyr/sys/util.h>
10 #include "test_gpio_api.h"
11
12 #define TEST_GPIO_MAX_SINGLE_ENDED_RISE_FALL_TIME_MS 100
13 #define TEST_POINT(n) (n)
14
pin_get_raw_and_verify(const struct device * port,unsigned int pin,int val_expected,int idx)15 static void pin_get_raw_and_verify(const struct device *port,
16 unsigned int pin,
17 int val_expected, int idx)
18 {
19 int val_actual;
20
21 val_actual = gpio_pin_get_raw(port, pin);
22 zassert_true(val_actual >= 0,
23 "Test point %d: failed to get pin value", idx);
24 zassert_equal(val_expected, val_actual,
25 "Test point %d: invalid pin get value", idx);
26 }
27
pin_set_raw_and_verify(const struct device * port,unsigned int pin,int val,int idx)28 static void pin_set_raw_and_verify(const struct device *port,
29 unsigned int pin,
30 int val, int idx)
31 {
32 zassert_equal(gpio_pin_set_raw(port, pin, val), 0,
33 "Test point %d: failed to set pin value", idx);
34 k_busy_wait(TEST_GPIO_MAX_RISE_FALL_TIME_US);
35 }
36
37 /** @brief Verify gpio_pin_configure function in push pull mode.
38 *
39 * - Configure pin in in/out mode, verify that gpio_pin_set_raw /
40 * gpio_pin_get_raw operations change pin state.
41 * - Verify that GPIO_OUTPUT_HIGH flag is initializing the pin to high.
42 * - Verify that GPIO_OUTPUT_LOW flag is initializing the pin to low.
43 * - Verify that configuring the pin as an output without initializing it
44 * to high or low does not change pin state.
45 * - Verify that it is not possible to change value of a pin via
46 * gpio_pin_set_raw function if pin is configured as an input.
47 */
ZTEST(gpio_api_1pin_conf,test_gpio_pin_configure_push_pull)48 ZTEST(gpio_api_1pin_conf, test_gpio_pin_configure_push_pull)
49 {
50 const struct device *port;
51 int ret;
52
53 port = DEVICE_DT_GET(TEST_NODE);
54 zassert_true(device_is_ready(port), "GPIO dev is not ready");
55
56 TC_PRINT("Running test on port=%s, pin=%d\n", port->name, TEST_PIN);
57
58 ret = gpio_pin_configure(port, TEST_PIN, GPIO_OUTPUT);
59 zassert_equal(ret, 0, "Failed to configure the pin as an output");
60
61 pin_set_raw_and_verify(port, TEST_PIN, 1, TEST_POINT(1));
62 pin_set_raw_and_verify(port, TEST_PIN, 0, TEST_POINT(1));
63
64 /* Configure pin in in/out mode, verify that gpio_pin_set_raw /
65 * gpio_pin_get_raw operations change pin state.
66 */
67 ret = gpio_pin_configure(port, TEST_PIN, GPIO_OUTPUT | GPIO_INPUT);
68 if (ret == -ENOTSUP) {
69 TC_PRINT("Simultaneous pin in/out mode is not supported.\n");
70 ztest_test_skip();
71 return;
72 }
73 zassert_equal(ret, 0, "Failed to configure the pin in in/out mode");
74
75 pin_set_raw_and_verify(port, TEST_PIN, 0, TEST_POINT(2));
76 pin_get_raw_and_verify(port, TEST_PIN, 0, TEST_POINT(2));
77
78 pin_set_raw_and_verify(port, TEST_PIN, 1, TEST_POINT(3));
79 pin_get_raw_and_verify(port, TEST_PIN, 1, TEST_POINT(3));
80
81 pin_set_raw_and_verify(port, TEST_PIN, 0, TEST_POINT(4));
82 pin_get_raw_and_verify(port, TEST_PIN, 0, TEST_POINT(4));
83
84 /* Verify that GPIO_OUTPUT_HIGH flag is initializing the pin to high. */
85 ret = gpio_pin_configure(port, TEST_PIN, GPIO_OUTPUT_HIGH | GPIO_INPUT);
86 zassert_equal(ret, 0,
87 "Failed to configure the pin in in/out mode and "
88 "initialize it to high");
89
90 pin_get_raw_and_verify(port, TEST_PIN, 1, TEST_POINT(5));
91
92 /* Verify that configuring the pin as an output without initializing it
93 * to high or low does not change pin state.
94 */
95 ret = gpio_pin_configure(port, TEST_PIN, GPIO_OUTPUT | GPIO_INPUT);
96 zassert_equal(ret, 0, "Failed to configure the pin in in/out mode");
97
98 pin_get_raw_and_verify(port, TEST_PIN, 1, TEST_POINT(6));
99
100 /* Verify that GPIO_OUTPUT_LOW flag is initializing the pin to low. */
101 ret = gpio_pin_configure(port, TEST_PIN, GPIO_OUTPUT_LOW | GPIO_INPUT);
102 zassert_equal(ret, 0,
103 "Failed to configure the pin in in/out mode and "
104 "initialize it to low");
105
106 pin_get_raw_and_verify(port, TEST_PIN, 0, TEST_POINT(7));
107
108 /* Verify that configuring the pin as an output without initializing it
109 * to high or low does not change pin state.
110 */
111 ret = gpio_pin_configure(port, TEST_PIN, GPIO_OUTPUT | GPIO_INPUT);
112 zassert_equal(ret, 0, "Failed to configure the pin in in/out mode");
113
114 pin_get_raw_and_verify(port, TEST_PIN, 0, TEST_POINT(8));
115
116 /* Verify that it is not possible to change value of a pin via
117 * gpio_pin_set_raw function if pin is configured as an input.
118 */
119 ret = gpio_pin_configure(port, TEST_PIN, GPIO_INPUT);
120 zassert_equal(ret, 0, "Failed to configure the pin as an input");
121 k_busy_wait(TEST_GPIO_MAX_RISE_FALL_TIME_US);
122
123 int pin_in_val;
124
125 pin_in_val = gpio_pin_get_raw(port, TEST_PIN);
126 zassert_true(pin_in_val >= 0,
127 "Test point %d: failed to get pin value", TEST_POINT(9));
128
129 pin_set_raw_and_verify(port, TEST_PIN, 0, TEST_POINT(10));
130 pin_get_raw_and_verify(port, TEST_PIN, pin_in_val, TEST_POINT(10));
131
132 pin_set_raw_and_verify(port, TEST_PIN, 1, TEST_POINT(11));
133 pin_get_raw_and_verify(port, TEST_PIN, pin_in_val, TEST_POINT(11));
134 }
135
136 /** @brief Verify gpio_pin_configure function in single ended mode.
137 *
138 * @note This test verifies single ended mode only partially. It should not be
139 * used as a sign off test.
140 *
141 * - Verify that pin configured in Open Drain mode and initialized
142 * to high results in pin high value if the same pin configured
143 * as input is high. Drivers that do not support Open Drain flag
144 * return ENOTSUP.
145 * - Setting pin configured in Open Drain mode to low results in
146 * pin low value if the same pin configured as input is high.
147 * - Verify that pin configured in Open Source mode and
148 * initialized to low results in pin high value if the same pin
149 * configured as input is high. Drivers that do not support Open
150 * Source flag return ENOTSUP.
151 * - Verify that pin configured in Open Source mode and
152 * initialized to low results in pin low value if the same pin
153 * configured as input is low. Drivers that do not support Open
154 * Source flag return ENOTSUP.
155 * - Setting pin configured in Open Source mode to high results in
156 * pin high value if the same pin configured as input is low.
157 * - Verify that pin configured in Open Drain mode and
158 * initialized to high results in pin low value if the same pin
159 * configured as input is low. Drivers that do not support Open
160 * Drain flag return ENOTSUP.
161 */
ZTEST(gpio_api_1pin_conf,test_gpio_pin_configure_single_ended)162 ZTEST(gpio_api_1pin_conf, test_gpio_pin_configure_single_ended)
163 {
164 const struct device *port;
165 int pin_in_val;
166 int pin_val;
167 unsigned int cfg_flag;
168 int ret;
169
170 port = DEVICE_DT_GET(TEST_NODE);
171 zassert_true(device_is_ready(port), "GPIO dev is not ready");
172
173 TC_PRINT("Running test on port=%s, pin=%d\n", port->name, TEST_PIN);
174
175 /* If the LED is connected directly between the MCU pin and power or
176 * ground we can test only one of the Open Drain / Open Source modes.
177 * Guess pin level when the LED is off. If the pin is not connected
178 * directly to LED but instead the signal is routed to an input of
179 * another chip we could test both modes. However, there is no way to
180 * find it out so only one mode is tested.
181 */
182 if ((TEST_PIN_DTS_FLAGS & GPIO_ACTIVE_LOW) != 0) {
183 cfg_flag = GPIO_PULL_UP;
184 pin_val = 1;
185 } else {
186 cfg_flag = GPIO_PULL_DOWN;
187 pin_val = 0;
188 }
189
190 /* Configure pin as an input with pull up/down and check input level. */
191 ret = gpio_pin_configure(port, TEST_PIN, GPIO_INPUT | cfg_flag);
192 if (ret == -ENOTSUP) {
193 TC_PRINT("Pull Up / Pull Down pin bias is not supported\n");
194 ztest_test_skip();
195 return;
196 }
197 zassert_equal(ret, 0, "Failed to configure pin as an input");
198
199 k_sleep(K_MSEC(TEST_GPIO_MAX_SINGLE_ENDED_RISE_FALL_TIME_MS));
200
201 pin_in_val = gpio_pin_get_raw(port, TEST_PIN);
202 zassert_true(pin_in_val >= 0, "Failed to get pin value");
203
204 if (pin_val != pin_in_val) {
205 TC_PRINT("Board configuration does not allow to run the test\n");
206 ztest_test_skip();
207 return;
208 }
209
210 if (pin_val == 1) {
211 TC_PRINT("When configured as input test pin value is high\n");
212 /* Verify that pin configured in Open Drain mode and initialized
213 * to high results in pin high value if the same pin configured
214 * as input is high. Drivers that do not support Open Drain flag
215 * return -ENOTSUP.
216 */
217 ret = gpio_pin_configure(port, TEST_PIN, GPIO_OUTPUT_HIGH |
218 GPIO_OPEN_DRAIN | GPIO_INPUT | GPIO_PULL_UP);
219 if (ret == -ENOTSUP) {
220 TC_PRINT("Open Drain configuration or Pull Up pin "
221 "bias is not supported\n");
222 ztest_test_skip();
223 return;
224 }
225 zassert_equal(ret, 0,
226 "Failed to configure the pin in Open Drain mode");
227
228 pin_get_raw_and_verify(port, TEST_PIN, 1, TEST_POINT(1));
229
230 /* Setting pin configured in Open Drain mode to low results in
231 * pin low value if the same pin configured as input is high.
232 */
233 pin_set_raw_and_verify(port, TEST_PIN, 0, TEST_POINT(2));
234 pin_get_raw_and_verify(port, TEST_PIN, 0, TEST_POINT(2));
235
236 /* Verify that pin configured in Open Source mode and
237 * initialized to low results in pin high value if the same pin
238 * configured as input is high. Drivers that do not support Open
239 * Source flag return -ENOTSUP.
240 */
241 ret = gpio_pin_configure(port, TEST_PIN, GPIO_OUTPUT_LOW |
242 GPIO_OPEN_SOURCE | GPIO_INPUT | GPIO_PULL_UP);
243 if (ret == -ENOTSUP) {
244 TC_PRINT("Open Source configuration or Pull Up pin "
245 "bias is not supported\n");
246 return;
247 }
248 zassert_equal(ret, 0,
249 "Failed to configure the pin in Open Source mode");
250
251 k_sleep(K_MSEC(TEST_GPIO_MAX_SINGLE_ENDED_RISE_FALL_TIME_MS));
252
253 pin_get_raw_and_verify(port, TEST_PIN, 1, TEST_POINT(3));
254
255 pin_set_raw_and_verify(port, TEST_PIN, 0, TEST_POINT(4));
256 pin_get_raw_and_verify(port, TEST_PIN, 1, TEST_POINT(4));
257 } else {
258 TC_PRINT("When configured as input test pin value is low\n");
259 /* Verify that pin configured in Open Source mode and
260 * initialized to low results in pin low value if the same pin
261 * configured as input is low. Drivers that do not support Open
262 * Source flag return -ENOTSUP.
263 */
264 ret = gpio_pin_configure(port, TEST_PIN, GPIO_OUTPUT_LOW |
265 GPIO_OPEN_SOURCE | GPIO_INPUT | GPIO_PULL_DOWN);
266 if (ret == -ENOTSUP) {
267 TC_PRINT("Open Source configuration or Pull Down pin "
268 "bias is not supported\n");
269 ztest_test_skip();
270 return;
271 }
272 zassert_equal(ret, 0,
273 "Failed to configure the pin in Open Source mode");
274
275 pin_get_raw_and_verify(port, TEST_PIN, 0, TEST_POINT(5));
276
277 /* Setting pin configured in Open Source mode to high results in
278 * pin high value if the same pin configured as input is low.
279 */
280 pin_set_raw_and_verify(port, TEST_PIN, 1, TEST_POINT(6));
281 pin_get_raw_and_verify(port, TEST_PIN, 1, TEST_POINT(6));
282
283 /* Verify that pin configured in Open Drain mode and
284 * initialized to high results in pin low value if the same pin
285 * configured as input is low. Drivers that do not support Open
286 * Drain flag return -ENOTSUP.
287 */
288 ret = gpio_pin_configure(port, TEST_PIN, GPIO_OUTPUT_HIGH |
289 GPIO_OPEN_DRAIN | GPIO_INPUT | GPIO_PULL_DOWN);
290 if (ret == -ENOTSUP) {
291 TC_PRINT("Open Drain configuration or Pull Down pin "
292 "bias is not supported\n");
293 return;
294 }
295 zassert_equal(ret, 0,
296 "Failed to configure the pin in Open Drain mode");
297
298 k_sleep(K_MSEC(TEST_GPIO_MAX_SINGLE_ENDED_RISE_FALL_TIME_MS));
299
300 pin_get_raw_and_verify(port, TEST_PIN, 0, TEST_POINT(7));
301
302 pin_set_raw_and_verify(port, TEST_PIN, 1, TEST_POINT(8));
303 pin_get_raw_and_verify(port, TEST_PIN, 0, TEST_POINT(8));
304 }
305 }
306
307 ZTEST_SUITE(gpio_api_1pin_conf, NULL, NULL, NULL, NULL, NULL);
308