提交 d22df879 编写于 作者: 勤为本

将“龙芯1c库”中硬件pwm相关接口移植到RT-Thread

上级 09403019
// 封装硬件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 ;
}
#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
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册