diff --git a/bsp/novosns/ns800/libraries/HAL_Drivers/drivers/SConscript b/bsp/novosns/ns800/libraries/HAL_Drivers/drivers/SConscript index 5662cb9b62a..8cbb9ff8467 100644 --- a/bsp/novosns/ns800/libraries/HAL_Drivers/drivers/SConscript +++ b/bsp/novosns/ns800/libraries/HAL_Drivers/drivers/SConscript @@ -35,6 +35,9 @@ if GetDepend('BSP_USING_WDT'): if GetDepend('BSP_USING_WWDG'): src += ['drv_wwdg.c'] +if GetDepend('BSP_USING_EPWM'): + src += ['drv_epwm.c'] + group = DefineGroup('HAL_Drivers', src, depend = [''], CPPPATH = path) Return('group') diff --git a/bsp/novosns/ns800/libraries/HAL_Drivers/drivers/drv_epwm.c b/bsp/novosns/ns800/libraries/HAL_Drivers/drivers/drv_epwm.c new file mode 100644 index 00000000000..bdd8c6c43a7 --- /dev/null +++ b/bsp/novosns/ns800/libraries/HAL_Drivers/drivers/drv_epwm.c @@ -0,0 +1,671 @@ +/* + * Copyright (c) 2006-2026, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2026-06-15 Eric Initial version. + */ + +#include +#include +#include "syscon.h" +#include "drv_epwm.h" + +#if defined(BSP_USING_EPWM) + +#define DBG_TAG "drv.epwm" +#define DBG_LVL DBG_INFO +#include + +enum +{ +#ifdef BSP_USING_EPWM1 + EPWM1_INDEX, +#endif +#ifdef BSP_USING_EPWM2 + EPWM2_INDEX, +#endif +#ifdef BSP_USING_EPWM3 + EPWM3_INDEX, +#endif +#ifdef BSP_USING_EPWM4 + EPWM4_INDEX, +#endif +#ifdef BSP_USING_EPWM5 + EPWM5_INDEX, +#endif +#ifdef BSP_USING_EPWM6 + EPWM6_INDEX, +#endif +#ifdef BSP_USING_EPWM7 + EPWM7_INDEX, +#endif +#ifdef BSP_USING_EPWM8 + EPWM8_INDEX, +#endif +#ifdef BSP_USING_EPWM9 + EPWM9_INDEX, +#endif +#ifdef BSP_USING_EPWM10 + EPWM10_INDEX, +#endif +#ifdef BSP_USING_EPWM11 + EPWM11_INDEX, +#endif +#ifdef BSP_USING_EPWM12 + EPWM12_INDEX, +#endif +#ifdef BSP_USING_EPWM13 + EPWM13_INDEX, +#endif +#ifdef BSP_USING_EPWM14 + EPWM14_INDEX, +#endif +#ifdef BSP_USING_EPWM15 + EPWM15_INDEX, +#endif +#ifdef BSP_USING_EPWM16 + EPWM16_INDEX, +#endif +#ifdef BSP_USING_EPWM17 + EPWM17_INDEX, +#endif +#ifdef BSP_USING_EPWM18 + EPWM18_INDEX, +#endif +}; + +struct ns800_epwm_pin_config +{ + GPIO_TypeDef *port_a; + GPIO_PinNum pin_a; + GPIO_AltFunc mux_a; + GPIO_TypeDef *port_b; + GPIO_PinNum pin_b; + GPIO_AltFunc mux_b; +}; + +struct ns800_epwm_config +{ + const char *name; + EPWM_TypeDef *instance; + EPWM_TimeBaseCountMode count_mode; + EPWM_ClockDivider clock_div; + EPWM_HSClockDivider hs_clock_div; +}; + +struct ns800_signal_params +{ + float signal_freq; /*!< Desired Signal Frequency(in Hz) */ + float duty_val; /*!< Desired ePWMxA/B Signal Duty */ + float sys_clk_freq; /*!< SYSCLK Frequency(in Hz) */ + float dead_band_val; + rt_bool_t invert_signal_b; + EPWM_TimeBaseCountMode count_mode; + EPWM_ClockDivider clock_div; + EPWM_HSClockDivider hs_clock_div; +}; + +struct ns800_epwm +{ + struct rt_device_pwm epwm_device; + const struct ns800_epwm_pin_config *pin_config; + const struct ns800_epwm_config *epwm_config; + rt_uint32_t current_period; + rt_uint32_t current_pulse; +}; + +static const struct ns800_epwm_pin_config epwm_pins[] = +{ +#ifdef BSP_USING_EPWM1 + [EPWM1_INDEX] = EPWM_PIN_INFO(GPIOA, GPIO_PIN_0, ALT1_FUNCTION, + GPIOA, GPIO_PIN_1, ALT1_FUNCTION), +#endif +#ifdef BSP_USING_EPWM2 + [EPWM2_INDEX] = EPWM_PIN_INFO(GPIOA, GPIO_PIN_2, ALT1_FUNCTION, + GPIOA, GPIO_PIN_3, ALT1_FUNCTION), +#endif +#ifdef BSP_USING_EPWM3 + [EPWM3_INDEX] = EPWM_PIN_INFO(GPIOA, GPIO_PIN_4, ALT1_FUNCTION, + GPIOA, GPIO_PIN_5, ALT1_FUNCTION), +#endif +#ifdef BSP_USING_EPWM4 + [EPWM4_INDEX] = EPWM_PIN_INFO(GPIOB, GPIO_PIN_14, ALT1_FUNCTION, + GPIOB, GPIO_PIN_15, ALT1_FUNCTION), +#endif +#ifdef BSP_USING_EPWM5 + [EPWM5_INDEX] = EPWM_PIN_INFO(GPIOA, GPIO_PIN_8, ALT1_FUNCTION, + GPIOA, GPIO_PIN_9, ALT1_FUNCTION), +#endif +#ifdef BSP_USING_EPWM6 + [EPWM6_INDEX] = EPWM_PIN_INFO(GPIOA, GPIO_PIN_10, ALT1_FUNCTION, + GPIOA, GPIO_PIN_11, ALT1_FUNCTION), +#endif +#ifdef BSP_USING_EPWM7 + [EPWM7_INDEX] = EPWM_PIN_INFO(GPIOA, GPIO_PIN_12, ALT1_FUNCTION, + GPIOA, GPIO_PIN_13, ALT1_FUNCTION), +#endif +#ifdef BSP_USING_EPWM8 + [EPWM8_INDEX] = EPWM_PIN_INFO(GPIOA, GPIO_PIN_14, ALT1_FUNCTION, + GPIOA, GPIO_PIN_15, ALT1_FUNCTION), +#endif +#ifdef BSP_USING_EPWM9 + [EPWM9_INDEX] = EPWM_PIN_INFO(GPIOA, GPIO_PIN_16, ALT5_FUNCTION, + GPIOA, GPIO_PIN_17, ALT5_FUNCTION), +#endif +#ifdef BSP_USING_EPWM10 + [EPWM10_INDEX] = EPWM_PIN_INFO(GPIOA, GPIO_PIN_18, ALT5_FUNCTION, + GPIOA, GPIO_PIN_19, ALT5_FUNCTION), +#endif +#ifdef BSP_USING_EPWM11 + [EPWM11_INDEX] = EPWM_PIN_INFO(GPIOA, GPIO_PIN_20, ALT5_FUNCTION, + GPIOA, GPIO_PIN_21, ALT5_FUNCTION), +#endif +#ifdef BSP_USING_EPWM12 /*failed*/ + [EPWM12_INDEX] = EPWM_PIN_INFO(GPIOF, GPIO_PIN_12, ALT5_FUNCTION, + GPIOA, GPIO_PIN_23, ALT5_FUNCTION), +#endif +#ifdef BSP_USING_EPWM13 + [EPWM13_INDEX] = EPWM_PIN_INFO(GPIOF, GPIO_PIN_14, ALT13_FUNCTION, + GPIOF, GPIO_PIN_15, ALT13_FUNCTION), +#endif +#ifdef BSP_USING_EPWM14 + [EPWM14_INDEX] = EPWM_PIN_INFO(GPIOF, GPIO_PIN_16, ALT13_FUNCTION, + GPIOF, GPIO_PIN_17, ALT13_FUNCTION), +#endif +#ifdef BSP_USING_EPWM15 + [EPWM15_INDEX] = EPWM_PIN_INFO(GPIOF, GPIO_PIN_18, ALT13_FUNCTION, + GPIOF, GPIO_PIN_19, ALT13_FUNCTION), +#endif +#ifdef BSP_USING_EPWM16 + [EPWM16_INDEX] = EPWM_PIN_INFO(GPIOF, GPIO_PIN_20, ALT13_FUNCTION, + GPIOB, GPIO_PIN_23, ALT3_FUNCTION), +#endif +#ifdef BSP_USING_EPWM17 + [EPWM17_INDEX] = EPWM_PIN_INFO(GPIOB, GPIO_PIN_24, ALT3_FUNCTION, + GPIOB, GPIO_PIN_25, ALT3_FUNCTION), +#endif +#ifdef BSP_USING_EPWM18 + [EPWM18_INDEX] = EPWM_PIN_INFO(GPIOD, GPIO_PIN_8, ALT2_FUNCTION, + GPIOD, GPIO_PIN_9, ALT2_FUNCTION), +#endif +}; + +static const struct ns800_epwm_config epwm_conf[] = +{ +#ifdef BSP_USING_EPWM1 + [EPWM1_INDEX] = EPWM_DRV_INIT(1, EPWM_COUNTER_MODE_UP_DOWN, + EPWM_CLOCK_DIVIDER_2, EPWM_HSCLOCK_DIVIDER_1), +#endif +#ifdef BSP_USING_EPWM2 + [EPWM2_INDEX] = EPWM_DRV_INIT(2, EPWM_COUNTER_MODE_UP_DOWN, + EPWM_CLOCK_DIVIDER_2, EPWM_HSCLOCK_DIVIDER_1), +#endif +#ifdef BSP_USING_EPWM3 + [EPWM3_INDEX] = EPWM_DRV_INIT(3, EPWM_COUNTER_MODE_UP_DOWN, + EPWM_CLOCK_DIVIDER_2, EPWM_HSCLOCK_DIVIDER_1), +#endif +#ifdef BSP_USING_EPWM4 + [EPWM4_INDEX] = EPWM_DRV_INIT(4, EPWM_COUNTER_MODE_UP_DOWN, + EPWM_CLOCK_DIVIDER_2, EPWM_HSCLOCK_DIVIDER_1), +#endif +#ifdef BSP_USING_EPWM5 + [EPWM5_INDEX] = EPWM_DRV_INIT(5, EPWM_COUNTER_MODE_UP_DOWN, + EPWM_CLOCK_DIVIDER_2, EPWM_HSCLOCK_DIVIDER_1), +#endif +#ifdef BSP_USING_EPWM6 + [EPWM6_INDEX] = EPWM_DRV_INIT(6, EPWM_COUNTER_MODE_UP_DOWN, + EPWM_CLOCK_DIVIDER_2, EPWM_HSCLOCK_DIVIDER_1), +#endif +#ifdef BSP_USING_EPWM7 + [EPWM7_INDEX] = EPWM_DRV_INIT(7, EPWM_COUNTER_MODE_UP_DOWN, + EPWM_CLOCK_DIVIDER_2, EPWM_HSCLOCK_DIVIDER_1), +#endif +#ifdef BSP_USING_EPWM8 + [EPWM8_INDEX] = EPWM_DRV_INIT(8, EPWM_COUNTER_MODE_UP_DOWN, + EPWM_CLOCK_DIVIDER_2, EPWM_HSCLOCK_DIVIDER_1), +#endif +#ifdef BSP_USING_EPWM9 + [EPWM9_INDEX] = EPWM_DRV_INIT(9, EPWM_COUNTER_MODE_UP_DOWN, + EPWM_CLOCK_DIVIDER_2, EPWM_HSCLOCK_DIVIDER_1), +#endif +#ifdef BSP_USING_EPWM10 + [EPWM10_INDEX] = EPWM_DRV_INIT(10, EPWM_COUNTER_MODE_UP_DOWN, + EPWM_CLOCK_DIVIDER_2, EPWM_HSCLOCK_DIVIDER_1), +#endif +#ifdef BSP_USING_EPWM11 + [EPWM11_INDEX] = EPWM_DRV_INIT(11, EPWM_COUNTER_MODE_UP_DOWN, + EPWM_CLOCK_DIVIDER_2, EPWM_HSCLOCK_DIVIDER_1), +#endif +#ifdef BSP_USING_EPWM12 + [EPWM12_INDEX] = EPWM_DRV_INIT(12, EPWM_COUNTER_MODE_UP_DOWN, + EPWM_CLOCK_DIVIDER_2, EPWM_HSCLOCK_DIVIDER_1), +#endif +#ifdef BSP_USING_EPWM13 + [EPWM13_INDEX] = EPWM_DRV_INIT(13, EPWM_COUNTER_MODE_UP_DOWN, + EPWM_CLOCK_DIVIDER_2, EPWM_HSCLOCK_DIVIDER_1), +#endif +#ifdef BSP_USING_EPWM14 + [EPWM14_INDEX] = EPWM_DRV_INIT(14, EPWM_COUNTER_MODE_UP_DOWN, + EPWM_CLOCK_DIVIDER_2, EPWM_HSCLOCK_DIVIDER_1), +#endif +#ifdef BSP_USING_EPWM15 + [EPWM15_INDEX] = EPWM_DRV_INIT(15, EPWM_COUNTER_MODE_UP_DOWN, + EPWM_CLOCK_DIVIDER_2, EPWM_HSCLOCK_DIVIDER_1), +#endif +#ifdef BSP_USING_EPWM16 + [EPWM16_INDEX] = EPWM_DRV_INIT(16, EPWM_COUNTER_MODE_UP_DOWN, + EPWM_CLOCK_DIVIDER_2, EPWM_HSCLOCK_DIVIDER_1), +#endif +#ifdef BSP_USING_EPWM17 + [EPWM17_INDEX] = EPWM_DRV_INIT(17, EPWM_COUNTER_MODE_UP_DOWN, + EPWM_CLOCK_DIVIDER_2, EPWM_HSCLOCK_DIVIDER_1), +#endif +#ifdef BSP_USING_EPWM18 + [EPWM18_INDEX] = EPWM_DRV_INIT(18, EPWM_COUNTER_MODE_UP_DOWN, + EPWM_CLOCK_DIVIDER_2, EPWM_HSCLOCK_DIVIDER_1), +#endif +}; + +static struct ns800_epwm ns800_epwm_obj[sizeof(epwm_conf) / sizeof(epwm_conf[0])]; + +static void ns800_epwm_gpio_init(const struct ns800_epwm_pin_config *pin_config) +{ + GPIO_setAnalogMode(pin_config->port_a, pin_config->pin_a, GPIO_ANALOG_DISABLED); + GPIO_setPinConfig(pin_config->port_a, pin_config->pin_a, pin_config->mux_a); + GPIO_setPadConfig(pin_config->port_a, pin_config->pin_a, GPIO_PIN_TYPE_STD); + GPIO_setQualificationMode(pin_config->port_a, pin_config->pin_a, GPIO_QUAL_SYNC); + + GPIO_setAnalogMode(pin_config->port_b, pin_config->pin_b, GPIO_ANALOG_DISABLED); + GPIO_setPinConfig(pin_config->port_b, pin_config->pin_b, pin_config->mux_b); + GPIO_setPadConfig(pin_config->port_b, pin_config->pin_b, GPIO_PIN_TYPE_STD); + GPIO_setQualificationMode(pin_config->port_b, pin_config->pin_b, GPIO_QUAL_SYNC); +} + +static rt_err_t configuration_convert(struct ns800_epwm *device, + struct rt_pwm_configuration *rt_conf, + struct ns800_signal_params *signal_params) +{ + float deadband_val = 0.0f; + const struct ns800_epwm_config *epwm_config; + + epwm_config = device->epwm_config; + + if ((EPWMX_A != rt_conf->channel) && (EPWMX_B != rt_conf->channel)) + { + return -RT_EINVAL; + } + + if ((rt_conf->pulse > rt_conf->period) || (RT_FALSE == (!!rt_conf->period))) + { + return -RT_EINVAL; + } + + if (epwm_config->count_mode == EPWM_COUNTER_MODE_UP_DOWN) + { + signal_params->signal_freq = 1.0f / ((float)rt_conf->period / 1000000.0f); + } + else if (epwm_config->count_mode < EPWM_COUNTER_MODE_UP_DOWN) + { + signal_params->signal_freq = 1.0f / ((float)rt_conf->period / 1000000.0f) / 2.0f; + } + + signal_params->duty_val = ((float)rt_conf->pulse / (float)rt_conf->period); + signal_params->sys_clk_freq = (float)RCC_getPclk1Frequency(); + signal_params->invert_signal_b = (rt_conf->complementary == RT_TRUE); + signal_params->count_mode = READ_BIT(epwm_config->instance->TBCTL.WORDVAL, + EPWM_TBCTL_CTRMODE_M); + signal_params->clock_div = epwm_config->clock_div; + signal_params->hs_clock_div = epwm_config->hs_clock_div; + signal_params->dead_band_val = 0; + + if (signal_params->hs_clock_div <= EPWM_HSCLOCK_DIVIDER_4) + { + deadband_val = (float)rt_conf->dead_time / (10.0f * (float)(1U << (uint16_t)signal_params->hs_clock_div)); + signal_params->dead_band_val = deadband_val; + } + + return RT_EOK; +} + +static void ns800_epwm_hw_init(EPWM_TypeDef *epwm) +{ + EPWM_setClockPrescaler(epwm, EPWM_CLOCK_DIVIDER_1, EPWM_HSCLOCK_DIVIDER_2); + EPWM_setTimeBasePeriod(epwm, 0); + EPWM_setTimeBaseCounter(epwm, 0); + EPWM_setTimeBaseCounterMode(epwm, EPWM_COUNTER_MODE_STOP_FREEZE); + EPWM_disablePhaseShiftLoad(epwm); + EPWM_setPhaseShift(epwm, 0); + EPWM_setCounterCompareValue(epwm, EPWM_COUNTER_COMPARE_A, 0); + EPWM_setCounterCompareShadowLoadMode(epwm, EPWM_COUNTER_COMPARE_A, EPWM_COMP_LOAD_ON_CNTR_ZERO); + EPWM_setCounterCompareValue(epwm, EPWM_COUNTER_COMPARE_B, 0); + EPWM_setCounterCompareShadowLoadMode(epwm, EPWM_COUNTER_COMPARE_B, EPWM_COMP_LOAD_ON_CNTR_ZERO); + EPWM_setActionQualifierAction(epwm, EPWM_AQ_OUTPUT_A, EPWM_AQ_OUTPUT_NO_CHANGE, EPWM_AQ_OUTPUT_ON_TIMEBASE_ZERO); + EPWM_setActionQualifierAction(epwm, EPWM_AQ_OUTPUT_A, EPWM_AQ_OUTPUT_NO_CHANGE, EPWM_AQ_OUTPUT_ON_TIMEBASE_PERIOD); + EPWM_setActionQualifierAction(epwm, EPWM_AQ_OUTPUT_A, EPWM_AQ_OUTPUT_NO_CHANGE, EPWM_AQ_OUTPUT_ON_TIMEBASE_UP_CMPA); + EPWM_setActionQualifierAction(epwm, EPWM_AQ_OUTPUT_A, EPWM_AQ_OUTPUT_NO_CHANGE, EPWM_AQ_OUTPUT_ON_TIMEBASE_DOWN_CMPA); + EPWM_setActionQualifierAction(epwm, EPWM_AQ_OUTPUT_A, EPWM_AQ_OUTPUT_NO_CHANGE, EPWM_AQ_OUTPUT_ON_TIMEBASE_UP_CMPB); + EPWM_setActionQualifierAction(epwm, EPWM_AQ_OUTPUT_A, EPWM_AQ_OUTPUT_NO_CHANGE, EPWM_AQ_OUTPUT_ON_TIMEBASE_DOWN_CMPB); + EPWM_setActionQualifierAction(epwm, EPWM_AQ_OUTPUT_B, EPWM_AQ_OUTPUT_NO_CHANGE, EPWM_AQ_OUTPUT_ON_TIMEBASE_ZERO); + EPWM_setActionQualifierAction(epwm, EPWM_AQ_OUTPUT_B, EPWM_AQ_OUTPUT_NO_CHANGE, EPWM_AQ_OUTPUT_ON_TIMEBASE_PERIOD); + EPWM_setActionQualifierAction(epwm, EPWM_AQ_OUTPUT_B, EPWM_AQ_OUTPUT_NO_CHANGE, EPWM_AQ_OUTPUT_ON_TIMEBASE_UP_CMPA); + EPWM_setActionQualifierAction(epwm, EPWM_AQ_OUTPUT_B, EPWM_AQ_OUTPUT_NO_CHANGE, EPWM_AQ_OUTPUT_ON_TIMEBASE_DOWN_CMPA); + EPWM_setActionQualifierAction(epwm, EPWM_AQ_OUTPUT_B, EPWM_AQ_OUTPUT_NO_CHANGE, EPWM_AQ_OUTPUT_ON_TIMEBASE_UP_CMPB); + EPWM_setActionQualifierAction(epwm, EPWM_AQ_OUTPUT_B, EPWM_AQ_OUTPUT_NO_CHANGE, EPWM_AQ_OUTPUT_ON_TIMEBASE_DOWN_CMPB); + EPWM_setRisingEdgeDelayCountShadowLoadMode(epwm, EPWM_RED_LOAD_ON_CNTR_ZERO); + EPWM_disableRisingEdgeDelayCountShadowLoadMode(epwm); + EPWM_setFallingEdgeDelayCountShadowLoadMode(epwm, EPWM_FED_LOAD_ON_CNTR_ZERO); + EPWM_disableFallingEdgeDelayCountShadowLoadMode(epwm); +} + +static void ns800_epwm_configure_signal(rt_int32_t channel, EPWM_TypeDef *epwm, const struct ns800_signal_params *signal_params) +{ + float time_base_clock = 0.0F; + uint16_t time_base_period = 0U, cmp_val = 0U; + + EPWM_setClockPrescaler(epwm, signal_params->clock_div, signal_params->hs_clock_div); + EPWM_setTimeBaseCounterMode(epwm, signal_params->count_mode); + + time_base_clock = ((float)signal_params->sys_clk_freq / (float)(1U << (uint16_t)signal_params->clock_div)); + + if (signal_params->hs_clock_div <= EPWM_HSCLOCK_DIVIDER_4) + { + time_base_clock /= (float)(1U << (uint16_t)signal_params->hs_clock_div); + } + else + { + time_base_clock /= (float)(2U * (uint16_t)signal_params->hs_clock_div); + } + + if (signal_params->count_mode == EPWM_COUNTER_MODE_UP) + { + time_base_period = (uint16_t)((time_base_clock / signal_params->signal_freq) - 1.0f); + cmp_val = (uint16_t)(signal_params->duty_val * (float)(time_base_period + 1U)); + } + else if (signal_params->count_mode == EPWM_COUNTER_MODE_DOWN) + { + time_base_period = (uint16_t)((time_base_clock / signal_params->signal_freq) - 1.0f); + cmp_val = (uint16_t)((float)(time_base_period + 1U) - (signal_params->duty_val * (float)(time_base_period + 1U))); + } + else + { + time_base_period = (uint16_t)(time_base_clock / (2.0f * signal_params->signal_freq)); + cmp_val = (uint16_t)(((float)time_base_period - ((signal_params->duty_val * (float)time_base_period))) + 0.5f); + } + + EPWM_setTimeBasePeriod(epwm, time_base_period); + EPWM_disablePhaseShiftLoad(epwm); + EPWM_setPhaseShift(epwm, 0U); + EPWM_setTimeBaseCounter(epwm, 0U); + + if (channel == EPWMX_A) + { + EPWM_setCounterCompareShadowLoadMode(epwm, EPWM_COUNTER_COMPARE_A, EPWM_COMP_LOAD_ON_CNTR_ZERO); + EPWM_setCounterCompareValue(epwm, EPWM_COUNTER_COMPARE_A, cmp_val); + } + else if(channel == EPWMX_B) + { + EPWM_setCounterCompareShadowLoadMode(epwm, EPWM_COUNTER_COMPARE_B, EPWM_COMP_LOAD_ON_CNTR_ZERO); + EPWM_setCounterCompareValue(epwm, EPWM_COUNTER_COMPARE_B, cmp_val); + } + + if (signal_params->count_mode == EPWM_COUNTER_MODE_UP) + { + if (channel == EPWMX_A) + { + EPWM_setActionQualifierAction(epwm, EPWM_AQ_OUTPUT_A, EPWM_AQ_OUTPUT_HIGH, EPWM_AQ_OUTPUT_ON_TIMEBASE_ZERO); + EPWM_setActionQualifierAction(epwm, EPWM_AQ_OUTPUT_A, EPWM_AQ_OUTPUT_LOW, EPWM_AQ_OUTPUT_ON_TIMEBASE_UP_CMPA); + } + else if(channel == EPWMX_B) + { + if (signal_params->invert_signal_b == RT_TRUE) + { + EPWM_setActionQualifierAction(epwm, EPWM_AQ_OUTPUT_B, EPWM_AQ_OUTPUT_LOW, EPWM_AQ_OUTPUT_ON_TIMEBASE_ZERO); + EPWM_setActionQualifierAction(epwm, EPWM_AQ_OUTPUT_B, EPWM_AQ_OUTPUT_HIGH, EPWM_AQ_OUTPUT_ON_TIMEBASE_UP_CMPB); + } + else + { + EPWM_setActionQualifierAction(epwm, EPWM_AQ_OUTPUT_B, EPWM_AQ_OUTPUT_HIGH, EPWM_AQ_OUTPUT_ON_TIMEBASE_ZERO); + EPWM_setActionQualifierAction(epwm, EPWM_AQ_OUTPUT_B, EPWM_AQ_OUTPUT_LOW, EPWM_AQ_OUTPUT_ON_TIMEBASE_UP_CMPB); + } + } + } + else if ((signal_params->count_mode == EPWM_COUNTER_MODE_DOWN)) + { + if (channel == EPWMX_A) + { + EPWM_setActionQualifierAction(epwm, EPWM_AQ_OUTPUT_A, EPWM_AQ_OUTPUT_HIGH, EPWM_AQ_OUTPUT_ON_TIMEBASE_ZERO); + EPWM_setActionQualifierAction(epwm, EPWM_AQ_OUTPUT_A, EPWM_AQ_OUTPUT_LOW, EPWM_AQ_OUTPUT_ON_TIMEBASE_DOWN_CMPA); + } + else if(channel == EPWMX_B) + { + if (signal_params->invert_signal_b == RT_TRUE) + { + EPWM_setActionQualifierAction(epwm, EPWM_AQ_OUTPUT_B, EPWM_AQ_OUTPUT_LOW, EPWM_AQ_OUTPUT_ON_TIMEBASE_ZERO); + EPWM_setActionQualifierAction(epwm, EPWM_AQ_OUTPUT_B, EPWM_AQ_OUTPUT_HIGH, EPWM_AQ_OUTPUT_ON_TIMEBASE_DOWN_CMPB); + } + else + { + EPWM_setActionQualifierAction(epwm, EPWM_AQ_OUTPUT_B, EPWM_AQ_OUTPUT_HIGH, EPWM_AQ_OUTPUT_ON_TIMEBASE_ZERO); + EPWM_setActionQualifierAction(epwm, EPWM_AQ_OUTPUT_B, EPWM_AQ_OUTPUT_LOW, EPWM_AQ_OUTPUT_ON_TIMEBASE_DOWN_CMPB); + } + } + } + else // UP_DOWN 对称模式 + { + if (channel == EPWMX_A) + { + EPWM_setActionQualifierAction(epwm, EPWM_AQ_OUTPUT_A, EPWM_AQ_OUTPUT_LOW, EPWM_AQ_OUTPUT_ON_TIMEBASE_ZERO); + EPWM_setActionQualifierAction(epwm, EPWM_AQ_OUTPUT_A, EPWM_AQ_OUTPUT_HIGH, EPWM_AQ_OUTPUT_ON_TIMEBASE_UP_CMPA); + EPWM_setActionQualifierAction(epwm, EPWM_AQ_OUTPUT_A, EPWM_AQ_OUTPUT_LOW, EPWM_AQ_OUTPUT_ON_TIMEBASE_DOWN_CMPA); + } + else if(channel == EPWMX_B) + { + if (signal_params->invert_signal_b == RT_TRUE) + { + EPWM_setActionQualifierAction(epwm, EPWM_AQ_OUTPUT_B, EPWM_AQ_OUTPUT_HIGH, EPWM_AQ_OUTPUT_ON_TIMEBASE_ZERO); + EPWM_setActionQualifierAction(epwm, EPWM_AQ_OUTPUT_B, EPWM_AQ_OUTPUT_LOW, EPWM_AQ_OUTPUT_ON_TIMEBASE_UP_CMPB); + EPWM_setActionQualifierAction(epwm, EPWM_AQ_OUTPUT_B, EPWM_AQ_OUTPUT_HIGH, EPWM_AQ_OUTPUT_ON_TIMEBASE_DOWN_CMPB); + } + else + { + EPWM_setActionQualifierAction(epwm, EPWM_AQ_OUTPUT_B, EPWM_AQ_OUTPUT_LOW, EPWM_AQ_OUTPUT_ON_TIMEBASE_ZERO); + EPWM_setActionQualifierAction(epwm, EPWM_AQ_OUTPUT_B, EPWM_AQ_OUTPUT_HIGH, EPWM_AQ_OUTPUT_ON_TIMEBASE_UP_CMPB); + EPWM_setActionQualifierAction(epwm, EPWM_AQ_OUTPUT_B, EPWM_AQ_OUTPUT_LOW, EPWM_AQ_OUTPUT_ON_TIMEBASE_DOWN_CMPB); + } + } + } + + EPWM_setDeadBandDelayPolarity(epwm, EPWM_DB_RED, EPWM_DB_POLARITY_ACTIVE_LOW); + EPWM_setDeadBandDelayPolarity(epwm, EPWM_DB_FED, EPWM_DB_POLARITY_ACTIVE_LOW); + + EPWM_setDeadBandDelayMode(epwm, EPWM_DB_RED, RT_TRUE); + EPWM_setRisingEdgeDelayCountShadowLoadMode(epwm, EPWM_RED_LOAD_ON_CNTR_ZERO); + EPWM_disableRisingEdgeDelayCountShadowLoadMode(epwm); + EPWM_setRisingEdgeDelayCount(epwm, (uint16_t)signal_params->dead_band_val); + + EPWM_setDeadBandDelayMode(epwm, EPWM_DB_FED, RT_TRUE); + EPWM_setFallingEdgeDelayCountShadowLoadMode(epwm, EPWM_FED_LOAD_ON_CNTR_ZERO); + EPWM_disableFallingEdgeDelayCountShadowLoadMode(epwm); + EPWM_setFallingEdgeDelayCount(epwm, (uint16_t)signal_params->dead_band_val); +} + +static rt_err_t ns800_epwm_drv_set(struct ns800_epwm *device, struct rt_pwm_configuration *rt_conf) +{ + rt_err_t ret; + struct ns800_signal_params signal_params; + + RT_ASSERT(RT_NULL != device); + RT_ASSERT(RT_NULL != device->epwm_config); + RT_ASSERT(RT_NULL != rt_conf); + + ret = configuration_convert(device, rt_conf, &signal_params); + if (ret != RT_EOK) + { + return ret; + } + + device->current_period = rt_conf->period; + device->current_pulse = rt_conf->pulse; + + ns800_epwm_configure_signal(rt_conf->channel, device->epwm_config->instance, &signal_params); + + return ret; +} + +static rt_err_t ns800_epwm_drv_get(struct ns800_epwm *device, struct rt_pwm_configuration *rt_conf) +{ + RT_ASSERT(RT_NULL != device); + RT_ASSERT(RT_NULL != rt_conf); + + rt_conf->period = device->current_period; + rt_conf->pulse = device->current_pulse; + + return RT_EOK; +} + +/** + * @brief Configure EPWM slave sync phase offset + * @param epwm_slave EPWM device pointer to a rt_epwm_slave_phase_ext structure + * @param ext Extended slave phase config parameter + * @return RT_EOK for success or error number + */ +static rt_err_t ns800_epwm_set_slave_phase(struct ns800_epwm *epwm_slave, + struct rt_epwm_slave_phase_ext *ext) +{ + struct ns800_epwm *epwm_master = RT_NULL; + struct rt_device_pwm *master_dev = RT_NULL; + EPWM_TypeDef *master_base = RT_NULL; + EPWM_TypeDef *slave_base = RT_NULL; + rt_uint32_t period_val = 0, phase_val = 0; + + RT_ASSERT(RT_NULL != epwm_slave); + RT_ASSERT(RT_NULL != ext); + RT_ASSERT(RT_NULL != ext->master_dev); + + if (ext->phase_angle > 360) + { + return -RT_EINVAL; + } + + master_dev = (struct rt_device_pwm *)(ext->master_dev); + epwm_master = rt_container_of(master_dev, struct ns800_epwm, epwm_device); + master_base = epwm_master->epwm_config->instance; + slave_base = epwm_slave->epwm_config->instance; + + /* Read Period value to calculate value for Phase Register */ + period_val = EPWM_getTimeBasePeriod(master_base); + /* Caluclate phase register values based on Time Base counter mode */ + if (slave_base->TBCTL.BIT.CTRMODE == EPWM_COUNTER_MODE_UP_DOWN) + { + phase_val = (2U * period_val * ext->phase_angle) / 360U; + } + else if (slave_base->TBCTL.BIT.CTRMODE < EPWM_COUNTER_MODE_UP_DOWN) + { + phase_val = (period_val * ext->phase_angle) / 360U; + } + + EPWM_selectPeriodLoadEvent(slave_base, EPWM_SHADOW_LOAD_MODE_SYNC); + EPWM_disablePhaseShiftLoad(slave_base); + EPWM_setPhaseShift(slave_base, phase_val); + EPWM_enablePhaseShiftLoad(slave_base); + EPWM_setTimeBaseCounter(slave_base, phase_val); + + return RT_EOK; +} + +static rt_err_t ns800_epwm_drv_enable(struct ns800_epwm *device) +{ + const struct ns800_epwm_config *epwm_config = device->epwm_config; + EPWM_setTimeBaseCounterMode(epwm_config->instance, epwm_config->count_mode); + return RT_EOK; +} + +static rt_err_t ns800_epwm_drv_disable(struct ns800_epwm *device) +{ + const struct ns800_epwm_config *epwm_config = device->epwm_config; + EPWM_setTimeBaseCounterMode(epwm_config->instance, EPWM_COUNTER_MODE_STOP_FREEZE); + return RT_EOK; +} + +static rt_err_t ns800_drv_pwm_control(struct rt_device_pwm *device, int cmd, void *arg) +{ + struct rt_pwm_configuration *conf = RT_NULL; + struct rt_epwm_slave_phase_ext *epwm_slave = RT_NULL; + struct ns800_epwm *epwm = RT_NULL; + rt_err_t ret = RT_EOK; + + epwm = rt_container_of(device, struct ns800_epwm, epwm_device); + + switch (cmd) + { + case PWM_CMD_ENABLE: + ret = ns800_epwm_drv_enable(epwm); + break; + case PWM_CMD_DISABLE: + ret = ns800_epwm_drv_disable(epwm); + break; + case PWM_CMD_SET: + conf = (struct rt_pwm_configuration *)arg; + ret = ns800_epwm_drv_set(epwm, conf); + break; + case PWM_CMD_GET: + conf = (struct rt_pwm_configuration *)arg; + ret = ns800_epwm_drv_get(epwm, conf); + break; + case PWM_CMD_EXT_SET_SLAVE_PHASE: + epwm_slave = (struct rt_epwm_slave_phase_ext *)arg; + ret = ns800_epwm_set_slave_phase(epwm, epwm_slave); + break; + default: + ret = -RT_EINVAL; + break; + } + + return ret; +} + +static const struct rt_pwm_ops drv_ops = +{ + ns800_drv_pwm_control +}; + +int ns800_epwm_init(void) +{ + rt_err_t result = RT_EOK; + rt_size_t i; + struct ns800_epwm *device = RT_NULL; + + SYSCON_UNLOCK; + SYSCON_setTbClkSync(SYSCON, false); + SYSCON_LOCK; + + for (i = 0; i < (sizeof(epwm_conf) / sizeof(epwm_conf[0])); i++) + { + device = &ns800_epwm_obj[i]; + device->pin_config = &epwm_pins[i]; + device->epwm_config = &epwm_conf[i]; + device->current_period = 0; + device->current_pulse = 0; + + ns800_epwm_gpio_init(device->pin_config); + ns800_epwm_hw_init(device->epwm_config->instance); + + result = rt_device_pwm_register(&ns800_epwm_obj[i].epwm_device, + epwm_conf[i].name, + &drv_ops, + &ns800_epwm_obj[i]); + RT_ASSERT(result == RT_EOK); + } + + SYSCON_UNLOCK; + SYSCON_setTbClkSync(SYSCON, true); + SYSCON_LOCK; + + return result; +} +INIT_DEVICE_EXPORT(ns800_epwm_init); + +#endif /* #if defined(BSP_USING_EPWM) */ \ No newline at end of file diff --git a/bsp/novosns/ns800/libraries/HAL_Drivers/drivers/drv_epwm.h b/bsp/novosns/ns800/libraries/HAL_Drivers/drivers/drv_epwm.h new file mode 100644 index 00000000000..079fc7b9af7 --- /dev/null +++ b/bsp/novosns/ns800/libraries/HAL_Drivers/drivers/drv_epwm.h @@ -0,0 +1,62 @@ +/**************************************************************************//** +* +* @copyright (C) 2026 Novosense Technology Corp. All rights reserved. +* +* SPDX-License-Identifier: Apache-2.0 +* +* Change Logs: +* Date Author Notes +* 2026-6-15 Eric First version +* +******************************************************************************/ + +#ifndef __DRV_EPWM_H__ +#define __DRV_EPWM_H__ + +#include + +/* custom command to configure phase */ +#define PWM_CMD_EXT_SET_SLAVE_PHASE (RT_DEVICE_CTRL_BASE(PWM) + 99) + +#define EPWM_PIN_INFO(epwm_port_a, epwm_pin_a, pin_mux_a, \ + epwm_port_b, epwm_pin_b, pin_mux_b) \ + { \ + .port_a = epwm_port_a, \ + .pin_a = epwm_pin_a, \ + .mux_a = pin_mux_a, \ + .port_b = epwm_port_b, \ + .pin_b = epwm_pin_b, \ + .mux_b = pin_mux_b \ + } + +#define EPWM_DRV_INIT(num, cnt_mode, clk_div, hs_clk_div) \ + { \ + .name = "epwm"#num , \ + .instance = EPWM##num, \ + .count_mode = cnt_mode, \ + .clock_div = clk_div, \ + .hs_clock_div = hs_clk_div \ + } + +/** + * @brief EPWMx channel + */ +enum +{ + EPWMX_A = 0, + EPWMX_B +}; + +/** + * @brief EPWMx phase configuration + */ +struct rt_epwm_slave_phase_ext +{ + /* EPWM master reference device, + slave pwm phase compare with this master devcie */ + rt_device_t master_dev; + /* unit: degree, 0~360 */ + rt_uint32_t phase_angle; +}; + +#endif diff --git a/bsp/novosns/ns800/ns800rt7p65-nssinepad/.ci/attachconfig/ci.attachconfig.yml b/bsp/novosns/ns800/ns800rt7p65-nssinepad/.ci/attachconfig/ci.attachconfig.yml index c1aa4777e4b..70332c07d91 100644 --- a/bsp/novosns/ns800/ns800rt7p65-nssinepad/.ci/attachconfig/ci.attachconfig.yml +++ b/bsp/novosns/ns800/ns800rt7p65-nssinepad/.ci/attachconfig/ci.attachconfig.yml @@ -22,4 +22,27 @@ devices.wdt: - CONFIG_BSP_USING_WDT=y - CONFIG_BSP_USING_IWDG1=y - CONFIG_BSP_USING_IWDG2=y - - CONFIG_BSP_USING_WWDG=y \ No newline at end of file + - CONFIG_BSP_USING_WWDG=y +devices.epwm: + <<: *scons + kconfig: + - CONFIG_RT_USING_PWM=y + - CONFIG_BSP_USING_EPWM=y + - CONFIG_BSP_USING_EPWM1=y + - CONFIG_BSP_USING_EPWM2=y + - CONFIG_BSP_USING_EPWM3=y + - CONFIG_BSP_USING_EPWM4=y + - CONFIG_BSP_USING_EPWM5=y + - CONFIG_BSP_USING_EPWM6=y + - CONFIG_BSP_USING_EPWM7=y + - CONFIG_BSP_USING_EPWM8=y + - CONFIG_BSP_USING_EPWM9=y + - CONFIG_BSP_USING_EPWM10=y + - CONFIG_BSP_USING_EPWM11=y + - CONFIG_BSP_USING_EPWM12=y + - CONFIG_BSP_USING_EPWM13=y + - CONFIG_BSP_USING_EPWM14=y + - CONFIG_BSP_USING_EPWM15=y + - CONFIG_BSP_USING_EPWM16=y + - CONFIG_BSP_USING_EPWM17=y + - CONFIG_BSP_USING_EPWM18=y \ No newline at end of file diff --git a/bsp/novosns/ns800/ns800rt7p65-nssinepad/board/Kconfig b/bsp/novosns/ns800/ns800rt7p65-nssinepad/board/Kconfig index b23da33d13c..2ee7710bcd1 100644 --- a/bsp/novosns/ns800/ns800rt7p65-nssinepad/board/Kconfig +++ b/bsp/novosns/ns800/ns800rt7p65-nssinepad/board/Kconfig @@ -229,4 +229,82 @@ menu "On-chip Peripheral Drivers" default n endif + menuconfig BSP_USING_EPWM + bool "Enable EPWM" + select RT_USING_PWM + default n + if BSP_USING_EPWM + config BSP_USING_EPWM1 + bool "Enable EPWM1" + default n + + config BSP_USING_EPWM2 + bool "Enable EPWM2" + default n + + config BSP_USING_EPWM3 + bool "Enable EPWM3" + default n + + config BSP_USING_EPWM4 + bool "Enable EPWM4" + default n + + config BSP_USING_EPWM5 + bool "Enable EPWM5" + default n + + config BSP_USING_EPWM6 + bool "Enable EPWM6" + default n + + config BSP_USING_EPWM7 + bool "Enable EPWM7" + default n + + config BSP_USING_EPWM8 + bool "Enable EPWM8" + default n + + config BSP_USING_EPWM9 + bool "Enable EPWM9" + default n + + config BSP_USING_EPWM10 + bool "Enable EPWM10" + default n + + config BSP_USING_EPWM11 + bool "Enable EPWM11" + default n + + config BSP_USING_EPWM12 + bool "Enable EPWM12" + default n + + config BSP_USING_EPWM13 + bool "Enable EPWM13" + default n + + config BSP_USING_EPWM14 + bool "Enable EPWM14" + default n + + config BSP_USING_EPWM15 + bool "Enable EPWM15" + default n + + config BSP_USING_EPWM16 + bool "Enable EPWM16" + default n + + config BSP_USING_EPWM17 + bool "Enable EPWM17" + default n + + config BSP_USING_EPWM18 + bool "Enable EPWM18" + default n + endif + endmenu