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 struct gpio_callback gpio_cb;
13 static int cb_count;
14 static int cb_count_target;
15
callback_edge(const struct device * port,struct gpio_callback * cb,gpio_port_pins_t pins)16 static void callback_edge(const struct device *port, struct gpio_callback *cb,
17 gpio_port_pins_t pins)
18 {
19 zassert_equal(pins, BIT(TEST_PIN),
20 "Detected interrupt on an invalid pin");
21 cb_count++;
22 }
23
callback_level(const struct device * port,struct gpio_callback * cb,gpio_port_pins_t pins)24 static void callback_level(const struct device *port,
25 struct gpio_callback *cb,
26 gpio_port_pins_t pins)
27 {
28 int ret;
29
30 zassert_equal(pins, BIT(TEST_PIN),
31 "Detected interrupt on an invalid pin");
32
33 cb_count++;
34 if (cb_count % cb_count_target == 0) {
35 ret = gpio_pin_interrupt_configure(port, TEST_PIN, GPIO_INT_DISABLE);
36 zassert_equal(ret, 0,
37 "Failed to disable pin interrupt in the callback");
38 }
39 }
40
pin_set_and_verify(const struct device * port,unsigned int pin,int val,int idx)41 static void pin_set_and_verify(const struct device *port, unsigned int pin,
42 int val,
43 int idx)
44 {
45 zassert_equal(gpio_pin_set(port, pin, val), 0,
46 "Test point %d: failed to set logical pin value", idx);
47 k_busy_wait(TEST_GPIO_MAX_RISE_FALL_TIME_US);
48 }
49
test_gpio_pin_interrupt_edge(unsigned int cfg_flags,unsigned int int_flags)50 void test_gpio_pin_interrupt_edge(unsigned int cfg_flags,
51 unsigned int int_flags)
52 {
53 const struct device *port;
54 int cb_count_expected;
55 unsigned int cfg_out_flag;
56 int ret;
57
58 port = DEVICE_DT_GET(TEST_NODE);
59 zassert_true(device_is_ready(port), "GPIO dev is not ready");
60
61 TC_PRINT("Running test on port=%s, pin=%d\n", port->name, TEST_PIN);
62
63 ret = gpio_pin_configure(port, TEST_PIN, GPIO_INPUT | GPIO_OUTPUT);
64 if (ret == -ENOTSUP) {
65 TC_PRINT("Simultaneous pin in/out mode is not supported.\n");
66 ztest_test_skip();
67 return;
68 }
69 zassert_equal(ret, 0, "Failed to configure the pin");
70
71 if ((cfg_flags & GPIO_ACTIVE_LOW) != 0) {
72 cfg_out_flag = GPIO_OUTPUT_HIGH;
73 } else {
74 cfg_out_flag = GPIO_OUTPUT_LOW;
75 }
76 ret = gpio_pin_configure(port, TEST_PIN, GPIO_INPUT | cfg_out_flag |
77 cfg_flags);
78 zassert_equal(ret, 0, "Failed to configure the pin");
79
80 cb_count = 0;
81 cb_count_expected = 0;
82
83 gpio_init_callback(&gpio_cb, callback_edge, BIT(TEST_PIN));
84 ret = gpio_add_callback(port, &gpio_cb);
85
86 ret = gpio_pin_interrupt_configure(port, TEST_PIN, int_flags);
87 if (ret == -ENOTSUP) {
88 TC_PRINT("Pin interrupt is not supported.\n");
89 ztest_test_skip();
90 return;
91 }
92 zassert_equal(ret, 0, "Failed to configure pin interrupt");
93
94 for (int i = 0; i < 6; i++) {
95 pin_set_and_verify(port, TEST_PIN, 1, i);
96 if (int_flags & GPIO_INT_HIGH_1) {
97 cb_count_expected++;
98 }
99 zassert_equal(cb_count, cb_count_expected,
100 "Test point %d: Pin interrupt triggered invalid "
101 "number of times on rising/to active edge", i);
102
103 pin_set_and_verify(port, TEST_PIN, 0, i);
104 if (int_flags & GPIO_INT_LOW_0) {
105 cb_count_expected++;
106 }
107 zassert_equal(cb_count, cb_count_expected,
108 "Test point %d: Pin interrupt triggered invalid "
109 "number of times on falling/to inactive edge", i);
110 }
111
112 ret = gpio_pin_interrupt_configure(port, TEST_PIN, GPIO_INT_DISABLE);
113 zassert_equal(ret, 0, "Failed to disable pin interrupt");
114
115 for (int i = 0; i < 6; i++) {
116 pin_set_and_verify(port, TEST_PIN, 1, i);
117 pin_set_and_verify(port, TEST_PIN, 0, i);
118 zassert_equal(cb_count, cb_count_expected,
119 "Pin interrupt triggered when disabled");
120 }
121 }
122
test_gpio_pin_interrupt_level(unsigned int cfg_flags,unsigned int int_flags,unsigned int interrupt_calls)123 void test_gpio_pin_interrupt_level(unsigned int cfg_flags,
124 unsigned int int_flags, unsigned int interrupt_calls)
125 {
126 const struct device *port;
127 int cb_count_expected;
128 unsigned int cfg_out_flag;
129 int pin_out_val;
130 int ret;
131
132 port = DEVICE_DT_GET(TEST_NODE);
133 zassert_true(device_is_ready(port), "GPIO dev is not ready");
134
135 TC_PRINT("Running test on port=%s, pin=%d\n", port->name, TEST_PIN);
136
137 ret = gpio_pin_configure(port, TEST_PIN, GPIO_INPUT | GPIO_OUTPUT);
138 if (ret == -ENOTSUP) {
139 TC_PRINT("Simultaneous pin in/out mode is not supported.\n");
140 ztest_test_skip();
141 return;
142 }
143 zassert_equal(ret, 0, "Failed to configure the pin");
144
145 pin_out_val = ((int_flags & GPIO_INT_HIGH_1) != 0) ? 0 : 1;
146
147 if ((cfg_flags & GPIO_ACTIVE_LOW) != 0) {
148 cfg_out_flag = (pin_out_val != 0) ? GPIO_OUTPUT_LOW :
149 GPIO_OUTPUT_HIGH;
150 } else {
151 cfg_out_flag = (pin_out_val != 0) ? GPIO_OUTPUT_HIGH :
152 GPIO_OUTPUT_LOW;
153 }
154
155 ret = gpio_pin_configure(port, TEST_PIN, GPIO_INPUT | cfg_out_flag |
156 cfg_flags);
157 zassert_equal(ret, 0, "Failed to configure the pin");
158
159 cb_count = 0;
160 cb_count_expected = 0;
161 cb_count_target = interrupt_calls;
162
163 gpio_init_callback(&gpio_cb, callback_level, BIT(TEST_PIN));
164 ret = gpio_add_callback(port, &gpio_cb);
165
166 ret = gpio_pin_interrupt_configure(port, TEST_PIN, int_flags);
167 if (ret == -ENOTSUP) {
168 TC_PRINT("Pin interrupt is not supported.\n");
169 ztest_test_skip();
170 return;
171 }
172 zassert_equal(ret, 0, "Failed to configure pin interrupt");
173
174 zassert_equal(cb_count, cb_count_expected,
175 "Pin interrupt triggered on level %d", pin_out_val);
176
177 for (int i = 0; i < 6; i++) {
178 pin_out_val = (pin_out_val != 0) ? 0 : 1;
179 pin_set_and_verify(port, TEST_PIN, pin_out_val, i);
180 cb_count_expected += interrupt_calls;
181 zassert_equal(cb_count, cb_count_expected,
182 "Test point %d: Pin interrupt triggered invalid "
183 "number of times on level %d", i, pin_out_val);
184
185 pin_out_val = (pin_out_val != 0) ? 0 : 1;
186 pin_set_and_verify(port, TEST_PIN, pin_out_val, i);
187 zassert_equal(cb_count, cb_count_expected,
188 "Test point %d: Pin interrupt triggered invalid "
189 "number of times on level %d", i, pin_out_val);
190
191 /* Re-enable pin level interrupt */
192 ret = gpio_pin_interrupt_configure(port, TEST_PIN, int_flags);
193 zassert_equal(ret, 0,
194 "Failed to re-enable pin level interrupt");
195 }
196
197 ret = gpio_pin_interrupt_configure(port, TEST_PIN, GPIO_INT_DISABLE);
198 zassert_equal(ret, 0, "Failed to disable pin interrupt");
199
200 for (int i = 0; i < 6; i++) {
201 pin_set_and_verify(port, TEST_PIN, 1, i);
202 pin_set_and_verify(port, TEST_PIN, 0, i);
203 zassert_equal(cb_count, cb_count_expected,
204 "Pin interrupt triggered when disabled");
205 }
206 }
207
208 /** @brief Verify GPIO_INT_EDGE_RISING flag. */
ZTEST(gpio_api_1pin_int,test_gpio_int_edge_rising)209 ZTEST(gpio_api_1pin_int, test_gpio_int_edge_rising)
210 {
211 test_gpio_pin_interrupt_edge(0, GPIO_INT_EDGE_RISING);
212 }
213
214 /** @brief Verify GPIO_INT_EDGE_FALLING flag. */
ZTEST(gpio_api_1pin_int,test_gpio_int_edge_falling)215 ZTEST(gpio_api_1pin_int, test_gpio_int_edge_falling)
216 {
217 test_gpio_pin_interrupt_edge(0, GPIO_INT_EDGE_FALLING);
218 }
219
220 /** @brief Verify GPIO_INT_EDGE_BOTH flag. */
ZTEST(gpio_api_1pin_int,test_gpio_int_edge_both)221 ZTEST(gpio_api_1pin_int, test_gpio_int_edge_both)
222 {
223 test_gpio_pin_interrupt_edge(0, GPIO_INT_EDGE_BOTH);
224 }
225
226 /** @brief Verify GPIO_INT_EDGE_TO_ACTIVE flag. */
ZTEST(gpio_api_1pin_int,test_gpio_int_edge_to_active)227 ZTEST(gpio_api_1pin_int, test_gpio_int_edge_to_active)
228 {
229 TC_PRINT("Step 1: Configure pin as active high\n");
230 test_gpio_pin_interrupt_edge(GPIO_ACTIVE_HIGH, GPIO_INT_EDGE_TO_ACTIVE);
231 TC_PRINT("Step 2: Configure pin as active low\n");
232 test_gpio_pin_interrupt_edge(GPIO_ACTIVE_LOW, GPIO_INT_EDGE_TO_ACTIVE);
233 }
234
235 /** @brief Verify GPIO_INT_EDGE_TO_INACTIVE flag. */
ZTEST(gpio_api_1pin_int,test_gpio_int_edge_to_inactive)236 ZTEST(gpio_api_1pin_int, test_gpio_int_edge_to_inactive)
237 {
238 TC_PRINT("Step 1: Configure pin as active high\n");
239 test_gpio_pin_interrupt_edge(GPIO_ACTIVE_HIGH, GPIO_INT_EDGE_TO_INACTIVE);
240 TC_PRINT("Step 2: Configure pin as active low\n");
241 test_gpio_pin_interrupt_edge(GPIO_ACTIVE_LOW, GPIO_INT_EDGE_TO_INACTIVE);
242 }
243
244 /** @brief Verify GPIO_INT_LEVEL_HIGH flag with 1 interrupt call */
ZTEST(gpio_api_1pin_int,test_gpio_int_level_high_interrupt_count_1)245 ZTEST(gpio_api_1pin_int, test_gpio_int_level_high_interrupt_count_1)
246 {
247 test_gpio_pin_interrupt_level(0, GPIO_INT_LEVEL_HIGH, 1);
248 }
249
250 /** @brief Verify GPIO_INT_LEVEL_HIGH flag with 5 interrupt call */
ZTEST(gpio_api_1pin_int,test_gpio_int_level_high_interrupt_count_5)251 ZTEST(gpio_api_1pin_int, test_gpio_int_level_high_interrupt_count_5)
252 {
253 test_gpio_pin_interrupt_level(0, GPIO_INT_LEVEL_HIGH, 5);
254 }
255
256 /** @brief Verify GPIO_INT_LEVEL_LOW flag with 1 interrupt call */
ZTEST(gpio_api_1pin_int,test_gpio_int_level_low_interrupt_count_1)257 ZTEST(gpio_api_1pin_int, test_gpio_int_level_low_interrupt_count_1)
258 {
259 test_gpio_pin_interrupt_level(0, GPIO_INT_LEVEL_LOW, 1);
260 }
261
262 /** @brief Verify GPIO_INT_LEVEL_LOW flag with 5 interrupt call */
ZTEST(gpio_api_1pin_int,test_gpio_int_level_low_interrupt_count_5)263 ZTEST(gpio_api_1pin_int, test_gpio_int_level_low_interrupt_count_5)
264 {
265 test_gpio_pin_interrupt_level(0, GPIO_INT_LEVEL_LOW, 5);
266 }
267
268 /** @brief Verify GPIO_INT_LEVEL_ACTIVE flag. */
ZTEST(gpio_api_1pin_int,test_gpio_int_level_active)269 ZTEST(gpio_api_1pin_int, test_gpio_int_level_active)
270 {
271 TC_PRINT("Step 1: Configure pin as active high\n");
272 test_gpio_pin_interrupt_level(GPIO_ACTIVE_HIGH, GPIO_INT_LEVEL_ACTIVE, 1);
273 TC_PRINT("Step 2: Configure pin as active low\n");
274 test_gpio_pin_interrupt_level(GPIO_ACTIVE_LOW, GPIO_INT_LEVEL_ACTIVE, 1);
275 }
276
277 /** @brief Verify GPIO_INT_LEVEL_INACTIVE flag. */
ZTEST(gpio_api_1pin_int,test_gpio_int_level_inactive)278 ZTEST(gpio_api_1pin_int, test_gpio_int_level_inactive)
279 {
280 TC_PRINT("Step 1: Configure pin as active high\n");
281 test_gpio_pin_interrupt_level(GPIO_ACTIVE_HIGH, GPIO_INT_LEVEL_INACTIVE, 1);
282 TC_PRINT("Step 2: Configure pin as active low\n");
283 test_gpio_pin_interrupt_level(GPIO_ACTIVE_LOW, GPIO_INT_LEVEL_INACTIVE, 1);
284 }
285
286 ZTEST_SUITE(gpio_api_1pin_int, NULL, NULL, NULL, NULL, NULL);
287