更新模板到最新状态
This commit is contained in:
18
app/CMakeLists.txt
Normal file
18
app/CMakeLists.txt
Normal file
@@ -0,0 +1,18 @@
|
||||
list(APPEND incs ".")
|
||||
list(APPEND incs "../components/system/include")
|
||||
list(APPEND incs "../components/system/source")
|
||||
list(APPEND incs "../components/system/source/k_kit")
|
||||
list(APPEND incs "../components/system/source/shell")
|
||||
|
||||
list(APPEND srcs "../app/app_main.c")
|
||||
list(APPEND srcs "../app/console.c")
|
||||
list(APPEND srcs "../app/drivers/data_port/sb_data_port.c")
|
||||
list(APPEND srcs "../app/drivers/data_port/uart/uart_port.c")
|
||||
list(APPEND srcs "../app/button/button_event.c")
|
||||
list(APPEND srcs "../app/config/board_config.c")
|
||||
|
||||
idf_component_register(
|
||||
INCLUDE_DIRS ${incs}
|
||||
SRCS ${srcs}
|
||||
REQUIRES driver nvs_flash
|
||||
)
|
||||
@@ -47,7 +47,7 @@ void work_app_main(void *arg)
|
||||
SYS_LOG_INF("app start");
|
||||
vset_init(&g_uart_handle_vt100, _vset_cb);
|
||||
os_thread_sleep(100);
|
||||
shell_start();
|
||||
shell_start(NULL);
|
||||
}
|
||||
|
||||
static void _init_nvs(void)
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#include "driver/uart.h"
|
||||
#include "console.h"
|
||||
#include "shell/sh.h"
|
||||
#include "shell/sh_vset.h"
|
||||
#include "os/os.h"
|
||||
#include "drivers/chip/uart.h"
|
||||
#include "config/board_config.h"
|
||||
@@ -83,7 +84,7 @@ static int _port_sh_vprint_fn(const char *format, va_list va)
|
||||
* 1. 执行对应的初始化
|
||||
* 2. 自动默认工作队列中创建一个解析数据的后台
|
||||
*/
|
||||
void shell_start(void)
|
||||
void shell_start(void *arg)
|
||||
{
|
||||
static uint8_t start_flag = 0;
|
||||
|
||||
@@ -94,6 +95,7 @@ void shell_start(void)
|
||||
|
||||
/* 执行 shell 内部的初始化 */
|
||||
sh_register_external(_port_sh_vprint_fn);
|
||||
vset_init(&g_uart_handle_vt100, arg);
|
||||
|
||||
/* 注册系统命令 */
|
||||
extern void soc_shell_register(void);
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
|
||||
typedef void (*shell_input_cb)(sh_t *sh_hdl, char c);
|
||||
|
||||
void shell_start();
|
||||
void shell_start(void *arg);
|
||||
|
||||
void shell_input_set(shell_input_cb cb);
|
||||
void shell_input_restore(void);
|
||||
|
||||
251
app/drivers/ws2812_spi/ws2812_spi.c
Executable file
251
app/drivers/ws2812_spi/ws2812_spi.c
Executable file
@@ -0,0 +1,251 @@
|
||||
/**
|
||||
* @file ws2812_spi.c
|
||||
* @author your name (you@domain.com)
|
||||
* @brief 通过 SPI 硬件模拟 PWM 信号,驱动 WS2812 的程序
|
||||
* @version 0.1
|
||||
* @date 2023-10-05
|
||||
*
|
||||
* @copyright Copyright (c) 2023
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
#include <sys/cdefs.h>
|
||||
|
||||
#include "esp_log.h"
|
||||
#include "esp_attr.h"
|
||||
#include "esp_rom_gpio.h"
|
||||
#include "driver/spi_master.h"
|
||||
#include "driver/gpio.h"
|
||||
#include "soc/spi_periph.h"
|
||||
#include "soc/gpio_periph.h"
|
||||
|
||||
#include "ws2812_spi.h"
|
||||
#include "drivers/pin_io/pin_io.h"
|
||||
|
||||
#include "os/os.h"
|
||||
|
||||
#define CONFIG_SYS_LOG_LEVEL SYS_LOG_LEVEL_INF
|
||||
#define SYS_LOG_DOMAIN "LED_STRIP_SPI"
|
||||
#include "sys_log.h"
|
||||
|
||||
#define SPI_CLK_HZ 8000000
|
||||
#define WS_HIGH 0x3
|
||||
#define WS_LOW 0x3F
|
||||
#define WS_RESET ~0
|
||||
#define RESET_TIME_US 50
|
||||
#define RESET_BIT_LENGTH (SPI_CLK_HZ * (RESET_TIME_US) / 1000000)
|
||||
#define _POW_Y 1.3
|
||||
|
||||
static struct
|
||||
{
|
||||
os_mutex_t mutex_hdl;
|
||||
} s_cm;
|
||||
|
||||
/**
|
||||
* @brief 初始化工作环境。这将初始化 SPI 驱动并申请显示缓存到对象中。可重初始化
|
||||
*
|
||||
* @param led_strip[out] 灯带驱动对象
|
||||
* @param spi_host 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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
esp_err_t ret;
|
||||
spi_bus_config_t buscfg = {
|
||||
.miso_io_num = -1,
|
||||
.mosi_io_num = -1,
|
||||
.sclk_io_num = -1,
|
||||
.quadwp_io_num = -1,
|
||||
.quadhd_io_num = -1,
|
||||
.max_transfer_sz = max_transfer_sz};
|
||||
|
||||
// Initialize the SPI bus
|
||||
ret = spi_bus_initialize(spi_host, &buscfg, SPI_DMA_CH_AUTO);
|
||||
ESP_ERROR_CHECK(ret);
|
||||
|
||||
spi_device_interface_config_t devcfg = {
|
||||
.clock_speed_hz = SPI_CLK_HZ,
|
||||
.mode = 0,
|
||||
.spics_io_num = -1,
|
||||
.queue_size = 1,
|
||||
.pre_cb = NULL,
|
||||
.command_bits = 0,
|
||||
.address_bits = 0};
|
||||
// Attach the LCD to the SPI bus
|
||||
ret = spi_bus_add_device(spi_host, &devcfg, &s_spi_hdl);
|
||||
ESP_ERROR_CHECK(ret);
|
||||
}
|
||||
|
||||
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);
|
||||
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;
|
||||
float max = pow(0x100, _POW_Y) / 0x100;
|
||||
for (int i = 0; i < 0x100; i++)
|
||||
{
|
||||
led_strip->pow_tbl[i] = (int)(pow(i, _POW_Y) / max) + 1;
|
||||
if (led_strip->pow_tbl[i] > 0xFF)
|
||||
{
|
||||
led_strip->pow_tbl[i] = 0xFF;
|
||||
}
|
||||
}
|
||||
led_strip->pow_tbl[0] = 0;
|
||||
|
||||
/* 使所有数据合法化 */
|
||||
ws2812_spi_led_strip_clear(led_strip);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 使所有显存清零。注意需要通过 ws2812_spi_led_strip_refresh() 方可把数据刷新到灯带中。
|
||||
*
|
||||
* @param led_strip 灯带驱动对象
|
||||
*/
|
||||
void ws2812_spi_led_strip_clear(ws2812_spi_led_strip_t *led_strip)
|
||||
{
|
||||
if (led_strip->led_dma_buffer == NULL)
|
||||
{
|
||||
SYS_LOG_WRN("led strip buffer is null");
|
||||
return;
|
||||
}
|
||||
|
||||
memset(led_strip->led_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);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @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
|
||||
*/
|
||||
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)
|
||||
{
|
||||
if (led_strip->led_dma_buffer == NULL)
|
||||
{
|
||||
SYS_LOG_WRN("led strip buffer is null");
|
||||
return;
|
||||
}
|
||||
|
||||
if (index > led_strip->max_led_num)
|
||||
{
|
||||
SYS_LOG_WRN("index: %u > led_strip->max_led_num: %u", index, led_strip->max_led_num);
|
||||
return;
|
||||
}
|
||||
|
||||
if (red > 255 || green > 255 || blue > 255)
|
||||
{
|
||||
SYS_LOG_WRN("param over range");
|
||||
return;
|
||||
}
|
||||
|
||||
/* 套指数表 */
|
||||
red = led_strip->pow_tbl[red];
|
||||
green = led_strip->pow_tbl[green];
|
||||
blue = led_strip->pow_tbl[blue];
|
||||
uint32_t color = (green & 0xFF) << 16 | (red & 0xFF) << 8 | (blue & 0xFF);
|
||||
|
||||
/* PWM 编码 */
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 执行把显示缓存刷新到灯带
|
||||
*
|
||||
* @param led_strip 灯带驱动对象
|
||||
* @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)
|
||||
{
|
||||
if (led_strip == NULL || led_strip->spi_handle == NULL)
|
||||
{
|
||||
SYS_LOG_ERR("led strip spi handler is null");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (leds > led_strip->max_led_num)
|
||||
{
|
||||
SYS_LOG_WRN("leds > led_strip->max_led_num");
|
||||
leds = led_strip->max_led_num;
|
||||
}
|
||||
|
||||
os_mutex_lock(&s_cm.mutex_hdl, OS_WAIT_FOREVER);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
if (led_strip->spi_pin != pin)
|
||||
{
|
||||
if (led_strip->spi_pin > 0)
|
||||
{
|
||||
cfg_board_pin_io_t cfg_pin = {.pin = led_strip->spi_pin, .en_lev = 1};
|
||||
pin_cfg_output(&cfg_pin);
|
||||
pin_set_valid(&cfg_pin, true);
|
||||
}
|
||||
|
||||
if (pin > 0)
|
||||
{
|
||||
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);
|
||||
}
|
||||
led_strip->spi_pin = pin;
|
||||
}
|
||||
|
||||
esp_err_t err = spi_device_transmit(led_strip->spi_handle, &t);
|
||||
|
||||
os_mutex_unlock(&s_cm.mutex_hdl);
|
||||
|
||||
ESP_ERROR_CHECK(err);
|
||||
return err;
|
||||
}
|
||||
32
app/drivers/ws2812_spi/ws2812_spi.h
Executable file
32
app/drivers/ws2812_spi/ws2812_spi.h
Executable file
@@ -0,0 +1,32 @@
|
||||
/**
|
||||
* @file ws2812_spi.h
|
||||
* @author Azol
|
||||
* @brief 通过 SPI 的 MOSI 引脚驱动灯带的程序
|
||||
* @version 0.1
|
||||
* @date 2023-09-28
|
||||
*
|
||||
* @copyright Copyright (c) 2023
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#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;
|
||||
|
||||
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_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);
|
||||
95
app/drivers/ws2812_spi/ws2812_spi_shell.c
Normal file
95
app/drivers/ws2812_spi/ws2812_spi_shell.c
Normal file
@@ -0,0 +1,95 @@
|
||||
#include "ws2812_spi_shell.h"
|
||||
#include "ws2812_spi.h"
|
||||
#include "shell/sh.h"
|
||||
#include "sh_vset.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
static ws2812_spi_led_strip_t *s_led_strip;
|
||||
static uint32_t s_value;
|
||||
|
||||
SH_CMD_FN(set);
|
||||
SH_CMD_FN(clr);
|
||||
|
||||
SH_DEF_SUB_CMD(
|
||||
sub_led,
|
||||
SH_SETUP_CMD("set", "点亮灯珠 <引脚号> <灯珠号> [红] [绿] [蓝]", set, NULL), //
|
||||
SH_SETUP_CMD("clr", "熄灭全部灯珠 <引脚号>", clr, NULL), //
|
||||
);
|
||||
|
||||
SH_DEF_CMD(
|
||||
_register_cmd,
|
||||
SH_SETUP_CMD("led", "操作灯带驱动", NULL, sub_led), //
|
||||
);
|
||||
|
||||
void ws2812_spi_shell_register(ws2812_spi_led_strip_t *led_strip)
|
||||
{
|
||||
s_led_strip = led_strip;
|
||||
sh_register_cmd(&_register_cmd);
|
||||
}
|
||||
|
||||
void ws2812_spi_shell_unregister(void)
|
||||
{
|
||||
sh_unregister_cmd(&_register_cmd);
|
||||
}
|
||||
|
||||
static int _set_value(const char *argv[]) { return SET_VAR(&s_value, 0, 0x100); }
|
||||
|
||||
SH_CMD_FN(set)
|
||||
{
|
||||
uint32_t pin = 0, index = 0, red = 0, green = 0, blue = 0;
|
||||
if (argc < 2)
|
||||
{
|
||||
sh_echo(sh_hdl, "输入少于 2 个参数\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;
|
||||
|
||||
ws2812_spi_led_strip_set_pixel(s_led_strip, index, red, green, blue);
|
||||
#if (CONFIG_LED_STRIP_MAX_LEDS)
|
||||
ws2812_spi_led_strip_refresh(s_led_strip, CONFIG_LED_STRIP_MAX_LEDS, pin);
|
||||
#else
|
||||
ws2812_spi_led_strip_refresh(s_led_strip, 126, pin);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
SH_CMD_FN(clr)
|
||||
{
|
||||
uint32_t pin = 0;
|
||||
if (argc < 1)
|
||||
{
|
||||
sh_echo(sh_hdl, "输入少于 1 个参数\r\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
_set_value(&argv[0]);
|
||||
pin = *(volatile __typeof(s_value) *)&s_value;
|
||||
|
||||
ws2812_spi_led_strip_clear(s_led_strip);
|
||||
#if (CONFIG_LED_STRIP_MAX_LEDS)
|
||||
ws2812_spi_led_strip_refresh(s_led_strip, CONFIG_LED_STRIP_MAX_LEDS, pin);
|
||||
#else
|
||||
ws2812_spi_led_strip_refresh(s_led_strip, 126, pin);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
6
app/drivers/ws2812_spi/ws2812_spi_shell.h
Normal file
6
app/drivers/ws2812_spi/ws2812_spi_shell.h
Normal file
@@ -0,0 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "ws2812_spi.h"
|
||||
|
||||
void ws2812_spi_shell_register(ws2812_spi_led_strip_t *led_strip);
|
||||
void ws2812_spi_strip_shell_unregister(void);
|
||||
BIN
app/drivers/ws2812_spi/ws2812b中文资料-数据手册-参数.pdf
Executable file
BIN
app/drivers/ws2812_spi/ws2812b中文资料-数据手册-参数.pdf
Executable file
Binary file not shown.
Reference in New Issue
Block a user