diff --git a/src/wsLED.cpp b/src/wsLED.cpp index 0e735f3..fab08c4 100644 --- a/src/wsLED.cpp +++ b/src/wsLED.cpp @@ -1,11 +1,25 @@ // Ovladani signalizacni chytre LED diody #include "wsLED.h" -//#if defined(ARDUINO_ARCH_ESP32) +#if defined(ARDUINO_ARCH_ESP32) //# include "esp_task.h" -//#endif +// https://github.com/JSchaenzle/ESP32-NeoPixel-WS2812-RMT/blob/master/ws2812_control.c +# include +# include +# ifndef LED_RMT_TX_CHANNEL +# define LED_RMT_TX_CHANNEL RMT_CHANNEL_0 +# endif +# define BITS_PER_LED_CMD 24 +# define LED_BUFFER_ITEMS ((1 * BITS_PER_LED_CMD)) +// These values are determined by measuring pulse timing with logic analyzer and adjusting to match datasheet. +# define T0H 14 // 0 bit high time +# define T1H 52 // 1 bit high time +# define TL 52 // low time for either bit +#endif +#if defined(ARDUINO_ARCH_ESP8266) // due to linker overriding the ICACHE_RAM_ATTR for cpp files, these methods are // moved into a C file so the attribute will be applied correctly extern "C" void ICACHE_RAM_ATTR send_pixels_800(uint8_t* pixel, size_t count, uint8_t pin); +#endif #define countof(a) (sizeof(a) / sizeof(a[0])) @@ -35,16 +49,20 @@ void wsLED::show(void) while (!canShow()) __asm__ volatile ("nop"); #if defined(ARDUINO_ARCH_ESP32) -// uint32_t volatile register ilevel = XTOS_DISABLE_ALL_INTERRUPTS; - portENTER_CRITICAL(&_mux); + rmt_item32_t led_data_buffer[LED_BUFFER_ITEMS]; + + uint32_t bits_to_send = ((uint32_t)color[0] << 16) | ((uint32_t)color[1] << 8) | (uint32_t)color[2]; + uint32_t mask = 1 << (BITS_PER_LED_CMD - 1); + for (uint32_t bit = 0; bit < BITS_PER_LED_CMD; bit++) { + uint32_t bit_is_set = bits_to_send & mask; + led_data_buffer[bit] = bit_is_set ? (rmt_item32_t) {{{T1H, 1, TL, 0}}} : (rmt_item32_t) {{{T0H, 1, TL, 0}}}; + mask >>= 1; + } + ESP_ERROR_CHECK(rmt_write_items(LED_RMT_TX_CHANNEL, led_data_buffer, LED_BUFFER_ITEMS, false)); + ESP_ERROR_CHECK(rmt_wait_tx_done(LED_RMT_TX_CHANNEL, portMAX_DELAY)); #else noInterrupts(); -#endif send_pixels_800(color, 1, _pin); -#if defined(ARDUINO_ARCH_ESP32) -// XTOS_RESTORE_INTLEVEL(ilevel); - portEXIT_CRITICAL(&_mux); -#else interrupts(); #endif _endtime = micros(); @@ -61,9 +79,28 @@ wsLED::wsLED(int pin, int order) void wsLED::begin(void) { - pinMode(_pin, OUTPUT); - _color[0] = _color[1] = _color[2] = 0; - show(); +#if defined(ARDUINO_ARCH_ESP8266) + pinMode(_pin, OUTPUT); +#endif +#if defined(ARDUINO_ARCH_ESP32) +// TODO: mozna nejak zkusit najit volny RMT kanal? + rmt_config_t config; + + config.rmt_mode = RMT_MODE_TX; + config.channel = LED_RMT_TX_CHANNEL; + config.gpio_num = (gpio_num_t)_pin; + config.mem_block_num = 3; + config.tx_config.loop_en = false; + config.tx_config.carrier_en = false; + config.tx_config.idle_output_en = true; + config.tx_config.idle_level = RMT_IDLE_LEVEL_LOW; + config.clk_div = 2; + + ESP_ERROR_CHECK(rmt_config(&config)); + ESP_ERROR_CHECK(rmt_driver_install(config.channel, 0, 0)); +#endif + _color[0] = _color[1] = _color[2] = 0; + show(); } void wsLED::setColor(LEDRGB &color) @@ -146,3 +183,5 @@ void wsLED::setOrder(int neworder) _order = neworder; } + + diff --git a/src/wsLED.h b/src/wsLED.h index 3590e09..781db78 100644 --- a/src/wsLED.h +++ b/src/wsLED.h @@ -131,6 +131,9 @@ protected: LED_PATTERN, } _ledState; // stav LEDky (blika, dycha, ...) int _subState; // pomocny stav/index v poli dychani +#if defined(ARDUINO_ARCH_ESP32) + int _rmtChannel; +#endif bool canShow(void); void show(void);