Arduino標準関数で必ず使う pinMode() と digitalWrite()は、全ボードに共有な為、関数内でのオーバヘッドが大きくコンパイルサイズも大きくなります。また、処理速度もオーバーヘッド分遅いため簡単な実験レベルではいいのですが、本格的なプログラムを作っていると結構ダメージが大きかったりします。ここでは、これら2つの関数を、AVRレジスタレベルで操作し、高速化・コンパクト化を図ってみたいと思います。
作成したサンプルコード
以下は、pinModeの高速化関数 avr_pinModeと、digitalWriteの高速化関数 avr_digitalWriteを全く同じ引数によって使えるようにし、13番のLEDをLチカさせたコードです。
#include<Arduino.h>
//
// pinModeをAVRレジスタを制御して高速化する関数
//
void avr_pinMode(uint8_t pin, uint8_t mode) {
uint8_t bit = digitalPinToBitMask(pin);
volatile uint8_t* reg = portModeRegister(digitalPinToPort(pin));
if (mode == OUTPUT) {
*reg |= bit;
} else {
*reg &= ~bit;
}
}
//
// digitalWriteをAVRレジスタを制御して高速化する関数
//
void avr_digitalWrite(uint8_t pin, uint8_t val) {
uint8_t bit = digitalPinToBitMask(pin);
volatile uint8_t* out = portOutputRegister(digitalPinToPort(pin));
if (val == HIGH) {
*out |= bit;
} else {
*out &= ~bit;
}
}
//
//実際にプログラムで使用する
//
void setup() {
avr_pinMode(13, OUTPUT); // ピン13を出力として設定
}
void loop() {
avr_digitalWrite(13, HIGH); // LEDをON
delay(1000); // 1秒待つ
avr_digitalWrite(13, LOW); // LEDをOFF
delay(1000); // 1秒待つ
}
本プログラムの中で使用した新しい3つのマクロについて説明を追加します。
digitalPinToBitMask(pin)
Arduinoで、特定のピンに対応するビットマスクを取得するために使用するマクロです。このビットマスクは、レジスタの特定のビットを操作する際に必要となります。引数としてデジタルピン番号を指定すると、そのピンに対応するビットマスクを返します。ビットマスクは、レジスタの中でそのピンがどのビット位置にあるかを示すものです。
例えば、ピンがポートの第3ビットに対応している場合、ビットマスクは 0b00001000(十進数で8)を返すこととなります。
digitalPinToPort(pin)
Arduinoで、特定のデジタルピンが属するポートを調べるためのマクロです。このマクロは、引数として与えたピン番号接続されているポート値を返します。返される値は、PORTB、PORTC、PORTD など、マイクロコントローラのポートレジスタです。
portModeRegister(port)
Arduinoで、特定のデジタルピンが属するポートのデータディレクションレジスタ(DDR)へのポインタを返します。このポインタを通じて、ピンを入力モード(0を書き込む)または出力モード(1を書き込む)に設定することができます。
注意
- サンプルで作った2つの関数は、レジスタ直接操作に依存しているため、ピン番号とポートが正しくマッピングされていることを前提としています。
- レジスターをつかった直接ポート操作は高速ですが、他のライブラリや関数との互換性が損なわれる可能性があります。また、エラーも発生しやすくなるため注意が必要です。
- avr_pinMode と avr_digitalWrite 関数は、digitalPinToBitMask、portModeRegister、portOutputRegister のArduinoのマクロや関数を使用しています。そのため、環境によってはヘッダファイルのインクルードが必要になる場合があります。
参考:ArduinoUNOにおけるピンとポート番号表
ご自分で使用されるCPUに関して、データシートなどからピン番号やポート番号の対応表を用意しておくと間違えは極力避けることができます。以下はArduinoUNO(ATmega328P)の対応表です。
Arduinoピン番号 | ポート名 | ポートビット |
---|---|---|
0 | PORTD | PD0 |
1 | PORTD | PD1 |
2 | PORTD | PD2 |
3 | PORTD | PD3 |
4 | PORTD | PD4 |
5 | PORTD | PD5 |
6 | PORTD | PD6 |
7 | PORTD | PD7 |
8 | PORTB | PB0 |
9 | PORTB | PB1 |
10 | PORTB | PB2 |
11 | PORTB | PB3 |
12 | PORTB | PB4 |
13 | PORTB | PB5 |
A0 | PORTC | PC0 |
A1 | PORTC | PC1 |
A2 | PORTC | PC2 |
A3 | PORTC | PC3 |
A4 | PORTC | PC4 |
A5 | PORTC | PC5 |
- Arduinoピン番号は、 Arduino Unoボード上のラベル付けされたピン番号です。
- ポート名は、 AVRマイクロコントローラのポート名(例:PORTB, PORTC, PORTDなど)です。
- ポートビットは、 そのポート内の具体的なビット位置(例:PB0はポートBの0番ビット)です。
コメント