From af6acf8afb8bdcabb76959d0205d53c4de78f7cc Mon Sep 17 00:00:00 2001 From: LokLiang Date: Wed, 19 Feb 2025 19:58:59 +0800 Subject: [PATCH] =?UTF-8?q?=E6=9B=B4=E6=96=B0=E7=81=AF=E5=B8=A6=E9=A9=B1?= =?UTF-8?q?=E5=8A=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/drivers/ws2812_spi/ws2812_spi.c | 129 +++++++++++++--------- app/drivers/ws2812_spi/ws2812_spi.h | 21 ++-- app/drivers/ws2812_spi/ws2812_spi_shell.c | 7 +- app/drivers/ws2812_spi/ws2812_spi_shell.h | 2 +- 4 files changed, 91 insertions(+), 68 deletions(-) diff --git a/app/drivers/ws2812_spi/ws2812_spi.c b/app/drivers/ws2812_spi/ws2812_spi.c index e1b5580..1e5ed0e 100755 --- a/app/drivers/ws2812_spi/ws2812_spi.c +++ b/app/drivers/ws2812_spi/ws2812_spi.c @@ -39,38 +39,44 @@ #define RESET_BIT_LENGTH (SPI_CLK_HZ * (RESET_TIME_US) / 1000000) #define _POW_Y 1.3 +typedef struct ws2812_spi_led_strip_s +{ + uint32_t buffer_size; + uint16_t pow_tbl[0x100]; + uint32_t max_led_num; + uint8_t dma_buffer[0]; +} __ws2812_spi_led_buf_t; + static struct { + spi_host_device_t host_id; + spi_device_handle_t spi_hdl; os_mutex_t mutex_hdl; + uint16_t spi_pin; + int max_transfer_sz; } s_cm; /** * @brief 初始化工作环境。这将初始化 SPI 驱动并申请显示缓存到对象中。可重初始化 * - * @param led_strip[out] 灯带驱动对象 - * @param spi_host SPI peripheral that controls this bus @ref spi_host_device_t + * @param led_strip[out] 灯带驱动缓存 + * @param host_id SPI peripheral that controls this bus @ref spi_host_device_t * @param max_led_num 最大可驱动灯条共多少个灯珠 */ -void ws2812_spi_led_strip_init(ws2812_spi_led_strip_t *led_strip, uint8_t spi_host, uint16_t max_led_num) +void ws2812_spi_led_strip_init(uint8_t host_id, uint16_t max_led_num) { - static spi_device_handle_t s_spi_hdl; - SYS_ASSERT(max_led_num > 0, ""); - if (led_strip->led_dma_buffer) - { - heap_caps_free(led_strip->led_dma_buffer); - led_strip->led_dma_buffer = NULL; - - spi_bus_remove_device(led_strip->spi_handle); - - spi_bus_free(led_strip->spi_host); - } - int max_transfer_sz = max_led_num * 24 + RESET_BIT_LENGTH * 2; - if (s_spi_hdl == NULL) + if (s_cm.max_transfer_sz > 0) { + SYS_ASSERT(max_transfer_sz <= s_cm.max_transfer_sz, ""); + } + + if (s_cm.spi_hdl == NULL) + { + s_cm.max_transfer_sz = max_transfer_sz; esp_err_t ret; spi_bus_config_t buscfg = { .miso_io_num = -1, @@ -81,7 +87,7 @@ void ws2812_spi_led_strip_init(ws2812_spi_led_strip_t *led_strip, uint8_t spi_ho .max_transfer_sz = max_transfer_sz}; // Initialize the SPI bus - ret = spi_bus_initialize(spi_host, &buscfg, SPI_DMA_CH_AUTO); + ret = spi_bus_initialize(host_id, &buscfg, SPI_DMA_CH_AUTO); ESP_ERROR_CHECK(ret); spi_device_interface_config_t devcfg = { @@ -93,22 +99,40 @@ void ws2812_spi_led_strip_init(ws2812_spi_led_strip_t *led_strip, uint8_t spi_ho .command_bits = 0, .address_bits = 0}; // Attach the LCD to the SPI bus - ret = spi_bus_add_device(spi_host, &devcfg, &s_spi_hdl); + ret = spi_bus_add_device(host_id, &devcfg, &s_cm.spi_hdl); ESP_ERROR_CHECK(ret); + + s_cm.host_id = host_id; + s_cm.spi_pin = -1; } if (!os_mutex_is_valid(&s_cm.mutex_hdl)) { os_mutex_create(&s_cm.mutex_hdl); } +} - led_strip->led_dma_buffer = heap_caps_malloc(max_transfer_sz, MALLOC_CAP_DMA); // Critical to be DMA memory. - memset(led_strip->led_dma_buffer, WS_RESET, max_transfer_sz); +/** + * @brief 创建灯带驱动缓存 + * + * @param led_strip[out] 灯带驱动缓存 + * @param leds 可驱动灯条共多少个灯珠 + */ +ws2812_spi_led_buf_t *ws2812_spi_led_new_buf(uint16_t leds) +{ + __ws2812_spi_led_buf_t *led_strip; + SYS_ASSERT(leds > 0, ""); + + int max_transfer_sz = leds * 24 + RESET_BIT_LENGTH * 2; + if (s_cm.max_transfer_sz > 0) + { + SYS_ASSERT(max_transfer_sz <= s_cm.max_transfer_sz, ""); + } + + led_strip = heap_caps_malloc(sizeof(__ws2812_spi_led_buf_t) + max_transfer_sz, MALLOC_CAP_DMA); // Critical to be DMA memory. + memset(led_strip->dma_buffer, WS_RESET, max_transfer_sz); led_strip->buffer_size = max_transfer_sz; - led_strip->spi_host = spi_host; - led_strip->spi_pin = -1; - led_strip->spi_handle = s_spi_hdl; - led_strip->max_led_num = max_led_num; + led_strip->max_led_num = leds; float max = pow(0x100, _POW_Y) / 0x100; for (int i = 0; i < 0x100; i++) { @@ -122,22 +146,25 @@ void ws2812_spi_led_strip_init(ws2812_spi_led_strip_t *led_strip, uint8_t spi_ho /* 使所有数据合法化 */ ws2812_spi_led_strip_clear(led_strip); + + return (ws2812_spi_led_buf_t *)led_strip; } /** * @brief 使所有显存清零。注意需要通过 ws2812_spi_led_strip_refresh() 方可把数据刷新到灯带中。 * - * @param led_strip 灯带驱动对象 + * @param buf 灯带驱动缓存 */ -void ws2812_spi_led_strip_clear(ws2812_spi_led_strip_t *led_strip) +void ws2812_spi_led_strip_clear(ws2812_spi_led_buf_t *buf) { - if (led_strip->led_dma_buffer == NULL) + __ws2812_spi_led_buf_t *led_strip = (__ws2812_spi_led_buf_t *)buf; + if (led_strip == NULL) { SYS_LOG_WRN("led strip buffer is null"); return; } - memset(led_strip->led_dma_buffer, WS_RESET, led_strip->buffer_size); + memset(led_strip->dma_buffer, WS_RESET, led_strip->buffer_size); for (int i = 0; i < led_strip->max_led_num; i++) { ws2812_spi_led_strip_set_pixel(led_strip, i, 0, 0, 0); @@ -147,15 +174,16 @@ void ws2812_spi_led_strip_clear(ws2812_spi_led_strip_t *led_strip) /** * @brief 设一个灯珠为一个像素,设置单个像素的颜色。注意需要通过 ws2812_spi_led_strip_refresh() 方可把数据刷新到灯带中。 * - * @param led_strip 灯带驱动对象 - * @param index 灯像素序号,0 .. led_strip->max_led_num - 1 - * @param red 红基色亮度,0 .. 255 - * @param green 绿基色亮度,0 .. 255 - * @param blue 蓝基色亮度,0 .. 255 + * @param buf 灯带驱动缓存 + * @param index 灯像素序号,0 .. led_strip->max_led_num - 1 + * @param red 红基色亮度,0 .. 255 + * @param green 绿基色亮度,0 .. 255 + * @param blue 蓝基色亮度,0 .. 255 */ -void ws2812_spi_led_strip_set_pixel(ws2812_spi_led_strip_t *led_strip, uint32_t index, uint32_t red, uint32_t green, uint32_t blue) +void ws2812_spi_led_strip_set_pixel(ws2812_spi_led_buf_t *buf, uint32_t index, uint32_t red, uint32_t green, uint32_t blue) { - if (led_strip->led_dma_buffer == NULL) + __ws2812_spi_led_buf_t *led_strip = (__ws2812_spi_led_buf_t *)buf; + if (led_strip == NULL) { SYS_LOG_WRN("led strip buffer is null"); return; @@ -183,22 +211,23 @@ void ws2812_spi_led_strip_set_pixel(ws2812_spi_led_strip_t *led_strip, uint32_t for (int i = 0; i < 24; i++) { int pos = RESET_BIT_LENGTH + index * 24 + i; - led_strip->led_dma_buffer[pos] = ((color << i) & 0x800000) ? WS_HIGH : WS_LOW; + led_strip->dma_buffer[pos] = ((color << i) & 0x800000) ? WS_HIGH : WS_LOW; } } /** * @brief 执行把显示缓存刷新到灯带 * - * @param led_strip 灯带驱动对象 - * @param leds 实际刷新的灯珠数 - * @param pin 使用的引脚 + * @param buf 灯带驱动缓存 + * @param leds 实际刷新的灯珠数 + * @param pin 使用的引脚 * @retval 0 操作成功 * @retval != 0 操作失败 */ -int ws2812_spi_led_strip_refresh(ws2812_spi_led_strip_t *led_strip, uint32_t leds, uint8_t pin) +int ws2812_spi_led_strip_refresh(ws2812_spi_led_buf_t *buf, uint32_t leds, uint8_t pin) { - if (led_strip == NULL || led_strip->spi_handle == NULL) + __ws2812_spi_led_buf_t *led_strip = (__ws2812_spi_led_buf_t *)buf; + if (led_strip == NULL || s_cm.spi_hdl == NULL) { SYS_LOG_ERR("led strip spi handler is null"); return -1; @@ -206,7 +235,7 @@ int ws2812_spi_led_strip_refresh(ws2812_spi_led_strip_t *led_strip, uint32_t led if (leds > led_strip->max_led_num) { - SYS_LOG_WRN("leds > led_strip->max_led_num"); + SYS_LOG_WRN("leds(%d) > led_strip->max_led_num(%d)", leds, led_strip->max_led_num); leds = led_strip->max_led_num; } @@ -215,19 +244,19 @@ int ws2812_spi_led_strip_refresh(ws2812_spi_led_strip_t *led_strip, uint32_t led uint32_t empty_bytes = (led_strip->max_led_num - leds) * 24; if (empty_bytes) { - memset(&led_strip->led_dma_buffer[led_strip->buffer_size - empty_bytes], WS_RESET, empty_bytes); + memset(&led_strip->dma_buffer[led_strip->buffer_size - empty_bytes], WS_RESET, empty_bytes); } spi_transaction_t t; memset(&t, 0, sizeof(t)); t.length = led_strip->buffer_size * 8 - empty_bytes; // length is in bits - t.tx_buffer = led_strip->led_dma_buffer; + t.tx_buffer = led_strip->dma_buffer; - if (led_strip->spi_pin != pin) + if (s_cm.spi_pin != pin) { - if (led_strip->spi_pin > 0) + if (s_cm.spi_pin > 0) { - cfg_board_pin_io_t cfg_pin = {.pin = led_strip->spi_pin, .en_lev = 1}; + cfg_board_pin_io_t cfg_pin = {.pin = s_cm.spi_pin, .en_lev = 1}; pin_cfg_output(&cfg_pin); pin_set_valid(&cfg_pin, true); } @@ -237,12 +266,12 @@ int ws2812_spi_led_strip_refresh(ws2812_spi_led_strip_t *led_strip, uint32_t led cfg_board_pin_io_t cfg_pin = {.pin = pin, .en_lev = 1}; pin_cfg_output(&cfg_pin); gpio_set_direction(pin, GPIO_MODE_INPUT_OUTPUT); - esp_rom_gpio_connect_out_signal(pin, spi_periph_signal[led_strip->spi_host].spid_out, true, false); + esp_rom_gpio_connect_out_signal(pin, spi_periph_signal[s_cm.host_id].spid_out, true, false); } - led_strip->spi_pin = pin; + s_cm.spi_pin = pin; } - esp_err_t err = spi_device_transmit(led_strip->spi_handle, &t); + esp_err_t err = spi_device_transmit(s_cm.spi_hdl, &t); os_mutex_unlock(&s_cm.mutex_hdl); diff --git a/app/drivers/ws2812_spi/ws2812_spi.h b/app/drivers/ws2812_spi/ws2812_spi.h index dcb7d76..a4784e6 100755 --- a/app/drivers/ws2812_spi/ws2812_spi.h +++ b/app/drivers/ws2812_spi/ws2812_spi.h @@ -14,19 +14,12 @@ #include #include -typedef struct ws2812_spi_led_strip_s -{ - uint8_t *led_dma_buffer; - uint32_t buffer_size; - uint8_t spi_host; - int16_t spi_pin; - void *spi_handle; - uint32_t max_led_num; - uint16_t pow_tbl[0x100]; -} ws2812_spi_led_strip_t; +typedef struct ws2812_spi_led_buf ws2812_spi_led_buf_t; -void ws2812_spi_led_strip_init(ws2812_spi_led_strip_t *led_strip, uint8_t spi_host, uint16_t max_led_num); +void ws2812_spi_led_strip_init(uint8_t host_id, uint16_t max_led_num); -void ws2812_spi_led_strip_clear(ws2812_spi_led_strip_t *led_strip); -void ws2812_spi_led_strip_set_pixel(ws2812_spi_led_strip_t *led_strip, uint32_t index, uint32_t red, uint32_t green, uint32_t blue); -int ws2812_spi_led_strip_refresh(ws2812_spi_led_strip_t *led_strip, uint32_t leds, uint8_t pin); +ws2812_spi_led_buf_t *ws2812_spi_led_new_buf(uint16_t leds); + +void ws2812_spi_led_strip_clear(ws2812_spi_led_buf_t *buf); +void ws2812_spi_led_strip_set_pixel(ws2812_spi_led_buf_t *buf, uint32_t index, uint32_t red, uint32_t green, uint32_t blue); +int ws2812_spi_led_strip_refresh(ws2812_spi_led_buf_t *buf, uint32_t leds, uint8_t pin); diff --git a/app/drivers/ws2812_spi/ws2812_spi_shell.c b/app/drivers/ws2812_spi/ws2812_spi_shell.c index 6bcf1e7..1d471ba 100644 --- a/app/drivers/ws2812_spi/ws2812_spi_shell.c +++ b/app/drivers/ws2812_spi/ws2812_spi_shell.c @@ -5,7 +5,7 @@ #include -static ws2812_spi_led_strip_t *s_led_strip; +static ws2812_spi_led_buf_t *s_led_strip; static uint32_t s_value; SH_CMD_FN(set); @@ -22,9 +22,10 @@ SH_DEF_CMD( SH_SETUP_CMD("led", "操作灯带驱动", NULL, sub_led), // ); -void ws2812_spi_shell_register(ws2812_spi_led_strip_t *led_strip) +void ws2812_spi_shell_register(void) { - s_led_strip = led_strip; + ws2812_spi_led_strip_init(SPI2_HOST, CONFIG_LED_STRIP_MAX_LEDS); + s_led_strip = ws2812_spi_led_new_buf(CONFIG_LED_STRIP_MAX_LEDS); sh_register_cmd(&_register_cmd); } diff --git a/app/drivers/ws2812_spi/ws2812_spi_shell.h b/app/drivers/ws2812_spi/ws2812_spi_shell.h index cc733ad..bfc38d9 100644 --- a/app/drivers/ws2812_spi/ws2812_spi_shell.h +++ b/app/drivers/ws2812_spi/ws2812_spi_shell.h @@ -2,5 +2,5 @@ #include "ws2812_spi.h" -void ws2812_spi_shell_register(ws2812_spi_led_strip_t *led_strip); +void ws2812_spi_shell_register(void); void ws2812_spi_strip_shell_unregister(void);