Arduino UNOへPN532をI2C接続してNFCネイルチップをLチカしてみた

# はじめに

NFCネイルチップをLチカするために前回はラズパイへRC-S310(ソニー製非接触ICカードリーダ/ライタ)を接続してサンプルプログラムを動かしました。

https://qiita.com/kitazaki/items/5ad8c6f6e48439d0088f

今回はArduinoへPN532(NFC RFIDリーダ/ライタモジュール)をI2Cで接続して動かしてみました。

![PN532_00.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/72479/c0762727-07e4-3ab8-7c1e-43f4a8f91faa.jpeg)

### PN532とは

NXP製のチップセットで、I2C、SPIおよびHSU(高速UART)で接続し、NFCモードまたはRFIDリーダライタモードで動作します。

![PN532.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/72479/26ba30bb-3116-2970-c15a-23c3d8c07a56.jpeg)

# 準備

基板の上についているDIPスイッチを変更してI2C接続に設定します。
基板上の印刷にはI2C接続の場合はDIPスイッチ1をON、スイッチ2をOFFに設定すると書かれています。

![PN532_01.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/72479/16995ded-c7cb-0423-a28c-16b9e3baea69.jpeg)

デフォルトではHSU(高速UART)接続に設定されていましたので、スイッチ1をONに変更しました。

![PN532_02.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/72479/08aade97-42a7-782c-a7ed-eb94f85b3b81.jpeg)

# 接続図

Arduino UNOとPN532を4本のジャンパー線(オス-メス)で接続します。
接続するピンは5V、GND、SDA、SCLです。

![スクリーンショット 2021-05-02 21.38.24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/72479/c614d5b7-2c16-2792-db45-d22ccafbd6c6.png)

# ソースコード

基本的にはサンプルコードのままで、I2C接続で動かすために、#if 0と#elif 0に変更して、#elseになるようにします。

<details>
<summary>ソースコード</summary>
<div>

```c++:
/**************************************************************************/
/*!
    This example will attempt to connect to an FeliCa
    card or tag and retrieve some basic information about it
    that can be used to determine what type of card it is.

    Note that you need the baud rate to be 115200 because we need to print
    out the data and read from the card at the same time!

    To enable debug message, define DEBUG in PN532/PN532_debug.h

 */
/**************************************************************************/
#include <Arduino.h>

#if 0
  #include <SPI.h>
  #include <PN532_SPI.h>
  #include <PN532.h>

PN532_SPI pn532spi(SPI, 10);
PN532 nfc(pn532spi);
#elif 0
  #include <PN532_HSU.h>
  #include <PN532.h>

PN532_HSU pn532hsu(Serial1);
PN532 nfc(pn532hsu);
#else
  #include <Wire.h>
  #include <PN532_I2C.h>
  #include <PN532.h>

PN532_I2C pn532i2c(Wire);
PN532 nfc(pn532i2c);
#endif

#include <PN532_debug.h>

uint8_t        _prevIDm[8];
unsigned long  _prevTime;

void PrintHex8(const uint8_t d) {
  Serial.print(" ");
  Serial.print( (d >> 4) & 0x0F, HEX);
  Serial.print( d & 0x0F, HEX);
}

void setup(void)
{
  Serial.begin(115200);
  Serial.println("Hello!");

  nfc.begin();

  uint32_t versiondata = nfc.getFirmwareVersion();
  if (!versiondata)
  {
    Serial.print("Didn't find PN53x board");
    while (1) {delay(10);};      // halt
  }

  // Got ok data, print it out!
  Serial.print("Found chip PN5"); Serial.println((versiondata >> 24) & 0xFF, HEX);
  Serial.print("Firmware ver. "); Serial.print((versiondata >> 16) & 0xFF, DEC);
  Serial.print('.'); Serial.println((versiondata >> 8) & 0xFF, DEC);

  // Set the max number of retry attempts to read from a card
  // This prevents us from waiting forever for a card, which is
  // the default behaviour of the PN532.
  nfc.setPassiveActivationRetries(0xFF);
  nfc.SAMConfig();

  memset(_prevIDm, 0, 8);
}

void loop(void)
{
  uint8_t ret;
  uint16_t systemCode = 0xFFFF;
  uint8_t requestCode = 0x01;       // System Code request
  uint8_t idm[8];
  uint8_t pmm[8];
  uint16_t systemCodeResponse;

  // Wait for an FeliCa type cards.
  // When one is found, some basic information such as IDm, PMm, and System Code are retrieved.
  Serial.print("Waiting for an FeliCa card...  ");
  ret = nfc.felica_Polling(systemCode, requestCode, idm, pmm, &systemCodeResponse, 5000);

  if (ret != 1)
  {
    Serial.println("Could not find a card");
    delay(500);
    return;
  }

  if ( memcmp(idm, _prevIDm, 8) == 0 ) {
    if ( (millis() - _prevTime) < 3000 ) {
      Serial.println("Same card");
      delay(500);
      return;
    }
  }

  Serial.println("Found a card!");
  Serial.print("  IDm: ");
  nfc.PrintHex(idm, 8);
  Serial.print("  PMm: ");
  nfc.PrintHex(pmm, 8);
  Serial.print("  System Code: ");
  Serial.print(systemCodeResponse, HEX);
  Serial.print("\n");

  memcpy(_prevIDm, idm, 8);
  _prevTime = millis();

  uint8_t blockData[3][16];
  uint16_t serviceCodeList[1];
  uint16_t blockList[3];

  Serial.println("Write Without Encryption command ");
  serviceCodeList[0] = 0x0009;
  blockList[0] = 0x8000;
  unsigned long now = millis();
  blockData[0][3] = now & 0xFF;
  blockData[0][2] = (now >>= 8) & 0xFF;
  blockData[0][1] = (now >>= 8) & 0xFF;
  blockData[0][0] = (now >>= 8) & 0xFF;
  Serial.print("   Writing current millis (");
  PrintHex8(blockData[0][0]);
  PrintHex8(blockData[0][1]);
  PrintHex8(blockData[0][2]);
  PrintHex8(blockData[0][3]);
  Serial.print(" ) to Block 0 -> ");
  ret = nfc.felica_WriteWithoutEncryption(1, serviceCodeList, 1, blockList, blockData);
  if (ret != 1)
  {
    Serial.println("error");
  } else {
    Serial.println("OK!");
  }
  memset(blockData[0], 0, 16);

  Serial.print("Read Without Encryption command -> ");
  serviceCodeList[0] = 0x000B;
  blockList[0] = 0x8000;
  blockList[1] = 0x8001;
  blockList[2] = 0x8002;
  ret = nfc.felica_ReadWithoutEncryption(1, serviceCodeList, 3, blockList, blockData);
  if (ret != 1)
  {
    Serial.println("error");
  } else {
    Serial.println("OK!");
    for(int i=0; i<3; i++ ) {
      Serial.print("  Block no. "); Serial.print(i, DEC); Serial.print(": ");
      nfc.PrintHex(blockData[i], 16);
    }
  }

  // Wait 1 second before continuing
  Serial.println("Card access completed!\n");
  delay(1000);
}
```

</div></details>

ソースコードはGithubにも置いておきます。

https://github.com/kitazaki/Arduino_UNO-PN532_I2C