Raspberry Pi 3とADS7843を使ってタッチスクリーンの情報をNodejsで受け取る

# 1. 概要

液晶のついていないタッチスクリーンだけの情報をRaspberry Piで受け取る方法です。
タッチスクリーンは抵抗皮膜型のものを使用し、コントローラとしてASA7843を使用します。
コントローラとRaspberry Piの通信はSPIで、プログラムはNode.jsです。

# 2. 環境、使用機器
* Raspberry Pi 3 (Rasbpian Stretch)
* 4線抵抗膜型タッチスクリーン(4.3インチ)
    * 1.25mmピッチ4P、FFCコネクタ
    * http://www.aitendo.com/product/16196
* タッチコントローラモジュールADS7843
    * 1.0mmピッチ4ピンFFCコネクタ（下接点）
    * http://www.aitendo.com/product/2308

※　上記のaitendoのモジュールにFFCのコネクタがついていますが、タッチスクリーンのFFCとピッチが合わないのでコネクタは使わずモジュールにピンソケットを追加して使用しています。

# 3. 参考サイト

1. [こじ研（ESP センシング編）](https://www.ei.tohoku.ac.jp/xkozima/lab/espTutorial2.html)
    - 下の方に「ESP にタッチパネルを SPI 接続する」という章があります
    - タッチスクリーンとADS7843の仕組みの勉強とArduinoプログラムの参考にしました。

2. [Getting started with SPI &amp; analog input in NodeJS using Raspberry Pi and MCP3008 | Mikael Levén](https://mikaelleven.wordpress.com/2015/12/13/getting-started-with-spi-analog-input-in-nodejs-using-raspberry-pi-and-mcp3008/)
    - Raspberry PiでSPIを使う参考にしました。

# 4. まずArduinoでテストしてみる

## 4.1 配線

| ADS7843 |  Arduino Uno |
| ------- |  ----------- |
| CS      |  10(SS)      |
| DOUT    |  12(MISO)    |
| DIN     |  11(MOSI)    |
| DCLK    |  13(SCK)     |
| 5V      |  5V          |
| GND     |  GND         |

![IMG_7190.JPG](https://qiita-image-store.s3.amazonaws.com/0/94069/7ab4f2a1-a3d0-7b16-55e3-5d5c1c54a9f5.jpeg)


## 4.2 プログラム

参考サイト(https://www.ei.tohoku.ac.jp/xkozima/lab/espTutorial2.html)のプログラムを元に以下の変更を加えました。

* CSのピンを`15`から`10`に変更
* `SPI.setFrequency(1000000ULL);`がArudino Unoにないので`SPI.setClockDivider(SPI_CLOCK_DIV8);`に変更

```c:Arduinoプログラム
#include <SPI.h>
//#define CS      15
#define CS      10
#define PEN     5
int Count = 0;

void setup() {
  //  debug output
  Serial.begin(115200); delay(100);
  Serial.println("");
  Serial.println("*** esp_touthPanel ***");
  //  SPI settings (SCK, MISO, MOSI, CS=IO15)
  pinMode(CS, OUTPUT);
  digitalWrite(CS, HIGH);
  SPI.begin();
  SPI.setBitOrder(MSBFIRST);
  SPI.setDataMode(SPI_MODE0);
  //  SPI.setFrequency(1000000ULL);  //  max 2MHz
  SPI.setClockDivider(SPI_CLOCK_DIV8);
  //  D5 for PEN
  pinMode(PEN, INPUT);
}

void loop() {
  int x, y;
  if (touchPanel(x, y)) {
    if (Count++ % 1000 == 0) {
      Serial.print(x), Serial.print(", "), Serial.println(y);
    }
  }
}

bool touchPanel(int &x, int &y) {
  if (digitalRead(PEN) == HIGH) {
    //  if not pen-down, return false
    return false;
  }
  else {
    //  get data from ADS7843
    unsigned char dataOut[3], dataIn[3];
    //  X-axis (X+)
    dataOut[0] = 0x94; dataOut[1] = 0x00; dataOut[2] = 0x00;
    digitalWrite(CS, LOW);
    dataIn[0] = SPI.transfer(dataOut[0]);
    dataIn[1] = SPI.transfer(dataOut[1]);
    dataIn[2] = SPI.transfer(dataOut[2]);
    digitalWrite(CS, HIGH);
    x = (dataIn[1] * 256 + dataIn[2]) >> 3;
    //  Y-axis (Y+)
    dataOut[0] = 0xD4; dataOut[1] = 0x00; dataOut[2] = 0x00;
    digitalWrite(CS, LOW);
    dataIn[0] = SPI.transfer(dataOut[0]);
    dataIn[1] = SPI.transfer(dataOut[1]);
    dataIn[2] = SPI.transfer(dataOut[2]);
    digitalWrite(CS, HIGH);
    y = (dataIn[1] * 256 + dataIn[2]) >> 3;
    //  return true
    return true;
  }
}
```

シリアルモニタでデータが取得できることを確認します。

# 5. Raspberry Pi 3で動かす

## 5.1 配線

| ADS7843 | Raspberry Pi              | 
| ------- | ------------------------- | 
| CS      | GPIO8 (CE0) / GPIO7 (CE1) | 
| DOUT    | GPIO9 (MISO)              | 
| DIN     | GPIO10 (MOSI)             | 
| DCLK    | GPIO11 (SCLK)             | 
| 5V      | 5V                        | 
| GND     | GND                       | 



## 5.2 プログラム

参考サイト(https://mikaelleven.wordpress.com/2015/12/13/getting-started-with-spi-analog-input-in-nodejs-using-raspberry-pi-and-mcp3008/ )を参考に以下の２点を変更しました。

* 1. spiTransfer()の形が変わったため修正
    * 参考：　https://gist.github.com/mikaelleven/8535ee6ce40d80f43b1f

```c:修正前
var recieveBuffer = rpio.spiTransfer(sendBuffer, sendBuffer.length); 
```

```c:修正後
var recieveBuffer = newBuffer(8);
rpio.spiTransfer(sendBuffer, recieveBuffer, sendBuffer.length);
```

* 2. `bcm2835_init: gpio mmap failed: Cannot allocate memory`で止まる問題を解決
    - 同じようなissueが
        - https://github.com/jperkin/node-rpio/issues/62
    - 解決方法
        - `rpio.init({gpiomem: false});`を宣言しました。
        - サイトに書いてありました(https://github.com/jperkin/node-rpio#gpiomem)

![image.png](https://qiita-image-store.s3.amazonaws.com/0/94069/96c4c758-ce82-03e9-e0d2-175918dbc99c.png)

```js:test.js
var rpio = require('rpio');

var pin = 15;

var begin = function(){
  rpio.spiBegin();
  rpio.spiChipSelect(0);                                      // 24番ピン(SPI0 CE0)に接続
  rpio.spiSetCSPolarity(0, rpio.LOW)    // ADS7843はActive-Low
};

var getValueX = function(){
  var sendBuffer = new Buffer([0x94, 0x00, 0x00]);  //
  var recieveBuffer = new Buffer(8);  // sendしたバイト数と同じバイト数返ってくる
  rpio.spiTransfer(sendBuffer, recieveBuffer, sendBuffer.length);
  var junk = recieveBuffer[0],
        MSB = recieveBuffer[1],
        LSB = recieveBuffer[2];
  var value = (((MSB & 0x7f) << 8) + LSB)>>3; // 下位2バイトを3ビットシフトする
  console.log('x :', value);
};

var getValueY = function(){
  var sendBuffer = new Buffer([0xD4, 0x00, 0x00]);
  var recieveBuffer = new Buffer(8);  // sendしたバイト数と同じバイト数返ってくる
  rpio.spiTransfer(sendBuffer, recieveBuffer, sendBuffer.length);
  var junk = recieveBuffer[0],
        MSB = recieveBuffer[1],
        LSB = recieveBuffer[2];
  var value = (((MSB & 0x7f) << 8) + LSB)>>3; // 下位2バイトを3ビットシフトする
  console.log('y :', value);
};

var end = function(){
  rpio.spiEnd();
};

rpio.init({gpiomem: false}); // SPI, I2Cを使用するため(実行時にsudoが必要)
rpio.open(15, rpio.INPUT, rpio.PULL_DOWN);

setInterval(function() {

  var state = rpio.read(pin) ? 'high' : 'low';
  console.log('Pin15  %s', rpio.read(15));

  if(state == 'low'){
    begin();    
    getValueX();
    getValueY();
    end();
  }
},100);
```

`sudo node test.js`で実行します。
実行するとコンソールに座標が表示されます。

## 5.3 SPIのトラブルシューティングの方法

- https://mikaelleven.wordpress.com/2015/12/10/troubleshooting-spi-on-raspberry-pi-nodejs/
- MOSIとMISOをループさせれば送ったものと同じものが返ってくる

## 5.4 追加のセンサを使う
IN3、IN4が空いているので別のアナログセンサを追加できます(配線が細かいですが)。
プログラム自体はほぼ同じで、`0x94`、`0xD4`となっていたところがIN3だと`0xA4`、IN4だと`0xE4`となります。