/* * Licensed under ST Liberty SW License Agreement V2, (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.st.com/software_license_agreement_liberty_v2 * * 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. */ /** * @file FlexPWM_v1/pwm_lld.c * @brief SPC5xx low level PWM driver code. * * @addtogroup PWM * @{ */ #include "ch.h" #include "hal.h" #if HAL_USE_PWM || defined(__DOXYGEN__) /*===========================================================================*/ /* Driver exported variables. */ /*===========================================================================*/ /** * @brief PWMD1 driver identifier. * @note The driver PWMD1 allocates the complex timer TIM1 when enabled. */ #if SPC5_PWM_USE_SMOD0 || defined(__DOXYGEN__) PWMDriver PWMD1; #endif /** * @brief PWMD2 driver identifier. * @note The driver PWMD2 allocates the timer TIM2 when enabled. */ #if SPC5_PWM_USE_SMOD1 || defined(__DOXYGEN__) PWMDriver PWMD2; #endif /** * @brief PWMD3 driver identifier. * @note The driver PWMD3 allocates the timer TIM3 when enabled. */ #if SPC5_PWM_USE_SMOD2 || defined(__DOXYGEN__) PWMDriver PWMD3; #endif /** * @brief PWMD4 driver identifier. * @note The driver PWMD4 allocates the timer TIM4 when enabled. */ #if SPC5_PWM_USE_SMOD3 || defined(__DOXYGEN__) PWMDriver PWMD4; #endif /** * @brief PWMD5 driver identifier. * @note The driver PWMD5 allocates the timer TIM5 when enabled. */ #if SPC5_PWM_USE_SMOD4 || defined(__DOXYGEN__) PWMDriver PWMD5; #endif /** * @brief PWMD6 driver identifier. * @note The driver PWMD6 allocates the timer TIM6 when enabled. */ #if SPC5_PWM_USE_SMOD5 || defined(__DOXYGEN__) PWMDriver PWMD6; #endif /** * @brief PWMD7 driver identifier. * @note The driver PWMD7 allocates the timer TIM7 when enabled. */ #if SPC5_PWM_USE_SMOD6 || defined(__DOXYGEN__) PWMDriver PWMD7; #endif /** * @brief PWMD8 driver identifier. * @note The driver PWMD8 allocates the timer TIM8 when enabled. */ #if SPC5_PWM_USE_SMOD7 || defined(__DOXYGEN__) PWMDriver PWMD8; #endif /*===========================================================================*/ /* Driver local variables. */ /*===========================================================================*/ /** * @brief Number of active FlexPWM0 submodules. */ static uint32_t flexpwm_active_submodules0; /** * @brief Number of active FlexPWM1 submodules. */ static uint32_t flexpwm_active_submodules1; /*===========================================================================*/ /* Driver local functions. */ /*===========================================================================*/ /** * @brief Configures and activates the PWM peripheral submodule. * * @param[in] pwmp pointer to a @p PWMDriver object * @param[in] sid PWM submodule identifier * * @notapi */ void pwm_lld_start_submodule(PWMDriver *pwmp, uint8_t sid) { pwmcnt_t pwmperiod; uint32_t psc; /* Clears Status Register.*/ pwmp->flexpwmp->SUB[sid].STS.R = 0xFFFF; /* Clears LDOK and initializes the registers.*/ pwmp->flexpwmp->MCTRL.B.CLDOK |= 1U << sid; /* Setting PWM clock frequency and submodule prescaler.*/ psc = SPC5_FLEXPWM0_CLK / pwmp->config->frequency; chDbgAssert((psc <= 0xFFFF) && (((psc) * pwmp->config->frequency) == SPC5_FLEXPWM0_CLK) && ((psc == 1) || (psc == 2) || (psc == 4) || (psc == 8) || (psc == 16) || (psc == 32) || (psc == 64) || (psc == 128)), "pwm_lld_start_submodule(), #1", "invalid frequency"); switch (psc) { case 1: pwmp->flexpwmp->SUB[sid].CTRL.B.PRSC = SPC5_FLEXPWM_PSC_1; break; case 2: pwmp->flexpwmp->SUB[sid].CTRL.B.PRSC = SPC5_FLEXPWM_PSC_2; break; case 4: pwmp->flexpwmp->SUB[sid].CTRL.B.PRSC = SPC5_FLEXPWM_PSC_4; break; case 8: pwmp->flexpwmp->SUB[sid].CTRL.B.PRSC = SPC5_FLEXPWM_PSC_8; break; case 16: pwmp->flexpwmp->SUB[sid].CTRL.B.PRSC = SPC5_FLEXPWM_PSC_16; break; case 32: pwmp->flexpwmp->SUB[sid].CTRL.B.PRSC = SPC5_FLEXPWM_PSC_32; break; case 64: pwmp->flexpwmp->SUB[sid].CTRL.B.PRSC = SPC5_FLEXPWM_PSC_64; break; case 128: pwmp->flexpwmp->SUB[sid].CTRL.B.PRSC = SPC5_FLEXPWM_PSC_128; break; } /* Disables PWM FAULT function. */ pwmp->flexpwmp->SUB[sid].DISMAP.R = 0; pwmp->flexpwmp->SUB[sid].CTRL2.B.INDEP = 1U; /* Sets PWM period.*/ pwmperiod = pwmp->period; pwmp->flexpwmp->SUB[sid].INIT.R = ~(pwmperiod / 2) + 1U; pwmp->flexpwmp->SUB[sid].VAL[0].R = 0; pwmp->flexpwmp->SUB[sid].VAL[1].R = pwmperiod / 2; /* Sets the submodule channels.*/ switch (pwmp->config->mode & PWM_OUTPUT_MASK) { case EDGE_ALIGNED_PWM: /* Setting reloads.*/ pwmp->flexpwmp->SUB[sid].CTRL.B.HALF = 0; pwmp->flexpwmp->SUB[sid].CTRL.B.FULL = 1; /* Setting active front of PWM channels.*/ pwmp->flexpwmp->SUB[sid].VAL[2].R = ~(pwmperiod / 2) + 1U; pwmp->flexpwmp->SUB[sid].VAL[4].R = ~(pwmperiod / 2) + 1U; break; case CENTER_ALIGNED_PWM: /* Setting reloads.*/ pwmp->flexpwmp->SUB[sid].CTRL.B.HALF = 1; pwmp->flexpwmp->SUB[sid].CTRL.B.FULL = 0; break; default: ; } /* Polarities setup.*/ switch (pwmp->config->channels[0].mode & PWM_OUTPUT_MASK) { case PWM_OUTPUT_ACTIVE_LOW: pwmp->flexpwmp->SUB[sid].OCTRL.B.POLA = 1; /* Enables CHA mask and CHA.*/ pwmp->flexpwmp->MASK.B.MASKA |= 1U << sid; pwmp->flexpwmp->OUTEN.B.PWMA_EN |= 1U << sid; break; case PWM_OUTPUT_ACTIVE_HIGH: pwmp->flexpwmp->SUB[sid].OCTRL.B.POLA = 0; /* Enables CHA mask and CHA.*/ pwmp->flexpwmp->MASK.B.MASKA |= 1U << sid; pwmp->flexpwmp->OUTEN.B.PWMA_EN |= 1U << sid; break; case PWM_OUTPUT_DISABLED: /* Enables CHA mask.*/ pwmp->flexpwmp->MASK.B.MASKA |= 1U << sid; break; default: ; } switch (pwmp->config->channels[1].mode & PWM_OUTPUT_MASK) { case PWM_OUTPUT_ACTIVE_LOW: pwmp->flexpwmp->SUB[sid].OCTRL.B.POLB = 1; /* Enables CHB mask and CHB.*/ pwmp->flexpwmp->MASK.B.MASKB |= 1U << sid; pwmp->flexpwmp->OUTEN.B.PWMB_EN |= 1U << sid; break; case PWM_OUTPUT_ACTIVE_HIGH: pwmp->flexpwmp->SUB[sid].OCTRL.B.POLB = 0; /* Enables CHB mask and CHB.*/ pwmp->flexpwmp->MASK.B.MASKB |= 1U << sid; pwmp->flexpwmp->OUTEN.B.PWMB_EN |= 1U << sid; break; case PWM_OUTPUT_DISABLED: /* Enables CHB mask.*/ pwmp->flexpwmp->MASK.B.MASKB |= 1U << sid; break; default: ; } /* Complementary output setup.*/ switch (pwmp->config->channels[0].mode & PWM_COMPLEMENTARY_OUTPUT_MASK) { case PWM_COMPLEMENTARY_OUTPUT_ACTIVE_LOW: chDbgAssert(pwmp->config->channels[1].mode == PWM_OUTPUT_ACTIVE_LOW, "pwm_lld_start_submodule(), #2", "the PWM chB must be set in PWM_OUTPUT_ACTIVE_LOW"); pwmp->flexpwmp->SUB[sid].OCTRL.B.POLA = 1; pwmp->flexpwmp->SUB[sid].CTRL2.B.INDEP = 0; pwmp->flexpwmp->OUTEN.B.PWMA_EN |= 1U << sid; break; case PWM_COMPLEMENTARY_OUTPUT_ACTIVE_HIGH: chDbgAssert(pwmp->config->channels[1].mode == PWM_OUTPUT_ACTIVE_HIGH, "pwm_lld_start_submodule(), #3", "the PWM chB must be set in PWM_OUTPUT_ACTIVE_HIGH"); pwmp->flexpwmp->SUB[sid].CTRL2.B.INDEP = 0; pwmp->flexpwmp->OUTEN.B.PWMA_EN |= 1U << sid; break; default: ; } switch (pwmp->config->channels[1].mode & PWM_COMPLEMENTARY_OUTPUT_MASK) { case PWM_COMPLEMENTARY_OUTPUT_ACTIVE_LOW: chDbgAssert(pwmp->config->channels[0].mode == PWM_OUTPUT_ACTIVE_LOW, "pwm_lld_start_submodule(), #4", "the PWM chA must be set in PWM_OUTPUT_ACTIVE_LOW"); pwmp->flexpwmp->SUB[sid].CTRL2.B.INDEP = 0; pwmp->flexpwmp->MCTRL.B.IPOL &= ~ (1U << sid); pwmp->flexpwmp->SUB[sid].OCTRL.B.POLB = 1; pwmp->flexpwmp->OUTEN.B.PWMB_EN |= 1U << sid; break; case PWM_COMPLEMENTARY_OUTPUT_ACTIVE_HIGH: chDbgAssert(pwmp->config->channels[0].mode == PWM_OUTPUT_ACTIVE_HIGH, "pwm_lld_start_submodule(), #5", "the PWM chA must be set in PWM_OUTPUT_ACTIVE_HIGH"); pwmp->flexpwmp->SUB[sid].CTRL2.B.INDEP = 0; pwmp->flexpwmp->MCTRL.B.IPOL |= 1U << sid; pwmp->flexpwmp->OUTEN.B.PWMB_EN |= 1U << sid; break; default: ; } /* Sets the INIT and MASK registers.*/ pwmp->flexpwmp->SUB[sid].CTRL2.B.FRCEN = 1U; pwmp->flexpwmp->SUB[sid].CTRL2.B.FORCE = 1U; /* Updates SMOD registers and starts SMOD.*/ pwmp->flexpwmp->MCTRL.B.LDOK |= 1U << sid; pwmp->flexpwmp->MCTRL.B.RUN |= 1U << sid; } /** * @brief Enables a PWM channel of a submodule. * * @param[in] pwmp pointer to a @p PWMDriver object * @param[in] channel PWM channel identifier (0...PWM_CHANNELS-1) * @param[in] width PWM pulse width as clock pulses number * @param[in] sid PWM submodule id * * @notapi */ void pwm_lld_enable_submodule_channel(PWMDriver *pwmp, pwmchannel_t channel, pwmcnt_t width, uint8_t sid) { pwmcnt_t pwmperiod; int16_t nwidth; pwmperiod = pwmp->period; nwidth = width - (pwmperiod / 2); /* Clears LDOK.*/ pwmp->flexpwmp->MCTRL.B.CLDOK |= 1U << sid; /* Active the width interrupt.*/ if (channel == 0) { if (pwmp->config->channels[0].callback != NULL) { if ((pwmp->flexpwmp->SUB[sid].INTEN.B.CMPIE & 0x08) == 0) { pwmp->flexpwmp->SUB[sid].INTEN.B.CMPIE |= 0x08; } } /* Sets the channel width.*/ switch (pwmp->config->mode & PWM_OUTPUT_MASK) { case EDGE_ALIGNED_PWM: if (nwidth >= 0) pwmp->flexpwmp->SUB[sid].VAL[3].R = nwidth; else pwmp->flexpwmp->SUB[sid].VAL[3].R = ~((pwmperiod / 2) - width) + 1U; break; case CENTER_ALIGNED_PWM: pwmp->flexpwmp->SUB[sid].VAL[3].R = width / 2; pwmp->flexpwmp->SUB[sid].VAL[2].R = ~(width / 2) + 1U; break; default: ; } /* Removes the channel mask if it is necessary.*/ if ((pwmp->flexpwmp->MASK.B.MASKA & (1U << sid)) == 1) pwmp->flexpwmp->MASK.B.MASKA &= ~ (1U << sid); if ((pwmp->config->channels[0].mode & PWM_COMPLEMENTARY_OUTPUT_MASK) != 0) { pwmp->flexpwmp->MASK.B.MASKB &= ~ (1U << sid); } } /* Active the width interrupt.*/ else if (channel == 1) { if (pwmp->config->channels[1].callback != NULL) { if ((pwmp->flexpwmp->SUB[sid].INTEN.B.CMPIE & 0x20) == 0) { pwmp->flexpwmp->SUB[sid].INTEN.B.CMPIE |= 0x20; } } /* Sets the channel width.*/ switch (pwmp->config->mode & PWM_OUTPUT_MASK) { case EDGE_ALIGNED_PWM: if (nwidth >= 0) pwmp->flexpwmp->SUB[sid].VAL[5].R = nwidth; else pwmp->flexpwmp->SUB[sid].VAL[5].R = ~((pwmperiod / 2) - width) + 1U; break; case CENTER_ALIGNED_PWM: pwmp->flexpwmp->SUB[sid].VAL[5].R = width / 2; pwmp->flexpwmp->SUB[sid].VAL[4].R = ~(width / 2) + 1U; break; default: ; } /* Removes the channel mask if it is necessary.*/ if ((pwmp->flexpwmp->MASK.B.MASKB & (1U << sid)) == 1) pwmp->flexpwmp->MASK.B.MASKB &= ~ (1U << sid); if ((pwmp->config->channels[1].mode & PWM_COMPLEMENTARY_OUTPUT_MASK) != 0) { pwmp->flexpwmp->MASK.B.MASKA &= ~ (1U << sid); } } /* Active the periodic interrupt.*/ if (pwmp->flexpwmp->SUB[sid].INTEN.B.RIE != 1U) { if (pwmp->config->callback != NULL) { pwmp->flexpwmp->SUB[sid].INTEN.B.RIE = 1; } } /* Sets the MASK registers.*/ pwmp->flexpwmp->SUB[sid].CTRL2.B.FRCEN = 1U; pwmp->flexpwmp->SUB[sid].CTRL2.B.FORCE = 1U; /* Forces reload of the VALUE registers.*/ pwmp->flexpwmp->MCTRL.B.LDOK |= 1U << sid; } /** * @brief Disables a PWM channel of a submodule. * * @param[in] pwmp pointer to a @p PWMDriver object * @param[in] channel PWM channel identifier (0...PWM_CHANNELS-1) * @param[in] sid PWM submodule id * * @notapi */ void pwm_lld_disable_submodule_channel(PWMDriver *pwmp, pwmchannel_t channel, uint8_t sid) { pwmp->flexpwmp->MCTRL.B.CLDOK |= 1U << sid; /* Disable the width interrupt.*/ if (channel == 0) { if (pwmp->config->channels[0].callback != NULL) { if ((pwmp->flexpwmp->SUB[sid].INTEN.B.CMPIE & 0x08) == 1) { pwmp->flexpwmp->SUB[sid].INTEN.B.CMPIE &= 0x37; } } /* Active the channel mask.*/ if ((pwmp->config->channels[0].mode & PWM_COMPLEMENTARY_OUTPUT_MASK) != 0) { pwmp->flexpwmp->MASK.B.MASKA |= 1U << sid; pwmp->flexpwmp->MASK.B.MASKB |= 1U << sid; } else pwmp->flexpwmp->MASK.B.MASKA |= 1U << sid; } /* Disable the width interrupt.*/ else if (channel == 1) { if (pwmp->config->channels[1].callback != NULL) { if ((pwmp->flexpwmp->SUB[sid].INTEN.B.CMPIE & 0x20) == 1) { pwmp->flexpwmp->SUB[sid].INTEN.B.CMPIE &= 0x1F; } } /* Active the channel mask.*/ if ((pwmp->config->channels[1].mode & PWM_COMPLEMENTARY_OUTPUT_MASK) != 0) { pwmp->flexpwmp->MASK.B.MASKA |= 1U << sid; pwmp->flexpwmp->MASK.B.MASKB |= 1U << sid; } else pwmp->flexpwmp->MASK.B.MASKB |= 1U << sid; } /* Sets the MASK registers.*/ pwmp->flexpwmp->SUB[sid].CTRL2.B.FRCEN = 1U; pwmp->flexpwmp->SUB[sid].CTRL2.B.FORCE = 1U; /* Disable RIE interrupt to prevent reload interrupt.*/ if ((pwmp->flexpwmp->MASK.B.MASKA & (1U << sid)) && (pwmp->flexpwmp->MASK.B.MASKB & (1U << sid)) == 1) { pwmp->flexpwmp->SUB[sid].INTEN.B.RIE = 0; /* Clear the reload flag.*/ pwmp->flexpwmp->SUB[sid].STS.B.RF = 1U; } pwmp->flexpwmp->MCTRL.B.LDOK |= (1U << sid); } /** * @brief Common SMOD0...SMOD7 IRQ handler. * @note It is assumed that the various sources are only activated if the * associated callback pointer is not equal to @p NULL in order to not * perform an extra check in a potentially critical interrupt handler. * * @param[in] pwmp pointer to a @p PWMDriver object */ static void pwm_lld_serve_interrupt(PWMDriver *pwmp) { uint16_t sr; #if SPC5_PWM_USE_SMOD0 if (&PWMD1 == pwmp) { sr = pwmp->flexpwmp->SUB[0].STS.R & pwmp->flexpwmp->SUB[0].INTEN.R; if ((sr & SPC5_FLEXPWM_STS_CMPF3) != 0) { pwmp->flexpwmp->SUB[0].STS.B.CMPF |= 0x08; pwmp->config->channels[0].callback(pwmp); } if ((sr & SPC5_FLEXPWM_STS_CMPF5) != 0) { pwmp->flexpwmp->SUB[0].STS.B.CMPF |= 0x20; pwmp->config->channels[1].callback(pwmp); } if ((sr & SPC5_FLEXPWM_STS_RF) != 0) { pwmp->flexpwmp->SUB[0].STS.B.RF = 1U; pwmp->config->callback(pwmp); } } #endif #if SPC5_PWM_USE_SMOD1 if (&PWMD2 == pwmp) { sr = pwmp->flexpwmp->SUB[1].STS.R & pwmp->flexpwmp->SUB[1].INTEN.R; if ((sr & SPC5_FLEXPWM_STS_CMPF3) != 0) { pwmp->flexpwmp->SUB[1].STS.B.CMPF |= 0x08; pwmp->config->channels[0].callback(pwmp); } if ((sr & SPC5_FLEXPWM_STS_CMPF5) != 0) { pwmp->flexpwmp->SUB[1].STS.B.CMPF |= 0x20; pwmp->config->channels[1].callback(pwmp); } if ((sr & SPC5_FLEXPWM_STS_RF) != 0) { pwmp->flexpwmp->SUB[1].STS.B.RF = 1U; pwmp->config->callback(pwmp); } } #endif #if SPC5_PWM_USE_SMOD2 if (&PWMD3 == pwmp) { sr = pwmp->flexpwmp->SUB[2].STS.R & pwmp->flexpwmp->SUB[2].INTEN.R; if ((sr & SPC5_FLEXPWM_STS_CMPF3) != 0) { pwmp->flexpwmp->SUB[2].STS.B.CMPF |= 0x08; pwmp->config->channels[0].callback(pwmp); } if ((sr & SPC5_FLEXPWM_STS_CMPF5) != 0) { pwmp->flexpwmp->SUB[2].STS.B.CMPF |= 0x20; pwmp->config->channels[1].callback(pwmp); } if ((sr & SPC5_FLEXPWM_STS_RF) != 0) { pwmp->flexpwmp->SUB[2].STS.B.RF = 1U; pwmp->config->callback(pwmp); } } #endif #if SPC5_PWM_USE_SMOD3 if (&PWMD4 == pwmp) { sr = pwmp->flexpwmp->SUB[3].STS.R & pwmp->flexpwmp->SUB[3].INTEN.R; if ((sr & SPC5_FLEXPWM_STS_CMPF3) != 0) { pwmp->flexpwmp->SUB[3].STS.B.CMPF |= 0x08; pwmp->config->channels[0].callback(pwmp); } if ((sr & SPC5_FLEXPWM_STS_CMPF5) != 0) { pwmp->flexpwmp->SUB[3].STS.B.CMPF |= 0x20; pwmp->config->channels[1].callback(pwmp); } if ((sr & SPC5_FLEXPWM_STS_RF) != 0) { pwmp->flexpwmp->SUB[3].STS.B.RF = 1U; pwmp->config->callback(pwmp); } } #endif #if SPC5_PWM_USE_SMOD4 if (&PWMD5 == pwmp) { sr = pwmp->flexpwmp->SUB[0].STS.R & pwmp->flexpwmp->SUB[0].INTEN.R; if ((sr & SPC5_FLEXPWM_STS_CMPF3) != 0) { pwmp->flexpwmp->SUB[0].STS.B.CMPF |= 0x08; pwmp->config->channels[0].callback(pwmp); } if ((sr & SPC5_FLEXPWM_STS_CMPF5) != 0) { pwmp->flexpwmp->SUB[0].STS.B.CMPF |= 0x20; pwmp->config->channels[1].callback(pwmp); } if ((sr & SPC5_FLEXPWM_STS_RF) != 0) { pwmp->flexpwmp->SUB[0].STS.B.RF = 1U; pwmp->config->callback(pwmp); } } #endif #if SPC5_PWM_USE_SMOD5 if (&PWMD6 == pwmp) { sr = pwmp->flexpwmp->SUB[1].STS.R & pwmp->flexpwmp->SUB[1].INTEN.R; if ((sr & SPC5_FLEXPWM_STS_CMPF3) != 0) { pwmp->flexpwmp->SUB[1].STS.B.CMPF |= 0x08; pwmp->config->channels[0].callback(pwmp); } if ((sr & SPC5_FLEXPWM_STS_CMPF5) != 0) { pwmp->flexpwmp->SUB[1].STS.B.CMPF |= 0x20; pwmp->config->channels[1].callback(pwmp); } if ((sr & SPC5_FLEXPWM_STS_RF) != 0) { pwmp->flexpwmp->SUB[1].STS.B.RF = 1U; pwmp->config->callback(pwmp); } } #endif #if SPC5_PWM_USE_SMOD6 if (&PWMD7 == pwmp) { sr = pwmp->flexpwmp->SUB[2].STS.R & pwmp->flexpwmp->SUB[2].INTEN.R; if ((sr & SPC5_FLEXPWM_STS_CMPF3) != 0) { pwmp->flexpwmp->SUB[2].STS.B.CMPF |= 0x08; pwmp->config->channels[0].callback(pwmp); } if ((sr & SPC5_FLEXPWM_STS_CMPF5) != 0) { pwmp->flexpwmp->SUB[2].STS.B.CMPF |= 0x20; pwmp->config->channels[1].callback(pwmp); } if ((sr & SPC5_FLEXPWM_STS_RF) != 0) { pwmp->flexpwmp->SUB[2].STS.B.RF = 1U; pwmp->config->callback(pwmp); } } #endif #if SPC5_PWM_USE_SMOD7 if (&PWMD8 == pwmp) { sr = pwmp->flexpwmp->SUB[3].STS.R & pwmp->flexpwmp->SUB[3].INTEN.R; if ((sr & SPC5_FLEXPWM_STS_CMPF3) != 0) { pwmp->flexpwmp->SUB[3].STS.B.CMPF |= 0x08; pwmp->config->channels[0].callback(pwmp); } if ((sr & SPC5_FLEXPWM_STS_CMPF5) != 0) { pwmp->flexpwmp->SUB[3].STS.B.CMPF |= 0x20; pwmp->config->channels[1].callback(pwmp); } if ((sr & SPC5_FLEXPWM_STS_RF) != 0) { pwmp->flexpwmp->SUB[3].STS.B.RF = 1U; pwmp->config->callback(pwmp); } } #endif } /*===========================================================================*/ /* Driver interrupt handlers. */ /*===========================================================================*/ #if SPC5_PWM_USE_SMOD0 || defined(__DOXYGEN__) #if !defined(SPC5_FLEXPWM0_RF0_HANDLER) #error "SPC5_FLEXPWM0_RF0_HANDLER not defined" #endif /** * @brief FlexPWM0-SMOD0 RF0 interrupt handler. * * @isr */ CH_IRQ_HANDLER(SPC5_FLEXPWM0_RF0_HANDLER) { CH_IRQ_PROLOGUE(); pwm_lld_serve_interrupt(&PWMD1); CH_IRQ_EPILOGUE(); } #if !defined(SPC5_FLEXPWM0_COF0_HANDLER) #error "SPC5_FLEXPWM0_COF0_HANDLER not defined" #endif /** * @brief FlexPWM0-SMOD0 COF0 interrupt handler. * * @isr */ CH_IRQ_HANDLER(SPC5_FLEXPWM0_COF0_HANDLER) { CH_IRQ_PROLOGUE(); pwm_lld_serve_interrupt(&PWMD1); CH_IRQ_EPILOGUE(); } #endif #if SPC5_PWM_USE_SMOD1 || defined(__DOXYGEN__) #if !defined(SPC5_FLEXPWM0_RF1_HANDLER) #error "SPC5_FLEXPWM0_RF1_HANDLER not defined" #endif /** * @brief FlexPWM0-SMOD1 RF1 interrupt handler. * * @isr */ CH_IRQ_HANDLER(SPC5_FLEXPWM0_RF1_HANDLER) { CH_IRQ_PROLOGUE(); pwm_lld_serve_interrupt(&PWMD2); CH_IRQ_EPILOGUE(); } #if !defined(SPC5_FLEXPWM0_COF1_HANDLER) #error "SPC5_FLEXPWM0_COF1_HANDLER not defined" #endif /** * @brief FlexPWM0-SMOD1 COF1 interrupt handler. * * @isr */ CH_IRQ_HANDLER(SPC5_FLEXPWM0_COF1_HANDLER) { CH_IRQ_PROLOGUE(); pwm_lld_serve_interrupt(&PWMD2); CH_IRQ_EPILOGUE(); } #endif #if SPC5_PWM_USE_SMOD2 || defined(__DOXYGEN__) #if !defined(SPC5_FLEXPWM0_RF2_HANDLER) #error "SPC5_FLEXPWM0_RF2_HANDLER not defined" #endif /** * @brief FlexPWM0-SMOD2 RF2 interrupt handler. * * @isr */ CH_IRQ_HANDLER(SPC5_FLEXPWM0_RF2_HANDLER) { CH_IRQ_PROLOGUE(); pwm_lld_serve_interrupt(&PWMD3); CH_IRQ_EPILOGUE(); } #if !defined(SPC5_FLEXPWM0_COF2_HANDLER) #error "SPC5_FLEXPWM0_COF2_HANDLER not defined" #endif /** * @brief FlexPWM0-SMOD2 COF2 interrupt handler. * * @isr */ CH_IRQ_HANDLER(SPC5_FLEXPWM0_COF2_HANDLER) { CH_IRQ_PROLOGUE(); pwm_lld_serve_interrupt(&PWMD3); CH_IRQ_EPILOGUE(); } #endif #if SPC5_PWM_USE_SMOD3 || defined(__DOXYGEN__) #if !defined(SPC5_FLEXPWM0_RF3_HANDLER) #error "SPC5_FLEXPWM0_RF3_HANDLER not defined" #endif /** * @brief FlexPWM0-SMOD1 RF3 interrupt handler. * * @isr */ CH_IRQ_HANDLER(SPC5_FLEXPWM0_RF3_HANDLER) { CH_IRQ_PROLOGUE(); pwm_lld_serve_interrupt(&PWMD4); CH_IRQ_EPILOGUE(); } #if !defined(SPC5_FLEXPWM0_COF3_HANDLER) #error "SPC5_FLEXPWM0_COF3_HANDLER not defined" #endif /** * @brief FlexPWM0-SMOD1 COF3 interrupt handler. * * @isr */ CH_IRQ_HANDLER(SPC5_FLEXPWM0_COF3_HANDLER) { CH_IRQ_PROLOGUE(); pwm_lld_serve_interrupt(&PWMD4); CH_IRQ_EPILOGUE(); } #endif #if SPC5_PWM_USE_SMOD4 || defined(__DOXYGEN__) #if !defined(SPC5_FLEXPWM1_RF0_HANDLER) #error "SPC5_FLEXPWM0_RF1_HANDLER not defined" #endif /** * @brief FlexPWM1-SMOD0 RF0 interrupt handler. * * @isr */ CH_IRQ_HANDLER(SPC5_FLEXPWM1_RF0_HANDLER) { CH_IRQ_PROLOGUE(); pwm_lld_serve_interrupt(&PWMD5); CH_IRQ_EPILOGUE(); } #if !defined(SPC5_FLEXPWM1_COF0_HANDLER) #error "SPC5_FLEXPWM1_COF0_HANDLER not defined" #endif /** * @brief FlexPWM1-SMOD0 COF0 interrupt handler. * * @isr */ CH_IRQ_HANDLER(SPC5_FLEXPWM1_COF0_HANDLER) { CH_IRQ_PROLOGUE(); pwm_lld_serve_interrupt(&PWMD5); CH_IRQ_EPILOGUE(); } #endif #if SPC5_PWM_USE_SMOD5 || defined(__DOXYGEN__) #if !defined(SPC5_FLEXPWM1_RF1_HANDLER) #error "SPC5_FLEXPWM1_RF1_HANDLER not defined" #endif /** * @brief FlexPWM1-SMOD1 RF1 interrupt handler. * * @isr */ CH_IRQ_HANDLER(SPC5_FLEXPWM1_RF1_HANDLER) { CH_IRQ_PROLOGUE(); pwm_lld_serve_interrupt(&PWMD6); CH_IRQ_EPILOGUE(); } #if !defined(SPC5_FLEXPWM1_COF1_HANDLER) #error "SPC5_FLEXPWM1_COF1_HANDLER not defined" #endif /** * @brief FlexPWM1-SMOD1 COF1 interrupt handler. * * @isr */ CH_IRQ_HANDLER(SPC5_FLEXPWM1_COF1_HANDLER) { CH_IRQ_PROLOGUE(); pwm_lld_serve_interrupt(&PWMD6); CH_IRQ_EPILOGUE(); } #endif #if SPC5_PWM_USE_SMOD6 || defined(__DOXYGEN__) #if !defined(SPC5_FLEXPWM1_RF2_HANDLER) #error "SPC5_FLEXPWM1_RF2_HANDLER not defined" #endif /** * @brief FlexPWM1-SMOD2 RF2 interrupt handler. * * @isr */ CH_IRQ_HANDLER(SPC5_FLEXPWM1_RF2_HANDLER) { CH_IRQ_PROLOGUE(); pwm_lld_serve_interrupt(&PWMD7); CH_IRQ_EPILOGUE(); } #if !defined(SPC5_FLEXPWM1_COF2_HANDLER) #error "SPC5_FLEXPWM1_COF2_HANDLER not defined" #endif /** * @brief FlexPWM1-SMOD2 COF2 interrupt handler. * * @isr */ CH_IRQ_HANDLER(SPC5_FLEXPWM1_COF2_HANDLER) { CH_IRQ_PROLOGUE(); pwm_lld_serve_interrupt(&PWMD7); CH_IRQ_EPILOGUE(); } #endif #if SPC5_PWM_USE_SMOD7 || defined(__DOXYGEN__) #if !defined(SPC5_FLEXPWM1_RF3_HANDLER) #error "SPC5_FLEXPWM1_RF3_HANDLER not defined" #endif /** * @brief FlexPWM1-SMOD3 RF3 interrupt handler. * * @isr */ CH_IRQ_HANDLER(SPC5_FLEXPWM1_RF3_HANDLER) { CH_IRQ_PROLOGUE(); pwm_lld_serve_interrupt(&PWMD8); CH_IRQ_EPILOGUE(); } #if !defined(SPC5_FLEXPWM1_COF3_HANDLER) #error "SPC5_FLEXPWM1_COF3_HANDLER not defined" #endif /** * @brief FlexPWM1-SMOD3 COF3 interrupt handler. * * @isr */ CH_IRQ_HANDLER(SPC5_FLEXPWM1_COF3_HANDLER) { CH_IRQ_PROLOGUE(); pwm_lld_serve_interrupt(&PWMD8); CH_IRQ_EPILOGUE(); } #endif /*===========================================================================*/ /* Driver exported functions. */ /*===========================================================================*/ /** * @brief Low level PWM driver initialization. * * @notapi */ void pwm_lld_init(void) { /* FlexPWM initially all not in use.*/ flexpwm_active_submodules0 = 0; flexpwm_active_submodules1 = 0; #if (SPC5_PWM_USE_SMOD0) /* Driver initialization.*/ pwmObjectInit(&PWMD1); PWMD1.flexpwmp = &SPC5_FLEXPWM_0; INTC.PSR[SPC5_FLEXPWM0_RF0_NUMBER].R = SPC5_PWM_SMOD0_PRIORITY; INTC.PSR[SPC5_FLEXPWM0_COF0_NUMBER].R = SPC5_PWM_SMOD0_PRIORITY; INTC.PSR[SPC5_FLEXPWM0_CAF0_NUMBER].R = SPC5_PWM_SMOD0_PRIORITY; INTC.PSR[SPC5_FLEXPWM0_FFLAG_NUMBER].R = SPC5_PWM_SMOD0_PRIORITY; INTC.PSR[SPC5_FLEXPWM0_REF_NUMBER].R = SPC5_PWM_SMOD0_PRIORITY; #endif #if (SPC5_PWM_USE_SMOD1) /* Driver initialization.*/ pwmObjectInit(&PWMD2); PWMD2.flexpwmp = &SPC5_FLEXPWM_0; INTC.PSR[SPC5_FLEXPWM0_RF1_NUMBER].R = SPC5_PWM_SMOD1_PRIORITY; INTC.PSR[SPC5_FLEXPWM0_COF1_NUMBER].R = SPC5_PWM_SMOD1_PRIORITY; INTC.PSR[SPC5_FLEXPWM0_CAF1_NUMBER].R = SPC5_PWM_SMOD1_PRIORITY; INTC.PSR[SPC5_FLEXPWM0_FFLAG_NUMBER].R = SPC5_PWM_SMOD1_PRIORITY; INTC.PSR[SPC5_FLEXPWM0_REF_NUMBER].R = SPC5_PWM_SMOD1_PRIORITY; #endif #if (SPC5_PWM_USE_SMOD2) /* Driver initialization.*/ pwmObjectInit(&PWMD3); PWMD3.flexpwmp = &SPC5_FLEXPWM_0; INTC.PSR[SPC5_FLEXPWM0_RF2_NUMBER].R = SPC5_PWM_SMOD2_PRIORITY; INTC.PSR[SPC5_FLEXPWM0_COF2_NUMBER].R = SPC5_PWM_SMOD2_PRIORITY; INTC.PSR[SPC5_FLEXPWM0_CAF2_NUMBER].R = SPC5_PWM_SMOD2_PRIORITY; INTC.PSR[SPC5_FLEXPWM0_FFLAG_NUMBER].R = SPC5_PWM_SMOD2_PRIORITY; INTC.PSR[SPC5_FLEXPWM0_REF_NUMBER].R = SPC5_PWM_SMOD2_PRIORITY; #endif #if (SPC5_PWM_USE_SMOD3) /* Driver initialization.*/ pwmObjectInit(&PWMD4); PWMD4.flexpwmp = &SPC5_FLEXPWM_0; INTC.PSR[SPC5_FLEXPWM0_RF3_NUMBER].R = SPC5_PWM_SMOD3_PRIORITY; INTC.PSR[SPC5_FLEXPWM0_COF3_NUMBER].R = SPC5_PWM_SMOD3_PRIORITY; INTC.PSR[SPC5_FLEXPWM0_CAF3_NUMBER].R = SPC5_PWM_SMOD3_PRIORITY; INTC.PSR[SPC5_FLEXPWM0_FFLAG_NUMBER].R = SPC5_PWM_SMOD3_PRIORITY; INTC.PSR[SPC5_FLEXPWM0_REF_NUMBER].R = SPC5_PWM_SMOD3_PRIORITY; #endif #if (SPC5_PWM_USE_SMOD4) /* Driver initialization.*/ pwmObjectInit(&PWMD5); PWMD5.flexpwmp = &SPC5_FLEXPWM_1; INTC.PSR[SPC5_FLEXPWM1_RF0_NUMBER].R = SPC5_PWM_SMOD4_PRIORITY; INTC.PSR[SPC5_FLEXPWM1_COF0_NUMBER].R = SPC5_PWM_SMOD4_PRIORITY; INTC.PSR[SPC5_FLEXPWM1_CAF0_NUMBER].R = SPC5_PWM_SMOD4_PRIORITY; INTC.PSR[SPC5_FLEXPWM1_FFLAG_NUMBER].R = SPC5_PWM_SMOD4_PRIORITY; INTC.PSR[SPC5_FLEXPWM1_REF_NUMBER].R = SPC5_PWM_SMOD4_PRIORITY; #endif #if (SPC5_PWM_USE_SMOD5) /* Driver initialization.*/ pwmObjectInit(&PWMD6); PWMD6.flexpwmp = &SPC5_FLEXPWM_1; INTC.PSR[SPC5_FLEXPWM1_RF1_NUMBER].R = SPC5_PWM_SMOD5_PRIORITY; INTC.PSR[SPC5_FLEXPWM1_COF1_NUMBER].R = SPC5_PWM_SMOD5_PRIORITY; INTC.PSR[SPC5_FLEXPWM1_CAF1_NUMBER].R = SPC5_PWM_SMOD5_PRIORITY; INTC.PSR[SPC5_FLEXPWM1_FFLAG_NUMBER].R = SPC5_PWM_SMOD5_PRIORITY; INTC.PSR[SPC5_FLEXPWM1_REF_NUMBER].R = SPC5_PWM_SMOD5_PRIORITY; #endif #if (SPC5_PWM_USE_SMOD6) /* Driver initialization.*/ pwmObjectInit(&PWMD7); PWMD7.flexpwmp = &SPC5_FLEXPWM_1; INTC.PSR[SPC5_FLEXPWM1_RF2_NUMBER].R = SPC5_PWM_SMOD6_PRIORITY; INTC.PSR[SPC5_FLEXPWM1_COF2_NUMBER].R = SPC5_PWM_SMOD6_PRIORITY; INTC.PSR[SPC5_FLEXPWM1_CAF2_NUMBER].R = SPC5_PWM_SMOD6_PRIORITY; INTC.PSR[SPC5_FLEXPWM1_FFLAG_NUMBER].R = SPC5_PWM_SMOD6_PRIORITY; INTC.PSR[SPC5_FLEXPWM1_REF_NUMBER].R = SPC5_PWM_SMOD6_PRIORITY; #endif #if (SPC5_PWM_USE_SMOD7) /* Driver initialization.*/ pwmObjectInit(&PWMD8); PWMD8.flexpwmp = &SPC5_FLEXPWM_1; INTC.PSR[SPC5_FLEXPWM1_RF3_NUMBER].R = SPC5_PWM_SMOD7_PRIORITY; INTC.PSR[SPC5_FLEXPWM1_COF3_NUMBER].R = SPC5_PWM_SMOD7_PRIORITY; INTC.PSR[SPC5_FLEXPWM1_CAF3_NUMBER].R = SPC5_PWM_SMOD7_PRIORITY; INTC.PSR[SPC5_FLEXPWM1_FFLAG_NUMBER].R = SPC5_PWM_SMOD7_PRIORITY; INTC.PSR[SPC5_FLEXPWM1_REF_NUMBER].R = SPC5_PWM_SMOD7_PRIORITY; #endif } /** * @brief Configures and activates the PWM peripheral. * @note Starting a driver that is already in the @p PWM_READY state * disables all the active channels. * * @param[in] pwmp pointer to a @p PWMDriver object * * @notapi */ void pwm_lld_start(PWMDriver *pwmp) { chDbgAssert(flexpwm_active_submodules0 < 5, "pwm_lld_start(), #1", "too many submodules"); chDbgAssert(flexpwm_active_submodules1 < 5, "pwm_lld_start(), #2", "too many submodules"); if (pwmp->state == PWM_STOP) { #if SPC5_PWM_USE_SMOD0 if (&PWMD1 == pwmp) { flexpwm_active_submodules0++; } #endif /* SPC5_PWM_USE_SMOD0 */ #if SPC5_PWM_USE_SMOD1 if (&PWMD2 == pwmp) { flexpwm_active_submodules0++; } #endif /* SPC5_PWM_USE_SMOD1 */ #if SPC5_PWM_USE_SMOD2 if (&PWMD3 == pwmp) { flexpwm_active_submodules0++; } #endif /* SPC5_PWM_USE_SMOD2 */ #if SPC5_PWM_USE_SMOD3 if (&PWMD4 == pwmp) { flexpwm_active_submodules0++; } #endif /* SPC5_PWM_USE_SMOD3 */ #if SPC5_PWM_USE_SMOD4 if (&PWMD5 == pwmp) { flexpwm_active_submodules1++; } #endif /* SPC5_PWM_USE_SMOD4 */ #if SPC5_PWM_USE_SMOD5 if (&PWMD6 == pwmp) { flexpwm_active_submodules1++; } #endif /* SPC5_PWM_USE_SMOD5 */ #if SPC5_PWM_USE_SMOD6 if (&PWMD7 == pwmp) { flexpwm_active_submodules1++; } #endif /* SPC5_PWM_USE_SMOD6 */ #if SPC5_PWM_USE_SMOD7 if (&PWMD8 == pwmp) { flexpwm_active_submodules1++; } #endif /* SPC5_PWM_USE_SMOD7 */ /** * If this is the first FlexPWM0 submodule * activated then the FlexPWM0 is enabled. */ #if SPC5_PWM_USE_FLEXPWM0 /* Set Peripheral Clock.*/ if (flexpwm_active_submodules0 == 1) { halSPCSetPeripheralClockMode(SPC5_FLEXPWM0_PCTL, SPC5_PWM_FLEXPWM0_START_PCTL); } #endif #if SPC5_PWM_USE_FLEXPWM1 /* Set Peripheral Clock.*/ if (flexpwm_active_submodules1 == 1) { halSPCSetPeripheralClockMode(SPC5_FLEXPWM1_PCTL, SPC5_PWM_FLEXPWM1_START_PCTL); } #endif #if SPC5_PWM_USE_SMOD0 if (&PWMD1 == pwmp) { pwm_lld_start_submodule(pwmp, 0); } #endif #if SPC5_PWM_USE_SMOD1 if (&PWMD2 == pwmp) { pwm_lld_start_submodule(pwmp, 1); } #endif #if SPC5_PWM_USE_SMOD2 if (&PWMD3 == pwmp) { pwm_lld_start_submodule(pwmp, 2); } #endif #if SPC5_PWM_USE_SMOD3 if (&PWMD4 == pwmp) { pwm_lld_start_submodule(pwmp, 3); } #endif #if SPC5_PWM_USE_SMOD4 if (&PWMD5 == pwmp) { pwm_lld_start_submodule(pwmp, 0); } #endif #if SPC5_PWM_USE_SMOD5 if (&PWMD6 == pwmp) { pwm_lld_start_submodule(pwmp, 1); } #endif #if SPC5_PWM_USE_SMOD6 if (&PWMD7 == pwmp) { pwm_lld_start_submodule(pwmp, 2); } #endif #if SPC5_PWM_USE_SMOD7 if (&PWMD8 == pwmp) { pwm_lld_start_submodule(pwmp, 3); } #endif } else { /* Driver re-configuration scenario, it must be stopped first.*/ #if SPC5_PWM_USE_SMOD0 if (&PWMD1 == pwmp) { /* Disable the interrupts.*/ pwmp->flexpwmp->SUB[0].INTEN.R = 0; /* Disable the submodule.*/ pwmp->flexpwmp->OUTEN.B.PWMA_EN &= 0xE; pwmp->flexpwmp->OUTEN.B.PWMB_EN &= 0xE; /* Active the submodule masks.*/ pwmp->flexpwmp->MASK.B.MASKA &= 0xE; pwmp->flexpwmp->MASK.B.MASKB &= 0xE; /* Sets the MASK registers.*/ pwmp->flexpwmp->SUB[0].CTRL2.B.FRCEN = 1U; pwmp->flexpwmp->SUB[0].CTRL2.B.FORCE = 1U; } #endif #if SPC5_PWM_USE_SMOD1 if (&PWMD2 == pwmp) { /* Disable the interrupts.*/ pwmp->flexpwmp->SUB[1].INTEN.R = 0; /* Disable the submodule.*/ pwmp->flexpwmp->OUTEN.B.PWMA_EN &= 0xD; pwmp->flexpwmp->OUTEN.B.PWMB_EN &= 0xD; /* Active the submodule masks.*/ pwmp->flexpwmp->MASK.B.MASKA &= 0xD; pwmp->flexpwmp->MASK.B.MASKB &= 0xD; /* Sets the MASK registers.*/ pwmp->flexpwmp->SUB[1].CTRL2.B.FRCEN = 1U; pwmp->flexpwmp->SUB[1].CTRL2.B.FORCE = 1U; } #endif #if SPC5_PWM_USE_SMOD2 if (&PWMD3 == pwmp) { /* Disable the interrupts.*/ pwmp->flexpwmp->SUB[2].INTEN.R = 0; /* Disable the submodule.*/ pwmp->flexpwmp->OUTEN.B.PWMA_EN &= 0xB; pwmp->flexpwmp->OUTEN.B.PWMB_EN &= 0xB; /* Active the submodule masks.*/ pwmp->flexpwmp->MASK.B.MASKA &= 0xB; pwmp->flexpwmp->MASK.B.MASKB &= 0xB; /* Sets the MASK registers.*/ pwmp->flexpwmp->SUB[2].CTRL2.B.FRCEN = 1U; pwmp->flexpwmp->SUB[2].CTRL2.B.FORCE = 1U; } #endif #if SPC5_PWM_USE_SMOD3 if (&PWMD4 == pwmp) { /* Disable the interrupts.*/ pwmp->flexpwmp->SUB[3].INTEN.R = 0; /* Disable the submodule.*/ pwmp->flexpwmp->OUTEN.B.PWMA_EN &= 0x7; pwmp->flexpwmp->OUTEN.B.PWMB_EN &= 0x7; /* Active the submodule masks.*/ pwmp->flexpwmp->MASK.B.MASKA &= 0x7; pwmp->flexpwmp->MASK.B.MASKB &= 0x7; /* Sets the MASK registers.*/ pwmp->flexpwmp->SUB[3].CTRL2.B.FRCEN = 1U; pwmp->flexpwmp->SUB[3].CTRL2.B.FORCE = 1U; } #endif #if SPC5_PWM_USE_SMOD4 if (&PWMD5 == pwmp) { /* Disable the interrupts.*/ pwmp->flexpwmp->SUB[0].INTEN.R = 0; /* Disable the submodule.*/ pwmp->flexpwmp->OUTEN.B.PWMA_EN &= 0xE; pwmp->flexpwmp->OUTEN.B.PWMB_EN &= 0xE; /* Active the submodule masks.*/ pwmp->flexpwmp->MASK.B.MASKA &= 0xE; pwmp->flexpwmp->MASK.B.MASKB &= 0xE; /* Sets the MASK registers.*/ pwmp->flexpwmp->SUB[0].CTRL2.B.FRCEN = 1U; pwmp->flexpwmp->SUB[0].CTRL2.B.FORCE = 1U; } #endif #if SPC5_PWM_USE_SMOD5 if (&PWMD6 == pwmp) { /* Disable the interrupts.*/ pwmp->flexpwmp->SUB[1].INTEN.R = 0; /* Disable the submodule.*/ pwmp->flexpwmp->OUTEN.B.PWMA_EN &= 0xD; pwmp->flexpwmp->OUTEN.B.PWMB_EN &= 0xD; /* Active the submodule masks.*/ pwmp->flexpwmp->MASK.B.MASKA &= 0xD; pwmp->flexpwmp->MASK.B.MASKB &= 0xD; /* Sets the MASK registers.*/ pwmp->flexpwmp->SUB[1].CTRL2.B.FRCEN = 1U; pwmp->flexpwmp->SUB[1].CTRL2.B.FORCE = 1U; } #endif #if SPC5_PWM_USE_SMOD6 if (&PWMD7 == pwmp) { /* Disable the interrupts.*/ pwmp->flexpwmp->SUB[2].INTEN.R = 0; /* Disable the submodule.*/ pwmp->flexpwmp->OUTEN.B.PWMA_EN &= 0xB; pwmp->flexpwmp->OUTEN.B.PWMB_EN &= 0xB; /* Active the submodule masks.*/ pwmp->flexpwmp->MASK.B.MASKA &= 0xB; pwmp->flexpwmp->MASK.B.MASKB &= 0xB; /* Sets the MASK registers.*/ pwmp->flexpwmp->SUB[2].CTRL2.B.FRCEN = 1U; pwmp->flexpwmp->SUB[2].CTRL2.B.FORCE = 1U; } #endif #if SPC5_PWM_USE_SMOD7 if (&PWMD8 == pwmp) { /* Disable the interrupts.*/ pwmp->flexpwmp->SUB[3].INTEN.R = 0; /* Disable the submodule.*/ pwmp->flexpwmp->OUTEN.B.PWMA_EN &= 0x7; pwmp->flexpwmp->OUTEN.B.PWMB_EN &= 0x7; /* Active the submodule masks.*/ pwmp->flexpwmp->MASK.B.MASKA &= 0x7; pwmp->flexpwmp->MASK.B.MASKB &= 0x7; /* Sets the MASK registers.*/ pwmp->flexpwmp->SUB[3].CTRL2.B.FRCEN = 1U; pwmp->flexpwmp->SUB[3].CTRL2.B.FORCE = 1U; } #endif } } /** * @brief Deactivates the PWM peripheral. * * @param[in] pwmp pointer to a @p PWMDriver object * * @notapi */ void pwm_lld_stop(PWMDriver *pwmp) { chDbgAssert(flexpwm_active_submodules0 < 5, "pwm_lld_stop(), #1", "too many submodules"); chDbgAssert(flexpwm_active_submodules1 < 5, "pwm_lld_stop(), #2", "too many submodules"); /* If in ready state then disables the PWM clock.*/ if (pwmp->state == PWM_READY) { #if SPC5_PWM_USE_SMOD0 if (&PWMD1 == pwmp) { flexpwm_active_submodules0--; } #endif /* SPC5_PWM_USE_SMOD0 */ #if SPC5_PWM_USE_SMOD1 if (&PWMD2 == pwmp) { flexpwm_active_submodules0--; } #endif /* SPC5_PWM_USE_SMOD1 */ #if SPC5_PWM_USE_SMOD2 if (&PWMD3 == pwmp) { flexpwm_active_submodules0--; } #endif /* SPC5_PWM_USE_SMOD2 */ #if SPC5_PWM_USE_SMOD3 if (&PWMD4 == pwmp) { flexpwm_active_submodules0--; } #endif /* SPC5_PWM_USE_SMOD3 */ #if SPC5_PWM_USE_SMOD4 if (&PWMD5 == pwmp) { flexpwm_active_submodules1--; } #endif /* SPC5_PWM_USE_SMOD4 */ #if SPC5_PWM_USE_SMOD5 if (&PWMD6 == pwmp) { flexpwm_active_submodules1--; } #endif /* SPC5_PWM_USE_SMOD5 */ #if SPC5_PWM_USE_SMOD6 if (&PWMD7 == pwmp) { flexpwm_active_submodules1--; } #endif /* SPC5_PWM_USE_SMOD6 */ #if SPC5_PWM_USE_SMOD7 if (&PWMD8 == pwmp) { flexpwm_active_submodules1--; } #endif /* SPC5_PWM_USE_SMOD7 */ #if SPC5_PWM_USE_SMOD0 if (&PWMD1 == pwmp) { /* SMOD stop.*/ pwmp->flexpwmp->MCTRL.B.CLDOK |= 1U; pwmp->flexpwmp->SUB[0].INTEN.R = 0; pwmp->flexpwmp->SUB[0].STS.R = 0xFFFF; pwmp->flexpwmp->OUTEN.B.PWMA_EN &= 0xE; pwmp->flexpwmp->OUTEN.B.PWMB_EN &= 0xE; pwmp->flexpwmp->MCTRL.B.RUN &= 0xE; } #endif #if SPC5_PWM_USE_SMOD1 if (&PWMD2 == pwmp) { /* SMOD stop.*/ pwmp->flexpwmp->MCTRL.B.CLDOK |= 2U; pwmp->flexpwmp->SUB[1].INTEN.R = 0; pwmp->flexpwmp->SUB[1].STS.R = 0xFFFF; pwmp->flexpwmp->OUTEN.B.PWMA_EN &= 0xD; pwmp->flexpwmp->OUTEN.B.PWMB_EN &= 0xD; pwmp->flexpwmp->MCTRL.B.RUN &= 0xD; } #endif #if SPC5_PWM_USE_SMOD2 if (&PWMD3 == pwmp) { /* SMOD stop.*/ pwmp->flexpwmp->MCTRL.B.CLDOK |= 4U; pwmp->flexpwmp->SUB[2].INTEN.R = 0; pwmp->flexpwmp->SUB[2].STS.R = 0xFFFF; pwmp->flexpwmp->OUTEN.B.PWMA_EN &= 0xB; pwmp->flexpwmp->OUTEN.B.PWMB_EN &= 0xB; pwmp->flexpwmp->MCTRL.B.RUN &= 0xB; } #endif #if SPC5_PWM_USE_SMOD3 if (&PWMD4 == pwmp) { /* SMOD stop.*/ pwmp->flexpwmp->MCTRL.B.CLDOK |= 8U; pwmp->flexpwmp->SUB[3].INTEN.R = 0; pwmp->flexpwmp->SUB[3].STS.R = 0xFFFF; pwmp->flexpwmp->OUTEN.B.PWMA_EN &= 0x7; pwmp->flexpwmp->OUTEN.B.PWMB_EN &= 0x7; pwmp->flexpwmp->MCTRL.B.RUN &= 0x7; } #endif #if SPC5_PWM_USE_SMOD4 if (&PWMD5 == pwmp) { /* SMOD stop.*/ pwmp->flexpwmp->MCTRL.B.CLDOK |= 1U; pwmp->flexpwmp->SUB[0].INTEN.R = 0; pwmp->flexpwmp->SUB[0].STS.R = 0xFFFF; pwmp->flexpwmp->OUTEN.B.PWMA_EN &= 0xE; pwmp->flexpwmp->OUTEN.B.PWMB_EN &= 0xE; pwmp->flexpwmp->MCTRL.B.RUN &= 0xE; } #endif #if SPC5_PWM_USE_SMOD5 if (&PWMD6 == pwmp) { /* SMOD stop.*/ pwmp->flexpwmp->MCTRL.B.CLDOK |= 2U; pwmp->flexpwmp->SUB[1].INTEN.R = 0; pwmp->flexpwmp->SUB[1].STS.R = 0xFFFF; pwmp->flexpwmp->OUTEN.B.PWMA_EN &= 0xD; pwmp->flexpwmp->OUTEN.B.PWMB_EN &= 0xD; pwmp->flexpwmp->MCTRL.B.RUN &= 0xD; } #endif #if SPC5_PWM_USE_SMOD6 if (&PWMD7 == pwmp) { /* SMOD stop.*/ pwmp->flexpwmp->MCTRL.B.CLDOK |= 4U; pwmp->flexpwmp->SUB[2].INTEN.R = 0; pwmp->flexpwmp->SUB[2].STS.R = 0xFFFF; pwmp->flexpwmp->OUTEN.B.PWMA_EN &= 0xB; pwmp->flexpwmp->OUTEN.B.PWMB_EN &= 0xB; pwmp->flexpwmp->MCTRL.B.RUN &= 0xB; } #endif #if SPC5_PWM_USE_SMOD7 if (&PWMD8 == pwmp) { /* SMOD stop.*/ pwmp->flexpwmp->MCTRL.B.CLDOK |= 8U; pwmp->flexpwmp->SUB[3].INTEN.R = 0; pwmp->flexpwmp->SUB[3].STS.R = 0xFFFF; pwmp->flexpwmp->OUTEN.B.PWMA_EN &= 0x7; pwmp->flexpwmp->OUTEN.B.PWMB_EN &= 0x7; pwmp->flexpwmp->MCTRL.B.RUN &= 0x7; } #endif #if SPC5_PWM_USE_FLEXPWM0 /* Disable peripheral clock if there is not an activated module.*/ if (flexpwm_active_submodules0 == 0) { halSPCSetPeripheralClockMode(SPC5_FLEXPWM0_PCTL, SPC5_PWM_FLEXPWM0_STOP_PCTL); } #endif #if SPC5_PWM_USE_FLEXPWM1 /* Disable peripheral clock if there is not an activated module.*/ if (flexpwm_active_submodules1 == 0) { halSPCSetPeripheralClockMode(SPC5_FLEXPWM1_PCTL, SPC5_PWM_FLEXPWM1_STOP_PCTL); } #endif } } /** * @brief Enables a PWM channel. * @pre The PWM unit must have been activated using @p pwmStart(). * @post The channel is active using the specified configuration. * @note The function has effect at the next cycle start. * * @param[in] pwmp pointer to a @p PWMDriver object * @param[in] channel PWM channel identifier (0...PWM_CHANNELS-1) * @param[in] width PWM pulse width as clock pulses number * * @notapi */ void pwm_lld_enable_channel(PWMDriver *pwmp, pwmchannel_t channel, pwmcnt_t width) { #if SPC5_PWM_USE_SMOD0 if (&PWMD1 == pwmp) { pwm_lld_enable_submodule_channel(pwmp, channel, width, 0); } #endif #if SPC5_PWM_USE_SMOD1 if (&PWMD2 == pwmp) { pwm_lld_enable_submodule_channel(pwmp, channel, width, 1); } #endif #if SPC5_PWM_USE_SMOD2 if (&PWMD3 == pwmp) { pwm_lld_enable_submodule_channel(pwmp, channel, width, 2); } #endif #if SPC5_PWM_USE_SMOD3 if (&PWMD4 == pwmp) { pwm_lld_enable_submodule_channel(pwmp, channel, width, 3); } #endif #if SPC5_PWM_USE_SMOD4 if (&PWMD5 == pwmp) { pwm_lld_enable_submodule_channel(pwmp, channel, width, 0); } #endif #if SPC5_PWM_USE_SMOD5 if (&PWMD6 == pwmp) { pwm_lld_enable_submodule_channel(pwmp, channel, width, 1); } #endif #if SPC5_PWM_USE_SMOD6 if (&PWMD7 == pwmp) { pwm_lld_enable_submodule_channel(pwmp, channel, width, 2); } #endif #if SPC5_PWM_USE_SMOD7 if (&PWMD8 == pwmp) { pwm_lld_enable_submodule_channel(pwmp, channel, width, 3); } #endif } /** * @brief Disables a PWM channel. * @pre The PWM unit must have been activated using @p pwmStart(). * @post The channel is disabled and its output line returned to the * idle state. * @note The function has effect at the next cycle start. * * @param[in] pwmp pointer to a @p PWMDriver object * @param[in] channel PWM channel identifier (0...PWM_CHANNELS-1) * * @notapi */ void pwm_lld_disable_channel(PWMDriver *pwmp, pwmchannel_t channel) { #if SPC5_PWM_USE_SMOD0 if (&PWMD1 == pwmp) { pwm_lld_disable_submodule_channel(pwmp, channel, 0); } #endif #if SPC5_PWM_USE_SMOD1 if (&PWMD2 == pwmp) { pwm_lld_disable_submodule_channel(pwmp, channel, 1); } #endif #if SPC5_PWM_USE_SMOD2 if (&PWMD3 == pwmp) { pwm_lld_disable_submodule_channel(pwmp, channel, 2); } #endif #if SPC5_PWM_USE_SMOD3 if (&PWMD4 == pwmp) { pwm_lld_disable_submodule_channel(pwmp, channel, 3); } #endif #if SPC5_PWM_USE_SMOD4 if (&PWMD5 == pwmp) { pwm_lld_disable_submodule_channel(pwmp, channel, 0); } #endif #if SPC5_PWM_USE_SMOD5 if (&PWMD6 == pwmp) { pwm_lld_disable_submodule_channel(pwmp, channel, 1); } #endif #if SPC5_PWM_USE_SMOD6 if (&PWMD7 == pwmp) { pwm_lld_disable_submodule_channel(pwmp, channel, 2); } #endif #if SPC5_PWM_USE_SMOD7 if (&PWMD8 == pwmp) { pwm_lld_disable_submodule_channel(pwmp, channel, 3); } #endif } /** * @brief Changes the period the PWM peripheral. * @details This function changes the period of a PWM unit that has already * been activated using @p pwmStart(). * @pre The PWM unit must have been activated using @p pwmStart(). * @post The PWM unit period is changed to the new value. * @note The function has effect at the next cycle start. * @note If a period is specified that is shorter than the pulse width * programmed in one of the channels then the behavior is not * guaranteed. * * @param[in] pwmp pointer to a @p PWMDriver object * @param[in] period new cycle time in ticks * * @notapi */ void pwm_lld_change_period(PWMDriver *pwmp, pwmcnt_t period) { pwmcnt_t pwmperiod = period; #if SPC5_PWM_USE_SMOD0 if (&PWMD1 == pwmp) { pwmp->flexpwmp->MCTRL.B.CLDOK |= 1U; /* Setting PWM period.*/ pwmp->flexpwmp->SUB[0].INIT.R = ~(pwmperiod / 2) + 1U; pwmp->flexpwmp->SUB[0].VAL[0].R = 0; pwmp->flexpwmp->SUB[0].VAL[1].R = pwmperiod / 2; switch (pwmp->config->mode & PWM_OUTPUT_MASK) { case EDGE_ALIGNED_PWM: /* Setting active front of PWM channels.*/ pwmp->flexpwmp->SUB[0].VAL[2].R = ~(pwmperiod / 2) + 1U; pwmp->flexpwmp->SUB[0].VAL[4].R = ~(pwmperiod / 2) + 1U; break; default: ; } pwmp->flexpwmp->MCTRL.B.LDOK |= 1U; } #endif #if SPC5_PWM_USE_SMOD1 if (&PWMD2 == pwmp) { pwmp->flexpwmp->MCTRL.B.CLDOK |= 2U; /* Setting PWM period.*/ pwmp->flexpwmp->SUB[1].INIT.R = ~(pwmperiod / 2) + 1U; pwmp->flexpwmp->SUB[1].VAL[0].R = 0; pwmp->flexpwmp->SUB[1].VAL[1].R = pwmperiod / 2; switch (pwmp->config->mode & PWM_OUTPUT_MASK) { case EDGE_ALIGNED_PWM: /* Setting active front of PWM channels.*/ pwmp->flexpwmp->SUB[1].VAL[2].R = ~(pwmperiod / 2) + 1U; pwmp->flexpwmp->SUB[1].VAL[4].R = ~(pwmperiod / 2) + 1U; break; default: ; } pwmp->flexpwmp->MCTRL.B.LDOK |= 2U; } #endif #if SPC5_PWM_USE_SMOD2 if (&PWMD3 == pwmp) { pwmp->flexpwmp->MCTRL.B.CLDOK |= 4U; /* Setting PWM period.*/ pwmp->flexpwmp->SUB[2].INIT.R = ~(pwmperiod / 2) + 1U; pwmp->flexpwmp->SUB[2].VAL[0].R = 0; pwmp->flexpwmp->SUB[2].VAL[1].R = pwmperiod / 2; switch (pwmp->config->mode & PWM_OUTPUT_MASK) { case EDGE_ALIGNED_PWM: /* Setting active front of PWM channels.*/ pwmp->flexpwmp->SUB[2].VAL[2].R = ~(pwmperiod / 2) + 1U; pwmp->flexpwmp->SUB[2].VAL[4].R = ~(pwmperiod / 2) + 1U; break; default: ; } pwmp->flexpwmp->MCTRL.B.LDOK |= 4U; } #endif #if SPC5_PWM_USE_SMOD3 if (&PWMD4 == pwmp) { pwmp->flexpwmp->MCTRL.B.CLDOK |= 8U; /* Setting PWM period.*/ pwmp->flexpwmp->SUB[3].INIT.R = ~(pwmperiod / 2) + 1U; pwmp->flexpwmp->SUB[3].VAL[0].R = 0; pwmp->flexpwmp->SUB[3].VAL[1].R = pwmperiod / 2; switch (pwmp->config->mode & PWM_OUTPUT_MASK) { case EDGE_ALIGNED_PWM: /* Setting active front of PWM channels.*/ pwmp->flexpwmp->SUB[3].VAL[2].R = ~(pwmperiod / 2) + 1U; pwmp->flexpwmp->SUB[3].VAL[4].R = ~(pwmperiod / 2) + 1U; break; default: ; } pwmp->flexpwmp->MCTRL.B.LDOK |= 8U; } #endif #if SPC5_PWM_USE_SMOD4 if (&PWMD5 == pwmp) { pwmp->flexpwmp->MCTRL.B.CLDOK |= 1U; /* Setting PWM period.*/ pwmp->flexpwmp->SUB[0].INIT.R = ~(pwmperiod / 2) + 1U; pwmp->flexpwmp->SUB[0].VAL[0].R = 0; pwmp->flexpwmp->SUB[0].VAL[1].R = pwmperiod / 2; switch (pwmp->config->mode & PWM_OUTPUT_MASK) { case EDGE_ALIGNED_PWM: /* Setting active front of PWM channels.*/ pwmp->flexpwmp->SUB[0].VAL[2].R = ~(pwmperiod / 2) + 1U; pwmp->flexpwmp->SUB[0].VAL[4].R = ~(pwmperiod / 2) + 1U; break; default: ; } pwmp->flexpwmp->MCTRL.B.LDOK |= 1U; } #endif #if SPC5_PWM_USE_SMOD5 if (&PWMD6 == pwmp) { pwmp->flexpwmp->MCTRL.B.CLDOK |= 2U; /* Setting PWM period.*/ pwmp->flexpwmp->SUB[1].INIT.R = ~(pwmperiod / 2) + 1U; pwmp->flexpwmp->SUB[1].VAL[0].R = 0; pwmp->flexpwmp->SUB[1].VAL[1].R = pwmperiod / 2; switch (pwmp->config->mode & PWM_OUTPUT_MASK) { case EDGE_ALIGNED_PWM: /* Setting active front of PWM channels.*/ pwmp->flexpwmp->SUB[1].VAL[2].R = ~(pwmperiod / 2) + 1U; pwmp->flexpwmp->SUB[1].VAL[4].R = ~(pwmperiod / 2) + 1U; break; default: ; } pwmp->flexpwmp->MCTRL.B.LDOK |= 2U; } #endif #if SPC5_PWM_USE_SMOD6 if (&PWMD7 == pwmp) { pwmp->flexpwmp->MCTRL.B.CLDOK |= 4U; /* Setting PWM period.*/ pwmp->flexpwmp->SUB[2].INIT.R = ~(pwmperiod / 2) + 1U; pwmp->flexpwmp->SUB[2].VAL[0].R = 0; pwmp->flexpwmp->SUB[2].VAL[1].R = pwmperiod / 2; switch (pwmp->config->mode & PWM_OUTPUT_MASK) { case EDGE_ALIGNED_PWM: /* Setting active front of PWM channels.*/ pwmp->flexpwmp->SUB[2].VAL[2].R = ~(pwmperiod / 2) + 1U; pwmp->flexpwmp->SUB[2].VAL[4].R = ~(pwmperiod / 2) + 1U; break; default: ; } pwmp->flexpwmp->MCTRL.B.LDOK |= 4U; } #endif #if SPC5_PWM_USE_SMOD7 if (&PWMD8 == pwmp) { pwmp->flexpwmp->MCTRL.B.CLDOK |= 8U; /* Setting PWM period.*/ pwmp->flexpwmp->SUB[3].INIT.R = ~(pwmperiod / 2) + 1U; pwmp->flexpwmp->SUB[3].VAL[0].R = 0; pwmp->flexpwmp->SUB[3].VAL[1].R = pwmperiod / 2; switch (pwmp->config->mode & PWM_OUTPUT_MASK) { case EDGE_ALIGNED_PWM: /* Setting active front of PWM channels.*/ pwmp->flexpwmp->SUB[3].VAL[2].R = ~(pwmperiod / 2) + 1U; pwmp->flexpwmp->SUB[3].VAL[4].R = ~(pwmperiod / 2) + 1U; break; default: ; } pwmp->flexpwmp->MCTRL.B.LDOK |= 8U; } #endif } #endif /* HAL_USE_PWM */ /** @} */