matlabでArduinoからデータを持ってくる③SPI その2

　前回は、泥縄的にA-DコンバータADS1256のプログラムを書きました。ここでは、レジスタの読み書きを関数にし、本体のプログラム部分をすっきりさせます。
###接続
　アナログ入力端子は8本あります。デフォルトではch0-ch1の差動入力になっています。24ビットの分解能を考え、ノイズに弱いシングルエンド入力は避け、差動のまま利用します。

| 本プログラムでのチャネルch | 入力端子 | data |
|:-----------:|:------------:|:------------:|
| 0| ch0-ch1        | 0b00000001 |
| 1| ch2-ch3        | 0b00100011 |
| 2| ch4-ch5        | 0b01000101 |
| 3| ch6-ch7        | 0b01100111 |

　ch0にはTL431の出力約2.5V、ch2には単4電池1個の約1.5V、ch1とch3は相互にショートし、0V入力としました。

###プログラム

　作った関数は次のとおりです。

| 関数名 | 機　能 | 
|:-----------|:------------|
| sendCommand(x)| 1バイトのコマンドを送る | 
| writeRegister(address, value)| レジスタに1バイト書き込む | 
| writeRegister3(address, value)| レジスタに3バイト書き込む | 
| readD = readRegister(address)| レジスタから1バイトと読む | 
| readD3 = readRegister3(address)| レジスタから3バイトと読む | 
| readADC()| アナログ値を読む | 
| selectCH(channel)| 0～3のチャネルを指定する | 


　初期設定値です。

- Auto-Calibration
- PGA x1
- DataRate　2.5SPS

　PGAは2倍とかを設定できますが、プログラムではその分を計算していません。増幅したら、その分readADC()の結果voltを割ってください。
　DataRateは、データシートにあるどの値でも正常に動作すると思います。2.5SPSは一番遅いレートです。データが用意できたというDRDY信号は見ていないので、十分な時間待ち時間を入れています。
　SPIのデータ転送速度は100kbpsと遅いです。細かなディレイを入れて、データシートのタイミングを確保できないので、これ以上のスピードではうまく読み書きができないかもしれません。

　コメントアウトしているのが、OFC（Offset Calibration）とFSC（Full–scale Calibration）の24ビットの値です。データシートを読んでも、これを設定しなければならないのか、自己キャリブレーションに任せればよいのかが読み取れませんでした。なので、3か所で読み出すようにして確認作業をしていましたが、それでも解決していません。
　
　ステータス・レジスタのAuto-CalibrationをONにしていますが、これが何をしているかは不明です。
　1回の測定のたびにsendCommand(SELFCAL);を実行しています。SELFCALは、自己オフセットおよび自己ゲイン･キャリブレーションの実行コマンドです。これを毎回実行しないと、DataRateをいろいろな数値に変更したら、読み出すデータがでたらめになるケースが増えました。

　ADCの読み出しは、4チャネルの読み出しを100回繰り返しています。

```matlab
clear all
a = arduino('COM10', 'MKRZero', 'Libraries', 'SPI');
global ads1256;
ads1256 = device(a, 'SPIChipSelectPin', 'D7', 'SPIMode', 1, 'BitRate', 100000, 'BitOrder', 'msbfirst');

statusRegister_address = 0x00;
autoCaliblation = 0b00000100;
RESET = 0xfe;
ADDataRateReg_address = 0x03;
PGAReg_address = 0x02;
RDATAC = 0x03;
SELFCAL = 0xf0;
OFC0 = 0x05;
FSC0 = 0x08;

%% main
global readD;
global readD3;
sendCommand(RESET);
pause(0.5);

% readRegister3(OFC0);
% d = double(bitshift(int32(readD3(3)), 16))  + double(bitshift(int32(readD3(2)), 8)) + double(readD3(1));
% fprintf('read OFC is %08s \n', dec2hex(d));  

% readRegister3(FSC0);
% d = double(bitshift(int32(readD3(3)), 16))  + double(bitshift(int32(readD3(2)), 8)) + double(readD3(1));
% fprintf('read FSC is %08s \n', dec2hex(d)); 

% readRegister(statusRegister_address);
% fprintf('read status  is %08s \n', dec2bin(readD(3)));

writeRegister(statusRegister_address, 0b00000100);  % Auto-Calibration
readRegister(statusRegister_address);
fprintf('read New status  is %08s \n', dec2bin(readD(3)));

writeRegister(PGAReg_address, 0b00100000);  % PGA x1
pause(0.1);
readRegister(PGAReg_address);
fprintf('read PGA is %08s \n', dec2bin(readD(3)));

writeRegister(ADDataRateReg_address, 0b00000011);  % 2.5SPS
pause(0.5);
readRegister(ADDataRateReg_address);
fprintf('read DataRate is %08s \n', dec2bin(readD(3)));
pause(0.5);
sendCommand(SELFCAL);
pause(1);

% readRegister3(OFC0);
% d = double(bitshift(int32(readD3(3)), 16))  + double(bitshift(int32(readD3(2)), 8)) + double(readD3(1));
% fprintf('read OFC is %08s \n', dec2hex(d)); 

% readRegister3(FSC0);
% d = double(bitshift(int32(readD3(3)), 16))  + double(bitshift(int32(readD3(2)), 8)) + double(readD3(1));
% fprintf('read FSC is %08s \n', dec2hex(d)); 

global volt;
for j=0:100
    for i=0:3
        selectCH(i);
        readADC();
        fprintf('read ch=%d  is %.8f \n', i, volt);
        sendCommand(SELFCAL);
        pause(0.9);
    end
    fprintf('---\n');
end

% readRegister3(OFC0);
% d = double(bitshift(int32(readD3(3)), 16))  + double(bitshift(int32(readD3(2)), 8)) + double(readD3(1));
% fprintf('read OFC is %08s \n', dec2hex(d)); 

% readRegister3(FSC0);
% d = double(bitshift(int32(readD3(3)), 16))  + double(bitshift(int32(readD3(2)), 8)) + double(readD3(1));
% fprintf('read FSC is %08s \n', dec2hex(d)); 

function sendCommand(x)
    global ads1256;
    writeRead(ads1256, x);
end

function writeRegister(address, value) % 1byte
    global ads1256;
    WREG = 0x50;
    wdata = bitor(WREG, address);
    out = [wdata 0 value];
    writeRead(ads1256, out, 'uint8') ; % write 
end

function writeRegister3(address, value) % 3byte
    global ads1256;
    WREG = 0x50;
    wdata = bitor(WREG, address);
    out = [wdata 2 value];
    writeRead(ads1256, out, 'uint8') ; % write 
end

function readD = readRegister(address) % 1byte
    global ads1256;
    global readD;
    RREG = 0x10;
    rdata = bitor(RREG, address);
    out = [rdata 0 0xff];
    readD = writeRead(ads1256, out, 'uint8') ;
end

function readD3 = readRegister3(address) % 3byte
    global ads1256;
    global readD3;
    RREG = 0x10;
    rdata = bitor(RREG, address);
    out = [rdata 2 0xff];
    readD3 = writeRead(ads1256, out, 'uint8');
end

function volt = readADC()
    global ads1256;
    global volt;
    Vref  = 2.5 - 0.003;
    out = [0x01,0xff 0xff 0xff];
    readD = writeRead(ads1256, out, 'uint8');
    ad = double(bitshift(int32(readD(2)), 16))  + double(bitshift(int32(readD(3)), 8)) + double(readD(4));
    volt = 2 * Vref * ( ad / 8388607.0);
end

function selectCH(channel)  % channel = 0(default), 1, 2, 3 only
     Input_Multiplexer_Control_Register_address = 0x01;
     SYNC = 0xfc;
     WAKEUP = 0x00;
     % select ch0-ch1 0000 0001, ch2-ch3 0010 0011, ch4-ch5 0100 0101, ch6-ch7 0110 0111
     switch channel
         case 0
             CH = 0b00000001;
         case 1
             CH = 0b00100011;
         case 2
             CH = 0b01000101;
         case 3
             CH = 0b01100111;
         otherwise
             CH = 0x01;             
     end
     writeRegister(Input_Multiplexer_Control_Register_address, CH) ; 
     sendCommand(SYNC);
     sendCommand(WAKEUP);
     pause(0.5);
end

```

（注）　データシート　https://www.tij.co.jp/jp/lit/ds/symlink/ads1256.pdf?ts=1597979092052&ref_url=https%253A%252F%252Fwww.tij.co.jp%252Fproduct%252Fjp%252FADS1256

global　変数の指定は、関数（ローカル）内とその外側の両方に宣言する。
関数の定義は、利用する後に行う。