Files
2026-06-06 16:49:48 +08:00

436 lines
14 KiB
C

/*!
* \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; }