From e8e97c0e6bff4e9dd13a335fde0eb1c44a52f4ae Mon Sep 17 00:00:00 2001 From: Drath Date: Mon, 16 Mar 2026 01:08:28 +0100 Subject: [PATCH] pre-calculated brightness table --- main/light_driver.c | 44 ++++++++++++++++++++++++++++++-------------- 1 file changed, 30 insertions(+), 14 deletions(-) diff --git a/main/light_driver.c b/main/light_driver.c index febc929..4bdf721 100644 --- a/main/light_driver.c +++ b/main/light_driver.c @@ -6,19 +6,25 @@ #include "esp_log.h" #include "esp_err.h" #include +#include static const char* TAG = "light_driver"; -static const uint8_t light_gpio = 15; -static const uint16_t light_pwm_freq = 20000; -static const ledc_channel_t light_ledc_channel = LEDC_CHANNEL_0; -static const ledc_mode_t light_ledc_mode = LEDC_LOW_SPEED_MODE; +/* tweakable stuff */ +static const uint8_t light_gpio = 2; +static const uint16_t light_pwm_freq = 65000; static const ledc_timer_bit_t light_pwm_resolution = LEDC_TIMER_10_BIT; -static const uint32_t light_max_brightness = (1 << light_pwm_resolution) - 1; -static const uint32_t light_max_level = 254; // zigbee light level, goes from 0 to 254 +static const double light_lowest_duty_pct = 0.05; // lowest duty percentage where the LEDs still light up nice +/* no need to tweak this stuff */ +static const ledc_channel_t light_ledc_channel = LEDC_CHANNEL_0; +static const ledc_mode_t light_ledc_speed_mode = LEDC_LOW_SPEED_MODE; +static const uint32_t light_brightness_steps = (1 << light_pwm_resolution) - 1; + +/* global vars */ static bool light_init_done = false; static uint8_t light_current_level = 0; +static uint16_t gamma_lut[ZIGBEE_LIGHT_LEVELS + 1]; esp_err_t light_driver_set_level(const uint8_t level, const uint16_t transition_ms) { if (!light_init_done) { @@ -27,12 +33,11 @@ esp_err_t light_driver_set_level(const uint8_t level, const uint16_t transition_ } light_current_level = level; - double brightness = (double)light_current_level / (double)light_max_level; - if (brightness > 1) brightness = 1; - if (brightness < 0) brightness = 0; - const uint32_t duty = (uint32_t)(light_max_brightness * brightness * brightness); // brightness^2 for fast gamma correction - ESP_ERROR_CHECK(ledc_set_fade_with_time(light_ledc_mode, light_ledc_channel, duty, transition_ms)); - ESP_ERROR_CHECK(ledc_fade_start(light_ledc_mode, light_ledc_channel, LEDC_FADE_NO_WAIT)); + const uint16_t duty = gamma_lut[light_current_level]; + ESP_ERROR_CHECK(ledc_fade_stop(light_ledc_speed_mode, light_ledc_channel)); + ESP_ERROR_CHECK(ledc_set_fade_with_time(light_ledc_speed_mode, light_ledc_channel, duty, transition_ms)); + ESP_ERROR_CHECK(ledc_fade_start(light_ledc_speed_mode, light_ledc_channel, LEDC_FADE_NO_WAIT)); + ESP_LOGI(TAG, "led set to %d, max is %d", duty, light_brightness_steps); return ESP_OK; } @@ -42,7 +47,7 @@ esp_err_t light_driver_set_power(const bool power, const uint16_t transition_ms) esp_err_t light_driver_init(const bool default_state) { const ledc_timer_config_t ledc_timer = { - .speed_mode = light_ledc_mode, + .speed_mode = light_ledc_speed_mode, .duty_resolution = light_pwm_resolution, .timer_num = LEDC_TIMER_2, .freq_hz = light_pwm_freq, @@ -57,10 +62,21 @@ esp_err_t light_driver_init(const bool default_state) { .duty = 0, // Set duty to 0% .hpoint = 0 }; + + for (uint8_t i = 0; i <= ZIGBEE_LIGHT_LEVELS; i++) { + const double brightness_pct = (double)i / (double)ZIGBEE_LIGHT_LEVELS; + const double gamma_corrected = pow(brightness_pct, 2.2); + const double scaled = (double)light_brightness_steps * gamma_corrected * (1 - light_lowest_duty_pct); + gamma_lut[i] = (uint16_t)scaled + (uint16_t)((double)light_brightness_steps * light_lowest_duty_pct) + 1; + } + gamma_lut[0] = 0; // 0 is always completely off + if (gamma_lut[ZIGBEE_LIGHT_LEVELS] > light_brightness_steps) gamma_lut[ZIGBEE_LIGHT_LEVELS] = light_brightness_steps; + ESP_LOGI(TAG, "pre-computed brightness lookup table"); + ESP_ERROR_CHECK(ledc_timer_config(&ledc_timer)); ESP_ERROR_CHECK(ledc_channel_config(&ledc_channel)); ESP_ERROR_CHECK(ledc_fade_func_install(0)); - ESP_LOGI(TAG, "light driver inited, f=%d Hz", light_pwm_freq); + ESP_LOGI(TAG, "ledc driver initialized, f=%d Hz, %d step resolution", light_pwm_freq, light_brightness_steps); light_init_done = true; light_driver_set_power(default_state, 100); return ESP_OK;