1 /*
2 * Copyright (c) 2023 Nordic Semiconductor ASA
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 /*
8 * GPIO - General purpose input/output
9 * https://infocenter.nordicsemi.com/topic/ps_nrf52833/gpio.html?cp=5_1_0_5_7
10 *
11 * This model has the following limitations:
12 * * Note a.1:
13 * PIN_CNF.PULL is ignored. If a pin input is disconnected and not driven externally it will
14 * just remain at zero/low.
15 * * Note a.2:
16 * PIN_CNF.DRIVE / drive strength is ignored
17 * It is not possible to connect two outputs together building a logical AND or OR
18 * * Note a.3:
19 * Reading OUTCLR & DIRCLR reads always 0
20 * * Note a.4: There is no modeling of system idle/off, and as such a DETECT raising edge from the
21 * GPIO will not cause the system to exit those states.
22 *
23 * This model has the following approximations:
24 * * Note b.1:
25 * If a DIR bit is cleared for a pin which was being driven as a high output,
26 * that pin will be lowered immediately (like if it was driven low)
27 * * Note b.2:
28 * All drives are instantaneous.
29 * * Note b.3:
30 * During pin reconfigurations, there can be spurious transitions in the pins outputs
31 * which may not correspond to how the real HW would behave
32 * * In real HW, after a write to LATCH, the DETECT event output to the GPIOTE is kept low for
33 * a few clocks, before being raised again (if it needs to), in the model the new pulse/raise
34 * is sent instantaneously to the GPIOTE
35 */
36
37 #include <stdint.h>
38 #include <stdbool.h>
39 #include <string.h>
40 #include "NHW_common_types.h"
41 #include "NHW_config.h"
42 #include "NHW_common_types.h"
43 #include "NHW_config.h"
44 #include "NHW_peri_types.h"
45 #include "NRF_GPIO.h"
46 #include "NRF_GPIOTE.h"
47 #include "bs_tracing.h"
48 #include "nsi_tasks.h"
49
50 NRF_GPIO_Type NRF_GPIO_regs[NRF_GPIOS];
51
52 /* Number of pins per port: */
53 static int GPIO_n_ports_pins[NRF_GPIOS] = NRF_GPIO_PORTS_PINS;
54
55 static uint32_t IO_level[NRF_GPIOS]; /* Actual level in the pin */
56 static uint32_t DETECT[NRF_GPIOS]; /* Sense output / unlatched/non-sticky detect */
57 static uint32_t LDETECT[NRF_GPIOS]; /* Latched sense output */
58 static bool DETECT_signal[NRF_GPIOS]; /* Individual detect signal to the GPIOTE */
59
60 static uint32_t INPUT_mask[NRF_GPIOS]; /* As a 32bit mask, PIN_CNF[*].INPUT (0: enabled; 1: disabled)*/
61 static uint32_t SENSE_mask[NRF_GPIOS]; /* As a 32bit mask, PIN_CNF[*].SENSE.en (1: enabled; 0: disabled)*/
62 static uint32_t SENSE_inv[NRF_GPIOS]; /* As a 32bit mask, PIN_CNF[*].SENSE.inv (1: inverted;0: not inverted) */
63
64 /*
65 * Is the output driven by another peripheral (1) or the GPIO directly (0).
66 * Note that we don't keep track of who "owns" a pin, only that somebody else does
67 */
68 static uint32_t out_override[NRF_GPIOS];
69 /* Out value provided by other peripherals */
70 static uint32_t external_OUT[NRF_GPIOS];
71
72 /* Is the pin input controlled by a peripheral(1) or the GPIO(0) */
73 static uint32_t input_override[NRF_GPIOS];
74 /* If input_override, is the peripheral configuring the input buffer as connected (1) or disconnected (0) */
75 static uint32_t input_override_connected[NRF_GPIOS];
76
77 /* Is "dir" controlled by a peripheral(1) or the GPIO(0) */
78 static uint32_t dir_override[NRF_GPIOS];
79 /* If dir_override is set, is the peripheral configuring the output as connected (1) or disconnected (0) */
80 static uint32_t dir_override_set[NRF_GPIOS];
81
82 /* Callbacks for peripherals to be informed of input changes */
83 static nrf_gpio_input_callback_t per_intoggle_callbacks[NRF_GPIOS][NRF_GPIO_MAX_PINS_PER_PORT];
84 /* Callbacks for test code to be informed of input/output changes: */
85 static nrf_gpio_input_callback_t test_intoggle_callback;
86 static nrf_gpio_input_callback_t test_outtoggle_callback;
87
88 /*
89 * Initialize the GPIOs model
90 */
nrf_gpio_init(void)91 static void nrf_gpio_init(void) {
92 memset(NRF_GPIO_regs, 0, sizeof(NRF_GPIO_regs));
93
94 for (int p = 0; p < NRF_GPIOS; p ++) {
95 for (int n = 0; n < GPIO_n_ports_pins[p]; n++) {
96 NRF_GPIO_regs[p].PIN_CNF[n] = 0x2; /* Disconnected out of reset */
97 }
98 INPUT_mask[p] = UINT32_MAX; /* All disconnected out of reset */
99 }
100
101 nrf_gpio_backend_init();
102 }
103
104 NSI_TASK(nrf_gpio_init, HW_INIT, 100);
105
nrf_gpio_get_number_pins_in_port(int port)106 unsigned int nrf_gpio_get_number_pins_in_port(int port) {
107 return GPIO_n_ports_pins[port];
108 }
109
110 static void nrf_gpio_eval_outputs(unsigned int port);
111 static void nrf_gpio_eval_inputs(unsigned int port);
112 void nrf_gpio_eval_input(unsigned int port, unsigned int n, bool value);
113
114 /*
115 * Register a test callback to be called whenever a pin IN register changes
116 */
nrf_gpio_test_register_in_callback(nrf_gpio_input_callback_t fptr)117 void nrf_gpio_test_register_in_callback(nrf_gpio_input_callback_t fptr) {
118 test_intoggle_callback = fptr;
119 }
120
121 /*
122 * Register a test callback to be called whenever an *output* pin changes
123 */
nrf_gpio_test_register_out_callback(nrf_gpio_input_callback_t fptr)124 void nrf_gpio_test_register_out_callback(nrf_gpio_input_callback_t fptr) {
125 test_outtoggle_callback = fptr;
126 }
127
128 /*
129 * Change a pin input value
130 *
131 * Note: The pin must not be currently driven by the SOC, or you will get an error
132 *
133 * Inputs:
134 * * port: Which GPIO port
135 * * n: which pin in that GPIO port
136 * * value: true: high, false: low
137 */
nrf_gpio_test_change_pin_level(unsigned int port,unsigned int n,bool value)138 void nrf_gpio_test_change_pin_level(unsigned int port, unsigned int n, bool value) {
139 nrf_gpio_eval_input(port, n, value);
140 }
141
142 /*
143 * Get a pin level
144 *
145 * Inputs:
146 * * port: Which GPIO port
147 * * n: which pin in that GPIO port
148 * Return: true (high), false (low)
149 */
nrf_gpio_get_pin_level(unsigned int port,unsigned int n)150 bool nrf_gpio_get_pin_level(unsigned int port, unsigned int n) {
151 return (IO_level[port] >> n) & 0x1;
152 }
153
154 #define CHECK_PIN_EXISTS(port, n, dir) \
155 if (port >= NRF_GPIOS || n >= GPIO_n_ports_pins[port]) { \
156 bs_trace_error_time_line("%s: Error, attempted to toggle "dir" for nonexistent " \
157 "GPIO port %i, pin %i\n", \
158 __func__, port, n); \
159 }
160
get_enabled_inputs(unsigned int port)161 static inline uint32_t get_enabled_inputs(unsigned int port){
162 return (~input_override[port] & ~INPUT_mask[port])
163 | (input_override[port] & input_override_connected[port]);
164 }
165
get_dir(unsigned int port)166 static inline uint32_t get_dir(unsigned int port){
167 return (~dir_override[port] & NRF_GPIO_regs[port].DIR)
168 | (dir_override[port] & dir_override_set[port]);
169 }
170
171 /*
172 * Function with which another peripheral can claim configuration control of a pin.
173 *
174 * Inputs:
175 * * port: Which GPIO port
176 * * n : which pin in that GPIO port
177 * * override_output:
178 * * -1 : Don't change
179 * * 0 : Leave for GPIO control (GPIO OUT register sets the output value)
180 * * 1 : Take external control of pin output value (peripheral sets the output value
181 * with nrf_gpio_peri_change_output() )
182 * * override_input:
183 * * -1 : Don't change
184 * * 0 : Leave input to be controlled by the GPIO module
185 * * 2 : Take external control of input, and disconnect
186 * * 3 : Take external control of input, and connect
187 * * override_dir:
188 * * -1 : Don't change
189 * * 0 : Leave DIR to be controlled by the GPIO module
190 * * 2 : Take external control of DIR, and disconnect
191 * * 3 : Take external control of DIR, and connect
192 * * fptr: Function to be called whenever that input toggles (if enabled).
193 * Set to NULL if not needed.
194 * * new_level:
195 * * -1: Don't change
196 * * 0: low
197 * * 1: high
198 */
nrf_gpio_peri_pin_control(unsigned int port,unsigned int n,int override_output,int override_input,int override_dir,nrf_gpio_input_callback_t fptr,int new_level)199 void nrf_gpio_peri_pin_control(unsigned int port, unsigned int n,
200 int override_output, int override_input, int override_dir,
201 nrf_gpio_input_callback_t fptr, int new_level) {
202
203 if (port >= NRF_GPIOS || n >= GPIO_n_ports_pins[port]) { /* LCOV_EXCL_BR_LINE */
204 bs_trace_error_time_line("Programming error\n"); /* LCOV_EXCL_LINE */
205 }
206
207 uint32_t mask = 1<<n;
208 bool need_output_eval = false;
209 bool need_input_eval = false;
210
211 if (override_output >= 0) {
212 out_override[port] &= ~mask;
213 out_override[port] |= (uint32_t)(override_output?1:0) << n;
214 need_output_eval = true;
215 }
216 if (override_input >= 0) {
217 input_override[port] &= ~mask;
218 input_override[port] |= (uint32_t)(override_input?1:0) << n;
219
220 input_override_connected[port] &= ~mask;
221 input_override_connected[port] |= (uint32_t)(override_input==3?1:0) << n;
222
223 need_input_eval = true;
224 }
225 if (override_dir >= 0) {
226 dir_override[port] &= ~mask;
227 dir_override[port] |= (uint32_t)(override_dir?1:0) << n;
228
229 dir_override_set[port] &= ~mask;
230 dir_override_set[port] |= (uint32_t)(override_dir==3?1:0) << n;
231
232 need_output_eval = true;
233 }
234 per_intoggle_callbacks[port][n] = fptr;
235 if (new_level >= 0) {
236 external_OUT[port] &= ~((uint32_t)1 << n);
237 external_OUT[port] |= (uint32_t)(new_level?1:0) << n;
238 need_output_eval = true;
239 }
240
241 if (need_output_eval) {
242 nrf_gpio_eval_outputs(port);
243 }
244 if (need_input_eval) {
245 nrf_gpio_eval_inputs(port);
246 }
247 }
248
249 /*
250 * A peripheral wants to toggle a GPIO output to a new value <value>.
251 * Note: The value may be the same as it was, in which case nothing will happen.
252 *
253 * Inputs:
254 * * port is the GPIO port
255 * * n is the pin number inside that GPIO port (0..31)
256 * * value is the new output value high (true) or low (false)
257 */
nrf_gpio_peri_change_output(unsigned int port,unsigned int n,bool value)258 void nrf_gpio_peri_change_output(unsigned int port, unsigned int n, bool value)
259 {
260 CHECK_PIN_EXISTS(port, n, "output"); /* LCOV_EXCL_BR_LINE */
261
262 if (((out_override[port] >> n) & 0x1) != 1) { /* LCOV_EXCL_START */
263 bs_trace_error_time_line("%s: Programming error, a peripheral is trying to toggle "
264 "a GPIO output it does not own, GPIO port %i, pin %i\n",
265 __func__, port, n);
266 }
267
268 if (((get_dir(port) >> n) & 0x1) != 1) {
269 bs_trace_warning_time_line("%s: A peripheral is trying to toggle "
270 "a GPIO output but the output is disabled, "
271 "GPIO port %i, pin %i\n",
272 __func__, port, n);
273 } /* LCOV_EXCL_STOP */
274
275 external_OUT[port] &= ~((uint32_t)1 << n);
276 external_OUT[port] |= (uint32_t)value << n;
277 nrf_gpio_eval_outputs(port);
278 }
279
nrf_gpio_update_detect_signal(unsigned int port)280 static void nrf_gpio_update_detect_signal(unsigned int port) {
281 if (NRF_GPIO_regs[port].DETECTMODE == 0){ //gpio.detect signal from not latched detect
282 DETECT_signal[port] = (DETECT[port] != 0);
283 } else {//gpio.detect signal from latched detect
284 DETECT_signal[port] = (LDETECT[port] != 0);
285 }
286 }
287
288 /*
289 * Evaluate sense output (after a change of input or configuration)
290 */
nrf_gpio_eval_sense(unsigned int port)291 static void nrf_gpio_eval_sense(unsigned int port){
292 /* Note SENSE_dir inverts the output */
293 DETECT[port] = (NRF_GPIO_regs[port].IN ^ SENSE_inv[port]) & SENSE_mask[port];
294 LDETECT[port] |= DETECT[port];
295 NRF_GPIO_regs[port].LATCH = LDETECT[port];
296
297 bool old_DETECT_signal = DETECT_signal[port];
298
299 nrf_gpio_update_detect_signal(port);
300
301 if ((DETECT_signal[port] == true) && (old_DETECT_signal==false)) {
302 nrf_gpiote_port_event_raise(port);
303 }
304 }
305
306 /*
307 * Return the level of the DETECT output signal for a GPIO instance
308 *
309 * input: port: The GPIO instance number
310 */
nrf_gpio_get_detect_level(unsigned int port)311 bool nrf_gpio_get_detect_level(unsigned int port){
312 return DETECT_signal[port];
313 }
314
315 /*
316 * The input has changed and the driver is connected,
317 * notify as necessary
318 */
nrf_gpio_input_change_sideeffects(unsigned int port,unsigned int n)319 static void nrf_gpio_input_change_sideeffects(unsigned int port,unsigned int n)
320 {
321 if (per_intoggle_callbacks[port][n] != NULL) {
322 per_intoggle_callbacks[port][n](port, n, (NRF_GPIO_regs[port].IN >> n) & 0x1);
323 }
324 if (test_intoggle_callback != NULL) {
325 test_intoggle_callback(port, n, (NRF_GPIO_regs[port].IN >> n) & 0x1);
326 }
327 }
328
329 /*
330 * Get the level of the IN signal for GPIO <port> pin <n>
331 */
nrf_gpio_get_IN(unsigned int port,unsigned int n)332 bool nrf_gpio_get_IN(unsigned int port, unsigned int n) {
333 return (NRF_GPIO_regs[port].IN >> n) & 0x1;
334 }
335
336 /*
337 * An input pin has toggled or the input configuration has changed,
338 * propagate it
339 */
nrf_gpio_eval_inputs(unsigned int port)340 static void nrf_gpio_eval_inputs(unsigned int port)
341 {
342 uint32_t new_IN = IO_level[port] & get_enabled_inputs(port);
343
344 uint32_t diff = new_IN ^ NRF_GPIO_regs[port].IN;
345
346 NRF_GPIO_regs[port].IN = new_IN;
347
348 for (int n = __builtin_ffs(diff) - 1; n >= 0; n = __builtin_ffs(diff) - 1) {
349 nrf_gpio_input_change_sideeffects(port, n);
350 diff &= ~(1 << n);
351 }
352
353 nrf_gpio_eval_sense(port);
354 }
355
356 /*
357 * An input *may* be changing to a new value <value>.
358 * Note: The value may be the same as it was, in which case nothing will happen.
359 *
360 * This function is meant to be called from something which drives the input
361 * **externally**
362 *
363 * Inputs:
364 * * port is the GPIO port
365 * * n is the pin number inside that GPIO port (0..31)
366 * * value: is the input high (true) or low (false)
367 */
nrf_gpio_eval_input(unsigned int port,unsigned int n,bool value)368 void nrf_gpio_eval_input(unsigned int port, unsigned int n, bool value)
369 {
370 CHECK_PIN_EXISTS(port, n, "input"); /* LCOV_EXCL_BR_LINE */
371
372 uint32_t dir = get_dir(port);
373
374 if ((dir >> n) & 0x1) { /* LCOV_EXCL_START */
375 bs_trace_warning_time_line("%s: Attempted to drive externally a pin which is "
376 "currently being driven by the SOC. It will be ignored."
377 "GPIO port %i, pin %i\n",
378 __func__, port, n);
379 return;
380 } /* LCOV_EXCL_STOP */
381
382 int diff = ((IO_level[port] >> n) & 0x1) ^ (uint32_t)value;
383
384 if (diff == 0) {
385 /* No toggle */
386 return;
387 }
388
389 IO_level[port] ^= (uint32_t)1 << n;
390
391 nrf_gpio_eval_inputs(port);
392 }
393
394 /*
395 * The output is being changed, propagate it as necessary and/or record it.
396 */
nrf_gpio_output_change_sideeffects(unsigned int port,unsigned int n,bool value)397 static void nrf_gpio_output_change_sideeffects(unsigned int port,unsigned int n, bool value)
398 {
399 nrf_gpio_backend_write_output_change(port, n, value);
400 if (test_outtoggle_callback != NULL) {
401 test_outtoggle_callback(port, n, value);
402 }
403 nrf_gpio_backend_short_propagate(port, n, value);
404 }
405
406 /*
407 * Reevaluate outputs after a configuration or OUT/external_OUT change
408 */
nrf_gpio_eval_outputs(unsigned int port)409 static void nrf_gpio_eval_outputs(unsigned int port)
410 {
411 /* Actual level in the pin, but only of the bits driven by output: */
412 static uint32_t O_level[NRF_GPIOS];
413
414 uint32_t dir = get_dir(port); /* Which pins are driven by output */
415
416 uint32_t out = (~out_override[port] & NRF_GPIO_regs[port].OUT)
417 | (out_override[port] & external_OUT[port]);
418
419 uint32_t new_output = dir & out;
420
421 uint32_t diff = new_output ^ O_level[port];
422
423 if (diff == 0) {
424 return;
425 }
426
427 O_level[port] = new_output;
428
429 IO_level[port] &= ~dir;
430 IO_level[port] |= O_level[port];
431
432 for (int n = __builtin_ffs(diff) - 1; n >= 0; n = __builtin_ffs(diff) - 1) {
433 nrf_gpio_output_change_sideeffects(port, n, (new_output >> n) & 0x1);
434 diff &= ~(1 << n);
435 }
436
437 /* Inputs may be connected to pins driven by outputs, let's check */
438 nrf_gpio_eval_inputs(port);
439 }
440
441
442 /*
443 * Register write side-effecting functions:
444 */
445
nrf_gpio_regw_sideeffects_OUT(unsigned int port)446 void nrf_gpio_regw_sideeffects_OUT(unsigned int port) {
447 nrf_gpio_eval_outputs(port);
448 }
449
nrf_gpio_regw_sideeffects_OUTSET(unsigned int port)450 void nrf_gpio_regw_sideeffects_OUTSET(unsigned int port) {
451 if (NRF_GPIO_regs[port].OUTSET) {
452 NRF_GPIO_regs[port].OUT |= NRF_GPIO_regs[port].OUTSET;
453 nrf_gpio_eval_outputs(port);
454 }
455 NRF_GPIO_regs[port].OUTSET = NRF_GPIO_regs[port].OUT;
456 }
457
nrf_gpio_regw_sideeffects_OUTCLR(unsigned int port)458 void nrf_gpio_regw_sideeffects_OUTCLR(unsigned int port) {
459 if (NRF_GPIO_regs[port].OUTCLR) {
460 NRF_GPIO_regs[port].OUT &= ~NRF_GPIO_regs[port].OUTCLR;
461 NRF_GPIO_regs[port].OUTCLR = 0;
462 nrf_gpio_eval_outputs(port);
463 }
464 }
465
nrf_gpio_regw_sideeffects_DIR(unsigned int port)466 void nrf_gpio_regw_sideeffects_DIR(unsigned int port) {
467 /* Mirror change into PIN_CNF[*].DIR */
468 for (int n = 0; n < GPIO_n_ports_pins[port]; n++ ) {
469 NRF_GPIO_regs[port].PIN_CNF[n] &= ~GPIO_PIN_CNF_DIR_Msk;
470 NRF_GPIO_regs[port].PIN_CNF[n] |= (NRF_GPIO_regs[port].DIR >> n) & 0x1;
471 }
472
473 nrf_gpio_eval_outputs(port);
474 }
475
nrf_gpio_regw_sideeffects_DIRSET(unsigned int port)476 void nrf_gpio_regw_sideeffects_DIRSET(unsigned int port) {
477 if (NRF_GPIO_regs[port].DIRSET) {
478 NRF_GPIO_regs[port].DIR |= NRF_GPIO_regs[port].DIRSET;
479 nrf_gpio_regw_sideeffects_DIR(port);
480 }
481 NRF_GPIO_regs[port].DIRSET = NRF_GPIO_regs[port].DIR;
482 }
483
nrf_gpio_regw_sideeffects_DIRCLR(unsigned int port)484 void nrf_gpio_regw_sideeffects_DIRCLR(unsigned int port) {
485 if (NRF_GPIO_regs[port].DIRCLR) {
486 NRF_GPIO_regs[port].DIR &= ~NRF_GPIO_regs[port].DIRCLR;
487 NRF_GPIO_regs[port].DIRCLR = 0;
488 nrf_gpio_regw_sideeffects_DIR(port);
489 }
490 }
491
nrf_gpio_regw_sideeffects_LATCH(unsigned int port)492 void nrf_gpio_regw_sideeffects_LATCH(unsigned int port) {
493
494 /* LATCH contains what SW wrote: */
495 uint32_t sw_input = NRF_GPIO_regs[port].LATCH;
496
497 /* Whatever bits SW set to 1, it is trying to clear: */
498 LDETECT[port] &= ~sw_input;
499
500 /* But where the sense output is high, the bits are kept high: */
501 LDETECT[port] |= DETECT[port];
502
503 NRF_GPIO_regs[port].LATCH = LDETECT[port];
504
505 nrf_gpio_update_detect_signal(port);
506
507 /*
508 * Note the text from the spec:
509 * If one or more bits in the LATCH register are '1' after the CPU has
510 * performed a clear operation on the LATCH registers, a rising edge will be generated
511 * on the LDETECT signal.
512 * "the CPU has performed a clear operation" == after writing LATCH with any bit to 1
513 */
514 if (sw_input != 0 && LDETECT[port] != 0 && NRF_GPIO_regs[port].DETECTMODE == 1) {
515 nrf_gpiote_port_event_raise(port);
516 }
517 }
518
nrf_gpio_regw_sideeffects_DETECTMODE(unsigned int port)519 void nrf_gpio_regw_sideeffects_DETECTMODE(unsigned int port) {
520 nrf_gpio_eval_sense(port);
521 }
522
nrf_gpio_regw_sideeffects_PIN_CNF(unsigned int port,unsigned int n)523 void nrf_gpio_regw_sideeffects_PIN_CNF(unsigned int port,unsigned int n) {
524
525 bool need_output_eval = false;
526 bool need_input_eval = false;
527 bool need_sense_eval = false;
528
529 int dir = NRF_GPIO_regs[port].PIN_CNF[n] & GPIO_PIN_CNF_DIR_Msk;
530
531 if (dir != ((NRF_GPIO_regs[port].DIR >> n) & 0x1)) {
532 NRF_GPIO_regs[port].DIR ^= 1 << n;
533 need_output_eval = true;
534 }
535
536 /* Note: DRIVE and PULL are not yet used in this model
537 int pull = (NRF_GPIO_regs[port].PIN_CNF[n] & GPIO_PIN_CNF_PULL_Msk)
538 >> GPIO_PIN_CNF_PULL_Pos;
539
540 int drive = (NRF_GPIO_regs[port].PIN_CNF[n] & GPIO_PIN_CNF_DRIVE_Msk)
541 >> GPIO_PIN_CNF_DRIVE_Pos;
542 */
543
544 int input = (NRF_GPIO_regs[port].PIN_CNF[n] & GPIO_PIN_CNF_INPUT_Msk)
545 >> GPIO_PIN_CNF_INPUT_Pos;
546 if (input != ((INPUT_mask[port] >> n) & 0x1)) {
547 INPUT_mask[port] ^= 1 << n;
548 need_input_eval = true;
549 }
550
551 int sense = (NRF_GPIO_regs[port].PIN_CNF[n] & GPIO_PIN_CNF_SENSE_Msk)
552 >> GPIO_PIN_CNF_SENSE_Pos;
553 if (((sense >> 1) & 0x1) != ((SENSE_mask[port] >> n) & 0x1)) {
554 SENSE_mask[port] ^= 1 << n;
555 need_sense_eval = true;
556 }
557 if ((sense & 0x1) != ((SENSE_inv[port] >> n) & 0x1)) {
558 SENSE_inv[port] ^= 1 << n;
559 need_sense_eval = true;
560 }
561
562 if (need_output_eval) {
563 nrf_gpio_eval_outputs(port);
564 }
565 if (need_input_eval) {
566 nrf_gpio_eval_inputs(port);
567 }
568 if (need_sense_eval) {
569 nrf_gpio_eval_sense(port);
570 }
571 }
572