Some time ago I asked why the combination of nRF52840 and nRF7002 does not work.
How do I build with the combination of nrf52840 and nrf7002? I get an error.
I decided that it would not work with the current SDK 2.5.2, so I gave up.
(Needless to say, I have patched the SDK bug fixes that were mentioned in the reference thread. Then gave up.)
It seems difficult to run with nRF52840, so I plan to use a combination of Raytac's MDBT53V (nRF5340) and Fanstel's WM02C (nRF7002). It doesn't require wireless authentication.
https://www.raytac.com/product/ins.php?index_id=135
https://www.fanstel.com/nrf7002wifi6module
We already have a sample project that has been tested with nRF7002DK. The project is below.
/* * Copyright (c) 2012-2014 Wind River Systems, Inc. * * SPDX-License-Identifier: Apache-2.0 */ #include <dk_buttons_and_leds.h> #include <stdio.h> #include <zephyr/kernel.h> #include <zephyr/logging/log.h> #include <zephyr/net/net_if.h> #include <zephyr/net/wifi_mgmt.h> LOG_MODULE_REGISTER(main, LOG_LEVEL_INF); #define NET_EVENT_WIFI_EVENTS ( \ NET_EVENT_WIFI_SCAN_RESULT | \ NET_EVENT_WIFI_SCAN_DONE | \ NET_EVENT_WIFI_CONNECT_RESULT | \ NET_EVENT_WIFI_DISCONNECT_RESULT | \ NET_EVENT_WIFI_IFACE_STATUS | \ NET_EVENT_WIFI_TWT | \ NET_EVENT_WIFI_TWT_SLEEP_STATE | \ NET_EVENT_WIFI_RAW_SCAN_RESULT | \ NET_EVENT_WIFI_DISCONNECT_COMPLETE \ ) #define NET_EVENT_IPV4_EVENTS ( \ NET_EVENT_IPV4_ADDR_ADD | \ NET_EVENT_IPV4_ADDR_DEL | \ NET_EVENT_IPV4_MADDR_ADD | \ NET_EVENT_IPV4_MADDR_DEL | \ NET_EVENT_IPV4_ROUTER_ADD | \ NET_EVENT_IPV4_ROUTER_DEL | \ NET_EVENT_IPV4_DHCP_START | \ NET_EVENT_IPV4_DHCP_BOUND | \ NET_EVENT_IPV4_DHCP_STOP | \ NET_EVENT_IPV4_MCAST_JOIN | \ NET_EVENT_IPV4_MCAST_LEAVE \ ) // for User queue(s) static struct k_work_q uq_button; K_THREAD_STACK_DEFINE(us_button, 512); // Semaphore(s) K_SEM_DEFINE(sem_udp_send, 0, 1); K_SEM_DEFINE(sem_udp_send_wait, 0, 1); // Variable(s) static struct net_mgmt_event_callback wifi_shell_mgmt_cb; static struct net_mgmt_event_callback net_shell_mgmt_cb; static struct net_context *udp_ctx; static char *host = "xxx.xxx.xxx.xxx"; static uint16_t port = 12345; static uint8_t packet[32]; /* ----- Timer Function Start ----- */ static void udp_rcvd(struct net_context *context, struct net_pkt *pkt, union net_ip_header *ip_hdr, union net_proto_header *proto_hdr, int status, void *user_data) { if (pkt) { size_t len = net_pkt_remaining_data(pkt); uint8_t byte; LOG_INF("Received UDP packet: "); for (size_t i = 0; i < len; ++i) { net_pkt_read_u8(pkt, &byte); LOG_INF("%02x ", byte); } net_pkt_unref(pkt); } } static void udp_sent(struct net_context *context, int status, void *user_data) { ARG_UNUSED(context); ARG_UNUSED(status); ARG_UNUSED(user_data); LOG_DBG("Message sent"); k_sem_give(&sem_udp_send_wait); } static void timer_handler(struct k_timer *timer) { // Send k_sem_give(&sem_udp_send); } K_TIMER_DEFINE(timer, timer_handler, NULL); /* ----- Timer Function End ----- */ static void wifi_disconnect_work_handler(struct k_work *work) { struct net_if *iface; // Parameter(s) iface = net_if_get_default(); // Connect if (net_mgmt(NET_REQUEST_WIFI_CONNECT, iface, NULL, 0)) { LOG_ERR("Disconnection request failed."); } } K_WORK_DELAYABLE_DEFINE(wifi_disconnect, wifi_disconnect_work_handler); static void wifi_connect_work_handler(struct k_work *work) { struct net_if *iface; struct wifi_connect_req_params cnx_params; // if (context.connected) { // LOG_WRN("Already connected."); // return; // } // Parameter(s) iface = net_if_get_default(); cnx_params.timeout = 30; cnx_params.ssid = "ssid"; cnx_params.ssid_length = strlen(cnx_params.ssid); cnx_params.security = WIFI_SECURITY_TYPE_PSK; cnx_params.psk = "password"; cnx_params.psk_length = strlen(cnx_params.psk); cnx_params.channel = WIFI_CHANNEL_ANY; cnx_params.mfp = WIFI_MFP_OPTIONAL; // Connect if (net_mgmt(NET_REQUEST_WIFI_CONNECT, iface, &cnx_params, sizeof(struct wifi_connect_req_params))) { LOG_ERR("Connection request failed."); } } K_WORK_DELAYABLE_DEFINE(wifi_connect, wifi_connect_work_handler); 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_ADDR_ADD: LOG_INF("NET_EVENT_IPV4_ADDR_ADD"); break; case NET_EVENT_IPV4_ADDR_DEL: LOG_INF("NET_EVENT_IPV4_ADDR_DEL"); break; case NET_EVENT_IPV4_MADDR_ADD: LOG_INF("NET_EVENT_IPV4_MADDR_ADD"); break; case NET_EVENT_IPV4_MADDR_DEL: LOG_INF("NET_EVENT_IPV4_MADDR_DEL"); break; case NET_EVENT_IPV4_ROUTER_ADD: LOG_INF("NET_EVENT_IPV4_ROUTER_ADD"); break; case NET_EVENT_IPV4_ROUTER_DEL: LOG_INF("NET_EVENT_IPV4_ROUTER_DEL"); break; case NET_EVENT_IPV4_DHCP_START: LOG_INF("NET_EVENT_IPV4_DHCP_START"); break; case NET_EVENT_IPV4_DHCP_BOUND: LOG_INF("NET_EVENT_IPV4_DHCP_BOUND"); print_dhcp_ip(cb); k_timer_start(&timer, K_NO_WAIT, K_MSEC(100)); break; case NET_EVENT_IPV4_DHCP_STOP: LOG_INF("NET_EVENT_IPV4_DHCP_STOP"); break; case NET_EVENT_IPV4_MCAST_JOIN: LOG_INF("NET_EVENT_IPV4_MCAST_JOIN"); break; case NET_EVENT_IPV4_MCAST_LEAVE: LOG_INF("NET_EVENT_IPV4_MCAST_LEAVE"); break; default: LOG_INF("NET_EVENT_IPV4_OTHER"); break; } } static void handle_wifi_disconnect_result(struct net_mgmt_event_callback *cb) { const struct wifi_status *status = (const struct wifi_status *) cb->info; LOG_INF("Disconnection request %s (%d)", status->status ? "failed" : "done", status->status); } static void handle_wifi_connect_result(struct net_mgmt_event_callback *cb) { const struct wifi_status *status = (const struct wifi_status *) cb->info; if (status->status) { LOG_ERR("Connection failed.(%d)", status->status); } else { LOG_INF("Connected"); } } // Callback 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_SCAN_RESULT: LOG_INF("NET_EVENT_WIFI_SCAN_RESULT"); break; case NET_EVENT_WIFI_SCAN_DONE: LOG_INF("NET_EVENT_WIFI_SCAN_DONE"); break; case NET_EVENT_WIFI_CONNECT_RESULT: LOG_INF("NET_EVENT_WIFI_CONNECT_RESULT"); handle_wifi_connect_result(cb); break; case NET_EVENT_WIFI_DISCONNECT_RESULT: LOG_INF("NET_EVENT_WIFI_DISCONNECT_RESULT"); handle_wifi_disconnect_result(cb); break; case NET_EVENT_WIFI_IFACE_STATUS: LOG_INF("NET_EVENT_WIFI_IFACE_STATUS"); break; case NET_EVENT_WIFI_TWT: LOG_INF("NET_EVENT_WIFI_TWT"); break; case NET_EVENT_WIFI_TWT_SLEEP_STATE: LOG_INF("NET_EVENT_WIFI_TWT_SLEEP_STATE"); break; case NET_EVENT_WIFI_RAW_SCAN_RESULT: LOG_INF("NET_EVENT_WIFI_RAW_SCAN_RESULT"); break; case NET_EVENT_WIFI_DISCONNECT_COMPLETE: LOG_INF("NET_EVENT_WIFI_DISCONNECT_COMPLETE"); break; default: LOG_WRN("NET_EVENT_WIFI_OTHER"); break; } } static void button_holding_work_handler(struct k_work *work) { LOG_INF("Button holding!"); } K_WORK_DELAYABLE_DEFINE(button_holding, button_holding_work_handler); void button_changed(uint32_t button_state, uint32_t has_changed) { if (has_changed & 0x01) { if (button_state & has_changed) { LOG_DBG("button 0 changes to on"); // WiFi connect k_work_schedule(&wifi_connect, K_NO_WAIT); // Long push k_work_schedule_for_queue(&uq_button, &button_holding, K_MSEC(2000)); } else { LOG_DBG("button 0 changes to off."); k_work_cancel_delayable(&button_holding); } } #if DT_NODE_EXISTS(DT_ALIAS(sw1)) if (has_changed & 0x02) { if (button_state & has_changed) { LOG_DBG("button 1 changes to on"); // WiFi disconnect k_work_schedule(&wifi_disconnect, K_NO_WAIT); // Long push k_work_schedule_for_queue(&uq_button, &button_holding, K_MSEC(2000)); } else { LOG_DBG("button 1 changes to off."); k_work_cancel_delayable(&button_holding); } } #endif #if DT_NODE_EXISTS(DT_ALIAS(sw2)) if (has_changed & 0x04) { if (button_state & has_changed) { LOG_INF("button 2 changes to on"); } else { LOG_INF("button 2 changes to off."); } } #endif #if DT_NODE_EXISTS(DT_ALIAS(sw3)) if (has_changed & 0x08) { if (button_state & has_changed) { LOG_INF("button 3 changes to on"); } else { LOG_INF("button 3 changes to off."); } } #endif } int main(void) { int err, ret; struct net_if *iface; struct sockaddr addr; int addrlen; // Initialize variable(s) memset(packet, 0x31, sizeof(packet)); // Initialize Buttons and LEDs err = dk_buttons_init(button_changed); if (err) { LOG_ERR("Failed to initialize button[s].(%d)", err); return -1; } err = dk_leds_init(); if (err) { LOG_ERR("Failed to initialize led[s].(%d)", err); return -1; } // User queue for button holding k_work_queue_start(&uq_button, us_button, K_THREAD_STACK_SIZEOF(us_button), K_PRIO_PREEMPT(0), NULL); // WiFi callback net_mgmt_init_event_callback(&wifi_shell_mgmt_cb, wifi_mgmt_event_handler, NET_EVENT_WIFI_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_EVENTS); net_mgmt_add_event_callback(&net_shell_mgmt_cb); while (true) { if (!k_sem_take(&sem_udp_send, K_MSEC(500))) { if (udp_ctx && net_context_is_used(udp_ctx)) { LOG_WRN("Network context already in use"); continue; } memset(&addr, 0, sizeof(addr)); ret = net_ipaddr_parse(host, strlen(host), &addr); if (ret < 0) { LOG_WRN("Cannot parse address \"%s\"", host); continue; } ret = net_context_get(addr.sa_family, SOCK_DGRAM, IPPROTO_UDP, &udp_ctx); if (ret < 0) { LOG_WRN("Cannot get UDP context.(%d)", ret); continue; } if (IS_ENABLED(CONFIG_NET_IPV4) && addr.sa_family == AF_INET) { net_sin(&addr)->sin_port = htons(port); addrlen = sizeof(struct sockaddr_in); iface = net_if_ipv4_select_src_iface(&net_sin(&addr)->sin_addr); } else { LOG_WRN("IPv4 is disabled, cannot %s.", "send"); goto release_ctx; } if (!iface) { LOG_WRN("No interface to send to given host"); goto release_ctx; } net_context_set_iface(udp_ctx, iface); ret = net_context_recv(udp_ctx, udp_rcvd, K_NO_WAIT, NULL); if (ret < 0) { LOG_WRN("Setting rcv callback failed (%d)", ret); goto release_ctx; } ret = net_context_sendto(udp_ctx, packet, sizeof(packet), &addr, addrlen, udp_sent, K_FOREVER, NULL); if (ret < 0) { LOG_WRN("Sending packet failed (%d)", ret); goto release_ctx; } ret = k_sem_take(&sem_udp_send_wait, K_SECONDS(2)); if (ret == -EAGAIN) { LOG_WRN("UDP packet sending failed"); } release_ctx: ret = net_context_put(udp_ctx); if (ret < 0) { LOG_WRN("Cannot put UDP context (%d)", ret); } } } }
CONFIG_WIFI=y CONFIG_NET_L2_ETHERNET=y CONFIG_NET_IPV6=n CONFIG_HEAP_MEM_POOL_SIZE=153600 CONFIG_MAIN_STACK_SIZE=4096 CONFIG_SYSTEM_WORKQUEUE_STACK_SIZE=4096 CONFIG_WPA_SUPP=y CONFIG_WPA_SUPP_ADVANCED_FEATURES=n CONFIG_WPA_SUPP_WPA3=n CONFIG_DK_LIBRARY=y CONFIG_WIFI_NRF700X=y CONFIG_NET_TX_STACK_SIZE=8192 CONFIG_NET_RX_STACK_SIZE=8192 CONFIG_USE_SEGGER_RTT=y CONFIG_FLASH=y CONFIG_COMMON_LIBC_MALLOC=n CONFIG_DEBUG_THREAD_INFO=y CONFIG_NVS=y CONFIG_LOG_PROCESS_THREAD_SLEEP_MS=100 CONFIG_NETWORKING=y CONFIG_NET_IPV4=y CONFIG_NET_DHCPV4=y CONFIG_NET_TCP=y CONFIG_NET_LOG=y CONFIG_NET_CONN_LOG_LEVEL_INF=y CONFIG_NET_CONFIG_INIT_TIMEOUT=0 CONFIG_NET_CONFIG_SETTINGS=y CONFIG_SETTINGS=y CONFIG_FLASH_MAP=y CONFIG_DEBUG_OPTIMIZATIONS=y
In addition, a script to receive UDP in Python is also attached. (Sorry, Japanese is used in some parts.)
import socket import threading import time def receive_data(): while True: data, addr = udp_socket.recvfrom(1024) message = data.decode() print(f"受信したデータ: {message}") print(f"送信元アドレス: {addr}") listen_ip = "" listen_port = 12345 udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) udp_socket.bind((listen_ip, listen_port)) receiver_thread = threading.Thread(target=receive_data) receiver_thread.daemon = True receiver_thread.start() # ここでメインスレッドで他の処理を実行できます while True: try: # print("Thread: " + str(receiver_thread.is_alive())) time.sleep(0.5) pass except KeyboardInterrupt: print('Interrupted.') break
The problem is that this sample project does not work on the Fanstel evaluation board.
https://www.fanstel.com/buy/ev-bt840f-evaluation-board-for-bt840f-6bk4n-98fsj-9b346
I purchased this evaluation board.
Here is the schematic of the Fanstel evaluation board, and as far as I can see it has the same connections as the nRF7002DK. In other words, Fanstel's evaluation board is compatible with the nRF7002DK. The only difference is that they have individual antennas instead of a common one. Hence the P1.10 GPIOs are not used on the Fanstel evaluation board.
I can't think of any reason why the Fanstel evaluation board wouldn't work. Are these two boards incompatible, even though they have the same I/O connections?