projet crepp_git/crepp-projects/my-sensors · branche main
DigitalPin.h Voir sur GitLab
/* Arduino DigitalIO Library
 * Copyright (C) 2013 by William Greiman
 *
 * This file is part of the Arduino DigitalIO Library
 *
 * This Library is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This Library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with the Arduino DigitalIO Library.  If not, see
 * <http://www.gnu.org/licenses/>.
 */
/**
 * @file
 * @brief Fast Digital Pin functions
 *
 * @defgroup digitalPin Fast Pin I/O
 * @details  Fast Digital I/O functions and template class.
 * @{
 */
#ifndef DigitalPin_h
#define DigitalPin_h
#if defined(__AVR__) || defined(DOXYGEN)
#include <avr/io.h>
/** GpioPinMap type */
struct GpioPinMap_t {
	volatile uint8_t* pin;   /**< address of PIN for this pin */
	volatile uint8_t* ddr;   /**< address of DDR for this pin */
	volatile uint8_t* port;  /**< address of PORT for this pin */
	uint8_t mask;            /**< bit mask for this pin */
};

/** Initializer macro. */
#define GPIO_PIN(reg, bit) {&PIN##reg, &DDR##reg, &PORT##reg, 1 << bit}

// Include pin map for current board.
#include "boards/GpioPinMap.h"
//------------------------------------------------------------------------------
/** generate bad pin number error */
void badPinNumber(void)
__attribute__((error("Pin number is too large or not a constant")));
//------------------------------------------------------------------------------
/** Check for valid pin number
 * @param[in] pin Number of pin to be checked.
 */
static inline __attribute__((always_inline))
void badPinCheck(uint8_t pin)
{
	if (!__builtin_constant_p(pin) || pin >= NUM_DIGITAL_PINS) {
		badPinNumber();
	}
}
//------------------------------------------------------------------------------
/** DDR register address
 * @param[in] pin Arduino pin number
 * @return register address
 */
static inline __attribute__((always_inline))
volatile uint8_t* ddrReg(uint8_t pin)
{
	badPinCheck(pin);
	return GpioPinMap[pin].ddr;
}
//------------------------------------------------------------------------------
/** Bit mask for pin
 * @param[in] pin Arduino pin number
 * @return mask
 */
static inline __attribute__((always_inline))
uint8_t pinMask(uint8_t pin)
{
	badPinCheck(pin);
	return GpioPinMap[pin].mask;
}
//------------------------------------------------------------------------------
/** PIN register address
 * @param[in] pin Arduino pin number
 * @return register address
 */
static inline __attribute__((always_inline))
volatile uint8_t* pinReg(uint8_t pin)
{
	badPinCheck(pin);
	return GpioPinMap[pin].pin;
}
//------------------------------------------------------------------------------
/** PORT register address
 * @param[in] pin Arduino pin number
 * @return register address
 */
static inline __attribute__((always_inline))
volatile uint8_t* portReg(uint8_t pin)
{
	badPinCheck(pin);
	return GpioPinMap[pin].port;
}
//------------------------------------------------------------------------------
/** Fast write helper.
 * @param[in] address I/O register address
 * @param[in] mask bit mask for pin
 * @param[in] level value for bit
 */
static inline __attribute__((always_inline))
void fastBitWriteSafe(volatile uint8_t* address, uint8_t mask, bool level)
{
	uint8_t s;
	if (address > reinterpret_cast<uint8_t*>(0X3F)) {
		s = SREG;
		cli();
	}
	if (level) {
		*address |= mask;
	} else {
		*address &= ~mask;
	}
	if (address > reinterpret_cast<uint8_t*>(0X3F)) {
		SREG = s;
	}
}
//------------------------------------------------------------------------------
/** Read pin value.
 * @param[in] pin Arduino pin number
 * @return value read
 */
static inline __attribute__((always_inline))
bool fastDigitalRead(uint8_t pin)
{
	return *pinReg(pin) & pinMask(pin);
}
//------------------------------------------------------------------------------
/** Toggle a pin.
 * @param[in] pin Arduino pin number
 *
 * If the pin is in output mode toggle the pin level.
 * If the pin is in input mode toggle the state of the 20K pullup.
 */
static inline __attribute__((always_inline))
void fastDigitalToggle(uint8_t pin)
{
	if (pinReg(pin) > reinterpret_cast<uint8_t*>(0X3F)) {
		// must write bit to high address port
		*pinReg(pin) = pinMask(pin);
	} else {
		// will compile to sbi and PIN register will not be read.
		*pinReg(pin) |= pinMask(pin);
	}
}
//------------------------------------------------------------------------------
/** Set pin value.
 * @param[in] pin Arduino pin number
 * @param[in] level value to write
 */
static inline __attribute__((always_inline))
void fastDigitalWrite(uint8_t pin, bool level)
{
	fastBitWriteSafe(portReg(pin), pinMask(pin), level);
}
//------------------------------------------------------------------------------
/** Write the DDR register.
 * @param[in] pin Arduino pin number
 * @param[in] level value to write
 */
static inline __attribute__((always_inline))
void fastDdrWrite(uint8_t pin, bool level)
{
	fastBitWriteSafe(ddrReg(pin), pinMask(pin), level);
}
//------------------------------------------------------------------------------
/** Set pin mode.
 * @param[in] pin Arduino pin number
 * @param[in] mode INPUT, OUTPUT, or INPUT_PULLUP.
 *
 * The internal pullup resistors will be enabled if mode is INPUT_PULLUP
 * and disabled if the mode is INPUT.
 */
static inline __attribute__((always_inline))
void fastPinMode(uint8_t pin, uint8_t mode)
{
	fastDdrWrite(pin, mode == OUTPUT);
	if (mode != OUTPUT) {
		fastDigitalWrite(pin, mode == INPUT_PULLUP);
	}
}
#else  // defined(__AVR__)
#if defined(CORE_TEENSY)
//------------------------------------------------------------------------------
/** read pin value
 * @param[in] pin Arduino pin number
 * @return value read
 */
static inline __attribute__((always_inline))
bool fastDigitalRead(uint8_t pin)
{
	return *portInputRegister(pin);
}
//------------------------------------------------------------------------------
/** Set pin value
 * @param[in] pin Arduino pin number
 * @param[in] level value to write
 */
static inline __attribute__((always_inline))
void fastDigitalWrite(uint8_t pin, bool value)
{
	if (value) {
		*portSetRegister(pin) = 1;
	} else {
		*portClearRegister(pin) = 1;
	}
}
#elif defined(__SAM3X8E__) || defined(__SAM3X8H__)
//------------------------------------------------------------------------------
/** read pin value
 * @param[in] pin Arduino pin number
 * @return value read
 */
static inline __attribute__((always_inline))
bool fastDigitalRead(uint8_t pin)
{
	return g_APinDescription[pin].pPort->PIO_PDSR & g_APinDescription[pin].ulPin;
}
//------------------------------------------------------------------------------
/** Set pin value
 * @param[in] pin Arduino pin number
 * @param[in] level value to write
 */
static inline __attribute__((always_inline))
void fastDigitalWrite(uint8_t pin, bool value)
{
	if (value) {
		g_APinDescription[pin].pPort->PIO_SODR = g_APinDescription[pin].ulPin;
	} else {
		g_APinDescription[pin].pPort->PIO_CODR = g_APinDescription[pin].ulPin;
	}
}
#elif defined(ESP8266)
//------------------------------------------------------------------------------
/** Set pin value
 * @param[in] pin Arduino pin number
 * @param[in] val value to write
 */
static inline __attribute__((always_inline))
void fastDigitalWrite(uint8_t pin, uint8_t val)
{
	if (pin < 16) {
		if (val) {
			GPOS = (1 << pin);
		} else {
			GPOC = (1 << pin);
		}
	} else if (pin == 16) {
		if (val) {
			GP16O |= 1;
		} else {
			GP16O &= ~1;
		}
	}
}
//------------------------------------------------------------------------------
/** Read pin value
 * @param[in] pin Arduino pin number
 * @return value read
 */
static inline __attribute__((always_inline))
bool fastDigitalRead(uint8_t pin)
{
	if (pin < 16) {
		return GPIP(pin);
	} else if (pin == 16) {
		return GP16I & 0x01;
	}
	return 0;
}
#else  // CORE_TEENSY
//------------------------------------------------------------------------------
inline void fastDigitalWrite(uint8_t pin, bool value)
{
	digitalWrite(pin, value);
}
//------------------------------------------------------------------------------
inline bool fastDigitalRead(uint8_t pin)
{
	return digitalRead(pin);
}
#endif  // CORE_TEENSY
//------------------------------------------------------------------------------
inline void fastDigitalToggle(uint8_t pin)
{
	fastDigitalWrite(pin, !fastDigitalRead(pin));
}
//------------------------------------------------------------------------------
inline void fastPinMode(uint8_t pin, uint8_t mode)
{
	pinMode(pin, mode);
}
#endif  // __AVR__
//------------------------------------------------------------------------------
/** set pin configuration
 * @param[in] pin Arduino pin number
 * @param[in] mode mode INPUT or OUTPUT.
 * @param[in] level If mode is output, set level high/low.
 *                  If mode is input, enable or disable the pin's 20K pullup.
 */
#define fastPinConfig(pin, mode, level)\
	{fastPinMode(pin, mode); fastDigitalWrite(pin, level);}
//==============================================================================
/**
 * @class DigitalPin
 * @brief Fast digital port I/O
 */
template<uint8_t PinNumber>
class DigitalPin
{
public:
	//----------------------------------------------------------------------------
	/** Constructor */
	DigitalPin() {}
	//----------------------------------------------------------------------------
	/** Asignment operator.
	 * @param[in] value If true set the pin's level high else set the
	 *  pin's level low.
	 *
	 * @return This DigitalPin instance.
	 */
	inline DigitalPin & operator = (bool value) __attribute__((always_inline))
	{
		write(value);
		return *this;
	}
	//----------------------------------------------------------------------------
	/** Parenthesis operator.
	 * @return Pin's level
	 */
	inline operator bool () const __attribute__((always_inline))
	{
		return read();
	}
	//----------------------------------------------------------------------------
	/** Set pin configuration.
	 * @param[in] mode: INPUT or OUTPUT.
	 * @param[in] level If mode is OUTPUT, set level high/low.
	 *                  If mode is INPUT, enable or disable the pin's 20K pullup.
	 */
	inline __attribute__((always_inline))
	void config(uint8_t mode, bool level)
	{
		fastPinConfig(PinNumber, mode, level);
	}
	//----------------------------------------------------------------------------
	/**
	 * Set pin level high if output mode or enable 20K pullup if input mode.
	 */
	inline __attribute__((always_inline))
	void high()
	{
		write(true);
	}
	//----------------------------------------------------------------------------
	/**
	 * Set pin level low if output mode or disable 20K pullup if input mode.
	 */
	inline __attribute__((always_inline))
	void low()
	{
		write(false);
	}
	//----------------------------------------------------------------------------
	/**
	 * Set pin mode.
	 * @param[in] mode: INPUT, OUTPUT, or INPUT_PULLUP.
	 *
	 * The internal pullup resistors will be enabled if mode is INPUT_PULLUP
	 * and disabled if the mode is INPUT.
	 */
	inline __attribute__((always_inline))
	void mode(uint8_t mode)
	{
		fastPinMode(PinNumber, mode);
	}
	//----------------------------------------------------------------------------
	/** @return Pin's level. */
	inline __attribute__((always_inline))
	bool read() const
	{
		return fastDigitalRead(PinNumber);
	}
	//----------------------------------------------------------------------------
	/** Toggle a pin.
	 *
	 * If the pin is in output mode toggle the pin's level.
	 * If the pin is in input mode toggle the state of the 20K pullup.
	 */
	inline __attribute__((always_inline))
	void toggle()
	{
		fastDigitalToggle(PinNumber);
	}
	//----------------------------------------------------------------------------
	/** Write the pin's level.
	 * @param[in] value If true set the pin's level high else set the
	 *  pin's level low.
	 */
	inline __attribute__((always_inline))
	void write(bool value)
	{
		fastDigitalWrite(PinNumber, value);
	}
};
#endif  // DigitalPin_h
/** @} */