Romi32U4 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_ATmega168__) || defined(__AVR_ATmega168P__) || defined(__AVR_ATmega328__) || defined(__AVR_ATmega328P__)
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(C, 6),
113  _FG_PIN(C, 7), // Null pin (IO_NONE)
114  };
115 
116 #define IO_D0 0
117 #define IO_D1 1
118 #define IO_D2 2
119 #define IO_D3 3
120 #define IO_D4 4
121 #define IO_D5 5
122 #define IO_D6 6
123 #define IO_D7 7
124 #define IO_B0 8
125 #define IO_B1 9
126 #define IO_B2 10
127 #define IO_B3 11
128 #define IO_B4 12
129 #define IO_B5 13
130 #define IO_C0 14
131 #define IO_C1 15
132 #define IO_C2 16
133 #define IO_C3 17
134 #define IO_C4 18
135 #define IO_C5 19
136 #define IO_C6 20
137 #define IO_NONE 21
138 
139 #elif defined(__AVR_ATmega32U4__)
140 
141  const IOStruct pinStructs[] = {
142  _FG_PIN(D, 2),
143  _FG_PIN(D, 3),
144  _FG_PIN(D, 1),
145  _FG_PIN(D, 0),
146  _FG_PIN(D, 4),
147  _FG_PIN(C, 6),
148  _FG_PIN(D, 7),
149  _FG_PIN(E, 6),
150 
151  _FG_PIN(B, 4),
152  _FG_PIN(B, 5),
153  _FG_PIN(B, 6),
154  _FG_PIN(B, 7),
155  _FG_PIN(D, 6),
156  _FG_PIN(C, 7),
157 
158  _FG_PIN(B, 3),
159  _FG_PIN(B, 1),
160  _FG_PIN(B, 2),
161  _FG_PIN(B, 0),
162 
163  _FG_PIN(F, 7),
164  _FG_PIN(F, 6),
165  _FG_PIN(F, 5),
166  _FG_PIN(F, 4),
167  _FG_PIN(F, 1),
168  _FG_PIN(F, 0),
169 
170  _FG_PIN(D, 4),
171  _FG_PIN(D, 7),
172  _FG_PIN(B, 4),
173  _FG_PIN(B, 5),
174  _FG_PIN(B, 6),
175  _FG_PIN(D, 6),
176 
177  // Extra pins added by this library and not supported by the
178  // Arduino GPIO functions:
179  _FG_PIN(D, 5),
180  _FG_PIN(E, 2),
181 
182  _FG_PIN(E, 0) // Null pin (IO_NONE)
183  };
184 
185 #define IO_D2 0
186 #define IO_D3 1
187 #define IO_D1 2
188 #define IO_D0 3
189 #define IO_D4 4
190 #define IO_C6 5
191 #define IO_D7 6
192 #define IO_E6 7
193 #define IO_B4 8
194 #define IO_B5 9
195 #define IO_B6 10
196 #define IO_B7 11
197 #define IO_D6 12
198 #define IO_C7 13
199 #define IO_B3 14
200 #define IO_B1 15
201 #define IO_B2 16
202 #define IO_B0 17
203 #define IO_F7 18
204 #define IO_F6 19
205 #define IO_F5 20
206 #define IO_F4 21
207 #define IO_F1 22
208 #define IO_F0 23
209 #define IO_D5 30
210 #define IO_E2 31
211 #define IO_NONE 32
212 
213 #else
214 #error FastGPIO does not support this board.
215 #endif
216 
217  template<uint8_t pin> class Pin
218  {
219  public:
226  static inline void setOutputLow() __attribute__((always_inline))
227  {
228  _FG_CBI(pinStructs[pin].portAddr, pinStructs[pin].bit);
229  _FG_SBI(pinStructs[pin].ddrAddr, pinStructs[pin].bit);
230  }
231 
238  static inline void setOutputHigh() __attribute__((always_inline))
239  {
240  _FG_SBI(pinStructs[pin].portAddr, pinStructs[pin].bit);
241  _FG_SBI(pinStructs[pin].ddrAddr, pinStructs[pin].bit);
242  }
243 
246  static inline void setOutputToggle() __attribute__((always_inline))
247  {
248  setOutputValueToggle();
249  _FG_SBI(pinStructs[pin].ddrAddr, pinStructs[pin].bit);
250  }
251 
260  static inline void setOutput(bool value) __attribute__((always_inline))
261  {
262  setOutputValue(value);
263  _FG_SBI(pinStructs[pin].ddrAddr, pinStructs[pin].bit);
264  }
265 
274  static inline void setOutputValueLow() __attribute__((always_inline))
275  {
276  _FG_CBI(pinStructs[pin].portAddr, pinStructs[pin].bit);
277  }
278 
287  static inline void setOutputValueHigh() __attribute__((always_inline))
288  {
289  _FG_SBI(pinStructs[pin].portAddr, pinStructs[pin].bit);
290  }
291 
302  static inline void setOutputValueToggle() __attribute__((always_inline))
303  {
304  _FG_SBI(pinStructs[pin].pinAddr, pinStructs[pin].bit);
305  }
306 
318  static inline void setOutputValue(bool value) __attribute__((always_inline))
319  {
320  if (value)
321  {
322  _FG_SBI(pinStructs[pin].portAddr, pinStructs[pin].bit);
323  }
324  else
325  {
326  _FG_CBI(pinStructs[pin].portAddr, pinStructs[pin].bit);
327  }
328  }
329 
333  static inline void setInput() __attribute__((always_inline))
334  {
335  _FG_CBI(pinStructs[pin].ddrAddr, pinStructs[pin].bit);
336  _FG_CBI(pinStructs[pin].portAddr, pinStructs[pin].bit);
337  }
338 
342  static inline void setInputPulledUp() __attribute__((always_inline))
343  {
344  _FG_CBI(pinStructs[pin].ddrAddr, pinStructs[pin].bit);
345  _FG_SBI(pinStructs[pin].portAddr, pinStructs[pin].bit);
346  }
347 
352  static inline bool isInputHigh() __attribute__((always_inline))
353  {
354  return *pinStructs[pin].pin() >> pinStructs[pin].bit & 1;
355 
356  /* This is another option but it is less efficient in code
357  like "if (isInputHigh()) { ... }":
358  bool value;
359  asm volatile(
360  "ldi %0, 0\n"
361  "sbic %2, %1\n"
362  "ldi %0, 1\n"
363  : "=d" (value)
364  : "I" (pinStructs[pin].bit),
365  "I" (pinStructs[pin].pinAddr - __SFR_OFFSET));
366  return value;
367  */
368  }
369 
374  static inline bool isOutput() __attribute__((always_inline))
375  {
376  return *pinStructs[pin].ddr() >> pinStructs[pin].bit & 1;
377  }
378 
385  static inline bool isOutputValueHigh() __attribute__((always_inline))
386  {
387  return *pinStructs[pin].port() >> pinStructs[pin].bit & 1;
388  }
389 
396  static uint8_t getState()
397  {
398  uint8_t state;
399  asm volatile(
400  "ldi %0, 0\n"
401  "sbic %2, %1\n"
402  "ori %0, 1\n" // Set state bit 0 to 1 if PORT bit is set.
403  "sbic %3, %1\n"
404  "ori %0, 2\n" // Set state bit 1 to 1 if DDR bit is set.
405  : "=a" (state)
406  : "I" (pinStructs[pin].bit),
407  "I" (pinStructs[pin].portAddr - __SFR_OFFSET),
408  "I" (pinStructs[pin].ddrAddr - __SFR_OFFSET));
409  return state;
410 
411  /* Equivalent C++ code:
412  return isOutput() << 1 | isOutputValueHigh();
413  */
414  }
415 
428  static void setState(uint8_t state)
429  {
430  asm volatile(
431  "bst %0, 1\n" // Set DDR to 0 if needed
432  "brts .+2\n"
433  "cbi %3, %1\n"
434  "bst %0, 0\n" // Copy state bit 0 to PORT bit
435  "brts .+2\n"
436  "cbi %2, %1\n"
437  "brtc .+2\n"
438  "sbi %2, %1\n"
439  "bst %0, 1\n" // Set DDR to 1 if needed
440  "brtc .+2\n"
441  "sbi %3, %1\n"
442  :
443  : "a" (state),
444  "I" (pinStructs[pin].bit),
445  "I" (pinStructs[pin].portAddr - __SFR_OFFSET),
446  "I" (pinStructs[pin].ddrAddr - __SFR_OFFSET));
447  }
448  };
449 
484  template<uint8_t pin> class PinLoan
485  {
486  public:
488  uint8_t state;
489 
490  PinLoan()
491  {
492  state = Pin<pin>::getState();
493  }
494 
495  ~PinLoan()
496  {
497  Pin<pin>::setState(state);
498  }
499  };
500 };
501 
502 #undef _FG_PIN
503 #undef _FG_CBI
504 #undef _FG_SBI
uint8_t state
The state of the pin as returned from FastGPIO::Pin::getState.
Definition: FastGPIO.h:488
static bool isInputHigh() __attribute__((always_inline))
Reads the input value of the pin.
Definition: FastGPIO.h:352
static void setOutputToggle() __attribute__((always_inline))
Configures the pin to be an output and toggles it.
Definition: FastGPIO.h:246
static void setOutput(bool value) __attribute__((always_inline))
Sets the pin as an output.
Definition: FastGPIO.h:260
static void setOutputValueLow() __attribute__((always_inline))
Sets the output value of the pin to 0.
Definition: FastGPIO.h:274
static void setInput() __attribute__((always_inline))
Sets a pin to be a digital input with the internal pull-up resistor disabled.
Definition: FastGPIO.h:333
static bool isOutputValueHigh() __attribute__((always_inline))
Returns the output value of the pin.
Definition: FastGPIO.h:385
static void setState(uint8_t state)
Sets the full 2-bit state of the pin.
Definition: FastGPIO.h:428
static void setOutputValueHigh() __attribute__((always_inline))
Sets the output value of the pin to 1.
Definition: FastGPIO.h:287
static bool isOutput() __attribute__((always_inline))
Returns 1 if the pin is configured as an output.
Definition: FastGPIO.h:374
static void setOutputValueToggle() __attribute__((always_inline))
Toggles the output value of the pin.
Definition: FastGPIO.h:302
static void setOutputHigh() __attribute__((always_inline))
Configures the pin to be an output driving high.
Definition: FastGPIO.h:238
static void setInputPulledUp() __attribute__((always_inline))
Sets a pin to be a digital input with the internal pull-up resistor enabled.
Definition: FastGPIO.h:342
static void setOutputValue(bool value) __attribute__((always_inline))
Sets the output value of the pin.
Definition: FastGPIO.h:318
static void setOutputLow() __attribute__((always_inline))
Configures the pin to be an output driving low.
Definition: FastGPIO.h:226
static uint8_t getState()
Returns the full 2-bit state of the pin.
Definition: FastGPIO.h:396