更新灯带驱动

This commit is contained in:
LokLiang
2025-02-19 19:58:59 +08:00
parent 141a9970d8
commit af6acf8afb
4 changed files with 91 additions and 68 deletions

View File

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

View File

@@ -14,19 +14,12 @@
#include <stdio.h>
#include <stdint.h>
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);

View File

@@ -5,7 +5,7 @@
#include <string.h>
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);
}

View File

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