From a28cb531ccdcb292a603c8c758776f35dff54ac9 Mon Sep 17 00:00:00 2001 From: Angus Gratton Date: Fri, 15 Feb 2013 13:12:39 +1100 Subject: [PATCH 01/10] Got things working, jump tables still far too big --- hardware/arduino/cores/arduino/Arduino.h | 67 +-- .../arduino/cores/arduino/pin_functions.h | 500 ++++++++++++++++++ .../arduino/cores/arduino/wiring_digital.c | 151 +----- hardware/arduino/cores/arduino/wiring_pulse.c | 3 + .../arduino/variants/standard/pins_arduino.h | 34 +- 5 files changed, 536 insertions(+), 219 deletions(-) create mode 100644 hardware/arduino/cores/arduino/pin_functions.h diff --git a/hardware/arduino/cores/arduino/Arduino.h b/hardware/arduino/cores/arduino/Arduino.h index b265825894a..5f218dcc466 100755 --- a/hardware/arduino/cores/arduino/Arduino.h +++ b/hardware/arduino/cores/arduino/Arduino.h @@ -8,6 +8,7 @@ #include #include #include +#include #include "binary.h" @@ -45,7 +46,7 @@ extern "C"{ #define DEFAULT 0 #define EXTERNAL 1 #define INTERNAL 2 -#else +#else #if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) || defined(__AVR_ATmega1284P__) || defined(__AVR_ATmega644P__) #define INTERNAL1V1 2 #define INTERNAL2V56 3 @@ -95,9 +96,9 @@ typedef uint8_t byte; void init(void); -void pinMode(uint8_t, uint8_t); -void digitalWrite(uint8_t, uint8_t); -int digitalRead(uint8_t); +static inline void pinMode(uint8_t, uint8_t); +static inline void digitalWrite(uint8_t, uint8_t); +static inline int digitalRead(uint8_t); int analogRead(uint8_t); void analogReference(uint8_t mode); void analogWrite(uint8_t, int); @@ -122,66 +123,12 @@ void loop(void); #define analogInPinToBit(P) (P) -// On the ATmega1280, the addresses of some of the port registers are -// greater than 255, so we can't store them in uint8_t's. -extern const uint16_t PROGMEM port_to_mode_PGM[]; -extern const uint16_t PROGMEM port_to_input_PGM[]; -extern const uint16_t PROGMEM port_to_output_PGM[]; - -extern const uint8_t PROGMEM digital_pin_to_port_PGM[]; -// extern const uint8_t PROGMEM digital_pin_to_bit_PGM[]; -extern const uint8_t PROGMEM digital_pin_to_bit_mask_PGM[]; -extern const uint8_t PROGMEM digital_pin_to_timer_PGM[]; - // Get the bit location within the hardware port of the given virtual pin. // This comes from the pins_*.c file for the active board configuration. -// +// // These perform slightly better as macros compared to inline functions // -#define digitalPinToPort(P) ( pgm_read_byte( digital_pin_to_port_PGM + (P) ) ) -#define digitalPinToBitMask(P) ( pgm_read_byte( digital_pin_to_bit_mask_PGM + (P) ) ) -#define digitalPinToTimer(P) ( pgm_read_byte( digital_pin_to_timer_PGM + (P) ) ) #define analogInPinToBit(P) (P) -#define portOutputRegister(P) ( (volatile uint8_t *)( pgm_read_word( port_to_output_PGM + (P))) ) -#define portInputRegister(P) ( (volatile uint8_t *)( pgm_read_word( port_to_input_PGM + (P))) ) -#define portModeRegister(P) ( (volatile uint8_t *)( pgm_read_word( port_to_mode_PGM + (P))) ) - -#define NOT_A_PIN 0 -#define NOT_A_PORT 0 - -#ifdef ARDUINO_MAIN -#define PA 1 -#define PB 2 -#define PC 3 -#define PD 4 -#define PE 5 -#define PF 6 -#define PG 7 -#define PH 8 -#define PJ 10 -#define PK 11 -#define PL 12 -#endif - -#define NOT_ON_TIMER 0 -#define TIMER0A 1 -#define TIMER0B 2 -#define TIMER1A 3 -#define TIMER1B 4 -#define TIMER2 5 -#define TIMER2A 6 -#define TIMER2B 7 - -#define TIMER3A 8 -#define TIMER3B 9 -#define TIMER3C 10 -#define TIMER4A 11 -#define TIMER4B 12 -#define TIMER4C 13 -#define TIMER4D 14 -#define TIMER5A 15 -#define TIMER5B 16 -#define TIMER5C 17 #ifdef __cplusplus } // extern "C" @@ -210,6 +157,6 @@ long map(long, long, long, long, long); #endif -#include "pins_arduino.h" +#include "pin_functions.h" #endif diff --git a/hardware/arduino/cores/arduino/pin_functions.h b/hardware/arduino/cores/arduino/pin_functions.h new file mode 100644 index 00000000000..9256aa1a611 --- /dev/null +++ b/hardware/arduino/cores/arduino/pin_functions.h @@ -0,0 +1,500 @@ +/* + * This header includes pins_arduino.h to get board-specific pin data, + * then lays out the functions for inlining digital reads & writes based + * on that pin data. + */ +#ifndef _PIN_FUNCTIONS_H +#define _PIN_FUNCTIONS_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define NOT_A_PIN 0 +#define NOT_A_PORT 0 + +#define NOT_ON_TIMER 0 +#define TIMER0A 1 +#define TIMER0B 2 +#define TIMER1A 3 +#define TIMER1B 4 +#define TIMER2 5 +#define TIMER2A 6 +#define TIMER2B 7 + +#define TIMER3A 8 +#define TIMER3B 9 +#define TIMER3C 10 +#define TIMER4A 11 +#define TIMER4B 12 +#define TIMER4C 13 +#define TIMER4D 14 +#define TIMER5A 15 +#define TIMER5B 16 +#define TIMER5C 17 + +#define PA 1 +#define PB 2 +#define PC 3 +#define PD 4 +#define PE 5 +#define PF 6 +#define PG 7 +#define PH 8 +#define PJ 10 +#define PK 11 +#define PL 12 + +#include "pins_arduino.h" + +__attribute__((always_inline)) +static inline uint8_t digitalPinToPort(uint8_t pin) { + return digital_pin_to_port[pin]; +} + +__attribute__((always_inline)) +static inline volatile uint8_t *portOutputRegister(uint8_t port_idx) { + return (volatile uint8_t *)port_to_output[port_idx]; +} + +__attribute__((always_inline)) +static inline volatile uint8_t *portDirectionRegister(uint8_t port_idx) { + return (volatile uint8_t *)port_to_mode[port_idx]; +} + +__attribute__((always_inline)) +static inline volatile uint8_t *portInputRegister(uint8_t port_idx) { + return (volatile uint8_t *)port_to_input[port_idx]; +} + +__attribute__((always_inline)) +static inline uint8_t digitalPinToBitMask(uint8_t pin) { + return digital_pin_to_bit_mask[pin]; +} + +/* +* Check if a given pin can be accessed in a single instruction. +* +* 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. +*/ +__attribute__((always_inline)) +static inline int portIsAtomic(volatile uint8_t *port) { + /* SBI/CBI instructions only work on lower 32 IO ports */ + return port <= (volatile uint8_t*) & _SFR_IO8(0x1F); +} + +__attribute__((always_inline)) +static inline void _pinModeClause(uint8_t pin, uint8_t mode) { + // At this point 'pin' is always known at compile time, 'mode' might be + const uint8_t port = digital_pin_to_port[pin]; + volatile uint8_t *dir = portDirectionRegister(port); + volatile uint8_t *out = portOutputRegister(port); + const uint8_t bitmask = digital_pin_to_bit_mask[pin]; + + if (pin >= NUM_DIGITAL_PINS) return; + + // We can only do this w/o disabling interrupts is if 'mode' + // is known at compile time, the direction register can use sbi/cbi + // & we're setting output... + if(__builtin_constant_p(mode) && portIsAtomic(dir) && (mode == OUTPUT)) { + *dir |= bitmask; + } else { // Otherwise, need to disable interrupts at minimum... + ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { + if(mode == INPUT_PULLUP) { + *out |= bitmask; + } else if(mode == INPUT) { + *out &= ~bitmask; + } + if(mode == INPUT_PULLUP || mode == INPUT) { + *dir &= ~bitmask; + } else { + *dir |= bitmask; + } + } + } +} +#define _PINMODECLAUSE(P) case P: _pinModeClause(P, mode); break + +__attribute__((always_inline)) +static inline void _pinModeInline(uint8_t pin, uint8_t mode) { + switch(pin) { + _PINMODECLAUSE(0); + _PINMODECLAUSE(1); + _PINMODECLAUSE(2); + _PINMODECLAUSE(3); + _PINMODECLAUSE(4); + _PINMODECLAUSE(5); + _PINMODECLAUSE(6); + _PINMODECLAUSE(7); + _PINMODECLAUSE(8); + _PINMODECLAUSE(9); + _PINMODECLAUSE(10); + _PINMODECLAUSE(11); + _PINMODECLAUSE(12); + _PINMODECLAUSE(13); + _PINMODECLAUSE(14); + _PINMODECLAUSE(15); + _PINMODECLAUSE(16); + _PINMODECLAUSE(17); + _PINMODECLAUSE(18); + _PINMODECLAUSE(19); + _PINMODECLAUSE(20); + _PINMODECLAUSE(21); + _PINMODECLAUSE(22); + _PINMODECLAUSE(23); + _PINMODECLAUSE(24); + _PINMODECLAUSE(25); + _PINMODECLAUSE(26); + _PINMODECLAUSE(27); + _PINMODECLAUSE(28); + _PINMODECLAUSE(29); + _PINMODECLAUSE(30); + _PINMODECLAUSE(31); + _PINMODECLAUSE(32); + _PINMODECLAUSE(33); + _PINMODECLAUSE(34); + _PINMODECLAUSE(35); + _PINMODECLAUSE(36); + _PINMODECLAUSE(37); + _PINMODECLAUSE(38); + _PINMODECLAUSE(39); + _PINMODECLAUSE(40); + _PINMODECLAUSE(41); + _PINMODECLAUSE(42); + _PINMODECLAUSE(43); + _PINMODECLAUSE(44); + _PINMODECLAUSE(45); + _PINMODECLAUSE(46); + _PINMODECLAUSE(47); + _PINMODECLAUSE(48); + _PINMODECLAUSE(49); + _PINMODECLAUSE(50); + _PINMODECLAUSE(51); + _PINMODECLAUSE(52); + _PINMODECLAUSE(53); + _PINMODECLAUSE(54); + _PINMODECLAUSE(55); + _PINMODECLAUSE(56); + _PINMODECLAUSE(57); + _PINMODECLAUSE(58); + _PINMODECLAUSE(59); + _PINMODECLAUSE(60); + _PINMODECLAUSE(61); + _PINMODECLAUSE(62); + _PINMODECLAUSE(63); + _PINMODECLAUSE(64); + _PINMODECLAUSE(65); + _PINMODECLAUSE(66); + _PINMODECLAUSE(67); + _PINMODECLAUSE(68); + _PINMODECLAUSE(69); + } +} + +void pinModeRuntime(uint8_t, uint8_t); + +__attribute__((always_inline)) +static inline void pinMode(uint8_t pin, uint8_t mode) { + // If we know the pin number, inline directly. Otherwise make a function call. + if(__builtin_constant_p(pin)) + _pinModeInline(pin,mode); + else + pinModeRuntime(pin,mode); +} + + +__attribute__((always_inline)) +static inline void turnOffPWM(uint8_t timer) +{ + // Timer should always be known at compile time here + switch (timer) + { +#if defined(TCCR1A) && defined(COM1A1) + case TIMER1A: TCCR1A &= ~_BV(COM1A1); break; +#endif +#if defined(TCCR1A) && defined(COM1B1) + case TIMER1B: TCCR1A &= ~_BV(COM1B1); break; +#endif + +#if defined(TCCR2) && defined(COM21) + case TIMER2: TCCR2 &= ~_BV(COM21); break; +#endif + +#if defined(TCCR0A) && defined(COM0A1) + case TIMER0A: TCCR0A &= ~_BV(COM0A1); break; +#endif + +#if defined(TIMER0B) && defined(COM0B1) + case TIMER0B: TCCR0A &= ~_BV(COM0B1); break; +#endif +#if defined(TCCR2A) && defined(COM2A1) + case TIMER2A: TCCR2A &= ~_BV(COM2A1); break; +#endif +#if defined(TCCR2A) && defined(COM2B1) + case TIMER2B: TCCR2A &= ~_BV(COM2B1); break; +#endif + +#if defined(TCCR3A) && defined(COM3A1) + case TIMER3A: TCCR3A &= ~_BV(COM3A1); break; +#endif +#if defined(TCCR3A) && defined(COM3B1) + case TIMER3B: TCCR3A &= ~_BV(COM3B1); break; +#endif +#if defined(TCCR3A) && defined(COM3C1) + case TIMER3C: TCCR3A &= ~_BV(COM3C1); break; +#endif + +#if defined(TCCR4A) && defined(COM4A1) + case TIMER4A: TCCR4A &= ~_BV(COM4A1); break; +#endif +#if defined(TCCR4A) && defined(COM4B1) + case TIMER4B: TCCR4A &= ~_BV(COM4B1); break; +#endif +#if defined(TCCR4A) && defined(COM4C1) + case TIMER4C: TCCR4A &= ~_BV(COM4C1); break; +#endif +#if defined(TCCR4C) && defined(COM4D1) + case TIMER4D: TCCR4C &= ~_BV(COM4D1); break; +#endif + +#if defined(TCCR5A) + case TIMER5A: TCCR5A &= ~_BV(COM5A1); break; + case TIMER5B: TCCR5A &= ~_BV(COM5B1); break; + case TIMER5C: TCCR5A &= ~_BV(COM5C1); break; +#endif + } +} + + +__attribute__((always_inline)) +static inline void _digitalWriteClause(uint8_t pin, uint8_t value) { + // At this point 'pin' is always known at compile time, 'value' might be + const uint8_t port = digital_pin_to_port[pin]; + volatile uint8_t *out = portOutputRegister(port); + const uint8_t bitmask = digital_pin_to_bit_mask[pin]; + const uint8_t timer = digital_pin_to_timer[pin]; + + if (pin >= NUM_DIGITAL_PINS) return; + + turnOffPWM(timer); + + if(portIsAtomic(out)) { + // Output is a single instruction write + if(value) + *out |= bitmask; + else + *out &= ~bitmask; + } + else { + // Output is non-atomic + ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { + if(value) + *out |= bitmask; + else + *out &= ~bitmask; + } + } +} +#define _DIGITALWRITECLAUSE(P) case P: _digitalWriteClause(P, value); break + +__attribute__((always_inline)) +static inline void _digitalWriteInline(const uint8_t pin, const uint8_t value) { + switch(pin) { + _DIGITALWRITECLAUSE(0); + _DIGITALWRITECLAUSE(1); + _DIGITALWRITECLAUSE(2); + _DIGITALWRITECLAUSE(3); + _DIGITALWRITECLAUSE(4); + _DIGITALWRITECLAUSE(5); + _DIGITALWRITECLAUSE(6); + _DIGITALWRITECLAUSE(7); + _DIGITALWRITECLAUSE(8); + _DIGITALWRITECLAUSE(9); + _DIGITALWRITECLAUSE(10); + _DIGITALWRITECLAUSE(11); + _DIGITALWRITECLAUSE(12); + _DIGITALWRITECLAUSE(13); + _DIGITALWRITECLAUSE(14); + _DIGITALWRITECLAUSE(15); + _DIGITALWRITECLAUSE(16); + _DIGITALWRITECLAUSE(17); + _DIGITALWRITECLAUSE(18); + _DIGITALWRITECLAUSE(19); + _DIGITALWRITECLAUSE(20); + _DIGITALWRITECLAUSE(21); + _DIGITALWRITECLAUSE(22); + _DIGITALWRITECLAUSE(23); + _DIGITALWRITECLAUSE(24); + _DIGITALWRITECLAUSE(25); + _DIGITALWRITECLAUSE(26); + _DIGITALWRITECLAUSE(27); + _DIGITALWRITECLAUSE(28); + _DIGITALWRITECLAUSE(29); + _DIGITALWRITECLAUSE(30); + _DIGITALWRITECLAUSE(31); + _DIGITALWRITECLAUSE(32); + _DIGITALWRITECLAUSE(33); + _DIGITALWRITECLAUSE(34); + _DIGITALWRITECLAUSE(35); + _DIGITALWRITECLAUSE(36); + _DIGITALWRITECLAUSE(37); + _DIGITALWRITECLAUSE(38); + _DIGITALWRITECLAUSE(39); + _DIGITALWRITECLAUSE(40); + _DIGITALWRITECLAUSE(41); + _DIGITALWRITECLAUSE(42); + _DIGITALWRITECLAUSE(43); + _DIGITALWRITECLAUSE(44); + _DIGITALWRITECLAUSE(45); + _DIGITALWRITECLAUSE(46); + _DIGITALWRITECLAUSE(47); + _DIGITALWRITECLAUSE(48); + _DIGITALWRITECLAUSE(49); + _DIGITALWRITECLAUSE(50); + _DIGITALWRITECLAUSE(51); + _DIGITALWRITECLAUSE(52); + _DIGITALWRITECLAUSE(53); + _DIGITALWRITECLAUSE(54); + _DIGITALWRITECLAUSE(55); + _DIGITALWRITECLAUSE(56); + _DIGITALWRITECLAUSE(57); + _DIGITALWRITECLAUSE(58); + _DIGITALWRITECLAUSE(59); + _DIGITALWRITECLAUSE(60); + _DIGITALWRITECLAUSE(61); + _DIGITALWRITECLAUSE(62); + _DIGITALWRITECLAUSE(63); + _DIGITALWRITECLAUSE(64); + _DIGITALWRITECLAUSE(65); + _DIGITALWRITECLAUSE(66); + _DIGITALWRITECLAUSE(67); + _DIGITALWRITECLAUSE(68); + _DIGITALWRITECLAUSE(69); + } +} + +void _digitalWriteRuntime(uint8_t, uint8_t); + +__attribute__((always_inline)) +static inline void digitalWrite(uint8_t pin, uint8_t value) { + // If we know the pin number, inline directly. Otherwise make a function call. + if(__builtin_constant_p(pin)) + _digitalWriteInline(pin,value); + else + _digitalWriteRuntime(pin,value); +} + + +__attribute__((always_inline)) +static inline uint8_t _digitalReadClause(uint8_t pin) { + // At this point 'pin' is always known at compile time + const uint8_t port = digital_pin_to_port[pin]; + const volatile uint8_t *in = portInputRegister(port); + const uint8_t bitmask = digital_pin_to_bit_mask[pin]; + const uint8_t timer = digital_pin_to_timer[pin]; + + if (port == NOT_A_PIN) return LOW; + if (pin >= NUM_DIGITAL_PINS) return LOW; + + turnOffPWM(timer); + + if (*in & bitmask) return HIGH; + return LOW; +} +#define _DIGITALREADCLAUSE(P) case P: return _digitalReadClause(P); + +__attribute__((always_inline)) +static inline int _digitalReadInline(uint8_t pin) { + switch(pin) { + _DIGITALREADCLAUSE(0); + _DIGITALREADCLAUSE(1); + _DIGITALREADCLAUSE(2); + _DIGITALREADCLAUSE(3); + _DIGITALREADCLAUSE(4); + _DIGITALREADCLAUSE(5); + _DIGITALREADCLAUSE(6); + _DIGITALREADCLAUSE(7); + _DIGITALREADCLAUSE(8); + _DIGITALREADCLAUSE(9); + _DIGITALREADCLAUSE(10); + _DIGITALREADCLAUSE(11); + _DIGITALREADCLAUSE(12); + _DIGITALREADCLAUSE(13); + _DIGITALREADCLAUSE(14); + _DIGITALREADCLAUSE(15); + _DIGITALREADCLAUSE(16); + _DIGITALREADCLAUSE(17); + _DIGITALREADCLAUSE(18); + _DIGITALREADCLAUSE(19); + _DIGITALREADCLAUSE(20); + _DIGITALREADCLAUSE(21); + _DIGITALREADCLAUSE(22); + _DIGITALREADCLAUSE(23); + _DIGITALREADCLAUSE(24); + _DIGITALREADCLAUSE(25); + _DIGITALREADCLAUSE(26); + _DIGITALREADCLAUSE(27); + _DIGITALREADCLAUSE(28); + _DIGITALREADCLAUSE(29); + _DIGITALREADCLAUSE(30); + _DIGITALREADCLAUSE(31); + _DIGITALREADCLAUSE(32); + _DIGITALREADCLAUSE(33); + _DIGITALREADCLAUSE(34); + _DIGITALREADCLAUSE(35); + _DIGITALREADCLAUSE(36); + _DIGITALREADCLAUSE(37); + _DIGITALREADCLAUSE(38); + _DIGITALREADCLAUSE(39); + _DIGITALREADCLAUSE(40); + _DIGITALREADCLAUSE(41); + _DIGITALREADCLAUSE(42); + _DIGITALREADCLAUSE(43); + _DIGITALREADCLAUSE(44); + _DIGITALREADCLAUSE(45); + _DIGITALREADCLAUSE(46); + _DIGITALREADCLAUSE(47); + _DIGITALREADCLAUSE(48); + _DIGITALREADCLAUSE(49); + _DIGITALREADCLAUSE(50); + _DIGITALREADCLAUSE(51); + _DIGITALREADCLAUSE(52); + _DIGITALREADCLAUSE(53); + _DIGITALREADCLAUSE(54); + _DIGITALREADCLAUSE(55); + _DIGITALREADCLAUSE(56); + _DIGITALREADCLAUSE(57); + _DIGITALREADCLAUSE(58); + _DIGITALREADCLAUSE(59); + _DIGITALREADCLAUSE(60); + _DIGITALREADCLAUSE(61); + _DIGITALREADCLAUSE(62); + _DIGITALREADCLAUSE(63); + _DIGITALREADCLAUSE(64); + _DIGITALREADCLAUSE(65); + _DIGITALREADCLAUSE(66); + _DIGITALREADCLAUSE(67); + _DIGITALREADCLAUSE(68); + _DIGITALREADCLAUSE(69); + } +} + +int _digitalReadRuntime(uint8_t); + +__attribute__((always_inline)) +static inline int digitalRead(uint8_t pin) { + // If we know the pin number, inline directly. Otherwise make a function call. + if(__builtin_constant_p(pin)) + return _digitalReadInline(pin); + else + return _digitalReadRuntime(pin); +} + +#ifdef __cplusplus +} +#endif +#endif + + diff --git a/hardware/arduino/cores/arduino/wiring_digital.c b/hardware/arduino/cores/arduino/wiring_digital.c index be323b1dfef..16a678c1165 100644 --- a/hardware/arduino/cores/arduino/wiring_digital.c +++ b/hardware/arduino/cores/arduino/wiring_digital.c @@ -26,153 +26,24 @@ #define ARDUINO_MAIN #include "wiring_private.h" -#include "pins_arduino.h" +#include "pin_functions.h" -void pinMode(uint8_t pin, uint8_t mode) -{ - uint8_t bit = digitalPinToBitMask(pin); - uint8_t port = digitalPinToPort(pin); - volatile uint8_t *reg, *out; - - if (port == NOT_A_PIN) return; - - // JWS: can I let the optimizer do this? - reg = portModeRegister(port); - out = portOutputRegister(port); - - if (mode == INPUT) { - uint8_t oldSREG = SREG; - cli(); - *reg &= ~bit; - *out &= ~bit; - SREG = oldSREG; - } else if (mode == INPUT_PULLUP) { - uint8_t oldSREG = SREG; - cli(); - *reg &= ~bit; - *out |= bit; - SREG = oldSREG; - } else { - uint8_t oldSREG = SREG; - cli(); - *reg |= bit; - SREG = oldSREG; - } -} - -// Forcing this inline keeps the callers from having to push their own stuff -// on the stack. It is a good performance win and only takes 1 more byte per -// user than calling. (It will take more bytes on the 168.) -// -// But shouldn't this be moved into pinMode? Seems silly to check and do on -// each digitalread or write. -// -// Mark Sproul: -// - Removed inline. Save 170 bytes on atmega1280 -// - changed to a switch statment; added 32 bytes but much easier to read and maintain. -// - Added more #ifdefs, now compiles for atmega645 +// This are versions from pin_functions.h, but where the pin isn't known +// at compile-time. // -//static inline void turnOffPWM(uint8_t timer) __attribute__ ((always_inline)); -//static inline void turnOffPWM(uint8_t timer) -static void turnOffPWM(uint8_t timer) -{ - switch (timer) - { - #if defined(TCCR1A) && defined(COM1A1) - case TIMER1A: cbi(TCCR1A, COM1A1); break; - #endif - #if defined(TCCR1A) && defined(COM1B1) - case TIMER1B: cbi(TCCR1A, COM1B1); break; - #endif - - #if defined(TCCR2) && defined(COM21) - case TIMER2: cbi(TCCR2, COM21); break; - #endif - - #if defined(TCCR0A) && defined(COM0A1) - case TIMER0A: cbi(TCCR0A, COM0A1); break; - #endif - - #if defined(TIMER0B) && defined(COM0B1) - case TIMER0B: cbi(TCCR0A, COM0B1); break; - #endif - #if defined(TCCR2A) && defined(COM2A1) - case TIMER2A: cbi(TCCR2A, COM2A1); break; - #endif - #if defined(TCCR2A) && defined(COM2B1) - case TIMER2B: cbi(TCCR2A, COM2B1); break; - #endif - - #if defined(TCCR3A) && defined(COM3A1) - case TIMER3A: cbi(TCCR3A, COM3A1); break; - #endif - #if defined(TCCR3A) && defined(COM3B1) - case TIMER3B: cbi(TCCR3A, COM3B1); break; - #endif - #if defined(TCCR3A) && defined(COM3C1) - case TIMER3C: cbi(TCCR3A, COM3C1); break; - #endif +// The inlined versions are designed to compile down to jump tables. - #if defined(TCCR4A) && defined(COM4A1) - case TIMER4A: cbi(TCCR4A, COM4A1); break; - #endif - #if defined(TCCR4A) && defined(COM4B1) - case TIMER4B: cbi(TCCR4A, COM4B1); break; - #endif - #if defined(TCCR4A) && defined(COM4C1) - case TIMER4C: cbi(TCCR4A, COM4C1); break; - #endif - #if defined(TCCR4C) && defined(COM4D1) - case TIMER4D: cbi(TCCR4C, COM4D1); break; - #endif - - #if defined(TCCR5A) - case TIMER5A: cbi(TCCR5A, COM5A1); break; - case TIMER5B: cbi(TCCR5A, COM5B1); break; - case TIMER5C: cbi(TCCR5A, COM5C1); break; - #endif - } +void pinModeRuntime(uint8_t pin, uint8_t mode) +{ + _pinModeInline(pin, mode); } -void digitalWrite(uint8_t pin, uint8_t val) +void _digitalWriteRuntime(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; + _digitalWriteInline(pin, val); } -int digitalRead(uint8_t pin) +int _digitalReadRuntime(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; + return _digitalReadInline(pin); } diff --git a/hardware/arduino/cores/arduino/wiring_pulse.c b/hardware/arduino/cores/arduino/wiring_pulse.c index 0d968865d2f..10cf6b67e7c 100755 --- a/hardware/arduino/cores/arduino/wiring_pulse.c +++ b/hardware/arduino/cores/arduino/wiring_pulse.c @@ -31,6 +31,7 @@ * before the start of the pulse. */ unsigned long pulseIn(uint8_t pin, uint8_t state, unsigned long timeout) { + /* // cache the port and bit of the pin in order to speed up the // pulse width measuring loop and achieve finer resolution. calling // digitalRead() instead yields much coarser resolution. @@ -66,4 +67,6 @@ unsigned long pulseIn(uint8_t pin, uint8_t state, unsigned long timeout) // and the start of the loop. There will be some error introduced by // the interrupt handlers. return clockCyclesToMicroseconds(width * 21 + 16); + */ + return 0; } diff --git a/hardware/arduino/variants/standard/pins_arduino.h b/hardware/arduino/variants/standard/pins_arduino.h index 30b42663065..cc1b5953acb 100644 --- a/hardware/arduino/variants/standard/pins_arduino.h +++ b/hardware/arduino/variants/standard/pins_arduino.h @@ -60,8 +60,6 @@ static const uint8_t A7 = 21; #define digitalPinToPCMSK(p) (((p) <= 7) ? (&PCMSK2) : (((p) <= 13) ? (&PCMSK0) : (((p) <= 21) ? (&PCMSK1) : ((uint8_t *)0)))) #define digitalPinToPCMSKbit(p) (((p) <= 7) ? (p) : (((p) <= 13) ? ((p) - 8) : ((p) - 14))) -#ifdef ARDUINO_MAIN - // On the Arduino board, digital pins are also used // for the analog output (software PWM). Analog input // pins are a separate set. @@ -105,31 +103,31 @@ static const uint8_t A7 = 21; // these arrays map port names (e.g. port B) to the // appropriate addresses for various functions (e.g. reading // and writing) -const uint16_t PROGMEM port_to_mode_PGM[] = { +const static volatile uint8_t *port_to_mode[] = { NOT_A_PORT, NOT_A_PORT, - (uint16_t) &DDRB, - (uint16_t) &DDRC, - (uint16_t) &DDRD, + &DDRB, + &DDRC, + &DDRD, }; -const uint16_t PROGMEM port_to_output_PGM[] = { +const static volatile uint8_t *port_to_output[] = { NOT_A_PORT, NOT_A_PORT, - (uint16_t) &PORTB, - (uint16_t) &PORTC, - (uint16_t) &PORTD, + &PORTB, + &PORTC, + &PORTD, }; -const uint16_t PROGMEM port_to_input_PGM[] = { +const static volatile uint8_t *port_to_input[] = { NOT_A_PORT, NOT_A_PORT, - (uint16_t) &PINB, - (uint16_t) &PINC, - (uint16_t) &PIND, + &PINB, + &PINC, + &PIND, }; -const uint8_t PROGMEM digital_pin_to_port_PGM[] = { +const static uint8_t digital_pin_to_port[] = { PD, /* 0 */ PD, PD, @@ -152,7 +150,7 @@ const uint8_t PROGMEM digital_pin_to_port_PGM[] = { PC, }; -const uint8_t PROGMEM digital_pin_to_bit_mask_PGM[] = { +const static uint8_t digital_pin_to_bit_mask[] = { _BV(0), /* 0, port D */ _BV(1), _BV(2), @@ -175,7 +173,7 @@ const uint8_t PROGMEM digital_pin_to_bit_mask_PGM[] = { _BV(5), }; -const uint8_t PROGMEM digital_pin_to_timer_PGM[] = { +const static uint8_t digital_pin_to_timer[] = { NOT_ON_TIMER, /* 0 - port D */ NOT_ON_TIMER, NOT_ON_TIMER, @@ -214,5 +212,3 @@ const uint8_t PROGMEM digital_pin_to_timer_PGM[] = { }; #endif - -#endif From 7b3309ad2236bd99102f0ccf7d34f90ee7e205f9 Mon Sep 17 00:00:00 2001 From: Angus Gratton Date: Fri, 15 Feb 2013 14:37:45 +1100 Subject: [PATCH 02/10] Rework out the jump tables, now runtime lookups use PROGMEM like before --- .../arduino/cores/arduino/pin_functions.h | 336 ++++-------------- .../arduino/cores/arduino/wiring_digital.c | 19 +- .../arduino/variants/standard/pins_arduino.h | 200 +++++------ 3 files changed, 184 insertions(+), 371 deletions(-) diff --git a/hardware/arduino/cores/arduino/pin_functions.h b/hardware/arduino/cores/arduino/pin_functions.h index 9256aa1a611..d5393b9e11e 100644 --- a/hardware/arduino/cores/arduino/pin_functions.h +++ b/hardware/arduino/cores/arduino/pin_functions.h @@ -47,60 +47,99 @@ extern "C" { #include "pins_arduino.h" +// The extern PROGMEM versions of each of these is for runtime lookups, +// the static const versions are for lookups when the pin is known at compile time +// (see the below inline functions, and wiring_digital.c) +// Source of the pin mappings is pins_arduino.h + +extern const uint16_t PROGMEM port_to_mode_P[]; +static const uint16_t port_to_mode[] = { PORT_TO_MODE }; + +extern const uint16_t PROGMEM port_to_output_P[]; +static const uint16_t port_to_output[] = { PORT_TO_OUTPUT }; + +extern const uint16_t PROGMEM port_to_input_P[]; +static const uint16_t port_to_input[] = { PORT_TO_INPUT }; + +extern const uint8_t PROGMEM digital_pin_to_port_P[]; +static const uint8_t digital_pin_to_port[] = { DIGITAL_PIN_TO_PORT }; + +extern const uint8_t PROGMEM digital_pin_to_bit_mask_P[]; +static const uint8_t digital_pin_to_bit_mask[] = { DIGITAL_PIN_TO_BIT_MASK }; + +extern const uint8_t PROGMEM digital_pin_to_timer_P[]; +static const uint8_t digital_pin_to_timer[] = { DIGITAL_PIN_TO_TIMER }; + __attribute__((always_inline)) static inline uint8_t digitalPinToPort(uint8_t pin) { - return digital_pin_to_port[pin]; + return __builtin_constant_p(pin) ? digital_pin_to_port[pin] + : pgm_read_byte( digital_pin_to_port_P + pin ); } __attribute__((always_inline)) static inline volatile uint8_t *portOutputRegister(uint8_t port_idx) { - return (volatile uint8_t *)port_to_output[port_idx]; + return (volatile uint8_t *)( __builtin_constant_p(port_idx) ? + port_to_output[port_idx] + : pgm_read_word( port_to_output_P + port_idx) ); } __attribute__((always_inline)) static inline volatile uint8_t *portDirectionRegister(uint8_t port_idx) { - return (volatile uint8_t *)port_to_mode[port_idx]; + return (volatile uint8_t *)( __builtin_constant_p(port_idx) ? + port_to_mode[port_idx] + : pgm_read_word( port_to_mode_P + port_idx ) ); } __attribute__((always_inline)) static inline volatile uint8_t *portInputRegister(uint8_t port_idx) { - return (volatile uint8_t *)port_to_input[port_idx]; + return (volatile uint8_t *)( __builtin_constant_p(port_idx) ? + port_to_input[port_idx] + : pgm_read_word( port_to_input_P + port_idx ) ); } __attribute__((always_inline)) static inline uint8_t digitalPinToBitMask(uint8_t pin) { - return digital_pin_to_bit_mask[pin]; + return __builtin_constant_p(pin) ? digital_pin_to_bit_mask[pin] + : pgm_read_byte( digital_pin_to_bit_mask_P + pin ); } +__attribute__((always_inline)) +static inline uint8_t digitalPinToTimer(uint8_t pin) { + return __builtin_constant_p(pin) ? digital_pin_to_timer[pin] + : pgm_read_byte( digital_pin_to_timer_P + pin ); +} + + /* * Check if a given pin can be accessed in a single instruction. * * 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. +* +* This routine only returns true if the port is known at compile time, because +* we'll be using memory mapped I/O regardless in the latter case. */ __attribute__((always_inline)) static inline int portIsAtomic(volatile uint8_t *port) { /* SBI/CBI instructions only work on lower 32 IO ports */ - return port <= (volatile uint8_t*) & _SFR_IO8(0x1F); + return __builtin_constant_p(port) && port <= (volatile uint8_t*) & _SFR_IO8(0x1F); } __attribute__((always_inline)) -static inline void _pinModeClause(uint8_t pin, uint8_t mode) { - // At this point 'pin' is always known at compile time, 'mode' might be - const uint8_t port = digital_pin_to_port[pin]; +static inline void _pinModeInline(uint8_t pin, uint8_t mode) { + const uint8_t port = digitalPinToPort(pin); volatile uint8_t *dir = portDirectionRegister(port); volatile uint8_t *out = portOutputRegister(port); - const uint8_t bitmask = digital_pin_to_bit_mask[pin]; + const uint8_t bitmask = digitalPinToBitMask(pin); if (pin >= NUM_DIGITAL_PINS) return; - // We can only do this w/o disabling interrupts is if 'mode' - // is known at compile time, the direction register can use sbi/cbi - // & we're setting output... - if(__builtin_constant_p(mode) && portIsAtomic(dir) && (mode == OUTPUT)) { + // We can only do this w/o disabling interrupts if setting output, + // and the direction register can use sbi/cbi + if(portIsAtomic(dir) && (mode == OUTPUT)) { *dir |= bitmask; - } else { // Otherwise, need to disable interrupts at minimum... + } else { // Otherwise, we need to disable interrupts... ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { if(mode == INPUT_PULLUP) { *out |= bitmask; @@ -114,86 +153,10 @@ static inline void _pinModeClause(uint8_t pin, uint8_t mode) { } } } -} -#define _PINMODECLAUSE(P) case P: _pinModeClause(P, mode); break -__attribute__((always_inline)) -static inline void _pinModeInline(uint8_t pin, uint8_t mode) { - switch(pin) { - _PINMODECLAUSE(0); - _PINMODECLAUSE(1); - _PINMODECLAUSE(2); - _PINMODECLAUSE(3); - _PINMODECLAUSE(4); - _PINMODECLAUSE(5); - _PINMODECLAUSE(6); - _PINMODECLAUSE(7); - _PINMODECLAUSE(8); - _PINMODECLAUSE(9); - _PINMODECLAUSE(10); - _PINMODECLAUSE(11); - _PINMODECLAUSE(12); - _PINMODECLAUSE(13); - _PINMODECLAUSE(14); - _PINMODECLAUSE(15); - _PINMODECLAUSE(16); - _PINMODECLAUSE(17); - _PINMODECLAUSE(18); - _PINMODECLAUSE(19); - _PINMODECLAUSE(20); - _PINMODECLAUSE(21); - _PINMODECLAUSE(22); - _PINMODECLAUSE(23); - _PINMODECLAUSE(24); - _PINMODECLAUSE(25); - _PINMODECLAUSE(26); - _PINMODECLAUSE(27); - _PINMODECLAUSE(28); - _PINMODECLAUSE(29); - _PINMODECLAUSE(30); - _PINMODECLAUSE(31); - _PINMODECLAUSE(32); - _PINMODECLAUSE(33); - _PINMODECLAUSE(34); - _PINMODECLAUSE(35); - _PINMODECLAUSE(36); - _PINMODECLAUSE(37); - _PINMODECLAUSE(38); - _PINMODECLAUSE(39); - _PINMODECLAUSE(40); - _PINMODECLAUSE(41); - _PINMODECLAUSE(42); - _PINMODECLAUSE(43); - _PINMODECLAUSE(44); - _PINMODECLAUSE(45); - _PINMODECLAUSE(46); - _PINMODECLAUSE(47); - _PINMODECLAUSE(48); - _PINMODECLAUSE(49); - _PINMODECLAUSE(50); - _PINMODECLAUSE(51); - _PINMODECLAUSE(52); - _PINMODECLAUSE(53); - _PINMODECLAUSE(54); - _PINMODECLAUSE(55); - _PINMODECLAUSE(56); - _PINMODECLAUSE(57); - _PINMODECLAUSE(58); - _PINMODECLAUSE(59); - _PINMODECLAUSE(60); - _PINMODECLAUSE(61); - _PINMODECLAUSE(62); - _PINMODECLAUSE(63); - _PINMODECLAUSE(64); - _PINMODECLAUSE(65); - _PINMODECLAUSE(66); - _PINMODECLAUSE(67); - _PINMODECLAUSE(68); - _PINMODECLAUSE(69); - } } -void pinModeRuntime(uint8_t, uint8_t); +void _pinModeRuntime(uint8_t, uint8_t); __attribute__((always_inline)) static inline void pinMode(uint8_t pin, uint8_t mode) { @@ -201,14 +164,14 @@ static inline void pinMode(uint8_t pin, uint8_t mode) { if(__builtin_constant_p(pin)) _pinModeInline(pin,mode); else - pinModeRuntime(pin,mode); + _pinModeRuntime(pin,mode); } __attribute__((always_inline)) -static inline void turnOffPWM(uint8_t timer) +static inline void _turnOffPWMInline(uint8_t pin) { - // Timer should always be known at compile time here + const uint8_t timer = digitalPinToTimer(pin); switch (timer) { #if defined(TCCR1A) && defined(COM1A1) @@ -267,18 +230,25 @@ static inline void turnOffPWM(uint8_t timer) } } +void _turnOffPWMRuntime(uint8_t pin); __attribute__((always_inline)) -static inline void _digitalWriteClause(uint8_t pin, uint8_t value) { - // At this point 'pin' is always known at compile time, 'value' might be - const uint8_t port = digital_pin_to_port[pin]; +static inline void turnOffPWM(const uint8_t pin) { + if(__builtin_constant_p(pin)) + _turnOffPWMInline(pin); + else + _turnOffPWMRuntime(pin); +} + +__attribute__((always_inline)) +static inline void _digitalWriteInline(const uint8_t pin, const uint8_t value) { + const uint8_t port = digitalPinToPort(pin); volatile uint8_t *out = portOutputRegister(port); - const uint8_t bitmask = digital_pin_to_bit_mask[pin]; - const uint8_t timer = digital_pin_to_timer[pin]; + const uint8_t bitmask = digitalPinToBitMask(pin); if (pin >= NUM_DIGITAL_PINS) return; - turnOffPWM(timer); + turnOffPWM(pin); if(portIsAtomic(out)) { // Output is a single instruction write @@ -297,83 +267,6 @@ static inline void _digitalWriteClause(uint8_t pin, uint8_t value) { } } } -#define _DIGITALWRITECLAUSE(P) case P: _digitalWriteClause(P, value); break - -__attribute__((always_inline)) -static inline void _digitalWriteInline(const uint8_t pin, const uint8_t value) { - switch(pin) { - _DIGITALWRITECLAUSE(0); - _DIGITALWRITECLAUSE(1); - _DIGITALWRITECLAUSE(2); - _DIGITALWRITECLAUSE(3); - _DIGITALWRITECLAUSE(4); - _DIGITALWRITECLAUSE(5); - _DIGITALWRITECLAUSE(6); - _DIGITALWRITECLAUSE(7); - _DIGITALWRITECLAUSE(8); - _DIGITALWRITECLAUSE(9); - _DIGITALWRITECLAUSE(10); - _DIGITALWRITECLAUSE(11); - _DIGITALWRITECLAUSE(12); - _DIGITALWRITECLAUSE(13); - _DIGITALWRITECLAUSE(14); - _DIGITALWRITECLAUSE(15); - _DIGITALWRITECLAUSE(16); - _DIGITALWRITECLAUSE(17); - _DIGITALWRITECLAUSE(18); - _DIGITALWRITECLAUSE(19); - _DIGITALWRITECLAUSE(20); - _DIGITALWRITECLAUSE(21); - _DIGITALWRITECLAUSE(22); - _DIGITALWRITECLAUSE(23); - _DIGITALWRITECLAUSE(24); - _DIGITALWRITECLAUSE(25); - _DIGITALWRITECLAUSE(26); - _DIGITALWRITECLAUSE(27); - _DIGITALWRITECLAUSE(28); - _DIGITALWRITECLAUSE(29); - _DIGITALWRITECLAUSE(30); - _DIGITALWRITECLAUSE(31); - _DIGITALWRITECLAUSE(32); - _DIGITALWRITECLAUSE(33); - _DIGITALWRITECLAUSE(34); - _DIGITALWRITECLAUSE(35); - _DIGITALWRITECLAUSE(36); - _DIGITALWRITECLAUSE(37); - _DIGITALWRITECLAUSE(38); - _DIGITALWRITECLAUSE(39); - _DIGITALWRITECLAUSE(40); - _DIGITALWRITECLAUSE(41); - _DIGITALWRITECLAUSE(42); - _DIGITALWRITECLAUSE(43); - _DIGITALWRITECLAUSE(44); - _DIGITALWRITECLAUSE(45); - _DIGITALWRITECLAUSE(46); - _DIGITALWRITECLAUSE(47); - _DIGITALWRITECLAUSE(48); - _DIGITALWRITECLAUSE(49); - _DIGITALWRITECLAUSE(50); - _DIGITALWRITECLAUSE(51); - _DIGITALWRITECLAUSE(52); - _DIGITALWRITECLAUSE(53); - _DIGITALWRITECLAUSE(54); - _DIGITALWRITECLAUSE(55); - _DIGITALWRITECLAUSE(56); - _DIGITALWRITECLAUSE(57); - _DIGITALWRITECLAUSE(58); - _DIGITALWRITECLAUSE(59); - _DIGITALWRITECLAUSE(60); - _DIGITALWRITECLAUSE(61); - _DIGITALWRITECLAUSE(62); - _DIGITALWRITECLAUSE(63); - _DIGITALWRITECLAUSE(64); - _DIGITALWRITECLAUSE(65); - _DIGITALWRITECLAUSE(66); - _DIGITALWRITECLAUSE(67); - _DIGITALWRITECLAUSE(68); - _DIGITALWRITECLAUSE(69); - } -} void _digitalWriteRuntime(uint8_t, uint8_t); @@ -388,98 +281,19 @@ static inline void digitalWrite(uint8_t pin, uint8_t value) { __attribute__((always_inline)) -static inline uint8_t _digitalReadClause(uint8_t pin) { - // At this point 'pin' is always known at compile time - const uint8_t port = digital_pin_to_port[pin]; +static inline int _digitalReadInline(uint8_t pin) { + const uint8_t port = digitalPinToPort(pin); const volatile uint8_t *in = portInputRegister(port); - const uint8_t bitmask = digital_pin_to_bit_mask[pin]; - const uint8_t timer = digital_pin_to_timer[pin]; + const uint8_t bitmask = digitalPinToBitMask(pin); if (port == NOT_A_PIN) return LOW; if (pin >= NUM_DIGITAL_PINS) return LOW; - turnOffPWM(timer); + turnOffPWM(pin); if (*in & bitmask) return HIGH; return LOW; } -#define _DIGITALREADCLAUSE(P) case P: return _digitalReadClause(P); - -__attribute__((always_inline)) -static inline int _digitalReadInline(uint8_t pin) { - switch(pin) { - _DIGITALREADCLAUSE(0); - _DIGITALREADCLAUSE(1); - _DIGITALREADCLAUSE(2); - _DIGITALREADCLAUSE(3); - _DIGITALREADCLAUSE(4); - _DIGITALREADCLAUSE(5); - _DIGITALREADCLAUSE(6); - _DIGITALREADCLAUSE(7); - _DIGITALREADCLAUSE(8); - _DIGITALREADCLAUSE(9); - _DIGITALREADCLAUSE(10); - _DIGITALREADCLAUSE(11); - _DIGITALREADCLAUSE(12); - _DIGITALREADCLAUSE(13); - _DIGITALREADCLAUSE(14); - _DIGITALREADCLAUSE(15); - _DIGITALREADCLAUSE(16); - _DIGITALREADCLAUSE(17); - _DIGITALREADCLAUSE(18); - _DIGITALREADCLAUSE(19); - _DIGITALREADCLAUSE(20); - _DIGITALREADCLAUSE(21); - _DIGITALREADCLAUSE(22); - _DIGITALREADCLAUSE(23); - _DIGITALREADCLAUSE(24); - _DIGITALREADCLAUSE(25); - _DIGITALREADCLAUSE(26); - _DIGITALREADCLAUSE(27); - _DIGITALREADCLAUSE(28); - _DIGITALREADCLAUSE(29); - _DIGITALREADCLAUSE(30); - _DIGITALREADCLAUSE(31); - _DIGITALREADCLAUSE(32); - _DIGITALREADCLAUSE(33); - _DIGITALREADCLAUSE(34); - _DIGITALREADCLAUSE(35); - _DIGITALREADCLAUSE(36); - _DIGITALREADCLAUSE(37); - _DIGITALREADCLAUSE(38); - _DIGITALREADCLAUSE(39); - _DIGITALREADCLAUSE(40); - _DIGITALREADCLAUSE(41); - _DIGITALREADCLAUSE(42); - _DIGITALREADCLAUSE(43); - _DIGITALREADCLAUSE(44); - _DIGITALREADCLAUSE(45); - _DIGITALREADCLAUSE(46); - _DIGITALREADCLAUSE(47); - _DIGITALREADCLAUSE(48); - _DIGITALREADCLAUSE(49); - _DIGITALREADCLAUSE(50); - _DIGITALREADCLAUSE(51); - _DIGITALREADCLAUSE(52); - _DIGITALREADCLAUSE(53); - _DIGITALREADCLAUSE(54); - _DIGITALREADCLAUSE(55); - _DIGITALREADCLAUSE(56); - _DIGITALREADCLAUSE(57); - _DIGITALREADCLAUSE(58); - _DIGITALREADCLAUSE(59); - _DIGITALREADCLAUSE(60); - _DIGITALREADCLAUSE(61); - _DIGITALREADCLAUSE(62); - _DIGITALREADCLAUSE(63); - _DIGITALREADCLAUSE(64); - _DIGITALREADCLAUSE(65); - _DIGITALREADCLAUSE(66); - _DIGITALREADCLAUSE(67); - _DIGITALREADCLAUSE(68); - _DIGITALREADCLAUSE(69); - } -} int _digitalReadRuntime(uint8_t); diff --git a/hardware/arduino/cores/arduino/wiring_digital.c b/hardware/arduino/cores/arduino/wiring_digital.c index 16a678c1165..cc34f81211a 100644 --- a/hardware/arduino/cores/arduino/wiring_digital.c +++ b/hardware/arduino/cores/arduino/wiring_digital.c @@ -28,12 +28,17 @@ #include "wiring_private.h" #include "pin_functions.h" -// This are versions from pin_functions.h, but where the pin isn't known +// This are versions that call back into, where the pin isn't known // at compile-time. -// -// The inlined versions are designed to compile down to jump tables. -void pinModeRuntime(uint8_t pin, uint8_t mode) +const uint16_t port_to_mode_P[] = { PORT_TO_MODE }; +const uint16_t PROGMEM port_to_output_P[] = { PORT_TO_OUTPUT }; +const uint16_t PROGMEM port_to_input_P[] = { PORT_TO_INPUT }; +const uint8_t PROGMEM digital_pin_to_port_P[] = { DIGITAL_PIN_TO_PORT }; +const uint8_t PROGMEM digital_pin_to_bit_mask_P[] = { DIGITAL_PIN_TO_BIT_MASK }; +const uint8_t PROGMEM digital_pin_to_timer_P[] = { DIGITAL_PIN_TO_TIMER }; + +void _pinModeRuntime(uint8_t pin, uint8_t mode) { _pinModeInline(pin, mode); } @@ -47,3 +52,9 @@ int _digitalReadRuntime(uint8_t pin) { return _digitalReadInline(pin); } + +void _turnOffPWMRuntime(uint8_t pin) +{ + _turnOffPWMInline(pin); +} + diff --git a/hardware/arduino/variants/standard/pins_arduino.h b/hardware/arduino/variants/standard/pins_arduino.h index cc1b5953acb..9016e2e8c42 100644 --- a/hardware/arduino/variants/standard/pins_arduino.h +++ b/hardware/arduino/variants/standard/pins_arduino.h @@ -100,115 +100,103 @@ static const uint8_t A7 = 21; // A8-A15 PK0-PK7 -// these arrays map port names (e.g. port B) to the +// these macros map port names (e.g. port B) to the // appropriate addresses for various functions (e.g. reading // and writing) -const static volatile uint8_t *port_to_mode[] = { - NOT_A_PORT, - NOT_A_PORT, - &DDRB, - &DDRC, - &DDRD, -}; - -const static volatile uint8_t *port_to_output[] = { - NOT_A_PORT, - NOT_A_PORT, - &PORTB, - &PORTC, - &PORTD, -}; - -const static volatile uint8_t *port_to_input[] = { - NOT_A_PORT, - NOT_A_PORT, - &PINB, - &PINC, - &PIND, -}; - -const static uint8_t digital_pin_to_port[] = { - PD, /* 0 */ - PD, - PD, - PD, - PD, - PD, - PD, - PD, - PB, /* 8 */ - PB, - PB, - PB, - PB, - PB, - PC, /* 14 */ - PC, - PC, - PC, - PC, - PC, -}; - -const static uint8_t digital_pin_to_bit_mask[] = { - _BV(0), /* 0, port D */ - _BV(1), - _BV(2), - _BV(3), - _BV(4), - _BV(5), - _BV(6), - _BV(7), - _BV(0), /* 8, port B */ - _BV(1), - _BV(2), - _BV(3), - _BV(4), - _BV(5), - _BV(0), /* 14, port C */ - _BV(1), - _BV(2), - _BV(3), - _BV(4), - _BV(5), -}; - -const static uint8_t digital_pin_to_timer[] = { - NOT_ON_TIMER, /* 0 - port D */ - NOT_ON_TIMER, - NOT_ON_TIMER, - // on the ATmega168, digital pin 3 has hardware pwm -#if defined(__AVR_ATmega8__) - NOT_ON_TIMER, -#else - TIMER2B, -#endif - NOT_ON_TIMER, - // on the ATmega168, digital pins 5 and 6 have hardware pwm -#if defined(__AVR_ATmega8__) - NOT_ON_TIMER, - NOT_ON_TIMER, -#else - TIMER0B, - TIMER0A, -#endif - NOT_ON_TIMER, - NOT_ON_TIMER, /* 8 - port B */ - TIMER1A, - TIMER1B, +#define PORT_TO_MODE \ + NOT_A_PORT, \ + NOT_A_PORT, \ + (uint16_t)&DDRB, \ + (uint16_t)&DDRC, \ + (uint16_t)&DDRD, + +#define PORT_TO_OUTPUT \ + NOT_A_PORT, \ + NOT_A_PORT, \ + (uint16_t)&PORTB, \ + (uint16_t)&PORTC, \ + (uint16_t)&PORTD, + + +#define PORT_TO_INPUT \ + NOT_A_PORT, \ + NOT_A_PORT, \ + (uint16_t)&PINB, \ + (uint16_t)&PINC, \ + (uint16_t)&PIND, + + +#define DIGITAL_PIN_TO_PORT \ + PD, /* 0 */ \ + PD, \ + PD, \ + PD, \ + PD, \ + PD, \ + PD, \ + PD, \ + PB, /* 8 */ \ + PB, \ + PB, \ + PB, \ + PB, \ + PB, \ + PC, /* 14 */ \ + PC, \ + PC, \ + PC, \ + PC, \ + PC, + + +#define DIGITAL_PIN_TO_BIT_MASK \ + _BV(0), /* 0, port D */ \ + _BV(1), \ + _BV(2), \ + _BV(3), \ + _BV(4), \ + _BV(5), \ + _BV(6), \ + _BV(7), \ + _BV(0), /* 8, port B */ \ + _BV(1), \ + _BV(2), \ + _BV(3), \ + _BV(4), \ + _BV(5), \ + _BV(0), /* 14, port C */ \ + _BV(1), \ + _BV(2), \ + _BV(3), \ + _BV(4), \ + _BV(5), + #if defined(__AVR_ATmega8__) - TIMER2, -#else - TIMER2A, +#define TIMER2B NOT_ON_TIMER +#define TIMER0A NOT_ON_TIMER +#define TIMER0B NOT_ON_TIMER +#define TIMER2A TIMER2 #endif - NOT_ON_TIMER, - NOT_ON_TIMER, - NOT_ON_TIMER, - NOT_ON_TIMER, /* 14 - port C */ - NOT_ON_TIMER, - NOT_ON_TIMER, - NOT_ON_TIMER, - NOT_ON_TIMER, -}; + +#define DIGITAL_PIN_TO_TIMER \ + NOT_ON_TIMER, /* 0 - port D */ \ + NOT_ON_TIMER, \ + NOT_ON_TIMER, \ + TIMER2B, \ + TIMER0B, \ + TIMER0A, \ + NOT_ON_TIMER, \ + NOT_ON_TIMER, /* 8 - port B */ \ + TIMER1A, \ + TIMER1B, \ + TIMER2A, \ + NOT_ON_TIMER, \ + NOT_ON_TIMER, \ + NOT_ON_TIMER, \ + NOT_ON_TIMER, /* 14 - port C */ \ + NOT_ON_TIMER, \ + NOT_ON_TIMER, \ + NOT_ON_TIMER, \ + NOT_ON_TIMER, #endif From 0fbc89c0be32cc3fe8a14f53a472fbab92e13d9b Mon Sep 17 00:00:00 2001 From: Angus Gratton Date: Fri, 15 Feb 2013 14:57:45 +1100 Subject: [PATCH 03/10] Re-enable wiring_pulse --- hardware/arduino/cores/arduino/wiring_pulse.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/hardware/arduino/cores/arduino/wiring_pulse.c b/hardware/arduino/cores/arduino/wiring_pulse.c index 10cf6b67e7c..0d968865d2f 100755 --- a/hardware/arduino/cores/arduino/wiring_pulse.c +++ b/hardware/arduino/cores/arduino/wiring_pulse.c @@ -31,7 +31,6 @@ * before the start of the pulse. */ unsigned long pulseIn(uint8_t pin, uint8_t state, unsigned long timeout) { - /* // cache the port and bit of the pin in order to speed up the // pulse width measuring loop and achieve finer resolution. calling // digitalRead() instead yields much coarser resolution. @@ -67,6 +66,4 @@ unsigned long pulseIn(uint8_t pin, uint8_t state, unsigned long timeout) // and the start of the loop. There will be some error introduced by // the interrupt handlers. return clockCyclesToMicroseconds(width * 21 + 16); - */ - return 0; } From 932a6a87829b66baa5b42a1fce3cc852573003cd Mon Sep 17 00:00:00 2001 From: Angus Gratton Date: Tue, 19 Feb 2013 21:53:50 +1100 Subject: [PATCH 04/10] Fix portIsAtomic() function refusing to inline correctly --- hardware/arduino/cores/arduino/pin_functions.h | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/hardware/arduino/cores/arduino/pin_functions.h b/hardware/arduino/cores/arduino/pin_functions.h index d5393b9e11e..18fd76c9dda 100644 --- a/hardware/arduino/cores/arduino/pin_functions.h +++ b/hardware/arduino/cores/arduino/pin_functions.h @@ -119,11 +119,17 @@ static inline uint8_t digitalPinToTimer(uint8_t pin) { * * This routine only returns true if the port is known at compile time, because * we'll be using memory mapped I/O regardless in the latter case. +* +* The correct argument for this function should be 'volatile uint8_t *const port', but +* gcc seems unable to evaluate __builtin_constant_p correctly on that type, so we cast to +* a plain int in ther caller... which oddly seems to work. Same with using __SFR_OFFSET +* instead of the _SFR_IO_REG_P macro or _SFR_IO8. +* */ __attribute__((always_inline)) -static inline int portIsAtomic(volatile uint8_t *port) { +static inline int portIsAtomic(uint16_t port) { /* SBI/CBI instructions only work on lower 32 IO ports */ - return __builtin_constant_p(port) && port <= (volatile uint8_t*) & _SFR_IO8(0x1F); + return __builtin_constant_p(port) && port <= 0x1F + __SFR_OFFSET; } __attribute__((always_inline)) @@ -137,7 +143,7 @@ static inline void _pinModeInline(uint8_t pin, uint8_t mode) { // We can only do this w/o disabling interrupts if setting output, // and the direction register can use sbi/cbi - if(portIsAtomic(dir) && (mode == OUTPUT)) { + if(portIsAtomic((uint16_t)dir) && (mode == OUTPUT)) { *dir |= bitmask; } else { // Otherwise, we need to disable interrupts... ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { @@ -250,7 +256,7 @@ static inline void _digitalWriteInline(const uint8_t pin, const uint8_t value) { turnOffPWM(pin); - if(portIsAtomic(out)) { + if(portIsAtomic((uint16_t)out)) { // Output is a single instruction write if(value) *out |= bitmask; From ff140e879eed3c2d83f4da132acd525b8279656f Mon Sep 17 00:00:00 2001 From: Angus Gratton Date: Tue, 19 Feb 2013 23:11:02 +1100 Subject: [PATCH 05/10] Update pins_arduino for Mega variant --- hardware/arduino/variants/mega/pins_arduino.h | 533 +++++++++--------- 1 file changed, 263 insertions(+), 270 deletions(-) diff --git a/hardware/arduino/variants/mega/pins_arduino.h b/hardware/arduino/variants/mega/pins_arduino.h index 5a9b4cb09b5..26e4c572ec2 100644 --- a/hardware/arduino/variants/mega/pins_arduino.h +++ b/hardware/arduino/variants/mega/pins_arduino.h @@ -83,281 +83,274 @@ static const uint8_t A15 = 69; ( (((p) >= 62) && ((p) <= 69)) ? ((p) - 62) : \ 0 ) ) ) ) ) ) -#ifdef ARDUINO_MAIN +#define PORT_TO_MODE \ + NOT_A_PORT, \ + (uint16_t) &DDRA, \ + (uint16_t) &DDRB, \ + (uint16_t) &DDRC, \ + (uint16_t) &DDRD, \ + (uint16_t) &DDRE, \ + (uint16_t) &DDRF, \ + (uint16_t) &DDRG, \ + (uint16_t) &DDRH, \ + NOT_A_PORT, \ + (uint16_t) &DDRJ, \ + (uint16_t) &DDRK, \ + (uint16_t) &DDRL, -const uint16_t PROGMEM port_to_mode_PGM[] = { - NOT_A_PORT, - (uint16_t) &DDRA, - (uint16_t) &DDRB, - (uint16_t) &DDRC, - (uint16_t) &DDRD, - (uint16_t) &DDRE, - (uint16_t) &DDRF, - (uint16_t) &DDRG, - (uint16_t) &DDRH, - NOT_A_PORT, - (uint16_t) &DDRJ, - (uint16_t) &DDRK, - (uint16_t) &DDRL, -}; +#define PORT_TO_OUTPUT \ + NOT_A_PORT, \ + (uint16_t) &PORTA, \ + (uint16_t) &PORTB, \ + (uint16_t) &PORTC, \ + (uint16_t) &PORTD, \ + (uint16_t) &PORTE, \ + (uint16_t) &PORTF, \ + (uint16_t) &PORTG, \ + (uint16_t) &PORTH, \ + NOT_A_PORT, \ + (uint16_t) &PORTJ, \ + (uint16_t) &PORTK, \ + (uint16_t) &PORTL, -const uint16_t PROGMEM port_to_output_PGM[] = { - NOT_A_PORT, - (uint16_t) &PORTA, - (uint16_t) &PORTB, - (uint16_t) &PORTC, - (uint16_t) &PORTD, - (uint16_t) &PORTE, - (uint16_t) &PORTF, - (uint16_t) &PORTG, - (uint16_t) &PORTH, - NOT_A_PORT, - (uint16_t) &PORTJ, - (uint16_t) &PORTK, - (uint16_t) &PORTL, -}; +#define PORT_TO_INPUT \ + NOT_A_PIN, \ + (uint16_t) &PINA, \ + (uint16_t) &PINB, \ + (uint16_t) &PINC, \ + (uint16_t) &PIND, \ + (uint16_t) &PINE, \ + (uint16_t) &PINF, \ + (uint16_t) &PING, \ + (uint16_t) &PINH, \ + NOT_A_PIN, \ + (uint16_t) &PINJ, \ + (uint16_t) &PINK, \ + (uint16_t) &PINL, -const uint16_t PROGMEM port_to_input_PGM[] = { - NOT_A_PIN, - (uint16_t) &PINA, - (uint16_t) &PINB, - (uint16_t) &PINC, - (uint16_t) &PIND, - (uint16_t) &PINE, - (uint16_t) &PINF, - (uint16_t) &PING, - (uint16_t) &PINH, - NOT_A_PIN, - (uint16_t) &PINJ, - (uint16_t) &PINK, - (uint16_t) &PINL, -}; -const uint8_t PROGMEM digital_pin_to_port_PGM[] = { - // PORTLIST - // ------------------------------------------- - PE , // PE 0 ** 0 ** USART0_RX - PE , // PE 1 ** 1 ** USART0_TX - PE , // PE 4 ** 2 ** PWM2 - PE , // PE 5 ** 3 ** PWM3 - PG , // PG 5 ** 4 ** PWM4 - PE , // PE 3 ** 5 ** PWM5 - PH , // PH 3 ** 6 ** PWM6 - PH , // PH 4 ** 7 ** PWM7 - PH , // PH 5 ** 8 ** PWM8 - PH , // PH 6 ** 9 ** PWM9 - PB , // PB 4 ** 10 ** PWM10 - PB , // PB 5 ** 11 ** PWM11 - PB , // PB 6 ** 12 ** PWM12 - PB , // PB 7 ** 13 ** PWM13 - PJ , // PJ 1 ** 14 ** USART3_TX - PJ , // PJ 0 ** 15 ** USART3_RX - PH , // PH 1 ** 16 ** USART2_TX - PH , // PH 0 ** 17 ** USART2_RX - PD , // PD 3 ** 18 ** USART1_TX - PD , // PD 2 ** 19 ** USART1_RX - PD , // PD 1 ** 20 ** I2C_SDA - PD , // PD 0 ** 21 ** I2C_SCL - PA , // PA 0 ** 22 ** D22 - PA , // PA 1 ** 23 ** D23 - PA , // PA 2 ** 24 ** D24 - PA , // PA 3 ** 25 ** D25 - PA , // PA 4 ** 26 ** D26 - PA , // PA 5 ** 27 ** D27 - PA , // PA 6 ** 28 ** D28 - PA , // PA 7 ** 29 ** D29 - PC , // PC 7 ** 30 ** D30 - PC , // PC 6 ** 31 ** D31 - PC , // PC 5 ** 32 ** D32 - PC , // PC 4 ** 33 ** D33 - PC , // PC 3 ** 34 ** D34 - PC , // PC 2 ** 35 ** D35 - PC , // PC 1 ** 36 ** D36 - PC , // PC 0 ** 37 ** D37 - PD , // PD 7 ** 38 ** D38 - PG , // PG 2 ** 39 ** D39 - PG , // PG 1 ** 40 ** D40 - PG , // PG 0 ** 41 ** D41 - PL , // PL 7 ** 42 ** D42 - PL , // PL 6 ** 43 ** D43 - PL , // PL 5 ** 44 ** D44 - PL , // PL 4 ** 45 ** D45 - PL , // PL 3 ** 46 ** D46 - PL , // PL 2 ** 47 ** D47 - PL , // PL 1 ** 48 ** D48 - PL , // PL 0 ** 49 ** D49 - PB , // PB 3 ** 50 ** SPI_MISO - PB , // PB 2 ** 51 ** SPI_MOSI - PB , // PB 1 ** 52 ** SPI_SCK - PB , // PB 0 ** 53 ** SPI_SS - PF , // PF 0 ** 54 ** A0 - PF , // PF 1 ** 55 ** A1 - PF , // PF 2 ** 56 ** A2 - PF , // PF 3 ** 57 ** A3 - PF , // PF 4 ** 58 ** A4 - PF , // PF 5 ** 59 ** A5 - PF , // PF 6 ** 60 ** A6 - PF , // PF 7 ** 61 ** A7 - PK , // PK 0 ** 62 ** A8 - PK , // PK 1 ** 63 ** A9 - PK , // PK 2 ** 64 ** A10 - PK , // PK 3 ** 65 ** A11 - PK , // PK 4 ** 66 ** A12 - PK , // PK 5 ** 67 ** A13 - PK , // PK 6 ** 68 ** A14 - PK , // PK 7 ** 69 ** A15 -}; +#define DIGITAL_PIN_TO_PORT \ + /* PORTLIST */ \ + /* ------------------------------------------- */ \ + PE , /* PE 0 ** 0 ** USART0_RX */ \ + PE , /* PE 1 ** 1 ** USART0_TX */ \ + PE , /* PE 4 ** 2 ** PWM2 */ \ + PE , /* PE 5 ** 3 ** PWM3 */ \ + PG , /* PG 5 ** 4 ** PWM4 */ \ + PE , /* PE 3 ** 5 ** PWM5 */ \ + PH , /* PH 3 ** 6 ** PWM6 */ \ + PH , /* PH 4 ** 7 ** PWM7 */ \ + PH , /* PH 5 ** 8 ** PWM8 */ \ + PH , /* PH 6 ** 9 ** PWM9 */ \ + PB , /* PB 4 ** 10 ** PWM10 */ \ + PB , /* PB 5 ** 11 ** PWM11 */ \ + PB , /* PB 6 ** 12 ** PWM12 */ \ + PB , /* PB 7 ** 13 ** PWM13 */ \ + PJ , /* PJ 1 ** 14 ** USART3_TX */ \ + PJ , /* PJ 0 ** 15 ** USART3_RX */ \ + PH , /* PH 1 ** 16 ** USART2_TX */ \ + PH , /* PH 0 ** 17 ** USART2_RX */ \ + PD , /* PD 3 ** 18 ** USART1_TX */ \ + PD , /* PD 2 ** 19 ** USART1_RX */ \ + PD , /* PD 1 ** 20 ** I2C_SDA */ \ + PD , /* PD 0 ** 21 ** I2C_SCL */ \ + PA , /* PA 0 ** 22 ** D22 */ \ + PA , /* PA 1 ** 23 ** D23 */ \ + PA , /* PA 2 ** 24 ** D24 */ \ + PA , /* PA 3 ** 25 ** D25 */ \ + PA , /* PA 4 ** 26 ** D26 */ \ + PA , /* PA 5 ** 27 ** D27 */ \ + PA , /* PA 6 ** 28 ** D28 */ \ + PA , /* PA 7 ** 29 ** D29 */ \ + PC , /* PC 7 ** 30 ** D30 */ \ + PC , /* PC 6 ** 31 ** D31 */ \ + PC , /* PC 5 ** 32 ** D32 */ \ + PC , /* PC 4 ** 33 ** D33 */ \ + PC , /* PC 3 ** 34 ** D34 */ \ + PC , /* PC 2 ** 35 ** D35 */ \ + PC , /* PC 1 ** 36 ** D36 */ \ + PC , /* PC 0 ** 37 ** D37 */ \ + PD , /* PD 7 ** 38 ** D38 */ \ + PG , /* PG 2 ** 39 ** D39 */ \ + PG , /* PG 1 ** 40 ** D40 */ \ + PG , /* PG 0 ** 41 ** D41 */ \ + PL , /* PL 7 ** 42 ** D42 */ \ + PL , /* PL 6 ** 43 ** D43 */ \ + PL , /* PL 5 ** 44 ** D44 */ \ + PL , /* PL 4 ** 45 ** D45 */ \ + PL , /* PL 3 ** 46 ** D46 */ \ + PL , /* PL 2 ** 47 ** D47 */ \ + PL , /* PL 1 ** 48 ** D48 */ \ + PL , /* PL 0 ** 49 ** D49 */ \ + PB , /* PB 3 ** 50 ** SPI_MISO */ \ + PB , /* PB 2 ** 51 ** SPI_MOSI */ \ + PB , /* PB 1 ** 52 ** SPI_SCK */ \ + PB , /* PB 0 ** 53 ** SPI_SS */ \ + PF , /* PF 0 ** 54 ** A0 */ \ + PF , /* PF 1 ** 55 ** A1 */ \ + PF , /* PF 2 ** 56 ** A2 */ \ + PF , /* PF 3 ** 57 ** A3 */ \ + PF , /* PF 4 ** 58 ** A4 */ \ + PF , /* PF 5 ** 59 ** A5 */ \ + PF , /* PF 6 ** 60 ** A6 */ \ + PF , /* PF 7 ** 61 ** A7 */ \ + PK , /* PK 0 ** 62 ** A8 */ \ + PK , /* PK 1 ** 63 ** A9 */ \ + PK , /* PK 2 ** 64 ** A10 */ \ + PK , /* PK 3 ** 65 ** A11 */ \ + PK , /* PK 4 ** 66 ** A12 */ \ + PK , /* PK 5 ** 67 ** A13 */ \ + PK , /* PK 6 ** 68 ** A14 */ \ + PK , /* PK 7 ** 69 ** A15 */ -const uint8_t PROGMEM digital_pin_to_bit_mask_PGM[] = { - // PIN IN PORT - // ------------------------------------------- - _BV( 0 ) , // PE 0 ** 0 ** USART0_RX - _BV( 1 ) , // PE 1 ** 1 ** USART0_TX - _BV( 4 ) , // PE 4 ** 2 ** PWM2 - _BV( 5 ) , // PE 5 ** 3 ** PWM3 - _BV( 5 ) , // PG 5 ** 4 ** PWM4 - _BV( 3 ) , // PE 3 ** 5 ** PWM5 - _BV( 3 ) , // PH 3 ** 6 ** PWM6 - _BV( 4 ) , // PH 4 ** 7 ** PWM7 - _BV( 5 ) , // PH 5 ** 8 ** PWM8 - _BV( 6 ) , // PH 6 ** 9 ** PWM9 - _BV( 4 ) , // PB 4 ** 10 ** PWM10 - _BV( 5 ) , // PB 5 ** 11 ** PWM11 - _BV( 6 ) , // PB 6 ** 12 ** PWM12 - _BV( 7 ) , // PB 7 ** 13 ** PWM13 - _BV( 1 ) , // PJ 1 ** 14 ** USART3_TX - _BV( 0 ) , // PJ 0 ** 15 ** USART3_RX - _BV( 1 ) , // PH 1 ** 16 ** USART2_TX - _BV( 0 ) , // PH 0 ** 17 ** USART2_RX - _BV( 3 ) , // PD 3 ** 18 ** USART1_TX - _BV( 2 ) , // PD 2 ** 19 ** USART1_RX - _BV( 1 ) , // PD 1 ** 20 ** I2C_SDA - _BV( 0 ) , // PD 0 ** 21 ** I2C_SCL - _BV( 0 ) , // PA 0 ** 22 ** D22 - _BV( 1 ) , // PA 1 ** 23 ** D23 - _BV( 2 ) , // PA 2 ** 24 ** D24 - _BV( 3 ) , // PA 3 ** 25 ** D25 - _BV( 4 ) , // PA 4 ** 26 ** D26 - _BV( 5 ) , // PA 5 ** 27 ** D27 - _BV( 6 ) , // PA 6 ** 28 ** D28 - _BV( 7 ) , // PA 7 ** 29 ** D29 - _BV( 7 ) , // PC 7 ** 30 ** D30 - _BV( 6 ) , // PC 6 ** 31 ** D31 - _BV( 5 ) , // PC 5 ** 32 ** D32 - _BV( 4 ) , // PC 4 ** 33 ** D33 - _BV( 3 ) , // PC 3 ** 34 ** D34 - _BV( 2 ) , // PC 2 ** 35 ** D35 - _BV( 1 ) , // PC 1 ** 36 ** D36 - _BV( 0 ) , // PC 0 ** 37 ** D37 - _BV( 7 ) , // PD 7 ** 38 ** D38 - _BV( 2 ) , // PG 2 ** 39 ** D39 - _BV( 1 ) , // PG 1 ** 40 ** D40 - _BV( 0 ) , // PG 0 ** 41 ** D41 - _BV( 7 ) , // PL 7 ** 42 ** D42 - _BV( 6 ) , // PL 6 ** 43 ** D43 - _BV( 5 ) , // PL 5 ** 44 ** D44 - _BV( 4 ) , // PL 4 ** 45 ** D45 - _BV( 3 ) , // PL 3 ** 46 ** D46 - _BV( 2 ) , // PL 2 ** 47 ** D47 - _BV( 1 ) , // PL 1 ** 48 ** D48 - _BV( 0 ) , // PL 0 ** 49 ** D49 - _BV( 3 ) , // PB 3 ** 50 ** SPI_MISO - _BV( 2 ) , // PB 2 ** 51 ** SPI_MOSI - _BV( 1 ) , // PB 1 ** 52 ** SPI_SCK - _BV( 0 ) , // PB 0 ** 53 ** SPI_SS - _BV( 0 ) , // PF 0 ** 54 ** A0 - _BV( 1 ) , // PF 1 ** 55 ** A1 - _BV( 2 ) , // PF 2 ** 56 ** A2 - _BV( 3 ) , // PF 3 ** 57 ** A3 - _BV( 4 ) , // PF 4 ** 58 ** A4 - _BV( 5 ) , // PF 5 ** 59 ** A5 - _BV( 6 ) , // PF 6 ** 60 ** A6 - _BV( 7 ) , // PF 7 ** 61 ** A7 - _BV( 0 ) , // PK 0 ** 62 ** A8 - _BV( 1 ) , // PK 1 ** 63 ** A9 - _BV( 2 ) , // PK 2 ** 64 ** A10 - _BV( 3 ) , // PK 3 ** 65 ** A11 - _BV( 4 ) , // PK 4 ** 66 ** A12 - _BV( 5 ) , // PK 5 ** 67 ** A13 - _BV( 6 ) , // PK 6 ** 68 ** A14 - _BV( 7 ) , // PK 7 ** 69 ** A15 -}; -const uint8_t PROGMEM digital_pin_to_timer_PGM[] = { - // TIMERS - // ------------------------------------------- - NOT_ON_TIMER , // PE 0 ** 0 ** USART0_RX - NOT_ON_TIMER , // PE 1 ** 1 ** USART0_TX - TIMER3B , // PE 4 ** 2 ** PWM2 - TIMER3C , // PE 5 ** 3 ** PWM3 - TIMER0B , // PG 5 ** 4 ** PWM4 - TIMER3A , // PE 3 ** 5 ** PWM5 - TIMER4A , // PH 3 ** 6 ** PWM6 - TIMER4B , // PH 4 ** 7 ** PWM7 - TIMER4C , // PH 5 ** 8 ** PWM8 - TIMER2B , // PH 6 ** 9 ** PWM9 - TIMER2A , // PB 4 ** 10 ** PWM10 - TIMER1A , // PB 5 ** 11 ** PWM11 - TIMER1B , // PB 6 ** 12 ** PWM12 - TIMER0A , // PB 7 ** 13 ** PWM13 - NOT_ON_TIMER , // PJ 1 ** 14 ** USART3_TX - NOT_ON_TIMER , // PJ 0 ** 15 ** USART3_RX - NOT_ON_TIMER , // PH 1 ** 16 ** USART2_TX - NOT_ON_TIMER , // PH 0 ** 17 ** USART2_RX - NOT_ON_TIMER , // PD 3 ** 18 ** USART1_TX - NOT_ON_TIMER , // PD 2 ** 19 ** USART1_RX - NOT_ON_TIMER , // PD 1 ** 20 ** I2C_SDA - NOT_ON_TIMER , // PD 0 ** 21 ** I2C_SCL - NOT_ON_TIMER , // PA 0 ** 22 ** D22 - NOT_ON_TIMER , // PA 1 ** 23 ** D23 - NOT_ON_TIMER , // PA 2 ** 24 ** D24 - NOT_ON_TIMER , // PA 3 ** 25 ** D25 - NOT_ON_TIMER , // PA 4 ** 26 ** D26 - NOT_ON_TIMER , // PA 5 ** 27 ** D27 - NOT_ON_TIMER , // PA 6 ** 28 ** D28 - NOT_ON_TIMER , // PA 7 ** 29 ** D29 - NOT_ON_TIMER , // PC 7 ** 30 ** D30 - NOT_ON_TIMER , // PC 6 ** 31 ** D31 - NOT_ON_TIMER , // PC 5 ** 32 ** D32 - NOT_ON_TIMER , // PC 4 ** 33 ** D33 - NOT_ON_TIMER , // PC 3 ** 34 ** D34 - NOT_ON_TIMER , // PC 2 ** 35 ** D35 - NOT_ON_TIMER , // PC 1 ** 36 ** D36 - NOT_ON_TIMER , // PC 0 ** 37 ** D37 - NOT_ON_TIMER , // PD 7 ** 38 ** D38 - NOT_ON_TIMER , // PG 2 ** 39 ** D39 - NOT_ON_TIMER , // PG 1 ** 40 ** D40 - NOT_ON_TIMER , // PG 0 ** 41 ** D41 - NOT_ON_TIMER , // PL 7 ** 42 ** D42 - NOT_ON_TIMER , // PL 6 ** 43 ** D43 - TIMER5C , // PL 5 ** 44 ** D44 - TIMER5B , // PL 4 ** 45 ** D45 - TIMER5A , // PL 3 ** 46 ** D46 - NOT_ON_TIMER , // PL 2 ** 47 ** D47 - NOT_ON_TIMER , // PL 1 ** 48 ** D48 - NOT_ON_TIMER , // PL 0 ** 49 ** D49 - NOT_ON_TIMER , // PB 3 ** 50 ** SPI_MISO - NOT_ON_TIMER , // PB 2 ** 51 ** SPI_MOSI - NOT_ON_TIMER , // PB 1 ** 52 ** SPI_SCK - NOT_ON_TIMER , // PB 0 ** 53 ** SPI_SS - NOT_ON_TIMER , // PF 0 ** 54 ** A0 - NOT_ON_TIMER , // PF 1 ** 55 ** A1 - NOT_ON_TIMER , // PF 2 ** 56 ** A2 - NOT_ON_TIMER , // PF 3 ** 57 ** A3 - NOT_ON_TIMER , // PF 4 ** 58 ** A4 - NOT_ON_TIMER , // PF 5 ** 59 ** A5 - NOT_ON_TIMER , // PF 6 ** 60 ** A6 - NOT_ON_TIMER , // PF 7 ** 61 ** A7 - NOT_ON_TIMER , // PK 0 ** 62 ** A8 - NOT_ON_TIMER , // PK 1 ** 63 ** A9 - NOT_ON_TIMER , // PK 2 ** 64 ** A10 - NOT_ON_TIMER , // PK 3 ** 65 ** A11 - NOT_ON_TIMER , // PK 4 ** 66 ** A12 - NOT_ON_TIMER , // PK 5 ** 67 ** A13 - NOT_ON_TIMER , // PK 6 ** 68 ** A14 - NOT_ON_TIMER , // PK 7 ** 69 ** A15 -}; +#define DIGITAL_PIN_TO_BIT_MASK \ + /* PIN IN PORT */ \ + /* ------------------------------------------- */ \ + _BV( 0 ) , /* PE 0 ** 0 ** USART0_RX */ \ + _BV( 1 ) , /* PE 1 ** 1 ** USART0_TX */ \ + _BV( 4 ) , /* PE 4 ** 2 ** PWM2 */ \ + _BV( 5 ) , /* PE 5 ** 3 ** PWM3 */ \ + _BV( 5 ) , /* PG 5 ** 4 ** PWM4 */ \ + _BV( 3 ) , /* PE 3 ** 5 ** PWM5 */ \ + _BV( 3 ) , /* PH 3 ** 6 ** PWM6 */ \ + _BV( 4 ) , /* PH 4 ** 7 ** PWM7 */ \ + _BV( 5 ) , /* PH 5 ** 8 ** PWM8 */ \ + _BV( 6 ) , /* PH 6 ** 9 ** PWM9 */ \ + _BV( 4 ) , /* PB 4 ** 10 ** PWM10 */ \ + _BV( 5 ) , /* PB 5 ** 11 ** PWM11 */ \ + _BV( 6 ) , /* PB 6 ** 12 ** PWM12 */ \ + _BV( 7 ) , /* PB 7 ** 13 ** PWM13 */ \ + _BV( 1 ) , /* PJ 1 ** 14 ** USART3_TX */ \ + _BV( 0 ) , /* PJ 0 ** 15 ** USART3_RX */ \ + _BV( 1 ) , /* PH 1 ** 16 ** USART2_TX */ \ + _BV( 0 ) , /* PH 0 ** 17 ** USART2_RX */ \ + _BV( 3 ) , /* PD 3 ** 18 ** USART1_TX */ \ + _BV( 2 ) , /* PD 2 ** 19 ** USART1_RX */ \ + _BV( 1 ) , /* PD 1 ** 20 ** I2C_SDA */ \ + _BV( 0 ) , /* PD 0 ** 21 ** I2C_SCL */ \ + _BV( 0 ) , /* PA 0 ** 22 ** D22 */ \ + _BV( 1 ) , /* PA 1 ** 23 ** D23 */ \ + _BV( 2 ) , /* PA 2 ** 24 ** D24 */ \ + _BV( 3 ) , /* PA 3 ** 25 ** D25 */ \ + _BV( 4 ) , /* PA 4 ** 26 ** D26 */ \ + _BV( 5 ) , /* PA 5 ** 27 ** D27 */ \ + _BV( 6 ) , /* PA 6 ** 28 ** D28 */ \ + _BV( 7 ) , /* PA 7 ** 29 ** D29 */ \ + _BV( 7 ) , /* PC 7 ** 30 ** D30 */ \ + _BV( 6 ) , /* PC 6 ** 31 ** D31 */ \ + _BV( 5 ) , /* PC 5 ** 32 ** D32 */ \ + _BV( 4 ) , /* PC 4 ** 33 ** D33 */ \ + _BV( 3 ) , /* PC 3 ** 34 ** D34 */ \ + _BV( 2 ) , /* PC 2 ** 35 ** D35 */ \ + _BV( 1 ) , /* PC 1 ** 36 ** D36 */ \ + _BV( 0 ) , /* PC 0 ** 37 ** D37 */ \ + _BV( 7 ) , /* PD 7 ** 38 ** D38 */ \ + _BV( 2 ) , /* PG 2 ** 39 ** D39 */ \ + _BV( 1 ) , /* PG 1 ** 40 ** D40 */ \ + _BV( 0 ) , /* PG 0 ** 41 ** D41 */ \ + _BV( 7 ) , /* PL 7 ** 42 ** D42 */ \ + _BV( 6 ) , /* PL 6 ** 43 ** D43 */ \ + _BV( 5 ) , /* PL 5 ** 44 ** D44 */ \ + _BV( 4 ) , /* PL 4 ** 45 ** D45 */ \ + _BV( 3 ) , /* PL 3 ** 46 ** D46 */ \ + _BV( 2 ) , /* PL 2 ** 47 ** D47 */ \ + _BV( 1 ) , /* PL 1 ** 48 ** D48 */ \ + _BV( 0 ) , /* PL 0 ** 49 ** D49 */ \ + _BV( 3 ) , /* PB 3 ** 50 ** SPI_MISO */ \ + _BV( 2 ) , /* PB 2 ** 51 ** SPI_MOSI */ \ + _BV( 1 ) , /* PB 1 ** 52 ** SPI_SCK */ \ + _BV( 0 ) , /* PB 0 ** 53 ** SPI_SS */ \ + _BV( 0 ) , /* PF 0 ** 54 ** A0 */ \ + _BV( 1 ) , /* PF 1 ** 55 ** A1 */ \ + _BV( 2 ) , /* PF 2 ** 56 ** A2 */ \ + _BV( 3 ) , /* PF 3 ** 57 ** A3 */ \ + _BV( 4 ) , /* PF 4 ** 58 ** A4 */ \ + _BV( 5 ) , /* PF 5 ** 59 ** A5 */ \ + _BV( 6 ) , /* PF 6 ** 60 ** A6 */ \ + _BV( 7 ) , /* PF 7 ** 61 ** A7 */ \ + _BV( 0 ) , /* PK 0 ** 62 ** A8 */ \ + _BV( 1 ) , /* PK 1 ** 63 ** A9 */ \ + _BV( 2 ) , /* PK 2 ** 64 ** A10 */ \ + _BV( 3 ) , /* PK 3 ** 65 ** A11 */ \ + _BV( 4 ) , /* PK 4 ** 66 ** A12 */ \ + _BV( 5 ) , /* PK 5 ** 67 ** A13 */ \ + _BV( 6 ) , /* PK 6 ** 68 ** A14 */ \ + _BV( 7 ) , /* PK 7 ** 69 ** A15 */ -#endif -#endif \ No newline at end of file +#define DIGITAL_PIN_TO_TIMER \ +/* TIMERS */ \ + /* ------------------------------------------- */ \ + NOT_ON_TIMER , /* PE 0 ** 0 ** USART0_RX */ \ + NOT_ON_TIMER , /* PE 1 ** 1 ** USART0_TX */ \ + TIMER3B , /* PE 4 ** 2 ** PWM2 */ \ + TIMER3C , /* PE 5 ** 3 ** PWM3 */ \ + TIMER0B , /* PG 5 ** 4 ** PWM4 */ \ + TIMER3A , /* PE 3 ** 5 ** PWM5 */ \ + TIMER4A , /* PH 3 ** 6 ** PWM6 */ \ + TIMER4B , /* PH 4 ** 7 ** PWM7 */ \ + TIMER4C , /* PH 5 ** 8 ** PWM8 */ \ + TIMER2B , /* PH 6 ** 9 ** PWM9 */ \ + TIMER2A , /* PB 4 ** 10 ** PWM10 */ \ + TIMER1A , /* PB 5 ** 11 ** PWM11 */ \ + TIMER1B , /* PB 6 ** 12 ** PWM12 */ \ + TIMER0A , /* PB 7 ** 13 ** PWM13 */ \ + NOT_ON_TIMER , /* PJ 1 ** 14 ** USART3_TX */ \ + NOT_ON_TIMER , /* PJ 0 ** 15 ** USART3_RX */ \ + NOT_ON_TIMER , /* PH 1 ** 16 ** USART2_TX */ \ + NOT_ON_TIMER , /* PH 0 ** 17 ** USART2_RX */ \ + NOT_ON_TIMER , /* PD 3 ** 18 ** USART1_TX */ \ + NOT_ON_TIMER , /* PD 2 ** 19 ** USART1_RX */ \ + NOT_ON_TIMER , /* PD 1 ** 20 ** I2C_SDA */ \ + NOT_ON_TIMER , /* PD 0 ** 21 ** I2C_SCL */ \ + NOT_ON_TIMER , /* PA 0 ** 22 ** D22 */ \ + NOT_ON_TIMER , /* PA 1 ** 23 ** D23 */ \ + NOT_ON_TIMER , /* PA 2 ** 24 ** D24 */ \ + NOT_ON_TIMER , /* PA 3 ** 25 ** D25 */ \ + NOT_ON_TIMER , /* PA 4 ** 26 ** D26 */ \ + NOT_ON_TIMER , /* PA 5 ** 27 ** D27 */ \ + NOT_ON_TIMER , /* PA 6 ** 28 ** D28 */ \ + NOT_ON_TIMER , /* PA 7 ** 29 ** D29 */ \ + NOT_ON_TIMER , /* PC 7 ** 30 ** D30 */ \ + NOT_ON_TIMER , /* PC 6 ** 31 ** D31 */ \ + NOT_ON_TIMER , /* PC 5 ** 32 ** D32 */ \ + NOT_ON_TIMER , /* PC 4 ** 33 ** D33 */ \ + NOT_ON_TIMER , /* PC 3 ** 34 ** D34 */ \ + NOT_ON_TIMER , /* PC 2 ** 35 ** D35 */ \ + NOT_ON_TIMER , /* PC 1 ** 36 ** D36 */ \ + NOT_ON_TIMER , /* PC 0 ** 37 ** D37 */ \ + NOT_ON_TIMER , /* PD 7 ** 38 ** D38 */ \ + NOT_ON_TIMER , /* PG 2 ** 39 ** D39 */ \ + NOT_ON_TIMER , /* PG 1 ** 40 ** D40 */ \ + NOT_ON_TIMER , /* PG 0 ** 41 ** D41 */ \ + NOT_ON_TIMER , /* PL 7 ** 42 ** D42 */ \ + NOT_ON_TIMER , /* PL 6 ** 43 ** D43 */ \ + TIMER5C , /* PL 5 ** 44 ** D44 */ \ + TIMER5B , /* PL 4 ** 45 ** D45 */ \ + TIMER5A , /* PL 3 ** 46 ** D46 */ \ + NOT_ON_TIMER , /* PL 2 ** 47 ** D47 */ \ + NOT_ON_TIMER , /* PL 1 ** 48 ** D48 */ \ + NOT_ON_TIMER , /* PL 0 ** 49 ** D49 */ \ + NOT_ON_TIMER , /* PB 3 ** 50 ** SPI_MISO */ \ + NOT_ON_TIMER , /* PB 2 ** 51 ** SPI_MOSI */ \ + NOT_ON_TIMER , /* PB 1 ** 52 ** SPI_SCK */ \ + NOT_ON_TIMER , /* PB 0 ** 53 ** SPI_SS */ \ + NOT_ON_TIMER , /* PF 0 ** 54 ** A0 */ \ + NOT_ON_TIMER , /* PF 1 ** 55 ** A1 */ \ + NOT_ON_TIMER , /* PF 2 ** 56 ** A2 */ \ + NOT_ON_TIMER , /* PF 3 ** 57 ** A3 */ \ + NOT_ON_TIMER , /* PF 4 ** 58 ** A4 */ \ + NOT_ON_TIMER , /* PF 5 ** 59 ** A5 */ \ + NOT_ON_TIMER , /* PF 6 ** 60 ** A6 */ \ + NOT_ON_TIMER , /* PF 7 ** 61 ** A7 */ \ + NOT_ON_TIMER , /* PK 0 ** 62 ** A8 */ \ + NOT_ON_TIMER , /* PK 1 ** 63 ** A9 */ \ + NOT_ON_TIMER , /* PK 2 ** 64 ** A10 */ \ + NOT_ON_TIMER , /* PK 3 ** 65 ** A11 */ \ + NOT_ON_TIMER , /* PK 4 ** 66 ** A12 */ \ + NOT_ON_TIMER , /* PK 5 ** 67 ** A13 */ \ + NOT_ON_TIMER , /* PK 6 ** 68 ** A14 */ \ + NOT_ON_TIMER , /* PK 7 ** 69 ** A15 */ + +#endif From 197ab92dc193424173a55753b097ca52dec96330 Mon Sep 17 00:00:00 2001 From: Angus Gratton Date: Tue, 19 Feb 2013 23:53:47 +1100 Subject: [PATCH 06/10] Change some things that don't work on gcc 4.3.2 --- .../arduino/cores/arduino/pin_functions.h | 47 ++++++++++--------- 1 file changed, 26 insertions(+), 21 deletions(-) diff --git a/hardware/arduino/cores/arduino/pin_functions.h b/hardware/arduino/cores/arduino/pin_functions.h index 18fd76c9dda..344ef16bdf9 100644 --- a/hardware/arduino/cores/arduino/pin_functions.h +++ b/hardware/arduino/cores/arduino/pin_functions.h @@ -120,16 +120,15 @@ static inline uint8_t digitalPinToTimer(uint8_t pin) { * This routine only returns true if the port is known at compile time, because * we'll be using memory mapped I/O regardless in the latter case. * -* The correct argument for this function should be 'volatile uint8_t *const port', but -* gcc seems unable to evaluate __builtin_constant_p correctly on that type, so we cast to -* a plain int in ther caller... which oddly seems to work. Same with using __SFR_OFFSET -* instead of the _SFR_IO_REG_P macro or _SFR_IO8. +* We test __builtin_constant_p on pin not port because testing the latter doesn't +* work in gcc 4.3.2, although gcc 4.3.2 is perfectly capable of optimising away +* the comparison test... * */ __attribute__((always_inline)) -static inline int portIsAtomic(uint16_t port) { +static inline int portIsAtomic(uint8_t pin, volatile uint8_t *port) { /* SBI/CBI instructions only work on lower 32 IO ports */ - return __builtin_constant_p(port) && port <= 0x1F + __SFR_OFFSET; + return __builtin_constant_p(pin) && (uint16_t)port <= 0x1F + __SFR_OFFSET; } __attribute__((always_inline)) @@ -143,21 +142,24 @@ static inline void _pinModeInline(uint8_t pin, uint8_t mode) { // We can only do this w/o disabling interrupts if setting output, // and the direction register can use sbi/cbi - if(portIsAtomic((uint16_t)dir) && (mode == OUTPUT)) { + if(portIsAtomic(pin, dir) && (mode == OUTPUT)) { *dir |= bitmask; } else { // Otherwise, we need to disable interrupts... - ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { - if(mode == INPUT_PULLUP) { - *out |= bitmask; - } else if(mode == INPUT) { - *out &= ~bitmask; - } - if(mode == INPUT_PULLUP || mode == INPUT) { - *dir &= ~bitmask; - } else { - *dir |= bitmask; - } + uint8_t oldSREG = SREG; + cli(); + + if(mode == INPUT_PULLUP) { + *out |= bitmask; + } else if(mode == INPUT) { + *out &= ~bitmask; } + if(mode == INPUT_PULLUP || mode == INPUT) { + *dir &= ~bitmask; + } else { + *dir |= bitmask; + } + + SREG = oldSREG; } } @@ -256,7 +258,7 @@ static inline void _digitalWriteInline(const uint8_t pin, const uint8_t value) { turnOffPWM(pin); - if(portIsAtomic((uint16_t)out)) { + if(portIsAtomic(pin, out)) { // Output is a single instruction write if(value) *out |= bitmask; @@ -265,12 +267,15 @@ static inline void _digitalWriteInline(const uint8_t pin, const uint8_t value) { } else { // Output is non-atomic - ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { + uint8_t oldSREG = SREG; + cli(); + if(value) *out |= bitmask; else *out &= ~bitmask; - } + + SREG = oldSREG; } } From b8a203714d70cc19f43d6fe60506d33322e54ea7 Mon Sep 17 00:00:00 2001 From: Angus Gratton Date: Wed, 20 Feb 2013 00:17:46 +1100 Subject: [PATCH 07/10] Update and test Leonardo port mappings --- .../arduino/variants/leonardo/pins_arduino.h | 269 +++++++++--------- 1 file changed, 132 insertions(+), 137 deletions(-) diff --git a/hardware/arduino/variants/leonardo/pins_arduino.h b/hardware/arduino/variants/leonardo/pins_arduino.h index 2c7f8372f45..2c391444981 100644 --- a/hardware/arduino/variants/leonardo/pins_arduino.h +++ b/hardware/arduino/variants/leonardo/pins_arduino.h @@ -132,8 +132,6 @@ static const uint8_t A11 = 29; // D12 extern const uint8_t PROGMEM analog_pin_to_channel_PGM[]; #define analogPinToChannel(P) ( pgm_read_byte( analog_pin_to_channel_PGM + (P) ) ) -#ifdef ARDUINO_MAIN - // On the Arduino board, digital pins are also used // for the analog output (software PWM). Analog input // pins are a separate set. @@ -177,146 +175,142 @@ extern const uint8_t PROGMEM analog_pin_to_channel_PGM[]; // these arrays map port names (e.g. port B) to the // appropriate addresses for various functions (e.g. reading // and writing) -const uint16_t PROGMEM port_to_mode_PGM[] = { - NOT_A_PORT, - NOT_A_PORT, - (uint16_t) &DDRB, - (uint16_t) &DDRC, - (uint16_t) &DDRD, - (uint16_t) &DDRE, - (uint16_t) &DDRF, -}; +#define PORT_TO_MODE \ + NOT_A_PORT, \ + NOT_A_PORT, \ + (uint16_t) &DDRB, \ + (uint16_t) &DDRC, \ + (uint16_t) &DDRD, \ + (uint16_t) &DDRE, \ + (uint16_t) &DDRF, -const uint16_t PROGMEM port_to_output_PGM[] = { - NOT_A_PORT, - NOT_A_PORT, - (uint16_t) &PORTB, - (uint16_t) &PORTC, - (uint16_t) &PORTD, - (uint16_t) &PORTE, - (uint16_t) &PORTF, -}; +#define PORT_TO_OUTPUT \ + NOT_A_PORT, \ + NOT_A_PORT, \ + (uint16_t) &PORTB, \ + (uint16_t) &PORTC, \ + (uint16_t) &PORTD, \ + (uint16_t) &PORTE, \ + (uint16_t) &PORTF, -const uint16_t PROGMEM port_to_input_PGM[] = { - NOT_A_PORT, - NOT_A_PORT, - (uint16_t) &PINB, - (uint16_t) &PINC, - (uint16_t) &PIND, - (uint16_t) &PINE, - (uint16_t) &PINF, -}; +#define PORT_TO_INPUT \ + NOT_A_PORT, \ + NOT_A_PORT, \ + (uint16_t) &PINB, \ + (uint16_t) &PINC, \ + (uint16_t) &PIND, \ + (uint16_t) &PINE, \ + (uint16_t) &PINF, \ -const uint8_t PROGMEM digital_pin_to_port_PGM[] = { - PD, // D0 - PD2 - PD, // D1 - PD3 - PD, // D2 - PD1 - PD, // D3 - PD0 - PD, // D4 - PD4 - PC, // D5 - PC6 - PD, // D6 - PD7 - PE, // D7 - PE6 - - PB, // D8 - PB4 - PB, // D9 - PB5 - PB, // D10 - PB6 - PB, // D11 - PB7 - PD, // D12 - PD6 - PC, // D13 - PC7 - - PB, // D14 - MISO - PB3 - PB, // D15 - SCK - PB1 - PB, // D16 - MOSI - PB2 - PB, // D17 - SS - PB0 - - PF, // D18 - A0 - PF7 - PF, // D19 - A1 - PF6 - PF, // D20 - A2 - PF5 - PF, // D21 - A3 - PF4 - PF, // D22 - A4 - PF1 - PF, // D23 - A5 - PF0 - - PD, // D24 / D4 - A6 - PD4 - PD, // D25 / D6 - A7 - PD7 - PB, // D26 / D8 - A8 - PB4 - PB, // D27 / D9 - A9 - PB5 - PB, // D28 / D10 - A10 - PB6 - PD, // D29 / D12 - A11 - PD6 -}; +#define DIGITAL_PIN_TO_PORT \ + PD, /* D0 - PD2 */ \ + PD, /* D1 - PD3 */ \ + PD, /* D2 - PD1 */ \ + PD, /* D3 - PD0 */ \ + PD, /* D4 - PD4 */ \ + PC, /* D5 - PC6 */ \ + PD, /* D6 - PD7 */ \ + PE, /* D7 - PE6 */ \ + \ + PB, /* D8 - PB4 */ \ + PB, /* D9 - PB5 */ \ + PB, /* D10 - PB6 */ \ + PB, /* D11 - PB7 */ \ + PD, /* D12 - PD6 */ \ + PC, /* D13 - PC7 */ \ + \ + PB, /* D14 - MISO - PB3 */ \ + PB, /* D15 - SCK - PB1 */ \ + PB, /* D16 - MOSI - PB2 */ \ + PB, /* D17 - SS - PB0 */ \ + \ + PF, /* D18 - A0 - PF7 */ \ + PF, /* D19 - A1 - PF6 */ \ + PF, /* D20 - A2 - PF5 */ \ + PF, /* D21 - A3 - PF4 */ \ + PF, /* D22 - A4 - PF1 */ \ + PF, /* D23 - A5 - PF0 */ \ + \ + PD, /* D24 / D4 - A6 - PD4 */ \ + PD, /* D25 / D6 - A7 - PD7 */ \ + PB, /* D26 / D8 - A8 - PB4 */ \ + PB, /* D27 / D9 - A9 - PB5 */ \ + PB, /* D28 / D10 - A10 - PB6 */ \ + PD, /* D29 / D12 - A11 - PD6 */ -const uint8_t PROGMEM digital_pin_to_bit_mask_PGM[] = { - _BV(2), // D0 - PD2 - _BV(3), // D1 - PD3 - _BV(1), // D2 - PD1 - _BV(0), // D3 - PD0 - _BV(4), // D4 - PD4 - _BV(6), // D5 - PC6 - _BV(7), // D6 - PD7 - _BV(6), // D7 - PE6 - - _BV(4), // D8 - PB4 - _BV(5), // D9 - PB5 - _BV(6), // D10 - PB6 - _BV(7), // D11 - PB7 - _BV(6), // D12 - PD6 - _BV(7), // D13 - PC7 - - _BV(3), // D14 - MISO - PB3 - _BV(1), // D15 - SCK - PB1 - _BV(2), // D16 - MOSI - PB2 - _BV(0), // D17 - SS - PB0 - - _BV(7), // D18 - A0 - PF7 - _BV(6), // D19 - A1 - PF6 - _BV(5), // D20 - A2 - PF5 - _BV(4), // D21 - A3 - PF4 - _BV(1), // D22 - A4 - PF1 - _BV(0), // D23 - A5 - PF0 - - _BV(4), // D24 / D4 - A6 - PD4 - _BV(7), // D25 / D6 - A7 - PD7 - _BV(4), // D26 / D8 - A8 - PB4 - _BV(5), // D27 / D9 - A9 - PB5 - _BV(6), // D28 / D10 - A10 - PB6 - _BV(6), // D29 / D12 - A11 - PD6 -}; +#define DIGITAL_PIN_TO_BIT_MASK \ + _BV(2), /* D0 - PD2 */ \ + _BV(3), /* D1 - PD3 */ \ + _BV(1), /* D2 - PD1 */ \ + _BV(0), /* D3 - PD0 */ \ + _BV(4), /* D4 - PD4 */ \ + _BV(6), /* D5 - PC6 */ \ + _BV(7), /* D6 - PD7 */ \ + _BV(6), /* D7 - PE6 */ \ + \ + _BV(4), /* D8 - PB4 */ \ + _BV(5), /* D9 - PB5 */ \ + _BV(6), /* D10 - PB6 */ \ + _BV(7), /* D11 - PB7 */ \ + _BV(6), /* D12 - PD6 */ \ + _BV(7), /* D13 - PC7 */ \ + \ + _BV(3), /* D14 - MISO - PB3 */ \ + _BV(1), /* D15 - SCK - PB1 */ \ + _BV(2), /* D16 - MOSI - PB2 */ \ + _BV(0), /* D17 - SS - PB0 */ \ + \ + _BV(7), /* D18 - A0 - PF7 */ \ + _BV(6), /* D19 - A1 - PF6 */ \ + _BV(5), /* D20 - A2 - PF5 */ \ + _BV(4), /* D21 - A3 - PF4 */ \ + _BV(1), /* D22 - A4 - PF1 */ \ + _BV(0), /* D23 - A5 - PF0 */ \ + \ + _BV(4), /* D24 / D4 - A6 - PD4 */ \ + _BV(7), /* D25 / D6 - A7 - PD7 */ \ + _BV(4), /* D26 / D8 - A8 - PB4 */ \ + _BV(5), /* D27 / D9 - A9 - PB5 */ \ + _BV(6), /* D28 / D10 - A10 - PB6 */ \ + _BV(6), /* D29 / D12 - A11 - PD6 */ -const uint8_t PROGMEM digital_pin_to_timer_PGM[] = { - NOT_ON_TIMER, - NOT_ON_TIMER, - NOT_ON_TIMER, - TIMER0B, /* 3 */ - NOT_ON_TIMER, - TIMER3A, /* 5 */ - TIMER4D, /* 6 */ - NOT_ON_TIMER, - - NOT_ON_TIMER, - TIMER1A, /* 9 */ - TIMER1B, /* 10 */ - TIMER0A, /* 11 */ - - NOT_ON_TIMER, - TIMER4A, /* 13 */ - - NOT_ON_TIMER, - NOT_ON_TIMER, - NOT_ON_TIMER, - NOT_ON_TIMER, - NOT_ON_TIMER, - NOT_ON_TIMER, +#define DIGITAL_PIN_TO_TIMER \ + NOT_ON_TIMER, \ + NOT_ON_TIMER, \ + NOT_ON_TIMER, \ + TIMER0B, /* 3 */ \ + NOT_ON_TIMER, \ + TIMER3A, /* 5 */ \ + TIMER4D, /* 6 */ \ + NOT_ON_TIMER, \ + \ + NOT_ON_TIMER, \ + TIMER1A, /* 9 */ \ + TIMER1B, /* 10 */ \ + TIMER0A, /* 11 */ \ + \ + NOT_ON_TIMER, \ + TIMER4A, /* 13 */ \ + \ + NOT_ON_TIMER, \ + NOT_ON_TIMER, \ + NOT_ON_TIMER, \ + NOT_ON_TIMER, \ + NOT_ON_TIMER, \ + NOT_ON_TIMER, \ + \ + NOT_ON_TIMER, \ + NOT_ON_TIMER, \ + NOT_ON_TIMER, \ + NOT_ON_TIMER, \ + NOT_ON_TIMER, \ + NOT_ON_TIMER, \ + NOT_ON_TIMER, \ + NOT_ON_TIMER, \ + NOT_ON_TIMER, \ + NOT_ON_TIMER, - NOT_ON_TIMER, - NOT_ON_TIMER, - NOT_ON_TIMER, - NOT_ON_TIMER, - NOT_ON_TIMER, - NOT_ON_TIMER, - NOT_ON_TIMER, - NOT_ON_TIMER, - NOT_ON_TIMER, - NOT_ON_TIMER, -}; +#ifdef ARDUINO_MAIN const uint8_t PROGMEM analog_pin_to_channel_PGM[] = { 7, // A0 PF7 ADC7 @@ -333,5 +327,6 @@ const uint8_t PROGMEM analog_pin_to_channel_PGM[] = { 9 // A11 D12 PD6 ADC9 }; -#endif /* ARDUINO_MAIN */ +#endif + #endif /* Pins_Arduino_h */ From f64b43e62eb2b3492c9c942a4b7dac61a1fe13ce Mon Sep 17 00:00:00 2001 From: Angus Gratton Date: Wed, 20 Feb 2013 00:38:12 +1100 Subject: [PATCH 08/10] Add some more comments, high level explanation --- .../arduino/cores/arduino/pin_functions.h | 41 ++++++++++++++++--- 1 file changed, 35 insertions(+), 6 deletions(-) diff --git a/hardware/arduino/cores/arduino/pin_functions.h b/hardware/arduino/cores/arduino/pin_functions.h index 344ef16bdf9..bf1b7f56e0d 100644 --- a/hardware/arduino/cores/arduino/pin_functions.h +++ b/hardware/arduino/cores/arduino/pin_functions.h @@ -67,8 +67,8 @@ static const uint8_t digital_pin_to_port[] = { DIGITAL_PIN_TO_PORT }; extern const uint8_t PROGMEM digital_pin_to_bit_mask_P[]; static const uint8_t digital_pin_to_bit_mask[] = { DIGITAL_PIN_TO_BIT_MASK }; -extern const uint8_t PROGMEM digital_pin_to_timer_P[]; -static const uint8_t digital_pin_to_timer[] = { DIGITAL_PIN_TO_TIMER }; + extern const uint8_t PROGMEM digital_pin_to_timer_P[]; + static const uint8_t digital_pin_to_timer[] = { DIGITAL_PIN_TO_TIMER }; __attribute__((always_inline)) static inline uint8_t digitalPinToPort(uint8_t pin) { @@ -76,6 +76,11 @@ static inline uint8_t digitalPinToPort(uint8_t pin) { : pgm_read_byte( digital_pin_to_port_P + pin ); } +/* These internal lookup functions will automatically resolve from the static const + * tables if evaluated at compile time, or the PROGMEM tables if evaluated + * at runtime: + */ + __attribute__((always_inline)) static inline volatile uint8_t *portOutputRegister(uint8_t port_idx) { return (volatile uint8_t *)( __builtin_constant_p(port_idx) ? @@ -121,8 +126,8 @@ static inline uint8_t digitalPinToTimer(uint8_t pin) { * we'll be using memory mapped I/O regardless in the latter case. * * We test __builtin_constant_p on pin not port because testing the latter doesn't -* work in gcc 4.3.2, although gcc 4.3.2 is perfectly capable of optimising away -* the comparison test... +* work in gcc 4.3.2, although gcc 4.3.2 does successfully optimise away the +* comparison... * */ __attribute__((always_inline)) @@ -131,6 +136,30 @@ static inline int portIsAtomic(uint8_t pin, volatile uint8_t *port) { return __builtin_constant_p(pin) && (uint16_t)port <= 0x1F + __SFR_OFFSET; } + +/* + * The following functions (pinMode, digitalWrite, digitalRead, + * turnOffPWM) all follow a pattern: + * + * _xxxxInline is a version of the function that is capable of being + * inlined at compile time. Where the pin number is known at compile + * time, this function can optimise down to the minimal number of + * instructions possible. The function still works adequately even + * if the pin number is not known at compile time. + * + * _xxxxRuntime is an extern version of the function suitable for + * being called at runtime (for when the pin number is not known at + * compile time.) The implementation is in wiring_digital.c, but it + * actually just inlines _xxxxInline to provide the matching + * non-inline implementation. + * + * 'xxxx' is the actual version of the function, which just chooses + * between _xxxxInline (inlined) or _xxxxRuntime (called + * conventionally) at compile time, based on whether the pin number is + * known. + * + */ + __attribute__((always_inline)) static inline void _pinModeInline(uint8_t pin, uint8_t mode) { const uint8_t port = digitalPinToPort(pin); @@ -147,7 +176,7 @@ static inline void _pinModeInline(uint8_t pin, uint8_t mode) { } else { // Otherwise, we need to disable interrupts... uint8_t oldSREG = SREG; cli(); - + if(mode == INPUT_PULLUP) { *out |= bitmask; } else if(mode == INPUT) { @@ -266,7 +295,7 @@ static inline void _digitalWriteInline(const uint8_t pin, const uint8_t value) { *out &= ~bitmask; } else { - // Output is non-atomic + // Output is non-atomic so we need to disable interrupts uint8_t oldSREG = SREG; cli(); From 18949a33dedee53e968581005a31fede67219e28 Mon Sep 17 00:00:00 2001 From: Angus Gratton Date: Wed, 20 Feb 2013 00:54:54 +1100 Subject: [PATCH 09/10] Reduce some code duplication between atomic and non-atomic versions of digitalWrite/pinMode --- .../arduino/cores/arduino/pin_functions.h | 64 +++++++++---------- 1 file changed, 31 insertions(+), 33 deletions(-) diff --git a/hardware/arduino/cores/arduino/pin_functions.h b/hardware/arduino/cores/arduino/pin_functions.h index bf1b7f56e0d..56cdf1e9f24 100644 --- a/hardware/arduino/cores/arduino/pin_functions.h +++ b/hardware/arduino/cores/arduino/pin_functions.h @@ -169,28 +169,30 @@ static inline void _pinModeInline(uint8_t pin, uint8_t mode) { if (pin >= NUM_DIGITAL_PINS) return; - // We can only do this w/o disabling interrupts if setting output, - // and the direction register can use sbi/cbi - if(portIsAtomic(pin, dir) && (mode == OUTPUT)) { - *dir |= bitmask; - } else { // Otherwise, we need to disable interrupts... - uint8_t oldSREG = SREG; + // We can only do this without disabling interrupts if + // both registers can use sbi/cbi + const int is_atomic = portIsAtomic(pin, dir) + && ((__builtin_constant_p(mode) && mode == OUTPUT) || portIsAtomic(pin, out)); + uint8_t oldSREG; + + if(!is_atomic) { // Resolves at compile time + oldSREG = SREG; cli(); + } - if(mode == INPUT_PULLUP) { - *out |= bitmask; - } else if(mode == INPUT) { - *out &= ~bitmask; - } - if(mode == INPUT_PULLUP || mode == INPUT) { - *dir &= ~bitmask; - } else { - *dir |= bitmask; - } - - SREG = oldSREG; + if(mode == INPUT_PULLUP) { + *out |= bitmask; + } else if(mode == INPUT) { + *out &= ~bitmask; + } + if(mode == INPUT_PULLUP || mode == INPUT) { + *dir &= ~bitmask; + } else { + *dir |= bitmask; } + if(!is_atomic) // Resolves at compile time + SREG = oldSREG; } void _pinModeRuntime(uint8_t, uint8_t); @@ -287,25 +289,21 @@ static inline void _digitalWriteInline(const uint8_t pin, const uint8_t value) { turnOffPWM(pin); - if(portIsAtomic(pin, out)) { - // Output is a single instruction write - if(value) - *out |= bitmask; - else - *out &= ~bitmask; - } - else { - // Output is non-atomic so we need to disable interrupts - uint8_t oldSREG = SREG; + const int is_atomic = portIsAtomic(pin, out); // Resolves at compile time + + uint8_t oldSREG; + if(!is_atomic) { // Resolves at compile time + oldSREG = SREG; cli(); + } - if(value) - *out |= bitmask; - else - *out &= ~bitmask; + if(value) + *out |= bitmask; + else + *out &= ~bitmask; + if(!is_atomic) // Resolves at compile time SREG = oldSREG; - } } void _digitalWriteRuntime(uint8_t, uint8_t); From f5607a553a0cce7e08aa24415ae88d065c250722 Mon Sep 17 00:00:00 2001 From: Angus Gratton Date: Wed, 20 Feb 2013 01:14:51 +1100 Subject: [PATCH 10/10] Add a macro for commonly used always_inline --- .../arduino/cores/arduino/pin_functions.h | 47 +++++++------------ 1 file changed, 17 insertions(+), 30 deletions(-) diff --git a/hardware/arduino/cores/arduino/pin_functions.h b/hardware/arduino/cores/arduino/pin_functions.h index 56cdf1e9f24..b1997afc9d8 100644 --- a/hardware/arduino/cores/arduino/pin_functions.h +++ b/hardware/arduino/cores/arduino/pin_functions.h @@ -47,6 +47,8 @@ extern "C" { #include "pins_arduino.h" +#define INLINED __attribute__((always_inline)) static inline + // The extern PROGMEM versions of each of these is for runtime lookups, // the static const versions are for lookups when the pin is known at compile time // (see the below inline functions, and wiring_digital.c) @@ -70,8 +72,7 @@ static const uint8_t digital_pin_to_bit_mask[] = { DIGITAL_PIN_TO_BIT_MASK }; extern const uint8_t PROGMEM digital_pin_to_timer_P[]; static const uint8_t digital_pin_to_timer[] = { DIGITAL_PIN_TO_TIMER }; -__attribute__((always_inline)) -static inline uint8_t digitalPinToPort(uint8_t pin) { +INLINED uint8_t digitalPinToPort(uint8_t pin) { return __builtin_constant_p(pin) ? digital_pin_to_port[pin] : pgm_read_byte( digital_pin_to_port_P + pin ); } @@ -81,35 +82,30 @@ static inline uint8_t digitalPinToPort(uint8_t pin) { * at runtime: */ -__attribute__((always_inline)) -static inline volatile uint8_t *portOutputRegister(uint8_t port_idx) { +INLINED volatile uint8_t *portOutputRegister(uint8_t port_idx) { return (volatile uint8_t *)( __builtin_constant_p(port_idx) ? port_to_output[port_idx] : pgm_read_word( port_to_output_P + port_idx) ); } -__attribute__((always_inline)) -static inline volatile uint8_t *portDirectionRegister(uint8_t port_idx) { +INLINED volatile uint8_t *portDirectionRegister(uint8_t port_idx) { return (volatile uint8_t *)( __builtin_constant_p(port_idx) ? port_to_mode[port_idx] : pgm_read_word( port_to_mode_P + port_idx ) ); } -__attribute__((always_inline)) -static inline volatile uint8_t *portInputRegister(uint8_t port_idx) { +INLINED volatile uint8_t *portInputRegister(uint8_t port_idx) { return (volatile uint8_t *)( __builtin_constant_p(port_idx) ? port_to_input[port_idx] : pgm_read_word( port_to_input_P + port_idx ) ); } -__attribute__((always_inline)) -static inline uint8_t digitalPinToBitMask(uint8_t pin) { +INLINED uint8_t digitalPinToBitMask(uint8_t pin) { return __builtin_constant_p(pin) ? digital_pin_to_bit_mask[pin] : pgm_read_byte( digital_pin_to_bit_mask_P + pin ); } -__attribute__((always_inline)) -static inline uint8_t digitalPinToTimer(uint8_t pin) { +INLINED uint8_t digitalPinToTimer(uint8_t pin) { return __builtin_constant_p(pin) ? digital_pin_to_timer[pin] : pgm_read_byte( digital_pin_to_timer_P + pin ); } @@ -130,8 +126,7 @@ static inline uint8_t digitalPinToTimer(uint8_t pin) { * comparison... * */ -__attribute__((always_inline)) -static inline int portIsAtomic(uint8_t pin, volatile uint8_t *port) { +INLINED int portIsAtomic(uint8_t pin, volatile uint8_t *port) { /* SBI/CBI instructions only work on lower 32 IO ports */ return __builtin_constant_p(pin) && (uint16_t)port <= 0x1F + __SFR_OFFSET; } @@ -160,8 +155,7 @@ static inline int portIsAtomic(uint8_t pin, volatile uint8_t *port) { * */ -__attribute__((always_inline)) -static inline void _pinModeInline(uint8_t pin, uint8_t mode) { +INLINED void _pinModeInline(uint8_t pin, uint8_t mode) { const uint8_t port = digitalPinToPort(pin); volatile uint8_t *dir = portDirectionRegister(port); volatile uint8_t *out = portOutputRegister(port); @@ -197,8 +191,7 @@ static inline void _pinModeInline(uint8_t pin, uint8_t mode) { void _pinModeRuntime(uint8_t, uint8_t); -__attribute__((always_inline)) -static inline void pinMode(uint8_t pin, uint8_t mode) { +INLINED void pinMode(uint8_t pin, uint8_t mode) { // If we know the pin number, inline directly. Otherwise make a function call. if(__builtin_constant_p(pin)) _pinModeInline(pin,mode); @@ -207,8 +200,7 @@ static inline void pinMode(uint8_t pin, uint8_t mode) { } -__attribute__((always_inline)) -static inline void _turnOffPWMInline(uint8_t pin) +INLINED void _turnOffPWMInline(uint8_t pin) { const uint8_t timer = digitalPinToTimer(pin); switch (timer) @@ -271,16 +263,14 @@ static inline void _turnOffPWMInline(uint8_t pin) void _turnOffPWMRuntime(uint8_t pin); -__attribute__((always_inline)) -static inline void turnOffPWM(const uint8_t pin) { +INLINED void turnOffPWM(const uint8_t pin) { if(__builtin_constant_p(pin)) _turnOffPWMInline(pin); else _turnOffPWMRuntime(pin); } -__attribute__((always_inline)) -static inline void _digitalWriteInline(const uint8_t pin, const uint8_t value) { +INLINED void _digitalWriteInline(const uint8_t pin, const uint8_t value) { const uint8_t port = digitalPinToPort(pin); volatile uint8_t *out = portOutputRegister(port); const uint8_t bitmask = digitalPinToBitMask(pin); @@ -308,8 +298,7 @@ static inline void _digitalWriteInline(const uint8_t pin, const uint8_t value) { void _digitalWriteRuntime(uint8_t, uint8_t); -__attribute__((always_inline)) -static inline void digitalWrite(uint8_t pin, uint8_t value) { +INLINED void digitalWrite(uint8_t pin, uint8_t value) { // If we know the pin number, inline directly. Otherwise make a function call. if(__builtin_constant_p(pin)) _digitalWriteInline(pin,value); @@ -318,8 +307,7 @@ static inline void digitalWrite(uint8_t pin, uint8_t value) { } -__attribute__((always_inline)) -static inline int _digitalReadInline(uint8_t pin) { +INLINED int _digitalReadInline(uint8_t pin) { const uint8_t port = digitalPinToPort(pin); const volatile uint8_t *in = portInputRegister(port); const uint8_t bitmask = digitalPinToBitMask(pin); @@ -335,8 +323,7 @@ static inline int _digitalReadInline(uint8_t pin) { int _digitalReadRuntime(uint8_t); -__attribute__((always_inline)) -static inline int digitalRead(uint8_t pin) { +INLINED int digitalRead(uint8_t pin) { // If we know the pin number, inline directly. Otherwise make a function call. if(__builtin_constant_p(pin)) return _digitalReadInline(pin);