Browse Source

[add] 添加 PWM 驱动
[fix] 修复scons脚本中错误的依赖宏

Sherman 3 years ago
parent
commit
84daab189d

BIN
bsp/ra6m4-cpk/docs/picture/add_gpt1.png


BIN
bsp/ra6m4-cpk/docs/picture/add_gpt2.png


BIN
bsp/ra6m4-cpk/docs/picture/add_gpt3.png


+ 27 - 0
bsp/ra6m4-cpk/docs/使用瑞萨FSP配置工具.md

@@ -159,3 +159,30 @@
 3. 修改通道号为 0,与 DAC0 对应
 
 ![img](picture/dac_config2.png)
+
+
+## 通用 PWM 定时器(GPT)
+
+GPT 定时器在该芯片中可作为通用定时器,也可以用于产生 PWM 信号。在将其用于产生 PWM 信号时,GPT 定时器提供了 gpt0 - gpt9 总共 10 个通道,每个通道可以设定两个输出端口。当前版本的 PWM 驱动将每个通道都看做一个单独的 PWM 设备,每个设备都只有一个通道。用户可以选择开启一个通道的任意一个输出端口,或将两个端口均开启,但在同时开启两个端口的情况下,它们输出的波形将完全一致。
+
+1. 添加 GPT 设备
+
+   ![img](./picture/add_gpt1.png)
+
+2. 配置通道
+
+   ![img](./picture/add_gpt2.png)
+
+   对 GPT 较为关键的配置如图所示,具体解释如下:
+
+   1. 将 ```Common``` -> ```Pin Output Support``` 设置为 Enable ,以开启 PWM 波形的输出。
+   2. 指定 GPT 通道,并根据通道数指定 GPT 的名称,例如此处指定 GPT 通道 3 ,所以 GPT 的名称必须为 ```g_timer3```。并且将定时器模式设置为 PWM ,并指定每个 PWM 周期的计数值。
+   3. 设定 PWM 通道默认输出的占空比,这里为 50% 。
+   4. 设定 GPT 通道下两个输出端口的使能状态。
+   5. 此处设置 GPT 通道下两个输出端口各自对应的引脚。
+
+3. 配置输出引脚
+
+   ![img](./picture/add_gpt3.png)
+
+   在完成上一步对 GPT 定时器的设置后,根据图示找到对应 GPT 通道输出引脚设置的界面(这里是 GPT3),将图中标号 **1** 处设置为 ```GTIOCA or GTIOCB``` ,并根据需要在图中标号 **2** 处设置 GPT 通道下两个输出端口各自对应的输出引脚。

+ 54 - 7
bsp/ra6m4-cpk/drivers/Kconfig

@@ -17,6 +17,15 @@ menu "Hardware Drivers Config"
             select RT_USING_PIN
             default y
 
+        config BSP_USING_ONCHIP_FLASH
+            bool "Enable Onchip FLASH"
+            default n
+
+        config BSP_USING_WDT
+            bool "Enable Watchdog Timer"
+            select RT_USING_WDT
+            default n
+
         menuconfig BSP_USING_UART
             bool "Enable UART"
             default y
@@ -73,11 +82,6 @@ menu "Hardware Drivers Config"
                     endif
             endif
 
-        config BSP_USING_WDT
-            bool "Enable Watchdog Timer"
-            select RT_USING_WDT
-            default n
-
         menuconfig BSP_USING_ONCHIP_RTC
             bool "Enable RTC"
             select RT_USING_RTC
@@ -141,9 +145,52 @@ menu "Hardware Drivers Config"
                     default n
             endif
 
-        config BSP_USING_ONCHIP_FLASH
-            bool "Enable Onchip FLASH"
+        menuconfig BSP_USING_PWM
+            bool "Enable PWM"
             default n
+            select RT_USING_PWM
+            if BSP_USING_PWM
+                config BSP_USING_PWM0
+                    bool "Enable GPT0 (32-Bits) output PWM"
+                    default n
+                
+                config BSP_USING_PWM1
+                    bool "Enable GPT1 (32-Bits) output PWM"
+                    default n
+
+                config BSP_USING_PWM2
+                    bool "Enable GPT2 (32-Bits) output PWM"
+                    default n
+
+                config BSP_USING_PWM3
+                    bool "Enable GPT3 (32-Bits) output PWM"
+                    default n
+
+                config BSP_USING_PWM4
+                    bool "Enable GPT4 (16-Bits) output PWM"
+                    default n
+
+                config BSP_USING_PWM5
+                    bool "Enable GPT5 (16-Bits) output PWM"
+                    default n
+
+                config BSP_USING_PWM6
+                    bool "Enable GPT6 (16-Bits) output PWM"
+                    default n
+
+                config BSP_USING_PWM7
+                    bool "Enable GPT7 (16-Bits) output PWM"
+                    default n
+
+                config BSP_USING_PWM8
+                    bool "Enable GPT8 (16-Bits) output PWM"
+                    default n
+
+                config BSP_USING_PWM9
+                    bool "Enable GPT9 (16-Bits) output PWM"
+                    default n
+            endif
+
     endmenu
 
     menu "Board extended module Drivers"

+ 5 - 2
bsp/ra6m4-cpk/drivers/SConscript

@@ -9,14 +9,14 @@ src = Split("""
     drv_common.c
 """)
 
-if GetDepend(['BSP_USING_SERIAL']):
+if GetDepend(['BSP_USING_UART']):
     if GetDepend(['RT_USING_SERIAL_V2']):
         src += ['drv_usart_v2.c']
     else:
         print("\nThe current project does not support serial-v1\n")
         Return('group')
 
-if GetDepend(['BSP_USING_PIN']):
+if GetDepend(['BSP_USING_GPIO']):
     src += ['drv_gpio.c']
 
 if GetDepend(['BSP_USING_WDT']):
@@ -41,6 +41,9 @@ if GetDepend(['BSP_USING_DAC']):
 if GetDepend(['BSP_USING_ONCHIP_FLASH']):
     src += ['drv_flash.c']
 
+if GetDepend(['BSP_USING_PWM']):
+    src += ['drv_pwm.c']
+
 path =  [cwd]
 path += [cwd + '/config']
 

+ 6 - 2
bsp/ra6m4-cpk/drivers/config/drv_config.h

@@ -21,14 +21,18 @@ extern "C" {
 #ifdef SOC_SERIES_R7FA6M4AF
 #include "ra6m4/uart_config.h"
 
-#ifdef RT_USING_ADC
+#ifdef BSP_USING_ADC
 #include "ra6m4/adc_config.h"
 #endif
 
-#ifdef RT_USING_DAC
+#ifdef BSP_USING_DAC
 #include "ra6m4/dac_config.h"
 #endif
 
+#ifdef BSP_USING_PWM
+#include "ra6m4/pwm_config.h"
+#endif
+
 #endif/* SOC_SERIES_R7FA6M4AF */
 
 #ifdef __cplusplus

+ 68 - 0
bsp/ra6m4-cpk/drivers/config/ra6m4/pwm_config.h

@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2006-2021, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date           Author            Notes
+ * 2021-10-26     KevinXu           first version
+ */
+#ifndef __PWM_CONFIG_H__
+#define __PWM_CONFIG_H__
+
+#include <rtthread.h>
+#include <drv_config.h>
+#include "hal_data.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+enum
+{
+#ifdef BSP_USING_PWM0
+    BSP_PWM0_INDEX,
+#endif
+#ifdef BSP_USING_PWM1
+    BSP_PWM1_INDEX,
+#endif
+#ifdef BSP_USING_PWM2
+    BSP_PWM2_INDEX,
+#endif
+#ifdef BSP_USING_PWM3
+    BSP_PWM3_INDEX,
+#endif
+#ifdef BSP_USING_PWM4
+    BSP_PWM4_INDEX,
+#endif
+#ifdef BSP_USING_PWM5
+    BSP_PWM5_INDEX,
+#endif
+#ifdef BSP_USING_PWM6
+    BSP_PWM6_INDEX,
+#endif
+#ifdef BSP_USING_PWM7
+    BSP_PWM7_INDEX,
+#endif
+#ifdef BSP_USING_PWM8
+    BSP_PWM8_INDEX,
+#endif
+#ifdef BSP_USING_PWM9
+    BSP_PWM9_INDEX,
+#endif
+    BSP_PWMS_NUM
+};
+
+#define PWM_DRV_INITIALIZER(num)        \
+    {                                   \
+        .name = "pwm"#num ,             \
+        .g_cfg = &g_timer##num##_cfg,   \
+        .g_ctrl = &g_timer##num##_ctrl, \
+        .g_timer = &g_timer##num,       \
+    }
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __PWM_CONFIG_H__ */

+ 220 - 0
bsp/ra6m4-cpk/drivers/drv_pwm.c

@@ -0,0 +1,220 @@
+/*
+ * Copyright (c) 2006-2021, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ * 2021-10-25     KevinXu      first version
+ */
+
+#include "drv_pwm.h"
+
+#ifdef RT_USING_PWM
+
+/* Declare the control function first */
+static rt_err_t drv_pwm_control(struct rt_device_pwm *, int, void *);
+static struct rt_pwm_ops drv_ops =
+{
+    drv_pwm_control
+};
+
+static struct ra_pwm ra6m4_pwm_obj[BSP_PWMS_NUM] =
+{
+#ifdef BSP_USING_PWM0
+    [BSP_PWM0_INDEX] = PWM_DRV_INITIALIZER(0),
+#endif
+#ifdef BSP_USING_PWM1
+    [BSP_PWM1_INDEX] = PWM_DRV_INITIALIZER(1),
+#endif
+#ifdef BSP_USING_PWM2
+    [BSP_PWM2_INDEX] = PWM_DRV_INITIALIZER(2),
+#endif
+#ifdef BSP_USING_PWM3
+    [BSP_PWM3_INDEX] = PWM_DRV_INITIALIZER(3),
+#endif
+#ifdef BSP_USING_PWM4
+    [BSP_PWM4_INDEX] = PWM_DRV_INITIALIZER(4),
+#endif
+#ifdef BSP_USING_PWM5
+    [BSP_PWM5_INDEX] = PWM_DRV_INITIALIZER(5),
+#endif
+#ifdef BSP_USING_PWM6
+    [BSP_PWM6_INDEX] = PWM_DRV_INITIALIZER(6),
+#endif
+#ifdef BSP_USING_PWM7
+    [BSP_PWM7_INDEX] = PWM_DRV_INITIALIZER(7),
+#endif
+#ifdef BSP_USING_PWM8
+    [BSP_PWM8_INDEX] = PWM_DRV_INITIALIZER(8),
+#endif
+#ifdef BSP_USING_PWM9
+    [BSP_PWM9_INDEX] = PWM_DRV_INITIALIZER(9),
+#endif
+};
+
+
+/* Convert the raw PWM period counts into ns */
+static rt_uint32_t _convert_counts_ns(uint32_t source_div, uint32_t raw)
+{
+    uint32_t pclkd_freq_hz = R_FSP_SystemClockHzGet(FSP_PRIV_CLOCK_PCLKD) >> source_div;
+    uint32_t ns = (uint32_t)(((uint64_t)raw * 1000000000ULL) / pclkd_freq_hz);
+    return ns;
+}
+
+/* Convert ns into raw PWM period counts */
+static rt_uint32_t _convert_ns_counts(uint32_t source_div, uint32_t raw)
+{
+    uint32_t pclkd_freq_hz = R_FSP_SystemClockHzGet(FSP_PRIV_CLOCK_PCLKD) >> source_div;
+    uint32_t counts = (uint32_t)(((uint64_t)raw * (uint64_t)pclkd_freq_hz) / 1000000000ULL);
+    return counts;
+}
+
+
+/* PWM_CMD_ENABLE or PWM_CMD_DISABLE */
+static rt_err_t drv_pwm_enable(struct ra_pwm *device,
+                               struct rt_pwm_configuration *configuration,
+                               rt_bool_t enable)
+{
+    fsp_err_t err = FSP_SUCCESS;
+
+    if (enable)
+    {
+        err = R_GPT_Start(device->g_ctrl);
+    }
+    else
+    {
+        err = R_GPT_Stop(device->g_ctrl);
+    }
+
+    return (err == FSP_SUCCESS) ? RT_EOK : -RT_ERROR;
+}
+
+/* PWM_CMD_GET */
+static rt_err_t drv_pwm_get(struct ra_pwm *device,
+                            struct rt_pwm_configuration *configuration)
+{
+    timer_info_t info;
+    if (R_GPT_InfoGet(device->g_ctrl, &info) != FSP_SUCCESS)
+        return -RT_ERROR;
+
+    configuration->pulse =
+        _convert_counts_ns(device->g_cfg->source_div, device->g_cfg->duty_cycle_counts);
+    configuration->period =
+        _convert_counts_ns(device->g_cfg->source_div, info.period_counts);
+    configuration->channel = device->g_cfg->channel;
+
+    return RT_EOK;
+}
+
+/* PWM_CMD_SET */
+static rt_err_t drv_pwm_set(struct ra_pwm *device,
+                            struct rt_pwm_configuration *conf)
+{
+    uint32_t counts;
+    fsp_err_t fsp_erra;
+    fsp_err_t fsp_errb;
+    rt_err_t rt_err;
+    uint32_t pulse;
+    uint32_t period;
+    struct rt_pwm_configuration orig_conf;
+
+    rt_err = drv_pwm_get(device, &orig_conf);
+    if (rt_err != RT_EOK)
+    {
+        return rt_err;
+    }
+
+    /* Pulse cannot last longer than period. */
+    period = conf->period;
+    pulse = (period >= conf->pulse) ? conf->pulse : period;
+
+    /* Not to set period again if it's not changed. */
+    if (period != orig_conf.period)
+    {
+        counts = _convert_ns_counts(device->g_cfg->source_div, period);
+        fsp_erra = R_GPT_PeriodSet(device->g_ctrl, counts);
+        if (fsp_erra != FSP_SUCCESS)
+        {
+            return -RT_ERROR;
+        }
+    }
+
+    /* Two pins of a channel will not be separated. */
+    counts = _convert_ns_counts(device->g_cfg->source_div, pulse);
+    fsp_erra = R_GPT_DutyCycleSet(device->g_ctrl, counts, GPT_IO_PIN_GTIOCA);
+    fsp_errb = R_GPT_DutyCycleSet(device->g_ctrl, counts, GPT_IO_PIN_GTIOCB);
+    if (fsp_erra != FSP_SUCCESS || fsp_errb != FSP_SUCCESS)
+    {
+        return -RT_ERROR;
+    }
+
+    return RT_EOK;
+}
+
+/**
+ * Implement of control method in struct rt_pwm_ops.
+ */
+static rt_err_t drv_pwm_control(struct rt_device_pwm *device, int cmd, void *arg)
+{
+    struct rt_pwm_configuration *configuration = (struct rt_pwm_configuration *)arg;
+    struct ra_pwm *pwm_device = (struct ra_pwm *)device->parent.user_data;
+
+    /**
+     * There's actually only one GPT timer with 10 channels. In this case, the
+     * timer is separated into 10 PWM devices, so each device has only one
+     * channel.
+     */
+    if (configuration->channel != 0)
+    {
+        return -RT_EINVAL;
+    }
+
+    switch (cmd)
+    {
+    case PWM_CMD_ENABLE:
+        return drv_pwm_enable(pwm_device, configuration, RT_TRUE);
+    case PWM_CMD_DISABLE:
+        return drv_pwm_enable(pwm_device, configuration, RT_FALSE);
+    case PWM_CMD_GET:
+        return drv_pwm_get(pwm_device, configuration);
+    case PWM_CMD_SET:
+        return drv_pwm_set(pwm_device, configuration);
+    default:
+        return -RT_EINVAL;
+    }
+
+    return RT_EOK;
+}
+
+/**
+ * This is to register the PWM device
+ *
+ * Note that the PWM driver only supports one fixed pin.
+ */
+int rt_hw_pwm_init(void)
+{
+    rt_err_t ret = RT_EOK;
+    rt_err_t rt_err = RT_EOK;
+    fsp_err_t fsp_err = FSP_SUCCESS;
+
+    for (int i = 0; i < BSP_PWMS_NUM; i++)
+    {
+        fsp_err = R_GPT_Open(ra6m4_pwm_obj[i].g_ctrl,
+                             ra6m4_pwm_obj[i].g_cfg);
+
+        rt_err = rt_device_pwm_register(&ra6m4_pwm_obj[i].pwm_device,
+                                        ra6m4_pwm_obj[i].name,
+                                        &drv_ops,
+                                        &ra6m4_pwm_obj[i]);
+
+        if (fsp_err != FSP_SUCCESS || rt_err != RT_EOK)
+        {
+            ret = -RT_ERROR;
+        }
+    }
+
+    return ret;
+}
+INIT_BOARD_EXPORT(rt_hw_pwm_init);
+#endif /* RT_USING_PWM */

+ 34 - 0
bsp/ra6m4-cpk/drivers/drv_pwm.h

@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2006-2021, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ * 2021-10-25     KevinXu      first version
+ */
+
+#ifndef __DRV_PWM_H__
+#define __DRV_PWM_H__
+
+#include <rtthread.h>
+#include <rtdevice.h>
+#include <rthw.h>
+#include <drv_common.h>
+#include <drv_config.h>
+#include <hal_data.h>
+
+/* PWM device object structure */
+struct ra_pwm
+{
+    struct rt_device_pwm            pwm_device;
+    gpt_instance_ctrl_t             *g_ctrl;
+    timer_instance_t const *const   g_timer;
+    timer_cfg_t const *const        g_cfg;
+    char                            *name;
+};
+
+/* Get ra6m4 pwm device object from the general pwm device object */
+#define _GET_RA6M4_PWM_OBJ(ptr) rt_container_of(ptr, struct ra_pwm, pwm_device)
+
+#endif /* __DRV_PWM_H__ */