/* * Copyright (c) 2019-2023 Beijing Hanwei Innovation Technology Ltd. Co. and * its subsidiaries and affiliates (collectly called MKSEMI). * * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. Redistributions in binary form, except as embedded into an MKSEMI * integrated circuit in a product or a software update for such product, * must reproduce the above copyright notice, this list of conditions and * the following disclaimer in the documentation and/or other materials * provided with the distribution. * * 3. Neither the name of MKSEMI nor the names of its contributors may be used * to endorse or promote products derived from this software without * specific prior written permission. * * 4. This software, with or without modification, must only be used with a * MKSEMI integrated circuit. * * 5. Any software provided in binary form under this license must not be * reverse engineered, decompiled, modified and/or disassembled. * * THIS SOFTWARE IS PROVIDED BY MKSEMI "AS IS" AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL MKSEMI OR CONTRIBUTORS BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "mk_pwm.h" #include "mk_trace.h" #include "mk_clock.h" #include "mk_reset.h" static struct PWM_HANDLE_T pwm_handle = { .base = PWM, .irq = PWM_IRQn, .general_prescale = 0, .int_en = false, .callback = NULL, }; int pwm_open(struct PWM_CFG_T *config) { // enable PWM clock clock_enable(CLOCK_PWM); reset_module(RESET_MODULE_PWM); if (config) { pwm_handle.general_prescale = config->general_prescale; pwm_handle.int_en = config->int_en; pwm_handle.callback = config->callback; } pwm_handle.base->CTRL = PWM_CTRL_GEN_PRESCALER(pwm_handle.general_prescale) | PWM_CTRL_GEN_PRESCALER_EN_MSK; #if PWM_INT_MODE_EN if (pwm_handle.int_en) { NVIC_SetPriority(pwm_handle.irq, IRQ_PRIORITY_NORMAL); NVIC_ClearPendingIRQ(pwm_handle.irq); NVIC_EnableIRQ(pwm_handle.irq); } #endif return DRV_OK; } int pwm_close(void) { // disable PWM pwm_handle.base->CTRL &= ~(PWM_CTRL_ALL_EN_MSK | PWM_CTRL_ALL_INT_EN_MSK); // disable PWM clock clock_disable(CLOCK_PWM); #if PWM_INT_MODE_EN if (pwm_handle.int_en) { NVIC_DisableIRQ(pwm_handle.irq); NVIC_ClearPendingIRQ(pwm_handle.irq); } #endif return DRV_OK; } int pwm_ch_enable(enum PWM_CH_T id, const struct PWM_CH_CFG_T *cfg) { if ((id >= PWM_MAX_NUM) || (cfg == NULL)) { return DRV_ERROR; } // configuration uint32_t val = PWM_PRESCALER(cfg->prescale) | PWM_WAVEFORM(cfg->waveform) | PWM_COUNTER(cfg->ratio * 255U / 100U); pwm_handle.base->CFG[id] = val; // phase if (id == PWM_ID0) { pwm_handle.base->PHASE[0] |= PWM_PHASE_PWM0_COUNTER(cfg->phase * 255U / 360U); } else if (id == PWM_ID1) { pwm_handle.base->PHASE[0] |= PWM_PHASE_PWM1_COUNTER(cfg->phase * 255U / 360U); } else if (id == PWM_ID2) { pwm_handle.base->PHASE[1] |= PWM_PHASE_PWM2_COUNTER(cfg->phase * 255U / 360U); } else if (id == PWM_ID3) { pwm_handle.base->PHASE[1] |= PWM_PHASE_PWM3_COUNTER(cfg->phase * 255U / 360U); } // enable val = pwm_handle.base->CTRL; if (cfg->pol_inv) { val |= PWM_CTRL_PWM0_POL_INV_MSK << id; } else { val &= ~(PWM_CTRL_PWM0_POL_INV_MSK << id); } if (cfg->int_en) { val |= PWM_CTRL_PWM0_INT_EN_MSK << id; } else { val &= ~(PWM_CTRL_PWM0_INT_EN_MSK << id); } val |= (PWM_CTRL_PWM0_EN_MSK << id); pwm_handle.base->CTRL = val; return DRV_OK; } int pwm_ch_disable(enum PWM_CH_T id) { if (id >= PWM_MAX_NUM) { return DRV_ERROR; } // disable PWM pwm_handle.base->CTRL &= ~((PWM_CTRL_PWM0_EN_MSK | PWM_CTRL_PWM0_INT_EN_MSK) << id); return DRV_OK; } void PWM_IRQHandler(void) { #if PWM_INT_MODE_EN uint32_t int_stat = pwm_handle.base->INTR_STATUS; // clear interrupt status pwm_handle.base->INTR_CLR = int_stat; for (uint8_t i = 0; i < PWM_MAX_NUM; i++) { if ((int_stat & (1U << i)) && (pwm_handle.callback)) { pwm_handle.callback(&i, 0); } } #endif }