@@ -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_han dle , & t ) ;
esp_err_t err = spi_device_transmit ( s_cm . spi_hdl , & t ) ;
os_mutex_unlock ( & s_cm . mutex_hdl ) ;