Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions drivers/led_strip/Kconfig.ws2812
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,13 @@ config WS2812_STRIP_SPI_FORCE_NOCACHE
For SPI communication using DMA, place the WS2812 SPI buffer in the __nocache section to
ensure it is stored in uncached memory, as DMA usually requires access to uncached regions.

config WS2812_STRIP_SPI_RESET_DELAY_SEND_NOP
bool "Send reset delay using NOP frames"
help
Use SPI NOP frames to generate the reset delay before and after sending pixel data. This
ensures the MOSI line is held low during the reset period, which may not be guaranteed on
some platforms such as STM32.

endif

config WS2812_STRIP_UART
Expand Down
38 changes: 31 additions & 7 deletions drivers/led_strip/ws2812_spi.c
Original file line number Diff line number Diff line change
Expand Up @@ -126,19 +126,41 @@ static int ws2812_strip_update_rgb(const struct device *dev,
const size_t total_bits = num_pixels * cfg->num_colors *
BITS_PER_COLOR_CHANNEL * bits_per_symbol;
const size_t buf_len = DIV_ROUND_UP(total_bits, SPI_FRAME_BITS);
struct spi_buf buf = {
.buf = cfg->px_buf,
.len = buf_len,
};
struct spi_buf buffers[COND_CODE_0(CONFIG_WS2812_STRIP_SPI_RESET_DELAY_SEND_NOP, (1), (3))];
struct spi_buf *buf = &buffers[0];
const struct spi_buf_set tx = {
.buffers = &buf,
.count = 1
.buffers = buffers,
.count = ARRAY_SIZE(buffers),
};
uint32_t reset_delay_cycles;
uint8_t *px_buf = cfg->px_buf;
uint8_t bit_mask = BIT(SPI_FRAME_BITS - 1);
size_t i;
int rc;

if (IS_ENABLED(CONFIG_WS2812_STRIP_SPI_RESET_DELAY_SEND_NOP)) {
/*
* Convert the reset delay from micro seconds to a number of cycles of the SPI
* clock. The bus frequency is a maximum and may not be the actual frequency used.
* In that case, the reset delay will be longer than expected but that should not be
* an issue.
*/
reset_delay_cycles = cfg->bus.config.frequency * cfg->reset_delay / USEC_PER_SEC;

/*
* Define dummy buffers that will send zeroes on the MOSI line for the duration of
* the reset delay.
*/
buffers[0].buf = NULL;
buffers[0].len = reset_delay_cycles / 8;
buf = &buffers[1];
buffers[2].buf = NULL;
buffers[2].len = reset_delay_cycles / 8;
}

buf->buf = cfg->px_buf;
buf->len = buf_len;

/*
* Convert pixel data into an SPI bitstream. The bitstream contains
* pixel data in color mapping on-wire format (e.g. GRB, GRBW, RGB,
Expand Down Expand Up @@ -182,7 +204,9 @@ static int ws2812_strip_update_rgb(const struct device *dev,
* Display the pixel data.
*/
rc = spi_write_dt(&cfg->bus, &tx);
ws2812_reset_delay(cfg->reset_delay);
if (!IS_ENABLED(CONFIG_WS2812_STRIP_SPI_RESET_DELAY_SEND_NOP)) {
ws2812_reset_delay(cfg->reset_delay);
}

return rc;
}
Expand Down