Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

cpu/stm32: Fix garbage on UART init #14426

Merged
merged 2 commits into from
Jul 15, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 23 additions & 10 deletions cpu/stm32/periph/gpio_all.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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));
Expand All @@ -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)
Expand Down
40 changes: 30 additions & 10 deletions cpu/stm32/periph/gpio_f1.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand All @@ -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 ODR */
if (mode == GPIO_IN_PU)
port->ODR |= 1 << pin_num;
else
port->ODR &= ~(1 << pin_num);
set_mode_or_af(port, pin_num, mode);

/* 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 */
}
Expand All @@ -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)
Expand Down
11 changes: 6 additions & 5 deletions cpu/stm32/periph/uart.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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 */
Expand All @@ -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);
Expand Down