@@ -1434,7 +1434,7 @@ static inline void uart_stm32_dma_tx_enable(const struct device *dev)
1434
1434
1435
1435
static inline void uart_stm32_dma_tx_disable (const struct device * dev )
1436
1436
{
1437
- #ifdef CONFIG_UART_STM32U5_ERRATA_DMAT
1437
+ #ifdef CONFIG_UART_STM32U5_ERRATA_DMAT_NOCLEAR
1438
1438
ARG_UNUSED (dev );
1439
1439
1440
1440
/*
@@ -1615,8 +1615,16 @@ static int uart_stm32_async_tx(const struct device *dev,
1615
1615
const struct uart_stm32_config * config = dev -> config ;
1616
1616
USART_TypeDef * usart = config -> usart ;
1617
1617
struct uart_stm32_data * data = dev -> data ;
1618
+ __maybe_unused unsigned int key ;
1618
1619
int ret ;
1619
1620
1621
+ /* Check size of singl character (1 or 2 bytes) */
1622
+ const int char_size = (IS_ENABLED (CONFIG_UART_WIDE_DATA ) &&
1623
+ (LL_USART_GetDataWidth (usart ) == LL_USART_DATAWIDTH_9B ) &&
1624
+ (LL_USART_GetParity (usart ) == LL_USART_PARITY_NONE ))
1625
+ ? 2
1626
+ : 1 ;
1627
+
1620
1628
if (data -> dma_tx .dma_dev == NULL ) {
1621
1629
return - ENODEV ;
1622
1630
}
@@ -1648,34 +1656,74 @@ static int uart_stm32_async_tx(const struct device *dev,
1648
1656
/* Enable TC interrupt so we can signal correct TX done */
1649
1657
LL_USART_EnableIT_TC (usart );
1650
1658
1651
- /* set source address */
1652
- data -> dma_tx .blk_cfg .source_address = (uint32_t )data -> dma_tx .buffer ;
1653
- data -> dma_tx .blk_cfg .block_size = data -> dma_tx .buffer_length ;
1659
+ /**
1660
+ * Setup DMA descriptor for TX.
1661
+ * If DMAT low-power errata workaround is enabled,
1662
+ * we send the first character using polling and the rest
1663
+ * using DMA; as such, single-character transfers use only
1664
+ * polling and don't need to prepare a DMA descriptor.
1665
+ * In other configurations, the DMA is always used.
1666
+ */
1667
+ if (!IS_ENABLED (CONFIG_UART_STM32U5_ERRATA_DMAT_LOWPOWER ) ||
1668
+ data -> dma_tx .buffer_length > char_size ) {
1669
+ if (IS_ENABLED (CONFIG_UART_STM32U5_ERRATA_DMAT_LOWPOWER )) {
1670
+ /* set source address */
1671
+ data -> dma_tx .blk_cfg .source_address =
1672
+ ((uint32_t )data -> dma_tx .buffer ) + char_size ;
1673
+ data -> dma_tx .blk_cfg .block_size = data -> dma_tx .buffer_length - char_size ;
1674
+ } else {
1675
+ /* set source address */
1676
+ data -> dma_tx .blk_cfg .source_address = ((uint32_t )data -> dma_tx .buffer );
1677
+ data -> dma_tx .blk_cfg .block_size = data -> dma_tx .buffer_length ;
1678
+ }
1654
1679
1655
- ret = dma_config (data -> dma_tx .dma_dev , data -> dma_tx .dma_channel ,
1656
- & data -> dma_tx .dma_cfg );
1680
+ ret = dma_config (data -> dma_tx .dma_dev , data -> dma_tx .dma_channel ,
1681
+ & data -> dma_tx .dma_cfg );
1657
1682
1658
- if (ret != 0 ) {
1659
- LOG_ERR ("dma tx config error!" );
1660
- return - EINVAL ;
1661
- }
1683
+ if (ret != 0 ) {
1684
+ LOG_ERR ("dma tx config error!" );
1685
+ return - EINVAL ;
1686
+ }
1662
1687
1663
- if (dma_start (data -> dma_tx .dma_dev , data -> dma_tx .dma_channel )) {
1664
- LOG_ERR ("UART err: TX DMA start failed!" );
1665
- return - EFAULT ;
1666
- }
1688
+ if (dma_start (data -> dma_tx .dma_dev , data -> dma_tx .dma_channel )) {
1689
+ LOG_ERR ("UART err: TX DMA start failed!" );
1690
+ return - EFAULT ;
1691
+ }
1667
1692
1668
- /* Start TX timer */
1669
- async_timer_start (& data -> dma_tx .timeout_work , data -> dma_tx .timeout );
1693
+ /* Start TX timer */
1694
+ async_timer_start (& data -> dma_tx .timeout_work , data -> dma_tx .timeout );
1695
+ }
1670
1696
1671
1697
#ifdef CONFIG_PM
1672
1698
1673
1699
/* Do not allow system to suspend until transmission has completed */
1674
1700
uart_stm32_pm_policy_state_lock_get_unconditional ();
1675
1701
#endif
1676
1702
1677
- /* Enable TX DMA requests */
1678
- uart_stm32_dma_tx_enable (dev );
1703
+ if (IS_ENABLED (CONFIG_UART_STM32U5_ERRATA_DMAT_LOWPOWER )) {
1704
+ /**
1705
+ * Send first character using polling.
1706
+ * The DMA TX needs to be enabled before the UART transmits
1707
+ * the character and triggers transfer complete event.
1708
+ */
1709
+ key = irq_lock ();
1710
+
1711
+ if (char_size > 1 ) {
1712
+ LL_USART_TransmitData9 (usart , * (const uint16_t * )tx_data );
1713
+ } else {
1714
+ LL_USART_TransmitData8 (usart , * tx_data );
1715
+ }
1716
+
1717
+ if (data -> dma_tx .buffer_length > char_size ) {
1718
+ /* Enable TX DMA requests */
1719
+ uart_stm32_dma_tx_enable (dev );
1720
+ }
1721
+
1722
+ irq_unlock (key );
1723
+ } else {
1724
+ /* Enable TX DMA requests */
1725
+ uart_stm32_dma_tx_enable (dev );
1726
+ }
1679
1727
1680
1728
return 0 ;
1681
1729
}
0 commit comments