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

stm32_common/uart: add baudrate recalculation based on clk settings #8401

Closed
wants to merge 3 commits into from
Closed
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
17 changes: 17 additions & 0 deletions cpu/stm32_common/include/periph_cpu_common.h
Original file line number Diff line number Diff line change
Expand Up @@ -306,6 +306,23 @@ uint32_t periph_apb_clk(uint8_t bus);
*/
uint32_t periph_timer_clk(uint8_t bus);

/**
* @brief Recalculate Baudrate for UART device
*
* The UART device will be initialized with the following configuration:
* - 8 data bits
* - no parity
* - 1 stop bit
* - baudrate as given
*
* @param[in] uart UART device to initialize
* @param[in] baudrate desired baudrate in baud/s
*
* @return UART_OK on success
* @return UART_NOBAUD on inapplicable baudrate
*/
int periph_uart_set_baudrate(unsigned int uart, uint32_t baudrate);

/**
* @brief Enable the given peripheral clock
*
Expand Down
63 changes: 50 additions & 13 deletions cpu/stm32_common/periph/uart.c
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,10 @@
#include "periph/uart.h"
#include "periph/gpio.h"

#define RXENABLE (USART_CR1_RE | USART_CR1_RXNEIE)
#define RXENABLE (USART_CR1_RE | USART_CR1_RXNEIE)

#define UART_8X_OVERSAMPLING 8
#define UART_16X_OVERSAMPLING 16
/**
* @brief Allocate memory to store the callback functions
*/
Expand All @@ -43,19 +45,57 @@ static inline USART_TypeDef *dev(uart_t uart)
return uart_config[uart].dev;
}

int uart_init(uart_t uart, uint32_t baudrate, uart_rx_cb_t rx_cb, void *arg)
{
int periph_uart_set_baudrate(uart_t uart, uint32_t baudrate) {
uint16_t mantissa;
uint8_t fraction;
uint32_t clk;
uint32_t uart_clk;

uart_clk = periph_apb_clk(uart_config[uart].bus)/baudrate;

if (uart_clk < 8) {
/* clock is too slow for using UART with specified baudrate */
periph_clk_dis(uart_config[uart].bus, uart_config[uart].rcc_mask);
return UART_NOBAUD;
} else {
/* Disable UART. Setting BRR on enabled USART1 sometimes somehow results in Hard Fault */
dev(uart)->CR1 &= ~USART_CR1_UE;

/* choose between 8x and 16x oversampling */
/* 16x is preferred, but is not possible on low clock frequency */
#ifdef USART_CR1_OVER8
if (uart_clk < 16) {
dev(uart)->CR1 |= USART_CR1_OVER8;
mantissa = (uint16_t)(uart_clk / UART_8X_OVERSAMPLING);
fraction = (uint8_t)(uart_clk - (mantissa * UART_8X_OVERSAMPLING));
dev(uart)->BRR = ((mantissa & 0x0fff) << 4) | (fraction & 0x07);
} else {
dev(uart)->CR1 &= ~USART_CR1_OVER8;
mantissa = (uint16_t)(uart_clk / UART_16X_OVERSAMPLING);
fraction = (uint8_t)(uart_clk - (mantissa * UART_16X_OVERSAMPLING));
dev(uart)->BRR = ((mantissa & 0x0fff) << 4) | (fraction & 0x0f);
}
#else
mantissa = (uint16_t)(uart_clk / UART_16X_OVERSAMPLING);
fraction = (uint8_t)(uart_clk - (mantissa * UART_16X_OVERSAMPLING));
dev(uart)->BRR = ((mantissa & 0x0fff) << 4) | (fraction & 0x0f);
#endif

/* Enable UART */
dev(uart)->CR1 |= USART_CR1_UE;

return UART_OK;
}
}

int uart_init(uart_t uart, uint32_t baudrate, uart_rx_cb_t rx_cb, void *arg) {
assert(uart < UART_NUMOF);

/* save ISR context */
isr_ctx[uart].rx_cb = rx_cb;
isr_ctx[uart].arg = arg;

/* configure TX pin */
/* configure RX and TX pin */
gpio_init(uart_config[uart].rx_pin, GPIO_IN);
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);
Expand Down Expand Up @@ -93,18 +133,15 @@ int uart_init(uart_t uart, uint32_t baudrate, uart_rx_cb_t rx_cb, void *arg)
dev(uart)->CR3 = 0;

/* calculate and apply baudrate */
clk = periph_apb_clk(uart_config[uart].bus) / baudrate;
mantissa = (uint16_t)(clk / 16);
fraction = (uint8_t)(clk - (mantissa * 16));
dev(uart)->BRR = ((mantissa & 0x0fff) << 4) | (fraction & 0x0f);
if (uart_set_baudrate(uart, baudrate) != UART_OK) {
return UART_NOBAUD;
}

dev(uart)->CR1 = (USART_CR1_UE | USART_CR1_TE);
/* enable RX interrupt if applicable */
if (rx_cb) {
NVIC_EnableIRQ(uart_config[uart].irqn);
dev(uart)->CR1 = (USART_CR1_UE | USART_CR1_TE | RXENABLE);
}
else {
dev(uart)->CR1 = (USART_CR1_UE | USART_CR1_TE);
dev(uart)->CR1 |= RXENABLE;
}

#ifdef MODULE_STM32_PERIPH_UART_HW_FC
Expand Down