Initial public release of the 2024A software.
This commit is contained in:
parent
7b9ad3edfd
commit
303e9e1dad
361 changed files with 60083 additions and 2 deletions
194
components/MuxedLedStrip/src/led_strip_rmt_dev_idf4.c
Normal file
194
components/MuxedLedStrip/src/led_strip_rmt_dev_idf4.c
Normal file
|
@ -0,0 +1,194 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/cdefs.h>
|
||||
#include "esp_log.h"
|
||||
#include "esp_check.h"
|
||||
#include "driver/rmt.h"
|
||||
#include "led_strip.h"
|
||||
#include "led_strip_interface.h"
|
||||
|
||||
static const char *TAG = "led_strip_rmt";
|
||||
|
||||
#define WS2812_T0H_NS (300)
|
||||
#define WS2812_T0L_NS (900)
|
||||
#define WS2812_T1H_NS (900)
|
||||
#define WS2812_T1L_NS (300)
|
||||
|
||||
#define SK6812_T0H_NS (300)
|
||||
#define SK6812_T0L_NS (900)
|
||||
#define SK6812_T1H_NS (600)
|
||||
#define SK6812_T1L_NS (600)
|
||||
|
||||
#define LED_STRIP_RESET_MS (10)
|
||||
|
||||
// the memory size of each RMT channel, in words (4 bytes)
|
||||
#if CONFIG_IDF_TARGET_ESP32 || CONFIG_IDF_TARGET_ESP32S2
|
||||
#define LED_STRIP_RMT_DEFAULT_MEM_BLOCK_SYMBOLS 64
|
||||
#else
|
||||
#define LED_STRIP_RMT_DEFAULT_MEM_BLOCK_SYMBOLS 48
|
||||
#endif
|
||||
|
||||
static uint32_t led_t0h_ticks = 0;
|
||||
static uint32_t led_t1h_ticks = 0;
|
||||
static uint32_t led_t0l_ticks = 0;
|
||||
static uint32_t led_t1l_ticks = 0;
|
||||
|
||||
typedef struct {
|
||||
led_strip_t base;
|
||||
rmt_channel_t rmt_channel;
|
||||
uint32_t strip_len;
|
||||
uint8_t bytes_per_pixel;
|
||||
uint8_t buffer[0];
|
||||
} led_strip_rmt_obj;
|
||||
|
||||
static void IRAM_ATTR ws2812_rmt_adapter(const void *src, rmt_item32_t *dest, size_t src_size,
|
||||
size_t wanted_num, size_t *translated_size, size_t *item_num)
|
||||
{
|
||||
if (src == NULL || dest == NULL) {
|
||||
*translated_size = 0;
|
||||
*item_num = 0;
|
||||
return;
|
||||
}
|
||||
const rmt_item32_t bit0 = {{{ led_t0h_ticks, 1, led_t0l_ticks, 0 }}}; //Logical 0
|
||||
const rmt_item32_t bit1 = {{{ led_t1h_ticks, 1, led_t1l_ticks, 0 }}}; //Logical 1
|
||||
size_t size = 0;
|
||||
size_t num = 0;
|
||||
uint8_t *psrc = (uint8_t *)src;
|
||||
rmt_item32_t *pdest = dest;
|
||||
while (size < src_size && num < wanted_num) {
|
||||
for (int i = 0; i < 8; i++) {
|
||||
// MSB first
|
||||
if (*psrc & (1 << (7 - i))) {
|
||||
pdest->val = bit1.val;
|
||||
} else {
|
||||
pdest->val = bit0.val;
|
||||
}
|
||||
num++;
|
||||
pdest++;
|
||||
}
|
||||
size++;
|
||||
psrc++;
|
||||
}
|
||||
*translated_size = size;
|
||||
*item_num = num;
|
||||
}
|
||||
|
||||
static esp_err_t led_strip_rmt_set_pixel(led_strip_t *strip, uint32_t index, uint32_t red, uint32_t green, uint32_t blue)
|
||||
{
|
||||
led_strip_rmt_obj *rmt_strip = __containerof(strip, led_strip_rmt_obj, base);
|
||||
ESP_RETURN_ON_FALSE(index < rmt_strip->strip_len, ESP_ERR_INVALID_ARG, TAG, "index out of the maximum number of leds");
|
||||
uint32_t start = index * rmt_strip->bytes_per_pixel;
|
||||
// In thr order of GRB
|
||||
rmt_strip->buffer[start + 0] = green & 0xFF;
|
||||
rmt_strip->buffer[start + 1] = red & 0xFF;
|
||||
rmt_strip->buffer[start + 2] = blue & 0xFF;
|
||||
if (rmt_strip->bytes_per_pixel > 3) {
|
||||
rmt_strip->buffer[start + 3] = 0;
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static esp_err_t led_strip_rmt_refresh(led_strip_t *strip)
|
||||
{
|
||||
led_strip_rmt_obj *rmt_strip = __containerof(strip, led_strip_rmt_obj, base);
|
||||
ESP_RETURN_ON_ERROR(rmt_write_sample(rmt_strip->rmt_channel, rmt_strip->buffer, rmt_strip->strip_len * rmt_strip->bytes_per_pixel, true), TAG,
|
||||
"transmit RMT samples failed");
|
||||
vTaskDelay(pdMS_TO_TICKS(LED_STRIP_RESET_MS));
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static esp_err_t led_strip_rmt_clear(led_strip_t *strip)
|
||||
{
|
||||
led_strip_rmt_obj *rmt_strip = __containerof(strip, led_strip_rmt_obj, base);
|
||||
// Write zero to turn off all LEDs
|
||||
memset(rmt_strip->buffer, 0, rmt_strip->strip_len * rmt_strip->bytes_per_pixel);
|
||||
return led_strip_rmt_refresh(strip);
|
||||
}
|
||||
|
||||
static esp_err_t led_strip_rmt_del(led_strip_t *strip)
|
||||
{
|
||||
led_strip_rmt_obj *rmt_strip = __containerof(strip, led_strip_rmt_obj, base);
|
||||
ESP_RETURN_ON_ERROR(rmt_driver_uninstall(rmt_strip->rmt_channel), TAG, "uninstall RMT driver failed");
|
||||
free(rmt_strip);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t led_strip_new_rmt_device(const led_strip_config_t *led_config, const led_strip_rmt_config_t *dev_config, led_strip_handle_t *ret_strip)
|
||||
{
|
||||
led_strip_rmt_obj *rmt_strip = NULL;
|
||||
esp_err_t ret = ESP_OK;
|
||||
ESP_RETURN_ON_FALSE(led_config && dev_config && ret_strip, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
|
||||
ESP_RETURN_ON_FALSE(led_config->led_pixel_format < LED_PIXEL_FORMAT_INVALID, ESP_ERR_INVALID_ARG, TAG, "invalid led_pixel_format");
|
||||
ESP_RETURN_ON_FALSE(dev_config->flags.with_dma == 0, ESP_ERR_NOT_SUPPORTED, TAG, "DMA is not supported");
|
||||
|
||||
uint8_t bytes_per_pixel = 3;
|
||||
if (led_config->led_pixel_format == LED_PIXEL_FORMAT_GRBW) {
|
||||
bytes_per_pixel = 4;
|
||||
} else if (led_config->led_pixel_format == LED_PIXEL_FORMAT_GRB) {
|
||||
bytes_per_pixel = 3;
|
||||
} else {
|
||||
assert(false);
|
||||
}
|
||||
|
||||
// allocate memory for led_strip object
|
||||
rmt_strip = calloc(1, sizeof(led_strip_rmt_obj) + led_config->max_leds * bytes_per_pixel);
|
||||
ESP_RETURN_ON_FALSE(rmt_strip, ESP_ERR_NO_MEM, TAG, "request memory for les_strip failed");
|
||||
|
||||
// install RMT channel driver
|
||||
rmt_config_t config = RMT_DEFAULT_CONFIG_TX(led_config->strip_gpio_num, dev_config->rmt_channel);
|
||||
// set the minimal clock division because the LED strip needs a high clock resolution
|
||||
config.clk_div = 2;
|
||||
|
||||
uint8_t mem_block_num = 2;
|
||||
// override the default value if the user specify the mem block size
|
||||
if (dev_config->mem_block_symbols) {
|
||||
mem_block_num = (dev_config->mem_block_symbols + LED_STRIP_RMT_DEFAULT_MEM_BLOCK_SYMBOLS / 2) / LED_STRIP_RMT_DEFAULT_MEM_BLOCK_SYMBOLS;
|
||||
}
|
||||
config.mem_block_num = mem_block_num;
|
||||
|
||||
ESP_GOTO_ON_ERROR(rmt_config(&config), err, TAG, "RMT config failed");
|
||||
ESP_GOTO_ON_ERROR(rmt_driver_install(config.channel, 0, 0), err, TAG, "RMT install failed");
|
||||
|
||||
uint32_t counter_clk_hz = 0;
|
||||
rmt_get_counter_clock((rmt_channel_t)dev_config->rmt_channel, &counter_clk_hz);
|
||||
// ns -> ticks
|
||||
float ratio = (float)counter_clk_hz / 1e9;
|
||||
if (led_config->led_model == LED_MODEL_WS2812) {
|
||||
led_t0h_ticks = (uint32_t)(ratio * WS2812_T0H_NS);
|
||||
led_t0l_ticks = (uint32_t)(ratio * WS2812_T0L_NS);
|
||||
led_t1h_ticks = (uint32_t)(ratio * WS2812_T1H_NS);
|
||||
led_t1l_ticks = (uint32_t)(ratio * WS2812_T1L_NS);
|
||||
} else if (led_config->led_model == LED_MODEL_SK6812) {
|
||||
led_t0h_ticks = (uint32_t)(ratio * SK6812_T0H_NS);
|
||||
led_t0l_ticks = (uint32_t)(ratio * SK6812_T0L_NS);
|
||||
led_t1h_ticks = (uint32_t)(ratio * SK6812_T1H_NS);
|
||||
led_t1l_ticks = (uint32_t)(ratio * SK6812_T1L_NS);
|
||||
} else {
|
||||
assert(false);
|
||||
}
|
||||
|
||||
// adapter to translates the LES strip date frame into RMT symbols
|
||||
rmt_translator_init((rmt_channel_t)dev_config->rmt_channel, ws2812_rmt_adapter);
|
||||
|
||||
rmt_strip->bytes_per_pixel = bytes_per_pixel;
|
||||
rmt_strip->rmt_channel = (rmt_channel_t)dev_config->rmt_channel;
|
||||
rmt_strip->strip_len = led_config->max_leds;
|
||||
rmt_strip->base.set_pixel = led_strip_rmt_set_pixel;
|
||||
rmt_strip->base.refresh = led_strip_rmt_refresh;
|
||||
rmt_strip->base.clear = led_strip_rmt_clear;
|
||||
rmt_strip->base.del = led_strip_rmt_del;
|
||||
|
||||
*ret_strip = &rmt_strip->base;
|
||||
return ESP_OK;
|
||||
|
||||
err:
|
||||
if (rmt_strip) {
|
||||
free(rmt_strip);
|
||||
}
|
||||
return ret;
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue