Skip to content

Conversation

@SeppoTakalo
Copy link
Contributor

@SeppoTakalo SeppoTakalo commented Oct 10, 2025

I'm putting up this PR as a RFC for now until I have been able to split the smaller commits to separate PR and to allow reviewers to see what the end goal is. It is easier to argue why I change something if I show the intent here.

I have so far submitted changes from this work on following PRs:

Description of the work: CMUX Power Saving

The 3GPP TS 27.010 specifies a power saving mechanism for CMUX which can be used in Zephyr when the modem supports it.

The power saving mechanism is covered in the following sections on the specification:

  • 5.2.5 Inter-frame Fill
  • 5.4.6.3.2 Power Saving Control (PSC) message
  • 5.4.7 Power Control and Wake-up Mechanisms
image

States are explained in the generated documen in OS Services -> Modem Modules.

The power saving mechanism allows runtime power management for the UART device used by the CMUX module. When there is no data to be sent or received on any DLCI channel, the CMUX module will enter the idle state after a configurable timeout. In the idle state, the CMUX module will send a Power Saving Control message to the modem, requesting it to enter a low power state. The CMUX module may then close the pipe device, allowing the UART device to be powered down if runtime power management is enabled.

PIPE backend is in response of actually power controlling the UART as it is the last endpoint in PIPE interface
image

When data is to be sent or received on any DLCI channel, the CMUX module will exit the idle state and wakes the modem up by sending flag characters until it receives a flag character from the modem.

Some modems allow UART to be powered down only when the DTR (Data Terminal Ready) signal is de-asserted. In this case, a UART device with DTR support can be used with the CMUX module to control the DTR signal based on the power state of the UART.

Waking up on incoming data when UART is powered down requires a modem that supports RING signal to wake up the host. The RING signal is handled by the modem driver and it opens the pipe device when the RING signal is detected, allowing the CMUX module to wake up the modem and process incoming data.

CMUX options are controlled using Device Tree settings, because CMUX is a modem dependant.

cmux-enable-runtime-power-save:
  type: boolean
  description: Enable runtime power saving using CMUX PSC commands.
               This requires modem to support CMUX and PSC commands while keeping the data
               connection active.
cmux-close-pipe-on-power-save:
  type: boolean
  description: Close the modem pipe when entering power save mode.
              When runtime power management is enabled, this closes the UART.
              This requires modem to support waking up the UART using RING signal.
cmux-idle-timeout-ms:
  type: int
  description: Time in milliseconds after which CMUX will enter power save mode.
  default: 10000

Example setup where CMUX power control is enabled and UART is allowed to shut down and control the DTR line:

&uart1 {
	current-speed = <115200>;
	zephyr,pm-device-runtime-auto;

	modem: modem {
		compatible = "nordic,nrf91-slm";
		status = "okay";
		mdm-ring-gpios = <&interface_to_nrf9160 5 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>;
		mdm-dtr-gpios = <&interface_to_nrf9160 4 GPIO_ACTIVE_LOW>;
		zephyr,pm-device-runtime-auto;
		cmux-enable-runtime-power-save;
		cmux-close-pipe-on-power-save;
		cmux-idle-timeout-ms = <500>;
	};
};

This PR implements CMUX Power Saving in a way that it allows Zephyr host to keep PPP connection up while the underlying UART is powered down and the module may enter eDRX or PSM sleep modes. Waking up is completely automatic when PPP is sending data. Incoming data wakes up the modem modules using RING signal.

UART power management requires DTR and RING as the CMUX itself can only initiate wake up by sending flag characters.

The usage of DTR pin is typical in such modems that allow disconnecting the UART:
image

However, even if UART cannot be shut down, modem MAY benefit from the knowledge that CMUX is in the sleep mode.
Without DTR/power off, this PR has been tested against Quectel BG96 modem. With DTR and power control, I have tested this against ongoing work of nRF9160 Serial Modem application.

@zephyrbot zephyrbot added area: Devicetree Bindings area: Tests Issues related to a particular existing or missing test area: Boards/SoCs area: UART Universal Asynchronous Receiver-Transmitter area: Modem area: Devicetree area: Modem Drivers labels Oct 10, 2025
@SeppoTakalo SeppoTakalo force-pushed the cmux_power_control_upstream branch 4 times, most recently from 1368e5f to de7938f Compare October 14, 2025 21:15
@SeppoTakalo SeppoTakalo force-pushed the cmux_power_control_upstream branch from de7938f to 9bd2b3f Compare October 21, 2025 06:32
@SeppoTakalo SeppoTakalo changed the title [RFC] modem: cmux: UART power control using CMUX Power Saving Control messages modem: cmux: UART power control using CMUX Power Saving Control messages Oct 21, 2025
Copy link
Contributor

@bjarki-andreasen bjarki-andreasen left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good, there is the serialization issue which is what is blocking, otherwise really nice additions!

@SeppoTakalo SeppoTakalo force-pushed the cmux_power_control_upstream branch from 9bd2b3f to eff0368 Compare October 21, 2025 14:21
@SeppoTakalo
Copy link
Contributor Author

@bjarki-andreasen I submitted a separate PR as it looks like all CMUX command structures relied on same bitfield behavior, so I fixed all of those.

This PR contains the fix for PSC as well as the requested pipe test.

@SeppoTakalo
Copy link
Contributor Author

Effects on power usage of nRF9160 modem with this PR

I did some evaluation of the effect of this PR as well as those mentioned smaller split-up PRs from this work.

Intention here is to properly show for reviewers why this really important step to make PPP+CMUX network configuration as power efficient solution as using simple AT command interfaces.

Pay attention that Zephyr IP stack, or PPP configuration have not been altered. So this effect would be same on any application that uses Zephyr's socket interface.

Test configuration

Board: nRF9160DK.

nrf9160dk/nrf52840 running Zephyr's command line application Zperf, compiled using following DTS setup for modem

&uart1 {
	current-speed = <115200>;
	hw-flow-control;
	zephyr,pm-device-runtime-auto;
	label = "modem_uart";
	status = "okay";
	pinctrl-0 = <&uart1_default_alt>;
	pinctrl-1 = <&uart1_sleep_pull>;
	pinctrl-names = "default", "sleep";

	modem: modem {
		compatible = "nordic,nrf91-slm";
		status = "okay";
		mdm-ring-gpios = <&interface_to_nrf9160 5 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>;
		mdm-dtr-gpios = <&interface_to_nrf9160 4 GPIO_ACTIVE_LOW>;
		zephyr,pm-device-runtime-auto;
		cmux-enable-runtime-power-save;
		cmux-close-pipe-on-power-save;
		cmux-idle-timeout-ms = <500>;
	};
};

Modem driver is changed so that nRF91 AT initialization script requests PSM+eDRX mode

			      MODEM_CHAT_SCRIPT_CMD_RESP("AT+CPSMS=1,,,\"00101100\",\"00000111\"", ok_match),
			      MODEM_CHAT_SCRIPT_CMD_RESP("AT+CEDRXS=2,4,\"0000\"", ok_match),
			      MODEM_CHAT_SCRIPT_CMD_RESP("AT%XPTW=4,\"0000\"", ok_match),

The example above requests active time of 14s, eDRX paging window 1.28s and cycle 5.12s.

nrf9160dk/nrf9160 running Serial Modem application on my work branch that contains all these CMUX changes on top of nRF Connect SDK.

Test case

Executing one DNS query from Zephyr shell, while modem and PPP is up and running but there is no traffic ongoing in past minute.

Test result without CMUX power saving

All CMUX, DTR and RING changes removed from test config:

	modem: modem {
		compatible = "nordic,nrf91-slm";
		status = "okay";
		zephyr,pm-device-runtime-auto;
	};
image

Modem's power usage:
image

About 451 uA while modem is in PSM mode and PPP is up and running.
I assume current is mostly result of high-speed clocks that are kept running because UART is active.

Test result with CMUX power saving

image

As seen above, CMUX wakes up from Power Saving mode quickly, and even drops back to power saving while waiting for DNS response. This is intentionally caused by very short idle period of 500 ms. See cmux-idle-timeout-ms on the DTS above.

Notice that LOG messages are not in order, because shell takes a priority, so wake up log messages are printed after the shell messages about respose are handled.

Modem's power usage:
image

Conclusion

Using nRF9160 modem, the power PSM usage is below 2 uA while the PPP+CMUX connection is still up.
This is only possible because we can shut down the UART as a result of the CMUX power saving mode.

The PSM power usage drops from ~400 uA down to ~2 uA.

This amount of power saving make almost unnecessary to shut down the modem while idling for many hours.

@rerickson1
Copy link
Member

The PSM power usage drops from ~400 uA down to ~2 uA.

This amount of power saving make almost unnecessary to shut down the modem while idling for many hours.

You are showing the current draw of the host (nRF52840) correct? Or is it the entire system, nRF52840 + nRF9160?

@SeppoTakalo
Copy link
Contributor Author

The PSM power usage drops from ~400 uA down to ~2 uA.
This amount of power saving make almost unnecessary to shut down the modem while idling for many hours.

You are showing the current draw of the host (nRF52840) correct? Or is it the entire system, nRF52840 + nRF9160?

No, only the nRF9160 modem.
nRF52840 is excluded from the measurement.

I have the Zephyr shell running on another UART, so it would not go down to any power saving mode.

@rerickson1
Copy link
Member

The PSM power usage drops from ~400 uA down to ~2 uA.
This amount of power saving make almost unnecessary to shut down the modem while idling for many hours.

You are showing the current draw of the host (nRF52840) correct? Or is it the entire system, nRF52840 + nRF9160?

No, only the nRF9160 modem. nRF52840 is excluded from the measurement.

I have the Zephyr shell running on another UART, so it would not go down to any power saving mode.

Thanks for clarification. In a production app, the nRF52840 would drop to ~2 uA as well.

Instead of relying non-standard compiler behavior, define
encode and decode functions for all CMUX command structures.

Final command is encoded into a shared buffer, because it is
always copied directly to TX ringbuffer.

Added also functions to validate commands.

Signed-off-by: Seppo Takalo <[email protected]>
DTR signal on UART extends the power saving by allowing host
to indicate the remote end that the UART is not in active state.

Signed-off-by: Seppo Takalo <[email protected]>
Signal powersaving mode for the remote end using PSC command.
Wakes up the remote end from powersaving mode by sending flag characters.

This method is defined in 3GPP TS 27.010.
Sections 5.4.6.3.2 Power Saving Control (PSC) and
5.4.7 Power Control and Wake-up Mechanisms.

Essentially it is one PSC command to indicate a sleep state, and
then repeated flag characters to wake up the remote end or indicate
that we have been woken up.

Signed-off-by: Seppo Takalo <[email protected]>
CMUX driver can enable the support for idle-timer in
devicetree and can be requested to shut down the pipe
during sleep.

Then UART backend put the actual device into sleep when
pipe is closed.

Waking up is requested by sending data to DLC pipe
or by manually opening the uart_pipe.
Modem may request similar wake-up by a RING interrupt which
would open the same pipe.

When UART is powered and pipe is not closed, CMUX wake-up
procedure is automatic. Either end may initiate the wake-up.

Signed-off-by: Seppo Takalo <[email protected]>
Ringbuffer is not safe in ISR but k_pipe without waiting is.
So use pipe for events, so that possible GPIO callbacks from
ISR content can post events.

Signed-off-by: Seppo Takalo <[email protected]>
Use ring indicator to wake up the CMUX device
from sleep.
Only used for runtime power management, but same event
could be used for initiating idle -> connected as well.

Signed-off-by: Seppo Takalo <[email protected]>
Add documentation and state machine diagrams for CMUX power saving
feature and how to use it with Zephyr.

Signed-off-by: Seppo Takalo <[email protected]>
Instead of copying all fields from cmux_config into run-time
struct cmux, just have the configuration structure as a member.

Signed-off-by: Seppo Takalo <[email protected]>
When working on CMUX power saving, it is typical
that we end up closing the pipe before the last
RX_READY event is handled from workqueue, so we end up
receiving -EPERM which is not really a fatal error.

Pipes recover when they are re-opened. So drop this error
and return zero instead, like modem_pipe_open() and close() does.

Signed-off-by: Seppo Takalo <[email protected]>
@SeppoTakalo SeppoTakalo force-pushed the cmux_power_control_upstream branch from 3ffa7d1 to 74f8d9a Compare October 29, 2025 14:58
@zephyrbot zephyrbot requested a review from mbolivar October 29, 2025 15:00
@sonarqubecloud
Copy link

*****************

The 3GPP TS 27.010 specifies a power saving mechanism for CMUX which can be used in
Zephyr when the modem supports it.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi,

I'm not sure if this is the correct place to add below idea but I think it could anticipate many questions from community:

I would recommend that we state the LPM mode: DRX, eDRX and PSM + the minimal supported version like 3GPP Release 12 to have PSM and 3GPP Release 13 to get eDRX and any other requirement like T34xx timers.

@nandojve
Copy link
Member

nandojve commented Nov 5, 2025

CC: @ceolin

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants