aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid A. Mellis <d.mellis@arduino.cc>2011-02-11 19:29:46 -0500
committerDavid A. Mellis <d.mellis@arduino.cc>2011-02-11 19:29:46 -0500
commiteed15e48d68d10426e015515ec4143849739f2de (patch)
tree4fc54101c58590a6c1c7225a60d223797f4e198b
parent3696fa044687542ee6b4a9bc488348e184ee3ae2 (diff)
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.
-rw-r--r--cores/arduino/pins_arduino.h46
-rwxr-xr-xcores/arduino/wiring.h148
-rwxr-xr-xcores/arduino/wiring_digital.c76
3 files changed, 116 insertions, 154 deletions
diff --git a/cores/arduino/pins_arduino.h b/cores/arduino/pins_arduino.h
index 63f4257..4bf6470 100644
--- a/cores/arduino/pins_arduino.h
+++ b/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/cores/arduino/wiring.h b/cores/arduino/wiring.h
index 433c87e..66ce2f7 100755
--- a/cores/arduino/wiring.h
+++ b/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/cores/arduino/wiring_digital.c b/cores/arduino/wiring_digital.c
index 95666b1..9671045 100755
--- a/cores/arduino/wiring_digital.c
+++ b/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);
}