nRF52840 TWIS hangs after WRITE_REQ with CONFIG_UART_ASYNC_API enabled; CONSTLAT prevents failure

I am seeing a reproducible interaction between asynchronous UART support and the TWIS peripheral on an nRF52840 running NCS v3.4.0.

The application uses nrfx TWIS to implement an I2C peripheral interface to another MCU. With CONFIG_UART_ASYNC_API=n, the I2C interface operates reliably.

When CONFIG_UART_ASYNC_API=y is enabled, the first few I2C transactions may complete normally, but eventually a transaction hangs. Instrumentation of the TWIS event handler shows that NRFX_TWIS_EVT_WRITE_REQ is received for the failing transaction, but the expected NRFX_TWIS_EVT_WRITE_DONE event never occurs.

The failure occurs even when the UART instance itself is disabled in devicetree, suggesting that simply enabling the async UART support/configuration is sufficient to expose the problem.

Some additional observations:

  • Delaying each MCU request by 10ms causes the 2nd command to fail, implying that timing is significant.
  • Running the application under debugger control appears to prevent the failure.
  • Keeping main() continuously busy also prevents the failure.
  • Setting CONFIG_TICKLESS_KERNEL=n does not prevent the failure.
  • Executing NRF_POWER->TASKS_CONSTLAT = 1 during startup prevents the failure and the TWIS interface remains reliable.

These results appear to indicate an interaction with the SoC power/clock state. I do not know whether the root cause is in the UARTE driver, TWIS/nrfx handling, or the associated power/clock management.

I would appreciate guidance on whether this is a known issue and whether enabling the UART asynchronous API could change power/clock handling in a way that affects TWIS/EasyDMA operation.

Thanks

Parents
  • Hie,

    Sorry for delay in the reply and thanks for your patience. The issue you are facing is an indicators of a power management and clock-state transition race condition involving EasyDMA which is a known problem

    Your approach of enabling the UART asynchronous API, enabling CONFIG_UART_ASYNC_API=y directly changes power and clock handling. Because the TWIS (Two-Wire Interface Slave) peripheral relies entirely on EasyDMA to stream data directly to RAM, it requires a stable, running high-frequency clock and uninterrupted readiness to respond to an external master. When the power management subsystem alters clock or power domains right as an I2C transaction is initiated, it triggers a race condition that causes the TWIS state machine to hang.

    I hope this helps you.

    Regards

    Pallavi

Reply
  • Hie,

    Sorry for delay in the reply and thanks for your patience. The issue you are facing is an indicators of a power management and clock-state transition race condition involving EasyDMA which is a known problem

    Your approach of enabling the UART asynchronous API, enabling CONFIG_UART_ASYNC_API=y directly changes power and clock handling. Because the TWIS (Two-Wire Interface Slave) peripheral relies entirely on EasyDMA to stream data directly to RAM, it requires a stable, running high-frequency clock and uninterrupted readiness to respond to an external master. When the power management subsystem alters clock or power domains right as an I2C transaction is initiated, it triggers a race condition that causes the TWIS state machine to hang.

    I hope this helps you.

    Regards

    Pallavi

Children
  • Hi,

    Is this a bug that will be fixed or a limitation I have to live with?  Is this "known problem" documented anywhere?  All of my searching for solutions to my issue did not find this which is why I posted here.

    What is the power impact of using constant latency mode?

    I am porting from a legacy application using the nRF5 SDK which does not use constant latency mode and the TWIS interface functions with no issues.

    My application requires fast serial UART streaming support, which lead me to use the Nordic recommended async API.

    What do you recommend is my best approach?  Switch to use the interrupt driven UART API?

    Thanks,

    Guenther

  • Hi,

    Guenther said:
    Is this a bug that will be fixed or a limitation I have to live with?  Is this "known problem" documented anywhere?

    I wouldnt call it a bug but it rather the architectural constrainst. When power management (CONFIG_PM=y) is enabled, Zephyr aggressively puts the SoC into low-power idle states whenever the CPU is free. Peripherals relying on uninterrupted EasyDMA (like TWIS) are sensitive to these background clock and power domain shifts are hence are affected.

    Guenther said:
    What is the power impact of using constant latency mode?

    It prevents the SoC from entering its deepest sleep states and keeps high-frequency clock infrastructure available. In Constant Latency mode, baseline idle current rises significantly (typically to 1 mA – 2 mA+), because internal oscillators and voltage regulation states are kept active to eliminate wakeup latency.

    Guenther said:
    I am porting from a legacy application using the nRF5 SDK which does not use constant latency mode and the TWIS interface functions with no issues.

    The legacy nRF5 SDK used a simpler, bare-metal or proprietary scheduler execution model where system power management was entirely opt-in and rarely enabled by default. Unless you explicitly called power-saving sleep functions, the CPU remained awake and clocks stayed running, implicitly mimicking Constant Latency behavior. In contrast, NCS (Zephyr RTOS) is built from the ground up with aggressive power management policies enabled by default to maximize energy efficiency.

    Guenther said:
    What do you recommend is my best approach?  Switch to use the interrupt driven UART API?

    My recommendation is based on the method you are using to pwer your device. If it is USB-powered: Simply disable system-wide power management in your prj.conf:

    CONFIG_PM=n
    

    This cleanly removes the aggressive sleep states that interfere with TWIS, behaving just like your CONSTLAT workaround without needing manual register tweaks. 

    If your device is battery powered, keep CONFIG_PM=y and CONFIG_UART_ASYNC_API=y, but use Zephyr Power Management Constraints (pm_policy_state_lock_get / pm_policy_state_lock_put). You can apply a latency or state constraint to block deep sleep only while your application expects active I2C slave transactions, allowing the device to drop back into ultra-low power sleep when the bus is idle.

    Regards

    Pallavi

  • Hi,

    Thanks for the detailed information.  I now understand the situation.  This is a power sensitive application which has battery variants.

    We are also planning to run this port on the nRF54LM20A.  Will it exhibit the same restrictions?

    Thanks.

  • Yes,

    Unfortunately, since this is an archtectural constraint, It will affect nRF54LM20A as well. You can still set latency or state constraint to block deep sleep only while your application expects active I2C slave transactions, allowing the device to drop back into ultra-low power sleep when the bus is idle. The ultra-low power sleep when the bus is idle for nrf54LM20A is much lower than nrf52840 hence your device on battery will last longer.

    Regards

    Pallavi

Related