PlatformIO package of the Teensy core framework compatible with GCC 10 & C++20
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.

271 lines
10KB

  1. #ifndef __INC_FASTPIN_H
  2. #define __INC_FASTPIN_H
  3. #include "FastLED.h"
  4. #include "led_sysdefs.h"
  5. #include <stddef.h>
  6. #pragma GCC diagnostic push
  7. #pragma GCC diagnostic ignored "-Wignored-qualifiers"
  8. ///@file fastpin.h
  9. /// Class base definitions for defining fast pin access
  10. FASTLED_NAMESPACE_BEGIN
  11. #define NO_PIN 255
  12. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  13. //
  14. // Pin access class - needs to tune for various platforms (naive fallback solution?)
  15. //
  16. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  17. class Selectable {
  18. public:
  19. virtual void select() = 0;
  20. virtual void release() = 0;
  21. virtual bool isSelected() = 0;
  22. };
  23. #if !defined(FASTLED_NO_PINMAP)
  24. class Pin : public Selectable {
  25. volatile RwReg *mPort;
  26. volatile RoReg *mInPort;
  27. RwReg mPinMask;
  28. uint8_t mPin;
  29. void _init() {
  30. mPinMask = digitalPinToBitMask(mPin);
  31. mPort = (volatile RwReg*)portOutputRegister(digitalPinToPort(mPin));
  32. mInPort = (volatile RoReg*)portInputRegister(digitalPinToPort(mPin));
  33. }
  34. public:
  35. Pin(int pin) : mPin(pin) { _init(); }
  36. typedef volatile RwReg * port_ptr_t;
  37. typedef RwReg port_t;
  38. inline void setOutput() { pinMode(mPin, OUTPUT); }
  39. inline void setInput() { pinMode(mPin, INPUT); }
  40. inline void hi() __attribute__ ((always_inline)) { *mPort |= mPinMask; }
  41. inline void lo() __attribute__ ((always_inline)) { *mPort &= ~mPinMask; }
  42. inline void strobe() __attribute__ ((always_inline)) { toggle(); toggle(); }
  43. inline void toggle() __attribute__ ((always_inline)) { *mInPort = mPinMask; }
  44. inline void hi(register port_ptr_t port) __attribute__ ((always_inline)) { *port |= mPinMask; }
  45. inline void lo(register port_ptr_t port) __attribute__ ((always_inline)) { *port &= ~mPinMask; }
  46. inline void set(register port_t val) __attribute__ ((always_inline)) { *mPort = val; }
  47. inline void fastset(register port_ptr_t port, register port_t val) __attribute__ ((always_inline)) { *port = val; }
  48. port_t hival() __attribute__ ((always_inline)) { return *mPort | mPinMask; }
  49. port_t loval() __attribute__ ((always_inline)) { return *mPort & ~mPinMask; }
  50. port_ptr_t port() __attribute__ ((always_inline)) { return mPort; }
  51. port_t mask() __attribute__ ((always_inline)) { return mPinMask; }
  52. virtual void select() { hi(); }
  53. virtual void release() { lo(); }
  54. virtual bool isSelected() { return (*mPort & mPinMask) == mPinMask; }
  55. };
  56. class OutputPin : public Pin {
  57. public:
  58. OutputPin(int pin) : Pin(pin) { setOutput(); }
  59. };
  60. class InputPin : public Pin {
  61. public:
  62. InputPin(int pin) : Pin(pin) { setInput(); }
  63. };
  64. #else
  65. // This is the empty code version of the raw pin class, method bodies should be filled in to Do The Right Thing[tm] when making this
  66. // available on a new platform
  67. class Pin : public Selectable {
  68. volatile RwReg *mPort;
  69. volatile RoReg *mInPort;
  70. RwReg mPinMask;
  71. uint8_t mPin;
  72. void _init() {
  73. // TODO: fill in init on a new platform
  74. mPinMask = 0;
  75. mPort = NULL;
  76. mInPort = NULL;
  77. }
  78. public:
  79. Pin(int pin) : mPin(pin) { _init(); }
  80. void setPin(int pin) { mPin = pin; _init(); }
  81. typedef volatile RwReg * port_ptr_t;
  82. typedef RwReg port_t;
  83. inline void setOutput() { /* TODO: Set pin output */ }
  84. inline void setInput() { /* TODO: Set pin input */ }
  85. inline void hi() __attribute__ ((always_inline)) { *mPort |= mPinMask; }
  86. inline void lo() __attribute__ ((always_inline)) { *mPort &= ~mPinMask; }
  87. inline void strobe() __attribute__ ((always_inline)) { toggle(); toggle(); }
  88. inline void toggle() __attribute__ ((always_inline)) { *mInPort = mPinMask; }
  89. inline void hi(register port_ptr_t port) __attribute__ ((always_inline)) { *port |= mPinMask; }
  90. inline void lo(register port_ptr_t port) __attribute__ ((always_inline)) { *port &= ~mPinMask; }
  91. inline void set(register port_t val) __attribute__ ((always_inline)) { *mPort = val; }
  92. inline void fastset(register port_ptr_t port, register port_t val) __attribute__ ((always_inline)) { *port = val; }
  93. port_t hival() __attribute__ ((always_inline)) { return *mPort | mPinMask; }
  94. port_t loval() __attribute__ ((always_inline)) { return *mPort & ~mPinMask; }
  95. port_ptr_t port() __attribute__ ((always_inline)) { return mPort; }
  96. port_t mask() __attribute__ ((always_inline)) { return mPinMask; }
  97. virtual void select() { hi(); }
  98. virtual void release() { lo(); }
  99. virtual bool isSelected() { return (*mPort & mPinMask) == mPinMask; }
  100. };
  101. class OutputPin : public Pin {
  102. public:
  103. OutputPin(int pin) : Pin(pin) { setOutput(); }
  104. };
  105. class InputPin : public Pin {
  106. public:
  107. InputPin(int pin) : Pin(pin) { setInput(); }
  108. };
  109. #endif
  110. /// The simplest level of Pin class. This relies on runtime functions durinig initialization to get the port/pin mask for the pin. Most
  111. /// of the accesses involve references to these static globals that get set up. This won't be the fastest set of pin operations, but it
  112. /// will provide pin level access on pretty much all arduino environments. In addition, it includes some methods to help optimize access in
  113. /// various ways. Namely, the versions of hi, lo, and fastset that take the port register as a passed in register variable (saving a global
  114. /// dereference), since these functions are aggressively inlined, that can help collapse out a lot of extraneous memory loads/dereferences.
  115. ///
  116. /// In addition, if, while writing a bunch of data to a pin, you know no other pins will be getting written to, you can get/cache a value of
  117. /// the pin's port register and use that to do a full set to the register. This results in one being able to simply do a store to the register,
  118. /// vs. the load, and/or, and store that would be done normally.
  119. ///
  120. /// There are platform specific instantiations of this class that provide direct i/o register access to pins for much higher speed pin twiddling.
  121. ///
  122. /// Note that these classes are all static functions. So the proper usage is Pin<13>::hi(); or such. Instantiating objects is not recommended,
  123. /// as passing Pin objects around will likely -not- have the effect you're expecting.
  124. #ifdef FASTLED_FORCE_SOFTWARE_PINS
  125. template<uint8_t PIN> class FastPin {
  126. static RwReg sPinMask;
  127. static volatile RwReg *sPort;
  128. static volatile RoReg *sInPort;
  129. static void _init() {
  130. #if !defined(FASTLED_NO_PINMAP)
  131. sPinMask = digitalPinToBitMask(PIN);
  132. sPort = portOutputRegister(digitalPinToPort(PIN));
  133. sInPort = portInputRegister(digitalPinToPort(PIN));
  134. #endif
  135. }
  136. public:
  137. typedef volatile RwReg * port_ptr_t;
  138. typedef RwReg port_t;
  139. inline static void setOutput() { _init(); pinMode(PIN, OUTPUT); }
  140. inline static void setInput() { _init(); pinMode(PIN, INPUT); }
  141. inline static void hi() __attribute__ ((always_inline)) { *sPort |= sPinMask; }
  142. inline static void lo() __attribute__ ((always_inline)) { *sPort &= ~sPinMask; }
  143. inline static void strobe() __attribute__ ((always_inline)) { toggle(); toggle(); }
  144. inline static void toggle() __attribute__ ((always_inline)) { *sInPort = sPinMask; }
  145. inline static void hi(register port_ptr_t port) __attribute__ ((always_inline)) { *port |= sPinMask; }
  146. inline static void lo(register port_ptr_t port) __attribute__ ((always_inline)) { *port &= ~sPinMask; }
  147. inline static void set(register port_t val) __attribute__ ((always_inline)) { *sPort = val; }
  148. inline static void fastset(register port_ptr_t port, register port_t val) __attribute__ ((always_inline)) { *port = val; }
  149. static port_t hival() __attribute__ ((always_inline)) { return *sPort | sPinMask; }
  150. static port_t loval() __attribute__ ((always_inline)) { return *sPort & ~sPinMask; }
  151. static port_ptr_t port() __attribute__ ((always_inline)) { return sPort; }
  152. static port_t mask() __attribute__ ((always_inline)) { return sPinMask; }
  153. };
  154. template<uint8_t PIN> RwReg FastPin<PIN>::sPinMask;
  155. template<uint8_t PIN> volatile RwReg *FastPin<PIN>::sPort;
  156. template<uint8_t PIN> volatile RoReg *FastPin<PIN>::sInPort;
  157. #else
  158. template<uint8_t PIN> class FastPin {
  159. constexpr static bool validpin() { return false; }
  160. static_assert(validpin(), "Invalid pin specified");
  161. static void _init() {
  162. }
  163. public:
  164. typedef volatile RwReg * port_ptr_t;
  165. typedef RwReg port_t;
  166. inline static void setOutput() { }
  167. inline static void setInput() { }
  168. inline static void hi() __attribute__ ((always_inline)) { }
  169. inline static void lo() __attribute__ ((always_inline)) { }
  170. inline static void strobe() __attribute__ ((always_inline)) { }
  171. inline static void toggle() __attribute__ ((always_inline)) { }
  172. inline static void hi(register port_ptr_t port) __attribute__ ((always_inline)) { }
  173. inline static void lo(register port_ptr_t port) __attribute__ ((always_inline)) { }
  174. inline static void set(register port_t val) __attribute__ ((always_inline)) { }
  175. inline static void fastset(register port_ptr_t port, register port_t val) __attribute__ ((always_inline)) { }
  176. static port_t hival() __attribute__ ((always_inline)) { return 0; }
  177. static port_t loval() __attribute__ ((always_inline)) { return 0;}
  178. static port_ptr_t port() __attribute__ ((always_inline)) { return NULL; }
  179. static port_t mask() __attribute__ ((always_inline)) { return 0; }
  180. };
  181. #endif
  182. template<uint8_t PIN> class FastPinBB : public FastPin<PIN> {};
  183. typedef volatile uint32_t & reg32_t;
  184. typedef volatile uint32_t * ptr_reg32_t;
  185. // Utility templates for tracking down information about pins and ports
  186. template<uint8_t port> struct __FL_PORT_INFO {
  187. static bool hasPort() { return 0; }
  188. static const char *portName() { return "--"; }
  189. static const void *portAddr() { return NULL; }
  190. };
  191. // Give us our instantiations for defined ports - we're going to abuse this later for
  192. // auto discovery of pin/port mappings for new variants. Use _FL_DEFINE_PORT for ports that
  193. // are numeric in nature, e.g. GPIO0, GPIO1. Use _FL_DEFINE_PORT3 for ports that are letters.
  194. // The first parameter will be the letter, the second parameter will be an integer/counter of smoe kind
  195. // (this is because attempts to turn macro parameters into character constants break in some compilers)
  196. #define _FL_DEFINE_PORT(L, BASE) template<> struct __FL_PORT_INFO<L> { static bool hasPort() { return 1; } \
  197. static const char *portName() { return #L; } \
  198. typedef BASE __t_baseType; \
  199. static const void *portAddr() { return (void*)&__t_baseType::r(); } };
  200. #define _FL_DEFINE_PORT3(L, LC, BASE) template<> struct __FL_PORT_INFO<LC> { static bool hasPort() { return 1; } \
  201. static const char *portName() { return #L; } \
  202. typedef BASE __t_baseType; \
  203. static const void *portAddr() { return (void*)&__t_baseType::r(); } };
  204. FASTLED_NAMESPACE_END
  205. #pragma GCC diagnostic pop
  206. #endif // __INC_FASTPIN_H