|
| 1 | +// 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 | + |
| 15 | +static uint32_t _getCycleCount(void) __attribute__((always_inline)); |
| 16 | +static inline uint32_t _getCycleCount(void) { |
| 17 | + uint32_t ccount; |
| 18 | + __asm__ __volatile__("rsr %0,ccount":"=a" (ccount)); |
| 19 | + return ccount; |
| 20 | +} |
| 21 | + |
| 22 | +void /*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 | +} |
0 commit comments