ポートに直接アクセスするコードを記述すると avr-gccはアセンブラのポート入出力命令に置き換えてくれるので高速に処理できるようになるのだがポートを関数引数で渡すことができないというジレンマがある。
しょうがないので、今までは、次のようにマクロ定義によりポート指定していた。
#define XXXX_PORT B
#define XXXX_POS 0
#include “XXXX.h”
この方法は、煩わしいし、美しくもない...
関数引数として指定でき、かつ、アセンブラのポート入出力命令に置き換わる方法を、今回、ようやく見つけることができたのでGPIOライブラリを作ってみた。
GPIOライブラリは、arduinoのpinMode/digitalWrite/digitalReadと同じ仕様なので使い方は説明するまでもないだろうが、各関数の第一引数のピン番号は必ず整数定数かIOPORT_PINマクロを指定すること。
間違って変数を指定してもコンパイルは通るが低速&巨大なコードが生成されるだけなので注意しよう。
また、ピン番号のマッピングはarduinoのものとは違うことにも注意してほしい。ピン情報については製品ドキュメントを参照。
サンプルスケッチをコンパイルし逆アセンブルすると次のようにポート操作命令に置き換わっていることが確認できるはずだ。
【サンプル・スケッチ】
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
#include "ioport.h" #define LED IOPORT_PIN('B', 1) // PB1 void setup() { IOPORT::pinMode(LED, OUTPUT); //sbi 0x04, 1 <-- DDRB |= _BV(PB1); } void loop() { while (1) { IOPORT::outputToggle(RXLED_PIN); // sbi 0x03, 1 <-- PINB |= _BV(PB1); delay(100); } } |
このライブラリを利用して他のライブラリ等を作成する場合などは、テンプレート・クラスのパラメタとしてピン番号を指定するのが良いだろう。例えば、こんな感じで...
1 2 3 4 5 6 7 8 9 10 11 12 |
#include "ioport.h" template<uint8_t PIN> class XXX : IOPORT { public: void begin() { pinMode(PIN, OUTPUT); } }; |
【修正履歴】
2020-06-23
toggleOutput()がバグってたと思って修正したけどバグってたのは私の頭のほうだったので元に戻した。(-_-;)
2020-06-22
toggleOutput()がバグってたので修正。
2020-06-20
不具合ではないが再度マクロ定義の変更とそれに伴うコード修正を行った。
2020-04-30
不具合ではないがマクロ定義の変更とそれに伴うコード修正を行った。
【ライブラリ】
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 |
/* ioport.h - I/O Port Library for AVR Series Copyright (c) 2020 Sasapea's Lab. All right reserved. [i/o pin number mapping] PA0 - PA7 ... 0 - 7 PB0 - PB7 ... 8 - 15 PC0 - PC7 ... 16 - 23 PD0 - PD7 ... 24 - 31 PE0 - PE7 ... 32 - 39 PF0 - PF7 ... 40 - 47 PG0 - PG7 ... 48 - 55 PH0 - PH7 ... 56 - 63 PI0 - PI7 ... 64 - 71 PJ0 - PJ7 ... 72 - 79 PK0 - PK7 ... 80 - 87 PL0 - PL7 ... 88 - 95 This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef __IOPORT_H #define __IOPORT_H #ifdef ARDUINO #include "Arduino.h" #else #include <stdint.h> #include <avr/io.h> #define INPUT 0 #define OUTPUT 1 #define INPUT_PULLUP 2 #define LOW 0 #define HIGH 1 #endif #define IOPORT_PID(port) ((port) - 'A') #define IOPORT_PIN(port, pos) ((IOPORT_PID(port) << 3) | (pos & 7)) #define IOPORT_PORTID(pin) ((pin) >> 3) #define IOPORT_PINPOS(pin) ((pin) & 7) #define IOPORT_PINVAL(pin) (1 << IOPORT_PINPOS(pin)) #define IOPORT_UNDEFINED _SFR_MEM8(0xFFFF) #ifdef PINA #define IOPORT_PINA PINA #else #define IOPORT_PINA IOPORT_UNDEFINED #endif #ifdef DDRA #define IOPORT_DDRA DDRA #else #define IOPORT_DDRA IOPORT_UNDEFINED #endif #ifdef PORTA #define IOPORT_PORTA PORTA #else #define IOPORT_PORTA IOPORT_UNDEFINED #endif #ifdef PINB #define IOPORT_PINB PINB #else #define IOPORT_PINB IOPORT_UNDEFINED #endif #ifdef DDRB #define IOPORT_DDRB DDRB #else #define IOPORT_DDRB IOPORT_UNDEFINED #endif #ifdef PORTB #define IOPORT_PORTB PORTB #else #define IOPORT_PORTB IOPORT_UNDEFINED #endif #ifdef PINC #define IOPORT_PINC PINC #else #define IOPORT_PINC IOPORT_UNDEFINED #endif #ifdef DDRC #define IOPORT_DDRC DDRC #else #define IOPORT_DDRC IOPORT_UNDEFINED #endif #ifdef PORTC #define IOPORT_PORTC PORTC #else #define IOPORT_PORTC IOPORT_UNDEFINED #endif #ifdef PIND #define IOPORT_PIND PIND #else #define IOPORT_PIND IOPORT_UNDEFINED #endif #ifdef DDRD #define IOPORT_DDRD DDRD #else #define IOPORT_DDRD IOPORT_UNDEFINED #endif #ifdef PORTD #define IOPORT_PORTD PORTD #else #define IOPORT_PORTD IOPORT_UNDEFINED #endif #ifdef PINE #define IOPORT_PINE PINE #else #define IOPORT_PINE IOPORT_UNDEFINED #endif #ifdef DDRE #define IOPORT_DDRE DDRE #else #define IOPORT_DDRE IOPORT_UNDEFINED #endif #ifdef PORTE #define IOPORT_PORTE PORTE #else #define IOPORT_PORTE IOPORT_UNDEFINED #endif #ifdef PINF #define IOPORT_PINF PINF #else #define IOPORT_PINF IOPORT_UNDEFINED #endif #ifdef DDRF #define IOPORT_DDRF DDRF #else #define IOPORT_DDRF IOPORT_UNDEFINED #endif #ifdef PORTF #define IOPORT_PORTF PORTF #else #define IOPORT_PORTF IOPORT_UNDEFINED #endif #ifdef PING #define IOPORT_PING PING #else #define IOPORT_PING IOPORT_UNDEFINED #endif #ifdef DDRG #define IOPORT_DDRG DDRG #else #define IOPORT_DDRG IOPORT_UNDEFINED #endif #ifdef PORTG #define IOPORT_PORTG PORTG #else #define IOPORT_PORTG IOPORT_UNDEFINED #endif #ifdef PINH #define IOPORT_PINH PINH #else #define IOPORT_PINH IOPORT_UNDEFINED #endif #ifdef DDRH #define IOPORT_DDRH DDRH #else #define IOPORT_DDRH IOPORT_UNDEFINED #endif #ifdef PORTH #define IOPORT_PORTH PORTH #else #define IOPORT_PORTH IOPORT_UNDEFINED #endif #ifdef PINI #define IOPORT_PINI PINI #else #define IOPORT_PINI IOPORT_UNDEFINED #endif #ifdef DDRI #define IOPORT_DDRI DDRI #else #define IOPORT_DDRI IOPORT_UNDEFINED #endif #ifdef PORTI #define IOPORT_PORTI PORTI #else #define IOPORT_PORTI IOPORT_UNDEFINED #endif #ifdef PINJ #define IOPORT_PINJ PINJ #else #define IOPORT_PINJ IOPORT_UNDEFINED #endif #ifdef DDRJ #define IOPORT_DDRJ DDRJ #else #define IOPORT_DDRJ IOPORT_UNDEFINED #endif #ifdef PORTJ #define IOPORT_PORTJ PORTJ #else #define IOPORT_PORTJ IOPORT_UNDEFINED #endif #ifdef PINK #define IOPORT_PINK PINK #else #define IOPORT_PINK IOPORT_UNDEFINED #endif #ifdef DDRK #define IOPORT_DDRK DDRK #else #define IOPORT_DDRK IOPORT_UNDEFINED #endif #ifdef PORTK #define IOPORT_PORTK PORTK #else #define IOPORT_PORTK IOPORT_UNDEFINED #endif #ifdef PINL #define IOPORT_PINL PINL #else #define IOPORT_PINL IOPORT_UNDEFINED #endif #ifdef DDRL #define IOPORT_DDRL DDRL #else #define IOPORT_DDRL IOPORT_UNDEFINED #endif #ifdef PORTL #define IOPORT_PORTL PORTL #else #define IOPORT_PORTL IOPORT_UNDEFINED #endif #define IOPORT_DIRREG(pin) \ ((pin) < (8 * 1) ? IOPORT_DDRA \ : ((pin) < (8 * 2) ? IOPORT_DDRB \ : ((pin) < (8 * 3) ? IOPORT_DDRC \ : ((pin) < (8 * 4) ? IOPORT_DDRD \ : ((pin) < (8 * 5) ? IOPORT_DDRE \ : ((pin) < (8 * 6) ? IOPORT_DDRF \ : ((pin) < (8 * 7) ? IOPORT_DDRG \ : ((pin) < (8 * 8) ? IOPORT_DDRH \ : ((pin) < (8 * 9) ? IOPORT_DDRI \ : ((pin) < (8 * 10) ? IOPORT_DDRJ \ : ((pin) < (8 * 11) ? IOPORT_DDRK \ : ((pin) < (8 * 12) ? IOPORT_DDRL \ : IOPORT_UNDEFINED)))))))))))) #define IOPORT_OUTREG(pin) \ ((pin) < (8 * 1) ? IOPORT_PORTA \ : ((pin) < (8 * 2) ? IOPORT_PORTB \ : ((pin) < (8 * 3) ? IOPORT_PORTC \ : ((pin) < (8 * 4) ? IOPORT_PORTD \ : ((pin) < (8 * 5) ? IOPORT_PORTE \ : ((pin) < (8 * 6) ? IOPORT_PORTF \ : ((pin) < (8 * 7) ? IOPORT_PORTG \ : ((pin) < (8 * 8) ? IOPORT_PORTH \ : ((pin) < (8 * 9) ? IOPORT_PORTI \ : ((pin) < (8 * 10) ? IOPORT_PORTJ \ : ((pin) < (8 * 11) ? IOPORT_PORTK \ : ((pin) < (8 * 12) ? IOPORT_PORTL \ : IOPORT_UNDEFINED)))))))))))) #define IOPORT_TGLREG(pin) IOPORT_INREG(pin) #define IOPORT_INREG(pin) \ ((pin) < (8 * 1) ? IOPORT_PINA \ : ((pin) < (8 * 2) ? IOPORT_PINB \ : ((pin) < (8 * 3) ? IOPORT_PINC \ : ((pin) < (8 * 4) ? IOPORT_PIND \ : ((pin) < (8 * 5) ? IOPORT_PINE \ : ((pin) < (8 * 6) ? IOPORT_PINF \ : ((pin) < (8 * 7) ? IOPORT_PING \ : ((pin) < (8 * 8) ? IOPORT_PINH \ : ((pin) < (8 * 9) ? IOPORT_PINI \ : ((pin) < (8 * 10) ? IOPORT_PINJ \ : ((pin) < (8 * 11) ? IOPORT_PINK \ : ((pin) < (8 * 12) ? IOPORT_PINL \ : IOPORT_UNDEFINED)))))))))))) class IOPORT { public: static void pinMode(uint8_t pin, uint8_t mode) { if (mode == OUTPUT) IOPORT_DIRREG(pin) |= IOPORT_PINVAL(pin); else { IOPORT_DIRREG(pin) &= ~IOPORT_PINVAL(pin); digitalWrite(pin, mode == INPUT_PULLUP); } } static void digitalWrite(uint8_t pin, uint8_t val) { if (val) IOPORT_OUTREG(pin) |= IOPORT_PINVAL(pin); else IOPORT_OUTREG(pin) &= ~IOPORT_PINVAL(pin); } static void toggleOutput(uint8_t pin) { IOPORT_TGLREG(pin) |= IOPORT_PINVAL(pin); } static uint8_t digitalRead(uint8_t pin) { return IOPORT_INREG(pin) & IOPORT_PINVAL(pin) ? HIGH : LOW; } }; #endif |