Files
E3_boot/drivers/source/epwm/sdrv_epwm.c
2025-11-07 10:05:24 +08:00

982 lines
30 KiB
C

/**
* @file sdrv_epwm.c
* @brief sdrv epwm driver source file.
*
* @Copyright (c) 2022 Semidrive Semiconductor.
* @All rights reserved.
**/
#include "sdrv_epwm.h"
#include "bits.h"
#include "clock_ip.h"
#include "debug.h"
#include "irq.h"
#include "sdrv_epwm_reg.h"
#include "string.h"
/**
* @brief sdrv epwm ns transfer to val.
*
* @param[in] clk src clk
* @param[in] ns time val
* @param[in] div src clk divider
* @return ns_to_val
*/
uint32_t sdrv_epwm_ns_to_val(uint32_t clk, uint32_t ns, uint32_t div)
{
uint32_t clk_cnt_per_ms = (clk / (div + 1)) / 1000;
uint32_t ns_to_val = (uint32_t)((uint64_t)ns * clk_cnt_per_ms / 1000000);
return ns_to_val;
}
/**
* @brief sdrv epwm ns transfer to val and minus 1.
*
* @param[in] clk src clk
* @param[in] ns time val
* @param[in] div src clk divider
* @return ns_to_val_minus_1
*/
uint32_t sdrv_epwm_ns_to_val_1(uint32_t clk, uint32_t ns, uint32_t div)
{
uint32_t clk_cnt_per_ms = (clk / (div + 1)) / 1000;
uint32_t ns_to_val = (uint32_t)((uint64_t)ns * clk_cnt_per_ms / 1000000);
ns_to_val = ns_to_val - 1;
return ns_to_val;
}
/**
* @brief sdrv epwm val transfer to ns.
*
* @param[in] clk src clk
* @param[in] cnt time val
* @param[in] div src clk divider
* @return val_to_ns
*/
uint32_t sdrv_epwm_val_to_ns(uint32_t clk, uint32_t val, uint32_t div)
{
uint32_t clk_cnt_per_ms = (clk / (div + 1)) / 1000;
uint32_t val_to_ns = (uint32_t)((uint64_t)val * 1000000 / clk_cnt_per_ms);
return val_to_ns;
}
/**
* @brief Start ePWM channel output.
*
* This function start pwm output
*
* @param[in] dev pwm common instance
*
*/
void sdrv_epwm_start(sdrv_epwm_t *dev)
{
ASSERT(dev != NULL);
sdrv_epwm_cmp_en(dev, true);
sdrv_epwm_cnt_en(dev, true);
}
/**
* @brief Stop ePWM channel output.
*
* This function stop pwm output
*
* @param[in] dev pwm common instance
*
*/
void sdrv_epwm_stop(sdrv_epwm_t *dev)
{
sdrv_epwm_cmp_en(dev, false);
sdrv_epwm_cnt_en(dev, false);
}
/**
* @brief epwm interrupt handler
*
* @param[in] irq irq_num
* @param[in] arg input argument
*
*/
static int sdrv_epwm_irq_handle(uint32_t irq, void *arg)
{
sdrv_epwm_controller_t *epwm_ctrl = (sdrv_epwm_controller_t *)arg;
uint32_t int_sta = sdrv_epwm_lld_int_sta_get(epwm_ctrl->base);
sdrv_epwm_lld_int_sta_clr(epwm_ctrl->base, int_sta);
for (uint8_t id = SDRV_EPWM_CNT_G0; id < SDRV_EPWM_CNT_MAX_NUM; id++) {
if (BIT_SET(int_sta, SDRV_EPWM_STA_CNT_OVF_SHIFT(id))) {
sdrv_epwm_t *epwm_dev = epwm_ctrl->epwm_bank[id];
epwm_dev->cb(epwm_dev, int_sta);
}
}
return 0;
}
/**
* @brief ePWM channel config.
*
* This function configure epwm
*
* @param[in] dev pwm common instance
* @param[in] state pwm duty and period
*
*/
status_t sdrv_epwm_config(sdrv_epwm_t *dev, const pwm_state_t *state)
{
ASSERT(dev != NULL);
ASSERT(state != NULL);
sdrv_epwm_controller_t *ctrl = dev->controller;
sdrv_epwm_channel_e chnl = dev->chnl;
epwm_cmp_cfg_t *cmp_cfg = &(dev->cmp_cfg);
dev->base = ctrl->base;
uint32_t clk_freq = 0;
uint16_t waitTime = 0U;
status_t retValue = SDRV_STATUS_FAIL;
/* all epwm use same src clk */
if (ctrl->clk_src == SDRV_EPWM_ALTERNATIVE_HIGH_FREQUENCY_CLOCK) {
clk_freq = sdrv_ckgen_get_rate(CLK_NODE(g_ckgen_ip_xtrg));
} else {
clk_freq = sdrv_ckgen_get_rate(CLK_NODE(g_ckgen_ip_epwm1));
}
if ((state->duty1 > state->period) || (state->duty2 > state->period)) {
return SDRV_STATUS_INVALID_PARAM;
}
uint32_t cmp_pulse_wid0_cmp00_cnt = sdrv_epwm_ns_to_val_1(
clk_freq, cmp_cfg->cmp_pulse_wid0.cmp00, ctrl->clk_div);
// cmp_pulse_wid0.cmp00 SHOULD LESS THAN OR EQUAL TO 1/EPWM_SRC_CLK * 0xFF
uint32_t cmp_pulse_wid0_cmp01_cnt = sdrv_epwm_ns_to_val_1(
clk_freq, cmp_cfg->cmp_pulse_wid0.cmp01, ctrl->clk_div);
// cmp_pulse_wid0.cmp01 SHOULD LESS THAN OR EQUAL TO 1/EPWM_SRC_CLK * 0xFF
uint32_t cmp_pulse_wid0_cmp10_cnt = sdrv_epwm_ns_to_val_1(
clk_freq, cmp_cfg->cmp_pulse_wid0.cmp10, ctrl->clk_div);
// cmp_pulse_wid0.cmp10 SHOULD LESS THAN OR EQUAL TO 1/EPWM_SRC_CLK * 0xFF
uint32_t cmp_pulse_wid0_cmp11_cnt = sdrv_epwm_ns_to_val_1(
clk_freq, cmp_cfg->cmp_pulse_wid0.cmp11, ctrl->clk_div);
// cmp_pulse_wid0.cmp11 SHOULD LESS THAN OR EQUAL TO 1/EPWM_SRC_CLK * 0xFF
uint32_t cmp_pulse_wid1_cmp0_ovf = sdrv_epwm_ns_to_val_1(
clk_freq, cmp_cfg->cmp_pulse_wid1.cmp0_ovf, ctrl->clk_div);
// cmp_pulse_wid0.cmp0_ovf SHOULD LESS THAN OR EQUAL TO 1/EPWM_SRC_CLK *
// 0xFF
uint32_t cmp_pulse_wid1_cmp1_ovf = sdrv_epwm_ns_to_val_1(
clk_freq, cmp_cfg->cmp_pulse_wid1.cmp1_ovf, ctrl->clk_div);
// cmp_pulse_wid0.cmp1_ovf SHOULD LESS THAN OR EQUAL TO 1/EPWM_SRC_CLK *
// 0xFF
sdrv_epwm_cmp_cfg_t cfg;
memset(&cfg, 0, sizeof(cfg));
cfg.con_mode = cmp_cfg->con_mode;
cfg.cnt_sel = cmp_cfg->cmp_cnt_sel;
cfg.cmp_x_out_mode = cmp_cfg->chnl_out_mode;
cfg.cmp_x_mode = cmp_cfg->cmp_mode;
cfg.refresh_intval = cmp_cfg->refresh_intval;
cfg.out_mode.cmp00 = cmp_cfg->out_mode.cmp00;
cfg.out_mode.cmp01 = cmp_cfg->out_mode.cmp01;
cfg.out_mode.cmp10 = cmp_cfg->out_mode.cmp10;
cfg.out_mode.cmp11 = cmp_cfg->out_mode.cmp11;
cfg.out_mode.cmp0_ovf = cmp_cfg->out_mode.cmp0_ovf;
cfg.out_mode.cmp1_ovf = cmp_cfg->out_mode.cmp1_ovf;
cfg.wid0.cmp00 = cmp_pulse_wid0_cmp00_cnt;
cfg.wid0.cmp01 = cmp_pulse_wid0_cmp01_cnt;
cfg.wid0.cmp10 = cmp_pulse_wid0_cmp10_cnt;
cfg.wid0.cmp11 = cmp_pulse_wid0_cmp11_cnt;
cfg.wid1.cmp0_ovf = cmp_pulse_wid1_cmp0_ovf;
cfg.wid1.cmp1_ovf = cmp_pulse_wid1_cmp1_ovf;
cfg.sw_rld_mode = cmp_cfg->sw_rld_mode;
// clk cfg
sdrv_epwm_lld_clk_mon_en(dev->base, false, false);
sdrv_epwm_lld_clk_config(dev->base, ctrl->clk_src, ctrl->clk_div);
for(; waitTime < 1000U; waitTime++)
{
if(false == sdrv_epwm_lld_clk_config_div_num_upd_sta(dev->base))
{
retValue = SDRV_STATUS_OK;
break;
}
}
sdrv_epwm_lld_clk_mon_en(dev->base, true, true);
// cnt cfg
sdrv_epwm_cnt_ovf_upd(dev, state->period);
// dma cfg
if (cmp_cfg->dma_cfg.dma_enable) {
sdrv_epwm_lld_dma_wml(dev->base, chnl, cmp_cfg->dma_cfg.fifo_wml);
sdrv_epwm_lld_chn_dma_ctrl_chn_en(dev->base, chnl, true);
} else
sdrv_epwm_cmp_val_upd(dev, state);
#if CONFIG_E3L
if (cmp_cfg->center_align_mode)
sdrv_epwm_center_align_mode_en(dev, true);
#endif
sdrv_epwm_lld_cmp_config(dev->base, chnl, &cfg);
// irq cfg
ctrl->epwm_bank[chnl] = dev;
if (ctrl->irq > 0) {
sdrv_epwm_lld_int_enable(dev->base, ctrl->irq_id);
irq_attach(ctrl->irq, sdrv_epwm_irq_handle, ctrl);
irq_enable(ctrl->irq);
}
return retValue;
}
/**
* @brief epwm setup callback function
*
* @param[in] dev: epwm ctrl instance
* @param[in] callback: user callback function
* @return succeed:0 fail:other
*/
uint8_t sdrv_epwm_set_callback(sdrv_epwm_t *dev, pwm_callback_t callback)
{
ASSERT(dev != NULL);
dev->cb = callback;
return 0;
}
/**
* @brief compare channel enable.
*
* This function enable compare channel
*
* @param[in] dev pwm common instance
*
*/
void sdrv_epwm_cmp_en(sdrv_epwm_t *dev, bool en)
{
ASSERT(dev != NULL);
sdrv_epwm_channel_e chnl = dev->chnl;
sdrv_epwm_lld_cmp_ctrl_cmp_en(dev->base, chnl, en);
}
/**
* @brief counter enable.
*
* This function enable CNTG0 or CNT_G1
*
* @param[in] dev pwm common instance
*
*/
void sdrv_epwm_cnt_en(sdrv_epwm_t *dev, bool en)
{
ASSERT(dev != NULL);
epwm_cmp_cfg_t *cmp_cfg = &(dev->cmp_cfg);
sdrv_epwm_lld_cnt_en(dev->base, cmp_cfg->cmp_cnt_sel, en);
}
/**
* @brief cnt overflow value upload (unit is ns)
*
* This function upload counter overflow value
*
* @param[in] dev pwm common instance
* @param[in] period cnt overflow value
*/
void sdrv_epwm_cnt_ovf_upd(sdrv_epwm_t *dev, uint32_t period)
{
ASSERT(dev != NULL);
epwm_cmp_cfg_t *cmp_cfg = &(dev->cmp_cfg);
sdrv_epwm_controller_t *ctrl = dev->controller;
uint32_t period_cnt;
uint32_t clk_freq = 0;
/* all epwm use same src clk */
if (ctrl->clk_src == SDRV_EPWM_ALTERNATIVE_HIGH_FREQUENCY_CLOCK) {
clk_freq = sdrv_ckgen_get_rate(CLK_NODE(g_ckgen_ip_xtrg));
} else {
clk_freq = sdrv_ckgen_get_rate(CLK_NODE(g_ckgen_ip_epwm1));
}
if (cmp_cfg->audio_enable)
period_cnt = sdrv_epwm_ns_to_val_1(clk_freq, period, ctrl->clk_div) - 1;
else {
#if CONFIG_E3L
if (cmp_cfg->center_align_mode)
period_cnt =
sdrv_epwm_ns_to_val(clk_freq, period, ctrl->clk_div) / 2 - 1;
else
#endif
period_cnt = sdrv_epwm_ns_to_val_1(clk_freq, period, ctrl->clk_div);
}
sdrv_epwm_lld_cnt_ovf_val(dev->base, cmp_cfg->cmp_cnt_sel, period_cnt);
sdrv_epwm_lld_cnt_cfg_ovf_upd(dev->base, cmp_cfg->cmp_cnt_sel);
}
/**
* @brief compare value upload
*
* This function upload compare value
*
* @param[in] dev pwm common instance
* @param[in] state pwm duty and period
*/
status_t sdrv_epwm_cmp_val_upd(sdrv_epwm_t *dev, const pwm_state_t *state)
{
ASSERT(dev != NULL);
ASSERT(state != NULL);
sdrv_epwm_channel_e chnl = dev->chnl;
epwm_cmp_cfg_t *cmp_cfg = &(dev->cmp_cfg);
sdrv_epwm_controller_t *ctrl = dev->controller;
if ((state->duty1 > state->period) || (state->duty2 > state->period)) {
return SDRV_STATUS_INVALID_PARAM;
}
uint32_t period_cnt;
uint32_t dual_period_cnt_left1 = 0;
uint32_t dual_period_cnt_right1 = 0;
uint32_t dual_period_cnt_left2 = 0;
uint32_t dual_period_cnt_right2 = 0;
uint32_t clk_freq = 0;
/* all epwm use same src clk */
if (ctrl->clk_src == SDRV_EPWM_ALTERNATIVE_HIGH_FREQUENCY_CLOCK) {
clk_freq = sdrv_ckgen_get_rate(CLK_NODE(g_ckgen_ip_xtrg));
} else {
clk_freq = sdrv_ckgen_get_rate(CLK_NODE(g_ckgen_ip_epwm1));
}
period_cnt = sdrv_epwm_ns_to_val(clk_freq, state->period, ctrl->clk_div);
uint32_t duty1_cnt;
uint32_t duty2_cnt;
#if CONFIG_E3L
if (cmp_cfg->center_align_mode) {
// duty1_cnt SHOULD LESS THAN OR EQUAL TO period_cnt/2
duty1_cnt =
sdrv_epwm_ns_to_val(clk_freq, state->duty1, ctrl->clk_div) / 2;
dual_period_cnt_left1 = (period_cnt) / 4 - duty1_cnt / 2;
dual_period_cnt_right1 = (period_cnt) / 4 + duty1_cnt / 2;
// duty2_cnt SHOULD LESS THAN OR EQUAL TO period_cnt/2
duty2_cnt =
sdrv_epwm_ns_to_val(clk_freq, state->duty2, ctrl->clk_div) / 2;
dual_period_cnt_left2 = (period_cnt) / 4 - duty2_cnt / 2;
dual_period_cnt_right2 = (period_cnt) / 4 + duty2_cnt / 2;
} else {
#endif
duty1_cnt = sdrv_epwm_ns_to_val(clk_freq, state->duty1, ctrl->clk_div);
dual_period_cnt_left1 = (period_cnt) / 2 - duty1_cnt / 2;
dual_period_cnt_right1 = (period_cnt) / 2 + duty1_cnt / 2;
duty2_cnt = sdrv_epwm_ns_to_val(clk_freq, state->duty2, ctrl->clk_div);
dual_period_cnt_left2 = (period_cnt) / 2 - duty2_cnt / 2;
dual_period_cnt_right2 = (period_cnt) / 2 + duty2_cnt / 2;
#if CONFIG_E3L
}
#endif
if (cmp_cfg->cmp_mode == SDRV_EPWM_SINGLE_COMPARE_MODE) {
sdrv_epwm_lld_cmp_val(dev->base, chnl, SDRV_EPWM_CMP_00, duty1_cnt);
if (cmp_cfg->chnl_out_mode == EPWM_BOTH_COMP0_AND_COMP1_OUTPUT)
sdrv_epwm_lld_cmp_val(dev->base, chnl, SDRV_EPWM_CMP_10, duty2_cnt);
} else if (cmp_cfg->cmp_mode == SDRV_EPWM_DUAL_COMPARE_MODE) {
sdrv_epwm_lld_cmp_val(dev->base, chnl, SDRV_EPWM_CMP_00,
dual_period_cnt_left1);
sdrv_epwm_lld_cmp_val(dev->base, chnl, SDRV_EPWM_CMP_01,
dual_period_cnt_right1);
if (cmp_cfg->chnl_out_mode == EPWM_BOTH_COMP0_AND_COMP1_OUTPUT) {
sdrv_epwm_lld_cmp_val(dev->base, chnl, SDRV_EPWM_CMP_10,
dual_period_cnt_left2);
sdrv_epwm_lld_cmp_val(dev->base, chnl, SDRV_EPWM_CMP_11,
dual_period_cnt_right2);
}
}
sdrv_epwm_lld_cmp_ctrl_cmp_val_upd(dev->base, chnl);
return SDRV_STATUS_OK;
}
/**
* @brief configure multi compare mode
*
* This function configure multi compare value
*
* @param[in] dev pwm common instance
* @param[in] state pwm duty and period
* @param[in] multi cmp00/01/10/11 val
*
*/
status_t sdrv_epwm_multi_cmp_mode(sdrv_epwm_t *dev, pwm_state_t *state,
epwm_multi_cmp_val_t *multi_cmp)
{
sdrv_epwm_channel_e chnl = dev->chnl;
sdrv_epwm_controller_t *ctrl = dev->controller;
uint32_t clk_freq = 0;
/* all epwm use same src clk */
if (ctrl->clk_src == SDRV_EPWM_ALTERNATIVE_HIGH_FREQUENCY_CLOCK) {
clk_freq = sdrv_ckgen_get_rate(CLK_NODE(g_ckgen_ip_xtrg));
} else {
clk_freq = sdrv_ckgen_get_rate(CLK_NODE(g_ckgen_ip_epwm1));
}
if ((state->duty1 > state->period) || (state->duty2 > state->period)) {
return SDRV_STATUS_INVALID_PARAM;
}
uint32_t cmp00_cnt =
sdrv_epwm_ns_to_val(clk_freq, multi_cmp->cmp00_val, ctrl->clk_div);
uint32_t cmp01_cnt =
sdrv_epwm_ns_to_val(clk_freq, multi_cmp->cmp01_val, ctrl->clk_div);
uint32_t cmp10_cnt =
sdrv_epwm_ns_to_val(clk_freq, multi_cmp->cmp10_val, ctrl->clk_div);
uint32_t cmp11_cnt =
sdrv_epwm_ns_to_val(clk_freq, multi_cmp->cmp11_val, ctrl->clk_div);
sdrv_epwm_lld_cmp_val(dev->base, chnl, SDRV_EPWM_CMP_00, cmp00_cnt);
sdrv_epwm_lld_cmp_val(dev->base, chnl, SDRV_EPWM_CMP_01, cmp01_cnt);
sdrv_epwm_lld_cmp_val(dev->base, chnl, SDRV_EPWM_CMP_10, cmp10_cnt);
sdrv_epwm_lld_cmp_val(dev->base, chnl, SDRV_EPWM_CMP_11, cmp11_cnt);
sdrv_epwm_lld_cmp_ctrl_cmp_val_upd(dev->base, chnl);
return SDRV_STATUS_OK;
}
/**
* @brief configure epwm counter clear
*
* This function configure counter clear
*
* @param[in] dev pwm common instance
* @param[in] cnt_clr_trig_sel sellect cnt_clr_trig_polarity
* @param[in] clr_sel input_clr_sel_trig
*
*/
void sdrv_epwm_cnt_clr_cfg(sdrv_epwm_t *dev,
sdrv_epwm_event_trigger_mode_e cnt_clr_trig_sel,
sdrv_epwm_input_sel_trig_e clr_sel)
{
epwm_cmp_cfg_t *cmp_cfg = &(dev->cmp_cfg);
sdrv_epwm_lld_cnt_cfg_clr_trig_sel(dev->base, cmp_cfg->cmp_cnt_sel,
cnt_clr_trig_sel);
sdrv_epwm_lld_cnt_input_sel_clr(dev->base, cmp_cfg->cmp_cnt_sel, clr_sel);
}
/**
* @brief configure epwm counter overflow upload cfg
*
* This function configure counter overflow upload
*
* @param[in] dev pwm common instance
* @param[in] set_mode_sel sellect set_mode
* @param[in] cnt_set_trig_sel sellect cnt_set_trig_polarity
* @param[in] set_sel input_set_sel_trig
*
*/
void sdrv_epwm_cnt_ovf_upd_cfg(sdrv_epwm_t *dev,
sdrv_epwm_cnt_cfg_set_upd_sel_e set_mode_sel,
sdrv_epwm_event_trigger_mode_e cnt_set_trig_sel,
sdrv_epwm_input_sel_trig_e set_sel)
{
epwm_cmp_cfg_t *cmp_cfg = &(dev->cmp_cfg);
sdrv_epwm_lld_cnt_cfg_set_trig_sel(dev->base, cmp_cfg->cmp_cnt_sel,
set_mode_sel, cnt_set_trig_sel);
sdrv_epwm_lld_cnt_input_sel_set(dev->base, cmp_cfg->cmp_cnt_sel, set_sel);
}
/**
* @brief software trigger
*
* This function configure software trigger, such as pulse.
*
* @param[in] dev pwm common instance
* @param[in] tirg sellect trigger mode
*
*/
void sdrv_epwm_sw_trig(sdrv_epwm_t *dev, sdrv_epwm_sw_trig_ctrl_e trig)
{
sdrv_epwm_channel_e chnl = dev->chnl;
sdrv_epwm_lld_sw_trig_ctrl(dev->base, chnl, trig);
}
/**
* @brief configure epwm death time
*
* This function configure compare death time
*
* @param[in] dev pwm common instance
* @param[in] prefin_pol prefinial polarity
* @param[in] dti_val death time value
*
*/
void sdrv_epwm_dti(sdrv_epwm_t *dev, sdrv_epwm_cmp_prefin_pol_t *prefin_pol,
const uint32_t dti_val)
{
sdrv_epwm_channel_e chnl = dev->chnl;
sdrv_epwm_controller_t *ctrl = dev->controller;
uint32_t clk_freq = 0;
/* all epwm use same src clk */
if (ctrl->clk_src == SDRV_EPWM_ALTERNATIVE_HIGH_FREQUENCY_CLOCK) {
clk_freq = sdrv_ckgen_get_rate(CLK_NODE(g_ckgen_ip_xtrg));
} else {
clk_freq = sdrv_ckgen_get_rate(CLK_NODE(g_ckgen_ip_epwm1));
}
uint32_t dti_cnt = sdrv_epwm_ns_to_val_1(clk_freq, dti_val, ctrl->clk_div);
sdrv_epwm_lld_cmp_prefin_pol(dev->base, chnl, prefin_pol);
sdrv_epwm_lld_cmp_dti_ctrl_inv(dev->base, chnl, true);
sdrv_epwm_lld_cmp_dti_wid(dev->base, chnl, dti_cnt, dti_cnt);
sdrv_epwm_lld_cmp_dti_ctrl_en(dev->base, chnl, true);
}
/**
* @brief configure sse epwm output
*
* This function configure compare sse mode
*
* @param[in] dev pwm common instance
* @param[in] sse_cfg sse_mode and edge sellect
* @param[in] sse_reg_val sse register value
*
*/
void sdrv_epwm_sse(sdrv_epwm_t *dev, sdrv_epwm_cmp_sse_ctrl_t *sse_cfg,
uint32_t sse_reg_val)
{
sdrv_epwm_channel_e chnl = dev->chnl;
sdrv_epwm_lld_cmp_sse_ctrl_cfg(dev->base, chnl, sse_cfg);
sdrv_epwm_lld_cmp_sse_ctrl_cfg_so_det_fault(dev->base, chnl,
sse_cfg->sse_so_det_fault);
sdrv_epwm_lld_cmp_sse_reg(dev->base, chnl, sse_reg_val);
sdrv_epwm_lld_cmp_sse_ctrl_sse_en(dev->base, chnl, true);
}
/**
* @brief configure modulation frequency control
*
* This function configure compare mfc mode
*
* @param[in] dev pwm common instance
* @param[in] val mfc up times to 2^val times
*
*/
void sdrv_epwm_mfc(sdrv_epwm_t *dev, uint8_t val)
{
epwm_cmp_cfg_t *cmp_cfg = &(dev->cmp_cfg);
sdrv_epwm_lld_cnt_mfc(dev->base, cmp_cfg->cmp_cnt_sel, val);
}
/**
* @brief configure compare data format
*
* This function configure compare data format, such as 8bit or 16bit.
*
* @param[in] dev pwm common instance
* @param[in] dat_format cmp data formate
*/
void sdrv_epwm_cmp_data_format(
sdrv_epwm_t *dev, sdrv_epwm_chn_dma_ctrl_cmp_x_dat_format_e dat_format)
{
sdrv_epwm_channel_e chnl = dev->chnl;
sdrv_epwm_lld_chn_dma_ctrl_cmp_dat_format(dev->base, chnl, dat_format);
}
/**
* @brief configure compare dither mode
*
* This function configure compare dither mode
*
* @param[in] dev pwm common instance
* @param[in] clip_rslt dither clip_rslt val
* @param[in] init_offset dither init_offset val
*/
void sdrv_epwm_cmp_dither(sdrv_epwm_t *dev, uint8_t clip_rslt,
uint16_t init_offset)
{
sdrv_epwm_channel_e chnl = dev->chnl;
sdrv_epwm_lld_cmp_dither(dev->base, chnl, clip_rslt, init_offset);
if (init_offset)
sdrv_epwm_lld_cmp_dither_init_offset_en(dev->base, chnl, true);
sdrv_epwm_lld_cmp_dither_en(dev->base, chnl, true);
}
/**
* @brief configure compare multi channels
*
* This function configure compare value of multi channels
*
* @param[in] dev pwm common instance
* @param[in] full_en full channels enable
*/
void sdrv_epwm_cmp_multi_chnl(sdrv_epwm_t *dev, bool full_en)
{
sdrv_epwm_channel_e chnl = dev->chnl;
if (full_en)
sdrv_epwm_lld_chn_dma_ctrl_four_chan_mode(dev->base, true);
else
sdrv_epwm_lld_chn_dma_ctrl_two_chn_xx_mode(dev->base, chnl, true);
}
/**
* @brief configure compare event/cnt overflow event
*
* This function configure compare event or counter event
*
* @param[in] dev pwm common instance
* @param[in] src_sel choose cmp or cnt trigger source
*/
void sdrv_epwm_ce_ctrl(sdrv_epwm_t *dev, bool src_sel)
{
sdrv_epwm_channel_e chnl = dev->chnl;
epwm_cmp_cfg_t *cmp_cfg = &(dev->cmp_cfg);
if (src_sel) {
sdrv_epwm_lld_cmp_config_ce_en(dev->base, chnl, true);
}
else {
sdrv_epwm_lld_cnt_cfg_ce_en(dev->base, cmp_cfg->cmp_cnt_sel, true);
}
}
/**
* @brief configure dma request except fifo wml trig
*
* This function configure pwm trig dma tranferrs with ce
*
* @param[in] dev pwm common instance
* @param[in] sel_trig sellect trigger source
*/
void sdrv_epwm_ce_dma_trig(sdrv_epwm_t *dev, uint8_t sel_trig)
{
sdrv_epwm_lld_config_dma_ctl_cfg(dev->base, false, sel_trig);
sdrv_epwm_lld_config_dma_ctl_en(dev->base, true);
}
/**
* @brief filter input fault source signals
*
* This function configure fault event source
*
* @param[in] dev pwm common instance
* @param[in] flt_cfg config filter
*/
void sdrv_epwm_fault_flt(sdrv_epwm_t *dev, sdrv_epwm_fault_flt_t *flt_cfg)
{
sdrv_epwm_channel_e chnl = dev->chnl;
// pos/neg_band_wid should equal or greater than 2 due to 0~15 indicate
// 2~17 sample interval
// smpl_intval should equal or greater than 1 due to 0~255 indicate
// 1~256 timer clock cycles
sdrv_epwm_lld_fault_flt(dev->base, chnl, flt_cfg);
sdrv_epwm_lld_fault_flt_en(dev->base, chnl, true);
}
/**
* @brief configure input fault event
*
* This function configure compare fault event
*
* @param[in] dev pwm common instance
* @param[in] fault_src config which fault source to trigger
* @param[in] fault_cfg config fault event
* @param[in] fs_state cmp failsafe status
*/
void sdrv_epwm_fault_event(sdrv_epwm_t *dev, uint8_t fault_src,
sdrv_epwm_cmp_fault_event_ctrl_t *fault_cfg,
epwm_fs_state_t *fs_state)
{
sdrv_epwm_channel_e chnl = dev->chnl;
sdrv_epwm_lld_cmp_fault_event_ctrl_config(
dev->base, chnl, (sdrv_epwm_cmp_fault_e)fault_src, fault_cfg);
sdrv_epwm_lld_cmp_fault_event_fs_sta_set(
dev->base, chnl, fs_state->cmp0_fs_state, fs_state->cmp1_fs_state);
sdrv_epwm_lld_cmp_fault_event_ctrl_en(
dev->base, chnl, (sdrv_epwm_cmp_fault_e)fault_src, true);
}
/**
* @brief input fault event clr
*
* This function clear fault status in sticky mode
*
* @param[in] dev pwm common instance
* @param[in] fault_src config which fault source to trigger
*/
void sdrv_epwm_fault_event_clr(sdrv_epwm_t *dev, uint8_t fault_src)
{
sdrv_epwm_channel_e chnl = dev->chnl;
sdrv_epwm_lld_cmp_fault_event_ctrl_clr(dev->base, chnl,
(sdrv_epwm_cmp_fault_e)fault_src);
}
/**
* @brief cnt overflow value upload directly (unit is cnt val)
*
* This function configure counter overflow upload
*
* @param[in] dev pwm common instance
* @param[in] period_cnt counter overflow value
*/
void sdrv_epwm_cnt_ovf_dir_upd(sdrv_epwm_t *dev, uint32_t period_cnt)
{
epwm_cmp_cfg_t *cmp_cfg = &(dev->cmp_cfg);
sdrv_epwm_lld_cnt_ovf_val(dev->base, cmp_cfg->cmp_cnt_sel, period_cnt);
sdrv_epwm_lld_cnt_cfg_ovf_upd(dev->base, cmp_cfg->cmp_cnt_sel);
}
/**
* @brief upload chnl_b/c/d compare value with dual mode 100% duty check(unit is
* cnt val)
*
* This function upload channel_b/c/d value with 100% over two period
*
* @param[in] dev pwm common instance
* @param[in] left_point dual mode left cmp_val
* @param[in] right_point dual mode right cmp_val
*/
void sdrv_epwm_cmp_bcd_update(sdrv_epwm_t *dev, uint32_t left_point,
uint32_t right_point)
{
sdrv_epwm_channel_e chnl = dev->chnl;
epwm_cmp_cfg_t *cmp_cfg = &(dev->cmp_cfg);
epwm_dual_duty_state_t *pre_duty = &(dev->pre_duty);
uint32_t cnt_ovf = 0;
if (pre_duty->left_point == 0 && left_point != 0) {
cnt_ovf = sdrv_epwm_lld_cnt_ovf_val_rd(dev->base, cmp_cfg->cmp_cnt_sel);
sdrv_epwm_lld_cmp_val(dev->base, chnl, SDRV_EPWM_CMP_01, cnt_ovf + 1);
sdrv_epwm_lld_cmp_ctrl_cmp_val_upd(dev->base, chnl);
sdrv_epwm_cmp_sw_rld(dev);
}
if (left_point != 0)
sdrv_epwm_cmp_val_upd_bcd(dev, left_point, right_point);
else {
sdrv_epwm_cmp_val_upd_bcd(dev, left_point, right_point + 1);
}
pre_duty->left_point = left_point;
pre_duty->right_point = right_point;
}
/**
* @brief compare value chnl_b/c/d upload (unit is cnt val)
*
* This function upload compare value in dual mode
*
* @param[in] dev pwm common instance
* @param[in] left_point dual mode left cmp_val
* @param[in] right_point dual mode right cmp_val
*/
void sdrv_epwm_cmp_val_upd_bcd(sdrv_epwm_t *dev, uint32_t left_point,
uint32_t right_point)
{
sdrv_epwm_channel_e chnl = dev->chnl;
sdrv_epwm_lld_cmp_val(dev->base, chnl, SDRV_EPWM_CMP_00, left_point);
if (left_point != 0)
sdrv_epwm_lld_cmp_val(dev->base, chnl, SDRV_EPWM_CMP_01, right_point);
else
sdrv_epwm_lld_cmp_val(dev->base, chnl, SDRV_EPWM_CMP_01,
right_point - 1);
sdrv_epwm_lld_cmp_ctrl_cmp_val_upd(dev->base, chnl);
}
/**
* @brief compare value chnl_a upload (unit is cnt val)
*
* This function upload channel a value
*
* @param[in] dev pwm common instance
* @param[in] trig_point set trig point to tmux
*/
void sdrv_epwm_cmp_val_upd_a(sdrv_epwm_t *dev, uint32_t trig_point)
{
sdrv_epwm_channel_e chnl = dev->chnl;
sdrv_epwm_lld_cmp_val(dev->base, chnl, SDRV_EPWM_CMP_00, trig_point);
sdrv_epwm_lld_cmp_ctrl_cmp_val_upd(dev->base, chnl);
}
/**
* @brief compare software reload
*
* This function set compare value valid immediately
*
* @param[in] dev pwm common instance
*/
void sdrv_epwm_cmp_sw_rld(sdrv_epwm_t *dev)
{
sdrv_epwm_channel_e chnl = dev->chnl;
sdrv_epwm_lld_cmp_config_sw_rld_set(dev->base, chnl, true);
}
/**
* @brief compare clr/set configure
*
* This function configure compare clear/set source
*
* @param[in] dev pwm common instance
* @param[in] input_sel input sellect
* @param[in] set_trig cmp set trigger sel
* @param[in] clr_trig cmp clr trigger sel
*/
void sdrv_epwm_cmp_input(sdrv_epwm_t *dev, sdrv_epwm_input_sel_t *input_sel,
uint8_t set_trig, uint8_t clr_trig)
{
sdrv_epwm_channel_e chnl = dev->chnl;
sdrv_epwm_lld_cmp_config_clr_set(dev->base, chnl,
(sdrv_epwm_event_trigger_mode_e)set_trig,
(sdrv_epwm_event_trigger_mode_e)clr_trig);
sdrv_epwm_lld_cmp_input_sel(dev->base, chnl, input_sel);
}
/**
* @brief configure compare a event id
*
* This function configure cmpa0 event id
*
* @param[in] dev pwm common instance
* @param[in] eid_val cmp00/01/10/11 eid
*/
void sdrv_epwm_cmp_a_eid(sdrv_epwm_t *dev, epwm_eid_val_t *eid_val)
{
sdrv_epwm_lld_cmp_a_eid(dev->base, SDRV_EPWM_CMP_00, eid_val->eid00);
sdrv_epwm_lld_cmp_a_eid(dev->base, SDRV_EPWM_CMP_01, eid_val->eid01);
sdrv_epwm_lld_cmp_a_eid(dev->base, SDRV_EPWM_CMP_10, eid_val->eid10);
sdrv_epwm_lld_cmp_a_eid(dev->base, SDRV_EPWM_CMP_11, eid_val->eid11);
sdrv_epwm_lld_cmp_ctrl_cmp_eid_upd(dev->base);
}
/**
* @brief epwm initial status.
*
* This function configure compare initial value
*
* @param[in] dev pwm common instance
* @param[in] cmp0_init cmp0 channel init status
* @param[in] cmp1_init cmp1 channel init status
*
*/
void sdrv_epwm_init_sta(sdrv_epwm_t *dev, bool cmp0_init, bool cmp1_init)
{
sdrv_epwm_channel_e chnl = dev->chnl;
sdrv_epwm_lld_cmp_ctrl_cmp_init_status(dev->base, chnl, cmp0_init,
cmp1_init);
sdrv_epwm_lld_cmp_ctrl_cmp_init_upd(dev->base, chnl, 0);
sdrv_epwm_lld_cmp_ctrl_cmp_init_upd(dev->base, chnl, 1);
}
/**
* @brief epwm upload chnl_b/c/d [X]0/1 compare value
*
* @param[in] dev pwm common instance
* @param[in] subchnl choose cmp0 or cmp1
* @param[in] left_point dual mode left cmp_val
* @param[in] right_point dual mode right cmp_val
*
*/
void sdrv_epwm_val_chnl_bcd_upd_split(sdrv_epwm_t *dev,
sdrv_epwm_output_e subchnl,
uint32_t left_point, uint32_t right_point)
{
if (!subchnl) {
sdrv_epwm_lld_cmp_val(dev->base, dev->chnl, SDRV_EPWM_CMP_00,
left_point);
sdrv_epwm_lld_cmp_val(dev->base, dev->chnl, SDRV_EPWM_CMP_01,
right_point);
} else {
sdrv_epwm_lld_cmp_val(dev->base, dev->chnl, SDRV_EPWM_CMP_10,
left_point);
sdrv_epwm_lld_cmp_val(dev->base, dev->chnl, SDRV_EPWM_CMP_11,
right_point);
}
sdrv_epwm_lld_cmp_ctrl_cmp_val_upd(dev->base, dev->chnl);
}
/**
* @brief epwm upload chnl_b/c/d [X]0/1 compare value
*
* @param[in] dev pwm common instance
* @param[in] cmp0_left_point cmp0 dual mode left cmp_val
* @param[in] cmp0_right_point cmp0 dual mode right cmp_val
* @param[in] cmp1_left_point cmp1 dual mode left cmp_val
* @param[in] cmp1_right_point cmp1 dual mode right cmp_val
*
*/
void sdrv_epwm_val_chnl_bcd_upd_split_both(sdrv_epwm_t *dev,
uint32_t cmp0_left_point,
uint32_t cmp0_right_point,
uint32_t cmp1_left_point,
uint32_t cmp1_right_point)
{
sdrv_epwm_val_chnl_bcd_upd_split(dev, SDRV_EPWM_CMP0_OUTPUT,
cmp0_left_point, cmp0_right_point);
sdrv_epwm_val_chnl_bcd_upd_split(dev, SDRV_EPWM_CMP1_OUTPUT,
cmp1_left_point, cmp1_right_point);
}
#if CONFIG_E3L
/**
* @brief center align mode enable.
*
* This function configure align mode enable
*
* @param[in] dev pwm common instance
* @param[in] en enable/diable center align mode
*
*/
void sdrv_epwm_center_align_mode_en(sdrv_epwm_t *dev, bool en)
{
sdrv_epwm_channel_e chnl = dev->chnl;
epwm_cmp_cfg_t *cmp_cfg = &(dev->cmp_cfg);
sdrv_epwm_lld_cnt_cfg_ovf_rst_dis(dev->base, cmp_cfg->cmp_cnt_sel, en);
sdrv_epwm_lld_cnt_center_align_mode_en(dev->base, cmp_cfg->cmp_cnt_sel, en);
sdrv_epwm_lld_cmp_center_align_mode_en(dev->base, chnl, en);
}
/**
* @brief compare value chnl_b/c/d upload in center align mode (unit is cnt val)
*
* This function configure channel_b/c/d value upload in center align mode
*
* @param[in] dev pwm common instance
* @param[in] cmp_point center align mode cmp_val
*/
void sdrv_epwm_cmp_center_align_val_upd_bcd(sdrv_epwm_t *dev,
uint32_t cmp_point)
{
sdrv_epwm_channel_e chnl = dev->chnl;
sdrv_epwm_lld_cmp_val(dev->base, chnl, SDRV_EPWM_CMP_00, cmp_point);
sdrv_epwm_lld_cmp_ctrl_cmp_val_upd(dev->base, chnl);
}
#endif