/** * @brief Configures and activates the ICU peripheral. * * @param[in] icup pointer to the @p ICUDriver object * * @notapi */ void icu_lld_start(ICUDriver *icup) { uint32_t psc; chDbgAssert((icup->config->channel == ICU_CHANNEL_1) || (icup->config->channel == ICU_CHANNEL_2), "icu_lld_start(), #1", "invalid input"); if (icup->state == ICU_STOP) { /* Clock activation and timer reset.*/ #if STM32_ICU_USE_TIM1 if (&ICUD1 == icup) { rccEnableTIM1(FALSE); rccResetTIM1(); nvicEnableVector(STM32_TIM1_UP_NUMBER, CORTEX_PRIORITY_MASK(STM32_ICU_TIM1_IRQ_PRIORITY)); nvicEnableVector(STM32_TIM1_CC_NUMBER, CORTEX_PRIORITY_MASK(STM32_ICU_TIM1_IRQ_PRIORITY)); #if defined(STM32_TIM1CLK) icup->clock = STM32_TIM1CLK; #else icup->clock = STM32_TIMCLK2; #endif } #endif #if STM32_ICU_USE_TIM2 if (&ICUD2 == icup) { rccEnableTIM2(FALSE); rccResetTIM2(); nvicEnableVector(STM32_TIM2_NUMBER, CORTEX_PRIORITY_MASK(STM32_ICU_TIM2_IRQ_PRIORITY)); icup->clock = STM32_TIMCLK1; } #endif #if STM32_ICU_USE_TIM3 if (&ICUD3 == icup) { rccEnableTIM3(FALSE); rccResetTIM3(); nvicEnableVector(STM32_TIM3_NUMBER, CORTEX_PRIORITY_MASK(STM32_ICU_TIM3_IRQ_PRIORITY)); icup->clock = STM32_TIMCLK1; } #endif #if STM32_ICU_USE_TIM4 if (&ICUD4 == icup) { rccEnableTIM4(FALSE); rccResetTIM4(); nvicEnableVector(STM32_TIM4_NUMBER, CORTEX_PRIORITY_MASK(STM32_ICU_TIM4_IRQ_PRIORITY)); icup->clock = STM32_TIMCLK1; } #endif #if STM32_ICU_USE_TIM5 if (&ICUD5 == icup) { rccEnableTIM5(FALSE); rccResetTIM5(); nvicEnableVector(STM32_TIM5_NUMBER, CORTEX_PRIORITY_MASK(STM32_ICU_TIM5_IRQ_PRIORITY)); icup->clock = STM32_TIMCLK1; } #endif #if STM32_ICU_USE_TIM8 if (&ICUD8 == icup) { rccEnableTIM8(FALSE); rccResetTIM8(); nvicEnableVector(STM32_TIM8_UP_NUMBER, CORTEX_PRIORITY_MASK(STM32_ICU_TIM8_IRQ_PRIORITY)); nvicEnableVector(STM32_TIM8_CC_NUMBER, CORTEX_PRIORITY_MASK(STM32_ICU_TIM8_IRQ_PRIORITY)); #if defined(STM32_TIM8CLK) icup->clock = STM32_TIM8CLK; #else icup->clock = STM32_TIMCLK2; #endif } #endif #if STM32_ICU_USE_TIM9 if (&ICUD9 == icup) { rccEnableTIM9(FALSE); rccResetTIM9(); nvicEnableVector(STM32_TIM9_NUMBER, CORTEX_PRIORITY_MASK(STM32_ICU_TIM9_IRQ_PRIORITY)); icup->clock = STM32_TIMCLK2; } #endif } else { /* Driver re-configuration scenario, it must be stopped first.*/ icup->tim->CR1 = 0; /* Timer disabled. */ icup->tim->CCR[0] = 0; /* Comparator 1 disabled. */ icup->tim->CCR[1] = 0; /* Comparator 2 disabled. */ icup->tim->CNT = 0; /* Counter reset to zero. */ } /* Timer configuration.*/ icup->tim->SR = 0; /* Clear eventual pending IRQs. */ icup->tim->DIER = icup->config->dier & /* DMA-related DIER settings. */ ~STM32_TIM_DIER_IRQ_MASK; psc = (icup->clock / icup->config->frequency) - 1; chDbgAssert((psc <= 0xFFFF) && ((psc + 1) * icup->config->frequency) == icup->clock, "icu_lld_start(), #1", "invalid frequency"); icup->tim->PSC = (uint16_t)psc; icup->tim->ARR = 0xFFFF; if (icup->config->channel == ICU_CHANNEL_1) { /* Selected input 1. CCMR1_CC1S = 01 = CH1 Input on TI1. CCMR1_CC2S = 10 = CH2 Input on TI1.*/ icup->tim->CCMR1 = STM32_TIM_CCMR1_CC1S(1) | STM32_TIM_CCMR1_CC2S(2); /* SMCR_TS = 101, input is TI1FP1. SMCR_SMS = 100, reset on rising edge.*/ icup->tim->SMCR = STM32_TIM_SMCR_TS(5) | STM32_TIM_SMCR_SMS(4); /* The CCER settings depend on the selected trigger mode. ICU_INPUT_ACTIVE_HIGH: Active on rising edge, idle on falling edge. ICU_INPUT_ACTIVE_LOW: Active on falling edge, idle on rising edge.*/ if (icup->config->mode == ICU_INPUT_ACTIVE_HIGH) icup->tim->CCER = STM32_TIM_CCER_CC1E | STM32_TIM_CCER_CC2E | STM32_TIM_CCER_CC2P; else icup->tim->CCER = STM32_TIM_CCER_CC1E | STM32_TIM_CCER_CC1P | STM32_TIM_CCER_CC2E; /* Direct pointers to the capture registers in order to make reading data faster from within callbacks.*/ icup->wccrp = &icup->tim->CCR[1]; icup->pccrp = &icup->tim->CCR[0]; } else { /* Selected input 2. CCMR1_CC1S = 10 = CH1 Input on TI2. CCMR1_CC2S = 01 = CH2 Input on TI2.*/ icup->tim->CCMR1 = STM32_TIM_CCMR1_CC1S(2) | STM32_TIM_CCMR1_CC2S(1); /* SMCR_TS = 110, input is TI2FP2. SMCR_SMS = 100, reset on rising edge.*/ icup->tim->SMCR = STM32_TIM_SMCR_TS(6) | STM32_TIM_SMCR_SMS(4); /* The CCER settings depend on the selected trigger mode. ICU_INPUT_ACTIVE_HIGH: Active on rising edge, idle on falling edge. ICU_INPUT_ACTIVE_LOW: Active on falling edge, idle on rising edge.*/ if (icup->config->mode == ICU_INPUT_ACTIVE_HIGH) icup->tim->CCER = STM32_TIM_CCER_CC1E | STM32_TIM_CCER_CC1P | STM32_TIM_CCER_CC2E; else icup->tim->CCER = STM32_TIM_CCER_CC1E | STM32_TIM_CCER_CC2E | STM32_TIM_CCER_CC2P; /* Direct pointers to the capture registers in order to make reading data faster from within callbacks.*/ icup->wccrp = &icup->tim->CCR[0]; icup->pccrp = &icup->tim->CCR[1]; } }
/** * @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) { uint32_t psc; uint32_t ccer; uint32_t dier; if (pwmp->state == PWM_STOP) { /* Clock activation and timer reset.*/ #if STM32_PWM_USE_TIM1 if (&PWMD1 == pwmp) { rccEnableTIM1(FALSE); rccResetTIM1(); nvicEnableVector(STM32_TIM1_UP_NUMBER, CORTEX_PRIORITY_MASK(STM32_PWM_TIM1_IRQ_PRIORITY)); nvicEnableVector(STM32_TIM1_CC_NUMBER, CORTEX_PRIORITY_MASK(STM32_PWM_TIM1_IRQ_PRIORITY)); #if defined(STM32_TIM1CLK) pwmp->clock = STM32_TIM1CLK; #else pwmp->clock = STM32_TIMCLK2; #endif } #endif #if STM32_PWM_USE_TIM2 if (&PWMD2 == pwmp) { rccEnableTIM2(FALSE); rccResetTIM2(); nvicEnableVector(STM32_TIM2_NUMBER, CORTEX_PRIORITY_MASK(STM32_PWM_TIM2_IRQ_PRIORITY)); pwmp->clock = STM32_TIMCLK1; } #endif #if STM32_PWM_USE_TIM3 if (&PWMD3 == pwmp) { rccEnableTIM3(FALSE); rccResetTIM3(); nvicEnableVector(STM32_TIM3_NUMBER, CORTEX_PRIORITY_MASK(STM32_PWM_TIM3_IRQ_PRIORITY)); pwmp->clock = STM32_TIMCLK1; } #endif #if STM32_PWM_USE_TIM4 if (&PWMD4 == pwmp) { rccEnableTIM4(FALSE); rccResetTIM4(); nvicEnableVector(STM32_TIM4_NUMBER, CORTEX_PRIORITY_MASK(STM32_PWM_TIM4_IRQ_PRIORITY)); pwmp->clock = STM32_TIMCLK1; } #endif #if STM32_PWM_USE_TIM5 if (&PWMD5 == pwmp) { rccEnableTIM5(FALSE); rccResetTIM5(); nvicEnableVector(STM32_TIM5_NUMBER, CORTEX_PRIORITY_MASK(STM32_PWM_TIM5_IRQ_PRIORITY)); pwmp->clock = STM32_TIMCLK1; } #endif #if STM32_PWM_USE_TIM8 if (&PWMD8 == pwmp) { rccEnableTIM8(FALSE); rccResetTIM8(); nvicEnableVector(STM32_TIM8_UP_NUMBER, CORTEX_PRIORITY_MASK(STM32_PWM_TIM8_IRQ_PRIORITY)); nvicEnableVector(STM32_TIM8_CC_NUMBER, CORTEX_PRIORITY_MASK(STM32_PWM_TIM8_IRQ_PRIORITY)); #if defined(STM32_TIM8CLK) pwmp->clock = STM32_TIM8CLK; #else pwmp->clock = STM32_TIMCLK2; #endif } #endif #if STM32_PWM_USE_TIM9 if (&PWMD9 == pwmp) { rccEnableTIM9(FALSE); rccResetTIM9(); nvicEnableVector(STM32_TIM9_NUMBER, CORTEX_PRIORITY_MASK(STM32_PWM_TIM9_IRQ_PRIORITY)); pwmp->clock = STM32_TIMCLK2; } #endif /* All channels configured in PWM1 mode with preload enabled and will stay that way until the driver is stopped.*/ pwmp->tim->CCMR1 = STM32_TIM_CCMR1_OC1M(6) | STM32_TIM_CCMR1_OC1PE | STM32_TIM_CCMR1_OC2M(6) | STM32_TIM_CCMR1_OC2PE; pwmp->tim->CCMR2 = STM32_TIM_CCMR2_OC3M(6) | STM32_TIM_CCMR2_OC3PE | STM32_TIM_CCMR2_OC4M(6) | STM32_TIM_CCMR2_OC4PE; } else { /* Driver re-configuration scenario, it must be stopped first.*/ pwmp->tim->CR1 = 0; /* Timer disabled. */ pwmp->tim->CCR[0] = 0; /* Comparator 1 disabled. */ pwmp->tim->CCR[1] = 0; /* Comparator 2 disabled. */ pwmp->tim->CCR[2] = 0; /* Comparator 3 disabled. */ pwmp->tim->CCR[3] = 0; /* Comparator 4 disabled. */ pwmp->tim->CNT = 0; /* Counter reset to zero. */ } /* Timer configuration.*/ psc = (pwmp->clock / pwmp->config->frequency) - 1; chDbgAssert((psc <= 0xFFFF) && ((psc + 1) * pwmp->config->frequency) == pwmp->clock, "pwm_lld_start(), #1", "invalid frequency"); pwmp->tim->PSC = (uint16_t)psc; pwmp->tim->ARR = (uint16_t)(pwmp->period - 1); pwmp->tim->CR2 = pwmp->config->cr2; /* Output enables and polarities setup.*/ ccer = 0; switch (pwmp->config->channels[0].mode & PWM_OUTPUT_MASK) { case PWM_OUTPUT_ACTIVE_LOW: ccer |= STM32_TIM_CCER_CC1P; case PWM_OUTPUT_ACTIVE_HIGH: ccer |= STM32_TIM_CCER_CC1E; default: ; } switch (pwmp->config->channels[1].mode & PWM_OUTPUT_MASK) { case PWM_OUTPUT_ACTIVE_LOW: ccer |= STM32_TIM_CCER_CC2P; case PWM_OUTPUT_ACTIVE_HIGH: ccer |= STM32_TIM_CCER_CC2E; default: ; } switch (pwmp->config->channels[2].mode & PWM_OUTPUT_MASK) { case PWM_OUTPUT_ACTIVE_LOW: ccer |= STM32_TIM_CCER_CC3P; case PWM_OUTPUT_ACTIVE_HIGH: ccer |= STM32_TIM_CCER_CC3E; default: ; } switch (pwmp->config->channels[3].mode & PWM_OUTPUT_MASK) { case PWM_OUTPUT_ACTIVE_LOW: ccer |= STM32_TIM_CCER_CC4P; case PWM_OUTPUT_ACTIVE_HIGH: ccer |= STM32_TIM_CCER_CC4E; default: ; } #if STM32_PWM_USE_ADVANCED #if STM32_PWM_USE_TIM1 && !STM32_PWM_USE_TIM8 if (&PWMD1 == pwmp) { #endif #if !STM32_PWM_USE_TIM1 && STM32_PWM_USE_TIM8 if (&PWMD8 == pwmp) { #endif #if STM32_PWM_USE_TIM1 && STM32_PWM_USE_TIM8 if ((&PWMD1 == pwmp) || (&PWMD8 == pwmp)) { #endif switch (pwmp->config->channels[0].mode & PWM_COMPLEMENTARY_OUTPUT_MASK) { case PWM_COMPLEMENTARY_OUTPUT_ACTIVE_LOW: ccer |= STM32_TIM_CCER_CC1NP; case PWM_COMPLEMENTARY_OUTPUT_ACTIVE_HIGH: ccer |= STM32_TIM_CCER_CC1NE; default: ; } switch (pwmp->config->channels[1].mode & PWM_COMPLEMENTARY_OUTPUT_MASK) { case PWM_COMPLEMENTARY_OUTPUT_ACTIVE_LOW: ccer |= STM32_TIM_CCER_CC2NP; case PWM_COMPLEMENTARY_OUTPUT_ACTIVE_HIGH: ccer |= STM32_TIM_CCER_CC2NE; default: ; } switch (pwmp->config->channels[2].mode & PWM_COMPLEMENTARY_OUTPUT_MASK) { case PWM_COMPLEMENTARY_OUTPUT_ACTIVE_LOW: ccer |= STM32_TIM_CCER_CC3NP; case PWM_COMPLEMENTARY_OUTPUT_ACTIVE_HIGH: ccer |= STM32_TIM_CCER_CC3NE; default: ; } } #endif /* STM32_PWM_USE_ADVANCED*/ pwmp->tim->CCER = ccer; pwmp->tim->EGR = STM32_TIM_EGR_UG; /* Update event. */ pwmp->tim->SR = 0; /* Clear pending IRQs. */ pwmp->tim->DIER = (pwmp->config->callback == NULL ? 0 : STM32_TIM_DIER_UIE) | (pwmp->config->dier & ~STM32_TIM_DIER_IRQ_MASK); #if STM32_PWM_USE_TIM1 || STM32_PWM_USE_TIM8 #if STM32_PWM_USE_ADVANCED pwmp->tim->BDTR = pwmp->config->bdtr | STM32_TIM_BDTR_MOE; #else pwmp->tim->BDTR = STM32_TIM_BDTR_MOE; #endif #endif /* Timer configured and started.*/ pwmp->tim->CR1 = STM32_TIM_CR1_ARPE | STM32_TIM_CR1_URS | STM32_TIM_CR1_CEN; } /** * @brief Deactivates the PWM peripheral. * * @param[in] pwmp pointer to a @p PWMDriver object * * @notapi */ void pwm_lld_stop(PWMDriver *pwmp) { /* If in ready state then disables the PWM clock.*/ if (pwmp->state == PWM_READY) { pwmp->tim->CR1 = 0; /* Timer disabled. */ pwmp->tim->DIER = 0; /* All IRQs disabled. */ pwmp->tim->SR = 0; /* Clear eventual pending IRQs. */ #if STM32_PWM_USE_TIM1 || STM32_PWM_USE_TIM8 pwmp->tim->BDTR = 0; #endif #if STM32_PWM_USE_TIM1 if (&PWMD1 == pwmp) { nvicDisableVector(STM32_TIM1_UP_NUMBER); nvicDisableVector(STM32_TIM1_CC_NUMBER); rccDisableTIM1(FALSE); } #endif #if STM32_PWM_USE_TIM2 if (&PWMD2 == pwmp) { nvicDisableVector(STM32_TIM2_NUMBER); rccDisableTIM2(FALSE); } #endif #if STM32_PWM_USE_TIM3 if (&PWMD3 == pwmp) { nvicDisableVector(STM32_TIM3_NUMBER); rccDisableTIM3(FALSE); } #endif #if STM32_PWM_USE_TIM4 if (&PWMD4 == pwmp) { nvicDisableVector(STM32_TIM4_NUMBER); rccDisableTIM4(FALSE); } #endif #if STM32_PWM_USE_TIM5 if (&PWMD5 == pwmp) { nvicDisableVector(STM32_TIM5_NUMBER); rccDisableTIM5(FALSE); } #endif #if STM32_PWM_USE_TIM8 if (&PWMD8 == pwmp) { nvicDisableVector(STM32_TIM8_UP_NUMBER); nvicDisableVector(STM32_TIM8_CC_NUMBER); rccDisableTIM8(FALSE); } #endif #if STM32_PWM_USE_TIM9 if (&PWMD9 == pwmp) { nvicDisableVector(STM32_TIM9_NUMBER); rccDisableTIM9(FALSE); } #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) { pwmp->tim->CCR[channel] = width; /* New duty cycle. */ /* If there is a callback defined for the channel then the associated interrupt must be enabled.*/ if (pwmp->config->channels[channel].callback != NULL) { uint32_t dier = pwmp->tim->DIER; /* If the IRQ is not already enabled care must be taken to clear it, it is probably already pending because the timer is running.*/ if ((dier & (2 << channel)) == 0) { pwmp->tim->DIER = dier | (2 << channel); pwmp->tim->SR = ~(2 << channel); } } } /** * @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) { pwmp->tim->CCR[channel] = 0; pwmp->tim->DIER &= ~(2 << channel); }
/** * @brief Configures and activates the GPT peripheral. * * @param[in] gptp pointer to the @p GPTDriver object * * @notapi */ void gpt_lld_start(GPTDriver *gptp) { uint16_t psc; if (gptp->state == GPT_STOP) { /* Clock activation.*/ #if STM32_GPT_USE_TIM1 if (&GPTD1 == gptp) { rccEnableTIM1(FALSE); rccResetTIM1(); #if !defined(STM32_TIM1_SUPPRESS_ISR) nvicEnableVector(STM32_TIM1_UP_NUMBER, STM32_GPT_TIM1_IRQ_PRIORITY); #endif #if defined(STM32_TIM1CLK) gptp->clock = STM32_TIM1CLK; #else gptp->clock = STM32_TIMCLK2; #endif } #endif #if STM32_GPT_USE_TIM2 if (&GPTD2 == gptp) { rccEnableTIM2(FALSE); rccResetTIM2(); #if !defined(STM32_TIM2_SUPPRESS_ISR) nvicEnableVector(STM32_TIM2_NUMBER, STM32_GPT_TIM2_IRQ_PRIORITY); #endif #if defined(STM32_TIM2CLK) gptp->clock = STM32_TIM2CLK; #else gptp->clock = STM32_TIMCLK1; #endif } #endif #if STM32_GPT_USE_TIM3 if (&GPTD3 == gptp) { rccEnableTIM3(FALSE); rccResetTIM3(); #if !defined(STM32_TIM3_SUPPRESS_ISR) nvicEnableVector(STM32_TIM3_NUMBER, STM32_GPT_TIM3_IRQ_PRIORITY); #endif #if defined(STM32_TIM3CLK) gptp->clock = STM32_TIM3CLK; #else gptp->clock = STM32_TIMCLK1; #endif } #endif #if STM32_GPT_USE_TIM4 if (&GPTD4 == gptp) { rccEnableTIM4(FALSE); rccResetTIM4(); #if !defined(STM32_TIM4_SUPPRESS_ISR) nvicEnableVector(STM32_TIM4_NUMBER, STM32_GPT_TIM4_IRQ_PRIORITY); #endif #if defined(STM32_TIM4CLK) gptp->clock = STM32_TIM4CLK; #else gptp->clock = STM32_TIMCLK1; #endif } #endif #if STM32_GPT_USE_TIM5 if (&GPTD5 == gptp) { rccEnableTIM5(FALSE); rccResetTIM5(); #if !defined(STM32_TIM5_SUPPRESS_ISR) nvicEnableVector(STM32_TIM5_NUMBER, STM32_GPT_TIM5_IRQ_PRIORITY); #endif #if defined(STM32_TIM5CLK) gptp->clock = STM32_TIM5CLK; #else gptp->clock = STM32_TIMCLK1; #endif } #endif #if STM32_GPT_USE_TIM6 if (&GPTD6 == gptp) { rccEnableTIM6(FALSE); rccResetTIM6(); #if !defined(STM32_TIM6_SUPPRESS_ISR) nvicEnableVector(STM32_TIM6_NUMBER, STM32_GPT_TIM6_IRQ_PRIORITY); #endif #if defined(STM32_TIM6CLK) gptp->clock = STM32_TIM6CLK; #else gptp->clock = STM32_TIMCLK1; #endif } #endif #if STM32_GPT_USE_TIM7 if (&GPTD7 == gptp) { rccEnableTIM7(FALSE); rccResetTIM7(); #if !defined(STM32_TIM7_SUPPRESS_ISR) nvicEnableVector(STM32_TIM7_NUMBER, STM32_GPT_TIM7_IRQ_PRIORITY); #endif #if defined(STM32_TIM7CLK) gptp->clock = STM32_TIM7CLK; #else gptp->clock = STM32_TIMCLK1; #endif } #endif #if STM32_GPT_USE_TIM8 if (&GPTD8 == gptp) { rccEnableTIM8(FALSE); rccResetTIM8(); #if !defined(STM32_TIM8_SUPPRESS_ISR) nvicEnableVector(STM32_TIM8_UP_NUMBER, STM32_GPT_TIM8_IRQ_PRIORITY); #endif #if defined(STM32_TIM8CLK) gptp->clock = STM32_TIM8CLK; #else gptp->clock = STM32_TIMCLK2; #endif } #endif #if STM32_GPT_USE_TIM9 if (&GPTD9 == gptp) { rccEnableTIM9(FALSE); rccResetTIM9(); #if !defined(STM32_TIM9_SUPPRESS_ISR) nvicEnableVector(STM32_TIM9_NUMBER, STM32_GPT_TIM9_IRQ_PRIORITY); #endif #if defined(STM32_TIM9CLK) gptp->clock = STM32_TIM9CLK; #else gptp->clock = STM32_TIMCLK2; #endif } #endif #if STM32_GPT_USE_TIM11 if (&GPTD11 == gptp) { rccEnableTIM11(FALSE); rccResetTIM11(); #if !defined(STM32_TIM11_SUPPRESS_ISR) nvicEnableVector(STM32_TIM11_NUMBER, STM32_GPT_TIM11_IRQ_PRIORITY); #endif #if defined(STM32_TIM11CLK) gptp->clock = STM32_TIM11CLK; #else gptp->clock = STM32_TIMCLK2; #endif } #endif #if STM32_GPT_USE_TIM12 if (&GPTD12 == gptp) { rccEnableTIM12(FALSE); rccResetTIM12(); #if !defined(STM32_TIM12_SUPPRESS_ISR) nvicEnableVector(STM32_TIM12_NUMBER, STM32_GPT_TIM12_IRQ_PRIORITY); #endif #if defined(STM32_TIM12CLK) gptp->clock = STM32_TIM12CLK; #else gptp->clock = STM32_TIMCLK1; #endif } #endif #if STM32_GPT_USE_TIM14 if (&GPTD14 == gptp) { rccEnableTIM14(FALSE); rccResetTIM14(); #if !defined(STM32_TIM14_SUPPRESS_ISR) nvicEnableVector(STM32_TIM14_NUMBER, STM32_GPT_TIM14_IRQ_PRIORITY); #endif #if defined(STM32_TIM14CLK) gptp->clock = STM32_TIM14CLK; #else gptp->clock = STM32_TIMCLK1; #endif } #endif } /* Prescaler value calculation.*/ psc = (uint16_t)((gptp->clock / gptp->config->frequency) - 1); osalDbgAssert(((uint32_t)(psc + 1) * gptp->config->frequency) == gptp->clock, "invalid frequency"); /* Timer configuration.*/ gptp->tim->CR1 = 0; /* Initially stopped. */ gptp->tim->CR2 = gptp->config->cr2; gptp->tim->PSC = psc; /* Prescaler value. */ gptp->tim->SR = 0; /* Clear pending IRQs. */ gptp->tim->DIER = gptp->config->dier & /* DMA-related DIER bits. */ ~STM32_TIM_DIER_IRQ_MASK; }
/** * @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) { uint32_t psc; uint32_t ccer; if (pwmp->state == PWM_STOP) { /* Clock activation and timer reset.*/ #if STM32_PWM_USE_TIM1 if (&PWMD1 == pwmp) { rccEnableTIM1(FALSE); rccResetTIM1(); #if !defined(STM32_TIM1_SUPPRESS_ISR) nvicEnableVector(STM32_TIM1_UP_NUMBER, STM32_PWM_TIM1_IRQ_PRIORITY); nvicEnableVector(STM32_TIM1_CC_NUMBER, STM32_PWM_TIM1_IRQ_PRIORITY); #endif #if defined(STM32_TIM1CLK) pwmp->clock = STM32_TIM1CLK; #else pwmp->clock = STM32_TIMCLK2; #endif } #endif #if STM32_PWM_USE_TIM2 if (&PWMD2 == pwmp) { rccEnableTIM2(FALSE); rccResetTIM2(); #if !defined(STM32_TIM2_SUPPRESS_ISR) nvicEnableVector(STM32_TIM2_NUMBER, STM32_PWM_TIM2_IRQ_PRIORITY); #endif #if defined(STM32_TIM2CLK) pwmp->clock = STM32_TIM2CLK; #else pwmp->clock = STM32_TIMCLK1; #endif } #endif #if STM32_PWM_USE_TIM3 if (&PWMD3 == pwmp) { rccEnableTIM3(FALSE); rccResetTIM3(); #if !defined(STM32_TIM3_SUPPRESS_ISR) nvicEnableVector(STM32_TIM3_NUMBER, STM32_PWM_TIM3_IRQ_PRIORITY); #endif #if defined(STM32_TIM3CLK) pwmp->clock = STM32_TIM3CLK; #else pwmp->clock = STM32_TIMCLK1; #endif } #endif #if STM32_PWM_USE_TIM4 if (&PWMD4 == pwmp) { rccEnableTIM4(FALSE); rccResetTIM4(); #if !defined(STM32_TIM4_SUPPRESS_ISR) nvicEnableVector(STM32_TIM4_NUMBER, STM32_PWM_TIM4_IRQ_PRIORITY); #endif #if defined(STM32_TIM4CLK) pwmp->clock = STM32_TIM4CLK; #else pwmp->clock = STM32_TIMCLK1; #endif } #endif #if STM32_PWM_USE_TIM5 if (&PWMD5 == pwmp) { rccEnableTIM5(FALSE); rccResetTIM5(); #if !defined(STM32_TIM5_SUPPRESS_ISR) nvicEnableVector(STM32_TIM5_NUMBER, STM32_PWM_TIM5_IRQ_PRIORITY); #endif #if defined(STM32_TIM5CLK) pwmp->clock = STM32_TIM5CLK; #else pwmp->clock = STM32_TIMCLK1; #endif } #endif #if STM32_PWM_USE_TIM8 if (&PWMD8 == pwmp) { rccEnableTIM8(FALSE); rccResetTIM8(); #if !defined(STM32_TIM8_SUPPRESS_ISR) nvicEnableVector(STM32_TIM8_UP_NUMBER, STM32_PWM_TIM8_IRQ_PRIORITY); nvicEnableVector(STM32_TIM8_CC_NUMBER, STM32_PWM_TIM8_IRQ_PRIORITY); #endif #if defined(STM32_TIM8CLK) pwmp->clock = STM32_TIM8CLK; #else pwmp->clock = STM32_TIMCLK2; #endif } #endif #if STM32_PWM_USE_TIM9 if (&PWMD9 == pwmp) { rccEnableTIM9(FALSE); rccResetTIM9(); #if !defined(STM32_TIM9_SUPPRESS_ISR) nvicEnableVector(STM32_TIM9_NUMBER, STM32_PWM_TIM9_IRQ_PRIORITY); #endif #if defined(STM32_TIM9CLK) pwmp->clock = STM32_TIM9CLK; #else pwmp->clock = STM32_TIMCLK2; #endif } #endif /* All channels configured in PWM1 mode with preload enabled and will stay that way until the driver is stopped.*/ pwmp->tim->CCMR1 = STM32_TIM_CCMR1_OC1M(6) | STM32_TIM_CCMR1_OC1PE | STM32_TIM_CCMR1_OC2M(6) | STM32_TIM_CCMR1_OC2PE; pwmp->tim->CCMR2 = STM32_TIM_CCMR2_OC3M(6) | STM32_TIM_CCMR2_OC3PE | STM32_TIM_CCMR2_OC4M(6) | STM32_TIM_CCMR2_OC4PE; #if STM32_TIM_MAX_CHANNELS > 4 pwmp->tim->CCMR3 = STM32_TIM_CCMR3_OC5M(6) | STM32_TIM_CCMR3_OC5PE | STM32_TIM_CCMR3_OC6M(6) | STM32_TIM_CCMR3_OC6PE; #endif } else { /* Driver re-configuration scenario, it must be stopped first.*/ pwmp->tim->CR1 = 0; /* Timer disabled. */ pwmp->tim->CCR[0] = 0; /* Comparator 1 disabled. */ pwmp->tim->CCR[1] = 0; /* Comparator 2 disabled. */ pwmp->tim->CCR[2] = 0; /* Comparator 3 disabled. */ pwmp->tim->CCR[3] = 0; /* Comparator 4 disabled. */ #if STM32_TIM_MAX_CHANNELS > 4 if (pwmp->channels > 4) { pwmp->tim->CCXR[0] = 0; /* Comparator 5 disabled. */ pwmp->tim->CCXR[1] = 0; /* Comparator 6 disabled. */ } #endif pwmp->tim->CNT = 0; /* Counter reset to zero. */ } /* Timer configuration.*/ psc = (pwmp->clock / pwmp->config->frequency) - 1; osalDbgAssert((psc <= 0xFFFF) && ((psc + 1) * pwmp->config->frequency) == pwmp->clock, "invalid frequency"); pwmp->tim->PSC = psc; pwmp->tim->ARR = pwmp->period - 1; pwmp->tim->CR2 = pwmp->config->cr2; /* Output enables and polarities setup.*/ ccer = 0; switch (pwmp->config->channels[0].mode & PWM_OUTPUT_MASK) { case PWM_OUTPUT_ACTIVE_LOW: ccer |= STM32_TIM_CCER_CC1P; case PWM_OUTPUT_ACTIVE_HIGH: ccer |= STM32_TIM_CCER_CC1E; default: ; } switch (pwmp->config->channels[1].mode & PWM_OUTPUT_MASK) { case PWM_OUTPUT_ACTIVE_LOW: ccer |= STM32_TIM_CCER_CC2P; case PWM_OUTPUT_ACTIVE_HIGH: ccer |= STM32_TIM_CCER_CC2E; default: ; } switch (pwmp->config->channels[2].mode & PWM_OUTPUT_MASK) { case PWM_OUTPUT_ACTIVE_LOW: ccer |= STM32_TIM_CCER_CC3P; case PWM_OUTPUT_ACTIVE_HIGH: ccer |= STM32_TIM_CCER_CC3E; default: ; } switch (pwmp->config->channels[3].mode & PWM_OUTPUT_MASK) { case PWM_OUTPUT_ACTIVE_LOW: ccer |= STM32_TIM_CCER_CC4P; case PWM_OUTPUT_ACTIVE_HIGH: ccer |= STM32_TIM_CCER_CC4E; default: ; } #if STM32_PWM_USE_ADVANCED #if STM32_PWM_USE_TIM1 && !STM32_PWM_USE_TIM8 if (&PWMD1 == pwmp) { #endif #if !STM32_PWM_USE_TIM1 && STM32_PWM_USE_TIM8 if (&PWMD8 == pwmp) { #endif #if STM32_PWM_USE_TIM1 && STM32_PWM_USE_TIM8 if ((&PWMD1 == pwmp) || (&PWMD8 == pwmp)) { #endif switch (pwmp->config->channels[0].mode & PWM_COMPLEMENTARY_OUTPUT_MASK) { case PWM_COMPLEMENTARY_OUTPUT_ACTIVE_LOW: ccer |= STM32_TIM_CCER_CC1NP; case PWM_COMPLEMENTARY_OUTPUT_ACTIVE_HIGH: ccer |= STM32_TIM_CCER_CC1NE; default: ; } switch (pwmp->config->channels[1].mode & PWM_COMPLEMENTARY_OUTPUT_MASK) { case PWM_COMPLEMENTARY_OUTPUT_ACTIVE_LOW: ccer |= STM32_TIM_CCER_CC2NP; case PWM_COMPLEMENTARY_OUTPUT_ACTIVE_HIGH: ccer |= STM32_TIM_CCER_CC2NE; default: ; } switch (pwmp->config->channels[2].mode & PWM_COMPLEMENTARY_OUTPUT_MASK) { case PWM_COMPLEMENTARY_OUTPUT_ACTIVE_LOW: ccer |= STM32_TIM_CCER_CC3NP; case PWM_COMPLEMENTARY_OUTPUT_ACTIVE_HIGH: ccer |= STM32_TIM_CCER_CC3NE; default: ; } } #endif /* STM32_PWM_USE_ADVANCED*/ pwmp->tim->CCER = ccer; pwmp->tim->EGR = STM32_TIM_EGR_UG; /* Update event. */ pwmp->tim->SR = 0; /* Clear pending IRQs. */ pwmp->tim->DIER = pwmp->config->dier & /* DMA-related DIER settings. */ ~STM32_TIM_DIER_IRQ_MASK; #if STM32_PWM_USE_TIM1 || STM32_PWM_USE_TIM8 #if STM32_PWM_USE_ADVANCED pwmp->tim->BDTR = pwmp->config->bdtr | STM32_TIM_BDTR_MOE; #else pwmp->tim->BDTR = STM32_TIM_BDTR_MOE; #endif #endif /* Timer configured and started.*/ pwmp->tim->CR1 = STM32_TIM_CR1_ARPE | STM32_TIM_CR1_URS | STM32_TIM_CR1_CEN; } /** * @brief Deactivates the PWM peripheral. * * @param[in] pwmp pointer to a @p PWMDriver object * * @notapi */ void pwm_lld_stop(PWMDriver *pwmp) { /* If in ready state then disables the PWM clock.*/ if (pwmp->state == PWM_READY) { pwmp->tim->CR1 = 0; /* Timer disabled. */ pwmp->tim->DIER = 0; /* All IRQs disabled. */ pwmp->tim->SR = 0; /* Clear eventual pending IRQs. */ #if STM32_PWM_USE_TIM1 || STM32_PWM_USE_TIM8 pwmp->tim->BDTR = 0; #endif #if STM32_PWM_USE_TIM1 if (&PWMD1 == pwmp) { #if !defined(STM32_TIM1_SUPPRESS_ISR) nvicDisableVector(STM32_TIM1_UP_NUMBER); nvicDisableVector(STM32_TIM1_CC_NUMBER); #endif rccDisableTIM1(FALSE); } #endif #if STM32_PWM_USE_TIM2 if (&PWMD2 == pwmp) { #if !defined(STM32_TIM2_SUPPRESS_ISR) nvicDisableVector(STM32_TIM2_NUMBER); #endif rccDisableTIM2(FALSE); } #endif #if STM32_PWM_USE_TIM3 if (&PWMD3 == pwmp) { #if !defined(STM32_TIM3_SUPPRESS_ISR) nvicDisableVector(STM32_TIM3_NUMBER); #endif rccDisableTIM3(FALSE); } #endif #if STM32_PWM_USE_TIM4 if (&PWMD4 == pwmp) { #if !defined(STM32_TIM4_SUPPRESS_ISR) nvicDisableVector(STM32_TIM4_NUMBER); #endif rccDisableTIM4(FALSE); } #endif #if STM32_PWM_USE_TIM5 if (&PWMD5 == pwmp) { #if !defined(STM32_TIM5_SUPPRESS_ISR) nvicDisableVector(STM32_TIM5_NUMBER); #endif rccDisableTIM5(FALSE); } #endif #if STM32_PWM_USE_TIM8 if (&PWMD8 == pwmp) { #if !defined(STM32_TIM8_SUPPRESS_ISR) nvicDisableVector(STM32_TIM8_UP_NUMBER); nvicDisableVector(STM32_TIM8_CC_NUMBER); #endif rccDisableTIM8(FALSE); } #endif #if STM32_PWM_USE_TIM9 if (&PWMD9 == pwmp) { #if !defined(STM32_TIM9_SUPPRESS_ISR) nvicDisableVector(STM32_TIM9_NUMBER); #endif rccDisableTIM9(FALSE); } #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. * @note Channel notification is not enabled. * * @param[in] pwmp pointer to a @p PWMDriver object * @param[in] channel PWM channel identifier (0...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) { /* Changing channel duty cycle on the fly.*/ #if STM32_TIM_MAX_CHANNELS <= 4 pwmp->tim->CCR[channel] = width; #else if (channel < 4) pwmp->tim->CCR[channel] = width; else pwmp->tim->CCXR[channel - 4] = width; #endif } /** * @brief Disables a PWM channel and its notification. * @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...channels-1) * * @notapi */ void pwm_lld_disable_channel(PWMDriver *pwmp, pwmchannel_t channel) { #if STM32_TIM_MAX_CHANNELS <= 4 pwmp->tim->CCR[channel] = 0; pwmp->tim->DIER &= ~(2 << channel); #else if (channel < 4) { pwmp->tim->CCR[channel] = 0; pwmp->tim->DIER &= ~(2 << channel); } else pwmp->tim->CCXR[channel - 4] = 0; #endif }
/** * @brief Configures and activates the GPT peripheral. * * @param[in] gptp pointer to the @p GPTDriver object * * @notapi */ void gpt_lld_start(GPTDriver *gptp) { uint16_t psc; if (gptp->state == GPT_STOP) { /* Clock activation.*/ #if STM32_GPT_USE_TIM1 if (&GPTD1 == gptp) { rccEnableTIM1(FALSE); rccResetTIM1(); nvicEnableVector(STM32_TIM1_UP_NUMBER, CORTEX_PRIORITY_MASK(STM32_GPT_TIM1_IRQ_PRIORITY)); gptp->clock = STM32_TIMCLK2; } #endif #if STM32_GPT_USE_TIM2 if (&GPTD2 == gptp) { rccEnableTIM2(FALSE); rccResetTIM2(); nvicEnableVector(STM32_TIM2_NUMBER, CORTEX_PRIORITY_MASK(STM32_GPT_TIM2_IRQ_PRIORITY)); gptp->clock = STM32_TIMCLK1; } #endif #if STM32_GPT_USE_TIM3 if (&GPTD3 == gptp) { rccEnableTIM3(FALSE); rccResetTIM3(); nvicEnableVector(STM32_TIM3_NUMBER, CORTEX_PRIORITY_MASK(STM32_GPT_TIM3_IRQ_PRIORITY)); gptp->clock = STM32_TIMCLK1; } #endif #if STM32_GPT_USE_TIM4 if (&GPTD4 == gptp) { rccEnableTIM4(FALSE); rccResetTIM4(); nvicEnableVector(STM32_TIM4_NUMBER, CORTEX_PRIORITY_MASK(STM32_GPT_TIM4_IRQ_PRIORITY)); gptp->clock = STM32_TIMCLK1; } #endif #if STM32_GPT_USE_TIM5 if (&GPTD5 == gptp) { rccEnableTIM5(FALSE); rccResetTIM5(); nvicEnableVector(STM32_TIM5_NUMBER, CORTEX_PRIORITY_MASK(STM32_GPT_TIM5_IRQ_PRIORITY)); gptp->clock = STM32_TIMCLK1; } #endif #if STM32_GPT_USE_TIM8 if (&GPTD8 == gptp) { rccEnableTIM8(FALSE); rccResetTIM8(); nvicEnableVector(STM32_TIM8_UP_NUMBER, CORTEX_PRIORITY_MASK(STM32_GPT_TIM8_IRQ_PRIORITY)); gptp->clock = STM32_TIMCLK2; } #endif } /* Prescaler value calculation.*/ psc = (uint16_t)((gptp->clock / gptp->config->frequency) - 1); chDbgAssert(((uint32_t)(psc + 1) * gptp->config->frequency) == gptp->clock, "gpt_lld_start(), #1", "invalid frequency"); /* Timer configuration.*/ gptp->tim->CR1 = 0; /* Initially stopped. */ gptp->tim->CR2 = TIM_CR2_CCDS; /* DMA on UE (if any). */ gptp->tim->PSC = psc; /* Prescaler value. */ gptp->tim->DIER = 0; }
/** * @brief Configures and activates the TIMCAP peripheral. * * @param[in] timcapp pointer to the @p TIMCAPDriver object * * @notapi */ void timcap_lld_start(TIMCAPDriver *timcapp) { uint32_t psc; const timcapchannel_t tim_max_channel = timcap_get_max_timer_channel(timcapp); if (timcapp->state == TIMCAP_STOP) { /* Clock activation and timer reset.*/ #if STM32_TIMCAP_USE_TIM1 if (&TIMCAPD1 == timcapp) { rccEnableTIM1(FALSE); rccResetTIM1(); nvicEnableVector(STM32_TIM1_UP_NUMBER, STM32_TIMCAP_TIM1_IRQ_PRIORITY); nvicEnableVector(STM32_TIM1_CC_NUMBER, STM32_TIMCAP_TIM1_IRQ_PRIORITY); #if defined(STM32_TIM1CLK) timcapp->clock = STM32_TIM1CLK; #else timcapp->clock = STM32_TIMCLK2; #endif } #endif #if STM32_TIMCAP_USE_TIM2 if (&TIMCAPD2 == timcapp) { rccEnableTIM2(FALSE); rccResetTIM2(); nvicEnableVector(STM32_TIM2_NUMBER, STM32_TIMCAP_TIM2_IRQ_PRIORITY); timcapp->clock = STM32_TIMCLK1; } #endif #if STM32_TIMCAP_USE_TIM3 if (&TIMCAPD3 == timcapp) { rccEnableTIM3(FALSE); rccResetTIM3(); nvicEnableVector(STM32_TIM3_NUMBER, STM32_TIMCAP_TIM3_IRQ_PRIORITY); timcapp->clock = STM32_TIMCLK1; } #endif #if STM32_TIMCAP_USE_TIM4 if (&TIMCAPD4 == timcapp) { rccEnableTIM4(FALSE); rccResetTIM4(); nvicEnableVector(STM32_TIM4_NUMBER, STM32_TIMCAP_TIM4_IRQ_PRIORITY); timcapp->clock = STM32_TIMCLK1; } #endif #if STM32_TIMCAP_USE_TIM5 if (&TIMCAPD5 == timcapp) { rccEnableTIM5(FALSE); rccResetTIM5(); nvicEnableVector(STM32_TIM5_NUMBER, STM32_TIMCAP_TIM5_IRQ_PRIORITY); timcapp->clock = STM32_TIMCLK1; } #endif #if STM32_TIMCAP_USE_TIM8 if (&TIMCAPD8 == timcapp) { rccEnableTIM8(FALSE); rccResetTIM8(); nvicEnableVector(STM32_TIM8_UP_NUMBER, STM32_TIMCAP_TIM8_IRQ_PRIORITY); nvicEnableVector(STM32_TIM8_CC_NUMBER, STM32_TIMCAP_TIM8_IRQ_PRIORITY); #if defined(STM32_TIM8CLK) timcapp->clock = STM32_TIM8CLK; #else timcapp->clock = STM32_TIMCLK2; #endif } #endif #if STM32_TIMCAP_USE_TIM9 if (&TIMCAPD9 == timcapp) { rccEnableTIM9(FALSE); rccResetTIM9(); nvicEnableVector(STM32_TIM9_NUMBER, STM32_TIMCAP_TIM9_IRQ_PRIORITY); timcapp->clock = STM32_TIMCLK1; } #endif } else { /* Driver re-configuration scenario, it must be stopped first.*/ timcapp->tim->CR1 = 0; /* Timer disabled. */ timcapp->tim->DIER = timcapp->config->dier &/* DMA-related DIER settings. */ ~STM32_TIM_DIER_IRQ_MASK; timcapp->tim->SR = 0; /* Clear eventual pending IRQs. */ timcapp->tim->CCR[0] = 0; /* Comparator 1 disabled. */ timcapp->tim->CCR[1] = 0; /* Comparator 2 disabled. */ if( tim_max_channel >= TIMCAP_CHANNEL_3 ) timcapp->tim->CCR[2] = 0; /* Comparator 3 disabled. */ if( tim_max_channel >= TIMCAP_CHANNEL_4 ) timcapp->tim->CCR[3] = 0; /* Comparator 4 disabled. */ timcapp->tim->CNT = 0; /* Counter reset to zero. */ } /* Timer configuration.*/ psc = (timcapp->clock / timcapp->config->frequency) - 1; osalDbgAssert((psc <= 0xFFFF) && ((psc + 1) * timcapp->config->frequency) == timcapp->clock, "invalid frequency"); timcapp->tim->PSC = (uint16_t)psc; timcapp->tim->ARR = timcap_get_max_arr(timcapp); timcapp->tim->CCMR1 = 0; timcapp->tim->CCMR2 = 0; timcapp->tim->CCER = 0; timcapchannel_t chan = TIMCAP_CHANNEL_1; /*go through each non-NULL callback channel and enable the capture register on rising/falling edge*/ for( chan = TIMCAP_CHANNEL_1; chan <= tim_max_channel; chan++ ) { if( timcapp->config->capture_cb_array[chan] == NULL ) { continue; } switch (chan) { case TIMCAP_CHANNEL_1: /*CCMR1_CC1S = 01 = CH1 Input on TI1.*/ timcapp->tim->CCMR1 |= STM32_TIM_CCMR1_CC1S(1); break; case TIMCAP_CHANNEL_2: /*CCMR1_CC2S = 10 = CH2 Input on TI1.*/ timcapp->tim->CCMR1 |= STM32_TIM_CCMR1_CC2S(1); break; case TIMCAP_CHANNEL_3: timcapp->tim->CCMR2 |= STM32_TIM_CCMR2_CC3S(1); break; case TIMCAP_CHANNEL_4: timcapp->tim->CCMR2 |= STM32_TIM_CCMR2_CC4S(1); break; } /* The CCER settings depend on the selected trigger mode. TIMCAP_INPUT_DISABLED: Input not used. TIMCAP_INPUT_ACTIVE_HIGH: Active on rising edge, idle on falling edge. TIMCAP_INPUT_ACTIVE_LOW: Active on falling edge, idle on rising edge.*/ if (timcapp->config->modes[chan] == TIMCAP_INPUT_ACTIVE_HIGH) { switch (chan) { case TIMCAP_CHANNEL_1: timcapp->tim->CCER |= STM32_TIM_CCER_CC1E; break; case TIMCAP_CHANNEL_2: timcapp->tim->CCER |= STM32_TIM_CCER_CC2E; break; case TIMCAP_CHANNEL_3: timcapp->tim->CCER |= STM32_TIM_CCER_CC3E; break; case TIMCAP_CHANNEL_4: timcapp->tim->CCER |= STM32_TIM_CCER_CC4E; break; } } else if (timcapp->config->modes[chan] == TIMCAP_INPUT_ACTIVE_LOW) { switch (chan) { case TIMCAP_CHANNEL_1: timcapp->tim->CCER |= STM32_TIM_CCER_CC1E | STM32_TIM_CCER_CC1P; break; case TIMCAP_CHANNEL_2: timcapp->tim->CCER |= STM32_TIM_CCER_CC2E | STM32_TIM_CCER_CC2P; break; case TIMCAP_CHANNEL_3: timcapp->tim->CCER |= STM32_TIM_CCER_CC3E | STM32_TIM_CCER_CC3P; break; case TIMCAP_CHANNEL_4: timcapp->tim->CCER |= STM32_TIM_CCER_CC4E | STM32_TIM_CCER_CC4P; break; } } else { switch (chan) { case TIMCAP_CHANNEL_1: timcapp->tim->CCER &= ~STM32_TIM_CCER_CC1E; break; case TIMCAP_CHANNEL_2: timcapp->tim->CCER &= ~STM32_TIM_CCER_CC2E; break; case TIMCAP_CHANNEL_3: timcapp->tim->CCER &= ~STM32_TIM_CCER_CC3E; break; case TIMCAP_CHANNEL_4: timcapp->tim->CCER &= ~STM32_TIM_CCER_CC4E; break; } } /* Direct pointers to the capture registers in order to make reading data faster from within callbacks.*/ timcapp->ccr_p[chan] = &timcapp->tim->CCR[chan]; } /* SMCR_TS = 101, input is TI1FP1.*/ timcapp->tim->SMCR = STM32_TIM_SMCR_TS(5); }
/** * @brief Configures and activates the EICU peripheral. * * @param[in] eicup Pointer to the @p EICUDriver object * * @notapi */ void eicu_lld_start(EICUDriver *eicup) { uint32_t psc; size_t ch; osalDbgAssert((eicup->config->iccfgp[0] != NULL) || (eicup->config->iccfgp[1] != NULL) || (eicup->config->iccfgp[2] != NULL) || (eicup->config->iccfgp[3] != NULL), "invalid input configuration"); if (eicup->state == EICU_STOP) { /* Clock activation and timer reset.*/ #if STM32_EICU_USE_TIM1 if (&EICUD1 == eicup) { rccEnableTIM1(FALSE); rccResetTIM1(); nvicEnableVector(STM32_TIM1_UP_NUMBER, STM32_EICU_TIM1_IRQ_PRIORITY); nvicEnableVector(STM32_TIM1_CC_NUMBER, STM32_EICU_TIM1_IRQ_PRIORITY); eicup->channels = 4; #if defined(STM32_TIM1CLK) eicup->clock = STM32_TIM1CLK; #else eicup->clock = STM32_TIMCLK2; #endif } #endif #if STM32_EICU_USE_TIM2 if (&EICUD2 == eicup) { rccEnableTIM2(FALSE); rccResetTIM2(); nvicEnableVector(STM32_TIM2_NUMBER, STM32_EICU_TIM2_IRQ_PRIORITY); eicup->channels = 4; eicup->clock = STM32_TIMCLK1; } #endif #if STM32_EICU_USE_TIM3 if (&EICUD3 == eicup) { rccEnableTIM3(FALSE); rccResetTIM3(); nvicEnableVector(STM32_TIM3_NUMBER, STM32_EICU_TIM3_IRQ_PRIORITY); eicup->channels = 4; eicup->clock = STM32_TIMCLK1; } #endif #if STM32_EICU_USE_TIM4 if (&EICUD4 == eicup) { rccEnableTIM4(FALSE); rccResetTIM4(); nvicEnableVector(STM32_TIM4_NUMBER, STM32_EICU_TIM4_IRQ_PRIORITY); eicup->channels = 4; eicup->clock = STM32_TIMCLK1; } #endif #if STM32_EICU_USE_TIM5 if (&EICUD5 == eicup) { rccEnableTIM5(FALSE); rccResetTIM5(); nvicEnableVector(STM32_TIM5_NUMBER, STM32_EICU_TIM5_IRQ_PRIORITY); eicup->channels = 4; eicup->clock = STM32_TIMCLK1; } #endif #if STM32_EICU_USE_TIM8 if (&EICUD8 == eicup) { rccEnableTIM8(FALSE); rccResetTIM8(); nvicEnableVector(STM32_TIM8_UP_NUMBER, STM32_EICU_TIM8_IRQ_PRIORITY); nvicEnableVector(STM32_TIM8_CC_NUMBER, STM32_EICU_TIM8_IRQ_PRIORITY); eicup->channels = 4; #if defined(STM32_TIM8CLK) eicup->clock = STM32_TIM8CLK; #else eicup->clock = STM32_TIMCLK2; #endif } #endif #if STM32_EICU_USE_TIM9 if (&EICUD9 == eicup) { rccEnableTIM9(FALSE); rccResetTIM9(); nvicEnableVector(STM32_TIM9_NUMBER, STM32_EICU_TIM9_IRQ_PRIORITY); eicup->channels = 2; eicup->clock = STM32_TIMCLK2; } #endif #if STM32_EICU_USE_TIM12 if (&EICUD12 == eicup) { rccEnableTIM12(FALSE); rccResetTIM12(); nvicEnableVector(STM32_TIM12_NUMBER, STM32_EICU_TIM12_IRQ_PRIORITY); eicup->channels = 2; eicup->clock = STM32_TIMCLK1; } #endif #if STM32_EICU_USE_TIM10 if (&EICUD10 == eicup) { rccEnableTIM10(FALSE); rccResetTIM10(); nvicEnableVector(STM32_TIM10_NUMBER, STM32_EICU_TIM10_IRQ_PRIORITY); eicup->channels = 1; eicup->clock = STM32_TIMCLK2; } #endif #if STM32_EICU_USE_TIM11 if (&EICUD11 == eicup) { rccEnableTIM11(FALSE); rccResetTIM11(); nvicEnableVector(STM32_TIM11_NUMBER, STM32_EICU_TIM11_IRQ_PRIORITY); eicup->channels = 1; eicup->clock = STM32_TIMCLK2; } #endif #if STM32_EICU_USE_TIM13 if (&EICUD13 == eicup) { rccEnableTIM13(FALSE); rccResetTIM13(); nvicEnableVector(STM32_TIM13_NUMBER, STM32_EICU_TIM13_IRQ_PRIORITY); eicup->channels = 1; eicup->clock = STM32_TIMCLK1; } #endif #if STM32_EICU_USE_TIM14 if (&EICUD14 == eicup) { rccEnableTIM14(FALSE); rccResetTIM14(); nvicEnableVector(STM32_TIM14_NUMBER, STM32_EICU_TIM14_IRQ_PRIORITY); eicup->channels = 1; eicup->clock = STM32_TIMCLK1; } #endif } else { /* Driver re-configuration scenario, it must be stopped first.*/ eicup->tim->CR1 = 0; /* Timer disabled. */ eicup->tim->DIER = eicup->config->dier &/* DMA-related DIER settings. */ ~STM32_TIM_DIER_IRQ_MASK; eicup->tim->SR = 0; /* Clear eventual pending IRQs. */ eicup->tim->CCR[0] = 0; /* Comparator 1 disabled. */ eicup->tim->CCR[1] = 0; /* Comparator 2 disabled. */ eicup->tim->CNT = 0; /* Counter reset to zero. */ } /* Timer configuration.*/ psc = (eicup->clock / eicup->config->frequency) - 1; chDbgAssert((psc <= 0xFFFF) && ((psc + 1) * eicup->config->frequency) == eicup->clock, "invalid frequency"); eicup->tim->PSC = (uint16_t)psc; eicup->tim->ARR = (eicucnt_t)-1; /* Detect width.*/ if (0xFFFFFFFF == eicup->tim->ARR) eicup->width = EICU_WIDTH_32; else if (0xFFFF == eicup->tim->ARR) eicup->width = EICU_WIDTH_16; else osalSysHalt("Unsupported width"); /* Reset registers */ eicup->tim->SMCR = 0; eicup->tim->CCMR1 = 0; if (eicup->channels > 2) eicup->tim->CCMR2 = 0; /* clean channel structures and set pointers to channel configs */ for (ch=0; ch<EICU_CHANNEL_ENUM_END; ch++) { eicup->channel[ch].last_active = 0; eicup->channel[ch].last_idle = 0; eicup->channel[ch].config = eicup->config->iccfgp[ch]; eicup->channel[ch].state = EICU_CH_IDLE; } /* TIM9 and TIM12 have only 2 channels.*/ if (eicup->channels == 2) { osalDbgCheck((eicup->config->iccfgp[2] == NULL) && (eicup->config->iccfgp[3] == NULL)); } /* TIM10, TIM11, TIM13 and TIM14 have only 1 channel.*/ if (eicup->channels == 1) { osalDbgCheck((eicup->config->iccfgp[1] == NULL) && (eicup->config->iccfgp[2] == NULL) && (eicup->config->iccfgp[3] == NULL)); } start_channels(eicup); }
/** * @brief Configures and activates the QEI peripheral. * * @param[in] qeip pointer to the @p QEIDriver object * * @notapi */ void qei_lld_start(QEIDriver *qeip) { osalDbgAssert((qeip->config->min == 0) || (qeip->config->max == 0), "only min/max set to 0 is supported"); if (qeip->state == QEI_STOP) { /* Clock activation and timer reset.*/ #if STM32_QEI_USE_TIM1 if (&QEID1 == qeip) { rccEnableTIM1(FALSE); rccResetTIM1(); } #endif #if STM32_QEI_USE_TIM2 if (&QEID2 == qeip) { rccEnableTIM2(FALSE); rccResetTIM2(); } #endif #if STM32_QEI_USE_TIM3 if (&QEID3 == qeip) { rccEnableTIM3(FALSE); rccResetTIM3(); } #endif #if STM32_QEI_USE_TIM4 if (&QEID4 == qeip) { rccEnableTIM4(FALSE); rccResetTIM4(); } #endif #if STM32_QEI_USE_TIM5 if (&QEID5 == qeip) { rccEnableTIM5(FALSE); rccResetTIM5(); } #endif #if STM32_QEI_USE_TIM8 if (&QEID8 == qeip) { rccEnableTIM8(FALSE); rccResetTIM8(); } #endif } /* Timer configuration.*/ qeip->tim->CR1 = 0; /* Initially stopped. */ qeip->tim->CR2 = 0; qeip->tim->PSC = 0; qeip->tim->DIER = 0; qeip->tim->ARR = 0xFFFF; /* Set Capture Compare 1 and Capture Compare 2 as input. */ qeip->tim->CCMR1 |= TIM_CCMR1_CC1S_0 | TIM_CCMR1_CC2S_0; if (qeip->config->mode == QEI_MODE_QUADRATURE) { if (qeip->config->resolution == QEI_BOTH_EDGES) qeip->tim->SMCR = TIM_SMCR_SMS_1 | TIM_SMCR_SMS_0; else qeip->tim->SMCR = TIM_SMCR_SMS_0; } else { /* Direction/Clock mode. * Direction input on TI1, Clock input on TI2. */ qeip->tim->SMCR = TIM_SMCR_SMS_0; } if (qeip->config->dirinv == QEI_DIRINV_TRUE) qeip->tim->CCER = TIM_CCER_CC1E | TIM_CCER_CC1P | TIM_CCER_CC2E; else qeip->tim->CCER = TIM_CCER_CC1E | TIM_CCER_CC2E; }
/** * @brief Configures and activates the ICU peripheral. * * @param[in] icup pointer to the @p ICUDriver object * * @notapi */ void icu_lld_start(ICUDriver *icup) { uint32_t psc; if (icup->state == ICU_STOP) { /* Clock activation and timer reset.*/ #if STM32_ICU_USE_TIM1 if (&ICUD1 == icup) { rccEnableTIM1(FALSE); rccResetTIM1(); nvicEnableVector(TIM1_CC_IRQn, CORTEX_PRIORITY_MASK(STM32_ICU_TIM1_IRQ_PRIORITY)); icup->clock = STM32_TIMCLK2; } #endif #if STM32_ICU_USE_TIM2 if (&ICUD2 == icup) { rccEnableTIM2(FALSE); rccResetTIM2(); nvicEnableVector(TIM2_IRQn, CORTEX_PRIORITY_MASK(STM32_ICU_TIM2_IRQ_PRIORITY)); icup->clock = STM32_TIMCLK1; } #endif #if STM32_ICU_USE_TIM3 if (&ICUD3 == icup) { rccEnableTIM3(FALSE); rccResetTIM3(); nvicEnableVector(TIM3_IRQn, CORTEX_PRIORITY_MASK(STM32_ICU_TIM3_IRQ_PRIORITY)); icup->clock = STM32_TIMCLK1; } #endif #if STM32_ICU_USE_TIM4 if (&ICUD4 == icup) { rccEnableTIM4(FALSE); rccResetTIM4(); nvicEnableVector(TIM4_IRQn, CORTEX_PRIORITY_MASK(STM32_ICU_TIM4_IRQ_PRIORITY)); icup->clock = STM32_TIMCLK1; } #endif #if STM32_ICU_USE_TIM5 if (&ICUD5 == icup) { rccEnableTIM5(FALSE); rccResetTIM5(); nvicEnableVector(TIM5_IRQn, CORTEX_PRIORITY_MASK(STM32_ICU_TIM5_IRQ_PRIORITY)); icup->clock = STM32_TIMCLK1; } #endif #if STM32_ICU_USE_TIM8 if (&ICUD8 == icup) { rccEnableTIM5(FALSE); rccResetTIM5(); nvicEnableVector(TIM8_CC_IRQn, CORTEX_PRIORITY_MASK(STM32_ICU_TIM8_IRQ_PRIORITY)); icup->clock = STM32_TIMCLK2; } #endif } else { /* Driver re-configuration scenario, it must be stopped first.*/ icup->tim->CR1 = 0; /* Timer disabled. */ icup->tim->DIER = 0; /* All IRQs disabled. */ icup->tim->SR = 0; /* Clear eventual pending IRQs. */ icup->tim->CCR[0] = 0; /* Comparator 1 disabled. */ icup->tim->CCR[1] = 0; /* Comparator 2 disabled. */ icup->tim->CNT = 0; /* Counter reset to zero. */ } /* Timer configuration.*/ psc = (icup->clock / icup->config->frequency) - 1; chDbgAssert((psc <= 0xFFFF) && ((psc + 1) * icup->config->frequency) == icup->clock, "icu_lld_start(), #1", "invalid frequency"); icup->tim->PSC = (uint16_t)psc; icup->tim->ARR = 0xFFFF; /* CCMR1_CC1S = 01 = CH1 Input on TI1. CCMR1_CC2S = 10 = CH2 Input on TI1.*/ icup->tim->CCMR1 = TIM_CCMR1_CC1S_0 | TIM_CCMR1_CC2S_1; /* SMCR_TS = 101, input is TI1FP1. SMCR_SMS = 100, reset on rising edge.*/ icup->tim->SMCR = TIM_SMCR_TS_2 | TIM_SMCR_TS_0 | TIM_SMCR_SMS_2; /* The CCER settings depend on the selected trigger mode. ICU_INPUT_ACTIVE_HIGH: Active on rising edge, idle on falling edge. ICU_INPUT_ACTIVE_LOW: Active on falling edge, idle on rising edge.*/ if (icup->config->mode == ICU_INPUT_ACTIVE_HIGH) icup->tim->CCER = TIM_CCER_CC1E | TIM_CCER_CC2E | TIM_CCER_CC2P; else icup->tim->CCER = TIM_CCER_CC1E | TIM_CCER_CC1P | TIM_CCER_CC2E; }