Skip to content
Permalink
Browse files

Enable support for nRF52 chipset. (#802)

LED strings for clockless are temporarily limited to 144 LEDs,
adjustable via led_sysdefs.h #define.
  • Loading branch information...
henrygab authored and focalintent committed Jun 7, 2019
1 parent fe94a0c commit 3698f8390e1de5628ed6025db133bbc54c14576d
@@ -428,17 +428,33 @@ class SM16716Controller : public CPixelLEDController<RGB_ORDER> {
//
// 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
/// @name clockless controllers
/// 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)
@@ -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"
@@ -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
@@ -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"
@@ -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

0 comments on commit 3698f83

Please sign in to comment.
You can’t perform that action at this time.