diff options
author | Henry Gabryjelski <henrygab@users.noreply.github.com> | 2019-06-07 07:03:24 +0300 |
---|---|---|
committer | Daniel Garcia <danielgarcia@gmail.com> | 2019-06-07 07:03:24 +0300 |
commit | 3698f8390e1de5628ed6025db133bbc54c14576d (patch) | |
tree | a2bc8f6f1ef1a14e8ae3552cf2808aea2f9ba8eb | |
parent | fe94a0ce3b71f368a81eed5685f6082df80894c3 (diff) |
Enable support for nRF52 chipset. (#802)
LED strings for clockless are temporarily limited to 144 LEDs,
adjustable via led_sysdefs.h #define.
-rw-r--r-- | chipsets.h | 69 | ||||
-rw-r--r-- | fastspi.h | 5 | ||||
-rw-r--r-- | led_sysdefs.h | 2 | ||||
-rw-r--r-- | platforms.cpp | 40 | ||||
-rw-r--r-- | platforms.h | 2 | ||||
-rw-r--r-- | platforms/arm/nrf52/arbiter_nrf52.h | 115 | ||||
-rw-r--r-- | platforms/arm/nrf52/clockless_arm_nrf52.h | 371 | ||||
-rw-r--r-- | platforms/arm/nrf52/fastled_arm_nrf52.h | 11 | ||||
-rw-r--r-- | platforms/arm/nrf52/fastpin_arm_nrf52.h | 328 | ||||
-rw-r--r-- | platforms/arm/nrf52/fastpin_arm_nrf52_variants.h | 579 | ||||
-rw-r--r-- | platforms/arm/nrf52/fastspi_arm_nrf52.h | 341 | ||||
-rw-r--r-- | platforms/arm/nrf52/led_sysdefs_arm_nrf52.h | 58 |
12 files changed, 1897 insertions, 24 deletions
@@ -428,6 +428,16 @@ protected: // // Clockless template instantiations - see clockless.h for how the timing values are used // +// Base template for clockless controllers. These controllers have 3 control points in their cycle for each bit. +// At T=0 : the line is raised hi to start a bit +// At T=T1 : the line is dropped low to transmit a zero bit +// At T=T1+T2 : the line is dropped low to transmit a one bit +// At T=T1+T2+T3 : the cycle is concluded (next bit can be sent) +// +// The units used for T1, T2, and T3 is nanoseconds. +// For 8MHz/16MHz/24MHz frequencies, these values are also guaranteed +// to be integral multiples of an 8MHz clock (125ns increments). +// ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// #ifdef FASTLED_HAS_CLOCKLESS @@ -435,10 +445,16 @@ protected: /// Provides timing definitions for the variety of clockless controllers supplied by the library. /// @{ +// Allow clock that clockless controller is based on to have different +// frequency than the CPU. +#if !defined(CLOCKLESS_FREQUENCY) + #define CLOCKLESS_FREQUENCY F_CPU +#endif + // We want to force all avr's to use the Trinket controller when running at 8Mhz, because even the 328's at 8Mhz // need the more tightly defined timeframes. -#if (F_CPU == 8000000 || F_CPU == 16000000 || F_CPU == 24000000) // || F_CPU == 48000000 || F_CPU == 96000000) // 125ns/clock -#define FMUL (F_CPU/8000000) +#if (CLOCKLESS_FREQUENCY == 8000000 || CLOCKLESS_FREQUENCY == 16000000 || CLOCKLESS_FREQUENCY == 24000000) // || CLOCKLESS_FREQUENCY == 48000000 || CLOCKLESS_FREQUENCY == 96000000) // 125ns/clock +#define FMUL (CLOCKLESS_FREQUENCY/8000000) // GE8822 template <uint8_t DATA_PIN, EOrder RGB_ORDER = RGB> @@ -493,7 +509,7 @@ template <uint8_t DATA_PIN, EOrder RGB_ORDER = RGB> class TM1803Controller400Khz : public ClocklessController<DATA_PIN, 6 * FMUL, 9 * FMUL, 6 * FMUL, RGB_ORDER> {}; template <uint8_t DATA_PIN, EOrder RGB_ORDER = RGB> -class TM1829Controller800Khz : public ClocklessController<DATA_PIN, 2 * FMUL, 5 * FMUL, 3 * FMUL, RGB_ORDER> {}; +class TM1829Controller800Khz : public ClocklessController<DATA_PIN, 2 * FMUL, 5 * FMUL, 3 * FMUL, RGB_ORDER, 0, true, 500> {}; template <uint8_t DATA_PIN, EOrder RGB_ORDER = RGB> class GW6205Controller400Khz : public ClocklessController<DATA_PIN, 6 * FMUL, 7 * FMUL, 6 * FMUL, RGB_ORDER, 4> {}; @@ -505,82 +521,87 @@ template <uint8_t DATA_PIN, EOrder RGB_ORDER = RGB> class PL9823Controller : public ClocklessController<DATA_PIN, 3 * FMUL, 8 * FMUL, 3 * FMUL, RGB_ORDER> {}; #else + +// Similar to NS() macro, this calculates the number of cycles for +// the clockless chipset (which may differ from CPU cycles) +#define C_NS(_NS) (((_NS * ((CLOCKLESS_FREQUENCY / 1000000L) + 999) / 1000) + // GE8822 - 350ns 660ns 350ns template <uint8_t DATA_PIN, EOrder RGB_ORDER = RGB> -class GE8822Controller800Khz : public ClocklessController<DATA_PIN, NS(350), NS(660), NS(350), RGB_ORDER, 4> {}; +class GE8822Controller800Khz : public ClocklessController<DATA_PIN, C_NS(350), C_NS(660), C_NS(350), RGB_ORDER, 4> {}; // GW6205@400khz - 800ns, 800ns, 800ns template <uint8_t DATA_PIN, EOrder RGB_ORDER = RGB> -class GW6205Controller400Khz : public ClocklessController<DATA_PIN, NS(800), NS(800), NS(800), RGB_ORDER, 4> {}; +class GW6205Controller400Khz : public ClocklessController<DATA_PIN, C_NS(800), C_NS(800), C_NS(800), RGB_ORDER, 4> {}; // GW6205@400khz - 400ns, 400ns, 400ns template <uint8_t DATA_PIN, EOrder RGB_ORDER = RGB> -class GW6205Controller800Khz : public ClocklessController<DATA_PIN, NS(400), NS(400), NS(400), RGB_ORDER, 4> {}; +class GW6205Controller800Khz : public ClocklessController<DATA_PIN, C_NS(400), C_NS(400), C_NS(400), RGB_ORDER, 4> {}; // UCS1903 - 500ns, 1500ns, 500ns template <uint8_t DATA_PIN, EOrder RGB_ORDER = RGB> -class UCS1903Controller400Khz : public ClocklessController<DATA_PIN, NS(500), NS(1500), NS(500), RGB_ORDER> {}; +class UCS1903Controller400Khz : public ClocklessController<DATA_PIN, C_NS(500), C_NS(1500), C_NS(500), RGB_ORDER> {}; // UCS1903B - 400ns, 450ns, 450ns template <uint8_t DATA_PIN, EOrder RGB_ORDER = RGB> -class UCS1903BController800Khz : public ClocklessController<DATA_PIN, NS(400), NS(450), NS(450), RGB_ORDER> {}; +class UCS1903BController800Khz : public ClocklessController<DATA_PIN, C_NS(400), C_NS(450), C_NS(450), RGB_ORDER> {}; // UCS1904 - 400ns, 400ns, 450ns template <uint8_t DATA_PIN, EOrder RGB_ORDER = RGB> -class UCS1904Controller800Khz : public ClocklessController<DATA_PIN, NS(400), NS(400), NS(450), RGB_ORDER> {}; +class UCS1904Controller800Khz : public ClocklessController<DATA_PIN, C_NS(400), C_NS(400), C_NS(450), RGB_ORDER> {}; // UCS2903 - 250ns, 750ns, 250ns template <uint8_t DATA_PIN, EOrder RGB_ORDER = RGB> -class UCS2903Controller : public ClocklessController<DATA_PIN, NS(250), NS(750), NS(250), RGB_ORDER> {}; +class UCS2903Controller : public ClocklessController<DATA_PIN, C_NS(250), C_NS(750), C_NS(250), RGB_ORDER> {}; // TM1809 - 350ns, 350ns, 550ns template <uint8_t DATA_PIN, EOrder RGB_ORDER = RGB> -class TM1809Controller800Khz : public ClocklessController<DATA_PIN, NS(350), NS(350), NS(450), RGB_ORDER> {}; +class TM1809Controller800Khz : public ClocklessController<DATA_PIN, C_NS(350), C_NS(350), C_NS(450), RGB_ORDER> {}; // WS2811 - 320ns, 320ns, 640ns template <uint8_t DATA_PIN, EOrder RGB_ORDER = RGB> -class WS2811Controller800Khz : public ClocklessController<DATA_PIN, NS(320), NS(320), NS(640), RGB_ORDER> {}; +class WS2811Controller800Khz : public ClocklessController<DATA_PIN, C_NS(320), C_NS(320), C_NS(640), RGB_ORDER> {}; // WS2813 - 320ns, 320ns, 640ns template <uint8_t DATA_PIN, EOrder RGB_ORDER = RGB> -class WS2813Controller : public ClocklessController<DATA_PIN, NS(320), NS(320), NS(640), RGB_ORDER> {}; +class WS2813Controller : public ClocklessController<DATA_PIN, C_NS(320), C_NS(320), C_NS(640), RGB_ORDER> {}; // WS2812 - 250ns, 625ns, 375ns template <uint8_t DATA_PIN, EOrder RGB_ORDER = RGB> -class WS2812Controller800Khz : public ClocklessController<DATA_PIN, NS(250), NS(625), NS(375), RGB_ORDER> {}; +class WS2812Controller800Khz : public ClocklessController<DATA_PIN, C_NS(250), C_NS(625), C_NS(375), RGB_ORDER> {}; // WS2811@400khz - 800ns, 800ns, 900ns template <uint8_t DATA_PIN, EOrder RGB_ORDER = RGB> -class WS2811Controller400Khz : public ClocklessController<DATA_PIN, NS(800), NS(800), NS(900), RGB_ORDER> {}; +class WS2811Controller400Khz : public ClocklessController<DATA_PIN, C_NS(800), C_NS(800), C_NS(900), RGB_ORDER> {}; // 750NS, 750NS, 750NS template <uint8_t DATA_PIN, EOrder RGB_ORDER = RGB> -class TM1803Controller400Khz : public ClocklessController<DATA_PIN, NS(700), NS(1100), NS(700), RGB_ORDER> {}; +class TM1803Controller400Khz : public ClocklessController<DATA_PIN, C_NS(700), C_NS(1100), C_NS(700), RGB_ORDER> {}; template <uint8_t DATA_PIN, EOrder RGB_ORDER = RGB> -class TM1829Controller800Khz : public ClocklessController<DATA_PIN, NS(340), NS(340), NS(550), RGB_ORDER, 0, true, 500> {}; +class TM1829Controller800Khz : public ClocklessController<DATA_PIN, C_NS(340), C_NS(340), C_NS(550), RGB_ORDER, 0, true, 500> {}; template <uint8_t DATA_PIN, EOrder RGB_ORDER = RGB> -class TM1829Controller1600Khz : public ClocklessController<DATA_PIN, NS(100), NS(300), NS(200), RGB_ORDER, 0, true, 500> {}; +class TM1829Controller1600Khz : public ClocklessController<DATA_PIN, C_NS(100), C_NS(300), C_NS(200), RGB_ORDER, 0, true, 500> {}; template <uint8_t DATA_PIN, EOrder RGB_ORDER = RGB> -class LPD1886Controller1250Khz : public ClocklessController<DATA_PIN, NS(200), NS(400), NS(200), RGB_ORDER, 4> {}; +class LPD1886Controller1250Khz : public ClocklessController<DATA_PIN, C_NS(200), C_NS(400), C_NS(200), RGB_ORDER, 4> {}; template <uint8_t DATA_PIN, EOrder RGB_ORDER = RGB> -class LPD1886Controller1250Khz_8bit : public ClocklessController<DATA_PIN, NS(200), NS(400), NS(200), RGB_ORDER> {}; +class LPD1886Controller1250Khz_8bit : public ClocklessController<DATA_PIN, C_NS(200), C_NS(400), C_NS(200), RGB_ORDER> {}; template <uint8_t DATA_PIN, EOrder RGB_ORDER = RGB> -class SK6822Controller : public ClocklessController<DATA_PIN, NS(375), NS(1000), NS(375), RGB_ORDER> {}; +class SK6822Controller : public ClocklessController<DATA_PIN, C_NS(375), C_NS(1000), C_NS(375), RGB_ORDER> {}; template <uint8_t DATA_PIN, EOrder RGB_ORDER = RGB> -class SK6812Controller : public ClocklessController<DATA_PIN, NS(300), NS(300), NS(600), RGB_ORDER> {}; +class SK6812Controller : public ClocklessController<DATA_PIN, C_NS(300), C_NS(300), C_NS(600), RGB_ORDER> {}; template <uint8_t DATA_PIN, EOrder RGB_ORDER = RGB> -class SM16703Controller : public ClocklessController<DATA_PIN, NS(300), NS(600), NS(300), RGB_ORDER> {}; +class SM16703Controller : public ClocklessController<DATA_PIN, C_NS(300), C_NS(600), C_NS(300), RGB_ORDER> {}; template <uint8_t DATA_PIN, EOrder RGB_ORDER = RGB> -class PL9823Controller : public ClocklessController<DATA_PIN, NS(350), NS(1010), NS(350), RGB_ORDER> {}; +class PL9823Controller : public ClocklessController<DATA_PIN, C_NS(350), C_NS(1010), C_NS(350), RGB_ORDER> {}; #endif ///@} @@ -40,6 +40,11 @@ template<uint8_t _DATA_PIN, uint8_t _CLOCK_PIN, uint8_t _SPI_CLOCK_DIVIDER> class SPIOutput : public NRF51SPIOutput<_DATA_PIN, _CLOCK_PIN, _SPI_CLOCK_DIVIDER> {}; #endif +#if defined(NRF52_SERIES) && defined(FASTLED_ALL_PINS_HARDWARE_SPI) +template<uint8_t _DATA_PIN, uint8_t _CLOCK_PIN, uint8_t _SPI_CLOCK_DIVIDER> +class SPIOutput : public NRF52SPIOutput<_DATA_PIN, _CLOCK_PIN, _SPI_CLOCK_DIVIDER> {}; +#endif + #if defined(SPI_DATA) && defined(SPI_CLOCK) #if defined(FASTLED_TEENSY3) && defined(ARM_HARDWARE_SPI) diff --git a/led_sysdefs.h b/led_sysdefs.h index ea8c14f4..7abcd15e 100644 --- a/led_sysdefs.h +++ b/led_sysdefs.h @@ -7,6 +7,8 @@ #if defined(NRF51) || defined(__RFduino__) || defined (__Simblee__) #include "platforms/arm/nrf51/led_sysdefs_arm_nrf51.h" +#elif defined(NRF52_SERIES) +#include "platforms/arm/nrf52/led_sysdefs_arm_nrf52.h" #elif defined(__MK20DX128__) || defined(__MK20DX256__) // Include k20/T3 headers #include "platforms/arm/k20/led_sysdefs_arm_k20.h" diff --git a/platforms.cpp b/platforms.cpp new file mode 100644 index 00000000..47a00883 --- /dev/null +++ b/platforms.cpp @@ -0,0 +1,40 @@ +#define FASTLED_INTERNAL + + +// Interrupt handlers cannot be defined in the header. +// They must be defined as C functions, or they won't +// be found (due to name mangling), and thus won't +// override any default weak definition. +#if defined(NRF52_SERIES) + + #include "platforms/arm/nrf52/led_sysdefs_arm_nrf52.h" + #include "platforms/arm/nrf52/arbiter_nrf52.h" + + uint32_t isrCount; + + #ifdef __cplusplus + extern "C" { + #endif + // NOTE: Update platforms.cpp in root of FastLED library if this changes + #if defined(FASTLED_NRF52_ENABLE_PWM_INSTANCE0) + void PWM0_IRQHandler(void) { isrCount++; PWM_Arbiter<0>::isr_handler(); } + #endif + #if defined(FASTLED_NRF52_ENABLE_PWM_INSTANCE1) + void PWM1_IRQHandler(void) { isrCount++; PWM_Arbiter<1>::isr_handler(); } + #endif + #if defined(FASTLED_NRF52_ENABLE_PWM_INSTANCE2) + void PWM2_IRQHandler(void) { isrCount++; PWM_Arbiter<2>::isr_handler(); } + #endif + #if defined(FASTLED_NRF52_ENABLE_PWM_INSTANCE3) + void PWM3_IRQHandler(void) { isrCount++; PWM_Arbiter<3>::isr_handler(); } + #endif + #ifdef __cplusplus + } + #endif + +#endif // defined(NRF52_SERIES) + + + +// FASTLED_NAMESPACE_BEGIN +// FASTLED_NAMESPACE_END diff --git a/platforms.h b/platforms.h index 625791bc..82d7d993 100644 --- a/platforms.h +++ b/platforms.h @@ -7,6 +7,8 @@ #if defined(NRF51) #include "platforms/arm/nrf51/fastled_arm_nrf51.h" +#elif defined(NRF52_SERIES) +#include "platforms/arm/nrf52/fastled_arm_nrf52.h" #elif defined(__MK20DX128__) || defined(__MK20DX256__) // Include k20/T3 headers #include "platforms/arm/k20/fastled_arm_k20.h" diff --git a/platforms/arm/nrf52/arbiter_nrf52.h b/platforms/arm/nrf52/arbiter_nrf52.h new file mode 100644 index 00000000..5a6aa92a --- /dev/null +++ b/platforms/arm/nrf52/arbiter_nrf52.h @@ -0,0 +1,115 @@ +#ifndef __INC_ARBITER_NRF52 +#define __INC_ARBITER_NRF52 + +#if defined(NRF52_SERIES) + +#include "led_sysdefs_arm_nrf52.h" + +//FASTLED_NAMESPACE_BEGIN + +typedef void (*FASTLED_NRF52_PWM_INTERRUPT_HANDLER)(); + +// a trick learned from other embedded projects .. +// use the enum as an index to a statically-allocated array +// to store unique information for that instance. +// also provides a count of how many instances were enabled. +// +// See led_sysdefs_arm_nrf52.h for selection.... +// +typedef enum _FASTLED_NRF52_ENABLED_PWM_INSTANCE { +#if defined(FASTLED_NRF52_ENABLE_PWM_INSTANCE0) + FASTLED_NRF52_PWM0_INSTANCE_IDX, +#endif +#if defined(FASTLED_NRF52_ENABLE_PWM_INSTANCE1) + FASTLED_NRF52_PWM1_INSTANCE_IDX, +#endif +#if defined(FASTLED_NRF52_ENABLE_PWM_INSTANCE2) + FASTLED_NRF52_PWM2_INSTANCE_IDX, +#endif +#if defined(FASTLED_NRF52_ENABLE_PWM_INSTANCE3) + FASTLED_NRF52_PWM3_INSTANCE_IDX, +#endif + FASTLED_NRF52_PWM_INSTANCE_COUNT +} FASTLED_NRF52_ENABLED_PWM_INSTANCES; + +static_assert(FASTLED_NRF52_PWM_INSTANCE_COUNT > 0, "Instance count must be greater than zero -- define FASTLED_NRF52_ENABLE_PWM_INSTNACE[n] (replace `[n]` with digit)"); + +template <uint32_t _PWM_ID> +class PWM_Arbiter { + +private: + static_assert(_PWM_ID < 32, "PWM_ID over 31 breaks current arbitration bitmask"); + //const uint32_t _ACQUIRE_MASK = (1u << _PWM_ID) ; + //const uint32_t _CLEAR_MASK = ~((uint32_t)(1u << _PWM_ID)); + static uint32_t s_PwmInUse; + static NRF_PWM_Type * const s_PWM; + static IRQn_Type const s_PWM_IRQ; + static FASTLED_NRF52_PWM_INTERRUPT_HANDLER volatile s_Isr; + +public: + static void isr_handler() { + return s_Isr(); + } + FASTLED_NRF52_INLINE_ATTRIBUTE static bool isAcquired() { + return (0u != (s_PwmInUse & 1u)); // _ACQUIRE_MASK + } + FASTLED_NRF52_INLINE_ATTRIBUTE static void acquire(FASTLED_NRF52_PWM_INTERRUPT_HANDLER isr) { + while (!tryAcquire(isr)); + } + FASTLED_NRF52_INLINE_ATTRIBUTE static bool tryAcquire(FASTLED_NRF52_PWM_INTERRUPT_HANDLER isr) { + uint32_t oldValue = __sync_fetch_and_or(&s_PwmInUse, 1u); // _ACQUIRE_MASK + if (0u == (oldValue & 1u)) { // _ACQUIRE_MASK + s_Isr = isr; + return true; + } + return false; + } + FASTLED_NRF52_INLINE_ATTRIBUTE static void releaseFromIsr() { + uint32_t oldValue = __sync_fetch_and_and(&s_PwmInUse, ~1u); // _CLEAR_MASK + if (0u == (oldValue & 1u)) { // _ACQUIRE_MASK + // TODO: This should never be true... indicates was not held. + // Assert here? + (void)oldValue; + } + return; + } + FASTLED_NRF52_INLINE_ATTRIBUTE static NRF_PWM_Type * getPWM() { + return s_PWM; + } + FASTLED_NRF52_INLINE_ATTRIBUTE static IRQn_Type getIRQn() { return s_PWM_IRQ; } +}; +template <uint32_t _PWM_ID> NRF_PWM_Type * const PWM_Arbiter<_PWM_ID>::s_PWM = + #if defined(FASTLED_NRF52_ENABLE_PWM_INSTANCE0) + (_PWM_ID == 0 ? NRF_PWM0 : + #endif + #if defined(FASTLED_NRF52_ENABLE_PWM_INSTANCE1) + (_PWM_ID == 1 ? NRF_PWM1 : + #endif + #if defined(FASTLED_NRF52_ENABLE_PWM_INSTANCE2) + (_PWM_ID == 2 ? NRF_PWM2 : + #endif + #if defined(FASTLED_NRF52_ENABLE_PWM_INSTANCE3) + (_PWM_ID == 3 ? NRF_PWM3 : + #endif + (NRF_PWM_Type*)-1 + #if defined(FASTLED_NRF52_ENABLE_PWM_INSTANCE0) + ) + #endif + #if defined(FASTLED_NRF52_ENABLE_PWM_INSTANCE1) + ) + #endif + #if defined(FASTLED_NRF52_ENABLE_PWM_INSTANCE2) + ) + #endif + #if defined(FASTLED_NRF52_ENABLE_PWM_INSTANCE3) + ) + #endif + ; +template <uint32_t _PWM_ID> IRQn_Type const PWM_Arbiter<_PWM_ID>::s_PWM_IRQ = ((IRQn_Type)((uint8_t)((uint32_t)(s_PWM) >> 12))); +template <uint32_t _PWM_ID> uint32_t PWM_Arbiter<_PWM_ID>::s_PwmInUse = 0; +template <uint32_t _PWM_ID> FASTLED_NRF52_PWM_INTERRUPT_HANDLER volatile PWM_Arbiter<_PWM_ID>::s_Isr = NULL; + +//FASTLED_NAMESPACE_END + +#endif // NRF52_SERIES +#endif // __INC_ARBITER_NRF52
\ No newline at end of file diff --git a/platforms/arm/nrf52/clockless_arm_nrf52.h b/platforms/arm/nrf52/clockless_arm_nrf52.h new file mode 100644 index 00000000..d8a5da98 --- /dev/null +++ b/platforms/arm/nrf52/clockless_arm_nrf52.h @@ -0,0 +1,371 @@ +#ifndef __INC_CLOCKLESS_ARM_NRF52 +#define __INC_CLOCKLESS_ARM_NRF52 + +#if defined(NRF52_SERIES) + + +//FASTLED_NAMESPACE_BEGIN + +#define FASTLED_HAS_CLOCKLESS 1 +#define FASTLED_NRF52_MAXIMUM_PIXELS_PER_STRING 144 // TODO: Figure out how to safely let this be calller-defined.... + +// nRF52810 has a single PWM peripheral (PWM0) +// nRF52832 has three PWM peripherals (PWM0, PWM1, PWM2) +// nRF52840 has four PWM peripherals (PWM0, PWM1, PWM2, PWM3) +// NOTE: Update platforms.cpp in root of FastLED library if this changes +#define FASTLED_NRF52_PWM_ID 0 + + +extern uint32_t isrCount; + + +template <uint8_t _DATA_PIN, int _T1, int _T2, int _T3, EOrder _RGB_ORDER = RGB, int _XTRA0 = 0, bool _FLIP = false, int _WAIT_TIME_MICROSECONDS = 10> +class ClocklessController : public CPixelLEDController<_RGB_ORDER> { + static_assert(FASTLED_NRF52_MAXIMUM_PIXELS_PER_STRING > 0, "Maximum string length must be positive value (FASTLED_NRF52_MAXIMUM_PIXELS_PER_STRING)"); + static_assert(_T1 > 0 , "negative values are not allowed"); + static_assert(_T2 > 0 , "negative values are not allowed"); + static_assert(_T3 > 0 , "negative values are not allowed"); + static_assert(_T1 < (0x8000u-2u), "_T1 must fit in 15 bits"); + static_assert(_T2 < (0x8000u-2u), "_T2 must fit in 15 bits"); + static_assert(_T3 < (0x8000u-2u), "_T3 must fit in 15 bits"); + static_assert(_T1 < (0x8000u-2u), "_T0H must fit in 15 bits"); + static_assert(_T1+_T2 < (0x8000u-2u), "_T1H must fit in 15 bits"); + static_assert(_T1+_T2+_T3 < (0x8000u-2u), "_TOP must fit in 15 bits"); + static_assert(_T1+_T2+_T3 <= PWM_COUNTERTOP_COUNTERTOP_Msk, "_TOP too large for peripheral"); + +private: + static const bool _INITIALIZE_PIN_HIGH = (_FLIP ? 1 : 0); + static const uint16_t _POLARITY_BIT = (_FLIP ? 0 : 0x8000); + + static const uint8_t _BITS_PER_PIXEL = (8 + _XTRA0) * 3; // NOTE: 3 means RGB only... + static const uint16_t _PWM_BUFFER_COUNT = (_BITS_PER_PIXEL * FASTLED_NRF52_MAXIMUM_PIXELS_PER_STRING); + static const uint8_t _T0H = ((uint16_t)(_T1 )); + static const uint8_t _T1H = ((uint16_t)(_T1+_T2 )); + static const uint8_t _TOP = ((uint16_t)(_T1+_T2+_T3)); + + // may as well be static, as can only attach one LED string per _DATA_PIN.... + static uint16_t s_SequenceBuffer[_PWM_BUFFER_COUNT]; + static uint16_t s_SequenceBufferValidElements; + static uint32_t s_SequenceBufferInUse; + static CMinWait<_WAIT_TIME_MICROSECONDS> mWait; // ensure data has time to latch + + FASTLED_NRF52_INLINE_ATTRIBUTE static void startPwmPlayback_InitializePinState() { + FastPin<_DATA_PIN>::setOutput(); + if (_INITIALIZE_PIN_HIGH) { + FastPin<_DATA_PIN>::hi(); + } else { + FastPin<_DATA_PIN>::lo(); + } + } + FASTLED_NRF52_INLINE_ATTRIBUTE static void startPwmPlayback_InitializePwmInstance(NRF_PWM_Type * pwm) { + + // Pins must be set before enabling the peripheral + pwm->PSEL.OUT[0] = FastPin<_DATA_PIN>::nrf_pin(); + pwm->PSEL.OUT[1] = NRF_PWM_PIN_NOT_CONNECTED; + pwm->PSEL.OUT[2] = NRF_PWM_PIN_NOT_CONNECTED; + pwm->PSEL.OUT[3] = NRF_PWM_PIN_NOT_CONNECTED; + nrf_pwm_enable(pwm); + nrf_pwm_configure(pwm, NRF_PWM_CLK_16MHz, NRF_PWM_MODE_UP, _TOP); + nrf_pwm_decoder_set(pwm, NRF_PWM_LOAD_COMMON, NRF_PWM_STEP_AUTO); + + // clear any prior shorts / interrupt enable bits + nrf_pwm_shorts_set(pwm, 0); + nrf_pwm_int_set(pwm, 0); + // clear all prior events + nrf_pwm_event_clear(pwm, NRF_PWM_EVENT_STOPPED); + nrf_pwm_event_clear(pwm, NRF_PWM_EVENT_SEQSTARTED0); + nrf_pwm_event_clear(pwm, NRF_PWM_EVENT_SEQSTARTED1); + nrf_pwm_event_clear(pwm, NRF_PWM_EVENT_SEQEND0); + nrf_pwm_event_clear(pwm, NRF_PWM_EVENT_SEQEND1); + nrf_pwm_event_clear(pwm, NRF_PWM_EVENT_PWMPERIODEND); + nrf_pwm_event_clear(pwm, NRF_PWM_EVENT_LOOPSDONE); + } + FASTLED_NRF52_INLINE_ATTRIBUTE static void startPwmPlayback_ConfigurePwmSequence(NRF_PWM_Type * pwm) { + // config is easy, using SEQ0, no loops... + nrf_pwm_sequence_t sequenceConfig; + sequenceConfig.values.p_common = &(s_SequenceBuffer[0]); + sequenceConfig.length = s_SequenceBufferValidElements; + sequenceConfig.repeats = 0; // send the data once, and only once + sequenceConfig.end_delay = 0; // no extra delay at the end of SEQ[0] / SEQ[1] + nrf_pwm_sequence_set(pwm, 0, &sequenceConfig); + nrf_pwm_sequence_set(pwm, 1, &sequenceConfig); + nrf_pwm_loop_set(pwm, 0); + + } + FASTLED_NRF52_INLINE_ATTRIBUTE static void startPwmPlayback_EnableInterruptsAndShortcuts(NRF_PWM_Type * pwm) { + IRQn_Type irqn = PWM_Arbiter<FASTLED_NRF52_PWM_ID>::getIRQn(); + // TODO: check API results... + uint32_t result; + + result = sd_nvic_SetPriority(irqn, configMAX_SYSCALL_INTERRUPT_PRIORITY); + (void)result; + result = sd_nvic_EnableIRQ(irqn); + (void)result; + + // shortcuts prevent (up to) 4-cycle delay from interrupt handler to next action + uint32_t shortsToEnable = 0; + shortsToEnable |= NRF_PWM_SHORT_SEQEND0_STOP_MASK; ///< SEQEND[0] --> STOP task. + shortsToEnable |= NRF_PWM_SHORT_SEQEND1_STOP_MASK; ///< SEQEND[1] --> STOP task. + //shortsToEnable |= NRF_PWM_SHORT_LOOPSDONE_SEQSTART0_MASK; ///< LOOPSDONE --> SEQSTART[0] task. + //shortsToEnable |= NRF_PWM_SHORT_LOOPSDONE_SEQSTART1_MASK; ///< LOOPSDONE --> SEQSTART[1] task. + shortsToEnable |= NRF_PWM_SHORT_LOOPSDONE_STOP_MASK; ///< LOOPSDONE --> STOP task. + nrf_pwm_shorts_set(pwm, shortsToEnable); + + // mark which events should cause interrupts... + uint32_t interruptsToEnable = 0; + interruptsToEnable |= NRF_PWM_INT_SEQEND0_MASK; + interruptsToEnable |= NRF_PWM_INT_SEQEND1_MASK; + interruptsToEnable |= NRF_PWM_INT_LOOPSDONE_MASK; + interruptsToEnable |= NRF_PWM_INT_STOPPED_MASK; + nrf_pwm_int_set(pwm, interruptsToEnable); + + } + FASTLED_NRF52_INLINE_ATTRIBUTE static void startPwmPlayback_StartTask(NRF_PWM_Type * pwm) { + nrf_pwm_task_trigger(pwm, NRF_PWM_TASK_SEQSTART0); + } + +public: + static void isr_handler() { + NRF_PWM_Type * pwm = PWM_Arbiter<FASTLED_NRF52_PWM_ID>::getPWM(); + IRQn_Type irqn = PWM_Arbiter<FASTLED_NRF52_PWM_ID>::getIRQn(); + + // Currently, only use SEQUENCE 0, so only event + // of consequence is LOOPSDONE ... + if (nrf_pwm_event_check(pwm,NRF_PWM_EVENT_STOPPED)) { + nrf_pwm_event_clear(pwm,NRF_PWM_EVENT_STOPPED); + + // mark the sequence as no longer in use -- pointer, comparator, exchange value + __sync_fetch_and_and(&s_SequenceBufferInUse, 0); + // prevent further interrupts from PWM events + nrf_pwm_int_set(pwm, 0); + // disable PWM interrupts - None of the PWM IRQs are shared + // with other peripherals, avoiding complexity of shared IRQs. + sd_nvic_DisableIRQ(irqn); + // disable the PWM instance + nrf_pwm_disable(pwm); + // may take up to 4 cycles for writes to propagate (APB bus @ 16MHz) + asm __volatile__ ( "NOP; NOP; NOP; NOP;" ); + // release the PWM arbiter to be re-used by another LED string + PWM_Arbiter<FASTLED_NRF52_PWM_ID>::releaseFromIsr(); + } + } + + + virtual void init() { + FASTLED_NRF52_DEBUGPRINT("Clockless Timings:\n"); + FASTLED_NRF52_DEBUGPRINT(" T0H == %d", _T0H); + FASTLED_NRF52_DEBUGPRINT(" T1H == %d", _T1H); + FASTLED_NRF52_DEBUGPRINT(" TOP == %d\n", _TOP); + } + virtual uint16_t getMaxRefreshRate() const { return 800; } + + virtual void showPixels(PixelController<_RGB_ORDER> & pixels) { + // wait for the only sequence buffer to become available + while (s_SequenceBufferInUse != 0); + prepareSequenceBuffers(pixels); + mWait.wait(); // ensure min time between updates + startPwmPlayback(s_SequenceBufferValidElements); + return; + } + + template<uint8_t _BIT> + FASTLED_NRF52_INLINE_ATTRIBUTE static void WriteBitToSequence(uint8_t byte, uint16_t * e) { + *e = _POLARITY_BIT | (((byte & (1u << _BIT)) == 0) ? _T0H : _T1H); + } + FASTLED_NRF52_INLINE_ATTRIBUTE static void prepareSequenceBuffers(PixelController<_RGB_ORDER> & pixels) { + s_SequenceBufferValidElements = 0; + int32_t remainingSequenceElements = _PWM_BUFFER_COUNT; + uint16_t * e = s_SequenceBuffer; + uint32_t size_needed = pixels.size(); // count of pixels + size_needed *= (8 + _XTRA0); // bits per pixel + size_needed *= 2; // each bit takes two bytes + + if (size_needed > _PWM_BUFFER_COUNT) { + // TODO: assert()? + return; + } + + while (pixels.has(1) && (remainingSequenceElements >= _BITS_PER_PIXEL)) { + uint8_t b0 = pixels.loadAndScale0(); + WriteBitToSequence<7>(b0, e); e++; + WriteBitToSequence<6>(b0, e); e++; + WriteBitToSequence<5>(b0, e); e++; + WriteBitToSequence<4>(b0, e); e++; + WriteBitToSequence<3>(b0, e); e++; + WriteBitToSequence<2>(b0, e); e++; + WriteBitToSequence<1>(b0, e); e++; + WriteBitToSequence<0>(b0, e); e++; + if (_XTRA0 > 0) { + for (int i = 0; i < _XTRA0; i++) { + WriteBitToSequence<0>(0,e); e++; + } + } + uint8_t b1 = pixels.loadAndScale1(); + WriteBitToSequence<7>(b1, e); e++; + WriteBitToSequence<6>(b1, e); e++; + WriteBitToSequence<5>(b1, e); e++; + WriteBitToSequence<4>(b1, e); e++; + WriteBitToSequence<3>(b1, e); e++; + WriteBitToSequence<2>(b1, e); e++; + WriteBitToSequence<1>(b1, e); e++; + WriteBitToSequence<0>(b1, e); e++; + if (_XTRA0 > 0) { + for (int i = 0; i < _XTRA0; i++) { + WriteBitToSequence<0>(0,e); e++; + } + } + uint8_t b2 = pixels.loadAndScale2(); + WriteBitToSequence<7>(b2, e); e++; + WriteBitToSequence<6>(b2, e); e++; + WriteBitToSequence<5>(b2, e); e++; + WriteBitToSequence<4>(b2, e); e++; + WriteBitToSequence<3>(b2, e); e++; + WriteBitToSequence<2>(b2, e); e++; + WriteBitToSequence<1>(b2, e); e++; + WriteBitToSequence<0>(b2, e); e++; + if (_XTRA0 > 0) { + for (int i = 0; i < _XTRA0; i++) { + WriteBitToSequence<0>(0,e); e++; + } + } + + // advance pixel and sequence pointers + s_SequenceBufferValidElements += _BITS_PER_PIXEL; + remainingSequenceElements -= _BITS_PER_PIXEL; + pixels.advanceData(); + pixels.stepDithering(); + } + } + + + FASTLED_NRF52_INLINE_ATTRIBUTE static void startPwmPlayback(uint16_t bytesToSend) { + PWM_Arbiter<FASTLED_NRF52_PWM_ID>::acquire(isr_handler); + NRF_PWM_Type * pwm = PWM_Arbiter<FASTLED_NRF52_PWM_ID>::getPWM(); + + // mark the sequence as being in-use + __sync_fetch_and_or(&s_SequenceBufferInUse, 1); + + startPwmPlayback_InitializePinState(); + startPwmPlayback_InitializePwmInstance(pwm); + startPwmPlayback_ConfigurePwmSequence(pwm); + startPwmPlayback_EnableInterruptsAndShortcuts(pwm); + startPwmPlayback_StartTask(pwm); + return; + } + + +#if 0 + FASTLED_NRF52_INLINE_ATTRIBUTE static uint16_t* getRawSequenceBuffer() { return s_SequenceBuffer; } + FASTLED_NRF52_INLINE_ATTRIBUTE static uint16_t getRawSequenceBufferSize() { return _PWM_BUFFER_COUNT; } + FASTLED_NRF52_INLINE_ATTRIBUTE static uint16_t getSequenceBufferInUse() { return s_SequenceBufferInUse; } + FASTLED_NRF52_INLINE_ATTRIBUTE static void sendRawSequenceBuffer(uint16_t bytesToSend) { + mWait.wait(); // ensure min time between updates + startPwmPlayback(bytesToSend); + } + FASTLED_NRF52_INLINE_ATTRIBUTE static void sendRawBytes(uint8_t * arrayOfBytes, uint16_t bytesToSend) { + // wait for sequence buffer to be available + while (s_SequenceBufferInUse != 0); + + s_SequenceBufferValidElements = 0; + int32_t remainingSequenceElements = _PWM_BUFFER_COUNT; + uint16_t * e = s_SequenceBuffer; + uint8_t * nextByte = arrayOfBytes; + for (uint16_t bytesRemain = bytesToSend; + (remainingSequenceElements >= 8) && (bytesRemain > 0); + bytesRemain--, + remainingSequenceElements -= 8, + s_SequenceBufferValidElements += 8 + ) { + uint8_t b = *nextByte; + WriteBitToSequence<7,false>(b, e); e++; + WriteBitToSequence<6,false>(b, e); e++; + WriteBitToSequence<5,false>(b, e); e++; + WriteBitToSequence<4,false>(b, e); e++; + WriteBitToSequence<3,false>(b, e); e++; + WriteBitToSequence<2,false>(b, e); e++; + WriteBitToSequence<1,false>(b, e); e++; + WriteBitToSequence<0,false>(b, e); e++; + if (_XTRA0 > 0) { + for (int i = 0; i < _XTRA0; i++) { + WriteBitToSequence<0,_FLIP>(0,e); e++; + } + } + } + mWait.wait(); // ensure min time between updates + + startPwmPlayback(s_SequenceBufferValidElements); + } +#endif // 0 + +}; + +template <uint8_t _DATA_PIN, int _T1, int _T2, int _T3, EOrder _RGB_ORDER, int _XTRA0, bool _FLIP, int _WAIT_TIME_MICROSECONDS> +uint16_t ClocklessController<_DATA_PIN, _T1, _T2, _T3, _RGB_ORDER, _XTRA0, _FLIP, _WAIT_TIME_MICROSECONDS>::s_SequenceBufferValidElements = 0; +template <uint8_t _DATA_PIN, int _T1, int _T2, int _T3, EOrder _RGB_ORDER, int _XTRA0, bool _FLIP, int _WAIT_TIME_MICROSECONDS> +uint32_t ClocklessController<_DATA_PIN, _T1, _T2, _T3, _RGB_ORDER, _XTRA0, _FLIP, _WAIT_TIME_MICROSECONDS>::s_SequenceBufferInUse = 0; +template <uint8_t _DATA_PIN, int _T1, int _T2, int _T3, EOrder _RGB_ORDER, int _XTRA0, bool _FLIP, int _WAIT_TIME_MICROSECONDS> +uint16_t ClocklessController<_DATA_PIN, _T1, _T2, _T3, _RGB_ORDER, _XTRA0, _FLIP, _WAIT_TIME_MICROSECONDS>::s_SequenceBuffer[_PWM_BUFFER_COUNT]; +template <uint8_t _DATA_PIN, int _T1, int _T2, int _T3, EOrder _RGB_ORDER, int _XTRA0, bool _FLIP, int _WAIT_TIME_MICROSECONDS> +CMinWait<_WAIT_TIME_MICROSECONDS> ClocklessController<_DATA_PIN, _T1, _T2, _T3, _RGB_ORDER, _XTRA0, _FLIP, _WAIT_TIME_MICROSECONDS>::mWait; + +/* nrf_pwm solution +// +// When the nRF52 softdevice (e.g., BLE) is enabled, the CPU can be pre-empted +// at any time for radio interrupts. These interrupts cannot be disabled. +// The problem is, even simple BLE advertising interrupts may take **`348μs`** +// (per softdevice 1.40, see http://infocenter.nordicsemi.com/pdf/S140_SDS_v1.3.pdf) +// +// The nRF52 chips have a decent Easy-DMA-enabled PWM peripheral. +// +// The major downside: +// [] The PWM peripheral has a fixed input buffer size at 16 bits per clock cycle. +// (each clockless protocol bit == 2 bytes) +// +// The major upsides include: +// [] Fully asynchronous, freeing CPU for other tasks +// [] Softdevice interrupts do not affect PWM clocked output (reliable clocking) +// +// The initial solution generally does the following for showPixels(): +// [] wait for a sequence buffer to become available +// [] prepare the entire LED string's sequence (see `prepareSequenceBuffers()`) +// [] ensures minimum wait time from prior sequence's end +// +// Options after initial solution working: +// [] + +// TODO: Double-buffers, so one can be doing DMA while the second +// buffer is being prepared. +// TODO: Pool of buffers, so can keep N-1 active in DMA, while +// preparing data in the final buffer? +// Write another class similar to PWM_Arbiter, only for +// tracking use of sequence buffers? +// TODO: Use volatile variable to track buffers that the +// prior DMA operation is finished with, so can fill +// in those buffers with newly-prepared data... +// apis to send the pre-generated buffer. This would be essentially asynchronous, +// and result in efficient run time if the pixels are either (a) static, or +// (b) cycle through a limited number of options whose converted results can +// be cached and re-used. While simple, this method takes lots of extra RAM... +// 16 bits for every full clock (high/low) cycle. +// +// Clockless chips typically send 24 bits (3x 8-bit) per pixel. +// One odd clockless chip sends 36 bits (3x 12-bit) per pixel. +// Each bit requires a 16-bit sequence entry for the PWM peripheral. +// This gives approximately: +// 24 bpp 36 bpp +// ========================================== +// 1 pixel 48 bytes 72 bytes +// 32 pixels 1,536 bytes 2,304 bytes +// 64 pixels 3,072 bytes 4,608 bytes +// +// +// UPDATE: this is the method I'm choosing, to get _SOMETHING_ +// clockless working... 3k RAM for 64 pixels is acceptable +// for a first release, as it allows re-use of FASTLED +// color correction, dithering, etc. .... +*/ + +//FASTLED_NAMESPACE_END + +#endif // NRF52_SERIES +#endif // __INC_CLOCKLESS_ARM_NRF52
\ No newline at end of file diff --git a/platforms/arm/nrf52/fastled_arm_nrf52.h b/platforms/arm/nrf52/fastled_arm_nrf52.h new file mode 100644 index 00000000..45300306 --- /dev/null +++ b/platforms/arm/nrf52/fastled_arm_nrf52.h @@ -0,0 +1,11 @@ +#ifndef __INC_FASTLED_ARM_NRF52_H +#define __INC_FASTLED_ARM_NRF52_H + +#include "led_sysdefs_arm_nrf52.h" +#include "arbiter_nrf52.h" +#include "fastpin_arm_nrf52.h" +#include "fastspi_arm_nrf52.h" +#include "clockless_arm_nrf52.h" + +#endif // #ifndef __INC_FASTLED_ARM_NRF52_H + diff --git a/platforms/arm/nrf52/fastpin_arm_nrf52.h b/platforms/arm/nrf52/fastpin_arm_nrf52.h new file mode 100644 index 00000000..a8684665 --- /dev/null +++ b/platforms/arm/nrf52/fastpin_arm_nrf52.h @@ -0,0 +1,328 @@ +#ifndef __FASTPIN_ARM_NRF52_H +#define __FASTPIN_ARM_NRF52_H + + +/* +// +// Background: +// =========== +// the nRF52 has more than 32 ports, and thus must support +// two distinct GPIO port registers. +// +// For the nRF52 series, the structure to control the port is +// `NRF_GPIO_Type`, with separate addresses mapped for set, clear, etc. +// The two ports are defined as NRF_P0 and NRF_P1. +// An example declaration for the ports is: +// #define NRF_P0_BASE 0x50000000UL +// #define NRF_P1_BASE 0x50000300UL +// #define NRF_P0 ((NRF_GPIO_Type*)NRF_P0_BASE) +// #define NRF_P1 ((NRF_GPIO_Type*)NRF_P1_BASE) +// +// Therefore, ideally, the _DEFPIN_ARM() macro would simply +// conditionally pass either NRF_P0 or NRF_P1 to the underlying +// FastPin<> template class class. +// +// The "pin" provided to the FastLED<> template (and which +// the _DEFPIN_ARM() macro specializes for valid pins) is NOT +// the microcontroller port.pin, but the Arduino digital pin. +// Some boards have an identity mapping (e.g., nRF52832 Feather) +// but most do not. Therefore, the _DEFPIN_ARM() macro +// must translate the Arduino pin to the mcu port.pin. +// +// +// Difficulties: +// ============= +// The goal is to avoid any such lookups, using compile-time +// optimized functions for speed, in line with FastLED's +// overall design goals. This means constexpr, compile-time +// and aggressive inlining of functions.... +// +// Right away, this precludes the use of g_ADigitalPinMap, +// which is not constexpr, and thus not available for +// preprocessor/compile-time optimizations. Therefore, +// we have to specialize FastPin<uint8_t PIN>, given a +// compile-time value for PIN, into at least a PORT and +// a BITMASK for the port. +// +// Arduino compiles using C++11 for at least Feather nRF52840 Express. +// C++11 is very restrictive about template parameters. +// Template parameters can only be: +// 1. a type (as most people expect) +// 2. a template +// 3. a constexpr native integer type +// +// Therefore, attempts to use `NRF_GPIO_Type *` as a +// template parameter will fail.... +// +// Solution: +// ========= +// The solution chosen is to define a unique structure for each port, +// whose SOLE purpose is to have a static inline function that +// returns the `NRF_GPIO_Type *` that is needed. +// +// Thus, while it's illegal to pass `NRF_P0` as a template +// parameter, it's perfectly legal to pass `__generated_struct_NRF_P0`, +// and have the template call a well-known `static inline` function +// that returns `NRF_P0` ... which is itself a compile-time constant. +// +// Note that additional magic can be applied that will automatically +// generate the structures. If you want to add that to this platform, +// check out the KL26 platform files for a starting point. +// +*/ + +// manually define two structures, to avoid fighting with preprocessor macros +struct __generated_struct_NRF_P0 { + FASTLED_NRF52_INLINE_ATTRIBUTE constexpr static NRF_GPIO_Type * r() { + return NRF_P0; + } +}; +struct __generated_struct_NRF_P1 { + FASTLED_NRF52_INLINE_ATTRIBUTE constexpr static NRF_GPIO_Type * r() { + return NRF_P1; + } +}; + + +// The actual class template can then use a typename, for what is essentially a constexpr NRF_GPIO_Type* +template <uint32_t _MASK, typename _PORT, uint8_t _PORT_NUMBER, uint8_t _PIN_NUMBER> class _ARMPIN { +public: + typedef volatile uint32_t * port_ptr_t; + typedef uint32_t port_t; + + FASTLED_NRF52_INLINE_ATTRIBUTE static void setOutput() { + // OK for this to be more than one instruction, as unusual to quickly switch input/output modes + nrf_gpio_cfg( + nrf_pin(), + NRF_GPIO_PIN_DIR_OUTPUT, // set pin as output + NRF_GPIO_PIN_INPUT_DISCONNECT, // disconnect the input buffering + NRF_GPIO_PIN_NOPULL, // neither pull-up nor pull-down resistors enabled + NRF_GPIO_PIN_H0H1, // high drive mode required for faster speeds + NRF_GPIO_PIN_NOSENSE // pin sense level disabled + ); + } + FASTLED_NRF52_INLINE_ATTRIBUTE static void setInput() { + // OK for this to be more than one instruction, as unusual to quickly switch input/output modes + nrf_gpio_cfg( + nrf_pin(), + NRF_GPIO_PIN_DIR_INPUT, // set pin as input + NRF_GPIO_PIN_INPUT_DISCONNECT, // disconnect the input buffering + NRF_GPIO_PIN_NOPULL, // neither pull-up nor pull-down resistors enabled + NRF_GPIO_PIN_H0H1, // high drive mode required for faster speeds + NRF_GPIO_PIN_NOSENSE // pin sense level disabled + ); + } + FASTLED_NRF52_INLINE_ATTRIBUTE static void hi() { _PORT::r()->OUTSET = _MASK; } // sets _MASK in the SET OUTPUT register (output set high) + FASTLED_NRF52_INLINE_ATTRIBUTE static void lo() { _PORT::r()->OUTCLR = _MASK; } // sets _MASK in the CLEAR OUTPUT register (output set low) + FASTLED_NRF52_INLINE_ATTRIBUTE static void toggle() { _PORT::r()->OUT ^= _MASK; } // toggles _MASK bits in the OUTPUT GPIO port directly + FASTLED_NRF52_INLINE_ATTRIBUTE static void strobe() { toggle(); toggle(); } // BUGBUG -- Is this used by FastLED? Without knowing (for example) SPI Speed? + FASTLED_NRF52_INLINE_ATTRIBUTE static port_t hival() { return _PORT::r()->OUT | _MASK; } // sets all _MASK bit(s) in the OUTPUT GPIO port to 1 + FASTLED_NRF52_INLINE_ATTRIBUTE static port_t loval() { return _PORT::r()->OUT & ~_MASK; } // sets all _MASK bit(s) in the OUTPUT GPIO port to 0 + FASTLED_NRF52_INLINE_ATTRIBUTE static port_ptr_t port() { return &(_PORT::r()->OUT); } // gets raw pointer to OUTPUT GPIO port + FASTLED_NRF52_INLINE_ATTRIBUTE static port_ptr_t cport() { return &(_PORT::r()->OUTCLR); } // gets raw pointer to SET DIRECTION GPIO port + FASTLED_NRF52_INLINE_ATTRIBUTE static port_ptr_t sport() { return &(_PORT::r()->OUTSET); } // gets raw pointer to CLEAR DIRECTION GPIO port + FASTLED_NRF52_INLINE_ATTRIBUTE static port_t mask() { return _MASK; } // gets the value of _MASK + FASTLED_NRF52_INLINE_ATTRIBUTE static void hi (register port_ptr_t port) { hi(); } // sets _MASK in the SET OUTPUT register (output set high) + FASTLED_NRF52_INLINE_ATTRIBUTE static void lo (register port_ptr_t port) { lo(); } // sets _MASK in the CLEAR OUTPUT register (output set low) + FASTLED_NRF52_INLINE_ATTRIBUTE static void set(register port_t val ) { _PORT::r()->OUT = val; } // sets entire port's value (optimization used by FastLED) + FASTLED_NRF52_INLINE_ATTRIBUTE static void fastset(register port_ptr_t port, register port_t val) { *port = val; } + constexpr static uint32_t nrf_pin2() { return NRF_GPIO_PIN_MAP(_PORT_NUMBER, _PIN_NUMBER); } + constexpr static bool LowSpeedOnlyRecommended() { + // only allow one function body. + #undef _FASTLED_NRF52_LOW_SPEED_ONLY_BOARD_DETECT + + // unique cases for each board / processor package / module? + #if defined(NRF52810_XXAA) && defined(NRF52810_PACKAGE_QFN48) + #if defined(_FASTLED_NRF52_LOW_SPEED_ONLY_BOARD_DETECT) + #error "Multiple board match" + #endif + #define _FASTLED_NRF52_LOW_SPEED_ONLY_BOARD_DETECT 1 + static_assert(_PORT_NUMBER == 0, "nRF52810 only has one port"); + return ( + (_PIN_NUMBER == 25) || + (_PIN_NUMBER == 26) || + (_PIN_NUMBER == 27) || + (_PIN_NUMBER == 28) || + (_PIN_NUMBER == 29) + ); + #endif + #if defined(NRF52810_XXAA) && defined(NRF52810_PACKAGE_QFN32) + #if defined(_FASTLED_NRF52_LOW_SPEED_ONLY_BOARD_DETECT) + #error "Multiple board match" + #endif + #define _FASTLED_NRF52_LOW_SPEED_ONLY_BOARD_DETECT 1 + static_assert(_PORT_NUMBER == 0, "nRF52810 only has one port"); + if (_PORT_NUMBER == 0) { + if ( + (_PIN_NUMBER == 26) || + (_PIN_NUMBER == 27) + ) { + return true; + } + } + return false; + #endif + #if defined(NRF52832_XXAA) || defined(NRF52832_XXAB) + #if defined(_FASTLED_NRF52_LOW_SPEED_ONLY_BOARD_DETECT) + #error "Multiple board match" + #endif + #define _FASTLED_NRF52_LOW_SPEED_ONLY_BOARD_DETECT 1 + static_assert(_PORT_NUMBER == 0, "nRF52832 only has one port"); + // data sheets shows the same pins in both QFN48 and WLCSP package + // are recommended as low-speed only: + return ( + (_PIN_NUMBER == 22) || + (_PIN_NUMBER == 23) || + (_PIN_NUMBER == 24) || + (_PIN_NUMBER == 25) || + (_PIN_NUMBER == 26) || + (_PIN_NUMBER == 27) || + (_PIN_NUMBER == 28) || + (_PIN_NUMBER == 29) || + (_PIN_NUMBER == 30) || + (_PIN_NUMBER == 31) + ); + #endif + #if defined(NRF52840_XXAA) && defined(NRF52840_PACKAGE_aQFN73) + #if defined(_FASTLED_NRF52_LOW_SPEED_ONLY_BOARD_DETECT) + #error "Multiple board match" + #endif + #define _FASTLED_NRF52_LOW_SPEED_ONLY_BOARD_DETECT 1 + static_assert(_PORT_NUMBER == 0 || _PORT_NUMBER == 1, "nRF52840 only has two ports"); + return + ( + ( + (_PORT_NUMBER == 0) && + ( + (_PIN_NUMBER == 2) || + (_PIN_NUMBER == 3) || + (_PIN_NUMBER == 9) || + (_PIN_NUMBER == 10) || + (_PIN_NUMBER == 11) || + (_PIN_NUMBER == 12) || + (_PIN_NUMBER == 14) || + (_PIN_NUMBER == 28) || + (_PIN_NUMBER == 29) || + (_PIN_NUMBER == 30) || + (_PIN_NUMBER == 31) + ) + ) + || + ( + (_PORT_NUMBER == 1) && + ( + (_PIN_NUMBER == 2) || + (_PIN_NUMBER == 3) || + (_PIN_NUMBER == 4) || + (_PIN_NUMBER == 5) || + (_PIN_NUMBER == 6) || + (_PIN_NUMBER == 7) || + (_PIN_NUMBER == 10) || + (_PIN_NUMBER == 13) || + (_PIN_NUMBER == 15) + ) + ) + ); + #endif + #if false && defined(NRF52840_XXAA) && (defined(NRF52840_PACKAGE_aQFN73) || defined(ARDUINO_NRF52840_FEATHER)) + // Adafruit nRF52840 feather uses RAYTAC MDBT50Q module, which is aQFN73 + // See https://cdn-learn.adafruit.com/assets/assets/000/068/544/original/Raytac_MDBT50Q.pdf + #if defined(_FASTLED_NRF52_LOW_SPEED_ONLY_BOARD_DETECT) + #error "Multiple board match" + #endif + #define _FASTLED_NRF52_LOW_SPEED_ONLY_BOARD_DETECT 1 + static_assert(_PORT_NUMBER == 0 || _PORT_NUMBER == 1, "nRF52840 only has two ports"); + return + ( + ( + (_PORT_NUMBER == 0) && + ( + (_PIN_NUMBER == 2) || + (_PIN_NUMBER == 3) || + (_PIN_NUMBER == 9) || + (_PIN_NUMBER == 10) || + (_PIN_NUMBER == 28) || + (_PIN_NUMBER == 29) || + (_PIN_NUMBER == 30) || + (_PIN_NUMBER == 31) + ) + ) + || + ( + (_PORT_NUMBER == 1) && + ( + (_PIN_NUMBER == 1) || + (_PIN_NUMBER == 2) || + (_PIN_NUMBER == 3) || + (_PIN_NUMBER == 4) || + (_PIN_NUMBER == 5) || + (_PIN_NUMBER == 6) || + (_PIN_NUMBER == 7) || + (_PIN_NUMBER == 10) || + (_PIN_NUMBER == 11) || + (_PIN_NUMBER == 12) || + (_PIN_NUMBER == 13) || + (_PIN_NUMBER == 14) || + (_PIN_NUMBER == 15) + ) + ) + ); + #endif + #if !defined(_FASTLED_NRF52_LOW_SPEED_ONLY_BOARD_DETECT) + #warning "Unknown board / package, ... caller must pins support high-speed" + return false; // choosing default to be FALSE, to allow users to ATTEMPT to use high-speed on pins where support is not known + #endif + } + // Expose the nrf pin (port/pin combined), port, and pin as properties (e.g., for setting up SPI) + + FASTLED_NRF52_INLINE_ATTRIBUTE static uint32_t nrf_pin() { return NRF_GPIO_PIN_MAP(_PORT_NUMBER, _PIN_NUMBER); } +}; + +// +// BOARD_PIN can be either the pin portion of a port.pin, or the combined NRF_GPIO_PIN_MAP() number. +// For example both the following two defines refer to P1.15 (pin 47) as Arduino pin 3: +// _DEFPIN_ARM(3, 1, 15); +// _DEFPIN_ARM(3, 1, 47); +// +// Similarly, the following defines are all equivalent: +// _DEFPIN_ARM_IDENTITY_P1(47); +// _DEFPIN_ARM(47, 1, 15); +// _DEFPIN_ARM(47, 1, 47); +// + +#define _DEFPIN_ARM(ARDUINO_PIN, BOARD_PORT, BOARD_PIN) \ + template<> class FastPin<ARDUINO_PIN> : \ + public _ARMPIN< \ + 1u << (BOARD_PIN & 31u), \ + __generated_struct_NRF_P ## BOARD_PORT, \ + (BOARD_PIN / 32), \ + BOARD_PIN & 31u \ + > \ + {} + +#define _DEFPIN_ARM_IDENTITY_P0(ARDUINO_PIN) \ + template<> class FastPin<ARDUINO_PIN> : \ + public _ARMPIN< \ + 1u << (ARDUINO_PIN & 31u), \ + __generated_struct_NRF_P0, \ + 0, \ + (ARDUINO_PIN & 31u) + 0 \ + > \ + {} + +#define _DEFPIN_ARM_IDENTITY_P1(ARDUINO_PIN) \ + template<> class FastPin<ARDUINO_PIN> : \ + public _ARMPIN< \ + 1u << (ARDUINO_PIN & 31u), \ + __generated_struct_NRF_P1, \ + 1, \ + (ARDUINO_PIN & 31u) + 32 \ + > \ + {} + +// The actual pin definitions are in a separate header file... +#include "fastpin_arm_nrf52_variants.h" + +#define HAS_HARDWARE_PIN_SUPPORT + +#endif // #ifndef __FASTPIN_ARM_NRF52_H diff --git a/platforms/arm/nrf52/fastpin_arm_nrf52_variants.h b/platforms/arm/nrf52/fastpin_arm_nrf52_variants.h new file mode 100644 index 00000000..b3b9ff99 --- /dev/null +++ b/platforms/arm/nrf52/fastpin_arm_nrf52_variants.h @@ -0,0 +1,579 @@ +#ifndef __FASTPIN_ARM_NRF52_VARIANTS_H +#define __FASTPIN_ARM_NRF52_VARIANTS_H + +// use this to determine if found variant or not (avoid multiple boards at once) +#undef __FASTPIN_ARM_NRF52_VARIANT_FOUND + +// Adafruit Bluefruit nRF52832 Feather +// From https://www.adafruit.com/package_adafruit_index.json +#if defined (ARDUINO_NRF52832_FEATHER) + #if defined(__FASTPIN_ARM_NRF52_VARIANT_FOUND) + #error "Cannot define more than one board at a time" + #else + #define __FASTPIN_ARM_NRF52_VARIANT_FOUND + #endif + #warning "Adafruit Bluefruit nRF52832 Feather is an untested board -- test and let use know your results via https://github.com/FastLED/FastLED/issues" + _DEFPIN_ARM_IDENTITY_P0( 0); // xtal 1 + _DEFPIN_ARM_IDENTITY_P0( 1); // xtal 2 + _DEFPIN_ARM_IDENTITY_P0( 2); // a0 + _DEFPIN_ARM_IDENTITY_P0( 3); // a1 + _DEFPIN_ARM_IDENTITY_P0( 4); // a2 + _DEFPIN_ARM_IDENTITY_P0( 5); // a3 + _DEFPIN_ARM_IDENTITY_P0( 6); // TXD + _DEFPIN_ARM_IDENTITY_P0( 7); // GPIO #7 + _DEFPIN_ARM_IDENTITY_P0( 8); // RXD + _DEFPIN_ARM_IDENTITY_P0( 9); // NFC1 + _DEFPIN_ARM_IDENTITY_P0(10); // NFC2 + _DEFPIN_ARM_IDENTITY_P0(11); // GPIO #11 + _DEFPIN_ARM_IDENTITY_P0(12); // SCK + _DEFPIN_ARM_IDENTITY_P0(13); // MOSI + _DEFPIN_ARM_IDENTITY_P0(14); // MISO + _DEFPIN_ARM_IDENTITY_P0(15); // GPIO #15 + _DEFPIN_ARM_IDENTITY_P0(16); // GPIO #16 + _DEFPIN_ARM_IDENTITY_P0(17); // LED #1 (red) + _DEFPIN_ARM_IDENTITY_P0(18); // SWO + _DEFPIN_ARM_IDENTITY_P0(19); // LED #2 (blue) + _DEFPIN_ARM_IDENTITY_P0(20); // DFU + // _DEFPIN_ARM_IDENTITY_P0(21); // Reset -- not valid to use for FastLED? + // _DEFPIN_ARM_IDENTITY_P0(22); // Factory Reset -- not vaild to use for FastLED? + // _DEFPIN_ARM_IDENTITY_P0(23); // N/A + // _DEFPIN_ARM_IDENTITY_P0(24); // N/A + _DEFPIN_ARM_IDENTITY_P0(25); // SDA + _DEFPIN_ARM_IDENTITY_P0(26); // SCL + _DEFPIN_ARM_IDENTITY_P0(27); // GPIO #27 + _DEFPIN_ARM_IDENTITY_P0(28); // A4 + _DEFPIN_ARM_IDENTITY_P0(29); // A5 + _DEFPIN_ARM_IDENTITY_P0(30); // A6 + _DEFPIN_ARM_IDENTITY_P0(31); // A7 +#endif // defined (ARDUINO_NRF52832_FEATHER) + +// Adafruit Bluefruit nRF52840 Feather Express +// From https://www.adafruit.com/package_adafruit_index.json +#if defined (ARDUINO_NRF52840_FEATHER) + #if defined(__FASTPIN_ARM_NRF52_VARIANT_FOUND) + #error "Cannot define more than one board at a time" + #else + #define __FASTPIN_ARM_NRF52_VARIANT_FOUND + #endif + + #define MAX_PIN (33u) // 34 if wanting to use NFC1 test point + + // Arduino pins 0..7 + _DEFPIN_ARM( 0, 0, 25); // D0 is P0.25 -- UART TX + //_DEFPIN_ARM( 1, 0, 24); // D1 is P0.24 -- UART RX + _DEFPIN_ARM( 2, 0, 10); // D2 is P0.10 -- NFC2 + _DEFPIN_ARM( 3, 1, 47); // D3 is P1.15 -- PIN_LED1 (red) + _DEFPIN_ARM( 4, 1, 42); // D4 is P1.10 -- PIN_LED2 (blue) + _DEFPIN_ARM( 5, 1, 40); // D5 is P1.08 -- SPI/SS + _DEFPIN_ARM( 6, 0, 7); // D6 is P0.07 + _DEFPIN_ARM( 7, 1, 34); // D7 is P1.02 -- PIN_DFU (Button) + + // Arduino pins 8..15 + _DEFPIN_ARM( 8, 0, 16); // D8 is P0.16 -- PIN_NEOPIXEL + _DEFPIN_ARM( 9, 0, 26); // D9 is P0.26 + _DEFPIN_ARM(10, 0, 27); // D10 is P0.27 + _DEFPIN_ARM(11, 0, 6); // D11 is P0.06 + _DEFPIN_ARM(12, 0, 8); // D12 is P0.08 + _DEFPIN_ARM(13, 1, 41); // D13 is P1.09 + _DEFPIN_ARM(14, 0, 4); // D14 is P0.04 -- A0 + _DEFPIN_ARM(15, 0, 5); // D15 is P0.05 -- A1 + + // Arduino pins 16..23 + _DEFPIN_ARM(16, 0, 30); // D16 is P0.30 -- A2 + _DEFPIN_ARM(17, 0, 28); // D17 is P0.28 -- A3 + _DEFPIN_ARM(18, 0, 2); // D18 is P0.02 -- A4 + _DEFPIN_ARM(19, 0, 3); // D19 is P0.03 -- A5 + //_DEFPIN_ARM(20, 0, 29); // D20 is P0.29 -- A6 -- Connected to battery! + //_DEFPIN_ARM(21, 0, 31); // D21 is P0.31 -- A7 -- AREF + _DEFPIN_ARM(22, 0, 12); // D22 is P0.12 -- SDA + _DEFPIN_ARM(23, 0, 11); // D23 is P0.11 -- SCL + + // Arduino pins 24..31 + _DEFPIN_ARM(24, 0, 15); // D24 is P0.15 -- PIN_SPI_MISO + _DEFPIN_ARM(25, 0, 13); // D25 is P0.13 -- PIN_SPI_MOSI + _DEFPIN_ARM(26, 0, 14); // D26 is P0.14 -- PIN_SPI_SCK + //_DEFPIN_ARM(27, 0, 19); // D27 is P0.19 -- PIN_QSPI_SCK + //_DEFPIN_ARM(28, 0, 20); // D28 is P0.20 -- PIN_QSPI_CS + //_DEFPIN_ARM(29, 0, 17); // D29 is P0.17 -- PIN_QSPI_DATA0 + //_DEFPIN_ARM(30, 0, 22); // D30 is P0.22 -- PIN_QSPI_DATA1 + //_DEFPIN_ARM(31, 0, 23); // D31 is P0.23 -- PIN_QSPI_DATA2 + + // Arduino pins 32..34 + //_DEFPIN_ARM(32, 0, 21); // D32 is P0.21 -- PIN_QSPI_DATA3 + //_DEFPIN_ARM(33, 0, 9); // D33 is NFC1, only accessible via test point +#endif // defined (ARDUINO_NRF52840_FEATHER) + +// Adafruit Bluefruit nRF52840 Metro Express +// From https://www.adafruit.com/package_adafruit_index.json +#if defined (ARDUINO_NRF52840_METRO) + #if defined(__FASTPIN_ARM_NRF52_VARIANT_FOUND) + #error "Cannot define more than one board at a time" + #else + #define __FASTPIN_ARM_NRF52_VARIANT_FOUND + #endif + #warning "Adafruit Bluefruit nRF52840 Metro Express is an untested board -- test and let use know your results via https://github.com/FastLED/FastLED/issues" + + _DEFPIN_ARM( 0, 0, 25); // D0 is P0.25 (UART TX) + _DEFPIN_ARM( 1, 0, 24); // D1 is P0.24 (UART RX) + _DEFPIN_ARM( 2, 1, 10); // D2 is P1.10 + _DEFPIN_ARM( 3, 1, 4); // D3 is P1.04 + _DEFPIN_ARM( 4, 1, 11); // D4 is P1.11 + _DEFPIN_ARM( 5, 1, 12); // D5 is P1.12 + _DEFPIN_ARM( 6, 1, 14); // D6 is P1.14 + _DEFPIN_ARM( 7, 0, 26); // D7 is P0.26 + _DEFPIN_ARM( 8, 0, 27); // D8 is P0.27 + _DEFPIN_ARM( 9, 0, 12); // D9 is P0.12 + _DEFPIN_ARM(10, 0, 6); // D10 is P0.06 + _DEFPIN_ARM(11, 0, 8); // D11 is P0.08 + _DEFPIN_ARM(12, 1, 9); // D12 is P1.09 + _DEFPIN_ARM(13, 0, 14); // D13 is P0.14 + _DEFPIN_ARM(14, 0, 4); // D14 is P0.04 (A0) + _DEFPIN_ARM(15, 0, 5); // D15 is P0.05 (A1) + _DEFPIN_ARM(16, 0, 28); // D16 is P0.28 (A2) + _DEFPIN_ARM(17, 0, 30); // D17 is P0.30 (A3) + _DEFPIN_ARM(18, 0, 2); // D18 is P0.02 (A4) + _DEFPIN_ARM(19, 0, 3); // D19 is P0.03 (A5) + _DEFPIN_ARM(20, 0, 29); // D20 is P0.29 (A6, battery) + _DEFPIN_ARM(21, 0, 31); // D21 is P0.31 (A7, ARef) + _DEFPIN_ARM(22, 0, 15); // D22 is P0.15 (SDA) + _DEFPIN_ARM(23, 0, 16); // D23 is P0.16 (SCL) + _DEFPIN_ARM(24, 0, 11); // D24 is P0.11 (SPI MISO) + _DEFPIN_ARM(25, 1, 8); // D25 is P1.08 (SPI MOSI) + _DEFPIN_ARM(26, 0, 7); // D26 is P0.07 (SPI SCK ) + //_DEFPIN_ARM(27, 0, 19); // D27 is P0.19 (QSPI CLK ) + //_DEFPIN_ARM(28, 0, 20); // D28 is P0.20 (QSPI CS ) + //_DEFPIN_ARM(29, 0, 17); // D29 is P0.17 (QSPI Data 0) + //_DEFPIN_ARM(30, 0, 23); // D30 is P0.23 (QSPI Data 1) + //_DEFPIN_ARM(31, 0, 22); // D31 is P0.22 (QSPI Data 2) + //_DEFPIN_ARM(32, 0, 21); // D32 is P0.21 (QSPI Data 3) + _DEFPIN_ARM(33, 1, 13); // D33 is P1.13 LED1 + _DEFPIN_ARM(34, 1, 15); // D34 is P1.15 LED2 + _DEFPIN_ARM(35, 0, 13); // D35 is P0.13 NeoPixel + _DEFPIN_ARM(36, 1, 0); // D36 is P1.02 Switch + _DEFPIN_ARM(37, 1, 0); // D37 is P1.00 SWO/DFU + _DEFPIN_ARM(38, 0, 9); // D38 is P0.09 NFC1 + _DEFPIN_ARM(39, 0, 10); // D39 is P0.10 NFC2 +#endif // defined (ARDUINO_NRF52840_METRO) + +// Adafruit Bluefruit on nRF52840DK PCA10056 +// From https://www.adafruit.com/package_adafruit_index.json +#if defined (ARDUINO_NRF52840_PCA10056) + #if defined(__FASTPIN_ARM_NRF52_VARIANT_FOUND) + #error "Cannot define more than one board at a time" + #else + #define __FASTPIN_ARM_NRF52_VARIANT_FOUND + #endif + #warning "Adafruit Bluefruit on nRF52840DK PCA10056 is an untested board -- test and let use know your results via https://github.com/FastLED/FastLED/issues" + + #if defined(USE_ARDUINO_PIN_NUMBERING) + /* pca10056_schematic_and_pcb.pdf + Page 3 shows the Arduino Pin to GPIO Px.xx mapping + */ + _DEFPIN_ARM( 0, 1, 1); // D0 is P1.01 + _DEFPIN_ARM( 1, 1, 2); // D1 is P1.02 + _DEFPIN_ARM( 2, 1, 3); // D2 is P1.03 + _DEFPIN_ARM( 3, 1, 4); // D3 is P1.04 + _DEFPIN_ARM( 4, 1, 5); // D4 is P1.05 + _DEFPIN_ARM( 5, 1, 6); // D5 is P1.06 + _DEFPIN_ARM( 6, 1, 7); // D6 is P1.07 (BUTTON1 option) + _DEFPIN_ARM( 7, 1, 8); // D7 is P1.08 (BUTTON2 option) + _DEFPIN_ARM( 8, 1, 10); // D8 is P1.10 + _DEFPIN_ARM( 9, 1, 11); // D9 is P1.11 + _DEFPIN_ARM(10, 1, 12); // D10 is P1.12 + _DEFPIN_ARM(11, 1, 13); // D11 is P1.13 + _DEFPIN_ARM(12, 1, 14); // D12 is P1.14 + _DEFPIN_ARM(13, 1, 15); // D13 is P1.15 + _DEFPIN_ARM(14, 0, 0); // D14 is P0.00 (if SB4 bridged) + _DEFPIN_ARM(15, 0, 1); // D15 is P0.01 (if SB3 bridged) + _DEFPIN_ARM(16, 0, 5); // D16 is P0.05 (aka AIN3, aka UART RTS) + _DEFPIN_ARM(17, 0, 6); // D17 is P0.06 (UART TxD) + _DEFPIN_ARM(18, 0, 7); // D18 is P0.07 (UART CTS default) + _DEFPIN_ARM(19, 0, 8); // D19 is P0.08 (UART RxD) + _DEFPIN_ARM(20, 0, 9); // D20 is P0.09 (NFC1) + _DEFPIN_ARM(21, 0, 10); // D21 is P0.10 (NFC2) + _DEFPIN_ARM(22, 0, 11); // D22 is P0.11 (TRACEDATA2 / BUTTON1 default) + _DEFPIN_ARM(23, 0, 12); // D23 is P0.12 (TRACEDATA1 / BUTTON2 default) + _DEFPIN_ARM(24, 0, 13); // D24 is P0.13 (LED1) + _DEFPIN_ARM(25, 0, 14); // D25 is P0.14 (LED2) + _DEFPIN_ARM(26, 0, 15); // D26 is P0.15 (LED3) + _DEFPIN_ARM(27, 0, 16); // D27 is P0.16 (LED4) + _DEFPIN_ARM(28, 0, 17); // D28 is P0.17 (QSPI !CS , unless SB13 cut) + // _DEFPIN_ARM(29, 0, 18); // D29 is P0.18 (RESET) + _DEFPIN_ARM(30, 0, 19); // D30 is P0.19 (QSPI CLK , unless SB11 cut) + _DEFPIN_ARM(31, 0, 20); // D31 is P0.20 (QSPI DIO0, unless SB12 cut) + _DEFPIN_ARM(32, 0, 21); // D32 is P0.21 (QSPI DIO1, unless SB14 cut) + _DEFPIN_ARM(33, 0, 22); // D33 is P0.22 (QSPI DIO2, unless SB15 cut) + _DEFPIN_ARM(34, 0, 23); // D34 is P0.23 (QSPI DIO3, unless SB10 cut) + _DEFPIN_ARM(35, 0, 24); // D35 is P0.24 (BUTTON3) + _DEFPIN_ARM(36, 0, 25); // D36 is P0.25 (BUTTON4) + _DEFPIN_ARM(37, 1, 00); // D37 is P1.00 (TRACEDATA0 / SWO) + _DEFPIN_ARM(38, 1, 09); // D38 is P1.09 (TRACEDATA3) + //_DEFPIN_ARM(??, 0, 2); // D?? is P0.02 (AREF, aka AIN0) + //_DEFPIN_ARM(??, 0, 3); // D?? is P0.03 (A0, aka AIN1) + //_DEFPIN_ARM(??, 0, 4); // D?? is P0.04 (A1, aka AIN2, aka UART CTS option) + //_DEFPIN_ARM(??, 0, 28); // D?? is P0.28 (A2, aka AIN4) + //_DEFPIN_ARM(??, 0, 29); // D?? is P0.29 (A3, aka AIN5) + //_DEFPIN_ARM(??, 0, 30); // D?? is P0.30 (A4, aka AIN6) + //_DEFPIN_ARM(??, 0, 31); // D?? is P0.31 (A5, aka AIN7) + + #else + /* 48 pins, defined using natural mapping in Adafruit's variant.cpp (!) */ + _DEFPIN_ARM_IDENTITY_P0( 0); // P0.00 (XL1 .. ensure SB4 bridged, SB2 cut) + _DEFPIN_ARM_IDENTITY_P0( 1); // P0.01 (XL2 .. ensure SB3 bridged, SB1 cut) + _DEFPIN_ARM_IDENTITY_P0( 2); // P0.02 (AIN0) + _DEFPIN_ARM_IDENTITY_P0( 3); // P0.03 (AIN1) + _DEFPIN_ARM_IDENTITY_P0( 4); // P0.04 (AIN2 / UART CTS option) + _DEFPIN_ARM_IDENTITY_P0( 5); // P0.05 (AIN3 / UART RTS) + _DEFPIN_ARM_IDENTITY_P0( 6); // P0.06 (UART TxD) + _DEFPIN_ARM_IDENTITY_P0( 7); // P0.07 (TRACECLK / UART CTS default) + _DEFPIN_ARM_IDENTITY_P0( 8); // P0.08 (UART RxD) + _DEFPIN_ARM_IDENTITY_P0( 9); // P0.09 (NFC1) + _DEFPIN_ARM_IDENTITY_P0(10); // P0.10 (NFC2) + _DEFPIN_ARM_IDENTITY_P0(11); // P0.11 (TRACEDATA2 / BUTTON1 default) + _DEFPIN_ARM_IDENTITY_P0(12); // P0.12 (TRACEDATA1 / BUTTON2 default) + _DEFPIN_ARM_IDENTITY_P0(13); // P0.13 (LED1) + _DEFPIN_ARM_IDENTITY_P0(14); // P0.14 (LED2) + _DEFPIN_ARM_IDENTITY_P0(15); // P0.15 (LED3) + _DEFPIN_ARM_IDENTITY_P0(16); // P0.16 (LED4) + //_DEFPIN_ARM_IDENTITY_P0(17); // P0.17 (QSPI !CS ) + //_DEFPIN_ARM_IDENTITY_P0(18); // P0.18 (RESET) + //_DEFPIN_ARM_IDENTITY_P0(19); // P0.19 (QSPI CLK ) + //_DEFPIN_ARM_IDENTITY_P0(20); // P0.20 (QSPI DIO0) + //_DEFPIN_ARM_IDENTITY_P0(21); // P0.21 (QSPI DIO1) + //_DEFPIN_ARM_IDENTITY_P0(22); // P0.22 (QSPI DIO2) + //_DEFPIN_ARM_IDENTITY_P0(23); // P0.23 (QSPI DIO3) + _DEFPIN_ARM_IDENTITY_P0(24); // P0.24 (BUTTON3) + _DEFPIN_ARM_IDENTITY_P0(25); // P0.25 (BUTTON4) + _DEFPIN_ARM_IDENTITY_P0(26); // P0.26 + _DEFPIN_ARM_IDENTITY_P0(27); // P0.27 + _DEFPIN_ARM_IDENTITY_P0(28); // P0.28 (AIN4) + _DEFPIN_ARM_IDENTITY_P0(29); // P0.29 (AIN5) + _DEFPIN_ARM_IDENTITY_P0(30); // P0.30 (AIN6) + _DEFPIN_ARM_IDENTITY_P0(31); // P0.31 (AIN7) + _DEFPIN_ARM_IDENTITY_P0(32); // P1.00 (SWO / TRACEDATA0) + _DEFPIN_ARM_IDENTITY_P0(33); // P1.01 + _DEFPIN_ARM_IDENTITY_P0(34); // P1.02 + _DEFPIN_ARM_IDENTITY_P0(35); // P1.03 + _DEFPIN_ARM_IDENTITY_P0(36); // P1.04 + _DEFPIN_ARM_IDENTITY_P0(37); // P1.05 + _DEFPIN_ARM_IDENTITY_P0(38); // P1.06 + _DEFPIN_ARM_IDENTITY_P0(39); // P1.07 (BUTTON1 option) + _DEFPIN_ARM_IDENTITY_P0(40); // P1.08 (BUTTON2 option) + _DEFPIN_ARM_IDENTITY_P0(41); // P1.09 (TRACEDATA3) + _DEFPIN_ARM_IDENTITY_P0(42); // P1.10 + _DEFPIN_ARM_IDENTITY_P0(43); // P1.11 + _DEFPIN_ARM_IDENTITY_P0(44); // P1.12 + _DEFPIN_ARM_IDENTITY_P0(45); // P1.13 + _DEFPIN_ARM_IDENTITY_P0(46); // P1.14 + _DEFPIN_ARM_IDENTITY_P0(47); // P1.15 + #endif +#endif // defined (ARDUINO_NRF52840_PCA10056) + +// Electronut labs bluey +// See https://github.com/sandeepmistry/arduino-nRF5/blob/master/variants/bluey/variant.cpp +#if defined(ARDUINO_ELECTRONUT_BLUEY) + #if defined(__FASTPIN_ARM_NRF52_VARIANT_FOUND) + #error "Cannot define more than one board at a time" + #else + #define __FASTPIN_ARM_NRF52_VARIANT_FOUND + #endif + #warning "Electronut labs bluey is an untested board -- test and let use know your results via https://github.com/FastLED/FastLED/issues" + + _DEFPIN_ARM( 0, 0, 26); // D0 is P0.26 + _DEFPIN_ARM( 1, 0, 27); // D1 is P0.27 + _DEFPIN_ARM( 2, 0, 22); // D2 is P0.22 (SPI SS ) + _DEFPIN_ARM( 3, 0, 23); // D3 is P0.23 (SPI MOSI) + _DEFPIN_ARM( 4, 0, 24); // D4 is P0.24 (SPI MISO, also A3) + _DEFPIN_ARM( 5, 0, 25); // D5 is P0.25 (SPI SCK ) + _DEFPIN_ARM( 6, 0, 16); // D6 is P0.16 (Button) + _DEFPIN_ARM( 7, 0, 19); // D7 is P0.19 (R) + _DEFPIN_ARM( 8, 0, 18); // D8 is P0.18 (G) + _DEFPIN_ARM( 9, 0, 17); // D9 is P0.17 (B) + _DEFPIN_ARM(10, 0, 11); // D10 is P0.11 (SCL) + _DEFPIN_ARM(11, 0, 12); // D11 is P0.12 (DRDYn) + _DEFPIN_ARM(12, 0, 13); // D12 is P0.13 (SDA) + _DEFPIN_ARM(13, 0, 14); // D13 is P0.17 (INT) + _DEFPIN_ARM(14, 0, 15); // D14 is P0.15 (INT1) + _DEFPIN_ARM(15, 0, 20); // D15 is P0.20 (INT2) + _DEFPIN_ARM(16, 0, 2); // D16 is P0.02 (A0) + _DEFPIN_ARM(17, 0, 3); // D17 is P0.03 (A1) + _DEFPIN_ARM(18, 0, 4); // D18 is P0.04 (A2) + _DEFPIN_ARM(19, 0, 24); // D19 is P0.24 (A3, also D4/SPI MISO) -- is this right? + _DEFPIN_ARM(20, 0, 29); // D20 is P0.29 (A4) + _DEFPIN_ARM(21, 0, 30); // D21 is P0.30 (A5) + _DEFPIN_ARM(22, 0, 31); // D22 is P0.31 (A6) + _DEFPIN_ARM(23, 0, 8); // D23 is P0.08 (RX) + _DEFPIN_ARM(24, 0, 6); // D24 is P0.06 (TX) + _DEFPIN_ARM(25, 0, 5); // D25 is P0.05 (RTS) + _DEFPIN_ARM(26, 0, 7); // D26 is P0.07 (CTS) +#endif // defined(ARDUINO_ELECTRONUT_BLUEY) + +// Electronut labs hackaBLE +// See https://github.com/sandeepmistry/arduino-nRF5/blob/master/variants/hackaBLE/variant.cpp +#if defined(ARDUINO_ELECTRONUT_HACKABLE) + #if defined(__FASTPIN_ARM_NRF52_VARIANT_FOUND) + #error "Cannot define more than one board at a time" + #else + #define __FASTPIN_ARM_NRF52_VARIANT_FOUND + #endif + #warning "Electronut labs hackaBLE is an untested board -- test and let use know your results via https://github.com/FastLED/FastLED/issues" + _DEFPIN_ARM( 0, 0, 14); // D0 is P0.14 (RX) + _DEFPIN_ARM( 1, 0, 13); // D1 is P0.13 (TX) + _DEFPIN_ARM( 2, 0, 12); // D2 is P0.12 + _DEFPIN_ARM( 3, 0, 11); // D3 is P0.11 (SPI MOSI) + _DEFPIN_ARM( 4, 0, 8); // D4 is P0.08 (SPI MISO) + _DEFPIN_ARM( 5, 0, 7); // D5 is P0.07 (SPI SCK ) + _DEFPIN_ARM( 6, 0, 6); // D6 is P0.06 + _DEFPIN_ARM( 7, 0, 27); // D7 is P0.27 + _DEFPIN_ARM( 8, 0, 26); // D8 is P0.26 + _DEFPIN_ARM( 9, 0, 25); // D9 is P0.25 + _DEFPIN_ARM(10, 0, 5); // D10 is P0.05 (A3) + _DEFPIN_ARM(11, 0, 4); // D11 is P0.04 (A2) + _DEFPIN_ARM(12, 0, 3); // D12 is P0.03 (A1) + _DEFPIN_ARM(13, 0, 2); // D13 is P0.02 (A0 / AREF) + _DEFPIN_ARM(14, 0, 23); // D14 is P0.23 + _DEFPIN_ARM(15, 0, 22); // D15 is P0.22 + _DEFPIN_ARM(16, 0, 18); // D16 is P0.18 + _DEFPIN_ARM(17, 0, 16); // D17 is P0.16 + _DEFPIN_ARM(18, 0, 15); // D18 is P0.15 + _DEFPIN_ARM(19, 0, 24); // D19 is P0.24 + _DEFPIN_ARM(20, 0, 28); // D20 is P0.28 (A4) + _DEFPIN_ARM(21, 0, 29); // D21 is P0.29 (A5) + _DEFPIN_ARM(22, 0, 30); // D22 is P0.30 (A6) + _DEFPIN_ARM(23, 0, 31); // D23 is P0.31 (A7) + _DEFPIN_ARM(24, 0, 19); // D24 is P0.19 (RED LED) + _DEFPIN_ARM(25, 0, 20); // D25 is P0.20 (GREEN LED) + _DEFPIN_ARM(26, 0, 17); // D26 is P0.17 (BLUE LED) +#endif // defined(ARDUINO_ELECTRONUT_HACKABLE) + +// Electronut labs hackaBLE_v2 +// See https://github.com/sandeepmistry/arduino-nRF5/blob/master/variants/hackaBLE_v2/variant.cpp +// (32 pins, natural mapping) +#if defined(ARDUINO_ELECTRONUT_hackaBLE_v2) + #if defined(__FASTPIN_ARM_NRF52_VARIANT_FOUND) + #error "Cannot define more than one board at a time" + #else + #define __FASTPIN_ARM_NRF52_VARIANT_FOUND + #endif + #warning "Electronut labs hackaBLE_v2 is an untested board -- test and let use know your results via https://github.com/FastLED/FastLED/issues" + _DEFPIN_ARM_IDENTITY_P0( 0); // P0.00 + _DEFPIN_ARM_IDENTITY_P0( 1); // P0.01 + _DEFPIN_ARM_IDENTITY_P0( 2); // P0.02 (A0 / SDA / AREF) + _DEFPIN_ARM_IDENTITY_P0( 3); // P0.03 (A1 / SCL ) + _DEFPIN_ARM_IDENTITY_P0( 4); // P0.04 (A2) + _DEFPIN_ARM_IDENTITY_P0( 5); // P0.05 (A3) + _DEFPIN_ARM_IDENTITY_P0( 6); // P0.06 + _DEFPIN_ARM_IDENTITY_P0( 7); // P0.07 (RX) + _DEFPIN_ARM_IDENTITY_P0( 8); // P0.08 (TX) + _DEFPIN_ARM_IDENTITY_P0( 9); // P0.09 + _DEFPIN_ARM_IDENTITY_P0(10); // P0.10 + _DEFPIN_ARM_IDENTITY_P0(11); // P0.11 (SPI MISO) + _DEFPIN_ARM_IDENTITY_P0(12); // P0.12 (SPI MOSI) + _DEFPIN_ARM_IDENTITY_P0(13); // P0.13 (SPI SCK ) + _DEFPIN_ARM_IDENTITY_P0(14); // P0.14 (SPI SS ) + _DEFPIN_ARM_IDENTITY_P0(15); // P0.15 + _DEFPIN_ARM_IDENTITY_P0(16); // P0.16 + _DEFPIN_ARM_IDENTITY_P0(17); // P0.17 (BLUE LED) + _DEFPIN_ARM_IDENTITY_P0(18); // P0.18 + _DEFPIN_ARM_IDENTITY_P0(19); // P0.19 (RED LED) + _DEFPIN_ARM_IDENTITY_P0(20); // P0.20 (GREEN LED) + // _DEFPIN_ARM_IDENTITY_P0(21); // P0.21 (RESET) + _DEFPIN_ARM_IDENTITY_P0(22); // P0.22 + _DEFPIN_ARM_IDENTITY_P0(23); // P0.23 + _DEFPIN_ARM_IDENTITY_P0(24); // P0.24 + _DEFPIN_ARM_IDENTITY_P0(25); // P0.25 + _DEFPIN_ARM_IDENTITY_P0(26); // P0.26 + _DEFPIN_ARM_IDENTITY_P0(27); // P0.27 + _DEFPIN_ARM_IDENTITY_P0(28); // P0.28 (A4) + _DEFPIN_ARM_IDENTITY_P0(29); // P0.29 (A5) + _DEFPIN_ARM_IDENTITY_P0(30); // P0.30 (A6) + _DEFPIN_ARM_IDENTITY_P0(31); // P0.31 (A7) +#endif // defined(ARDUINO_ELECTRONUT_hackaBLE_v2) + +// RedBear Blend 2 +// See https://github.com/sandeepmistry/arduino-nRF5/blob/master/variants/RedBear_Blend2/variant.cpp +#if defined(ARDUINO_RB_BLEND_2) + #if defined(__FASTPIN_ARM_NRF52_VARIANT_FOUND) + #error "Cannot define more than one board at a time" + #else + #define __FASTPIN_ARM_NRF52_VARIANT_FOUND + #endif + #warning "RedBear Blend 2 is an untested board -- test and let use know your results via https://github.com/FastLED/FastLED/issues" + _DEFPIN_ARM( 0, 0, 11); // D0 is P0.11 + _DEFPIN_ARM( 1, 0, 12); // D1 is P0.12 + _DEFPIN_ARM( 2, 0, 13); // D2 is P0.13 + _DEFPIN_ARM( 3, 0, 14); // D3 is P0.14 + _DEFPIN_ARM( 4, 0, 15); // D4 is P0.15 + _DEFPIN_ARM( 5, 0, 16); // D5 is P0.16 + _DEFPIN_ARM( 6, 0, 17); // D6 is P0.17 + _DEFPIN_ARM( 7, 0, 18); // D7 is P0.18 + _DEFPIN_ARM( 8, 0, 19); // D8 is P0.19 + _DEFPIN_ARM( 9, 0, 20); // D9 is P0.20 + _DEFPIN_ARM(10, 0, 22); // D10 is P0.22 (SPI SS ) + _DEFPIN_ARM(11, 0, 23); // D11 is P0.23 (SPI MOSI) + _DEFPIN_ARM(12, 0, 24); // D12 is P0.24 (SPI MISO) + _DEFPIN_ARM(13, 0, 25); // D13 is P0.25 (SPI SCK / LED) + _DEFPIN_ARM(14, 0, 3); // D14 is P0.03 (A0) + _DEFPIN_ARM(15, 0, 4); // D15 is P0.04 (A1) + _DEFPIN_ARM(16, 0, 28); // D16 is P0.28 (A2) + _DEFPIN_ARM(17, 0, 29); // D17 is P0.29 (A3) + _DEFPIN_ARM(18, 0, 30); // D18 is P0.30 (A4) + _DEFPIN_ARM(19, 0, 31); // D19 is P0.31 (A5) + _DEFPIN_ARM(20, 0, 26); // D20 is P0.26 (SDA) + _DEFPIN_ARM(21, 0, 27); // D21 is P0.27 (SCL) + _DEFPIN_ARM(22, 0, 8); // D22 is P0.08 (RX) + _DEFPIN_ARM(23, 0, 6); // D23 is P0.06 (TX) + _DEFPIN_ARM(24, 0, 2); // D24 is P0.02 (AREF) +#endif // defined(ARDUINO_RB_BLEND_2) + +// RedBear BLE Nano 2 +// See https://github.com/sandeepmistry/arduino-nRF5/blob/master/variants/RedBear_BLENano2/variant.cpp +#if defined(ARDUINO_RB_BLE_NANO_2) + #if defined(__FASTPIN_ARM_NRF52_VARIANT_FOUND) + #error "Cannot define more than one board at a time" + #else + #define __FASTPIN_ARM_NRF52_VARIANT_FOUND + #endif + #warning "RedBear BLE Nano 2 is an untested board -- test and let use know your results via https://github.com/FastLED/FastLED/issues" + _DEFPIN_ARM( 0, 0, 30); // D0 is P0.30 (A0 / RX) + _DEFPIN_ARM( 1, 0, 29); // D1 is P0.29 (A1 / TX) + _DEFPIN_ARM( 2, 0, 28); // D2 is P0.28 (A2 / SDA) + _DEFPIN_ARM( 3, 0, 2); // D3 is P0.02 (A3 / SCL) + _DEFPIN_ARM( 4, 0, 5); // D4 is P0.05 (A4) + _DEFPIN_ARM( 5, 0, 4); // D5 is P0.04 (A5) + _DEFPIN_ARM( 6, 0, 3); // D6 is P0.03 (SPI SS ) + _DEFPIN_ARM( 7, 0, 6); // D7 is P0.06 (SPI MOSI) + _DEFPIN_ARM( 8, 0, 7); // D8 is P0.07 (SPI MISO) + _DEFPIN_ARM( 9, 0, 8); // D9 is P0.08 (SPI SCK ) + // _DEFPIN_ARM(10, 0, 21); // D10 is P0.21 (RESET) + _DEFPIN_ARM(13, 0, 11); // D11 is P0.11 (LED) +#endif // defined(ARDUINO_RB_BLE_NANO_2) + +// Nordic Semiconductor nRF52 DK +// See https://github.com/sandeepmistry/arduino-nRF5/blob/master/variants/nRF52DK/variant.cpp +#if defined(ARDUINO_NRF52_DK) + #if defined(__FASTPIN_ARM_NRF52_VARIANT_FOUND) + #error "Cannot define more than one board at a time" + #else + #define __FASTPIN_ARM_NRF52_VARIANT_FOUND + #endif + #warning "Nordic Semiconductor nRF52 DK is an untested board -- test and let use know your results via https://github.com/FastLED/FastLED/issues" + _DEFPIN_ARM( 0, 0, 11); // D0 is P0.11 + _DEFPIN_ARM( 1, 0, 12); // D1 is P0.12 + _DEFPIN_ARM( 2, 0, 13); // D2 is P0.13 (BUTTON1) + _DEFPIN_ARM( 3, 0, 14); // D3 is P0.14 (BUTTON2) + _DEFPIN_ARM( 4, 0, 15); // D4 is P0.15 (BUTTON3) + _DEFPIN_ARM( 5, 0, 16); // D5 is P0.16 (BUTTON4) + _DEFPIN_ARM( 6, 0, 17); // D6 is P0.17 (LED1) + _DEFPIN_ARM( 7, 0, 18); // D7 is P0.18 (LED2) + _DEFPIN_ARM( 8, 0, 19); // D8 is P0.19 (LED3) + _DEFPIN_ARM( 9, 0, 20); // D9 is P0.20 (LED4) + _DEFPIN_ARM(10, 0, 22); // D10 is P0.22 (SPI SS ) + _DEFPIN_ARM(11, 0, 23); // D11 is P0.23 (SPI MOSI) + _DEFPIN_ARM(12, 0, 24); // D12 is P0.24 (SPI MISO) + _DEFPIN_ARM(13, 0, 25); // D13 is P0.25 (SPI SCK / LED) + _DEFPIN_ARM(14, 0, 3); // D14 is P0.03 (A0) + _DEFPIN_ARM(15, 0, 4); // D15 is P0.04 (A1) + _DEFPIN_ARM(16, 0, 28); // D16 is P0.28 (A2) + _DEFPIN_ARM(17, 0, 29); // D17 is P0.29 (A3) + _DEFPIN_ARM(18, 0, 30); // D18 is P0.30 (A4) + _DEFPIN_ARM(19, 0, 31); // D19 is P0.31 (A5) + _DEFPIN_ARM(20, 0, 5); // D20 is P0.05 (A6) + _DEFPIN_ARM(21, 0, 2); // D21 is P0.02 (A7 / AREF) + _DEFPIN_ARM(22, 0, 26); // D22 is P0.26 (SDA) + _DEFPIN_ARM(23, 0, 27); // D23 is P0.27 (SCL) + _DEFPIN_ARM(24, 0, 8); // D24 is P0.08 (RX) + _DEFPIN_ARM(25, 0, 6); // D25 is P0.06 (TX) +#endif // defined(ARDUINO_NRF52_DK) + +// Taida Century nRF52 mini board +// https://github.com/sandeepmistry/arduino-nRF5/blob/master/variants/Taida_Century_nRF52_minidev/variant.cpp +#if defined(ARDUINO_STCT_NRF52_minidev) + #if defined(__FASTPIN_ARM_NRF52_VARIANT_FOUND) + #error "Cannot define more than one board at a time" + #else + #define __FASTPIN_ARM_NRF52_VARIANT_FOUND + #endif + #warning "Taida Century nRF52 mini board is an untested board -- test and let use know your results via https://github.com/FastLED/FastLED/issues" + //_DEFPIN_ARM( 0, 0, 25); // D0 is P0.xx (near radio!) + //_DEFPIN_ARM( 1, 0, 26); // D1 is P0.xx (near radio!) + //_DEFPIN_ARM( 2, 0, 27); // D2 is P0.xx (near radio!) + //_DEFPIN_ARM( 3, 0, 28); // D3 is P0.xx (near radio!) + //_DEFPIN_ARM( 4, 0, 29); // D4 is P0.xx (Not connected, near radio!) + //_DEFPIN_ARM( 5, 0, 30); // D5 is P0.xx (LED1, near radio!) + //_DEFPIN_ARM( 6, 0, 31); // D6 is P0.xx (LED2, near radio!) + _DEFPIN_ARM( 7, 0, 2); // D7 is P0.xx (SDA) + _DEFPIN_ARM( 8, 0, 3); // D8 is P0.xx (SCL) + _DEFPIN_ARM( 9, 0, 4); // D9 is P0.xx (BUTTON1 / NFC1) + _DEFPIN_ARM(10, 0, 5); // D10 is P0.xx + //_DEFPIN_ARM(11, 0, 0); // D11 is P0.xx (Not connected) + //_DEFPIN_ARM(12, 0, 1); // D12 is P0.xx (Not connected) + _DEFPIN_ARM(13, 0, 6); // D13 is P0.xx + _DEFPIN_ARM(14, 0, 7); // D14 is P0.xx + _DEFPIN_ARM(15, 0, 8); // D15 is P0.xx + //_DEFPIN_ARM(16, 0, 9); // D16 is P0.xx (Not connected) + //_DEFPIN_ARM(17, 0, 10); // D17 is P0.xx (NFC2, Not connected) + _DEFPIN_ARM(18, 0, 11); // D18 is P0.xx (RXD) + _DEFPIN_ARM(19, 0, 12); // D19 is P0.xx (TXD) + _DEFPIN_ARM(20, 0, 13); // D20 is P0.xx (SPI SS ) + _DEFPIN_ARM(21, 0, 14); // D21 is P0.xx (SPI MISO) + _DEFPIN_ARM(22, 0, 15); // D22 is P0.xx (SPI MOSI) + _DEFPIN_ARM(23, 0, 16); // D23 is P0.xx (SPI SCK ) + _DEFPIN_ARM(24, 0, 17); // D24 is P0.xx (A0) + _DEFPIN_ARM(25, 0, 18); // D25 is P0.xx (A1) + _DEFPIN_ARM(26, 0, 19); // D26 is P0.xx (A2) + _DEFPIN_ARM(27, 0, 20); // D27 is P0.xx (A3) + //_DEFPIN_ARM(28, 0, 22); // D28 is P0.xx (A4, near radio!) + //_DEFPIN_ARM(29, 0, 23); // D29 is P0.xx (A5, near radio!) + _DEFPIN_ARM(30, 0, 24); // D30 is P0.xx + // _DEFPIN_ARM(31, 0, 21); // D31 is P0.21 (RESET) +#endif // defined(ARDUINO_STCT_NRF52_minidev) + +// Generic nRF52832 +// See https://github.com/sandeepmistry/arduino-nRF5/blob/master/boards.txt +#if defined(ARDUINO_GENERIC) && (\ + defined(NRF52832_XXAA) || defined(NRF52832_XXAB)\ + ) + #if defined(__FASTPIN_ARM_NRF52_VARIANT_FOUND) + #error "Cannot define more than one board at a time" + #else + #define __FASTPIN_ARM_NRF52_VARIANT_FOUND + #endif + #warning "Using `generic` NRF52832 board is an untested configuration -- test and let use know your results via https://github.com/FastLED/FastLED/issues" + + _DEFPIN_ARM_IDENTITY_P0( 0); // P0.00 ( UART RX + _DEFPIN_ARM_IDENTITY_P0( 1); // P0.01 (A0, UART TX) + _DEFPIN_ARM_IDENTITY_P0( 2); // P0.02 (A1) + _DEFPIN_ARM_IDENTITY_P0( 3); // P0.03 (A2) + _DEFPIN_ARM_IDENTITY_P0( 4); // P0.04 (A3) + _DEFPIN_ARM_IDENTITY_P0( 5); // P0.05 (A4) + _DEFPIN_ARM_IDENTITY_P0( 6); // P0.06 (A5) + _DEFPIN_ARM_IDENTITY_P0( 7); // P0.07 + _DEFPIN_ARM_IDENTITY_P0( 8); // P0.08 + _DEFPIN_ARM_IDENTITY_P0( 9); // P0.09 + _DEFPIN_ARM_IDENTITY_P0(10); // P0.10 + _DEFPIN_ARM_IDENTITY_P0(11); // P0.11 + _DEFPIN_ARM_IDENTITY_P0(12); // P0.12 + _DEFPIN_ARM_IDENTITY_P0(13); // P0.13 (LED) + _DEFPIN_ARM_IDENTITY_P0(14); // P0.14 + _DEFPIN_ARM_IDENTITY_P0(15); // P0.15 + _DEFPIN_ARM_IDENTITY_P0(16); // P0.16 + _DEFPIN_ARM_IDENTITY_P0(17); // P0.17 + _DEFPIN_ARM_IDENTITY_P0(18); // P0.18 + _DEFPIN_ARM_IDENTITY_P0(19); // P0.19 + _DEFPIN_ARM_IDENTITY_P0(20); // P0.20 (I2C SDA) + _DEFPIN_ARM_IDENTITY_P0(21); // P0.21 (I2C SCL) + _DEFPIN_ARM_IDENTITY_P0(22); // P0.22 (SPI MISO) + _DEFPIN_ARM_IDENTITY_P0(23); // P0.23 (SPI MOSI) + _DEFPIN_ARM_IDENTITY_P0(24); // P0.24 (SPI SCK ) + _DEFPIN_ARM_IDENTITY_P0(25); // P0.25 (SPI SS ) + _DEFPIN_ARM_IDENTITY_P0(26); // P0.26 + _DEFPIN_ARM_IDENTITY_P0(27); // P0.27 + _DEFPIN_ARM_IDENTITY_P0(28); // P0.28 + _DEFPIN_ARM_IDENTITY_P0(29); // P0.29 + _DEFPIN_ARM_IDENTITY_P0(30); // P0.30 + _DEFPIN_ARM_IDENTITY_P0(31); // P0.31 +#endif // defined(ARDUINO_GENERIC) + + +#endif // __FASTPIN_ARM_NRF52_VARIANTS_H
\ No newline at end of file diff --git a/platforms/arm/nrf52/fastspi_arm_nrf52.h b/platforms/arm/nrf52/fastspi_arm_nrf52.h new file mode 100644 index 00000000..8492282b --- /dev/null +++ b/platforms/arm/nrf52/fastspi_arm_nrf52.h @@ -0,0 +1,341 @@ +#ifndef __FASTSPI_ARM_NRF52_H +#define __FASTSPI_ARM_NRF52_H + + +#ifndef FASTLED_FORCE_SOFTWARE_SPI + + #include <nrf_spim.h> + + #define FASTLED_ALL_PINS_HARDWARE_SPI + + + // NRF52810 has SPIM0: Frequencies from 125kbps to 8Mbps + // NRF52832 adds SPIM1, SPIM2 (same frequencies) + // NRF52840 adds SPIM3 (same frequencies), adds SPIM3 that can be @ up to 32Mbps frequency(!) + #if !defined(FASTLED_NRF52_SPIM) + #define FASTLED_NRF52_SPIM NRF_SPIM0 + #endif + + /* This class is slightly simpler than fastpin, as it can rely on fastpin + * to handle the mapping to the underlying PN.XX board-level pins... + */ + + /// SPI_CLOCK_DIVIDER is number of CPU clock cycles per SPI transmission bit? + template <uint8_t _DATA_PIN, uint8_t _CLOCK_PIN, uint8_t _SPI_CLOCK_DIVIDER> + class NRF52SPIOutput { + + private: + // static variables -- always using same SPIM instance + static bool s_InUse; + static bool s_NeedToWait; // a data transfer was started, and completion event was not cleared. + + /* + // TODO -- Workaround nRF52840 errata #198, which relates to + // contention between SPIM3 and CPU over AHB. + // The workaround is to ensure the SPIM TX buffer + // is on a different / dedicated RAM block. + // This also avoids AHB contention generally, so + // should be applied to all supported boards. + // + // But... how to allocate m_Buffer[] to be at a + // specific memory range? Also, might need to + // avoid use of single-transaction writeBytes() + // as cannot control where that memory lies.... + */ + static uint8_t s_BufferIndex; + static uint8_t s_Buffer[2][2]; // 2x two-byte buffers, allows one buffer currently being sent, and a second one being prepped to send. + + // This allows saving the configuration of the SPIM instance + // upon select(), and restoring the configuration upon release(). + struct spim_config { + uint32_t inten; + uint32_t shorts; + uint32_t sck_pin; + uint32_t mosi_pin; + uint32_t miso_pin; + uint32_t frequency; + // data pointers, RX/TX counts not saved as would only hide bugs + uint32_t config; // mode & bit order + uint32_t orc; + +#if false // additional configuration to save/restore for SPIM3 + uint32_t csn_pin; + uint32_t csn_polarity; // CSNPOL + uint32_t csn_duration; // IFTIMING.CSNDUR + uint32_t rx_delay; // IFTIMING.RXDELAY + uint32_t dcx_pin; // PSELDCX + uint32_t dcx_config; // DCXCNT +#endif + + } m_SpiSavedConfig; + void saveSpimConfig() { + m_SpiSavedConfig.inten = FASTLED_NRF52_SPIM->INTENSET; + m_SpiSavedConfig.shorts = FASTLED_NRF52_SPIM->SHORTS; + m_SpiSavedConfig.sck_pin = FASTLED_NRF52_SPIM->PSEL.SCK; + m_SpiSavedConfig.mosi_pin = FASTLED_NRF52_SPIM->PSEL.MOSI; + m_SpiSavedConfig.miso_pin = FASTLED_NRF52_SPIM->PSEL.MISO; + m_SpiSavedConfig.frequency = FASTLED_NRF52_SPIM->FREQUENCY; + m_SpiSavedConfig.config = FASTLED_NRF52_SPIM->CONFIG; + m_SpiSavedConfig.orc = FASTLED_NRF52_SPIM->ORC; + +#if false // additional configuration to save/restore for SPIM3 + m_SpiSavedConfig.csn_pin = FASTLED_NRF52_SPIM->PSEL.CSN; + m_SpiSavedConfig.csn_polarity = FASTLED_NRF52_SPIM->CSNPOL; + m_SpiSavedConfig.csn_duration = FASTLED_NRF52_SPIM->IFTIMING.CSNDUR; + m_SpiSavedConfig.dcx_pin = FASTLED_NRF52_SPIM->PSELDCX; + m_SpiSavedConfig.dcx_config = FASTLED_NRF52_SPIM->DCXCNT; +#endif + } + void restoreSpimConfig() { + // 0. ASSERT() the SPIM instance is not enabled + + FASTLED_NRF52_SPIM->INTENCLR = 0xFFFFFFFF; + FASTLED_NRF52_SPIM->INTENSET = m_SpiSavedConfig.inten; + FASTLED_NRF52_SPIM->SHORTS = m_SpiSavedConfig.shorts; + FASTLED_NRF52_SPIM->PSEL.SCK = m_SpiSavedConfig.sck_pin; + FASTLED_NRF52_SPIM->PSEL.MOSI = m_SpiSavedConfig.mosi_pin; + FASTLED_NRF52_SPIM->PSEL.MISO = m_SpiSavedConfig.miso_pin; + FASTLED_NRF52_SPIM->FREQUENCY = m_SpiSavedConfig.frequency; + FASTLED_NRF52_SPIM->CONFIG = m_SpiSavedConfig.config; + FASTLED_NRF52_SPIM->ORC = m_SpiSavedConfig.orc; + +#if false // additional configuration to save/restore for SPIM3 + FASTLED_NRF52_SPIM->PSEL.CSN = m_SpiSavedConfig.csn_pin; + FASTLED_NRF52_SPIM->CSNPOL = m_SpiSavedConfig.csn_polarity; + FASTLED_NRF52_SPIM->IFTIMING.CSNDUR = m_SpiSavedConfig.csn_duration; + FASTLED_NRF52_SPIM->PSELDCX = m_SpiSavedConfig.dcx_pin; + FASTLED_NRF52_SPIM->DCXCNT = m_SpiSavedConfig.dcx_config; +#endif + } + + public: + NRF52SPIOutput() {} + + // Low frequency GPIO is for signals with a frequency up to 10 kHz. Lowest speed SPIM is 125kbps. + static_assert(!FastPin<_DATA_PIN>::LowSpeedOnlyRecommended(), "Invalid (low-speed only) pin specified"); + static_assert(!FastPin<_CLOCK_PIN>::LowSpeedOnlyRecommended(), "Invalid (low-speed only) pin specified"); + + /// initialize the SPI subssytem + void init() { + // 0. ASSERT() the SPIM instance is not enabled / in use + //ASSERT(m_SPIM->ENABLE != (SPIM_ENABLE_ENABLE_Enabled << SPIM_ENABLE_ENABLE_Pos)); + + // 1. set pins to output/H0H1 drive/etc. + FastPin<_DATA_PIN>::setOutput(); + FastPin<_CLOCK_PIN>::setOutput(); + + // 2. Configure SPIMx + nrf_spim_configure( + FASTLED_NRF52_SPIM, + NRF_SPIM_MODE_0, + NRF_SPIM_BIT_ORDER_MSB_FIRST + ); + nrf_spim_frequency_set( + FASTLED_NRF52_SPIM, + NRF_SPIM_FREQ_4M // BUGBUG -- use _SPI_CLOCK_DIVIDER to determine frequency + ); + nrf_spim_pins_set( + FASTLED_NRF52_SPIM, + FastPin<_CLOCK_PIN>::nrf_pin(), + FastPin<_DATA_PIN>::nrf_pin(), + NRF_SPIM_PIN_NOT_CONNECTED + ); + + // 4. Ensure events are cleared + nrf_spim_event_clear(FASTLED_NRF52_SPIM, NRF_SPIM_EVENT_END); + nrf_spim_event_clear(FASTLED_NRF52_SPIM, NRF_SPIM_EVENT_STARTED); + + // 5. Enable the SPIM instance + nrf_spim_enable(FASTLED_NRF52_SPIM); + } + + /// latch the CS select + void select() { + //ASSERT(!s_InUse); + saveSpimConfig(); + s_InUse = true; + init(); + } + + /// release the CS select + void release() { + //ASSERT(s_InUse); + waitFully(); + s_InUse = false; + restoreSpimConfig(); + } + + /// wait until all queued up data has been written + static void waitFully() { + if (!s_NeedToWait) return; + // else, need to wait for END event + while(!FASTLED_NRF52_SPIM->EVENTS_END) {}; + s_NeedToWait = 0; + // only use two events in this code... + nrf_spim_event_clear(FASTLED_NRF52_SPIM, NRF_SPIM_EVENT_END); + nrf_spim_event_clear(FASTLED_NRF52_SPIM, NRF_SPIM_EVENT_STARTED); + return; + } + // wait only until we can add a new transaction into the registers + // (caller must still waitFully() before actually starting this next transaction) + static void wait() { + if (!s_NeedToWait) return; + while (!FASTLED_NRF52_SPIM->EVENTS_STARTED) {}; + // leave the event set here... caller must waitFully() and start next transaction + return; + } + + /// write a byte out via SPI (returns immediately on writing register) + static void writeByte(uint8_t b) { + wait(); + // cannot use pointer to stack, so copy to m_buffer[] + uint8_t i = (s_BufferIndex ? 1u : 0u); + s_BufferIndex = !s_BufferIndex; // 1 <==> 0 swap + + s_Buffer[i][0u] = b; // cannot use the stack location, so copy to a more permanent buffer... + nrf_spim_tx_buffer_set( + FASTLED_NRF52_SPIM, + &(s_Buffer[i][0u]), + 1 + ); + + waitFully(); + nrf_spim_task_trigger( + FASTLED_NRF52_SPIM, + NRF_SPIM_TASK_START + ); + return; + } + + /// write a word out via SPI (returns immediately on writing register) + static void writeWord(uint16_t w) { + wait(); + // cannot use pointer to stack, so copy to m_buffer[] + uint8_t i = (s_BufferIndex ? 1u : 0u); + s_BufferIndex = !s_BufferIndex; // 1 <==> 0 swap + + s_Buffer[i][0u] = (w >> 8u); // cannot use the stack location, so copy to a more permanent buffer... + s_Buffer[i][1u] = (w & 0xFFu); // cannot use the stack location, so copy to a more permanent buffer... + nrf_spim_tx_buffer_set( + FASTLED_NRF52_SPIM, + &(s_Buffer[i][0u]), + 2 + ); + + waitFully(); + nrf_spim_task_trigger( + FASTLED_NRF52_SPIM, + NRF_SPIM_TASK_START + ); + return; + } + + /// A raw set of writing byte values, assumes setup/init/waiting done elsewhere (static for use by adjustment classes) + static void writeBytesValueRaw(uint8_t value, int len) { + while (len--) { writeByte(value); } + } + + /// A full cycle of writing a value for len bytes, including select, release, and waiting + void writeBytesValue(uint8_t value, int len) { + select(); + writeBytesValueRaw(value, len); + waitFully(); + release(); + } + + /// A full cycle of writing a raw block of data out, including select, release, and waiting + void writeBytes(uint8_t *data, int len) { + // This is a special-case, with no adjustment of the bytes... write them directly... + select(); + wait(); + nrf_spim_tx_buffer_set( + FASTLED_NRF52_SPIM, + data, + len + ); + waitFully(); + nrf_spim_task_trigger( + FASTLED_NRF52_SPIM, + NRF_SPIM_TASK_START + ); + waitFully(); + release(); + } + + /// A full cycle of writing a raw block of data out, including select, release, and waiting + template<class D> void writeBytes(uint8_t *data, int len) { + uint8_t * end = data + len; + select(); + wait(); + while(data != end) { + writeByte(D::adjust(*data++)); + } + D::postBlock(len); + waitFully(); + release(); + } + /// specialization for DATA_NOP ... + //template<DATA_NOP> void writeBytes(uint8_t * data, int len) { + // writeBytes(data, len); + //} + + /// write a single bit out, which bit from the passed in byte is determined by template parameter + template <uint8_t BIT> inline static void writeBit(uint8_t b) { + // SPIM instance must be finished transmitting and then disabled + waitFully(); + nrf_spim_disable(FASTLED_NRF52_SPIM); + // set the data pin to appropriate state + if (b & (1 << BIT)) { + FastPin<_DATA_PIN>::hi(); + } else { + FastPin<_DATA_PIN>::lo(); + } + // delay 1/2 cycle per SPI bit + delaycycles<_SPI_CLOCK_DIVIDER/2>(); + FastPin<_CLOCK_PIN>::toggle(); + delaycycles<_SPI_CLOCK_DIVIDER/2>(); + FastPin<_CLOCK_PIN>::toggle(); + // re-enable the SPIM instance + nrf_spim_enable(FASTLED_NRF52_SPIM); + } + + /// write out pixel data from the given PixelController object, including select, release, and waiting + template <uint8_t FLAGS, class D, EOrder RGB_ORDER> void writePixels(PixelController<RGB_ORDER> pixels) { + select(); + int len = pixels.mLen; + // TODO: If user indicates a pre-allocated double-buffer, + // then process all the pixels at once into that buffer, + // then use the non-templated WriteBytes(data, len) function + // to write the entire buffer as a single SPI transaction. + while (pixels.has(1)) { + if (FLAGS & FLAG_START_BIT) { + writeBit<0>(1); + } + writeByte(D::adjust(pixels.loadAndScale0())); + writeByte(D::adjust(pixels.loadAndScale1())); + writeByte(D::adjust(pixels.loadAndScale2())); + pixels.advanceData(); + pixels.stepDithering(); + } + D::postBlock(len); + waitFully(); + release(); + } + }; + + // Static member definition and initialization using templates. + // see https://stackoverflow.com/questions/3229883/static-member-initialization-in-a-class-template#answer-3229919 + template <uint8_t _DATA_PIN, uint8_t _CLOCK_PIN, uint8_t _SPI_CLOCK_DIVIDER> + bool NRF52SPIOutput<_DATA_PIN, _CLOCK_PIN, _SPI_CLOCK_DIVIDER>::s_InUse = false; + template <uint8_t _DATA_PIN, uint8_t _CLOCK_PIN, uint8_t _SPI_CLOCK_DIVIDER> + bool NRF52SPIOutput<_DATA_PIN, _CLOCK_PIN, _SPI_CLOCK_DIVIDER>::s_NeedToWait = false; + template <uint8_t _DATA_PIN, uint8_t _CLOCK_PIN, uint8_t _SPI_CLOCK_DIVIDER> + uint8_t NRF52SPIOutput<_DATA_PIN, _CLOCK_PIN, _SPI_CLOCK_DIVIDER>::s_BufferIndex = 0; + template <uint8_t _DATA_PIN, uint8_t _CLOCK_PIN, uint8_t _SPI_CLOCK_DIVIDER> + uint8_t NRF52SPIOutput<_DATA_PIN, _CLOCK_PIN, _SPI_CLOCK_DIVIDER>::s_Buffer[2][2] = {{0,0},{0,0}}; + +#endif // #ifndef FASTLED_FORCE_SOFTWARE_SPI + + + +#endif // #ifndef __FASTPIN_ARM_NRF52_H diff --git a/platforms/arm/nrf52/led_sysdefs_arm_nrf52.h b/platforms/arm/nrf52/led_sysdefs_arm_nrf52.h new file mode 100644 index 00000000..440aed9e --- /dev/null +++ b/platforms/arm/nrf52/led_sysdefs_arm_nrf52.h @@ -0,0 +1,58 @@ +#ifndef __LED_SYSDEFS_ARM_NRF52 +#define __LED_SYSDEFS_ARM_NRF52 + +#define FASTLED_ARM + +#ifndef F_CPU + #define F_CPU 64000000 // the NRF52 series has a 64MHz CPU +#endif + +// even though CPU is at 64MHz, use the 8MHz-defined timings because... +// PWM module runs at 16MHz +// SPI0..2 runs at 8MHz +#define CLOCKLESS_FREQUENCY 16000000 // the NRF52 has EasyDMA for PWM module at 16MHz + +#ifndef F_TIMER + #define F_TIMER 16000000 // the NRF52 timer is 16MHz, even though CPU is 64MHz +#endif + +#if !defined(FASTLED_USE_PROGMEM) + #define FASTLED_USE_PROGMEM 0 // nRF52 series have flat memory model +#endif + +#if !defined(FASTLED_ALLOW_INTERRUPTS) + #define FASTLED_ALLOW_INTERRUPTS 1 +#endif + +// Use PWM instance 0 +// See clockless_arm_nrf52.h and (in root of library) platforms.cpp +#define FASTLED_NRF52_ENABLE_PWM_INSTANCE0 + +#if defined(FASTLED_NRF52_NEVER_INLINE) + #define FASTLED_NRF52_INLINE_ATTRIBUTE __attribute__((always_inline)) inline +#else + #define FASTLED_NRF52_INLINE_ATTRIBUTE __attribute__((always_inline)) inline +#endif + + + +#include <nrf.h> +#include <nrf_spim.h> // for FastSPI +#include <nrf_pwm.h> // for Clockless +#include <nrf_nvic.h> // for Clockless / anything else using interrupts +typedef __I uint32_t RoReg; +typedef __IO uint32_t RwReg; + +#define cli() __disable_irq() +#define sei() __enable_irq() + +#define FASTLED_NRF52_DEBUGPRINT(format, ...) +//#define FASTLED_NRF52_DEBUGPRINT(format, ...)\ +// do {\ +// FastLED_NRF52_DebugPrint(format, ##__VA_ARGS__);\ +// } while(0); + + + + +#endif // __LED_SYSDEFS_ARM_NRF52 |