Pouziti RMT periferie pro ESP32

This commit is contained in:
Pavel Brychta 2020-09-04 11:21:26 +02:00
parent 44de7d5d15
commit 3bbb76672a
2 changed files with 54 additions and 12 deletions

View File

@ -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 <driver/rmt.h>
# include <set>
# 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;
}

View File

@ -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);