diff --git a/cpu/stm32/periph/gpio_all.c b/cpu/stm32/periph/gpio_all.c index ef9a6bb09a..a9abf6ea28 100644 --- a/cpu/stm32/periph/gpio_all.c +++ b/cpu/stm32/periph/gpio_all.c @@ -83,12 +83,9 @@ static inline int _pin_num(gpio_t pin) return (pin & 0x0f); } -int gpio_init(gpio_t pin, gpio_mode_t mode) +static inline void port_init_clock(GPIO_TypeDef *port, gpio_t pin) { - GPIO_TypeDef *port = _port(pin); - int pin_num = _pin_num(pin); - - /* enable clock */ + (void)port; /* <-- Only used for when port G requires special handling */ #if defined(CPU_FAM_STM32F0) || defined (CPU_FAM_STM32F3) || defined(CPU_FAM_STM32L1) periph_clk_en(AHB, (RCC_AHBENR_GPIOAEN << _port_num(pin))); #elif defined (CPU_FAM_STM32L0) @@ -106,10 +103,25 @@ int gpio_init(gpio_t pin, gpio_mode_t mode) #else periph_clk_en(AHB1, (RCC_AHB1ENR_GPIOAEN << _port_num(pin))); #endif +} +static inline void set_mode(GPIO_TypeDef *port, int pin_num, unsigned mode) +{ + uint32_t tmp = port->MODER; + tmp &= ~(0x3 << (2 * pin_num)); + tmp |= ((mode & 0x3) << (2 * pin_num)); + port->MODER = tmp; +} + +int gpio_init(gpio_t pin, gpio_mode_t mode) +{ + GPIO_TypeDef *port = _port(pin); + int pin_num = _pin_num(pin); + + /* enable clock */ + port_init_clock(port, pin); /* set mode */ - port->MODER &= ~(0x3 << (2 * pin_num)); - port->MODER |= ((mode & 0x3) << (2 * pin_num)); + set_mode(port, pin_num, mode); /* set pull resistor configuration */ port->PUPDR &= ~(0x3 << (2 * pin_num)); port->PUPDR |= (((mode >> 2) & 0x3) << (2 * pin_num)); @@ -127,12 +139,13 @@ void gpio_init_af(gpio_t pin, gpio_af_t af) GPIO_TypeDef *port = _port(pin); uint32_t pin_num = _pin_num(pin); - /* set pin to AF mode */ - port->MODER &= ~(3 << (2 * pin_num)); - port->MODER |= (2 << (2 * pin_num)); + /* enable clock */ + port_init_clock(port, pin); /* set selected function */ port->AFR[(pin_num > 7) ? 1 : 0] &= ~(0xf << ((pin_num & 0x07) * 4)); port->AFR[(pin_num > 7) ? 1 : 0] |= (af << ((pin_num & 0x07) * 4)); + /* set pin to AF mode */ + set_mode(port, pin_num, 2); } void gpio_init_analog(gpio_t pin) diff --git a/cpu/stm32/periph/gpio_f1.c b/cpu/stm32/periph/gpio_f1.c index 938c75ea01..523cdef47e 100644 --- a/cpu/stm32/periph/gpio_f1.c +++ b/cpu/stm32/periph/gpio_f1.c @@ -74,6 +74,26 @@ static inline int _pin_num(gpio_t pin) return (pin & 0x0f); } +/** + * @brief Check if the given mode is some kind of input mdoe + * @param[in] mode Mode to check + * @retval 1 @p mode is GPIO_IN, GPIO_IN_PD, or GPIO_IN_PU + * @retval 0 @p mode is not an input mode + */ +static inline int gpio_mode_is_input(gpio_mode_t mode) +{ + return !(mode & 3); +} + +static inline void set_mode_or_af(GPIO_TypeDef *port, int pin_num, + unsigned mode_or_af) +{ + volatile uint32_t *crl = (&port->CRL + (pin_num >> 3)); + uint32_t tmp = *crl; + tmp &= ~(0xf << ((pin_num & 0x7) * 4)); + tmp |= ((mode_or_af & MODE_MASK) << ((pin_num & 0x7) * 4)); + *crl = tmp; +} int gpio_init(gpio_t pin, gpio_mode_t mode) { @@ -89,14 +109,15 @@ int gpio_init(gpio_t pin, gpio_mode_t mode) periph_clk_en(APB2, (RCC_APB2ENR_IOPAEN << _port_num(pin))); /* set pin mode */ - *(uint32_t *)(&port->CRL + (pin_num >> 3)) &= ~(0xf << ((pin_num & 0x7) * 4)); - *(uint32_t *)(&port->CRL + (pin_num >> 3)) |= ((mode & MODE_MASK) << ((pin_num & 0x7) * 4)); + set_mode_or_af(port, pin_num, mode); - /* set ODR */ - if (mode == GPIO_IN_PU) - port->ODR |= 1 << pin_num; - else - port->ODR &= ~(1 << pin_num); + /* For input modes, ODR controls pull up settings */ + if (gpio_mode_is_input(mode)) { + if (mode == GPIO_IN_PU) + port->ODR |= 1 << pin_num; + else + port->ODR &= ~(1 << pin_num); + } return 0; /* all OK */ } @@ -109,8 +130,7 @@ void gpio_init_af(gpio_t pin, gpio_af_t af) /* enable the clock for the selected port */ periph_clk_en(APB2, (RCC_APB2ENR_IOPAEN << _port_num(pin))); /* configure the pin */ - *(uint32_t *)(&port->CRL + (pin_num >> 3)) &= ~(0xf << ((pin_num & 0x7) * 4)); - *(uint32_t *)(&port->CRL + (pin_num >> 3)) |= (af << ((pin_num & 0x7) * 4)); + set_mode_or_af(port, pin_num, af); } void gpio_init_analog(gpio_t pin) diff --git a/cpu/stm32/periph/uart.c b/cpu/stm32/periph/uart.c index 5cba9470ec..0f9791fa79 100644 --- a/cpu/stm32/periph/uart.c +++ b/cpu/stm32/periph/uart.c @@ -117,9 +117,6 @@ static inline void uart_init_cts_pin(uart_t uart) static inline void uart_init_pins(uart_t uart, uart_rx_cb_t rx_cb) { /* configure TX pin */ - gpio_init(uart_config[uart].tx_pin, GPIO_OUT); - /* set TX pin high to avoid garbage during further initialization */ - gpio_set(uart_config[uart].tx_pin); #ifdef CPU_FAM_STM32F1 gpio_init_af(uart_config[uart].tx_pin, GPIO_AF_OUT_PP); #else @@ -172,8 +169,6 @@ int uart_init(uart_t uart, uint32_t baudrate, uart_rx_cb_t rx_cb, void *arg) tsrb_init(&uart_tx_rb[uart], uart_tx_rb_buf[uart], UART_TXBUF_SIZE); #endif - uart_init_pins(uart, rx_cb); - uart_enable_clock(uart); /* reset UART configuration -> defaults to 8N1 mode */ @@ -199,6 +194,12 @@ int uart_init(uart_t uart, uint32_t baudrate, uart_rx_cb_t rx_cb, void *arg) uart_init_usart(uart, baudrate); #endif + /* Attach pins to enabled UART periph. Note: It is important that the UART + * interface is configured prior to attaching the pins, as otherwise the + * signal level flickers during initialization resulting in garbage being + * sent. */ + uart_init_pins(uart, rx_cb); + /* enable RX interrupt if applicable */ if (rx_cb) { NVIC_EnableIRQ(uart_config[uart].irqn);