Funpack第二季第六期:NRF7002-DK
一、序言
funpack电子设计活动!这是一个专为电子爱好者和创客们打造的盛会。在这里,您可以探索电子设计的无限可能,与志同道合的人一起分享创意和经验。我们提供丰富多样的工作坊、讲座和展示,涵盖了从基础电路到高级项目的各个方面。无论您是初学者还是经验丰富的专业人士,funpack都将为您带来乐趣和学习的机会。加入我们,一起享受电子设计的魅力!
我这次参加的是Funpack第二季第六期:NRF7002-DK,实现了NFC打开一个视频的功能。
二、硬件介绍
根据官方权威介绍:
nRF7002 DK 是 nRF7002 和 nRF7001 Wi-Fi 6 协同 IC 的开发套件。它包含在单个板上开始开发所需的一切。DK 采用 nRF5340 多协议系统级芯片(SoC) 作为 nRF7002 的主机处理器。该DK 支持低功耗 Wi-Fi 应用的开发,并支持 Wi-Fi 6 功能,如 OFDMA、波束成形和目标唤醒时间。nRF7002 是一款 Wi-Fi 6 协同 IC,提供无缝连接和基于 Wi-Fi 的定位(本地 Wi-Fi 集线器的 SSID 嗅探)。它旨在与Nordic现有的nRF52®和nRF53®系列蓝牙系统级芯片(SoC)以及nRF91®系列蜂窝物联网系统级封装(SiP)一起使用。nRF7002 还可以与非Nordic主机设备结合使用。为了与主机通信,可以使用SPI或QSPI,并且额外的共存功能允许与其他协议(如蓝牙,线程或Zigbee)无缝共存。nRF7002已被Nordic nRF Connect SDK集成并支持,nRF7002 Dk也可用于模拟nRF7001。nRF7002是Nordic独特Wi-Fi产品组合中的第一款设备,它将与Nordic现有的超低功耗技术无缝结合。Nordic 将其数十年的超低功耗无线物联网和硅设计专业知识带到 Wi-Fi 中。Wi-Fi 6 为物联网应用带来了更多优势,包括进一步提高效率,支持长寿命的电池供电 Wi-Fi 操作。借助 Wi-Fi 6,Nordic 支持用于 Matter 的所有无线协议、用于调试的蓝牙 LE、用于低功耗网状网络的 Thread 以及用于高吞吐量的 Wi-Fi。Matter是苹果、亚马逊、谷歌、Nordic、三星和消费者物联网中数百家其他公司倡导的协议。
本人拿到板子后的感受是:精致、人性化、遥遥领先!
PCB是沉金工艺,高端大气上档次。背面有详细的丝印说明,将以人为本的思想落到实处。Nordic Semiconductor (简称 Nordic)成立于1983年,是全球领先的集成电路硬件及软件供应商。公司致力于无线物联网系统级芯片的研发、设计与销售,并开创了超低功耗无线技术的先河,成为无线技术领域的代表性企业。作为无线技术的先行者,Nordic同时也是 ANT+联盟、蓝牙技术联盟(SIG)、Thread Group、Zigbee联盟、Wi-Fi联盟和全球移动通信系统协会(GSMA)的重要成员,遥遥领先!
先看靓照正面+背面。
再看实现功能后的效果图,看红箭头,这个是手机读到了NFC的信息跳出的弹窗。
三、开发环境介绍
开发环境是官方工具+VScode。说句实在话,环境配置困了我好久。没有群友的指导,我可能无法完成这次活动。下面我们来认识一下官方工具:
SDK说明
Nordic BLE 目前有两个SDK,nRF5 SDK和NCS。nRF5 SDK,这个是以前的BLE产品线用的,目前已经进入只维护阶段,不再加新功能。NCS,最新的SDK,它整合了Nordic所有无线芯片,包括BLE系列产品。所以有新的默认用新的,用NCS进行开发环境的搭建。
什么是NCS
NCS全称 nRF Connect SDK,是一个开源的软件开发套件(SDK),由Nordic Semiconductor公司开发和维护,旨在支持基于其nRF系列芯片的物联网应用程序的开发。nRF Connect SDK包含了一系列的软件组件和库,包括操作系统、通信协议、硬件抽象层、设备驱动程序等,以及一些示例应用程序,可以快速地开发各种物联网应用程序。nRF Connect SDK支持多种编程语言,包括C、C++和Python等。nRF Connect SDK还提供了一些工具,如编译器、调试器、仿真器和配置工具等,以帮助开发人员进行开发和调试。此外,nRF Connect SDK还提供了与Nordic的开发板和工具集成的支持,使得开发人员可以方便地进行硬件和软件的联合开发。总之,nRF Connect SDK是一种强大而灵活的开发工具,可以帮助开发人员快速地开发出高质量的物联网应用程序,并加速物联网产品的上市时间。
什么是Zephyr
Zephyr是目前在NCS中采用的系统,和FreeROTS、uCOS类似,这里简单说明一下。Zephyr是一个基于Apache 2.0开源的实时操作系统(RTOS),专门用于嵌入式系统和物联网设备。它的特点是具有低功耗、小内存占用、支持多种通信协议(如BLE、Zigbee、WiFi、LoRa等)、实时性和安全性。
四、设计思路与过程
- step1、深刻领悟项目需求与选题要求。我选的奋斗方向是任务三:使用板卡的NFC功能,模拟出一个自定义功能的卡片,使用手机靠近并能读取卡片信息。需要学习的内容有NFC基础知识、NRF7002-DK的NFC实现方法。
- step2、NFC基础知识。NFC的中文全称为近场通信技术。
NFC是一种短距高频的无线电技术,NFCIP-1标准规定NFC的通信距离为10厘米以内,运行频率13.56MHz,传输速度有106Kbit/s、212Kbit/s或者424Kbit/s三种。NFCIP-1标准详细规定NFC设备的传输速度、编解码方法、调制方案以及射频接口的帧格式,此标准中还定义了NFC的传输协议,其中包括启动协议和数据交换方法等。
NFC工作模式分为被动模式和主动模式。被动模式中NFC发起设备(也称为主设备)需要供电设备,主设备利用供电设备的能量来提供射频场,并将数据发送到NFC目标设备(也称作从设备),传输速率需在106kbps、212kbps或424kbps中选择其中一种。从设备不产生射频场,所以可以不需要供电设备,而是利用主设备产生的射频场转换为电能,为从设备的电路供电,接收主设备发送的数据,并且利用负载调制(load modulation)技术,以相同的速度将从设备数据传回主设备。因为此工作模式下从设备不产生射频场,而是被动接收主设备产生的射频场,所以被称作被动模式,在此模式下,NFC主设备可以检测非接触式卡或NFC目标设备,与之建立连接。
主动模式中,发起设备和目标设备在向对方发送数据时,都必须主动产生射频场,所以称为主动模式,它们都需要供电设备来提供产生射频场的能量。这种通信模式是对等网络通信的标准模式,可以获得非常快速的连接速率。
NFC标准为了和非接触式智能卡兼容,规定了一种灵活的网关系统,具体分为三种工作模式:点对点通信模式、读写器模式和NFC卡模拟模式。
我们着重了解卡模拟形式:模拟卡片模式,这种模式就是将具有NFC功能的设备模拟成一张标签或非接触卡,例如支持NFC的手机可以作为门禁卡、银行卡等而被读取。 - step3、NRF7002-DK的NFC实现。硬件基础是nRF5340+nRF天线。可实现性见下图。 在官方例程中也有相关可用的函数。如nfc_t2t_setup、nfc_launchapp_msg_encode等等。
- step4、验证开发板的NFC硬件功能是否正常。
使用官方最容易实现的一个example:NFC Records text,一路按官网给的guide点点点,成功烧录。
到App Store下载NFC tools并安装,扫描NRF7002-DK的NFC,得到信息。成功了!!!如图 - step5、制作本次目标程序和测试。
先阅读例程launchapp代码,了解代码执行流程。然后发现只要修改URL就可以实现功能。接着我就去网上找我喜欢的URL,经过千挑万选,终于选定了这个让我热泪盈眶的视频——《我将无我,不负人民》。
XXX : DO YOU“愿意做到一个‘无我’的状态,为中国的发展奉献自己。”?
SOME LIKE ME : YES, I DO.
然后按函数要求的格式填入。
烧录。。。。。。。。。。。。。【OK】
测试。。。。。。。。。。。。。【OK】
录视频。。。。。。。。。。。。【OK】
写文档,等待审核。。。。。。。【FAIL】
写文档,等待审核。。。。。。。
五、代码介绍(附录有完整代码)
看到例程是利用URL编码规则来打开一个app,我就想是不是可以利用这一点来打开一个视频链接呢?结果是YES
然后就开始动手了。
首先,说一个对功能实现非常重要的量static const uint8_t universal_link[],它是你手机NFC扫描了NRF7002-DK后要打开的链接。一定要写对,并注意字符的分割。否则到处怀疑找bug非常费时间。
static const uint8_t universal_link[] = {'h', 't', 't', 'p', 's', ':', '/', '/', 't', 'v', '.', 'c', 'c', 't', 'v', '.', 'c', 'o', 'm', '/', '2', '0', '2', '1', '/', '0', '2', '/', '1', '8', '/', 'V', 'I', 'D', 'E', '6', 'V', 'm', 'Y', 'i', 'd', 'Y', 'L', 'T', 'M', '6', '2', '9', 'R', 'q', 'f', '5', 'H', 'I', 'R', '2', '1', '0', '2', '1', '8', '.', 's', 'h', 't', 'm', 'l', '?', 's', 'p', 'm', '=', 'C', '5', '5', '9', '5', '3', '8', '7', '7', '1', '5', '1', '.','P', 'X', 'X', 'w', 'e', 'f', 'e', 'H', 'c', 'O', 'A', 'R', '.', '0', '.', '0'};
其次是nfc_launchapp_msg_encode这个函数。
Int nfc_launchapp_msg_encode(
uint8_t *android_package_name,
uint32_t android_package_name_len,
const uint8_t *universal_link,
uint32_t universal_link_len,
uint8_t *buf,
size_t *len)
功能是用于编码NFC NDEF启动应用程序消息的函数。这个函数将NFC NDEF消息编码到缓冲区中。
参数:
android_package_name - Android包名字符串指针。如果为NULL, Android应用记录将被跳过。
android_package_name_len - Android包名的长度。
universal_link -指向通用链接字符串的指针。如果为NULL,将跳过通用链接记录。
universal_link_len -通用链路长度。
buf-指向消息缓冲区的指针。
len -作为输入的消息可用内存的大小。作为输出的生成消息的大小。
返回值:
如果消息创建成功,则为0。
-EINVAL如果android_package_name_len和universal_link都无效(等于NULL)。
如果预测的消息大于提供的缓冲区空间,则使用enomem。
/* Set up NFC */
err = nfc_t2t_setup(nfc_callback, NULL);
if (err) {
printk("Cannot setup NFC T2T library!\n");
goto fail;
}
err = nfc_t2t_setup(nfc_callback, NULL);是初始化NFC并设置callback函数。当NFC被配置时将调用callback。异常时err=1,并打印异常。
/* Encode launch app data */
err = nfc_launchapp_msg_encode(android_pkg_name,
sizeof(android_pkg_name),
universal_link,
sizeof(universal_link),
ndef_msg_buf,
&len);
if (err) {
printk("Cannot encode message!\n");
goto fail;
}
err = nfc_launchapp_msg_encode函数将对目标URL进行编码,并将编码储存到msg_buf数组中。
/* Set created message as the NFC payload */
err = nfc_t2t_payload_set(ndef_msg_buf, len);
if (err) {
printk("Cannot set payload!\n");
goto fail;
}
err = nfc_t2t_payload_set(ndef_msg_buf, len); 将message(msg_buf)load到NFC控制器
下面是这个工程的工作示意图和main函数的流程图。
其他代码可能根据nfc_ndef_msg_encode和nfc_ndef_msg_record_add函数返回
剩下的代码就是一些比较容易理解的常规代码了。
六、致谢
尊敬的eetree团队,我想借这个机会向eetree团队表达我最诚挚的感谢。感谢您提供了这次宝贵的机会,让我能够参加这次活动。这次活动不仅让我有机会与电子设计的专业人士们交流和学习,更让我结识了一群志同道合的朋友。首先,我要感谢您和eetree团队的辛勤努力和精心策划。您们为这次活动的安排提供了一切必要的支持和资源,使我们能够全神贯注地参与。活动的议程安排得非常合理,让我们能够学习到最新的技术知识和行业趋势。同时,我要特别感谢那些和我一起参加活动的朋友们。与你们共同度过的这段时间,给我留下了深刻的印象。我们之间的交流和互动让我受益匪浅。我很荣幸能与你们一起分享我们的想法、经验和知识。通过参加这次活动,我不仅加深了对电子设计领域的理解,还学习到了许多实用的技巧和方法。与专业人士的交流让我得以进一步拓宽我的视野,并为我未来的发展提供了很多有价值的参考。最重要的是,我从这次活动中深刻体会到了团队合作和互助的重要性。大家相互帮助、鼓励和支持,这让我感受到了团队的力量和凝聚力。我将把这份团队精神带回我的日常工作与我一同参加活动的朋友们。我相信这次活动将在我的职业生涯中留下美好的回忆,并对我的个人成长产生积极的影响。衷心感谢!
七、附录
#include <zephyr/kernel.h>
#include <zephyr/sys/reboot.h>
#include <nfc_t2t_lib.h>
#include <nfc/ndef/launchapp_msg.h>
#include <dk_buttons_and_leds.h>
#define NDEF_MSG_BUF_SIZE 256
#define NFC_FIELD_LED DK_LED1
/** .. include_startingpoint_pkg_def_launchapp_rst */
/* Package: no.nordicsemi.android.nrftoolbox */
static const uint8_t android_pkg_name[] = {
'I', ' ', 'w', 'i', 'l', 'l', ' ', 'l', 'i', 'v', 'e', ' ', 'u', 'p', ' ',
't', 'o', ' ', 't', 'h', 'e', ' ', 'p', 'e', 'o', 'p', 'l', 'e', ' ', 'w',
'i', 't', 'h', 'o', 'u', 't', ' ', 'm', 'y', 's', 'e', 'l', 'f' };
/* URI nrf-toolbox://main/ */
static const uint8_t universal_link[] = {
'h', 't', 't', 'p', 's', ':', '/', '/', 't', 'v', '.', 'c', 'c', 't', 'v', '.', 'c', 'o', 'm', '/',
'2', '0', '2', '1', '/', '0', '2', '/', '1', '8', '/', 'V', 'I', 'D', 'E', '6', 'V', 'm', 'Y', 'i', 'd',
'Y', 'L', 'T', 'M', '6', '2', '9', 'R', 'q', 'f', '5', 'H', 'I', 'R', '2', '1', '0', '2', '1', '8', '.',
's', 'h', 't', 'm', 'l', '?', 's', 'p', 'm', '=', 'C', '5', '5', '9', '5', '3', '8', '7', '7', '1', '5', '1', '.',
'P', 'X', 'X', 'w', 'e', 'f', 'e', 'H', 'c', 'O', 'A', 'R', '.', '0', '.', '0'
/*'h', 't', 't', 'p', 's', ':', '/', '/', 'w', 'w', 'w', '.',
'b', 'i', 'l', 'i', 'b', 'i', 'l', 'i', '.', 'c', 'o', 'm',
'/', 'b', 'a', 'n', 'g', 'u', 'm', 'i', '/', 'p', 'l', 'a',
'y', '/', 'e', 'p', '4', '5', '4', '1', '4', '0', '?', 's',
'p', 'm', '_', 'i', 'd', '_', 'f', 'r', 'o', 'm', '=', '3',
'3', '3', '.', '3', '3', '7', '.', '0', '.', '0'*/
};
// 'i', 'o', 's', 'a', 'm', 'a', 'p', ':', '/', '/'};
/** .. include_endpoint_pkg_def_launchapp_rst */
/* Buffer used to hold an NFC NDEF message. */
static uint8_t ndef_msg_buf[NDEF_MSG_BUF_SIZE];
static void nfc_callback(void *context,
nfc_t2t_event_t event,
const uint8_t *data,
size_t data_length)
{
ARG_UNUSED(context);
ARG_UNUSED(data);
ARG_UNUSED(data_length);
switch (event) {
case NFC_T2T_EVENT_FIELD_ON:
dk_set_led_on(NFC_FIELD_LED);
break;
case NFC_T2T_EVENT_FIELD_OFF:
dk_set_led_off(NFC_FIELD_LED);
break;
default:
break;
}
}
int main(void)
{
int err;
size_t len = sizeof(ndef_msg_buf);
printk("Starting NFC Launch app example\n");
/* Configure LED-pins as outputs */
err = dk_leds_init();
if (err) {
printk("Cannot init LEDs!\n");
goto fail;
}
/* Set up NFC */
err = nfc_t2t_setup(nfc_callback, NULL);
if (err) {
printk("Cannot setup NFC T2T library!\n");
goto fail;
}
/* Encode launch app data */
err = nfc_launchapp_msg_encode(android_pkg_name,
sizeof(android_pkg_name),
universal_link,
sizeof(universal_link),
ndef_msg_buf,
&len);
if (err) {
printk("Cannot encode message!\n");
goto fail;
}
/* Set created message as the NFC payload */
err = nfc_t2t_payload_set(ndef_msg_buf, len);
if (err) {
printk("Cannot set payload!\n");
goto fail;
}
/* Start sensing NFC field */
err = nfc_t2t_emulation_start();
if (err) {
printk("Cannot start emulation!\n");
goto fail;
}
printk("NFC configuration done\n");
return 0;
fail:
#if CONFIG_REBOOT
sys_reboot(SYS_REBOOT_COLD);
#endif /* CONFIG_REBOOT */
return err;
}