[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.
This commit is contained in:
Eduardo José Tagle 2018-04-24 15:45:43 -03:00 committed by Scott Lahteine
parent 02a711c4d6
commit c1e5ebbc1e
4 changed files with 113 additions and 108 deletions

View File

@ -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

View File

@ -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

View File

@ -32,23 +32,24 @@
#include <libmaple/gpio.h>
#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.
*/

View File

@ -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