秋月MCP3564をRP2350で動かす

## これなに？
秋月で売ってる良さげなADCをrp2350で動かすだけです。データシート読みつつ、1日ほど苦戦したので残します。

## どうやって使うんだYo!

SPIなので、それぞれの端子を以下のように結線します。
で、初期化は以下のようにします。

```
# fastコマンドを送信 (RESET)
> 0x78

# CONFIG0_REG = 0x01   # CONFIG0レジスタのアドレス
# ADDR = 0x01          # デバイスのアドレス (SPI)
# CMD_INC_WRITE = 0x02 # 連続書き込み
command = (ADDR << 6) | (CONFIG0_REG << 2) | (CMD_INC_WRITE & 0x03);
# 内部クロックを使用する + 計測スタンバイモード
> command 0x32

# CONFIG1_REG = 0x02   # CONFIG2レジスタのアドレス
command = (ADDR << 6) | (CONFIG1_REG << 2) | (CMD_INC_WRITE & 0x03);
# OSR = 1024 階調に設定
> command 0x0E

# CONFIG2_REG = 0x03   # CONFIG2レジスタのアドレス
command = (ADDR << 6) | (CONFIG2_REG << 2) | (CMD_INC_WRITE & 0x03);
# BOOST = x1, GAIN = x1に設定
> command 0x8B

# CONFIG3_REG = 0x04
command = (ADDR << 6) | (CONFIG3_REG << 2) | (CMD_INC_WRITE & 0x03);
# 継続変換モード (内部で変換を連続して行う, モードによっては一回変換すると動作が止まるやつもある)
> command 0xC0

# IRQ_REG = 0x05
command = (ADDR << 6) | (IRQ_REG << 2) | (CMD_INC_WRITE & 0x03);
# プルアップしていない場合は，0x07を設定する．
> command 0x07

# ADCを開始する
> 0x68
```

として，あとは`ADCDATA_REG(0x00)`を読み出すするだけでOK. その場合は`CMD_INC_READ(0x03)`を使って読み込みます．返してくるビットの形式などは，上記のレジスタの部分で変えることができます．
より細かい設定は，全てデータシート(80ページあたり)に書いてあるので，そちらを参照してください．

データシートにはどの流れで設定すればいいか，簡単に書いておらず，書き込み順序が違うとちゃんと動きませんでした．


### で，プログラムは？

はい，実際のコードです．
```c++
#include <SPI.h>

// ピンアサイン定義
// ADC0
#define ADC0_IRQ_PIN 16
#define ADC0_CS_PIN 17
#define ADC0_SCK_PIN 18
#define ADC0_MOSI_PIN 19
#define ADC0_MISO_PIN 20

// ADC1
#define ADC1_IRQ_PIN 24
#define ADC1_CS_PIN 25
#define ADC1_SCK_PIN 26
#define ADC1_MOSI_PIN 27
#define ADC1_MISO_PIN 28

// MCP3564 レジスタアドレス
#define ADCDATA_REG 0x0
#define CONFIG0_REG 0x1
#define CONFIG1_REG 0x2
#define CONFIG2_REG 0x3
#define CONFIG3_REG 0x4
#define IRQ_REG 0x5
#define MUX_REG 0x6

// コマンドタイプ
#define CMD_STATIC_READ 0x01
#define CMD_INCR_WRITE 0x02
#define CMD_INCR_READ 0x03

// デバイスアドレス
#define DEVICE_ADDR 0x40

// Fast Commands
#define FAST_CMD_START 0x68
#define FAST_CMD_STANDBY 0x6C
#define FAST_CMD_SHUTDOWN 0x70
#define FAST_CMD_RESET 0x78

// SPI設定（10MHz）
SPISettings spiSettings(10000000, MSBFIRST, SPI_MODE0);

// MUX設定定義（シングルエンド CHx-AGND）
uint8_t mux_ch0_8[] = {0x08, 0x18, 0x28, 0x38, 0x48, 0x58, 0x68, 0x78, 0x88}; // CH0-AGND ~ CH8-AGND
uint8_t mux_special[] = {0xDE, 0x98, 0x88}; 

void setup() {
  Serial.begin(115200); 
  while (!Serial) {
    delay(10);
  }
  
  // ADC0 SPI設定
  pinMode(ADC0_CS_PIN, OUTPUT);
  digitalWrite(ADC0_CS_PIN, HIGH);
  SPI.setMISO(ADC0_MISO_PIN);
  SPI.setMOSI(ADC0_MOSI_PIN);
  SPI.setSCK(ADC0_SCK_PIN);
  SPI.begin();

  // ADC1 SPI設定
  pinMode(ADC1_CS_PIN, OUTPUT);
  digitalWrite(ADC1_CS_PIN, HIGH);
  SPI1.setMISO(ADC1_MISO_PIN);
  SPI1.setMOSI(ADC1_MOSI_PIN);
  SPI1.setSCK(ADC1_SCK_PIN);
  SPI1.begin();

  delay(50); 
  
  // 両方のADCを初期化
  initializeADC(0);
  initializeADC(1);
}

void loop() {
    int adc_num = 0;
    int ch = 0;
    writeRegister(adc_num, MUX_REG, mux_ch0_8[ch]);
    delay(1); 
  
    // ADCデータ読み取り
    uint32_t adc_data = readADCData(adc_num);

    // 24ビット符号付き整数に変換
    int32_t signed_data;
    if (adc_data & 0x800000) {
        signed_data = (int32_t)(adc_data | 0xFF000000);
    } else {
        signed_data = (int32_t)adc_data;
    }

    // シングルエンド
    float voltage = ((float)signed_data / 8388608.0f) * 3.27f;
    // 温度の時: 0.00133f * (float)signed_data - 267.146f;
    // その他の時: ((float)signed_data / 8388608.0f) * 3.27f;
}

void initializeADC(int adc_num) {
  // フルリセット
  sendFastCommandReturn(adc_num, FAST_CMD_RESET);
  delay(1);

  writeRegister(adc_num, CONFIG0_REG, 0x32); // Internal clock, conversion
  delay(1);
  writeRegister(adc_num, CONFIG1_REG, 0x0E); // OSR=1024 (高精度維持)
  writeRegister(adc_num, CONFIG2_REG, 0x8B); // BOOST=1x, GAIN=1x
  writeRegister(adc_num, CONFIG3_REG, 0xC0); // Continuous mode
  writeRegister(adc_num, IRQ_REG,     0x07); // IRQ settings

  // ADC開始
  sendFastCommandReturn(adc_num, FAST_CMD_START);
  delay(1);
}

uint8_t sendFastCommandReturn(int adc_num, uint8_t fast_cmd) {
  uint8_t status = 0;
  
  if (adc_num == 0) {
    SPI.beginTransaction(spiSettings);
    digitalWrite(ADC0_CS_PIN, LOW);
    // delayMicroseconds削除 - SPI速度に依存
    status = SPI.transfer(fast_cmd);
    digitalWrite(ADC0_CS_PIN, HIGH);
    SPI.endTransaction();
  } else {
    SPI1.beginTransaction(spiSettings);
    digitalWrite(ADC1_CS_PIN, LOW);
    status = SPI1.transfer(fast_cmd);
    digitalWrite(ADC1_CS_PIN, HIGH);
    SPI1.endTransaction();
  }
  return status;
}

void writeRegister(int adc_num, uint8_t reg, uint8_t data) {
  uint8_t command = DEVICE_ADDR | (reg << 2) | (CMD_INCR_WRITE & 0x03);
  
  if (adc_num == 0) {
    SPI.beginTransaction(spiSettings);
    digitalWrite(ADC0_CS_PIN, LOW);
    SPI.transfer(command);
    SPI.transfer(data);
    digitalWrite(ADC0_CS_PIN, HIGH);
    SPI.endTransaction();
  } else {
    SPI1.beginTransaction(spiSettings);
    digitalWrite(ADC1_CS_PIN, LOW);
    SPI1.transfer(command);
    SPI1.transfer(data);
    digitalWrite(ADC1_CS_PIN, HIGH);
    SPI1.endTransaction();
  }
}

uint32_t readADCData(int adc_num) {
  uint8_t command = DEVICE_ADDR | (ADCDATA_REG << 2) | (CMD_INCR_READ & 0x03);
  uint32_t result = 0;
  
  if (adc_num == 0) {
    SPI.beginTransaction(spiSettings);
    digitalWrite(ADC0_CS_PIN, LOW);
    
    uint8_t status = SPI.transfer(command);
    uint8_t byte1 = SPI.transfer(0x00);
    uint8_t byte2 = SPI.transfer(0x00);
    uint8_t byte3 = SPI.transfer(0x00);
    
    result = ((uint32_t)byte1 << 16) | ((uint32_t)byte2 << 8) | byte3;
    
    digitalWrite(ADC0_CS_PIN, HIGH);
    SPI.endTransaction();
  } else {
    SPI1.beginTransaction(spiSettings);
    digitalWrite(ADC1_CS_PIN, LOW);
    
    uint8_t status = SPI1.transfer(command);
    uint8_t byte1 = SPI1.transfer(0x00);
    uint8_t byte2 = SPI1.transfer(0x00);
    uint8_t byte3 = SPI1.transfer(0x00);
    
    result = ((uint32_t)byte1 << 16) | ((uint32_t)byte2 << 8) | byte3;
    
    digitalWrite(ADC1_CS_PIN, HIGH);
    SPI1.endTransaction();
  }
  
  return result;
}

```