Skip to content
This repository
Browse code

Changes to optimized digitalWrte(), etc.

Factoring out the implementation of digitalWrite(), digitalRead(), and pinMode() into macros that can either be inlined (for constant pin numbers) or executed within a function (non-constant pins).  Removing testing for timers on pins in digitalWrite(), digitalRead(), and pinMode().  Moving pin to port macros from pins_arduino.h to wiring.h.
  • Loading branch information...
commit aa1f1cbda9d6bb52785f98b40746920853d6579b 1 parent 9dccd63
David A. Mellis authored February 11, 2011
46  hardware/arduino/cores/arduino/pins_arduino.h
@@ -339,6 +339,8 @@ INLINED uint8_t inlined_digitalPinToBitMask(uint8_t pin)
339 339
 	}
340 340
 }
341 341
 
  342
+// XXX: this needs to return false (or -1) if the pin doesn't have a timer,
  343
+// rather than throwing a compilation error.
342 344
 INLINED uint8_t inlined_digitalPinToTimer(uint8_t pin)
343 345
 {
344 346
 	switch(pin) {
@@ -453,6 +455,8 @@ INLINED uint8_t inlined_digitalPinToBitMask(uint8_t pin)
453 455
 	}
454 456
 }
455 457
 
  458
+// XXX: this needs to return false (or -1) if the pin doesn't have a timer,
  459
+// rather than throwing a compilation error.
456 460
 INLINED uint8_t inlined_digitalPinToTimer(uint8_t pin)
457 461
 {
458 462
 	switch(pin) {
@@ -477,46 +481,4 @@ INLINED uint8_t inlined_digitalPinToTimer(uint8_t pin)
477 481
 
478 482
 #define analogInPinToBit(P) (P)
479 483
 
480  
-INLINED uint8_t digitalPinToPort(uint8_t pin) {
481  
-	if (__builtin_constant_p(pin))
482  
-		return inlined_digitalPinToPort(pin);
483  
-	else
484  
-		return pgm_read_byte( digital_pin_to_port_PGM + pin );
485  
-}
486  
-
487  
-INLINED uint8_t digitalPinToBitMask(uint8_t pin) {
488  
-	if (__builtin_constant_p(pin))
489  
-		return inlined_digitalPinToBitMask(pin);
490  
-	else
491  
-		return pgm_read_byte( digital_pin_to_bit_mask_PGM + pin );
492  
-}
493  
-
494  
-INLINED uint8_t digitalPinToTimer(uint8_t pin) {
495  
-	if (__builtin_constant_p(pin))
496  
-		return inlined_digitalPinToTimer(pin);
497  
-	else
498  
-		return pgm_read_byte( digital_pin_to_timer_PGM + pin );
499  
-}
500  
-
501  
-INLINED volatile uint8_t *portOutputRegister(uint8_t index) {
502  
-	if (__builtin_constant_p(index))
503  
-		return inlined_portOutputRegister(index);
504  
-	else
505  
-		return (volatile uint8_t *)( pgm_read_word( port_to_output_PGM + index ) );
506  
-}
507  
-
508  
-INLINED volatile uint8_t* portInputRegister(uint8_t index) {
509  
-	if (__builtin_constant_p(index))
510  
-		return inlined_portInputRegister(index);
511  
-	else
512  
-		return (volatile uint8_t *)( pgm_read_word( port_to_input_PGM + index) );
513  
-}
514  
-
515  
-INLINED volatile uint8_t* portModeRegister(uint8_t index) {
516  
-	if (__builtin_constant_p(index))
517  
-		return inlined_portModeRegister(index);
518  
-	else
519  
-		return (volatile uint8_t *)( pgm_read_word( port_to_mode_PGM + index) );
520  
-}
521  
-
522 484
 #endif
148  hardware/arduino/cores/arduino/wiring.h
@@ -130,68 +130,136 @@ void detachInterrupt(uint8_t);
130 130
 void setup(void);
131 131
 void loop(void);
132 132
 
  133
+INLINED uint8_t digitalPinToPort(uint8_t pin) {
  134
+	if (__builtin_constant_p(pin))
  135
+		return inlined_digitalPinToPort(pin);
  136
+	else
  137
+		return pgm_read_byte( digital_pin_to_port_PGM + pin );
  138
+}
  139
+
  140
+INLINED uint8_t digitalPinToBitMask(uint8_t pin) {
  141
+	if (__builtin_constant_p(pin))
  142
+		return inlined_digitalPinToBitMask(pin);
  143
+	else
  144
+		return pgm_read_byte( digital_pin_to_bit_mask_PGM + pin );
  145
+}
  146
+
  147
+INLINED uint8_t digitalPinToTimer(uint8_t pin) {
  148
+	if (__builtin_constant_p(pin))
  149
+		return inlined_digitalPinToTimer(pin);
  150
+	else
  151
+		return pgm_read_byte( digital_pin_to_timer_PGM + pin );
  152
+}
  153
+
  154
+INLINED volatile uint8_t *portOutputRegister(uint8_t index) {
  155
+	if (__builtin_constant_p(index))
  156
+		return inlined_portOutputRegister(index);
  157
+	else
  158
+		return (volatile uint8_t *)( pgm_read_word( port_to_output_PGM + index ) );
  159
+}
  160
+
  161
+INLINED volatile uint8_t* portInputRegister(uint8_t index) {
  162
+	if (__builtin_constant_p(index))
  163
+		return inlined_portInputRegister(index);
  164
+	else
  165
+		return (volatile uint8_t *)( pgm_read_word( port_to_input_PGM + index) );
  166
+}
  167
+
  168
+INLINED volatile uint8_t* portModeRegister(uint8_t index) {
  169
+	if (__builtin_constant_p(index))
  170
+		return inlined_portModeRegister(index);
  171
+	else
  172
+		return (volatile uint8_t *)( pgm_read_word( port_to_mode_PGM + index) );
  173
+}
  174
+
133 175
 /*
134 176
  * Check if a given pin requires locking.
135 177
  * When accessing lower 32 IO ports we can use SBI/CBI instructions, which are atomic. However
136 178
  * other IO ports require load+modify+store and we need to make them atomic by disabling
137 179
  * interrupts.
138 180
  */
139  
-INLINED int portWriteNeedsLocking(uint8_t pin)
  181
+INLINED int registerWriteNeedsLocking(volatile uint8_t *reg)
140 182
 {
141 183
 	/* SBI/CBI instructions only work on lower 32 IO ports */
142  
-	if (inlined_portOutputRegister(inlined_digitalPinToPort(pin)) > (volatile uint8_t*)&_SFR_IO8(0x1F)) {
  184
+	if (reg > (volatile uint8_t*)&_SFR_IO8(0x1F)) {
143 185
 		return 1;
144 186
 	}
145 187
 	return 0;
146 188
 }
147 189
 
148  
-/*
149  
- * These functions will perform OR/AND on a given register, and are atomic.
150  
- */
151  
-extern void __digitalWriteOR_locked(volatile uint8_t*out, uint8_t bit);
152  
-extern void __digitalWriteAND_locked(volatile uint8_t*out, uint8_t bit);
153  
-
  190
+#define digitalWrite_implementation(pin, value)\
  191
+do {\
  192
+	uint8_t oldSREG;\
  193
+	uint8_t bit = digitalPinToBitMask(pin);\
  194
+	uint8_t port = digitalPinToPort(pin);\
  195
+	volatile uint8_t *reg = portOutputRegister(port);\
  196
+\
  197
+	if (!__builtin_constant_p(pin) || registerWriteNeedsLocking(reg)) {\
  198
+		oldSREG = SREG;\
  199
+		cli();\
  200
+	}\
  201
+\
  202
+	if (value == LOW) {\
  203
+		*reg &= ~bit;\
  204
+	} else {\
  205
+		*reg |= bit;\
  206
+	}\
  207
+\
  208
+	if (!__builtin_constant_p(pin) || registerWriteNeedsLocking(reg)) {\
  209
+		SREG = oldSREG;\
  210
+	}\
  211
+} while(0)
  212
+	
154 213
 INLINED void digitalWrite(uint8_t pin, uint8_t value)
155 214
 {
156  
-	if (__builtin_constant_p(pin)) {
157  
-		if (portWriteNeedsLocking(pin)) {
158  
-			if (value==LOW) {
159  
-				__digitalWriteAND_locked(inlined_portOutputRegister(inlined_digitalPinToPort(pin)),~inlined_digitalPinToBitMask(pin));
160  
-			} else {
161  
-				__digitalWriteOR_locked(inlined_portOutputRegister(inlined_digitalPinToPort(pin)),inlined_digitalPinToBitMask(pin));
162  
-			}
163  
-		} else {
164  
-			if (value==LOW) {
165  
-				*inlined_portOutputRegister(inlined_digitalPinToPort(pin)) &= ~(inlined_digitalPinToBitMask(pin));
166  
-			} else {
167  
-				*inlined_portOutputRegister(inlined_digitalPinToPort(pin)) |= inlined_digitalPinToBitMask(pin);
168  
-			}
169  
-		}
170  
-	} else {
171  
-		digitalWrite_lookup(pin,value);
172  
-	}
  215
+	if (__builtin_constant_p(pin)) digitalWrite_implementation(pin, value);
  216
+	else digitalWrite_lookup(pin, value);
173 217
 }
174 218
 
175  
-INLINED void pinMode(uint8_t pin, uint8_t mode)
  219
+#define pinMode_implementation(pin, value)\
  220
+do {\
  221
+	uint8_t bit = digitalPinToBitMask(pin);\
  222
+	uint8_t oldSREG;\
  223
+	uint8_t port = digitalPinToPort(pin);\
  224
+	volatile uint8_t *reg = portModeRegister(port);\
  225
+\
  226
+	if (!__builtin_constant_p(pin) || registerWriteNeedsLocking(reg)) {\
  227
+		oldSREG = SREG;\
  228
+		cli();\
  229
+	}\
  230
+\
  231
+	if (value == INPUT) { \
  232
+		*reg &= ~bit;\
  233
+	} else {\
  234
+		*reg |= bit;\
  235
+	}\
  236
+\
  237
+	if (!__builtin_constant_p(pin) || registerWriteNeedsLocking(reg)) {\
  238
+		SREG = oldSREG;\
  239
+	}\
  240
+} while(0)
  241
+
  242
+INLINED void pinMode(uint8_t pin, uint8_t value)
176 243
 {
177  
-	if (__builtin_constant_p(pin)) {
178  
-		if (mode==INPUT) {
179  
-			*inlined_portModeRegister(inlined_digitalPinToPort(pin)) &= ~(inlined_digitalPinToBitMask(pin));
180  
-		} else {
181  
-			*inlined_portModeRegister(inlined_digitalPinToPort(pin)) |= inlined_digitalPinToBitMask(pin);
182  
-		}
183  
-	} else {
184  
-		pinMode_lookup(pin,mode);
185  
-	}
  244
+	if (__builtin_constant_p(pin)) pinMode_implementation(pin, value);
  245
+	else pinMode_lookup(pin, value);
186 246
 }
187 247
 
  248
+#define digitalRead_implementation(pin)\
  249
+do {\
  250
+	uint8_t bit = digitalPinToBitMask(pin);\
  251
+	uint8_t port = digitalPinToPort(pin);\
  252
+\
  253
+	if (port == NOT_A_PIN) return LOW;\
  254
+\
  255
+	if (*portInputRegister(port) & bit) return HIGH;\
  256
+	return LOW;\
  257
+} while(0)
  258
+
188 259
 INLINED int digitalRead(uint8_t pin)
189 260
 {
190  
-	if (__builtin_constant_p(pin)) {
191  
-		return !! *inlined_portInputRegister(inlined_digitalPinToPort(pin));
192  
-	} else {
193  
-		return digitalRead_lookup(pin);
194  
-	}
  261
+	if (__builtin_constant_p(pin)) digitalRead_implementation(pin);
  262
+	else return digitalRead_lookup(pin);
195 263
 }
196 264
 
197 265
 
76  hardware/arduino/cores/arduino/wiring_digital.c
@@ -27,28 +27,9 @@
27 27
 #include "wiring_private.h"
28 28
 #include "pins_arduino.h"
29 29
 
30  
-void pinMode_lookup(uint8_t pin, uint8_t mode)
  30
+void pinMode_lookup(uint8_t pin, uint8_t val)
31 31
 {
32  
-	uint8_t bit = digitalPinToBitMask(pin);
33  
-	uint8_t port = digitalPinToPort(pin);
34  
-	volatile uint8_t *reg;
35  
-
36  
-	if (port == NOT_A_PIN) return;
37  
-
38  
-	// JWS: can I let the optimizer do this?
39  
-	reg = portModeRegister(port);
40  
-
41  
-	if (mode == INPUT) { 
42  
-		uint8_t oldSREG = SREG;
43  
-                cli();
44  
-		*reg &= ~bit;
45  
-		SREG = oldSREG;
46  
-	} else {
47  
-		uint8_t oldSREG = SREG;
48  
-                cli();
49  
-		*reg |= bit;
50  
-		SREG = oldSREG;
51  
-	}
  32
+	pinMode_implementation(pin, val);
52 33
 }
53 34
 
54 35
 // Forcing this inline keeps the callers from having to push their own stuff
@@ -121,61 +102,12 @@ static void turnOffPWM(uint8_t timer)
121 102
 	}
122 103
 }
123 104
 
124  
-void __digitalWriteOR_locked(volatile uint8_t*out, uint8_t bit)
125  
-{
126  
-	uint8_t oldSREG = SREG;
127  
-	cli();
128  
-	*out |= bit;
129  
-	SREG=oldSREG;
130  
-}
131  
-
132  
-void __digitalWriteAND_locked(volatile uint8_t*out, uint8_t bit)
133  
-{
134  
-	uint8_t oldSREG = SREG;
135  
-	cli();
136  
-	*out &= bit; // NOTE - no inversion here, invert before calling!!!
137  
-	SREG=oldSREG;
138  
-}
139  
-
140 105
 void digitalWrite_lookup(uint8_t pin, uint8_t val)
141 106
 {
142  
-	uint8_t timer = digitalPinToTimer(pin);
143  
-	uint8_t bit = digitalPinToBitMask(pin);
144  
-	uint8_t port = digitalPinToPort(pin);
145  
-	volatile uint8_t *out;
146  
-
147  
-	if (port == NOT_A_PIN) return;
148  
-
149  
-	// If the pin that support PWM output, we need to turn it off
150  
-	// before doing a digital write.
151  
-	if (timer != NOT_ON_TIMER) turnOffPWM(timer);
152  
-
153  
-	out = portOutputRegister(port);
154  
-
155  
-	uint8_t oldSREG = SREG;
156  
-	cli();
157  
-
158  
-	if (val == LOW) {
159  
-		*out &= ~bit;
160  
-	} else {
161  
-		*out |= bit;
162  
-	}
163  
-
164  
-	SREG = oldSREG;
  107
+	digitalWrite_implementation(pin, val);
165 108
 }
166 109
 
167 110
 int digitalRead_lookup(uint8_t pin)
168 111
 {
169  
-	uint8_t timer = digitalPinToTimer(pin);
170  
-	uint8_t bit = digitalPinToBitMask(pin);
171  
-	uint8_t port = digitalPinToPort(pin);
172  
-
173  
-	if (port == NOT_A_PIN) return LOW;
174  
-
175  
-	// If the pin that support PWM output, we need to turn it off
176  
-	// before getting a digital reading.
177  
-	if (timer != NOT_ON_TIMER) turnOffPWM(timer);
178  
-
179  
-	if (*portInputRegister(port) & bit) return HIGH;
180  
-	return LOW;
  112
+	digitalRead_implementation(pin);
181 113
 }

0 notes on commit aa1f1cb

Please sign in to comment.
Something went wrong with that request. Please try again.