PlatformIO package of the Teensy core framework compatible with GCC 10 & C++20
Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.

186 lines
6.6KB

  1. #ifndef __INC_CLOCKLESS_APOLLO3_H
  2. #define __INC_CLOCKLESS_APOLLO3_H
  3. FASTLED_NAMESPACE_BEGIN
  4. #if defined(FASTLED_APOLLO3)
  5. // Clockless support for the SparkFun Artemis / Ambiq Micro Apollo3 Blue
  6. // Uses SysTick to govern the pulse timing
  7. //*****************************************************************************
  8. //
  9. // Code taken from Ambiq Micro's am_hal_systick.c
  10. // and converted to inline static for speed
  11. //
  12. //! @brief Get the current count value in the SYSTICK.
  13. //!
  14. //! This function gets the current count value in the systick timer.
  15. //!
  16. //! @return Current count value.
  17. //
  18. //*****************************************************************************
  19. __attribute__ ((always_inline)) inline static uint32_t __am_hal_systick_count() {
  20. return SysTick->VAL;
  21. }
  22. #define FASTLED_HAS_CLOCKLESS 1
  23. template <uint8_t DATA_PIN, int T1, int T2, int T3, EOrder RGB_ORDER = RGB, int XTRA0 = 0, bool FLIP = false, int WAIT_TIME = 50>
  24. class ClocklessController : public CPixelLEDController<RGB_ORDER> {
  25. typedef typename FastPin<DATA_PIN>::port_ptr_t data_ptr_t;
  26. typedef typename FastPin<DATA_PIN>::port_t data_t;
  27. CMinWait<WAIT_TIME> mWait;
  28. public:
  29. virtual void init() {
  30. // Initialize everything
  31. // Configure DATA_PIN for FastGPIO (settings are in fastpin_apollo3.h)
  32. FastPin<DATA_PIN>::setOutput();
  33. FastPin<DATA_PIN>::lo();
  34. // Make sure the system clock is running at the full 48MHz
  35. am_hal_clkgen_control(AM_HAL_CLKGEN_CONTROL_SYSCLK_MAX, 0);
  36. // Make sure interrupts are enabled
  37. //am_hal_interrupt_master_enable();
  38. // Enable SysTick Interrupts in the NVIC
  39. //NVIC_EnableIRQ(SysTick_IRQn);
  40. // SysTick is 24-bit and counts down (not up)
  41. // Stop the SysTick (just in case it is already running).
  42. // This clears the ENABLE bit in the SysTick Control and Status Register (SYST_CSR).
  43. // In Ambiq naming convention, the control register is SysTick->CTRL
  44. am_hal_systick_stop();
  45. // Call SysTick_Config
  46. // This is defined in core_cm4.h
  47. // It loads the specified LOAD value into the SysTick Reload Value Register (SYST_RVR)
  48. // In Ambiq naming convention, the reload register is SysTick->LOAD
  49. // It sets the SysTick interrupt priority
  50. // It clears the SysTick Current Value Register (SYST_CVR)
  51. // In Ambiq naming convention, the current value register is SysTick->VAL
  52. // Finally it sets these bits in the SysTick Control and Status Register (SYST_CSR):
  53. // CLKSOURCE: SysTick uses the processor clock
  54. // TICKINT: When the count reaches zero, the SysTick exception (interrupt) is changed to pending
  55. // ENABLE: Enables the counter
  56. // SysTick_Config returns 0 if successful. 1 indicates a failure (the LOAD value was invalid).
  57. SysTick_Config(0xFFFFFFUL); // The LOAD value needs to be 24-bit
  58. }
  59. virtual uint16_t getMaxRefreshRate() const { return 400; }
  60. protected:
  61. virtual void showPixels(PixelController<RGB_ORDER> & pixels) {
  62. mWait.wait();
  63. if(!showRGBInternal(pixels)) {
  64. sei(); delayMicroseconds(WAIT_TIME); cli();
  65. showRGBInternal(pixels);
  66. }
  67. mWait.mark();
  68. }
  69. template<int BITS> __attribute__ ((always_inline)) inline static void writeBits(register uint32_t & next_mark, register uint8_t & b) {
  70. // SysTick counts down (not up) and is 24-bit
  71. for(register uint32_t i = BITS-1; i > 0; i--) { // We could speed this up by using Bit Banding
  72. while(__am_hal_systick_count() > next_mark) { ; } // Wait for the remainder of this cycle to complete
  73. // Calculate next_mark (the time of the next DATA_PIN transition) by subtracting T1+T2+T3
  74. // SysTick counts down (not up) and is 24-bit
  75. next_mark = (__am_hal_systick_count() - (T1+T2+T3)) & 0xFFFFFFUL;
  76. FastPin<DATA_PIN>::hi();
  77. if(b&0x80) {
  78. // "1 code" = longer pulse width
  79. while((__am_hal_systick_count() - next_mark) > (T3+(3*(F_CPU/24000000)))) { ; }
  80. FastPin<DATA_PIN>::lo();
  81. } else {
  82. // "0 code" = shorter pulse width
  83. while((__am_hal_systick_count() - next_mark) > (T2+T3+(4*(F_CPU/24000000)))) { ; }
  84. FastPin<DATA_PIN>::lo();
  85. }
  86. b <<= 1;
  87. }
  88. while(__am_hal_systick_count() > next_mark) { ; }// Wait for the remainder of this cycle to complete
  89. // Calculate next_mark (the time of the next DATA_PIN transition) by subtracting T1+T2+T3
  90. // SysTick counts down (not up) and is 24-bit
  91. next_mark = (__am_hal_systick_count() - (T1+T2+T3)) & 0xFFFFFFUL;
  92. FastPin<DATA_PIN>::hi();
  93. if(b&0x80) {
  94. // "1 code" = longer pulse width
  95. while((__am_hal_systick_count() - next_mark) > (T3+(2*(F_CPU/24000000)))) { ; }
  96. FastPin<DATA_PIN>::lo();
  97. } else {
  98. // "0 code" = shorter pulse width
  99. while((__am_hal_systick_count() - next_mark) > (T2+T3+(4*(F_CPU/24000000)))) { ; }
  100. FastPin<DATA_PIN>::lo();
  101. }
  102. }
  103. // This method is made static to force making register Y available to use for data on AVR - if the method is non-static, then
  104. // gcc will use register Y for the this pointer.
  105. static uint32_t showRGBInternal(PixelController<RGB_ORDER> pixels) {
  106. // Setup the pixel controller and load/scale the first byte
  107. pixels.preStepFirstByteDithering();
  108. register uint8_t b = pixels.loadAndScale0();
  109. cli();
  110. // Calculate next_mark (the time of the next DATA_PIN transition) by subtracting T1+T2+T3
  111. // SysTick counts down (not up) and is 24-bit
  112. // The subtraction could underflow (wrap round) so let's mask the result to 24 bits
  113. register uint32_t next_mark = (__am_hal_systick_count() - (T1+T2+T3)) & 0xFFFFFFUL;
  114. while(pixels.has(1)) { // Keep going for as long as we have pixels
  115. pixels.stepDithering();
  116. #if (FASTLED_ALLOW_INTERRUPTS == 1)
  117. cli();
  118. // Have we already missed the next_mark?
  119. if(__am_hal_systick_count() < next_mark) {
  120. // If we have exceeded next_mark by an excessive amount, then bail (return 0)
  121. if((next_mark - __am_hal_systick_count()) > ((WAIT_TIME-INTERRUPT_THRESHOLD)*CLKS_PER_US)) { sei(); return 0; }
  122. }
  123. #endif
  124. // Write first byte, read next byte
  125. writeBits<8+XTRA0>(next_mark, b);
  126. b = pixels.loadAndScale1();
  127. // Write second byte, read 3rd byte
  128. writeBits<8+XTRA0>(next_mark, b);
  129. b = pixels.loadAndScale2();
  130. // Write third byte, read 1st byte of next pixel
  131. writeBits<8+XTRA0>(next_mark, b);
  132. b = pixels.advanceAndLoadAndScale0();
  133. #if (FASTLED_ALLOW_INTERRUPTS == 1)
  134. sei();
  135. #endif
  136. }; // end of while(pixels.has(1))
  137. // Unfortunately SysTick relies on an interrupt to reload it once it reaches zero
  138. // and having interrupts disabled for most of the above means the interrupt doesn't get serviced.
  139. // So we had better reload it here instead...
  140. am_hal_systick_load(0xFFFFFFUL);
  141. sei();
  142. return (1);
  143. }
  144. };
  145. #endif
  146. FASTLED_NAMESPACE_END
  147. #endif