文档结构  
翻译进度:已翻译     翻译赏金:0 元 (?)    ¥ 我要打赏

RFID和NFC十分的有趣,它们随处可见。为了研究项目,我探索了不同的RFID标签和方案。我拥有好几种类型的RFID和NFC很长一段时间了,但是我没有时间对他们进行实际的操作。昨晚,我想我应该尝试一下, 所以利用GNU ARM和Eclipse,我让它在恩智浦FRDM-K64F板子工作了。

NXP NFC PN7120S

NXP NFC PN7120S 和 FRDM-K64F 板子

我使用的是NXP工具套件 (PN7120 NFC Controller SBC Kit, OM5577/PN7120S) ,它适配BeagleBone板子和树莓派:

PN7120 NFC Controller SBC Kit OM5577 PN7120S

PN7120 NFC Controller SBC Kit OM5577 PN7120S

第 1 段(可获 1.34 积分)

还有另一个版本适用于Arduino的工具包 (详情看 https://community.nxp.com/docs/DOC-331907), 但是我没有使用它。使用BeagleBone和树莓派是以后做的事情。

我有几个可用的文章和教程, 但是由于种种原因,它们立即无法使用。 因此,,我最终决定制作自己制作特别的教程,在写教程的过程中,我有额外的收获,学到了很多关于如何使用该板子的知识,并解决了NXP应用说明和演示代码的问题。

材料

在这个教程里,我使用了以下的材料:

第 2 段(可获 1.28 积分)
  • Eclipse 和 GNU 工具(Kinetis Design Studio V3.2.0, 但是可以使用任何其他IDE或工具链): 详情看 NXP Kinetis Design Studio v3.2.0.
  • Kinetis SDK V2.0: 详情看Kinetis SDK V2.0.
  • Processor Expert 工具与 McuOnEclipse 组件(详情看 “McuOnEclipse Releases on SourceForge“).
  • NXP FRDM-K64F 板子(其他板子也可以使用).
  • NXP PN7120 控制板(PN7120 NFC Controller SBC 工具包).
  • RFID tags测试 (有两个RFID标签在上面的套件).
  • 导线和数据线

项目和资源发布于GitHub:

第 3 段(可获 1.16 积分)

NXP PN7120

NXP PN7120 是一个集成了ARM Cortex-M0的集成电路,它可以处理所有的射频通信和NFC相关协议:

PN7120 block diagram

PN7120 架构框图

它简化了我的设计,因为PN7120上的ARM Cortex-M0执行了所有的RF(射频)功能— 我可以利用其它单片机通过 I²C 与 M0 进行通信。 NXP提供了库与 PN7120 进行通信,这些库包含了完整的源码,例如“NfcLibrary”库。“NfcLibrary”库也是我要在我的应用程序中使用的。

硬件连接

I²C 作为NFC控制板的通信接口。该板子的侧边有以下的引脚:

第 4 段(可获 1.34 积分)

OM5577 schematics

OM5577 原理图

所以我需要连接电源(3.3V and GND), 和i2c接口(SCL and SDA), 以及一个外部中断引脚(IRQ),和一个输出引脚(VEN). 这些引脚在模块的两侧:

NFC Controller Board Top Side

NFC 控制板顶面

我使用了一个排针(header),将它侧插在模块的两边的插座(socket)上作为连接器,所以我不需要焊接任何东西:

NFC Module Bottom Side

NFC 模块的底面

下图是我连接到FRDM-K64F的接线图。我使用了以下的引脚:

  • 3.3V ==> 3.3V.
  • SCL  ==> PTE24 (I2C0).
  • SDA  ==> PTE23 (I2C0).
  • IRQ  ==> PTC4.
  • VEN  ==> PTC3.
  • GND  ==> GND.

NFC Controller Wiring

NFC 控制板接线图

第 5 段(可获 1.33 积分)

请注意,我现在使用的是一块RevA/Sch-RevC FRDM-K64F 的板子。新的板子需要交换SDA/SCL!

软件

http://cache.nxp.com/documents/software/SW3735.zip下载一个压缩包。

NFC Library

NFC 库

压缩包包含了NFC库和两个Kinetis SDK工程。因为这两个工程是独立的而且设置不对,所以这两个工程不能编译成功。我放弃了修复这他们。取而代之,我选择了新建一个工程。

创建一个新工程。

在Kinetis Design Studio V3.2.0,创建一个新工程需要按下File > New > Kinetis SDK V2.0 Project。

New Kinetis SDK Project

新建Kinetis SDK工程。

第 6 段(可获 1.28 积分)

在新建工程时,选中All drivers和FreeRTOS:

SDK Project Creation

创建SDK工程

NFC 库

从SW3735压缩包解压的KDSK2.0工程中,复制以下文件夹到新的项目中:

nfclibrary

Nfclibrary

  • NfcLibrary: PN7120协议栈.
  • TML: 传输映射层, 它实现了低级别的接口, 例如:中断处理和I²C通信。
  • Tool: 有一个延时函数(delay()).
  • Main.c: 此文件运行演示应用程序.

我把它们放到项目中,构建了相同的目录结构。 mian.c文件被替换成了zip包里面的文件。

第 7 段(可获 1.21 积分)

NFC Files in New Project

新工程中的 NFC 文件

Include 路径

因为我有添加头文件的文件夹,我需要告诉编译器在哪里可以找到它们。 我在编译器中添加以下项目属性的搜索路径:

../source/TML
../source/tool
../NfcLibrary/inc
../NfcLibrary/NdefLibrary/inc
../NfcLibrary/NxpNci/inc

Extended Include Paths

额外的头文件路径

预处理器定义

源文件使用了几个 #defines,,所以我将以下内容添加到项目设置中:

RW_SUPPORT
P2P_SUPPORT
CARDEMU_SUPPORT

支持以下定义(详情看 https://community.nxp.com/docs/DOC-331907):

第 8 段(可获 0.91 积分)
  • RW_SUPPORT: 在这个模式下,主机可以通过NFC控制器访问远程非接触式标签/卡。
  • P2P_SUPPORT: 主机MCU可以建立双向通信访问或发送数据到外部读写器。
  • CARDEMU_SUPPORT:NFC控制器主机(MCU)可以模拟非接触卡,它可以被外部的读/写器访问。
  • NCI-DEBUG: 如果定义了,在主机MCU和NFC控制器接口之间传送的所有的信息将会被回送到控制台用于调试。

禁用中断

第 9 段(可获 1.11 积分)

我们开始使用 FreeRTOS,,当我们启动调度程序时,使能中断。 我们必须确保中断被禁用,直到这一点。 然而,默认的启动代码在跳转到main()之前启用中断。 为了确保中断被禁用,我在startup/startup_MK64F12.S 中编辑并注释了“cpsie i”这行:

Not enabling interrupts in startup code

在启动代码不允许中断

引脚

在 board\board.h,,我为要用的引脚添加了以下定义:

/* NXPNCI NFC related declaration */
#define NXPNCI_I2C_INSTANCE         I2C0
#define NXPNCI_I2C_BAUDRATE         (100000)
#define NXPNCI_I2C_ADDR_7BIT         (0x28)
#if 1  /* use PTC4 instead of PTC12, because PTC12 might be on different pins depending on the FRDM-K64F board revision */
  #define NXPNCI_IRQ_PORTIRQn   PORTC_IRQn
  #define NXPNCI_IRQ_GPIO       (GPIOC)
  #define NXPNCI_IRQ_PORT       (PORTC)
  #define NXPNCI_IRQ_PIN        (4U)
#else /* original example uses PTC12 */
  #define NXPNCI_IRQ_PORTIRQn   PORTC_IRQn
  #define NXPNCI_IRQ_GPIO                (GPIOC)
  #define NXPNCI_IRQ_PORT                (PORTC)
  #define NXPNCI_IRQ_PIN                (12U)
#endif
#define NXPNCI_VEN_GPIO                (GPIOC)
#define NXPNCI_VEN_PORT                (PORTC)
#define NXPNCI_VEN_PIN                (3U)
第 10 段(可获 1.01 积分)

原始的示例使用的是PTC12(引脚),在FRDM-K64F开发板上映射到了不同的排针<pin>上,, 和板子的具体版本有关。这就是我为什么要改用PTC4的原因。

在 board\pinmux.c中,增加对这个头文件的include:

#include "board.h"

在BOARD_InitPins()函数中,增加:

    /* Declare and initialize for pull up configuration */
    port_pin_config_t pinConfig = {0};

#if 0 /* internal pull-up on I2C as workaround: do *not* use this for real! */
    pinConfig.pullSelect = kPORT_PullUp;
#if defined(FSL_FEATURE_PORT_HAS_OPEN_DRAIN) && FSL_FEATURE_PORT_HAS_OPEN_DRAIN
    pinConfig.openDrainEnable = kPORT_OpenDrainEnable;
#endif /* FSL_FEATURE_PORT_HAS_OPEN_DRAIN */
#endif
第 11 段(可获 0.55 积分)

原始代码中I²C总线使能了内部上拉电阻— 如果I²C总线没有上拉。内部上拉电阻通常是弱电阻,因此在大多数情况下不起作用,所以在依赖这一点时要小心。因为FRDM-K64F开发板的I2C0线路有上拉电阻,因此我们不需要这种解决方案。

为了配置这些引脚, 我在 BOARD_InitPins() 中添加了以下代码:

    /* Initialize I2C0 pins below */
    /* Ungate the port clock */
    CLOCK_EnableClock(kCLOCK_PortE);
    /* I2C0 pull up resistor setting */
    PORT_SetPinConfig(PORTE, 24U, &pinConfig);
    PORT_SetPinConfig(PORTE, 25U, &pinConfig);
    /* I2C0 PIN_MUX Configuration */
    PORT_SetPinMux(PORTE, 24U, kPORT_MuxAlt5);
    PORT_SetPinMux(PORTE, 25U, kPORT_MuxAlt5);

    /* Initialize NXPNCI GPIO pins below */
    /* Ungate the port clock */
    CLOCK_EnableClock(kCLOCK_PortC);
    /* IRQ and VEN PIN_MUX Configuration */
    PORT_SetPinMux(NXPNCI_IRQ_PORT, NXPNCI_IRQ_PIN, kPORT_MuxAsGpio);
    PORT_SetPinMux(NXPNCI_VEN_PORT, NXPNCI_VEN_PIN, kPORT_MuxAsGpio);
    /* IRQ interrupt Configuration */
    NVIC_SetPriority(NXPNCI_IRQ_PORTIRQn, 5);
    EnableIRQ(NXPNCI_IRQ_PORTIRQn);
    PORT_SetPinInterruptConfig(NXPNCI_IRQ_PORT, NXPNCI_IRQ_PIN, kPORT_InterruptRisingEdge);
第 12 段(可获 1.01 积分)

上述使能了时钟,I²C引脚复用,中断和GPIO口,并配置中断的优先级。

关于ARM Cortex-M的中断优先级和FreeRTOS,可以阅读“ARM Cortex-M, Interrupts and FreeRTOS: Part 1” 这一个特殊系列作为入门。

运行它…

在此,保存所有文件,建立它,并调试它。

打开一个终端/控制台,波特率使用 115200连接到开发板的OpenSDA UART端口,然后你应该看到这样的东西:

demo-app

示例程序

使用 PN7120 盒子上的标签贴纸:

Reading RFID with NXP FRDM-K64F Board

读取RFID与恩智浦FRDM-K64F开发板

它给出了这个输出:

第 13 段(可获 1.25 积分)

Ntag Message

Ntag消息

我也有一些 1K Mifare cards from Adafruit, 在这里,我可以读和写卡片:

mifare-1k-card

Mifare-1k-card

我现在能读写RFID卡。

读写RFID卡的能力取决于安全协议。 Mifare卡使用的协议已经损坏,详情看https://en.wikipedia.org/wiki/MIFARE.

Processor Expert

PN7120 可以使用 Kinetis SDK 工具,但是需要很多相当复杂的必要的步骤。使用 Processor Expert 不仅能够使它更容易更简单,而且也可以移植。此外,不是所有的 Kinetis 设备都支持 Kinetis SDK。

第 14 段(可获 1.34 积分)

我已经发表在Processor Expert 项目在 GitHub 上 .

步骤与 SDK 项目非常类似:

  1. 使用 Processor Expert 为开发板创建一个工程。
  2. 为项目添加NfcLibrary库,TML和工具文件夹。
  3. 为 SDK 工程添加预处定义。
  4. 向SDK项目添加与编译器设置相同的包含路径。
  5. 添加FreeRTOS。
  6. 为通信设备添加Shell组件(例如:串口或者 USB)。
  7. 为VEN添加BitIO(输出引脚)。
  8. 为模块的中断添加ExtInt,在上升沿触发。
  9. 为I²C通信添加 GenericI2C 组件。
第 15 段(可获 1.34 积分)

在这里,我用了基础的工程文件(我已经为RGB LED开发板添加了三个额外的组件):

processor-expert-project-for-pn7120

给pn7120的Processor-expert工程

因为最初的例程使用的是print()(哦,看这篇文章 “Why I don’t like printf()“)

在这个TML 代码中, 我替换了中断处理和 I²C读写例程,用Processor Expert 调用:

void PORTC_IRQHandler(void)
{
    BaseType_t xHigherPriorityTaskWoken = pdFALSE;
    xSemaphoreGiveFromISR(IrqSem, &xHigherPriorityTaskWoken);
}

static Status I2C_WRITE(uint8_t *pBuff, uint16_t buffLen)
{
    uint8_t res;

    GI2C1_SelectSlave(NXPNCI_I2C_ADDR_7BIT);
    res = GI2C1_WriteBlock(pBuff, buffLen, GI2C1_SEND_STOP);
    GI2C1_UnselectSlave();
    if (res==ERR_OK) {
        return SUCCESS;
    }
    return ERROR;
}

static Status I2C_READ(uint8_t *pBuff, uint16_t buffLen)
{
    uint8_t res;

    GI2C1_SelectSlave(NXPNCI_I2C_ADDR_7BIT);
    res = GI2C1_ReadBlock(pBuff, buffLen, GI2C1_SEND_STOP);
    GI2C1_UnselectSlave();
    if (res==ERR_OK) {
        return SUCCESS;
    }
    return ERROR;
}
第 16 段(可获 0.96 积分)

就是这样! 在我看来容易多了简单多了。我可以去掉所有的引脚配置和映射代码,因为Processor Expert接管了这些操作。

两个版本的对比

使用 Processor Expert 编写的项目不仅仅是更简单和运行得更快。将这两个运行同样功能的项目的代码和数据长度进行比较得到了一个耐人寻味的结果。 (没有打开编译器优化).

Kinetis SDK V2.0 版本:

arm-none-eabi-size --format=berkeley "FRDM-K64F_PN7120_SDK_v2.0.elf"
   text       data        bss        dec        hex    filename
  65012        340      15652      81004      13c6c    FRDM-K64F_PN7120_SDK_v2.0.elf
第 17 段(可获 0.83 积分)

Processor Expert版本:

arm-none-eabi-size --format=berkeley "FRDM-K64F_PN7120_PEx.elf"
   text       data        bss        dec        hex    filename
  36152        364       9108      45624       b238    FRDM-K64F_PN7120_PEx.elf

 Processor Expert版本需要的RAM (bss)明显少了很多, 主要是因为使用SDK的版本在堆和任务栈<heap and task stack>上花费了大量的RAM。除了这一点外<but>,SDK drivers的代码(text)长度几乎是Processor Expert 版本的两倍!

总结

我现在可以读和写 (! ) 几种RFID 卡和标签了。比如,我可以用这个项目来读取我的SwissPass 卡或者我的大学校园卡:

第 18 段(可获 1.04 积分)

Reading SwissPass

读取SwissPass

虽然 SDK V2.0工作起来一切正常,但和 Processor Expert相比需要几乎2倍的FLASH和 RAM 空间,主要原因是看起来使用了很多的抽象层的SDK驱动代码,示例代码使用了大量的RAM (我觉得主要是printf()?).

本文提到的Kinetis SDK项目已发布在GitHub上.

本文提到的Processor Expert 项目 已发布在GitHub上.

祝你RFID开发愉快!

第 19 段(可获 0.88 积分)

文章评论