zephyrproject-rtos / zephyr

Primary Git Repository for the Zephyr Project. Zephyr is a new generation, scalable, optimized, secure RTOS for multiple hardware architectures.
https://docs.zephyrproject.org
Apache License 2.0
10.61k stars 6.5k forks source link

soc: stm32u5: sys_poweroff does not bring the device into shutdown mode when UART DMA is enabled #63236

Open vai-mikar opened 1 year ago

vai-mikar commented 1 year ago

Describe the bug sys_poweroff() does not switch the STM32U585 MCU into shutdown mode when called when UART DMA is enabled. The system freezes when sys_poweroff() is called, but it is not consuming less power (checked with a power analyzer).

When UART DMA is not enabled, the sys_poweroff() really brings the device into shutdown mode, lowering the power consumption of the device.

To Reproduce Steps to reproduce the behavior:

  1. Configure and use an UART with DMA on some STM32U5 board.
  2. call sys_poweroff()
  3. Measure the system power use and notice it has not dropped.

Expected behavior The MCU goes really to shutdown mode dropping the power consumption.

Environment (please complete the following information):

Additional context

This could be related to a workaround of the issues 2.18.2 and 2.19.1 in STM33U585 errata. One STM forum post suggest that keeping the UART DMAT active prevents going into shutdown mode (maybe the peripheral is requesting the bus clock then?)

In Zephyr, commit 1b2942ffeeb4bcc3f93f15d84aff840723f4413e started to keep the DMAT always on.

But there's no mechanism at the moment to allow a driver to preparations for going into shutdown mode.

erwango commented 10 months ago

See https://github.com/zephyrproject-rtos/zephyr/pull/65186#issuecomment-1814099875.

I'll dig a bit more into proposed use case.

ajarmouni-st commented 8 months ago

To Reproduce Steps to reproduce the behavior:

  1. Configure and use an UART with DMA on some STM32U5 board.
  2. call sys_poweroff()
  3. Measure the system power use and notice it has not dropped.

@mkaranki Hi, can you please provide more context about how UART with DMA is used before calling sys_poweroff(), is it called while the UART in question is actively used?

I am unable to reproduce the issue on B-U585I-IOT02A, main 06edc375, SDK 0.16.3 .

ajarmouni-st commented 8 months ago

To Reproduce Steps to reproduce the behavior:

  1. Configure and use an UART with DMA on some STM32U5 board.
  2. call sys_poweroff()
  3. Measure the system power use and notice it has not dropped.

@mkaranki Hi, can you please provide more context about how UART with DMA is used before calling sys_poweroff(), is it called while the UART in question is actively used?

I am unable to reproduce the issue on B-U585I-IOT02A, main 06edc37, SDK 0.16.3 .

I was able to reproduce the issue when sys_poweroff() is called from the main thread while 2 other threads are actively sending & receiving on the same looped-back USART3. Calling uart_rx_disable() & uart_tx_abort(), & suspending the threads before calling sys_poweroff() does not solve the issue.

[00:00:06.151,000] <err> os: ***** USAGE FAULT *****
[00:00:06.151,000] <err> os:   No coprocessor instructions
[00:00:06.151,000] <err> os: r0/a1:  0x00000000  r1/a2:  0x00000000  r2/a3:  0x00000000
[00:00:06.151,000] <err> os: r3/a4:  0x00000014 r12/ip:  0x200002d8 r14/lr:  0x0800128f
[00:00:06.151,000] <err> os:  xpsr:  0x49000000
[00:00:06.151,000] <err> os: Faulting instruction address (r15/pc): 0x08001294
[00:00:06.151,000] <err> os: >>> ZEPHYR FATAL ERROR 33: Unknown error on CPU 0
[00:00:06.151,000] <err> os: Current thread: 0x20000ad8 (unknown)
[00:00:06.221,000] <err> os: Halting system
mkaranki commented 8 months ago

Good to hear. I have not seen the usage fault message regarding this, but might be that it is really happening.

I have this workaround, which is quite a hack, not a proper solution, but helps to get the device into shutdown:

#if DT_HAS_COMPAT_STATUS_OKAY(st_stm32u5_dma)
#define DT_DRV_COMPAT st_stm32_uart
#define TURN_OFF_UART_DMA(inst)                                                                    \
    {                                                                                              \
        USART_TypeDef *usart = (USART_TypeDef *)DT_INST_REG_ADDR(inst);                            \
        if (DT_INST_DMAS_HAS_NAME(inst, rx))                                                       \
            LL_USART_DisableDMAReq_RX(usart);                                                      \
        if (DT_INST_DMAS_HAS_NAME(inst, tx))                                                       \
            LL_USART_DisableDMAReq_TX(usart);                                                      \
    }

    // No way back from now on. Otherwise something could re-enable the UART DMAs.
    irq_lock();

    // Turn off DMA for all UARTs to let the MCU to go into shutdown mode.
    DT_INST_FOREACH_STATUS_OKAY(TURN_OFF_UART_DMA)
#endif /* DT_HAS_COMPAT_STATUS_OKAY(st_stm32u5_dma) */

    sys_poweroff();
    CODE_UNREACHABLE;
ajarmouni-st commented 8 months ago

I have this workaround, which is quite a hack, not a proper solution, but helps to get the device into shutdown:

#if DT_HAS_COMPAT_STATUS_OKAY(st_stm32u5_dma)
#define DT_DRV_COMPAT st_stm32_uart
#define TURN_OFF_UART_DMA(inst)                                                                    \
    {                                                                                              \
        USART_TypeDef *usart = (USART_TypeDef *)DT_INST_REG_ADDR(inst);                            \
        if (DT_INST_DMAS_HAS_NAME(inst, rx))                                                       \
            LL_USART_DisableDMAReq_RX(usart);                                                      \
        if (DT_INST_DMAS_HAS_NAME(inst, tx))                                                       \
            LL_USART_DisableDMAReq_TX(usart);                                                      \
    }

    // No way back from now on. Otherwise something could re-enable the UART DMAs.
    irq_lock();

    // Turn off DMA for all UARTs to let the MCU to go into shutdown mode.
    DT_INST_FOREACH_STATUS_OKAY(TURN_OFF_UART_DMA)
#endif /* DT_HAS_COMPAT_STATUS_OKAY(st_stm32u5_dma) */

    sys_poweroff();
    CODE_UNREACHABLE;

Thank you @mkaranki, I can confirm this workaround fixes the issue. Will dig deeper & hopefully push a permanent fix.

In the meantime, this patch can be used @vai-mikar:

--- a/soc/arm/st_stm32/stm32u5/poweroff.c
+++ b/soc/arm/st_stm32/stm32u5/poweroff.c
@@ -9,9 +9,27 @@

 #include <stm32_ll_cortex.h>
 #include <stm32_ll_pwr.h>
+#include <stm32_ll_usart.h>
+
+#if DT_HAS_COMPAT_STATUS_OKAY(st_stm32u5_dma)
+#define DT_DRV_COMPAT st_stm32_uart
+#define TURN_OFF_UART_DMA(inst)                                                \
+       {                                                                       \
+               USART_TypeDef *usart = (USART_TypeDef *)DT_INST_REG_ADDR(inst); \
+               if (DT_INST_DMAS_HAS_NAME(inst, rx))                            \
+                       LL_USART_DisableDMAReq_RX(usart);                       \
+               if (DT_INST_DMAS_HAS_NAME(inst, tx))                            \
+                       LL_USART_DisableDMAReq_TX(usart);                       \
+       }
+#endif /* DT_HAS_COMPAT_STATUS_OKAY(st_stm32u5_dma) */

 void z_sys_poweroff(void)
 {
+#if DT_HAS_COMPAT_STATUS_OKAY(st_stm32u5_dma)
+       /* Turn off DMA for all UARTs to let the MCU to go into shutdown mode. */
+       DT_INST_FOREACH_STATUS_OKAY(TURN_OFF_UART_DMA)
+#endif /* DT_HAS_COMPAT_STATUS_OKAY(st_stm32u5_dma) */
+
        LL_PWR_SetPowerMode(LL_PWR_SHUTDOWN_MODE);
        LL_LPM_EnableDeepSleep();
github-actions[bot] commented 6 months ago

This issue has been marked as stale because it has been open (more than) 60 days with no activity. Remove the stale label or add a comment saying that you would like to have the label removed otherwise this issue will automatically be closed in 14 days. Note, that you can always re-open a closed issue at any time.

github-actions[bot] commented 3 months ago

This issue has been marked as stale because it has been open (more than) 60 days with no activity. Remove the stale label or add a comment saying that you would like to have the label removed otherwise this issue will automatically be closed in 14 days. Note, that you can always re-open a closed issue at any time.

github-actions[bot] commented 3 weeks ago

This issue has been marked as stale because it has been open (more than) 60 days with no activity. Remove the stale label or add a comment saying that you would like to have the label removed otherwise this issue will automatically be closed in 14 days. Note, that you can always re-open a closed issue at any time.