From 7263ad9ebcb0da56b265059817c4d8aa83ca33ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=90=B4=E7=90=AA?= Date: Mon, 27 Jul 2026 21:23:11 +0800 Subject: [PATCH] =?UTF-8?q?=E6=8C=8965=E5=BE=AE=E7=A7=92=E7=A8=B3=E5=AE=9A?= =?UTF-8?q?=E9=98=88=E5=80=BC=E6=98=A0=E5=B0=84=E6=B7=B7=E5=90=88=E5=85=89?= =?UTF-8?q?=E4=BA=AE=E5=BA=A6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ble_peripheral/app/src/light_transition.c | 74 ++++++++++++++++++- 1 file changed, 72 insertions(+), 2 deletions(-) diff --git a/project/example/ble/ble_peripheral/app/src/light_transition.c b/project/example/ble/ble_peripheral/app/src/light_transition.c index 3088be2..128be69 100644 --- a/project/example/ble/ble_peripheral/app/src/light_transition.c +++ b/project/example/ble/ble_peripheral/app/src/light_transition.c @@ -8,6 +8,7 @@ volatile uint8_t Light_Transition_FadeActive; #define OUTPUT_SMOOTH_SHIFT 4U #define LIGHT_OUTPUT_SCALE 1000U #define BREATH_MIN_OUTPUT (LIGHT_OUTPUT_SCALE / 100U) +#define DUAL_MIN_STABLE_CHANNEL_OUTPUT 145U #define POWER_FADE_Q12_MAX 4096U #define POWER_FADE_ON_TICKS 140U #define POWER_FADE_OFF_TICKS 160U @@ -34,6 +35,25 @@ static const uint16_t brightness_gamma_q12[100] = { 3457U, 3525U, 3595U, 3664U, 3735U, 3806U, 3878U, 3950U, 4023U, 4096U }; +/* + * Mixed-light Gamma table. Its first level equals the original 50% APP level + * (1184/4096), where a 50:50 mix measures about 65 us per direction at 2 kHz. + * The remaining range is expanded to 100%, so all brightness levels remain + * distinct instead of clamping the lower levels to one fixed output. + */ +static const uint16_t mixed_brightness_gamma_q12[100] = { + 1184U, 1185U, 1187U, 1189U, 1193U, 1198U, 1203U, 1208U, 1216U, 1223U, + 1231U, 1240U, 1249U, 1259U, 1270U, 1282U, 1293U, 1306U, 1319U, 1333U, + 1348U, 1363U, 1378U, 1394U, 1411U, 1428U, 1446U, 1465U, 1484U, 1504U, + 1524U, 1544U, 1565U, 1587U, 1609U, 1632U, 1655U, 1680U, 1703U, 1728U, + 1753U, 1780U, 1806U, 1833U, 1860U, 1888U, 1916U, 1946U, 1975U, 2005U, + 2036U, 2067U, 2097U, 2130U, 2162U, 2195U, 2228U, 2262U, 2296U, 2331U, + 2366U, 2402U, 2438U, 2474U, 2512U, 2549U, 2587U, 2626U, 2665U, 2704U, + 2744U, 2785U, 2826U, 2867U, 2908U, 2951U, 2993U, 3036U, 3080U, 3124U, + 3168U, 3213U, 3259U, 3304U, 3351U, 3397U, 3444U, 3492U, 3539U, 3588U, + 3637U, 3686U, 3736U, 3786U, 3837U, 3888U, 3939U, 3991U, 4044U, 4096U +}; + /* * Gamma 1.8 envelope for power-on/off. The transition progress is advanced * independently of the requested brightness, so every turn-on takes about @@ -68,6 +88,18 @@ static uint16_t brightness_scale_for_level(uint8_t level) return brightness_gamma_q12[level - 1U]; } +static uint16_t output_brightness_scale_for_level(uint8_t level) +{ + if(level == 0U) return 0U; + if(level < BRIGHTNESS_MIN_PERCENT) level = BRIGHTNESS_MIN_PERCENT; + if(level > BRIGHTNESS_MAX_PERCENT) level = BRIGHTNESS_MAX_PERCENT; + + if(W_PWM != 0U && C_PWM != 0U) + return mixed_brightness_gamma_q12[level - 1U]; + + return brightness_scale_for_level(level); +} + static uint16_t approach_brightness_scale(uint16_t current, uint16_t target) { uint16_t delta; @@ -178,7 +210,7 @@ static void update_power_fade(uint8_t powered_on) void Light_Transition_SyncBrightness(uint8_t level) { - current_brightness_q12 = brightness_scale_for_level(level); + current_brightness_q12 = output_brightness_scale_for_level(level); power_fade_progress_q12 = level == 0U ? 0U : POWER_FADE_Q12_MAX; power_fade_remainder = 0U; @@ -194,13 +226,17 @@ void Light_Transition_Task(void) uint16_t target_brightness_scale; uint16_t brightness_scale; uint16_t fade_scale; + uint16_t mix_total; + uint16_t weak_mix; + uint16_t required_total; + uint16_t floor_w; uint8_t power_transitioning; /* * Keep APP brightness tracking while off. Power fading is a separate * envelope, so on/off duration does not change with the saved brightness. */ - target_brightness_scale = brightness_scale_for_level(Brightness); + target_brightness_scale = output_brightness_scale_for_level(Brightness); current_brightness_q12 = approach_brightness_scale(current_brightness_q12, target_brightness_scale); @@ -218,6 +254,40 @@ void Light_Transition_Task(void) (uint16_t)(((uint32_t)C_PWM * brightness_scale * (LIGHT_OUTPUT_SCALE / 100U) + 2048U) >> 12); + /* + * Keep the weaker mixed-light direction at the measured stable threshold. + * Raise the combined output only when the requested W:C ratio needs it. + * A ratio that cannot provide 145/1000 to its weak side even at full + * brightness is treated as single color. + */ + if(W_PWM != 0U && C_PWM != 0U) + { + mix_total = (uint16_t)(W_PWM + C_PWM); + weak_mix = (W_PWM < C_PWM) ? W_PWM : C_PWM; + required_total = (uint16_t)( + ((uint32_t)DUAL_MIN_STABLE_CHANNEL_OUTPUT * mix_total + + weak_mix - 1U) / weak_mix); + + if(required_total > LIGHT_OUTPUT_SCALE) + { + if(W_PWM < C_PWM) + target_w = 0U; + else + target_c = 0U; + } + else if((uint16_t)(target_w + target_c) < required_total) + { + floor_w = (uint16_t)( + ((uint32_t)required_total * W_PWM + + (mix_total / 2U)) / mix_total); + if(floor_w == 0U) floor_w = 1U; + if(floor_w >= required_total) + floor_w = required_total - 1U; + target_w = floor_w; + target_c = required_total - floor_w; + } + } + target_w = (uint16_t)(((uint32_t)target_w * fade_scale + 2048U) >> 12); target_c = (uint16_t)(((uint32_t)target_c * fade_scale + 2048U) >> 12);