diff --git a/bsp/ra6m4-cpk/docs/picture/add_gpt1.png b/bsp/ra6m4-cpk/docs/picture/add_gpt1.png new file mode 100644 index 0000000000..2164bf075a Binary files /dev/null and b/bsp/ra6m4-cpk/docs/picture/add_gpt1.png differ diff --git a/bsp/ra6m4-cpk/docs/picture/add_gpt2.png b/bsp/ra6m4-cpk/docs/picture/add_gpt2.png new file mode 100644 index 0000000000..3194c3fa3e Binary files /dev/null and b/bsp/ra6m4-cpk/docs/picture/add_gpt2.png differ diff --git a/bsp/ra6m4-cpk/docs/picture/add_gpt3.png b/bsp/ra6m4-cpk/docs/picture/add_gpt3.png new file mode 100644 index 0000000000..674e971706 Binary files /dev/null and b/bsp/ra6m4-cpk/docs/picture/add_gpt3.png differ diff --git a/bsp/ra6m4-cpk/docs/使用瑞萨FSP配置工具.md b/bsp/ra6m4-cpk/docs/使用瑞萨FSP配置工具.md index 295f13788b..24832213b5 100644 --- a/bsp/ra6m4-cpk/docs/使用瑞萨FSP配置工具.md +++ b/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 通道下两个输出端口各自对应的输出引脚。 \ No newline at end of file diff --git a/bsp/ra6m4-cpk/drivers/Kconfig b/bsp/ra6m4-cpk/drivers/Kconfig index cdae43b1d0..56e2cbc325 100644 --- a/bsp/ra6m4-cpk/drivers/Kconfig +++ b/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" diff --git a/bsp/ra6m4-cpk/drivers/SConscript b/bsp/ra6m4-cpk/drivers/SConscript index 5238cb6f60..ad8fefaf8d 100644 --- a/bsp/ra6m4-cpk/drivers/SConscript +++ b/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'] diff --git a/bsp/ra6m4-cpk/drivers/config/drv_config.h b/bsp/ra6m4-cpk/drivers/config/drv_config.h index 66f8316ec8..60586fe622 100644 --- a/bsp/ra6m4-cpk/drivers/config/drv_config.h +++ b/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 diff --git a/bsp/ra6m4-cpk/drivers/config/ra6m4/pwm_config.h b/bsp/ra6m4-cpk/drivers/config/ra6m4/pwm_config.h new file mode 100644 index 0000000000..9dd5f01e54 --- /dev/null +++ b/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 +#include +#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__ */ diff --git a/bsp/ra6m4-cpk/drivers/drv_pwm.c b/bsp/ra6m4-cpk/drivers/drv_pwm.c new file mode 100644 index 0000000000..9b6369d9b3 --- /dev/null +++ b/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 */ diff --git a/bsp/ra6m4-cpk/drivers/drv_pwm.h b/bsp/ra6m4-cpk/drivers/drv_pwm.h new file mode 100644 index 0000000000..0bf39b8699 --- /dev/null +++ b/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 +#include +#include +#include +#include +#include + +/* 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__ */