[STM32H7] STM32H7S78-DK驱动SPI接口WIFI模块(EMW3080)

[复制链接]
 楼主| sujingliang 发表于 2025-5-13 15:45 | 显示全部楼层 |阅读模式
本帖最后由 sujingliang 于 2025-5-15 20:19 编辑

起源

在去年STM32H7S78-DK开发板评测中,随套件而来的有一个WI-FI Module (EMW3080-BP) MB1400。
不同常见的WI-FI串口模块,这个模块是基于SPI接口通信。当时就想把它驱动了,但是找遍了例程和application都没有相关资料。倒是凭着ST官方论坛上的互动的只言片语中发现STM32H573I-DK有这款WI-FI模块驱动例程,位置大概在:
C:\Users\用户名\STM32Cube\Repository\STM32Cube_FW_H5_V1.3.0\Projects\STM32H573I-DK\Applications\NetXDuo\Nx_Network_Basics_wifi
由于当时时间紧张,并且能力有限,没有在评测期间在STM32H7S78-DK上的移植。于是一直搁置了,而想要实现对这个WI-FI  SPI接口模块驱动的想法从来没有改变

2.png

3.png
SPI接口的WI-FI模块

本来想着
今年有幸入围STM32N6570-DK的评测,正好都具有STMOD+CONNECTOR,所以就想着不如在STM32N6570-DK实现对这款模块的驱动,也算了却一个心愿。
于是仿照STM32Cube_FW_H5_V1.3.0的Nx_Network_Basics_wifi例程开始搭建N6下的应用。开始并不顺利,由于对ThreadX、NetXDuo不了解,而且似乎串口重定向和程序有冲突也耽误了一些时间。最后程序调试通了,因为日志已经打印出来了,可以肉眼可见几个线程都跑起来了,似乎一切都向好的方向发展。但接上WI-FI模块,还是报错了无法连接,后来查看了一下STM32N6570-DK原理图,发现开发板上的STMOD+CONNECTOR引出的是串口,而非SPI,乌龙了。无法在STM32N6570-DK中实现驱动这个模块了。

偶然发现

尽管很乌龙,但是经过之前的磨难基本把STM32cubeMX配置和在KEIL中的编码流程搞清楚了,再到STM32H7S78-DK搭建应该是不成问题了。所以又回到原点,在STM32H7S78-DK中驱动这个模块。


照例打开STM32cubeMX,STM32H7RS软件包升级到v1.2.0,选择STM32H7S78-DK。突发奇想为什么每次都费时费力从空模板开始,为什么不从Start My project from Example开始一个工程,也许能解决一些时间。于是就发现虽然软件包的目录中没有WI-FI例程,但是MX例程中是存在WI-FI模块的例程。这难道就是众里寻他千百度,那人却在灯火阑珊处吗?我已顾不上各种复杂的心情,快速生成了工程,在经过漫长的编译,烧录后,验证一切功能正常,可以驱动了。


1.png

简单分析一下
这是生成的工程:
4.png
ThreadXThreadX是Express Logic公司开发的一款高性能实时操作系统(RTOS),现在由Microsoft维护。
NetXDuoNetX Duo 是 Azure RTOS(ThreadX)提供的 双协议栈(IPv4/IPv6)网络协议栈,专为嵌入式设备设计,支持 TCP/IP、UDP、DHCP、DNS 等协议,具有低内存占用和高实时性特点。
mx_wifi:WIFI模块驱动,其中包括spi接口的EMW3080。
FileX:在这里用来生成网页。


1、main.c主要部分
  1. int main(void)
  2. {

  3.   /* Initialize all configured peripherals */
  4.   MX_GPIO_Init();
  5.   MX_GPDMA1_Init();
  6.   MX_SPI4_Init();
  7.   MX_UART4_Init();
  8.   /* USER CODE BEGIN 2 */

  9.   /* USER CODE END 2 */

  10.   MX_ThreadX_Init();

  11.   while (1)
  12.   {
  13.   }

  14. }
MX_ThreadX_Init();//ThreadX初始化

2、app_threadx.c
  1. void MX_ThreadX_Init(void)
  2. {
  3.   /* USER CODE BEGIN  Before_Kernel_Start */

  4.   /* USER CODE END  Before_Kernel_Start */

  5.   tx_kernel_enter();

  6.   /* USER CODE BEGIN  Kernel_Start_Error */

  7.   /* USER CODE END  Kernel_Start_Error */
  8. }
tx_kernel_enter();//ThreadX入口

3、app_azure_rtos.c

VOID tx_application_define(VOID *first_unused_memory)
中调用了:
    status = MX_FileX_Init(memory_ptr);//处理网页读取
    status = MX_NetXDuo_Init(memory_ptr);//处理网络相关


4、app_netxduo.c

UINT MX_NetXDuo_Init(VOID *memory_ptr)
中执行了:
  ret = tx_thread_create(&AppMainThread, AppMainThreadName, App_Main_Thread_Entry,
                           (ULONG)byte_pool, stack_ptr, stack_size,
                           MAIN_THREAD_PRIORITY, MAIN_THREAD_PRIORITY, TX_NO_TIME_SLICE, TX_AUTO_START);

    ret = tx_thread_create(&AppMain2Thread, AppMain2ThreadName, App_Main2_Thread_Entry,
                           (ULONG)byte_pool, stack_ptr, stack_size,
                           MAIN2_THREAD_PRIORITY, MAIN2_THREAD_PRIORITY, TX_NO_TIME_SLICE, TX_AUTO_START);

    ret = tx_thread_create(&AppIperfThread, AppIperfThreadName, App_Iperf_Thread_Entry,
                           (ULONG)byte_pool, stack_ptr, stack_size,
                           APP_IPERF_THREAD_PRIORITY, APP_IPERF_THREAD_PRIORITY, TX_NO_TIME_SLICE, TX_DONT_START);

生成了几个线程,其中App_Iperf_Thread_Entry生成了一个Iperf网络测试界面供浏览器访问。
  1. static VOID App_Iperf_Thread_Entry(ULONG thread_input)
  2. {
  3.   TX_BYTE_POOL *const byte_pool = (TX_BYTE_POOL *) thread_input;

  4.   MSG_DEBUG("[%06" PRIu32 "]>\n", HAL_GetTick());

  5.   {
  6.     MSG_INFO(" - Device Name    : %s.\n", wifi_obj_get()->SysInfo.Product_Name);
  7.     MSG_INFO(" - Device ID      : %s.\n", wifi_obj_get()->SysInfo.Product_ID);
  8.     MSG_INFO(" - Device Version : %s.\n", wifi_obj_get()->SysInfo.FW_Rev);
  9.     MSG_INFO(" - MAC address    : %02X.%02X.%02X.%02X.%02X.%02X\n",
  10.              wifi_obj_get()->SysInfo.MAC[0], wifi_obj_get()->SysInfo.MAC[1],
  11.              wifi_obj_get()->SysInfo.MAC[2], wifi_obj_get()->SysInfo.MAC[3],
  12.              wifi_obj_get()->SysInfo.MAC[4], wifi_obj_get()->SysInfo.MAC[5]);
  13.   }


  14.   /* The network is correctly initialized, start the Iperf utility. */


  15.   /* Allocate the memory for HTTP and Iperf stack */
  16.   {
  17.     const ULONG http_stack_size = NX_IPERF_HTTP_STACK_SIZE;
  18.     UCHAR *http_stack;
  19.     const ULONG iperf_stack_size = NX_IPERF_STACK_SIZE;
  20.     UCHAR *iperf_stack;

  21.     if (tx_byte_allocate(byte_pool, (VOID **)&http_stack, http_stack_size, TX_NO_WAIT) != TX_SUCCESS)
  22.     {
  23.       MSG_ERROR("Allocation failed!\n");
  24.       Error_Handler();
  25.     }

  26.     if (tx_byte_allocate(byte_pool, (VOID **)&iperf_stack, iperf_stack_size, TX_NO_WAIT) != TX_SUCCESS)
  27.     {
  28.       MSG_ERROR("Allocation failed!\n");
  29.       Error_Handler();
  30.     }

  31.     MSG_INFO("\n##### Please open a browser window with the Target board's IP address\n\n");

  32.     /* Application body. */
  33.     nx_iperf_entry(&IperfPacketPool, &IpInstance, http_stack, http_stack_size, iperf_stack, iperf_stack_size);
  34.   }
  35. }
程序运行起来打印的日志:
6.png
浏览器访问返回:
5.png


5、与模块相关的配置:
mx_wifi_conf.h
  1. #define MX_WIFI_USE_SPI                             (1)


  2. #define WIFI_SSID                                   "SSID"
  3. #define WIFI_PASSWORD                   "PASSWORD"
6、网页内容定义
nx_iperf.h
  1. #define htmlresponse    "HTTP/1.0 200 \r\nContent-Type: text/html\r\n\r\n"
  2. #define htmltag         "<HTML>"
  3. #define htmlendtag      "</HTML>"
  4. #define titleline       "<HEAD><TITLE>NetX IPerf Demonstration</TITLE></HEAD>\r\n"

  5. #define bodytag         "<body bgcolor="#000000">\r\n"
  6. #define bodyendtag      "</body>\r\n"

  7. #define **_area                                   \
  8.     "<table border=0 align=center width=90%><tr>"   \
  9.     "<td width=30%><img align=left src=ms**.jpg>" \
  10.     "</td><td width=33%></td><td width=33%><img align=right src=nx**.png></td></tr></table>"

  11. #define hrline          "<HR SIZE=6 WIDTH="90%" NOSHADE COLOR="#FFFF00">"
  12. #define h1line1         " <H1><font face=arial color="#FFFFFF">NetX IP Address: "
  13. #define h1line2         "</font></H1><br>\r\n"
  14. #define tabletag        "<table height=50%>"


最后

由于个人能力有限,而且例程篇幅过长不做一一解读了,如果有兴趣可以通过MX生成代码解读。

SPI接口WIFI模块不常见,而且ST在实现上运用了ThreadX、NetXDuo等技术,而且封装了和模块通信的协议,再加上防御性编程,感觉远比驱动一般串口WFI模块复杂,甚至可以说不比直接通过WIFI模块二次开发简单。

终于跑通了,再无心魔,念头通达,修为又可以提升了。



地瓜patch 发表于 2025-5-26 16:51 来自手机 | 显示全部楼层
的确spi接口不常见,一般wifi模块都是串口+at指令实现,多快好省,开发简单
tpgf 发表于 2025-5-27 08:32 | 显示全部楼层
我们可以利用STLINK-V3E的串口调试功能,结合STM32CubeIDE的断点与变量监控
您需要登录后才可以回帖 登录 | 注册

本版积分规则

84

主题

148

帖子

3

粉丝
快速回复 在线客服 返回列表 返回顶部