369 lines
11 KiB
C
369 lines
11 KiB
C
/*================================================================
|
|
Copyright (c) 2022, Quectel Wireless Solutions Co., Ltd. All rights reserved.
|
|
Quectel Wireless Solutions Proprietary and Confidential.
|
|
=================================================================*/
|
|
|
|
/*=================================================================
|
|
|
|
EDIT HISTORY FOR MODULE
|
|
|
|
This section contains comments describing changes made to the module.
|
|
Notice that changes are listed in reverse chronological order.
|
|
|
|
WHEN WHO WHAT, WHERE, WHY
|
|
------------ ------- -------------------------------------------------------------------------------
|
|
19/04/2022 Fias.fan Added PWM interface
|
|
=================================================================*/
|
|
|
|
|
|
#include "quec_pwm.h"
|
|
#include "utlTimer.h"
|
|
//#include "quec_atcmd_network.h"
|
|
#include "quec_rtos.h"
|
|
#include "quec_gpio.h"
|
|
#include "gpio.h"
|
|
#include "bsp.h"
|
|
#if defined QUEC_PWM_ENBALE
|
|
|
|
#ifndef MIN_SYS
|
|
|
|
|
|
#if defined QUEC_PWM_LOG_ENABLE
|
|
#define pwm_log(msg, ...) custom_log("PWM", msg, ##__VA_ARGS__)
|
|
#else
|
|
#define pwm_log(msg, ...)
|
|
#endif
|
|
|
|
|
|
|
|
#define PWM_PSCLK (13000000) // 13 MHz
|
|
#define PWM_PSCLK_32K (32000) //32KHz
|
|
|
|
#define PWM_MAX_FREQ (PWM_PSCLK)
|
|
|
|
#define PWM_SD_POS (6)
|
|
#define PWM_FD_POS (10)
|
|
|
|
#define PWM_FREQ_MASK (0x3f)
|
|
#define PWM_DUTY_CYCLE_MASK (0x3ff)
|
|
#define PWM_PERIOD_MASK (0x3ff)
|
|
|
|
#define PWM_0_START_ADDRESS (0xD401A000)
|
|
#define PWM_1_START_ADDRESS (0xD401A400)
|
|
#define PWM_2_START_ADDRESS (0xD401A800)
|
|
#define PWM_3_START_ADDRESS (0xD401AC00)
|
|
|
|
#define APBC_PWM0_CLK_RST (0xD401500C)
|
|
#define APBC_PWM1_CLK_RST (0xD4015010)
|
|
#define APBC_PWM2_CLK_RST (0xD4015014)
|
|
#define APBC_PWM3_CLK_RST (0xD4015018)
|
|
|
|
#define PWM_RST_BIT 0x4
|
|
#define PWM_FUNC_CLK_EN_BIT 0x2
|
|
#define PWM_APB_CLK_EN_BIT 0x1
|
|
|
|
|
|
#define pwm_reg_read(reg) *(volatile unsigned int *)(reg)
|
|
#define pwm_reg_write(reg, val) *(volatile unsigned int *)(reg) = (val);
|
|
#define pwm_reg_bit_set(reg, val) *(volatile unsigned int *)(reg) |= (val);
|
|
#define pwm_reg_bit_clr(reg, val) *(volatile unsigned int *)(reg) &= ~(val);
|
|
|
|
|
|
static volatile QUEC_PWM_REGISTERED_T *pwm_register[QUEC_PWM_MAX_DEVICE] =
|
|
{
|
|
(volatile QUEC_PWM_REGISTERED_T *)(PWM_0_START_ADDRESS),
|
|
(volatile QUEC_PWM_REGISTERED_T *)(PWM_1_START_ADDRESS),
|
|
(volatile QUEC_PWM_REGISTERED_T *)(PWM_2_START_ADDRESS),
|
|
(volatile QUEC_PWM_REGISTERED_T *)(PWM_3_START_ADDRESS)
|
|
};
|
|
|
|
static unsigned long pwm_apb_register[QUEC_PWM_MAX_DEVICE] =
|
|
{
|
|
(APBC_PWM0_CLK_RST),
|
|
(APBC_PWM1_CLK_RST),
|
|
(APBC_PWM2_CLK_RST),
|
|
(APBC_PWM3_CLK_RST)
|
|
};
|
|
|
|
struct QUEC_PWM_MAP_GPIO_S gpio_map_pwm_table[] =
|
|
{
|
|
{117, 0, 2},
|
|
{32, 1, 2},
|
|
{10, 2, 3},
|
|
{11, 3, 3},
|
|
#ifdef __QUECTEL_PROJECT_EG800WCN_11LG__
|
|
{6, 2, 5},
|
|
#else
|
|
{6, 2, 3},
|
|
#endif
|
|
#ifdef __QUECTEL_PROJECT_EG800PCN_LA__
|
|
{8, 2, 1},
|
|
#else
|
|
{8, 0, 1},
|
|
#endif
|
|
#ifdef __QUECTEL_PROJECT_EG800WCN_11LG__
|
|
{7, 3, 5},
|
|
{9, 3, 3},
|
|
#else
|
|
{7, 3, 3},
|
|
#endif
|
|
{69, 0, 1},
|
|
{70, 1, 1},
|
|
{89, 2, 2},
|
|
{29, 0, 1},
|
|
{56, 1, 2},
|
|
{58, 3, 2},
|
|
};
|
|
|
|
extern void Delay(unsigned long uSec);
|
|
|
|
void quec_pwm_apb_bus_clk_enable(QUEC_PWM_DEVICE_NUM_E pwm_num)
|
|
{
|
|
if(IsChipCraneLRH() || IsChipCraneLG())
|
|
{
|
|
pwm_reg_bit_clr(pwm_apb_register[pwm_num],PWM_RST_BIT);
|
|
pwm_reg_bit_set(pwm_apb_register[pwm_num],PWM_APB_CLK_EN_BIT);
|
|
//CPUartLogPrintf("%s,addr=%x,,reg=%x",__func__,pwm_apb_register[pwm_num],pwm_reg_read(pwm_apb_register[pwm_num]));
|
|
}
|
|
else
|
|
{
|
|
if(pwm_num <= QUEC_PWM_DEVICE_1)
|
|
{
|
|
pwm_reg_bit_clr(pwm_apb_register[QUEC_PWM_DEVICE_0],PWM_RST_BIT);
|
|
pwm_reg_bit_set(pwm_apb_register[QUEC_PWM_DEVICE_0],PWM_APB_CLK_EN_BIT);
|
|
//CPUartLogPrintf("%s,addr=%x,,reg=%x",__func__,pwm_apb_register[QUEC_PWM_DEVICE_0],pwm_reg_read(pwm_apb_register[QUEC_PWM_DEVICE_0]));
|
|
}
|
|
else
|
|
{
|
|
pwm_reg_bit_clr(pwm_apb_register[QUEC_PWM_DEVICE_2],PWM_RST_BIT);
|
|
pwm_reg_bit_set(pwm_apb_register[QUEC_PWM_DEVICE_2],PWM_APB_CLK_EN_BIT);
|
|
//CPUartLogPrintf("%s,addr=%x,,reg=%x",__func__,pwm_apb_register[QUEC_PWM_DEVICE_2],pwm_reg_read(pwm_apb_register[QUEC_PWM_DEVICE_2]));
|
|
}
|
|
}
|
|
}
|
|
|
|
//获取GPIO复用为pwm功能的pwm号
|
|
int quec_gpio_mapto_pwm_device_num(unsigned int gpio_num)
|
|
{
|
|
unsigned int i;
|
|
for(i = 0; i < (sizeof(gpio_map_pwm_table)/sizeof(gpio_map_pwm_table[0])); i++)
|
|
{
|
|
if(gpio_map_pwm_table[i].gpio_num == gpio_num)
|
|
{
|
|
return gpio_map_pwm_table[i].pwm_num;
|
|
}
|
|
}
|
|
return QUEC_PWM_MAX_DEVICE;
|
|
}
|
|
|
|
//获取GPIO复用为pwm功能的fun号
|
|
int quec_pwm_get_gpio_function(unsigned int gpio_num)
|
|
{
|
|
unsigned int i;
|
|
for(i = 0; i < (sizeof(gpio_map_pwm_table)/sizeof(gpio_map_pwm_table[0])); i++)
|
|
{
|
|
if(gpio_map_pwm_table[i].gpio_num == gpio_num)
|
|
{
|
|
return gpio_map_pwm_table[i].gpio_fun;
|
|
}
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
|
|
void quec_pwm_apb_bus_clk_disable(QUEC_PWM_DEVICE_NUM_E pwm_num)
|
|
{
|
|
if(IsChipCraneLRH() || IsChipCraneLG())
|
|
{
|
|
pwm_reg_bit_clr(pwm_apb_register[pwm_num],PWM_APB_CLK_EN_BIT);
|
|
//CPUartLogPrintf("%s,addr=%x,,reg=%x",__func__,pwm_apb_register[pwm_num],pwm_reg_read(pwm_apb_register[pwm_num]));
|
|
}
|
|
else
|
|
{
|
|
if(pwm_num <= QUEC_PWM_DEVICE_1)
|
|
{
|
|
pwm_reg_bit_clr(pwm_apb_register[QUEC_PWM_DEVICE_0],PWM_APB_CLK_EN_BIT);
|
|
//CPUartLogPrintf("%s,addr=%x,,reg=%x",__func__,pwm_apb_register[QUEC_PWM_DEVICE_0],pwm_reg_read(pwm_apb_register[QUEC_PWM_DEVICE_0]));
|
|
}
|
|
else
|
|
{
|
|
pwm_reg_bit_clr(pwm_apb_register[QUEC_PWM_DEVICE_2],PWM_APB_CLK_EN_BIT);
|
|
//CPUartLogPrintf("%s,addr=%x,,reg=%x",__func__,pwm_apb_register[QUEC_PWM_DEVICE_2],pwm_reg_read(pwm_apb_register[QUEC_PWM_DEVICE_2]));
|
|
}
|
|
}
|
|
}
|
|
|
|
int quec_pwm_enable(unsigned int gpio_num)
|
|
{
|
|
|
|
int pwm_num = 0;
|
|
|
|
pwm_num = (QUEC_PWM_DEVICE_NUM_E)quec_gpio_mapto_pwm_device_num(gpio_num);
|
|
if( pwm_num >= QUEC_PWM_MAX_DEVICE )
|
|
{
|
|
return -1;
|
|
}
|
|
//barry 解决宝蓝低功耗pwm无法关闭
|
|
pwm_reg_bit_clr(pwm_apb_register[pwm_num],PWM_RST_BIT);
|
|
|
|
quec_pwm_apb_bus_clk_enable((QUEC_PWM_DEVICE_NUM_E)pwm_num);
|
|
|
|
Delay(1*1000);
|
|
pwm_reg_bit_set(pwm_apb_register[pwm_num],PWM_FUNC_CLK_EN_BIT);
|
|
//pwm_log("%s, addr=%x,,reg=%x",__func__,pwm_apb_register[pwm_num],pwm_reg_read(pwm_apb_register[pwm_num]));
|
|
return 0;
|
|
}
|
|
|
|
int quec_pwm_disable(unsigned int gpio_num)
|
|
{
|
|
int pwm_num = 0;
|
|
|
|
pwm_num = quec_gpio_mapto_pwm_device_num(gpio_num);
|
|
if ( pwm_num >= QUEC_PWM_MAX_DEVICE )
|
|
return -1;
|
|
|
|
/* Warning !!! Using of a Graceful shutdown should be done with a care */
|
|
/* Writing 0 to the SD bit, needs a little delay before turn the clock to off */
|
|
|
|
pwm_reg_bit_clr(pwm_apb_register[pwm_num],PWM_FUNC_CLK_EN_BIT);
|
|
Delay(100*1000);
|
|
quec_pwm_apb_bus_clk_disable((QUEC_PWM_DEVICE_NUM_E)pwm_num);
|
|
//pwm_log("%s, addr=%x,reg=%x",__func__,pwm_apb_register[pwm_num],pwm_reg_read(pwm_apb_register[pwm_num]));
|
|
|
|
return 0;
|
|
|
|
|
|
}
|
|
|
|
int quec_pwm_pinmux_configure(unsigned int gpio_num)
|
|
{
|
|
|
|
int fun = quec_pwm_get_gpio_function(gpio_num);
|
|
if(fun != -1)
|
|
{
|
|
(*(volatile unsigned long *)(GPIO_MFPR_ADDR(gpio_num))) = (0x10c0 | fun);
|
|
|
|
return 0;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
QUEC_PWM_RETURN_CODE_E quec_pwm_configure( QUEC_PWM_DEVICE_NUM_E pwm_num , QUEC_PWM_CONFIG_T *configuration )
|
|
{
|
|
|
|
unsigned short total_cycle;
|
|
unsigned char i;
|
|
|
|
if ( pwm_num >= QUEC_PWM_MAX_DEVICE )
|
|
return QUEC_PWM_RC_ILLEGALL_DEVICE_NUMBER;
|
|
|
|
if( (PWM_PSCLK/configuration->clk_freq ) > PWM_MAX_FREQ )
|
|
return QUEC_PWM_RC_ILLEGALL_FREQUENCY;
|
|
|
|
if ( configuration->high_one_cycle_duration > configuration->total_one_cycle_duration )
|
|
return QUEC_PWM_RC_ILLEGALL_DUTY_CYCLE;
|
|
|
|
|
|
quec_pwm_apb_bus_clk_enable(pwm_num);
|
|
pwm_reg_bit_clr(pwm_apb_register[pwm_num],PWM_RST_BIT); //clear rst bit
|
|
|
|
pwm_reg_bit_clr(pwm_apb_register[pwm_num], 1<< 4); //clr clk src
|
|
pwm_reg_bit_set(pwm_apb_register[pwm_num],configuration->clk_src << 4); //set clk src 32K or 13M
|
|
|
|
pwm_register[pwm_num]->control = ( ( configuration->shutdown << PWM_SD_POS) | (( configuration->clk_freq - 1 ) & PWM_FREQ_MASK ));
|
|
|
|
pwm_register[pwm_num]->duty_cycle = (( configuration->pwm_out << PWM_FD_POS) | (configuration->high_one_cycle_duration & PWM_DUTY_CYCLE_MASK));
|
|
|
|
pwm_register[pwm_num]->period_val = ( configuration->total_one_cycle_duration & PWM_PERIOD_MASK);
|
|
|
|
//pwm_log("%s,control=%x,,duty_cycle=%x,, period_val=%x",__func__,pwm_register[pwm_num]->control,pwm_register[pwm_num]->duty_cycle,pwm_register[pwm_num]->period_val);
|
|
|
|
return QUEC_PWM_RC_OK;
|
|
|
|
}
|
|
|
|
int quec_pwm_config_plus_ex(unsigned int gpio_num,QL_PWM_CONFIG_EX *pwm_parameter)
|
|
{
|
|
int ret = 0;
|
|
int pwm_num = 0;
|
|
|
|
QUEC_PWM_CONFIG_T pwm_config ;
|
|
memset(&pwm_config,0,sizeof(QUEC_PWM_CONFIG_T));
|
|
|
|
if(CHIP_IS_CRANEL)
|
|
{
|
|
if(gpio_num != 117 && gpio_num != 32 && gpio_num != 11 && gpio_num != 10
|
|
&& gpio_num != 6 && gpio_num != 8 && gpio_num != 7){
|
|
return -1;
|
|
}
|
|
}
|
|
else if(CHIP_IS_CRANELR)
|
|
{
|
|
if(gpio_num != 69 && gpio_num != 70 && gpio_num != 89){
|
|
return -1;
|
|
}
|
|
}
|
|
else if(CHIP_IS_CRANELS)
|
|
{
|
|
if(gpio_num != 29 && gpio_num != 56 && gpio_num != 58){
|
|
return -1;
|
|
}
|
|
}
|
|
else if(CHIP_IS_CRANELG)
|
|
{
|
|
if(gpio_num != 6 && gpio_num != 7 && gpio_num != 9 && gpio_num != 69
|
|
&& gpio_num != 70 && gpio_num != 89){
|
|
return -1;
|
|
}
|
|
}
|
|
//Although the register has a full duty cycle output of 1, it will show a little duty cycle from the oscilloscope, so it is replaced by a gpio output high and low level
|
|
if(pwm_parameter->high_one_cycle_duration==0 || pwm_parameter->total_one_cycle_duration==0)
|
|
{
|
|
quec_gpio_init( (GPIO_PIN_NUMBER_E)gpio_num,PIN_DIRECTION_OUT, PIN_PULL_PD,PIN_LEVEL_LOW);
|
|
return 0;
|
|
}
|
|
if(pwm_parameter->high_one_cycle_duration==pwm_parameter->total_one_cycle_duration)
|
|
{
|
|
quec_gpio_init( (GPIO_PIN_NUMBER_E)gpio_num,PIN_DIRECTION_OUT, PIN_PULL_PU,PIN_LEVEL_HIGH );
|
|
return 0;
|
|
}
|
|
/**/
|
|
pwm_num = quec_gpio_mapto_pwm_device_num(gpio_num);
|
|
ret = quec_pwm_pinmux_configure(gpio_num);
|
|
if(ret != 0)
|
|
{
|
|
//pwm_log("gpio number =%d is invalid.\n",gpio_num);
|
|
return -1;
|
|
}
|
|
|
|
pwm_config.shutdown = QUEC_PWM_SHUTDOWN_ABRUPTLY;
|
|
pwm_config.pwm_out = QUEC_PWM_OUT_SET_BY_DCYCLE;
|
|
pwm_config.clk_src = (QUEC_PWM_CLK_SRC_E)pwm_parameter->clk_src;
|
|
pwm_config.clk_freq =pwm_parameter->pwm_psc;
|
|
pwm_config.high_one_cycle_duration = pwm_parameter->high_one_cycle_duration;
|
|
pwm_config.total_one_cycle_duration = pwm_parameter->total_one_cycle_duration ;
|
|
|
|
// printf("PWM=%d\n %d\n %ld\n %d\n %d\n",gpio_num,pwm_parameter->clk_src,pwm_parameter->pwm_psc,pwm_parameter->high_one_cycle_duration,pwm_parameter->total_one_cycle_duration);
|
|
|
|
if(pwm_config.total_one_cycle_duration>1024)
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
ret = (int)quec_pwm_configure((QUEC_PWM_DEVICE_NUM_E)pwm_num,&pwm_config);
|
|
|
|
if((QUEC_PWM_RETURN_CODE_E)ret != QUEC_PWM_RC_OK)
|
|
{
|
|
return -1;
|
|
}
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif /*MIN_SYS*/
|
|
|
|
#endif
|
|
|