#include "gpio.h" gpio_pindef_t gpio_pins[] = { GPIO_TABLE(EXPAND_AS_DEFS) }; void gpio_hw_config_pin(GPIO_TypeDef *port, uint8_t pin, uint16_t conf) { uint8_t shift; shift = pin * 2; port->MODER &= ~(GPIO_MODER_MASK << shift); port->MODER |= (uint32_t)((conf >> GPIO_MODE_CFG_SHIFT) & GPIO_MODER_MASK) << shift; port->OTYPER &= ~(GPIO_TYPER_MASK << pin); port->OTYPER |= (uint32_t)((conf >> GPIO_TYPE_CFG_SHIFT) & GPIO_TYPER_MASK) << pin; port->OSPEEDR &= ~(GPIO_SPEEDR_MASK << shift); port->OSPEEDR |= (uint32_t)((conf >> GPIO_SPEED_CFG_SHIFT) & GPIO_SPEEDR_MASK) << shift; port->PUPDR &= ~(GPIO_PUPDR_MASK << shift); port->PUPDR |= (uint32_t)((conf >> GPIO_PUPD_CFG_SHIFT) & GPIO_PUPDR_MASK) << shift; } void gpio_connect_af(gpio_t id, uint8_t af_n) { gpio_pindef_t *pin = &gpio_pins[id]; uint8_t shift; if (pin->pin < 8) { shift = pin->pin * 4; pin->port->AFR[0] &= ~((uint32_t)GPIO_AFR_MASK << shift); pin->port->AFR[0] |= af_n << shift; } else { shift = (pin->pin - 8) * 4; pin->port->AFR[1] &= ~((uint32_t)GPIO_AFR_MASK << shift); pin->port->AFR[1] |= af_n << shift; } } /* * TODO add analog flag and setup ADC pins in a proper way */ static void gpio_set_config(gpio_t id) { gpio_pindef_t *pin = &gpio_pins[id]; if (pin->flags & GPIO_AF) { uint8_t af_n = (uint8_t)(pin->flags >> _GPIO_AF_SHIFT); gpio_connect_af(id, af_n); gpio_hw_config_pin(pin->port, pin->pin, GPIO_MODE_AF_CFG | GPIO_SPEED_HIGH_CFG); } else if (pin->flags & GPIO_IN) gpio_hw_config_pin(pin->port, pin->pin, GPIO_MODE_IN_CFG | GPIO_SPEED_HIGH_CFG); else if (pin->flags & GPIO_IN_PU) { gpio_hw_config_pin(pin->port, pin->pin, GPIO_MODE_IN_CFG | GPIO_PU_CFG | GPIO_SPEED_HIGH_CFG); gpio_set(id, pin->flags & GPIO_SET); } else if (pin->flags & GPIO_OUT) { gpio_hw_config_pin(pin->port, pin->pin, GPIO_MODE_OUT_CFG | ((pin->flags & GPIO_OD) ? GPIO_TYPE_OD_CFG : GPIO_TYPE_PP_CFG) | GPIO_SPEED_HIGH_CFG); gpio_set(id, pin->flags & GPIO_SET); } } void gpio_init(void) { uint32_t i; GPIO_DeInit(GPIOA); GPIO_DeInit(GPIOB); GPIO_DeInit(GPIOC); GPIO_DeInit(GPIOD); GPIO_DeInit(GPIOE); // configure clocks RCC->AHB1ENR |= RCC_AHB1ENR_GPIOAEN | RCC_AHB1ENR_GPIOBEN | RCC_AHB1ENR_GPIOCEN | RCC_AHB1ENR_GPIODEN | RCC_AHB1ENR_GPIOEEN; // configure gpios for (i = 0; i < GPIO_TOTAL_COUNT; i++) { if (gpio_pins[i].flags & GPIO_NOINIT) continue; else { gpio_set_config(i); } } } void gpio_set(gpio_t pin, bool value) { if (gpio_pins[pin].flags & GPIO_INV) value = !value; if (value) gpio_pins[pin].port->BSRRL = 1 << gpio_pins[pin].pin; else gpio_pins[pin].port->BSRRH = 1 << gpio_pins[pin].pin; } void gpio_invert_output(gpio_t pin) { gpio_pins[pin].port->ODR ^= 1 << gpio_pins[pin].pin; } bool gpio_get(gpio_t pin) { bool value; if (gpio_pins[pin].flags & GPIO_NOINIT) { return false; } else { value = (gpio_pins[pin].port->IDR & (1 << gpio_pins[pin].pin)) >> gpio_pins[pin].pin; return (gpio_pins[pin].flags & GPIO_INV) ? !value : value; } } bool gpio_is_output(gpio_t pin) { return (gpio_pins[pin].flags & GPIO_OUT) ? true : false; } void gpio_set_direction(gpio_t pin, bool out) { if (out) { gpio_pins[pin].flags &= ~(GPIO_IN | GPIO_IN_PU); gpio_pins[pin].flags |= GPIO_OUT; } else { gpio_pins[pin].flags &= ~(GPIO_OUT | GPIO_OD); gpio_pins[pin].flags |= GPIO_IN; } gpio_set_config(pin); } void gpio_test() { } typedef struct { gpio_pindef_t *gpio; void (*handler)(void); } exti_handler_t;