First commit.

This commit is contained in:
2020-07-17 18:55:06 +02:00
commit b47a0ab935
247 changed files with 30192 additions and 0 deletions

View File

@ -0,0 +1,83 @@
#ifndef __INC_CLOCKLESS_ARM_NRF51
#define __INC_CLOCKLESS_ARM_NRF51
#if defined(NRF51)
#include <nrf51_bitfields.h>
#define FASTLED_HAS_CLOCKLESS 1
#if (FASTLED_ALLOW_INTERRUPTS==1)
#define SEI_CHK LED_TIMER->CC[0] = (WAIT_TIME * (F_CPU/1000000)); LED_TIMER->TASKS_CLEAR; LED_TIMER->EVENTS_COMPARE[0] = 0;
#define CLI_CHK cli(); if(LED_TIMER->EVENTS_COMPARE[0]) { LED_TIMER->TASKS_STOP = 1; return 0; }
#define INNER_SEI sei();
#else
#define SEI_CHK
#define CLI_CHK
#define INNER_SEI delaycycles<1>();
#endif
#include "../common/m0clockless.h"
template <uint8_t DATA_PIN, int T1, int T2, int T3, EOrder RGB_ORDER = RGB, int XTRA0 = 0, bool FLIP = false, int WAIT_TIME = 75>
class ClocklessController : public CPixelLEDController<RGB_ORDER> {
typedef typename FastPinBB<DATA_PIN>::port_ptr_t data_ptr_t;
typedef typename FastPinBB<DATA_PIN>::port_t data_t;
data_t mPinMask;
data_ptr_t mPort;
CMinWait<WAIT_TIME> mWait;
public:
virtual void init() {
FastPinBB<DATA_PIN>::setOutput();
mPinMask = FastPinBB<DATA_PIN>::mask();
mPort = FastPinBB<DATA_PIN>::port();
}
virtual uint16_t getMaxRefreshRate() const { return 400; }
virtual void showPixels(PixelController<RGB_ORDER> & pixels) {
mWait.wait();
cli();
if(!showRGBInternal(pixels)) {
sei(); delayMicroseconds(WAIT_TIME); cli();
showRGBInternal(pixels);
}
sei();
mWait.mark();
}
// This method is made static to force making register Y available to use for data on AVR - if the method is non-static, then
// gcc will use register Y for the this pointer.
static uint32_t showRGBInternal(PixelController<RGB_ORDER> pixels) {
struct M0ClocklessData data;
data.d[0] = pixels.d[0];
data.d[1] = pixels.d[1];
data.d[2] = pixels.d[2];
data.s[0] = pixels.mScale[0];
data.s[1] = pixels.mScale[1];
data.s[2] = pixels.mScale[2];
data.e[0] = pixels.e[0];
data.e[1] = pixels.e[1];
data.e[2] = pixels.e[2];
data.adj = pixels.mAdvance;
typename FastPin<DATA_PIN>::port_ptr_t portBase = FastPin<DATA_PIN>::port();
// timer mode w/prescaler of 0
LED_TIMER->MODE = TIMER_MODE_MODE_Timer;
LED_TIMER->PRESCALER = 0;
LED_TIMER->EVENTS_COMPARE[0] = 0;
LED_TIMER->BITMODE = TIMER_BITMODE_BITMODE_16Bit;
LED_TIMER->SHORTS = TIMER_SHORTS_COMPARE0_CLEAR_Msk;
LED_TIMER->TASKS_START = 1;
int ret = showLedData<4,8,T1,T2,T3,RGB_ORDER,WAIT_TIME>(portBase, FastPin<DATA_PIN>::mask(), pixels.mData, pixels.mLen, &data);
LED_TIMER->TASKS_STOP = 1;
return ret; // 0x00FFFFFF - _VAL;
}
};
#endif // NRF51
#endif // __INC_CLOCKLESS_ARM_NRF51

View File

@ -0,0 +1,9 @@
#ifndef __INC_FASTLED_ARM_NRF51_H
#define __INC_FASTLED_ARM_NRF51_H
// Include the k20 headers
#include "fastpin_arm_nrf51.h"
#include "fastspi_arm_nrf51.h"
#include "clockless_arm_nrf51.h"
#endif

View File

@ -0,0 +1,119 @@
#ifndef __FASTPIN_ARM_NRF51_H
#define __FASTPIN_ARM_NRF51_H
#if defined(NRF51)
/// Template definition for teensy 3.0 style ARM pins, providing direct access to the various GPIO registers. Note that this
/// uses the full port GPIO registers. In theory, in some way, bit-band register access -should- be faster, however I have found
/// that something about the way gcc does register allocation results in the bit-band code being slower. It will need more fine tuning.
/// The registers are data output, set output, clear output, toggle output, input, and direction
#if 0
template<uint8_t PIN, uint32_t _MASK, typename _DIRSET, typename _DIRCLR, typename _OUTSET, typename _OUTCLR, typename _OUT> class _ARMPIN {
public:
typedef volatile uint32_t * port_ptr_t;
typedef uint32_t port_t;
inline static void setOutput() { _DIRSET::r() = _MASK; }
inline static void setInput() { _DIRCLR::r() = _MASK; }
inline static void hi() __attribute__ ((always_inline)) { _OUTSET::r() = _MASK; }
inline static void lo() __attribute__ ((always_inline)) { _OUTCLR::r() = _MASK; }
inline static void set(register port_t val) __attribute__ ((always_inline)) { _OUT::r() = val; }
inline static void strobe() __attribute__ ((always_inline)) { toggle(); toggle(); }
inline static void toggle() __attribute__ ((always_inline)) { _OUT::r() ^= _MASK; }
inline static void hi(register port_ptr_t port) __attribute__ ((always_inline)) { hi(); }
inline static void lo(register port_ptr_t port) __attribute__ ((always_inline)) { lo(); }
inline static void fastset(register port_ptr_t port, register port_t val) __attribute__ ((always_inline)) { *port = val; }
inline static port_t hival() __attribute__ ((always_inline)) { return _OUT::r() | _MASK; }
inline static port_t loval() __attribute__ ((always_inline)) { return _OUT::r() & ~_MASK; }
inline static port_ptr_t port() __attribute__ ((always_inline)) { return &_OUT::r(); }
inline static port_t mask() __attribute__ ((always_inline)) { return _MASK; }
};
#define ADDR(X) *(volatile uint32_t*)X
#define NR_GPIO_ADDR(base,offset) (*(volatile uint32_t *))((uint32_t)(base + offset))
#define NR_DIRSET ADDR(0x50000518UL) // NR_GPIO_ADDR(NRF_GPIO_BASE, 0x518)
#define NR_DIRCLR ADDR(0x5000051CUL) // NR_GPIO_ADDR(NRF_GPIO_BASE, 0x51C)
#define NR_OUTSET ADDR(0x50000508UL) // NR_GPIO_ADDR(NRF_GPIO_BASE, 0x508)
#define NR_OUTCLR ADDR(0x5000050CUL) // NR_GPIO_ADDR(NRF_GPIO_BASE, 0x50C)
#define NR_OUT ADDR(0x50000504UL) // NR_GPIO_ADDR(NRF_GPIO_BASE, 0x504)
#define _RD32_NRF(T) struct __gen_struct_ ## T { static __attribute__((always_inline)) inline reg32_t r() { return T; }};
_RD32_NRF(NR_DIRSET);
_RD32_NRF(NR_DIRCLR);
_RD32_NRF(NR_OUTSET);
_RD32_NRF(NR_OUTCLR);
_RD32_NRF(NR_OUT);
#define _FL_DEFPIN(PIN) template<> class FastPin<PIN> : public _ARMPIN<PIN, 1 << PIN, \
_R(NR_DIRSET), _R(NR_DIRCLR), _R(NR_OUTSET), _R(NR_OUTCLR), _R(NR_OUT)> {};
#else
typedef struct { /*!< GPIO Structure */
// __I uint32_t RESERVED0[321];
__IO uint32_t OUT; /*!< Write GPIO port. */
__IO uint32_t OUTSET; /*!< Set individual bits in GPIO port. */
__IO uint32_t OUTCLR; /*!< Clear individual bits in GPIO port. */
__I uint32_t IN; /*!< Read GPIO port. */
__IO uint32_t DIR; /*!< Direction of GPIO pins. */
__IO uint32_t DIRSET; /*!< DIR set register. */
__IO uint32_t DIRCLR; /*!< DIR clear register. */
__I uint32_t RESERVED1[120];
__IO uint32_t PIN_CNF[32]; /*!< Configuration of GPIO pins. */
} FL_NRF_GPIO_Type;
#define FL_NRF_GPIO_BASE 0x50000504UL
#define FL_NRF_GPIO ((FL_NRF_GPIO_Type *) FL_NRF_GPIO_BASE)
template<uint8_t PIN, uint32_t _MASK> class _ARMPIN {
public:
typedef volatile uint32_t * port_ptr_t;
typedef uint32_t port_t;
inline static void setOutput() { FL_NRF_GPIO->DIRSET = _MASK; }
inline static void setInput() { FL_NRF_GPIO->DIRCLR = _MASK; }
inline static void hi() __attribute__ ((always_inline)) { FL_NRF_GPIO->OUTSET = _MASK; }
inline static void lo() __attribute__ ((always_inline)) { FL_NRF_GPIO->OUTCLR= _MASK; }
inline static void set(register port_t val) __attribute__ ((always_inline)) { FL_NRF_GPIO->OUT = val; }
inline static void strobe() __attribute__ ((always_inline)) { toggle(); toggle(); }
inline static void toggle() __attribute__ ((always_inline)) { FL_NRF_GPIO->OUT ^= _MASK; }
inline static void hi(register port_ptr_t port) __attribute__ ((always_inline)) { hi(); }
inline static void lo(register port_ptr_t port) __attribute__ ((always_inline)) { lo(); }
inline static void fastset(register port_ptr_t port, register port_t val) __attribute__ ((always_inline)) { *port = val; }
inline static port_t hival() __attribute__ ((always_inline)) { return FL_NRF_GPIO->OUT | _MASK; }
inline static port_t loval() __attribute__ ((always_inline)) { return FL_NRF_GPIO->OUT & ~_MASK; }
inline static port_ptr_t port() __attribute__ ((always_inline)) { return &FL_NRF_GPIO->OUT; }
inline static port_t mask() __attribute__ ((always_inline)) { return _MASK; }
inline static bool isset() __attribute__ ((always_inline)) { return (FL_NRF_GPIO->IN & _MASK) != 0; }
};
#define _FL_DEFPIN(PIN) template<> class FastPin<PIN> : public _ARMPIN<PIN, 1 << PIN> {};
#endif
// Actual pin definitions
#define MAX_PIN 31
_FL_DEFPIN(0); _FL_DEFPIN(1); _FL_DEFPIN(2); _FL_DEFPIN(3);
_FL_DEFPIN(4); _FL_DEFPIN(5); _FL_DEFPIN(6); _FL_DEFPIN(7);
_FL_DEFPIN(8); _FL_DEFPIN(9); _FL_DEFPIN(10); _FL_DEFPIN(11);
_FL_DEFPIN(12); _FL_DEFPIN(13); _FL_DEFPIN(14); _FL_DEFPIN(15);
_FL_DEFPIN(16); _FL_DEFPIN(17); _FL_DEFPIN(18); _FL_DEFPIN(19);
_FL_DEFPIN(20); _FL_DEFPIN(21); _FL_DEFPIN(22); _FL_DEFPIN(23);
_FL_DEFPIN(24); _FL_DEFPIN(25); _FL_DEFPIN(26); _FL_DEFPIN(27);
_FL_DEFPIN(28); _FL_DEFPIN(29); _FL_DEFPIN(30); _FL_DEFPIN(31);
#define HAS_HARDWARE_PIN_SUPPORT
#endif
#endif

View File

@ -0,0 +1,150 @@
#ifndef __INC_FASTSPI_NRF_H
#define __INC_FASTSPI_NRF_H
#ifdef NRF51
#ifndef FASTLED_FORCE_SOFTWARE_SPI
#define FASTLED_ALL_PINS_HARDWARE_SPI
// A nop/stub class, mostly to show the SPI methods that are needed/used by the various SPI chipset implementations. Should
// be used as a definition for the set of methods that the spi implementation classes should use (since C++ doesn't support the
// idea of interfaces - it's possible this could be done with virtual classes, need to decide if i want that overhead)
template <uint8_t _DATA_PIN, uint8_t _CLOCK_PIN, uint32_t _SPI_CLOCK_DIVIDER>
class NRF51SPIOutput {
struct saveData {
uint32_t sck;
uint32_t mosi;
uint32_t miso;
uint32_t freq;
uint32_t enable;
} mSavedData;
void saveSPIData() {
mSavedData.sck = NRF_SPI0->PSELSCK;
mSavedData.mosi = NRF_SPI0->PSELMOSI;
mSavedData.miso = NRF_SPI0->PSELMISO;
mSavedData.freq = NRF_SPI0->FREQUENCY;
mSavedData.enable = NRF_SPI0->ENABLE;
}
void restoreSPIData() {
NRF_SPI0->PSELSCK = mSavedData.sck;
NRF_SPI0->PSELMOSI = mSavedData.mosi;
NRF_SPI0->PSELMISO = mSavedData.miso;
NRF_SPI0->FREQUENCY = mSavedData.freq;
mSavedData.enable = NRF_SPI0->ENABLE;
}
public:
NRF51SPIOutput() { FastPin<_DATA_PIN>::setOutput(); FastPin<_CLOCK_PIN>::setOutput(); }
NRF51SPIOutput(Selectable *pSelect) { FastPin<_DATA_PIN>::setOutput(); FastPin<_CLOCK_PIN>::setOutput(); }
// set the object representing the selectable
void setSelect(Selectable *pSelect) { /* TODO */ }
// initialize the SPI subssytem
void init() {
FastPin<_DATA_PIN>::setOutput();
FastPin<_CLOCK_PIN>::setOutput();
NRF_SPI0->PSELSCK = _CLOCK_PIN;
NRF_SPI0->PSELMOSI = _DATA_PIN;
NRF_SPI0->PSELMISO = 0xFFFFFFFF;
NRF_SPI0->FREQUENCY = 0x80000000;
NRF_SPI0->ENABLE = 1;
NRF_SPI0->EVENTS_READY = 0;
}
// latch the CS select
void select() { saveSPIData(); init(); }
// release the CS select
void release() { shouldWait(); restoreSPIData(); }
static bool shouldWait(bool wait = false) __attribute__((always_inline)) __attribute__((always_inline)) {
// static bool sWait=false;
// bool oldWait = sWait;
// sWait = wait;
// never going to bother with waiting since we're always running the spi clock at max speed on the rfduino
// TODO: When we set clock rate, implement/fix waiting properly, otherwise the world hangs up
return false;
}
// wait until all queued up data has been written
static void waitFully() __attribute__((always_inline)){ if(shouldWait()) { while(NRF_SPI0->EVENTS_READY==0); } NRF_SPI0->INTENCLR; }
static void wait() __attribute__((always_inline)){ if(shouldWait()) { while(NRF_SPI0->EVENTS_READY==0); } NRF_SPI0->INTENCLR; }
// write a byte out via SPI (returns immediately on writing register)
static void writeByte(uint8_t b) __attribute__((always_inline)) { wait(); NRF_SPI0->TXD = b; NRF_SPI0->INTENCLR; shouldWait(true); }
// write a word out via SPI (returns immediately on writing register)
static void writeWord(uint16_t w) __attribute__((always_inline)){ writeByte(w>>8); writeByte(w & 0xFF); }
// 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();
while(len--) {
writeByte(value);
}
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();
while(data != end) {
writeByte(D::adjust(*data++));
}
D::postBlock(len);
waitFully();
release();
}
void writeBytes(uint8_t *data, int len) {
writeBytes<DATA_NOP>(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) {
waitFully();
NRF_SPI0->ENABLE = 0;
if(b & 1<<BIT) {
FastPin<_DATA_PIN>::hi();
} else {
FastPin<_DATA_PIN>::lo();
}
FastPin<_CLOCK_PIN>::toggle();
FastPin<_CLOCK_PIN>::toggle();
NRF_SPI0->ENABLE = 1;
}
template <uint8_t FLAGS, class D, EOrder RGB_ORDER> void writePixels(PixelController<RGB_ORDER> pixels) {
select();
int len = pixels.mLen;
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();
}
};
#endif
#endif
#endif

View File

@ -0,0 +1,46 @@
#ifndef __LED_SYSDEFS_ARM_NRF51
#define __LED_SYSDEFS_ARM_NRF51
#ifndef NRF51
#define NRF51
#endif
#define LED_TIMER NRF_TIMER1
#define FASTLED_NO_PINMAP
#define FASTLED_HAS_CLOCKLESS
#define FASTLED_SPI_BYTE_ONLY
#define FASTLED_ARM
#define FASTLED_ARM_M0
#ifndef F_CPU
#define F_CPU 16000000
#endif
#include <stdint.h>
#include <nrf51.h>
#include <core_cm0.h>
typedef volatile uint32_t RoReg;
typedef volatile uint32_t RwReg;
typedef uint32_t prog_uint32_t;
typedef uint8_t boolean;
#define PROGMEM
#define NO_PROGMEM
#define NEED_CXX_BITS
// Default to NOT using PROGMEM here
#ifndef FASTLED_USE_PROGMEM
#define FASTLED_USE_PROGMEM 0
#endif
#ifndef FASTLED_ALLOW_INTERRUPTS
#define FASTLED_ALLOW_INTERRUPTS 1
#endif
#define cli() __disable_irq();
#define sei() __enable_irq();
#endif