/*! * \file xc_drv_pwm.c * * \brief Target xc pwm driver implementation * * \copyright Revised BSD License, see section \ref LICENSE. * * \code * * _ __ _ ________ _ * | |/ /(_)___ / ____/ /_ (_)___ * | // / __ \/ / / __ \/ / __ \ * / |/ / / / / /___/ / / / / /_/ / * /_/|_/_/_/ /_/\____/_/ /_/_/ .___/ * /_/ * (C) 2022-2025 XinChip * * \endcode * * \author ( XinChip ) Alex-J * * \author ( XinChip ) */ /*------------------------------------------------------------------------------------ INCLUDE HEADE FILES -------------------------------------------------------------------------------------*/ #include "xc_drv_pwm.h" #include "xc_drv_gpio.h" /*------------------------------------------------------------------------------------ Macros -------------------------------------------------------------------------------------*/ /*------------------------------------------------------------------------------------ Global Variables -------------------------------------------------------------------------------------*/ /*------------------------------------------------------------------------------------ TypeDef -------------------------------------------------------------------------------------*/ typedef enum { STATE_UNINITIALIZED, STATE_INITIALIZED, } xincx_drv_state_t; pwm_handler_callback pwm_n_callback[3] = { pwm_capture_ch0_callback, pwm_capture_ch1_callback, pwm_capture_ch2_callback, }; /*------------------------------------------------------------------------------------ Local Variables -------------------------------------------------------------------------------------*/ static uint32_t pwm_clk_init_state = STATE_UNINITIALIZED; static uint16_t pwm_freq_to_period(PWM_InitCfg_t *pwm_cfg, PWM_ClkDiv_TypeDef div_clk); double period; /*------------------------------------------------------------------------------------ Func Prototype -------------------------------------------------------------------------------------*/ /*------------------------------------------------------------------------------------ Functions -------------------------------------------------------------------------------------*/ void xc_pwm_init(uint8_t reg_idx, PWM_InitCfg_t *init_cfg) { if (pwm_clk_init_state == STATE_UNINITIALIZED) { cpr_ctlapbclken_grctl__pwm_pclk_en__setf(ENABLE); cpr_rstctl_ctlapb_sw__pwm_rstn__setf(RSTCTL_ENABLE); cpr_rstctl_ctlapb_sw__pwm_rstn__setf(RSTCTL_DISABLE); cpr_pwm_clk_ctl__pwm_clk_en__setf(ENABLE); cpr_pwm_clk_ctl__pwm_clksel__setf(init_cfg->SrcClk); cpr_pwm_clk_ctl__pwm_clk0_div__setf(init_cfg->DivClk); cpr_pwm_clk_ctl__pwm_clk1_div__setf(init_cfg->DivClk); pwm_clk_init_state = STATE_INITIALIZED; } pwm_pin_set(reg_idx, init_cfg); pwm_en__en__setf(reg_idx, DISABLE); pwm_en__en_sel__setf(reg_idx, init_cfg->SrcEnable); xc_pwm_dutycycle_set(reg_idx, init_cfg->DutyCycleAcc, init_cfg->DutyCycle); pwm_period__period__setf(reg_idx, pwm_freq_to_period(init_cfg, PWM_CLK_DIV0)); pwm_compen__pwmcompen__setf(reg_idx, init_cfg->InvertEnable); pwm_comptime__comptime__setf(reg_idx, init_cfg->InvertDelay); } void xc_pwm_start(uint8_t reg_idx) { pwm_en__en__setf(reg_idx, PWM_EN_ENABLE); } void xc_pwm_stop(uint8_t reg_idx) { pwm_en__en__setf(reg_idx, PWM_EN_DISABLE); } void pwm_src_enable_set(uint8_t reg_idx, uint8_t src_enable) { pwm_en__en_sel__setf(reg_idx, src_enable); } void xc_pwm_start_all(void) { pwm_en__pwm_en_all__setf(PWM0_IDX, PWM_EN_ALL_ENABLE); } void xc_pwm_stop_all(void) { pwm_en__pwm_en_all__setf(PWM0_IDX, PWM_EN_ALL_DISABLE); } void pwm_pin_set(uint8_t reg_idx, PWM_InitCfg_t *pwm_cfg) { GPIO_InitCfg_t gpio_cfg; if(pwm_cfg->OutputPin==GPIO_11||pwm_cfg->OutputPin==GPIO_12||pwm_cfg->OutputPin==GPIO_13){ gpio_cfg.Mux = GPIO_Mux1; }else { gpio_cfg.Mux = GPIO_Mux0; } gpio_cfg.Dir = GPIO_DIR_OUTPUT; gpio_cfg.Pull = GPIO_PULLDOWN; gpio_cfg.Int = NOT_INT; gpio_cfg.Pin = pwm_cfg->OutputPin; if (reg_idx == PWM0_IDX || reg_idx == PWM1_IDX) { gpio_cfg.FunSel = (reg_idx == PWM0_IDX) ? PWM0 : PWM1; xc_gpio_init(&gpio_cfg); if (pwm_cfg->InvertEnable) { gpio_cfg.FunSel = (reg_idx == PWM0_IDX) ? PWM0_INV : PWM1_INV; gpio_cfg.Pin = pwm_cfg->OutputInvertPin; xc_gpio_init(&gpio_cfg); } } else if (reg_idx == PWM2_IDX) { gpio_cfg.Mux = GPIO_Mux3; if (pwm_cfg->OutputPin == GPIO_12) { xc_gpio_init(&gpio_cfg); } } else if (reg_idx == PWM3_IDX) { gpio_cfg.Mux = GPIO_Mux3; if (pwm_cfg->OutputPin == GPIO_13) { xc_gpio_init(&gpio_cfg); } } else if (reg_idx == PWM4_IDX) { gpio_cfg.Mux = GPIO_Mux2; if (pwm_cfg->OutputPin == GPIO_0) { xc_gpio_init(&gpio_cfg); } } else if (reg_idx == PWM5_IDX) { gpio_cfg.Mux = GPIO_Mux2; if (pwm_cfg->OutputPin == GPIO_1) { xc_gpio_init(&gpio_cfg); } } } static uint16_t pwm_freq_to_period(PWM_InitCfg_t *pwm_cfg, PWM_ClkDiv_TypeDef div_clk) { uint32_t pwm_clk; switch (pwm_cfg->SrcClk) { case PWM_CLK_SRC_32M_DIV: { pwm_clk = xc_clock_hfclk_in_get() / PWM_CLK_DIV_CAL(div_clk); } break; case PWM_CLK_SRC_32K_DIV: { pwm_clk = xc_clock_lfclk_in_get() / PWM_CLK_DIV_CAL(div_clk); } break; case PWM_CLK_SRC_32K: { pwm_clk = CLOCK_LFCLK_IN_32K; } break; default: break; } uint32_t freq_max = PWM_FREQ_MAX_CAL(pwm_clk, pwm_cfg->DutyCycleAcc); uint32_t freq = PWM_FREQ_CAL(pwm_clk, pwm_cfg->DutyCycleAcc, pwm_cfg->Period); if (freq > freq_max) { DEBUG("%s,line=%d,set freq=%d,The maximum configurable frequency %d hz " "has been exceeded.\n", __func__, __LINE__, freq, freq_max); } else { DEBUG("%s,line=%d,set freq=%d,maximum configurable frequency %d hz\n", __func__, __LINE__, freq, freq_max); } return pwm_cfg->Period; } void xc_pwm_dutycycle_set(uint8_t reg_idx, uint32_t dutycycle_acc, uint32_t dutycycle) { pwm_en__mode__setf(reg_idx, PWM_EN_MODE_EDGE_ALIGNED); pwm_ocpy__ocpy_ratio_config__setf(reg_idx, (dutycycle_acc - 1)); pwm_ocpy__ocpy_ratio__setf(reg_idx, dutycycle_acc - dutycycle); pwm_up__update__setf(reg_idx, PWM_UP_UPDATE_ENABLE); } void xc_pwm_lowpower_enable(uint8_t reg_idx) { pwm_en__sleep_en__setf(reg_idx, PWM_EN_SLEEP_EN_ENABLE); } void xc_pwm_lowpower_disable(uint8_t reg_idx) { pwm_en__sleep_en__setf(reg_idx, PWM_EN_SLEEP_EN_DISABLE); } void xc_pwm_lowpower_countdirection_set(uint8_t reg_idx, uint32_t direction) { pwm_en__sleep_incr__setf(reg_idx, direction); } void xc_pwm_brake_enable(uint8_t reg_idx) { uint32_t val; val = pwm_break_ctl__pwm_brk_enable__getf(PWM0_IDX); if (reg_idx == PWM0_IDX || reg_idx == PWM1_IDX) { val &= ~(PWM_BRK0_ENABLE_ENABLE); val |= (PWM_BRK0_ENABLE_ENABLE); } else if (reg_idx == PWM2_IDX || reg_idx == PWM3_IDX) { val &= ~(PWM_BRK1_ENABLE_ENABLE); val |= (PWM_BRK1_ENABLE_ENABLE); } else if (reg_idx == PWM4_IDX || reg_idx == PWM5_IDX) { val &= ~(PWM_BRK2_ENABLE_ENABLE); val |= (PWM_BRK2_ENABLE_ENABLE); } pwm_break_ctl__pwm_brk_enable__setf(PWM0_IDX, val); } void xc_pwm_brake_disable(uint8_t reg_idx) { uint32_t val; val = pwm_break_ctl__pwm_brk_enable__getf(PWM0_IDX); if (reg_idx == PWM0_IDX || reg_idx == PWM1_IDX) { val &= ~(PWM_BRK0_ENABLE_ENABLE); } else if (reg_idx == PWM2_IDX || reg_idx == PWM3_IDX) { val &= ~(PWM_BRK1_ENABLE_ENABLE); } else if (reg_idx == PWM4_IDX || reg_idx == PWM5_IDX) { val &= ~(PWM_BRK2_ENABLE_ENABLE); } pwm_break_ctl__pwm_brk_enable__setf(PWM0_IDX, val); } uint8_t xc_pwm_brake_signal_valid_get(void) { return pwm_break_ctl__pwm_brk_sync__getf(PWM0_IDX); } void xc_pwm_brake_signal_mask_set(uint32_t mask) { pwm_break_ctl__pwm_brk_mask__setf(PWM0_IDX, mask); } void xc_pwm_brake_signal_trigger_level_set(uint32_t level) { pwm_break_ctl__pwm_brk_inv__setf(PWM0_IDX, level); } void xc_pwm_brake_recovery_mode_set(uint32_t mode) { pwm_break_ctl__brk_mode__setf(PWM0_IDX, mode); } uint8_t xc_pwm_brake_recovery_mode_get(void) { return (pwm_break_ctl__brk_mode__getf(PWM0_IDX)); } void xc_pwm_brake_debounce_set(uint32_t debounce, uint32_t step) { pwm_break_ctl__brk_dbc_en__setf(PWM0_IDX, debounce); pwm_break_ctl__brk_dbc_step__setf(PWM0_IDX, step); } void xc_pwm_brake_clear() { pwm_break_ctl__clear__setf(PWM0_IDX, PWM_BRK_BRK_CLEAR_EXIT); } void xc_pwm_capture_enable(uint8_t ch) { cap_tim_ctl__capture_enable__setf(ch, PWM_CAPTURE_ENABLE); } void xc_pwm_capture_disable(uint8_t ch) { cap_tim_ctl__capture_enable__setf(ch, PWM_CAPTURE_DISABLE); } void xc_pwm_capture_enable_it(uint8_t ch) { if (ch == 0) { pwm_cap_tim_int_en__capture_upd_0_en__setf(ENABLE); } else if (ch == 1) { pwm_cap_tim_int_en__capture_upd_1_en__setf(ENABLE); } else if (ch == 2) { pwm_cap_tim_int_en__capture_upd_2_en__setf(ENABLE); } } void xc_pwm_capture_disable_it(uint8_t ch) { if (ch == PWM_IC_CH0) { pwm_cap_tim_int_en__capture_upd_0_en__setf(DISABLE); } else if (ch == PWM_IC_CH1) { pwm_cap_tim_int_en__capture_upd_1_en__setf(DISABLE); } else if (ch == PWM_IC_CH2) { pwm_cap_tim_int_en__capture_upd_2_en__setf(DISABLE); } } void xc_pwm_capture_signal_set(uint8_t ch, uint32_t signal) { cap_tim_ctl__capture_sig_sel__setf(ch, signal); } void xc_pwm_capture_debounce_enable(uint8_t ch, uint32_t step) { cap_tim_ctl__dbc_en__setf(ch, PWM_CAPTURE_DBC_ENABLE); cap_tim_ctl__dbc_step__setf(ch, step); } void xc_pwm_capture_debounce_disable(uint8_t ch, uint32_t step) { cap_tim_ctl__dbc_en__setf(ch, PWM_CAPTURE_DBC_DISABLE); cap_tim_ctl__dbc_step__setf(ch, step); } void xc_pwm_capture_edge_set(uint8_t ch, uint32_t edge) { cap_tim_ctl__capture_mode__setf(ch, edge); } void xc_pwm_capture_psc_set(uint8_t ch, uint32_t psc) { cap_tim_ctl__capture_psc__setf(ch, psc); } void xc_pwm_capture_counter_enable(uint8_t ch) { cap_tim_ctl__common_cnt_enable__setf(ch, PWM_CAPTURE_COMMON_CNT_ENABLE); } void xc_pwm_capture_counter_disable(uint8_t ch) { cap_tim_ctl__common_cnt_enable__setf(ch, PWM_CAPTURE_COMMON_CNT_DISABLE); } uint16_t xc_pwm_capture_val_get(uint8_t ch) { return cap_tim_val__capture_value__getf(ch); } /* *----------------------------------------------------------------------------------------------- * PWM Timer *----------------------------------------------------------------------------------------------- */ /** **************************************************************************************** * @brief * * @param[in] * @param[in] **************************************************************************************** */ void xc_pwm_timer_init(uint8_t reg_idx, PWM_Timer_InitCfg_t *init_cfg) { if (reg_idx > PWM_TIMER5_IDX) return; if (pwm_clk_init_state == STATE_UNINITIALIZED) { cpr_ctlapbclken_grctl__pwm_pclk_en__setf(ENABLE); cpr_rstctl_ctlapb_sw__pwm_rstn__setf(RSTCTL_ENABLE); cpr_rstctl_ctlapb_sw__pwm_rstn__setf(RSTCTL_DISABLE); cpr_pwm_clk_ctl__pwm_clk_en__setf(ENABLE); cpr_pwm_clk_ctl__pwm_clksel__setf(init_cfg->src_clk); cpr_pwm_clk_ctl__pwm_clk0_div__setf(init_cfg->clk_div); cpr_pwm_clk_ctl__pwm_clk1_div__setf(init_cfg->clk_div); pwm_clk_init_state = STATE_INITIALIZED; } uint32_t ctl_reg = (init_cfg->timer_mode << TIMER_MODE_POS) | (init_cfg->timer_int_mask_en << TIMER_INT_MASK_POS) | (init_cfg->timer_pwm_en << TIMER_PWM_POS) | (init_cfg->timer_0to100_pwm_en << TIMER_ON10OPWM_EN_POS); pwm_timer_controlreg_set(reg_idx, ctl_reg); } void xc_pwm_timer_deinit(uint8_t reg_idx) { pwm_clk_init_state = STATE_UNINITIALIZED; cpr_ctlapbclken_grctl__pwm_pclk_en__setf(DISABLE); } /** **************************************************************************************** * @brief * * @param[in] * @param[in] **************************************************************************************** */ void xc_pwm_timer_set_freq(uint8_t reg_idx, uint32_t freq) { period = xc_clock_hfclk_in_get() / 2 / freq; } void xc_pwm_timer_set_dutycycle(uint8_t reg_idx, double dutycycle) { uint16_t high_cnt = ((uint32_t)(period * dutycycle) / 100); uint16_t low_cnt = (uint32_t)(period - high_cnt); pwm_timer_loadcount__timer_lc__setf(reg_idx, low_cnt); pwm_timer_loadcount2__timer_lc2__setf(reg_idx, high_cnt); } void xc_pwm_timer_set_high_cnt(uint8_t reg_idx, uint16_t high_cnt) { pwm_timer_loadcount2__timer_lc2__setf(reg_idx, high_cnt); } void xc_pwm_timer_set_low_cnt(uint8_t reg_idx, uint16_t low_cnt) { pwm_timer_loadcount__timer_lc__setf(reg_idx, low_cnt); } /** **************************************************************************************** * @brief * * @param[in] * @param[in] **************************************************************************************** */ void xc_pwm_timer_start(uint8_t reg_idx) { pwm_timer_controlreg__timer_en__setf(reg_idx, ENABLE); } void xc_pwm_timer_stop(uint8_t reg_idx) { pwm_timer_controlreg__timer_en__setf(reg_idx, DISABLE); } /*-----------------------------------------------------------------------------------------------*/ void PWM_Handler(void) { uint32_t cap_tim_int; cap_tim_int = pwm_cap_tim_int_get(); pwm_cap_tim_int_set(cap_tim_int); // clear inter if ((cap_tim_int & PWM_CAPTURE_UPD0_EN_ENABLE) == PWM_CAPTURE_UPD0_EN_ENABLE) { pwm_capture_ch0_callback(NULL); } if ((cap_tim_int & PWM_CAPTURE_UPD1_EN_ENABLE) == PWM_CAPTURE_UPD1_EN_ENABLE) { pwm_capture_ch1_callback(NULL); } if ((cap_tim_int & PWM_CAPTURE_UPD2_EN_ENABLE) == PWM_CAPTURE_UPD2_EN_ENABLE) { pwm_capture_ch2_callback(NULL); } } __WEAK uint8_t pwm_capture_ch0_callback(void *context) { return 0; } __WEAK uint8_t pwm_capture_ch1_callback(void *context) { return 0; } __WEAK uint8_t pwm_capture_ch2_callback(void *context) { return 0; }