[gnoduino: 2/237] Changes to optimized digitalWrte(), etc.



commit eaa2c19de15230c729158656f680162815233163
Author: David A. Mellis <d mellis arduino cc>
Date:   Fri Feb 11 19:29:46 2011 -0500

    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.

 arduino/cores/arduino/pins_arduino.h   |   46 +---------
 arduino/cores/arduino/wiring.h         |  148 +++++++++++++++++++++++---------
 arduino/cores/arduino/wiring_digital.c |   76 +---------------
 3 files changed, 116 insertions(+), 154 deletions(-)
---
diff --git a/arduino/cores/arduino/pins_arduino.h b/arduino/cores/arduino/pins_arduino.h
index 63f4257..4bf6470 100644
--- a/arduino/cores/arduino/pins_arduino.h
+++ b/arduino/cores/arduino/pins_arduino.h
@@ -339,6 +339,8 @@ INLINED uint8_t inlined_digitalPinToBitMask(uint8_t pin)
 	}
 }
 
+// XXX: this needs to return false (or -1) if the pin doesn't have a timer,
+// rather than throwing a compilation error.
 INLINED uint8_t inlined_digitalPinToTimer(uint8_t pin)
 {
 	switch(pin) {
@@ -453,6 +455,8 @@ INLINED uint8_t inlined_digitalPinToBitMask(uint8_t pin)
 	}
 }
 
+// XXX: this needs to return false (or -1) if the pin doesn't have a timer,
+// rather than throwing a compilation error.
 INLINED uint8_t inlined_digitalPinToTimer(uint8_t pin)
 {
 	switch(pin) {
@@ -477,46 +481,4 @@ INLINED uint8_t inlined_digitalPinToTimer(uint8_t pin)
 
 #define analogInPinToBit(P) (P)
 
-INLINED uint8_t digitalPinToPort(uint8_t pin) {
-	if (__builtin_constant_p(pin))
-		return inlined_digitalPinToPort(pin);
-	else
-		return pgm_read_byte( digital_pin_to_port_PGM + pin );
-}
-
-INLINED uint8_t digitalPinToBitMask(uint8_t pin) {
-	if (__builtin_constant_p(pin))
-		return inlined_digitalPinToBitMask(pin);
-	else
-		return pgm_read_byte( digital_pin_to_bit_mask_PGM + pin );
-}
-
-INLINED uint8_t digitalPinToTimer(uint8_t pin) {
-	if (__builtin_constant_p(pin))
-		return inlined_digitalPinToTimer(pin);
-	else
-		return pgm_read_byte( digital_pin_to_timer_PGM + pin );
-}
-
-INLINED volatile uint8_t *portOutputRegister(uint8_t index) {
-	if (__builtin_constant_p(index))
-		return inlined_portOutputRegister(index);
-	else
-		return (volatile uint8_t *)( pgm_read_word( port_to_output_PGM + index ) );
-}
-
-INLINED volatile uint8_t* portInputRegister(uint8_t index) {
-	if (__builtin_constant_p(index))
-		return inlined_portInputRegister(index);
-	else
-		return (volatile uint8_t *)( pgm_read_word( port_to_input_PGM + index) );
-}
-
-INLINED volatile uint8_t* portModeRegister(uint8_t index) {
-	if (__builtin_constant_p(index))
-		return inlined_portModeRegister(index);
-	else
-		return (volatile uint8_t *)( pgm_read_word( port_to_mode_PGM + index) );
-}
-
 #endif
diff --git a/arduino/cores/arduino/wiring.h b/arduino/cores/arduino/wiring.h
index 433c87e..66ce2f7 100755
--- a/arduino/cores/arduino/wiring.h
+++ b/arduino/cores/arduino/wiring.h
@@ -130,68 +130,136 @@ void detachInterrupt(uint8_t);
 void setup(void);
 void loop(void);
 
+INLINED uint8_t digitalPinToPort(uint8_t pin) {
+	if (__builtin_constant_p(pin))
+		return inlined_digitalPinToPort(pin);
+	else
+		return pgm_read_byte( digital_pin_to_port_PGM + pin );
+}
+
+INLINED uint8_t digitalPinToBitMask(uint8_t pin) {
+	if (__builtin_constant_p(pin))
+		return inlined_digitalPinToBitMask(pin);
+	else
+		return pgm_read_byte( digital_pin_to_bit_mask_PGM + pin );
+}
+
+INLINED uint8_t digitalPinToTimer(uint8_t pin) {
+	if (__builtin_constant_p(pin))
+		return inlined_digitalPinToTimer(pin);
+	else
+		return pgm_read_byte( digital_pin_to_timer_PGM + pin );
+}
+
+INLINED volatile uint8_t *portOutputRegister(uint8_t index) {
+	if (__builtin_constant_p(index))
+		return inlined_portOutputRegister(index);
+	else
+		return (volatile uint8_t *)( pgm_read_word( port_to_output_PGM + index ) );
+}
+
+INLINED volatile uint8_t* portInputRegister(uint8_t index) {
+	if (__builtin_constant_p(index))
+		return inlined_portInputRegister(index);
+	else
+		return (volatile uint8_t *)( pgm_read_word( port_to_input_PGM + index) );
+}
+
+INLINED volatile uint8_t* portModeRegister(uint8_t index) {
+	if (__builtin_constant_p(index))
+		return inlined_portModeRegister(index);
+	else
+		return (volatile uint8_t *)( pgm_read_word( port_to_mode_PGM + index) );
+}
+
 /*
  * Check if a given pin requires locking.
  * When accessing lower 32 IO ports we can use SBI/CBI instructions, which are atomic. However
  * other IO ports require load+modify+store and we need to make them atomic by disabling
  * interrupts.
  */
-INLINED int portWriteNeedsLocking(uint8_t pin)
+INLINED int registerWriteNeedsLocking(volatile uint8_t *reg)
 {
 	/* SBI/CBI instructions only work on lower 32 IO ports */
-	if (inlined_portOutputRegister(inlined_digitalPinToPort(pin)) > (volatile uint8_t*)&_SFR_IO8(0x1F)) {
+	if (reg > (volatile uint8_t*)&_SFR_IO8(0x1F)) {
 		return 1;
 	}
 	return 0;
 }
 
-/*
- * These functions will perform OR/AND on a given register, and are atomic.
- */
-extern void __digitalWriteOR_locked(volatile uint8_t*out, uint8_t bit);
-extern void __digitalWriteAND_locked(volatile uint8_t*out, uint8_t bit);
-
+#define digitalWrite_implementation(pin, value)\
+do {\
+	uint8_t oldSREG;\
+	uint8_t bit = digitalPinToBitMask(pin);\
+	uint8_t port = digitalPinToPort(pin);\
+	volatile uint8_t *reg = portOutputRegister(port);\
+\
+	if (!__builtin_constant_p(pin) || registerWriteNeedsLocking(reg)) {\
+		oldSREG = SREG;\
+		cli();\
+	}\
+\
+	if (value == LOW) {\
+		*reg &= ~bit;\
+	} else {\
+		*reg |= bit;\
+	}\
+\
+	if (!__builtin_constant_p(pin) || registerWriteNeedsLocking(reg)) {\
+		SREG = oldSREG;\
+	}\
+} while(0)
+	
 INLINED void digitalWrite(uint8_t pin, uint8_t value)
 {
-	if (__builtin_constant_p(pin)) {
-		if (portWriteNeedsLocking(pin)) {
-			if (value==LOW) {
-				__digitalWriteAND_locked(inlined_portOutputRegister(inlined_digitalPinToPort(pin)),~inlined_digitalPinToBitMask(pin));
-			} else {
-				__digitalWriteOR_locked(inlined_portOutputRegister(inlined_digitalPinToPort(pin)),inlined_digitalPinToBitMask(pin));
-			}
-		} else {
-			if (value==LOW) {
-				*inlined_portOutputRegister(inlined_digitalPinToPort(pin)) &= ~(inlined_digitalPinToBitMask(pin));
-			} else {
-				*inlined_portOutputRegister(inlined_digitalPinToPort(pin)) |= inlined_digitalPinToBitMask(pin);
-			}
-		}
-	} else {
-		digitalWrite_lookup(pin,value);
-	}
+	if (__builtin_constant_p(pin)) digitalWrite_implementation(pin, value);
+	else digitalWrite_lookup(pin, value);
 }
 
-INLINED void pinMode(uint8_t pin, uint8_t mode)
+#define pinMode_implementation(pin, value)\
+do {\
+	uint8_t bit = digitalPinToBitMask(pin);\
+	uint8_t oldSREG;\
+	uint8_t port = digitalPinToPort(pin);\
+	volatile uint8_t *reg = portModeRegister(port);\
+\
+	if (!__builtin_constant_p(pin) || registerWriteNeedsLocking(reg)) {\
+		oldSREG = SREG;\
+		cli();\
+	}\
+\
+	if (value == INPUT) { \
+		*reg &= ~bit;\
+	} else {\
+		*reg |= bit;\
+	}\
+\
+	if (!__builtin_constant_p(pin) || registerWriteNeedsLocking(reg)) {\
+		SREG = oldSREG;\
+	}\
+} while(0)
+
+INLINED void pinMode(uint8_t pin, uint8_t value)
 {
-	if (__builtin_constant_p(pin)) {
-		if (mode==INPUT) {
-			*inlined_portModeRegister(inlined_digitalPinToPort(pin)) &= ~(inlined_digitalPinToBitMask(pin));
-		} else {
-			*inlined_portModeRegister(inlined_digitalPinToPort(pin)) |= inlined_digitalPinToBitMask(pin);
-		}
-	} else {
-		pinMode_lookup(pin,mode);
-	}
+	if (__builtin_constant_p(pin)) pinMode_implementation(pin, value);
+	else pinMode_lookup(pin, value);
 }
 
+#define digitalRead_implementation(pin)\
+do {\
+	uint8_t bit = digitalPinToBitMask(pin);\
+	uint8_t port = digitalPinToPort(pin);\
+\
+	if (port == NOT_A_PIN) return LOW;\
+\
+	if (*portInputRegister(port) & bit) return HIGH;\
+	return LOW;\
+} while(0)
+
 INLINED int digitalRead(uint8_t pin)
 {
-	if (__builtin_constant_p(pin)) {
-		return !! *inlined_portInputRegister(inlined_digitalPinToPort(pin));
-	} else {
-		return digitalRead_lookup(pin);
-	}
+	if (__builtin_constant_p(pin)) digitalRead_implementation(pin);
+	else return digitalRead_lookup(pin);
 }
 
 
diff --git a/arduino/cores/arduino/wiring_digital.c b/arduino/cores/arduino/wiring_digital.c
index 95666b1..9671045 100755
--- a/arduino/cores/arduino/wiring_digital.c
+++ b/arduino/cores/arduino/wiring_digital.c
@@ -27,28 +27,9 @@
 #include "wiring_private.h"
 #include "pins_arduino.h"
 
-void pinMode_lookup(uint8_t pin, uint8_t mode)
+void pinMode_lookup(uint8_t pin, uint8_t val)
 {
-	uint8_t bit = digitalPinToBitMask(pin);
-	uint8_t port = digitalPinToPort(pin);
-	volatile uint8_t *reg;
-
-	if (port == NOT_A_PIN) return;
-
-	// JWS: can I let the optimizer do this?
-	reg = portModeRegister(port);
-
-	if (mode == INPUT) { 
-		uint8_t oldSREG = SREG;
-                cli();
-		*reg &= ~bit;
-		SREG = oldSREG;
-	} else {
-		uint8_t oldSREG = SREG;
-                cli();
-		*reg |= bit;
-		SREG = oldSREG;
-	}
+	pinMode_implementation(pin, val);
 }
 
 // Forcing this inline keeps the callers from having to push their own stuff
@@ -121,61 +102,12 @@ static void turnOffPWM(uint8_t timer)
 	}
 }
 
-void __digitalWriteOR_locked(volatile uint8_t*out, uint8_t bit)
-{
-	uint8_t oldSREG = SREG;
-	cli();
-	*out |= bit;
-	SREG=oldSREG;
-}
-
-void __digitalWriteAND_locked(volatile uint8_t*out, uint8_t bit)
-{
-	uint8_t oldSREG = SREG;
-	cli();
-	*out &= bit; // NOTE - no inversion here, invert before calling!!!
-	SREG=oldSREG;
-}
-
 void digitalWrite_lookup(uint8_t pin, uint8_t val)
 {
-	uint8_t timer = digitalPinToTimer(pin);
-	uint8_t bit = digitalPinToBitMask(pin);
-	uint8_t port = digitalPinToPort(pin);
-	volatile uint8_t *out;
-
-	if (port == NOT_A_PIN) return;
-
-	// If the pin that support PWM output, we need to turn it off
-	// before doing a digital write.
-	if (timer != NOT_ON_TIMER) turnOffPWM(timer);
-
-	out = portOutputRegister(port);
-
-	uint8_t oldSREG = SREG;
-	cli();
-
-	if (val == LOW) {
-		*out &= ~bit;
-	} else {
-		*out |= bit;
-	}
-
-	SREG = oldSREG;
+	digitalWrite_implementation(pin, val);
 }
 
 int digitalRead_lookup(uint8_t pin)
 {
-	uint8_t timer = digitalPinToTimer(pin);
-	uint8_t bit = digitalPinToBitMask(pin);
-	uint8_t port = digitalPinToPort(pin);
-
-	if (port == NOT_A_PIN) return LOW;
-
-	// If the pin that support PWM output, we need to turn it off
-	// before getting a digital reading.
-	if (timer != NOT_ON_TIMER) turnOffPWM(timer);
-
-	if (*portInputRegister(port) & bit) return HIGH;
-	return LOW;
+	digitalRead_implementation(pin);
 }



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]