Skip to content

Commit b95cdb2

Browse files
arbraunscarlescufi
authored andcommitted
drivers: serial: stm32: add support for RS485 configuration
The stm32 UART can output a "driver enable" signal on the RTS pin that allows controlling e.g. external RS-485 drivers. This can already be configured through the devicetree using the `de-*` properties, but not through uart_configure(). This commit enables the use of .flow_ctrl=UART_CFG_FLOW_CTRL_RS485. This is supported on all devices other than l1, f1, f2, and f4 as found by this search: $ grep -rLw USART_CR3_DEM ../modules/hal/stm32/stm32cube/*/soc/*.h |\ grep -vE 'system_|partition_|stm32[^0-9]+[0-9]?xx\.h' |\ cut -d/ -f6 |\ sort -u Signed-off-by: Armin Brauns <[email protected]>
1 parent 652d9a5 commit b95cdb2

File tree

1 file changed

+58
-9
lines changed

1 file changed

+58
-9
lines changed

drivers/serial/uart_stm32.c

Lines changed: 58 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,13 @@ LOG_MODULE_REGISTER(uart_stm32, CONFIG_UART_LOG_LEVEL);
5656
#define HAS_LPUART_1 (DT_NODE_HAS_COMPAT_STATUS(DT_NODELABEL(lpuart1), \
5757
st_stm32_lpuart, okay))
5858

59+
/* Available everywhere except l1, f1, f2, f4. */
60+
#ifdef USART_CR3_DEM
61+
#define HAS_DRIVER_ENABLE 1
62+
#else
63+
#define HAS_DRIVER_ENABLE 0
64+
#endif
65+
5966
#if HAS_LPUART_1
6067
#ifdef USART_PRESC_PRESCALER
6168
uint32_t lpuartdiv_calc(const uint64_t clock_rate, const uint16_t presc_idx,
@@ -256,6 +263,27 @@ static inline uint32_t uart_stm32_get_hwctrl(const struct device *dev)
256263
return LL_USART_GetHWFlowCtrl(config->usart);
257264
}
258265

266+
#if HAS_DRIVER_ENABLE
267+
static inline void uart_stm32_set_driver_enable(const struct device *dev,
268+
bool driver_enable)
269+
{
270+
const struct uart_stm32_config *config = dev->config;
271+
272+
if (driver_enable) {
273+
LL_USART_EnableDEMode(config->usart);
274+
} else {
275+
LL_USART_DisableDEMode(config->usart);
276+
}
277+
}
278+
279+
static inline bool uart_stm32_get_driver_enable(const struct device *dev)
280+
{
281+
const struct uart_stm32_config *config = dev->config;
282+
283+
return LL_USART_IsEnabledDEMode(config->usart);
284+
}
285+
#endif
286+
259287
static inline uint32_t uart_stm32_cfg2ll_parity(enum uart_config_parity parity)
260288
{
261289
switch (parity) {
@@ -388,14 +416,17 @@ static inline enum uart_config_data_bits uart_stm32_ll2cfg_databits(uint32_t db,
388416
/**
389417
* @brief Get LL hardware flow control define from
390418
* Zephyr hardware flow control option.
391-
* @note Supports only UART_CFG_FLOW_CTRL_RTS_CTS.
419+
* @note Supports only UART_CFG_FLOW_CTRL_RTS_CTS and UART_CFG_FLOW_CTRL_RS485.
392420
* @param fc: Zephyr hardware flow control option.
393421
* @retval LL_USART_HWCONTROL_RTS_CTS, or LL_USART_HWCONTROL_NONE.
394422
*/
395423
static inline uint32_t uart_stm32_cfg2ll_hwctrl(enum uart_config_flow_control fc)
396424
{
397425
if (fc == UART_CFG_FLOW_CTRL_RTS_CTS) {
398426
return LL_USART_HWCONTROL_RTS_CTS;
427+
} else if (fc == UART_CFG_FLOW_CTRL_RS485) {
428+
/* Driver Enable is handled separately */
429+
return LL_USART_HWCONTROL_NONE;
399430
}
400431

401432
return LL_USART_HWCONTROL_NONE;
@@ -428,6 +459,9 @@ static int uart_stm32_configure(const struct device *dev,
428459
const uint32_t databits = uart_stm32_cfg2ll_databits(cfg->data_bits,
429460
cfg->parity);
430461
const uint32_t flowctrl = uart_stm32_cfg2ll_hwctrl(cfg->flow_ctrl);
462+
#if HAS_DRIVER_ENABLE
463+
bool driver_enable = cfg->flow_ctrl == UART_CFG_FLOW_CTRL_RS485;
464+
#endif
431465

432466
/* Hardware doesn't support mark or space parity */
433467
if ((cfg->parity == UART_CFG_PARITY_MARK) ||
@@ -473,12 +507,16 @@ static int uart_stm32_configure(const struct device *dev,
473507
return -ENOTSUP;
474508
}
475509

476-
/* Driver supports only RTS CTS flow control */
477-
if (cfg->flow_ctrl != UART_CFG_FLOW_CTRL_NONE) {
478-
if (!IS_UART_HWFLOW_INSTANCE(config->usart) ||
479-
UART_CFG_FLOW_CTRL_RTS_CTS != cfg->flow_ctrl) {
480-
return -ENOTSUP;
481-
}
510+
/* Driver supports only RTS/CTS and RS485 flow control */
511+
if (!(cfg->flow_ctrl == UART_CFG_FLOW_CTRL_NONE
512+
|| (cfg->flow_ctrl == UART_CFG_FLOW_CTRL_RTS_CTS &&
513+
IS_UART_HWFLOW_INSTANCE(config->usart))
514+
#if HAS_DRIVER_ENABLE
515+
|| (cfg->flow_ctrl == UART_CFG_FLOW_CTRL_RS485 &&
516+
IS_UART_DRIVER_ENABLE_INSTANCE(config->usart))
517+
#endif
518+
)) {
519+
return -ENOTSUP;
482520
}
483521

484522
LL_USART_Disable(config->usart);
@@ -499,6 +537,12 @@ static int uart_stm32_configure(const struct device *dev,
499537
uart_stm32_set_hwctrl(dev, flowctrl);
500538
}
501539

540+
#if HAS_DRIVER_ENABLE
541+
if (driver_enable != uart_stm32_get_driver_enable(dev)) {
542+
uart_stm32_set_driver_enable(dev, driver_enable);
543+
}
544+
#endif
545+
502546
if (cfg->baudrate != data->baud_rate) {
503547
uart_stm32_set_baudrate(dev, cfg->baudrate);
504548
data->baud_rate = cfg->baudrate;
@@ -521,6 +565,11 @@ static int uart_stm32_config_get(const struct device *dev,
521565
uart_stm32_get_databits(dev), uart_stm32_get_parity(dev));
522566
cfg->flow_ctrl = uart_stm32_ll2cfg_hwctrl(
523567
uart_stm32_get_hwctrl(dev));
568+
#if HAS_DRIVER_ENABLE
569+
if (uart_stm32_get_driver_enable(dev)) {
570+
cfg->flow_ctrl = UART_CFG_FLOW_CTRL_RS485;
571+
}
572+
#endif
524573
return 0;
525574
}
526575
#endif /* CONFIG_UART_USE_RUNTIME_CONFIGURE */
@@ -1705,14 +1754,14 @@ static int uart_stm32_init(const struct device *dev)
17051754
}
17061755
#endif
17071756

1708-
#ifdef USART_CR3_DEM
1757+
#if HAS_DRIVER_ENABLE
17091758
if (config->de_enable) {
17101759
if (!IS_UART_DRIVER_ENABLE_INSTANCE(config->usart)) {
17111760
LOG_ERR("%s does not support driver enable", dev->name);
17121761
return -EINVAL;
17131762
}
17141763

1715-
LL_USART_EnableDEMode(config->usart);
1764+
uart_stm32_set_driver_enable(dev, true);
17161765
LL_USART_SetDEAssertionTime(config->usart, config->de_assert_time);
17171766
LL_USART_SetDEDeassertionTime(config->usart, config->de_deassert_time);
17181767

0 commit comments

Comments
 (0)