blob: 26776f025e41c816886960323ab008e328cda59d [file] [log] [blame]
Damien George39627662016-02-11 13:19:11 +00001// Original version from https://github.com/adafruit/Adafruit_NeoPixel
2// Modifications by dpgeorge to support auto-CPU-frequency detection
3
4// This is a mash-up of the Due show() code + insights from Michael Miller's
5// ESP8266 work for the NeoPixelBus library: github.com/Makuna/NeoPixelBus
6// Needs to be a separate .c file to enforce ICACHE_RAM_ATTR execution.
7
8#include "c_types.h"
9#include "eagle_soc.h"
10#include "user_interface.h"
11#include "espneopixel.h"
12
13#define NEO_KHZ400 (1)
14
15static uint32_t _getCycleCount(void) __attribute__((always_inline));
16static inline uint32_t _getCycleCount(void) {
17 uint32_t ccount;
18 __asm__ __volatile__("rsr %0,ccount":"=a" (ccount));
19 return ccount;
20}
21
22void /*ICACHE_RAM_ATTR*/ esp_neopixel_write(uint8_t pin, uint8_t *pixels, uint32_t numBytes, bool is800KHz) {
23
24 uint8_t *p, *end, pix, mask;
25 uint32_t t, time0, time1, period, c, startTime, pinMask;
26
27 pinMask = 1 << pin;
28 p = pixels;
29 end = p + numBytes;
30 pix = *p++;
31 mask = 0x80;
32 startTime = 0;
33
34 uint32_t fcpu = system_get_cpu_freq() * 1000000;
35
36#ifdef NEO_KHZ400
37 if(is800KHz) {
38#endif
39 time0 = fcpu / 2500000; // 0.4us
40 time1 = fcpu / 1250000; // 0.8us
41 period = fcpu / 800000; // 1.25us per bit
42#ifdef NEO_KHZ400
43 } else { // 400 KHz bitstream
44 time0 = fcpu / 2000000; // 0.5uS
45 time1 = fcpu / 833333; // 1.2us
46 period = fcpu / 400000; // 2.5us per bit
47 }
48#endif
49
50 for(t = time0;; t = time0) {
51 if(pix & mask) t = time1; // Bit high duration
52 while(((c = _getCycleCount()) - startTime) < period); // Wait for bit start
53 GPIO_REG_WRITE(GPIO_OUT_W1TS_ADDRESS, pinMask); // Set high
54 startTime = c; // Save start time
55 while(((c = _getCycleCount()) - startTime) < t); // Wait high duration
56 GPIO_REG_WRITE(GPIO_OUT_W1TC_ADDRESS, pinMask); // Set low
57 if(!(mask >>= 1)) { // Next bit/byte
58 if(p >= end) break;
59 pix = *p++;
60 mask = 0x80;
61 }
62 }
63 while((_getCycleCount() - startTime) < period); // Wait for last bit
64}