Files
AC707N/SDK/cpu/br35/periph/led/pwm_led.c
T
2025-12-03 11:12:34 +08:00

727 lines
23 KiB
C

#include "asm/power_interface.h"
#include "cpu/includes.h"
#include "system/timer.h"
#include "app_config.h"
#include "pwm_led.h"
#if 1
#define LOG_TAG_CONST PWM_LED
#define LOG_TAG "[PWM_LED]"
/* #define LOG_ERROR_ENABLE */
/* #define LOG_DEBUG_ENABLE */
#define LOG_INFO_ENABLE
#define LOG_DUMP_ENABLE
#define LOG_CLI_ENABLE
#include "debug.h"
#else
#define log_debug printf
#endif
enum led_clk_div {
led_clk_div1 = 0b0000,
led_clk_div4 = 0b0001,
led_clk_div16 = 0b0010,
led_clk_div64 = 0b0011,
led_clk_div2 = 0b0100,
led_clk_div8 = 0b0101,
led_clk_div32 = 0b0110,
led_clk_div128 = 0b0111,
led_clk_div256 = 0b1000,
};
const static u8 led_clk_div_table[9] = {
led_clk_div1,
led_clk_div2,
led_clk_div4,
led_clk_div8,
led_clk_div16,
led_clk_div32,
led_clk_div64,
led_clk_div128,
led_clk_div256,
};
static struct pwm_led_platform_data pled_pdata;
#define __this (&pled_pdata)
static u8 pwm_led_data_init = 0;
static u8 pwm_led_ctl_cnt;
static u32 soft_alternate_ref;
static u32 soft_alternate_timer;
static u32 pwm_led_ctl_unit;
#define PWM_LED_CLK (clk_get("lrc") / 10)
volatile u8 pwm_led_active = 0;
void pwm_led_wkup_to_switch_io(void *priv)
{
pwm_led_active = 1;
}
/*
* @brief PWM_LED模块中断服务函数
*/
___interrupt
static void pwm_led_isr(void)
{
JL_PLED->CON3 |= BIT(6);
pwm_led_ctl_cnt ++;
if ((__this->ctl_cycle_num) && (pwm_led_ctl_cnt >= __this->ctl_cycle_num)) {
pwm_led_hw_close();
if (__this->cbfunc) {
__this->cbfunc(__this->cbpriv);
}
} else if (soft_alternate_ref) {
if ((pwm_led_ctl_cnt % 2)) {
gpio_set_mode(IO_PORT_SPILT(__this->port0), PORT_HIGHZ);
gpio_set_function(IO_PORT_SPILT(__this->port1), PORT_FUNC_PWM_LED);
} else {
gpio_set_mode(IO_PORT_SPILT(__this->port1), PORT_HIGHZ);
gpio_set_function(IO_PORT_SPILT(__this->port0), PORT_FUNC_PWM_LED);
}
if (soft_alternate_timer) {
usr_timer_modify(soft_alternate_timer, (__this->ctl_cycle * soft_alternate_ref / PWM_LED_CLK) - 10);
}
soft_alternate_ref = PWM_LED_CLK;
pwm_led_active = 0;
}
}
static void pwm_led_set_h_pwm_duty(u32 pwm_prd, u32 pwm_duty)
{
u32 h_pwm_duty_prd = pwm_prd * pwm_duty / 100;
if (h_pwm_duty_prd) {
h_pwm_duty_prd += 1;
h_pwm_duty_prd = h_pwm_duty_prd > pwm_prd ? pwm_prd : h_pwm_duty_prd;
}
JL_PLED->BRI_DUTY0H = ((h_pwm_duty_prd >> 8) & 0xff);
JL_PLED->BRI_DUTY0L = ((h_pwm_duty_prd >> 0) & 0xff);
}
static void pwm_led_set_l_pwm_duty(u32 pwm_prd, u32 pwm_duty)
{
u32 l_pwm_duty_prd = pwm_prd * pwm_duty / 100;
if (l_pwm_duty_prd) {
l_pwm_duty_prd += 1;
l_pwm_duty_prd = l_pwm_duty_prd > pwm_prd ? pwm_prd : l_pwm_duty_prd;
}
JL_PLED->BRI_DUTY1H = ((l_pwm_duty_prd >> 8) & 0xff);
JL_PLED->BRI_DUTY1L = ((l_pwm_duty_prd >> 0) & 0xff);
}
static void pwm_led_set_pwm_out_once_time(u32 t_cnt3)
{
u32 t_cnt0 = 0;
u32 t_cnt1 = 0;
u32 t_cnt2 = 0;
u32 factor = 1000;
u32 ctl_cycle = __this->ctl_cycle * factor;
u32 pwm_out_time = (__this->out_once.pwm_out_time & 0x7fffffff) * factor;
u32 cnt = pwm_out_time * t_cnt3 / ctl_cycle;
if (cnt) {
if (!(__this->out_once.pwm_out_time & BIT(31))) {//out defer
t_cnt0 = 0;
t_cnt1 = t_cnt3 - cnt;
t_cnt1 = t_cnt1 < 1 ? 1 : t_cnt1;
t_cnt2 = t_cnt3;
} else {
t_cnt0 = 0;
t_cnt1 = 1;
t_cnt2 = t_cnt1 + cnt;
t_cnt2 = t_cnt2 > t_cnt3 ? t_cnt3 : t_cnt2;
}
} else {
t_cnt3 = 0;
}
JL_PLED->DUTY0 = t_cnt0;
JL_PLED->DUTY1 = t_cnt1;
JL_PLED->DUTY2 = t_cnt2;
JL_PLED->DUTY3 = t_cnt3;
JL_PLED->CON1 |= (!!t_cnt0) * BIT(4);//PWM_DUTY0_EN
JL_PLED->CON1 |= (!!t_cnt1) * BIT(5);//PWM_DUTY1_EN
JL_PLED->CON1 |= (!!t_cnt2) * BIT(6);//PWM_DUTY2_EN
JL_PLED->CON1 |= (!!t_cnt3) * BIT(7);//PWM_DUTY3_EN
/* JL_PLED->CON1 |= BIT(3); */
}
static void pwm_led_set_pwm_out_twice_time(u32 t_cnt3)
{
u32 cnt0, t_cnt0 = 0;
u32 cnt1, t_cnt1 = 0;
u32 cnt2, t_cnt2 = 0;
u32 factor = 1000;
u32 ctl_cycle = __this->ctl_cycle * factor;
u32 first_pwm_out_time = __this->out_twice.first_pwm_out_time * factor;
u32 second_pwm_out_time = __this->out_twice.second_pwm_out_time * factor;
u32 pwm_gap_time = __this->out_twice.pwm_gap_time * factor;
u32 highz_time = ctl_cycle - (first_pwm_out_time + pwm_gap_time + second_pwm_out_time);
if (highz_time == ctl_cycle) {
t_cnt3 = 0;
} else {
cnt0 = highz_time * t_cnt3 / ctl_cycle;
cnt1 = first_pwm_out_time * t_cnt3 / ctl_cycle;
cnt2 = pwm_gap_time * t_cnt3 / ctl_cycle;
/* t_cnt0 = cnt0 < 1 ? 1 : cnt0; */
t_cnt0 = cnt0 + 1;
t_cnt1 = t_cnt0 + cnt1;
t_cnt1 = (t_cnt1 < (t_cnt0 + 1)) ? (t_cnt0 + 1) : t_cnt1;
t_cnt2 = t_cnt1 + cnt2;
t_cnt2 = (t_cnt2 < (t_cnt1 + 1)) ? (t_cnt1 + 1) : t_cnt2;
}
JL_PLED->DUTY0 = t_cnt0;
JL_PLED->DUTY1 = t_cnt1;
JL_PLED->DUTY2 = t_cnt2;
JL_PLED->DUTY3 = t_cnt3;
JL_PLED->CON1 |= (!!t_cnt0) * BIT(4);//PWM_DUTY3_EN
JL_PLED->CON1 |= (!!t_cnt1) * BIT(5);//PWM_DUTY2_EN
JL_PLED->CON1 |= (!!t_cnt2) * BIT(6);//PWM_DUTY1_EN
JL_PLED->CON1 |= (!!t_cnt3) * BIT(7);//PWM_DUTY0_EN
/* JL_PLED->CON1 |= BIT(3); */
}
static void pwm_led_fixed_output_mode(void)
{
JL_PLED->CON2 &= ~(0b1111 << 4);
JL_PLED->CON2 |= ((__this->alternate_out & 0b111) << 4);
u32 factor = 1000;
u32 ctl_cycle = __this->ctl_cycle * factor;
u32 ctl_num = 255;
u32 ctl_unit = ctl_cycle / ctl_num;
u32 div_idx = 0;
u32 ctl_prd_div, div;
__get_ctl_div:
div = 1 << div_idx;
ctl_prd_div = PWM_LED_CLK * ctl_unit / (100000 * div);
if (ctl_prd_div > 4096) {
div_idx ++;
goto __get_ctl_div;
}
log_debug("ctl_prd_div = %d\n", ctl_prd_div);
if (ctl_prd_div) {
JL_PLED->PRD_DIVL = (ctl_prd_div - 1) & 0xff;
JL_PLED->CON3 |= ((ctl_prd_div - 1) >> 8) & 0xf;
} else {
JL_PLED->PRD_DIVL = 0;
}
log_debug("clk_div = %d\n", div);
u8 div_reg_value = led_clk_div_table[div_idx];
SFR(JL_PLED->CON0, 4, 4, div_reg_value);//时钟源分频
u32 pwm_cycle = __this->pwm_cycle * 10;
u32 pwm_prd = PWM_LED_CLK * pwm_cycle / (100000 * div);
log_debug("pwm_prd = %d\n", pwm_prd);
JL_PLED->BRI_PRDH = (pwm_prd >> 8) & 0b11;
JL_PLED->BRI_PRDL = (pwm_prd >> 0) & 0xff;
if ((__this->first_logic == 0) || (__this->alternate_out)) {
pwm_led_set_h_pwm_duty(pwm_prd, __this->h_pwm_duty);
}
if ((__this->first_logic == 1) || (__this->alternate_out)) {
pwm_led_set_l_pwm_duty(pwm_prd, __this->l_pwm_duty);
}
if (__this->out_mode == 0) {
pwm_led_set_pwm_out_once_time(ctl_num);
} else {
pwm_led_set_pwm_out_twice_time(ctl_num);
}
pwm_led_ctl_unit = ctl_unit;
}
static void pwm_led_breathe_output_mode(void)
{
JL_PLED->CON0 |= BIT(1); //呼吸变化模式
JL_PLED->CON2 &= ~(0b1111 << 4);
JL_PLED->CON2 |= ((__this->alternate_out & 0b111) << 5);
u32 factor = 1000;
u32 ctl_cycle = __this->ctl_cycle * factor;
u32 pwm_out_time = __this->out_breathe.pwm_out_time * factor;
u32 pwm_duty_max_keep_time = __this->out_breathe.pwm_duty_max_keep_time * factor;
if (pwm_duty_max_keep_time > (pwm_out_time / 2)) {
pwm_duty_max_keep_time = pwm_out_time / 2;
}
u32 pwm_duty_change_time = (pwm_out_time - pwm_duty_max_keep_time) / 2;
log_debug("ctl_cycle = %d", ctl_cycle);
log_debug("pwm_out_time = %d", pwm_out_time);
log_debug("pwm_duty_max_keep_time = %d", pwm_duty_max_keep_time);
log_debug("pwm_duty_change_time = %d", pwm_duty_change_time);
u32 h_pwm_duty = 0;
u32 l_pwm_duty = 0;
u32 div_idx = 0;
u32 ctl_prd_div, div = 1;
u32 ctl_num, ctl_unit;
u32 pwm_prd;
u32 pwm_cycle = __this->pwm_cycle * 10;
__get_ctl_div:
pwm_prd = PWM_LED_CLK * pwm_cycle / (100000 * div);
log_debug("pwm_prd = %d\n", pwm_prd);
ctl_num = 0;
if ((__this->first_logic == 0) || (__this->alternate_out)) {
h_pwm_duty = pwm_prd * __this->h_pwm_duty / 100;
ctl_num = ctl_num < h_pwm_duty ? h_pwm_duty : ctl_num;
}
if ((__this->first_logic == 1) || (__this->alternate_out)) {
l_pwm_duty = pwm_prd * __this->l_pwm_duty / 100;
ctl_num = ctl_num < l_pwm_duty ? l_pwm_duty : ctl_num;
}
if (ctl_num) {
ctl_unit = pwm_duty_change_time / ctl_num;
} else {
ctl_unit = pwm_cycle;
}
div = 1 << div_idx;
ctl_prd_div = PWM_LED_CLK * ctl_unit / (100000 * div);
if (ctl_prd_div > 4096) {
div_idx ++;
goto __get_ctl_div;
}
log_debug("ctl_num = %d\n", ctl_num);
log_debug("ctl_unit = %d\n", ctl_unit);
log_debug("ctl_prd_div = %d\n", ctl_prd_div);
if (ctl_prd_div) {
JL_PLED->PRD_DIVL = (ctl_prd_div - 1) & 0xff;
JL_PLED->CON3 |= ((ctl_prd_div - 1) >> 8) & 0xf;
} else {
JL_PLED->PRD_DIVL = 0;
}
log_debug("clk_div = %d\n", div);
u32 div_reg_value = led_clk_div_table[div_idx];
SFR(JL_PLED->CON0, 4, 4, div_reg_value);//时钟源分频
JL_PLED->BRI_PRDH = (pwm_prd >> 8) & 0b11;
JL_PLED->BRI_PRDL = (pwm_prd >> 0) & 0xff;
if ((__this->first_logic == 0) || (__this->alternate_out)) {
pwm_led_set_h_pwm_duty(pwm_prd, __this->h_pwm_duty);
u32 h_pwm_duty_change_time = ctl_unit * h_pwm_duty * 2;
u32 h_pwm_duty_max_keep_time = 0;
if (pwm_out_time > h_pwm_duty_change_time) {
h_pwm_duty_max_keep_time = pwm_out_time - h_pwm_duty_change_time;
}
log_debug("h_pwm_duty_change_time = %d", h_pwm_duty_change_time);
log_debug("h_pwm_duty_max_keep_time = %d", h_pwm_duty_max_keep_time);
u32 h_pwm_duty_max_keep_prd = h_pwm_duty_max_keep_time / ctl_unit;
h_pwm_duty_max_keep_prd = h_pwm_duty_max_keep_prd > 255 ? 255 : h_pwm_duty_max_keep_prd;
JL_PLED->DUTY1 = h_pwm_duty_max_keep_prd;
}
if ((__this->first_logic == 1) || (__this->alternate_out)) {
pwm_led_set_l_pwm_duty(pwm_prd, __this->l_pwm_duty);
u32 l_pwm_duty_change_time = ctl_unit * l_pwm_duty * 2;
u32 l_pwm_duty_max_keep_time = 0;
if (pwm_out_time > l_pwm_duty_change_time) {
l_pwm_duty_max_keep_time = pwm_out_time - l_pwm_duty_change_time;
}
log_debug("l_pwm_duty_change_time = %d", l_pwm_duty_change_time);
log_debug("l_pwm_duty_max_keep_time = %d", l_pwm_duty_max_keep_time);
u32 l_pwm_duty_max_keep_prd = l_pwm_duty_max_keep_time / ctl_unit;
l_pwm_duty_max_keep_prd = l_pwm_duty_max_keep_prd > 255 ? 255 : l_pwm_duty_max_keep_prd;
JL_PLED->DUTY0 = l_pwm_duty_max_keep_prd;
}
u32 pwm_duty_0_keep_time = ctl_cycle - pwm_out_time;
log_debug("pwm_duty_0_keep_time = %d", pwm_duty_0_keep_time);
u32 pwm_duty_0_keep_prd = pwm_duty_0_keep_time / ctl_unit;
JL_PLED->DUTY3 = ((pwm_duty_0_keep_prd >> 8) & 0xff);
JL_PLED->DUTY2 = ((pwm_duty_0_keep_prd >> 0) & 0xff);
JL_PLED->CON1 |= BIT(7);//PWM_DUTY3_EN
JL_PLED->CON1 |= BIT(6);//PWM_DUTY2_EN
JL_PLED->CON1 |= BIT(5);//PWM_DUTY1_EN
JL_PLED->CON1 |= BIT(4);//PWM_DUTY0_EN
pwm_led_ctl_unit = ctl_unit;
}
void pwm_led_io_mount(void)
{
if (pwm_led_data_init == 0) {
return ;
}
if ((__this->port0 < IO_PORT_MAX) && \
(__this->port1 < IO_PORT_MAX) && \
(__this->port0 != __this->port1) && \
(__this->h_pwm_duty == __this->l_pwm_duty) && \
(__this->alternate_out)) {
__this->alternate_out = 0;
JL_PLED->CON3 |= BIT(6);
JL_PLED->CON3 |= BIT(5);
request_irq(IRQ_LED_IDX, 1, pwm_led_isr, 0);
gpio_set_function(IO_PORT_SPILT(__this->port0), PORT_FUNC_PWM_LED);
gpio_set_mode(IO_PORT_SPILT(__this->port1), PORT_HIGHZ);
if (soft_alternate_timer == 0) {
soft_alternate_timer = usr_timer_add(NULL, pwm_led_wkup_to_switch_io, __this->ctl_cycle - 10, 1);
} else {
usr_timer_modify(soft_alternate_timer, __this->ctl_cycle - 10);
}
soft_alternate_ref = PWM_LED_CLK;
pwm_led_active = 0;
} else {
if (__this->port0 < IO_PORT_MAX) {
gpio_set_function(IO_PORT_SPILT(__this->port0), PORT_FUNC_PWM_LED);
}
if (__this->port1 < IO_PORT_MAX) {
gpio_set_function(IO_PORT_SPILT(__this->port1), PORT_FUNC_PWM_LED);
}
}
}
void pwm_led_io_unmount(void)
{
if (pwm_led_data_init == 0) {
return ;
}
soft_alternate_ref = 0;
pwm_led_active = 0;
if (soft_alternate_timer) {
usr_timer_del(soft_alternate_timer);
soft_alternate_timer = 0;
__this->alternate_out = 1;
JL_PLED->CON3 &= ~BIT(5);
}
if (__this->port0 < IO_PORT_MAX) {
gpio_set_mode(IO_PORT_SPILT(__this->port0), PORT_HIGHZ);
}
if (__this->port1 < IO_PORT_MAX) {
gpio_set_mode(IO_PORT_SPILT(__this->port1), PORT_HIGHZ);
}
}
void pwm_led_dump(void)
{
#if 1
printf("port0 = %d\n", __this->port0);
printf("port1 = %d\n", __this->port1);
printf("first_logic = %d\n", __this->first_logic);
printf("alternate_out = %d\n", __this->alternate_out);
printf("pwm_cycle = %u\n", __this->pwm_cycle);
printf("ctl_cycle = %u\n", __this->ctl_cycle);
printf("h_pwm_duty = %d\n", __this->h_pwm_duty);
printf("l_pwm_duty = %d\n", __this->l_pwm_duty);
printf("mode = %d\n", __this->out_mode);
printf("ctl_cycle_num = %d\n", __this->ctl_cycle_num);
printf("cbfunc = %p\n", __this->cbfunc);
switch (__this->out_mode) {
case 0:
printf("out_once.pwm_out_time = %u\n", __this->out_once.pwm_out_time);
break;
case 1:
printf("out_twice.first_pwm_out_time = %u\n", __this->out_twice.first_pwm_out_time);
printf("out_twice.second_pwm_out_time = %u\n", __this->out_twice.second_pwm_out_time);
printf("out_twice.pwm_gap_time = %u\n", __this->out_twice.pwm_gap_time);
break;
case 2:
printf("out_breathe.pwm_duty_max_keep_time = %u\n", __this->out_breathe.pwm_duty_max_keep_time);
printf("out_breathe.pwm_out_time = %u\n", __this->out_breathe.pwm_out_time);
break;
}
#endif
#if 1
printf("JL_PLED->CON0 = 0x%x\n", JL_PLED->CON0);
printf("JL_PLED->CON1 = 0x%x\n", JL_PLED->CON1);
printf("JL_PLED->CON2 = 0x%x\n", JL_PLED->CON2);
printf("JL_PLED->CON3 = 0x%x\n", JL_PLED->CON3);
printf("JL_PLED->CON4 = 0x%x\n", JL_PLED->CON4);
printf("JL_PLED->BRI_PRDL = 0x%x\n", JL_PLED->BRI_PRDL);
printf("JL_PLED->BRI_PRDH = 0x%x\n", JL_PLED->BRI_PRDH);
printf("JL_PLED->BRI_DUTY0L = 0x%x\n", JL_PLED->BRI_DUTY0L);
printf("JL_PLED->BRI_DUTY0L = 0x%x\n", JL_PLED->BRI_DUTY0H);
printf("JL_PLED->BRI_DUTY1L = 0x%x\n", JL_PLED->BRI_DUTY1L);
printf("JL_PLED->BRI_DUTY1H = 0x%x\n", JL_PLED->BRI_DUTY1H);
printf("JL_PLED->PRD_DIV = 0x%x\n", JL_PLED->PRD_DIVL);
printf("JL_PLED->DUTY0 = %d\n", JL_PLED->DUTY0);
printf("JL_PLED->DUTY1 = %d\n", JL_PLED->DUTY1);
printf("JL_PLED->DUTY2 = %d\n", JL_PLED->DUTY2);
printf("JL_PLED->DUTY3 = %d\n", JL_PLED->DUTY3);
#endif
}
/*
* @brief PWM_LED模块初始化函数
* @arg pdata 初始化的参数结构体地址: struct pwm_led_platform_data *
*/
void pwm_led_hw_init(void *pdata)
{
if (!pdata) {
return;
}
pwm_led_hw_close();
memset((u8 *)JL_PLED, 0, sizeof(JL_PLED_TypeDef));
memcpy((u8 *)__this, (u8 *)pdata, sizeof(struct pwm_led_platform_data));
pwm_led_data_init = 1;
pwm_led_ctl_cnt = 0;
//初始化引脚
pwm_led_io_mount();
SFR(P11_SYSTEM->P2M_CLK_CON0, 8, 3, 3);
JL_PLED->CON0 &= ~(0b11 << 2); //PWM_LED选择LRD_200K做时钟源
JL_PLED->CON0 &= ~(0b1111 << 4); //时钟源不分频
if (__this->first_logic == 0) {
JL_PLED->CON1 &= ~BIT(2);
} else {
JL_PLED->CON1 |= BIT(2);
}
JL_PLED->CON3 |= BIT(4);
JL_PLED->CON3 |= BIT(6);
if (__this->out_mode < 2) {
pwm_led_fixed_output_mode();
} else {
pwm_led_breathe_output_mode();
}
if (__this->cbfunc || __this->ctl_cycle_num) {
JL_PLED->CON3 |= BIT(5);
request_irq(IRQ_LED_IDX, 1, pwm_led_isr, 0);
}
JL_PLED->CON0 |= BIT(0);
pwm_led_dump();
}
/*
* @brief 关闭pwm_led模块
*/
void pwm_led_hw_close(void)
{
JL_PLED->CON0 &= ~BIT(0);
SFR(P11_SYSTEM->P2M_CLK_CON0, 8, 3, 0);
pwm_led_io_unmount();
pwm_led_data_init = 0;
}
u32 pwm_led_is_working(void)
{
return (!!(JL_PLED->CON0 & BIT(0)));
}
static u8 pwm_led_idle_query()
{
if ((soft_alternate_ref) && (pwm_led_active)) {
return 0;
}
return 1;
}
static enum LOW_POWER_LEVEL pwm_led_low_power_level()
{
if (pwm_led_data_init) {
return LOW_POWER_MODE_SLEEP;
}
return LOW_POWER_MODE_DEEP_SLEEP;
}
REGISTER_LP_TARGET(pwm_led) = {
.name = "pwm_led",
.is_idle = pwm_led_idle_query,
.level = pwm_led_low_power_level,
};
static void pwm_led_get_next_dir_level(u32 cur_dir, u32 cur_level, u32 *dir, u32 *level)
{
if (JL_PLED->CON0 & BIT(1)) {//呼吸变化模式
*dir = !cur_dir;
if (__this->alternate_out) {
if (cur_dir) {
*level = cur_level;
} else {
*level = !cur_level;
}
} else {
*level = cur_level;
}
} else {
*dir = cur_dir;
if (__this->alternate_out) {
*level = !cur_level;
} else {
*level = cur_level;
}
}
}
static u32 pwm_led_get_cur_status_cnt_max(u32 cur_dir, u32 cur_level)
{
u32 keep_prd;
u32 cnt_max;
if (JL_PLED->CON0 & BIT(1)) {//呼吸变化模式
u32 h_pwm_duty_prd = (JL_PLED->BRI_DUTY0H >> 8) | JL_PLED->BRI_DUTY0L;
u32 l_pwm_duty_prd = (JL_PLED->BRI_DUTY1H >> 8) | JL_PLED->BRI_DUTY1L;
if (cur_dir) {
keep_prd = (JL_PLED->DUTY3 << 8) | JL_PLED->DUTY2;
if (cur_level) {
cnt_max = keep_prd + l_pwm_duty_prd;
} else {
cnt_max = keep_prd + h_pwm_duty_prd;
}
} else {
if (cur_level) {
keep_prd = JL_PLED->DUTY0;
cnt_max = keep_prd + l_pwm_duty_prd;
} else {
keep_prd = JL_PLED->DUTY1;
cnt_max = keep_prd + h_pwm_duty_prd;
}
}
} else {
cnt_max = JL_PLED->DUTY3;
}
return cnt_max;
}
/*
* @brief 获取PWM_LED模块状态信息
*/
void pwm_led_get_sync_status(struct pwm_led_status_t *status)
{
if (!status) {
return;
}
status->cnt_max = 0;
if ((JL_PLED->CON0 & BIT(0)) == 0) {
return;
}
JL_PLED->CON4 |= BIT(4);
while (!(JL_PLED->CON4 & BIT(5)));
u32 cnt_rd = JL_PLED->CNT_RD;
u32 next_dir = 0;
u32 next_level = 0;
status->dir = !!(cnt_rd & BIT(17));
status->level = !!(cnt_rd & BIT(16));
status->cur_cnt = cnt_rd & 0xffff;
if ((JL_PLED->CON0 & BIT(1)) == 0) {//不是呼吸变化模式
status->cur_cnt = cnt_rd & 0xff;
}
status->cnt_max = pwm_led_get_cur_status_cnt_max(status->dir, status->level);
pwm_led_get_next_dir_level(status->dir, status->level, (u32 *)&next_dir, (u32 *)&next_level);
status->next_cnt_max = pwm_led_get_cur_status_cnt_max(next_dir, next_level);
status->cnt_unit = pwm_led_ctl_unit;
}
/*
* @brief 设置PWM_LED暂停同步
* @arg status 另一个样机的pwm_led的状态
* @arg how_long_ago 另一个样机的pwm_led的状态是多久之前的, 单位us
* @arg sync_time 如果为快的样机,则通过该变量获取同步暂停时间, 单位us
* @return 0:成功 1:失败
*/
u32 pwm_led_set_sync(struct pwm_led_status_t *status, u32 how_long_ago, u32 *sync_time)
{
if (!status) {
return 1;
}
if (status->cnt_max == 0) {
return 1;
}
if (status->next_cnt_max == 0) {
return 1;
}
if ((status->cnt_unit == 0) || (pwm_led_ctl_unit == 0)) {
return 1;
}
if ((JL_PLED->CON0 & BIT(0)) == 0) {
return 1;
}
/* u32 dir = status->dir; */
/* u32 level = status->level; */
u32 cnt_delta = how_long_ago / status->cnt_unit;
u32 cnt = status->cur_cnt;
u32 table_idle = 0;
u32 cnt_max_table[2];
cnt_max_table[0] = status->cnt_max;
cnt_max_table[1] = status->next_cnt_max;
u32 cnt_max = cnt_max_table[0];
if (JL_PLED->CON0 & BIT(1)) {//呼吸变化模式
for (u32 i = 0; i < cnt_delta; i ++) {
cnt ++;
if (cnt > cnt_max) {
cnt = 0;
table_idle = !table_idle;
cnt_max = cnt_max_table[table_idle];
}
}
} else {
cnt += cnt_delta;
cnt %= (cnt_max + 1);
}
u32 progress = 1000 * cnt / cnt_max;
JL_PLED->CON4 |= BIT(4);
while (!(JL_PLED->CON4 & BIT(5)));
u32 cnt_rd = JL_PLED->CNT_RD;
u32 cur_dir = !!(cnt_rd & BIT(17));
u32 cur_level = !!(cnt_rd & BIT(16));
u32 cur_cnt = cnt_rd & 0xffff;
if ((JL_PLED->CON0 & BIT(1)) == 0) {//不是呼吸变化模式
cur_cnt &= 0xff;
}
u32 cur_cnt_max = pwm_led_get_cur_status_cnt_max(cur_dir, cur_level);
u32 cur_progress = 1000 * cur_cnt / cur_cnt_max;
u32 wait_time = 0;
u32 diff;
if (JL_PLED->CON0 & BIT(1)) {//呼吸变化模式
if ((cnt_max_table[0] > cnt_max_table[1]) && (cnt_max == cnt_max_table[1]) && (cur_dir == 1)) {
wait_time = ((cnt_max - cnt) + (cur_progress * cnt_max_table[0] / 1000)) * status->cnt_unit;
}
if ((cnt_max_table[0] < cnt_max_table[1]) && (cnt_max == cnt_max_table[0]) && (cur_dir == 1)) {
wait_time = ((cnt_max - cnt) + (cur_progress * cnt_max_table[1] / 1000)) * status->cnt_unit;
}
if (cur_progress > progress) {
diff = cur_progress - progress;
wait_time = (diff * cnt_max / 1000) * status->cnt_unit;
}
} else {
if ((cur_progress > progress) && ((cur_progress - progress) <= 500)) {
diff = cur_progress - progress;
wait_time = (diff * cnt_max / 1000) * status->cnt_unit;
}
if ((cur_progress < progress) && ((progress - cur_progress) >= 500)) {
diff = 1000 - (progress - cur_progress);
wait_time = (diff * cnt_max / 1000) * status->cnt_unit;
}
}
*sync_time = 0;
u32 sync = wait_time / pwm_led_ctl_unit;
if (sync) {
*sync_time = wait_time;
JL_PLED->CNT_SYNC = sync;
log_debug("sync = %d\n", sync);
}
#if 0
if (sync) {
u32 dec = cur_cnt_max / sync;
JL_PLED->CNT_DEC = dec > 255 ? 0 : dec;
log_debug("dec = %d\n", dec);
}
#endif
return 0;
}