Merge pull request #14426 from maribu/stm32f4_uart_init

cpu/stm32: Fix garbage on UART init
This commit is contained in:
Alexandre Abadie 2020-07-15 21:14:42 +02:00 committed by GitHub
commit 7fd25f21c9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 58 additions and 24 deletions

View File

@ -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)

View File

@ -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)

View File

@ -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);