2017年6月29日木曜日

SPI Digital PotのAD8403の処理速度を調べてみた。

KIK01で使うかもしれないので、Analog DevicesのSPI接続のデジタル・ポテンショメータのAD8403の処理速度をArduinoとNucleoで調べてみた。

Arduino Uno


配線は「Arduinoでデジタル・ポテンショメータメーター(AD8403)を使ってみた」のものと同じ。

スケッチ
<AD8403_Control.ino>

// inslude the SPI library:
#include <SPI.h>

// set pin 10 as the slave select for the digital pot:
const int slaveSelectPin = 10;

void setup() {
  // set the slaveSelectPin as an output:
  pinMode(slaveSelectPin, OUTPUT);
  // initialize SPI:
  SPI.begin();
}

void loop() {
  // go through the four channels of the digital pot:
  for (int channel = 0; channel < 4; channel++) {
    // change the resistance on this channel from min to max:
    digitalPotWrite(channel, 255);
    digitalPotWrite(channel, 0);
  }
}

void digitalPotWrite(int address, int value) {
  // take the SS pin low to select the chip:
  digitalWrite(slaveSelectPin, LOW);
  //  send in the address and value via SPI:
  SPI.transfer(address);
  SPI.transfer(value);
  // take the SS pin high to de-select the chip:
  digitalWrite(slaveSelectPin, HIGH);
}


AD8403への出力はノーウェイトで0と255を切り替えている。slaveSelectPin(CS)がアクティブ(L)の時間を見ればAD8403に値を送るのにかかった時間がわかる。

CS

ch1:CS ch2:SCK

CSがアクティブな時間は9.680us。SPIクロック(SCK)は3.538MHzとなっているが、拡大してオシロのカーソルで測ると約4MHzだった。

2回目のSPI.transfer()の後、CSをHiにするまでに結構時間がかかっているようだ。

W1

ch1:CS ch2:W1

W1はAD8403のchannel 1のWiperの出力電圧で、プログラムでここの電圧値を制御している。CSがL->H、つまりSPI通信が終了したタイミングでほぼ遅延なく送った設定値が反映されている。

Nucleo F446RE


配線はArduinoと同じ。(NucleoのArduino Headerで配線した)

プログラム

/*
 * Digital Potentiometer AD8304のテスト
 *
 * 2017.06.28
 *
 */

#include "mbed.h"

#define SPI_CLOCK   (16000000)

SPI SpiM(SPI_MOSI, SPI_MISO, SPI_SCK);  // mosi, miso, sclk
DigitalOut Cs(D10, 1);

// address: 0..4
// value:   0..255
void outDigiPot(uint8_t address, uint8_t value)
{
    Cs = 0;
    SpiM.write(address);
    SpiM.write(value);
    Cs = 1;
}

int main()
{
    SpiM.format(8, 0);
    SpiM.frequency(SPI_CLOCK);

    for (;;) {
        for (int channel = 0; channel < 4; channel++) {
            outDigiPot(channel, 255);
            wait_us(1);
            outDigiPot(channel, 0);
            wait_us(1);
        }
    }
}

メインループ内でwait_us(1)を入れているが、これは処理が速すぎてオシロで信号が見辛かったため。

AD8403の最大クロックは10MHzなので、SPI_CLOCKを1MHz、6MHz、12MHzにして測定してみた。

1MHz CS

ch1:CS ch2:SCK

CSがアクティブな時間は26.240us。SPIクロックは597.0kHz

1MHz W1

ch1:CS ch2:W1

Arduinoと同じくCSがインアクティブになってからほぼ遅延なく設定した値が出力されている。

6MHz CS

CS:7.820us。SCKは拡大して測ると5.627MHz。

12MHz CS

CS:6.220us。SCKは拡大して測ると11.25MHz。(AD8403の仕様外)

Nucleo F303K8


F303K8はSPIクロックを1MHz、8MHz、16MHzにして測定。


1MHz CS

CS:34.6us。SCKは拡大して測ると約1MHz。

8MHz CS

CS:20.8us。SCKは拡大して測ると約8MHz。

16MHz CS

CS:20.84us。SCKは拡大して測ると約16MHz。(AD8403)

比較表


Device SCK(設定値) SCK(実測値) CS
Arduino 4MHz 4MHz 9.680us
F446RE 1MHz 597.0kHz 26.24us
F446RE 6MHz 5.627MHz 7.820us
F446RE 12MHz 11.25MHz 6.22us
F303K8 1MHz 1MHz 34.6us
F303K8 8MHz 8MHz 20.8us
F303K8 16MHz 16MHz 20.84us

比較してみると、Arduino Unoがかなり健闘している。SPIクロックが同程度ならNucleoF446REと同じぐらいかもしれない。NucleoF303K8はSPI通信前後のオーバーヘッドが大きく、SPIクロックを上げてもArduino Unoよりも悪い結果となってしまった。

F446もF303もコアは同じCortex-M4だが処理能力はかなり差がある。

Interface2016年12月号に「定番ARMマイコンSTM32便利帳2016」 という付録がついているので見てみると、F3はADC、DACなどのアナログ機能やPWMなどのタイマ機能が充実しているそうだ。



使いこなすにはもう少し慣れる必要がありそう。