Feather M4 Expressを使ってみる

どこに需要あるかは分からないけど備忘録です。

個人的には Arduino 互換ボードの中では高性能で公式ドキュメントも充実してるので、1枚あれば色々と遊べるオススメボードです。

~~Espressif ESP は宗教上の理由で NG~~


# Feather M4 Express

![](https://cdn-learn.adafruit.com/assets/assets/000/057/476/small360/arduino_compatibles_pinout.jpg)

- [Feather M4 Express - Adafruit](https://learn.adafruit.com/adafruit-feather-m4-express-atsamd51)

Arduino M0 等でお馴染み SAMD21 の兄貴分である SAMD51 を搭載した Adafruit 社製 Arduino 互換ボードです。

"Feather" シリーズとしてエコシステムを構築しており、同フォームファクタで Mega328P や SAMD21 を搭載したボードのほか、拡張基板やアクセサリなども多数展開されています。


# SAMD51

- [ATSAMD51J19 - Microchip](https://www.microchip.com/wwwproducts/en/ATSAMD51J19A)

Cortex-M4F を搭載した Microchip 社製 MCU です。
SAMD21 の上位互換的な存在なので、SAMD 向けライブラリならほぼ使えます。

なお Adafruit 社の Cortex-M4F 搭載ボードは、`float`型が存在すると自動的に FPU が適用されるとの事です。

ハードウェアスペックをざっくりおさらい。
高性能なので、何をするにも困る事は無いと思います。

||AT SAMD21 G18|AT SAMD51 J19|
|:--|:--|:--|
|Architecture|ARM<br>Cortex-M0+|ARM<br>Cortex-M4F|
|Frequency|48 MHz|120 MHz|
|RAM|32 KB|192 KB|
|Flash ROM|256 KB|512 KB|
|I/O|USB, Serial, I2C, SPI, I2S<br>etc...|USB, Serial, I2C, SPI, I2S, QSPI<br>etc...|
|ADC|12 bit<br>350 kSPS<br>x1<br>(16 bit HW over sampling)|12 bit<br>1000 kSPS<br>x2<br>(16 bit HW over sampling)|
|DAC|10 bit<br>350 kSPS<br>x1|12 bit<br>1000 kSPS<br>x2|
|Accelerator||FPU, SHA256, AES, RSA|


# 使ってみる
## 割込タイマ
マイコンって大体、割込タイマとか DMA とか、レジスタ操作が絡んでくる辺りから訳が分からなくなるんですよね...

今回は、Adafruit 公式から割込タイマのライブラリが公開されていたので、物は試しで使ってみます。

- [Adafruit ZeroTimer - GitHub](https://github.com/adafruit/Adafruit_ZeroTimer)


### インストール
ArduinoIDE の "ライブラリ管理" で、`Adafruit ZeroTimer`をインストールしておきます。


### ライブラリ仕様
クロックソースは`DFLL48M`が使われているようです。
~~これは内蔵の発振逓倍回路で生成される CPU クロック源です。~~

折角ボード上に`32.768 kHz`の`XOSC32K`水晶が載っているので使いたいところですが、指定方法がよく分からなかったので課題としておきます。

> 【訂正】
CPU クロック源は`FDPLL200M`でした。
全てのクロックソースは`32.768 kHz`の`XOSC32K`水晶から`GCLKx`で逓倍され、`DFLL48M`や`FDPLL200M`に分配されます。
`DFLL48M`は1系統のみで`48 MHz`を出力するクロックソースです。
`FDPLL200M`は2系統あり`48 MHz ~ 200 MHz`まで任意に出力可能なクロックソースです。
[32.768kHz, 8MHz, or 48MHz External Crystal for D51 - avrfreaks](https://www.avrfreaks.net/forum/32768khz-8mhz-or-48mhz-external-crystal-d51)


TCは3系統が使えます。

- `TC3`
- `TC4`
- `TC5`

プリスケーラは以下から選択可能です。

- `1 (TC_CLOCK_PRESCALER_DIV1)`
- `2 (TC_CLOCK_PRESCALER_DIV2)`
- `4 (TC_CLOCK_PRESCALER_DIV4)`
- `8 (TC_CLOCK_PRESCALER_DIV8)`
- `16 (TC_CLOCK_PRESCALER_DIV16)`
- `64 (TC_CLOCK_PRESCALER_DIV64)`
- `256 (TC_CLOCK_PRESCALER_DIV256)`
- `1024 (TC_CLOCK_PRESCALER_DIV1024)`

カウンタサイズは以下の3つから選択可能です。

- `8 bit (TC_COUNTER_SIZE_8BIT)`
- `16 bit (TC_COUNTER_SIZE_16BIT)`
- `32 bit (TC_COUNTER_SIZE_32BIT)`

タイマチャネルは以下2つから選択可能です

- `0 (TC_CALLBACK_CC_CHANNEL0)`
- `1 (TC_CALLBACK_CC_CHANNEL1)`

`32 bit`カウンタが使えるので、コンパレータと組み合わせて微調整が出来ます。
が、`32 bit`は試したところ上手く動かなかったので検証中です。

> 【追記】
`32 bit`カウンタは偶数タイマでしか使えないとの記載がありました。
つまり、このライブラリだと`TC4`でのみ使えるという事になります。

### コード
```c++:ZeroTimer.ino
#include "Adafruit_ZeroTimer.h"

// Timerインスタンスを作成
Adafruit_ZeroTimer tc3 = Adafruit_ZeroTimer(3);
// Adafruit_ZeroTimer tc4 = Adafruit_ZeroTimer(4);
// Adafruit_ZeroTimer tc5 = Adafruit_ZeroTimer(5);

// これが無いと動かなかったのでおまじない
void TC3_Handler(){
    Adafruit_ZeroTimer::timerHandler(3);
}
// void TC4_Handler(){
//     Adafruit_ZeroTimer::timerHandler(4);
// }
// void TC5_Handler(){
//     Adafruit_ZeroTimer::timerHandler(5);
// }

// 割込コールバック
void tc3Callback(){
    Serial.print(".");
}

void setup(){
    Serial.begin(115200);
    while(!Serial);

    // タイマ設定
    // プリスケーラ: 2
    // カウンタ: 16bit
    // 波形生成: PWM (あまり気にしないでOK)
    tc3.configure(TC_CLOCK_PRESCALER_DIV2, TC_COUNTER_SIZE_16BIT, TC_WAVE_GENERATION_NORMAL_PWM);

    // コンパレータ設定
    // チャネル: 0
    // コンペア値: 0xFFFF
    tc3.setCompare(0, 0xFFFF);

    // コールバック設定
    // チャネル: 0
    // コールバック関数: tc3Callback
    tc3.setCallback(true, TC_CALLBACK_CC_CHANNEL0, tc3Callback);

    // 割込ループ開始
    tc3.enable(true);
}

void loop(){}

// 割込周期T
// 48000000 (Hz)
// 2 (PreScaler)
// 65536 (16bit)

// 48000000 / 2 / 65536 = 366.21 (Hz)
// 1 / 366.21 = 0.00273 (s)
```

シリアル接続すると`.`が無限に出力されると思います。


## オーバークロックと最適化
コンピュータオタクのサガ、速さは正義。

つい最近のツールチェインアップデートで、SAMD51 のオーバークロック関連が解禁されたので、早速試してみます。


### 要件
- Adafruit SAMD Boards v1.4.0 ~


### インストール
ArduinoIDE の "ボードマネージャ" で、`Adafruit SAMD Boards`を最新にしておきます。


### 設定
![featherm4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/253070/4a48d8a1-9b2c-2497-a06c-07cb790de1b2.png)


#### Cache
キャッシュを有効化する事で、通常 FlashROM からより高速なアクセスが可能となります。
デフォルトで有効化されているので、そのままで問題ありません。

- `Enable` (Default)
- `Disable`


#### CPU Speed
CPU のオーバークロック設定です。
試したところ`200 MHz`でも発熱や異常終了はありませんでした。

- `120 MHz` (Default)
- `150 MHz`
- `180 MHz`
- `200 MHz`


#### Optimize
コンパイラの最適化設定です。
`Fastest`まではバイナリ互換性がありますが`Here be dragons`では互換性が損なわれ、実行エラーを招く可能性がある、との事です。

- `Small (-Os)` (Default)
- `Fast (-O2)`
- `Faster (-O3)`
- `Fastest (-Ofast)`
- `Here be dragons (-Ofast -funroll-loops)`


#### Max SPI
~~SPI バスのオーバークロック設定です。~~
~~結構デリケートなので`50 MHz`にすると大半の機器が動かなくなるとの事です。~~
~~デフォルトの`24 MHz`が推奨されています。~~

- ~~`24 MHz` (Default)~~
- ~~`50 MHz`~~
- ~~`CPU Speed / 2`~~

**2019/07/25追記**
Max SPI の項目はいつの間にか削除されていました。


#### Max QSPI
QSPI バスのオーバークロック設定です。
と言っても、接続されているのはボード上の SPI Flash だけなのですが。

- `50 MHz` (Default)
- `CPU Speed / 2`


# ToDo...
I2S と DMA ライブラリの検証をしているので、動くようになったら記事にまとめようと思います。

- [Adafruit ZeroI2S - GitHub](https://github.com/adafruit/Adafruit_ZeroI2S)
- [Adafruit ZeroDMA - GitHub](https://github.com/adafruit/Adafruit_ZeroDMA)