Pico W基于C/C++ SDK适配RT-Thread Wi-Fi经验总结

电子说

1.2w人已加入

描述

前言:

Pico W 作为 Raspberry Pi Pico 的衍生版本,主要增加了无线通信的功能,通过搭载 CYW43439 无线芯片,支持 2.4 GHz Wi-Fi 4 及蓝牙5.0 ,其余和 Raspberry Pi Pico 基本相同,外部引脚也相互兼容。

也可以参考我之前文章中介绍的使用 Clion 搭建开发调试下载环境,同样适用。这里需要注意的一点是,当你首次烧录使板载 LED 闪烁的程序时,开发板可能没有相应的现象,这可能不是你下载失败了,也不是你的开发板是坏的,而是 Pico W 的板载 LED 由无线模块控制

准备工作

开发环境搭建完成后,接下来就可以根据树莓派官方的 SDK 和 Example 调一调程序,逐渐梳理清楚逻辑和各模块之间的依赖关系。例如先运行一个最简单的 Wi-Fi scan 的示例程序,其主要逻辑是先 cyw43_arch_init() 初始化模块,再通过 cyw43_arch_enable_sta_mode() 使能为 STA 模式,最后使用cyw43_wifi_scan() 开始扫描并注册扫描完成回调函数打印扫描结果,整体的逻辑和 API 还是很简洁明了的。

开始开发

主要有以下三种类型:poll , threadsafe_background, freertos 。poll 是需要用户定期调用的,并且不保证线程安全性;threadsafe_background 和 freertos 能够保证线程安全性,threadsafe_background 不使用 RTOS,通过低优先级的 ISR 实现调度同步,freertos 是通过专门的线程处理调动同步。

一开始我选择的是基于 threadsafe_background 进行开发,通过参照以上 Cmake 关系图很快就成功在 RT-Thread 的 Bsp 中复现了 Wi-Fi scan 示例程序。但是开发后续需要使用 lwip 的功能时,与 RT-Thread 就产生了很多冲突。

想要更好的适配 RT-Thread 还是得按照 RTOS 的来,于是开始复现官方提供的基于 FreeRTOS 的,首先想到的是使用 RT-Thread 的 FreeRTOS 兼容层软件包,在 menuconfig 中使能即可:

Wi-Fi技术

引入兼容层后大部分报错消失了,但报错没有 portCHECK_IF_IN_ISR 的相关实现,在 FreeRTOS 的源码中查找发现其为 RP2040 特有的实现。其是用于判断上下文环境是否处于中断中,改为 RT-Thread 中的检测中断 nest 是否大于 0 即可。

成功编译下载程序后,却因为定时器进入了 hardfault ,检查发现 FreeRTOS 兼容层中的 portMAX_DEALY 对接错了,不是 RT_TICK_MAX ,应该为 RT_TICK_MAX / 2 - 1(韦东山老师在rtt开发者大会上专门讲解过 RTT 优雅的定时器算法,感兴趣可以看看)这个问题目前已经修复了。

之后程序还是进入 hardfault ,一直 debug 对比代码没有发现问题,再次分析对比 FreeRTOS 和 RT-Thread 之间的差异,两者的优先级等级和数值的关系是相反的,检查发现 async_context_task 线程的优先级为 tskIDLE_PRIORITY + 4 在 FreeRTOS 中优先级比空闲线程高4,但在 RT-Thread 中因为优先级太低,得不到调度,造成死锁问题。解决办法是将其线程优先级提高。

移植 RT-Thread

以上的示例程序跑通以后,就开始将 wifi freertos 的相关的文件移植为 RT-Thread 。主要包含以下内容:

替换头文件:

用 RT-Thread 的头文件替换 FreeRTOS 的头文件。

修改任务创建和管理:

使用 RT-Thread 的任务创建和管理 API 替代 FreeRTOS 的任务 API。

注意 RT-Thread 的任务入口函数参数和返回值的差异。

修改互斥锁:

替换 xSemaphoreCreateRecursiveMutex 为 RT-Thread 提供的互斥锁创建 API。

替换 xSemaphoreTakeRecursive 和 xSemaphoreGiveRecursive 为 RT-Thread 互斥锁的 API。

替换定时器:

使用 RT-Thread 的软定时器或者实时时钟服务替代 FreeRTOS 定时器。

任务通知:

替换 FreeRTOS 的任务通知 API 为 RT-Thread 的事件和信号量等。

任务挂起和唤醒:

替换 FreeRTOS 的 vTaskSuspend 和 vTaskResume 为 RT-Thread 的任务挂起和唤醒 API
主要涉及 async_context_rtthread,cyw43_arch,cyw43_arch_rtthread,lwip_rtthread这些文件,基础的移植完成后,就可以开始将其对接到 RT-Thread 的 Wi-Fi 设备驱动框架了,主要参考 rw007 和 cyw43012-RTT 的对接。需要使能 RT-Thread 的 lwip 和 SAL 等组件。
需要注意的一点是 RT-Thread 的 lwip 组件使能后,已经包含了 lwip 的初始化,cyw43_arch_init() 中的 lwip 初始化相关注释即可,否则重复初始化会因为完成量无法获取造成阻塞。

#if CYW43_LWIP
// ok &= lwip_rtthread_init(context);
#endif
// 重复初始化信号量无法获取造成阻塞
bool lwip_rtthread_init(async_context_t *context) {
RT_ASSERT(!lwip_context);
lwip_context = context;
static bool done_lwip_init;
if (!done_lwip_init) {
done_lwip_init = true;
rt_sem_t init_sem = rt_sem_create("lwip_init_sem", 0, RT_IPC_FLAG_PRIO);
tcpip_task_blocker = rt_sem_create("tcpip_task_blocker", 0, RT_IPC_FLAG_PRIO);
tcpip_init(tcpip_init_done, init_sem);
// 阻塞在信号量获取
rt_sem_take(init_sem, RT_TICK_MAX / 2 - 1);
rt_sem_delete(init_sem);
} else {
rt_sem_release(tcpip_task_blocker);
}
return true;
}

运行过程中可能会报错提示 lwip 线程栈空间不足,在 menuconfig 中适当改大即可

Wi-Fi技术

对接完成后测试功能,使能为 STA 模式,日志中显示 mac 地址

Wi-Fi技术

扫描附近ap

Wi-Fi技术

连接ap并成功ping通

Wi-Fi技术

测试ap功能,使能为AP模式,设置名称及pwd,可以使用手机成功连接。

注意事项

使用pico w的无线模块需要使用一些相关的宏定义,如无线模块的引脚定义等,其定义在 picow.h 中。但程序默认包含的是 pico.h 。可以通过定义宏 PICO_CONFIG_HEADER=boards/pico_w.h 进行切换。

吞吐量还未进行测试。

目前基于 C/C++ SDK 的开发案例较少,推荐直接阅读官方文档。

在对接设备驱动框架 wifi_join 方法时苦恼于 ap 的 channel 和 bssid 没有正常传递,查看源码发现使能 RT_WLAN_JOIN_SCAN_BY_MGNT
这个宏可以先扫描ap,并传递包含 channel 和 bssid 的 info,但要将以下改为rt_memcpy

Wi-Fi技术

个人理解,没有找到其他的说明和用例。(不过最后发现,连接ap没有 channel 和 bssid 也行,直接设置为 RT_NULL )

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分