AVRマイコンをPlatformIOで使う

#免責
この記事に従って発生した如何なる損害も筆者は負うことができません。ご免なさい。

#目標
秋月電子通商さんで手軽に買えるAVRマイコンをコンソールなどCUI/CLIでArduino風に取り扱える環境を整えたいです。この記事ではATtimy13Aを例にしています。
私は今のところATmega328P、ATmega88V、ATtiny2313、ATtiny85、ATtiny13Aを使って、この環境で遊んでいます。

#準備するもの
###Debian/Ubuntu環境
どちらかを用意してください。いわゆるlinuxです。
まだWindowsで、この記事と同じことをする方法は書けていません。ただしVirtualBox使えば解決。
あるいは、Arduinoを使う場合だけWSLも使えるようです。

- パソコン (VirtualBoxでも可)のDebian/Ubuntu
- RaspberryPiなどのLinuxBoxのDebian/Ubuntu

###AVRライター
どれか、ひとつ以上を用意してください。私は専用AVRライターを持っていないので紹介できません。ごめんなさい。

- Arduinoボード ([Arduino Nano](http://akizukidenshi.com/catalog/g/gM-09059/))
- AE-UM232R ([FT232RL USBシリアル変換モジュール](http://akizukidenshi.com/catalog/g/gK-01977/))
- RaspberryPiなどのGPIO

###AVRマイコンと電子工作DIYセット
これらは必要最低限のものです。デジタルトランジスタやスイッチがあると、より楽しいです。

1. AVRマイコン ([ATtiny13A](http://akizukidenshi.com/catalog/g/gI-02911/))
- ブレッドボードとワイヤ
- 抵抗入りLED(もちろんLEDと抵抗(220Ω以上かな)でも可) ([抵抗入りLED](http://akizukidenshi.com/catalog/c/cregled/))

#動かすモノ
###動かす回路
D1ピンにLEDを直接つないでLチカをします。図ではLEDと抵抗が別になっていますが、抵抗入りLEDの方が簡単で省スペースです。
トランジスタを使って別電源でLEDを点けるとPWMを使わずに明るさを調整できます。
回路が完成した後は、RESETやSCK、MISO、MOSIは不要です。
![qiita_attiny13_led_only_ブレッドボード.png](https://qiita-image-store.s3.amazonaws.com/0/190950/7857b0ba-1693-bde0-c4d3-84d01f5dd11f.png)

###動かすスケッチ(プログラム)
D1ピンにLEDをつなぐので、こんなスケッチになります。

```c:main.ino
void setup() {
    pinMode(1, OUTPUT);
}

void loop() {
    digitalWrite(1, HIGH);
    delay(1000);
    digitalWrite(1, LOW);
    delay(1000);
}
```
#共通の準備
- python3-pipのインストール ~~([公式によると](http://docs.platformio.org/en/latest/installation.html#system-requirements)platformioは2.7のみサポートだそうです)~~
- [platformioのインストール] (http://docs.platformio.org/en/latest/installation.html)
- ワークスペースの作成

```shell-session:python3-pipのインストール
$ sudo apt install -y python3-pip
```
```shell-session:platformioのインストール
$ pip3 install --user --upgrade platformio
$ ~/.local/bin/platformio --version
PlatformIO, version 4.1.0
$ ~/.local/bin/platformio platform install atmelavr --with-package tool-avrdude
```
なお、上記のように--userを付けてpip installする場合はplatformioがユーザーのローカルにインストールされるので、~/.local/binが実行パス(\${PATH})に含まれている必要があります。 ~/.local/binは、${PYTHONUSERBASE}で変更している可能性があります。
platformioをアンインストールするには「<font color="Blue">pip3 uninstall platformio</font>」です。

```shell-session:ワークスペースの作成手順
$ mkdir attiny13work
$ cd attiny13work
$ pio init -b attiny13

$ vi src/main.ino # ～スケッチ(main.ino)を前述の通りに作成～
$ vi platformio.ini # ～platformio.iniを「それぞれの準備」の通りに編集～

$ pio run # ここで色々とインストールされるかも
```
<font color="Red">↓のファームウェアの書き込みの前に後述の準備をしてください。</font>

```shell-session:ファームウェアの書き込み
$ pio run -t upload # ←これは、それぞれの準備ができていないと正常に動作しません。
```
~~なお、uploadではなく[programを使う](https://community.platformio.org/t/arduino-uno-avrdude-option-d-added/3363)ようです。私は、ずっとuploadを使っていてエラーが出ていました。~~
#それぞれの準備
##Arduino Nano(arduino)の場合
###準備
Arduinoボード(互換でも可)をAVRライターとして使うために予めArduinoボードに[ArduinoISPソフトウェア](https://raw.githubusercontent.com/arduino/Arduino/master/build/shared/examples/11.ArduinoISP/ArduinoISP/ArduinoISP.ino)を書き込んでおきます。

- [事前にArduinoボードをArduinoISP化する](https://qiita.com/tab4moji/items/f58e12d7d1fbb34179c9)

###接続図 (arduino)
コンデンサを挿したままだとArduinoISPの書き込みに失敗します。
ただしAVRマイコンを書き換えるときにはコンデンサを挿してください。
![qiita_attiny13_led_ブレッドボード.png](https://qiita-image-store.s3.amazonaws.com/0/190950/6db93fad-64dc-45c7-75bd-f8c455fecb2b.png)

###PlatformIO設定 (arduino)
以前upload_protocol = arduinoispとしていて動きませんでした。

```ini:platformio.ini(arduino)
[env:attiny13]
platform = atmelavr
framework = arduino
board = attiny13
;board_build.f_cpu = 8000000L
board_build.f_cpu = 1000000L
upload_protocol = arduino
```

###確認 (arduino)
正しく接続できていれば、AVRマイコンのfuse設定値などの情報を表示することができます。

```console:確認コマンド
$ ~/.platformio/packages/tool-avrdude/avrdude -c arduino -p t13
```
##AE-UM232R(arduino-ft232r)の場合
###準備
AE-UM232RのJ1を図のように、いじって3.3V出力に変えましょう。
3.3VになっているかDSR#などをテスターで確認してください。

- J1で信号を3.3V出力に変更

###接続図 (arduino-ft232r)
![qiita_attiny13_led_um232r_ブレッドボード.png](https://qiita-image-store.s3.amazonaws.com/0/190950/08bea698-6d64-00fc-6cfe-9d3305be65a1.png)

###PlatformIO設定 (arduino-ft232r)
```ini:platformio.ini
[env:attiny13]
platform = atmelavr
framework = arduino
board = attiny13
;board_build.f_cpu = 8000000L
board_build.f_cpu = 1000000L
upload_protocol = arduino-ft232r
upload_port = ft0
upload_speed = 300
```
###確認 (arduino-ft232r)
正しく接続できていれば、AVRマイコンのfuse設定値などの情報を表示することができます。

```console:確認コマンド
$ ~/.platformio/packages/tool-avrdude/avrdude -c arduino-ft232r -b 300 -p t13
```
##GPIO(linuxgpio)の場合
###準備 (linuxgpio)
linuxgpioでは、どのピンを何に使うのか設定するために~/.avrdudercを用意してください。
avrdudeを実行したときに「<font color="Red">Can't export GPIO 17, already exported/busy?: Invalid argument</font>」などのエラーが出ることがあります。これはavrdudeがlinuxgpioに対応していない可能性があります。このときはaptのavrdudeパッケージを使うように~/.platformio以下のavrduddeコマンドを置き換えてみて下さい。
あと「<font color="Red">*** [upload] could not open port ft0: [Errno 2] No such file or directory: 'ft0'</font>」というエラーが出ることがあります。platformio.iniと同じディレクトリにft0をtouchで作成してみてください。

- ~/.avrdudercを用意
- 場合によってはavrdudeを置き換え
- ft0をtouchして作成する

```VimL:RaspberryPi用の~/.avrduderc
programmer
  id    = "linuxgpio";
  desc  = "Use the Linux sysfs interface to bitbang GPIO lines";
  type  = "linuxgpio";
  sck   = 2; # ここは環境に合わせて変更してください
  miso  = 3; # ここは環境に合わせて変更してください
  mosi  = 4; # ここは環境に合わせて変更してください
  reset = 17; # ここは環境に合わせて変更してください
;
```

###接続図 (linuxgpio)
RaspberryPiでは、前述の~/.avrdudercを設定して、このように接続します。
![qiita_attiny13_led_gpio_ブレッドボード.png](https://qiita-image-store.s3.amazonaws.com/0/190950/28c4b922-acbf-e8a1-9445-7132c239a320.png)

###PlatformIO設定 (linuxgpio)
```ini:platformio.ini
[env:attiny13]
platform = atmelavr
framework = arduino
board = attiny13
;board_build.f_cpu = 8000000L
board_build.f_cpu = 1000000L
upload_protocol = linuxgpio
upload_port = ft0
upload_speed = 300
```

###確認 (linuxgpio)
正しく接続できていれば、AVRマイコンのfuse設定値などの情報を表示することができます。

```console:確認コマンド
$ ~/.platformio/packages/tool-avrdude/avrdude -c linuxgpio -p t13
```

#うまく動かないとき
###AE-UM232R(arduino-ft232r)でISPの代わりは割と微妙
特に、ATtiny13Aを1.2MHzで動かしているとfuseが読めなかったり、反応が悪いことがあります。
arduinoやlinuxgpioの方が、いいかも。
###avrdudeコマンドにルート権限がないとダメ
avrdudeコマンドにルート権限がないと駄目なことがあるようです。
linuxgpioの場合は「<font color="Red">Can't open gpioX/direction: Permission denied</font>」や「<font color="Red">Can't export GPIO 17, already exported/busy?: Invalid argument</font>」などのエラーが出ます。後者のメッセージはavrdudeが一度gpioへのアクセスに失敗した後出ます。

```shell-session:ユーザーをdialoutグループに入れてみる
$ sudo adduser `whoami` dialout
```
```shell-session:avrdudeコマンドにルート権限を与えてみる
$ sudo chmod a+s `which avrdude`
$ sudo chmod a+s ~/.platformio/packages/tool-avrdude/avrdude
```
```shell-session:avrdudeにルート権限なしで失敗したときの後始末
$ echo 17 > /sys/class/gpio/unexport # 前述の~/.avrdudercを設定した場合
$ echo 2 > /sys/class/gpio/unexport # 前述の~/.avrdudercを設定した場合
$ echo 3 > /sys/class/gpio/unexport # 前述の~/.avrdudercを設定した場合
$ echo 4 > /sys/class/gpio/unexport # 前述の~/.avrdudercを設定した場合
```
###PlatformIOのavrdudeがlinuxgpioに対応していない
、PlatformIOのavrdudeコマンドがlinuxgpioに対応していない可能性があります。
その場合は、aptのavrdudeパッケージをインストールしてみて下さい。そして~/.platformio以下のavrdudeコマンドと置き換えてみて下さい。
ただし「--with-package tool-avrdude」を付けてplatformioをインストールしていない場合は、「pio run -t program」した後でないと、~/.platformio以下のavrdudeが配置されませんのでご注意を。

```shell-session:場合によっては、avrdudeを置き換え
$ sudo apt install -y avrdude
$ pushd ~/.platformio/packages/tool-avrdude
$ mv avrdude avrdude.old
$ popd 
```

###RaspberryPI Zero Wの新しいaptのavrdudeだとAE-UM232Rが動かなかった
RaspberryPI Zero W用のavrdude=6.3+r1425-1+rpt1バージョンでは「<font color="Red">avrdude: ft245r_open(): invalid device identifier '        '</font>」というようなエラーが出ました。代わりにavrdude=6.3-2バージョンを入れました。

```shell-session:RPiZeroWではaptの古いavrdudeパッケージを入れた
$ apt-cache madison avrdude
   avrdude | 6.3+r1425-1+rpt1 | http://archive.raspberrypi.org/debian stretch/main armhf Packages
   avrdude |      6.3-2 | http://raspbian.raspberrypi.org/raspbian stretch/main armhf Packages
$ sudo apt install -y --allow-downgrades avrdude=6.3-2
$ sudo apt-mark hold avrdude
```
なお、<font color="Blue">sudo apt-mark unhold avrdude && sudo apt upgrade</font>で、元に戻せます。

#その他のメモ
ここの情報は確認が不足しているので自信がありません。
###AVRマイコンの種類とplatform ID
http://docs.platformio.org/en/latest/platforms/atmelavr.html
delay関数は<util/delay.h>の_delay_ms関数で代用してます。INPUT_PULLUPはpinMode関数でINPUTにしてからdigitalWrite関数でHIGHにします(後述)。
↓は「<font color="Blue">pio boards</font>」で出力した結果をまとめたものです。

| AVRマイコン|platform ID|avrdude partno|特徴|
|:--|:--|:--|:--|
|ATtiny13A|attiny13|t13|INPUT_PULLUPなし|
|ATiny85|attiny85|t85||
|ATmega328P|pro8MHzatmega328|m328p||
|ATmega88V|bob3|m88|delay関数なし|

###AVRマイコンのfuse設定値(書き換え危険)
fuse設定は特に注意です。失敗すると12Vが必要になったり、ISPが使えなくなったり、外部クロックが必要になったり大変な目に会います。
<font color="Red">まだまだ未確認です。fuseの値は確認してください。</font>

|AVR|Hz|Ex|Hi|Lo|
|:--|:--|:--:|:--:|:--:|
|ATtiny13A|1.2MHz|-|FF|6A|
|ATtiny13A|9.6MHz|-|FF|7A|
|ATtiny85|1MHz|FF|DF|62|
|ATtiny85|8MHz|FF|DF|e2|
|ATtiny85|16MHz|Fe|DD|e1|
|ATmega328P|1MHz|FF|D9|62|
|ATmega328P|8MHz|FF|D9|e2|
|ATmega88V|1MHz|F9|DF|62|
|ATmega88V|8MHz|F9|DF|e2|

#最後に
これは自分のためのメモですが、なるべく拡充していこうと思います。

#参考
みなさまのおかげです。

###Qiita
[Debian 系であえて古い APT パッケージをインストールする方法](https://qiita.com/kitsuyui/items/d8940e093fa41b58fe71)
[pipに--userをつけた時のインストール先を変える](https://qiita.com/ronin_gw/items/cdf8112b61649ca455f5)

###ATTiny13Aのデータシート 
内蔵プルアップ抵抗あり(1.1.3 Port B (PB5:PB0)
内蔵プルアップ抵抗値は20kΩ～50kΩ (Table 18-1)
http://ww1.microchip.com/downloads/en/DeviceDoc/doc8126.pdf

###意外と知られていない？INPUT_PULLUP
INPUT_PULLUPが便利
http://mag.switch-science.com/2013/05/23/input_pullup/

###Digital Pins
INPUT_PULLUPが無いときはINPUTにしてからHIGHにする
https://www.arduino.cc/en/Tutorial/DigitalPins

###Fritzing.org
回路を描くためのツールです
http://fritzing.org

###DENSIKIT.COMさんのAE-UM232Rの電子パーツ
こういうものを作れるのは凄いですね
https://sites.google.com/a/densikit.com/ds/home/fritzing