ロジックアナライザを試すその4:ハードウェアSPIとソフトウェアSPI


MCP3008でのハードウェアSPIとソフトウェアSPIの処理時間

A/DコンバータであるMCP3008を用いたハードウェアSPIとソフトウェアSPIの処理時間に差があることに気がついたので、ここに記録する。

ハードウェアSPIとソフトウェアSPI

こちらに説明あり。ハードウェアSPIは専用回路を用い、ソフトウェアSPIはGPIOを用いる。

環境

ロジックアナライザを試すその3(SPI)と同じ。ArduinoでA/DコンバータMCP3008と温度センサーMCP9700とを利用。

MCP3008データシート

ハードウェアSPI処理



ハードウェアSPIでは8ビットをまとめて処理する、‘leading zeros’がきっかけとなっているらしい。これをもとにコーディングする(前回のソースコード参照

ソフトウェアSPI処理



シリアルに1ビットずつ処理する。

ソースコード

ハードウェアSPI

前回と全く同じ。

#include <SPI.h>
#define SPI_CS 10
float Vref = 5.0 ;
SPISettings settings(1000000,MSBFIRST,SPI_MODE0);

void setup() {
  Serial.begin(9600);
  pinMode(SPI_CS, OUTPUT);
  SPI.begin();
}

void loop(){
  // SPI setting and write&read
  SPI.beginTransaction(settings);
  digitalWrite(SPI_CS, LOW);
  SPI.transfer(0b00000001);                 // Start bit 1
  byte highByte = SPI.transfer(0b10000000); // SingleEnd Channel 0
  byte lowByte = SPI.transfer(0x00);        // dummy
  digitalWrite(SPI_CS, HIGH);
  SPI.endTransaction();
  unsigned int dataCh0 = ((highByte & 0x03) << 8) + lowByte;

  // Conversion of read data according to MCP9700 spec
   float volts = dataCh0 * Vref / 1024;
  float temperature = (volts - 0.5) / 0.01; // : 500 mv at 0 degree and 10 mv / degree 
  Serial.println("dataCh0: " + String(dataCh0,HEX) + "  Voltage: " + String(volts,3));
  Serial.println("Temperature: " + String(temperature,2) + " degrees");
  Serial.println();
  delay(3000);
}

ソフトウェアSPI

こちらにあるものとほぼ同じ。

#include <SPI.h>
#define SPI_CS   7
#define SPI_MOSI 6
#define SPI_MISO 5
#define SPI_CLK  4
float Vref = 5.0;

void setup() {
  Serial.begin(9600);
  pinMode(SPI_CS, OUTPUT);
  pinMode(SPI_CLK, OUTPUT);
  pinMode(SPI_MOSI, OUTPUT);
  pinMode(SPI_MISO, INPUT);
  digitalWrite(SPI_CLK, LOW);
  digitalWrite(SPI_MOSI, LOW);
  digitalWrite(SPI_CS, HIGH);
}

void loop() {
  // SPI setting and write&read
  unsigned int outBuffer, inBuffer = 0;
  byte command = ((0x01 << 7) |        // Start bit
                  (1 << 6) |           // 1: SingleEnd
                  ((0 & 0x07) << 3));  // Channel 0
  digitalWrite(SPI_CS, LOW);
  outBuffer = command << 8;
  for (int c = 0; c < 16; c++) {
    digitalWrite(SPI_MOSI, (outBuffer >> (15 - c)) & 0x01);
    digitalWrite(SPI_CLK, HIGH);
    digitalWrite(SPI_CLK, LOW);
    inBuffer <<= 1;
    if (digitalRead(SPI_MISO))
      inBuffer |= 0x01;
  }
  digitalWrite(SPI_CS, HIGH);
  unsigned int dataCh0 = inBuffer & 0x3ff;

  // Conversion of read data according to MCP9700 spec
  float volts = dataCh0 * Vref / 1024;
  float temperature = (volts - 0.5) / 0.01; // : 500 mv at 0 degree and 10 mv / degree 
  Serial.println("dataCh0: " + String(dataCh0,HEX) + "  Voltage: " + String(volts,3));
  Serial.println("Temperature: " + String(temperature,2) + " degrees");
  Serial.println();
  delay(3000);
}

ロジックアナライザ

ハードウェアSPI

ソフトウェアSPI


所持するロジックアナライザのSPIデコードはハードウェアSPIを前提にしているようで、そのままではデコードできず。試しに、Clock polarityとClock phaseを適当に選ぶとデコードしてくれた。

比較

どちらもMISOにらしいデータ('9c'および'9f'、変換後は26−27度)が見られる。ここでのポイントは処理速度。ロジックアナライザでの取得データの処理時間(赤枠)を見ると、
- ハードウェアSPI  26μs
- ソフトウェアSPI  340μs
となっている。これだけ差があるのは少々びっくり。

ソフトウェアSPIについては用いるマイコンなどの能力にも依存するのであろう。また、他のSPI対応デバイスでどんな結果となるかは不明。