// Copyright 2020-2021 Beken // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #include #include #include #include #include #include "pwm_hal_v1px.h" #include "pwm_driver.h" #include "clock_driver.h" #include "power_driver.h" #include #include "sys_driver.h" #include "gpio_driver.h" #include #if CONFIG_PWM_PM_CB_SUPPORT #include #endif static void pwm_isr_common(pwm_id_t id); static void pwm0_isr(void); static void pwm1_isr(void); #define PWM_GPIO_MODE_MAX 4 #define PWM_CHAN_MASK 0x3f // 6 channels #define PWM_GROUP_NUM_PER_UNIT SOC_PWM_GROUP_NUM #define PWM_GROUP_NUM (PWM_GROUP_NUM_PER_UNIT * SOC_PWM_UNIT_NUM) #define PWM_CHAN_TO_UNIT_ID(chan) (chan / SOC_PWM_CHAN_NUM_PER_UNIT) #define PWM_CHAN_ID_TO_HW_CHAN_ID(chan) (chan % SOC_PWM_CHAN_NUM_PER_UNIT) #define PWM_GROUP_TO_UNIT_ID(group) (group / SOC_PWM_GROUP_NUM) #define PWM_GROUP_TO_HW_GROUP_ID(group) (group % SOC_PWM_GROUP_NUM) #define PWM_INIT_LEVEL_HIGH 1 #define PWM_INIT_LEVEL_LOW 0 typedef struct { pwm_chan_t chan1; pwm_chan_t chan2; bool is_valid; uint32_t period_cycle; /**< PWM Group period cycle */ uint32_t chan1_duty_cycle; /**< Duty cycle of chan1 */ uint32_t chan2_duty_cycle; /**< Duty cycle of chan2 */ uint32_t dead_cycle; bool is_param_need_update; bool is_flip_mode_need_update; } pwm_group_info_t; typedef struct { pwm_hal_t hal; //Important notes: currently no lock for bits //Concurrently operation is NOT allowed!!!s_pwm_pin_id_map uint32_t chan_init_bits; uint32_t chan_init_signal_level; volatile uint32_t phase_shift_chan_init_level; #if CONFIG_PWM_PM_CB_SUPPORT uint32_t pm_backup[PWM_PM_BACKUP_REG_NUM]; uint8_t pm_bakeup_is_valid; #endif } pwm_driver_t; typedef struct { gpio_id_t gpio_id; gpio_dev_t gpio_dev; } pwm_gpio_map_t; typedef enum { PWM_SINGLE_CHAN_MODE = (1 << 0), PWM_GROUP_MODE = (1 << 1), PWM_PHASE_SHIFT_MODE = (1 << 2), } pwm_func_mode_t; static pwm_driver_t s_pwm[SOC_PWM_UNIT_NUM] = {0}; static pwm_isr_t s_pwm_isr[SOC_PWM_UNIT_NUM][SOC_PWM_CHAN_NUM_PER_UNIT] = {NULL}; static bool s_pwm_driver_is_init = false; static const pwm_gpio_map_t s_pwm_pin_id_map[SOC_PWM_UNIT_NUM][SOC_PWM_CHAN_NUM_PER_UNIT] = GPIO_PWM_MAP_TABLE; static pwm_group_info_t s_pwm_groups[PWM_GROUP_NUM]; static uint8_t s_pwm_mode = 0; #if CONFIG_PWM_PHASE_SHIFT static pwm_chan_t s_phase_shift_multi_hw_ch[SOC_PWM_UNIT_NUM] = {0}; static uint32_t s_phase_shift_first_valid_ch = 0; static pwm_phase_shift_config_t *s_shift_config = NULL; #endif #define PWM_RETURN_ON_INVALID_CHAN(hw_ch) do {\ if ((hw_ch) >= SOC_PWM_CHAN_NUM_PER_UNIT) {\ return BK_ERR_PWM_CHAN_ID;\ }\ } while(0) #define PWM_RETURN_ON_INVALID_CHAN_CLOCK(clock) do {\ if ((clock) >= PWM_CHAN_CLOCK_MAX) {\ return BK_ERR_PWM_CHAN_CLOCK;\ }\ } while(0) #define PWM_RETURN_ON_NOT_INIT() do {\ if (!s_pwm_driver_is_init) {\ return BK_ERR_PWM_NOT_INIT;\ }\ } while(0) #define PWM_RETURN_ON_CHAN_NOT_INIT(id, hw_ch) do {\ if (!(s_pwm[id].chan_init_bits & BIT((hw_ch)))) {\ return BK_ERR_PWM_CHAN_NOT_INIT;\ }\ } while(0) #define PWM_RETURN_ON_INVALID_GROUP(hw_ch) do {\ if (hw_ch >= PWM_GROUP_NUM_PER_UNIT) {\ return BK_ERR_PWM_GROUP_ID;\ }\ } while(0) #define PWM_RETURN_ON_INVALID_GPIO_MODE(hw_ch) do {\ if (hw_ch >= PWM_GPIO_MODE_MAX) {\ return BK_ERR_PWM_INVALID_GPIO_MODE;\ }\ } while(0) #define PWM_RETURN_ON_INVALID_CHAN_NUM(shift_config) do {\ if (shift_config->chan_num < 2) {\ return BK_ERR_PWM_PHASE_SHIFT_CHAN_NUM;\ }\ } while(0) #define PWM_PHASE_SHIFT_RETURN_ON_INVALID_DUTY(shift_config) do {\ for (uint32_t index = 0; index < shift_config->chan_num; index++) {\ if ((shift_config->duty_config[index].duty_cycle == 1) ||\ (shift_config->duty_config[index].duty_cycle > shift_config->period_cycle)) {\ PWM_LOGE("invalid duty cycle, index:%d, period_cycle:%d, duty_cycle:%d\r\n",\ index,\ shift_config->period_cycle,\ shift_config->duty_config[index].duty_cycle);\ return BK_ERR_PWM_PERIOD_DUTY;\ }\ }\ } while(0) #if CONFIG_PWM_PM_CB_SUPPORT #define PWM_PM_CHECK_RESTORE(id) do {\ GLOBAL_INT_DECLARATION();\ GLOBAL_INT_DISABLE();\ switch (id) {\ case PWM_ID_0:\ if (bk_pm_module_lv_sleep_state_get(PM_DEV_ID_PWM_1)) {\ bk_pm_module_vote_power_ctrl(PM_POWER_SUB_MODULE_NAME_BAKP_PWM0, PM_POWER_MODULE_STATE_ON);\ pwm_pm_restore(0, (void *)id);\ bk_pm_module_lv_sleep_state_clear(PM_DEV_ID_PWM_1);\ }\ break;\ case PWM_ID_1:\ if (bk_pm_module_lv_sleep_state_get(PM_DEV_ID_PWM_2)) {\ bk_pm_module_vote_power_ctrl(PM_POWER_SUB_MODULE_NAME_BAKP_PWM1, PM_POWER_MODULE_STATE_ON);\ pwm_pm_restore(0, (void *)id);\ bk_pm_module_lv_sleep_state_clear(PM_DEV_ID_PWM_2);\ }\ break;\ default:\ break;\ }\ GLOBAL_INT_RESTORE();\ } while(0) #else #define PWM_PM_CHECK_RESTORE(id) #endif static void pwm_sw_ch_to_hw_id_ch(pwm_ch_t sw_ch, pwm_id_t *id, pwm_ch_t *hw_ch) { if(id) *id = sw_ch / SOC_PWM_CHAN_NUM_PER_UNIT; if(hw_ch) *hw_ch = sw_ch % SOC_PWM_CHAN_NUM_PER_UNIT; } static void pwm_chan_init_gpio(pwm_ch_t sw_ch) { pwm_id_t id; pwm_ch_t hw_ch; pwm_sw_ch_to_hw_id_ch(sw_ch, &id, &hw_ch); gpio_dev_unmap(s_pwm_pin_id_map[id][hw_ch].gpio_id); gpio_dev_map(s_pwm_pin_id_map[id][hw_ch].gpio_id, s_pwm_pin_id_map[id][hw_ch].gpio_dev); bk_gpio_pull_up(s_pwm_pin_id_map[id][hw_ch].gpio_id); } static void pwm_chan_enable_interrupt_common(pwm_chan_t sw_ch) { pwm_id_t id; pwm_ch_t hw_ch; pwm_sw_ch_to_hw_id_ch(sw_ch, &id, &hw_ch); if(id == PWM_ID_0) sys_drv_int_enable(PWM_INTERRUPT_CTRL_BIT); else sys_drv_int_enable(PWM1_INTERRUPT_CTRL_BIT); pwm_hal_enable_interrupt(&s_pwm[id].hal, hw_ch); } /* Once the global PWM interrupt is enabled, we never disable it. * It should be OK, because if all PWM are stop, there will be no * PWM interrupt even though the global PWM interrupt is enabled. * * We can choose to disable the global PWM interrupt if all PWM * channels are stopped, but it make the code complex! **/ static void pwm_chan_disable_interrupt_common(pwm_chan_t sw_ch) { pwm_id_t id; pwm_ch_t hw_ch; pwm_sw_ch_to_hw_id_ch(sw_ch, &id, &hw_ch); #if 0 pwm_hal_disable_interrupt(&s_pwm[id].hal, hw_ch); pwm_hal_clear_chan_interrupt_status(&s_pwm[id].hal, hw_ch); #endif } /* Init common to PWM/Capture init * 1. Set channel init bit * 2. Power up channel * 3. Set channel specific clock */ static void pwm_chan_init_common(pwm_chan_t sw_ch) { pwm_id_t id; pwm_ch_t hw_ch; pwm_sw_ch_to_hw_id_ch(sw_ch, &id, &hw_ch); s_pwm[id].chan_init_bits |= BIT(hw_ch); if(id == PWM_ID_0) { sys_drv_dev_clk_pwr_up(CLK_PWR_ID_PWM_1, CLK_PWR_CTRL_PWR_UP); sys_drv_pwm_select_clock(SYS_SEL_PWM0, PWM_SCLK_XTAL); sys_drv_int_enable(PWM_INTERRUPT_CTRL_BIT); } if(id == PWM_ID_1) { sys_drv_dev_clk_pwr_up(CLK_PWR_ID_PWM_2, CLK_PWR_CTRL_PWR_UP); sys_drv_pwm_select_clock(SYS_SEL_PWM1, PWM_SCLK_XTAL); sys_drv_int_group2_enable(PWM1_INTERRUPT_CTRL_BIT); } pwm_chan_init_gpio(sw_ch); } static void pwm_chan_deinit_common(pwm_chan_t sw_ch) { pwm_id_t unit_id; pwm_ch_t hw_ch; pwm_sw_ch_to_hw_id_ch(sw_ch, &unit_id, &hw_ch); s_pwm[unit_id].chan_init_bits &= ~BIT(hw_ch); pwm_hal_set_chan_enable(&s_pwm[unit_id].hal, hw_ch, false); //all of the channels deinit, then power-down if ((unit_id == 0) && ((s_pwm[unit_id].chan_init_bits & PWM_CHAN_MASK)== 0)) { sys_drv_dev_clk_pwr_up(CLK_PWR_ID_PWM_1, CLK_PWR_CTRL_PWR_DOWN); } if ((unit_id == 1) && ((s_pwm[unit_id].chan_init_bits & PWM_CHAN_MASK)== 0)) { sys_drv_dev_clk_pwr_up(CLK_PWR_ID_PWM_2, CLK_PWR_CTRL_PWR_DOWN); } } #if (CONFIG_PWM_PM_CB_SUPPORT) static int pwm_pm_backup(uint64_t sleep_time, void *args) { PWM_RETURN_ON_NOT_INIT(); pwm_id_t id = (pwm_id_t)args; if (!s_pwm[id].pm_bakeup_is_valid) { pwm_hal_pm_backup(&s_pwm[id].hal, s_pwm[id].pm_backup); s_pwm[id].pm_bakeup_is_valid = 1; } if (id == PWM_ID_0) { sys_drv_dev_clk_pwr_up(CLK_PWR_ID_PWM_1, CLK_PWR_CTRL_PWR_DOWN); } else if (id == PWM_ID_1) { sys_drv_dev_clk_pwr_up(CLK_PWR_ID_PWM_2, CLK_PWR_CTRL_PWR_DOWN); } return BK_OK; } static int pwm_pm_restore(uint64_t sleep_time, void *args) { PWM_RETURN_ON_NOT_INIT(); pwm_id_t id = (pwm_id_t)args; if (id == PWM_ID_0) { sys_drv_dev_clk_pwr_up(CLK_PWR_ID_PWM_1, CLK_PWR_CTRL_PWR_UP); } else if (id == PWM_ID_1) { sys_drv_dev_clk_pwr_up(CLK_PWR_ID_PWM_2, CLK_PWR_CTRL_PWR_UP); } if (s_pwm[id].pm_bakeup_is_valid) { pwm_hal_pm_restore(&s_pwm[id].hal, s_pwm[id].pm_backup); s_pwm[id].pm_bakeup_is_valid = 0; } return BK_OK; } #endif bk_err_t bk_pwm_driver_init(void) { if (s_pwm_driver_is_init) return BK_OK; os_memset(&s_pwm, 0, sizeof(s_pwm)); os_memset(&s_pwm_isr, 0, sizeof(s_pwm_isr)); bk_int_isr_register(INT_SRC_PWM, pwm0_isr, NULL); bk_int_isr_register(INT_SRC_PWM1, pwm1_isr, NULL); #if (CONFIG_PWM_PM_CB_SUPPORT) bk_pm_module_vote_power_ctrl(PM_POWER_SUB_MODULE_NAME_BAKP_PWM0, PM_POWER_MODULE_STATE_ON); #if (SOC_PWM_UNIT_NUM > 1) bk_pm_module_vote_power_ctrl(PM_POWER_SUB_MODULE_NAME_BAKP_PWM1, PM_POWER_MODULE_STATE_ON); #endif #endif for (uint32_t uint_id = 0; uint_id < SOC_PWM_UNIT_NUM; uint_id++) { s_pwm[uint_id].hal.id = uint_id; pwm_hal_init(&s_pwm[uint_id].hal); } s_pwm_driver_is_init = true; return BK_OK; } bk_err_t bk_pwm_driver_deinit(void) { if (!s_pwm_driver_is_init) return BK_OK; for (int sw_ch = 0; sw_ch < (SOC_PWM_CHAN_NUM_PER_UNIT * SOC_PWM_UNIT_NUM); sw_ch++) pwm_chan_deinit_common(sw_ch); #if (CONFIG_PWM_PM_CB_SUPPORT) bk_pm_module_vote_power_ctrl(PM_POWER_SUB_MODULE_NAME_BAKP_PWM0, PM_POWER_MODULE_STATE_OFF); #if (SOC_PWM_UNIT_NUM > 1) bk_pm_module_vote_power_ctrl(PM_POWER_SUB_MODULE_NAME_BAKP_PWM1, PM_POWER_MODULE_STATE_OFF); #endif #endif s_pwm_driver_is_init = false; return BK_OK; } static void pwm_adjust_init_signal_via_duty(pwm_chan_t sw_ch, uint32_t period, uint32_t duty1, uint32_t duty2, uint32_t duty3) { pwm_id_t id; pwm_ch_t hw_ch; pwm_sw_ch_to_hw_id_ch(sw_ch, &id, &hw_ch); /** If duty ratio is 0% and initial signal is high, * then the PWM signal will always be high. * To avoid that, we manually configure init signal to low if * duty ratio is 0%. */ if (duty1 == 0) { pwm_hal_set_init_signal_low(&s_pwm[id].hal, hw_ch); pwm_hal_set_flip_mode(&s_pwm[id].hal, hw_ch, 4); } /** If duty ratio is 100% and initial signal is low, * then the PWM signal will always be low. * To avoid that, we manually configure init signal to high if * duty ratio is 100%. */ else if (duty1 == period) { pwm_hal_set_init_signal_high(&s_pwm[id].hal, hw_ch); pwm_hal_set_flip_mode(&s_pwm[id].hal, hw_ch, 4); } } static inline bool pwm_driver_duty_is_valid(uint32_t period, uint32_t duty1, uint32_t duty2, uint32_t duty3) { if (period <= 1 || duty1 == 1) { PWM_LOGE("period and duty1 must be more than 1\r\n"); return false; } //Not consider (duty1 + duty2 + duty3) overflow if ((duty1 + duty2 + duty3) > period) return false; //Not consier (duty2 + duty3) overflow if ((duty1 == 0) && ((duty2 + duty3) != 0)) return false; if ((duty2 == 0) && (duty3 != 0)) return false; return true; } static void pwm_output_mode_config(pwm_chan_t sw_ch, int end_val, int psc, int cc, int ddt) { pwm_id_t id; pwm_ch_t hw_ch; pwm_sw_ch_to_hw_id_ch(sw_ch, &id, &hw_ch); switch(hw_ch) { case 0: //PWM_CHANNEL0: case 1: pwm_hal_set_pwm_cr1_arpe1(&s_pwm[id].hal, 1) ; //enable arr1 preload pwm_hal_set_tim1_arr_tim1_arr(&s_pwm[id].hal, end_val); //end value arr1 0x60 pwm_hal_set_prescaler_psc1(&s_pwm[id].hal, psc) ; //prescale is 5 pwm_hal_set_ccr1_value(&s_pwm[id].hal, cc); pwm_hal_set_pwm_ccmr_oc1m(&s_pwm[id].hal, 0x3) ; //toggle at ccr1 and arr1 //pwm_hal_set_pwm_dier_cc1ie(&s_pwm[id].hal, true) ; //enable ccr1 int pwm_hal_set_pwm_ccmr_ch1e(&s_pwm[id].hal, true); //enable pwm_o[0] pwm_hal_set_pwm_ccmr_ch2e(&s_pwm[id].hal, true); //enable pwm_o[1] pwm_hal_set_dt_dt1(&s_pwm[id].hal, ddt) ; //set deadtime as 5 cycle pwm_hal_set_pwm_ccmr_ch1p(&s_pwm[id].hal, 0x00) ; //set pwm_o[1] as complementary of pwm_o[0] pwm_hal_set_pwm_ccmr_ch2p(&s_pwm[id].hal, 0x00) ; //set pwm_o[1] as complementary of pwm_o[0] pwm_hal_set_pwm_edtr_ug1(&s_pwm[id].hal, 0x01); //update ccr1 and arr1 break; case 2: //PWM_CHANNEL2: case 3: pwm_hal_set_pwm_cr1_arpe2(&s_pwm[id].hal, 1) ; //enable arr1 preload pwm_hal_set_tim2_arr_tim2_arr(&s_pwm[id].hal, end_val); //end value arr1 0x60 pwm_hal_set_prescaler_psc2(&s_pwm[id].hal, psc) ; //prescale is 5 pwm_hal_set_ccr4_value(&s_pwm[id].hal, cc); pwm_hal_set_pwm_ccmr_oc2m(&s_pwm[id].hal, 0x3) ; //toggle at ccr1 and arr1 //pwm_hal_set_pwm_dier_cc3ie(&s_pwm[id].hal, true) ; //enable ccr1 int pwm_hal_set_pwm_ccmr_ch3e(&s_pwm[id].hal, true); //enable pwm_o[0] pwm_hal_set_pwm_ccmr_ch4e(&s_pwm[id].hal, true); //enable pwm_o[1] pwm_hal_set_dt_dt2(&s_pwm[id].hal, ddt) ; //set deadtime as 5 cycle pwm_hal_set_pwm_ccmr_ch3p(&s_pwm[id].hal, 0x00) ; //set pwm_o[1] as complementary of pwm_o[0] pwm_hal_set_pwm_ccmr_ch4p(&s_pwm[id].hal, 0x00) ; //set pwm_o[1] as complementary of pwm_o[0] pwm_hal_set_pwm_edtr_ug2(&s_pwm[id].hal, 0x01); //update ccr1 and arr1 break; case 4: //PWM_CHANNEL4: case 5: pwm_hal_set_pwm_cr1_arpe3(&s_pwm[id].hal, 1) ; //enable arr1 preload pwm_hal_set_tim3_arr_tim3_arr(&s_pwm[id].hal, end_val); //end value arr1 0x60 pwm_hal_set_prescaler_psc3(&s_pwm[id].hal, psc) ; //prescale is 5 pwm_hal_set_ccr7_value(&s_pwm[id].hal, cc); pwm_hal_set_pwm_ccmr_oc3m(&s_pwm[id].hal, 0x3) ; //toggle at ccr1 and arr1 //pwm_hal_set_pwm_dier_cc7ie(&s_pwm[id].hal, true) ; //enable ccr1 int pwm_hal_set_pwm_ccmr_ch5e(&s_pwm[id].hal, true); //enable pwm_o[0] pwm_hal_set_pwm_ccmr_ch6e(&s_pwm[id].hal, true); //enable pwm_o[1] pwm_hal_set_dt_dt3(&s_pwm[id].hal, ddt) ; //set deadtime as 5 cycle pwm_hal_set_pwm_ccmr_ch5p(&s_pwm[id].hal, 0x00) ; //set pwm_o[1] as complementary of pwm_o[0] pwm_hal_set_pwm_ccmr_ch6p(&s_pwm[id].hal, 0x00) ; //set pwm_o[1] as complementary of pwm_o[0] pwm_hal_set_pwm_edtr_ug3(&s_pwm[id].hal, 0x01); //update ccr1 and arr1 break; default: break; } } static void pwm_group_set_complementary_mode(pwm_chan_t sw_chan) { pwm_id_t id = 0; pwm_ch_t hw_ch = 0; pwm_sw_ch_to_hw_id_ch(sw_chan, &id, &hw_ch); PWM_LOGI("group pwm_id:%d, chan:%d\r\n", id, hw_ch); switch (hw_ch) { case PWM_CH_0: //PWM_CHANNEL0: case PWM_CH_1: pwm_hal_set_pwm_ccmr_ch1p(&s_pwm[id].hal, 0x00) ; //set pwm_o[1] as complementary of pwm_o[0] pwm_hal_set_pwm_ccmr_ch2p(&s_pwm[id].hal, 0x01) ; break; case PWM_CH_2: //PWM_CHANNEL2: case PWM_CH_3: pwm_hal_set_pwm_ccmr_ch3p(&s_pwm[id].hal, 0x00) ; //set pwm_o[2] as complementary of pwm_o[3] pwm_hal_set_pwm_ccmr_ch4p(&s_pwm[id].hal, 0x01) ; break; case PWM_CH_4: //PWM_CHANNEL4: case PWM_CH_5: pwm_hal_set_pwm_ccmr_ch5p(&s_pwm[id].hal, 0x00) ; //set pwm_o[4] as complementary of pwm_o[5] pwm_hal_set_pwm_ccmr_ch6p(&s_pwm[id].hal, 0x01) ; break; default: break; } } static void pwm_group_output_mode_config(const pwm_group_init_config_t *config, int psc, int ddt) { pwm_output_mode_config(config->chan1, config->period_cycle - 1, psc, config->chan1_duty_cycle + ddt, ddt); pwm_output_mode_config(config->chan2, config->period_cycle - 1, psc, config->chan2_duty_cycle + ddt, ddt); pwm_group_set_complementary_mode(config->chan1); pwm_group_set_complementary_mode(config->chan2); } static void pwm_set_channel_config(pwm_ch_t sw_ch, const pwm_period_duty_config_t *config) { pwm_id_t id; pwm_ch_t hw_ch; pwm_sw_ch_to_hw_id_ch(sw_ch, &id, &hw_ch); PWM_LOGD("hw:%d, period_cycle:%d, duty_cycle:%d, duty2_cycle:%d, duty3_cycle:%d\r\n", hw_ch, config->period_cycle, config->duty_cycle, config->duty2_cycle, config->duty3_cycle); switch(hw_ch) { case 0: pwm_hal_set_tim1_arr_tim1_arr(&s_pwm[id].hal, config->period_cycle - 1); pwm_hal_set_ccr1_value(&s_pwm[id].hal, config->duty_cycle); pwm_hal_set_ccr2_value(&s_pwm[id].hal, config->duty2_cycle); pwm_hal_set_ccr3_value(&s_pwm[id].hal, config->duty3_cycle); pwm_hal_set_prescaler_psc1(&s_pwm[id].hal, config->psc); pwm_hal_set_pwm_ccmr_ch1e(&s_pwm[id].hal, true); break; case 1: pwm_hal_set_tim1_arr_tim1_arr(&s_pwm[id].hal, config->period_cycle - 1); pwm_hal_set_ccr1_value(&s_pwm[id].hal, config->duty_cycle); pwm_hal_set_ccr2_value(&s_pwm[id].hal, config->duty2_cycle); pwm_hal_set_ccr3_value(&s_pwm[id].hal, config->duty3_cycle); pwm_hal_set_prescaler_psc1(&s_pwm[id].hal, config->psc); pwm_hal_set_pwm_ccmr_ch2e(&s_pwm[id].hal, true); break; case 2: pwm_hal_set_tim2_arr_tim2_arr(&s_pwm[id].hal, config->period_cycle - 1); pwm_hal_set_ccr4_value(&s_pwm[id].hal, config->duty_cycle); pwm_hal_set_ccr5_value(&s_pwm[id].hal, config->duty2_cycle); pwm_hal_set_ccr6_value(&s_pwm[id].hal, config->duty3_cycle); pwm_hal_set_prescaler_psc2(&s_pwm[id].hal, config->psc); pwm_hal_set_pwm_ccmr_ch3e(&s_pwm[id].hal, true); break; case 3: pwm_hal_set_tim2_arr_tim2_arr(&s_pwm[id].hal, config->period_cycle - 1); pwm_hal_set_ccr4_value(&s_pwm[id].hal, config->duty_cycle); pwm_hal_set_ccr5_value(&s_pwm[id].hal, config->duty2_cycle); pwm_hal_set_ccr6_value(&s_pwm[id].hal, config->duty3_cycle); pwm_hal_set_prescaler_psc2(&s_pwm[id].hal, config->psc); pwm_hal_set_pwm_ccmr_ch4e(&s_pwm[id].hal, true); break; case 4: pwm_hal_set_tim3_arr_tim3_arr(&s_pwm[id].hal, config->period_cycle - 1); pwm_hal_set_ccr7_value(&s_pwm[id].hal, config->duty_cycle); pwm_hal_set_ccr8_value(&s_pwm[id].hal, config->duty2_cycle); pwm_hal_set_ccr9_value(&s_pwm[id].hal, config->duty3_cycle); pwm_hal_set_prescaler_psc3(&s_pwm[id].hal, config->psc); pwm_hal_set_pwm_ccmr_ch5e(&s_pwm[id].hal, true); break; case 5: pwm_hal_set_tim3_arr_tim3_arr(&s_pwm[id].hal, config->period_cycle - 1); pwm_hal_set_ccr7_value(&s_pwm[id].hal, config->duty_cycle); pwm_hal_set_ccr8_value(&s_pwm[id].hal, config->duty2_cycle); pwm_hal_set_ccr9_value(&s_pwm[id].hal, config->duty3_cycle); pwm_hal_set_prescaler_psc3(&s_pwm[id].hal, config->psc); pwm_hal_set_pwm_ccmr_ch6e(&s_pwm[id].hal, true); break; default: break; } } bk_err_t bk_pwm_init(pwm_chan_t sw_ch, const pwm_init_config_t *config) { PWM_RETURN_ON_NOT_INIT(); BK_RETURN_ON_NULL(config); pwm_id_t id; pwm_ch_t hw_ch; pwm_period_duty_config_t pwm_config; pwm_sw_ch_to_hw_id_ch(sw_ch, &id, &hw_ch); PWM_RETURN_ON_INVALID_CHAN(hw_ch); if (!pwm_driver_duty_is_valid(config->period_cycle, config->duty_cycle, config->duty2_cycle, config->duty3_cycle)) return BK_ERR_PWM_PERIOD_DUTY; #if (CONFIG_PWM_PM_CB_SUPPORT) pm_cb_conf_t enter_cfg = {pwm_pm_backup, (void *)id}; if (id == PWM_ID_0) { bk_pm_module_vote_power_ctrl(PM_POWER_SUB_MODULE_NAME_BAKP_PWM0, PM_POWER_MODULE_STATE_ON); bk_pm_sleep_register_cb(PM_MODE_LOW_VOLTAGE, PM_DEV_ID_PWM_1, &enter_cfg, NULL); bk_pm_module_lv_sleep_state_clear(PM_DEV_ID_PWM_1); } else if (id == PWM_ID_1) { bk_pm_module_vote_power_ctrl(PM_POWER_SUB_MODULE_NAME_BAKP_PWM1, PM_POWER_MODULE_STATE_ON); bk_pm_sleep_register_cb(PM_MODE_LOW_VOLTAGE, PM_DEV_ID_PWM_2, &enter_cfg, NULL); bk_pm_module_lv_sleep_state_clear(PM_DEV_ID_PWM_2); } #endif pwm_chan_init_common(sw_ch); pwm_hal_set_init_signal_low(&s_pwm[id].hal, hw_ch); /* duty ratio is 0% */ if (config->duty_cycle == 0) { s_pwm[id].chan_init_signal_level &= ~BIT(hw_ch); pwm_hal_set_flip_mode(&s_pwm[id].hal, hw_ch, 4); pwm_config.period_cycle = config->period_cycle; pwm_config.duty_cycle = 0; pwm_config.duty2_cycle = 0; pwm_config.duty3_cycle = 0; pwm_config.psc = config->psc; pwm_set_channel_config(sw_ch, &pwm_config); pwm_hal_set_single_chan_tim_enable(&s_pwm[id].hal, hw_ch, 1); return BK_OK; } /* duty ratio is 100% */ if (config->duty_cycle == config->period_cycle) { s_pwm[id].chan_init_signal_level |= BIT(hw_ch); pwm_hal_set_flip_mode(&s_pwm[id].hal, hw_ch, 2); pwm_config.period_cycle = config->period_cycle; pwm_config.duty_cycle = 0; pwm_config.duty2_cycle = 0; pwm_config.duty3_cycle = 0; pwm_config.psc = config->psc; pwm_set_channel_config(sw_ch, &pwm_config); pwm_hal_set_single_chan_tim_enable(&s_pwm[id].hal, hw_ch, 1); return BK_OK; } s_pwm[id].chan_init_signal_level &= ~BIT(hw_ch); pwm_hal_set_flip_mode(&s_pwm[id].hal, hw_ch, 1); pwm_config.period_cycle = config->period_cycle; pwm_config.duty_cycle = config->period_cycle - config->duty_cycle; pwm_config.duty2_cycle = config->period_cycle; pwm_config.duty3_cycle = 0; pwm_config.psc = config->psc; pwm_set_channel_config(sw_ch, &pwm_config); pwm_hal_set_single_chan_tim_enable(&s_pwm[id].hal, hw_ch, 1); return BK_OK; } bk_err_t bk_pwm_deinit(pwm_chan_t sw_ch) { pwm_id_t id; pwm_ch_t hw_ch; bk_pwm_stop(sw_ch); pwm_chan_deinit_common(sw_ch); pwm_sw_ch_to_hw_id_ch(sw_ch, &id, &hw_ch); #if CONFIG_PWM_PM_CB_SUPPORT if (id == PWM_ID_0) { bk_pm_sleep_unregister_cb(PM_MODE_LOW_VOLTAGE, PM_DEV_ID_PWM_1, true, false); bk_pm_module_vote_power_ctrl(PM_POWER_SUB_MODULE_NAME_BAKP_PWM0, PM_POWER_MODULE_STATE_OFF); } else if (id == PWM_ID_1) { bk_pm_sleep_unregister_cb(PM_MODE_LOW_VOLTAGE, PM_DEV_ID_PWM_2, true, false); bk_pm_module_vote_power_ctrl(PM_POWER_SUB_MODULE_NAME_BAKP_PWM1, PM_POWER_MODULE_STATE_OFF); } #endif pwm_hal_set_single_chan_tim_enable(&s_pwm[id].hal, hw_ch, 0); return BK_OK; } bk_err_t bk_pwm_start(pwm_chan_t sw_ch) { pwm_id_t id; pwm_ch_t hw_ch; pwm_sw_ch_to_hw_id_ch(sw_ch, &id, &hw_ch); PWM_RETURN_ON_CHAN_NOT_INIT(id, hw_ch); PWM_PM_CHECK_RESTORE(id); pwm_hal_set_chan_enable(&s_pwm[id].hal, hw_ch, true); return BK_OK; } bk_err_t bk_pwm_stop(pwm_chan_t sw_ch) { pwm_id_t unit_id; pwm_ch_t hw_ch; pwm_sw_ch_to_hw_id_ch(sw_ch, &unit_id, &hw_ch); PWM_RETURN_ON_CHAN_NOT_INIT(unit_id, hw_ch); PWM_PM_CHECK_RESTORE(unit_id); pwm_hal_set_chan_enable(&s_pwm[unit_id].hal, hw_ch, false); return BK_OK; } bk_err_t bk_pwm_register_isr(pwm_chan_t sw_ch, pwm_isr_t isr) { PWM_RETURN_ON_NOT_INIT(); pwm_id_t id; pwm_ch_t hw_ch; pwm_sw_ch_to_hw_id_ch(sw_ch, &id, &hw_ch); PWM_RETURN_ON_INVALID_CHAN(hw_ch); GLOBAL_INT_DECLARATION(); GLOBAL_INT_DISABLE(); s_pwm_isr[id][hw_ch] = isr; GLOBAL_INT_RESTORE(); return BK_OK; } /* The PWM channel should be started before interrupt can be enabled. */ bk_err_t bk_pwm_enable_interrupt(pwm_chan_t sw_ch) { pwm_id_t id; pwm_ch_t hw_ch; pwm_sw_ch_to_hw_id_ch(sw_ch, &id, &hw_ch); PWM_RETURN_ON_CHAN_NOT_INIT(id, hw_ch); PWM_RETURN_ON_INVALID_CHAN(hw_ch); pwm_chan_enable_interrupt_common(sw_ch); return BK_OK; } bk_err_t bk_pwm_disable_interrupt(pwm_chan_t sw_ch) { #if 0 pwm_id_t id; pwm_ch_t hw_ch; pwm_sw_ch_to_hw_id_ch(sw_ch, &id, &hw_ch); PWM_RETURN_ON_INVALID_CHAN(hw_ch); pwm_chan_disable_interrupt_common(hw_ch); #endif return BK_OK; } bk_err_t bk_pwm_set_period_duty(pwm_chan_t sw_ch, pwm_period_duty_config_t *config) { BK_RETURN_ON_NULL(config); pwm_id_t id; pwm_ch_t hw_ch; pwm_sw_ch_to_hw_id_ch(sw_ch, &id, &hw_ch); PWM_RETURN_ON_INVALID_CHAN(hw_ch); PWM_RETURN_ON_CHAN_NOT_INIT(id, hw_ch); pwm_hal_set_new_config_way(&s_pwm[id].hal, hw_ch, 1); /* duty ratio is 0% */ if (config->duty_cycle == 0) { s_pwm[id].chan_init_signal_level &= ~BIT(hw_ch); pwm_hal_set_flip_mode(&s_pwm[id].hal, hw_ch, 4); config->duty_cycle = 0; config->duty2_cycle = 0; config->duty3_cycle = 0; pwm_set_channel_config(sw_ch, config); return BK_OK; } /* duty ratio is 100% */ if (config->duty_cycle == config->period_cycle) { s_pwm[id].chan_init_signal_level |= BIT(hw_ch); pwm_hal_set_flip_mode(&s_pwm[id].hal, hw_ch, 2); config->duty_cycle = 0; config->duty2_cycle = 0; config->duty3_cycle = 0; pwm_set_channel_config(sw_ch, config); return BK_OK; } if (s_pwm[id].chan_init_signal_level & BIT(hw_ch)) { config->duty_cycle = config->duty_cycle; config->duty2_cycle = config->period_cycle; config->duty3_cycle = 0; } else { config->duty_cycle = config->period_cycle - config->duty_cycle; config->duty2_cycle = config->period_cycle; config->duty3_cycle = 0; } pwm_set_channel_config(sw_ch, config); pwm_hal_set_flip_mode(&s_pwm[id].hal, hw_ch, 1); return BK_OK; } static bool pwm_is_0_duty_ratio(pwm_chan_t sw_ch) { pwm_id_t id; pwm_ch_t hw_ch; pwm_sw_ch_to_hw_id_ch(sw_ch, &id, &hw_ch); return (pwm_hal_get_tim_ccr1(&s_pwm[id].hal, hw_ch) == 0); } static bool pwm_is_100_duty_ratio(pwm_chan_t sw_ch) { pwm_id_t id; pwm_ch_t hw_ch; pwm_sw_ch_to_hw_id_ch(sw_ch, &id, &hw_ch); return (pwm_hal_get_tim_ccr1(&s_pwm[id].hal, hw_ch) == pwm_hal_get_tim_arr(&s_pwm[id].hal, hw_ch)); } bk_err_t bk_pwm_set_init_signal_low(pwm_chan_t sw_ch) { pwm_id_t id; pwm_ch_t hw_ch; pwm_sw_ch_to_hw_id_ch(sw_ch, &id, &hw_ch); PWM_RETURN_ON_INVALID_CHAN(hw_ch); PWM_RETURN_ON_CHAN_NOT_INIT(id, hw_ch); if (pwm_is_100_duty_ratio(sw_ch)) pwm_hal_set_init_signal_high(&s_pwm[id].hal, hw_ch); else pwm_hal_set_init_signal_low(&s_pwm[id].hal, hw_ch); return BK_OK; } bk_err_t bk_pwm_set_init_signal_high(pwm_chan_t sw_ch) { pwm_id_t id; pwm_ch_t hw_ch; pwm_sw_ch_to_hw_id_ch(sw_ch, &id, &hw_ch); PWM_RETURN_ON_INVALID_CHAN(hw_ch); PWM_RETURN_ON_CHAN_NOT_INIT(id, hw_ch); if (pwm_is_0_duty_ratio(hw_ch)) pwm_hal_set_init_signal_low(&s_pwm[id].hal, hw_ch); else pwm_hal_set_init_signal_high(&s_pwm[id].hal, hw_ch); return BK_OK; } //TODO finish it bk_err_t bk_pwm_set_gpio(pwm_chan_t sw_ch, uint32 mode) { pwm_id_t id; pwm_ch_t hw_ch; pwm_sw_ch_to_hw_id_ch(sw_ch, &id, &hw_ch); PWM_RETURN_ON_INVALID_CHAN(hw_ch); PWM_RETURN_ON_CHAN_NOT_INIT(id, hw_ch); PWM_RETURN_ON_INVALID_GPIO_MODE(id); pwm_chan_init_gpio(sw_ch); return BK_OK; } bk_err_t bk_pwm_capture_init(pwm_chan_t sw_ch, const pwm_capture_init_config_t *config) { pwm_id_t id; pwm_ch_t hw_ch; pwm_sw_ch_to_hw_id_ch(sw_ch, &id, &hw_ch); pwm_chan_init_common(sw_ch); pwm_hal_set_pwm_ursx(&s_pwm[id].hal, hw_ch/2, 1) ; pwm_hal_set_timx_arr(&s_pwm[id].hal, hw_ch/2, 0xffffffff); // PWM_LOGE("TODO:%s,fixed psc", __func__); pwm_hal_set_prescaler_pscx(&s_pwm[id].hal, hw_ch/2, 25); pwm_hal_set_pwm_dier_ccxie(&s_pwm[id].hal, hw_ch, 1); //ccr2,5,8 pwm_hal_set_pwm_ccmr_chxe(&s_pwm[id].hal, hw_ch, 1); //channel 2 pwm_hal_set_timx_ccm(&s_pwm[id].hal, (hw_ch/2), 1); //CAPTURE mode pwm_hal_set_smsx(&s_pwm[id].hal, (hw_ch/2), 5) ; //clear timer every capture PWM_LOGE("TODO:%s,detect input type should change from hw_ch to xxx", __func__); pwm_hal_set_tsx(&s_pwm[id].hal, (hw_ch/2), hw_ch); #if 0 pwm_id_t id; pwm_ch_t hw_ch; pwm_sw_ch_to_hw_id_ch(sw_ch, &id, &hw_ch); PWM_RETURN_ON_INVALID_CHAN(hw_ch); PWM_RETURN_ON_CHAN_NOT_INIT(id, hw_ch); PWM_RETURN_ON_NOT_INIT(); BK_RETURN_ON_NULL(config); PWM_RETURN_ON_INVALID_CHAN(hw_ch); if (!pwm_hal_is_capture_edge_valid(config->edge)) return BK_ERR_PWM_CAPTURE_EDGE; pwm_chan_init_common(hw_ch); s_pwm_isr[id][hw_ch] = config->isr; pwm_hal_capture_config_t hal_config = { .edge = config->edge, }; return pwm_hal_init_capture(&s_pwm[id].hal, hw_ch, &hal_config); #endif return BK_OK; } bk_err_t bk_pwm_capture_deinit(pwm_chan_t sw_ch) { #if 0 pwm_id_t id; pwm_ch_t hw_ch; pwm_sw_ch_to_hw_id_ch(sw_ch, &id, &hw_ch); PWM_RETURN_ON_NOT_INIT(); PWM_RETURN_ON_INVALID_CHAN(hw_ch); pwm_chan_deinit_common(hw_ch); #endif return BK_OK; } bk_err_t bk_pwm_capture_start(pwm_chan_t sw_ch) { #if 1 pwm_id_t id; pwm_ch_t hw_ch; pwm_sw_ch_to_hw_id_ch(sw_ch, &id, &hw_ch); PWM_RETURN_ON_CHAN_NOT_INIT(id, hw_ch); PWM_RETURN_ON_INVALID_CHAN(hw_ch); pwm_hal_set_group_chan_tim_enable(&s_pwm[id].hal, hw_ch, 1); pwm_chan_enable_interrupt_common(sw_ch); //interrupt should be enabled after capture start #endif return BK_OK; } bk_err_t bk_pwm_capture_stop(pwm_chan_t sw_ch) { pwm_id_t id; pwm_ch_t hw_ch; pwm_sw_ch_to_hw_id_ch(sw_ch, &id, &hw_ch); PWM_RETURN_ON_CHAN_NOT_INIT(id, hw_ch); PWM_RETURN_ON_INVALID_CHAN(hw_ch); PWM_LOGE("TODO:%s:pwm_hal_stop_common", __func__); #if 0 pwm_hal_stop_common(&s_pwm[id].hal, hw_ch); #endif return BK_OK; } //It's up the caller to make sure the channel ID is correct uint32_t bk_pwm_capture_get_value(pwm_chan_t sw_ch) { #if 0 pwm_id_t id; pwm_ch_t hw_ch; pwm_sw_ch_to_hw_id_ch(sw_ch, &id, &hw_ch); return pwm_hal_get_capture_value(&s_pwm[id].hal, hw_ch); #endif return 0; } static pwm_group_t pwm_group_find_channel(pwm_chan_t sw_ch) { for (int i = 0; i < PWM_GROUP_NUM; i++) { if (s_pwm_groups[i].is_valid && ((s_pwm_groups[i].chan1 == sw_ch) || (s_pwm_groups[i].chan2 == sw_ch))) return i; } return PWM_GROUP_ID_INVALID; } static pwm_group_t pwm_group_find(pwm_chan_t chan1, pwm_chan_t chan2) { for (int i = 0; i < PWM_GROUP_NUM; i++) { if (s_pwm_groups[i].is_valid) { if ((s_pwm_groups[i].chan1 == chan1) && (s_pwm_groups[i].chan2 == chan2)) return i; if ((s_pwm_groups[i].chan1 == chan2) && (s_pwm_groups[i].chan2 == chan1)) return i; } } return PWM_GROUP_ID_INVALID; } static bool pwm_group_is_existed(pwm_group_t group) { if (group >= PWM_GROUP_NUM) { return false; } return (s_pwm_groups[group].is_valid == true); } static pwm_group_t pwm_group_add(pwm_chan_t chan1, pwm_chan_t chan2) { for (int i = 0; i < PWM_GROUP_NUM; i++) { if (!s_pwm_groups[i].is_valid) { s_pwm_groups[i].is_valid = true; s_pwm_groups[i].chan1 = chan1; s_pwm_groups[i].chan2 = chan2; return (i); } } return PWM_GROUP_ID_INVALID; } static void pwm_group_delete(pwm_group_t group) { if (group >= PWM_GROUP_NUM) { PWM_LOGE("pwm group delete error!\r\n"); return; } if (group < PWM_GROUP_NUM) { s_pwm_groups[group].is_valid = false; s_pwm_groups[group].chan1 = 0; s_pwm_groups[group].chan2 = 0; } } static bk_err_t pwm_group_validate_param(pwm_chan_t sw_ch1, pwm_chan_t sw_ch2, uint32_t period_cycle, uint32_t chan1_duty_cycle, uint32_t chan2_duty_cycle) { pwm_id_t id1, id2; pwm_ch_t hw_ch1, hw_ch2; pwm_sw_ch_to_hw_id_ch(sw_ch1, &id1, &hw_ch1); pwm_sw_ch_to_hw_id_ch(sw_ch2, &id2, &hw_ch2); PWM_RETURN_ON_INVALID_CHAN(hw_ch1); PWM_RETURN_ON_INVALID_CHAN(hw_ch2); if (sw_ch1 == sw_ch2) return BK_ERR_PWM_GROUP_SAME_CHAN; if (PWM_GROUP_ID_INVALID != pwm_group_find(sw_ch1, sw_ch2)) return BK_ERR_PWM_GROUP_EXIST; if (PWM_GROUP_ID_INVALID != pwm_group_find_channel(sw_ch1)) return BK_ERR_PWM_GROUP_CHAN_USED; if (PWM_GROUP_ID_INVALID != pwm_group_find_channel(sw_ch2)) return BK_ERR_PWM_GROUP_CHAN_USED; if (period_cycle == 0) return BK_ERR_PWM_GROUP_DUTY; if ((chan1_duty_cycle <= 1)) return BK_ERR_PWM_GROUP_DUTY; if (period_cycle < (chan1_duty_cycle + chan2_duty_cycle)) return BK_ERR_PWM_GROUP_DUTY; return BK_OK; } static const pwm_group_info_t s_default_groups[PWM_GROUP_NUM_PER_UNIT] = { {.chan1 = 0, .chan2 = 1}, {.chan1 = 2, .chan2 = 3}, {.chan1 = 4, .chan2 = 5}, }; static bool pwm_chan_is_default_group(pwm_chan_t chan1, pwm_chan_t chan2) { pwm_id_t id1, id2; pwm_ch_t hw_ch1, hw_ch2; pwm_sw_ch_to_hw_id_ch(chan1, &id1, &hw_ch1); pwm_sw_ch_to_hw_id_ch(chan2, &id2, &hw_ch2); if (id1 != id2) { return false; } for (int i = 0; i < PWM_GROUP_NUM_PER_UNIT; i++) { if ((s_default_groups[i].chan1 == hw_ch1 && s_default_groups[i].chan2 == hw_ch2) || (s_default_groups[i].chan1 == hw_ch2 && s_default_groups[i].chan2 == hw_ch1)) { return true; } } return false; } static void pwm_group_init_with_any_channel(const pwm_group_init_config_t *config, int dead_cycle) { pwm_id_t id1, id2; pwm_ch_t hw_ch1, hw_ch2; pwm_period_duty_config_t pwm_config; os_memset(&pwm_config, 0, sizeof(pwm_config)); pwm_sw_ch_to_hw_id_ch(config->chan1, &id1, &hw_ch1); pwm_sw_ch_to_hw_id_ch(config->chan2, &id2, &hw_ch2); pwm_config.period_cycle = config->period_cycle; pwm_config.duty_cycle = config->chan1_duty_cycle; pwm_config.duty2_cycle = 0; pwm_config.duty3_cycle = 0; pwm_set_channel_config(config->chan1, &pwm_config); pwm_hal_set_flip_mode(&s_pwm[id1].hal, hw_ch1, 3); pwm_hal_set_init_signal_high(&s_pwm[id1].hal, hw_ch1); pwm_config.duty_cycle = config->chan1_duty_cycle + dead_cycle; pwm_config.duty2_cycle = config->chan2_duty_cycle + pwm_config.duty_cycle; pwm_set_channel_config(config->chan2, &pwm_config); pwm_hal_set_flip_mode(&s_pwm[id2].hal, hw_ch2, 1); pwm_hal_set_init_signal_low(&s_pwm[id2].hal, hw_ch2); extern void delay_ms(UINT32 ms); delay_ms(50); } bk_err_t bk_pwm_group_init(const pwm_group_init_config_t *config, pwm_group_t *group) { PWM_RETURN_ON_NOT_INIT(); BK_RETURN_ON_NULL(group); uint32_t dead_cycle = 0; int ret; *group = PWM_GROUP_ID_INVALID; ret = pwm_group_validate_param(config->chan1, config->chan2, config->period_cycle, config->chan1_duty_cycle, config->chan2_duty_cycle); if (ret != BK_OK) { PWM_LOGE("pwm_group_validate_param, ret:-0x%x\r\n", -ret); return ret; } s_pwm_mode |= PWM_GROUP_MODE; dead_cycle = (config->period_cycle - config->chan1_duty_cycle - config->chan2_duty_cycle) >> 1; pwm_chan_init_common(config->chan1); pwm_chan_init_common(config->chan2); if (pwm_chan_is_default_group(config->chan1, config->chan2)) { PWM_LOGI("use hardware default group\r\n"); pwm_group_output_mode_config(config, 25, dead_cycle); } else { PWM_LOGI("configure channels into group mode manually\r\n"); pwm_group_init_with_any_channel(config, dead_cycle); } *group = pwm_group_add(config->chan1, config->chan2); PWM_LOGI("group(%d) period=%d chan1_duty=%d chan2_duty=%d, dead_cycle=%d\n", *group, config->period_cycle, config->chan1_duty_cycle, config->chan2_duty_cycle, dead_cycle); s_pwm_groups[*group].period_cycle = config->period_cycle; s_pwm_groups[*group].chan1_duty_cycle = config->chan1_duty_cycle; s_pwm_groups[*group].chan2_duty_cycle = config->chan2_duty_cycle; s_pwm_groups[*group].dead_cycle = dead_cycle; s_pwm_groups[*group].is_param_need_update = false; s_pwm_groups[*group].is_flip_mode_need_update = false; return BK_OK; } bk_err_t bk_pwm_group_deinit(pwm_group_t group) { if (!pwm_group_is_existed(group)) return BK_ERR_PWM_GROUP_NOT_EXIST; PWM_LOGI("group(%d) deinit\r\n", group); s_pwm_mode &= ~PWM_GROUP_MODE; bk_pm_module_vote_cpu_freq(PM_DEV_ID_PWM_2, PM_CPU_FRQ_DEFAULT); bk_pwm_group_stop(group); pwm_chan_deinit_common(s_pwm_groups[group].chan1); pwm_chan_deinit_common(s_pwm_groups[group].chan2); pwm_group_delete(group); return BK_OK; } bk_err_t bk_pwm_group_start(pwm_group_t group) { if (!pwm_group_is_existed(group)) { PWM_LOGE("pwm group(%d) not existed\r\n", group); return BK_ERR_PWM_GROUP_NOT_EXIST; } PWM_PM_CHECK_RESTORE(PWM_ID_0); PWM_PM_CHECK_RESTORE(PWM_ID_1); PWM_LOGI("group(%d) start\r\n", group); pwm_id_t id1, id2; pwm_ch_t hw_ch1, hw_ch2; pwm_sw_ch_to_hw_id_ch(s_pwm_groups[group].chan1, &id1, &hw_ch1); pwm_sw_ch_to_hw_id_ch(s_pwm_groups[group].chan2, &id2, &hw_ch2); PWM_LOGI("group(%d) chan1:%d, chan2:%d\r\n", group, s_pwm_groups[group].chan1, s_pwm_groups[group].chan2); pwm_hal_group_start(id1, id2, hw_ch1, hw_ch2); return BK_OK; } bk_err_t bk_pwm_group_stop(pwm_group_t group) { if (!pwm_group_is_existed(group)) { return BK_ERR_PWM_GROUP_NOT_EXIST; } PWM_PM_CHECK_RESTORE(PWM_ID_0); PWM_PM_CHECK_RESTORE(PWM_ID_1); PWM_LOGI("group(%d) stop\r\n", group); pwm_id_t id1, id2; pwm_ch_t hw_ch1, hw_ch2; pwm_sw_ch_to_hw_id_ch(s_pwm_groups[group].chan1, &id1, &hw_ch1); pwm_sw_ch_to_hw_id_ch(s_pwm_groups[group].chan2, &id2, &hw_ch2); pwm_hal_set_single_chan_tim_enable(&s_pwm[id1].hal, hw_ch1, 0); pwm_hal_set_single_chan_tim_enable(&s_pwm[id2].hal, hw_ch2, 0); return BK_OK; } bk_err_t bk_pwm_group_set_config(pwm_group_t group, const pwm_group_config_t *config) { PWM_RETURN_ON_NOT_INIT(); BK_RETURN_ON_NULL(config); if (!pwm_group_is_existed(group)) { return BK_ERR_PWM_GROUP_NOT_EXIST; } pwm_id_t id1, id2; pwm_ch_t hw_ch1, hw_ch2; uint32_t dead_cycle = 0; pwm_sw_ch_to_hw_id_ch(s_pwm_groups[group].chan1, &id1, &hw_ch1); pwm_sw_ch_to_hw_id_ch(s_pwm_groups[group].chan2, &id2, &hw_ch2); if (s_pwm_groups[group].chan1 == s_pwm_groups[group].chan2) return BK_ERR_PWM_GROUP_SAME_CHAN; if (config->period_cycle == 0 || config->period_cycle < (config->chan1_duty_cycle + config->chan2_duty_cycle)) return BK_ERR_PWM_GROUP_DUTY; if (((config->chan1_duty_cycle == 0) && (config->chan2_duty_cycle != config->period_cycle)) || ((config->chan2_duty_cycle == 0) && (config->chan1_duty_cycle != config->period_cycle))) { return BK_ERR_PWM_GROUP_DUTY; } bk_pm_module_vote_cpu_freq(PM_DEV_ID_PWM_2, PM_CPU_FRQ_120M); dead_cycle = (config->period_cycle - config->chan1_duty_cycle - config->chan2_duty_cycle) >> 1; pwm_hal_set_new_config_way(&s_pwm[id1].hal, hw_ch1, 1); pwm_hal_set_new_config_way(&s_pwm[id2].hal, hw_ch2, 1); uint32_t int_level = rtos_disable_int(); s_pwm_groups[group].period_cycle = config->period_cycle; s_pwm_groups[group].chan1_duty_cycle = config->chan1_duty_cycle; s_pwm_groups[group].chan2_duty_cycle = config->chan2_duty_cycle; s_pwm_groups[group].dead_cycle = dead_cycle; s_pwm_groups[group].is_param_need_update = true; s_pwm_groups[group].is_flip_mode_need_update = true; pwm_hal_set_uie(&s_pwm[id1].hal, hw_ch1, 1); rtos_enable_int(int_level); return BK_OK; } bk_err_t bk_pwm_group_set_init_signal(pwm_group_t group, const pwm_group_config_t *config) { return BK_OK; } bk_err_t bk_pwm_set_mode_timer(pwm_chan_t sw_ch) { #if 0 pwm_id_t id; pwm_ch_t hw_ch; pwm_sw_ch_to_hw_id_ch(sw_ch, &id, &hw_ch); PWM_RETURN_ON_INVALID_CHAN(hw_ch); pwm_hal_set_mode_timer(&s_pwm[id].hal, hw_ch); #endif return BK_OK; } #if CONFIG_PWM_PHASE_SHIFT static bk_err_t pwm_init_with_phase(pwm_chan_t sw_ch, const pwm_init_config_t *config) { PWM_RETURN_ON_NOT_INIT(); BK_RETURN_ON_NULL(config); pwm_id_t id; pwm_ch_t hw_ch; pwm_period_duty_config_t pwm_config; pwm_sw_ch_to_hw_id_ch(sw_ch, &id, &hw_ch); PWM_RETURN_ON_INVALID_CHAN(hw_ch); if ((config->duty_cycle == 1) || (config->duty_cycle > config->period_cycle) || (config->duty2_cycle > config->period_cycle) || (config->duty3_cycle > config->period_cycle)) { PWM_LOGE("invalid duty cycle!\r\n"); return BK_ERR_PWM_PERIOD_DUTY; } pwm_chan_init_common(sw_ch); pwm_hal_set_flip_mode(&s_pwm[id].hal, hw_ch, 1); /* duty ratio is 0% */ if (config->duty_cycle == 0 && config->duty2_cycle == 0 && config->duty3_cycle == 0) { pwm_config.period_cycle = config->period_cycle; pwm_config.duty_cycle = 0; pwm_config.duty2_cycle = 0; pwm_config.duty3_cycle = 0; pwm_config.psc = config->psc; pwm_hal_set_init_signal_low(&s_pwm[id].hal, hw_ch); pwm_set_channel_config(sw_ch, &pwm_config); pwm_hal_set_chan_enable(&s_pwm[id].hal, hw_ch, true); return BK_OK; } /* duty ratio is 100% */ if (config->duty_cycle == config->period_cycle && config->duty2_cycle == 0 && config->duty3_cycle == 0) { pwm_config.period_cycle = config->period_cycle; pwm_config.duty_cycle = 0; pwm_config.duty2_cycle = 0; pwm_config.duty3_cycle = 0; pwm_config.psc = config->psc; pwm_hal_set_init_signal_high(&s_pwm[id].hal, hw_ch); pwm_set_channel_config(sw_ch, &pwm_config); pwm_hal_set_chan_enable(&s_pwm[id].hal, hw_ch, true); return BK_OK; } pwm_config.period_cycle = config->period_cycle; pwm_config.duty_cycle = config->duty_cycle; pwm_config.duty2_cycle = config->duty2_cycle; pwm_config.duty3_cycle = config->duty3_cycle;; pwm_config.psc = config->psc; pwm_set_channel_config(sw_ch, &pwm_config); pwm_hal_set_chan_enable(&s_pwm[id].hal, hw_ch, true); return BK_OK; } static bk_err_t pwm_set_period_duty_with_phase(pwm_chan_t sw_ch, pwm_period_duty_config_t *config) { BK_RETURN_ON_NULL(config); if ((config->duty_cycle == 1) || (config->duty_cycle > config->period_cycle) || (config->duty2_cycle > config->period_cycle) || (config->duty3_cycle > config->period_cycle)) { PWM_LOGE("invalid duty cycle!\r\n"); return BK_ERR_PWM_PERIOD_DUTY; } pwm_id_t id; pwm_ch_t hw_ch; pwm_sw_ch_to_hw_id_ch(sw_ch, &id, &hw_ch); PWM_RETURN_ON_INVALID_CHAN(hw_ch); pwm_hal_set_flip_mode(&s_pwm[id].hal, hw_ch, 1); /* duty ratio is 0% */ if (config->duty_cycle == 0 && config->duty2_cycle == 0 && config->duty3_cycle == 0) { pwm_set_channel_config(sw_ch, config); pwm_hal_set_init_signal_low(&s_pwm[id].hal, hw_ch); return BK_OK; } /* duty ratio is 100% */ if (config->duty_cycle == config->period_cycle && config->duty2_cycle == 0 && config->duty3_cycle == 0) { config->duty_cycle = 0; config->duty2_cycle = 0; config->duty3_cycle = 0; pwm_set_channel_config(sw_ch, config); pwm_hal_set_init_signal_high(&s_pwm[id].hal, hw_ch); return BK_OK; } pwm_set_channel_config(sw_ch, config); return BK_OK; } static uint32_t pwm_phase_shift_find_first_valid_index(const pwm_phase_shift_config_t *shift_config) { for (uint32_t index = 0; index < shift_config->chan_num; index++) { if ((shift_config->duty_config[index].duty_cycle != 0) && (shift_config->duty_config[index].duty_cycle != shift_config->period_cycle)) { return index; } } return 0xff; } static void pwm_phase_shift_set_duty(void) { if (s_shift_config == NULL) { return; } __attribute__((unused)) bk_err_t ret = 0; pwm_id_t id; pwm_ch_t hw_ch; uint32_t ccr1 = 0, ccr2 = 0, duty_cycle = 0; pwm_period_duty_config_t pwm_config = {0}; uint32_t first_valid_index = pwm_phase_shift_find_first_valid_index(s_shift_config); pwm_sw_ch_to_hw_id_ch(s_shift_config->duty_config[0].chan, &id, &hw_ch); pwm_hal_set_uie(&s_pwm[id].hal, hw_ch, 0); for (uint32_t index = 0; index < s_shift_config->chan_num; index++) { pwm_sw_ch_to_hw_id_ch(s_shift_config->duty_config[index].chan, &id, &hw_ch); pwm_hal_set_new_config_way(&s_pwm[id].hal, hw_ch, 1); if (s_shift_config->duty_config[index].duty_cycle == 0) { pwm_config.period_cycle = s_shift_config->period_cycle; pwm_config.duty_cycle = 0; pwm_config.duty2_cycle = 0; pwm_config.duty3_cycle = 0; pwm_config.psc = s_shift_config->psc; ret = pwm_set_period_duty_with_phase(s_shift_config->duty_config[index].chan, &pwm_config); s_pwm[id].phase_shift_chan_init_level &= ~BIT(hw_ch); } else if (s_shift_config->duty_config[index].duty_cycle == s_shift_config->period_cycle) { pwm_config.period_cycle = s_shift_config->period_cycle; pwm_config.duty_cycle = s_shift_config->period_cycle; pwm_config.duty2_cycle = 0; pwm_config.duty3_cycle = 0; pwm_config.psc = s_shift_config->psc; ret = pwm_set_period_duty_with_phase(s_shift_config->duty_config[index].chan, &pwm_config); s_pwm[id].phase_shift_chan_init_level |= BIT(hw_ch); } else if (index == first_valid_index) { ccr1 = 0; ccr2 = ccr1 + s_shift_config->duty_config[index].duty_cycle; if ((s_pwm[id].phase_shift_chan_init_level & BIT(hw_ch)) == 0) { pwm_hal_set_init_signal_high(&s_pwm[id].hal, hw_ch); } pwm_config.period_cycle = s_shift_config->period_cycle; pwm_config.duty_cycle = s_shift_config->period_cycle; pwm_config.duty2_cycle = ccr2; pwm_config.duty3_cycle = 0; pwm_config.psc = s_shift_config->psc; ret = pwm_set_period_duty_with_phase(s_shift_config->duty_config[index].chan, &pwm_config); s_pwm[id].phase_shift_chan_init_level |= BIT(hw_ch); } else { ccr1 = ccr2; duty_cycle = s_shift_config->duty_config[index].duty_cycle; pwm_config.psc = s_shift_config->psc; pwm_config.period_cycle = s_shift_config->period_cycle; if ((ccr2 + duty_cycle) > s_shift_config->period_cycle) { if ((s_pwm[id].phase_shift_chan_init_level & BIT(hw_ch)) == 0) { pwm_hal_set_init_signal_high(&s_pwm[id].hal, hw_ch); } ccr2 = ccr2 + s_shift_config->duty_config[index].duty_cycle - s_shift_config->period_cycle; s_pwm[id].phase_shift_chan_init_level |= BIT(hw_ch); } else { if (s_pwm[id].phase_shift_chan_init_level & BIT(hw_ch)) { pwm_hal_set_init_signal_low(&s_pwm[id].hal, hw_ch); } ccr2 = ccr2 + s_shift_config->duty_config[index].duty_cycle; s_pwm[id].phase_shift_chan_init_level &= ~BIT(hw_ch); } pwm_config.duty_cycle = ccr1; pwm_config.duty2_cycle = ccr2; pwm_config.duty3_cycle = 0; ret = pwm_set_period_duty_with_phase(s_shift_config->duty_config[index].chan, &pwm_config); } } } bk_err_t bk_pwm_phase_shift_init(const pwm_phase_shift_config_t *shift_config) { BK_RETURN_ON_NULL(shift_config); PWM_RETURN_ON_INVALID_CHAN_NUM(shift_config); PWM_PHASE_SHIFT_RETURN_ON_INVALID_DUTY(shift_config); bk_err_t ret = 0; pwm_id_t id; pwm_ch_t hw_ch; uint32_t ccr1 = 0, ccr2 = 0, duty_cycle = 0; pwm_init_config_t pwm_init_config = {0}; s_shift_config = (pwm_phase_shift_config_t *)os_malloc(sizeof(pwm_phase_shift_config_t)); if (s_shift_config == NULL) { return BK_ERR_NO_MEM; } s_pwm_mode |= PWM_PHASE_SHIFT_MODE; os_memset(&s_phase_shift_multi_hw_ch, 0, sizeof(s_phase_shift_multi_hw_ch)); memcpy(s_shift_config, shift_config, sizeof(pwm_phase_shift_config_t)); uint32_t first_valid_index = pwm_phase_shift_find_first_valid_index(shift_config); s_phase_shift_first_valid_ch = shift_config->duty_config[0].chan; for (uint32_t index = 0; index < shift_config->chan_num; index++) { pwm_sw_ch_to_hw_id_ch(shift_config->duty_config[index].chan, &id, &hw_ch); if (shift_config->duty_config[index].duty_cycle == 0) { pwm_init_config.period_cycle = shift_config->period_cycle; pwm_init_config.duty_cycle = 0; pwm_init_config.duty2_cycle = 0; pwm_init_config.duty3_cycle = 0; pwm_init_config.psc = shift_config->psc; ret = pwm_init_with_phase(shift_config->duty_config[index].chan, &pwm_init_config); s_pwm[id].phase_shift_chan_init_level &= ~BIT(hw_ch); } else if (shift_config->duty_config[index].duty_cycle == shift_config->period_cycle) { pwm_init_config.period_cycle = shift_config->period_cycle; pwm_init_config.duty_cycle = shift_config->period_cycle; pwm_init_config.duty2_cycle = 0; pwm_init_config.duty3_cycle = 0; pwm_init_config.psc = shift_config->psc; ret = pwm_init_with_phase(shift_config->duty_config[index].chan, &pwm_init_config); s_pwm[id].phase_shift_chan_init_level |= BIT(hw_ch); } else if (index == first_valid_index) { ccr1 = 0; ccr2 = ccr1 + shift_config->duty_config[index].duty_cycle; pwm_hal_set_init_signal_high(&s_pwm[id].hal, hw_ch); pwm_init_config.period_cycle = shift_config->period_cycle; pwm_init_config.duty_cycle = shift_config->period_cycle; pwm_init_config.duty2_cycle = ccr2; pwm_init_config.duty3_cycle = 0; pwm_init_config.psc = shift_config->psc; ret = pwm_init_with_phase(shift_config->duty_config[index].chan, &pwm_init_config); s_pwm[id].phase_shift_chan_init_level |= BIT(hw_ch); } else { ccr1 = ccr2; duty_cycle = shift_config->duty_config[index].duty_cycle; if ((ccr2 + duty_cycle) > shift_config->period_cycle) { pwm_hal_set_init_signal_high(&s_pwm[id].hal, hw_ch); ccr2 = ccr2 + shift_config->duty_config[index].duty_cycle - shift_config->period_cycle; s_pwm[id].phase_shift_chan_init_level |= BIT(hw_ch); } else { pwm_hal_set_init_signal_low(&s_pwm[id].hal, hw_ch); ccr2 = ccr2 + shift_config->duty_config[index].duty_cycle; s_pwm[id].phase_shift_chan_init_level &= ~BIT(hw_ch); } pwm_init_config.period_cycle = shift_config->period_cycle; pwm_init_config.duty_cycle = ccr1; pwm_init_config.duty2_cycle = ccr2; pwm_init_config.duty3_cycle = 0; pwm_init_config.psc = shift_config->psc; ret = pwm_init_with_phase(shift_config->duty_config[index].chan, &pwm_init_config); } s_phase_shift_multi_hw_ch[id] |= BIT(hw_ch); } return ret; } bk_err_t bk_pwm_phase_shift_deinit(void) { if (s_shift_config) { os_free(s_shift_config); s_shift_config = NULL; } s_pwm_mode &= ~PWM_PHASE_SHIFT_MODE; os_memset(&s_phase_shift_multi_hw_ch, 0, sizeof(s_phase_shift_multi_hw_ch)); bk_pwm_phase_shift_stop(); return BK_OK; } bk_err_t bk_pwm_phase_shift_start(void) { pwm_id_t id; pwm_ch_t hw_ch; pwm_sw_ch_to_hw_id_ch(s_phase_shift_first_valid_ch, &id, &hw_ch); if (id == 1) { pwm_hal_set_multi_chan_tim_enable(&s_pwm[1].hal, s_phase_shift_multi_hw_ch[1], 1); pwm_hal_set_multi_chan_tim_enable(&s_pwm[0].hal, s_phase_shift_multi_hw_ch[0], 1); } else { pwm_hal_set_multi_chan_tim_enable(&s_pwm[0].hal, s_phase_shift_multi_hw_ch[0], 1); pwm_hal_set_multi_chan_tim_enable(&s_pwm[1].hal, s_phase_shift_multi_hw_ch[1], 1); } return BK_OK; } bk_err_t bk_pwm_phase_shift_stop(void) { for (uint32_t id = 0; id < SOC_PWM_UNIT_NUM; id++) { pwm_hal_set_multi_chan_tim_enable(&s_pwm[id].hal, s_phase_shift_multi_hw_ch[id], 0); } return BK_OK; } bk_err_t bk_pwm_phase_shift_set_duty_and_update(const pwm_phase_shift_config_t *shift_config) { BK_RETURN_ON_NULL(shift_config); PWM_RETURN_ON_INVALID_CHAN_NUM(shift_config); PWM_PHASE_SHIFT_RETURN_ON_INVALID_DUTY(shift_config); bk_err_t ret = 0; pwm_id_t id; pwm_ch_t hw_ch; bk_pm_module_vote_cpu_freq(PM_DEV_ID_PWM_2, PM_CPU_FRQ_120M); pwm_sw_ch_to_hw_id_ch(shift_config->duty_config[0].chan, &id, &hw_ch); uint32_t int_level = rtos_disable_int(); memcpy(s_shift_config, shift_config, sizeof(pwm_phase_shift_config_t)); pwm_hal_set_uie(&s_pwm[id].hal, hw_ch, 1); rtos_enable_int(int_level); return ret; } bk_err_t bk_pwm_phase_shift_set_duty(pwm_chan_t chan, uint32_t duty_cycle) { BK_RETURN_ON_NULL(s_shift_config); if (duty_cycle == 1 || duty_cycle > s_shift_config->period_cycle) { return BK_ERR_PWM_PERIOD_DUTY; } for (uint32_t index = 0; index < s_shift_config->chan_num; index++) { if (s_shift_config->duty_config[index].chan == chan) { s_shift_config->duty_config[index].duty_cycle = duty_cycle; return BK_OK;; } } return BK_ERR_PWM_CHAN_ID; } bk_err_t bk_pwm_phase_shift_update_duty(void) { BK_RETURN_ON_NULL(s_shift_config); pwm_id_t id; pwm_ch_t hw_ch; bk_pm_module_vote_cpu_freq(PM_DEV_ID_PWM_2, PM_CPU_FRQ_120M); pwm_sw_ch_to_hw_id_ch(s_shift_config->duty_config[0].chan, &id, &hw_ch); uint32_t int_level = rtos_disable_int(); pwm_hal_set_uie(&s_pwm[id].hal, hw_ch, 1); rtos_enable_int(int_level); return BK_OK; } #endif static void pwm_set_flip_mode(pwm_ch_t sw_ch, uint32_t mode) { pwm_ch_t hw_ch; pwm_id_t unit_id; pwm_sw_ch_to_hw_id_ch(sw_ch, &unit_id, &hw_ch); pwm_hal_set_flip_mode(&s_pwm[unit_id].hal, hw_ch, mode); } static uint32_t pwm_get_flip_mode(pwm_ch_t sw_ch) { pwm_ch_t hw_ch; pwm_id_t unit_id; pwm_sw_ch_to_hw_id_ch(sw_ch, &unit_id, &hw_ch); return pwm_hal_get_flip_mode(&s_pwm[unit_id].hal, hw_ch); } static uint32_t pwm_get_tim_arr(pwm_ch_t sw_ch) { pwm_ch_t hw_ch; pwm_id_t unit_id; pwm_sw_ch_to_hw_id_ch(sw_ch, &unit_id, &hw_ch); return pwm_hal_get_tim_arr(&s_pwm[unit_id].hal, hw_ch); } static void pwm_group_update_config(pwm_group_t group) { pwm_ch_t hw_ch; pwm_id_t unit_id; uint32_t chan1_flip_mode; uint32_t chan2_flip_mode; pwm_period_duty_config_t config1 = {0}; pwm_period_duty_config_t config2 = {0}; chan1_flip_mode = pwm_get_flip_mode(s_pwm_groups[group].chan1); chan2_flip_mode = pwm_get_flip_mode(s_pwm_groups[group].chan2); pwm_sw_ch_to_hw_id_ch(s_pwm_groups[group].chan1, &unit_id, &hw_ch); pwm_hal_t *hal = &s_pwm[unit_id].hal; /* chan1: duty ratio is 100%, chan2: duty ratio is 0% */ if (s_pwm_groups[group].period_cycle == s_pwm_groups[group].chan1_duty_cycle && s_pwm_groups[group].chan2_duty_cycle == 0) { if (chan1_flip_mode == 0x2 && chan2_flip_mode == 0x2) { pwm_hal_set_uie(hal, hw_ch, 0); pwm_set_flip_mode(s_pwm_groups[group].chan2, 4); pwm_set_flip_mode(s_pwm_groups[group].chan1, 4); s_pwm_groups[group].is_param_need_update = false; s_pwm_groups[group].is_flip_mode_need_update = false; return; } if (s_pwm_groups[group].is_flip_mode_need_update) { config1.period_cycle = pwm_get_tim_arr(s_pwm_groups[group].chan1) + 1; config1.duty_cycle = 0; config1.duty2_cycle = 0; config1.duty3_cycle = 0; config2.period_cycle = pwm_get_tim_arr(s_pwm_groups[group].chan2) + 1; config2.duty_cycle = 0; config2.duty2_cycle = 0; config2.duty3_cycle = 0; pwm_set_channel_config(s_pwm_groups[group].chan2, &config2); pwm_set_channel_config(s_pwm_groups[group].chan1, &config1); s_pwm_groups[group].is_flip_mode_need_update = false; } else { pwm_hal_set_uie(hal, hw_ch, 0); pwm_set_flip_mode(s_pwm_groups[group].chan1, 4); pwm_set_flip_mode(s_pwm_groups[group].chan2, 4); s_pwm_groups[group].is_param_need_update = false; } } else if ((s_pwm_groups[group].chan1_duty_cycle == 0) && (s_pwm_groups[group].chan2_duty_cycle == s_pwm_groups[group].period_cycle)) { /* chan1: duty ratio is 0%, chan2: duty ratio is 100% */ if (chan1_flip_mode == 0x4 && chan2_flip_mode == 0x4) { pwm_hal_set_uie(hal, hw_ch, 0); pwm_set_flip_mode(s_pwm_groups[group].chan1, 2); pwm_set_flip_mode(s_pwm_groups[group].chan2, 2); s_pwm_groups[group].is_param_need_update = false; s_pwm_groups[group].is_flip_mode_need_update = false; return; } if (s_pwm_groups[group].is_flip_mode_need_update) { pwm_set_flip_mode(s_pwm_groups[group].chan1, 1); pwm_set_flip_mode(s_pwm_groups[group].chan2, 3); s_pwm_groups[group].is_flip_mode_need_update = false; } else { pwm_hal_set_uie(hal, hw_ch, 0); pwm_set_flip_mode(s_pwm_groups[group].chan1, 2); pwm_set_flip_mode(s_pwm_groups[group].chan2, 2); s_pwm_groups[group].is_param_need_update = false; } } else if (chan1_flip_mode == 0x4 && chan2_flip_mode == 0x4) { if (s_pwm_groups[group].is_flip_mode_need_update) { config1.period_cycle = s_pwm_groups[group].period_cycle; config1.duty_cycle = s_pwm_groups[group].chan1_duty_cycle; config1.duty2_cycle = 0; config1.duty3_cycle = 0; config2.period_cycle = s_pwm_groups[group].period_cycle; config2.duty_cycle = s_pwm_groups[group].chan1_duty_cycle + s_pwm_groups[group].dead_cycle; config2.duty2_cycle = config2.duty_cycle + s_pwm_groups[group].chan2_duty_cycle; config2.duty3_cycle = 0; pwm_set_channel_config(s_pwm_groups[group].chan2, &config2); pwm_set_channel_config(s_pwm_groups[group].chan1, &config1); s_pwm_groups[group].is_flip_mode_need_update = false; } else { pwm_hal_set_uie(hal, hw_ch, 0); pwm_set_flip_mode(s_pwm_groups[group].chan1, 3); pwm_set_flip_mode(s_pwm_groups[group].chan2, 1); s_pwm_groups[group].is_param_need_update = false; } } else if (chan1_flip_mode == 0x2 && chan2_flip_mode == 0x2) { if (s_pwm_groups[group].is_flip_mode_need_update) { config1.period_cycle = s_pwm_groups[group].period_cycle; config1.duty_cycle = 0; config1.duty2_cycle = 0; config1.duty3_cycle = 0; config2.period_cycle = s_pwm_groups[group].period_cycle; config2.duty_cycle = s_pwm_groups[group].period_cycle - s_pwm_groups[group].dead_cycle; config2.duty2_cycle = 0; config2.duty3_cycle = 0; pwm_set_channel_config(s_pwm_groups[group].chan2, &config2); pwm_set_channel_config(s_pwm_groups[group].chan1, &config1); s_pwm_groups[group].is_flip_mode_need_update = false; } else { pwm_set_flip_mode(s_pwm_groups[group].chan1, 3); pwm_set_flip_mode(s_pwm_groups[group].chan2, 1); config1.period_cycle = s_pwm_groups[group].period_cycle; config1.duty_cycle = s_pwm_groups[group].chan1_duty_cycle; config1.duty2_cycle = 0; config1.duty3_cycle = 0; config2.period_cycle = s_pwm_groups[group].period_cycle; config2.duty_cycle = s_pwm_groups[group].chan1_duty_cycle + s_pwm_groups[group].dead_cycle; config2.duty2_cycle = config2.duty_cycle + s_pwm_groups[group].chan2_duty_cycle; config2.duty3_cycle = 0; pwm_set_channel_config(s_pwm_groups[group].chan2, &config2); pwm_set_channel_config(s_pwm_groups[group].chan1, &config1); pwm_hal_set_uie(hal, hw_ch, 0); s_pwm_groups[group].is_param_need_update = false; } } else { config1.period_cycle = s_pwm_groups[group].period_cycle; config1.duty_cycle = s_pwm_groups[group].chan1_duty_cycle; config1.duty2_cycle = 0; config1.duty3_cycle = 0; config2.period_cycle = s_pwm_groups[group].period_cycle; config2.duty_cycle = s_pwm_groups[group].chan1_duty_cycle + s_pwm_groups[group].dead_cycle; config2.duty2_cycle = config2.duty_cycle + s_pwm_groups[group].chan2_duty_cycle; config2.duty3_cycle = 0; pwm_set_channel_config(s_pwm_groups[group].chan2, &config2); pwm_set_channel_config(s_pwm_groups[group].chan1, &config1); pwm_set_flip_mode(s_pwm_groups[group].chan1, 3); pwm_set_flip_mode(s_pwm_groups[group].chan2, 1); pwm_hal_set_uie(hal, hw_ch, 0); s_pwm_groups[group].is_param_need_update = false; s_pwm_groups[group].is_flip_mode_need_update = false; } } static void pwm_isr_common(pwm_id_t id) { pwm_hal_t *hal = &s_pwm[id].hal; uint32_t int_status; pwm_ch_t hw_ch; pwm_id_t unit_id; int_status = pwm_hal_get_pwm_interrupt_status(hal); pwm_hal_clr_interrupt_status(hal, int_status); #if CONFIG_PWM_PHASE_SHIFT if (s_pwm_mode & PWM_PHASE_SHIFT_MODE) { pwm_phase_shift_set_duty(); } else #endif { for (pwm_group_t group = 0; group < PWM_GROUP_NUM; group++) { pwm_sw_ch_to_hw_id_ch(s_pwm_groups[group].chan1, &unit_id, &hw_ch); hal = &s_pwm[unit_id].hal; if (pwm_hal_is_uif_triggered(hal, hw_ch, int_status)) { if (s_pwm_groups[group].is_valid && s_pwm_groups[group].is_param_need_update) { pwm_group_update_config(group); } } } hal = &s_pwm[id].hal; for (hw_ch = 0; hw_ch < SOC_PWM_CHAN_NUM_PER_UNIT; hw_ch++) { if (pwm_hal_get_pwm_sr_ccxif(hal, hw_ch)) { if (s_pwm_isr[id][hw_ch]) s_pwm_isr[id][hw_ch](hw_ch); } } } } static void pwm0_isr(void) { PWM_LOGD("%s\n", __func__); pwm_isr_common(0); } static void pwm1_isr(void) { PWM_LOGD("%s\n", __func__); pwm_isr_common(1); }