FastGPIO library
FastGPIO.h
Go to the documentation of this file.
1 // Copyright Pololu Corporation. For more information, see http://www.pololu.com/
2 
44 #pragma once
45 #include <avr/io.h>
46 #include <stdint.h>
47 
49 #define _FG_SBI(mem_addr, bit) asm volatile("sbi %0, %1\n" : \
50  : "I" (mem_addr - __SFR_OFFSET), "I" (bit))
51 #define _FG_CBI(mem_addr, bit) asm volatile("cbi %0, %1\n" : \
52  : "I" (mem_addr - __SFR_OFFSET), "I" (bit))
53 #define _FG_PIN(port, bit) { _SFR_MEM_ADDR(PIN##port), _SFR_MEM_ADDR(PORT##port), \
54  _SFR_MEM_ADDR(DDR##port), bit }
55 
57 namespace FastGPIO
58 {
65  typedef struct IOStruct
66  {
67  uint8_t pinAddr;
68  uint8_t portAddr;
69  uint8_t ddrAddr;
70  uint8_t bit;
71 
72  volatile uint8_t * pin() const
73  {
74  return (volatile uint8_t *)(uint16_t)pinAddr;
75  }
76 
77  volatile uint8_t * port() const
78  {
79  return (volatile uint8_t *)(uint16_t)portAddr;
80  }
81 
82  volatile uint8_t * ddr() const
83  {
84  return (volatile uint8_t *)(uint16_t)ddrAddr;
85  }
86  } IOStruct;
89 #if defined(__AVR_ATmega328PB__) || defined(ARDUINO_AVR_A_STAR_328PB)
90 
91  const IOStruct pinStructs[] = {
92  _FG_PIN(D, 0),
93  _FG_PIN(D, 1),
94  _FG_PIN(D, 2),
95  _FG_PIN(D, 3),
96  _FG_PIN(D, 4),
97  _FG_PIN(D, 5),
98  _FG_PIN(D, 6),
99  _FG_PIN(D, 7),
100  _FG_PIN(B, 0),
101  _FG_PIN(B, 1),
102  _FG_PIN(B, 2),
103  _FG_PIN(B, 3),
104  _FG_PIN(B, 4),
105  _FG_PIN(B, 5),
106  _FG_PIN(C, 0),
107  _FG_PIN(C, 1),
108  _FG_PIN(C, 2),
109  _FG_PIN(C, 3),
110  _FG_PIN(C, 4),
111  _FG_PIN(C, 5),
112  _FG_PIN(E, 2),
113  _FG_PIN(E, 3),
114  _FG_PIN(E, 0),
115  _FG_PIN(E, 1),
116  _FG_PIN(C, 6), // RESET
117  _FG_PIN(C, 7), // Null pin (IO_NONE)
118  };
119 
120 #define IO_D0 0
121 #define IO_D1 1
122 #define IO_D2 2
123 #define IO_D3 3
124 #define IO_D4 4
125 #define IO_D5 5
126 #define IO_D6 6
127 #define IO_D7 7
128 #define IO_B0 8
129 #define IO_B1 9
130 #define IO_B2 10
131 #define IO_B3 11
132 #define IO_B4 12
133 #define IO_B5 13
134 #define IO_C0 14
135 #define IO_C1 15
136 #define IO_C2 16
137 #define IO_C3 17
138 #define IO_C4 18
139 #define IO_C5 19
140 #define IO_E2 20
141 #define IO_E3 21
142 #define IO_E0 22
143 #define IO_E1 23
144 #define IO_C6 24
145 #define IO_NONE 25
146 
147 #elif defined(__AVR_ATmega168__) || defined(__AVR_ATmega168P__) || defined(__AVR_ATmega328__) || defined(__AVR_ATmega328P__)
148 
149  const IOStruct pinStructs[] = {
150  _FG_PIN(D, 0),
151  _FG_PIN(D, 1),
152  _FG_PIN(D, 2),
153  _FG_PIN(D, 3),
154  _FG_PIN(D, 4),
155  _FG_PIN(D, 5),
156  _FG_PIN(D, 6),
157  _FG_PIN(D, 7),
158  _FG_PIN(B, 0),
159  _FG_PIN(B, 1),
160  _FG_PIN(B, 2),
161  _FG_PIN(B, 3),
162  _FG_PIN(B, 4),
163  _FG_PIN(B, 5),
164  _FG_PIN(C, 0),
165  _FG_PIN(C, 1),
166  _FG_PIN(C, 2),
167  _FG_PIN(C, 3),
168  _FG_PIN(C, 4),
169  _FG_PIN(C, 5),
170  _FG_PIN(C, 6), // RESET
171  _FG_PIN(C, 7), // Null pin (IO_NONE)
172  };
173 
174 #define IO_D0 0
175 #define IO_D1 1
176 #define IO_D2 2
177 #define IO_D3 3
178 #define IO_D4 4
179 #define IO_D5 5
180 #define IO_D6 6
181 #define IO_D7 7
182 #define IO_B0 8
183 #define IO_B1 9
184 #define IO_B2 10
185 #define IO_B3 11
186 #define IO_B4 12
187 #define IO_B5 13
188 #define IO_C0 14
189 #define IO_C1 15
190 #define IO_C2 16
191 #define IO_C3 17
192 #define IO_C4 18
193 #define IO_C5 19
194 #define IO_C6 20
195 #define IO_NONE 21
196 
197 #elif defined(__AVR_ATmega32U4__)
198 
199  const IOStruct pinStructs[] = {
200  _FG_PIN(D, 2),
201  _FG_PIN(D, 3),
202  _FG_PIN(D, 1),
203  _FG_PIN(D, 0),
204  _FG_PIN(D, 4),
205  _FG_PIN(C, 6),
206  _FG_PIN(D, 7),
207  _FG_PIN(E, 6),
208 
209  _FG_PIN(B, 4),
210  _FG_PIN(B, 5),
211  _FG_PIN(B, 6),
212  _FG_PIN(B, 7),
213  _FG_PIN(D, 6),
214  _FG_PIN(C, 7),
215 
216  _FG_PIN(B, 3),
217  _FG_PIN(B, 1),
218  _FG_PIN(B, 2),
219  _FG_PIN(B, 0),
220 
221  _FG_PIN(F, 7),
222  _FG_PIN(F, 6),
223  _FG_PIN(F, 5),
224  _FG_PIN(F, 4),
225  _FG_PIN(F, 1),
226  _FG_PIN(F, 0),
227 
228  _FG_PIN(D, 4),
229  _FG_PIN(D, 7),
230  _FG_PIN(B, 4),
231  _FG_PIN(B, 5),
232  _FG_PIN(B, 6),
233  _FG_PIN(D, 6),
234 
235  // Extra pins added by this library and not supported by the
236  // Arduino GPIO functions:
237  _FG_PIN(D, 5),
238  _FG_PIN(E, 2),
239 
240  _FG_PIN(E, 0) // Null pin (IO_NONE)
241  };
242 
243 #define IO_D2 0
244 #define IO_D3 1
245 #define IO_D1 2
246 #define IO_D0 3
247 #define IO_D4 4
248 #define IO_C6 5
249 #define IO_D7 6
250 #define IO_E6 7
251 #define IO_B4 8
252 #define IO_B5 9
253 #define IO_B6 10
254 #define IO_B7 11
255 #define IO_D6 12
256 #define IO_C7 13
257 #define IO_B3 14
258 #define IO_B1 15
259 #define IO_B2 16
260 #define IO_B0 17
261 #define IO_F7 18
262 #define IO_F6 19
263 #define IO_F5 20
264 #define IO_F4 21
265 #define IO_F1 22
266 #define IO_F0 23
267 #define IO_D5 30
268 #define IO_E2 31
269 #define IO_NONE 32
270 
271 #else
272 #error FastGPIO does not support this board.
273 #endif
274 
275  template<uint8_t pin> class Pin
276  {
277  public:
284  static inline void setOutputLow() __attribute__((always_inline))
285  {
286  _FG_CBI(pinStructs[pin].portAddr, pinStructs[pin].bit);
287  _FG_SBI(pinStructs[pin].ddrAddr, pinStructs[pin].bit);
288  }
289 
296  static inline void setOutputHigh() __attribute__((always_inline))
297  {
298  _FG_SBI(pinStructs[pin].portAddr, pinStructs[pin].bit);
299  _FG_SBI(pinStructs[pin].ddrAddr, pinStructs[pin].bit);
300  }
301 
304  static inline void setOutputToggle() __attribute__((always_inline))
305  {
306  setOutputValueToggle();
307  _FG_SBI(pinStructs[pin].ddrAddr, pinStructs[pin].bit);
308  }
309 
318  static inline void setOutput(bool value) __attribute__((always_inline))
319  {
320  setOutputValue(value);
321  _FG_SBI(pinStructs[pin].ddrAddr, pinStructs[pin].bit);
322  }
323 
332  static inline void setOutputValueLow() __attribute__((always_inline))
333  {
334  _FG_CBI(pinStructs[pin].portAddr, pinStructs[pin].bit);
335  }
336 
345  static inline void setOutputValueHigh() __attribute__((always_inline))
346  {
347  _FG_SBI(pinStructs[pin].portAddr, pinStructs[pin].bit);
348  }
349 
360  static inline void setOutputValueToggle() __attribute__((always_inline))
361  {
362  _FG_SBI(pinStructs[pin].pinAddr, pinStructs[pin].bit);
363  }
364 
376  static inline void setOutputValue(bool value) __attribute__((always_inline))
377  {
378  if (value)
379  {
380  _FG_SBI(pinStructs[pin].portAddr, pinStructs[pin].bit);
381  }
382  else
383  {
384  _FG_CBI(pinStructs[pin].portAddr, pinStructs[pin].bit);
385  }
386  }
387 
391  static inline void setInput() __attribute__((always_inline))
392  {
393  _FG_CBI(pinStructs[pin].ddrAddr, pinStructs[pin].bit);
394  _FG_CBI(pinStructs[pin].portAddr, pinStructs[pin].bit);
395  }
396 
400  static inline void setInputPulledUp() __attribute__((always_inline))
401  {
402  _FG_CBI(pinStructs[pin].ddrAddr, pinStructs[pin].bit);
403  _FG_SBI(pinStructs[pin].portAddr, pinStructs[pin].bit);
404  }
405 
410  static inline bool isInputHigh() __attribute__((always_inline))
411  {
412  return *pinStructs[pin].pin() >> pinStructs[pin].bit & 1;
413 
414  /* This is another option but it is less efficient in code
415  like "if (isInputHigh()) { ... }":
416  bool value;
417  asm volatile(
418  "ldi %0, 0\n"
419  "sbic %2, %1\n"
420  "ldi %0, 1\n"
421  : "=d" (value)
422  : "I" (pinStructs[pin].bit),
423  "I" (pinStructs[pin].pinAddr - __SFR_OFFSET));
424  return value;
425  */
426  }
427 
432  static inline bool isOutput() __attribute__((always_inline))
433  {
434  return *pinStructs[pin].ddr() >> pinStructs[pin].bit & 1;
435  }
436 
443  static inline bool isOutputValueHigh() __attribute__((always_inline))
444  {
445  return *pinStructs[pin].port() >> pinStructs[pin].bit & 1;
446  }
447 
454  static uint8_t getState()
455  {
456  uint8_t state;
457  asm volatile(
458  "ldi %0, 0\n"
459  "sbic %2, %1\n"
460  "ori %0, 1\n" // Set state bit 0 to 1 if PORT bit is set.
461  "sbic %3, %1\n"
462  "ori %0, 2\n" // Set state bit 1 to 1 if DDR bit is set.
463  : "=a" (state)
464  : "I" (pinStructs[pin].bit),
465  "I" (pinStructs[pin].portAddr - __SFR_OFFSET),
466  "I" (pinStructs[pin].ddrAddr - __SFR_OFFSET));
467  return state;
468 
469  /* Equivalent C++ code:
470  return isOutput() << 1 | isOutputValueHigh();
471  */
472  }
473 
486  static void setState(uint8_t state)
487  {
488  asm volatile(
489  "bst %0, 1\n" // Set DDR to 0 if needed
490  "brts .+2\n"
491  "cbi %3, %1\n"
492  "bst %0, 0\n" // Copy state bit 0 to PORT bit
493  "brts .+2\n"
494  "cbi %2, %1\n"
495  "brtc .+2\n"
496  "sbi %2, %1\n"
497  "bst %0, 1\n" // Set DDR to 1 if needed
498  "brtc .+2\n"
499  "sbi %3, %1\n"
500  :
501  : "a" (state),
502  "I" (pinStructs[pin].bit),
503  "I" (pinStructs[pin].portAddr - __SFR_OFFSET),
504  "I" (pinStructs[pin].ddrAddr - __SFR_OFFSET));
505  }
506  };
507 
542  template<uint8_t pin> class PinLoan
543  {
544  public:
546  uint8_t state;
547 
548  PinLoan()
549  {
550  state = Pin<pin>::getState();
551  }
552 
553  ~PinLoan()
554  {
555  Pin<pin>::setState(state);
556  }
557  };
558 };
559 
560 #undef _FG_PIN
561 #undef _FG_CBI
562 #undef _FG_SBI
static bool isInputHigh() __attribute__((always_inline))
Reads the input value of the pin.
Definition: FastGPIO.h:410
static bool isOutput() __attribute__((always_inline))
Returns 1 if the pin is configured as an output.
Definition: FastGPIO.h:432
static bool isOutputValueHigh() __attribute__((always_inline))
Returns the output value of the pin.
Definition: FastGPIO.h:443
uint8_t state
The state of the pin as returned from FastGPIO::Pin::getState.
Definition: FastGPIO.h:546
static void setOutputValueToggle() __attribute__((always_inline))
Toggles the output value of the pin.
Definition: FastGPIO.h:360
static void setInput() __attribute__((always_inline))
Sets a pin to be a digital input with the internal pull-up resistor disabled.
Definition: FastGPIO.h:391
static void setOutputValue(bool value) __attribute__((always_inline))
Sets the output value of the pin.
Definition: FastGPIO.h:376
static void setOutputValueHigh() __attribute__((always_inline))
Sets the output value of the pin to 1.
Definition: FastGPIO.h:345
static void setInputPulledUp() __attribute__((always_inline))
Sets a pin to be a digital input with the internal pull-up resistor enabled.
Definition: FastGPIO.h:400
static void setOutputHigh() __attribute__((always_inline))
Configures the pin to be an output driving high.
Definition: FastGPIO.h:296
static void setState(uint8_t state)
Sets the full 2-bit state of the pin.
Definition: FastGPIO.h:486
static void setOutputToggle() __attribute__((always_inline))
Configures the pin to be an output and toggles it.
Definition: FastGPIO.h:304
static void setOutput(bool value) __attribute__((always_inline))
Sets the pin as an output.
Definition: FastGPIO.h:318
static void setOutputLow() __attribute__((always_inline))
Configures the pin to be an output driving low.
Definition: FastGPIO.h:284
static uint8_t getState()
Returns the full 2-bit state of the pin.
Definition: FastGPIO.h:454
static void setOutputValueLow() __attribute__((always_inline))
Sets the output value of the pin to 0.
Definition: FastGPIO.h:332