nRF9160 PSM active time strange behaviour

Hello everyone!

I have just got started working with Nordic devices, in particular the nRF9160. I have been doing tests using the provided UDP sample from nRF Connect SDK and a nRF9160DK board.  I am connecting to Sweden's Telia network over LTE-M. I am using PSM and setting the active time (iDRX) to 20 seconds. However from the current consumption and terminal output of the device it seems that the modem is reentering cDRX mode and restarting the iDRX timer afterwards, although there is no data being sent to the nRF9160. The amount of reconnections also change from one transmission event to the next. I am still new to cellular networks and do not understand what can be going on here.

Best regards,

Tomás H.

 PSM with active time

Transmitting UDP/IP payload of 78 bytes to the IP address 213.185.10.144, port number 4000
RRC mode: Connected
RRC mode: Idle

RRC mode: Connected
RRC mode: Idle

RRC mode: Connected
RRC mode: Idle

RRC mode: Connected
RRC mode: Idle

RRC mode: Connected
RRC mode: Idle

Transmitting UDP/IP payload of 78 bytes to the IP address 213.185.10.144, port number 4000

Parents Reply Children
  • Hi Jonathan!

    I turned logging on and looked at the trace output with Wireshark. I can see that after sending data the modem receives a random amount of unintended TCP packets from several different sources. If this reception happens to be under the Active mode it triggers the modem back into RRC_CONNECTED state, as expected. I have no idea why these inbound TCP packets are being generated, but they would really impact the power consumption of my application. I attach the RAW and PCAP modem traces.

    trace-2022-02-16T16-14-57.136Z.bin      trace-2022-02-16T16-14-57.136Z.pcapng

    Best regards,

    Tomás

  • I dont think there should be any TCP traffic so this is strange, what modifications have you done to the UDP sample?

    Regards,
    Jonathan

  • Right now I am using an almost unmodified version of the UDP sample application. I have changed the proj.conf to modify transmission interval and server address, and to set up the desired PSM configuration and modem tracing. The only change in main.c has been adding some text to the data being send over UDP. I attach both files to the message. The server I communicate with is currently unavailable, but I tried using the default "8.8.8.8" Google server and obtained similar results.

    4645.prj.conf

    /*
     * Copyright (c) 2020 Nordic Semiconductor ASA
     *
     * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
     */
    
    #include <zephyr.h>
    #include <stdio.h>
    #include <modem/lte_lc.h>
    #include <net/socket.h>
    
    #define UDP_IP_HEADER_SIZE 28
    
    static int client_fd;
    static struct sockaddr_storage host_addr;
    static struct k_work_delayable server_transmission_work;
    
    K_SEM_DEFINE(lte_connected, 0, 1);
    
    static void server_transmission_work_fn(struct k_work *work)
    {
    	int err;
    	char buffer[CONFIG_UDP_DATA_UPLOAD_SIZE_BYTES] = {"Hello World\0"};
    
    	printk("Transmitting UDP/IP payload of %d bytes to the ",
    	       CONFIG_UDP_DATA_UPLOAD_SIZE_BYTES + UDP_IP_HEADER_SIZE);
    	printk("IP address %s, port number %d\n",
    	       CONFIG_UDP_SERVER_ADDRESS_STATIC,
    	       CONFIG_UDP_SERVER_PORT);
    
    	err = send(client_fd, buffer, sizeof(buffer), 0);
    	if (err < 0) {
    		printk("Failed to transmit UDP packet, %d\n", errno);
    		return;
    	}
    
    	k_work_schedule(&server_transmission_work,
    			K_SECONDS(CONFIG_UDP_DATA_UPLOAD_FREQUENCY_SECONDS));
    }
    
    static void work_init(void)
    {
    	k_work_init_delayable(&server_transmission_work,
    			      server_transmission_work_fn);
    }
    
    #if defined(CONFIG_NRF_MODEM_LIB)
    static void lte_handler(const struct lte_lc_evt *const evt)
    {
    	switch (evt->type) {
    	case LTE_LC_EVT_NW_REG_STATUS:
    		if ((evt->nw_reg_status != LTE_LC_NW_REG_REGISTERED_HOME) &&
    		     (evt->nw_reg_status != LTE_LC_NW_REG_REGISTERED_ROAMING)) {
    			break;
    		}
    
    		printk("Network registration status: %s\n",
    			evt->nw_reg_status == LTE_LC_NW_REG_REGISTERED_HOME ?
    			"Connected - home network" : "Connected - roaming\n");
    		k_sem_give(&lte_connected);
    		break;
    	case LTE_LC_EVT_PSM_UPDATE:
    		printk("PSM parameter update: TAU: %d, Active time: %d\n",
    			evt->psm_cfg.tau, evt->psm_cfg.active_time);
    		break;
    	case LTE_LC_EVT_EDRX_UPDATE: {
    		char log_buf[60];
    		ssize_t len;
    
    		len = snprintf(log_buf, sizeof(log_buf),
    			       "eDRX parameter update: eDRX: %f, PTW: %f\n",
    			       evt->edrx_cfg.edrx, evt->edrx_cfg.ptw);
    		if (len > 0) {
    			printk("%s\n", log_buf);
    		}
    		break;
    	}
    	case LTE_LC_EVT_RRC_UPDATE:
    		printk("RRC mode: %s\n",
    			evt->rrc_mode == LTE_LC_RRC_MODE_CONNECTED ?
    			"Connected" : "Idle\n");
    		break;
    	case LTE_LC_EVT_CELL_UPDATE:
    		printk("LTE cell changed: Cell ID: %d, Tracking area: %d\n",
    		       evt->cell.id, evt->cell.tac);
    		break;
    	default:
    		break;
    	}
    }
    
    static int configure_low_power(void)
    {
    	int err;
    
    #if defined(CONFIG_UDP_PSM_ENABLE)
    	/** Power Saving Mode */
    	err = lte_lc_psm_req(true);
    	if (err) {
    		printk("lte_lc_psm_req, error: %d\n", err);
    	}
    #else
    	err = lte_lc_psm_req(false);
    	if (err) {
    		printk("lte_lc_psm_req, error: %d\n", err);
    	}
    #endif
    
    #if defined(CONFIG_UDP_EDRX_ENABLE)
    	/** enhanced Discontinuous Reception */
    	err = lte_lc_edrx_req(true);
    	if (err) {
    		printk("lte_lc_edrx_req, error: %d\n", err);
    	}
    #else
    	err = lte_lc_edrx_req(false);
    	if (err) {
    		printk("lte_lc_edrx_req, error: %d\n", err);
    	}
    #endif
    
    #if defined(CONFIG_UDP_RAI_ENABLE)
    	/** Release Assistance Indication  */
    	err = lte_lc_rai_req(true);
    	if (err) {
    		printk("lte_lc_rai_req, error: %d\n", err);
    	}
    #endif
    
    	return err;
    }
    
    static void modem_init(void)
    {
    	int err;
    
    	if (IS_ENABLED(CONFIG_LTE_AUTO_INIT_AND_CONNECT)) {
    		/* Do nothing, modem is already configured and LTE connected. */
    	} else {
    		err = lte_lc_init();
    		if (err) {
    			printk("Modem initialization failed, error: %d\n", err);
    			return;
    		}
    	}
    }
    
    static void modem_connect(void)
    {
    	int err;
    
    	if (IS_ENABLED(CONFIG_LTE_AUTO_INIT_AND_CONNECT)) {
    		/* Do nothing, modem is already configured and LTE connected. */
    	} else {
    		err = lte_lc_connect_async(lte_handler);
    		if (err) {
    			printk("Connecting to LTE network failed, error: %d\n",
    			       err);
    			return;
    		}
    	}
    }
    #endif
    
    static void server_disconnect(void)
    {
    	(void)close(client_fd);
    }
    
    static int server_init(void)
    {
    	struct sockaddr_in *server4 = ((struct sockaddr_in *)&host_addr);
    
    	server4->sin_family = AF_INET;
    	server4->sin_port = htons(CONFIG_UDP_SERVER_PORT);
    
    	inet_pton(AF_INET, CONFIG_UDP_SERVER_ADDRESS_STATIC,
    		  &server4->sin_addr);
    
    	return 0;
    }
    
    static int server_connect(void)
    {
    	int err;
    
    	client_fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
    	if (client_fd < 0) {
    		printk("Failed to create UDP socket: %d\n", errno);
    		err = -errno;
    		goto error;
    	}
    
    	err = connect(client_fd, (struct sockaddr *)&host_addr,
    		      sizeof(struct sockaddr_in));
    	if (err < 0) {
    		printk("Connect failed : %d\n", errno);
    		goto error;
    	}
    
    	return 0;
    
    error:
    	server_disconnect();
    
    	return err;
    }
    
    void main(void)
    {
    	int err;
    
    	printk("UDP sample has started\n");
    
    	work_init();
    
    #if defined(CONFIG_NRF_MODEM_LIB)
    
    	/* Initialize the modem before calling configure_low_power(). This is
    	 * because the enabling of RAI is dependent on the
    	 * configured network mode which is set during modem initialization.
    	 */
    	modem_init();
    
    	err = configure_low_power();
    	if (err) {
    		printk("Unable to set low power configuration, error: %d\n",
    		       err);
    	}
    
    	modem_connect();
    
    	k_sem_take(&lte_connected, K_FOREVER);
    #endif
    
    	err = server_init();
    	if (err) {
    		printk("Not able to initialize UDP server connection\n");
    		return;
    	}
    
    	err = server_connect();
    	if (err) {
    		printk("Not able to connect to UDP server\n");
    		return;
    	}
    
    	k_work_schedule(&server_transmission_work, K_NO_WAIT);
    }
    

    Best regards,

    Tomás

Related