aboutsummaryrefslogtreecommitdiffstats
path: root/libmaple/gpio.c
diff options
context:
space:
mode:
Diffstat (limited to 'libmaple/gpio.c')
-rw-r--r--libmaple/gpio.c165
1 files changed, 136 insertions, 29 deletions
diff --git a/libmaple/gpio.c b/libmaple/gpio.c
index 71e5230..5484e21 100644
--- a/libmaple/gpio.c
+++ b/libmaple/gpio.c
@@ -26,44 +26,151 @@
* @brief GPIO initialization routine
*/
-#include "libmaple.h"
-#include "rcc.h"
#include "gpio.h"
+#include "rcc.h"
+
+/*
+ * GPIO devices
+ */
+
+gpio_dev gpioa = {
+ .regs = GPIOA_BASE,
+ .clk_id = RCC_GPIOA,
+ .exti_port = AFIO_EXTI_PA,
+};
+gpio_dev* const GPIOA = &gpioa;
+
+gpio_dev gpiob = {
+ .regs = GPIOB_BASE,
+ .clk_id = RCC_GPIOB,
+ .exti_port = AFIO_EXTI_PB,
+};
+gpio_dev* const GPIOB = &gpiob;
+
+gpio_dev gpioc = {
+ .regs = GPIOC_BASE,
+ .clk_id = RCC_GPIOC,
+ .exti_port = AFIO_EXTI_PC,
+};
+gpio_dev* const GPIOC = &gpioc;
+
+gpio_dev gpiod = {
+ .regs = GPIOD_BASE,
+ .clk_id = RCC_GPIOD,
+ .exti_port = AFIO_EXTI_PD,
+};
+gpio_dev* const GPIOD = &gpiod;
+
+#ifdef STM32_HIGH_DENSITY
+gpio_dev gpioe = {
+ .regs = GPIOE_BASE,
+ .clk_id = RCC_GPIOE,
+ .exti_port = AFIO_EXTI_PE,
+};
+gpio_dev* const GPIOE = &gpioe;
+
+gpio_dev gpiof = {
+ .regs = GPIOF_BASE,
+ .clk_id = RCC_GPIOF,
+ .exti_port = AFIO_EXTI_PF,
+};
+gpio_dev* const GPIOF = &gpiof;
-void gpio_init(void) {
- rcc_clk_enable(RCC_GPIOA);
- rcc_clk_enable(RCC_GPIOB);
- rcc_clk_enable(RCC_GPIOC);
-#if NR_GPIO_PORTS >= 4 /* Maple, but not Maple Mini */
- rcc_clk_enable(RCC_GPIOD);
-#elif NR_GPIO_PORTS >= 7 /* Maple Native (high density only) */
- rcc_clk_enable(RCC_GPIOE);
- rcc_clk_enable(RCC_GPIOF);
- rcc_clk_enable(RCC_GPIOG);
+gpio_dev gpiog = {
+ .regs = GPIOG_BASE,
+ .clk_id = RCC_GPIOG,
+ .exti_port = AFIO_EXTI_PG,
+};
+gpio_dev* const GPIOG = &gpiog;
#endif
- rcc_clk_enable(RCC_AFIO);
+
+/*
+ * GPIO convenience routines
+ */
+
+/**
+ * Initialize a GPIO device.
+ *
+ * Enables the clock for and resets the given device.
+ *
+ * @param dev GPIO device to initialize.
+ */
+void gpio_init(gpio_dev *dev) {
+ rcc_clk_enable(dev->clk_id);
+ rcc_reset_dev(dev->clk_id);
}
-void gpio_set_mode(GPIO_Port* port, uint8 gpio_pin, GPIOPinMode mode) {
- uint32 tmp;
- uint32 shift = POS(gpio_pin % 8);
- GPIOReg CR;
+/**
+ * Initialize and reset all available GPIO devices.
+ */
+void gpio_init_all(void) {
+ gpio_init(GPIOA);
+ gpio_init(GPIOB);
+ gpio_init(GPIOC);
+ gpio_init(GPIOD);
+#ifdef STM32_HIGH_DENSITY
+ gpio_init(GPIOE);
+ gpio_init(GPIOF);
+ gpio_init(GPIOG);
+#endif
+}
- ASSERT(port);
- ASSERT(gpio_pin < 16);
+/**
+ * Set the mode of a GPIO pin.
+ *
+ * @param dev GPIO device.
+ * @param pin Pin on the device whose mode to set, 0--15.
+ * @param mode General purpose or alternate function mode to set the pin to.
+ * @see gpio_pin_mode
+ */
+void gpio_set_mode(gpio_dev *dev, uint8 pin, gpio_pin_mode mode) {
+ gpio_reg_map *regs = dev->regs;
+ __io uint32 *cr = &regs->CRL + (pin >> 3);
+ uint32 shift = (pin & 0x7) * 4;
+ uint32 tmp = *cr;
+
+ tmp &= ~(0xF << shift);
+ tmp |= (mode == GPIO_INPUT_PU ? GPIO_INPUT_PD : mode) << shift;
+ *cr = tmp;
- if (mode == GPIO_MODE_INPUT_PU) {
- port->ODR |= BIT(gpio_pin);
- mode = CNF_INPUT_PD;
- } else if (mode == GPIO_MODE_INPUT_PD) {
- port->ODR &= ~BIT(gpio_pin);
+ if (mode == GPIO_INPUT_PD) {
+ regs->ODR &= ~BIT(pin);
+ } else if (mode == GPIO_INPUT_PU) {
+ regs->ODR |= BIT(pin);
}
+}
+
+/*
+ * AFIO
+ */
- CR = (gpio_pin < 8) ? &(port->CRL) : &(port->CRH);
+/**
+ * Initialize the AFIO clock, and reset the AFIO registers.
+ */
+void afio_init(void) {
+ rcc_clk_enable(RCC_AFIO);
+ rcc_reset_dev(RCC_AFIO);
+}
- tmp = *CR;
- tmp &= POS_MASK(shift);
- tmp |= mode << shift;
+#define AFIO_EXTI_SEL_MASK 0xF
+
+/**
+ * Select a source input for an external interrupt.
+ *
+ * @param exti External interrupt. One of: AFIO_EXTI_0,
+ * AFIO_EXTI_1, ..., AFIO_EXTI_15.
+ * @param gpio_port Port which contains pin to use as source input.
+ * One of: AFIO_EXTI_PA, AFIO_EXTI_PB, AFIO_EXTI_PC,
+ * AFIO_EXTI_PD, and, on high density devices,
+ * AFIO_EXTI_PE, AFIO_EXTI_PF, AFIO_EXTI_PG.
+ * @see exti_port
+ */
+void afio_exti_select(afio_exti_num exti, afio_exti_port gpio_port) {
+ __io uint32 *exti_cr = &AFIO_BASE->EXTICR1 + exti / 4;
+ uint32 shift = 4 * (exti % 4);
+ uint32 cr = *exti_cr;
- *CR = tmp;
+ cr &= ~(AFIO_EXTI_SEL_MASK << shift);
+ cr |= gpio_port << shift;
+ *exti_cr = cr;
}