From 0853287c7c0ae90f5c015f3637ed49a57f1b7729 Mon Sep 17 00:00:00 2001 From: OPTOC <9159397+optoc@user.noreply.gitee.com> Date: Wed, 20 Aug 2025 11:31:55 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B7=BB=E5=8A=A0RGB=E7=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/CMakeLists.txt | 3 + app/drivers/led_strip/led_strip.c | 103 ++++++++++++++++++ app/drivers/led_strip/led_strip.h | 48 +++++++++ app/drivers/led_strip/led_strip_encoder.c | 125 ++++++++++++++++++++++ app/drivers/led_strip/led_strip_encoder.h | 36 +++++++ app/drivers/led_strip/led_strip_shell.c | 100 +++++++++++++++++ app/drivers/led_strip/led_strip_shell.h | 8 ++ app/drivers/sertrf/sertrf.c | 3 +- app/drivers/sertrf/sertrf.h | 2 +- 9 files changed, 426 insertions(+), 2 deletions(-) create mode 100644 app/drivers/led_strip/led_strip.c create mode 100644 app/drivers/led_strip/led_strip.h create mode 100644 app/drivers/led_strip/led_strip_encoder.c create mode 100644 app/drivers/led_strip/led_strip_encoder.h create mode 100644 app/drivers/led_strip/led_strip_shell.c create mode 100644 app/drivers/led_strip/led_strip_shell.h diff --git a/app/CMakeLists.txt b/app/CMakeLists.txt index 79ab790..7a0f5ef 100644 --- a/app/CMakeLists.txt +++ b/app/CMakeLists.txt @@ -30,6 +30,9 @@ list(APPEND srcs "utils/sb_aes.c") list(APPEND srcs "drivers/sertrf/sertrf.c") list(APPEND srcs "drivers/sertrf/device.c") +list(APPEND srcs "drivers/led_strip/led_strip.c") +list(APPEND srcs "drivers/led_strip/led_strip_encoder.c") + if(CONFIG_BUILD_BLE) list(APPEND srcs "drivers/data_port/ble_spp/ble_spp_server.c") list(APPEND srcs "drivers/data_port/ble_spp/ble_spp_server_shell.c") diff --git a/app/drivers/led_strip/led_strip.c b/app/drivers/led_strip/led_strip.c new file mode 100644 index 0000000..3af327b --- /dev/null +++ b/app/drivers/led_strip/led_strip.c @@ -0,0 +1,103 @@ +#include "led_strip.h" + +rmt_channel_handle_t led_chan = NULL; +rmt_encoder_handle_t led_encoder = NULL; +rmt_transmit_config_t tx_config = { + .loop_count = 0, // no transfer loop +}; + +static uint8_t led_strip_pixels[EXAMPLE_LED_NUMBERS * 3]; +uint16_t toggle_cycle = 1000; +static uint8_t rgb_color_index = RGB_COLOR_RAD; + +rgb_color_t rgb_color_rad = {0,255,0,0,0}; +rgb_color_t rgb_color_green = {0,0,255,0,0}; +rgb_color_t rgb_color_blue = {0,0,0,255,0}; + + + +void led_strip_init(void) +{ + + // ESP_LOGI(TAG, "Create RMT TX channel"); + + rmt_tx_channel_config_t tx_chan_config = { + .clk_src = RMT_CLK_SRC_DEFAULT, // select source clock + .gpio_num = RMT_LED_STRIP_GPIO_NUM, + .mem_block_symbols = 64, // increase the block size can make the LED less flickering + .resolution_hz = RMT_LED_STRIP_RESOLUTION_HZ, + .trans_queue_depth = 4, // set the number of transactions that can be pending in the background + }; + ESP_ERROR_CHECK(rmt_new_tx_channel(&tx_chan_config, &led_chan)); + + // ESP_LOGI(TAG, "Install led strip encoder"); + + led_strip_encoder_config_t encoder_config = { + .resolution = RMT_LED_STRIP_RESOLUTION_HZ, + }; + ESP_ERROR_CHECK(rmt_new_led_strip_encoder(&encoder_config, &led_encoder)); + + // ESP_LOGI(TAG, "Enable RMT TX channel"); + ESP_ERROR_CHECK(rmt_enable(led_chan)); + + // ESP_LOGI(TAG, "Start LED rainbow chase"); + + +} +void led_strip_set_pixel(uint8_t pin, uint8_t index, uint8_t green, uint8_t blue, uint8_t red) +{ + led_strip_pixels[0 + index * 3] = green; + led_strip_pixels[1 + index * 3] = red; + led_strip_pixels[2 + index * 3] = blue; + ESP_ERROR_CHECK(rmt_transmit(led_chan, led_encoder, led_strip_pixels, sizeof(led_strip_pixels), &tx_config)); + ESP_ERROR_CHECK(rmt_tx_wait_all_done(led_chan, portMAX_DELAY)); +} + +void work_rgb_led_start(void) +{ + led_strip_init(); + /* 创建 shell 的接收任务 _work_sh() */ + static os_work_t work_handler_rgb_led; + os_work_create(&work_handler_rgb_led, "work-rgb-led", _work_rgb_led, NULL, OS_PRIORITY_NORMAL); + os_work_submit(default_os_work_q_hdl, &work_handler_rgb_led, toggle_cycle * 0.5); + +} + +void _work_rgb_led(void *arg) +{ + static rgb_color_t* expression; + switch (rgb_color_index) + { + case RGB_COLOR_RAD: + expression = &rgb_color_rad; + break; + case RGB_COLOR_GREEN: + expression = &rgb_color_green; + break; + case RGB_COLOR_BLUE: + expression = &rgb_color_blue; + break; + default: + break; + } + rgb_toggle(expression); + os_work_later(toggle_cycle * 0.5); +} +void rgb_update_cyle(uint16_t cyle) +{ + toggle_cycle = cyle; +} +void rgb_toggle(rgb_color_t* rgb_color) +{ + if(rgb_color->toggle_flag == 0) + led_strip_set_pixel(0,rgb_color->index,rgb_color->green,rgb_color->blue,rgb_color->red); + else + led_strip_set_pixel(0,rgb_color->index,0,0,0); + + rgb_color->toggle_flag = !rgb_color->toggle_flag; +} + +void rgb_color_change(uint8_t index, uint8_t color) +{ + rgb_color_index = color; +} \ No newline at end of file diff --git a/app/drivers/led_strip/led_strip.h b/app/drivers/led_strip/led_strip.h new file mode 100644 index 0000000..d3c7de3 --- /dev/null +++ b/app/drivers/led_strip/led_strip.h @@ -0,0 +1,48 @@ +#pragma once + +#include +#include +#include "led_strip_encoder.h" +#include "esp_log.h" +#include "driver/rmt_tx.h" +#include "freertos/FreeRTOS.h" +#include "os/os.h" +#include "../../config/board_config.h" + +#define RMT_LED_STRIP_RESOLUTION_HZ 10000000 // 10MHz resolution, 1 tick = 0.1us (led strip needs a high resolution) +// #define RMT_LED_STRIP_GPIO_NUM g_cfg_board->rgb_led_pin +#define RMT_LED_STRIP_GPIO_NUM 8 + +#define EXAMPLE_LED_NUMBERS 2 +#define EXAMPLE_CHASE_SPEED_MS 10 + +// static const char *TAG = "example"; + +extern rmt_channel_handle_t led_chan; +extern rmt_encoder_handle_t led_encoder; +extern rmt_transmit_config_t tx_config; + + +typedef struct rgb_color_s +{ + uint8_t index; + uint8_t red; + uint8_t green; + uint8_t blue; + uint8_t toggle_flag; +}rgb_color_t; + +typedef enum +{ + RGB_COLOR_RAD = 0, + RGB_COLOR_GREEN, + RGB_COLOR_BLUE, +}RGB_COLOR; + +void led_strip_init(void); +void led_strip_set_pixel(uint8_t pin, uint8_t index, uint8_t green, uint8_t blue, uint8_t red); +void work_rgb_led_start(void); +void _work_rgb_led(void *arg); +void rgb_update_cyle(uint16_t cyle); +void rgb_toggle(rgb_color_t* rgb_color); +void rgb_color_change(uint8_t index, uint8_t color); \ No newline at end of file diff --git a/app/drivers/led_strip/led_strip_encoder.c b/app/drivers/led_strip/led_strip_encoder.c new file mode 100644 index 0000000..15b5018 --- /dev/null +++ b/app/drivers/led_strip/led_strip_encoder.c @@ -0,0 +1,125 @@ +/* + * SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "esp_check.h" +#include "led_strip_encoder.h" + +static const char *TAG = "led_encoder"; + +typedef struct { + rmt_encoder_t base; + rmt_encoder_t *bytes_encoder; + rmt_encoder_t *copy_encoder; + int state; + rmt_symbol_word_t reset_code; +} rmt_led_strip_encoder_t; + + +static size_t rmt_encode_led_strip(rmt_encoder_t *encoder, rmt_channel_handle_t channel, const void *primary_data, size_t data_size, rmt_encode_state_t *ret_state) +{ + rmt_led_strip_encoder_t *led_encoder = __containerof(encoder, rmt_led_strip_encoder_t, base); + rmt_encoder_handle_t bytes_encoder = led_encoder->bytes_encoder; + rmt_encoder_handle_t copy_encoder = led_encoder->copy_encoder; + rmt_encode_state_t session_state = RMT_ENCODING_RESET; + rmt_encode_state_t state = RMT_ENCODING_RESET; + size_t encoded_symbols = 0; + switch (led_encoder->state) { + case 0: // send RGB data + encoded_symbols += bytes_encoder->encode(bytes_encoder, channel, primary_data, data_size, &session_state); + if (session_state & RMT_ENCODING_COMPLETE) { + led_encoder->state = 1; // switch to next state when current encoding session finished + } + if (session_state & RMT_ENCODING_MEM_FULL) { + state |= RMT_ENCODING_MEM_FULL; + goto out; // yield if there's no free space for encoding artifacts + } + // fall-through + case 1: // send reset code + encoded_symbols += copy_encoder->encode(copy_encoder, channel, &led_encoder->reset_code, + sizeof(led_encoder->reset_code), &session_state); + if (session_state & RMT_ENCODING_COMPLETE) { + led_encoder->state = RMT_ENCODING_RESET; // back to the initial encoding session + state |= RMT_ENCODING_COMPLETE; + } + if (session_state & RMT_ENCODING_MEM_FULL) { + state |= RMT_ENCODING_MEM_FULL; + goto out; // yield if there's no free space for encoding artifacts + } + } +out: + *ret_state = state; + return encoded_symbols; +} + +static esp_err_t rmt_del_led_strip_encoder(rmt_encoder_t *encoder) +{ + rmt_led_strip_encoder_t *led_encoder = __containerof(encoder, rmt_led_strip_encoder_t, base); + rmt_del_encoder(led_encoder->bytes_encoder); + rmt_del_encoder(led_encoder->copy_encoder); + free(led_encoder); + return ESP_OK; +} + +static esp_err_t rmt_led_strip_encoder_reset(rmt_encoder_t *encoder) +{ + rmt_led_strip_encoder_t *led_encoder = __containerof(encoder, rmt_led_strip_encoder_t, base); + rmt_encoder_reset(led_encoder->bytes_encoder); + rmt_encoder_reset(led_encoder->copy_encoder); + led_encoder->state = RMT_ENCODING_RESET; + return ESP_OK; +} + +esp_err_t rmt_new_led_strip_encoder(const led_strip_encoder_config_t *config, rmt_encoder_handle_t *ret_encoder) +{ + esp_err_t ret = ESP_OK; + rmt_led_strip_encoder_t *led_encoder = NULL; + ESP_GOTO_ON_FALSE(config && ret_encoder, ESP_ERR_INVALID_ARG, err, TAG, "invalid argument"); + led_encoder = rmt_alloc_encoder_mem(sizeof(rmt_led_strip_encoder_t)); + ESP_GOTO_ON_FALSE(led_encoder, ESP_ERR_NO_MEM, err, TAG, "no mem for led strip encoder"); + led_encoder->base.encode = rmt_encode_led_strip; + led_encoder->base.del = rmt_del_led_strip_encoder; + led_encoder->base.reset = rmt_led_strip_encoder_reset; + // different led strip might have its own timing requirements, following parameter is for WS2812 + rmt_bytes_encoder_config_t bytes_encoder_config = { + .bit0 = { + .level0 = 1, + .duration0 = 0.3 * config->resolution / 1000000, // T0H=0.3us + .level1 = 0, + .duration1 = 0.9 * config->resolution / 1000000, // T0L=0.9us + }, + .bit1 = { + .level0 = 1, + .duration0 = 0.9 * config->resolution / 1000000, // T1H=0.9us + .level1 = 0, + .duration1 = 0.3 * config->resolution / 1000000, // T1L=0.3us + }, + .flags.msb_first = 1 // WS2812 transfer bit order: G7...G0R7...R0B7...B0 + }; + ESP_GOTO_ON_ERROR(rmt_new_bytes_encoder(&bytes_encoder_config, &led_encoder->bytes_encoder), err, TAG, "create bytes encoder failed"); + rmt_copy_encoder_config_t copy_encoder_config = {}; + ESP_GOTO_ON_ERROR(rmt_new_copy_encoder(©_encoder_config, &led_encoder->copy_encoder), err, TAG, "create copy encoder failed"); + + uint32_t reset_ticks = config->resolution / 1000000 * 50 / 2; // reset code duration defaults to 50us + led_encoder->reset_code = (rmt_symbol_word_t) { + .level0 = 0, + .duration0 = reset_ticks, + .level1 = 0, + .duration1 = reset_ticks, + }; + *ret_encoder = &led_encoder->base; + return ESP_OK; +err: + if (led_encoder) { + if (led_encoder->bytes_encoder) { + rmt_del_encoder(led_encoder->bytes_encoder); + } + if (led_encoder->copy_encoder) { + rmt_del_encoder(led_encoder->copy_encoder); + } + free(led_encoder); + } + return ret; +} diff --git a/app/drivers/led_strip/led_strip_encoder.h b/app/drivers/led_strip/led_strip_encoder.h new file mode 100644 index 0000000..db5ef07 --- /dev/null +++ b/app/drivers/led_strip/led_strip_encoder.h @@ -0,0 +1,36 @@ +/* + * SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#pragma once + +#include +#include "driver/rmt_encoder.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Type of led strip encoder configuration + */ +typedef struct { + uint32_t resolution; /*!< Encoder resolution, in Hz */ +} led_strip_encoder_config_t; + +/** + * @brief Create RMT encoder for encoding LED strip pixels into RMT symbols + * + * @param[in] config Encoder configuration + * @param[out] ret_encoder Returned encoder handle + * @return + * - ESP_ERR_INVALID_ARG for any invalid arguments + * - ESP_ERR_NO_MEM out of memory when creating led strip encoder + * - ESP_OK if creating encoder successfully + */ +esp_err_t rmt_new_led_strip_encoder(const led_strip_encoder_config_t *config, rmt_encoder_handle_t *ret_encoder); + +#ifdef __cplusplus +} +#endif diff --git a/app/drivers/led_strip/led_strip_shell.c b/app/drivers/led_strip/led_strip_shell.c new file mode 100644 index 0000000..18efdf9 --- /dev/null +++ b/app/drivers/led_strip/led_strip_shell.c @@ -0,0 +1,100 @@ +#include "led_strip_shell.h" +#include "../pin_io/pin_io.h" + +static int32_t s_value = 0; + +SH_CMD_FN(set); +SH_CMD_FN(start); +SH_CMD_FN(clr); + +//设置子命令 +SH_DEF_SUB_CMD( + sub_led, + SH_SETUP_CMD("set", "点亮灯珠 <引脚号> <灯珠号> [红] [绿] [蓝]", set, NULL), // + SH_SETUP_CMD("start", "开启按键检测 1:初始化 2:检测", start, NULL), // + SH_SETUP_CMD("clr", "熄灭全部灯珠 <引脚号>", clr, NULL), // + +); +//设置主命令 +SH_DEF_CMD( + _register_cmd, + SH_SETUP_CMD("led", "操作灯带驱动", NULL, sub_led), // +); +//设置存储解析到的数据 +static int _set_value(const char *argv[]) { return SET_VAR(&s_value, 0, 0x100); } + +void led_strip_shell_register(void) +{ + sh_register_cmd(&_register_cmd); +} + +void led_strip_shell_unregister(void) +{ + +} +SH_CMD_FN(set) +{ + uint32_t pin = 0, index = 0, red = 0, green = 0, blue = 0; + if (argc < 5) + { + sh_echo(sh_hdl, "输入少于 5 个参数\r\n"); + return -1; + } + + if (argc >= 1 && _set_value(&argv[0])) + return -1; + pin = *(volatile __typeof(s_value) *)&s_value; + + if (argc >= 2 && _set_value(&argv[1])) + return -1; + index = *(volatile __typeof(s_value) *)&s_value; + + if (argc >= 3 && _set_value(&argv[2])) + return -1; + red = *(volatile __typeof(s_value) *)&s_value; + + if (argc >= 4 && _set_value(&argv[3])) + return -1; + green = *(volatile __typeof(s_value) *)&s_value; + + if (argc >= 5 && _set_value(&argv[4])) + return -1; + blue = *(volatile __typeof(s_value) *)&s_value; + + led_strip_set_pixel(pin,index,green,red,blue); + return 0; +} + +SH_CMD_FN(start) +{ + static uint32_t start_flag; + if (argc < 1) + { + sh_echo(sh_hdl, "输入少于 1 个参数\r\n"); + return -1; + } + + if (argc >= 1 && _set_value(&argv[0])) + return -1; + start_flag = *(volatile __typeof(s_value) *)&s_value; + + if (start_flag == 1) + { + // pin_cfg_input(&g_cfg_board->key_reset); + } + else if (start_flag == 2) + { + // bool data_flag = pin_get_valid(&g_cfg_board->key_reset); + // sh_echo(sh_hdl, "数据 %d\r\n", data_flag); + } + return 0; +} +SH_CMD_FN(clr) +{ + if (argc < 1) + { + sh_echo(sh_hdl, "输入少于 1 个参数\r\n"); + return -1; + } + return 0; +} \ No newline at end of file diff --git a/app/drivers/led_strip/led_strip_shell.h b/app/drivers/led_strip/led_strip_shell.h new file mode 100644 index 0000000..21874ac --- /dev/null +++ b/app/drivers/led_strip/led_strip_shell.h @@ -0,0 +1,8 @@ +#pragma once + +#include "led_strip.h" +#include "shell/sh.h" +#include "sh_vset.h" + +void led_strip_shell_register(void); +void led_strip_shell_register(void); diff --git a/app/drivers/sertrf/sertrf.c b/app/drivers/sertrf/sertrf.c index 099b4d7..f0fe845 100644 --- a/app/drivers/sertrf/sertrf.c +++ b/app/drivers/sertrf/sertrf.c @@ -10,7 +10,8 @@ void sertrf_init(void) { SYS_LOG_WRN("device init error"); } - + //RGB灯 + work_rgb_led_start(); sertrf_start(); } void sertrf_start(void) diff --git a/app/drivers/sertrf/sertrf.h b/app/drivers/sertrf/sertrf.h index 4fd7eea..8070730 100644 --- a/app/drivers/sertrf/sertrf.h +++ b/app/drivers/sertrf/sertrf.h @@ -1,7 +1,7 @@ #pragma once #include "device.h" - +#include "../led_strip/led_strip.h" typedef struct {