Nie możesz wybrać więcej, niż 25 tematów Tematy muszą się zaczynać od litery lub cyfry, mogą zawierać myślniki ('-') i mogą mieć do 35 znaków.

376 lines
12KB

  1. /* Arduino DigitalIO Library
  2. * Copyright (C) 2013 by William Greiman
  3. *
  4. * This file is part of the Arduino DigitalIO Library
  5. *
  6. * This Library is free software: you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation, either version 3 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * This Library is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with the Arduino DigitalIO Library. If not, see
  18. * <http://www.gnu.org/licenses/>.
  19. */
  20. /**
  21. * @file
  22. * @brief Fast Digital Pin functions
  23. *
  24. * @defgroup digitalPin Fast Pin I/O
  25. * @details Fast Digital I/O functions and template class.
  26. * @{
  27. */
  28. #ifndef DigitalPin_h
  29. #define DigitalPin_h
  30. #include "SystemInclude.h"
  31. #if defined(__AVR__)
  32. #include <avr/io.h>
  33. /** GpioPinMap type */
  34. struct GpioPinMap_t {
  35. volatile uint8_t* pin; /**< address of PIN for this pin */
  36. volatile uint8_t* ddr; /**< address of DDR for this pin */
  37. volatile uint8_t* port; /**< address of PORT for this pin */
  38. uint8_t mask; /**< bit mask for this pin */
  39. };
  40. /** Initializer macro. */
  41. #define GPIO_PIN(reg, bit) {&PIN##reg, &DDR##reg, &PORT##reg, 1 << bit}
  42. // Include pin map for current board.
  43. #include "boards/GpioPinMap.h"
  44. //------------------------------------------------------------------------------
  45. /** generate bad pin number error */
  46. void badPinNumber(void)
  47. __attribute__((error("Pin number is too large or not a constant")));
  48. //------------------------------------------------------------------------------
  49. /** Check for valid pin number
  50. * @param[in] pin Number of pin to be checked.
  51. */
  52. static inline __attribute__((always_inline))
  53. void badPinCheck(uint8_t pin) {
  54. if (!__builtin_constant_p(pin) || pin >= NUM_DIGITAL_PINS) {
  55. badPinNumber();
  56. }
  57. }
  58. //------------------------------------------------------------------------------
  59. /** DDR register address
  60. * @param[in] pin Arduino pin number
  61. * @return register address
  62. */
  63. static inline __attribute__((always_inline))
  64. volatile uint8_t* ddrReg(uint8_t pin) {
  65. badPinCheck(pin);
  66. return GpioPinMap[pin].ddr;
  67. }
  68. //------------------------------------------------------------------------------
  69. /** Bit mask for pin
  70. * @param[in] pin Arduino pin number
  71. * @return mask
  72. */
  73. static inline __attribute__((always_inline))
  74. uint8_t pinMask(uint8_t pin) {
  75. badPinCheck(pin);
  76. return GpioPinMap[pin].mask;
  77. }
  78. //------------------------------------------------------------------------------
  79. /** PIN register address
  80. * @param[in] pin Arduino pin number
  81. * @return register address
  82. */
  83. static inline __attribute__((always_inline))
  84. volatile uint8_t* pinReg(uint8_t pin) {
  85. badPinCheck(pin);
  86. return GpioPinMap[pin].pin;
  87. }
  88. //------------------------------------------------------------------------------
  89. /** PORT register address
  90. * @param[in] pin Arduino pin number
  91. * @return register address
  92. */
  93. static inline __attribute__((always_inline))
  94. volatile uint8_t* portReg(uint8_t pin) {
  95. badPinCheck(pin);
  96. return GpioPinMap[pin].port;
  97. }
  98. //------------------------------------------------------------------------------
  99. /** Fast write helper.
  100. * @param[in] address I/O register address
  101. * @param[in] mask bit mask for pin
  102. * @param[in] level value for bit
  103. */
  104. static inline __attribute__((always_inline))
  105. void fastBitWriteSafe(volatile uint8_t* address, uint8_t mask, bool level) {
  106. uint8_t s;
  107. if (address > reinterpret_cast<uint8_t*>(0X3F)) {
  108. s = SREG;
  109. cli();
  110. }
  111. if (level) {
  112. *address |= mask;
  113. } else {
  114. *address &= ~mask;
  115. }
  116. if (address > reinterpret_cast<uint8_t*>(0X3F)) {
  117. SREG = s;
  118. }
  119. }
  120. //------------------------------------------------------------------------------
  121. /** Read pin value.
  122. * @param[in] pin Arduino pin number
  123. * @return value read
  124. */
  125. static inline __attribute__((always_inline))
  126. bool fastDigitalRead(uint8_t pin) {
  127. return *pinReg(pin) & pinMask(pin);
  128. }
  129. //------------------------------------------------------------------------------
  130. /** Toggle a pin.
  131. * @param[in] pin Arduino pin number
  132. *
  133. * If the pin is in output mode toggle the pin level.
  134. * If the pin is in input mode toggle the state of the 20K pullup.
  135. */
  136. static inline __attribute__((always_inline))
  137. void fastDigitalToggle(uint8_t pin) {
  138. if (pinReg(pin) > reinterpret_cast<uint8_t*>(0X3F)) {
  139. // must write bit to high address port
  140. *pinReg(pin) = pinMask(pin);
  141. } else {
  142. // will compile to sbi and PIN register will not be read.
  143. *pinReg(pin) |= pinMask(pin);
  144. }
  145. }
  146. //------------------------------------------------------------------------------
  147. /** Set pin value.
  148. * @param[in] pin Arduino pin number
  149. * @param[in] level value to write
  150. */
  151. static inline __attribute__((always_inline))
  152. void fastDigitalWrite(uint8_t pin, bool level) {
  153. fastBitWriteSafe(portReg(pin), pinMask(pin), level);
  154. }
  155. //------------------------------------------------------------------------------
  156. /** Write the DDR register.
  157. * @param[in] pin Arduino pin number
  158. * @param[in] level value to write
  159. */
  160. static inline __attribute__((always_inline))
  161. void fastDdrWrite(uint8_t pin, bool level) {
  162. fastBitWriteSafe(ddrReg(pin), pinMask(pin), level);
  163. }
  164. //------------------------------------------------------------------------------
  165. /** Set pin mode.
  166. * @param[in] pin Arduino pin number
  167. * @param[in] mode INPUT, OUTPUT, or INPUT_PULLUP.
  168. *
  169. * The internal pullup resistors will be enabled if mode is INPUT_PULLUP
  170. * and disabled if the mode is INPUT.
  171. */
  172. static inline __attribute__((always_inline))
  173. void fastPinMode(uint8_t pin, uint8_t mode) {
  174. fastDdrWrite(pin, mode == OUTPUT);
  175. if (mode != OUTPUT) {
  176. fastDigitalWrite(pin, mode == INPUT_PULLUP);
  177. }
  178. }
  179. #else // defined(__AVR__)
  180. #if defined(CORE_TEENSY)
  181. //------------------------------------------------------------------------------
  182. /** read pin value
  183. * @param[in] pin Arduino pin number
  184. * @return value read
  185. */
  186. static inline __attribute__((always_inline))
  187. bool fastDigitalRead(uint8_t pin) {
  188. return *portInputRegister(pin);
  189. }
  190. //------------------------------------------------------------------------------
  191. /** Set pin value
  192. * @param[in] pin Arduino pin number
  193. * @param[in] level value to write
  194. */
  195. static inline __attribute__((always_inline))
  196. void fastDigitalWrite(uint8_t pin, bool value) {
  197. if (value) {
  198. *portSetRegister(pin) = 1;
  199. } else {
  200. *portClearRegister(pin) = 1;
  201. }
  202. }
  203. #elif defined(__SAM3X8E__) || defined(__SAM3X8H__)
  204. //------------------------------------------------------------------------------
  205. /** read pin value
  206. * @param[in] pin Arduino pin number
  207. * @return value read
  208. */
  209. static inline __attribute__((always_inline))
  210. bool fastDigitalRead(uint8_t pin) {
  211. return g_APinDescription[pin].pPort->PIO_PDSR & g_APinDescription[pin].ulPin;
  212. }
  213. //------------------------------------------------------------------------------
  214. /** Set pin value
  215. * @param[in] pin Arduino pin number
  216. * @param[in] level value to write
  217. */
  218. static inline __attribute__((always_inline))
  219. void fastDigitalWrite(uint8_t pin, bool value) {
  220. if (value) {
  221. g_APinDescription[pin].pPort->PIO_SODR = g_APinDescription[pin].ulPin;
  222. } else {
  223. g_APinDescription[pin].pPort->PIO_CODR = g_APinDescription[pin].ulPin;
  224. }
  225. }
  226. #elif defined(ESP8266)
  227. //------------------------------------------------------------------------------
  228. /** Set pin value
  229. * @param[in] pin Arduino pin number
  230. * @param[in] level value to write
  231. */
  232. static inline __attribute__((always_inline))
  233. void fastDigitalWrite(uint8_t pin, uint8_t val) {
  234. if(pin < 16){
  235. if(val) GPOS = (1 << pin);
  236. else GPOC = (1 << pin);
  237. } else if(pin == 16){
  238. if(val) GP16O |= 1;
  239. else GP16O &= ~1;
  240. }
  241. }
  242. //------------------------------------------------------------------------------
  243. /** read pin value
  244. * @param[in] pin Arduino pin number
  245. * @return value read
  246. */
  247. static inline __attribute__((always_inline))
  248. bool fastDigitalRead(uint8_t pin) {
  249. if(pin < 16){
  250. return GPIP(pin);
  251. } else if(pin == 16){
  252. return GP16I & 0x01;
  253. }
  254. return 0;
  255. }
  256. #else // CORE_TEENSY
  257. //------------------------------------------------------------------------------
  258. inline void fastDigitalWrite(uint8_t pin, bool value) {
  259. digitalWrite(pin, value);
  260. }
  261. //------------------------------------------------------------------------------
  262. inline bool fastDigitalRead(uint8_t pin) {return digitalRead(pin);}
  263. #endif // CORE_TEENSY
  264. //------------------------------------------------------------------------------
  265. inline void fastDigitalToggle(uint8_t pin) {
  266. fastDigitalWrite(pin, !fastDigitalRead(pin));
  267. }
  268. //------------------------------------------------------------------------------
  269. inline void fastPinMode(uint8_t pin, uint8_t mode) {pinMode(pin, mode);}
  270. #endif // __AVR__
  271. //------------------------------------------------------------------------------
  272. /** set pin configuration
  273. * @param[in] pin Arduino pin number
  274. * @param[in] mode mode INPUT or OUTPUT.
  275. * @param[in] level If mode is output, set level high/low.
  276. * If mode is input, enable or disable the pin's 20K pullup.
  277. */
  278. static inline __attribute__((always_inline))
  279. void fastPinConfig(uint8_t pin, uint8_t mode, bool level) {
  280. fastPinMode(pin, mode);
  281. fastDigitalWrite(pin, level);
  282. }
  283. //==============================================================================
  284. /**
  285. * @class DigitalPin
  286. * @brief Fast digital port I/O
  287. */
  288. template<uint8_t PinNumber>
  289. class DigitalPin {
  290. public:
  291. //----------------------------------------------------------------------------
  292. /** Constructor */
  293. DigitalPin() {}
  294. //----------------------------------------------------------------------------
  295. /** Asignment operator.
  296. * @param[in] value If true set the pin's level high else set the
  297. * pin's level low.
  298. *
  299. * @return This DigitalPin instance.
  300. */
  301. inline DigitalPin & operator = (bool value) __attribute__((always_inline)) {
  302. write(value);
  303. return *this;
  304. }
  305. //----------------------------------------------------------------------------
  306. /** Parenthesis operator.
  307. * @return Pin's level
  308. */
  309. inline operator bool () const __attribute__((always_inline)) {
  310. return read();
  311. }
  312. //----------------------------------------------------------------------------
  313. /** Set pin configuration.
  314. * @param[in] mode: INPUT or OUTPUT.
  315. * @param[in] level If mode is OUTPUT, set level high/low.
  316. * If mode is INPUT, enable or disable the pin's 20K pullup.
  317. */
  318. inline __attribute__((always_inline))
  319. void config(uint8_t mode, bool level) {
  320. fastPinConfig(PinNumber, mode, level);
  321. }
  322. //----------------------------------------------------------------------------
  323. /**
  324. * Set pin level high if output mode or enable 20K pullup if input mode.
  325. */
  326. inline __attribute__((always_inline))
  327. void high() {write(true);}
  328. //----------------------------------------------------------------------------
  329. /**
  330. * Set pin level low if output mode or disable 20K pullup if input mode.
  331. */
  332. inline __attribute__((always_inline))
  333. void low() {write(false);}
  334. //----------------------------------------------------------------------------
  335. /**
  336. * Set pin mode.
  337. * @param[in] mode: INPUT, OUTPUT, or INPUT_PULLUP.
  338. *
  339. * The internal pullup resistors will be enabled if mode is INPUT_PULLUP
  340. * and disabled if the mode is INPUT.
  341. */
  342. inline __attribute__((always_inline))
  343. void mode(uint8_t mode) {
  344. fastPinMode(PinNumber, mode);
  345. }
  346. //----------------------------------------------------------------------------
  347. /** @return Pin's level. */
  348. inline __attribute__((always_inline))
  349. bool read() const {
  350. return fastDigitalRead(PinNumber);
  351. }
  352. //----------------------------------------------------------------------------
  353. /** Toggle a pin.
  354. *
  355. * If the pin is in output mode toggle the pin's level.
  356. * If the pin is in input mode toggle the state of the 20K pullup.
  357. */
  358. inline __attribute__((always_inline))
  359. void toggle() {
  360. fastDigitalToggle(PinNumber);
  361. }
  362. //----------------------------------------------------------------------------
  363. /** Write the pin's level.
  364. * @param[in] value If true set the pin's level high else set the
  365. * pin's level low.
  366. */
  367. inline __attribute__((always_inline))
  368. void write(bool value) {
  369. fastDigitalWrite(PinNumber, value);
  370. }
  371. };
  372. #endif // DigitalPin_h
  373. /** @} */