/** * @file sdrv_etimer.c * @brief Semidrive ETIMER driver source file. * * @copyright Copyright (c) 2022 Semidrive Semiconductor. * All rights reserved. */ #include #include #include "sdrv_etimer.h" #include "clock_ip.h" #include "bits.h" #include "debug.h" #include "irq.h" #include "regs_base.h" #define EXTRA_FMT "sdrv_etimer:" #define SDRV_ETIMER_ERR(format, ...) \ ssdk_printf(SSDK_ERR, EXTRA_FMT format, ##__VA_ARGS__) #define SDRV_ETIMER_WARN(format, ...) \ ssdk_printf(SSDK_WARNING, EXTRA_FMT format, ##__VA_ARGS__) #define SDRV_ETIMER_INFO(format, ...) \ ssdk_printf(SSDK_INFO, EXTRA_FMT format, ##__VA_ARGS__) /** * @brief sdrv etimer ns transfer to val. * * @param[in] clk src clk * @param[in] ns time val * @param[in] div src clk divider * @return ns_to_val */ static inline uint32_t sdrv_etimer_ns_to_val(uint32_t clk, uint32_t ns, uint32_t div) { uint32_t clk_cnt_per_ms = (clk / (div + 1)) / 1000; uint32_t ns_to_val = (uint32_t)((uint64_t)ns * clk_cnt_per_ms / 1000000); return ns_to_val; } /** * @brief sdrv etimer ns transfer to val . * * @param[in] clk src clk * @param[in] ns time val * @param[in] div src clk divider * @return ns_to_val */ static inline uint32_t sdrv_etimer_ns_to_val_1(uint32_t clk, uint32_t ns, uint32_t div) { uint32_t clk_cnt_per_ms = (clk / (div + 1)) / 1000; uint32_t ns_to_val = (uint32_t)((uint64_t)ns * clk_cnt_per_ms / 1000000); uint32_t ns_to_val_1 = ns_to_val - 1; return ns_to_val_1; } /** * @brief sdrv etimer val transfer to ns. * * @param[in] clk src clk * @param[in] ns time val * @param[in] div src clk divider * @return val_to_ns */ static inline uint32_t sdrv_etimer_val_to_ns(uint32_t clk, uint32_t val, uint32_t div) { uint32_t clk_cnt_per_ms = (clk / (div + 1)) / 1000; uint32_t val_to_ns = (uint32_t)((uint64_t)val * 1000000 / clk_cnt_per_ms); return val_to_ns; } /** * @brief sdrv etimer irq handle function * * @param[in] irq irq id * @param[in] arg irq arg */ static int sdrv_etimer_irq_handle(uint32_t irq, void *arg) { /* capture channel ctrl */ sdrv_etimer_controller_t *pst_etimer_controller = arg; sdrv_etimer_t *sdrv_etimer_cpt_chn_a = pst_etimer_controller->etimer_bank[SDRV_ETIMR_CHN_A]; sdrv_etimer_t *sdrv_etimer_cpt_chn_b = pst_etimer_controller->etimer_bank[SDRV_ETIMR_CHN_B]; sdrv_etimer_t *sdrv_etimer_cpt_chn_c = pst_etimer_controller->etimer_bank[SDRV_ETIMR_CHN_C]; sdrv_etimer_t *sdrv_etimer_cpt_chn_d = pst_etimer_controller->etimer_bank[SDRV_ETIMR_CHN_D]; /* compare channel ctrl */ sdrv_etimer_t *sdrv_etimer_cmp_chn_a = pst_etimer_controller->etimer_bank[SDRV_ETIMR_CHN_A + 4]; sdrv_etimer_t *sdrv_etimer_cmp_chn_b = pst_etimer_controller->etimer_bank[SDRV_ETIMR_CHN_B + 4]; sdrv_etimer_t *sdrv_etimer_cmp_chn_c = pst_etimer_controller->etimer_bank[SDRV_ETIMR_CHN_C + 4]; sdrv_etimer_t *sdrv_etimer_cmp_chn_d = pst_etimer_controller->etimer_bank[SDRV_ETIMR_CHN_D + 4]; volatile uint32_t int_sta = 0; int_sta = sdrv_etimer_lld_get_int_status(pst_etimer_controller->base); uint32_t clr_int_sta = 0; if (int_sta & ETMR_BM_INT_STA_CPT(SDRV_ETIMR_CHN_A)) { clr_int_sta = int_sta & ETMR_BM_INT_STA_CPT(SDRV_ETIMR_CHN_A); sdrv_etimer_lld_clear_int_status(pst_etimer_controller->base, clr_int_sta); if (sdrv_etimer_cpt_chn_a->mode == ETIMER_PWM_CAPTURE) { sdrv_etimer_cpt_chn_a->cpt_read_flag = false; } if ((sdrv_etimer_cpt_chn_a != NULL) && (sdrv_etimer_cpt_chn_a->callback)) { sdrv_etimer_cpt_chn_a->callback(sdrv_etimer_cpt_chn_a->arg); } } if (int_sta & ETMR_BM_INT_STA_CMP(SDRV_ETIMR_CHN_A)) { clr_int_sta = int_sta & ETMR_BM_INT_STA_CMP(SDRV_ETIMR_CHN_A); sdrv_etimer_lld_clear_int_status(pst_etimer_controller->base, clr_int_sta); if ((sdrv_etimer_cmp_chn_a != NULL) && (sdrv_etimer_cmp_chn_a->callback)) { sdrv_etimer_cmp_chn_a->callback(sdrv_etimer_cmp_chn_a->arg); } } if (int_sta & ETMR_BM_INT_STA_CPT(SDRV_ETIMR_CHN_B)) { clr_int_sta = int_sta & ETMR_BM_INT_STA_CPT(SDRV_ETIMR_CHN_B); sdrv_etimer_lld_clear_int_status(pst_etimer_controller->base, clr_int_sta); if (sdrv_etimer_cpt_chn_b->mode == ETIMER_PWM_CAPTURE) { sdrv_etimer_cpt_chn_b->cpt_read_flag = false; } if ((sdrv_etimer_cpt_chn_b != NULL) && (sdrv_etimer_cpt_chn_b->callback)) { sdrv_etimer_cpt_chn_b->callback(sdrv_etimer_cpt_chn_b->arg); } } if (int_sta & ETMR_BM_INT_STA_CMP(SDRV_ETIMR_CHN_B)) { clr_int_sta = int_sta & ETMR_BM_INT_STA_CMP(SDRV_ETIMR_CHN_B); sdrv_etimer_lld_clear_int_status(pst_etimer_controller->base, clr_int_sta); if ((sdrv_etimer_cmp_chn_b != NULL) && (sdrv_etimer_cmp_chn_b->callback)) { sdrv_etimer_cmp_chn_b->callback(sdrv_etimer_cmp_chn_b->arg); } } if (int_sta & ETMR_BM_INT_STA_CPT(SDRV_ETIMR_CHN_C)) { clr_int_sta = int_sta & ETMR_BM_INT_STA_CPT(SDRV_ETIMR_CHN_C); sdrv_etimer_lld_clear_int_status(pst_etimer_controller->base, clr_int_sta); if (sdrv_etimer_cpt_chn_c->mode == ETIMER_PWM_CAPTURE) { sdrv_etimer_cpt_chn_c->cpt_read_flag = false; } if ((sdrv_etimer_cpt_chn_c != NULL) && (sdrv_etimer_cpt_chn_c->callback)) { sdrv_etimer_cpt_chn_c->callback(sdrv_etimer_cpt_chn_c->arg); } } if (int_sta & ETMR_BM_INT_STA_CMP(SDRV_ETIMR_CHN_C)) { clr_int_sta = int_sta & ETMR_BM_INT_STA_CMP(SDRV_ETIMR_CHN_C); sdrv_etimer_lld_clear_int_status(pst_etimer_controller->base, clr_int_sta); if ((sdrv_etimer_cmp_chn_c != NULL) && (sdrv_etimer_cmp_chn_c->callback)) { sdrv_etimer_cmp_chn_c->callback(sdrv_etimer_cmp_chn_c->arg); } } if (int_sta & ETMR_BM_INT_STA_CPT(SDRV_ETIMR_CHN_D)) { clr_int_sta = int_sta & ETMR_BM_INT_STA_CPT(SDRV_ETIMR_CHN_D); sdrv_etimer_lld_clear_int_status(pst_etimer_controller->base, clr_int_sta); if (sdrv_etimer_cpt_chn_d->mode == ETIMER_PWM_CAPTURE) { sdrv_etimer_cpt_chn_d->cpt_read_flag = false; } if ((sdrv_etimer_cpt_chn_d != NULL) && (sdrv_etimer_cpt_chn_d->callback)) { sdrv_etimer_cpt_chn_d->callback(sdrv_etimer_cpt_chn_d->arg); } } if (int_sta & ETMR_BM_INT_STA_CMP(SDRV_ETIMR_CHN_D)) { clr_int_sta = int_sta & ETMR_BM_INT_STA_CMP(SDRV_ETIMR_CHN_D); sdrv_etimer_lld_clear_int_status(pst_etimer_controller->base, clr_int_sta); if ((sdrv_etimer_cmp_chn_d != NULL) && (sdrv_etimer_cmp_chn_d->callback)) { sdrv_etimer_cmp_chn_d->callback(sdrv_etimer_cmp_chn_d->arg); } } return 0; } /** * @brief sdrv etimer timer ovf irq handle function * * @param[in] irq irq id * @param[in] arg irq arg */ static int sdrv_etimer_timer_ovf_irq_handle(uint32_t irq, void *arg) { sdrv_etimer_controller_t *pst_etimer_tmr = arg; sdrv_etimer_t *sdrv_etimer_cnt_g0 = pst_etimer_tmr->cnt_bank[ETIMR_BASIC_TMR_G0]; sdrv_etimer_t *sdrv_etimer_cnt_g1 = pst_etimer_tmr->cnt_bank[ETIMR_BASIC_TMR_G1]; volatile uint32_t int_sta = 0; int_sta = sdrv_etimer_lld_get_int_status(pst_etimer_tmr->base); uint32_t clr_int_sta = 0; if (int_sta & ETMR_BM_INT_STA_CNT_OVF(ETIMR_BASIC_TMR_G0)) { clr_int_sta = int_sta & ETMR_BM_INT_STA_CNT_OVF(ETIMR_BASIC_TMR_G0); sdrv_etimer_lld_clear_int_status(pst_etimer_tmr->base, clr_int_sta); if ((sdrv_etimer_cnt_g0 != NULL) && (sdrv_etimer_cnt_g0->callback)) { sdrv_etimer_cnt_g0->callback(sdrv_etimer_cnt_g0->arg); } } if (int_sta & ETMR_BM_INT_STA_CNT_OVF(ETIMR_BASIC_TMR_G1)) { clr_int_sta = int_sta & ETMR_BM_INT_STA_CNT_OVF(ETIMR_BASIC_TMR_G1); sdrv_etimer_lld_clear_int_status(pst_etimer_tmr->base, clr_int_sta); if ((sdrv_etimer_cnt_g1 != NULL) && (sdrv_etimer_cnt_g1->callback)) { sdrv_etimer_cnt_g1->callback(sdrv_etimer_cnt_g1->arg); } } return 0; } /** * @brief check etimer clk set status and int set * * @param[in] etmr: etimer ctrl instance * @param[in] etimer_module etimer module id */ static bool sdrv_etimer_clk_int_set(sdrv_etimer_t *etmr) { sdrv_etimer_controller_t *ctrl = etmr->controller; ASSERT(ctrl != NULL); /* check etimer clk set */ if (ctrl->clk_set_flag == false) { clk_set_t clk_config; if (etmr->use_multicpt) { clk_config.src_clk_sel = SDRV_ETIMR_AHF_CLK; } else { clk_config.src_clk_sel = etmr->clk_src; } clk_config.div_num = etmr->clk_div; sdrv_etimer_lld_clk_mon_en(etmr->base, false); sdrv_etimer_lld_clk_cfg(etmr->base, &clk_config); sdrv_etimer_lld_clk_mon_en(etmr->base, true); ctrl->clk_set_flag = true; ctrl->etimer_clk_src = etmr->clk_src; ctrl->etimer_clk_div = etmr->clk_div; } else { /* The timer function needs to set the clock source consistent with the * configured clock source */ if ((etmr->mode == ETIMER_TIMER_FUNC) && (etmr->clk_src != ctrl->etimer_clk_src)) { return false; } } if ((ctrl->int_init_flag == false) && (etmr->use_multicpt == false)) { /* clear all int status */ sdrv_etimer_lld_int_enable(etmr->base, 0x0); sdrv_etimer_lld_clear_int_status(etmr->base, 0xFFFFFFFF); ctrl->int_init_flag = true; } if (etmr->mode == ETIMER_PWM_CAPTURE) { /* pwm capture function always enable irq */ sdrv_etimer_lld_int_en(etmr->base, ETMR_BM_INT_STA_EN_CPT(etmr->channel), true); } /* check etimer int set */ if (etmr->int_en == true) { if (etmr->mode == ETIMER_PWM_GENERATE) { sdrv_etimer_lld_int_en(etmr->base, ETMR_BM_INT_STA_EN_CMP(etmr->channel), true); } else if (etmr->mode == ETIMER_TIMER_FUNC) { sdrv_etimer_lld_int_en(etmr->base, ETMR_BM_INT_STA_EN_CNT_OVF(etmr->config.cnt_cfg->tmr_id), true); } else if (etmr->mode == ETIMER_ICU_FUNC) { sdrv_etimer_lld_int_en(etmr->base, ETMR_BM_INT_STA_EN_CPT(etmr->channel), true); } } return true; } /** * @brief etimer setup callback funciton * * @param[in] etmr: etimer ctrl instance * @param[in] callback: user callback function * @return succeed:0 fail:other */ uint8_t sdrv_etimer_set_callback(sdrv_etimer_t *etmr, etimer_callback callback, void *arg) { ASSERT(etmr != NULL); etmr->callback = callback; etmr->arg = arg; return 0; } /* etimer timer function */ /** * @brief etimer timer init * * @param[in] etmr: etimer ctrl instance * @param[in] cnt_cfg: timer counter config */ status_t sdrv_etimer_timer_init(sdrv_etimer_t *etmr, sdrv_etimer_basic_cnt_cfg_t *cnt_cfg) { ASSERT(etmr != NULL); sdrv_etimer_controller_t *ctrl = etmr->controller; ASSERT(ctrl != NULL); sdrv_etimer_basic_cnt_id_t cnt_sel = cnt_cfg->tmr_id; /* chcek the timer status */ if ((etmr->mode != ETIMER_TIMER_FUNC) || (etmr->crtl_sta != ETIMER_CHAN_UNINIT) || (ctrl->g0_mode != G0_IDLE)) { return SDRV_STATUS_INVALID_PARAM; } etmr->clk_src = cnt_cfg->clk_sel; etmr->clk_div = cnt_cfg->clk_div; etmr->config.cnt_cfg = cnt_cfg; bool ret = sdrv_etimer_clk_int_set(etmr); if (ret == false) { /* The timer function needs to set the clock source consistent with the * configured clock source */ return SDRV_STATUS_FAIL; } etmr->config.cnt_per_ms = (cnt_cfg->clk_frq / (cnt_cfg->clk_div + 1)) / 1000; basic_cnt_config_t basic_cnt_config; memset(&basic_cnt_config, 0, sizeof(basic_cnt_config)); /* set cnt consective mode */ basic_cnt_config.ce_en = true; basic_cnt_config.con_mode = cnt_cfg->con_mode; sdrv_etimer_lld_basic_cnt_cfg(etmr->base, (sdrv_etimer_cnt_id_e)cnt_sel, &basic_cnt_config); if (cnt_sel == ETIMR_BASIC_TMR_G0) { ctrl->g0_mode = G0_FOR_TIMER; } ctrl->base = etmr->base; ctrl->cnt_bank[cnt_sel] = etmr; etmr->crtl_sta = ETIMER_CHAN_INIT; /* register the irq */ if (etmr->irq > 0) { irq_attach(etmr->irq, sdrv_etimer_timer_ovf_irq_handle, ctrl); irq_enable(etmr->irq); } return SDRV_STATUS_OK; } /** * @brief etimer timer start (us) * * @param[in] etmr: etimer ctrl instance * @param[in] time_out: timer timeout value */ status_t sdrv_etimer_timer_start(sdrv_etimer_t *etmr, uint32_t time_out) { ASSERT(etmr != NULL); sdrv_etimer_basic_cnt_id_t cnt_sel = etmr->config.cnt_cfg->tmr_id; /* chcek the timer status */ if ((etmr->mode != ETIMER_TIMER_FUNC) || (etmr->crtl_sta == ETIMER_CHAN_UNINIT) || time_out == 0) { return SDRV_STATUS_INVALID_PARAM; } /* reset the counter to 0 */ sdrv_etimer_lld_cnt_frc_rld(etmr->base, (sdrv_etimer_cnt_id_e)cnt_sel); etmr->config.time_out = time_out; /* set the counter ovf value */ uint32_t ovf_val = (uint32_t)(((uint64_t)time_out * etmr->config.cnt_per_ms) / 1000); sdrv_etimer_lld_cnt_ovf(etmr->base, (sdrv_etimer_cnt_id_e)cnt_sel, ovf_val); /* enable the counter */ sdrv_etimer_lld_cnt_en(etmr->base, (sdrv_etimer_cnt_id_e)cnt_sel, true); etmr->crtl_sta = ETIMER_CHAN_RUNNING; return SDRV_STATUS_OK; } /** * @brief etimer timer stop * * @param[in] etmr: etimer ctrl instance */ status_t sdrv_etimer_timer_stop(sdrv_etimer_t *etmr) { ASSERT(etmr != NULL); sdrv_etimer_basic_cnt_id_t cnt_sel = etmr->config.cnt_cfg->tmr_id; /* chcek the timer status */ if ((etmr->mode != ETIMER_TIMER_FUNC) || (etmr->crtl_sta == ETIMER_CHAN_UNINIT)) { return SDRV_STATUS_INVALID_PARAM; } /* disable the counter */ sdrv_etimer_lld_cnt_en(etmr->base, (sdrv_etimer_cnt_id_e)cnt_sel, false); etmr->crtl_sta = ETIMER_CHAN_STOP; return SDRV_STATUS_OK; } /** * @brief etimer timer get current time val (us) * * @param[in] etmr: etimer ctrl instance * @return current time val */ uint32_t sdrv_etimer_timer_get_current_time(sdrv_etimer_t *etmr) { ASSERT(etmr != NULL); sdrv_etimer_basic_cnt_id_t cnt_sel = etmr->config.cnt_cfg->tmr_id; /* chcek the timer status */ if ((etmr->mode != ETIMER_TIMER_FUNC) || (etmr->crtl_sta != ETIMER_CHAN_RUNNING)) { return 0; } uint32_t cnt_val = sdrv_etimer_lld_get_cnt_value(etmr->base, (sdrv_etimer_cnt_id_e)cnt_sel); uint32_t ret = 0; if (etmr->config.cnt_per_ms == 0) { ret = 0; } else { ret = (uint32_t)((uint64_t)cnt_val * 1000 / (etmr->config.cnt_per_ms)); } return ret; } /* capture function */ /** * @brief init etimer capture chan. * * @param[in] etmr etimer ctrl instance */ status_t sdrv_etimer_capture_init(sdrv_etimer_t *etmr) { ASSERT(etmr != NULL); sdrv_etimer_controller_t *ctrl = etmr->controller; ASSERT(ctrl != NULL); sdrv_etimer_chn_id_e cpt_chn = etmr->channel; if ((etmr->mode != ETIMER_PWM_CAPTURE) || (etmr->crtl_sta != ETIMER_CHAN_UNINIT)) { return SDRV_STATUS_INVALID_PARAM; } sdrv_etimer_clk_int_set(etmr); cpt_config_t cpt_config; local_cnt_config_t local_cnt_config; memset(&cpt_config, 0, sizeof(cpt_config)); memset(&local_cnt_config, 0, sizeof(local_cnt_config)); /* capture cnt config */ sdrv_etimer_cnt_id_e cpt_cnt_sel = (sdrv_etimer_cnt_id_e)(cpt_chn + 2); local_cnt_config.cpt1_clr_en = true; local_cnt_config.start_by_first_cpt = true; sdrv_etimer_lld_local_cnt_cfg(etmr->base, cpt_cnt_sel, &local_cnt_config); /* cpt_config */ cpt_config.cnt_sel = SDRV_ETIMR_CPT_LCNT; cpt_config.con_mode = SDRV_ETIMR_CPT_CONSECTIVE; cpt_config.dual_mode = SDRV_ETIMR_CPT_CPT0_CPT1; cpt_config.cpt1_trig_mode = SDRV_ETIMR_CPT_RISE_EDGE; cpt_config.cpt0_trig_mode = SDRV_ETIMR_CPT_FALL_EDGE; sdrv_etimer_lld_cpt_cfg(etmr->base, cpt_chn, &cpt_config); sdrv_etimer_lld_cpt_config_set(etmr->base, cpt_chn); ctrl->base = etmr->base; ctrl->etimer_bank[cpt_chn] = etmr; etmr->crtl_sta = ETIMER_CHAN_INIT; etmr->cpt_read_flag = true; if (etmr->irq > 0) { irq_attach(etmr->irq, sdrv_etimer_irq_handle, ctrl); irq_enable(etmr->irq); } return SDRV_STATUS_OK; } /** * @brief start etimer capture chan. * * @param[in] etmr etimer ctrl instance */ status_t sdrv_etimer_capture_start(sdrv_etimer_t *etmr) { ASSERT(etmr != NULL); sdrv_etimer_chn_id_e cpt_chn = etmr->channel; if ((etmr->mode != ETIMER_PWM_CAPTURE) || (etmr->crtl_sta == ETIMER_CHAN_UNINIT)) { return SDRV_STATUS_INVALID_PARAM; } sdrv_etimer_cnt_id_e cpt_cnt_sel = (sdrv_etimer_cnt_id_e)(cpt_chn + 2); /* reset the counter to 0 */ sdrv_etimer_lld_cnt_frc_rld(etmr->base, cpt_cnt_sel); sdrv_etimer_lld_cpt_en(etmr->base, cpt_chn, true); sdrv_etimer_lld_cnt_en(etmr->base, cpt_cnt_sel, true); etmr->crtl_sta = ETIMER_CHAN_RUNNING; return SDRV_STATUS_OK; } /** * @brief stop etimer capture chan. * * @param[in] etmr etimer ctrl instance */ status_t sdrv_etimer_capture_stop(sdrv_etimer_t *etmr) { ASSERT(etmr != NULL); sdrv_etimer_chn_id_e cpt_chn = etmr->channel; if ((etmr->mode != ETIMER_PWM_CAPTURE) || (etmr->crtl_sta == ETIMER_CHAN_UNINIT)) { return SDRV_STATUS_INVALID_PARAM; } sdrv_etimer_cnt_id_e cpt_cnt_sel = (sdrv_etimer_cnt_id_e)(cpt_chn + 2); sdrv_etimer_lld_cpt_en(etmr->base, cpt_chn, false); sdrv_etimer_lld_cnt_en(etmr->base, cpt_cnt_sel, false); etmr->crtl_sta = ETIMER_CHAN_STOP; return SDRV_STATUS_OK; } /** * @brief etimer capture pwm signal. * * @param[in] etmr etimer ctrl instance * @param[in] state pwm duty and period */ status_t sdrv_etimer_capture_pwm(sdrv_etimer_t *etmr, sdrv_etimer_pwm_state_t *state) { ASSERT(etmr != NULL); ASSERT(state != NULL); sdrv_etimer_controller_t *ctrl = etmr->controller; ASSERT(ctrl != NULL); sdrv_etimer_chn_id_e cpt_chn = etmr->channel; if ((etmr->mode != ETIMER_PWM_CAPTURE) || (etmr->crtl_sta != ETIMER_CHAN_RUNNING)) { return SDRV_STATUS_INVALID_PARAM; } uint32_t duty_val = 0; uint32_t period_val = 0; uint32_t clk_freq = 0; /* all etimer use same src clk */ if (ctrl->etimer_clk_src == SDRV_ETIMR_AHF_CLK) { clk_freq = sdrv_ckgen_get_rate(CLK_NODE(g_ckgen_ip_xtrg)); } else if (ctrl->etimer_clk_src == SDRV_ETIMR_LP_CLK) { /* LP_CLK : 24M */ clk_freq = 24000000; } else { clk_freq = sdrv_ckgen_get_rate(CLK_NODE(g_ckgen_ip_etmr1)); } if (etmr->cpt_read_flag == false) { uint32_t duty_cnt = sdrv_etimer_lld_get_cpt0_cnt0(etmr->base, cpt_chn); uint32_t period_cnt = sdrv_etimer_lld_get_cpt1_cnt0(etmr->base, cpt_chn); duty_val = sdrv_etimer_val_to_ns(clk_freq, duty_cnt, ctrl->etimer_clk_div); period_val = sdrv_etimer_val_to_ns(clk_freq, period_cnt, ctrl->etimer_clk_div); etmr->cpt_read_flag = true; } state->duty1 = duty_val; state->period = period_val; return SDRV_STATUS_OK; } /** * @brief etimer pwm set initial putput status. * * @param[in] etmr etimer ctrl instance * @param[in] cmp0_init etimer cmp0 initial out status * @param[in] cmp1_init etimer cmp1 initial out status */ status_t sdrv_etimer_compare_pwm_initial_out_status(sdrv_etimer_t *etmr, bool cmp0_init, bool cmp1_init) { ASSERT(etmr != NULL); sdrv_etimer_chn_id_e cmp_chn = etmr->channel; if (etmr->mode != ETIMER_PWM_GENERATE) { return SDRV_STATUS_INVALID_PARAM; } etimer_cmp_init_status_t cmp_init_sta; memset(&cmp_init_sta, 0, sizeof(cmp_init_sta)); cmp_init_sta.init_status_x0 = cmp0_init; cmp_init_sta.init_status_x1 = cmp1_init; sdrv_etimer_lld_cmp_init_status(etmr->base, cmp_chn, &cmp_init_sta); return SDRV_STATUS_OK; } /** * @brief etimer pwm state config. * * @param[in] etmr etimer ctrl instance * @param[in] cmp_cfg etimer cmp common config * @param[in] state pwm duty and period */ status_t sdrv_etimer_compare_pwm_config(sdrv_etimer_t *etmr, sdrv_etimer_cmp_cfg_t *cmp_cfg, const sdrv_etimer_pwm_state_t *state) { ASSERT(etmr != NULL); ASSERT(cmp_cfg != NULL); ASSERT(state != NULL); sdrv_etimer_controller_t *ctrl = etmr->controller; ASSERT(ctrl != NULL); sdrv_etimer_chn_id_e cmp_chn = etmr->channel; /* check pwm signal value */ if ((state->duty1) > (state->period) || (state->duty2) > (state->period)) { return SDRV_STATUS_INVALID_PARAM; } if ((etmr->mode != ETIMER_PWM_GENERATE) || (etmr->crtl_sta != ETIMER_CHAN_UNINIT)) { return SDRV_STATUS_INVALID_PARAM; } if (etmr->use_g0_cnt == true) { if (ctrl->g0_mode == G0_FOR_TIMER) { /* g0 is used for timer */ return SDRV_STATUS_INVALID_PARAM; } else if (ctrl->g0_mode == G0_FOR_PWM_GEN) { if (state->period != ctrl->g0_period) { /* g0 is used but the period is different */ return SDRV_STATUS_INVALID_PARAM; } } } sdrv_etimer_clk_int_set(etmr); cmp_config_t cmp_config; etimer_cmp_event_mode_t cmp_event_mode; memset(&cmp_config, 0, sizeof(cmp_config)); sdrv_etimer_cnt_id_e cmp_cnt_sel; if (etmr->use_g0_cnt == true) { cmp_config.cnt_sel = SDRV_ETIMR_CMP_CNT_G0; cmp_cnt_sel = SDRV_ETIMR_CNT_G0; } else { cmp_config.cnt_sel = SDRV_ETIMR_CMP_LCNT; cmp_cnt_sel = (sdrv_etimer_cnt_id_e)(cmp_chn + 2); } uint32_t clk_freq = 0; /* all etimer use same src clk */ if (ctrl->etimer_clk_src == SDRV_ETIMR_AHF_CLK) { clk_freq = sdrv_ckgen_get_rate(CLK_NODE(g_ckgen_ip_xtrg)); } else if (ctrl->etimer_clk_src == SDRV_ETIMR_LP_CLK) { /* LP_CLK : 24M */ clk_freq = 24000000; } else { clk_freq = sdrv_ckgen_get_rate(CLK_NODE(g_ckgen_ip_etmr1)); } uint32_t period_cnt = 0; uint32_t duty_cnt1 = 0; uint32_t duty_cnt2 = 0; uint32_t dual_period_cnt_left1 = 0; uint32_t dual_period_cnt_right1 = 0; uint32_t dual_period_cnt_left2 = 0; uint32_t dual_period_cnt_right2 = 0; #if CONFIG_E3L if (etmr->center_align_mode == true) { period_cnt = sdrv_etimer_ns_to_val_1(clk_freq, state->period, ctrl->etimer_clk_div) / 2 - 1; } else { #endif period_cnt = sdrv_etimer_ns_to_val_1(clk_freq, state->period, ctrl->etimer_clk_div); #if CONFIG_E3L } #endif #if CONFIG_E3L if (etmr->center_align_mode == true || etmr->fre_double_flag == true) { /* in double fre mode, dual_period_cnt_right1 set a useless value */ duty_cnt1 = sdrv_etimer_ns_to_val(clk_freq, (state->duty1) / 2, ctrl->etimer_clk_div); dual_period_cnt_left1 = period_cnt + 1 - duty_cnt1; dual_period_cnt_right1 = period_cnt - 1; } else { #endif duty_cnt1 = sdrv_etimer_ns_to_val(clk_freq, state->duty1, ctrl->etimer_clk_div); dual_period_cnt_left1 = (period_cnt + 1) / 2 - duty_cnt1 / 2; dual_period_cnt_right1 = (period_cnt + 1) / 2 + duty_cnt1 / 2; #if CONFIG_E3L } #endif duty_cnt2 = sdrv_etimer_ns_to_val(clk_freq, state->duty2, ctrl->etimer_clk_div); dual_period_cnt_left2 = (period_cnt + 1) / 2 - duty_cnt2 / 2; dual_period_cnt_right2 = (period_cnt + 1) / 2 + duty_cnt2 / 2; cmp_config.out_mode = cmp_cfg->chnl_out_mode; cmp_config.con_mode = cmp_cfg->con_mode; cmp_config.cmp_mode = cmp_cfg->cmp_mode; /* cmp cnt cfg */ sdrv_etimer_lld_cnt_ovf(etmr->base, cmp_cnt_sel, period_cnt); /* pwm cfg -- cmp config */ cmp_event_mode.cmp_0_ovf_out = SDRV_ETIMR_KEEP; cmp_event_mode.cmp_1_ovf_out = SDRV_ETIMR_KEEP; #if CONFIG_E3L /* if use center_align_mode , cmp_mode use dual mode only */ if (etmr->center_align_mode == true) { /* in center_align_mode situation, initial status need to set to low * level */ etimer_cmp_init_status_t cmp_init_sta; memset(&cmp_init_sta, 0, sizeof(cmp_init_sta)); cmp_init_sta.init_status_x0 = false; cmp_init_sta.init_status_x1 = false; sdrv_etimer_lld_cmp_init_status(etmr->base, cmp_chn, &cmp_init_sta); sdrv_etimer_lld_cmp_val(etmr->base, cmp_chn, SDRV_ETIMR_CMP_00, dual_period_cnt_left1); sdrv_etimer_lld_cmp_val(etmr->base, cmp_chn, SDRV_ETIMR_CMP_01, dual_period_cnt_right1); if (etmr->fre_double_flag == true) { cmp_event_mode.cmp_00_out = SDRV_ETIMR_LEVEL_HIGH; cmp_event_mode.cmp_01_out = SDRV_ETIMR_KEEP; } else { cmp_event_mode.cmp_00_out = SDRV_ETIMR_LEVEL_HIGH; cmp_event_mode.cmp_01_out = SDRV_ETIMR_LEVEL_LOW; } if (state->duty1 == 0) { sdrv_etimer_lld_cmp_val(etmr->base, cmp_chn, SDRV_ETIMR_CMP_00, (period_cnt + 1) / 2); sdrv_etimer_lld_cmp_val(etmr->base, cmp_chn, SDRV_ETIMR_CMP_01, (period_cnt + 1) / 2); cmp_event_mode.cmp_00_out = SDRV_ETIMR_LEVEL_HIGH; cmp_event_mode.cmp_01_out = SDRV_ETIMR_LEVEL_LOW; } else if (state->duty1 == state->period) { sdrv_etimer_lld_cmp_val(etmr->base, cmp_chn, SDRV_ETIMR_CMP_00, (period_cnt + 1) / 2); sdrv_etimer_lld_cmp_val(etmr->base, cmp_chn, SDRV_ETIMR_CMP_01, (period_cnt + 1) / 2); cmp_event_mode.cmp_00_out = SDRV_ETIMR_LEVEL_LOW; cmp_event_mode.cmp_01_out = SDRV_ETIMR_LEVEL_HIGH; } if (cmp_cfg->chnl_out_mode == SDRV_ETIMR_CMP_OUT_CMP0_CMP1) { sdrv_etimer_lld_cmp_val(etmr->base, cmp_chn, SDRV_ETIMR_CMP_10, dual_period_cnt_left2); sdrv_etimer_lld_cmp_val(etmr->base, cmp_chn, SDRV_ETIMR_CMP_11, dual_period_cnt_right2); cmp_event_mode.cmp_10_out = SDRV_ETIMR_LEVEL_HIGH; cmp_event_mode.cmp_11_out = SDRV_ETIMR_LEVEL_LOW; if (state->duty2 == (state->period) / 2) { sdrv_etimer_lld_cmp_val(etmr->base, cmp_chn, SDRV_ETIMR_CMP_10, (period_cnt + 1) / 2); sdrv_etimer_lld_cmp_val(etmr->base, cmp_chn, SDRV_ETIMR_CMP_11, (period_cnt + 1) / 2); cmp_event_mode.cmp_10_out = SDRV_ETIMR_LEVEL_LOW; cmp_event_mode.cmp_11_out = SDRV_ETIMR_LEVEL_HIGH; } } } else { #endif if (cmp_cfg->cmp_mode == SDRV_ETIMR_CMP_SINGLE) { sdrv_etimer_lld_cmp_val(etmr->base, cmp_chn, SDRV_ETIMR_CMP_00, duty_cnt1); cmp_event_mode.cmp_00_out = SDRV_ETIMR_LEVEL_LOW; cmp_event_mode.cmp_0_ovf_out = SDRV_ETIMR_LEVEL_HIGH; if (cmp_cfg->chnl_out_mode == SDRV_ETIMR_CMP_OUT_CMP0_CMP1) { sdrv_etimer_lld_cmp_val(etmr->base, cmp_chn, SDRV_ETIMR_CMP_10, duty_cnt2); cmp_event_mode.cmp_10_out = SDRV_ETIMR_LEVEL_LOW; cmp_event_mode.cmp_1_ovf_out = SDRV_ETIMR_LEVEL_HIGH; } } else if (cmp_cfg->cmp_mode == SDRV_ETIMR_CMP_DUAL) { sdrv_etimer_lld_cmp_val(etmr->base, cmp_chn, SDRV_ETIMR_CMP_00, dual_period_cnt_left1); sdrv_etimer_lld_cmp_val(etmr->base, cmp_chn, SDRV_ETIMR_CMP_01, dual_period_cnt_right1); cmp_event_mode.cmp_00_out = SDRV_ETIMR_LEVEL_HIGH; cmp_event_mode.cmp_01_out = SDRV_ETIMR_LEVEL_LOW; if (cmp_cfg->chnl_out_mode == SDRV_ETIMR_CMP_OUT_CMP0_CMP1) { sdrv_etimer_lld_cmp_val(etmr->base, cmp_chn, SDRV_ETIMR_CMP_10, dual_period_cnt_left2); sdrv_etimer_lld_cmp_val(etmr->base, cmp_chn, SDRV_ETIMR_CMP_11, dual_period_cnt_right2); cmp_event_mode.cmp_10_out = SDRV_ETIMR_LEVEL_HIGH; cmp_event_mode.cmp_11_out = SDRV_ETIMR_LEVEL_LOW; } } #if CONFIG_E3L } #endif sdrv_etimer_lld_cmp_val_upd(etmr->base, cmp_chn); sdrv_etimer_lld_out_mode(etmr->base, cmp_chn, &cmp_event_mode); #if CONFIG_E3L if (etmr->center_align_mode == true) { if (etmr->use_g0_cnt == true) { basic_cnt_config_t basic_cnt_cfg; memset(&basic_cnt_cfg, 0, sizeof(basic_cnt_cfg)); basic_cnt_cfg.ovf_rst_dis = true; sdrv_etimer_lld_basic_cnt_cfg(etmr->base, cmp_cnt_sel, &basic_cnt_cfg); } else { local_cnt_config_t local_cnt_cfg; memset(&local_cnt_cfg, 0, sizeof(local_cnt_cfg)); local_cnt_cfg.ovf_rst_dis = true; sdrv_etimer_lld_local_cnt_cfg(etmr->base, cmp_cnt_sel, &local_cnt_cfg); } sdrv_etimer_lld_cnt_center_align_en(etmr->base, cmp_cnt_sel, true); sdrv_etimer_lld_cmp_center_align_en(etmr->base, cmp_chn, true); } #endif sdrv_etimer_lld_cmp_cfg(etmr->base, cmp_chn, &cmp_config); sdrv_etimer_lld_cmp_config_set(etmr->base, cmp_chn); ctrl->base = etmr->base; if (etmr->use_g0_cnt == true) { ctrl->g0_mode = G0_FOR_PWM_GEN; ctrl->g0_period = state->period; } ctrl->etimer_bank[cmp_chn + 4] = etmr; if ((cmp_cfg->cmp_mode == SDRV_ETIMR_CMP_SINGLE) || (cmp_cfg->cmp_mode == SDRV_ETIMR_CMP_DUAL)) { etmr->crtl_sta = ETIMER_CHAN_INIT; } if ((etmr->irq > 0) && (etmr->int_en == true) ) { irq_attach(etmr->irq, sdrv_etimer_irq_handle, ctrl); irq_enable(etmr->irq); } return SDRV_STATUS_OK; } /** * @brief etimer pwm config update. * * @param[in] etmr etimer ctrl instance * @param[in] cmp_cfg etimer cmp common config * @param[in] state pwm duty and period */ status_t sdrv_etimer_compare_pwm_config_update(sdrv_etimer_t *etmr, sdrv_etimer_cmp_cfg_t *cmp_cfg, const sdrv_etimer_pwm_state_t *state) { ASSERT(etmr != NULL); ASSERT(cmp_cfg != NULL); ASSERT(state != NULL); sdrv_etimer_controller_t *ctrl = etmr->controller; ASSERT(ctrl != NULL); sdrv_etimer_chn_id_e cmp_chn = etmr->channel; /* check pwm signal value */ if ((state->duty1) > (state->period) || (state->duty2) > (state->period)) { return SDRV_STATUS_INVALID_PARAM; } if ((etmr->mode != ETIMER_PWM_GENERATE) || (etmr->crtl_sta == ETIMER_CHAN_UNINIT)) { return SDRV_STATUS_INVALID_PARAM; } /* clear fifo first */ sdrv_etimer_lld_clear_fifo(etmr->base, cmp_chn); cmp_config_t cmp_config; etimer_cmp_event_mode_t cmp_event_mode; memset(&cmp_config, 0, sizeof(cmp_config)); sdrv_etimer_cnt_id_e cmp_cnt_sel; if (etmr->use_g0_cnt == true) { cmp_config.cnt_sel = SDRV_ETIMR_CMP_CNT_G0; cmp_cnt_sel = SDRV_ETIMR_CNT_G0; } else { cmp_config.cnt_sel = SDRV_ETIMR_CMP_LCNT; cmp_cnt_sel = (sdrv_etimer_cnt_id_e)(cmp_chn + 2); } uint32_t clk_freq = 0; /* all etimer use same src clk */ if (ctrl->etimer_clk_src == SDRV_ETIMR_AHF_CLK) { clk_freq = sdrv_ckgen_get_rate(CLK_NODE(g_ckgen_ip_xtrg)); } else if (ctrl->etimer_clk_src == SDRV_ETIMR_LP_CLK) { /* LP_CLK : 24M */ clk_freq = 24000000; } else { clk_freq = sdrv_ckgen_get_rate(CLK_NODE(g_ckgen_ip_etmr1)); } uint32_t period_cnt = 0; uint32_t duty_cnt1 = 0; uint32_t duty_cnt2 = 0; uint32_t dual_period_cnt_left1 = 0; uint32_t dual_period_cnt_right1 = 0; uint32_t dual_period_cnt_left2 = 0; uint32_t dual_period_cnt_right2 = 0; #if CONFIG_E3L if (etmr->center_align_mode == true) { period_cnt = sdrv_etimer_ns_to_val_1(clk_freq, state->period, ctrl->etimer_clk_div) / 2 - 1; } else { #endif period_cnt = sdrv_etimer_ns_to_val_1(clk_freq, state->period, ctrl->etimer_clk_div); #if CONFIG_E3L } #endif #if CONFIG_E3L if (etmr->center_align_mode == true || etmr->fre_double_flag == true) { /* in double fre mode, dual_period_cnt_right1 set a useless value */ duty_cnt1 = sdrv_etimer_ns_to_val(clk_freq, (state->duty1) / 2, ctrl->etimer_clk_div); dual_period_cnt_left1 = period_cnt + 1 - duty_cnt1; dual_period_cnt_right1 = period_cnt - 1; } else { #endif duty_cnt1 = sdrv_etimer_ns_to_val(clk_freq, state->duty1, ctrl->etimer_clk_div); dual_period_cnt_left1 = (period_cnt + 1) / 2 - duty_cnt1 / 2; dual_period_cnt_right1 = (period_cnt + 1) / 2 + duty_cnt1 / 2; #if CONFIG_E3L } #endif duty_cnt2 = sdrv_etimer_ns_to_val(clk_freq, state->duty2, ctrl->etimer_clk_div); dual_period_cnt_left2 = (period_cnt + 1) / 2 - duty_cnt2 / 2; dual_period_cnt_right2 = (period_cnt + 1) / 2 + duty_cnt2 / 2; cmp_config.out_mode = cmp_cfg->chnl_out_mode; cmp_config.con_mode = cmp_cfg->con_mode; cmp_config.cmp_mode = cmp_cfg->cmp_mode; /* cmp cnt cfg */ sdrv_etimer_lld_cnt_ovf(etmr->base, cmp_cnt_sel, period_cnt); /* pwm cfg -- cmp config */ cmp_event_mode.cmp_0_ovf_out = SDRV_ETIMR_KEEP; cmp_event_mode.cmp_1_ovf_out = SDRV_ETIMR_KEEP; #if CONFIG_E3L /* if use center_align_mode , cmp_mode use dual mode only */ if (etmr->center_align_mode == true) { sdrv_etimer_lld_cmp_val(etmr->base, cmp_chn, SDRV_ETIMR_CMP_00, dual_period_cnt_left1); sdrv_etimer_lld_cmp_val(etmr->base, cmp_chn, SDRV_ETIMR_CMP_01, dual_period_cnt_right1); if (etmr->fre_double_flag == true) { cmp_event_mode.cmp_00_out = SDRV_ETIMR_LEVEL_HIGH; cmp_event_mode.cmp_01_out = SDRV_ETIMR_KEEP; } else { cmp_event_mode.cmp_00_out = SDRV_ETIMR_LEVEL_HIGH; cmp_event_mode.cmp_01_out = SDRV_ETIMR_LEVEL_LOW; } if (state->duty1 == 0) { sdrv_etimer_lld_cmp_val(etmr->base, cmp_chn, SDRV_ETIMR_CMP_00, (period_cnt + 1) / 2); sdrv_etimer_lld_cmp_val(etmr->base, cmp_chn, SDRV_ETIMR_CMP_01, (period_cnt + 1) / 2); cmp_event_mode.cmp_00_out = SDRV_ETIMR_LEVEL_HIGH; cmp_event_mode.cmp_01_out = SDRV_ETIMR_LEVEL_LOW; } else if (state->duty1 == state->period) { sdrv_etimer_lld_cmp_val(etmr->base, cmp_chn, SDRV_ETIMR_CMP_00, (period_cnt + 1) / 2); sdrv_etimer_lld_cmp_val(etmr->base, cmp_chn, SDRV_ETIMR_CMP_01, (period_cnt + 1) / 2); cmp_event_mode.cmp_00_out = SDRV_ETIMR_LEVEL_LOW; cmp_event_mode.cmp_01_out = SDRV_ETIMR_LEVEL_HIGH; } if (cmp_cfg->chnl_out_mode == SDRV_ETIMR_CMP_OUT_CMP0_CMP1) { sdrv_etimer_lld_cmp_val(etmr->base, cmp_chn, SDRV_ETIMR_CMP_10, dual_period_cnt_left2); sdrv_etimer_lld_cmp_val(etmr->base, cmp_chn, SDRV_ETIMR_CMP_11, dual_period_cnt_right2); cmp_event_mode.cmp_10_out = SDRV_ETIMR_LEVEL_HIGH; cmp_event_mode.cmp_11_out = SDRV_ETIMR_LEVEL_LOW; } if (state->duty2 == (state->period) / 2) { sdrv_etimer_lld_cmp_val(etmr->base, cmp_chn, SDRV_ETIMR_CMP_10, (period_cnt + 1) / 2); sdrv_etimer_lld_cmp_val(etmr->base, cmp_chn, SDRV_ETIMR_CMP_11, (period_cnt + 1) / 2); cmp_event_mode.cmp_10_out = SDRV_ETIMR_LEVEL_LOW; cmp_event_mode.cmp_11_out = SDRV_ETIMR_LEVEL_HIGH; } } else { #endif if (cmp_cfg->cmp_mode == SDRV_ETIMR_CMP_SINGLE) { sdrv_etimer_lld_cmp_val(etmr->base, cmp_chn, SDRV_ETIMR_CMP_00, duty_cnt1); cmp_event_mode.cmp_00_out = SDRV_ETIMR_LEVEL_LOW; cmp_event_mode.cmp_0_ovf_out = SDRV_ETIMR_LEVEL_HIGH; if (cmp_cfg->chnl_out_mode == SDRV_ETIMR_CMP_OUT_CMP0_CMP1) { sdrv_etimer_lld_cmp_val(etmr->base, cmp_chn, SDRV_ETIMR_CMP_10, duty_cnt2); cmp_event_mode.cmp_10_out = SDRV_ETIMR_LEVEL_LOW; cmp_event_mode.cmp_1_ovf_out = SDRV_ETIMR_LEVEL_HIGH; } } else if (cmp_cfg->cmp_mode == SDRV_ETIMR_CMP_DUAL) { sdrv_etimer_lld_cmp_val(etmr->base, cmp_chn, SDRV_ETIMR_CMP_00, dual_period_cnt_left1); sdrv_etimer_lld_cmp_val(etmr->base, cmp_chn, SDRV_ETIMR_CMP_01, dual_period_cnt_right1); cmp_event_mode.cmp_00_out = SDRV_ETIMR_LEVEL_HIGH; cmp_event_mode.cmp_01_out = SDRV_ETIMR_LEVEL_LOW; if (cmp_cfg->chnl_out_mode == SDRV_ETIMR_CMP_OUT_CMP0_CMP1) { sdrv_etimer_lld_cmp_val(etmr->base, cmp_chn, SDRV_ETIMR_CMP_10, dual_period_cnt_left2); sdrv_etimer_lld_cmp_val(etmr->base, cmp_chn, SDRV_ETIMR_CMP_11, dual_period_cnt_right2); cmp_event_mode.cmp_10_out = SDRV_ETIMR_LEVEL_HIGH; cmp_event_mode.cmp_11_out = SDRV_ETIMR_LEVEL_LOW; } } #if CONFIG_E3L } #endif if (etmr->use_g0_cnt == true) { ctrl->g0_period = state->period; } sdrv_etimer_lld_cmp_val_upd(etmr->base, cmp_chn); sdrv_etimer_lld_out_mode(etmr->base, cmp_chn, &cmp_event_mode); sdrv_etimer_lld_cmp_cfg(etmr->base, cmp_chn, &cmp_config); sdrv_etimer_lld_cmp_config_set(etmr->base, cmp_chn); return SDRV_STATUS_OK; } /** * @brief configure etimer pwm output dma enable (dma_en must after pwm config) * * @param[in] etmr etimer ctrl instance * @param[in] wml water mark level (range : 1-15) */ status_t sdrv_etimer_compare_pwm_dma_en(sdrv_etimer_t *etmr, uint16_t wml) { ASSERT(etmr != NULL); sdrv_etimer_controller_t *ctrl = etmr->controller; ASSERT(ctrl != NULL); sdrv_etimer_chn_id_e cmp_chn = etmr->channel; if ((etmr->mode != ETIMER_PWM_GENERATE) || (etmr->crtl_sta == ETIMER_CHAN_UNINIT)) { return SDRV_STATUS_INVALID_PARAM; } /* water mark level (range : 1-15) */ if ((wml == 0) || (wml > 0xF)) { return SDRV_STATUS_INVALID_PARAM; } /* set dma wml */ sdrv_etimer_lld_dma_wml(etmr->base, cmp_chn, wml); chn_etimer_dma_ctrl_t dma_config; memset(&dma_config, 0, sizeof(dma_config)); /* select dma block */ dma_config.block_sel = SDRV_ETIMR_CMP_BLOCK; /* enable dma */ dma_config.chn_en = 1; sdrv_etimer_lld_dma_chn_cfg(etmr->base, cmp_chn, &dma_config); return SDRV_STATUS_OK; } /** * @brief configure multi compare mode. * * @param[in] etmr etimer ctrl instance * @param[in] multi_cmp etimer multi cmp config */ status_t sdrv_etimer_compare_multi_mode(sdrv_etimer_t *etmr, sdrv_etimer_multi_cmp_val_t *multi_cmp) { ASSERT(etmr != NULL); sdrv_etimer_controller_t *ctrl = etmr->controller; ASSERT(ctrl != NULL); sdrv_etimer_chn_id_e cmp_chn = etmr->channel; if ((etmr->mode != ETIMER_PWM_GENERATE) || (etmr->crtl_sta != ETIMER_CHAN_UNINIT)) { return SDRV_STATUS_INVALID_PARAM; } /* pwm config api first */ sdrv_etimer_cmp_mode_e cmp_mode = (sdrv_etimer_cmp_mode_e)sdrv_etimer_lld_get_cmp_mode(etmr->base, cmp_chn); if (cmp_mode != SDRV_ETIMR_CMP_MULTI) { return SDRV_STATUS_INVALID_PARAM; } uint32_t clk_freq = 0; /* all etimer use same src clk */ if (ctrl->etimer_clk_src == SDRV_ETIMR_AHF_CLK) { clk_freq = sdrv_ckgen_get_rate(CLK_NODE(g_ckgen_ip_xtrg)); } else if (ctrl->etimer_clk_src == SDRV_ETIMR_LP_CLK) { /* LP_CLK : 24M */ clk_freq = 24000000; } else { clk_freq = sdrv_ckgen_get_rate(CLK_NODE(g_ckgen_ip_etmr1)); } uint32_t cmp00_cnt = sdrv_etimer_ns_to_val(clk_freq, multi_cmp->cmp00_val, ctrl->etimer_clk_div); uint32_t cmp01_cnt = sdrv_etimer_ns_to_val(clk_freq, multi_cmp->cmp01_val, ctrl->etimer_clk_div); uint32_t cmp10_cnt = sdrv_etimer_ns_to_val(clk_freq, multi_cmp->cmp10_val, ctrl->etimer_clk_div); uint32_t cmp11_cnt = sdrv_etimer_ns_to_val(clk_freq, multi_cmp->cmp11_val, ctrl->etimer_clk_div); sdrv_etimer_lld_cmp_val(etmr->base, cmp_chn, SDRV_ETIMR_CMP_00, cmp00_cnt); sdrv_etimer_lld_cmp_val(etmr->base, cmp_chn, SDRV_ETIMR_CMP_01, cmp01_cnt); sdrv_etimer_lld_cmp_val(etmr->base, cmp_chn, SDRV_ETIMR_CMP_10, cmp10_cnt); sdrv_etimer_lld_cmp_val(etmr->base, cmp_chn, SDRV_ETIMR_CMP_11, cmp11_cnt); etmr->crtl_sta = ETIMER_CHAN_INIT; return SDRV_STATUS_OK; } /** * @brief start to generate etimer pwm signal. * * @param[in] etmr etimer ctrl instance */ status_t sdrv_etimer_compare_pwm_start(sdrv_etimer_t *etmr) { ASSERT(etmr != NULL); sdrv_etimer_chn_id_e cmp_chn = etmr->channel; if ((etmr->mode != ETIMER_PWM_GENERATE) || (etmr->crtl_sta == ETIMER_CHAN_UNINIT)) { return SDRV_STATUS_INVALID_PARAM; } sdrv_etimer_cnt_id_e cmp_cnt_sel; if (etmr->use_g0_cnt == true) { cmp_cnt_sel = SDRV_ETIMR_CNT_G0; } else { cmp_cnt_sel = (sdrv_etimer_cnt_id_e)(cmp_chn + 2); } /* reset the counter to 0 */ sdrv_etimer_lld_cnt_frc_rld(etmr->base, cmp_cnt_sel); sdrv_etimer_lld_cmp_en(etmr->base, cmp_chn, true); sdrv_etimer_lld_cnt_en(etmr->base, cmp_cnt_sel, true); etmr->crtl_sta = ETIMER_CHAN_RUNNING; return SDRV_STATUS_OK; } /** * @brief stop to generate etimer pwm signal. * * @param[in] etmr etimer ctrl instance */ status_t sdrv_etimer_compare_pwm_stop(sdrv_etimer_t *etmr) { ASSERT(etmr != NULL); sdrv_etimer_chn_id_e cmp_chn = etmr->channel; if ((etmr->mode != ETIMER_PWM_GENERATE) || (etmr->crtl_sta == ETIMER_CHAN_UNINIT)) { return SDRV_STATUS_INVALID_PARAM; } sdrv_etimer_cnt_id_e cmp_cnt_sel; if (etmr->use_g0_cnt == true) { cmp_cnt_sel = SDRV_ETIMR_CNT_G0; } else { cmp_cnt_sel = (sdrv_etimer_cnt_id_e)(cmp_chn + 2); } sdrv_etimer_lld_cmp_en(etmr->base, cmp_chn, false); sdrv_etimer_lld_cnt_en(etmr->base, cmp_cnt_sel, false); etmr->crtl_sta = ETIMER_CHAN_STOP; return SDRV_STATUS_OK; } /** * @brief etimer quad config. * * @param[in] etmr etimer ctrl instance * @param[in] quad_ctrl etimer quad config */ status_t sdrv_etimer_quad_config(sdrv_etimer_t *etmr, quad_ctrl_t *quad_ctrl) { ASSERT(etmr != NULL); sdrv_etimer_chn_id_e cpt_chn = etmr->channel; if (cpt_chn != SDRV_ETIMR_CHN_A) { return SDRV_STATUS_INVALID_PARAM; } if ((etmr->mode != ETIMER_PWM_OTHERS) || (etmr->crtl_sta != ETIMER_CHAN_UNINIT)) { return SDRV_STATUS_INVALID_PARAM; } sdrv_etimer_lld_cpt_quad_ctrl(etmr->base, quad_ctrl); sdrv_etimer_lld_lcnt_sig_en(etmr->base, SDRV_ETIMR_LCNT_A, true); sdrv_etimer_lld_cpt_quad_en(etmr->base, true); etmr->crtl_sta = ETIMER_CHAN_INIT; return SDRV_STATUS_OK; } /** * @brief start etimer config. * * @param[in] etmr etimer ctrl instance */ status_t sdrv_etimer_quad_start(sdrv_etimer_t *etmr) { ASSERT(etmr != NULL); sdrv_etimer_chn_id_e cpt_chn = etmr->channel; if (cpt_chn != SDRV_ETIMR_CHN_A) { return SDRV_STATUS_INVALID_PARAM; } if ((etmr->mode != ETIMER_PWM_OTHERS) || (etmr->crtl_sta == ETIMER_CHAN_UNINIT)) { return SDRV_STATUS_INVALID_PARAM; } sdrv_etimer_lld_cpt_en(etmr->base, SDRV_ETIMR_CHN_A, true); sdrv_etimer_lld_cnt_en(etmr->base, SDRV_ETIMR_LCNT_A, true); etmr->crtl_sta = ETIMER_CHAN_RUNNING; return SDRV_STATUS_OK; } /** * @brief stop etimer quad. * * @param[in] etmr etimer ctrl instance */ status_t sdrv_etimer_quad_stop(sdrv_etimer_t *etmr) { ASSERT(etmr != NULL); sdrv_etimer_chn_id_e cpt_chn = etmr->channel; if (cpt_chn != SDRV_ETIMR_CHN_A) { return SDRV_STATUS_INVALID_PARAM; } if ((etmr->mode != ETIMER_PWM_OTHERS) || (etmr->crtl_sta == ETIMER_CHAN_UNINIT)) { return SDRV_STATUS_INVALID_PARAM; } sdrv_etimer_lld_cpt_en(etmr->base, SDRV_ETIMR_CHN_A, false); sdrv_etimer_lld_cnt_en(etmr->base, SDRV_ETIMR_LCNT_A, false); etmr->crtl_sta = ETIMER_CHAN_STOP; return SDRV_STATUS_OK; } /** * @brief get quad dir signal status * * @param[in] etmr etimer ctrl instance */ bool sdrv_etimer_quad_dir_up(sdrv_etimer_t *etmr) { ASSERT(etmr != NULL); uint32_t sig_sta = sdrv_etimer_lld_get_sig_status(etmr->base); bool dir_up = false; /* bit 17 : cpt_a_dir */ if (sig_sta & (0x1U << 17)) { dir_up = false; } else { dir_up = true; } return dir_up; } /** * @brief configure etimer filter config * * @param[in] etmr etimer ctrl instance * @param[in] filter_cfg filter_cfg */ status_t sdrv_etimer_filter_config(sdrv_etimer_t *etmr, flt_config_t *filter_cfg) { ASSERT(etmr != NULL); sdrv_etimer_chn_id_e cpt_chn = etmr->channel; /* filter function is used to quad or capture */ if ((etmr->mode != ETIMER_PWM_OTHERS) && (etmr->mode != ETIMER_PWM_CAPTURE)) { return SDRV_STATUS_INVALID_PARAM; } sdrv_etimer_lld_cpt_flt_cfg(etmr->base, cpt_chn, filter_cfg); sdrv_etimer_lld_cpt_flt_en(etmr->base, cpt_chn, true); return SDRV_STATUS_OK; } /* icu function */ /** * @brief configure etimer icu config * * @param[in] etmr etimer ctrl instance * @param[in] edge_sel capture edge select */ status_t sdrv_etimer_icu_config(sdrv_etimer_t *etmr, sdrv_etimer_cpt_trig_mode_e edge_sel) { ASSERT(etmr != NULL); sdrv_etimer_controller_t *ctrl = etmr->controller; ASSERT(ctrl != NULL); sdrv_etimer_chn_id_e cpt_chn = etmr->channel; if ((etmr->mode != ETIMER_ICU_FUNC) || (etmr->crtl_sta != ETIMER_CHAN_UNINIT)) { return SDRV_STATUS_INVALID_PARAM; } sdrv_etimer_clk_int_set(etmr); /* clear fifo first */ sdrv_etimer_lld_clear_fifo(etmr->base, cpt_chn); cpt_config_t cpt_config; local_cnt_config_t local_cnt_config; memset(&cpt_config, 0, sizeof(cpt_config)); memset(&local_cnt_config, 0, sizeof(local_cnt_config)); /* capture cnt config */ sdrv_etimer_cnt_id_e cpt_cnt_sel = (sdrv_etimer_cnt_id_e)(cpt_chn + 2); /* set local cnt ovf val 0xFFFFFFFF */ sdrv_etimer_lld_cnt_ovf(etmr->base, cpt_cnt_sel, 0xFFFFFFFF); local_cnt_config.no_stop_mode = true; sdrv_etimer_lld_local_cnt_cfg(etmr->base, cpt_cnt_sel, &local_cnt_config); /* cpt_config */ cpt_config.cnt_sel = SDRV_ETIMR_CPT_LCNT; cpt_config.con_mode = SDRV_ETIMR_CPT_CONSECTIVE; cpt_config.dual_mode = SDRV_ETIMR_CPT_CPT0; cpt_config.cpt0_trig_mode = edge_sel; sdrv_etimer_lld_cpt_cfg(etmr->base, cpt_chn, &cpt_config); sdrv_etimer_lld_cpt_config_set(etmr->base, cpt_chn); ctrl->base = etmr->base; ctrl->etimer_bank[cpt_chn] = etmr; etmr->crtl_sta = ETIMER_CHAN_INIT; if (etmr->irq > 0) { irq_attach(etmr->irq, sdrv_etimer_irq_handle, ctrl); irq_enable(etmr->irq); } return SDRV_STATUS_OK; } /** * @brief configure etimer icu dma enable (dma_en must after icu config) * * @param[in] etmr etimer ctrl instance * @param[in] wml water mark level (range : 1-15) */ status_t sdrv_etimer_icu_dma_en(sdrv_etimer_t *etmr, uint16_t wml) { ASSERT(etmr != NULL); sdrv_etimer_controller_t *ctrl = etmr->controller; ASSERT(ctrl != NULL); sdrv_etimer_chn_id_e cpt_chn = etmr->channel; if ((etmr->mode != ETIMER_ICU_FUNC) || (etmr->crtl_sta == ETIMER_CHAN_UNINIT)) { return SDRV_STATUS_INVALID_PARAM; } /* water mark level (range : 1-15) */ if ((wml == 0) || (wml > 0xF)) { return SDRV_STATUS_INVALID_PARAM; } /* dma mode don't need cpt interrupt */ sdrv_etimer_lld_int_en(etmr->base, ETMR_BM_INT_STA_EN_CPT(etmr->channel), false); /* set dma wml */ sdrv_etimer_lld_dma_wml(etmr->base, cpt_chn, wml); chn_etimer_dma_ctrl_t dma_config; memset(&dma_config, 0, sizeof(dma_config)); /* select dma block */ dma_config.block_sel = SDRV_ETIMR_CPT_BLOCK; /* enable dma */ dma_config.chn_en = 1; sdrv_etimer_lld_dma_chn_cfg(etmr->base, cpt_chn, &dma_config); return SDRV_STATUS_OK; } /** * @brief start etimer icu chan. * * @param[in] etmr etimer ctrl instance */ status_t sdrv_etimer_icu_start(sdrv_etimer_t *etmr) { ASSERT(etmr != NULL); sdrv_etimer_chn_id_e cpt_chn = etmr->channel; sdrv_etimer_cnt_id_e cpt_cnt_sel = (sdrv_etimer_cnt_id_e)(cpt_chn + 2); if ((etmr->mode != ETIMER_ICU_FUNC) || (etmr->crtl_sta == ETIMER_CHAN_UNINIT)) { return SDRV_STATUS_INVALID_PARAM; } /* reset the counter to 0 */ sdrv_etimer_lld_cnt_frc_rld(etmr->base, cpt_cnt_sel); sdrv_etimer_lld_cpt_en(etmr->base, cpt_chn, true); sdrv_etimer_lld_cnt_en(etmr->base, cpt_cnt_sel, true); etmr->crtl_sta = ETIMER_CHAN_RUNNING; return SDRV_STATUS_OK; } /** * @brief stop etimer icu chan. * * @param[in] etmr etimer ctrl instance */ status_t sdrv_etimer_icu_stop(sdrv_etimer_t *etmr) { ASSERT(etmr != NULL); sdrv_etimer_chn_id_e cpt_chn = etmr->channel; sdrv_etimer_cnt_id_e cpt_cnt_sel = (sdrv_etimer_cnt_id_e)(cpt_chn + 2); if ((etmr->mode != ETIMER_ICU_FUNC) || (etmr->crtl_sta == ETIMER_CHAN_UNINIT)) { return SDRV_STATUS_INVALID_PARAM; } sdrv_etimer_lld_cnt_en(etmr->base, cpt_cnt_sel, false); sdrv_etimer_lld_cpt_en(etmr->base, cpt_chn, false); etmr->crtl_sta = ETIMER_CHAN_STOP; return SDRV_STATUS_OK; } /** * @brief stop etimer icu get capture timestamp. * * @param[in] etmr etimer ctrl instance * @return cpt_val : capture val */ uint32_t sdrv_etimer_icu_get_cnt_val(sdrv_etimer_t *etmr) { ASSERT(etmr != NULL); sdrv_etimer_chn_id_e cpt_chn = etmr->channel; if (etmr->mode != ETIMER_ICU_FUNC) { return 0; } uint32_t cpt_val = sdrv_etimer_lld_get_cpt0_cnt0(etmr->base, cpt_chn); return cpt_val; } /** * @brief stop etimer icu get channel level status. * * @param[in] etmr etimer ctrl instance * @return high level : true low level : false */ bool sdrv_etimer_icu_get_level(sdrv_etimer_t *etmr) { ASSERT(etmr != NULL); sdrv_etimer_chn_id_e cpt_chn = etmr->channel; uint32_t sig_sta = sdrv_etimer_lld_get_sig_status(etmr->base); bool level_sta = false; /* bit 16/20/24/28 : capture a/b/c/d signal status */ if (sig_sta & (0x1 << (16 + (0x4 * cpt_chn)))) { level_sta = true; } return level_sta; }