瀏覽代碼

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

勤为本 7 年之前
父節點
當前提交
d22df879ac
共有 2 個文件被更改,包括 274 次插入0 次删除
  1. 197 0
      bsp/ls1cdev/libraries/ls1c_pwm.c
  2. 77 0
      bsp/ls1cdev/libraries/ls1c_pwm.h

+ 197 - 0
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 ;
+}
+
+
+

+ 77 - 0
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
+