summaryrefslogtreecommitdiffstatshomepage
path: root/esp8266/espneopixel.c
diff options
context:
space:
mode:
authorDamien George <damien.p.george@gmail.com>2016-02-11 13:19:11 +0000
committerPaul Sokolovsky <pfalcon@users.sourceforge.net>2016-03-26 10:55:21 +0200
commit3962766be08f0ccd81bedab1a5d1d8f6468f972e (patch)
treeb119f29d21f591bb94b0c6605738a39d092ca8f5 /esp8266/espneopixel.c
parentb62beadae01f65d7751d26d82e35d56925f4e6d9 (diff)
downloadmicropython-3962766be08f0ccd81bedab1a5d1d8f6468f972e.tar.gz
micropython-3962766be08f0ccd81bedab1a5d1d8f6468f972e.zip
esp8266: Add esp.neopixel_write function to bit-bang WS2812 data.
Diffstat (limited to 'esp8266/espneopixel.c')
-rw-r--r--esp8266/espneopixel.c64
1 files changed, 64 insertions, 0 deletions
diff --git a/esp8266/espneopixel.c b/esp8266/espneopixel.c
new file mode 100644
index 0000000000..26776f025e
--- /dev/null
+++ b/esp8266/espneopixel.c
@@ -0,0 +1,64 @@
+// Original version from https://github.com/adafruit/Adafruit_NeoPixel
+// Modifications by dpgeorge to support auto-CPU-frequency detection
+
+// 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.
+
+#include "c_types.h"
+#include "eagle_soc.h"
+#include "user_interface.h"
+#include "espneopixel.h"
+
+#define NEO_KHZ400 (1)
+
+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*/ esp_neopixel_write(uint8_t pin, uint8_t *pixels, uint32_t numBytes, bool is800KHz) {
+
+ uint8_t *p, *end, pix, mask;
+ uint32_t t, time0, time1, period, c, startTime, pinMask;
+
+ pinMask = 1 << pin;
+ p = pixels;
+ end = p + numBytes;
+ pix = *p++;
+ mask = 0x80;
+ startTime = 0;
+
+ uint32_t fcpu = system_get_cpu_freq() * 1000000;
+
+#ifdef NEO_KHZ400
+ if(is800KHz) {
+#endif
+ time0 = fcpu / 2500000; // 0.4us
+ time1 = fcpu / 1250000; // 0.8us
+ period = fcpu / 800000; // 1.25us per bit
+#ifdef NEO_KHZ400
+ } else { // 400 KHz bitstream
+ time0 = fcpu / 2000000; // 0.5uS
+ time1 = fcpu / 833333; // 1.2us
+ period = fcpu / 400000; // 2.5us per bit
+ }
+#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
+}