diff options
-rw-r--r-- | src/gpio.c | 254 | ||||
-rw-r--r-- | src/gpio.h | 101 |
2 files changed, 355 insertions, 0 deletions
diff --git a/src/gpio.c b/src/gpio.c new file mode 100644 index 0000000..93fc7a6 --- /dev/null +++ b/src/gpio.c @@ -0,0 +1,254 @@ +#include "gpio.h" +#include "peripherals.h" +#include "types.h" + +#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, reg, value) +#define READ_GPIO_REG(reg) READ_REGISTER(P0, 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, +}; + +/** + * GPIO direction for each pin. + * When a GPIO is in disabled state, we forcefully put it in INPUT mode. + */ +enum gpio_direction { + INPUT = 0, + OUTPUT = 1, +}; + +/** + * 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, +}; + +struct pin_configuration { + enum gpio_direction direction; + union { + struct { + enum gpio_pull_configuration pull_config; + enum gpio_level sensibility; + } input; + + struct { + enum gpio_drive_configuration drive_config; + } output; + } config; +}; + +/** + * The hardcoded configuration for each GPIO pin. + */ +static const struct pin_configuration pins_configs[32] = { + [PIN_DISPLAY_SPI_CLOCK] = { + .direction = OUTPUT, + .config = { + .output = { + .drive_config = S0S1, + }, + }, + }, +}; + +/** + * 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 active if it's in `INPUT` mode + * but 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]); + + enum gpio_direction dir = conf & 0x1; + u8 sense = (conf >> 16) & 0x3; + + return (dir != INPUT) || (sense != 0); +} + +void gpio_init_pin(enum gpio_pin pin) { + u32 pin_reg = cnf_offsets[pin]; + struct pin_configuration pin_config = pins_configs[pin]; + + u32 pin_reg_value = 0; + pin_reg_value |= pin_config.direction & 0x1; + + if (pin_config.direction == INPUT) { + pin_reg_value |= (pin_config.config.input.pull_config & 0x3) << 2; + pin_reg_value |= (pin_config.config.input.sensibility & 0x3) << 16; + } else { + pin_reg_value |= (pin_config.config.output.drive_config & 0x7) << 8; + } + + WRITE_PIN_CNF(pin_reg, pin_reg_value); +} + +u8 gpio_disable_pin(enum gpio_pin pin) { + u32 pin_cnf_value = 0x0; + + if (!is_pin_active(pin)) { + return 0; + } + + /* INPUT mode with detection mechanism disabled */ + pin_cnf_value |= INPUT & 0x1; + + WRITE_PIN_CNF(cnf_offsets[pin], pin_cnf_value); + + return 1; +} + + +enum gpio_level gpio_read_pin(enum gpio_pin pin) { + u32 pins_level = READ_GPIO_REG(IN); + + return (pins_level >> pin) & 0x1; +} + +u8 gpio_write_pin(enum gpio_pin pin, enum gpio_level level) { + enum gpio_register reg = level == HIGH ? OUTSET : OUTCLR; + + if (pins_configs[pin].direction != OUTPUT) { + return 1; + } + + WRITE_GPIO_REG(reg, (1 << pin)); + return 0; +} diff --git a/src/gpio.h b/src/gpio.h new file mode 100644 index 0000000..adcf76a --- /dev/null +++ b/src/gpio.h @@ -0,0 +1,101 @@ +#ifndef GPIO_H +#define GPIO_H + +#include "types.h" + +/* GPIO pins used for the LCD display */ +#define PIN_DISPLAY_SPI_CLOCK PIN_2 +#define PIN_DISPLAY_SPI_MOSI PIN_3 +#define PIN_DISPLAY_COMMAND_DATA PIN_18 +#define PIN_DISPLAY_CHIP_SELECT PIN_25 +#define PIN_DISPLAY_RESET PIN_26 + +/* GPIO pins used for the touch panel */ +#define PIN_TOUCH_PANEL_RESET PIN_10 +#define PIN_TOUCH_PANEL_IRQ PIN_28 +#define PIN_TOUCH_PANEL_I2C_SDA PIN_06 +#define PIN_TOUCH_PANEL_I2C_SCL PIN_07 + +/* GPIO pins used for the battery management */ +#define PIN_BATTERY_CHARGE_INDICATOR PIN_12 +#define PIN_BATTERY_VOLTAGE PIN_31 + +/* GPIO pins used for the button */ +#define PIN_BUTTON_ENABLE PIN_15 +#define PIN_BUTTON_PRESS PIN_13 + +/* GPIO pins used for the accelerometer */ +#define PIN_ACCEL_I2C_SDA PIN_06 +#define PIN_ACCEL_I2C_SCL PIN_07 +#define PIN_ACCEL_IRQ PIN_08 + +/** + * 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, +}; + +/** + * Init the given pin. + * Note that each pin configuration is hardcoded to fit the peripheral it is connected to. + */ +void gpio_init_pin(enum gpio_pin pin); + +/** + * Disable a GPIO pin. + */ +u8 gpio_disable_pin(enum gpio_pin pin); + +/** + * Read the current signal level of the given GPIO pin. + */ +enum gpio_level gpio_read_pin(enum gpio_pin pin); + +/** + * Set the given GPIO pin to the given level. + * Returns 0 if the given pin is not an output pin. + * Returns 1 if written successfully + */ +u8 gpio_write_pin(enum gpio_pin pin, enum gpio_level level); + +#endif |