指紋スキャナーモジュール　GT-521F52をM5stackで動くようにしてみる　デモ編

住んでいるシェアハウスで[supurkfun](https://www.sparkfun.com)の指紋センサー[GT-521F52](https://www.switch-science.com/catalog/3758/)を使ったプロジェクトが立ち上がり、Arduino UNO用のライブラリを[M5stack Basic](http://m5stack.com)用に移植しました。
いろいろ梃子摺ったので、備忘録として書いておきます。

#GT-521F52はどんなハードウェアなのか
一言で言ってしまうと、コマンドを送るだけで指紋の記録、判別を行ってくれる指紋センサです。
マイコン側でいちいち指紋画像データを取り込んで画像解析したりしなくても、コマンド一つで指紋を登録し、これまで登録された指紋かどうかを判定してくれるわけです。便利ですね。
指紋は3000個まで。ちなみに廉価版の[GT-521F32](https://www.switch-science.com/catalog/3757/)の場合は200個まで指紋を登録することができます。
マイコンとの接続は[4ピンのJST SHコネクタ付ジャンパケーブル](https://www.switch-science.com/catalog/5497/)を使います。
このケーブルは指紋センサに付属していないので忘れずに買っておきましょう。

#Arduino Unoで動かしてみる
[スイッチサイエンス](https://www.switch-science.com/catalog/3758/)の商品ページに[ガイド](https://learn.sparkfun.com/tutorials/fingerprint-scanner-gt-521fxx-hookup-guide?_ga=2.214585874.40579103.1521421384-1937571979.1501724101)へのリンクがあるのでGoogle翻訳にかけて読んでみます。

とりあえずデモソフトを動かすにはUSBから3.3Vのシリアル通信に変換できるFTDIがあるのがいいようですが、Arduino Unoと、5.5Vと3.3Vを変換できる[変換モジュール](http://akizukidenshi.com/catalog/g/gK-13837/)があれば十分です。
ライブラリに同梱されている[シリアルパススルーコード](https://github.com/sparkfun/Fingerprint_Scanner-TTL/blob/master/examples/FPS_Serial_Passthrough/FPS_Serial_Passthrough.ino)をArduinoに書き込むと、PCとセンサ間のシリアル通信をArduino経由ででできるようになります。
まずはここで一段落です。

このコードを読んでみます。

```C++
#include <SoftwareSerial.h>
SoftwareSerial fps(4, 5); 
void setup()
{
  Serial.begin(9600); 
  fps.begin(9600);   
}

void loop()
{
  if (Serial.available())
  { 
    fps.write(Serial.read());
  }
  if (fps.available())
  { 
    Serial.write(fps.read());
  }
}
```

ちょっと詳しく見てみます
##1.シリアル通信を使えるようにする

```C++

#include <SoftwareSerial.h>
SoftwareSerial fps(4, 5); 
void setup()
{
  Serial.begin(9600); 
  fps.begin(9600);   
}

```
ソフトウェアシリアルライブラリのヘッダファイルをインクルードし、ソフトウェアシリアルを使えるようにした後、SoftwareSerialオブジェクト**fps**を、受信側4番ピン、送信側5番ピンで作成しています。
fpsというのは**F**inger **P**rint **S**cannerの頭文字です。
これでArduinoの４番ピンと５番ピンをソフトウェアでのシリアル通信に割り当てることができるようになりました。

そしてsetup関数でPCとの接続に使用しているハードウェアのシリアル通信と、センサとの接続にしようしているソフトウェアのシリアル通信の２つを初期化します。


##2.ソフトウェアシリアル(センサ側)のバッファにデータが溜まったらPCに送信し、PCからのシリアル通信のバッファにデータが溜まったらセンサに送信する

```C++
void loop()
{
  if (Serial.available())
  { 
    fps.write(Serial.read());
  }
  if (fps.available())
  { 
    Serial.write(fps.read());
  }
}
```
Arduino系ではsetup関数を実行後、Loop関数が延々と実行されるようになっています。

もしPCと繋がっているハードウェアシリアルSerialが信号を受信しているなら(Serial.available()が0以外)、Serialから1バイト読んで(Serial.read)、センサと繋がっているソフトウェアシリアルfpsに送信します(fps.write(Serial.read()))。

もしセンサと繋がっているソフトウェアシリアルfpsが信号を受信しているなら(fps.available()が0以外)、fpsから1バイト読んで(fps.read)、PCと繋がっているハードウェアシリアルSerialに送信します(Serial.write(fps.read()))。

これによってPCからの信号をセンサに流し、逆にセンサからの信号をPCに送信することを可能にしています。

シンプルなコードですので[Arduino 日本語リファレンス](http://www.musashinodenpa.com/arduino/ref/)を読めば理解できます。

ちなみにSoftwareSerialを使用できるのはArduinoUnoの系列だけですので、他のチップをしようしているマイコンにこのコードを書き込んでもそのままでは動作しないと思います。
公式としてもAruduinoであればどれでもいいというわけではないようです。
ガイドにはこうあります。

>注意： FPS_GT511C3ライブラリは、Arduino IDEを使用するすべてのマイクロコントローラーで機能しない場合があります。ATmega328Pファミリから離れると、コードを修正するか、ライブラリを移植して動作させる必要があります。FPSコードを処理するためにArduinoでAtmega328Pをブートロードする方が簡単で高速です。指紋スキャナーを使用するには、追加のコードを書くだけで、ATmega328Pが他のマイクロコントローラーにシリアルデータを送信することができます。

この場合Arduino Unoは安価な互換機が出回っているのでそれを使用するのが早いと思います。

このシリアルパススルーコードをArduinoに書き込んで、デモソフトが動いたら、今度はこれをM5Stack Basicでも動くようにしていきます。
![demo1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/216739/bb77e876-27e6-610f-4446-5a8b3e123022.png)

![DSC_0332.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/216739/cf62640a-e51b-6667-710b-7d5af8255967.jpeg)


#M5stackへの移植
参考にするのはM5stackのサンプルコードです
[M5stackのSerial2のサンプルコード](https://github.com/m5stack/M5Stack/blob/master/examples/Advanced/Serial2/Serial2.ino)
このコードを参考にして下のようなコードを書いてみました。

```C++
#include <M5Stack.h>

void setup() {

  M5.begin();

  Serial.begin(9600);

  // Serial2.begin(unsigned long baud, uint32_t config, int8_t rxPin, int8_t txPin, bool invert)
  Serial2.begin(9600, SERIAL_8N1, 16, 17);
}

void loop() {

 if(Serial.available()) {
   Serial2.write(Serial.read());
 }

 if(Serial2.available()) {
   Serial.write(Serial2.read());
 }
}
```

変更点を見ていきます。

```C++
#include <M5Stack.h>
void setup() {

  M5.begin();

  Serial.begin(9600);

  // Serial2.begin(unsigned long baud, uint32_t config, int8_t rxPin, int8_t txPin, bool invert)
  Serial2.begin(9600, SERIAL_8N1, 16, 17);
}
```

includeするヘッダファイルがSoftwareSerial.hからM5Stack.hに変わっています。
正確に言うと変わったのではなく、必要なものを入れ、使えないものを消しています。
これはマイクロチップの違いによるものです
**Arduino Uno は Atmel の AVR　ATmega328P**
**M5stackのESP32 は Tensilica の Xtensa LX6**
まったく別の会社の、異なったチップを使っているのでこのようになります。

そしてこのSoftwareSerialですが、これはほぼ特定の系列のArduinoでしか使えません。
[Arduino DueのSoftwareSerial](https://translate.google.com/translate?hl=ja&sl=en&u=https://forum.arduino.cc/index.php%3Ftopic%3D142902.0&prev=search)
という記事を読んでもらえばわかりますが、SoftwareSerialは特定の周波数用にインラインアセンブラ(機械語に近いレベル)で書かれているので、構造の違う他のチップにホイと放り込んで使えるような代物ではありません。

#SoftwareSerialとはなんなのか
SoftwareSerialライブラリは、Arduinoの0,1番ピン以外のピンでシリアル通信を行うために作られたライブラリです。

このSoftwareSerial.hはArduinoUnoにシリアル通信ポートが一つしかないので生まれました。(Arduino Unoではデジタルピンの0番と1番にRX,TXと書かれているのがそれです。このピンはUSBポートとも繋がっているので、プログラムを書き込むときに他のデバイスを繋いでいると誤作動が起きることが知られています)

これはシリアル通信の送信と受信を受け持つユニットが、チップに１つしか入っていないからです。このユニットはRS-232規格のシリアル通信の信号が入力されると、自動で信号を変換し、受信バッファに16進数のデータを読めるようにしてくれたり、送信バッファにデータを入力すると自動で送信してくれたりと、便利なことこの上ないのですが、便利故に複雑で高コストです。作るのにシリコンチップの面積を使うので、いくつも組み込むとチップのサイズが大きくなって、値段が跳ね上がってしまいます。
現在Arduino Unoに使われているチップが開発されたころの半導体技術ではコストとの関係もあり、いくつもシリアル通信用ユニットを搭載できなかったのでしょう。しかしマイコンでいろいろやるときは、他のピンでもシリアル通信をさせたいわけです。

そこで生まれたのがソフトウェアシリアルです。
SoftwareSerialライブラリはチップにシリアル通信ユニットと同じ動作をさせることができるようになるライブラリです。
これにより、シリアル通信ユニットの有無に関わらずにシリアル通信ができるという利点が生まれましたが、同時にチップの計算能力を使用してしまうので動作が遅くなったりメモリを余計に使ってしまったりという欠点もあります。通信速度も専用のユニットに比べて遅く、特にArduino Unoでは9600bpsを超えた速度ではチップの動作が追いつかず、エラーが出て安定しないといったことが知られています。

そうした欠点を嫌って作られた当時の高級なチップや、最近の半導体技術で作られた機能テンコ盛り系チップには複数のシリアル通信ユニットが組み込まれていることが多いです。
高速なシリアル通信ユニットが複数搭載されているのですから、SoftwareSerialは必要ないわけです。

ちなみにM5Stackに使われているESP32は機能テンコ盛り系チップで、シリアル通信ユニットを3つ搭載しています。一つはUSBに使われているので、実質２つが使用可能です。

あと、ESP32用のSoftwareSerialライブラリは探せば出てくるのですが、私は動かせなかったので今回は使用せずにハードウェアシリアルを使用します。
なのでSoftwareSerialを削除します。

そしてM5Stack.hを新たにインクルードします。
M5StackはESP32に画面等の様々なモジュールをくっつけているので、それらを使用する関係もあり、こうしたヘッダファイルをインクルードする必要があります。

#追加、変更したコード
さて、

```C++
M5.begin()
```
ですが、これはもう[リンク先](https://github.com/m5stack/m5-docs/blob/master/docs/ja/api/system_m5stickc.md)を読んでもらえばわかる初期設定用の関数です。

```C++
Serial2.begin(9600, SERIAL_8N1, 16, 17);
```
これはM5stackのサンプルコードを書き換えてあります。
Serial2は2つめのシリアル通信オブジェクトです。（1つ目がUSBコネクタです）
ハードウェアで実装されている。つまりはじめから存在しているので、ソフトウェアシリアルのようにわざわざ

```C++
HardwareSerial fps(4, 5); 
```
とやって作成する必要はありません。

**SERIAL_8N1**に関しては以下のリンクが参考になります。
[Serial.begin()](https://www.arduino.cc/reference/jp/language/functions/communication/serial/begin/)
これはシリアル通信のパリティとストップビットの指定を行います。
特に特殊な方式ではないのでデフォルトのSERIAL_8N1で問題ありません。

GPIO16,17は以下の公式ドキュメントを読んでもらえればわかるようにシリアル通信ピンの番号に対応しています。
[M5-Core-Schematic(20171206).pdf](https://github.com/m5stack/M5-Schematic/blob/master/Core/Basic/M5-Core-Schematic(20171206).pdf)
GPIO16番がRXD2でデータを受信するピン、
GPIO17番がTXD2でデータを送信するピンです

そしてloop関数ですが、特にやっていることに変更は無いので説明はしません。
受信先と送信先が書き換わっているだけです。

#実行してみる
M5stackとGT-521F52をピンで接続します。
**M5stackのGPIO16番ピンがRX**なので**GT-521F52のTX**に
**M5stackのGPIO17番ピンがTX**なので**GT-521F52のRX**に
**M5stackのGNDピン**を**GT-521F52のGND**に
**M5stackの3.3Vピン**を**GT-521F52のVin**に
それぞれ接続します。
(ちなみにガイドではVin(3.3V～6V)と書いてありますが、私の環境ではM5stackの5Vを接続した場合動作しませんでした)
![AMZN_2019-11-19_22_22_14.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/216739/e4472e5b-80ec-e1a0-76b0-29ba4a74797b.jpeg)

M5stackにスケッチを書き込んでから開発環境を閉じると、デモソフトが動くようになりました。
![demo2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/216739/ed11f5d4-26a0-321e-592b-30a83b85e804.png)

これでデモソフトをM5Stack経由で動作させることができるようになりました。
次回からはデモソフトからシリアル通信で制御するのではなく、M5Stackに制御用のスケッチを移植して動作させていきます。