| 1 | // This is a mash-up of the Due show() code + insights from Michael Miller's |
| 2 | // ESP8266 work for the NeoPixelBus library: github.com/Makuna/NeoPixelBus |
| 3 | // Needs to be a separate .c file to enforce ICACHE_RAM_ATTR execution. |
| 4 | |
| 5 | #if defined(ESP8266) |
| 6 | |
| 7 | #include <Arduino.h> |
| 8 | #ifdef ESP8266 |
| 9 | #include <eagle_soc.h> |
| 10 | #endif |
| 11 | |
| 12 | static uint32_t _getCycleCount(void) __attribute__((always_inline)); |
| 13 | static inline uint32_t _getCycleCount(void) { |
| 14 | uint32_t ccount; |
| 15 | __asm__ __volatile__("rsr %0,ccount" : "=a"(ccount)); |
| 16 | return ccount; |
| 17 | } |
| 18 | |
| 19 | #ifdef ESP8266 |
| 20 | IRAM_ATTR void espShow(uint8_t pin, uint8_t *pixels, uint32_t numBytes, |
| 21 | __attribute__((unused)) boolean is800KHz) { |
| 22 | #else |
| 23 | void espShow(uint8_t pin, uint8_t *pixels, uint32_t numBytes, |
| 24 | boolean is800KHz) { |
| 25 | #endif |
| 26 | |
| 27 | #define CYCLES_800_T0H (F_CPU / 2500001) // 0.4us |
| 28 | #define CYCLES_800_T1H (F_CPU / 1250001) // 0.8us |
| 29 | #define CYCLES_800 (F_CPU / 800001) // 1.25us per bit |
| 30 | #define CYCLES_400_T0H (F_CPU / 2000000) // 0.5uS |
| 31 | #define CYCLES_400_T1H (F_CPU / 833333) // 1.2us |
| 32 | #define CYCLES_400 (F_CPU / 400000) // 2.5us per bit |
| 33 | |
| 34 | uint8_t *p, *end, pix, mask; |
| 35 | uint32_t t, time0, time1, period, c, startTime; |
| 36 | |
| 37 | #ifdef ESP8266 |
| 38 | uint32_t pinMask; |
| 39 | pinMask = _BV(pin); |
| 40 | #endif |
| 41 | |
| 42 | p = pixels; |
| 43 | end = p + numBytes; |
| 44 | pix = *p++; |
| 45 | mask = 0x80; |
| 46 | startTime = 0; |
| 47 | |
| 48 | #ifdef NEO_KHZ400 |
| 49 | if (is800KHz) { |
| 50 | #endif |
| 51 | time0 = CYCLES_800_T0H; |
| 52 | time1 = CYCLES_800_T1H; |
| 53 | period = CYCLES_800; |
| 54 | #ifdef NEO_KHZ400 |
| 55 | } else { // 400 KHz bitstream |
| 56 | time0 = CYCLES_400_T0H; |
| 57 | time1 = CYCLES_400_T1H; |
| 58 | period = CYCLES_400; |
| 59 | } |
| 60 | #endif |
| 61 | |
| 62 | for (t = time0;; t = time0) { |
| 63 | if (pix & mask) |
| 64 | t = time1; // Bit high duration |
| 65 | while (((c = _getCycleCount()) - startTime) < period) |
| 66 | ; // Wait for bit start |
| 67 | #ifdef ESP8266 |
| 68 | GPIO_REG_WRITE(GPIO_OUT_W1TS_ADDRESS, pinMask); // Set high |
| 69 | #else |
| 70 | gpio_set_level(pin, HIGH); |
| 71 | #endif |
| 72 | startTime = c; // Save start time |
| 73 | while (((c = _getCycleCount()) - startTime) < t) |
| 74 | ; // Wait high duration |
| 75 | #ifdef ESP8266 |
| 76 | GPIO_REG_WRITE(GPIO_OUT_W1TC_ADDRESS, pinMask); // Set low |
| 77 | #else |
| 78 | gpio_set_level(pin, LOW); |
| 79 | #endif |
| 80 | if (!(mask >>= 1)) { // Next bit/byte |
| 81 | if (p >= end) |
| 82 | break; |
| 83 | pix = *p++; |
| 84 | mask = 0x80; |
| 85 | } |
| 86 | } |
| 87 | while ((_getCycleCount() - startTime) < period) |
| 88 | ; // Wait for last bit |
| 89 | } |
| 90 | |
| 91 | #endif // ESP8266 |