Zumo32U4 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 }
57namespace 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 {
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 {
551 }
552
553 ~PinLoan()
554 {
556 }
557 };
558};
559
560#undef _FG_PIN
561#undef _FG_CBI
562#undef _FG_SBI
static bool isOutputValueHigh() __attribute__((always_inline))
Returns the output value of the pin.
Definition: FastGPIO.h:443
static void setOutputValue(bool value) __attribute__((always_inline))
Sets the output value of the pin.
Definition: FastGPIO.h:376
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 setOutputLow() __attribute__((always_inline))
Configures the pin to be an output driving low.
Definition: FastGPIO.h:284
static void setOutputValueToggle() __attribute__((always_inline))
Toggles the output value of the pin.
Definition: FastGPIO.h:360
static void setOutputValueHigh() __attribute__((always_inline))
Sets the output value of the pin to 1.
Definition: FastGPIO.h:345
static void setState(uint8_t state)
Sets the full 2-bit state of the pin.
Definition: FastGPIO.h:486
static uint8_t getState()
Returns the full 2-bit state of the pin.
Definition: FastGPIO.h:454
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 setOutput(bool value) __attribute__((always_inline))
Sets the pin as an output.
Definition: FastGPIO.h:318
static void setOutputHigh() __attribute__((always_inline))
Configures the pin to be an output driving high.
Definition: FastGPIO.h:296
static void setOutputToggle() __attribute__((always_inline))
Configures the pin to be an output and toggles it.
Definition: FastGPIO.h:304
static bool isInputHigh() __attribute__((always_inline))
Reads the input value of the pin.
Definition: FastGPIO.h:410
static void setOutputValueLow() __attribute__((always_inline))
Sets the output value of the pin to 0.
Definition: FastGPIO.h:332
static bool isOutput() __attribute__((always_inline))
Returns 1 if the pin is configured as an output.
Definition: FastGPIO.h:432
uint8_t state
The state of the pin as returned from FastGPIO::Pin::getState.
Definition: FastGPIO.h:546