Files
kunlun/driver/src/hw3/pwm.c
2024-09-28 14:24:04 +08:00

2103 lines
55 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/****************************************************************************
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==0cnt==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;
}