From 3962766be08f0ccd81bedab1a5d1d8f6468f972e Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 11 Feb 2016 13:19:11 +0000 Subject: [PATCH] esp8266: Add esp.neopixel_write function to bit-bang WS2812 data. --- esp8266/Makefile | 1 + esp8266/espneopixel.c | 64 ++++++++++++++++++++++++++++++++++++++++++ esp8266/espneopixel.h | 1 + esp8266/modesp.c | 12 ++++++++ esp8266/qstrdefsport.h | 1 + 5 files changed, 79 insertions(+) create mode 100644 esp8266/espneopixel.c create mode 100644 esp8266/espneopixel.h diff --git a/esp8266/Makefile b/esp8266/Makefile index b30bb2f95b..1836e7eb4a 100644 --- a/esp8266/Makefile +++ b/esp8266/Makefile @@ -58,6 +58,7 @@ SRC_C = \ lexerstr32.c \ uart.c \ esppwm.c \ + espneopixel.c \ modpyb.c \ modpybpin.c \ modpybpwm.c \ 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 +} diff --git a/esp8266/espneopixel.h b/esp8266/espneopixel.h new file mode 100644 index 0000000000..4b20afda58 --- /dev/null +++ b/esp8266/espneopixel.h @@ -0,0 +1 @@ +void esp_neopixel_write(uint8_t pin, uint8_t *pixels, uint32_t numBytes, bool is800KHz); diff --git a/esp8266/modesp.c b/esp8266/modesp.c index 73cfc4275c..18859ead8a 100644 --- a/esp8266/modesp.c +++ b/esp8266/modesp.c @@ -39,6 +39,8 @@ #include "espconn.h" #include "spi_flash.h" #include "utils.h" +#include "espneopixel.h" +#include "modpyb.h" #define MODESP_ESPCONN (0) @@ -573,6 +575,15 @@ STATIC mp_obj_t esp_flash_erase(mp_obj_t sector_in) { } STATIC MP_DEFINE_CONST_FUN_OBJ_1(esp_flash_erase_obj, esp_flash_erase); +STATIC mp_obj_t esp_neopixel_write_(mp_obj_t pin, mp_obj_t buf, mp_obj_t is800k) { + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(buf, &bufinfo, MP_BUFFER_READ); + esp_neopixel_write(mp_obj_get_pin_obj(pin)->phys_port, + (uint8_t*)bufinfo.buf, bufinfo.len, mp_obj_is_true(is800k)); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_3(esp_neopixel_write_obj, esp_neopixel_write_); + STATIC const mp_map_elem_t esp_module_globals_table[] = { { MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_esp) }, @@ -586,6 +597,7 @@ STATIC const mp_map_elem_t esp_module_globals_table[] = { { MP_OBJ_NEW_QSTR(MP_QSTR_socket), (mp_obj_t)&esp_socket_type }, { MP_OBJ_NEW_QSTR(MP_QSTR_getaddrinfo), (mp_obj_t)&esp_getaddrinfo_obj }, #endif + { MP_OBJ_NEW_QSTR(MP_QSTR_neopixel_write), (mp_obj_t)&esp_neopixel_write_obj }, #if MODESP_INCLUDE_CONSTANTS { MP_OBJ_NEW_QSTR(MP_QSTR_MODE_11B), diff --git a/esp8266/qstrdefsport.h b/esp8266/qstrdefsport.h index 77e66d85cc..f82e0d1a53 100644 --- a/esp8266/qstrdefsport.h +++ b/esp8266/qstrdefsport.h @@ -87,6 +87,7 @@ Q(onconnect) Q(onrecv) Q(onsent) Q(ondisconnect) +Q(neopixel_write) Q(MODE_11B) Q(MODE_11G) Q(MODE_11N)