アナログ回路への理解を深めたい。まだ全然、やりたいことをすぐに実現できるレベルにならない。どうすればできるのかわからない、ということが多すぎる。
✖
|
アナログ回路への理解を深めたい。まだ全然、やりたいことをすぐに実現できるレベルにならない。どうすればできるのかわからない、ということが多すぎる。
2015年もたくさんコードかきました。他人に承認されないことはせめて自分で承認しましょう。つらい
[tech] リファレンスマニュアルをインクリメンタル検索するやつを Electron で実装した | Wed, Oct 14. 2015 - 氾濫原
ドキュメントビューワ。Mac AppStore まで出してみたが全く売れておりません。自分では便利に使ってる
[tech] Arduino の digitalWrite / pinMode / digitalRead をコンパイル時に展開する | Wed, Dec 16. 2015 - 氾濫原
digitalWrite とかを静的に解決するやつ。
[tech] もう僕らは OpenGL ライブラリにリンクするビルドに悩むことはない | Thu, Oct 8. 2015 - 氾濫原
KX3(無線機)用のパナダプター(Panoramic Adapter = FFTウォーターフォール) WebGL に書きなおしたりした。便利
[tech] CNC フライス Grbl 制御編 | Sun, Aug 16. 2015 - 氾濫原
CNCフライス制御用のアプリケーション。最近あんまり切削してない。
[tech] スクリーンキャスト用のキーストローク表示アプリ | Sat, Feb 14. 2015 - 氾濫原
入力したキーを画面に表示するやつ。
[tech] CopyHook というペーストボードの中身をいじるツールを作った | Wed, Mar 18. 2015 - 氾濫原
クリップボードコピーしたときにフックでJS実行するやつ。なんかうまく動いてない気がするがデバッグの時間がとれない。
[tech] JavaScript で書かれたリードソロモン符号のエンコーダ・デコーダ | Tue, Mar 31. 2015 - 氾濫原
任意のリードソロモン(誤り訂正)符号のエンコーダデコーダ。Zxing (Java) の一部ライブラリの移植
[tech] WebAudio の BiquadFilterNode の周波数特性をグラフにするやつ | Fri, Mar 20. 2015 - 氾濫原
WebAudio のフィルタの周波数特性を出すやつ。
[tech] デカい文字をA4で分割して印刷するツールをJSで書いた | Sat, Mar 7. 2015 - 氾濫原
ー https://cho45.stfuawsc.com/dekaimoji-a4/
A4プリンタでデカい文字が印刷できるやつ。
C/C++にはほとんど使われてないがビットフィールドという機能がある。
union {
uint8_t raw;
struct {
unsigned FAULT_QUEUE : 2;
unsigned CT_PIN_POLARITY : 1;
unsigned INT_PIN_POLARITY : 1;
unsigned INT_CT_MODE : 1;
unsigned OPERATION_MODE : 2;
unsigned RESOLUTION : 1;
};
} config; このように書ける。struct 内で名前の後ろについているのが、そのフィールドで消費するビット数で、この場合合計で8bitになり、それを uint8_t と共用している。
こうすると config.OPERATION_MODE = 2; などと、マスクやシフトを伴わずに直接書けて、結果をconfig.rawでとれる。
めっちゃ便利なので使わない手はなさそうだと思いきや、実際のところ実用するのは不安がある。というのも、この struct 内のビット配置の順序は実装依存となっていて、uint8_t として評価したとき、どのような結果が返ってくるか確かなことがいえない。
コンパイラ依存
そこで、上記のようなビットフィールドを以下のように書きなおす
template <class T, uint8_t s, uint8_t e = s>
struct bits {
T ref;
static constexpr T mask = (T)(~( (T)(~0) << (e - s + 1))) << s;
void operator=(const T val) { ref = (ref & ~mask) | ((val & (mask >> s)) << s); }
operator T() const { return (ref & mask) >> s; }
};
template <uint8_t s, uint8_t e = s>
using bits8 = bits<uint8_t, s, e>;
union {
uint8_t raw = 0;
bits8<0, 1> FAULT_QUEUE ;
bits8<2> CT_PIN_POLARITY ;
bits8<3> INT_PIN_POLARITY ;
bits8<4> INT_CT_MODE ;
bits8<5, 6> OPERATION_MODE ;
bits8<7> RESOLUTION ;
} config; uint8_t 全体を明確に共用する複数のstructという形にし、明示的にビットシフトやマスクを行っている。それぞれ、テンプレートの第一引数〜第二引数のビットを扱うクラスになっている。
組み込みで他のデジタルICとやりとりをする場合、だいたいデータシートには [0:1] foobar みたいな形でビット範囲と値の説明が書いてあるので、それをその通り書きうつして union を作れば間違いなくビット操作できる状態になる。
これで安心してビットフィールドっぽいものが使える。
試した限りだと完全にインライン化される。また、1bitだけ書く場合andかorだけにまで最適化される。
int main(void) {
asm volatile ("nop");
config.OPERATION_MODE = 0b11;
asm volatile ("nop");
config.RESOLUTION = 1;
asm volatile ("nop");
config.FAULT_QUEUE = 1;
asm volatile ("nop");
for (;;) {
}
return 0;
}
こういうコードは
000000a0 <main>: a0: 00 00 nop a2: 00 00 nop a4: 00 00 nop a6: 80 91 00 01 lds r24, 0x0100 aa: 8c 71 andi r24, 0x1C ; 28 ac: 81 6e ori r24, 0xE1 ; 225 ae: 80 93 00 01 sts 0x0100, r24 b2: 00 00 nop b4: ff cf rjmp .-2 ; 0xb4 <main+0x14>
こうなる
| #include <cstdio> | |
| #include <stdint.h> | |
| #include <iostream> | |
| template <class T, class U> | |
| void is(T got, U expected) { | |
| if (got == expected) { | |
| std::cout << "ok" << std::endl; | |
| } else { | |
| std::cout << "not ok " << got << " != " << expected << std::endl; | |
| } | |
| } | |
| template <class T, uint8_t s, uint8_t e = s> | |
| struct bits { | |
| T ref; | |
| static constexpr T mask = (T)(~( (T)(~0) << (e - s + 1))) << s; | |
| void operator=(const T val) { ref = (ref & ~mask) | ((val & (mask >> s)) << s); } | |
| operator T() const { return (ref & mask) >> s; } | |
| }; | |
| template <uint8_t s, uint8_t e = s> | |
| using bits8 = bits<uint8_t, s, e>; | |
| int main () { | |
| union { | |
| uint8_t raw = 0; | |
| bits8<0, 1> FAULT_QUEUE ; | |
| bits8<2> CT_PIN_POLARITY ; | |
| bits8<3> INT_PIN_POLARITY ; | |
| bits8<4> INT_CT_MODE ; | |
| bits8<5, 6> OPERATION_MODE ; | |
| bits8<7> RESOLUTION ; | |
| } config; | |
| config.OPERATION_MODE = 0b11; | |
| is((uint)config.raw, 0b01100000); | |
| config.FAULT_QUEUE = 0b10; | |
| is((uint)config.raw, 0b01100010); | |
| config.RESOLUTION = 1; | |
| is((uint)config.raw, 0b11100010); | |
| config.OPERATION_MODE = 0; | |
| is((uint)config.raw, 0b10000010); | |
| config.raw = 0; | |
| is((uint)config.OPERATION_MODE, 0b00); | |
| config.raw = 0b01000000; | |
| is((uint)config.OPERATION_MODE, 0b10); | |
| config.FAULT_QUEUE = 0b111; | |
| is((uint)config.raw, 0b01000011); | |
| return 0; | |
| } |
I2Cセンサーとかを扱うと固定小数点表現によく出会う。が、固定小数点のままだと計算がめんどうなので、とりあえず浮動小数点に変換しときたいというケースがまぁまぁある。
そういうときに雑に使えるスニペットがほしかったので書いた。
#include <type_traits>
template <uint8_t int_bits, uint8_t fractional_bits, class T>
inline float fixed_point_to_float(const T fixed) {
static_assert(std::is_unsigned<T>::value, "argument must be unsigned");
constexpr uint8_t msb = int_bits + fractional_bits - 1;
constexpr T mask = static_cast<T>(~(( static_cast<T>(~0)) << msb));
constexpr float deno = 1<<fractional_bits;
if (fixed & (1<<msb)) {
// negative
return -( ( (~fixed & mask) + 1) / deno);
} else {
// positive
return fixed / deno;
}
} type_traits がない環境の場合、include と static_assert を消すだけで動く。これはエラーチェックにしか使ってなくて、もし消したとしても、負の signed を渡すと左シフトが不正になるのでエラーになる。
センサ出力とかの場合、8bit単位のビット数ではないことが多いので、渡された型のサイズに関わらずに処理できるようにマスクを作っている。
// usage
int main (int argc, char* argv[]) {
// from ADT7410 datasheet
is(fixed_point_to_float<9, 4>((uint16_t)0b0000000000001), 0.0625);
is(fixed_point_to_float<9, 4>((uint16_t)0b0100101100000), 150.0);
is(fixed_point_to_float<9, 4>((uint16_t)0b0000000000000), 0);
is(fixed_point_to_float<9, 4>((uint16_t)0b1110010010000), -55.0);
is(fixed_point_to_float<9, 4>((uint16_t)0b1111111111111), -0.0625);
is(fixed_point_to_float<9, 4>((uint32_t)0b1111111111111), -0.0625 );
/** compile error : argument must be unsigned
printf("%f\n", fixed_point_to_float<9, 4>((int16_t)0b1111111111111));
*/
// from MCP3425 datasheet
is(fixed_point_to_float<1, 11>((uint16_t)0x001) * (2.048), 1e-3);
is(fixed_point_to_float<1, 13>((uint16_t)0x001) * (2.048), 250e-6);
is(fixed_point_to_float<1, 15>((uint16_t)0x001) * (2.048), 62.5e-6);
// from MPL115A2 datasheet
// a0 coefficient
is(fixed_point_to_float<13, 3>((uint16_t)0x3ECE), 2009.75);
// b1 coefficient
is(fixed_point_to_float<3, 13>((uint16_t)0xB3F9), -2.37585);
// b2 coefficient
is(fixed_point_to_float<2, 14>((uint16_t)0xC517), -0.92047);
// c12 coefficient
is(fixed_point_to_float<1, 15>((uint16_t)0x33C8)/(1<<9), 0.000790);
// test dynamic variable
volatile uint16_t x = 0x001;
is(fixed_point_to_float<1, 11>(x) * (2.048), 1e-3);
} テンプレートの第1引数は整数部(符号込み)のビット数・第2引数は小数点分のビット数
これはQ表記に対応する。
Q表記だと Q1.15 だと符号分1・整数部なし・15ビットの小数点桁。Q9.4 だと符号付き整数部8bit、小数部4bit。
固定小数点数用のクラス作って可能な限りは固定小数点で演算したほうがいい気はする。ヘッダ1ファイルとかで使えるの、当然もうありそうだけど見つけられてない。
モバイバッテリーは低電流時、充電完了と判断してパワーオフする(出力回路の動作をやめる)が、これをやらせたくない場合どうすればいいか。現時点でのメモ
Arduino に適当なプログラムを書きこんで、ポートに抵抗を繋ぎ(複数ポートにわけて) パワーオフするかどうかを調べた。測定時は電源供給経路途中に1Ωの抵抗をいれ、オシロでこの抵抗の両端電圧を測ることで間接的に実測の電流値を求めている。
Arduino のベースの消費電力は40mA程度。なので以下でさらに大きな電流を流しているが、40mA との切り替えということになる。
Anker は製品説明書に最低限充電電流が書いてある (50mA)
しかし連続で流し続けなければならないのか、パルスでいいのかはわからない。
A1208
検知できないと30秒ぐらいでパワーオフする
すくなくとも短いパルスではリセットできないっぽい
一定時間内の平均消費をみている?
PB-T1
説明書には特にオートパワーオフの閾値の記載なし。
約3分後にパワーオフ。電流を検知している間はバッテリーランプが点灯するっぽい?
ランプが5秒ぐらいで消灯するが、その前にパルスを検知すればいいっぽい… 謎
100mA ぐらい常時流しといたらいいんちゃう?
→ 5V 100mA (0.5W)
3.3V 10000mAh のやつは26Whぐらいなので、とても厳しいという状態でなければそれでもいいかもしれない。
Quick Charge バッテリの場合、電流値で検出しているのか電力値で検出しているのかで大きくわかれる。12V 100mA 流すことになったら常時 1.2W 消費ということになりつらい。
Quick Charge 2.0 電源から 9V をとる (任意の電圧をとる) | tech - 氾濫原 で、だいたいこれで良さそうと思ったので ATTiny13A 使ってユニバーサル基板にまとめた。
3端子レギュレータの S-812C33AY は安い (12.5円/個) から以外の意味はとくにない。ピン配置が GND IN OUT と 78* 系と違うので注意
Tiny13A は8pinなのでIOが最大で6pinしかない。そしてRESETをIOにするとISP書きこみができなくなるので、ISPを使うなら、実質5ピンのIOになる。
レポジトリ https://github.com/cho45/QCdirect
コードは Arduino 版とほぼ同じだが、AVR ネイティブで書きなおしてある。
main.cpp https://github.com/cho45/QCdirect/blob/master/firmware/main.cpp
ISP ピンヘッダの位置でいつも困る。AVRISP mkII の直で繋げられるようにしようとすると、意外と干渉するので、ピンヘッダまわりに十分スペースが必要
esptool が以下で死ぬ。
warning: espcomm_send_command: didn't receive command response warning: espcomm_send_command(FLASH_DOWNLOAD_DATA) failed warning: espcomm_send_command: wrong direction/command: 0x01 0x03, expected 0x01 0x04
シリアルダウンロードのモードにはなっているがうまくいかなかった。
書きこみに使う USB シリアル変換を別のもの(FT234X使用のもの)にしたらうまくいった。
使えなかったのはFT4232Hを使ったもので、このチップは4chを1つのUSBポートで通信できるものだが、どのチャンネルを使ってもダメだった。
ドライババージョンは現時点で最新
$ kextstat | grep FTDI 86 0 0xffffff7f80f6c000 0x7000 0x7000 com.FTDI.driver.FTDIUSBSerialDriver (2.3) ECC3AF36-431D-370D-86F2-5237785E9CF8 <85 39 5 4 3 1>
いまいち原因がわからない。
各チャンネルをループバックして screen を使って手動で通信テストする限りはうまく動いているようにみえる。壊れているわけではないっぽい。なぜこんなことになるのかわからない。
Over The Air で (すなわち Wifi 経由で)、ファームウェア書きかえをするやつ。
https://github.com/esp8266/Arduino/blob/master/libraries/ArduinoOTA/examples/BasicOTA/BasicOTA.ino
これの通りにすればコード的にはとりあえずうまくいく。
board は esp12e にしとかないとだめ。generic と書いてあるからといって、esp01 とか esp01_1m とかは flash のサイズが小さいので OTA_BEGIN_ERROR と言われる。
OTA の場合使える容量は半分以下になる。というのも、既存領域の余った部分にとりあえず書くからっぽい。
まずアドレスを mDNS からひいてくる (シリアルに表示させてもいいけど)
$ dns-sd -B _arduino._tcp Browsing for _arduino._tcp DATE: ---Wed 23 Dec 2015--- 17:49:14.912 ...STARTING... Timestamp A/R Flags if Domain Service Type Instance Name 17:49:14.913 Add 2 4 local. _arduino._tcp. esp8266-ee8488 $ dns-sd -G v4 esp8266-ee8488.local DATE: ---Wed 23 Dec 2015--- 17:48:48.955 ...STARTING... Timestamp A/R Flags if Hostname Address TTL 17:48:48.958 Add 2 4 esp8266-ee8488.local. 192.168.0.11 120
platform.ini の port に、この ip address を書いておく。これだけで自動的に OTA 経由と判別して書きこもうとする。
222K のbinファイル書きこみに4秒ぐらい。
$ ls -altrh .pioenvs/esp12e/firmware.bin
-rw-r--r--@ 1 cho45 staff 222K 12 23 21:05 .pioenvs/esp12e/firmware.bin
$ time "/Users/cho45/.platformio/packages/framework-arduinoespressif/tools/espota.py" --debug --progress -i 192.168.0.11 -f .pioenvs/esp12e/firmware.bin
18:55:58 [DEBUG]: Options: {'esp_ip': '192.168.0.11', 'image': '.pioenvs/esp12e/firmware.bin', 'auth': '', 'esp_port': 8266, 'spiffs': False, 'debug': True, 'progress': True}
18:55:58 [INFO]: Starting on 0.0.0.0:24984
18:55:58 [INFO]: Upload size: 227280
18:55:58 [INFO]: Sending invitation to: 192.168.0.11
18:55:58 [INFO]: Waiting for device...
Uploading: [============================================================] 100% Done...
18:56:02 [INFO]: Waiting for result...
18:56:02 [INFO]: Result: OK
"/Users/cho45/.platformio/packages/framework-arduinoespressif/tools/espota.py 0.06s user 0.05s system 2% cpu 4.417 total UART Download で書きこんだ直後の起動中に OTA 書きこみをした場合、ESP.restart() が失敗するっぽい。UART Download したあとは、一旦 reset してから OTA すればいいっぽい。
だいぶ忘れてたが、しばらくぶりにとりくんだらうまくいった。
こんな回路で
入出力DCスイープ
1石で非反転にしたいのでベース接地とした。ヘッドフォン出力を入力にすることを想定しているので入力インピーダンスはそれほど高くなくても良いだろう。この回路の入力インピーダンスは約100Ω(100Ωと20kΩの並列)
そして出力インピーダンスは100kとかなり大きいがデジタル入力なのでたぶん大丈夫だろう……
バイアスは0Vから飽和になるように選び、負の出力のときだけLOWに。
赤が入力(ヘッドフォン出力)、黄がUARTへの出力
9600baud 拡大
受信側はよくあるFTDI チップのUSBシリアル変換のもので、screen でデバイスファイルを指定して見ている。どのボーレートでも問題なく受信できた。
まだ実験的なページしか作っていない。これでだいたいうまくいきそうなので汎用的に使えるようにしたい。
これ以上簡単な回路にはならない気がする。
最初オーディオ出力がハイになるときにスパイクが出てしまう。これは出力に100pFぐらいつけたらだいぶ良くなるが、別段つけなくても問題はなさそう。
なお ASUS Zenfone2 で実験を行なった。他のデバイスだとうまくいかないケースがあるかもしれない。
3.3V 版もつくる。たぶん↓でよさそう
AVR のビルドツールといえば Arduino.app 1.6.5 に含まれているのでそれ使うのが一番楽だけど、この avr-gcc は 4.8.1 で、ちょっと古い。だんだん試行錯誤が嫌になって C++ で書きたくなってくると、どうせなら C++14 で書きたいと思うのが人間でしょう。
http://www.nongnu.org/avr-libc/user-manual/install_tools.html
このページを見ながら最初から順番にやれば、基本的にはできる。
注意点は
ということをやるビルド用のスクリプトを OS X 向けにかいた (依存のインストール用に homebrew が必要)
それなりのマシンで全部ビルドにするのに30分〜40分ぐらいかかる。
先日 [tech] Arduino の digitalWrite をコンパイルタイムに解決する | Tue, Dec 15. 2015 - 氾濫原 というのをコンセプト的にやってみたが割と良さそうな気がしたので、.hpp なライブラリにしてみた。
include してコンパイル時に -std=c++11 を指定すれば使える。
#include <Arduino.h>
#include "Arduino-meta.hpp"
constexpr uint8_t LED_RED = 0;
constexpr uint8_t LED_GREEN = 1;
constexpr uint8_t LED_BLUE = 2;
void setup() {
pinMode(LED_BUILTIN, OUTPUT);
// static version of pinMode()
pinMode(
LED_RED, OUTPUT,
LED_GREEN, OUTPUT,
LED_BLUE, OUTPUT
);
}
void loop() {
// this is also static
digitalWrite(LED_RED, HIGH, LED_GREEN, LOW, LED_BLUE, LOW);
delay(1000);
digitalWrite(LED_RED, LOW, LED_GREEN, HIGH, LED_BLUE, LOW);
delay(1000);
digitalWrite(LED_RED, LOW, LED_GREEN, LOW, LED_BLUE, HIGH);
delay(1000);
// original version of digitalWrite()
digitalWriteDynamic(LED_BUILTIN, HIGH);
delay(1000);
digitalWriteDynamic(LED_BUILTIN, LOW);
delay(1000);
} デフォルトの digitalWrite / pinMode / digitalRead をマクロで置き換えるようにして、完全にインターフェイスを互換にしたので、基本的に include したらあとはほぼ気にする必要がない。
ただ、静的に解決できない引数を指定するとコンパイルエラーになるので、この場合は何も考えず Dynamic をサフィックスにして元の Arduino 組込み関数をよぶようにすればいい。
基本 include するだけで最適化されたコードが生成されるようになり、必要に応じて複数ピンの同時操作もできる。
そして引数がおかしい場合コンパイルエラーになってくれるので便利。
何も失うものはない。
前のエントリに書いた通り、C++ の template を使ってコンパイル時にビットマスクとかを計算しているだけ。pinMode も面倒くさいけど実装したり、digitalWrite/digitalRead 前に timer 付きピンなら無効にするような処理を入れたり (互換性のため) した。
Arduino.h を include すると、PROGMEM 指定されている const なテーブルが見えるので、本当はそれを直接コンパイル時にも使いたいのだけれど、どうしても無理っぽいので、独自にマップをコピペして持っている。無駄感
最終的には使う側の見た目をあわせるためプリプロセッサマクロを使って、マクロ関数の引数をテンプレートパラメータとして渡している。
static constexpr void (*digitalWriteDynamic)(uint8_t, uint8_t) = *digitalWrite;
#define digitalWrite(...) digitalWriteMulti<__VA_ARGS__>()
static constexpr void (*pinModeDynamic)(uint8_t, uint8_t) = *pinMode;
#define pinMode(...) pinModeMulti<__VA_ARGS__>()
static constexpr int (*digitalReadDynamic)(uint8_t) = *digitalRead;
#define digitalRead(pin) digitalReadX<pin>() 一応テストも書いてあって
test(<<-'EOS')
void expected() {
DDRD = (DDRD & 0b11111100) | (0b00000000);
PORTD = (PORTD & 0b11111100) | (0b00000010);
}
void result() {
pinMode(0, INPUT, 1, INPUT_PULLUP);
}
EOS こんな感じで、想定する展開コードとテンプレート関数とをコンパイルしたあと obj-dump して突き合せしている。これら2つの関数は全くバイナリ的に同一になることをテストしている。
最初からテンプレートを駆使するつもりで AVR のライブラリを設計すればもっと良いものができそうだが、Arduino が覇権を握っているので、Arduino のインターフェイスにあわせるほうが嬉しい人が多いだろう。Arduino の基板上にはピン番号が書いてあるので、いちいちAVRのポート名とかとのマッピングを見ながら書くよりは、このほうが楽だ。
そしてテンプレート駆使しまくりすぎたライブラリは理解がつらいのが明かなので、このぐらいのショボいラッパぐらいがちょうどいいような気もする。一方でそれはそれで反知性的であるともいえそうだしなんともいえない。
digitalWrite(pin, state) の引数はほとんど固定で使うことが多い (と思いますがどうでしょうか? http://lowreal.net/2015/12/14/1 こういうケースでは常に固定ですね) が、digitalWrite は実装上、実行時にいちいちテーブルを使って、ピン番号からどのポートのどのビットかをひいている。たいへん無駄である。
そして、digitalWrite() は1度の1つのビットしか設定できないという制約がある。これは大変こまる場合がある (同時に複数のビットを設定して出力を変化させようとしても、タイムラグができてしまう)
ということで、これらを解決できないかと思った結果 C++ のテンプレートメタプログラミングに手を出すことになった
Arduino が使っている 8bit AVR では PORTB, PORTC, PORTD などと最大8bitのレジスタがあり、これら単位では同時に操作が可能になっている。
Arduino ではこれらのポート単位を隠蔽し、ピン番号という一連の番号によって区別するように抽象化されている。具体的には 0〜7 が PD, 8〜14 が PB というような感じ (standard なArduino の場合)
// オリジナル。0ピンをLOWにする digitalWrite(0, LOW); // 作ったもの。0ピンをLOW, 1ピンをHIGH... とする (同時に) WRITE_MULTI( 0, LOW, 1, HIGH, 2, LOW, 3, HIGH );
Gist
| //#!ano build -f="-std=c++11 -Os" && /Applications/Arduino.app/Contents/Java/hardware/tools/avr/bin/avr-objdump -d .build_ano/uno/firmware.elf ;: | |
| #include <Arduino.h> | |
| // ARDUINO_MAIN で ifdef されているので外からみえない | |
| constexpr uint8_t PB = 2; | |
| constexpr uint8_t PC = 3; | |
| constexpr uint8_t PD = 4; | |
| // template version of Arduino builtin functions | |
| constexpr uint16_t port_to_mode[] = { | |
| NOT_A_PORT, | |
| NOT_A_PORT, | |
| (uint16_t) &DDRB, | |
| (uint16_t) &DDRC, | |
| (uint16_t) &DDRD, | |
| }; | |
| constexpr uint16_t port_to_output[] = { | |
| NOT_A_PORT, | |
| NOT_A_PORT, | |
| (uint16_t) &PORTB, | |
| (uint16_t) &PORTC, | |
| (uint16_t) &PORTD, | |
| }; | |
| constexpr uint16_t port_to_input[] = { | |
| NOT_A_PORT, | |
| NOT_A_PORT, | |
| (uint16_t) &PINB, | |
| (uint16_t) &PINC, | |
| (uint16_t) &PIND, | |
| }; | |
| constexpr uint8_t digital_pin_to_port[] = { | |
| PD, /* 0 */ | |
| PD, | |
| PD, | |
| PD, | |
| PD, | |
| PD, | |
| PD, | |
| PD, | |
| PB, /* 8 */ | |
| PB, | |
| PB, | |
| PB, | |
| PB, | |
| PB, | |
| PC, /* 14 */ | |
| PC, | |
| PC, | |
| PC, | |
| PC, | |
| PC, | |
| }; | |
| constexpr uint8_t digital_pin_to_bit_mask[] = { | |
| _BV(0), /* 0, port D */ | |
| _BV(1), | |
| _BV(2), | |
| _BV(3), | |
| _BV(4), | |
| _BV(5), | |
| _BV(6), | |
| _BV(7), | |
| _BV(0), /* 8, port B */ | |
| _BV(1), | |
| _BV(2), | |
| _BV(3), | |
| _BV(4), | |
| _BV(5), | |
| _BV(0), /* 14, port C */ | |
| _BV(1), | |
| _BV(2), | |
| _BV(3), | |
| _BV(4), | |
| _BV(5), | |
| }; | |
| template<uint8_t port> | |
| constexpr volatile uint8_t* portModeRegisterX() { | |
| static_assert(port < sizeof(port_to_mode), "invalid port number"); | |
| static_assert(port_to_mode[port] != NOT_A_PORT, "invalid port number"); | |
| return (volatile uint8_t*)port_to_mode[port]; | |
| } | |
| template<uint8_t port> | |
| constexpr volatile uint8_t* portOutputRegisterX() { | |
| static_assert(port < sizeof(port_to_output), "invalid port number"); | |
| static_assert(port_to_output[port] != NOT_A_PORT, "invalid port number"); | |
| return (volatile uint8_t*)port_to_output[port]; | |
| } | |
| template<uint8_t port> | |
| constexpr volatile uint8_t* portInputRegisterX() { | |
| static_assert(port < sizeof(port_to_input), "invalid port number"); | |
| static_assert(port_to_input[port] != NOT_A_PORT, "invalid port number"); | |
| return (volatile uint8_t*)port_to_input[port]; | |
| } | |
| template <uint16_t pin> | |
| constexpr uint8_t digitalPinToBitMaskX() { | |
| static_assert(pin < sizeof(digital_pin_to_bit_mask), "invalid pin number"); | |
| return digital_pin_to_bit_mask[pin]; | |
| }; | |
| template <uint16_t pin> | |
| constexpr uint8_t digitalPinToPortX() { | |
| static_assert(pin < sizeof(digital_pin_to_port), "invalid pin number"); | |
| return digital_pin_to_port[pin]; | |
| }; | |
| // multiple bit set function with cheking port consistency | |
| template<uint8_t port, uint8_t mask, uint8_t vals> | |
| constexpr void digitalWriteMulti_() { | |
| volatile uint8_t *out = portOutputRegisterX<port>(); | |
| *out = (*out & ~mask) | vals; | |
| } | |
| template<uint8_t port, uint8_t mask, uint8_t vals, uint16_t pin, uint8_t val, uint16_t... Rest> | |
| constexpr void digitalWriteMulti_() { | |
| static_assert(digitalPinToPortX<pin>() == port, "all port must be same"); | |
| constexpr uint8_t bit = digitalPinToBitMaskX<pin>(); | |
| digitalWriteMulti_< | |
| port, | |
| mask | bit, | |
| vals | (val ? bit : 0), | |
| Rest... | |
| >(); | |
| } | |
| template<uint16_t pin, uint8_t val, uint16_t... Rest> | |
| constexpr void digitalWriteMulti() { | |
| constexpr uint8_t port = digitalPinToPortX<pin>(); | |
| return digitalWriteMulti_< | |
| port, | |
| 0, | |
| 0, | |
| pin, | |
| val, | |
| Rest... | |
| >(); | |
| } | |
| // hide template magic from surface | |
| #define WRITE_MULTI(...) digitalWriteMulti<__VA_ARGS__>() | |
| void setup() { | |
| PORTD = (PORTD & 0b11110000) | (0b1010); | |
| asm volatile ("nop"); // marker | |
| // same as above | |
| WRITE_MULTI( | |
| 0, LOW, | |
| 1, HIGH, | |
| 2, LOW, | |
| 3, HIGH | |
| ); | |
| asm volatile ("nop"); | |
| // another port | |
| WRITE_MULTI( | |
| 8, LOW, | |
| 9, HIGH, | |
| 10, LOW, | |
| 11, HIGH | |
| ); | |
| asm volatile ("nop"); | |
| /** following is invalid | |
| * static_assert(digitalPinToPortX<pin>() == port, "all port must be same"); | |
| * pin=0 -> PORTB, pin=8 -> PORTC error | |
| digitalWriteMulti< | |
| 0, LOW, | |
| 1, HIGH, | |
| 2, LOW, | |
| 8, HIGH | |
| >(); | |
| */ | |
| asm volatile ("nop"); | |
| /** builtin dynamic method | |
| * this is very slow | |
| */ | |
| digitalWrite(0, LOW); | |
| } | |
| void loop() { | |
| } |
| .build_ano/uno/firmware.elf: file format elf32-avr | |
| Disassembly of section .text: | |
| 00000000 <__vectors>: | |
| 0: 0c 94 61 00 jmp 0xc2 ; 0xc2 <__ctors_end> | |
| 4: 0c 94 73 00 jmp 0xe6 ; 0xe6 <__bad_interrupt> | |
| 8: 0c 94 73 00 jmp 0xe6 ; 0xe6 <__bad_interrupt> | |
| c: 0c 94 73 00 jmp 0xe6 ; 0xe6 <__bad_interrupt> | |
| 10: 0c 94 73 00 jmp 0xe6 ; 0xe6 <__bad_interrupt> | |
| 14: 0c 94 73 00 jmp 0xe6 ; 0xe6 <__bad_interrupt> | |
| 18: 0c 94 73 00 jmp 0xe6 ; 0xe6 <__bad_interrupt> | |
| 1c: 0c 94 73 00 jmp 0xe6 ; 0xe6 <__bad_interrupt> | |
| 20: 0c 94 73 00 jmp 0xe6 ; 0xe6 <__bad_interrupt> | |
| 24: 0c 94 73 00 jmp 0xe6 ; 0xe6 <__bad_interrupt> | |
| 28: 0c 94 73 00 jmp 0xe6 ; 0xe6 <__bad_interrupt> | |
| 2c: 0c 94 73 00 jmp 0xe6 ; 0xe6 <__bad_interrupt> | |
| 30: 0c 94 73 00 jmp 0xe6 ; 0xe6 <__bad_interrupt> | |
| 34: 0c 94 73 00 jmp 0xe6 ; 0xe6 <__bad_interrupt> | |
| 38: 0c 94 73 00 jmp 0xe6 ; 0xe6 <__bad_interrupt> | |
| 3c: 0c 94 73 00 jmp 0xe6 ; 0xe6 <__bad_interrupt> | |
| 40: 0c 94 71 01 jmp 0x2e2 ; 0x2e2 <__vector_16> | |
| 44: 0c 94 73 00 jmp 0xe6 ; 0xe6 <__bad_interrupt> | |
| 48: 0c 94 73 00 jmp 0xe6 ; 0xe6 <__bad_interrupt> | |
| 4c: 0c 94 73 00 jmp 0xe6 ; 0xe6 <__bad_interrupt> | |
| 50: 0c 94 73 00 jmp 0xe6 ; 0xe6 <__bad_interrupt> | |
| 54: 0c 94 73 00 jmp 0xe6 ; 0xe6 <__bad_interrupt> | |
| 58: 0c 94 73 00 jmp 0xe6 ; 0xe6 <__bad_interrupt> | |
| 5c: 0c 94 73 00 jmp 0xe6 ; 0xe6 <__bad_interrupt> | |
| 60: 0c 94 73 00 jmp 0xe6 ; 0xe6 <__bad_interrupt> | |
| 64: 0c 94 73 00 jmp 0xe6 ; 0xe6 <__bad_interrupt> | |
| 00000068 <__trampolines_end>: | |
| 68: 00 00 nop | |
| 6a: 00 08 sbc r0, r0 | |
| 6c: 00 02 muls r16, r16 | |
| 6e: 01 00 .word 0x0001 ; ???? | |
| 70: 00 03 mulsu r16, r16 | |
| 72: 04 07 cpc r16, r20 | |
| ... | |
| 0000007c <digital_pin_to_bit_mask_PGM>: | |
| 7c: 01 02 04 08 10 20 40 80 01 02 04 08 10 20 01 02 ..... @...... .. | |
| 8c: 04 08 10 20 ... | |
| 00000090 <digital_pin_to_port_PGM>: | |
| 90: 04 04 04 04 04 04 04 04 02 02 02 02 02 02 03 03 ................ | |
| a0: 03 03 03 03 .... | |
| 000000a4 <port_to_input_PGM>: | |
| a4: 00 00 00 00 23 00 26 00 29 00 ....#.&.). | |
| 000000ae <port_to_output_PGM>: | |
| ae: 00 00 00 00 25 00 28 00 2b 00 ....%.(.+. | |
| 000000b8 <port_to_mode_PGM>: | |
| b8: 00 00 00 00 24 00 27 00 2a 00 ....$.'.*. | |
| 000000c2 <__ctors_end>: | |
| c2: 11 24 eor r1, r1 | |
| c4: 1f be out 0x3f, r1 ; 63 | |
| c6: cf ef ldi r28, 0xFF ; 255 | |
| c8: d8 e0 ldi r29, 0x08 ; 8 | |
| ca: de bf out 0x3e, r29 ; 62 | |
| cc: cd bf out 0x3d, r28 ; 61 | |
| 000000ce <__do_clear_bss>: | |
| ce: 21 e0 ldi r18, 0x01 ; 1 | |
| d0: a0 e0 ldi r26, 0x00 ; 0 | |
| d2: b1 e0 ldi r27, 0x01 ; 1 | |
| d4: 01 c0 rjmp .+2 ; 0xd8 <.do_clear_bss_start> | |
| 000000d6 <.do_clear_bss_loop>: | |
| d6: 1d 92 st X+, r1 | |
| 000000d8 <.do_clear_bss_start>: | |
| d8: a9 30 cpi r26, 0x09 ; 9 | |
| da: b2 07 cpc r27, r18 | |
| dc: e1 f7 brne .-8 ; 0xd6 <.do_clear_bss_loop> | |
| de: 0e 94 b8 02 call 0x570 ; 0x570 <main> | |
| e2: 0c 94 cc 02 jmp 0x598 ; 0x598 <_exit> | |
| 000000e6 <__bad_interrupt>: | |
| e6: 0c 94 00 00 jmp 0 ; 0x0 <__vectors> | |
| 000000ea <setup>: | |
| ea: 8b b1 in r24, 0x0b ; 11 | |
| ec: 80 7f andi r24, 0xF0 ; 240 | |
| ee: 8a 60 ori r24, 0x0A ; 10 | |
| f0: 8b b9 out 0x0b, r24 ; 11 | |
| f2: 00 00 nop | |
| f4: 8b b1 in r24, 0x0b ; 11 | |
| f6: 80 7f andi r24, 0xF0 ; 240 | |
| f8: 8a 60 ori r24, 0x0A ; 10 | |
| fa: 8b b9 out 0x0b, r24 ; 11 | |
| fc: 00 00 nop | |
| fe: 85 b1 in r24, 0x05 ; 5 | |
| 100: 80 7f andi r24, 0xF0 ; 240 | |
| 102: 8a 60 ori r24, 0x0A ; 10 | |
| 104: 85 b9 out 0x05, r24 ; 5 | |
| 106: 00 00 nop | |
| 108: 00 00 nop | |
| 10a: 60 e0 ldi r22, 0x00 ; 0 | |
| 10c: 80 e0 ldi r24, 0x00 ; 0 | |
| 10e: 0c 94 c8 00 jmp 0x190 ; 0x190 <digitalWrite> | |
| 00000112 <loop>: | |
| 112: 08 95 ret | |
| 00000114 <pinMode>: | |
| 114: cf 93 push r28 | |
| 116: df 93 push r29 | |
| 118: 90 e0 ldi r25, 0x00 ; 0 | |
| 11a: fc 01 movw r30, r24 | |
| 11c: e4 58 subi r30, 0x84 ; 132 | |
| 11e: ff 4f sbci r31, 0xFF ; 255 | |
| 120: 24 91 lpm r18, Z | |
| 122: fc 01 movw r30, r24 | |
| 124: e0 57 subi r30, 0x70 ; 112 | |
| 126: ff 4f sbci r31, 0xFF ; 255 | |
| 128: 84 91 lpm r24, Z | |
| 12a: 88 23 and r24, r24 | |
| 12c: b9 f0 breq .+46 ; 0x15c <pinMode+0x48> | |
| 12e: 90 e0 ldi r25, 0x00 ; 0 | |
| 130: 88 0f add r24, r24 | |
| 132: 99 1f adc r25, r25 | |
| 134: fc 01 movw r30, r24 | |
| 136: e8 54 subi r30, 0x48 ; 72 | |
| 138: ff 4f sbci r31, 0xFF ; 255 | |
| 13a: a5 91 lpm r26, Z+ | |
| 13c: b4 91 lpm r27, Z | |
| 13e: 82 55 subi r24, 0x52 ; 82 | |
| 140: 9f 4f sbci r25, 0xFF ; 255 | |
| 142: fc 01 movw r30, r24 | |
| 144: c5 91 lpm r28, Z+ | |
| 146: d4 91 lpm r29, Z | |
| 148: 9f b7 in r25, 0x3f ; 63 | |
| 14a: 66 23 and r22, r22 | |
| 14c: 51 f0 breq .+20 ; 0x162 <pinMode+0x4e> | |
| 14e: 62 30 cpi r22, 0x02 ; 2 | |
| 150: a1 f0 breq .+40 ; 0x17a <pinMode+0x66> | |
| 152: f8 94 cli | |
| 154: 8c 91 ld r24, X | |
| 156: 82 2b or r24, r18 | |
| 158: 8c 93 st X, r24 | |
| 15a: 9f bf out 0x3f, r25 ; 63 | |
| 15c: df 91 pop r29 | |
| 15e: cf 91 pop r28 | |
| 160: 08 95 ret | |
| 162: f8 94 cli | |
| 164: 8c 91 ld r24, X | |
| 166: 20 95 com r18 | |
| 168: 82 23 and r24, r18 | |
| 16a: 8c 93 st X, r24 | |
| 16c: 88 81 ld r24, Y | |
| 16e: 82 23 and r24, r18 | |
| 170: 88 83 st Y, r24 | |
| 172: 9f bf out 0x3f, r25 ; 63 | |
| 174: df 91 pop r29 | |
| 176: cf 91 pop r28 | |
| 178: 08 95 ret | |
| 17a: f8 94 cli | |
| 17c: 8c 91 ld r24, X | |
| 17e: 32 2f mov r19, r18 | |
| 180: 30 95 com r19 | |
| 182: 83 23 and r24, r19 | |
| 184: 8c 93 st X, r24 | |
| 186: 88 81 ld r24, Y | |
| 188: 82 2b or r24, r18 | |
| 18a: 88 83 st Y, r24 | |
| 18c: 9f bf out 0x3f, r25 ; 63 | |
| 18e: e6 cf rjmp .-52 ; 0x15c <pinMode+0x48> | |
| 00000190 <digitalWrite>: | |
| 190: 90 e0 ldi r25, 0x00 ; 0 | |
| 192: fc 01 movw r30, r24 | |
| 194: e8 59 subi r30, 0x98 ; 152 | |
| 196: ff 4f sbci r31, 0xFF ; 255 | |
| 198: 24 91 lpm r18, Z | |
| 19a: fc 01 movw r30, r24 | |
| 19c: e4 58 subi r30, 0x84 ; 132 | |
| 19e: ff 4f sbci r31, 0xFF ; 255 | |
| 1a0: 34 91 lpm r19, Z | |
| 1a2: fc 01 movw r30, r24 | |
| 1a4: e0 57 subi r30, 0x70 ; 112 | |
| 1a6: ff 4f sbci r31, 0xFF ; 255 | |
| 1a8: 84 91 lpm r24, Z | |
| 1aa: 88 23 and r24, r24 | |
| 1ac: 99 f0 breq .+38 ; 0x1d4 <digitalWrite+0x44> | |
| 1ae: 21 11 cpse r18, r1 | |
| 1b0: 16 c0 rjmp .+44 ; 0x1de <digitalWrite+0x4e> | |
| 1b2: e8 2f mov r30, r24 | |
| 1b4: f0 e0 ldi r31, 0x00 ; 0 | |
| 1b6: ee 0f add r30, r30 | |
| 1b8: ff 1f adc r31, r31 | |
| 1ba: e2 55 subi r30, 0x52 ; 82 | |
| 1bc: ff 4f sbci r31, 0xFF ; 255 | |
| 1be: a5 91 lpm r26, Z+ | |
| 1c0: b4 91 lpm r27, Z | |
| 1c2: 8f b7 in r24, 0x3f ; 63 | |
| 1c4: f8 94 cli | |
| 1c6: 9c 91 ld r25, X | |
| 1c8: 61 11 cpse r22, r1 | |
| 1ca: 05 c0 rjmp .+10 ; 0x1d6 <digitalWrite+0x46> | |
| 1cc: 30 95 com r19 | |
| 1ce: 93 23 and r25, r19 | |
| 1d0: 9c 93 st X, r25 | |
| 1d2: 8f bf out 0x3f, r24 ; 63 | |
| 1d4: 08 95 ret | |
| 1d6: 93 2b or r25, r19 | |
| 1d8: 9c 93 st X, r25 | |
| 1da: 8f bf out 0x3f, r24 ; 63 | |
| 1dc: fb cf rjmp .-10 ; 0x1d4 <digitalWrite+0x44> | |
| 1de: 23 30 cpi r18, 0x03 ; 3 | |
| 1e0: 29 f1 breq .+74 ; 0x22c <digitalWrite+0x9c> | |
| 1e2: 60 f0 brcs .+24 ; 0x1fc <digitalWrite+0x6c> | |
| 1e4: 27 30 cpi r18, 0x07 ; 7 | |
| 1e6: e1 f0 breq .+56 ; 0x220 <digitalWrite+0x90> | |
| 1e8: 28 30 cpi r18, 0x08 ; 8 | |
| 1ea: a1 f0 breq .+40 ; 0x214 <digitalWrite+0x84> | |
| 1ec: 24 30 cpi r18, 0x04 ; 4 | |
| 1ee: 09 f7 brne .-62 ; 0x1b2 <digitalWrite+0x22> | |
| 1f0: 90 91 80 00 lds r25, 0x0080 | |
| 1f4: 9f 7d andi r25, 0xDF ; 223 | |
| 1f6: 90 93 80 00 sts 0x0080, r25 | |
| 1fa: db cf rjmp .-74 ; 0x1b2 <digitalWrite+0x22> | |
| 1fc: 21 30 cpi r18, 0x01 ; 1 | |
| 1fe: 31 f0 breq .+12 ; 0x20c <digitalWrite+0x7c> | |
| 200: 22 30 cpi r18, 0x02 ; 2 | |
| 202: b9 f6 brne .-82 ; 0x1b2 <digitalWrite+0x22> | |
| 204: 94 b5 in r25, 0x24 ; 36 | |
| 206: 9f 7d andi r25, 0xDF ; 223 | |
| 208: 94 bd out 0x24, r25 ; 36 | |
| 20a: d3 cf rjmp .-90 ; 0x1b2 <digitalWrite+0x22> | |
| 20c: 94 b5 in r25, 0x24 ; 36 | |
| 20e: 9f 77 andi r25, 0x7F ; 127 | |
| 210: 94 bd out 0x24, r25 ; 36 | |
| 212: cf cf rjmp .-98 ; 0x1b2 <digitalWrite+0x22> | |
| 214: 90 91 b0 00 lds r25, 0x00B0 | |
| 218: 9f 7d andi r25, 0xDF ; 223 | |
| 21a: 90 93 b0 00 sts 0x00B0, r25 | |
| 21e: c9 cf rjmp .-110 ; 0x1b2 <digitalWrite+0x22> | |
| 220: 90 91 b0 00 lds r25, 0x00B0 | |
| 224: 9f 77 andi r25, 0x7F ; 127 | |
| 226: 90 93 b0 00 sts 0x00B0, r25 | |
| 22a: c3 cf rjmp .-122 ; 0x1b2 <digitalWrite+0x22> | |
| 22c: 90 91 80 00 lds r25, 0x0080 | |
| 230: 9f 77 andi r25, 0x7F ; 127 | |
| 232: 90 93 80 00 sts 0x0080, r25 | |
| 236: bd cf rjmp .-134 ; 0x1b2 <digitalWrite+0x22> | |
| 00000238 <digitalRead>: | |
| 238: 90 e0 ldi r25, 0x00 ; 0 | |
| 23a: fc 01 movw r30, r24 | |
| 23c: e8 59 subi r30, 0x98 ; 152 | |
| 23e: ff 4f sbci r31, 0xFF ; 255 | |
| 240: 24 91 lpm r18, Z | |
| 242: fc 01 movw r30, r24 | |
| 244: e4 58 subi r30, 0x84 ; 132 | |
| 246: ff 4f sbci r31, 0xFF ; 255 | |
| 248: 34 91 lpm r19, Z | |
| 24a: fc 01 movw r30, r24 | |
| 24c: e0 57 subi r30, 0x70 ; 112 | |
| 24e: ff 4f sbci r31, 0xFF ; 255 | |
| 250: 84 91 lpm r24, Z | |
| 252: 88 23 and r24, r24 | |
| 254: 91 f0 breq .+36 ; 0x27a <digitalRead+0x42> | |
| 256: 21 11 cpse r18, r1 | |
| 258: 13 c0 rjmp .+38 ; 0x280 <digitalRead+0x48> | |
| 25a: e8 2f mov r30, r24 | |
| 25c: f0 e0 ldi r31, 0x00 ; 0 | |
| 25e: ee 0f add r30, r30 | |
| 260: ff 1f adc r31, r31 | |
| 262: ec 55 subi r30, 0x5C ; 92 | |
| 264: ff 4f sbci r31, 0xFF ; 255 | |
| 266: a5 91 lpm r26, Z+ | |
| 268: b4 91 lpm r27, Z | |
| 26a: 2c 91 ld r18, X | |
| 26c: 23 23 and r18, r19 | |
| 26e: 81 e0 ldi r24, 0x01 ; 1 | |
| 270: 90 e0 ldi r25, 0x00 ; 0 | |
| 272: 09 f0 breq .+2 ; 0x276 <digitalRead+0x3e> | |
| 274: 08 95 ret | |
| 276: 80 e0 ldi r24, 0x00 ; 0 | |
| 278: 08 95 ret | |
| 27a: 80 e0 ldi r24, 0x00 ; 0 | |
| 27c: 90 e0 ldi r25, 0x00 ; 0 | |
| 27e: 08 95 ret | |
| 280: 23 30 cpi r18, 0x03 ; 3 | |
| 282: 29 f1 breq .+74 ; 0x2ce <digitalRead+0x96> | |
| 284: 60 f0 brcs .+24 ; 0x29e <digitalRead+0x66> | |
| 286: 27 30 cpi r18, 0x07 ; 7 | |
| 288: e1 f0 breq .+56 ; 0x2c2 <digitalRead+0x8a> | |
| 28a: 28 30 cpi r18, 0x08 ; 8 | |
| 28c: a1 f0 breq .+40 ; 0x2b6 <digitalRead+0x7e> | |
| 28e: 24 30 cpi r18, 0x04 ; 4 | |
| 290: 21 f7 brne .-56 ; 0x25a <digitalRead+0x22> | |
| 292: 90 91 80 00 lds r25, 0x0080 | |
| 296: 9f 7d andi r25, 0xDF ; 223 | |
| 298: 90 93 80 00 sts 0x0080, r25 | |
| 29c: de cf rjmp .-68 ; 0x25a <digitalRead+0x22> | |
| 29e: 21 30 cpi r18, 0x01 ; 1 | |
| 2a0: 31 f0 breq .+12 ; 0x2ae <digitalRead+0x76> | |
| 2a2: 22 30 cpi r18, 0x02 ; 2 | |
| 2a4: d1 f6 brne .-76 ; 0x25a <digitalRead+0x22> | |
| 2a6: 94 b5 in r25, 0x24 ; 36 | |
| 2a8: 9f 7d andi r25, 0xDF ; 223 | |
| 2aa: 94 bd out 0x24, r25 ; 36 | |
| 2ac: d6 cf rjmp .-84 ; 0x25a <digitalRead+0x22> | |
| 2ae: 94 b5 in r25, 0x24 ; 36 | |
| 2b0: 9f 77 andi r25, 0x7F ; 127 | |
| 2b2: 94 bd out 0x24, r25 ; 36 | |
| 2b4: d2 cf rjmp .-92 ; 0x25a <digitalRead+0x22> | |
| 2b6: 90 91 b0 00 lds r25, 0x00B0 | |
| 2ba: 9f 7d andi r25, 0xDF ; 223 | |
| 2bc: 90 93 b0 00 sts 0x00B0, r25 | |
| 2c0: cc cf rjmp .-104 ; 0x25a <digitalRead+0x22> | |
| 2c2: 90 91 b0 00 lds r25, 0x00B0 | |
| 2c6: 9f 77 andi r25, 0x7F ; 127 | |
| 2c8: 90 93 b0 00 sts 0x00B0, r25 | |
| 2cc: c6 cf rjmp .-116 ; 0x25a <digitalRead+0x22> | |
| 2ce: 90 91 80 00 lds r25, 0x0080 | |
| 2d2: 9f 77 andi r25, 0x7F ; 127 | |
| 2d4: 90 93 80 00 sts 0x0080, r25 | |
| 2d8: c0 cf rjmp .-128 ; 0x25a <digitalRead+0x22> | |
| 000002da <atexit>: | |
| 2da: 80 e0 ldi r24, 0x00 ; 0 | |
| 2dc: 90 e0 ldi r25, 0x00 ; 0 | |
| 2de: 08 95 ret | |
| 000002e0 <initVariant>: | |
| 2e0: 08 95 ret | |
| 000002e2 <__vector_16>: | |
| 2e2: 1f 92 push r1 | |
| 2e4: 0f 92 push r0 | |
| 2e6: 0f b6 in r0, 0x3f ; 63 | |
| 2e8: 0f 92 push r0 | |
| 2ea: 11 24 eor r1, r1 | |
| 2ec: 2f 93 push r18 | |
| 2ee: 3f 93 push r19 | |
| 2f0: 8f 93 push r24 | |
| 2f2: 9f 93 push r25 | |
| 2f4: af 93 push r26 | |
| 2f6: bf 93 push r27 | |
| 2f8: 80 91 00 01 lds r24, 0x0100 | |
| 2fc: 90 91 01 01 lds r25, 0x0101 | |
| 300: a0 91 02 01 lds r26, 0x0102 | |
| 304: b0 91 03 01 lds r27, 0x0103 | |
| 308: 30 91 08 01 lds r19, 0x0108 | |
| 30c: 23 e0 ldi r18, 0x03 ; 3 | |
| 30e: 23 0f add r18, r19 | |
| 310: 2d 37 cpi r18, 0x7D ; 125 | |
| 312: 68 f1 brcs .+90 ; 0x36e <__vector_16+0x8c> | |
| 314: 26 e8 ldi r18, 0x86 ; 134 | |
| 316: 23 0f add r18, r19 | |
| 318: 02 96 adiw r24, 0x02 ; 2 | |
| 31a: a1 1d adc r26, r1 | |
| 31c: b1 1d adc r27, r1 | |
| 31e: 20 93 08 01 sts 0x0108, r18 | |
| 322: 80 93 00 01 sts 0x0100, r24 | |
| 326: 90 93 01 01 sts 0x0101, r25 | |
| 32a: a0 93 02 01 sts 0x0102, r26 | |
| 32e: b0 93 03 01 sts 0x0103, r27 | |
| 332: 80 91 04 01 lds r24, 0x0104 | |
| 336: 90 91 05 01 lds r25, 0x0105 | |
| 33a: a0 91 06 01 lds r26, 0x0106 | |
| 33e: b0 91 07 01 lds r27, 0x0107 | |
| 342: 01 96 adiw r24, 0x01 ; 1 | |
| 344: a1 1d adc r26, r1 | |
| 346: b1 1d adc r27, r1 | |
| 348: 80 93 04 01 sts 0x0104, r24 | |
| 34c: 90 93 05 01 sts 0x0105, r25 | |
| 350: a0 93 06 01 sts 0x0106, r26 | |
| 354: b0 93 07 01 sts 0x0107, r27 | |
| 358: bf 91 pop r27 | |
| 35a: af 91 pop r26 | |
| 35c: 9f 91 pop r25 | |
| 35e: 8f 91 pop r24 | |
| 360: 3f 91 pop r19 | |
| 362: 2f 91 pop r18 | |
| 364: 0f 90 pop r0 | |
| 366: 0f be out 0x3f, r0 ; 63 | |
| 368: 0f 90 pop r0 | |
| 36a: 1f 90 pop r1 | |
| 36c: 18 95 reti | |
| 36e: 01 96 adiw r24, 0x01 ; 1 | |
| 370: a1 1d adc r26, r1 | |
| 372: b1 1d adc r27, r1 | |
| 374: d4 cf rjmp .-88 ; 0x31e <__vector_16+0x3c> | |
| 00000376 <millis>: | |
| 376: 2f b7 in r18, 0x3f ; 63 | |
| 378: f8 94 cli | |
| 37a: 60 91 00 01 lds r22, 0x0100 | |
| 37e: 70 91 01 01 lds r23, 0x0101 | |
| 382: 80 91 02 01 lds r24, 0x0102 | |
| 386: 90 91 03 01 lds r25, 0x0103 | |
| 38a: 2f bf out 0x3f, r18 ; 63 | |
| 38c: 08 95 ret | |
| 0000038e <micros>: | |
| 38e: 3f b7 in r19, 0x3f ; 63 | |
| 390: f8 94 cli | |
| 392: 80 91 04 01 lds r24, 0x0104 | |
| 396: 90 91 05 01 lds r25, 0x0105 | |
| 39a: a0 91 06 01 lds r26, 0x0106 | |
| 39e: b0 91 07 01 lds r27, 0x0107 | |
| 3a2: 26 b5 in r18, 0x26 ; 38 | |
| 3a4: a8 9b sbis 0x15, 0 ; 21 | |
| 3a6: 05 c0 rjmp .+10 ; 0x3b2 <micros+0x24> | |
| 3a8: 2f 3f cpi r18, 0xFF ; 255 | |
| 3aa: 19 f0 breq .+6 ; 0x3b2 <micros+0x24> | |
| 3ac: 01 96 adiw r24, 0x01 ; 1 | |
| 3ae: a1 1d adc r26, r1 | |
| 3b0: b1 1d adc r27, r1 | |
| 3b2: 3f bf out 0x3f, r19 ; 63 | |
| 3b4: 66 27 eor r22, r22 | |
| 3b6: 78 2f mov r23, r24 | |
| 3b8: 89 2f mov r24, r25 | |
| 3ba: 9a 2f mov r25, r26 | |
| 3bc: 62 0f add r22, r18 | |
| 3be: 71 1d adc r23, r1 | |
| 3c0: 81 1d adc r24, r1 | |
| 3c2: 91 1d adc r25, r1 | |
| 3c4: 66 0f add r22, r22 | |
| 3c6: 77 1f adc r23, r23 | |
| 3c8: 88 1f adc r24, r24 | |
| 3ca: 99 1f adc r25, r25 | |
| 3cc: 66 0f add r22, r22 | |
| 3ce: 77 1f adc r23, r23 | |
| 3d0: 88 1f adc r24, r24 | |
| 3d2: 99 1f adc r25, r25 | |
| 3d4: 08 95 ret | |
| 000003d6 <delay>: | |
| 3d6: cf 92 push r12 | |
| 3d8: df 92 push r13 | |
| 3da: ef 92 push r14 | |
| 3dc: ff 92 push r15 | |
| 3de: 0f 93 push r16 | |
| 3e0: 1f 93 push r17 | |
| 3e2: cf 93 push r28 | |
| 3e4: df 93 push r29 | |
| 3e6: 00 d0 rcall .+0 ; 0x3e8 <delay+0x12> | |
| 3e8: 00 d0 rcall .+0 ; 0x3ea <delay+0x14> | |
| 3ea: cd b7 in r28, 0x3d ; 61 | |
| 3ec: de b7 in r29, 0x3e ; 62 | |
| 3ee: 3f b7 in r19, 0x3f ; 63 | |
| 3f0: f8 94 cli | |
| 3f2: c0 90 04 01 lds r12, 0x0104 | |
| 3f6: d0 90 05 01 lds r13, 0x0105 | |
| 3fa: e0 90 06 01 lds r14, 0x0106 | |
| 3fe: f0 90 07 01 lds r15, 0x0107 | |
| 402: 26 b5 in r18, 0x26 ; 38 | |
| 404: a8 9b sbis 0x15, 0 ; 21 | |
| 406: 07 c0 rjmp .+14 ; 0x416 <delay+0x40> | |
| 408: 2f 3f cpi r18, 0xFF ; 255 | |
| 40a: 29 f0 breq .+10 ; 0x416 <delay+0x40> | |
| 40c: 4f ef ldi r20, 0xFF ; 255 | |
| 40e: c4 1a sub r12, r20 | |
| 410: d4 0a sbc r13, r20 | |
| 412: e4 0a sbc r14, r20 | |
| 414: f4 0a sbc r15, r20 | |
| 416: 3f bf out 0x3f, r19 ; 63 | |
| 418: fe 2c mov r15, r14 | |
| 41a: ed 2c mov r14, r13 | |
| 41c: dc 2c mov r13, r12 | |
| 41e: cc 24 eor r12, r12 | |
| 420: c2 0e add r12, r18 | |
| 422: d1 1c adc r13, r1 | |
| 424: e1 1c adc r14, r1 | |
| 426: f1 1c adc r15, r1 | |
| 428: cc 0c add r12, r12 | |
| 42a: dd 1c adc r13, r13 | |
| 42c: ee 1c adc r14, r14 | |
| 42e: ff 1c adc r15, r15 | |
| 430: cc 0c add r12, r12 | |
| 432: dd 1c adc r13, r13 | |
| 434: ee 1c adc r14, r14 | |
| 436: ff 1c adc r15, r15 | |
| 438: 86 01 movw r16, r12 | |
| 43a: 61 15 cp r22, r1 | |
| 43c: 71 05 cpc r23, r1 | |
| 43e: 81 05 cpc r24, r1 | |
| 440: 91 05 cpc r25, r1 | |
| 442: 09 f4 brne .+2 ; 0x446 <delay+0x70> | |
| 444: 41 c0 rjmp .+130 ; 0x4c8 <delay+0xf2> | |
| 446: 69 83 std Y+1, r22 ; 0x01 | |
| 448: 7a 83 std Y+2, r23 ; 0x02 | |
| 44a: 8b 83 std Y+3, r24 ; 0x03 | |
| 44c: 9c 83 std Y+4, r25 ; 0x04 | |
| 44e: 0e 94 b7 02 call 0x56e ; 0x56e <yield> | |
| 452: 3f b7 in r19, 0x3f ; 63 | |
| 454: f8 94 cli | |
| 456: c0 90 04 01 lds r12, 0x0104 | |
| 45a: d0 90 05 01 lds r13, 0x0105 | |
| 45e: e0 90 06 01 lds r14, 0x0106 | |
| 462: f0 90 07 01 lds r15, 0x0107 | |
| 466: 26 b5 in r18, 0x26 ; 38 | |
| 468: 69 81 ldd r22, Y+1 ; 0x01 | |
| 46a: 7a 81 ldd r23, Y+2 ; 0x02 | |
| 46c: 8b 81 ldd r24, Y+3 ; 0x03 | |
| 46e: 9c 81 ldd r25, Y+4 ; 0x04 | |
| 470: a8 9b sbis 0x15, 0 ; 21 | |
| 472: 07 c0 rjmp .+14 ; 0x482 <delay+0xac> | |
| 474: 2f 3f cpi r18, 0xFF ; 255 | |
| 476: 29 f0 breq .+10 ; 0x482 <delay+0xac> | |
| 478: ef ef ldi r30, 0xFF ; 255 | |
| 47a: ce 1a sub r12, r30 | |
| 47c: de 0a sbc r13, r30 | |
| 47e: ee 0a sbc r14, r30 | |
| 480: fe 0a sbc r15, r30 | |
| 482: 3f bf out 0x3f, r19 ; 63 | |
| 484: fe 2c mov r15, r14 | |
| 486: ed 2c mov r14, r13 | |
| 488: dc 2c mov r13, r12 | |
| 48a: cc 24 eor r12, r12 | |
| 48c: c2 0e add r12, r18 | |
| 48e: d1 1c adc r13, r1 | |
| 490: e1 1c adc r14, r1 | |
| 492: f1 1c adc r15, r1 | |
| 494: cc 0c add r12, r12 | |
| 496: dd 1c adc r13, r13 | |
| 498: ee 1c adc r14, r14 | |
| 49a: ff 1c adc r15, r15 | |
| 49c: cc 0c add r12, r12 | |
| 49e: dd 1c adc r13, r13 | |
| 4a0: ee 1c adc r14, r14 | |
| 4a2: ff 1c adc r15, r15 | |
| 4a4: 96 01 movw r18, r12 | |
| 4a6: 20 1b sub r18, r16 | |
| 4a8: 31 0b sbc r19, r17 | |
| 4aa: 28 3e cpi r18, 0xE8 ; 232 | |
| 4ac: 33 40 sbci r19, 0x03 ; 3 | |
| 4ae: 28 f2 brcs .-118 ; 0x43a <delay+0x64> | |
| 4b0: 61 50 subi r22, 0x01 ; 1 | |
| 4b2: 71 09 sbc r23, r1 | |
| 4b4: 81 09 sbc r24, r1 | |
| 4b6: 91 09 sbc r25, r1 | |
| 4b8: 08 51 subi r16, 0x18 ; 24 | |
| 4ba: 1c 4f sbci r17, 0xFC ; 252 | |
| 4bc: 61 15 cp r22, r1 | |
| 4be: 71 05 cpc r23, r1 | |
| 4c0: 81 05 cpc r24, r1 | |
| 4c2: 91 05 cpc r25, r1 | |
| 4c4: 09 f0 breq .+2 ; 0x4c8 <delay+0xf2> | |
| 4c6: bf cf rjmp .-130 ; 0x446 <delay+0x70> | |
| 4c8: 0f 90 pop r0 | |
| 4ca: 0f 90 pop r0 | |
| 4cc: 0f 90 pop r0 | |
| 4ce: 0f 90 pop r0 | |
| 4d0: df 91 pop r29 | |
| 4d2: cf 91 pop r28 | |
| 4d4: 1f 91 pop r17 | |
| 4d6: 0f 91 pop r16 | |
| 4d8: ff 90 pop r15 | |
| 4da: ef 90 pop r14 | |
| 4dc: df 90 pop r13 | |
| 4de: cf 90 pop r12 | |
| 4e0: 08 95 ret | |
| 000004e2 <delayMicroseconds>: | |
| 4e2: 82 30 cpi r24, 0x02 ; 2 | |
| 4e4: 91 05 cpc r25, r1 | |
| 4e6: 38 f0 brcs .+14 ; 0x4f6 <delayMicroseconds+0x14> | |
| 4e8: 88 0f add r24, r24 | |
| 4ea: 99 1f adc r25, r25 | |
| 4ec: 88 0f add r24, r24 | |
| 4ee: 99 1f adc r25, r25 | |
| 4f0: 05 97 sbiw r24, 0x05 ; 5 | |
| 4f2: 01 97 sbiw r24, 0x01 ; 1 | |
| 4f4: f1 f7 brne .-4 ; 0x4f2 <delayMicroseconds+0x10> | |
| 4f6: 08 95 ret | |
| 000004f8 <init>: | |
| 4f8: 78 94 sei | |
| 4fa: 84 b5 in r24, 0x24 ; 36 | |
| 4fc: 82 60 ori r24, 0x02 ; 2 | |
| 4fe: 84 bd out 0x24, r24 ; 36 | |
| 500: 84 b5 in r24, 0x24 ; 36 | |
| 502: 81 60 ori r24, 0x01 ; 1 | |
| 504: 84 bd out 0x24, r24 ; 36 | |
| 506: 85 b5 in r24, 0x25 ; 37 | |
| 508: 82 60 ori r24, 0x02 ; 2 | |
| 50a: 85 bd out 0x25, r24 ; 37 | |
| 50c: 85 b5 in r24, 0x25 ; 37 | |
| 50e: 81 60 ori r24, 0x01 ; 1 | |
| 510: 85 bd out 0x25, r24 ; 37 | |
| 512: ee e6 ldi r30, 0x6E ; 110 | |
| 514: f0 e0 ldi r31, 0x00 ; 0 | |
| 516: 80 81 ld r24, Z | |
| 518: 81 60 ori r24, 0x01 ; 1 | |
| 51a: 80 83 st Z, r24 | |
| 51c: e1 e8 ldi r30, 0x81 ; 129 | |
| 51e: f0 e0 ldi r31, 0x00 ; 0 | |
| 520: 10 82 st Z, r1 | |
| 522: 80 81 ld r24, Z | |
| 524: 82 60 ori r24, 0x02 ; 2 | |
| 526: 80 83 st Z, r24 | |
| 528: 80 81 ld r24, Z | |
| 52a: 81 60 ori r24, 0x01 ; 1 | |
| 52c: 80 83 st Z, r24 | |
| 52e: e0 e8 ldi r30, 0x80 ; 128 | |
| 530: f0 e0 ldi r31, 0x00 ; 0 | |
| 532: 80 81 ld r24, Z | |
| 534: 81 60 ori r24, 0x01 ; 1 | |
| 536: 80 83 st Z, r24 | |
| 538: e1 eb ldi r30, 0xB1 ; 177 | |
| 53a: f0 e0 ldi r31, 0x00 ; 0 | |
| 53c: 80 81 ld r24, Z | |
| 53e: 84 60 ori r24, 0x04 ; 4 | |
| 540: 80 83 st Z, r24 | |
| 542: e0 eb ldi r30, 0xB0 ; 176 | |
| 544: f0 e0 ldi r31, 0x00 ; 0 | |
| 546: 80 81 ld r24, Z | |
| 548: 81 60 ori r24, 0x01 ; 1 | |
| 54a: 80 83 st Z, r24 | |
| 54c: ea e7 ldi r30, 0x7A ; 122 | |
| 54e: f0 e0 ldi r31, 0x00 ; 0 | |
| 550: 80 81 ld r24, Z | |
| 552: 84 60 ori r24, 0x04 ; 4 | |
| 554: 80 83 st Z, r24 | |
| 556: 80 81 ld r24, Z | |
| 558: 82 60 ori r24, 0x02 ; 2 | |
| 55a: 80 83 st Z, r24 | |
| 55c: 80 81 ld r24, Z | |
| 55e: 81 60 ori r24, 0x01 ; 1 | |
| 560: 80 83 st Z, r24 | |
| 562: 80 81 ld r24, Z | |
| 564: 80 68 ori r24, 0x80 ; 128 | |
| 566: 80 83 st Z, r24 | |
| 568: 10 92 c1 00 sts 0x00C1, r1 | |
| 56c: 08 95 ret | |
| 0000056e <yield>: | |
| 56e: 08 95 ret | |
| 00000570 <main>: | |
| 570: 0e 94 7c 02 call 0x4f8 ; 0x4f8 <init> | |
| 574: 0e 94 70 01 call 0x2e0 ; 0x2e0 <initVariant> | |
| 578: 0e 94 75 00 call 0xea ; 0xea <setup> | |
| 57c: 80 e0 ldi r24, 0x00 ; 0 | |
| 57e: 90 e0 ldi r25, 0x00 ; 0 | |
| 580: 89 2b or r24, r25 | |
| 582: 29 f0 breq .+10 ; 0x58e <main+0x1e> | |
| 584: 0e 94 89 00 call 0x112 ; 0x112 <loop> | |
| 588: 0e 94 00 00 call 0 ; 0x0 <__vectors> | |
| 58c: fb cf rjmp .-10 ; 0x584 <main+0x14> | |
| 58e: 0e 94 89 00 call 0x112 ; 0x112 <loop> | |
| 592: 0e 94 89 00 call 0x112 ; 0x112 <loop> | |
| 596: fb cf rjmp .-10 ; 0x58e <main+0x1e> | |
| 00000598 <_exit>: | |
| 598: f8 94 cli | |
| 0000059a <__stop_program>: | |
| 59a: ff cf rjmp .-2 ; 0x59a <__stop_program> |
コンパイラは Arduino.app に入っている avr-gcc を使っているが -std=c++11 を指定して C++11 の機能を有効にしている (constexpr 関数) なので素の Arduino.app からだとコンパイルできない。
Arduino 側で portOutputRegister digitalPinToBitMask digitalPinToPort といった関数が定義されており、これらは PROGMEM からテーブルをひいてくる実装になっているので、まずこれをコンパイル時にできるように constexpr 関数で再実装した。
C++14 ならもっと簡単に書けるはずなんだけど、C++11 相当だと関数本体に return 以外書けないのでキモい実装になっている。
ここがキモで、まず digitalWriteMulti でうけて、digitalWriteMulti_ で再帰的に処理している。digitalWriteMulti_ の最初の3引数は、持ってまわっている状態で、残りは元の digitalWriteMulti に渡された引数。
C++ のテンプレートメタプログラミングではこのようにパターンマッチでしか可変長引数を扱えないみたい。だけど思ったより綺麗に実装できた気がする。
これはプリプロセッサマクロで単に置換している。テンプレート引数として渡すのが気持ち悪かったので(慣れかもしれない)マクロでラップしている。
C++ はほとんど書いたことがないので、きっともっといい方法がありそうだと思う。特にテンプレートメタプログラミングで可変長引数を処理するとき、状態を全てテンプレート引数の頭にフラットに渡しているのがダサい。うまくコンパイル時だけ使えるコンテナみたいなのを持ちまわしていければよかったが、おもいつかなかった。
pinMode にも応用できると思うが pinMode は PORTx もいじるのでとりあえず省略した。
同じようなことはテンプレートを使わない場合(素のCとか)だとまずできない。
特に「指定しなかった部分のビットはかえない」を実現しようとすると、どうしてもビットマスクと実際に設定するビット値の2つを扱わないといけないので、かなりコードが煩雑になる。テンプレート化することで表面上の可読性がかなり上がる (テンプレート部分はアレだけど)
そしてコンパイル時にチェックができる点はおおきい。マイコンはどうしてもフィードバックがすくないので、実行時エラーというのは実際気付くのが難しい。
速度的にも当然メリットがある。これの場合はコンパイルしたあとは素で書く場合と完全に同じバイナリになる。
000000ea <setup>:
; PORTD = (PORTD & 0b11110000) | (0b1010);
ea: 8b b1 in r24, 0x0b ; 11
ec: 80 7f andi r24, 0xF0 ; 240
ee: 8a 60 ori r24, 0x0A ; 10
f0: 8b b9 out 0x0b, r24 ; 11
; asm volatile ("nop"); // marker
f2: 00 00 nop
; WRITE_MULTI(...)
f4: 8b b1 in r24, 0x0b ; 11
f6: 80 7f andi r24, 0xF0 ; 240
f8: 8a 60 ori r24, 0x0A ; 10
fa: 8b b9 out 0x0b, r24 ; 11 素の digitalWrite の場合
; digitalWrite(0, LOW); 10a: 60 e0 ldi r22, 0x00 ; 0 10c: 80 e0 ldi r24, 0x00 ; 0 10e: 0c 94 c8 00 jmp 0x190 ; 0x190 <digitalWrite>
で関数コールして
00000190 <digitalWrite>: 190: 90 e0 ldi r25, 0x00 ; 0 192: fc 01 movw r30, r24 194: e8 59 subi r30, 0x98 ; 152 196: ff 4f sbci r31, 0xFF ; 255 198: 24 91 lpm r18, Z 19a: fc 01 movw r30, r24 19c: e4 58 subi r30, 0x84 ; 132 19e: ff 4f sbci r31, 0xFF ; 255 1a0: 34 91 lpm r19, Z 1a2: fc 01 movw r30, r24 1a4: e0 57 subi r30, 0x70 ; 112 1a6: ff 4f sbci r31, 0xFF ; 255 1a8: 84 91 lpm r24, Z 1aa: 88 23 and r24, r24 1ac: 99 f0 breq .+38 ; 0x1d4 <digitalWrite+0x44> 1ae: 21 11 cpse r18, r1 1b0: 16 c0 rjmp .+44 ; 0x1de <digitalWrite+0x4e> 1b2: e8 2f mov r30, r24 1b4: f0 e0 ldi r31, 0x00 ; 0 1b6: ee 0f add r30, r30 1b8: ff 1f adc r31, r31 1ba: e2 55 subi r30, 0x52 ; 82 1bc: ff 4f sbci r31, 0xFF ; 255 1be: a5 91 lpm r26, Z+ 1c0: b4 91 lpm r27, Z 1c2: 8f b7 in r24, 0x3f ; 63 1c4: f8 94 cli 1c6: 9c 91 ld r25, X 1c8: 61 11 cpse r22, r1 1ca: 05 c0 rjmp .+10 ; 0x1d6 <digitalWrite+0x46> 1cc: 30 95 com r19 1ce: 93 23 and r25, r19 1d0: 9c 93 st X, r25 1d2: 8f bf out 0x3f, r24 ; 63 1d4: 08 95 ret 1d6: 93 2b or r25, r19 1d8: 9c 93 st X, r25 1da: 8f bf out 0x3f, r24 ; 63 1dc: fb cf rjmp .-10 ; 0x1d4 <digitalWrite+0x44> 1de: 23 30 cpi r18, 0x03 ; 3 1e0: 29 f1 breq .+74 ; 0x22c <digitalWrite+0x9c> 1e2: 60 f0 brcs .+24 ; 0x1fc <digitalWrite+0x6c> 1e4: 27 30 cpi r18, 0x07 ; 7 1e6: e1 f0 breq .+56 ; 0x220 <digitalWrite+0x90> 1e8: 28 30 cpi r18, 0x08 ; 8 1ea: a1 f0 breq .+40 ; 0x214 <digitalWrite+0x84> 1ec: 24 30 cpi r18, 0x04 ; 4 1ee: 09 f7 brne .-62 ; 0x1b2 <digitalWrite+0x22> 1f0: 90 91 80 00 lds r25, 0x0080 1f4: 9f 7d andi r25, 0xDF ; 223 1f6: 90 93 80 00 sts 0x0080, r25 1fa: db cf rjmp .-74 ; 0x1b2 <digitalWrite+0x22> 1fc: 21 30 cpi r18, 0x01 ; 1 1fe: 31 f0 breq .+12 ; 0x20c <digitalWrite+0x7c> 200: 22 30 cpi r18, 0x02 ; 2 202: b9 f6 brne .-82 ; 0x1b2 <digitalWrite+0x22> 204: 94 b5 in r25, 0x24 ; 36 206: 9f 7d andi r25, 0xDF ; 223 208: 94 bd out 0x24, r25 ; 36 20a: d3 cf rjmp .-90 ; 0x1b2 <digitalWrite+0x22> 20c: 94 b5 in r25, 0x24 ; 36 20e: 9f 77 andi r25, 0x7F ; 127 210: 94 bd out 0x24, r25 ; 36 212: cf cf rjmp .-98 ; 0x1b2 <digitalWrite+0x22> 214: 90 91 b0 00 lds r25, 0x00B0 218: 9f 7d andi r25, 0xDF ; 223 21a: 90 93 b0 00 sts 0x00B0, r25 21e: c9 cf rjmp .-110 ; 0x1b2 <digitalWrite+0x22> 220: 90 91 b0 00 lds r25, 0x00B0 224: 9f 77 andi r25, 0x7F ; 127 226: 90 93 b0 00 sts 0x00B0, r25 22a: c3 cf rjmp .-122 ; 0x1b2 <digitalWrite+0x22> 22c: 90 91 80 00 lds r25, 0x0080 230: 9f 77 andi r25, 0x7F ; 127 232: 90 93 80 00 sts 0x0080, r25 236: bd cf rjmp .-134 ; 0x1b2 <digitalWrite+0x22>
となっていて、1bit 書くだけでかなり大層なことをしていることがわかる。