aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVictor Mignot <victor@vmignot.fr>2026-02-02 20:18:48 +0100
committerVictor Mignot <victor@vmignot.fr>2026-02-03 21:02:18 +0100
commitf19ca61f48710fab019f39bb87bf6fb15f4ae7da (patch)
tree24a8371b6a6f286ca80eb8ab9ef3524b97588463
parentfb859c9c85688d1a144b732cf688746f2651be40 (diff)
downloadnanji-f19ca61f48710fab019f39bb87bf6fb15f4ae7da.tar.gz
nrf52832: add interface to control GPIO pins
-rw-r--r--src/gpio.c170
-rw-r--r--src/gpio.h120
2 files changed, 290 insertions, 0 deletions
diff --git a/src/gpio.c b/src/gpio.c
new file mode 100644
index 0000000..b1f8e94
--- /dev/null
+++ b/src/gpio.c
@@ -0,0 +1,170 @@
+#include "gpio.h"
+#include "register.h"
+#include "types.h"
+
+#define P0_BASE_ADDR 0x50000000
+
+#define WRITE_PIN_CNF(pin, value) WRITE_GPIO_REG(pin, value)
+#define READ_PIN_CNF(pin) READ_GPIO_REG(pin)
+
+#define WRITE_GPIO_REG(reg, value) WRITE_REGISTER(P0_BASE_ADDR, reg, value)
+#define READ_GPIO_REG(reg) READ_REGISTER(P0_BASE_ADDR, reg)
+
+/**
+ * Available behaviours for the DETECT signal.
+ * `PIN_DETECT` combines every individuals PIN's DETECT signal.
+ * `LDETECT` uses the LDETECT signal.
+ */
+enum gpio_detect_mode {
+ PIN_DETECT = 0,
+ LDETECT = 1,
+};
+
+/**
+ * Memory-mapped register for the GPIO peripheral with their offset from its base address.
+ * Check the nrf52832's manual for their description.
+ */
+enum gpio_register {
+ OUT = 0x504,
+ OUTSET = 0x508,
+ OUTCLR = 0x50c,
+ IN = 0x510,
+ DIR = 0x514,
+ DIRSET = 0x518,
+ DIRCLR = 0x51c,
+ LATCH = 0x520,
+ DETECTMODE = 0x524,
+ PIN_CNF_0 = 0x700,
+ PIN_CNF_1 = 0x704,
+ PIN_CNF_2 = 0x708,
+ PIN_CNF_3 = 0x70c,
+ PIN_CNF_4 = 0x71c,
+ PIN_CNF_5 = 0x714,
+ PIN_CNF_6 = 0x718,
+ PIN_CNF_7 = 0x71c,
+ PIN_CNF_8 = 0x720,
+ PIN_CNF_9 = 0x724,
+ PIN_CNF_10 = 0x728,
+ PIN_CNF_11 = 0x72c,
+ PIN_CNF_12 = 0x730,
+ PIN_CNF_13 = 0x734,
+ PIN_CNF_14 = 0x738,
+ PIN_CNF_15 = 0x73c,
+ PIN_CNF_16 = 0x740,
+ PIN_CNF_17 = 0x744,
+ PIN_CNF_18 = 0x748,
+ PIN_CNF_19 = 0x74c,
+ PIN_CNF_20 = 0x750,
+ PIN_CNF_21 = 0x754,
+ PIN_CNF_22 = 0x758,
+ PIN_CNF_23 = 0x75c,
+ PIN_CNF_24 = 0x760,
+ PIN_CNF_25 = 0x764,
+ PIN_CNF_26 = 0x768,
+ PIN_CNF_27 = 0x76c,
+ PIN_CNF_28 = 0x770,
+ PIN_CNF_29 = 0x774,
+ PIN_CNF_30 = 0x778,
+ PIN_CNF_31 = 0x77c,
+};
+
+/**
+ * The offset of each pin configuration register from the GPIO base address.
+ */
+static const u32 cnf_offsets[] = {
+ [PIN_0] = PIN_CNF_0,
+ [PIN_1] = PIN_CNF_1,
+ [PIN_2] = PIN_CNF_2,
+ [PIN_3] = PIN_CNF_3,
+ [PIN_4] = PIN_CNF_4,
+ [PIN_5] = PIN_CNF_5,
+ [PIN_6] = PIN_CNF_6,
+ [PIN_7] = PIN_CNF_7,
+ [PIN_8] = PIN_CNF_8,
+ [PIN_9] = PIN_CNF_9,
+ [PIN_10] = PIN_CNF_10,
+ [PIN_11] = PIN_CNF_11,
+ [PIN_12] = PIN_CNF_12,
+ [PIN_13] = PIN_CNF_13,
+ [PIN_14] = PIN_CNF_14,
+ [PIN_15] = PIN_CNF_15,
+ [PIN_16] = PIN_CNF_16,
+ [PIN_17] = PIN_CNF_17,
+ [PIN_18] = PIN_CNF_18,
+ [PIN_19] = PIN_CNF_19,
+ [PIN_20] = PIN_CNF_20,
+ [PIN_21] = PIN_CNF_21,
+ [PIN_22] = PIN_CNF_22,
+ [PIN_23] = PIN_CNF_23,
+ [PIN_24] = PIN_CNF_24,
+ [PIN_25] = PIN_CNF_25,
+ [PIN_26] = PIN_CNF_26,
+ [PIN_27] = PIN_CNF_27,
+ [PIN_28] = PIN_CNF_28,
+ [PIN_29] = PIN_CNF_29,
+ [PIN_30] = PIN_CNF_30,
+ [PIN_31] = PIN_CNF_31,
+};
+
+/**
+ * We consider that a pin is inactive if it's in `INPUT` mode
+ * and has its detect mechanism disabled (the SENSE field of
+ * its configuration register is 0).
+ *
+ * Warning: that does not mean the pin is not already used elsewhere.
+ * Peripherals or drivers can put a pin in this state for whatever reason.
+ * Always make sure that the pin is not currently is use before doing
+ * anything with it.
+ */
+static u8 is_pin_active(enum gpio_pin pin) {
+ u32 conf = READ_PIN_CNF(cnf_offsets[pin]);
+
+ u32 dir = conf & 0x1;
+ u8 sense = (conf >> 16) & 0x3;
+
+ return (dir != 0) || (sense != 0);
+}
+
+void gpio_input_pin_init(enum gpio_pin pin, enum gpio_pull_configuration pull_config, enum gpio_level sensibility) {
+ u32 pin_reg = cnf_offsets[pin];
+
+ u32 pin_reg_value = 0x0;
+ pin_reg_value |= (pull_config & 0x3) << 2;
+ pin_reg_value |= (sensibility & 0x3) << 16;
+
+ WRITE_PIN_CNF(pin_reg, pin_reg_value);
+}
+
+void gpio_output_pin_init(enum gpio_pin pin, enum gpio_drive_configuration drive_config) {
+ u32 pin_reg = cnf_offsets[pin];
+
+ u32 pin_reg_value = 0x1;
+ pin_reg_value |= (drive_config & 0x7) << 8;
+
+ WRITE_PIN_CNF(pin_reg, pin_reg_value);
+
+}
+
+u8 gpio_pin_disable(enum gpio_pin pin) {
+ if (!is_pin_active(pin)) {
+ return 0;
+ }
+
+ /* Configuration register reset value */
+ WRITE_PIN_CNF(cnf_offsets[pin], 0x2);
+
+ return 1;
+}
+
+
+enum gpio_level gpio_pin_get_level(enum gpio_pin pin) {
+ u32 pins_level = READ_GPIO_REG(IN);
+
+ return (pins_level >> pin) & 0x1;
+}
+
+void gpio_pin_set_level(enum gpio_pin pin, enum gpio_level level) {
+ enum gpio_register reg = level == HIGH ? OUTSET : OUTCLR;
+
+ WRITE_GPIO_REG(reg, (1 << pin));
+}
diff --git a/src/gpio.h b/src/gpio.h
new file mode 100644
index 0000000..28c0c20
--- /dev/null
+++ b/src/gpio.h
@@ -0,0 +1,120 @@
+#ifndef GPIO_H
+#define GPIO_H
+
+#include "types.h"
+
+/**
+ * The signal level of a GPIO line.
+ */
+enum gpio_level {
+ LOW = 0,
+ HIGH = 1,
+};
+
+/**
+ * The availables GPIO pins on the NRF82832.
+ */
+enum gpio_pin {
+ PIN_0 = 0,
+ PIN_1 = 1,
+ PIN_2 = 2,
+ PIN_3 = 3,
+ PIN_4 = 4,
+ PIN_5 = 5,
+ PIN_6 = 6,
+ PIN_7 = 7,
+ PIN_8 = 8,
+ PIN_9 = 9,
+ PIN_10 = 10,
+ PIN_11 = 11,
+ PIN_12 = 12,
+ PIN_13 = 13,
+ PIN_14 = 14,
+ PIN_15 = 15,
+ PIN_16 = 16,
+ PIN_17 = 17,
+ PIN_18 = 18,
+ PIN_19 = 19,
+ PIN_20 = 20,
+ PIN_21 = 21,
+ PIN_22 = 22,
+ PIN_23 = 23,
+ PIN_24 = 24,
+ PIN_25 = 25,
+ PIN_26 = 26,
+ PIN_27 = 27,
+ PIN_28 = 28,
+ PIN_29 = 29,
+ PIN_30 = 30,
+ PIN_31 = 31,
+};
+
+/**
+ * The pull configuration for a GPIO line.
+ */
+enum gpio_pull_configuration {
+ /** Keep the GPIO in a floating state when the circuit is open */
+ NO_PULL = 0,
+
+ /** Force the signal to the `LOW` level when the circuit is open */
+ PULL_DOWN = 1,
+
+ /** Force the signal to the `HIGH` level when the circuit is open */
+ PULL_UP = 3,
+};
+
+/**
+ * The drive configuration for a GPIO line.
+ */
+enum gpio_drive_configuration {
+ /** Standard 0, Standard 1 */
+ S0S1 = 0,
+
+ /** High drive 0, Standard 1 */
+ H0S1 = 1,
+
+ /** Standard 0, High drive 1 */
+ S0H1 = 2,
+
+ /** High drive 0, High Drive 1 */
+ H0H1 = 3,
+
+ /** Disconnect 0, Standard 1 */
+ D0S1 = 4,
+
+ /** Disconnect 0, High drive 1 */
+ D0H1 = 5,
+
+ /** Standard 0, Disconnect 1 */
+ S0D1 = 6,
+
+ /** High drive 0, Disconnect 1 */
+ H0D1 = 7,
+};
+
+/**
+ * Init the given pin as an input.
+ */
+void gpio_input_pin_init(enum gpio_pin pin, enum gpio_pull_configuration pull_config, enum gpio_level sensibility);
+
+/**
+ * Init the given pin as output.
+ */
+void gpio_output_pin_init(enum gpio_pin pin, enum gpio_drive_configuration drive_config);
+
+/**
+ * Disable a GPIO pin.
+ */
+u8 gpio_pin_disable(enum gpio_pin pin);
+
+/**
+ * Read the current signal level of the given GPIO pin.
+ */
+enum gpio_level gpio_pin_get_level(enum gpio_pin pin);
+
+/**
+ * Set the given GPIO pin to the given level.
+ */
+void gpio_pin_set_level(enum gpio_pin pin, enum gpio_level level);
+
+#endif