Skip to content

Commit baa49f6

Browse files
GardeningSteviekartben
authored andcommitted
drivers: led_strip: ws2812_i2s: code cleanup, runtime optimization
Runtime improvements - bitstream calculation saves ~12% of runtime (Cortex M33) Code cleanup - unused include removed - use of util macro Signed-off-by: Stefan Schwendeler <[email protected]>
1 parent d0bc95c commit baa49f6

File tree

1 file changed

+14
-31
lines changed

1 file changed

+14
-31
lines changed

drivers/led_strip/ws2812_i2s.c

Lines changed: 14 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
* WS/LRCK frequency:
1010
* This refers to the "I2S word or channel select" clock.
11-
* The I2C peripheral sends two 16-bit channel values for each clock period.
11+
* The I2S peripheral sends two 16-bit channel values for each clock period.
1212
* A single LED color (8 data bits) will take up one 32-bit word or one LRCK
1313
* period. This means a standard RGB led will take 3 LRCK periods to transmit.
1414
*
@@ -17,8 +17,6 @@
1717

1818
#define DT_DRV_COMPAT worldsemi_ws2812_i2s
1919

20-
#include <string.h>
21-
2220
#include <zephyr/drivers/led_strip.h>
2321

2422
#define LOG_LEVEL CONFIG_LED_STRIP_LOG_LEVEL
@@ -51,43 +49,31 @@ struct ws2812_i2s_cfg {
5149
/* Serialize an 8-bit color channel value into two 16-bit I2S values (or 1 32-bit
5250
* word).
5351
*/
54-
static inline void ws2812_i2s_ser(uint32_t *word, uint8_t color, const uint8_t sym_one,
55-
const uint8_t sym_zero)
52+
static inline uint32_t ws2812_i2s_ser(uint8_t color, const uint8_t sym_one, const uint8_t sym_zero)
5653
{
57-
*word = 0;
58-
for (uint16_t i = 0; i < 8; i++) {
59-
if ((1 << i) & color) {
60-
*word |= sym_one << (i * 4);
61-
} else {
62-
*word |= sym_zero << (i * 4);
63-
}
54+
uint32_t word = 0;
55+
56+
for (uint_fast8_t mask = 0x80; mask != 0; mask >>= 1) {
57+
word <<= 4;
58+
word |= (color & mask) ? sym_one : sym_zero;
6459
}
6560

6661
/* Swap the two I2S values due to the (audio) channel TX order. */
67-
*word = (*word >> 16) | (*word << 16);
62+
return (word >> 16) | (word << 16);
6863
}
6964

7065
static int ws2812_strip_update_rgb(const struct device *dev, struct led_rgb *pixels,
7166
size_t num_pixels)
7267
{
7368
const struct ws2812_i2s_cfg *cfg = dev->config;
74-
uint8_t sym_one, sym_zero;
75-
uint32_t reset_word;
69+
const uint8_t sym_one = cfg->nibble_one;
70+
const uint8_t sym_zero = cfg->nibble_zero;
71+
const uint32_t reset_word = cfg->active_low ? ~0 : 0;
7672
uint32_t *tx_buf;
7773
uint32_t flush_time_us;
7874
void *mem_block;
7975
int ret;
8076

81-
if (cfg->active_low) {
82-
sym_one = (~cfg->nibble_one) & 0x0F;
83-
sym_zero = (~cfg->nibble_zero) & 0x0F;
84-
reset_word = 0xFFFFFFFF;
85-
} else {
86-
sym_one = cfg->nibble_one & 0x0F;
87-
sym_zero = cfg->nibble_zero & 0x0F;
88-
reset_word = 0;
89-
}
90-
9177
/* Acquire memory for the I2S payload. */
9278
ret = k_mem_slab_alloc(cfg->mem_slab, &mem_block, K_SECONDS(10));
9379
if (ret < 0) {
@@ -127,7 +113,7 @@ static int ws2812_strip_update_rgb(const struct device *dev, struct led_rgb *pix
127113
default:
128114
return -EINVAL;
129115
}
130-
ws2812_i2s_ser(tx_buf, pixel, sym_one, sym_zero);
116+
*tx_buf = ws2812_i2s_ser(pixel, sym_one, sym_zero) ^ reset_word;
131117
tx_buf++;
132118
}
133119
}
@@ -221,15 +207,12 @@ static const struct led_strip_driver_api ws2812_i2s_api = {
221207
.length = ws2812_strip_length,
222208
};
223209

224-
/* Integer division, but always rounds up: e.g. 10/3 = 4 */
225-
#define WS2812_ROUNDED_DIVISION(x, y) ((x + (y - 1)) / y)
226-
227210
#define WS2812_I2S_LRCK_PERIOD_US(idx) DT_INST_PROP(idx, lrck_period)
228211

229212
#define WS2812_RESET_DELAY_US(idx) DT_INST_PROP(idx, reset_delay)
230213
/* Rounds up to the next 20us. */
231-
#define WS2812_RESET_DELAY_WORDS(idx) WS2812_ROUNDED_DIVISION(WS2812_RESET_DELAY_US(idx), \
232-
WS2812_I2S_LRCK_PERIOD_US(idx))
214+
#define WS2812_RESET_DELAY_WORDS(idx) \
215+
DIV_ROUND_UP(WS2812_RESET_DELAY_US(idx), WS2812_I2S_LRCK_PERIOD_US(idx))
233216

234217
#define WS2812_NUM_COLORS(idx) (DT_INST_PROP_LEN(idx, color_mapping))
235218

0 commit comments

Comments
 (0)