diff --git a/bsp/ls1cdev/libraries/ls1c_pwm.c b/bsp/ls1cdev/libraries/ls1c_pwm.c new file mode 100644 index 0000000000..01ffc6f3a9 --- /dev/null +++ b/bsp/ls1cdev/libraries/ls1c_pwm.c @@ -0,0 +1,197 @@ +// 封装硬件pwm接口 + +#include "ls1c_public.h" +#include "ls1c_pin.h" +#include "ls1c_pwm.h" +#include "ls1c_clock.h" +#include "ls1c_regs.h" + + + +// pwm的最大周期 +#define PWM_MAX_PERIOD (0xFFFFFF) // 计数器的值 + + + +/* + * 根据gpio获取相应pwm的基地址 + * @gpio pwm引脚 + * @ret pwm基地址 + */ +unsigned int pwm_get_reg_base(unsigned int gpio) +{ + unsigned int reg_base = 0; + + switch (gpio) + { + case LS1C_PWM0_GPIO06: + case LS1C_PWM0_GPIO04: + reg_base = LS1C_REG_BASE_PWM0; + break; + + case LS1C_PWM1_GPIO92: + case LS1C_PWM1_GPIO05: + reg_base = LS1C_REG_BASE_PWM1; + break; + + case LS1C_PWM2_GPIO52: + case LS1C_PWM2_GPIO46: + reg_base = LS1C_REG_BASE_PWM2; + break; + + case LS1C_PWM3_GPIO47: + case LS1C_PWM3_GPIO53: + reg_base = LS1C_REG_BASE_PWM3; + break; + } + + return reg_base; +} + + +/* + * 禁止pwm + * @pwm_info PWMn的详细信息 + */ +void pwm_disable(pwm_info_t *pwm_info) +{ + unsigned int pwm_reg_base = 0; + + // 检查入参 + if (NULL == pwm_info) + { + return ; + } + + pwm_reg_base = pwm_get_reg_base(pwm_info->gpio); + reg_write_32(0, (volatile unsigned int *)(pwm_reg_base + LS1C_PWM_CTRL)); + + return ; +} + + + +/* + * 使能PWM + * @pwm_info PWMn的详细信息 + */ +void pwm_enable(pwm_info_t *pwm_info) +{ + unsigned int pwm_reg_base = 0; + unsigned int ctrl = 0; + + // 检查入参 + if (NULL == pwm_info) + { + return ; + } + + // 获取基地址 + pwm_reg_base = pwm_get_reg_base(pwm_info->gpio); + + // 清零计数器 + reg_write_32(0, (volatile unsigned int *)(pwm_reg_base + LS1C_PWM_CNTR)); + + // 设置控制寄存器 + ctrl = (0 << LS1C_PWM_INT_LRC_EN) + | (0 << LS1C_PWM_INT_HRC_EN) + | (0 << LS1C_PWM_CNTR_RST) + | (0 << LS1C_PWM_INT_SR) + | (0 << LS1C_PWM_INTEN) + | (0 << LS1C_PWM_OE) + | (1 << LS1C_PWM_CNT_EN); + if (PWM_MODE_PULSE == pwm_info->mode) // 单脉冲 + { + ctrl |= (1 << LS1C_PWM_SINGLE); + } + else // 连续脉冲 + { + ctrl &= ~(1 << LS1C_PWM_SINGLE); + } + reg_write_32(ctrl, (volatile unsigned int *)(pwm_reg_base + LS1C_PWM_CTRL)); + + return ; +} + + + +/* + * 初始化PWMn + * @pwm_info PWMn的详细信息 + */ +void pwm_init(pwm_info_t *pwm_info) +{ + unsigned int gpio; + unsigned long pwm_clk = 0; // pwm模块的时钟频率 + unsigned long tmp = 0; + unsigned int pwm_reg_base = 0; + unsigned long period = 0; + + // 判断入参 + if (NULL == pwm_info) + { + // 入参非法,则直接返回 + return ; + } + gpio = pwm_info->gpio; + + // 配置相应引脚用作pwm,而非gpio + pin_set_purpose(gpio, PIN_PURPOSE_OTHER); + + // 复用 + switch (gpio) + { + // 不需要复用 + case LS1C_PWM0_GPIO06: + case LS1C_PWM1_GPIO92: + break; + + case LS1C_PWM0_GPIO04: // gpio04的第三复用 + pin_set_remap(LS1C_PWM0_GPIO04, PIN_REMAP_THIRD); + break; + + case LS1C_PWM1_GPIO05: // gpio05的第三复用 + pin_set_remap(LS1C_PWM1_GPIO05, PIN_REMAP_THIRD); + break; + + case LS1C_PWM2_GPIO52: // gpio52的第四复用 + pin_set_remap(LS1C_PWM2_GPIO52, PIN_REMAP_FOURTH); + break; + + case LS1C_PWM2_GPIO46: // gpio46的第四复用 + pin_set_remap(LS1C_PWM2_GPIO46, PIN_REMAP_FOURTH); + break; + + case LS1C_PWM3_GPIO47: // gpio47的第四复用 + pin_set_remap(LS1C_PWM3_GPIO47, PIN_REMAP_FOURTH); + break; + + case LS1C_PWM3_GPIO53: // gpio53的第四复用 + pin_set_remap(LS1C_PWM3_GPIO53, PIN_REMAP_FOURTH); + break; + + default: + break; + } + + // 根据占空比和pwm周期计算寄存器HRC和LRC的值 + // 两个64位数相乘,只能得到低32位,linux下却可以得到64位结果, + // 暂不清楚原因,用浮点运算代替 + pwm_clk = clk_get_apb_rate(); + period = (1.0 * pwm_clk * pwm_info->period_ns) / 1000000000; + period = MIN(period, PWM_MAX_PERIOD); // 限制周期不能超过最大值 + tmp = period - (period * pwm_info->duty); + + // 写寄存器HRC和LRC + pwm_reg_base = pwm_get_reg_base(gpio); + reg_write_32(--tmp, (volatile unsigned int *)(pwm_reg_base + LS1C_PWM_HRC)); + reg_write_32(--period, (volatile unsigned int *)(pwm_reg_base + LS1C_PWM_LRC)); + + // 写主计数器 + pwm_enable(pwm_info); + + return ; +} + + + diff --git a/bsp/ls1cdev/libraries/ls1c_pwm.h b/bsp/ls1cdev/libraries/ls1c_pwm.h new file mode 100644 index 0000000000..aa9daeeb0c --- /dev/null +++ b/bsp/ls1cdev/libraries/ls1c_pwm.h @@ -0,0 +1,77 @@ + + +#ifndef __OPENLOONGSON_PWM_H +#define __OPENLOONGSON_PWM_H + + +// pwm引脚定义 +#define LS1C_PWM0_GPIO06 (6) // gpio06用作pwm0 +#define LS1C_PWM0_GPIO04 (4) // gpio04复用为pwm0 +#define LS1C_PWM1_GPIO92 (92) // gpio92用作pwm1 +#define LS1C_PWM1_GPIO05 (5) // gpio05复用为pwm1 +#define LS1C_PWM2_GPIO52 (52) // gpio52复用为pwm2 +#define LS1C_PWM2_GPIO46 (46) // gpio46复用为pwm2 +#define LS1C_PWM3_GPIO47 (47) // gpio47复用为pwm3 +#define LS1C_PWM3_GPIO53 (53) // gpio53复用为pwm3 +// ...还有一些gpio可以复用为gpio的,有需要可以自己添加 + + + +// pwm控制寄存器的每个bit +#define LS1C_PWM_INT_LRC_EN (11) // 低脉冲计数器中断使能 +#define LS1C_PWM_INT_HRC_EN (10) // 高脉冲计数器中断使能 +#define LS1C_PWM_CNTR_RST (7) // 使能CNTR计数器清零 +#define LS1C_PWM_INT_SR (6) // 中断状态位 +#define LS1C_PWM_INTEN (5) // 中断使能位 +#define LS1C_PWM_SINGLE (4) // 单脉冲控制位 +#define LS1C_PWM_OE (3) // 脉冲输出使能 +#define LS1C_PWM_CNT_EN (0) // 主计数器使能 + + +// 硬件pwm工作模式 +enum +{ + // 正常模式--连续输出pwm波形 + PWM_MODE_NORMAL = 0, + + // 单脉冲模式,每次调用只发送一个脉冲,调用间隔必须大于pwm周期 + PWM_MODE_PULSE +}; + + +// 硬件pwm信息 +typedef struct +{ + unsigned int gpio; // PWMn所在的gpio + unsigned int mode; // 工作模式(单脉冲、连续脉冲) + float duty; // pwm的占空比 + unsigned long period_ns; // pwm周期(单位ns) +}pwm_info_t; + + + + +/* + * 初始化PWMn + * @pwm_info PWMn的详细信息 + */ +void pwm_init(pwm_info_t *pwm_info); + + +/* + * 禁止pwm + * @pwm_info PWMn的详细信息 + */ +void pwm_disable(pwm_info_t *pwm_info); + + + +/* + * 使能PWM + * @pwm_info PWMn的详细信息 + */ +void pwm_enable(pwm_info_t *pwm_info); + + +#endif +