Skip to content

Commit

Permalink
ESP8266 support (based on Makuna's NeoPixelBus lib)
Browse files Browse the repository at this point in the history
  • Loading branch information
PaintYourDragon committed Jun 27, 2015
1 parent 45376f8 commit c27d9bf
Show file tree
Hide file tree
Showing 4 changed files with 108 additions and 17 deletions.
54 changes: 39 additions & 15 deletions Adafruit_NeoPixel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@
(possible exception with upper PORT registers on the Arduino Mega).
Written by Phil Burgess / Paint Your Dragon for Adafruit Industries,
contributions by PJRC and other members of the open source community.
contributions by PJRC, Michael Miller and other members of the open
source community.
Adafruit invests time and resources providing this open source code,
please support Adafruit and open-source hardware by purchasing products
Expand Down Expand Up @@ -70,6 +71,13 @@ void Adafruit_NeoPixel::begin(void) {
digitalWrite(pin, LOW);
}


#ifdef ESP8266
// ESP8266 show() is external to enforce ICACHE_RAM_ATTR execution
extern "C" void ICACHE_RAM_ATTR espShow(
uint8_t pin, uint8_t *pixels, uint32_t numBytes, uint8_t type);
#endif // ESP8266

void Adafruit_NeoPixel::show(void) {

if(!pixels) return;
Expand Down Expand Up @@ -97,7 +105,9 @@ void Adafruit_NeoPixel::show(void) {

noInterrupts(); // Need 100% focus on instruction timing


#ifdef __AVR__
// AVR MCUs -- ATmega & ATtiny (no XMEGA) ---------------------------------

volatile uint16_t
i = numBytes; // Loop counter
Expand Down Expand Up @@ -377,7 +387,7 @@ void Adafruit_NeoPixel::show(void) {
[lo] "r" (lo),
[ptr] "e" (ptr));
}
#endif
#endif // NEO_KHZ400

// 12 MHz(ish) AVR --------------------------------------------------------
#elif (F_CPU >= 11100000UL) && (F_CPU <= 14300000UL)
Expand Down Expand Up @@ -557,7 +567,7 @@ void Adafruit_NeoPixel::show(void) {
[lo] "r" (lo),
[ptr] "e" (ptr));
}
#endif
#endif // NEO_KHZ400

// 16 MHz(ish) AVR --------------------------------------------------------
#elif (F_CPU >= 15400000UL) && (F_CPU <= 19000000L)
Expand Down Expand Up @@ -669,14 +679,19 @@ void Adafruit_NeoPixel::show(void) {
[hi] "r" (hi),
[lo] "r" (lo));
}
#endif
#endif // NEO_KHZ400

#else
#error "CPU SPEED NOT SUPPORTED"
#endif
#endif // end F_CPU ifdefs on __AVR__

// END AVR ----------------------------------------------------------------


#elif defined(__arm__)

// ARM MCUs -- Teensy 3.0, 3.1, LC, Arduino Due ---------------------------

#if defined(__MK20DX128__) || defined(__MK20DX256__) // Teensy 3.0 & 3.1
#define CYCLES_800_T0H (F_CPU / 4000000)
#define CYCLES_800_T1H (F_CPU / 1250000)
Expand Down Expand Up @@ -732,11 +747,7 @@ void Adafruit_NeoPixel::show(void) {
}
while(ARM_DWT_CYCCNT - cyc < CYCLES_400);
}
#endif




#endif // NEO_KHZ400

#elif defined(__MKL26Z64__) // Teensy-LC

Expand Down Expand Up @@ -822,10 +833,9 @@ void Adafruit_NeoPixel::show(void) {
);
#else
#error "Sorry, only 48 MHz is supported, please set Tools > CPU Speed to 48 MHz"
#endif
#endif // F_CPU == 48000000


#else // Arduino Due
#else // Other ARM architecture -- Presumed Arduino Due

#define SCALE VARIANT_MCK / 2UL / 1000000UL
#define INST (2UL * F_CPU / VARIANT_MCK)
Expand Down Expand Up @@ -888,9 +898,23 @@ void Adafruit_NeoPixel::show(void) {
while(*timeValue < period); // Wait for last bit
TC_Stop(TC1, 0);

#endif // end Arduino Due
#endif // end Due

// END ARM ----------------------------------------------------------------


#elif defined(ESP8266)

// ESP8266 ----------------------------------------------------------------

// ESP8266 show() is external to enforce ICACHE_RAM_ATTR execution
espShow(pin, pixels, numBytes, type);

#endif // ESP8266


// END ARCHITECTURE SELECT ------------------------------------------------

#endif // end Architecture select

interrupts();
endTime = micros(); // Save EOD time for latch on next call
Expand Down
67 changes: 67 additions & 0 deletions esp8266.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
// This is a mash-up of the Due show() code + insights from Michael Miller's
// ESP8266 work for the NeoPixelBus library: github.com/Makuna/NeoPixelBus
// Needs to be a separate .c file to enforce ICACHE_RAM_ATTR execution.

#ifdef ESP8266

#include <Arduino.h>
#include <eagle_soc.h>

static uint32_t _getCycleCount(void) __attribute__((always_inline));
static inline uint32_t _getCycleCount(void) {
uint32_t ccount;
__asm__ __volatile__("rsr %0,ccount":"=a" (ccount));
return ccount;
}

void ICACHE_RAM_ATTR espShow(
uint8_t pin, uint8_t *pixels, uint32_t numBytes, uint8_t type) {

#define CYCLES_800_T0H (F_CPU / 2500000) // 0.4us
#define CYCLES_800_T1H (F_CPU / 1250000) // 0.8us
#define CYCLES_800 (F_CPU / 800000) // 1.25us per bit
#define CYCLES_400_T0H (F_CPU / 2000000) // 0.5uS
#define CYCLES_400_T1H (F_CPU / 833333) // 1.2us
#define CYCLES_400 (F_CPU / 400000) // 2.5us per bit

uint8_t *p, *end, pix, mask;
uint32_t t, time0, time1, period, c, startTime, pinMask;

pinMask = _BV(pin);
p = pixels;
end = p + numBytes;
pix = *p++;
mask = 0x80;
startTime = 0;

#ifdef NEO_KHZ400
if((type & NEO_SPDMASK) == NEO_KHZ800) { // 800 KHz bitstream
#endif
time0 = CYCLES_800_T0H;
time1 = CYCLES_800_T1H;
period = CYCLES_800;
#ifdef NEO_KHZ400
} else { // 400 KHz bitstream
time0 = CYCLES_400_T0H;
time1 = CYCLES_400_T1H;
period = CYCLES_800;
}
#endif

for(t = time0;; t = time0) {
if(pix & mask) t = time1; // Bit high duration
while(((c = _getCycleCount()) - startTime) < period); // Wait for bit start
GPIO_REG_WRITE(GPIO_OUT_W1TS_ADDRESS, pinMask); // Set high
startTime = c; // Save start time
while(((c = _getCycleCount()) - startTime) < t); // Wait high duration
GPIO_REG_WRITE(GPIO_OUT_W1TC_ADDRESS, pinMask); // Set low
if(!(mask >>= 1)) { // Next bit/byte
if(p >= end) break;
pix = *p++;
mask = 0x80;
}
}
while((_getCycleCount() - startTime) < period); // Wait for last bit
}

#endif // ESP8266
2 changes: 1 addition & 1 deletion examples/strandtest/strandtest.ino
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#include <Adafruit_NeoPixel.h>
#include <avr/power.h>
#include <avr/power.h> // Comment out this line for non-AVR boards (Arduino Due, etc.)

#define PIN 6

Expand Down
2 changes: 1 addition & 1 deletion library.properties
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
name=Adafruit NeoPixel
version=1.0
version=1.0.1
author=Adafruit
maintainer=Adafruit <[email protected]>
sentence=Arduino library for controlling single-wire-based LED pixels and strip.
Expand Down

0 comments on commit c27d9bf

Please sign in to comment.