diff --git a/project/example/ble/ble_peripheral/app/src/Mode.c b/project/example/ble/ble_peripheral/app/src/Mode.c index 0c6c0a9..d661c51 100644 --- a/project/example/ble/ble_peripheral/app/src/Mode.c +++ b/project/example/ble/ble_peripheral/app/src/Mode.c @@ -19,8 +19,6 @@ uint8_t Mode=mode0; //mode0 1 2 3 4 uint8_t Speed=5; //速度 uint8_t direction = 1; // 呼吸灯的亮度变化方向,1表示增加,0表示减小 -#define THREE_COLOR_SINGLE_JOIN_LEVEL 41U - uint8_t choose_mode_falsg=0; //模式值 uint8_t choose_mode_bh=0; //模式变化 static uint8_t mode_entry_initialized; @@ -232,7 +230,7 @@ void Mode1(){ // breathespeed_flag=0; W_PWM -= 1; C_PWM = 0; - if (W_PWM <= THREE_COLOR_SINGLE_JOIN_LEVEL) { + if (W_PWM <= 1) { direction = 2; driveMode=0; W_PWM = 1; @@ -257,7 +255,7 @@ void Mode1(){ // driveMode=2; direction = 4; W_PWM = 0; - C_PWM = THREE_COLOR_SINGLE_JOIN_LEVEL; + C_PWM = 1; } break; case 4: @@ -274,10 +272,10 @@ void Mode1(){ // breathespeed_flag=0; W_PWM = 0; C_PWM -= 1; - if (C_PWM <= THREE_COLOR_SINGLE_JOIN_LEVEL){ + if (C_PWM <=1){ direction = 0; driveMode=1; - W_PWM = THREE_COLOR_SINGLE_JOIN_LEVEL; + W_PWM = 1; C_PWM = 0; } diff --git a/project/example/ble/ble_peripheral/app/src/bridge_pwm.c b/project/example/ble/ble_peripheral/app/src/bridge_pwm.c index a1d6295..0f1eb9b 100644 --- a/project/example/ble/ble_peripheral/app/src/bridge_pwm.c +++ b/project/example/ble/ble_peripheral/app/src/bridge_pwm.c @@ -17,7 +17,9 @@ * OFF -> W pulse -> OFF -> C pulse -> OFF to frame end. * The available OFF time is distributed around both direction changes and * each W/C transition retains at least 25 us protection. - * Both non-zero colors therefore produce exactly one pulse per frame (2 kHz). + * Normal dual-color output produces one pulse per color per frame (2 kHz). + * Low-level three-color breathing keeps 50 us pulses but density-modulates + * them across frames so the average output can fade below that pulse width. */ #define BRIDGE_PWM_SCALE 1000U #define BRIDGE_PWM_PERIOD 6U @@ -26,8 +28,11 @@ #define BRIDGE_DEADTIME_US 25U #define BRIDGE_DUAL_ACTIVE_US 450U #define BRIDGE_MIN_DUAL_PULSE_US 1U +#define BRIDGE_TRICOLOR_PDM_PULSE_US 50U #define BRIDGE_TIMER_TICKS_PER_US 16U #define BRIDGE_PDM_THRESHOLD (BRIDGE_MIX_SCALE * 4096UL) +#define BRIDGE_TRICOLOR_PDM_THRESHOLD \ + (BRIDGE_TRICOLOR_PDM_PULSE_US * BRIDGE_PDM_THRESHOLD) #define BRIDGE_GPIO_PORT 0U #define BRIDGE_GPIO_MASK ((1UL << IO_PWM_W) | (1UL << IO_PWM_C)) @@ -65,9 +70,11 @@ static volatile uint16_t next_wc_off_us; static volatile uint16_t next_cw_off_us; static volatile uint32_t next_pdm_w_step; static volatile uint32_t next_pdm_c_step; +static volatile uint32_t next_pdm_threshold; static volatile uint8_t next_pdm_enabled; static volatile uint32_t pdm_w_accumulator; static volatile uint32_t pdm_c_accumulator; +static volatile uint32_t frame_pdm_threshold; static volatile uint8_t frame_pdm_enabled; static volatile uint8_t frame_w_emit; static volatile uint8_t frame_c_emit; @@ -226,9 +233,11 @@ void Bridge_Off(void) next_cw_off_us = 0U; next_pdm_w_step = 0U; next_pdm_c_step = 0U; + next_pdm_threshold = 0U; next_pdm_enabled = 0U; pdm_w_accumulator = 0U; pdm_c_accumulator = 0U; + frame_pdm_threshold = 0U; frame_pdm_enabled = 0U; frame_w_emit = 0U; frame_c_emit = 0U; @@ -242,6 +251,7 @@ __RAM_CODE void Bridge_Deadtime_Expired(void) { uint32_t w_step; uint32_t c_step; + uint32_t pdm_threshold; uint8_t pdm_enabled; if (!bridge_ready || @@ -262,25 +272,29 @@ __RAM_CODE void Bridge_Deadtime_Expired(void) pdm_enabled = next_pdm_enabled; w_step = next_pdm_w_step; c_step = next_pdm_c_step; + pdm_threshold = next_pdm_threshold; - if (pdm_enabled && !frame_pdm_enabled) { - pdm_w_accumulator = BRIDGE_PDM_THRESHOLD - w_step; - pdm_c_accumulator = BRIDGE_PDM_THRESHOLD - c_step; + if (pdm_enabled && + (!frame_pdm_enabled || + frame_pdm_threshold != pdm_threshold)) { + pdm_w_accumulator = pdm_threshold - w_step; + pdm_c_accumulator = pdm_threshold - c_step; } frame_pdm_enabled = pdm_enabled; + frame_pdm_threshold = pdm_enabled ? pdm_threshold : 0U; if (frame_pdm_enabled) { pdm_w_accumulator += w_step; - if (pdm_w_accumulator >= BRIDGE_PDM_THRESHOLD) { - pdm_w_accumulator -= BRIDGE_PDM_THRESHOLD; + if (pdm_w_accumulator >= frame_pdm_threshold) { + pdm_w_accumulator -= frame_pdm_threshold; frame_w_emit = 1U; } else { frame_w_emit = 0U; } pdm_c_accumulator += c_step; - if (pdm_c_accumulator >= BRIDGE_PDM_THRESHOLD) { - pdm_c_accumulator -= BRIDGE_PDM_THRESHOLD; + if (pdm_c_accumulator >= frame_pdm_threshold) { + pdm_c_accumulator -= frame_pdm_threshold; frame_c_emit = 1U; } else { frame_c_emit = 0U; @@ -367,6 +381,36 @@ __RAM_CODE void Bridge_Service_1ms(void) (uint16_t)(total_off_us - next_wc_off_us); next_pdm_w_step = pdm_w_step; next_pdm_c_step = pdm_c_step; + next_pdm_threshold = BRIDGE_PDM_THRESHOLD; + next_pdm_enabled = 1U; + cached_w_mix = (uint16_t)w_mix; + cached_c_mix = (uint16_t)c_mix; + goto dual_output_ready; + } + + /* + * The low part of the three-color breathing effect cannot use short + * continuous W/C pulses reliably. Emit verified 50 us pulses and vary + * their density across the fixed 2 kHz frames instead. At the configured + * minimum output this gives about 450 emitted pulses per second. + */ + if (deviceStatus != POWEROFF && + Mode == mode1 && choose_mode_falsg == 5U && + w_mix != 0U && c_mix != 0U && + pdm_w_step != 0U && pdm_c_step != 0U && + pdm_w_step < BRIDGE_TRICOLOR_PDM_THRESHOLD && + pdm_c_step < BRIDGE_TRICOLOR_PDM_THRESHOLD) { + next_w_us = BRIDGE_TRICOLOR_PDM_PULSE_US; + next_c_us = BRIDGE_TRICOLOR_PDM_PULSE_US; + total_off_us = + BRIDGE_FRAME_US - + (2U * BRIDGE_TRICOLOR_PDM_PULSE_US); + next_wc_off_us = (uint16_t)(total_off_us / 2U); + next_cw_off_us = + (uint16_t)(total_off_us - next_wc_off_us); + next_pdm_w_step = pdm_w_step; + next_pdm_c_step = pdm_c_step; + next_pdm_threshold = BRIDGE_TRICOLOR_PDM_THRESHOLD; next_pdm_enabled = 1U; cached_w_mix = (uint16_t)w_mix; cached_c_mix = (uint16_t)c_mix; @@ -380,6 +424,7 @@ __RAM_CODE void Bridge_Service_1ms(void) next_pdm_enabled = 0U; next_pdm_w_step = 0U; next_pdm_c_step = 0U; + next_pdm_threshold = 0U; if (total == 0U) { Bridge_Off(); 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 a793aad..72aedb2 100644 --- a/project/example/ble/ble_peripheral/app/src/light_transition.c +++ b/project/example/ble/ble_peripheral/app/src/light_transition.c @@ -13,7 +13,8 @@ volatile uint32_t Light_Transition_C_Output_Q12; #define LIGHT_OUTPUT_SCALE 1000U #define BREATH_MIN_OUTPUT (LIGHT_OUTPUT_SCALE / 100U) #define DUAL_MIN_STABLE_CHANNEL_OUTPUT 102U -#define THREE_COLOR_JOIN_OUTPUT (2U * DUAL_MIN_STABLE_CHANNEL_OUTPUT) +#define THREE_COLOR_MIN_CHANNEL_OUTPUT 25U +#define THREE_COLOR_MIN_SINGLE_OUTPUT 45U #define POWER_FADE_Q12_MAX 4096U #define POWER_FADE_ON_TICKS 140U #define POWER_FADE_OFF_TICKS 160U @@ -355,19 +356,26 @@ void Light_Transition_Task(void) } /* - * The three-color breathing effect joins a single-color phase to a - * 50:50 phase. Keep the single-color side at the same physical minimum - * as the stable dual-color side, otherwise the first mixed step jumps - * from about 10/1000 to at least 204/1000. + * Three-color breathing uses 50 us pulse-density modulation below the + * normal dual-color pulse range. Keep both sides of each color join at + * the same low physical on-time: 45/1000 of a 500 us single-color frame, + * or 25 + 25 over the 450 us dual-color active interval. */ if(Mode == mode1 && choose_mode_falsg == 5U) { if(W_PWM != 0U && C_PWM == 0U && - target_w < THREE_COLOR_JOIN_OUTPUT) - target_w = THREE_COLOR_JOIN_OUTPUT; + target_w < THREE_COLOR_MIN_SINGLE_OUTPUT) + target_w = THREE_COLOR_MIN_SINGLE_OUTPUT; else if(C_PWM != 0U && W_PWM == 0U && - target_c < THREE_COLOR_JOIN_OUTPUT) - target_c = THREE_COLOR_JOIN_OUTPUT; + target_c < THREE_COLOR_MIN_SINGLE_OUTPUT) + target_c = THREE_COLOR_MIN_SINGLE_OUTPUT; + else if(W_PWM != 0U && C_PWM != 0U) + { + if(target_w < THREE_COLOR_MIN_CHANNEL_OUTPUT) + target_w = THREE_COLOR_MIN_CHANNEL_OUTPUT; + if(target_c < THREE_COLOR_MIN_CHANNEL_OUTPUT) + target_c = THREE_COLOR_MIN_CHANNEL_OUTPUT; + } } /* @@ -376,7 +384,8 @@ void Light_Transition_Task(void) * A ratio that cannot provide 102/1000 to its weak side even at full * brightness is treated as single color. */ - if(W_PWM != 0U && C_PWM != 0U) + if(W_PWM != 0U && C_PWM != 0U && + !(Mode == mode1 && choose_mode_falsg == 5U)) { mix_total = (uint16_t)(W_PWM + C_PWM); weak_mix = (W_PWM < C_PWM) ? W_PWM : C_PWM;