Damien George | 3962766 | 2016-02-11 13:19:11 +0000 | [diff] [blame] | 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 | } |