2103 lines
55 KiB
C
2103 lines
55 KiB
C
/****************************************************************************
|
||
|
||
Copyright(c) 2019 by Aerospace C.Power (Chongqing) Microelectronics. ALL RIGHTS RESERVED.
|
||
|
||
This Information is proprietary to Aerospace C.Power (Chongqing) Microelectronics and MAY NOT
|
||
be copied by any method or incorporated into another program without
|
||
the express written consent of Aerospace C.Power. This Information or any portion
|
||
thereof remains the property of Aerospace C.Power. The Information contained herein
|
||
is believed to be accurate and Aerospace C.Power assumes no responsibility or
|
||
liability for its use in any way and conveys no license or title under
|
||
any patent or copyright and makes no representation or warranty that this
|
||
Information is free from patent or copyright infringement.
|
||
|
||
****************************************************************************/
|
||
|
||
/* os shim includes */
|
||
#include "os_types.h"
|
||
|
||
#include "apb.h"
|
||
#include "pwm.h"
|
||
#include "irq.h"
|
||
|
||
#include "hw_reg_api.h"
|
||
#include "gpio_mtx.h"
|
||
|
||
#include "pwm_reg.h"
|
||
#include "clk.h"
|
||
#include "pwm_hw.h"
|
||
#include "apb_hw.h"
|
||
|
||
#include "chip_reg_base.h"
|
||
#include "os_mem_api.h"
|
||
|
||
const uint32_t pwm_base[] = {
|
||
PWM0_REG_BASEADDR,
|
||
PWM1_REG_BASEADDR,
|
||
PWM2_REG_BASEADDR,
|
||
PWM3_REG_BASEADDR,
|
||
PWM4_REG_BASEADDR,
|
||
PWM5_REG_BASEADDR,
|
||
};
|
||
|
||
const uint32_t apb_module[] = {
|
||
APB_PWM0,
|
||
APB_PWM1,
|
||
APB_PWM2,
|
||
APB_PWM3,
|
||
APB_PWM4,
|
||
APB_PWM5,
|
||
};
|
||
|
||
#define INNER_SEL_OPT_RESERVED 0
|
||
#define INNER_SEL_OPT_TB_CNT_EQ_ZERO 1
|
||
#define INNER_SEL_OPT_TB_CNT_EQ_PRD 2
|
||
#define INNER_SEL_OPT_TB_CNT_EQ_ZERO_OR_PRD 3
|
||
#define INNER_SEL_OPT_TB_CNT_EQ_CMPA_INC 4
|
||
#define INNER_SEL_OPT_TB_CNT_EQ_CMPA_DEC 5
|
||
#define INNER_SEL_OPT_TB_CNT_EQ_CMPB_INT 6
|
||
#define INNER_SEL_OPT_TB_CNT_EQ_CMPB_DEC 7
|
||
|
||
#define CHANGE_DUTY 1000 // cmp duty value
|
||
#define PWM_NEW_WRITE(d, a, v) SOC_WRITE_REG(pwm_base[d] + (a), v)
|
||
#define PWM_NEW_READ(d, a) SOC_READ_REG(pwm_base[d] + (a))
|
||
|
||
#define PWM_CH_REG_FIELD_SET(ch, reg, field, val) \
|
||
do { \
|
||
uint32_t tmp; \
|
||
tmp = PWM_NEW_READ(ch, reg); \
|
||
(tmp) &= ~field##_MASK; \
|
||
(tmp) |= (((val) << field##_OFFSET) & field##_MASK); \
|
||
PWM_NEW_WRITE(ch, reg, tmp); \
|
||
} while(0)
|
||
|
||
typedef struct pwm_device_info_t {
|
||
uint32_t int_num;
|
||
iot_irq_t irq_handle;
|
||
/* PWM常规中断,可选由cnt==0,cnt==period等触发 */
|
||
pwm_isr isr[PWM_CHANNEL_MAX];
|
||
/* 触发ADC采样的信号SOCA的中断 */
|
||
pwm_isr soca_isr[PWM_CHANNEL_MAX];
|
||
/* 触发ADC采样的信号SOCB的中断 */
|
||
pwm_isr socb_isr[PWM_CHANNEL_MAX];
|
||
/* 刹车功能,CBC(cycle by cycle)模式的中断 */
|
||
pwm_isr fault_cbc_isr[PWM_CHANNEL_MAX];
|
||
/* 刹车功能,OSHT(one shut)模式的中断 */
|
||
pwm_isr fault_osht_isr[PWM_CHANNEL_MAX];
|
||
} pwm_device_info;
|
||
|
||
pwm_device_info g_pwm_info;
|
||
|
||
#define PWM_CHANNEL_INVALID(ch) ((ch) >= PWM_CHANNEL_MAX ? 1 : 0)
|
||
|
||
#include "apb_glb_reg.h"
|
||
void pwm_apb_enable(uint8_t ch)
|
||
{
|
||
uint32_t tmp;
|
||
// volatile int i;
|
||
// volatile uint32_t delay = 100;
|
||
//enable module;
|
||
tmp = APB_REG_LITE0_READ_REG(CFG_PWM_CTRL0_ADDR);
|
||
if(tmp & (1 << (PWM0_EB_OFFSET + ch) ))
|
||
return;
|
||
tmp |= (1 << (PWM0_EB_OFFSET + ch));
|
||
APB_REG_LITE0_WRITE_REG(CFG_PWM_CTRL0_ADDR, tmp);
|
||
#if 0
|
||
//soft reset module;
|
||
tmp = APB_REG_LITE0_READ_REG(CFG_PWM_CTRL0_ADDR);
|
||
tmp |= (1 << (PWM0_SOFT_RST_OFFSET + ch));
|
||
APB_REG_LITE0_WRITE_REG(CFG_PWM_CTRL0_ADDR, tmp);
|
||
|
||
//delay
|
||
for(i = 0; i < delay; i++);
|
||
|
||
//reset done
|
||
tmp = APB_REG_LITE0_READ_REG(CFG_PWM_CTRL0_ADDR);
|
||
tmp &= ~(1 << (PWM0_SOFT_RST_OFFSET + ch));
|
||
APB_REG_LITE0_WRITE_REG(CFG_PWM_CTRL0_ADDR, tmp);
|
||
#endif
|
||
}
|
||
|
||
void pwm_apb_disable(uint8_t ch)
|
||
{
|
||
uint32_t tmp;
|
||
volatile int i;
|
||
volatile uint32_t delay = 100;
|
||
|
||
//enable module;
|
||
tmp = APB_REG_LITE0_READ_REG(CFG_PWM_CTRL0_ADDR);
|
||
tmp &= ~(1 << (PWM0_EB_OFFSET + ch));
|
||
APB_REG_LITE0_WRITE_REG(CFG_PWM_CTRL0_ADDR, tmp);
|
||
|
||
//soft reset module;
|
||
tmp = APB_REG_LITE0_READ_REG(CFG_PWM_CTRL0_ADDR);
|
||
tmp |= (1 << (PWM0_SOFT_RST_OFFSET + ch));
|
||
APB_REG_LITE0_WRITE_REG(CFG_PWM_CTRL0_ADDR, tmp);
|
||
|
||
//delay
|
||
for(i = 0; i < delay; i++);
|
||
|
||
//reset done
|
||
tmp = APB_REG_LITE0_READ_REG(CFG_PWM_CTRL0_ADDR);
|
||
tmp &= ~(1 << (PWM0_SOFT_RST_OFFSET + ch));
|
||
APB_REG_LITE0_WRITE_REG(CFG_PWM_CTRL0_ADDR, tmp);
|
||
}
|
||
|
||
int8_t pwm_tbclk_ctrl(uint8_t ch, bool_t en)
|
||
{
|
||
if (PWM_CHANNEL_INVALID(ch)) {
|
||
return -1;
|
||
}
|
||
|
||
if (en) {
|
||
//apb_enable(apb_module[ch]);
|
||
pwm_apb_enable(ch);
|
||
} else {
|
||
//apb_disable(apb_module[ch]);
|
||
pwm_apb_disable(ch);
|
||
}
|
||
|
||
return 0;
|
||
}
|
||
|
||
// pwm sync eb 打开总时钟
|
||
|
||
int8_t pwm_tbclk_sync(uint8_t ch, bool_t en)
|
||
{
|
||
uint32_t tmp;
|
||
if (PWM_CHANNEL_INVALID(ch)) {
|
||
return -1;
|
||
}
|
||
|
||
if (en) {
|
||
//apb_enable(APB_PWM_SYNC);
|
||
tmp = APB_REG_LITE0_READ_REG(CFG_PWM_CTRL0_ADDR);
|
||
tmp |= (1 << PWM_SYNC_EB_OFFSET);
|
||
APB_REG_LITE0_WRITE_REG(CFG_PWM_CTRL0_ADDR, tmp);
|
||
|
||
} else {
|
||
//apb_disable(APB_PWM_SYNC);
|
||
tmp = APB_REG_LITE0_READ_REG(CFG_PWM_CTRL0_ADDR);
|
||
tmp &= ~(1 << PWM_SYNC_EB_OFFSET);
|
||
APB_REG_LITE0_WRITE_REG(CFG_PWM_CTRL0_ADDR, tmp);
|
||
}
|
||
|
||
return 0;
|
||
}
|
||
|
||
int8_t pwm_cnt_start(uint8_t ch, bool_t en)
|
||
{
|
||
uint32_t tmp;
|
||
if (PWM_CHANNEL_INVALID(ch)) {
|
||
return -1;
|
||
}
|
||
|
||
tmp = PWM_NEW_READ(ch, CFG_TBCTL_ADDR);
|
||
|
||
if (en) {
|
||
REG_FIELD_SET(CNT_START, tmp, 1);
|
||
} else {
|
||
REG_FIELD_SET(CNT_START, tmp, 0);
|
||
}
|
||
PWM_NEW_WRITE(ch, CFG_TBCTL_ADDR, tmp);
|
||
|
||
return 0;
|
||
}
|
||
|
||
int8_t pwm_cnt_load_mode(uint8_t ch, uint8_t mode)
|
||
{
|
||
uint32_t tmp;
|
||
if (PWM_CHANNEL_INVALID(ch)) {
|
||
return -1;
|
||
}
|
||
mode = mode ? 1 : 0;
|
||
tmp = PWM_NEW_READ(ch, CFG_TBCTL_ADDR);
|
||
REG_FIELD_SET(SYNC_LOAD_MODE, tmp, mode);
|
||
PWM_NEW_WRITE(ch, CFG_TBCTL_ADDR, tmp);
|
||
return 0;
|
||
}
|
||
void pwm_cnt_soc_sync_load(void)
|
||
{
|
||
uint32_t tmp;
|
||
|
||
tmp = APB_REG_LITE0_READ_REG(CFG_PWM_CTRL0_ADDR);
|
||
tmp |= (1 << PWM_SYNC_LOAD_OFFSET);
|
||
APB_REG_LITE0_WRITE_REG(CFG_PWM_CTRL0_ADDR, tmp);
|
||
}
|
||
|
||
int8_t pwm_cnt_inner_sync(uint8_t ch)
|
||
{
|
||
uint32_t tmp;
|
||
if (PWM_CHANNEL_INVALID(ch)) {
|
||
return -1;
|
||
}
|
||
tmp = PWM_NEW_READ(ch, CFG_TBCTL_ADDR);
|
||
REG_FIELD_SET(INNER_SYNC_LOAD, tmp, 1);
|
||
PWM_NEW_WRITE(ch, CFG_TBCTL_ADDR, tmp);
|
||
return 0;
|
||
}
|
||
|
||
int8_t pwm_soft_force_sync(uint8_t ch)
|
||
{
|
||
uint32_t tmp;
|
||
if (PWM_CHANNEL_INVALID(ch)) {
|
||
return -1;
|
||
}
|
||
tmp = PWM_NEW_READ(ch, CFG_TBCTL_ADDR);
|
||
REG_FIELD_SET(SWFSYNC, tmp, 1);
|
||
PWM_NEW_WRITE(ch, CFG_TBCTL_ADDR, tmp);
|
||
return 0;
|
||
}
|
||
|
||
|
||
/*在初始化的最后调用*/
|
||
int8_t pwm_cnt_mode_set(uint8_t ch, uint8_t cnt_mod)
|
||
{
|
||
uint32_t tmp;
|
||
|
||
if (PWM_CHANNEL_INVALID(ch)) {
|
||
return -1;
|
||
}
|
||
tmp = PWM_NEW_READ(ch, CFG_TBCTL_ADDR);
|
||
|
||
/* cnt_mod
|
||
00b: Up-count mode;
|
||
01b: Down-count mode;
|
||
10b: Up-down-count mode;
|
||
11b: Stop-freeze;
|
||
*/
|
||
REG_FIELD_SET(CNT_MODE, tmp, cnt_mod);
|
||
|
||
PWM_NEW_WRITE(ch, CFG_TBCTL_ADDR, tmp);
|
||
|
||
return 0;
|
||
}
|
||
|
||
static uint32_t pwm_cnt_mode_get(uint8_t ch)
|
||
{
|
||
uint32_t tmp;
|
||
|
||
tmp = PWM_NEW_READ(ch, CFG_TBCTL_ADDR);
|
||
tmp = (tmp & CNT_MODE_MASK) >> CNT_MODE_OFFSET;
|
||
return tmp;
|
||
}
|
||
|
||
void pwm_tb_single_pulse_set(uint8_t ch, uint8_t en)
|
||
{
|
||
uint32_t tmp;
|
||
|
||
if (PWM_CHANNEL_INVALID(ch)) {
|
||
return;
|
||
}
|
||
en = en ? 1 : 0;
|
||
tmp = PWM_NEW_READ(ch, CFG_TBCTL_ADDR);
|
||
REG_FIELD_SET(SINGL_PULS_EN, tmp, en);
|
||
PWM_NEW_WRITE(ch, CFG_TBCTL_ADDR, tmp);
|
||
}
|
||
|
||
int8_t pwm_tbctl_set(uint8_t ch, uint8_t phsen, uint8_t prdld, uint8_t syncosel ,uint8_t div)
|
||
{
|
||
uint32_t tmp;
|
||
|
||
if (PWM_CHANNEL_INVALID(ch)) {
|
||
return -1;
|
||
}
|
||
tmp = PWM_NEW_READ(ch, CFG_TBCTL_ADDR);
|
||
/*
|
||
div 0 - 256
|
||
|
||
*/
|
||
|
||
REG_FIELD_SET(CLK_PWM_DIV, tmp, div);
|
||
|
||
/* PHSEN
|
||
0: Disable phase sync;
|
||
1: Enable phase sync;
|
||
*/
|
||
REG_FIELD_SET(PHSEN, tmp, phsen);
|
||
|
||
/*
|
||
PRDLD
|
||
0: load when Cnt=zero;
|
||
1: load immediately
|
||
*/
|
||
REG_FIELD_SET(PRDLD, tmp, prdld);
|
||
|
||
/*
|
||
SYNCOSEL
|
||
00b: PWM_SYNCI;
|
||
01b: Cnt=zero;
|
||
10b: Cnt=CMPB;
|
||
11b: Disable
|
||
*/
|
||
REG_FIELD_SET(SYNCOSEL, tmp, syncosel);
|
||
PWM_NEW_WRITE(ch, CFG_TBCTL_ADDR, tmp);
|
||
|
||
return 0;
|
||
}
|
||
|
||
int8_t pwm_tb_set_clk_div(uint8_t ch, uint8_t div)
|
||
{
|
||
uint32_t tmp;
|
||
|
||
if (PWM_CHANNEL_INVALID(ch)) {
|
||
return -1;
|
||
}
|
||
tmp = PWM_NEW_READ(ch, CFG_TBCTL_ADDR);
|
||
REG_FIELD_SET(CLK_PWM_DIV, tmp, div);
|
||
PWM_NEW_WRITE(ch, CFG_TBCTL_ADDR, tmp);
|
||
return 0;
|
||
}
|
||
|
||
int8_t pwm_tb_set_phase_en(uint8_t ch, uint8_t phsen)
|
||
{
|
||
uint32_t tmp;
|
||
|
||
if (PWM_CHANNEL_INVALID(ch)) {
|
||
return -1;
|
||
}
|
||
tmp = PWM_NEW_READ(ch, CFG_TBCTL_ADDR);
|
||
REG_FIELD_SET(PHSEN, tmp, phsen);
|
||
PWM_NEW_WRITE(ch, CFG_TBCTL_ADDR, tmp);
|
||
return 0;
|
||
}
|
||
|
||
int8_t pwm_tb_set_prd_load_mode(uint8_t ch, uint8_t prdld)
|
||
{
|
||
uint32_t tmp;
|
||
|
||
if (PWM_CHANNEL_INVALID(ch)) {
|
||
return -1;
|
||
}
|
||
tmp = PWM_NEW_READ(ch, CFG_TBCTL_ADDR);
|
||
REG_FIELD_SET(PRDLD, tmp, prdld);
|
||
PWM_NEW_WRITE(ch, CFG_TBCTL_ADDR, tmp);
|
||
return 0;
|
||
}
|
||
|
||
int8_t pwm_tb_set_sync_out_src(uint8_t ch, uint8_t syncosel)
|
||
{
|
||
uint32_t tmp;
|
||
|
||
if (PWM_CHANNEL_INVALID(ch)) {
|
||
return -1;
|
||
}
|
||
tmp = PWM_NEW_READ(ch, CFG_TBCTL_ADDR);
|
||
REG_FIELD_SET(SYNCOSEL, tmp, syncosel);
|
||
PWM_NEW_WRITE(ch, CFG_TBCTL_ADDR, tmp);
|
||
return 0;
|
||
}
|
||
|
||
void pwm_cmpctl_auto_duty(uint8_t ch, bool_t cmpa_en, bool_t cmpb_en)
|
||
{
|
||
uint32_t tmp;
|
||
|
||
if (PWM_CHANNEL_INVALID(ch))
|
||
return;
|
||
cmpa_en = cmpa_en ? 1 : 0;
|
||
cmpb_en = cmpb_en ? 1 : 0;
|
||
|
||
tmp = PWM_NEW_READ(ch, CFG_CMPCTL_ADDR);
|
||
REG_FIELD_SET(CMPB_AUTO_EN, tmp, cmpb_en);
|
||
REG_FIELD_SET(CMPA_AUTO_EN, tmp, cmpa_en);
|
||
|
||
|
||
PWM_NEW_WRITE(ch, CFG_CMPCTL_ADDR, tmp);
|
||
|
||
}
|
||
|
||
void pwm_cmpctl_cmpa_end(uint8_t ch, uint32_t cmpa_end)
|
||
{
|
||
uint32_t tmp;
|
||
|
||
if (PWM_CHANNEL_INVALID(ch))
|
||
return;
|
||
|
||
tmp = PWM_NEW_READ(ch, CFG_CMPA_AUTO_ADDR);
|
||
REG_FIELD_SET(CMPA_END, tmp, cmpa_end);
|
||
|
||
PWM_NEW_WRITE(ch, CFG_CMPA_AUTO_ADDR, tmp);
|
||
}
|
||
|
||
void pwm_cmpctl_cmpa_step(uint8_t ch, uint8_t cmpa_step)
|
||
{
|
||
uint32_t tmp;
|
||
|
||
if (PWM_CHANNEL_INVALID(ch))
|
||
return;
|
||
|
||
tmp = PWM_NEW_READ(ch, CFG_CMPA_AUTO_ADDR);
|
||
REG_FIELD_SET(CMPA_STEP, tmp, cmpa_step);
|
||
|
||
PWM_NEW_WRITE(ch, CFG_CMPA_AUTO_ADDR, tmp);
|
||
}
|
||
|
||
void pwm_cmpctl_cmpb_end(uint8_t ch, uint32_t cmpb_end)
|
||
{
|
||
uint32_t tmp;
|
||
|
||
if (PWM_CHANNEL_INVALID(ch))
|
||
return;
|
||
|
||
tmp = PWM_NEW_READ(ch, CFG_CMPB_AUTO_ADDR);
|
||
REG_FIELD_SET(CMPB_END, tmp, cmpb_end);
|
||
|
||
PWM_NEW_WRITE(ch, CFG_CMPB_AUTO_ADDR, tmp);
|
||
}
|
||
|
||
void pwm_cmpctl_cmpb_step(uint8_t ch, uint8_t cmpb_step)
|
||
{
|
||
uint32_t tmp;
|
||
|
||
if (PWM_CHANNEL_INVALID(ch))
|
||
return;
|
||
|
||
tmp = PWM_NEW_READ(ch, CFG_CMPB_AUTO_ADDR);
|
||
REG_FIELD_SET(CMPB_STEP, tmp, cmpb_step);
|
||
|
||
PWM_NEW_WRITE(ch, CFG_CMPB_AUTO_ADDR, tmp);
|
||
}
|
||
|
||
void pwm_cmpctl_set(uint8_t ch, uint8_t lda_mod, uint8_t ldb_mod,
|
||
uint8_t shda_mod, uint8_t shdb_mod)
|
||
{
|
||
uint32_t tmp;
|
||
|
||
if (PWM_CHANNEL_INVALID(ch))
|
||
return;
|
||
|
||
tmp = PWM_NEW_READ(ch, CFG_CMPCTL_ADDR);
|
||
/*
|
||
Active Counter-Compare A or B (CMPA) Load From Shadow Select Mode
|
||
00: Load on Cnt_Zero;
|
||
01: Load on Cnt_PRD;
|
||
10: Load on either Cnt_Zero or Cnt_PRD
|
||
11: Freeze(No Load)
|
||
*/
|
||
REG_FIELD_SET(LDA_MOD, tmp, lda_mod);
|
||
REG_FIELD_SET(LDB_MOD, tmp, ldb_mod);
|
||
|
||
/*
|
||
CMPA or CMPB Register operation mode
|
||
0: Shadow mode;
|
||
1: Immediate mode;
|
||
*/
|
||
REG_FIELD_SET(SHDA_MOD, tmp, shda_mod);
|
||
REG_FIELD_SET(SHDB_MOD, tmp, shdb_mod);
|
||
PWM_NEW_WRITE(ch, CFG_CMPCTL_ADDR, tmp);
|
||
}
|
||
|
||
void pwm_aqctla_set(uint8_t ch, uint8_t cnt_zero, uint8_t cnt_prd,
|
||
uint8_t cnta_up, uint8_t cnta_dwn, uint8_t cntb_up, uint8_t cntb_dwn)
|
||
{
|
||
uint32_t tmp;
|
||
|
||
if (PWM_CHANNEL_INVALID(ch)) {
|
||
return;
|
||
}
|
||
|
||
tmp = PWM_NEW_READ(ch, CFG_AQCTLA_ADDR);
|
||
/*
|
||
Action when the counter equals zero or period
|
||
00: Do nothing;
|
||
01: Force PWMA to low;
|
||
10: Force PWMA to high;
|
||
11: Force PWMA toggle.
|
||
*/
|
||
REG_FIELD_SET(ACTA_CNT_ZERO, tmp, cnt_zero);
|
||
REG_FIELD_SET(ACTA_CNT_PRD, tmp, cnt_prd);
|
||
/*
|
||
Action when the counter equals the active CMPA register and cnt_dir is up or down
|
||
00: Do nothing;
|
||
01: Force PWMA to low;
|
||
10: Force PWMA to high;
|
||
11: Force PWMA toggle.
|
||
*/
|
||
REG_FIELD_SET(ACTA_CNTA_UP, tmp, cnta_up);
|
||
REG_FIELD_SET(ACTA_CNTA_DWN, tmp, cnta_dwn);
|
||
|
||
/*
|
||
Action when the counter equals the active CMPB register and cnt_dir is up or down
|
||
00: Do nothing;
|
||
01: Force PWMA to low;
|
||
10: Force PWMA to high;
|
||
11: Force PWMA toggle.
|
||
*/
|
||
REG_FIELD_SET(ACTA_CNTB_UP, tmp, cntb_up);
|
||
REG_FIELD_SET(ACTA_CNTB_DWN, tmp, cntb_dwn);
|
||
PWM_NEW_WRITE(ch, CFG_AQCTLA_ADDR, tmp);
|
||
}
|
||
|
||
void pwm_aqctlb_set(uint8_t ch, uint8_t cnt_zero, uint8_t cnt_prd,
|
||
uint8_t cnta_up, uint8_t cnta_dwn, uint8_t cntb_up, uint8_t cntb_dwn)
|
||
{
|
||
uint32_t tmp;
|
||
|
||
if (PWM_CHANNEL_INVALID(ch)) {
|
||
return;
|
||
}
|
||
|
||
tmp = PWM_NEW_READ(ch, CFG_AQCTLB_ADDR);
|
||
REG_FIELD_SET(ACTB_CNT_ZERO, tmp, cnt_zero);
|
||
REG_FIELD_SET(ACTB_CNT_PRD, tmp, cnt_prd);
|
||
REG_FIELD_SET(ACTB_CNTA_UP, tmp, cnta_up);
|
||
REG_FIELD_SET(ACTB_CNTA_DWN, tmp, cnta_dwn);
|
||
REG_FIELD_SET(ACTB_CNTB_UP, tmp, cntb_up);
|
||
REG_FIELD_SET(ACTB_CNTB_DWN, tmp, cntb_dwn);
|
||
PWM_NEW_WRITE(ch, CFG_AQCTLB_ADDR, tmp);
|
||
}
|
||
|
||
void pwm_aq_action_clear(uint8_t ch, PWM_OUT out)
|
||
{
|
||
if (PWM_CHANNEL_INVALID(ch)) {
|
||
return;
|
||
}
|
||
|
||
if (PWMA == out) {
|
||
PWM_NEW_WRITE(ch, CFG_AQCTLA_ADDR, 0);
|
||
} else if (PWMB == out) {
|
||
PWM_NEW_WRITE(ch, CFG_AQCTLB_ADDR, 0);
|
||
}
|
||
}
|
||
|
||
void pwm_aq_set_action_with_condition(uint8_t ch, PWM_OUT out, AQ_INPUT in,
|
||
AQ_ACTION act)
|
||
{
|
||
uint32_t tmp;
|
||
|
||
if (PWM_CHANNEL_INVALID(ch)) {
|
||
return;
|
||
}
|
||
if (PWMA == out) {
|
||
tmp = PWM_NEW_READ(ch, CFG_AQCTLA_ADDR);
|
||
if (AQ_INPUT_CNT_EQU_PRD == in) {
|
||
REG_FIELD_SET(ACTA_CNT_PRD, tmp, act);
|
||
} else if (AQ_INPUT_CNT_EQU_ZERO == in) {
|
||
REG_FIELD_SET(ACTA_CNT_ZERO, tmp, act);
|
||
} else if (AQ_INPUT_CNT_UP_EQU_CMPA == in) {
|
||
REG_FIELD_SET(ACTA_CNTA_UP, tmp, act);
|
||
} else if (AQ_INPUT_CNT_DOWN_EQU_CMPA == in) {
|
||
REG_FIELD_SET(ACTA_CNTA_DWN, tmp, act);
|
||
} else if (AQ_INPUT_CNT_UP_EQU_CMPB == in) {
|
||
REG_FIELD_SET(ACTA_CNTB_UP, tmp, act);
|
||
} else if (AQ_INPUT_CNT_DOWN_EQU_CMPB == in) {
|
||
REG_FIELD_SET(ACTA_CNTB_DWN, tmp, act);
|
||
} else {
|
||
return;
|
||
}
|
||
PWM_NEW_WRITE(ch, CFG_AQCTLA_ADDR, tmp);
|
||
} else if (PWMB == out) {
|
||
tmp = PWM_NEW_READ(ch, CFG_AQCTLB_ADDR);
|
||
if (AQ_INPUT_CNT_EQU_PRD == in) {
|
||
REG_FIELD_SET(ACTB_CNT_PRD, tmp, act);
|
||
} else if (AQ_INPUT_CNT_EQU_ZERO == in) {
|
||
REG_FIELD_SET(ACTB_CNT_ZERO, tmp, act);
|
||
} else if (AQ_INPUT_CNT_UP_EQU_CMPA == in) {
|
||
REG_FIELD_SET(ACTB_CNTA_UP, tmp, act);
|
||
} else if (AQ_INPUT_CNT_DOWN_EQU_CMPA == in) {
|
||
REG_FIELD_SET(ACTB_CNTA_DWN, tmp, act);
|
||
} else if (AQ_INPUT_CNT_UP_EQU_CMPB == in) {
|
||
REG_FIELD_SET(ACTB_CNTB_UP, tmp, act);
|
||
} else if (AQ_INPUT_CNT_DOWN_EQU_CMPB == in) {
|
||
REG_FIELD_SET(ACTB_CNTB_DWN, tmp, act);
|
||
} else {
|
||
return;
|
||
}
|
||
PWM_NEW_WRITE(ch, CFG_AQCTLB_ADDR, tmp);
|
||
}
|
||
}
|
||
|
||
int8_t IRAM_ATTR pwm_tb_period_set(uint8_t ch, uint32_t period)
|
||
{
|
||
if (PWM_CHANNEL_INVALID(ch)) {
|
||
return -1;
|
||
}
|
||
|
||
PWM_NEW_WRITE(ch, CFG_TBPRD_ADDR, period);
|
||
|
||
return 0;
|
||
}
|
||
|
||
int8_t IRAM_ATTR pwm_tb_phase_set(uint8_t ch, uint32_t phase)
|
||
{
|
||
if (PWM_CHANNEL_INVALID(ch)) {
|
||
return -1;
|
||
}
|
||
|
||
PWM_NEW_WRITE(ch, CFG_TBPHS_ADDR, phase);
|
||
|
||
return 0;
|
||
}
|
||
|
||
int8_t IRAM_ATTR pwm_tb_cnt_set(uint8_t ch, uint32_t cnt)
|
||
{
|
||
if (PWM_CHANNEL_INVALID(ch)) {
|
||
return -1;
|
||
}
|
||
|
||
PWM_NEW_WRITE(ch, CFG_TBCNT_ADDR, cnt);
|
||
return 0;
|
||
}
|
||
|
||
uint32_t IRAM_ATTR pwm_tb_period_get(uint8_t ch)
|
||
{
|
||
uint32_t period_cnt = 0;
|
||
|
||
if (PWM_CHANNEL_INVALID(ch)) {
|
||
return -1;
|
||
}
|
||
period_cnt = PWM_NEW_READ(ch, CFG_TBPRD_ADDR);
|
||
|
||
return period_cnt ;
|
||
}
|
||
|
||
int8_t IRAM_ATTR pwm_cmpa_cmpb_set(uint8_t ch, uint32_t cnta, uint32_t cntb)
|
||
{
|
||
if (PWM_CHANNEL_INVALID(ch)) {
|
||
return -1;
|
||
}
|
||
|
||
PWM_NEW_WRITE(ch, CFG_CMPA_ADDR, cnta);
|
||
|
||
PWM_NEW_WRITE(ch, CFG_CMPB_ADDR, cntb);
|
||
|
||
return 0;
|
||
}
|
||
|
||
int8_t pwm_db_inmode_set(uint8_t ch, uint8_t rising_inmode, uint8_t falling_inmode)
|
||
{
|
||
uint32_t tmp;
|
||
if (PWM_CHANNEL_INVALID(ch)) {
|
||
return -1;
|
||
}
|
||
|
||
//二者的值只能是0或1
|
||
rising_inmode = rising_inmode ? 1 : 0;
|
||
falling_inmode = falling_inmode ? 1 : 0;
|
||
|
||
tmp = PWM_NEW_READ(ch, CFG_DBCTL_ADDR);
|
||
REG_FIELD_SET(IN_MODE, tmp, (falling_inmode << 1) | rising_inmode);
|
||
PWM_NEW_WRITE(ch, CFG_DBCTL_ADDR, tmp);
|
||
return 0;
|
||
}
|
||
|
||
int8_t pwm_db_polsel_set(uint8_t ch, uint8_t pwma_pol, uint8_t pwmb_pol)
|
||
{
|
||
uint32_t tmp;
|
||
if (PWM_CHANNEL_INVALID(ch)) {
|
||
return -1;
|
||
}
|
||
|
||
//二者的值只能是0或1
|
||
pwma_pol = pwma_pol ? 1 : 0;
|
||
pwmb_pol = pwmb_pol ? 1 : 0;
|
||
|
||
tmp = PWM_NEW_READ(ch, CFG_DBCTL_ADDR);
|
||
REG_FIELD_SET(POLSEL, tmp, (pwmb_pol << 1) | pwma_pol);
|
||
PWM_NEW_WRITE(ch, CFG_DBCTL_ADDR, tmp);
|
||
return 0;
|
||
}
|
||
|
||
int8_t pwm_db_outmode_set(uint8_t ch, uint8_t pwma_outmode, uint8_t pwmb_outmode)
|
||
{
|
||
uint32_t tmp;
|
||
if (PWM_CHANNEL_INVALID(ch)) {
|
||
return -1;
|
||
}
|
||
|
||
//二者的值只能是0或1
|
||
pwma_outmode = pwma_outmode ? 1 : 0;
|
||
pwmb_outmode = pwmb_outmode ? 1 : 0;
|
||
|
||
tmp = PWM_NEW_READ(ch, CFG_DBCTL_ADDR);
|
||
REG_FIELD_SET(OUT_MODE, tmp, (pwma_outmode << 1) | pwmb_outmode);
|
||
PWM_NEW_WRITE(ch, CFG_DBCTL_ADDR, tmp);
|
||
return 0;
|
||
}
|
||
|
||
int8_t pwm_db_rising_delay_set(uint8_t ch, uint16_t delay)
|
||
{
|
||
if (PWM_CHANNEL_INVALID(ch)) {
|
||
return -1;
|
||
}
|
||
|
||
PWM_NEW_WRITE(ch, CFG_DBRED_ADDR, delay);
|
||
return 0;
|
||
}
|
||
|
||
int8_t pwm_db_falling_delay_set(uint8_t ch, uint16_t delay)
|
||
{
|
||
if (PWM_CHANNEL_INVALID(ch)) {
|
||
return -1;
|
||
}
|
||
|
||
PWM_NEW_WRITE(ch, CFG_DBFED_ADDR, delay);
|
||
return 0;
|
||
}
|
||
|
||
void pwm_tz_pin_set(uint8_t ch, uint8_t tz_pin)
|
||
{
|
||
gpio_sig_info_t tz_gpio_mtx = {
|
||
1,
|
||
{
|
||
{IO_TYPE_IN, 0, 0xff, 41, 0xff}
|
||
}
|
||
};
|
||
|
||
tz_gpio_mtx.CFG[0].gpio = tz_pin;
|
||
tz_gpio_mtx.CFG[0].inid = GPIO_MTX_PWM_TZ1_IN + ch;
|
||
|
||
gpio_module_pin_select(&tz_gpio_mtx);
|
||
gpio_module_sig_select(&tz_gpio_mtx, GPIO_MTX_MODE_MATRIX);
|
||
}
|
||
|
||
void pwm_tz_sel(uint8_t ch, uint8_t sel)
|
||
{
|
||
uint32_t tmp;
|
||
|
||
if (PWM_CHANNEL_INVALID(ch)) {
|
||
return ;
|
||
}
|
||
|
||
tmp = PWM_NEW_READ(ch, CFG_TZSEL_ADDR);
|
||
|
||
if (sel & TZ_SEL_TZ1_OSHT) {
|
||
tmp |= TZ1_OSHT_MASK;
|
||
}
|
||
if (sel & TZ_SEL_TZ2_OSHT) {
|
||
tmp |= TZ2_OSHT_MASK;
|
||
}
|
||
if (sel & TZ_SEL_TZ3_OSHT) {
|
||
tmp |= TZ3_OSHT_MASK;
|
||
}
|
||
|
||
if (sel & TZ_SEL_TZ1_CBC) {
|
||
tmp |= TZ1_CBC_MASK;
|
||
}
|
||
if (sel & TZ_SEL_TZ2_CBC) {
|
||
tmp |= TZ2_CBC_MASK;
|
||
}
|
||
if (sel & TZ_SEL_TZ3_CBC) {
|
||
tmp |= TZ3_CBC_MASK;
|
||
}
|
||
PWM_NEW_WRITE(ch, CFG_TZSEL_ADDR, tmp);
|
||
}
|
||
|
||
void pwm_tz_unsel(uint8_t ch, uint8_t sel)
|
||
{
|
||
uint32_t tmp;
|
||
|
||
if (PWM_CHANNEL_INVALID(ch)) {
|
||
return ;
|
||
}
|
||
|
||
tmp = PWM_NEW_READ(ch, CFG_TZSEL_ADDR);
|
||
|
||
if (sel & TZ_SEL_TZ1_OSHT) {
|
||
tmp &= ~TZ1_OSHT_MASK;
|
||
}
|
||
if (sel & TZ_SEL_TZ2_OSHT) {
|
||
tmp &= ~TZ2_OSHT_MASK;
|
||
}
|
||
if (sel & TZ_SEL_TZ3_OSHT) {
|
||
tmp &= ~TZ3_OSHT_MASK;
|
||
}
|
||
|
||
if (sel & TZ_SEL_TZ1_CBC) {
|
||
tmp &= ~TZ1_CBC_MASK;
|
||
}
|
||
if (sel & TZ_SEL_TZ2_CBC) {
|
||
tmp &= ~TZ2_CBC_MASK;
|
||
}
|
||
if (sel & TZ_SEL_TZ3_CBC) {
|
||
tmp &= ~TZ3_CBC_MASK;
|
||
}
|
||
PWM_NEW_WRITE(ch, CFG_TZSEL_ADDR, tmp);
|
||
}
|
||
|
||
void pwm_tz_clear(uint8_t ch)
|
||
{
|
||
if (PWM_CHANNEL_INVALID(ch)) {
|
||
return ;
|
||
}
|
||
PWM_NEW_WRITE(ch, CFG_TZSEL_ADDR, 0);
|
||
}
|
||
|
||
void pwm_tz_pin_mode_set(uint8_t ch, TZ_NUM num, uint8_t pin, TZ_MODE mode)
|
||
{
|
||
gpio_sig_info_t tz_gpio_mtx = {
|
||
1,
|
||
{
|
||
{IO_TYPE_IN, 0, 0xff, 41, 0xff}
|
||
}
|
||
};
|
||
uint32_t tmp;
|
||
|
||
if (PWM_CHANNEL_INVALID(ch) || num >= TZ_NUM_MAX) {
|
||
return ;
|
||
}
|
||
|
||
tz_gpio_mtx.CFG[0].gpio = pin;
|
||
tz_gpio_mtx.CFG[0].inid = GPIO_MTX_PWM_TZ1_IN + num;
|
||
|
||
gpio_module_pin_select(&tz_gpio_mtx);
|
||
gpio_module_sig_select(&tz_gpio_mtx, GPIO_MTX_MODE_MATRIX);
|
||
|
||
tmp = PWM_NEW_READ(ch, CFG_TZSEL_ADDR);
|
||
if (TZ_MODE_OSHT == mode) {
|
||
if (TZ_NUM_0 == num) {
|
||
tmp |= TZ1_OSHT_MASK;
|
||
} else if (TZ_NUM_1 == num) {
|
||
tmp |= TZ2_OSHT_MASK;
|
||
} else if (TZ_NUM_2 == num) {
|
||
tmp |= TZ3_OSHT_MASK;
|
||
}
|
||
} else if (TZ_MODE_CBC == mode) {
|
||
if (TZ_NUM_0 == num) {
|
||
tmp |= TZ1_CBC_MASK;
|
||
} else if (TZ_NUM_1 == num) {
|
||
tmp |= TZ2_CBC_MASK;
|
||
} else if (TZ_NUM_2 == num) {
|
||
tmp |= TZ3_CBC_MASK;
|
||
}
|
||
}
|
||
PWM_NEW_WRITE(ch, CFG_TZSEL_ADDR, tmp);
|
||
}
|
||
|
||
void pwm_tz_action_set(uint8_t ch, PWM_OUT out, TZ_ACTION action)
|
||
{
|
||
uint32_t tmp;
|
||
|
||
if (PWM_CHANNEL_INVALID(ch)) {
|
||
return ;
|
||
}
|
||
|
||
tmp = PWM_NEW_READ(ch, CFG_TZCTL_ADDR);
|
||
if (PWMA == out) {
|
||
REG_FIELD_SET(TZ_ACTA, tmp, action);
|
||
PWM_NEW_WRITE(ch, CFG_TZCTL_ADDR, tmp);
|
||
} else if (PWMB == out) {
|
||
REG_FIELD_SET(TZ_ACTB, tmp, action);
|
||
PWM_NEW_WRITE(ch, CFG_TZCTL_ADDR, tmp);
|
||
}
|
||
}
|
||
|
||
void pwm_chopping_duty_sel(uint8_t ch, uint8_t duty)
|
||
{
|
||
uint32_t tmp;
|
||
if (PWM_CHANNEL_INVALID(ch)) {
|
||
return ;
|
||
}
|
||
tmp = PWM_NEW_READ(ch, CFG_PCCTL_ADDR);
|
||
REG_FIELD_SET(CHP_DUTY, tmp, duty);
|
||
PWM_NEW_WRITE(ch, CFG_PCCTL_ADDR, tmp);
|
||
}
|
||
|
||
void pwm_chopping_div_sel(uint8_t ch, uint8_t div)
|
||
{
|
||
uint32_t tmp;
|
||
if (PWM_CHANNEL_INVALID(ch)) {
|
||
return ;
|
||
}
|
||
tmp = PWM_NEW_READ(ch, CFG_PCCTL_ADDR);
|
||
REG_FIELD_SET(CHP_FREQ, tmp, div);
|
||
PWM_NEW_WRITE(ch, CFG_PCCTL_ADDR, tmp);
|
||
}
|
||
|
||
void pwm_chopping_one_shot_width_sel(uint8_t ch, uint8_t with)
|
||
{
|
||
uint32_t tmp;
|
||
if (PWM_CHANNEL_INVALID(ch)) {
|
||
return ;
|
||
}
|
||
tmp = PWM_NEW_READ(ch, CFG_PCCTL_ADDR);
|
||
REG_FIELD_SET(OSHT_WTH, tmp, with);
|
||
PWM_NEW_WRITE(ch, CFG_PCCTL_ADDR, tmp);
|
||
}
|
||
|
||
void pwm_chopping_en(uint8_t ch, bool_t en)
|
||
{
|
||
uint32_t tmp;
|
||
if (PWM_CHANNEL_INVALID(ch)) {
|
||
return ;
|
||
}
|
||
|
||
en = en ? 1 : 0;
|
||
|
||
tmp = PWM_NEW_READ(ch, CFG_PCCTL_ADDR);
|
||
REG_FIELD_SET(CHP_EN, tmp, en);
|
||
PWM_NEW_WRITE(ch, CFG_PCCTL_ADDR, tmp);
|
||
}
|
||
|
||
void pwm_tz_acta_set(uint8_t ch, uint8_t action_a)
|
||
{
|
||
uint32_t tmp;
|
||
|
||
if (PWM_CHANNEL_INVALID(ch)) {
|
||
return ;
|
||
}
|
||
|
||
tmp = PWM_NEW_READ(ch, CFG_TZCTL_ADDR);
|
||
REG_FIELD_SET(TZ_ACTA, tmp, action_a);
|
||
PWM_NEW_WRITE(ch, CFG_TZCTL_ADDR, tmp);
|
||
}
|
||
void pwm_tz_actb_set(uint8_t ch, uint8_t action_b)
|
||
{
|
||
uint32_t tmp;
|
||
|
||
if (PWM_CHANNEL_INVALID(ch)) {
|
||
return ;
|
||
}
|
||
|
||
tmp = PWM_NEW_READ(ch, CFG_TZCTL_ADDR);
|
||
REG_FIELD_SET(TZ_ACTB, tmp, action_b);
|
||
PWM_NEW_WRITE(ch, CFG_TZCTL_ADDR, tmp);
|
||
}
|
||
|
||
static void IRAM_ATTR pwm_interrupt_mask(uint8_t ch, uint32_t mask)
|
||
{
|
||
uint32_t tmp;
|
||
|
||
if (PWM_CHANNEL_INVALID(ch)) {
|
||
return ;
|
||
}
|
||
|
||
tmp = PWM_NEW_READ(ch, CFG_PWMINT_ENA_ADDR);
|
||
tmp &= ~mask;
|
||
PWM_NEW_WRITE(ch, CFG_PWMINT_ENA_ADDR, tmp);
|
||
}
|
||
|
||
static void IRAM_ATTR pwm_interrupt_clear(uint8_t ch, uint32_t status)
|
||
{
|
||
uint32_t tmp;
|
||
|
||
if (PWM_CHANNEL_INVALID(ch)) {
|
||
return ;
|
||
}
|
||
|
||
tmp = PWM_NEW_READ(ch, CFG_PWMINT_CLR_ADDR);
|
||
tmp |= status;
|
||
PWM_NEW_WRITE(ch, CFG_PWMINT_CLR_ADDR, tmp);
|
||
}
|
||
|
||
static void IRAM_ATTR pwm_interrupt_unmask(uint8_t ch, uint32_t mask)
|
||
{
|
||
uint32_t tmp;
|
||
|
||
if (PWM_CHANNEL_INVALID(ch)) {
|
||
return ;
|
||
}
|
||
|
||
tmp = PWM_NEW_READ(ch, CFG_PWMINT_ENA_ADDR);
|
||
tmp |= mask;
|
||
PWM_NEW_WRITE(ch, CFG_PWMINT_ENA_ADDR, tmp);
|
||
}
|
||
|
||
static uint32_t IRAM_ATTR pwm_interupt_handler(uint32_t vector,
|
||
iot_addrword_t data)
|
||
{
|
||
uint32_t status = 0;
|
||
|
||
int ch = 0;
|
||
// 因pwm vector 不再连续故做如下修改
|
||
if (HAL_VECTOR_PWM0 == vector ) {
|
||
ch = 0;
|
||
} else if(HAL_VECTOR_PWM1 == vector ) {
|
||
ch = 1;
|
||
} else if(HAL_VECTOR_PWM2 == vector ) {
|
||
ch = 2;
|
||
} else if(HAL_VECTOR_PWM3 == vector ) {
|
||
ch = 3;
|
||
} else if(HAL_VECTOR_PWM4 == vector ) {
|
||
ch = 4;
|
||
} else if(HAL_VECTOR_PWM5 == vector ) {
|
||
ch = 5;
|
||
} else {
|
||
return 0;
|
||
}
|
||
|
||
/* get int status */
|
||
status = (PWM_NEW_READ(ch, CFG_PWMINT_ST_ADDR));
|
||
|
||
pwm_interrupt_mask(ch, status);
|
||
|
||
/* clr intr. except OSHT_INT_ST_MASK, which should be clear by app. */
|
||
pwm_interrupt_clear(ch, status & (~OSHT_INT_ST_MASK));
|
||
|
||
|
||
if (status & INNER_INT_ST_MASK) {
|
||
if (g_pwm_info.isr[ch] != NULL) {
|
||
g_pwm_info.isr[ch]();
|
||
}
|
||
}
|
||
|
||
if (status & SOCA_INT_ST_MASK ) {
|
||
if (g_pwm_info.soca_isr[ch] != NULL) {
|
||
g_pwm_info.soca_isr[ch]();
|
||
}
|
||
}
|
||
|
||
if (status & SOCB_INT_ST_MASK ) {
|
||
if (g_pwm_info.socb_isr[ch] != NULL) {
|
||
g_pwm_info.socb_isr[ch]();
|
||
}
|
||
}
|
||
|
||
if (status & CBC_INT_ST_MASK ) {
|
||
if (g_pwm_info.fault_cbc_isr[ch] != NULL) {
|
||
g_pwm_info.fault_cbc_isr[ch]();
|
||
}
|
||
}
|
||
|
||
if (status & OSHT_INT_ST_MASK ) {
|
||
if (g_pwm_info.fault_osht_isr[ch] != NULL) {
|
||
g_pwm_info.fault_osht_isr[ch]();
|
||
}
|
||
}
|
||
|
||
/* enable intr */
|
||
pwm_interrupt_unmask(ch, status);
|
||
return 0;
|
||
}
|
||
|
||
static uint32_t pwm_get_interrupt_vector(uint8_t ch)
|
||
{
|
||
uint32_t vector = (uint32_t) -1;
|
||
switch(ch) {
|
||
case PWM_CHANNEL_0 : {
|
||
vector = HAL_VECTOR_PWM0;
|
||
break;
|
||
}
|
||
case PWM_CHANNEL_1 : {
|
||
vector = HAL_VECTOR_PWM1;
|
||
break;
|
||
}
|
||
case PWM_CHANNEL_2 : {
|
||
vector = HAL_VECTOR_PWM2;
|
||
break;
|
||
}
|
||
case PWM_CHANNEL_3 : {
|
||
vector = HAL_VECTOR_PWM3;
|
||
break;
|
||
}
|
||
case PWM_CHANNEL_4 : {
|
||
vector = HAL_VECTOR_PWM4;
|
||
break;
|
||
}
|
||
case PWM_CHANNEL_5 : {
|
||
vector = HAL_VECTOR_PWM5;
|
||
break;
|
||
}
|
||
|
||
}
|
||
|
||
return vector;
|
||
}
|
||
|
||
/*Event-Trigger Selection*/
|
||
void pwm_set_etsel(uint8_t ch, uint8_t inner_int_sel,
|
||
uint8_t soca_sel, uint8_t soca_en, uint8_t socb_sel, uint8_t socb_en)
|
||
{
|
||
uint32_t tmp;
|
||
|
||
if (PWM_CHANNEL_INVALID(ch)) {
|
||
return ;
|
||
}
|
||
|
||
tmp = PWM_NEW_READ(ch, CFG_ETSEL_ADDR);
|
||
|
||
REG_FIELD_SET(INNER_INT_SEL, tmp, inner_int_sel);
|
||
REG_FIELD_SET(SOCA_SEL, tmp, soca_sel);
|
||
REG_FIELD_SET(SOCA_EN, tmp, soca_en);
|
||
REG_FIELD_SET(SOCB_SEL, tmp, socb_sel);
|
||
REG_FIELD_SET(SOCB_EN, tmp, socb_en);
|
||
PWM_NEW_WRITE(ch, CFG_ETSEL_ADDR, tmp);
|
||
}
|
||
|
||
/*Event-Trigger Prescale*/
|
||
void pwm_set_etps(uint8_t ch, uint8_t int_prd, uint8_t soca_prd, uint8_t socb_prd)
|
||
{
|
||
uint32_t tmp;
|
||
|
||
if (PWM_CHANNEL_INVALID(ch)) {
|
||
return ;
|
||
}
|
||
|
||
tmp = PWM_NEW_READ(ch, CFG_ETPS_ADDR);
|
||
|
||
REG_FIELD_SET(INT_PRD, tmp, int_prd);
|
||
REG_FIELD_SET(SOCA_PRD, tmp, soca_prd);
|
||
REG_FIELD_SET(SOCB_PRD, tmp, socb_prd);
|
||
PWM_NEW_WRITE(ch, CFG_ETPS_ADDR, tmp);
|
||
}
|
||
|
||
void pwm_interrupt_init(uint8_t ch)
|
||
{
|
||
uint32_t mask = INNER_INT_ST_MASK;
|
||
if (PWM_CHANNEL_INVALID(ch)) {
|
||
return ;
|
||
}
|
||
|
||
/* clr pwm int */
|
||
pwm_interrupt_clear(ch, mask);
|
||
/* inner int enable */
|
||
pwm_interrupt_unmask(ch, mask);
|
||
|
||
/*Enable event time-base counter equal to period (TBCTR = TBPRD)*/
|
||
pwm_set_etsel(ch, INNER_SEL_OPT_TB_CNT_EQ_PRD, 0, 0, 0, 0);
|
||
|
||
/*Generate an interrupt on the first event INTCNT = 01 (first event)*/
|
||
pwm_set_etps(ch, 100, 0, 0);
|
||
|
||
/* interrupt controller */
|
||
if(!g_pwm_info.irq_handle) {
|
||
g_pwm_info.irq_handle = iot_interrupt_create(
|
||
pwm_get_interrupt_vector(ch),
|
||
HAL_INTR_PRI_0, 0, pwm_interupt_handler);
|
||
|
||
iot_interrupt_attach(g_pwm_info.irq_handle);
|
||
iot_interrupt_unmask(g_pwm_info.irq_handle);
|
||
}
|
||
}
|
||
|
||
void pwm_hw_init(uint8_t ch)
|
||
{
|
||
if (PWM_CHANNEL_INVALID(ch)) {
|
||
return ;
|
||
}
|
||
|
||
//load from shadow select mode
|
||
//注意这里必须都设为CC_CTR_PRD,如果为CC_CTR_ZERO 输出的波形不对,
|
||
//在B的占空比为0时,A会少一个脉冲
|
||
pwm_cmpctl_set(ch, CC_CTR_PRD, CC_CTR_PRD, CC_SHADOW, CC_SHADOW);
|
||
|
||
//action when counter equals zero or CMPA register
|
||
pwm_aqctla_set(ch, AQ_SET, AQ_NOTHING,
|
||
AQ_CLEAR, AQ_NOTHING, AQ_NOTHING, AQ_NOTHING);
|
||
|
||
pwm_aqctlb_set(ch, AQ_SET, AQ_NOTHING,
|
||
AQ_NOTHING, AQ_NOTHING, AQ_CLEAR, AQ_NOTHING);
|
||
|
||
}
|
||
|
||
uint8_t pwm_init(uint8_t ch)
|
||
{
|
||
if (PWM_CHANNEL_INVALID(ch)) {
|
||
return -1;
|
||
}
|
||
pwm_tbclk_sync(ch, false);
|
||
|
||
/* disable PWMx module in APB */
|
||
pwm_tbclk_ctrl(ch, true);
|
||
|
||
//pwm_stop(ch);
|
||
pwm_tb_phase_set(ch, 0);
|
||
pwm_tbctl_set(ch, TB_DISABLE, TB_SHADOW, TB_SYNC_PWM, 0);
|
||
|
||
pwm_tb_period_set(ch, 999);
|
||
|
||
pwm_hw_init(ch);
|
||
|
||
int duty_a = 100;
|
||
int duty_b = CHANGE_DUTY; //为适配iot 层,这里仅仅输出无死区的互补PWM波形
|
||
|
||
pwm_cmpa_cmpb_set(ch, duty_a, duty_b);
|
||
|
||
return 0;
|
||
}
|
||
|
||
void pwm_deinit(uint8_t ch)
|
||
{
|
||
if (PWM_CHANNEL_INVALID(ch)) {
|
||
return;
|
||
}
|
||
apb_disable(apb_module[ch]);
|
||
}
|
||
|
||
void pwm_close(uint8_t ch)
|
||
{
|
||
if (PWM_CHANNEL_INVALID(ch)) {
|
||
return;
|
||
}
|
||
uint32_t mask = INNER_INT_ST_MASK | SOCA_INT_ST_MASK | SOCB_INT_ST_MASK |
|
||
CBC_INT_ST_MASK | OSHT_INT_ST_MASK;
|
||
|
||
/* mask this channel */
|
||
pwm_interrupt_mask(ch, mask);
|
||
|
||
g_pwm_info.isr[ch] = NULL;
|
||
g_pwm_info.soca_isr[ch] = NULL;
|
||
g_pwm_info.socb_isr[ch] = NULL;
|
||
g_pwm_info.fault_cbc_isr[ch] = NULL;
|
||
g_pwm_info.fault_osht_isr[ch] = NULL;
|
||
}
|
||
|
||
void IRAM_ATTR pwm_set_period(uint8_t ch, uint32_t period)
|
||
{
|
||
if (PWM_CHANNEL_INVALID(ch)) {
|
||
return;
|
||
}
|
||
|
||
pwm_tb_period_set(ch, period - 1);
|
||
pwm_cnt_inner_sync(ch);
|
||
}
|
||
|
||
uint32_t pwm_get_clk()
|
||
{
|
||
return clk_pwm_src_freq_get();
|
||
}
|
||
|
||
int pwm_set_clk(uint8_t clk_src)
|
||
{
|
||
uint32_t target_freq = 0;
|
||
if (clk_src == IOT_PWM_CLK_SRC_25M) {
|
||
target_freq = CLK_FRQ_25M;
|
||
} else if(clk_src == IOT_PWM_CLK_SRC_150M) {
|
||
target_freq = CLK_FRQ_150M;
|
||
} else {
|
||
return -1;
|
||
}
|
||
|
||
clk_pwm_src_freq_set(target_freq);
|
||
return 0;
|
||
}
|
||
|
||
uint32_t pwm_get_ch_clk(uint8_t ch)
|
||
{
|
||
uint32_t clk_src = pwm_get_clk();
|
||
uint32_t div = PWM_NEW_READ(ch, CFG_TBCTL_ADDR);
|
||
div = (div & CLK_PWM_DIV_MASK) >> CLK_PWM_DIV_OFFSET;
|
||
return clk_src / (div + 1);
|
||
}
|
||
|
||
/*
|
||
duty : range 0 - 10000 --> 0.00% - 100.00%
|
||
*/
|
||
void IRAM_ATTR pwm_set_duty(uint8_t ch, uint32_t duty)
|
||
{
|
||
if (PWM_CHANNEL_INVALID(ch)) {
|
||
return;
|
||
}
|
||
#if 1
|
||
uint32_t period = 0;
|
||
uint32_t tmp ;
|
||
|
||
if (0 == duty) {
|
||
tmp = 0;
|
||
} else if ( duty >= 10000 ) {
|
||
tmp = pwm_tb_period_get(ch) + 1;
|
||
} else {
|
||
period = pwm_tb_period_get(ch);
|
||
|
||
tmp = duty * (period + 1) / 10000;
|
||
tmp -= 1;
|
||
}
|
||
|
||
pwm_cmpa_cmpb_set(ch, tmp, CHANGE_DUTY);
|
||
pwm_cnt_inner_sync(ch);
|
||
#else
|
||
pwm_cmpa_cmpb_set(ch, duty, CHANGE_DUTY);
|
||
pwm_cnt_inner_sync(ch);
|
||
#endif
|
||
|
||
}
|
||
|
||
uint8_t pwm_single_mode_init(uint8_t ch)
|
||
{
|
||
uint8_t ret = 0;
|
||
|
||
if (PWM_CHANNEL_INVALID(ch)) {
|
||
return ret;
|
||
}
|
||
/* enable PWMx module in APB */
|
||
apb_enable(apb_module[ch]);
|
||
pwm_hw_init(ch);
|
||
pwm_interrupt_init(ch);
|
||
|
||
return ret;
|
||
}
|
||
|
||
void pwm_start_for_single(uint8_t ch)
|
||
{
|
||
uint32_t tmp;
|
||
|
||
if (PWM_CHANNEL_INVALID(ch)) {
|
||
return;
|
||
}
|
||
tmp = PWM_NEW_READ(ch, CFG_TBCTL_ADDR);
|
||
REG_FIELD_SET(CNT_MODE, tmp, 0b00);
|
||
PWM_NEW_WRITE(ch, CFG_TBCTL_ADDR, tmp);
|
||
|
||
tmp = PWM_NEW_READ(ch, CFG_TBCTL_ADDR);
|
||
REG_FIELD_SET(CNT_MODE, tmp, 0b11);
|
||
PWM_NEW_WRITE(ch, CFG_TBCTL_ADDR, tmp);
|
||
}
|
||
|
||
void pwm_open(uint8_t ch, pwm_isr isr)
|
||
{
|
||
if (PWM_CHANNEL_INVALID(ch)) {
|
||
return;
|
||
}
|
||
}
|
||
|
||
void pwm_start(uint8_t ch)
|
||
{
|
||
pwm_cnt_mode_set(ch, TB_COUNT_UP);
|
||
|
||
pwm_db_inmode_set(ch, DB_INMODE_PWMA_RAW, DB_INMODE_PWMA_RAW);
|
||
pwm_db_polsel_set(ch, DB_POLSE_NORMAL, DB_POLSE_INVERTED); //A不反相,B反相
|
||
pwm_db_outmode_set(ch, DB_OUTMODE_DELAYED, DB_OUTMODE_DELAYED ); //都不产生死区
|
||
|
||
pwm_db_rising_delay_set(ch, 0);
|
||
pwm_db_falling_delay_set(ch, 0);
|
||
pwm_tb_cnt_set(ch, 0);
|
||
pwm_cnt_start(ch, true);
|
||
pwm_cnt_load_mode(ch, TB_LOAD_MODE_INNER_SYNC);
|
||
|
||
pwm_tbclk_sync(ch, true);
|
||
|
||
pwm_cnt_inner_sync(ch);
|
||
}
|
||
|
||
void pwm_stop(uint8_t ch)
|
||
{
|
||
pwm_cnt_mode_set(ch, TB_COUNT_STOP_FREEZE);
|
||
|
||
pwm_cnt_start(ch, false);
|
||
pwm_tbclk_ctrl(ch, false);
|
||
}
|
||
|
||
void pwm_ch_init(uint8_t ch)
|
||
{
|
||
if (PWM_CHANNEL_INVALID(ch)) {
|
||
return;
|
||
}
|
||
}
|
||
|
||
void pwm_synci_in_config(uint8_t gpio)
|
||
{
|
||
gpio_sig_info_t info = {0};
|
||
info.CFG[0].outid = 0xff;
|
||
|
||
info.CFG[0].type = IO_TYPE_IN;
|
||
info.CFG[0].func = gpio_pin_func_get(gpio);
|
||
info.CFG[0].gpio = gpio;
|
||
info.CFG[0].inid = GPIO_MTX_PWMSYNCI_IN;
|
||
|
||
info.sig_type = 1;
|
||
|
||
gpio_mtx_enable();
|
||
gpio_module_pin_select(&info);
|
||
gpio_module_sig_select(&info, GPIO_MTX_MODE_MATRIX);
|
||
}
|
||
|
||
void pwm_gpio_config(uint8_t ch, uint8_t gpio_h, uint8_t gpio_l)
|
||
{
|
||
gpio_sig_info_t info = {0};
|
||
uint8_t index = 0;
|
||
uint8_t gpio_h_outid, gpio_l_outid;
|
||
|
||
if (PWM_CHANNEL_INVALID(ch)) {
|
||
return;
|
||
}
|
||
|
||
if (ch == PWM_CHANNEL_0) {
|
||
gpio_h_outid = GPIO_MTX_PWM0A_OUT;
|
||
gpio_l_outid = GPIO_MTX_PWM0B_OUT;
|
||
} else if (ch == PWM_CHANNEL_1) {
|
||
gpio_h_outid = GPIO_MTX_PWM1A_OUT;
|
||
gpio_l_outid = GPIO_MTX_PWM1B_OUT;
|
||
} else if (ch == PWM_CHANNEL_2) {
|
||
gpio_h_outid = GPIO_MTX_PWM2A_OUT;
|
||
gpio_l_outid = GPIO_MTX_PWM2B_OUT;
|
||
} else if (ch == PWM_CHANNEL_3) {
|
||
gpio_h_outid = GPIO_MTX_PWM3A_OUT;
|
||
gpio_l_outid = GPIO_MTX_PWM3B_OUT;
|
||
} else if (ch == PWM_CHANNEL_4) {
|
||
gpio_h_outid = GPIO_MTX_PWM4A_OUT;
|
||
gpio_l_outid = GPIO_MTX_PWM4B_OUT;
|
||
} else if (ch == PWM_CHANNEL_5) {
|
||
gpio_h_outid = GPIO_MTX_PWM5A_OUT;
|
||
gpio_l_outid = GPIO_MTX_PWM5B_OUT;
|
||
}
|
||
|
||
if (gpio_h != 0xff) {
|
||
info.CFG[index].type = IO_TYPE_OUT;
|
||
info.CFG[index].func = gpio_pin_func_get(gpio_h);
|
||
info.CFG[index].gpio = gpio_h;
|
||
info.CFG[index].inid = 0xff;
|
||
info.CFG[index].outid = gpio_h_outid;
|
||
index++;
|
||
}
|
||
|
||
if (gpio_l != 0xff) {
|
||
info.CFG[index].type = IO_TYPE_OUT;
|
||
info.CFG[index].func = gpio_pin_func_get(gpio_l);
|
||
info.CFG[index].gpio = gpio_l;
|
||
info.CFG[index].inid = 0xff;
|
||
info.CFG[index].outid = gpio_l_outid;
|
||
index++;
|
||
}
|
||
|
||
info.sig_type = index;
|
||
|
||
//gpio_mtx_enable();
|
||
gpio_module_pin_select(&info);
|
||
gpio_module_sig_select(&info, GPIO_MTX_MODE_MATRIX);
|
||
}
|
||
|
||
void pwm_gpio_config_with_isr(uint8_t ch, uint8_t gpio_h, uint8_t gpio_l,
|
||
pwm_isr isr)
|
||
{
|
||
if (PWM_CHANNEL_INVALID(ch)) {
|
||
return;
|
||
}
|
||
pwm_interrupt_init(ch);
|
||
pwm_gpio_config(ch, gpio_h, gpio_l);
|
||
|
||
g_pwm_info.isr[ch] = isr;
|
||
|
||
}
|
||
|
||
void pwm_set_isr(uint8_t ch, pwm_isr isr, pwm_isr soca_isr, pwm_isr socb_isr,
|
||
pwm_isr tz_cbc_isr, pwm_isr tz_osht_isr)
|
||
{
|
||
if (PWM_CHANNEL_INVALID(ch)) {
|
||
return;
|
||
}
|
||
|
||
g_pwm_info.isr[ch] = isr;
|
||
g_pwm_info.soca_isr[ch] = soca_isr;
|
||
g_pwm_info.socb_isr[ch] = socb_isr;
|
||
g_pwm_info.fault_cbc_isr[ch] = tz_cbc_isr;
|
||
g_pwm_info.fault_osht_isr[ch] = tz_osht_isr;
|
||
}
|
||
|
||
int pwm_config(uint8_t ch, uint8_t clk_source,
|
||
uint32_t period, uint8_t gpio_p, uint8_t gpio_n)
|
||
{
|
||
return -1;
|
||
}
|
||
|
||
int pwm_deconfig(uint8_t ch)
|
||
{
|
||
return -1;
|
||
}
|
||
|
||
int IRAM_ATTR pwm_set_raw_duty(uint8_t ch, uint32_t duty_cnt)
|
||
{
|
||
return -1;
|
||
}
|
||
|
||
void pwm_fault_config(uint8_t ch, uint8_t gpio, uint8_t h_state,
|
||
uint8_t l_state,pwm_isr cb){
|
||
pwm_tz_pin_set(TZ_NUM_0, gpio);
|
||
pwm_tz_sel(ch, TZ_SEL_TZ1_CBC);
|
||
|
||
if (h_state) {
|
||
pwm_tz_acta_set(ch, TZ_ACTION_FORCE_HIGHT);
|
||
} else {
|
||
pwm_tz_acta_set(ch, TZ_ACTION_FORCE_LOW);
|
||
}
|
||
|
||
if (l_state) {
|
||
pwm_tz_actb_set(ch, TZ_ACTION_FORCE_HIGHT);
|
||
} else {
|
||
pwm_tz_actb_set(ch, TZ_ACTION_FORCE_LOW);
|
||
}
|
||
|
||
uint32_t mask = CBC_INT_ST_MASK;
|
||
if (cb) {
|
||
/* clr pwm int */
|
||
pwm_interrupt_clear(ch, mask);
|
||
/* inner int enable */
|
||
pwm_interrupt_unmask(ch, mask);
|
||
g_pwm_info.fault_cbc_isr[ch] = cb;
|
||
|
||
if(!g_pwm_info.irq_handle) {
|
||
g_pwm_info.irq_handle = iot_interrupt_create(pwm_get_interrupt_vector(ch),
|
||
HAL_INTR_PRI_0, 0, pwm_interupt_handler);
|
||
|
||
iot_interrupt_attach(g_pwm_info.irq_handle);
|
||
iot_interrupt_unmask(g_pwm_info.irq_handle);
|
||
}
|
||
}
|
||
}
|
||
|
||
static iot_epwm_global_config_t iot_epwm_golbal_config;
|
||
|
||
static iot_epwm_ch_config_t iot_epwm_ch_config[PWM_CHANNEL_MAX];
|
||
|
||
static uint32_t epwm_get_channel_clock(uint8_t ch)
|
||
{
|
||
return pwm_get_ch_clk(ch);
|
||
}
|
||
|
||
static uint32_t epwm_get_channel_period(uint8_t ch)
|
||
{
|
||
uint32_t prd = PWM_NEW_READ(ch, CFG_TBPRD_ADDR);
|
||
prd = (prd & TBPRD_MASK) >> TBPRD_OFFSET;
|
||
return (prd + 1);
|
||
}
|
||
|
||
uint8_t epwm_get_channel_count(void)
|
||
{
|
||
return PWM_CHANNEL_MAX;
|
||
}
|
||
|
||
int epwm_global_config_set(iot_epwm_global_config_t *cfg)
|
||
{
|
||
if (NULL == cfg) {
|
||
return -1;
|
||
}
|
||
|
||
if (IOT_PWM_CLK_SRC_25M == cfg->clk_src) {
|
||
pwm_set_clk(IOT_PWM_CLK_SRC_25M);
|
||
} else if (IOT_PWM_CLK_SRC_150M == cfg->clk_src) {
|
||
clk_core_freq_set(CLK_FRQ_150M);
|
||
pwm_set_clk(IOT_PWM_CLK_SRC_150M);
|
||
} else {
|
||
return -1;
|
||
}
|
||
pwm_synci_in_config(cfg->ext_sync_pin);
|
||
pwm_tz_pin_set(TZ_NUM_0, cfg->tz_pins[IOT_EPWM_TZ_1]);
|
||
pwm_tz_pin_set(TZ_NUM_1, cfg->tz_pins[IOT_EPWM_TZ_2]);
|
||
pwm_tz_pin_set(TZ_NUM_2, cfg->tz_pins[IOT_EPWM_TZ_3]);
|
||
|
||
os_mem_cpy(&iot_epwm_golbal_config, cfg, sizeof(iot_epwm_global_config_t));
|
||
return 0;
|
||
}
|
||
|
||
iot_epwm_global_config_t * epwm_global_config_get(void)
|
||
{
|
||
return &iot_epwm_golbal_config;
|
||
}
|
||
|
||
void epwm_global_start(void)
|
||
{
|
||
pwm_tbclk_sync(PWM_CHANNEL_0, true);
|
||
}
|
||
|
||
void epwm_global_stop(void)
|
||
{
|
||
pwm_tbclk_sync(PWM_CHANNEL_0, false);
|
||
}
|
||
|
||
void epwm_global_sync(void)
|
||
{
|
||
pwm_cnt_soc_sync_load();
|
||
}
|
||
|
||
void epwm_ch_start(uint8_t ch)
|
||
{
|
||
pwm_cnt_start(ch, true);
|
||
}
|
||
|
||
void epwm_ch_stop(uint8_t ch)
|
||
{
|
||
pwm_cnt_start(ch, false);
|
||
}
|
||
|
||
void epwm_ch_close(uint8_t ch)
|
||
{
|
||
if (PWM_CHANNEL_INVALID(ch)) {
|
||
return;
|
||
}
|
||
|
||
/* stop counter. */
|
||
pwm_cnt_start(ch, false);
|
||
|
||
/* release interrupt. */
|
||
uint32_t mask = INNER_INT_ST_MASK | SOCA_INT_ST_MASK | SOCB_INT_ST_MASK |
|
||
CBC_INT_ST_MASK | OSHT_INT_ST_MASK;
|
||
/* clear interrupt. */
|
||
pwm_interrupt_clear(ch, mask);
|
||
/* mask this channel, disable interrupts. */
|
||
pwm_interrupt_mask(ch, mask);
|
||
g_pwm_info.isr[ch] = NULL;
|
||
g_pwm_info.soca_isr[ch] = NULL;
|
||
g_pwm_info.socb_isr[ch] = NULL;
|
||
g_pwm_info.fault_cbc_isr[ch] = NULL;
|
||
g_pwm_info.fault_osht_isr[ch] = NULL;
|
||
|
||
/* release pin. */
|
||
if (0xFF != iot_epwm_ch_config[ch].ch_pin_outa) {
|
||
gpio_mtx_sig_out_default(0xFF, iot_epwm_ch_config[ch].ch_pin_outa);
|
||
}
|
||
if (0xFF != iot_epwm_ch_config[ch].ch_pin_outb) {
|
||
gpio_mtx_sig_out_default(0xFF, iot_epwm_ch_config[ch].ch_pin_outb);
|
||
}
|
||
|
||
/* disable channel clock. */
|
||
apb_disable(apb_module[ch]);
|
||
|
||
os_mem_set(&iot_epwm_ch_config[ch], 0, sizeof(iot_epwm_ch_config_t));
|
||
}
|
||
|
||
int epwm_ch_config_set(uint8_t ch, iot_epwm_ch_config_t *cfg)
|
||
{
|
||
if (PWM_CHANNEL_INVALID(ch) || NULL == cfg) {
|
||
return -1;
|
||
}
|
||
/* open channel clock gate */
|
||
pwm_tbclk_ctrl(ch, true);
|
||
/* output pin */
|
||
pwm_gpio_config(ch, cfg->ch_pin_outa, cfg->ch_pin_outb);
|
||
/* clock divider */
|
||
pwm_tb_set_clk_div(ch, cfg->ch_clk_div - 1);
|
||
pwm_tb_set_prd_load_mode(ch,
|
||
(IOT_EPWM_PERIOD_LOAD_IMMEDIATELY == cfg->ch_period_load_mode) ?
|
||
TB_NO_SHADOW : TB_SHADOW);
|
||
pwm_tb_set_sync_out_src(ch, TB_SYNC_PWM);
|
||
/* period and duty config */
|
||
if (IOT_EPWM_CH_USEAGE_COMMON == cfg->ch_usage ) {
|
||
uint32_t prd = (pwm_get_clk()/cfg->ch_clk_div)/
|
||
cfg->ch_common_cfg.freq;
|
||
uint32_t cmp = (prd * cfg->ch_common_cfg.duty) / 10000;
|
||
pwm_tb_period_set(ch, prd - 1);
|
||
pwm_cmpa_cmpb_set(ch, cmp, cmp);
|
||
} else {
|
||
pwm_tb_period_set(ch, cfg->ch_precise_cfg.period_cnt - 1);
|
||
pwm_cmpa_cmpb_set(ch, cfg->ch_precise_cfg.compare_cnt,
|
||
cfg->ch_precise_cfg.compare_cnt);
|
||
}
|
||
if (IOT_EPWM_DUTY_LOAD_IMMEDIATELY == cfg->ch_duty_load_mode) {
|
||
pwm_cmpctl_set(ch, CC_CTR_FREEZE, CC_CTR_FREEZE, CC_NO_SHADOW,
|
||
CC_NO_SHADOW);
|
||
} else if (IOT_EPWM_DUTY_LOAD_CNT_EQU_ZERO == cfg->ch_duty_load_mode) {
|
||
pwm_cmpctl_set(ch, CC_CTR_ZERO, CC_CTR_ZERO, CC_SHADOW, CC_SHADOW);
|
||
} else if (IOT_EPWM_DUTY_LOAD_CNT_EQU_PRD == cfg->ch_duty_load_mode) {
|
||
pwm_cmpctl_set(ch, CC_CTR_PRD, CC_CTR_PRD, CC_SHADOW, CC_SHADOW);
|
||
} else if (IOT_EPWM_DUTY_LOAD_CNT_EQU_ZERO_OR_PRD ==
|
||
cfg->ch_duty_load_mode) {
|
||
pwm_cmpctl_set(ch, CC_CTR_ZERO_OR_PRD, CC_CTR_ZERO_OR_PRD, CC_SHADOW,
|
||
CC_SHADOW);
|
||
}
|
||
/* action config */
|
||
pwm_aq_action_clear(ch, PWMA);
|
||
pwm_aq_action_clear(ch, PWMB);
|
||
if (IOT_EPWM_ALIGN_EDGE == cfg->ch_align_mode) {
|
||
/* ACTA: CNT=0, set high; CNT up and equal CMPA, set low; */
|
||
pwm_aq_set_action_with_condition(ch, PWMA, AQ_INPUT_CNT_EQU_ZERO,
|
||
AQ_ACTION_SET);
|
||
pwm_aq_set_action_with_condition(ch, PWMA, AQ_INPUT_CNT_UP_EQU_CMPA,
|
||
AQ_ACTION_CLEAR);
|
||
/* ACTB: CNT=0, set high; CNT up and equal CMPB, set low; */
|
||
pwm_aq_set_action_with_condition(ch, PWMB, AQ_INPUT_CNT_EQU_ZERO,
|
||
AQ_ACTION_SET);
|
||
pwm_aq_set_action_with_condition(ch, PWMB, AQ_INPUT_CNT_UP_EQU_CMPB,
|
||
AQ_ACTION_CLEAR);
|
||
} else {
|
||
/* ACTA: CNT=0, set low; CNT up and eqaul CMPA, set high;
|
||
CNT down and equal CMPB, set low; */
|
||
pwm_aq_set_action_with_condition(ch, PWMA, AQ_INPUT_CNT_EQU_ZERO,
|
||
AQ_ACTION_CLEAR);
|
||
pwm_aq_set_action_with_condition(ch, PWMA, AQ_INPUT_CNT_UP_EQU_CMPA,
|
||
AQ_ACTION_SET);
|
||
pwm_aq_set_action_with_condition(ch, PWMA,AQ_INPUT_CNT_DOWN_EQU_CMPA,
|
||
AQ_ACTION_CLEAR);
|
||
/* ACTB: CNT=0, set low; CNT up and eqaul CMPB, set high;
|
||
CNT down and equal CMPB, set low; */
|
||
pwm_aq_set_action_with_condition(ch, PWMB, AQ_INPUT_CNT_EQU_ZERO,
|
||
AQ_ACTION_CLEAR);
|
||
pwm_aq_set_action_with_condition(ch, PWMB, AQ_INPUT_CNT_UP_EQU_CMPB,
|
||
AQ_ACTION_SET);
|
||
pwm_aq_set_action_with_condition(ch, PWMB,AQ_INPUT_CNT_DOWN_EQU_CMPB,
|
||
AQ_ACTION_CLEAR);
|
||
}
|
||
/* dead band config */
|
||
pwm_db_inmode_set(ch, DB_INMODE_PWMA_RAW, DB_INMODE_PWMA_RAW);
|
||
pwm_db_polsel_set(ch,
|
||
(cfg->ch_polarity_outa == IOT_EPWM_POLARITY_INVERTED) ?
|
||
DB_POLSE_INVERTED : DB_POLSE_NORMAL,
|
||
(cfg->ch_polarity_outb == IOT_EPWM_POLARITY_INVERTED) ?
|
||
DB_POLSE_INVERTED : DB_POLSE_NORMAL);
|
||
pwm_db_outmode_set(ch, DB_OUTMODE_DELAYED, DB_OUTMODE_DELAYED);
|
||
if (cfg->ch_dead_band.enable > 0) {
|
||
pwm_db_rising_delay_set(ch, cfg->ch_dead_band.rising_delay);
|
||
pwm_db_falling_delay_set(ch, cfg->ch_dead_band.falling_delay);
|
||
} else {
|
||
pwm_db_rising_delay_set(ch, 0);
|
||
pwm_db_falling_delay_set(ch, 0);
|
||
}
|
||
/* trip zone config */
|
||
if (cfg->ch_trip_zone.enable > 0) {
|
||
uint8_t tz_sel = 0;
|
||
if (cfg->ch_trip_zone.tz_en_for_osht[IOT_EPWM_TZ_1] > 0) {
|
||
tz_sel |= TZ_SEL_TZ1_OSHT;
|
||
}
|
||
if (cfg->ch_trip_zone.tz_en_for_osht[IOT_EPWM_TZ_2] > 0) {
|
||
tz_sel |= TZ_SEL_TZ2_OSHT;
|
||
}
|
||
if (cfg->ch_trip_zone.tz_en_for_osht[IOT_EPWM_TZ_3] > 0) {
|
||
tz_sel |= TZ_SEL_TZ3_OSHT;
|
||
}
|
||
if (cfg->ch_trip_zone.tz_en_for_cbc[IOT_EPWM_TZ_1] > 0) {
|
||
tz_sel |= TZ_SEL_TZ1_CBC;
|
||
}
|
||
if (cfg->ch_trip_zone.tz_en_for_cbc[IOT_EPWM_TZ_2] > 0) {
|
||
tz_sel |= TZ_SEL_TZ2_CBC;
|
||
}
|
||
if (cfg->ch_trip_zone.tz_en_for_cbc[IOT_EPWM_TZ_3] > 0) {
|
||
tz_sel |= TZ_SEL_TZ3_CBC;
|
||
}
|
||
pwm_tz_sel(ch, tz_sel);
|
||
pwm_tz_action_set(ch, PWMA, cfg->ch_trip_zone.act_outa);
|
||
pwm_tz_action_set(ch, PWMB, cfg->ch_trip_zone.act_outb);
|
||
} else {
|
||
pwm_tz_clear(ch);
|
||
pwm_tz_action_set(ch, PWMA, TZ_ACTION_NOTHING);
|
||
pwm_tz_action_set(ch, PWMB, TZ_ACTION_NOTHING);
|
||
}
|
||
/* single pulse mode config */
|
||
pwm_tb_single_pulse_set(ch, cfg->ch_single_pulse_en);
|
||
/* auto duty config */
|
||
if (cfg->ch_auto_duty.enable > 0) {
|
||
pwm_cmpa_cmpb_set(ch, cfg->ch_auto_duty.cmp_start,
|
||
cfg->ch_auto_duty.cmp_start);
|
||
pwm_cmpctl_cmpa_end(ch, cfg->ch_auto_duty.cmp_end);
|
||
pwm_cmpctl_cmpa_step(ch, cfg->ch_auto_duty.cmp_step);
|
||
pwm_cmpctl_cmpb_end(ch, cfg->ch_auto_duty.cmp_end);
|
||
pwm_cmpctl_cmpb_step(ch, cfg->ch_auto_duty.cmp_step);
|
||
pwm_cmpctl_auto_duty(ch, true, true);
|
||
} else {
|
||
pwm_cmpctl_auto_duty(ch, false, false);
|
||
}
|
||
/* chopper config */
|
||
if (cfg->ch_chopper.enable > 0) {
|
||
pwm_chopping_duty_sel(ch, cfg->ch_chopper.duty - 1);
|
||
pwm_chopping_div_sel(ch, cfg->ch_chopper.divider - 1);
|
||
pwm_chopping_one_shot_width_sel(ch, cfg->ch_chopper.osht_width - 1);
|
||
pwm_chopping_en(ch, true);
|
||
} else {
|
||
pwm_chopping_en(ch, false);
|
||
}
|
||
/* phase synchronization config */
|
||
pwm_tb_phase_set(ch, cfg->ch_phase);
|
||
pwm_tb_set_phase_en(ch, (cfg->ch_phs_en > 0) ? 1 : 0);
|
||
/* count mode config */
|
||
pwm_cnt_mode_set(ch, (IOT_EPWM_ALIGN_EDGE == cfg->ch_align_mode) ?
|
||
TB_COUNT_UP : TB_COUNT_UP_DOWN);
|
||
/* sync mode config */
|
||
if (IOT_EPWM_CH_INNER_SYNC == cfg->ch_sync_mode) {
|
||
pwm_cnt_load_mode(ch, 1);
|
||
pwm_cnt_inner_sync(ch);
|
||
} else {
|
||
pwm_cnt_load_mode(ch, 0);
|
||
}
|
||
|
||
pwm_tb_cnt_set(ch, 0);
|
||
|
||
/* interrupt config */
|
||
uint32_t mask = 0;
|
||
if (cfg->ch_interrupt.enable > 0) {
|
||
mask |= INNER_INT_ST_MASK;
|
||
PWM_CH_REG_FIELD_SET(ch, CFG_ETSEL_ADDR, INNER_INT_SEL,
|
||
cfg->ch_interrupt.trigger);
|
||
PWM_CH_REG_FIELD_SET(ch, CFG_ETPS_ADDR, INT_PRD,
|
||
cfg->ch_interrupt.divider);
|
||
g_pwm_info.isr[ch] = cfg->ch_interrupt.callback;
|
||
} else {
|
||
g_pwm_info.isr[ch] = NULL;
|
||
}
|
||
if (cfg->ch_soca.enable > 0) {
|
||
PWM_CH_REG_FIELD_SET(ch, CFG_ETSEL_ADDR, SOCA_EN, 1);
|
||
PWM_CH_REG_FIELD_SET(ch, CFG_ETSEL_ADDR, SOCA_SEL,
|
||
cfg->ch_soca.trigger);
|
||
PWM_CH_REG_FIELD_SET(ch, CFG_ETPS_ADDR, SOCA_PRD,
|
||
cfg->ch_soca.divider);
|
||
if (NULL == cfg->ch_soca.callback) {
|
||
g_pwm_info.soca_isr[ch] = NULL;
|
||
} else {
|
||
mask |= SOCA_INT_ST_MASK;
|
||
g_pwm_info.soca_isr[ch] = cfg->ch_soca.callback;
|
||
}
|
||
}
|
||
if (cfg->ch_socb.enable > 0) {
|
||
PWM_CH_REG_FIELD_SET(ch, CFG_ETSEL_ADDR, SOCB_EN, 1);
|
||
PWM_CH_REG_FIELD_SET(ch, CFG_ETSEL_ADDR, SOCB_SEL,
|
||
cfg->ch_socb.trigger);
|
||
PWM_CH_REG_FIELD_SET(ch, CFG_ETPS_ADDR, SOCB_PRD,
|
||
cfg->ch_socb.divider);
|
||
if (NULL == cfg->ch_socb.callback) {
|
||
g_pwm_info.socb_isr[ch] = NULL;
|
||
} else {
|
||
mask |= SOCB_INT_ST_MASK;
|
||
g_pwm_info.socb_isr[ch] = cfg->ch_socb.callback;
|
||
}
|
||
}
|
||
if (cfg->ch_trip_zone.enable > 0) {
|
||
if (cfg->ch_trip_zone.callback_cbc) {
|
||
mask |= CBC_INT_ST_MASK;
|
||
g_pwm_info.fault_cbc_isr[ch] = cfg->ch_trip_zone.callback_cbc;
|
||
} else {
|
||
g_pwm_info.fault_cbc_isr[ch] = NULL;
|
||
}
|
||
if (cfg->ch_trip_zone.callback_osht) {
|
||
mask |= OSHT_INT_ST_MASK;
|
||
g_pwm_info.fault_osht_isr[ch] = cfg->ch_trip_zone.callback_osht;
|
||
} else {
|
||
g_pwm_info.fault_osht_isr[ch] = NULL;
|
||
}
|
||
}
|
||
/* clear all interrupt. */
|
||
pwm_interrupt_clear(ch, 0xFFFFFFFF);
|
||
/* disable all interrupt. */
|
||
pwm_interrupt_mask(ch, 0xFFFFFFFF);
|
||
if (mask > 0) {
|
||
/* enable selected interrupt. */
|
||
pwm_interrupt_unmask(ch, mask);
|
||
/* interrupt controller. */
|
||
if(!g_pwm_info.irq_handle) {
|
||
g_pwm_info.irq_handle = iot_interrupt_create(
|
||
pwm_get_interrupt_vector(ch),
|
||
HAL_INTR_PRI_0, 0, pwm_interupt_handler);
|
||
iot_interrupt_attach(g_pwm_info.irq_handle);
|
||
iot_interrupt_unmask(g_pwm_info.irq_handle);
|
||
}
|
||
}
|
||
|
||
os_mem_cpy(&iot_epwm_ch_config[ch], cfg, sizeof(iot_epwm_ch_config_t));
|
||
return 0;
|
||
}
|
||
|
||
iot_epwm_ch_config_t * epwm_ch_config_get(uint8_t ch)
|
||
{
|
||
if (PWM_CHANNEL_INVALID(ch)) {
|
||
return NULL;
|
||
}
|
||
|
||
return &iot_epwm_ch_config[ch];
|
||
}
|
||
|
||
int epwm_ch_update(uint8_t ch, iot_epwm_ch_updater_e field, uint32_t val1,
|
||
uint32_t val2)
|
||
{
|
||
if (PWM_CHANNEL_INVALID(ch)) {
|
||
return -1;
|
||
}
|
||
switch (field) {
|
||
case IOT_EPWM_CH_UPDATER_FREQUENCY: {
|
||
if (iot_epwm_ch_config[ch].ch_usage != IOT_EPWM_CH_USEAGE_COMMON) {
|
||
return -1;
|
||
}
|
||
uint32_t ch_clk = epwm_get_channel_clock(ch);
|
||
if (0 == val1 || val1 > (ch_clk / 2)) {
|
||
return -1;
|
||
}
|
||
pwm_tb_period_set(ch, (ch_clk / val1) - 1);
|
||
break;
|
||
}
|
||
case IOT_EPWM_CH_UPDATER_DUTY: {
|
||
if ((iot_epwm_ch_config[ch].ch_usage != IOT_EPWM_CH_USEAGE_COMMON)
|
||
|| (val1 > 10000)) {
|
||
return -1;
|
||
}
|
||
uint32_t prd = epwm_get_channel_period(ch);
|
||
uint32_t cmp = (uint32_t)(((uint64_t)prd * (uint64_t)val1) / 10000);
|
||
pwm_cmpa_cmpb_set(ch, cmp, cmp);
|
||
break;
|
||
}
|
||
case IOT_EPWM_CH_UPDATER_FREQUENCY_DUTY: {
|
||
if (iot_epwm_ch_config[ch].ch_usage != IOT_EPWM_CH_USEAGE_COMMON) {
|
||
return -1;
|
||
}
|
||
uint32_t ch_clk = epwm_get_channel_clock(ch);
|
||
if ((0 == val1 || val1 > (ch_clk / 2)) || (val2 > 10000) ) {
|
||
return -1;
|
||
}
|
||
pwm_tb_period_set(ch, (ch_clk / val1) - 1);
|
||
uint32_t prd = epwm_get_channel_period(ch);
|
||
uint32_t cmp = (uint32_t)(((uint64_t)prd * (uint64_t)val2) / 10000);
|
||
pwm_cmpa_cmpb_set(ch, cmp, cmp);
|
||
break;
|
||
}
|
||
case IOT_EPWM_CH_UPDATER_PERIOD_CNT: {
|
||
if ((iot_epwm_ch_config[ch].ch_usage != IOT_EPWM_CH_USEAGE_PRECISE)
|
||
|| (val1 < 1 || val1 > 0x1000000)) {
|
||
return -1;
|
||
}
|
||
pwm_tb_period_set(ch, val1 - 1);
|
||
break;
|
||
}
|
||
case IOT_EPWM_CH_UPDATER_COMPARE_CNT: {
|
||
if ((iot_epwm_ch_config[ch].ch_usage != IOT_EPWM_CH_USEAGE_PRECISE)
|
||
|| (val1 > 0xFFFFFF)) {
|
||
return -1;
|
||
}
|
||
pwm_cmpa_cmpb_set(ch, val1, val1);
|
||
break;
|
||
}
|
||
case IOT_EPWM_CH_UPDATER_PERIOD_COMPARE_CNT: {
|
||
if ((iot_epwm_ch_config[ch].ch_usage != IOT_EPWM_CH_USEAGE_PRECISE)
|
||
|| (val1 < 1 || val1 > 0x1000000) || (val2 > 0xFFFFFF)) {
|
||
return -1;
|
||
}
|
||
pwm_tb_period_set(ch, val1 - 1);
|
||
pwm_cmpa_cmpb_set(ch, val2, val2);
|
||
break;
|
||
}
|
||
default: {
|
||
return -1;
|
||
}
|
||
}
|
||
pwm_cnt_inner_sync(ch);
|
||
/* while period load mode is immediately, counter value should be set to
|
||
default. */
|
||
if (IOT_EPWM_PERIOD_LOAD_IMMEDIATELY ==
|
||
iot_epwm_ch_config[ch].ch_period_load_mode) {
|
||
if (0x1 == pwm_cnt_mode_get(ch)) {
|
||
/* count down mode. */
|
||
pwm_tb_cnt_set(ch, epwm_get_channel_period(ch) - 1);
|
||
} else {
|
||
/* count up or up-down mode. */
|
||
pwm_tb_cnt_set(ch, 0);
|
||
}
|
||
}
|
||
return 0;
|
||
}
|
||
|
||
void epwm_ch_sw_force(uint8_t ch, iot_epwm_ch_event_e event)
|
||
{
|
||
if (PWM_CHANNEL_INVALID(ch)) {
|
||
return;
|
||
}
|
||
|
||
switch (event) {
|
||
case IOT_EPWM_CH_SW_EVENT_INNER_INT: {
|
||
PWM_CH_REG_FIELD_SET(ch, CFG_EVTFRC_ADDR, INNER_INT_FRC, 1);
|
||
break;
|
||
}
|
||
case IOT_EPWM_CH_SW_EVENT_SOCA: {
|
||
PWM_CH_REG_FIELD_SET(ch, CFG_EVTFRC_ADDR, SOCA_FRC, 1);
|
||
break;
|
||
}
|
||
case IOT_EPWM_CH_SW_EVENT_SOCB: {
|
||
PWM_CH_REG_FIELD_SET(ch, CFG_EVTFRC_ADDR, SOCB_FRC, 1);
|
||
break;
|
||
}
|
||
case IOT_EPWM_CH_SW_EVENT_TZ_CBC: {
|
||
PWM_CH_REG_FIELD_SET(ch, CFG_EVTFRC_ADDR, CBC_FRC, 1);
|
||
break;
|
||
}
|
||
case IOT_EPWM_CH_SW_EVENT_TZ_OSHT: {
|
||
PWM_CH_REG_FIELD_SET(ch, CFG_EVTFRC_ADDR, OSHT_FRC, 1);
|
||
break;
|
||
}
|
||
case IOT_EPWM_CH_SW_EVENT_OUTA_LOW_OSHT: {
|
||
PWM_CH_REG_FIELD_SET(ch, CFG_AQSFRC_ADDR, ACTSFA, 1);
|
||
PWM_CH_REG_FIELD_SET(ch, CFG_AQSFRC_ADDR, OTSFA, 1);
|
||
break;
|
||
}
|
||
case IOT_EPWM_CH_SW_EVENT_OUTA_HIGH_OSHT: {
|
||
PWM_CH_REG_FIELD_SET(ch, CFG_AQSFRC_ADDR, ACTSFA, 2);
|
||
PWM_CH_REG_FIELD_SET(ch, CFG_AQSFRC_ADDR, OTSFA, 1);
|
||
break;
|
||
}
|
||
case IOT_EPWM_CH_SW_EVENT_OUTA_TOGG_OSHT: {
|
||
PWM_CH_REG_FIELD_SET(ch, CFG_AQSFRC_ADDR, ACTSFA, 3);
|
||
PWM_CH_REG_FIELD_SET(ch, CFG_AQSFRC_ADDR, OTSFA, 1);
|
||
break;
|
||
}
|
||
case IOT_EPWM_CH_SW_EVENT_OUTB_LOW_OSHT: {
|
||
PWM_CH_REG_FIELD_SET(ch, CFG_AQSFRC_ADDR, ACTSFB, 1);
|
||
PWM_CH_REG_FIELD_SET(ch, CFG_AQSFRC_ADDR, OTSFB, 1);
|
||
break;
|
||
}
|
||
case IOT_EPWM_CH_SW_EVENT_OUTB_HIGH_OSHT: {
|
||
PWM_CH_REG_FIELD_SET(ch, CFG_AQSFRC_ADDR, ACTSFB, 2);
|
||
PWM_CH_REG_FIELD_SET(ch, CFG_AQSFRC_ADDR, OTSFB, 1);
|
||
break;
|
||
}
|
||
case IOT_EPWM_CH_SW_EVENT_OUTB_TOGG_OSHT: {
|
||
PWM_CH_REG_FIELD_SET(ch, CFG_AQSFRC_ADDR, ACTSFB, 3);
|
||
PWM_CH_REG_FIELD_SET(ch, CFG_AQSFRC_ADDR, OTSFB, 1);
|
||
break;
|
||
}
|
||
case IOT_EPWM_CH_SW_EVENT_OUTA_LOW_CTNU: {
|
||
PWM_CH_REG_FIELD_SET(ch, CFG_AQCSFRC_ADDR, CSFA, 1);
|
||
break;
|
||
}
|
||
case IOT_EPWM_CH_SW_EVENT_OUTA_HIGH_CTNU: {
|
||
PWM_CH_REG_FIELD_SET(ch, CFG_AQCSFRC_ADDR, CSFA, 2);
|
||
break;
|
||
}
|
||
case IOT_EPWM_CH_SW_EVENT_OUTA_RESUME: {
|
||
PWM_CH_REG_FIELD_SET(ch, CFG_AQCSFRC_ADDR, CSFA, 0);
|
||
break;
|
||
}
|
||
case IOT_EPWM_CH_SW_EVENT_OUTB_LOW_CTNU: {
|
||
PWM_CH_REG_FIELD_SET(ch, CFG_AQCSFRC_ADDR, CSFB, 1);
|
||
break;
|
||
}
|
||
case IOT_EPWM_CH_SW_EVENT_OUTB_HIGH_CTNU: {
|
||
PWM_CH_REG_FIELD_SET(ch, CFG_AQCSFRC_ADDR, CSFB, 2);
|
||
break;
|
||
}
|
||
case IOT_EPWM_CH_SW_EVENT_OUTB_RESUME: {
|
||
PWM_CH_REG_FIELD_SET(ch, CFG_AQCSFRC_ADDR, CSFB, 0);
|
||
break;
|
||
}
|
||
default: {
|
||
return;
|
||
}
|
||
}
|
||
}
|
||
|
||
void epwm_ch_clear(uint8_t ch, iot_epwm_ch_event_e event)
|
||
{
|
||
if (PWM_CHANNEL_INVALID(ch)) {
|
||
return;
|
||
}
|
||
|
||
switch (event) {
|
||
case IOT_EPWM_CH_SW_EVENT_INNER_INT: {
|
||
PWM_CH_REG_FIELD_SET(ch, CFG_PWMINT_CLR_ADDR, INNER_INT_CLR, 1);
|
||
break;
|
||
}
|
||
case IOT_EPWM_CH_SW_EVENT_SOCA: {
|
||
PWM_CH_REG_FIELD_SET(ch, CFG_PWMINT_CLR_ADDR, SOCA_INT_CLR, 1);
|
||
break;
|
||
}
|
||
case IOT_EPWM_CH_SW_EVENT_SOCB: {
|
||
PWM_CH_REG_FIELD_SET(ch, CFG_PWMINT_CLR_ADDR, SOCB_INT_CLR, 1);
|
||
break;
|
||
}
|
||
case IOT_EPWM_CH_SW_EVENT_TZ_CBC: {
|
||
PWM_CH_REG_FIELD_SET(ch, CFG_PWMINT_CLR_ADDR, CBC_INT_CLR, 1);
|
||
break;
|
||
}
|
||
case IOT_EPWM_CH_SW_EVENT_TZ_OSHT: {
|
||
PWM_CH_REG_FIELD_SET(ch, CFG_PWMINT_CLR_ADDR, OSHT_INT_CLR, 1);
|
||
break;
|
||
}
|
||
default: {
|
||
return;
|
||
}
|
||
}
|
||
}
|
||
|
||
void epwm_ch_status_get(uint8_t ch, iot_epwm_ch_status_t *status)
|
||
{
|
||
if (PWM_CHANNEL_INVALID(ch) || NULL == status) {
|
||
return;
|
||
}
|
||
|
||
/* ch_clk */
|
||
status->actual_ch_clk = epwm_get_channel_clock(ch);
|
||
/* freq = ch_clk/prd */
|
||
uint32_t prd = epwm_get_channel_period(ch);
|
||
status->actual_freq = status->actual_ch_clk / prd;
|
||
/* duty = cmp/prd */
|
||
uint32_t cmp = PWM_NEW_READ(ch, CFG_CMPA_ADDR);
|
||
cmp = (cmp & CMPA_MASK) >> CMPA_OFFSET;
|
||
status->actual_duty = (uint32_t)(((uint64_t)cmp * 10000) / prd);
|
||
/* period value */
|
||
status->actual_period = prd;
|
||
/* compare value */
|
||
status->actual_compare = cmp;
|
||
/* counter value */
|
||
uint32_t cnt = PWM_NEW_READ(ch, CFG_TBSTS_ADDR);
|
||
status->actual_counter = (cnt & CNT_VAL_LAT_MASK) >> CNT_VAL_LAT_OFFSET;
|
||
}
|