Seeeduino XIAO 背面パッドをGPIOとして使う

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/30370/b4f21419-898a-1830-6820-92d3517bccc8.jpeg"/>

[**Seeeduino XIAO**](https://www.seeedstudio.com/Seeeduino-XIAO-Arduino-Microcontroller-SAMD21-Cortex-M0+-p-4426.html) の背面には 6 つのパッドがあり、そのうち **SWCLK (PA30)** と **SWDIO (PA31)** は GPIO ピンとして使用できます。

# TL;DR

**ボードライブラリ [1.7.6](https://github.com/Seeed-Studio/ArduinoCore-samd/blob/1.7.6/variants/XIAO_m0/variant.cpp#L24-L54) 時点では `pinMode` や `digitalWrite` は使えません。**
代わりにレジスタを直接設定する必要があります。`digitalRead` も同様です。

```cpp:pa30_pa31.ino
void setup() {
  // instead of pinMode(PA30, OUTPUT) and pinMode(PA31, OUTPUT)
  (&(PORT->Group[PORTA]))->PINCFG[30].reg = (uint8_t)(PORT_PINCFG_INEN);
  (&(PORT->Group[PORTA]))->PINCFG[31].reg = (uint8_t)(PORT_PINCFG_INEN);
  (&(PORT->Group[PORTA]))->DIRSET.reg = (1 << 30);
  (&(PORT->Group[PORTA]))->DIRSET.reg = (1 << 31);
}

void loop() {
  // instead of digitalWrite(PA30, HIGH) and digitalWrite(PA31, HIGH)
  (&(PORT->Group[PORTA]))->OUTSET.reg = (1 << 30);
  (&(PORT->Group[PORTA]))->OUTSET.reg = (1 << 31);
  delay(1000);

  // instead of digitalWrite(PA30, LOW) and digitalWrite(PA31, LOW)
  (&(PORT->Group[PORTA]))->OUTCLR.reg = (1 << 30);
  (&(PORT->Group[PORTA]))->OUTCLR.reg = (1 << 31);
  delay(1000);
}
```

# SWCLK/SWDIO パッド

<img width="600" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/30370/ff8d65fd-32e8-c22e-16c3-b3e4fb11aa2b.png"/>


SWD用に用意されたパッドです。Seeeduino XIAO では基板背面に配置されています。上記の XIAO の回路図（該当部分のみ抜粋）からわかるとおり、これらのパッドに繋がっているピンは **PA30**, **PA31** という PORTA の GPIO として利用できます。

他の背面パッドと同様に直接はんだづけしない限りは利用機会は少ないでしょう。しかし、利用できる物理ピン数が限られている XIAO にとって、追加で 2 つも GPIO ピンが使えるメリットは大きいです。

# pinMode と digitalWrite

冒頭で示したとおり、残念ながら `pinMode` と `digitalWrite` は使えません。理想では、Arduino であれば以下のようなスケッチになるはずです。

```cpp:pa30_pa31_ideal.ino
// 注意: このスケッチは動作しない

void setup() {
  pinMode(PA30, OUTPUT);
  pinMode(PA31, OUTPUT);
}

void loop() {
  digitalWrite(PA30, HIGH);
  digitalWrite(PA31, HIGH);
  delay(1000);

  digitalWrite(PA30, HIGH);
  digitalWrite(PA31, HIGH);
  delay(1000);
}
```

実際にはどちらの関数も正しく動作しません。原因は [**variant.cpp**](https://github.com/Seeed-Studio/ArduinoCore-samd/blob/1.7.6/variants/XIAO_m0/variant.cpp#L24-L54) にあります。
variant.cpp には Arduino で指定するピン番号と SAMD21G18 のピン番号などの対応表が定義されています。

```cpp:variant.cpp（抜粋）
const PinDescription g_APinDescription[]=
{
  // 0..10 - Digitabl & Analog pins
  { PORTA,  2, PIO_ANALOG, PIN_ATTR_ANALOG, ADC_Channel0, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_2 }, // ADC/AIN[0]
  { PORTA,  4, PIO_ANALOG, (PIN_ATTR_PWM|PIN_ATTR_TIMER), ADC_Channel4, PWM0_CH0, TCC0_CH0, EXTERNAL_INT_4 }, // ADC/AIN[4]
  { PORTA, 10, PIO_ANALOG, (PIN_ATTR_DIGITAL|PIN_ATTR_PWM|PIN_ATTR_TIMER), ADC_Channel18, PWM1_CH0, TCC1_CH0, EXTERNAL_INT_10 }, 
  { PORTA, 11, PIO_ANALOG, (PIN_ATTR_DIGITAL|PIN_ATTR_PWM|PIN_ATTR_TIMER), ADC_Channel19, PWM1_CH1, TCC1_CH1, EXTERNAL_INT_11 }, 
  
  // ... (snip) ...

  // 14..16 - USB
  // --------------------  
  { PORTA, 28, PIO_COM, PIN_ATTR_NONE, No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_NONE }, // USB Host enable
  { PORTA, 24, PIO_COM, PIN_ATTR_NONE, No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_NONE }, // USB/DM
  { PORTA, 25, PIO_COM, PIN_ATTR_NONE, No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_NONE } // USB/DP

} ;
```

この対応表には PA30, PA31 にあたるエントリがありません。

`pinMode` と `digitalWrite` はこのエントリをもとに、指定されたピン番号に該当するポート名や属性を参照し適切なレジスタを設定します。PA30, PA31 のエントリがないために適切なレジスタが判明せず動作しません。

# レジスタを直接設定

variant.cpp は対応していませんが PA30, PA31 に相当するレジスタは存在します。

`pinMode(PA30, OUTPUT)` に対応する指定は以下になります。

```cpp
(&(PORT->Group[PORTA]))->PINCFG[30].reg = (uint8_t)(PORT_PINCFG_INEN);
(&(PORT->Group[PORTA]))->DIRSET.reg = (1 << 30);
```

`digitalWrite(PA30, HIGH)` および `digitalWrite(PA30, LOW)` に対応する指定は以下になります。

```cpp
(&(PORT->Group[PORTA]))->OUTSET.reg = (1 << 30);  // HIGH
(&(PORT->Group[PORTA]))->OUTCLR.reg = (1 << 30);  // LOW
```

PA31 も同様です。

これ以外のピンモードや `digitalRead` については [**内部実装**](https://github.com/Seeed-Studio/ArduinoCore-samd/blob/1.7.6/cores/arduino/wiring_digital.c#L25) を参照してください。