ArduinoをArduino IDEなしで頑張る

# この記事について
ArduinoをArduino IDEなしで開発していきます。
なぜ、そんな面倒なことをするのかだって？暇だったから以外には理由はない。

# 必要なもの
この記事と同じことをするには以下のものが必要です。
* Arduino UNO Rev.3(Atmega328P搭載)
    [アマゾンで買えます](https://www.amazon.co.jp/ELEGOO-ATmega328P-ATMEGA16U2-USB%E3%82%B1%E3%83%BC%E3%83%96%E3%83%AB-Arduino%E7%94%A8/dp/B06Y5TBNQX/ref=sr_1_2_sspa?adgrpid=53389878716&dchild=1&gclid=CjwKCAiA25v_BRBNEiwAZb4-ZevUV-FQPWnpUwyplNKfVUoPrch47A5MQcurkrdD2hT9RvYbAf19wxoC0LMQAvD_BwE&hvadid=259339959493&hvdev=c&hvlocphy=1009383&hvnetw=g&hvqmt=e&hvrand=12995423076952090773&hvtargid=kwd-299835594131&hydadcr=2013_10144829&jp-ad-ap=0&keywords=amazon+arduino&qid=1608989419&sr=8-2-spons&tag=googhydr-22&psc=1&spLa=ZW5jcnlwdGVkUXVhbGlmaWVyPUEzVU9JSVMzWVlLSVVWJmVuY3J5cHRlZElkPUEwNzIyMjU5MTBEWUpaQlAxSEJIUSZlbmNyeXB0ZWRBZElkPUEzRU9DMDRMWEUyODQ5JndpZGdldE5hbWU9c3BfYXRmJmFjdGlvbj1jbGlja1JlZGlyZWN0JmRvTm90TG9nQ2xpY2s9dHJ1ZQ==)
搭載されているMCUがAtmega328Pでない場合はこの記事で紹介するコードの編集が必要です。

* PC(Ubuntu20.04 LTS搭載) 
同じ方法が通用すると思われますが、WindowsやMacでは環境構築に苦労します。ubuntuならパッケージマネージャから一発で手に入ります。

* USBケーブル
書き込みに使います。

# 開発環境セットアップ
Ubuntu20.04 LTS環境を前提にして話を進めます。
まず、以下の開発に必要なツールを揃えます。

1. gcc-avr  
      avrのクロスコンパイラです。
2. avr-libc  
       AVRのCライブラリです。
3. avrdude  
       AVRのIntel Hexファイルのライタアプリケーションです。

以下のコマンドにより一発で手に入ります。
```
sudo apt install gcc-avr avr-libc avrdude
```

# ビルドディレクトリを作る
以下のようにビルドディレクトリを作ります。

![Document.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/77676/a5f95ce6-e019-52d3-f8d0-5a3488deefc0.png)



# Makefileを書く
ビルドステップは以下のようなステップを踏みます。

![Document-1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/77676/3db80ff6-7961-a68e-d614-890e0c3906a1.png)

このビルドステップをmakeファイルに直すと以下のようになります。

```makefile
#!/usr/bin/make -f

# setting output file
OUT = build/Program.ihex

# compiler setting
CC = avr-gcc
CFILES = $(wildcard src/*.c)
CPU_FREQ = 16000000
CFLAGS = -c -std=gnu99 -Os -Wall -ffunction-sections -fdata-sections -mmcu=atmega328p

# linker setting
LD = avr-gcc
OBJFILES = $(addprefix build/, $(notdir $(CFILES:.c=.o)))
LDFLAGS = -Os -mmcu=atmega328p -ffunction-sections -fdata-sections -Wl,--gc-sections

#  objcopy setting
OBJCOPY = avr-objcopy
OBJFLAGS = -O ihex -R .eeprom 

# avrdude setting
AVRDUDE = avrdude
PORT = /dev/ttyACM0
AVRDUDECONF = ./conf/avrdude.conf
AVRDUDEFLAGS = -C $(AVRDUDECONF) -v -V -p atmega328p -carduino -b 115200 -P $(PORT) -D

# Build Step Setting
all : $(OUT)

$(OUT) : $(OUT:.ihex=.elf)
	$(OBJCOPY) $(OBJFLAGS) $^ $@

$(OUT:.ihex=.elf) : $(OBJFILES)
	$(LD) $(LDFLAGS) $^ -o $@

build/%.o : src/%.c
	$(CC) $(CFLAGS) -DF_CPU=$(CPU_FREQ) $^ -o $@

upload : $(OUT)
	$(AVRDUDE) $(AVRDUDEFLAGS) -U flash:w:$^:i

clean :
	rm -rf build/*.o
	rm -rf build/*.ihex
	rm -rf build/*.elf

.PHONY : all upload clean
```

このmakefileはsrc/ディレクトリ以下の*.cファイルを抽出してビルドします。
ビルド生成物はbuild/ディレクトリに配置されます。

ビルドするには以下のコマンドを実行します。

```sh
make all
```

ビルド時の設定はmakefile内の以下の変数の値を書き換えることで設定できます。

| 変数名 | 設定内容 |
|-------|---------|
| CPU_FREQ | CPU動作周波数（デフォルトは16MHz) |
| PORT | Arduinoが接続されたポート |

ビルドしたファイルをArduinoに書き込みたいときは

```sh
make upload
```

を実行します。

ビルド生成物を削除したいときは

```sh
make clean
```

でbuild/ディレクトリ内のビルド生成物が削除されます。

# avrdudeの設定
avrdudeの設定はconf/avrdude.confファイルに書きます。
avrdude.confの勉強がめんどくさかったのでArduino IDEの設定を~~パクリ~~参考にします。
Arduino IDEのavrdudeの設定はhardware/tools/avr/etcにあります。
同じものはGithubにもあります。

https://github.com/arduino/arduino-flash-tools/blob/master/tools_linux_64/avrdude/etc/avrdude.conf

書き込みにはシリアルポートのアクセス制限変更が必要です。
書き込み前に以下のコマンドを実行してください。

```sh
sudo chmod a+rw /dev/ttyACM0
```

環境によってはttyACM0がttyACM1だったりttyACM2だったりします。

# コードを書く

src/Main.cにコードを書きましょう。
組み込みエンジニアおなじみのLチカをやりましょう。
まず、Arduinoの回路図を見てどのピンがオンボードのLEDに接続されているかを調べます。

Arduinoの回路図は以下のリンクから見れます。

https://www.arduino.cc/en/uploads/Main/Arduino_Uno_Rev3-schematic.pdf

![Screenshot from 2020-12-26 20-56-57.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/77676/5cf2cf54-bc71-5473-4a9b-75730250057e.png)

PIN13がオンボードLEDに接続されていることがわかります。13PINをHighに設定できればLEDが光ることがわかります。13PINがどこに接続されているかたどっていくと…

![Screenshot from 2020-12-26 21-49-41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/77676/d48d06eb-793b-8b98-e064-8d7325142479.png)


PB5ピンということがわかりました。

次にAtmega238pのマニュアルを調べます。

https://ww1.microchip.com/downloads/en/DeviceDoc/ATmega48A-PA-88A-PA-168A-PA-328-P-DS-DS40002061B.pdf

> The DDxn bit in the DDRx Register selects the direction of this pin. If DDxn is written logic one, Pxn is configured as an output pin. If DDxn is written logic zero, Pxn is configured as an input pin.

さらに、

> If PORTxn is written logic one when the pin is configured as an output pin, the port pin is driven high (one). If PORTxn is written logic zero when the pin is configured as an output pin, the port pin is driven low (zero).

とあります。
というわけでsrc/Main.cに以下のようなコードを書きます。

```c:
#include <avr/io.h>
#include <util/delay.h>

#define MS_DELAY 500

void setup(void);
void loop(void);

int main(void)
{
    setup();

    while (1)
    {
        loop();
    }
}

void setup(void)
{
    /* configure PB5 pin as an output pin */
    DDRB |= _BV(DDB5);
}

void loop(void)
{
    /* set PB5 pin high */
    PORTB |= _BV(PORTB5);

    /*Wait 500 ms */
    _delay_ms(MS_DELAY);

    /* set PB5 pin low */
    PORTB &= ~_BV(PORTB5);

    /*Wait 500 ms */
    _delay_ms(MS_DELAY);

    /* set PB5 pin high */
    PORTB |= _BV(PORTB5);

    /*Wait 500 ms */
    _delay_ms(MS_DELAY);

    /* set PB5 pin low */
    PORTB &= ~_BV(PORTB5);

    /*Wait 500 ms */
    _delay_ms(MS_DELAY);

    /* set PB5 pin high */
    PORTB |= _BV(PORTB5);

    /*Wait 2000 ms */
    _delay_ms(MS_DELAY);
    _delay_ms(MS_DELAY);
    _delay_ms(MS_DELAY);
    _delay_ms(MS_DELAY);

    /* set PB5 pin low */
    PORTB &= ~_BV(PORTB5);

    /*Wait 500 ms */
    _delay_ms(MS_DELAY);
}
```

かけたら

```sh
make all
```

Arduinoをパソコンに接続して

```sh
make upload
```

します。

そうすると、以下のようにLEDがチカチカします。

https://www.youtube.com/watch?v=SDSMGKEa5V0

# Githubレポジトリ
この記事で使用したコードは以下のレポジトリから手に入れることができます。

https://github.com/MoriokaReimen/ArduinoDev

# 参考文献

* [Arduino本家](https://www.arduino.cc/)
* [MICROCHIP Technology - ATmega328P](https://www.microchip.com/wwwproducts/en/ATmega328p)
* [GNU.org - Simple Makefile(GNU make)](https://www.gnu.org/software/make/manual/html_node/Simple-Makefile.html)
* [Introduction to Bare Metal Programming in Arduino Uno ](https://create.arduino.cc/projecthub/milanistef/introduction-to-bare-metal-programming-in-arduino-uno-f3e2b4)