👥

How to use multiple MFRC522 devices on Wio Terminal

に公開

Wio Terminalで複数のMFRC522を制御する

ArduinoRFIDとの組み合わせでしばしば用いられるMFRC522ですが、一度に複数を制御する情報となると途端に少なくなります。一応サンプルプログラムは用意されているので、Arduino UNOなど主要なデバイスであればこれを参考にどうにかできますが、他のデバイスでも同様にできるのか試しました。

https://github.com/miguelbalboa/rfid/tree/master/examples/ReadUidMultiReader

前提知識

かなり大雑把ですが、用語と意味の別を紹介しておきます。これらの語はサンプルプログラムのコメントやプログラムに現れます。本記事で載せるプログラムにも、PCDUIDという語が現れています。

  • PICCProximity Integrated Circuit Card
    ICカードやICタグのこと
  • PCDProximity Coupling Device
    ICカードのデータを読書きする機器

MFRC522とICカード、ICタグ
中央の基板がPCD、左右のカードとタグがPICCに該当
引用:https://amzn.asia/d/dszK7YW

  • RFIDRadio Frequency IDentification
    技術概念そのもの
  • UIDUnique IDentifier
    重複しない一意の識別番号
  • NUIDNon Unique IDentifier
    重複し得る識別番号
    UIDだけでは足りない場合に使うらしい

回路

二つのMFRC522と40ピンボード

一つでもそれなりの配線になるものを二つ使おうとしているだけあって、配線が煩雑になります。勿論、もっと配線を簡略化することもできますが、できるだけ見通しが良くなるよう、わざと変な配線図にしています。

図の中にWio Terminalがない?

Wio Terminalから直接線を伸ばしてもよくわからない図になるため、敢えてGPIO拡張ボードを使って作図しています。

Wio TerminalとT型ブレイクアウト基板
引用:https://ht-deko.com/arduino/wio_terminal.html

配線図に使っているのは丁字のGPIO拡張ボードで、Raspberry Pi40ピンに対応したものです。文字でピンの役割が記載されており、視覚的にも分かりやすくなります。Wio TerminalのピンはRaspberry Piのそれと対応しているため、上図の向きで接続できます。

製品によって色や形状が異なり、佳品には塀のようなものが付いています。コネクターを挿すに当たっては親切な作りです。

ARCELI
引用:https://amzn.asia/d/bXha1l2

KEYESTUDIO
引用:https://amzn.asia/d/fZKcPLe

Adafruit
引用:https://amzn.asia/d/8pKova1

しかしWio Terminalへ指すに当たっては邪魔になるため、破壊するか、始めからないものを使うことになります。

秋月電子
引用:https://akizukidenshi.com/catalog/g/g108889/

但し秋月電子のこちらは半田付けが必要です。面倒なら、上に並べたような佳品を破壊するのが楽でしょう。

とは言え図でも最早よくわからないので、表にもしておきます。

Wio Terminal PCD1 PCD2
GPIO8 SDA -
GPIO16 - SDA
GPIO11 SCK SCK
GPIO10 MOSI MOSI
GPIO9 MISO MISO
GPIO24 IRQ IRQ
GND GND GND
GPIO25 RST RST
3V3 3.3V 3.3V

プログラム

事前にArduino IDEMFRC522をダウンロードします。

install MFRC522

https://docs.arduino.cc/libraries/mfrc522/

結論から言えば、サンプルプログラムそのままの流れでは正しく動きませんでした。

#include <SPI.h>
#include <MFRC522.h>

// Interrupt Request
constexpr uint16_t IRQ_PIN = BCM24;

// PCD count
constexpr uint16_t PCD_COUNT = 2;

// Reset
constexpr uint16_t RST_PIN_1 = BCM25;
constexpr uint16_t RST_PIN_2 = BCM25; // = same as RST_PIN_1
const byte RESETS[PCD_COUNT] = {RST_PIN_1, RST_PIN_2};

// Slave Select (Serial Data)
constexpr uint16_t SS_PIN_1 = PIN_SPI_SS; // BCM8
constexpr uint16_t SS_PIN_2 = BCM16;
const byte SLAVE_SELECTIONS[PCD_COUNT] = {SS_PIN_1, SS_PIN_2};
const byte SLAVE_SELECTIONS_WITH_DEFAULT[PCD_COUNT] = {PIN_SPI_SS, SS_PIN_2};

// MFRC522 instance
MFRC522 g_aMfrc522[PCD_COUNT];

// dump a byte array to the serial monitor
void dump_byte_array(byte* pBBuffer, uint8_t u8BufferSize);
void dump_byte_array(byte* pBBuffer, uint8_t u8BufferSize) {
    for (uint8_t i = 0; i < u8BufferSize; i++) {
        Serial.print(pBBuffer[i] < 0x10 ? " 0" : " ");
        Serial.print(pBBuffer[i], HEX);
    }
    Serial.println(); // line feed
}

void setup() {
    Serial.begin(115200);
    while (!Serial);

    SPI.begin();

    for (uint8_t i = 0; i < PCD_COUNT; i++) {
        g_aMfrc522[i].PCD_Init(SLAVE_SELECTIONS_WITH_DEFAULT[i], RST_PIN_1);

        // ここで待機しないと片方しか動かない
        delay(100);
    }

    Serial.println(F("[INFO]\tRC522 Multi-PCD Sample"));
}

void loop() {
    for (uint8_t i = 0; i < PCD_COUNT; i++) {
        if ( g_aMfrc522[i].PICC_IsNewCardPresent() && g_aMfrc522[i].PICC_ReadCardSerial() ) {
            Serial.print(F("[INFO]\tPCD ")); Serial.print(i); Serial.println(F(" detected new card."));

            Serial.print(F("[DEBUG]\tUID: ")); dump_byte_array(g_aMfrc522[i].uid.uidByte, g_aMfrc522[i].uid.size);

            MFRC522::PICC_Type piccType = g_aMfrc522[i].PICC_GetType(g_aMfrc522[i].uid.sak);
            Serial.print(F("[DEBUG]\tType: ")); Serial.println(g_aMfrc522[i].PICC_GetTypeName(piccType));

            g_aMfrc522[i].PICC_HaltA();
            g_aMfrc522[i].PCD_StopCrypto1();
        }
        delay(50);
    }
}

複数のPCDを使用する場合、MFRC522::PCD_Init()を複数回実行します。この時サンプルプログラムでは、delay()を入れることなく実行しています。

https://github.com/miguelbalboa/rfid/blob/master/examples/ReadUidMultiReader/ReadUidMultiReader.ino#L55-L61

しかしWio Terminalでは、このように続けると一方のPCDしか動かない場合がありました。そこでMFRC522::PCD_Init()の間にdelay()を挿んだところ、安定して動作するようになりました。

動作の様子

念のためUIDは隠蔽しています。PCD 0とあるのが一つ目、PCD 1とあるのが二つ目です。

serial monitor
[INFO]	RC522 Multi-PCD Sample
[INFO]	PCD 0 detected new card.
[DEBUG]	UID:  ■■ ■■ ■■ ■■
[DEBUG]	Type: MIFARE 1KB
[INFO]	PCD 1 detected new card.
[DEBUG]	UID:  ■■ ■■ ■■ ■■
[DEBUG]	Type: MIFARE 1KB
[INFO]	PCD 0 detected new card.
[DEBUG]	UID:  ■■ ■■ ■■ ■■
[DEBUG]	Type: MIFARE 1KB
[INFO]	PCD 1 detected new card.
[DEBUG]	UID:  ■■ ■■ ■■ ■■
[DEBUG]	Type: MIFARE 1KB
[INFO]	PCD 0 detected new card.
[DEBUG]	UID:  ■■ ■■ ■■ ■■
[DEBUG]	Type: MIFARE 1KB
[INFO]	PCD 1 detected new card.
[DEBUG]	UID:  ×× ×× ×× ××
[DEBUG]	Type: MIFARE 1KB
[INFO]	PCD 0 detected new card.
[DEBUG]	UID:  ■■ ■■ ■■ ■■
[DEBUG]	Type: MIFARE 1KB

以上、二つのPCDを使ってICカードの読み取りができることを確認しました。

Discussion