Skip to content

Commit 6f1d8ad

Browse files
Merge branch 'feat/lightbulb_enable_dimming_curve' into 'master'
feat(lightbulb): Enable dimming curve See merge request ae_group/esp-iot-solution!1139
2 parents f293523 + 13cb283 commit 6f1d8ad

File tree

7 files changed

+108
-86
lines changed

7 files changed

+108
-86
lines changed

components/led/lightbulb_driver/CHANGELOG.md

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
# ChangeLog
22

3+
## v1.5.0 - 2024-12-25
4+
5+
### Enhancements:
6+
7+
* Remove linear dimming, default to enabling curve dimming for all.
8+
39
## v1.4.0 - 2024-11-15
410

511
### Enhancements:
@@ -16,7 +22,7 @@
1622

1723
### Enhancements:
1824

19-
* Added cct range check in precision mode
25+
* Added CCT range check in precision mode
2026

2127
## v1.3.1 - 2024-08-28
2228

@@ -75,7 +81,7 @@
7581
### Enhancements:
7682

7783
* Added the conversion function of IIC current values to the enumeration values required by the driver.
78-
* Added driver layer parameter checking macro and allowed to configure the detail level of the output log through menuconfig.
84+
* Added driver layer parameter checking macro and allowed configuring the detail level of the output log through menuconfig.
7985

8086
## v1.0.0 - 2024-01-16
8187

components/led/lightbulb_driver/idf_component.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
1-
version: "1.4.0"
1+
version: "1.5.0"
22
description: Provide multiple dimming driver solutions to easily build lightbulb applications
33
url: https://github.com/espressif/esp-iot-solution/tree/master/components/led/lightbulb_driver
44
dependencies:
55
idf: ">=4.3.2"
6-
espressif/cmake_utilities: "0.*"
6+
espressif/cmake_utilities: "*"
77
examples:
88
- path: ../../../examples/lighting/lightbulb
99
sbom:

components/led/lightbulb_driver/include/lightbulb.h

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD
2+
* SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD
33
*
44
* SPDX-License-Identifier: Apache-2.0
55
*/
@@ -173,9 +173,8 @@ typedef struct {
173173
float balance_coefficient[5]; /**< Array of float coefficients for adjusting the intensity of each color channel (R, G, B, C, W).
174174
These coefficients help in achieving the desired color balance for the light output. */
175175

176-
float curve_coefficient; /**< Coefficient for gamma correction. This value is used to modify the luminance levels
177-
to suit the non-linear characteristics of human vision, thus improving the overall
178-
visual appearance of the light. */
176+
float color_curve_coefficient; /**< Coefficient for gamma correction (RGB mode). The default value is 1.0, which is linear.*/
177+
float white_curve_coefficient; /**< Coefficient for gamma correction (CCT mode). The default value is 1.0, which is linear.*/
179178
} lightbulb_gamma_config_t;
180179

181180
/**

components/led/lightbulb_driver/src/hal_driver.c

Lines changed: 27 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD
2+
* SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD
33
*
44
* SPDX-License-Identifier: Apache-2.0
55
*/
@@ -100,10 +100,7 @@ typedef struct {
100100
hal_obj_t *interface;
101101
int s_err_count;
102102
bool use_hw_fade;
103-
bool linear_use_curve_table;
104-
// index 0: curve table
105-
// index 1: linear table
106-
uint16_t *table_group[2];
103+
uint16_t *table_group;
107104
// R G B C W
108105
float balance_coefficient[5];
109106
SemaphoreHandle_t fade_mutex;
@@ -252,7 +249,7 @@ static float final_processing(uint8_t channel, uint16_t src_value)
252249
return s_hal_obj->balance_coefficient[channel] * src_value;
253250
}
254251

255-
static esp_err_t gamma_table_create(uint16_t *output_gamma_table, uint16_t table_size, float gamma_curve_coefficient, int32_t grayscale_level)
252+
esp_err_t hal_gamma_table_create(uint16_t *output_gamma_table, uint16_t table_size, float gamma_curve_coefficient, int32_t grayscale_level)
256253
{
257254
float value_tmp = 0;
258255

@@ -290,13 +287,9 @@ static void force_stop_all_ch(void)
290287

291288
static void cleanup(void)
292289
{
293-
if (s_hal_obj->table_group[0]) {
294-
free(s_hal_obj->table_group[0]);
295-
s_hal_obj->table_group[0] = NULL;
296-
}
297-
if (s_hal_obj->table_group[1]) {
298-
free(s_hal_obj->table_group[1]);
299-
s_hal_obj->table_group[1] = NULL;
290+
if (s_hal_obj->table_group) {
291+
free(s_hal_obj->table_group);
292+
s_hal_obj->table_group = NULL;
300293
}
301294
if (s_hal_obj->fade_mutex) {
302295
vSemaphoreDelete(s_hal_obj->fade_mutex);
@@ -493,38 +486,34 @@ esp_err_t hal_output_init(hal_config_t *config, lightbulb_gamma_config_t *gamma,
493486
err = s_hal_obj->interface->init(config->driver_data, driver_default_hook_func);
494487
LIGHTBULB_CHECK(err == ESP_OK, "driver init fail", goto EXIT);
495488

496-
s_hal_obj->table_group[0] = calloc(s_hal_obj->interface->driver_grayscale_level, sizeof(uint16_t));
497-
LIGHTBULB_CHECK(s_hal_obj->table_group[0], "curve table buffer alloc fail", goto EXIT);
498-
499-
float curve_coe = gamma ? gamma->curve_coefficient : DEFAULT_CURVE_COE;
500-
float linear_coe = 1.0;
501-
502-
gamma_table_create(s_hal_obj->table_group[0], s_hal_obj->interface->driver_grayscale_level, curve_coe, s_hal_obj->interface->driver_grayscale_level);
503-
s_hal_obj->table_group[0][s_hal_obj->interface->driver_grayscale_level - 1] = s_hal_obj->interface->hardware_allow_max_input_value;
504-
505-
if (linear_coe == curve_coe) {
506-
s_hal_obj->linear_use_curve_table = true;
507-
} else {
508-
s_hal_obj->table_group[1] = calloc(s_hal_obj->interface->driver_grayscale_level, sizeof(uint16_t));
509-
LIGHTBULB_CHECK(s_hal_obj->table_group[1], "linear table buffer alloc fail", goto EXIT);
510-
gamma_table_create(s_hal_obj->table_group[1], s_hal_obj->interface->driver_grayscale_level, linear_coe, s_hal_obj->interface->driver_grayscale_level);
511-
s_hal_obj->table_group[1][s_hal_obj->interface->driver_grayscale_level - 1] = s_hal_obj->interface->hardware_allow_max_input_value;
512-
}
513-
514-
for (int i = 0; i < 5; i++) {
515-
float balance = gamma ? gamma->balance_coefficient[i] : 1.0;
516-
LIGHTBULB_CHECK(balance >= 0.0 && balance <= 1.0, "balance data error", goto EXIT);
517-
s_hal_obj->balance_coefficient[i] = balance;
518-
}
519-
520489
/**
521490
* @brief Differential configuration for different chips
522491
*
523492
*/
493+
int table_size = s_hal_obj->interface->driver_grayscale_level;
524494
if (s_hal_obj->interface->type == DRIVER_ESP_PWM) {
525495
#if CONFIG_PWM_ENABLE_HW_FADE
526496
s_hal_obj->use_hw_fade = true;
527497
#endif
498+
// PWM
499+
// 10bit: 0~1024, size: 1024 + 1
500+
table_size += 1;
501+
502+
// I2C Chip
503+
// 10bit: 0~1023, size: 1024
504+
}
505+
506+
s_hal_obj->table_group = calloc(table_size, sizeof(uint16_t));
507+
LIGHTBULB_CHECK(s_hal_obj->table_group, "curve table buffer alloc fail", goto EXIT);
508+
509+
//Currently only used as a mapping table, it will be used for fade to achieve curve sliding changes in the future
510+
float curve_coe = DEFAULT_CURVE_COE;
511+
hal_gamma_table_create(s_hal_obj->table_group, table_size, curve_coe, s_hal_obj->interface->hardware_allow_max_input_value);
512+
513+
for (int i = 0; i < 5; i++) {
514+
float balance = gamma ? gamma->balance_coefficient[i] : 1.0;
515+
LIGHTBULB_CHECK(balance >= 0.0 && balance <= 1.0, "balance data error", goto EXIT);
516+
s_hal_obj->balance_coefficient[i] = balance;
528517
}
529518

530519
#ifdef FADE_TICKS_FROM_GPTIMER
@@ -1052,21 +1041,7 @@ esp_err_t hal_get_curve_table_value(uint16_t input, uint16_t *output)
10521041
LIGHTBULB_CHECK(s_hal_obj, "init() must be called first", return ESP_ERR_INVALID_STATE);
10531042
LIGHTBULB_CHECK(output, "out_data is null", return ESP_ERR_INVALID_STATE);
10541043

1055-
*output = s_hal_obj->table_group[0][input];
1056-
1057-
return ESP_OK;
1058-
}
1059-
1060-
esp_err_t hal_get_linear_table_value(uint16_t input, uint16_t *output)
1061-
{
1062-
LIGHTBULB_CHECK(s_hal_obj, "init() must be called first", return ESP_ERR_INVALID_STATE);
1063-
LIGHTBULB_CHECK(output, "out_data is null", return ESP_ERR_INVALID_STATE);
1064-
1065-
if (s_hal_obj->linear_use_curve_table) {
1066-
*output = s_hal_obj->table_group[0][input];
1067-
} else {
1068-
*output = s_hal_obj->table_group[1][input];
1069-
}
1044+
*output = s_hal_obj->table_group[input];
10701045

10711046
return ESP_OK;
10721047
}

components/led/lightbulb_driver/src/lightbulb.c

Lines changed: 55 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD
2+
* SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD
33
*
44
* SPDX-License-Identifier: Apache-2.0
55
*/
@@ -62,6 +62,12 @@ typedef struct {
6262
TimerHandle_t effect_timer; // Timer handle related to the flashing, fading
6363
SemaphoreHandle_t mutex; // For multi-thread protection
6464

65+
// Structure containing pointers to gamma correction tables for color and white
66+
struct {
67+
uint16_t *color_gamma_table; // Pointer to the color gamma correction table (for RGB)
68+
uint16_t *white_gamma_table; // Pointer to the white gamma correction table (for CCT)
69+
} gamma_correction;
70+
6571
// Structure containing flags related to effects
6672
struct {
6773
bool allow_interrupt : 1; // Flag indicating if the effect can be interrupted
@@ -304,23 +310,22 @@ static void cct_and_brightness_convert_and_power_limit(lightbulb_led_beads_comb_
304310
hal_get_driver_feature(QUERY_MAX_INPUT_VALUE, &max_value);
305311

306312
if (led_beads == LED_BEADS_1CH_C || led_beads == LED_BEADS_4CH_RGBC || led_beads == LED_BEADS_4CH_RGBCC) {
307-
uint16_t value = brightness / 100.0 * max_value;
308-
hal_get_linear_table_value((uint8_t)value, &white_value[3]);
313+
uint16_t value = brightness * max_value / 100;
314+
hal_get_curve_table_value(value, &white_value[3]);
309315
if (led_beads == LED_BEADS_4CH_RGBCC) {
310-
hal_get_linear_table_value((uint8_t)value, &white_value[4]);
316+
hal_get_curve_table_value(value, &white_value[4]);
311317
}
312318
} else if (led_beads == LED_BEADS_1CH_W || led_beads == LED_BEADS_4CH_RGBW || led_beads == LED_BEADS_4CH_RGBWW) {
313-
uint16_t value = brightness / 100.0 * max_value;
314-
hal_get_linear_table_value(value, &white_value[4]);
315-
319+
uint16_t value = brightness * max_value / 100;
320+
hal_get_curve_table_value(value, &white_value[4]);
316321
if (led_beads == LED_BEADS_4CH_RGBWW) {
317-
hal_get_linear_table_value((uint8_t)value, &white_value[3]);
322+
hal_get_curve_table_value(value, &white_value[3]);
318323
}
319324
} else if ((led_beads == LED_BEADS_2CH_CW || led_beads == LED_BEADS_5CH_RGBCW) && IS_WHITE_OUTPUT_HARDWARE_MIXED()) {
320-
uint16_t value1 = cct / 100.0 * max_value;
321-
uint16_t value2 = brightness / 100.0 * max_value;
322-
hal_get_linear_table_value((uint8_t)value1, &white_value[3]);
323-
hal_get_linear_table_value((uint8_t)value2, &white_value[4]);
325+
uint16_t value1 = cct * max_value / 100;
326+
uint16_t value2 = brightness * max_value / 100;
327+
hal_get_curve_table_value(value1, &white_value[3]);
328+
hal_get_curve_table_value(value2, &white_value[4]);
324329
} else if (led_beads == LED_BEADS_2CH_CW || ((led_beads == LED_BEADS_5CH_RGBCW) && (s_lb_obj->cap.enable_precise_cct_control == false))) {
325330
float max_power;
326331
float _c = cct / 100.0;
@@ -330,8 +335,8 @@ static void cct_and_brightness_convert_and_power_limit(lightbulb_led_beads_comb_
330335
max_power = MIN(max_value * multiple, max_value / baseline);
331336
_c = max_power * _c * (brightness / 100.0);
332337
_w = max_power * _w * (brightness / 100.0);
333-
hal_get_linear_table_value((uint16_t)_c, &white_value[3]);
334-
hal_get_linear_table_value((uint16_t)_w, &white_value[4]);
338+
hal_get_curve_table_value(_c, &white_value[3]);
339+
hal_get_curve_table_value(_w, &white_value[4]);
335340
} else {
336341
float max_power;
337342
lightbulb_cct_mapping_data_t data = search_mapping_cct_data(cct);
@@ -344,7 +349,8 @@ static void cct_and_brightness_convert_and_power_limit(lightbulb_led_beads_comb_
344349
max_power = MIN(max_value * multiple, max_value / baseline);
345350
ESP_LOGD(TAG, "%f, %d, %f", max_power, max_value, baseline);
346351
for (int i = 0; i < 5; i++) {
347-
white_value[i] = round(max_power * data.rgbcw[i] * (brightness / 100.0));
352+
float value = round(max_power * data.rgbcw[i] * (brightness / 100.0));
353+
hal_get_curve_table_value((uint16_t)value, &white_value[i]);
348354
}
349355
}
350356
}
@@ -371,7 +377,9 @@ static uint8_t process_color_value_limit(uint8_t value)
371377
float percentage = value / 100.0;
372378

373379
uint8_t result = (s_lb_obj->power.color_max_value - s_lb_obj->power.color_min_value) * percentage + s_lb_obj->power.color_min_value;
380+
result = s_lb_obj->gamma_correction.color_gamma_table[result];
374381
ESP_LOGD(TAG, "color_value convert input:%d output:%d", value, result);
382+
375383
return result;
376384
}
377385

@@ -397,7 +405,9 @@ static uint8_t process_white_brightness_limit(uint8_t brightness)
397405
float percentage = brightness / 100.0;
398406

399407
uint8_t result = (s_lb_obj->power.white_max_brightness - s_lb_obj->power.white_min_brightness) * percentage + s_lb_obj->power.white_min_brightness;
408+
result = s_lb_obj->gamma_correction.white_gamma_table[result];
400409
ESP_LOGD(TAG, "white_brightness_output input:%d output:%d", brightness, result);
410+
401411
return result;
402412
}
403413

@@ -428,7 +438,8 @@ static void process_color_power_limit(float multiple, float rgbcw[5], uint16_t v
428438
max_power = MIN(max_power, max_value / baseline);
429439
ESP_LOGD(TAG, "%f, %d, %f", max_power, max_value, baseline);
430440
for (int i = 0; i < 5; i++) {
431-
out[i] = round(max_power * rgbcw[i] * (value / 100.0));
441+
float value = round(max_power * rgbcw[i]);
442+
hal_get_curve_table_value((uint16_t)value, &out[i]);
432443
}
433444
}
434445

@@ -911,6 +922,20 @@ esp_err_t lightbulb_init(lightbulb_config_t *config)
911922
s_lb_obj->cap.fade_time_ms = MAX(MIN_FADE_MS, s_lb_obj->cap.fade_time_ms);
912923
}
913924

925+
//Gamma table create
926+
float color_coe = 1.0;
927+
float white_coe = 1.0;
928+
if (config->gamma_conf) {
929+
color_coe = config->gamma_conf->color_curve_coefficient;
930+
white_coe = config->gamma_conf->white_curve_coefficient;
931+
}
932+
s_lb_obj->gamma_correction.color_gamma_table = calloc(101, sizeof(uint16_t));
933+
LIGHTBULB_CHECK(s_lb_obj->gamma_correction.color_gamma_table, "curve table buffer alloc fail", goto EXIT);
934+
s_lb_obj->gamma_correction.white_gamma_table = calloc(101, sizeof(uint16_t));
935+
LIGHTBULB_CHECK(s_lb_obj->gamma_correction.white_gamma_table, "curve table buffer alloc fail", goto EXIT);
936+
hal_gamma_table_create(s_lb_obj->gamma_correction.color_gamma_table, 101, color_coe, 100);
937+
hal_gamma_table_create(s_lb_obj->gamma_correction.white_gamma_table, 101, white_coe, 100);
938+
914939
// Low power check
915940
if (config->capability.enable_lowpower) {
916941
/* Make sure the fade is done and the flash operation is done, then enable light sleep */
@@ -991,6 +1016,15 @@ esp_err_t lightbulb_deinit(void)
9911016
s_lb_obj->color_manager.mix_table = NULL;
9921017
}
9931018

1019+
if (s_lb_obj->gamma_correction.color_gamma_table) {
1020+
free(s_lb_obj->gamma_correction.color_gamma_table);
1021+
s_lb_obj->gamma_correction.color_gamma_table = NULL;
1022+
}
1023+
if (s_lb_obj->gamma_correction.white_gamma_table) {
1024+
free(s_lb_obj->gamma_correction.white_gamma_table);
1025+
s_lb_obj->gamma_correction.white_gamma_table = NULL;
1026+
}
1027+
9941028
free(s_lb_obj);
9951029
s_lb_obj = NULL;
9961030

@@ -1196,11 +1230,11 @@ static esp_err_t lightbulb_hsv2rgb_adjusted(uint16_t hue, uint8_t saturation, ui
11961230
}
11971231
}
11981232

1199-
*red = interpolated_rgbcw[0];
1200-
*green = interpolated_rgbcw[1];
1201-
*blue = interpolated_rgbcw[2];
1202-
*cold = interpolated_rgbcw[3];
1203-
*warm = interpolated_rgbcw[4];
1233+
*red = interpolated_rgbcw[0] * value / 100.0;
1234+
*green = interpolated_rgbcw[1] * value / 100.0;
1235+
*blue = interpolated_rgbcw[2] * value / 100.0;
1236+
*cold = interpolated_rgbcw[3] * value / 100.0;
1237+
*warm = interpolated_rgbcw[4] * value / 100.0;
12041238

12051239
return ESP_OK;
12061240
}

components/led/lightbulb_driver/src/priv_include/hal_driver.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,13 +56,13 @@ esp_err_t hal_output_deinit(void);
5656
esp_err_t hal_regist_channel(int channel, gpio_num_t gpio_num);
5757
esp_err_t hal_get_driver_feature(hal_feature_query_list_t type, void *out_data);
5858
esp_err_t hal_get_curve_table_value(uint16_t input, uint16_t *output);
59-
esp_err_t hal_get_linear_table_value(uint16_t input, uint16_t *output);
6059
esp_err_t hal_set_channel(int channel, uint16_t value, uint16_t fade_ms);
6160
esp_err_t hal_set_channel_group(uint16_t value[], uint8_t channel_mask, uint16_t fade_ms);
6261
esp_err_t hal_start_channel_action(int channel, uint16_t value_min, uint16_t value_max, uint16_t period_ms, bool fade_flag);
6362
esp_err_t hal_start_channel_group_action(uint16_t value_min[], uint16_t value_max[], uint8_t channel_mask, uint16_t period_ms, bool fade_flag);
6463
esp_err_t hal_stop_channel_action(uint8_t channel_mask);
6564
esp_err_t hal_sleep_control(bool enable_sleep);
65+
esp_err_t hal_gamma_table_create(uint16_t *output_gamma_table, uint16_t table_size, float gamma_curve_coefficient, int32_t grayscale_level);
6666

6767
/**
6868
* @brief To resolve some compilation warning issues

0 commit comments

Comments
 (0)