初版
This commit is contained in:
@@ -0,0 +1,726 @@
|
||||
#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;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,552 @@
|
||||
#include "asm/mcpwm.h"
|
||||
#include "clock.h"
|
||||
#include "gpio.h"
|
||||
#include "spinlock.h"
|
||||
|
||||
#define MCPWM_DEBUG_ENABLE 0 //MCPWM打印使能
|
||||
#if MCPWM_DEBUG_ENABLE
|
||||
#define mcpwm_debug(fmt, ...) printf("[MCPWM] "fmt, ##__VA_ARGS__)
|
||||
#else
|
||||
#define mcpwm_debug(...)
|
||||
#endif
|
||||
|
||||
#define log_error(fmt, ...) printf("[MCPWM](err): "fmt, ##__VA_ARGS__)
|
||||
|
||||
#define MCPWM_CLK clk_get("mcpwm")
|
||||
DEFINE_SPINLOCK(mcpwm_lock);
|
||||
|
||||
static struct mcpwm_info_t *mcpwm_info[MCPWM_NUM_MAX] = {NULL};
|
||||
|
||||
static MCPWM_TIMERx_REG *mcpwm_get_timerx_reg(mcpwm_ch_type ch)
|
||||
{
|
||||
ASSERT((u32)ch < MCPWM_CH_MAX, "func:%s(), line:%d\n", __func__, __LINE__);
|
||||
MCPWM_TIMERx_REG *reg = NULL;
|
||||
reg = (MCPWM_TIMERx_REG *)(MCPWM_TMR_BASE_ADDR + ch * MCPWM_TMR_OFFSET);
|
||||
return reg;
|
||||
}
|
||||
|
||||
static MCPWM_CHx_REG *mcpwm_get_chx_reg(mcpwm_ch_type ch)
|
||||
{
|
||||
ASSERT((u32)ch < MCPWM_CH_MAX, "func:%s(), line:%d\n", __func__, __LINE__);
|
||||
MCPWM_CHx_REG *reg = NULL;
|
||||
reg = (MCPWM_CHx_REG *)(MCPWM_CH_BASE_ADDR + ch * MCPWM_CH_OFFSET);
|
||||
return reg;
|
||||
}
|
||||
|
||||
static int mcpwm_get_cfg_id(u32 ch)
|
||||
{
|
||||
for (u8 id = 0; id < MCPWM_NUM_MAX; id++) {
|
||||
if (mcpwm_info[id] != NULL) {
|
||||
if ((u32)mcpwm_info[id]->cfg.ch == ch) {
|
||||
return (int)id;
|
||||
}
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static u32 old_mcpwm_clk = 0;
|
||||
static void clock_critical_enter(void)
|
||||
{
|
||||
old_mcpwm_clk = MCPWM_CLK;
|
||||
}
|
||||
static void clock_critical_exit(void)
|
||||
{
|
||||
u32 new_mcpwm_clk = MCPWM_CLK;
|
||||
if (new_mcpwm_clk == old_mcpwm_clk) {
|
||||
return;
|
||||
}
|
||||
MCPWM_CHx_REG *ch_reg = NULL;
|
||||
for (u8 ch = 0; ch < MCPWM_CH_MAX; ch++) {
|
||||
ch_reg = mcpwm_get_chx_reg(ch);
|
||||
if (ch_reg->ch_con0 & (BIT(MCPWM_CH_H_EN) | BIT(MCPWM_CH_L_EN))) {
|
||||
int id = mcpwm_get_cfg_id(ch);
|
||||
if (id != -1) {
|
||||
mcpwm_set_frequency(id, mcpwm_info[id]->cfg.aligned_mode, mcpwm_info[id]->cfg.frequency);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
LSB_CRITICAL_HANDLE_REG(mcpwm, clock_critical_enter, clock_critical_exit)
|
||||
|
||||
static void mcpwm_reg_log_info(int mcpwm_cfg_id)
|
||||
{
|
||||
int id = mcpwm_cfg_id;
|
||||
u32 ch = (u32)mcpwm_info[id]->cfg.ch;
|
||||
//cppcheck-suppress unreadVariable
|
||||
MCPWM_CHx_REG *ch_reg = mcpwm_get_chx_reg(ch);
|
||||
//cppcheck-suppress unreadVariable
|
||||
MCPWM_TIMERx_REG *timer_reg = mcpwm_get_timerx_reg(ch);
|
||||
mcpwm_debug("tmr%d con = 0x%x", ch, timer_reg->tmr_con);
|
||||
mcpwm_debug("tmr%d pr = 0x%x", ch, timer_reg->tmr_pr);
|
||||
mcpwm_debug("pwm ch%d_con0 = 0x%x", ch, ch_reg->ch_con0);
|
||||
mcpwm_debug("pwm ch%d_con1 = 0x%x", ch, ch_reg->ch_con1);
|
||||
mcpwm_debug("pwm ch%d_cmph = 0x%x, pwm ch%d_cmpl = 0x%x", ch, ch_reg->ch_cmph, ch, ch_reg->ch_cmpl);
|
||||
mcpwm_debug("pwm ch%d_fpin = 0x%x", ch, JL_MCPWM->FPIN_CON);
|
||||
mcpwm_debug("MCPWM_CON0 = 0x%x", JL_MCPWM->MCPWM_CON0);
|
||||
mcpwm_debug("mcpwm clk = %d", MCPWM_CLK);
|
||||
}
|
||||
|
||||
static void (*mcpwm_cb_table[MCPWM_CH_MAX])(u32 ch);
|
||||
static void mcpwm_cb(u32 ch)
|
||||
{
|
||||
if (mcpwm_cb_table[ch]) {
|
||||
mcpwm_cb_table[ch](ch);
|
||||
}
|
||||
asm("csync");
|
||||
}
|
||||
___interrupt
|
||||
static void mcpwm_fpin_cb()
|
||||
{
|
||||
MCPWM_CHx_REG *ch_reg = NULL;
|
||||
for (u8 ch = 0; ch < MCPWM_CH_MAX; ch++) {
|
||||
ch_reg = mcpwm_get_chx_reg(ch);
|
||||
if (ch_reg->ch_con1 & BIT(MCPWM_CH_FPND)) {
|
||||
JL_MCPWM->MCPWM_CON0 &= ~BIT(ch + MCPWM_CON_PWM_EN);
|
||||
JL_MCPWM->MCPWM_CON0 &= ~BIT(ch + MCPWM_CON_TMR_EN);
|
||||
if (ch_reg->ch_con1 & BIT(MCPWM_CH_INTEN)) {
|
||||
ch_reg->ch_con1 &= ~BIT(MCPWM_CH_INTEN); //关闭故障保护输入IE使能
|
||||
mcpwm_cb(ch);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
static void mcpwm_cfg_info_load(int mcpwm_cfg_id)
|
||||
{
|
||||
if (!mcpwm_info[mcpwm_cfg_id]) {
|
||||
log_error("[%s]mcpwm_cfg_id:%d not init", __func__, mcpwm_cfg_id);
|
||||
return;
|
||||
}
|
||||
/* ASSERT(mcpwm_info[mcpwm_cfg_id] != NULL, "func:%s(), line:%d\n", __func__, __LINE__); */
|
||||
|
||||
int id = mcpwm_cfg_id;
|
||||
u32 ch = (u32)mcpwm_info[id]->cfg.ch;
|
||||
MCPWM_CHx_REG *ch_reg = mcpwm_get_chx_reg(ch);
|
||||
|
||||
mcpwm_set_frequency(id, mcpwm_info[id]->cfg.aligned_mode, mcpwm_info[id]->cfg.frequency);
|
||||
|
||||
mcpwm_set_duty(id, mcpwm_info[id]->cfg.duty);
|
||||
|
||||
u16 ch_con0 = 0;
|
||||
u16 ch_con1 = 0;
|
||||
if (mcpwm_info[id]->cfg.complementary_en) { //是否互补
|
||||
ch_con0 &= ~(BIT(MCPWM_CH_L_INV) | BIT(MCPWM_CH_H_INV));
|
||||
ch_con0 |= BIT(MCPWM_CH_L_INV); //L_INV
|
||||
} else {
|
||||
ch_con0 &= ~(BIT(MCPWM_CH_L_INV) | BIT(MCPWM_CH_H_INV));
|
||||
}
|
||||
ch_con1 &= ~(0b111 << MCPWM_CH_TMRSEL);
|
||||
ch_con1 |= (ch << MCPWM_CH_TMRSEL); //sel mctmr
|
||||
//H:
|
||||
if (mcpwm_info[id]->cfg.h_pin < IO_MAX_NUM) { //任意引脚
|
||||
ch_con0 |= BIT(MCPWM_CH_H_EN); //H_EN
|
||||
gpio_set_mode(IO_PORT_SPILT(mcpwm_info[id]->cfg.h_pin), PORT_OUTPUT_LOW);
|
||||
gpio_set_function(IO_PORT_SPILT(mcpwm_info[id]->cfg.h_pin), PORT_FUNC_MCPWM0_H + 2 * ch);
|
||||
|
||||
#ifdef IO_LCD_PG
|
||||
} else if (mcpwm_info[id]->cfg.h_pin == IO_LCD_PG) {
|
||||
ch_con0 |= BIT(MCPWM_CH_H_EN); //H_EN
|
||||
SFR(JL_IOMC->LCDPG_CON, 2, 6, (FO_MCPWM0_H >> 2) + ch);
|
||||
JL_IOMC->LCDPG_CON |= BIT(0);
|
||||
#endif
|
||||
|
||||
#ifdef IO_MT_PG
|
||||
} else if (mcpwm_info[id]->cfg.h_pin == IO_MT_PG) {
|
||||
ch_con0 |= BIT(MCPWM_CH_H_EN); //H_EN
|
||||
SFR(JL_IOMC->MTPG_CON, 2, 6, (FO_MCPWM0_H >> 2) + ch);
|
||||
JL_IOMC->MTPG_CON |= BIT(0);
|
||||
#endif
|
||||
}
|
||||
//L:
|
||||
if (mcpwm_info[id]->cfg.l_pin < IO_MAX_NUM) { //任意引脚
|
||||
ch_con0 |= BIT(MCPWM_CH_L_EN); //L_EN
|
||||
gpio_set_mode(IO_PORT_SPILT(mcpwm_info[id]->cfg.l_pin), PORT_OUTPUT_LOW);
|
||||
gpio_set_function(IO_PORT_SPILT(mcpwm_info[id]->cfg.l_pin), PORT_FUNC_MCPWM0_L + 2 * ch);
|
||||
}
|
||||
|
||||
if (mcpwm_info[id]->cfg.detect_port < IO_MAX_NUM) { //需要开启故障保护功能
|
||||
ASSERT(mcpwm_info[id]->cfg.edge != MCPWM_EDGE_DEFAULT, "func:%s(), line:%d\n", __func__, __LINE__);
|
||||
u32 fpin_con = JL_MCPWM->FPIN_CON;
|
||||
asm("csync");
|
||||
if (mcpwm_info[id]->cfg.edge) { //上升沿
|
||||
gpio_set_mode(IO_PORT_SPILT(mcpwm_info[id]->cfg.detect_port), PORT_INPUT_PULLDOWN_10K);
|
||||
fpin_con |= BIT(MCPWM_FPIN_EDGE + ch);//上升沿触发
|
||||
} else {
|
||||
gpio_set_mode(IO_PORT_SPILT(mcpwm_info[id]->cfg.detect_port), PORT_INPUT_PULLUP_10K);
|
||||
fpin_con &= ~BIT(MCPWM_FPIN_EDGE + ch);//下升沿触发
|
||||
}
|
||||
fpin_con |= BIT(MCPWM_FPIN_FLT_EN + ch);//开启滤波
|
||||
fpin_con |= (0b111111 << MCPWM_FPIN_FLT_PR); //滤波时间 = 16 * 64 / lsb_clk (单位:s)
|
||||
gpio_set_function(IO_PORT_SPILT(mcpwm_info[id]->cfg.detect_port), PORT_FUNC_MCPWM0_FP + ch);
|
||||
mcpwm_cb_table[ch] = mcpwm_info[id]->cfg.irq_cb;
|
||||
request_irq(IRQ_MCPWM_CHX_IDX, mcpwm_info[id]->cfg.irq_priority, mcpwm_fpin_cb, 0);
|
||||
|
||||
ch_con1 |= BIT(MCPWM_CH_FCLR) | BIT(MCPWM_CH_INTEN) | BIT(MCPWM_CH_FPINEN) | BIT(MCPWM_CH_FPINAUTO) | (ch << MCPWM_CH_FPINSEL);
|
||||
spin_lock(&mcpwm_lock);
|
||||
JL_MCPWM->FPIN_CON = fpin_con;
|
||||
spin_unlock(&mcpwm_lock);
|
||||
}
|
||||
|
||||
spin_lock(&mcpwm_lock);
|
||||
ch_reg->ch_con0 = ch_con0;
|
||||
ch_reg->ch_con1 = ch_con1;
|
||||
spin_unlock(&mcpwm_lock);
|
||||
}
|
||||
|
||||
int mcpwm_init(struct mcpwm_config *mcpwm_cfg)
|
||||
{
|
||||
MCPWM_CHx_REG *ch_reg = mcpwm_get_chx_reg(mcpwm_cfg->ch);
|
||||
MCPWM_TIMERx_REG *timer_reg = mcpwm_get_timerx_reg(mcpwm_cfg->ch);
|
||||
|
||||
int cfg_id = -1;
|
||||
for (u32 i = 0; i < MCPWM_NUM_MAX; i++) {
|
||||
if (mcpwm_info[i]) {
|
||||
continue;
|
||||
}
|
||||
if (mcpwm_info[i] == NULL) {
|
||||
mcpwm_info[i] = (struct mcpwm_info_t *)malloc(sizeof(struct mcpwm_info_t));
|
||||
ASSERT(mcpwm_info[i] != NULL, "func:%s(), line:%d\n", __func__, __LINE__);
|
||||
cfg_id = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (cfg_id == -1) {
|
||||
mcpwm_debug("mcpwm_config_id is null!!!\n");
|
||||
return cfg_id;
|
||||
}
|
||||
|
||||
mcpwm_info[cfg_id]->ch_reg = ch_reg;
|
||||
mcpwm_info[cfg_id]->timer_reg = timer_reg;
|
||||
memcpy(&mcpwm_info[cfg_id]->cfg, mcpwm_cfg, sizeof(struct mcpwm_config));
|
||||
mcpwm_debug("mcpwm_info[%d]->ch_reg = 0x%x\n", cfg_id, (u32)mcpwm_info[cfg_id]->ch_reg);
|
||||
mcpwm_debug("mcpwm_info[%d]->timer_reg = 0x%x\n", cfg_id, (u32)mcpwm_info[cfg_id]->timer_reg);
|
||||
mcpwm_debug("mcpwm_info[%d]->cfg.ch = %d\n", cfg_id, (u32)mcpwm_info[cfg_id]->cfg.ch);
|
||||
mcpwm_debug("mcpwm_info[%d]->cfg.alifned_mode = %d\n", cfg_id, (u32)mcpwm_info[cfg_id]->cfg.aligned_mode);
|
||||
mcpwm_debug("mcpwm_info[%d]->cfg.frequency = %d\n", cfg_id, (u32)mcpwm_info[cfg_id]->cfg.frequency);
|
||||
mcpwm_debug("mcpwm_info[%d]->cfg.duty = %d\n", cfg_id, (u32)mcpwm_info[cfg_id]->cfg.duty);
|
||||
mcpwm_debug("mcpwm_info[%d]->cfg.h_pin = %d\n", cfg_id, (u32)mcpwm_info[cfg_id]->cfg.h_pin);
|
||||
mcpwm_debug("mcpwm_info[%d]->cfg.l_pin = %d\n", cfg_id, (u32)mcpwm_info[cfg_id]->cfg.l_pin);
|
||||
mcpwm_debug("mcpwm_info[%d]->cfg.complementary_en = %d\n", cfg_id, (u32)mcpwm_info[cfg_id]->cfg.complementary_en);
|
||||
mcpwm_debug("mcpwm_info[%d]->cfg.detect_port = %d\n", cfg_id, (u32)mcpwm_info[cfg_id]->cfg.detect_port);
|
||||
mcpwm_debug("mcpwm_info[%d]->cfg.irq_cb = %d\n", cfg_id, (u32)mcpwm_info[cfg_id]->cfg.irq_cb);
|
||||
mcpwm_debug("mcpwm_info[%d]->cfg.irq_priority = %d\n", cfg_id, (u32)mcpwm_info[cfg_id]->cfg.irq_priority);
|
||||
return cfg_id;
|
||||
|
||||
}
|
||||
|
||||
void mcpwm_deinit(int mcpwm_cfg_id)
|
||||
{
|
||||
if (!mcpwm_info[mcpwm_cfg_id]) {
|
||||
log_error("[%s]mcpwm_cfg_id:%d not init", __func__, mcpwm_cfg_id);
|
||||
return;
|
||||
}
|
||||
/* ASSERT(mcpwm_info[mcpwm_cfg_id] != NULL, "func:%s(), line:%d\n", __func__, __LINE__); */
|
||||
|
||||
int id = mcpwm_cfg_id;
|
||||
u32 ch = (u32)mcpwm_info[id]->cfg.ch;
|
||||
MCPWM_TIMERx_REG *timer_reg = mcpwm_get_timerx_reg(ch);
|
||||
MCPWM_CHx_REG *ch_reg = mcpwm_get_chx_reg(ch);
|
||||
|
||||
u32 mcpwm_con = JL_MCPWM->MCPWM_CON0;
|
||||
asm("csync");
|
||||
mcpwm_con &= ~BIT(ch + MCPWM_CON_PWM_EN);
|
||||
mcpwm_con &= ~BIT(ch + MCPWM_CON_TMR_EN);
|
||||
if ((JL_MCPWM->MCPWM_CON0 & 0xff) == 0) {
|
||||
mcpwm_con &= ~BIT(MCPWM_CON_CLK_EN);
|
||||
}
|
||||
spin_lock(&mcpwm_lock);
|
||||
JL_MCPWM->MCPWM_CON0 = mcpwm_con;
|
||||
spin_unlock(&mcpwm_lock);
|
||||
if (mcpwm_info[id]->cfg.h_pin < IO_MAX_NUM) {
|
||||
gpio_disable_function(IO_PORT_SPILT(mcpwm_info[mcpwm_cfg_id]->cfg.h_pin), PORT_FUNC_MCPWM0_H + 2 * ch);
|
||||
gpio_set_mode(IO_PORT_SPILT(mcpwm_info[mcpwm_cfg_id]->cfg.h_pin), PORT_HIGHZ);
|
||||
|
||||
#ifdef IO_LCD_PG
|
||||
} else if (mcpwm_info[id]->cfg.h_pin == IO_LCD_PG) {
|
||||
JL_IOMC->LCDPG_CON = 0;
|
||||
#endif
|
||||
|
||||
#ifdef IO_MT_PG
|
||||
} else if (mcpwm_info[id]->cfg.h_pin == IO_MT_PG) {
|
||||
JL_IOMC->MTPG_CON = 0;
|
||||
#endif
|
||||
}
|
||||
if (mcpwm_info[id]->cfg.l_pin < IO_MAX_NUM) {
|
||||
gpio_disable_function(IO_PORT_SPILT(mcpwm_info[mcpwm_cfg_id]->cfg.l_pin), PORT_FUNC_MCPWM0_L + 2 * ch);
|
||||
gpio_set_mode(IO_PORT_SPILT(mcpwm_info[mcpwm_cfg_id]->cfg.l_pin), PORT_HIGHZ);
|
||||
}
|
||||
if (mcpwm_info[id]->cfg.detect_port < IO_MAX_NUM) { //需要开启故障保护功能
|
||||
gpio_disable_function(IO_PORT_SPILT(mcpwm_info[mcpwm_cfg_id]->cfg.detect_port), PORT_FUNC_MCPWM0_FP + ch);
|
||||
gpio_set_mode(IO_PORT_SPILT(mcpwm_info[mcpwm_cfg_id]->cfg.detect_port), PORT_HIGHZ);
|
||||
spin_lock(&mcpwm_lock);
|
||||
ch_reg->ch_con1 = BIT(MCPWM_CH_FCLR);
|
||||
spin_unlock(&mcpwm_lock);
|
||||
}
|
||||
free(mcpwm_info[mcpwm_cfg_id]);
|
||||
memset(mcpwm_info[mcpwm_cfg_id], 0, sizeof(struct mcpwm_info_t));
|
||||
}
|
||||
|
||||
void mcpwm_start(int mcpwm_cfg_id)
|
||||
{
|
||||
if (!mcpwm_info[mcpwm_cfg_id]) {
|
||||
log_error("[%s]mcpwm_cfg_id:%d not init", __func__, mcpwm_cfg_id);
|
||||
return;
|
||||
}
|
||||
/* ASSERT(mcpwm_info[mcpwm_cfg_id] != NULL, "func:%s(), line:%d\n", __func__, __LINE__); */
|
||||
int id = mcpwm_cfg_id;
|
||||
u32 ch = (u32)mcpwm_info[id]->cfg.ch;
|
||||
mcpwm_cfg_info_load(id);
|
||||
u32 mcpwm_con = JL_MCPWM->MCPWM_CON0;
|
||||
asm("csync");
|
||||
mcpwm_con |= BIT(MCPWM_CON_CLK_EN);
|
||||
mcpwm_con |= BIT(ch + MCPWM_CON_TMR_EN);
|
||||
mcpwm_con |= BIT(ch + MCPWM_CON_PWM_EN);
|
||||
spin_lock(&mcpwm_lock);
|
||||
JL_MCPWM->MCPWM_CON0 = mcpwm_con;
|
||||
spin_unlock(&mcpwm_lock);
|
||||
mcpwm_reg_log_info(id);
|
||||
}
|
||||
|
||||
void mcpwm_pause(int mcpwm_cfg_id)
|
||||
{
|
||||
if (!mcpwm_info[mcpwm_cfg_id]) {
|
||||
log_error("[%s]mcpwm_cfg_id:%d not init", __func__, mcpwm_cfg_id);
|
||||
return;
|
||||
}
|
||||
int id = mcpwm_cfg_id;
|
||||
u32 ch = (u32)mcpwm_info[id]->cfg.ch;
|
||||
u32 mcpwm_con = JL_MCPWM->MCPWM_CON0;
|
||||
asm("csync");
|
||||
mcpwm_con &= ~BIT(ch + MCPWM_CON_PWM_EN);
|
||||
mcpwm_con &= ~BIT(ch + MCPWM_CON_TMR_EN);
|
||||
if ((JL_MCPWM->MCPWM_CON0 & 0xff) == 0) {
|
||||
mcpwm_con &= ~BIT(MCPWM_CON_CLK_EN);
|
||||
}
|
||||
spin_lock(&mcpwm_lock);
|
||||
JL_MCPWM->MCPWM_CON0 = mcpwm_con;
|
||||
spin_unlock(&mcpwm_lock);
|
||||
}
|
||||
|
||||
void mcpwm_resume(int mcpwm_cfg_id)
|
||||
{
|
||||
mcpwm_start(mcpwm_cfg_id);
|
||||
}
|
||||
|
||||
void mcpwm_set_frequency(int mcpwm_cfg_id, mcpwm_aligned_mode_type align, u32 frequency)
|
||||
{
|
||||
if (!mcpwm_info[mcpwm_cfg_id]) {
|
||||
log_error("[%s]mcpwm_cfg_id:%d not init", __func__, mcpwm_cfg_id);
|
||||
return;
|
||||
}
|
||||
/* ASSERT(mcpwm_info[mcpwm_cfg_id] != NULL, "func:%s(), line:%d\n", __func__, __LINE__); */
|
||||
|
||||
int id = mcpwm_cfg_id;
|
||||
u32 ch = (u32)mcpwm_info[id]->cfg.ch;
|
||||
MCPWM_TIMERx_REG *timer_reg = mcpwm_get_timerx_reg(ch);
|
||||
|
||||
u32 tmr_con = timer_reg->tmr_con;
|
||||
u16 tmr_pr = 0;
|
||||
asm("csync");
|
||||
|
||||
u32 i = 0;
|
||||
u32 mcpwm_div_clk = 0;
|
||||
u32 mcpwm_tmr_pr = 0;
|
||||
u32 mcpwm_fre_min;
|
||||
u32 clk = MCPWM_CLK;
|
||||
for (i = 0; i < 16; i++) {
|
||||
mcpwm_fre_min = clk / (65536u << i);
|
||||
if ((frequency >= mcpwm_fre_min) || (i == 15)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
tmr_con |= (i << MCPWM_TMR_CKPS); //div 2^i
|
||||
mcpwm_div_clk = clk / (1 << i);
|
||||
if (frequency == 0) {
|
||||
mcpwm_tmr_pr = 0;
|
||||
} else {
|
||||
if (align == MCPWM_CENTER_ALIGNED) { //中心对齐
|
||||
mcpwm_tmr_pr = mcpwm_div_clk / (frequency * 2) - 1;
|
||||
} else {
|
||||
mcpwm_tmr_pr = mcpwm_div_clk / frequency - 1;
|
||||
}
|
||||
}
|
||||
tmr_pr = mcpwm_tmr_pr;
|
||||
//timer mode
|
||||
if (align == MCPWM_CENTER_ALIGNED) { //中心对齐
|
||||
tmr_con |= 0b10; //递增-递降循环模式,中心对齐
|
||||
} else {
|
||||
tmr_con |= 0b01; //递增模式,边沿对齐
|
||||
}
|
||||
spin_lock(&mcpwm_lock);
|
||||
timer_reg->tmr_con = tmr_con;
|
||||
timer_reg->tmr_pr = tmr_pr;
|
||||
spin_unlock(&mcpwm_lock);
|
||||
}
|
||||
|
||||
void mcpwm_set_duty(int mcpwm_cfg_id, u16 duty)
|
||||
{
|
||||
if (!mcpwm_info[mcpwm_cfg_id]) {
|
||||
log_error("[%s]mcpwm_cfg_id:%d not init", __func__, mcpwm_cfg_id);
|
||||
return;
|
||||
}
|
||||
/* ASSERT(mcpwm_info[mcpwm_cfg_id] != NULL, "func:%s(), line:%d\n", __func__, __LINE__); */
|
||||
int id = mcpwm_cfg_id;
|
||||
u32 ch = (u32)mcpwm_info[id]->cfg.ch;
|
||||
MCPWM_TIMERx_REG *timer_reg = mcpwm_get_timerx_reg(ch);
|
||||
MCPWM_CHx_REG *ch_reg = mcpwm_get_chx_reg(ch);
|
||||
|
||||
u16 ch_cmph = 0;
|
||||
u16 ch_cmpl = 0;
|
||||
u16 tmr_cnt = 0;
|
||||
u16 tmr_con = timer_reg->tmr_con;
|
||||
u16 tmr_pr = timer_reg->tmr_pr;
|
||||
asm("csync");
|
||||
|
||||
ch_cmpl = tmr_pr * duty / 10000;
|
||||
/* printf("---%d---%d---%d\n", ch_cmpl, tmr_pr, duty); */
|
||||
ch_cmph = ch_cmpl;
|
||||
tmr_cnt = 0;
|
||||
/* tmr_con |= 0b01; */
|
||||
/* if (duty == 10000) { */
|
||||
/* tmr_cnt = 0; */
|
||||
/* tmr_con &= ~(0b11); */
|
||||
/* } else if (duty == 0) { */
|
||||
/* tmr_cnt = ch_cmpl; */
|
||||
/* tmr_con &= ~(0b11); */
|
||||
/* } */
|
||||
|
||||
spin_lock(&mcpwm_lock);
|
||||
ch_reg->ch_cmph = ch_cmph;
|
||||
ch_reg->ch_cmpl = ch_cmpl;
|
||||
u32 mcpwm_con = JL_MCPWM->MCPWM_CON0;
|
||||
JL_MCPWM->MCPWM_CON0 |= BIT(MCPWM_CON_CLK_EN);
|
||||
timer_reg->tmr_cnt = tmr_cnt;
|
||||
timer_reg->tmr_con = tmr_con;
|
||||
JL_MCPWM->MCPWM_CON0 = mcpwm_con;
|
||||
spin_unlock(&mcpwm_lock);
|
||||
}
|
||||
|
||||
void mcpwm_fpnd_clr(u32 ch)
|
||||
{
|
||||
MCPWM_CHx_REG *ch_reg = mcpwm_get_chx_reg(ch);
|
||||
|
||||
u32 mcpwm_con = JL_MCPWM->MCPWM_CON0;
|
||||
u16 ch_con1 = ch_reg->ch_con1;
|
||||
asm("csync");
|
||||
mcpwm_con |= BIT(MCPWM_CON_CLK_EN);
|
||||
mcpwm_con |= BIT(ch + MCPWM_CON_TMR_EN);
|
||||
mcpwm_con |= BIT(ch + MCPWM_CON_PWM_EN);
|
||||
ch_con1 |= BIT(MCPWM_CH_FCLR) | BIT(MCPWM_CH_INTEN);
|
||||
spin_lock(&mcpwm_lock);
|
||||
JL_MCPWM->MCPWM_CON0 = mcpwm_con;
|
||||
ch_reg->ch_con1 = ch_con1;
|
||||
spin_unlock(&mcpwm_lock);
|
||||
}
|
||||
|
||||
#include "asm/power_interface.h"
|
||||
static u16 mcpwm_con_en AT_VOLATILE_RAM_BSS_LOWPOWER;
|
||||
static void mcpwm_enter_deepsleep(void)
|
||||
{
|
||||
mcpwm_con_en = 0;
|
||||
for (u8 id = 0; id < MCPWM_NUM_MAX; id++) {
|
||||
if (mcpwm_info[id] != NULL) {
|
||||
u32 ch = (u32)mcpwm_info[id]->cfg.ch;
|
||||
if (JL_MCPWM->MCPWM_CON0 & BIT(ch + MCPWM_CON_TMR_EN)) {
|
||||
mcpwm_con_en |= BIT(ch + MCPWM_CON_TMR_EN);
|
||||
}
|
||||
if (JL_MCPWM->MCPWM_CON0 & BIT(ch + MCPWM_CON_PWM_EN)) {
|
||||
mcpwm_con_en |= BIT(ch + MCPWM_CON_PWM_EN);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
static void mcpwm_post_deepsleep(void)
|
||||
{
|
||||
for (u8 id = 0; id < MCPWM_NUM_MAX; id++) {
|
||||
if (mcpwm_info[id] != NULL) {
|
||||
u32 ch = (u32)mcpwm_info[id]->cfg.ch;
|
||||
if ((mcpwm_con_en & BIT(ch + MCPWM_CON_TMR_EN)) && (mcpwm_con_en & BIT(ch + MCPWM_CON_PWM_EN))) {
|
||||
mcpwm_start(id);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
DEEPSLEEP_TARGET_REGISTER(mcpwm) = {
|
||||
.name = "mcpwm",
|
||||
.enter = (void *)mcpwm_enter_deepsleep,
|
||||
.post = (void *)mcpwm_post_deepsleep,
|
||||
};
|
||||
|
||||
#if 0
|
||||
static void usr_mcpwm_detect_test_func(u32 ch)
|
||||
{
|
||||
mcpwm_debug("usr ch %d\n", ch);
|
||||
mcpwm_fpnd_clr(ch); //检测到故障,手动清PND恢复
|
||||
}
|
||||
void mcpwm_test(void)
|
||||
{
|
||||
#define PWM_CH0_ENABLE 1
|
||||
#define PWM_CH1_ENABLE 0
|
||||
|
||||
struct mcpwm_config usr_mcpwm_cfg;
|
||||
|
||||
#if PWM_CH0_ENABLE
|
||||
usr_mcpwm_cfg.ch = MCPWM_CH0; //通道号
|
||||
usr_mcpwm_cfg.aligned_mode = MCPWM_EDGE_ALIGNED; //边沿对齐
|
||||
usr_mcpwm_cfg.frequency = 1000; //1KHz
|
||||
usr_mcpwm_cfg.duty = 0; //占空比50%
|
||||
usr_mcpwm_cfg.h_pin = IO_PORTC_08; //任意引脚
|
||||
usr_mcpwm_cfg.l_pin = IO_PORTC_09; //任意引脚,不需要就填-1
|
||||
usr_mcpwm_cfg.complementary_en = 0; //两个引脚的波形, 0: 同步, 1: 互补,互补波形的占空比体现在H引脚上
|
||||
usr_mcpwm_cfg.detect_port = IO_PORTC_02; //任意引脚,不需要就填-1
|
||||
usr_mcpwm_cfg.edge = MCPWM_EDGE_FAILL;
|
||||
usr_mcpwm_cfg.irq_cb = usr_mcpwm_detect_test_func;
|
||||
usr_mcpwm_cfg.irq_priority = 1; //优先级默认为1
|
||||
int ch0_id0 = mcpwm_init(&usr_mcpwm_cfg);
|
||||
|
||||
usr_mcpwm_cfg.ch = MCPWM_CH0; //通道号
|
||||
usr_mcpwm_cfg.aligned_mode = MCPWM_EDGE_ALIGNED; //边沿对齐
|
||||
usr_mcpwm_cfg.frequency = 1000; //1KHz
|
||||
usr_mcpwm_cfg.duty = 5000; //占空比50%
|
||||
usr_mcpwm_cfg.h_pin = IO_PORTC_00; //任意引脚
|
||||
usr_mcpwm_cfg.l_pin = IO_PORTC_01; //任意引脚,不需要就填-1
|
||||
usr_mcpwm_cfg.complementary_en = 1; //两个引脚的波形, 0: 同步, 1: 互补,互补波形的占空比体现在H引脚上
|
||||
usr_mcpwm_cfg.detect_port = IO_PORTC_02; //任意引脚,不需要就填-1
|
||||
usr_mcpwm_cfg.irq_cb = NULL;
|
||||
usr_mcpwm_cfg.irq_priority = 1; //优先级默认为1
|
||||
int ch0_id1 = mcpwm_init(&usr_mcpwm_cfg);
|
||||
#endif
|
||||
#if PWM_CH1_ENABLE
|
||||
usr_mcpwm_cfg.ch = MCPWM_CH1; //通道号
|
||||
usr_mcpwm_cfg.aligned_mode = MCPWM_EDGE_ALIGNED; //边沿对齐
|
||||
usr_mcpwm_cfg.frequency = 2000; //1KHz
|
||||
usr_mcpwm_cfg.duty = 5000; //占空比50%
|
||||
usr_mcpwm_cfg.h_pin = IO_PORTC_03; //任意引脚
|
||||
usr_mcpwm_cfg.l_pin = IO_PORTC_04; //任意引脚,不需要就填-1
|
||||
usr_mcpwm_cfg.complementary_en = 1; //两个引脚的波形, 0: 同步, 1: 互补,互补波形的占空比体现在H引脚上
|
||||
usr_mcpwm_cfg.detect_port = IO_PORTC_05; //任意引脚,不需要就填-1
|
||||
usr_mcpwm_cfg.edge = MCPWM_EDGE_FAILL;
|
||||
usr_mcpwm_cfg.irq_cb = usr_mcpwm_detect_test_func;
|
||||
usr_mcpwm_cfg.irq_priority = 1; //优先级默认为1
|
||||
int ch1_id0 = mcpwm_init(&usr_mcpwm_cfg);
|
||||
#endif
|
||||
|
||||
mcpwm_start(ch0_id0);
|
||||
mcpwm_start(ch1_id0);
|
||||
/* mcpwm_start(ch1_id0); */
|
||||
/* extern void wdt_clear(); */
|
||||
u32 duty = 0;
|
||||
JL_PORTC->DIR &= ~BIT(7);
|
||||
while (1) {
|
||||
mdelay(1000);
|
||||
JL_PORTC->OUT ^= BIT(7);
|
||||
mcpwm_set_duty(ch0_id0, duty);
|
||||
if (duty == 0) {
|
||||
duty = 10000;
|
||||
} else {
|
||||
duty = 0;
|
||||
}
|
||||
wdt_clear();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,457 @@
|
||||
#include "system/includes.h"
|
||||
#include "asm/power_interface.h"
|
||||
#include "asm/lpctmu_hw.h"
|
||||
#include "asm/charge.h"
|
||||
#include "app_charge.h"
|
||||
#include "gpadc.h"
|
||||
#include "app_config.h"
|
||||
|
||||
#if TCFG_LPCTMU_ENABLE
|
||||
|
||||
#if 1
|
||||
|
||||
#define LOG_TAG_CONST LP_KEY
|
||||
#define LOG_TAG "[LP_KEY]"
|
||||
/* #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
|
||||
|
||||
|
||||
|
||||
static const u8 ch_port[LPCTMU_CHANNEL_SIZE] = {
|
||||
IO_PORTB_00,
|
||||
IO_PORTB_01,
|
||||
IO_PORTB_02,
|
||||
IO_PORTB_03,
|
||||
IO_PORTB_04,
|
||||
};
|
||||
|
||||
static struct lpctmu_config_data *__this = NULL;
|
||||
static u8 lpctmu_timer_cmd;
|
||||
|
||||
|
||||
void lpctmu_send_m2p_cmd(enum CTMU_M2P_CMD cmd)
|
||||
{
|
||||
P2M_CTMU_CMD_ACK = 0;
|
||||
M2P_CTMU_CMD = cmd;
|
||||
P11_SYSTEM->M2P_INT_SET = BIT(M2P_CTMU_INDEX);
|
||||
while (!(P2M_CTMU_CMD_ACK));
|
||||
}
|
||||
|
||||
|
||||
u32 lpctmu_get_cur_ch_by_idx(u32 ch_idx)
|
||||
{
|
||||
ch_idx %= __this->ch_num;
|
||||
return __this->ch_list[ch_idx];
|
||||
}
|
||||
|
||||
u32 lpctmu_get_idx_by_cur_ch(u32 cur_ch)
|
||||
{
|
||||
for (u32 ch_idx = 0; ch_idx < __this->ch_num; ch_idx ++) {
|
||||
if (cur_ch == __this->ch_list[ch_idx]) {
|
||||
return ch_idx;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
u32 lpctmu_get_cur_ch_res(u32 cur_ch)
|
||||
{
|
||||
u32 res = 0;
|
||||
res = (P2M_MESSAGE_ACCESS(P2M_MASSAGE_CTMU_CH0_H_RES + cur_ch * 2)) << 8;
|
||||
res |= (P2M_MESSAGE_ACCESS(P2M_MASSAGE_CTMU_CH0_L_RES + cur_ch * 2)) << 0;
|
||||
return res;
|
||||
}
|
||||
|
||||
void lpctmu_port_init(u32 ch)
|
||||
{
|
||||
u8 port = ch_port[ch];
|
||||
gpio_set_mode(port / 16, BIT(port % 16), PORT_HIGHZ);
|
||||
SFR(P11_PORT->PB_SEL, ch, 1, 1);
|
||||
SFR(P11_PORT->PB_DIR, ch, 1, 1);
|
||||
SFR(P11_PORT->PB_DIE, ch, 1, 0);
|
||||
SFR(P11_PORT->PB_PU0, ch, 1, 0);
|
||||
SFR(P11_PORT->PB_PU1, ch, 1, 0);
|
||||
SFR(P11_PORT->PB_PD0, ch, 1, 0);
|
||||
SFR(P11_PORT->PB_PD1, ch, 1, 0);
|
||||
}
|
||||
|
||||
|
||||
void lpctmu_set_ana_hv_level(u32 level)
|
||||
{
|
||||
SFR(P11_LPCTM0->ANA0, 5, 3, level & 0b111);
|
||||
}
|
||||
|
||||
u32 lpctmu_get_ana_hv_level(void)
|
||||
{
|
||||
u32 level = (P11_LPCTM0->ANA0 >> 5) & 0b111;
|
||||
return level;
|
||||
}
|
||||
|
||||
void lpctmu_vsel_trim(void)
|
||||
{
|
||||
if (__this->pdata->aim_vol_delta < 8) {
|
||||
lpctmu_set_ana_hv_level(__this->pdata->aim_vol_delta);
|
||||
SFR(P11_LPCTM0->ANA1, 0, 2, 0b00);//关闭HV/LV
|
||||
log_debug("hv_level = %d", __this->pdata->aim_vol_delta);
|
||||
return;
|
||||
}
|
||||
SFR(P11_LPCTM0->ANA1, 0, 2, 0b01);//先使能LV
|
||||
u32 lv_vol = adc_get_voltage_blocking(AD_CH_LPCTMU); //阻塞式采集一个指定通道的电压值(经过均值滤波处理)
|
||||
log_debug("lv_vol = %dmv", lv_vol);
|
||||
|
||||
SFR(P11_LPCTM0->ANA1, 0, 2, 0b10);//再使能HV
|
||||
u32 delta, diff, diff_min = -1;
|
||||
u8 aim_hv_level = 7;
|
||||
for (u8 hv_level = 0; hv_level < 8; hv_level ++) {
|
||||
lpctmu_set_ana_hv_level(hv_level);
|
||||
u32 hv_vol = adc_get_voltage_blocking(AD_CH_LPCTMU); //阻塞式采集一个指定通道的电压值(经过均值滤波处理)
|
||||
log_debug("hv_vol = %dmv", hv_vol);
|
||||
if (hv_vol > lv_vol) {
|
||||
delta = hv_vol - lv_vol;
|
||||
} else {
|
||||
delta = lv_vol - hv_vol;
|
||||
}
|
||||
if (delta > __this->pdata->aim_vol_delta) {
|
||||
diff = delta - __this->pdata->aim_vol_delta;
|
||||
} else {
|
||||
diff = __this->pdata->aim_vol_delta - delta;
|
||||
}
|
||||
if (diff_min >= diff) {
|
||||
diff_min = diff;
|
||||
aim_hv_level = hv_level;
|
||||
}
|
||||
}
|
||||
log_debug("hv_level = %d diff %d", aim_hv_level, diff_min);
|
||||
lpctmu_set_ana_hv_level(aim_hv_level);
|
||||
SFR(P11_LPCTM0->ANA1, 0, 2, 0b00);//关闭HV/LV
|
||||
}
|
||||
|
||||
u32 lpctmu_get_charge_clk(void)
|
||||
{
|
||||
#if 0
|
||||
|
||||
JL_GPCNT0->CON = BIT(30);
|
||||
|
||||
SFR(P11_PORT->OCH_CON0, 8, 4, 9);//p11 output_ch2 sel lpctmu_test
|
||||
|
||||
SFR(JL_GPCNT0->CON, 1, 5, 17);//次时钟选择p11_dbg_out
|
||||
|
||||
SFR(JL_GPCNT0->CON, 16, 4, 8); //主时钟周期数:32 * 2^n = 8192
|
||||
SFR(JL_GPCNT0->CON, 8, 5, 15); //主时钟选择std24m
|
||||
|
||||
JL_GPCNT0->CON |= BIT(30) | BIT(0);
|
||||
|
||||
while (!(JL_GPCNT0->CON & BIT(31)));
|
||||
u32 gpcnt_num = JL_GPCNT0->NUM;
|
||||
JL_GPCNT0->CON &= ~BIT(0);
|
||||
|
||||
u32 std24m_clk_khz = 24000;
|
||||
u32 charge_clk = std24m_clk_khz * gpcnt_num / 8192;
|
||||
log_debug("gpcnt_num = %d charge_clk = %dKHz\n", gpcnt_num, charge_clk);
|
||||
|
||||
#else
|
||||
|
||||
P11_LPCTM0->WCON |= BIT(6); //clear pend
|
||||
P11_LPCTM0->WCON |= BIT(0); //kick
|
||||
while (!(P11_LPCTM0->CON0 & BIT(7)));//wait pend
|
||||
P11_LPCTM0->WCON |= BIT(6); //clear pend
|
||||
u32 res = (P11_LPCTM0->RES & 0xffffff);
|
||||
u32 charge_clk = res / __this->pdata->sample_window_time;
|
||||
log_debug("lpctmu_res = %d charge_clk = %dKHz\n", res, charge_clk);
|
||||
|
||||
#endif
|
||||
|
||||
return charge_clk;
|
||||
}
|
||||
|
||||
void lpctmu_set_ana_cur_level(u32 ch, u32 cur_level)
|
||||
{
|
||||
SFR(P11_LPCTM0->CHIS, ch * 4, 3, cur_level);
|
||||
}
|
||||
|
||||
u32 lpctmu_get_ana_cur_level(u32 ch)
|
||||
{
|
||||
u32 level = (P11_LPCTM0->CHIS >> (ch * 4)) & 0b111;
|
||||
return level;
|
||||
}
|
||||
|
||||
void lpctmu_isel_trim(u8 ch)
|
||||
{
|
||||
SFR(P11_LPCTM0->ANA1, 4, 4, ch + 1);//使能对应通道
|
||||
|
||||
u32 diff, diff_min = -1;
|
||||
u8 aim_cur_level = 7;
|
||||
if (__this->pdata->aim_charge_khz < 8) {
|
||||
aim_cur_level = __this->pdata->aim_charge_khz;
|
||||
} else {
|
||||
for (u8 cur_level = 0; cur_level < 8; cur_level ++) {
|
||||
SFR(P11_LPCTM0->ANA0, 1, 3, cur_level);
|
||||
lpctmu_set_ana_cur_level(ch, cur_level);
|
||||
u32 charge_clk = lpctmu_get_charge_clk();
|
||||
if (charge_clk > __this->pdata->aim_charge_khz) {
|
||||
diff = charge_clk - __this->pdata->aim_charge_khz;
|
||||
} else {
|
||||
diff = __this->pdata->aim_charge_khz - charge_clk;
|
||||
}
|
||||
if (diff_min >= diff) {
|
||||
diff_min = diff;
|
||||
aim_cur_level = cur_level;
|
||||
}
|
||||
}
|
||||
}
|
||||
log_debug("ch%d cur_level = %d diff %d", ch, aim_cur_level, diff_min);
|
||||
SFR(P11_LPCTM0->ANA0, 1, 3, aim_cur_level);
|
||||
lpctmu_set_ana_cur_level(ch, aim_cur_level);
|
||||
}
|
||||
|
||||
void lpctmu_vsel_isel_trim(void)
|
||||
{
|
||||
SFR(P11_LPCTM0->ANA1, 3, 1, 1);//软件控制
|
||||
SFR(P11_LPCTM0->ANA1, 2, 1, 1);//模拟模块偏置使能
|
||||
SFR(P11_LPCTM0->ANA0, 0, 1, 1);//模拟模块使能
|
||||
SFR(P11_LPCTM0->ANA1, 4, 4, 0);//先不使能任何通道
|
||||
|
||||
lpctmu_vsel_trim();
|
||||
|
||||
for (u32 ch_idx = 0; ch_idx < __this->ch_num; ch_idx ++) {
|
||||
lpctmu_isel_trim(__this->ch_list[ch_idx]);
|
||||
}
|
||||
}
|
||||
|
||||
void lpctmu_lptimer_disable(void)
|
||||
{
|
||||
lpctmu_timer_cmd = REQUEST_LPCTMU_TIMER_DEL;
|
||||
lpctmu_send_m2p_cmd(lpctmu_timer_cmd);
|
||||
}
|
||||
|
||||
void lpctmu_lptimer_enable(void)
|
||||
{
|
||||
lpctmu_timer_cmd = REQUEST_LPCTMU_TIMER_ADD;
|
||||
lpctmu_send_m2p_cmd(lpctmu_timer_cmd);
|
||||
}
|
||||
|
||||
u32 lpctmu_lptimer_is_working(void)
|
||||
{
|
||||
if (lpctmu_timer_cmd == REQUEST_LPCTMU_TIMER_ADD) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void lpctmu_lptimer_init(u32 scan_time)
|
||||
{
|
||||
lpctmu_lptimer_enable();
|
||||
}
|
||||
|
||||
void lpctmu_dump(void)
|
||||
{
|
||||
log_debug("P11_LPCTM0->CON0 = 0x%x", P11_LPCTM0->CON0);
|
||||
log_debug("P11_LPCTM0->CHEN = 0x%x", P11_LPCTM0->CHEN);
|
||||
log_debug("P11_LPCTM0->CNUM = 0x%x", P11_LPCTM0->CNUM);
|
||||
log_debug("P11_LPCTM0->PPRD = 0x%x", P11_LPCTM0->PPRD);
|
||||
log_debug("P11_LPCTM0->DPRD = 0x%x", P11_LPCTM0->DPRD);
|
||||
log_debug("P11_LPCTM0->ECON = 0x%x", P11_LPCTM0->ECON);
|
||||
log_debug("P11_LPCTM0->EXEN = 0x%x", P11_LPCTM0->EXEN);
|
||||
log_debug("P11_LPCTM0->CHIS = 0x%x", P11_LPCTM0->CHIS);
|
||||
log_debug("P11_LPCTM0->CLKC = 0x%x", P11_LPCTM0->CLKC);
|
||||
log_debug("P11_LPCTM0->WCON = 0x%x", P11_LPCTM0->WCON);
|
||||
log_debug("P11_LPCTM0->ANA0 = 0x%x", P11_LPCTM0->ANA0);
|
||||
log_debug("P11_LPCTM0->ANA1 = 0x%x", P11_LPCTM0->ANA1);
|
||||
log_debug("P11_LPCTM0->RES = %d", P11_LPCTM0->RES);
|
||||
log_debug("P11_LPCTM0->DMA_START_ADR = %d", P11_LPCTM0->DMA_START_ADR);
|
||||
log_debug("P11_LPCTM0->DMA_HALF_ADR = %d", P11_LPCTM0->DMA_HALF_ADR);
|
||||
log_debug("P11_LPCTM0->DMA_END_ADR = %d", P11_LPCTM0->DMA_END_ADR);
|
||||
log_debug("P11_LPCTM0->DMA_CON = 0x%x", P11_LPCTM0->DMA_CON);
|
||||
log_debug("P11_LPCTM0->MSG_CON = 0x%x", P11_LPCTM0->MSG_CON);
|
||||
log_debug("P11_LPCTM0->DMA_WADR = 0x%x", P11_LPCTM0->DMA_WADR);
|
||||
log_debug("P11_LPCTM0->SLEEP_CON = 0x%x", P11_LPCTM0->SLEEP_CON);
|
||||
}
|
||||
|
||||
void lpctmu_init(struct lpctmu_config_data *cfg_data)
|
||||
{
|
||||
printf("%s() : %d\n", __func__, __LINE__);
|
||||
|
||||
__this = cfg_data;
|
||||
if (!__this) {
|
||||
return;
|
||||
}
|
||||
|
||||
__this->ch_num = 0;
|
||||
__this->ch_wkp_en = 0;
|
||||
__this->softoff_wakeup_cfg = 0;
|
||||
|
||||
for (u32 ch = 0; ch < LPCTMU_CHANNEL_SIZE; ch ++) {
|
||||
if (__this->ch_en & BIT(ch)) {
|
||||
__this->ch_list[__this->ch_num] = ch;
|
||||
__this->ch_num ++;
|
||||
}
|
||||
}
|
||||
|
||||
for (u32 ch_idx = 0; ch_idx < __this->ch_num; ch_idx ++) {
|
||||
lpctmu_port_init(__this->ch_list[ch_idx]);
|
||||
}
|
||||
|
||||
M2P_CTMU_CH_ENABLE = __this->ch_en;
|
||||
M2P_CTMU_CH_WAKEUP_EN = __this->ch_wkp_en;
|
||||
M2P_CTMU_SCAN_TIME = __this->pdata->sample_scan_time;
|
||||
M2P_CTMU_LOWPOER_SCAN_TIME = __this->pdata->lowpower_sample_scan_time;
|
||||
|
||||
if (!is_wakeup_source(PWR_WK_REASON_P11)) {
|
||||
|
||||
memset(P11_LPCTM0, 0, sizeof(P11_LPCTM_TypeDef));
|
||||
|
||||
lpctmu_send_m2p_cmd(REQUEST_LPCTMU_IRQ);
|
||||
|
||||
//时钟源配置
|
||||
u32 lpctmu_clk = clk_get("lrc");
|
||||
log_debug("lpctmu_clk = %dHz", lpctmu_clk);
|
||||
SFR(P11_LPCTM0->CLKC, 0, 2, 0); //ctm_clk_p sel lrc200KHz
|
||||
//设置分频
|
||||
SFR(P11_LPCTM0->CLKC, 6, 1, 0); //divB = 1分频
|
||||
SFR(P11_LPCTM0->CLKC, 7, 1, 0); //divC = 1分频
|
||||
SFR(P11_LPCTM0->CLKC, 3, 3, 2); //div = 2^2 = 4分频
|
||||
/**********************/
|
||||
//通道采集前的待稳定时间配置
|
||||
SFR(P11_LPCTM0->PPRD, 4, 4, 9); //prp_prd = (9 + 1) * t 约等 50us > 10us
|
||||
//多通道轮询采集, 切通道时, 通道与通道的间隙时间配置
|
||||
SFR(P11_LPCTM0->PPRD, 0, 4, 9); //stop_prd= (9 + 1) * t 约等 50us > 10us
|
||||
|
||||
//每个通道采集的周期,常设几个毫秒
|
||||
u8 det_prd = __this->pdata->sample_window_time * lpctmu_clk / 4 / 1000 - 1;
|
||||
SFR(P11_LPCTM0->DPRD, 0, 8, det_prd);
|
||||
|
||||
SFR(P11_LPCTM0->CON0, 2, 1, 1); //LPCTM WKUP en
|
||||
SFR(P11_LPCTM0->CON0, 4, 1, 1); //模拟滤波使能
|
||||
SFR(P11_LPCTM0->CON0, 1, 1, 0); //模块的中断不使能
|
||||
SFR(P11_LPCTM0->CON0, 0, 1, 1); //模块总开关
|
||||
|
||||
lpctmu_vsel_isel_trim();
|
||||
|
||||
SFR(P11_LPCTM0->ANA0, 0, 1, 0);
|
||||
SFR(P11_LPCTM0->ANA1, 3, 1, 0);
|
||||
SFR(P11_LPCTM0->ANA1, 2, 1, 0);
|
||||
|
||||
SFR(P11_LPCTM0->CHEN, 0, 5, __this->ch_en);
|
||||
|
||||
if (__this->pdata->ext_stop_ch_en) {
|
||||
SFR(P11_LPCTM0->EXEN, 0, 5, __this->pdata->ext_stop_ch_en);
|
||||
SFR(P11_LPCTM0->ECON, 2, 2, __this->pdata->ext_stop_sel);
|
||||
SFR(P11_LPCTM0->ECON, 0, 1, 1);//与蓝牙的互斥使能
|
||||
|
||||
extern void set_bt_wl_rab_wl2ext(u8 wl2ext_act0, u8 wl2ext_act1);
|
||||
set_bt_wl_rab_wl2ext(RF_TX_LDO, RF_TX_EN);
|
||||
}
|
||||
|
||||
SFR(P11_LPCTM0->WCON, 6, 1, 1); //clear pnd
|
||||
SFR(P11_LPCTM0->CON0, 0, 1, 0); //模块先关闭
|
||||
SFR(P11_LPCTM0->CON0, 1, 1, 1); //模块的RES中断使能
|
||||
|
||||
}
|
||||
|
||||
lpctmu_lptimer_init(__this->pdata->sample_scan_time);
|
||||
|
||||
lpctmu_dump();
|
||||
}
|
||||
|
||||
void lpctmu_disable(void)
|
||||
{
|
||||
lpctmu_lptimer_disable();
|
||||
}
|
||||
|
||||
void lpctmu_enable(void)
|
||||
{
|
||||
lpctmu_lptimer_enable();
|
||||
}
|
||||
|
||||
static int lpctmu_charge_msg_handler(int msg, int type)
|
||||
{
|
||||
switch (msg) {
|
||||
case CHARGE_EVENT_LDO5V_IN:
|
||||
lpctmu_disable();
|
||||
break;
|
||||
case CHARGE_EVENT_CHARGE_FULL:
|
||||
case CHARGE_EVENT_LDO5V_KEEP:
|
||||
case CHARGE_EVENT_LDO5V_OFF:
|
||||
lpctmu_enable();
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
APP_CHARGE_HANDLER(lpctmu_charge_msg_entry, 0) = {
|
||||
.handler = lpctmu_charge_msg_handler,
|
||||
};
|
||||
|
||||
|
||||
u32 lpctmu_is_sf_keep(void)
|
||||
{
|
||||
/* extern void pvdd_output(u32 output); */
|
||||
/* pvdd_output(1); */
|
||||
if (!__this) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
u32 lpctmu_softoff_keep_work;
|
||||
|
||||
if (lpctmu_lptimer_is_working()) {
|
||||
|
||||
switch (__this->softoff_wakeup_cfg) {
|
||||
case LPCTMU_WAKEUP_DISABLE:
|
||||
lpctmu_softoff_keep_work = 0;
|
||||
break;
|
||||
case LPCTMU_WAKEUP_EN_WITHOUT_CHARGE_ONLINE:
|
||||
lpctmu_softoff_keep_work = 1;
|
||||
if (get_charge_online_flag()) {
|
||||
lpctmu_softoff_keep_work = 0;
|
||||
}
|
||||
break;
|
||||
case LPCTMU_WAKEUP_EN_ALWAYS:
|
||||
lpctmu_softoff_keep_work = 1;
|
||||
break;
|
||||
default :
|
||||
lpctmu_softoff_keep_work = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
if (lpctmu_softoff_keep_work == 0) {
|
||||
lpctmu_disable();
|
||||
return 0;
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
* SDK 测试函数
|
||||
**************************************************************************/
|
||||
void lpctmu_res_deal(void *priv)
|
||||
{
|
||||
u32 res = lpctmu_get_cur_ch_res(1);
|
||||
|
||||
printf("res = %d\n", res);
|
||||
}
|
||||
|
||||
void lpctmu_test(void)
|
||||
{
|
||||
sys_timer_add(NULL, lpctmu_res_deal, 20);
|
||||
}
|
||||
|
||||
#else /* #if TCFG_LPCTMU_ENABLE */
|
||||
|
||||
u32 lpctmu_is_sf_keep(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* #if TCFG_LPCTMU_ENABLE */
|
||||
|
||||
Reference in New Issue
Block a user