Dear Devzone-Team,
I am working on an nRF7002 based IoT Sensor using the nRF7002DK. I managed to set up the WiFi in STA mode and connect to Raspberry Pi working as AP. The nRF7002 should act as a UDP Client and send data to the AP. I managed to set up the socket and the communication to the Raspberry is working.
Now the problem:
When I look at the measurements with the Power Profiler Kit II there is too much power consumption in my opinion. Without UDP transmissions I have roughly the power consumption mentioned in Operating in power save modes and Target Wake Time on the nRF7002 DK for the normal DTIM Mode.
However, it seems that for the UDP transmissions it takes a long time until the sleep mode is activated again (~60mA for around 150ms). Please look at the attached figure from the PPK2, where you can see the UDP transmissions every 1s. The narrow spikes are the DTIM and the broader ones (~150ms) are when the UDP transmission is started.
Maybe you can help me to reduce the power of the UDP transmissions to the absolute minimum. (Maybe the nRF7002 waits for an response by the AP?)
Here is the main file:
/* * Copyright (c) 2022 Nordic Semiconductor ASA * * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause */ /** @file * @brief WiFi station sample */ #include <zephyr/logging/log.h> LOG_MODULE_REGISTER(sta, CONFIG_LOG_DEFAULT_LEVEL); #include <nrfx_clock.h> #include <zephyr/kernel.h> #include <stdio.h> #include <stdlib.h> #include <zephyr/shell/shell.h> #include <zephyr/sys/printk.h> #include <zephyr/init.h> #include <zephyr/net/net_if.h> #include <zephyr/net/wifi_mgmt.h> #include <zephyr/net/net_event.h> #include <zephyr/drivers/gpio.h> #include <zephyr/net/wifi.h> #include <qspi_if.h> #include <zephyr/net/socket.h> #include <unistd.h> #include "net_private.h" #define WIFI_SHELL_MODULE "wifi" #define WIFI_SHELL_MGMT_EVENTS (NET_EVENT_WIFI_CONNECT_RESULT | \ NET_EVENT_WIFI_DISCONNECT_RESULT) #define MAX_SSID_LEN 32 #define DHCP_TIMEOUT 70 #define CONNECTION_TIMEOUT 100 #define STATUS_POLLING_MS 300 /* 1000 msec = 1 sec */ #define LED_SLEEP_TIME_MS 100 /* The devicetree node identifier for the "led0" alias. */ #define LED0_NODE DT_ALIAS(led0) #define UDP_CLIENT_PORT 4242 // Tasks: //! Wifi thread priority level #define WIFI_STACK_SIZE 4096 //! Wifi thread priority level #define WIFI_PRIORITY 4 //! WiFi stack definition K_THREAD_STACK_DEFINE(WIFI_STACK, WIFI_STACK_SIZE); //! Variable to identify the Wifi thread static struct k_thread wifiThread; #define SENSOR_DATA_LENGTH 1000 struct sensorData { uint16_t frame_number; uint8_t data[SENSOR_DATA_LENGTH]; }; struct sensorData transmit_data; void fillArrayWithRandom(uint8_t *array, uint16_t size) { for (uint16_t i = 0; i < size; i++) { array[i] = (uint8_t)rand(); // Fill each element with a random value } } /* * A build error on this line means your board is unsupported. * See the sample documentation for information on how to fix this. */ static const struct gpio_dt_spec led = GPIO_DT_SPEC_GET(LED0_NODE, gpios); static struct net_mgmt_event_callback wifi_shell_mgmt_cb; static struct net_mgmt_event_callback net_shell_mgmt_cb; static struct { const struct shell *sh; union { struct { uint8_t connected : 1; uint8_t connect_result : 1; uint8_t disconnect_requested : 1; uint8_t _unused : 5; }; uint8_t all; }; } context; void toggle_led(void) { int ret; if (!device_is_ready(led.port)) { LOG_ERR("LED device is not ready"); return; } ret = gpio_pin_configure_dt(&led, GPIO_OUTPUT_ACTIVE); if (ret < 0) { LOG_ERR("Error %d: failed to configure LED pin", ret); return; } while (1) { if (context.connected) { gpio_pin_toggle_dt(&led); k_msleep(LED_SLEEP_TIME_MS); } else { gpio_pin_set_dt(&led, 0); k_msleep(LED_SLEEP_TIME_MS); } } } K_THREAD_DEFINE(led_thread_id, 1024, toggle_led, NULL, NULL, NULL, 7, 0, 0); static int cmd_wifi_status(void) { struct net_if *iface = net_if_get_default(); struct wifi_iface_status status = { 0 }; if (net_mgmt(NET_REQUEST_WIFI_IFACE_STATUS, iface, &status, sizeof(struct wifi_iface_status))) { LOG_INF("Status request failed"); return -ENOEXEC; } LOG_INF("=================="); LOG_INF("State: %s", wifi_state_txt(status.state)); if (status.state >= WIFI_STATE_ASSOCIATED) { uint8_t mac_string_buf[sizeof("xx:xx:xx:xx:xx:xx")]; LOG_INF("Interface Mode: %s", wifi_mode_txt(status.iface_mode)); LOG_INF("Link Mode: %s", wifi_link_mode_txt(status.link_mode)); LOG_INF("SSID: %-32s", status.ssid); LOG_INF("BSSID: %s", net_sprint_ll_addr_buf( status.bssid, WIFI_MAC_ADDR_LEN, mac_string_buf, sizeof(mac_string_buf))); LOG_INF("Band: %s", wifi_band_txt(status.band)); LOG_INF("Channel: %d", status.channel); LOG_INF("Security: %s", wifi_security_txt(status.security)); LOG_INF("MFP: %s", wifi_mfp_txt(status.mfp)); LOG_INF("RSSI: %d", status.rssi); } return 0; } static void handle_wifi_connect_result(struct net_mgmt_event_callback *cb) { const struct wifi_status *status = (const struct wifi_status *) cb->info; if (context.connected) { return; } if (status->status) { LOG_ERR("Connection failed (%d)", status->status); } else { LOG_INF("Connected"); context.connected = true; } context.connect_result = true; } static void handle_wifi_disconnect_result(struct net_mgmt_event_callback *cb) { const struct wifi_status *status = (const struct wifi_status *) cb->info; if (!context.connected) { return; } if (context.disconnect_requested) { LOG_INF("Disconnection request %s (%d)", status->status ? "failed" : "done", status->status); context.disconnect_requested = false; } else { LOG_INF("Received Disconnected"); context.connected = false; } cmd_wifi_status(); } static void wifi_mgmt_event_handler(struct net_mgmt_event_callback *cb, uint32_t mgmt_event, struct net_if *iface) { switch (mgmt_event) { case NET_EVENT_WIFI_CONNECT_RESULT: handle_wifi_connect_result(cb); break; case NET_EVENT_WIFI_DISCONNECT_RESULT: handle_wifi_disconnect_result(cb); break; default: break; } } static void print_dhcp_ip(struct net_mgmt_event_callback *cb) { /* Get DHCP info from struct net_if_dhcpv4 and print */ const struct net_if_dhcpv4 *dhcpv4 = cb->info; const struct in_addr *addr = &dhcpv4->requested_ip; char dhcp_info[128]; net_addr_ntop(AF_INET, addr, dhcp_info, sizeof(dhcp_info)); LOG_INF("DHCP IP address: %s", dhcp_info); } static void net_mgmt_event_handler(struct net_mgmt_event_callback *cb, uint32_t mgmt_event, struct net_if *iface) { switch (mgmt_event) { case NET_EVENT_IPV4_DHCP_BOUND: print_dhcp_ip(cb); break; default: break; } } static int __wifi_args_to_params(struct wifi_connect_req_params *params) { params->timeout = SYS_FOREVER_MS; /* SSID */ params->ssid = CONFIG_STA_SAMPLE_SSID; params->ssid_length = strlen(params->ssid); #if defined(CONFIG_STA_KEY_MGMT_WPA2) params->security = 1; #elif defined(CONFIG_STA_KEY_MGMT_WPA2_256) params->security = 2; #elif defined(CONFIG_STA_KEY_MGMT_WPA3) params->security = 3; #else params->security = 0; #endif #if !defined(CONFIG_STA_KEY_MGMT_NONE) params->psk = CONFIG_STA_SAMPLE_PASSWORD; params->psk_length = strlen(params->psk); #endif params->channel = WIFI_CHANNEL_ANY; /* MFP (optional) */ params->mfp = WIFI_MFP_OPTIONAL; return 0; } static int wifi_connect(void) { struct net_if *iface = net_if_get_default(); static struct wifi_connect_req_params cnx_params; context.connected = false; context.connect_result = false; __wifi_args_to_params(&cnx_params); if (net_mgmt(NET_REQUEST_WIFI_CONNECT, iface, &cnx_params, sizeof(struct wifi_connect_req_params))) { LOG_ERR("Connection request failed"); return -ENOEXEC; } LOG_INF("Connection requested"); return 0; } int bytes_from_str(const char *str, uint8_t *bytes, size_t bytes_len) { size_t i; char byte_str[3]; if (strlen(str) != bytes_len * 2) { LOG_ERR("Invalid string length: %zu (expected: %d)\n", strlen(str), bytes_len * 2); return -EINVAL; } for (i = 0; i < bytes_len; i++) { memcpy(byte_str, str + i * 2, 2); byte_str[2] = '\0'; bytes[i] = strtol(byte_str, NULL, 16); } return 0; } int Wifi_Stationing(void) { int i; memset(&context, 0, sizeof(context)); net_mgmt_init_event_callback(&wifi_shell_mgmt_cb, wifi_mgmt_event_handler,WIFI_SHELL_MGMT_EVENTS); net_mgmt_add_event_callback(&wifi_shell_mgmt_cb); net_mgmt_init_event_callback(&net_shell_mgmt_cb,net_mgmt_event_handler,NET_EVENT_IPV4_DHCP_BOUND); net_mgmt_add_event_callback(&net_shell_mgmt_cb); LOG_INF("Starting %s with CPU frequency: %d MHz", CONFIG_BOARD, SystemCoreClock/MHZ(1)); k_sleep(K_SECONDS(1)); LOG_INF("Static IP address (overridable): %s/%s -> %s", CONFIG_NET_CONFIG_MY_IPV4_ADDR, CONFIG_NET_CONFIG_MY_IPV4_NETMASK, CONFIG_NET_CONFIG_MY_IPV4_GW); while (1) { wifi_connect(); for (i = 0; i < CONNECTION_TIMEOUT; i++) { k_sleep(K_MSEC(STATUS_POLLING_MS)); cmd_wifi_status(); if (context.connect_result) { break; } } if (context.connected) { k_sleep(K_FOREVER); } else if (!context.connect_result) { LOG_ERR("Connection Timed Out"); } } return 0; } int udpClientSocket; struct sockaddr_in serverAddress; void UDP_Client(uint8_t* connected_flag) { int connectionResult; int sentBytes = 0; // Starve the thread until a DHCP IP is assigned to the board while( !context.connected ){ k_msleep( 100 ); } // Server IPV4 address configuration serverAddress.sin_family = AF_INET; serverAddress.sin_port = htons( UDP_CLIENT_PORT ); zsock_inet_pton( \ AF_INET, \ "192.168.1.1", \ &serverAddress.sin_addr ); // Client socket creation udpClientSocket = zsock_socket( \ serverAddress.sin_family, \ SOCK_DGRAM, \ IPPROTO_UDP ); \ if ( udpClientSocket < 0 ) { LOG_ERR( "UDP Client error: socket: %d\n", errno ); k_sleep( K_FOREVER ); } // Connection to the server. connectionResult = connect( \ udpClientSocket, \ ( struct sockaddr * )&serverAddress, \ sizeof( serverAddress )); if ( connectionResult < 0 ) { LOG_ERR( "UDP Client error: connect: %d\n", errno ); k_sleep( K_FOREVER ); } LOG_INF( "UDP Client connected correctly" ); *connected_flag = 1; } int main(void) { // START THE WIFI CONNECTION THREAD k_thread_create ( \ &wifiThread, \ WIFI_STACK, \ WIFI_STACK_SIZE, \ (k_thread_entry_t)Wifi_Stationing, \ NULL, \ NULL, \ NULL, \ WIFI_PRIORITY, \ 0, \ K_NO_WAIT); k_thread_name_set(&wifiThread, "wifiStationing"); k_thread_start(&wifiThread); while( !context.connected ){ k_msleep( 1000 ); } LOG_INF("Connection Worked"); uint8_t client_connected = 0; UDP_Client(&client_connected); LOG_INF("wait until client is connected"); while(client_connected == 0){ k_msleep( 500 ); } LOG_INF("Client is connected -> start transmitting data"); // struct wifi_ps_params params = { 0 }; // params.wakeup_mode = WIFI_PS_WAKEUP_MODE_LISTEN_INTERVAL; // params.type = WIFI_PS_PARAM_WAKEUP_MODE; // struct net_if *iface = net_if_get_default(); // net_mgmt(NET_REQUEST_WIFI_PS, iface, ¶ms, sizeof(params)); uint32_t counter = 0; while(1){ transmit_data.frame_number = counter; fillArrayWithRandom(transmit_data.data, SENSOR_DATA_LENGTH); send(udpClientSocket, (uint8_t* ) &transmit_data, sizeof(transmit_data), 0); //sendto(udpClientSocket, (uint8_t* ) &transmit_data, sizeof(transmit_data), 0,( struct sockaddr * )&serverAddress, sizeof( serverAddress )); counter++; k_msleep( 1000 ); } }
and the prj.conf
# # Copyright (c) 2022 Nordic Semiconductor ASA # # SPDX-License-Identifier: LicenseRef-Nordic-5-Clause # CONFIG_WIFI=y CONFIG_WIFI_NRF700X=y # WPA supplicant CONFIG_WPA_SUPP=y # Below configs need to be modified based on security # CONFIG_STA_KEY_MGMT_NONE=y CONFIG_STA_KEY_MGMT_WPA2=y # CONFIG_STA_KEY_MGMT_WPA2_256=y # CONFIG_STA_KEY_MGMT_WPA3=y CONFIG_STA_SAMPLE_SSID="RSPILAN" CONFIG_STA_SAMPLE_PASSWORD="silicon123" # System settings CONFIG_NEWLIB_LIBC=y CONFIG_NEWLIB_LIBC_NANO=n # Networking CONFIG_NETWORKING=y CONFIG_NET_SOCKETS=y CONFIG_NET_LOG=y CONFIG_NET_IPV4=y CONFIG_NET_UDP=y CONFIG_NET_TCP=y CONFIG_NET_DHCPV4=y CONFIG_NET_PKT_RX_COUNT=8 CONFIG_NET_PKT_TX_COUNT=8 # Below section is the primary contributor to SRAM and is currently # tuned for performance, but this will be revisited in the future. CONFIG_NET_BUF_RX_COUNT=16 CONFIG_NET_BUF_TX_COUNT=16 CONFIG_NET_BUF_DATA_SIZE=128 CONFIG_HEAP_MEM_POOL_SIZE=153600 CONFIG_NET_TC_TX_COUNT=0 CONFIG_NET_IF_UNICAST_IPV4_ADDR_COUNT=1 CONFIG_NET_MAX_CONTEXTS=5 CONFIG_NET_CONTEXT_SYNC_RECV=y CONFIG_INIT_STACKS=y CONFIG_NET_L2_ETHERNET=y CONFIG_NET_CONFIG_SETTINGS=y CONFIG_NET_SOCKETS_POLL_MAX=4 # Memories CONFIG_MAIN_STACK_SIZE=4096 CONFIG_SYSTEM_WORKQUEUE_STACK_SIZE=2048 CONFIG_NET_TX_STACK_SIZE=4096 CONFIG_NET_RX_STACK_SIZE=4096 # Debugging CONFIG_STACK_SENTINEL=y CONFIG_DEBUG_COREDUMP=y CONFIG_DEBUG_COREDUMP_BACKEND_LOGGING=y CONFIG_DEBUG_COREDUMP_MEMORY_DUMP_MIN=y CONFIG_SHELL_CMDS_RESIZE=n # Kernel options CONFIG_ENTROPY_GENERATOR=y # Logging CONFIG_LOG=y CONFIG_LOG_BUFFER_SIZE=2048 CONFIG_POSIX_CLOCK=y CONFIG_PM=y CONFIG_NET_CONFIG_MY_IPV4_ADDR="192.168.1.99" CONFIG_NET_CONFIG_MY_IPV4_NETMASK="255.255.255.0" CONFIG_NET_CONFIG_MY_IPV4_GW="192.168.1.1" # printing of scan results puts pressure on queues in new locking # design in net_mgmt. So, use a higher timeout for a crowded # environment. CONFIG_NET_MGMT_EVENT_QUEUE_TIMEOUT=5000 CONFIG_NET_SOCKETS_POSIX_NAMES=y CONFIG_POSIX_MAX_FDS=9
I am using nrf connect sdk v2.4.1 currently.
Thanks in advance
Julian