From c1e5ebbc1e0ef043b6870e0f63b8d908edabc1b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eduardo=20Jos=C3=A9=20Tagle?= Date: Tue, 24 Apr 2018 15:45:43 -0300 Subject: [PATCH] [2.0.x] AVR: Atomic bit set and clear of upper pin ports without critical section (#10502) * AVR: Atomic bit set and clear The critical section can be dropped, saving 3 cycles per access. Also simplified pin toggling for all ports. --- Marlin/src/HAL/HAL_AVR/fastio_AVR.h | 60 ++++++------ Marlin/src/HAL/HAL_DUE/fastio_Due.h | 92 ++++++++++--------- Marlin/src/HAL/HAL_STM32F1/fastio_Stm32f1.h | 13 +-- .../src/HAL/HAL_TEENSY35_36/fastio_Teensy.h | 56 ++++++----- 4 files changed, 113 insertions(+), 108 deletions(-) diff --git a/Marlin/src/HAL/HAL_AVR/fastio_AVR.h b/Marlin/src/HAL/HAL_AVR/fastio_AVR.h index e70f3f3da..0c782988f 100644 --- a/Marlin/src/HAL/HAL_AVR/fastio_AVR.h +++ b/Marlin/src/HAL/HAL_AVR/fastio_AVR.h @@ -63,49 +63,43 @@ * Why double up on these macros? see http://gcc.gnu.org/onlinedocs/cpp/Stringification.html */ -#define _READ(IO) ((bool)(DIO ## IO ## _RPORT & _BV(DIO ## IO ## _PIN))) +#define _READ(IO) TEST(DIO ## IO ## _RPORT, DIO ## IO ## _PIN) -// On some boards pins > 0x100 are used. These are not converted to atomic actions. A critical section is needed. +#define _WRITE_NC(IO,V) do{ \ + if (V) SBI(DIO ## IO ## _WPORT, DIO ## IO ## _PIN); \ + else CBI(DIO ## IO ## _WPORT, DIO ## IO ## _PIN); \ +}while(0) -#define _WRITE_NC(IO, v) do { if (v) {DIO ## IO ## _WPORT |= _BV(DIO ## IO ## _PIN); } else {DIO ## IO ## _WPORT &= ~_BV(DIO ## IO ## _PIN); }; } while (0) +#define _WRITE_C(IO,V) do{ \ + uint8_t port_bits = DIO ## IO ## _WPORT; /* Get a mask from the current port bits */ \ + if (V) port_bits = ~port_bits; /* For setting bits, invert the mask */ \ + DIO ## IO ## _RPORT = port_bits & _BV(DIO ## IO ## _PIN); /* Atomically toggle the output port bits */ \ +}while(0) -#define _WRITE_C(IO, v) do { if (v) { \ - CRITICAL_SECTION_START; \ - {DIO ## IO ## _WPORT |= _BV(DIO ## IO ## _PIN); } \ - CRITICAL_SECTION_END; \ - } \ - else { \ - CRITICAL_SECTION_START; \ - {DIO ## IO ## _WPORT &= ~_BV(DIO ## IO ## _PIN); } \ - CRITICAL_SECTION_END; \ - } \ - } \ - while (0) +#define _WRITE(IO,V) do{ if (&(DIO ## IO ## _RPORT) < (uint8_t*)0x100) _WRITE_NC(IO,V); else _WRITE_C(IO,V); }while(0) -#define _WRITE(IO, v) do { if (&(DIO ## IO ## _RPORT) >= (uint8_t *)0x100) {_WRITE_C(IO, v); } else {_WRITE_NC(IO, v); }; } while (0) +#define _TOGGLE(IO) (DIO ## IO ## _RPORT = _BV(DIO ## IO ## _PIN)) -#define _TOGGLE(IO) do {DIO ## IO ## _RPORT ^= _BV(DIO ## IO ## _PIN); } while (0) +#define _SET_INPUT(IO) CBI(DIO ## IO ## _DDR, DIO ## IO ## _PIN) +#define _SET_OUTPUT(IO) SBI(DIO ## IO ## _DDR, DIO ## IO ## _PIN) -#define _SET_INPUT(IO) do {DIO ## IO ## _DDR &= ~_BV(DIO ## IO ## _PIN); } while (0) -#define _SET_OUTPUT(IO) do {DIO ## IO ## _DDR |= _BV(DIO ## IO ## _PIN); } while (0) +#define _GET_INPUT(IO) !TEST(DIO ## IO ## _DDR, DIO ## IO ## _PIN) +#define _GET_OUTPUT(IO) TEST(DIO ## IO ## _DDR, DIO ## IO ## _PIN) +#define _GET_TIMER(IO) DIO ## IO ## _PWM -#define _GET_INPUT(IO) ((DIO ## IO ## _DDR & _BV(DIO ## IO ## _PIN)) == 0) -#define _GET_OUTPUT(IO) ((DIO ## IO ## _DDR & _BV(DIO ## IO ## _PIN)) != 0) -#define _GET_TIMER(IO) (DIO ## IO ## _PWM) +#define READ(IO) _READ(IO) +#define WRITE(IO,V) _WRITE(IO,V) +#define TOGGLE(IO) _TOGGLE(IO) -#define READ(IO) _READ(IO) -#define WRITE(IO,V) _WRITE(IO,V) -#define TOGGLE(IO) _TOGGLE(IO) +#define SET_INPUT(IO) _SET_INPUT(IO) +#define SET_INPUT_PULLUP(IO) do{ _SET_INPUT(IO); _WRITE(IO, HIGH); }while(0) +#define SET_OUTPUT(IO) _SET_OUTPUT(IO) -#define SET_INPUT(IO) _SET_INPUT(IO) -#define SET_INPUT_PULLUP(IO) do{ _SET_INPUT(IO); _WRITE(IO, HIGH); }while(0) -#define SET_OUTPUT(IO) _SET_OUTPUT(IO) +#define GET_INPUT(IO) _GET_INPUT(IO) +#define GET_OUTPUT(IO) _GET_OUTPUT(IO) +#define GET_TIMER(IO) _GET_TIMER(IO) -#define GET_INPUT(IO) _GET_INPUT(IO) -#define GET_OUTPUT(IO) _GET_OUTPUT(IO) -#define GET_TIMER(IO) _GET_TIMER(IO) - -#define OUT_WRITE(IO, v) do{ SET_OUTPUT(IO); WRITE(IO, v); }while(0) +#define OUT_WRITE(IO,V) do{ SET_OUTPUT(IO); WRITE(IO,V); }while(0) /** * Timer and Interrupt Control diff --git a/Marlin/src/HAL/HAL_DUE/fastio_Due.h b/Marlin/src/HAL/HAL_DUE/fastio_Due.h index e1d3fc756..fe0923ead 100644 --- a/Marlin/src/HAL/HAL_DUE/fastio_Due.h +++ b/Marlin/src/HAL/HAL_DUE/fastio_Due.h @@ -48,7 +48,7 @@ #define USEABLE_HARDWARE_PWM(p) ((2 <= p) && (p <= 13)) #ifndef MASK - #define MASK(PIN) (1 << PIN) + #define MASK(PIN) (1 << PIN) #endif /** @@ -59,76 +59,78 @@ * Why double up on these macros? see http://gcc.gnu.org/onlinedocs/cpp/Stringification.html */ -/// Read a pin -#define _READ(IO) ((bool)(DIO ## IO ## _WPORT -> PIO_PDSR & (MASK(DIO ## IO ## _PIN)))) +// Read a pin +#define _READ(IO) bool(DIO ## IO ## _WPORT -> PIO_PDSR & MASK(DIO ## IO ## _PIN)) -/// Write to a pin -#define _WRITE_VAR(IO, v) do { \ +// Write to a pin +#define _WRITE_VAR(IO,V) do { \ volatile Pio* port = g_APinDescription[IO].pPort; \ uint32_t mask = g_APinDescription[IO].ulPin; \ - if (v) port->PIO_SODR = mask; \ + if (V) port->PIO_SODR = mask; \ else port->PIO_CODR = mask; \ } while(0) -/// Write to a pin -#define _WRITE(IO, v) do { \ +// Write to a pin +#define _WRITE(IO,V) do { \ volatile Pio* port = (DIO ## IO ## _WPORT); \ uint32_t mask = MASK(DIO ## IO ## _PIN); \ - if (v) port->PIO_SODR = mask; \ + if (V) port->PIO_SODR = mask; \ else port->PIO_CODR = mask; \ } while(0) -/// toggle a pin -#define _TOGGLE(IO) _WRITE(IO, !READ(IO)) +// toggle a pin +#define _TOGGLE(IO) _WRITE(IO, !READ(IO)) -/// set pin as input -#define _SET_INPUT(IO) do{ pmc_enable_periph_clk(g_APinDescription[IO].ulPeripheralId); \ - PIO_Configure(g_APinDescription[IO].pPort, PIO_INPUT, g_APinDescription[IO].ulPin, 0); \ - }while(0) -/// set pin as output -#define _SET_OUTPUT(IO) do{ pmc_enable_periph_clk(g_APinDescription[IO].ulPeripheralId); \ - PIO_Configure(g_APinDescription[IO].pPort, _READ(IO) ? PIO_OUTPUT_1 : PIO_OUTPUT_0, \ - g_APinDescription[IO].ulPin, g_APinDescription[IO].ulPinConfiguration); \ - g_pinStatus[IO] = (g_pinStatus[IO] & 0xF0) | PIN_STATUS_DIGITAL_OUTPUT;\ - }while(0) +// set pin as input +#define _SET_INPUT(IO) do{ \ + pmc_enable_periph_clk(g_APinDescription[IO].ulPeripheralId); \ + PIO_Configure(g_APinDescription[IO].pPort, PIO_INPUT, g_APinDescription[IO].ulPin, 0); \ +}while(0) -/// set pin as input with pullup mode -#define _PULLUP(IO, v) { pinMode(IO, v != LOW ? INPUT_PULLUP : INPUT); } +// set pin as output +#define _SET_OUTPUT(IO) do{ \ + pmc_enable_periph_clk(g_APinDescription[IO].ulPeripheralId); \ + PIO_Configure(g_APinDescription[IO].pPort, _READ(IO) ? PIO_OUTPUT_1 : PIO_OUTPUT_0, g_APinDescription[IO].ulPin, g_APinDescription[IO].ulPinConfiguration); \ + g_pinStatus[IO] = (g_pinStatus[IO] & 0xF0) | PIN_STATUS_DIGITAL_OUTPUT;\ +}while(0) -/// check if pin is an input +// set pin as input with pullup mode +#define _PULLUP(IO,V) pinMode(IO, (V) ? INPUT_PULLUP : INPUT) + +// check if pin is an input #define _GET_INPUT(IO) -/// check if pin is an output +// check if pin is an output #define _GET_OUTPUT(IO) -/// check if pin is a timer +// check if pin is a timer #define _GET_TIMER(IO) -/// Read a pin wrapper -#define READ(IO) _READ(IO) +// Read a pin wrapper +#define READ(IO) _READ(IO) -/// Write to a pin wrapper -#define WRITE_VAR(IO, v) _WRITE_VAR(IO, v) -#define WRITE(IO, v) _WRITE(IO, v) +// Write to a pin wrapper +#define WRITE_VAR(IO,V) _WRITE_VAR(IO,V) +#define WRITE(IO,V) _WRITE(IO,V) -/// toggle a pin wrapper -#define TOGGLE(IO) _TOGGLE(IO) +// toggle a pin wrapper +#define TOGGLE(IO) _TOGGLE(IO) -/// set pin as input wrapper -#define SET_INPUT(IO) _SET_INPUT(IO) -/// set pin as input with pullup wrapper +// set pin as input wrapper +#define SET_INPUT(IO) _SET_INPUT(IO) +// set pin as input with pullup wrapper #define SET_INPUT_PULLUP(IO) do{ _SET_INPUT(IO); _PULLUP(IO, HIGH); }while(0) -/// set pin as output wrapper - reads the pin and sets the output to that value -#define SET_OUTPUT(IO) _SET_OUTPUT(IO) -/// check if pin is an input wrapper -#define GET_INPUT(IO) _GET_INPUT(IO) -/// check if pin is an output wrapper -#define GET_OUTPUT(IO) _GET_OUTPUT(IO) +// set pin as output wrapper - reads the pin and sets the output to that value +#define SET_OUTPUT(IO) _SET_OUTPUT(IO) +// check if pin is an input wrapper +#define GET_INPUT(IO) _GET_INPUT(IO) +// check if pin is an output wrapper +#define GET_OUTPUT(IO) _GET_OUTPUT(IO) -/// check if pin is a timer (wrapper) -#define GET_TIMER(IO) _GET_TIMER(IO) +// check if pin is a timer (wrapper) +#define GET_TIMER(IO) _GET_TIMER(IO) // Shorthand -#define OUT_WRITE(IO, v) { SET_OUTPUT(IO); WRITE(IO, v); } +#define OUT_WRITE(IO,V) { SET_OUTPUT(IO); WRITE(IO,V); } /** * Ports and functions diff --git a/Marlin/src/HAL/HAL_STM32F1/fastio_Stm32f1.h b/Marlin/src/HAL/HAL_STM32F1/fastio_Stm32f1.h index 1ebf9e855..3674856fe 100644 --- a/Marlin/src/HAL/HAL_STM32F1/fastio_Stm32f1.h +++ b/Marlin/src/HAL/HAL_STM32F1/fastio_Stm32f1.h @@ -32,23 +32,24 @@ #include #define READ(IO) (PIN_MAP[IO].gpio_device->regs->IDR & (1U << PIN_MAP[IO].gpio_bit) ? HIGH : LOW) -#define WRITE(IO, v) (PIN_MAP[IO].gpio_device->regs->BSRR = (1U << PIN_MAP[IO].gpio_bit) << (16 * !(bool)v)) +#define WRITE(IO,V) (PIN_MAP[IO].gpio_device->regs->BSRR = (1U << PIN_MAP[IO].gpio_bit) << (16 * !(bool)v)) #define TOGGLE(IO) (PIN_MAP[IO].gpio_device->regs->ODR = PIN_MAP[IO].gpio_device->regs->ODR ^ (1U << PIN_MAP[IO].gpio_bit)) -#define WRITE_VAR(IO, v) WRITE(io, v) +#define WRITE_VAR(IO,V) WRITE(io,V) -#define _GET_MODE(IO) (gpio_get_mode(PIN_MAP[IO].gpio_device, PIN_MAP[IO].gpio_bit)) -#define _SET_MODE(IO,M) do{ gpio_set_mode(PIN_MAP[IO].gpio_device, PIN_MAP[IO].gpio_bit, M); } while (0) +#define _GET_MODE(IO) gpio_get_mode(PIN_MAP[IO].gpio_device, PIN_MAP[IO].gpio_bit) +#define _SET_MODE(IO,M) gpio_set_mode(PIN_MAP[IO].gpio_device, PIN_MAP[IO].gpio_bit, M) #define _SET_OUTPUT(IO) _SET_MODE(IO, GPIO_OUTPUT_PP) +#define OUT_WRITE(IO,V) do{ _SET_OUTPUT(IO); WRITE(IO,V); }while(0) + #define SET_INPUT(IO) _SET_MODE(IO, GPIO_INPUT_FLOATING) #define SET_INPUT_PULLUP(IO) _SET_MODE(IO, GPIO_INPUT_PU) -#define SET_OUTPUT(IO) do{ _SET_OUTPUT(IO); WRITE(IO, LOW); }while(0) +#define SET_OUTPUT(IO) OUT_WRITE(IO,LOW) #define GET_INPUT(IO) (_GET_MODE(IO) == GPIO_INPUT_FLOATING || _GET_MODE(IO) == GPIO_INPUT_ANALOG || _GET_MODE(IO) == GPIO_INPUT_PU || _GET_MODE(IO) == GPIO_INPUT_PD) #define GET_OUTPUT(IO) (_GET_MODE(IO) == GPIO_OUTPUT_PP) #define GET_TIMER(IO) (PIN_MAP[IO].timer_device != NULL) -#define OUT_WRITE(IO, v) { _SET_OUTPUT(IO); WRITE(IO, v); } /** * TODO: Write a macro to test if PIN is PWM or not. */ diff --git a/Marlin/src/HAL/HAL_TEENSY35_36/fastio_Teensy.h b/Marlin/src/HAL/HAL_TEENSY35_36/fastio_Teensy.h index ce31ed206..dc350df5c 100644 --- a/Marlin/src/HAL/HAL_TEENSY35_36/fastio_Teensy.h +++ b/Marlin/src/HAL/HAL_TEENSY35_36/fastio_Teensy.h @@ -30,7 +30,7 @@ #define _FASTIO_TEENSY_H #ifndef MASK - #define MASK(PIN) (1 << PIN) + #define MASK(PIN) (1 << PIN) #endif #define GPIO_BITBAND_ADDR(reg, bit) (((uint32_t)&(reg) - 0x40000000) * 32 + (bit) * 4 + 0x42000000) @@ -44,38 +44,46 @@ * Why double up on these macros? see http://gcc.gnu.org/onlinedocs/cpp/Stringification.html */ -#define _READ(p) ((bool)(CORE_PIN ## p ## _PINREG & CORE_PIN ## p ## _BITMASK)) -#define _WRITE(p, v) do { if (v) CORE_PIN ## p ## _PORTSET = CORE_PIN ## p ## _BITMASK; \ - else CORE_PIN ## p ## _PORTCLEAR = CORE_PIN ## p ## _BITMASK; } while (0) -#define _TOGGLE(p) (*(&(CORE_PIN ## p ## _PORTCLEAR)+1) = CORE_PIN ## p ## _BITMASK) -#define _SET_INPUT(p) do { CORE_PIN ## p ## _CONFIG = PORT_PCR_MUX(1); \ - GPIO_BITBAND(CORE_PIN ## p ## _DDRREG , CORE_PIN ## p ## _BIT) = 0; \ - } while (0) -#define _SET_OUTPUT(p) do { CORE_PIN ## p ## _CONFIG = PORT_PCR_MUX(1)|PORT_PCR_SRE|PORT_PCR_DSE; \ - GPIO_BITBAND(CORE_PIN ## p ## _DDRREG , CORE_PIN ## p ## _BIT) = 1; \ - } while (0) +#define _READ(p) bool(CORE_PIN ## p ## _PINREG & CORE_PIN ## p ## _BITMASK) -//#define _PULLUP(IO, v) { pinMode(IO, (v!=LOW ? INPUT_PULLUP : INPUT)); } +#define _WRITE(P,V) do{ \ + if (V) CORE_PIN ## P ## _PORTSET = CORE_PIN ## P ## _BITMASK; \ + else CORE_PIN ## P ## _PORTCLEAR = CORE_PIN ## P ## _BITMASK; \ +}while(0) -#define _GET_INPUT(p) ((CORE_PIN ## p ## _DDRREG & CORE_PIN ## p ## _BITMASK) == 0) -#define _GET_OUTPUT(p) ((CORE_PIN ## p ## _DDRREG & CORE_PIN ## p ## _BITMASK) == 0) +#define _TOGGLE(P) (*(&(CORE_PIN ## P ## _PORTCLEAR)+1) = CORE_PIN ## P ## _BITMASK) + +#define _SET_INPUT(P) do{ \ + CORE_PIN ## P ## _CONFIG = PORT_PCR_MUX(1); \ + GPIO_BITBAND(CORE_PIN ## P ## _DDRREG , CORE_PIN ## P ## _BIT) = 0; \ +}while(0) + +#define _SET_OUTPUT(P) do{ \ + CORE_PIN ## P ## _CONFIG = PORT_PCR_MUX(1)|PORT_PCR_SRE|PORT_PCR_DSE; \ + GPIO_BITBAND(CORE_PIN ## P ## _DDRREG , CORE_PIN ## P ## _BIT) = 1; \ +}while(0) + +//#define _PULLUP(IO,V) { pinMode(IO, (v!=LOW ? INPUT_PULLUP : INPUT)); } + +#define _GET_INPUT(P) ((CORE_PIN ## P ## _DDRREG & CORE_PIN ## P ## _BITMASK) == 0) +#define _GET_OUTPUT(P) ((CORE_PIN ## P ## _DDRREG & CORE_PIN ## P ## _BITMASK) == 0) //#define _GET_TIMER(IO) -#define READ(IO) _READ(IO) +#define READ(IO) _READ(IO) -#define WRITE_VAR(IO, v) _WRITE_VAR(IO, v) -#define WRITE(IO, v) _WRITE(IO, v) -#define TOGGLE(IO) _TOGGLE(IO) +#define WRITE_VAR(IO,V) _WRITE_VAR(IO,V) +#define WRITE(IO,V) _WRITE(IO,V) +#define TOGGLE(IO) _TOGGLE(IO) -#define SET_INPUT(IO) _SET_INPUT(IO) -#define SET_INPUT_PULLUP(IO) do{ _SET_INPUT(IO); _WRITE(IO, HIGH); }while(0) -#define SET_OUTPUT(IO) _SET_OUTPUT(IO) +#define SET_INPUT(IO) _SET_INPUT(IO) +#define SET_INPUT_PULLUP(IO) do{ _SET_INPUT(IO); _WRITE(IO,HIGH); }while(0) +#define SET_OUTPUT(IO) _SET_OUTPUT(IO) -#define GET_INPUT(IO) _GET_INPUT(IO) -#define GET_OUTPUT(IO) _GET_OUTPUT(IO) +#define GET_INPUT(IO) _GET_INPUT(IO) +#define GET_OUTPUT(IO) _GET_OUTPUT(IO) -#define OUT_WRITE(IO, v) { SET_OUTPUT(IO); WRITE(IO, v); } +#define OUT_WRITE(IO,V) do{ SET_OUTPUT(IO); WRITE(IO,V); }while(0) /** * Ports, functions, and pins