/* * Copyright (c) 2019 Nordic Semiconductor ASA * Copyright 2024 NXP * * SPDX-License-Identifier: Apache-2.0 */ #include "test_gpio.h" #define ALL_BITS ((gpio_port_value_t)-1) static const struct device *const dev_in = DEVICE_DT_GET(DEV_IN); static const struct device *const dev_out = DEVICE_DT_GET(DEV_OUT); /* Short-hand for a checked read of PIN_IN raw state */ static bool raw_in(void) { gpio_port_value_t v; int rc = gpio_port_get_raw(dev_in, &v); #if CONFIG_READ_DELAY k_sleep(K_MSEC(CONFIG_READ_DELAY)); rc = gpio_port_get_raw(dev_in, &v); #endif zassert_equal(rc, 0, "raw_in failed"); return (v & BIT(PIN_IN)) ? true : false; } /* Short-hand for a checked read of PIN_IN logical state */ static bool logic_in(void) { gpio_port_value_t v; int rc = gpio_port_get(dev_in, &v); #if CONFIG_READ_DELAY k_sleep(K_MSEC(CONFIG_READ_DELAY)); rc = gpio_port_get(dev_in, &v); #endif zassert_equal(rc, 0, "logic_in failed"); return (v & BIT(PIN_IN)) ? true : false; } /* Short-hand for a checked write of PIN_OUT raw state */ static void raw_out(bool set) { int rc; if (set) { rc = gpio_port_set_bits_raw(dev_out, BIT(PIN_OUT)); } else { rc = gpio_port_clear_bits_raw(dev_out, BIT(PIN_OUT)); } zassert_equal(rc, 0, "raw_out failed"); } /* Short-hand for a checked write of PIN_OUT logic state */ static void logic_out(bool set) { int rc; if (set) { rc = gpio_port_set_bits(dev_out, BIT(PIN_OUT)); } else { rc = gpio_port_clear_bits(dev_out, BIT(PIN_OUT)); } zassert_equal(rc, 0, "raw_out failed"); } /* Verify device, configure for physical in and out, verify * connection, verify raw_in(). */ static int setup(void) { int rc; gpio_port_value_t v1; TC_PRINT("Validate device %s and %s\n", dev_in->name, dev_out->name); zassert_true(device_is_ready(dev_out), "GPIO dev is not ready"); TC_PRINT("Check %s output %d connected to %s input %d\n", dev_out->name, PIN_OUT, dev_in->name, PIN_IN); rc = gpio_pin_configure(dev_in, PIN_IN, GPIO_INPUT); zassert_equal(rc, 0, "pin config input failed"); /* Test output low */ rc = gpio_pin_configure(dev_out, PIN_OUT, GPIO_OUTPUT_LOW); zassert_equal(rc, 0, "pin config output low failed"); rc = gpio_port_get_raw(dev_in, &v1); zassert_equal(rc, 0, "get raw low failed"); if (raw_in() != false) { TC_PRINT("FATAL output pin not wired to input pin? (out low => in high)\n"); while (true) { k_sleep(K_FOREVER); } } zassert_equal(v1 & BIT(PIN_IN), 0, "out low does not read low"); /* Disconnect output */ rc = gpio_pin_configure(dev_out, PIN_OUT, GPIO_DISCONNECTED); if (rc == -ENOTSUP) { TC_PRINT("NOTE: cannot configure pin as disconnected; trying as input\n"); rc = gpio_pin_configure(dev_out, PIN_OUT, GPIO_INPUT); } zassert_equal(rc, 0, "output disconnect failed"); /* Test output high */ rc = gpio_pin_configure(dev_out, PIN_OUT, GPIO_OUTPUT_HIGH | GPIO_PULL_UP); if (rc == -ENOTSUP) { TC_PRINT("NOTE: pull-up not supported; trying as output high\n"); rc = gpio_pin_configure(dev_out, PIN_OUT, GPIO_OUTPUT_HIGH); } zassert_equal(rc, 0, "pin config output high failed"); rc = gpio_port_get_raw(dev_in, &v1); zassert_equal(rc, 0, "get raw high failed"); if (raw_in() != true) { TC_PRINT("FATAL output pin not wired to input pin? (out high => in low)\n"); while (raw_in() != true) { k_sleep(K_MSEC(100)); } } /* rread again in case the gpio changes slow */ gpio_port_get_raw(dev_in, &v1); zassert_not_equal(v1 & BIT(PIN_IN), 0, "out high does not read low"); TC_PRINT("OUT %d to IN %d linkage works\n", PIN_OUT, PIN_IN); return TC_PASS; } /* gpio_port_set_bits_raw() * gpio_port_clear_bits_raw() * gpio_port_set_masked_raw() * gpio_port_toggle_bits() */ static int bits_physical(void) { int rc; TC_PRINT("- %s\n", __func__); /* port_set_bits_raw */ rc = gpio_port_set_bits_raw(dev_out, BIT(PIN_OUT)); zassert_equal(rc, 0, "port set raw out failed"); zassert_equal(raw_in(), true, "raw set mismatch"); /* port_clear_bits_raw */ rc = gpio_port_clear_bits_raw(dev_out, BIT(PIN_OUT)); zassert_equal(rc, 0, "port clear raw out failed"); zassert_equal(raw_in(), false, "raw clear mismatch"); /* set after clear changes */ rc = gpio_port_set_bits_raw(dev_out, BIT(PIN_OUT)); zassert_equal(rc, 0, "port set raw out failed"); zassert_equal(raw_in(), true, "raw set mismatch"); /* raw_out() after set works */ raw_out(false); zassert_equal(raw_in(), false, "raw_out() false mismatch"); /* raw_out() set after raw_out() clear works */ raw_out(true); zassert_equal(raw_in(), true, "raw_out() true mismatch"); rc = gpio_port_set_masked_raw(dev_out, BIT(PIN_OUT), 0); zassert_equal(rc, 0, "set_masked_raw low failed"); zassert_equal(raw_in(), false, "set_masked_raw low mismatch"); rc = gpio_port_set_masked_raw(dev_out, BIT(PIN_OUT), ALL_BITS); zassert_equal(rc, 0, "set_masked_raw high failed"); zassert_equal(raw_in(), true, "set_masked_raw high mismatch"); rc = gpio_port_set_masked_raw(dev_in, BIT(PIN_IN), 0); zassert_equal(rc, 0, "set_masked_raw low failed"); zassert_equal(raw_in(), true, "set_masked_raw low affected other pins"); rc = gpio_port_set_clr_bits_raw(dev_out, BIT(PIN_IN), BIT(PIN_OUT)); zassert_equal(rc, 0, "set in clear out failed"); zassert_equal(raw_in(), false, "set in clear out mismatch"); rc = gpio_port_set_clr_bits_raw(dev_out, BIT(PIN_OUT), BIT(PIN_IN)); zassert_equal(rc, 0, "set out clear in failed"); zassert_equal(raw_in(), true, "set out clear in mismatch"); /* Conditionally verify that behavior with __ASSERT disabled * is to set the bit. */ if (false) { /* preserve set */ rc = gpio_port_set_clr_bits_raw(dev_out, BIT(PIN_OUT), BIT(PIN_OUT)); zassert_equal(rc, 0, "s/c dup set failed"); zassert_equal(raw_in(), true, "s/c dup set mismatch"); /* do set */ raw_out(false); rc = gpio_port_set_clr_bits_raw(dev_out, BIT(PIN_OUT), BIT(PIN_OUT)); zassert_equal(rc, 0, "s/c dup2 set failed"); zassert_equal(raw_in(), true, "s/c dup2 set mismatch"); } rc = gpio_port_toggle_bits(dev_out, BIT(PIN_OUT)); zassert_equal(rc, 0, "toggle_bits high-to-low failed"); zassert_equal(raw_in(), false, "toggle_bits high-to-low mismatch"); rc = gpio_port_toggle_bits(dev_out, BIT(PIN_OUT)); zassert_equal(rc, 0, "toggle_bits low-to-high failed"); zassert_equal(raw_in(), true, "toggle_bits low-to-high mismatch"); return TC_PASS; } /* gpio_pin_get_raw() * gpio_pin_set_raw() */ static int pin_physical(void) { int rc; TC_PRINT("- %s\n", __func__); raw_out(true); zassert_equal(gpio_pin_get_raw(dev_in, PIN_IN), raw_in(), "pin_get_raw high failed"); raw_out(false); zassert_equal(gpio_pin_get_raw(dev_in, PIN_IN), raw_in(), "pin_get_raw low failed"); rc = gpio_pin_set_raw(dev_out, PIN_OUT, 32); zassert_equal(rc, 0, "pin_set_raw high failed"); zassert_equal(raw_in(), true, "pin_set_raw high failed"); rc = gpio_pin_set_raw(dev_out, PIN_OUT, 0); zassert_equal(rc, 0, "pin_set_raw low failed"); zassert_equal(raw_in(), false, "pin_set_raw low failed"); rc = gpio_pin_toggle(dev_out, PIN_OUT); zassert_equal(rc, 0, "pin_toggle low-to-high failed"); zassert_equal(raw_in(), true, "pin_toggle low-to-high mismatch"); rc = gpio_pin_toggle(dev_out, PIN_OUT); zassert_equal(rc, 0, "pin_toggle high-to-low failed"); zassert_equal(raw_in(), false, "pin_toggle high-to-low mismatch"); return TC_PASS; } /* Verify configure output level is independent of active level, and * raw output is independent of active level. */ static int check_raw_output_levels(void) { int rc; TC_PRINT("- %s\n", __func__); rc = gpio_pin_configure(dev_out, PIN_OUT, GPIO_ACTIVE_HIGH | GPIO_OUTPUT_LOW | PIN_OUT_FLAGS); zassert_equal(rc, 0, "active high output low failed"); zassert_equal(raw_in(), false, "active high output low raw mismatch"); raw_out(true); zassert_equal(raw_in(), true, "set high mismatch"); rc = gpio_pin_configure(dev_out, PIN_OUT, GPIO_ACTIVE_HIGH | GPIO_OUTPUT_HIGH | PIN_OUT_FLAGS); zassert_equal(rc, 0, "active high output high failed"); zassert_equal(raw_in(), true, "active high output high raw mismatch"); raw_out(false); zassert_equal(raw_in(), false, "set low mismatch"); rc = gpio_pin_configure(dev_out, PIN_OUT, GPIO_ACTIVE_LOW | GPIO_OUTPUT_LOW | PIN_OUT_FLAGS); zassert_equal(rc, 0, "active low output low failed"); zassert_equal(raw_in(), false, "active low output low raw mismatch"); raw_out(true); zassert_equal(raw_in(), true, "set high mismatch"); rc = gpio_pin_configure(dev_out, PIN_OUT, GPIO_ACTIVE_LOW | GPIO_OUTPUT_HIGH | PIN_OUT_FLAGS); zassert_equal(rc, 0, "active low output high failed"); zassert_equal(raw_in(), true, "active low output high raw mismatch"); raw_out(false); zassert_equal(raw_in(), false, "set low mismatch"); return TC_PASS; } /* Verify configure output level is dependent on active level, and * logic output is dependent on active level. */ static int check_logic_output_levels(void) { int rc; TC_PRINT("- %s\n", __func__); rc = gpio_pin_configure(dev_out, PIN_OUT, GPIO_ACTIVE_HIGH | GPIO_OUTPUT_INACTIVE | PIN_OUT_FLAGS); zassert_equal(rc, 0, "active true output false failed: %d", rc); zassert_equal(raw_in(), false, "active true output false logic mismatch"); logic_out(true); zassert_equal(raw_in(), true, "set true mismatch"); rc = gpio_pin_configure(dev_out, PIN_OUT, GPIO_ACTIVE_HIGH | GPIO_OUTPUT_ACTIVE | PIN_OUT_FLAGS); zassert_equal(rc, 0, "active true output true failed"); zassert_equal(raw_in(), true, "active true output true logic mismatch"); logic_out(false); zassert_equal(raw_in(), false, "set false mismatch"); rc = gpio_pin_configure(dev_out, PIN_OUT, GPIO_ACTIVE_LOW | GPIO_OUTPUT_ACTIVE | PIN_OUT_FLAGS); zassert_equal(rc, 0, "active low output true failed"); zassert_equal(raw_in(), false, "active low output true raw mismatch"); logic_out(false); zassert_equal(raw_in(), true, "set false mismatch"); rc = gpio_pin_configure(dev_out, PIN_OUT, GPIO_ACTIVE_LOW | GPIO_OUTPUT_INACTIVE | PIN_OUT_FLAGS); zassert_equal(rc, 0, "active low output false failed"); zassert_equal(raw_in(), true, "active low output false logic mismatch"); logic_out(true); zassert_equal(raw_in(), false, "set true mismatch"); return TC_PASS; } /* Verify active-high input matches physical level, and active-low * input inverts physical level. */ static int check_input_levels(void) { int rc; TC_PRINT("- %s\n", __func__); rc = gpio_pin_configure(dev_out, PIN_OUT, GPIO_OUTPUT | PIN_OUT_FLAGS); zassert_equal(rc, 0, "output configure failed"); rc = gpio_pin_configure(dev_in, PIN_IN, GPIO_INPUT); zassert_equal(rc, 0, "active high failed"); raw_out(true); zassert_equal(raw_in(), true, "raw high mismatch"); zassert_equal(logic_in(), true, "logic high mismatch"); raw_out(false); zassert_equal(raw_in(), false, "raw low mismatch"); zassert_equal(logic_in(), false, "logic low mismatch"); rc = gpio_pin_configure(dev_in, PIN_IN, GPIO_INPUT | GPIO_ACTIVE_LOW); zassert_equal(rc, 0, "active low failed"); raw_out(true); zassert_equal(raw_in(), true, "raw high mismatch"); zassert_equal(logic_in(), false, "logic inactive mismatch"); raw_out(false); zassert_equal(raw_in(), false, "raw low mismatch"); zassert_equal(logic_in(), true, "logic active mismatch"); return TC_PASS; } /* Delay after pull input config to allow signal to settle. The value * selected is conservative (higher than may be necessary). */ #define PULL_DELAY_US 100U /* Verify that pull-up and pull-down work for a disconnected input. */ static int check_pulls(void) { int rc; TC_PRINT("- %s\n", __func__); /* Disconnect output */ rc = gpio_pin_configure(dev_out, PIN_OUT, GPIO_DISCONNECTED); if (rc == -ENOTSUP) { TC_PRINT("NOTE: cannot configure pin as disconnected; trying as input\n"); rc = gpio_pin_configure(dev_out, PIN_OUT, GPIO_INPUT); } zassert_equal(rc, 0, "output disconnect failed"); rc = gpio_pin_configure(dev_in, PIN_IN, GPIO_INPUT | GPIO_PULL_UP); k_busy_wait(PULL_DELAY_US); if (rc == -ENOTSUP) { TC_PRINT("pull-up not supported\n"); return TC_PASS; } else if (rc != 0) { TC_ERROR("input pull-up fail: %d\n", rc); return TC_FAIL; } zassert_equal(raw_in(), true, "physical pull-up does not read high"); rc = gpio_pin_configure(dev_in, PIN_IN, GPIO_INPUT | GPIO_PULL_DOWN); k_busy_wait(PULL_DELAY_US); if (rc == -ENOTSUP) { TC_PRINT("pull-down not supported\n"); return TC_PASS; } else if (rc != 0) { TC_ERROR("input pull-down fail: %d\n", rc); return TC_FAIL; } zassert_equal(raw_in(), false, "physical pull-down does not read low"); /* Test that pull is not affected by active level */ rc = gpio_pin_configure(dev_in, PIN_IN, GPIO_INPUT | GPIO_ACTIVE_LOW | GPIO_PULL_UP); k_busy_wait(PULL_DELAY_US); if (rc == -ENOTSUP) { TC_PRINT("pull-up not supported\n"); return TC_PASS; } else if (rc != 0) { TC_ERROR("input pull-up fail: %d\n", rc); return TC_FAIL; } zassert_equal(raw_in(), true, "logical pull-up does not read high"); zassert_equal(logic_in(), false, "logical pull-up reads true"); rc = gpio_pin_configure(dev_in, PIN_IN, GPIO_INPUT | GPIO_ACTIVE_LOW | GPIO_PULL_DOWN); k_busy_wait(PULL_DELAY_US); if (rc == -ENOTSUP) { TC_PRINT("pull-up not supported\n"); return TC_PASS; } else if (rc != 0) { TC_ERROR("input pull-up fail: %d\n", rc); return TC_FAIL; } zassert_equal(raw_in(), false, "logical pull-down does not read low"); zassert_equal(logic_in(), true, "logical pull-down reads false"); return TC_PASS; } /* gpio_port_set_bits() * gpio_port_clear_bits() * gpio_port_set_masked() * gpio_port_toggle_bits() */ static int bits_logical(void) { int rc; TC_PRINT("- %s\n", __func__); rc = gpio_pin_configure(dev_out, PIN_OUT, GPIO_OUTPUT_HIGH | GPIO_ACTIVE_LOW | PIN_OUT_FLAGS); zassert_equal(rc, 0, "output configure failed"); zassert_equal(raw_in(), true, "raw out high mismatch"); zassert_equal(logic_in(), !raw_in(), "logic in active mismatch"); /* port_set_bits */ rc = gpio_port_set_bits(dev_out, BIT(PIN_OUT)); zassert_equal(rc, 0, "port set raw out failed"); zassert_equal(raw_in(), false, "raw low set mismatch"); zassert_equal(logic_in(), !raw_in(), "logic in inactive mismatch"); /* port_clear_bits */ rc = gpio_port_clear_bits(dev_out, BIT(PIN_OUT)); zassert_equal(rc, 0, "port clear raw out failed"); zassert_equal(logic_in(), false, "low clear mismatch"); /* set after clear changes */ rc = gpio_port_set_bits_raw(dev_out, BIT(PIN_OUT)); zassert_equal(rc, 0, "port set raw out failed"); zassert_equal(logic_in(), false, "raw set mismatch"); /* pin_set false */ rc = gpio_pin_set(dev_out, PIN_OUT, 0); zassert_equal(rc, 0, "pin clear failed"); zassert_equal(logic_in(), false, "pin clear mismatch"); /* pin_set true */ rc = gpio_pin_set(dev_out, PIN_OUT, 32); zassert_equal(rc, 0, "pin set failed"); zassert_equal(logic_in(), true, "pin set mismatch"); rc = gpio_port_set_masked(dev_out, BIT(PIN_OUT), 0); zassert_equal(rc, 0, "set_masked low failed"); zassert_equal(logic_in(), false, "set_masked low mismatch"); rc = gpio_port_set_masked(dev_out, BIT(PIN_OUT), ALL_BITS); zassert_equal(rc, 0, "set_masked high failed"); zassert_equal(logic_in(), true, "set_masked high mismatch"); rc = gpio_port_set_clr_bits(dev_out, BIT(PIN_IN), BIT(PIN_OUT)); zassert_equal(rc, 0, "set in clear out failed"); zassert_equal(logic_in(), false, "set in clear out mismatch"); rc = gpio_port_set_clr_bits(dev_out, BIT(PIN_OUT), BIT(PIN_IN)); zassert_equal(rc, 0, "set out clear in failed"); zassert_equal(logic_in(), true, "set out clear in mismatch"); /* Conditionally verify that behavior with __ASSERT disabled * is to set the bit. */ if (false) { /* preserve set */ rc = gpio_port_set_clr_bits(dev_out, BIT(PIN_OUT), BIT(PIN_OUT)); zassert_equal(rc, 0, "s/c set toggle failed"); zassert_equal(logic_in(), false, "s/c set toggle mismatch"); /* force set */ raw_out(true); rc = gpio_port_set_clr_bits(dev_out, BIT(PIN_OUT), BIT(PIN_OUT)); zassert_equal(rc, 0, "s/c dup set failed"); zassert_equal(logic_in(), false, "s/c dup set mismatch"); } rc = gpio_port_toggle_bits(dev_out, BIT(PIN_OUT)); zassert_equal(rc, 0, "toggle_bits active-to-inactive failed"); zassert_equal(logic_in(), false, "toggle_bits active-to-inactive mismatch"); rc = gpio_port_toggle_bits(dev_out, BIT(PIN_OUT)); zassert_equal(rc, 0, "toggle_bits inactive-to-active failed"); zassert_equal(logic_in(), true, "toggle_bits inactive-to-active mismatch"); rc = gpio_pin_toggle(dev_out, PIN_OUT); zassert_equal(rc, 0, "pin_toggle low-to-high failed"); zassert_equal(logic_in(), false, "pin_toggle low-to-high mismatch"); return TC_PASS; } /* gpio_pin_get_config() */ static int pin_get_config(void) { gpio_flags_t flags_get = 0; gpio_flags_t flags_set; int rc; flags_set = GPIO_OUTPUT_HIGH; rc = gpio_pin_configure(dev_out, PIN_OUT, flags_set); zassert_equal(rc, 0, "pin configure failed"); rc = gpio_pin_get_config(dev_out, PIN_OUT, &flags_get); if (rc == -ENOSYS) { return TC_PASS; } zassert_equal(rc, 0, "pin get config failed"); zassert_equal(flags_get, flags_set, "flags are different"); return TC_PASS; } ZTEST(gpio_port, test_gpio_port) { zassert_equal(setup(), TC_PASS, "device setup failed"); zassert_equal(bits_physical(), TC_PASS, "bits_physical failed"); zassert_equal(pin_physical(), TC_PASS, "pin_physical failed"); zassert_equal(check_raw_output_levels(), TC_PASS, "check_raw_output_levels failed"); zassert_equal(check_logic_output_levels(), TC_PASS, "check_logic_output_levels failed"); zassert_equal(check_input_levels(), TC_PASS, "check_input_levels failed"); zassert_equal(bits_logical(), TC_PASS, "bits_logical failed"); if (!IS_ENABLED(CONFIG_SKIP_PULL_TEST)) { zassert_equal(check_pulls(), TC_PASS, "check_pulls failed"); } if (IS_ENABLED(CONFIG_GPIO_GET_CONFIG)) { zassert_equal(pin_get_config(), TC_PASS, "pin_get_config failed"); } }