Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/FastLED/FastLED.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHenry Gabryjelski <henrygab@users.noreply.github.com>2019-06-07 07:03:24 +0300
committerDaniel Garcia <danielgarcia@gmail.com>2019-06-07 07:03:24 +0300
commit3698f8390e1de5628ed6025db133bbc54c14576d (patch)
treea2bc8f6f1ef1a14e8ae3552cf2808aea2f9ba8eb
parentfe94a0ce3b71f368a81eed5685f6082df80894c3 (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.h69
-rw-r--r--fastspi.h5
-rw-r--r--led_sysdefs.h2
-rw-r--r--platforms.cpp40
-rw-r--r--platforms.h2
-rw-r--r--platforms/arm/nrf52/arbiter_nrf52.h115
-rw-r--r--platforms/arm/nrf52/clockless_arm_nrf52.h371
-rw-r--r--platforms/arm/nrf52/fastled_arm_nrf52.h11
-rw-r--r--platforms/arm/nrf52/fastpin_arm_nrf52.h328
-rw-r--r--platforms/arm/nrf52/fastpin_arm_nrf52_variants.h579
-rw-r--r--platforms/arm/nrf52/fastspi_arm_nrf52.h341
-rw-r--r--platforms/arm/nrf52/led_sysdefs_arm_nrf52.h58
12 files changed, 1897 insertions, 24 deletions
diff --git a/chipsets.h b/chipsets.h
index 97ddc947..5651d280 100644
--- a/chipsets.h
+++ b/chipsets.h
@@ -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
///@}
diff --git a/fastspi.h b/fastspi.h
index 8e2a593b..fc0843be 100644
--- a/fastspi.h
+++ b/fastspi.h
@@ -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