/** * @brief Starts the PWM output. * @note The pwmStart() function used in this code is not * the original ChibiOS HAL function, but modified * one with STM32_TIM_CR1_CEN flag removed. * @return none. */ void pwmOutputStart(void) { #if STM32_PWM_USE_ADVANCED /* Get dead-time generator value for TIM1. */ uint32_t bdtr_dt = pwmOutputGetBDTRDeadTime(g_pwmOutput[PWM_OUT_ROLL].dt_cmd_id & PWM_OUT_DT_ID_MASK); pwmcfg_d1_d8.bdtr |= bdtr_dt; #endif pwmStart(&PWMD1, &pwmcfg_d1_d8); #if STM32_PWM_USE_ADVANCED /* Clear bdtr_dt value from previous calculation. */ pwmcfg_d1_d8.bdtr &= ~bdtr_dt; /* Get dead-time generator value for TIM8. */ bdtr_dt = pwmOutputGetBDTRDeadTime(g_pwmOutput[PWM_OUT_PITCH].dt_cmd_id & PWM_OUT_DT_ID_MASK); pwmcfg_d1_d8.bdtr |= bdtr_dt; #endif /* Configure TIM8 as master timer: */ pwmcfg_d1_d8.cr2 = STM32_TIM_CR2_MMS(1); // Master mode set to Enable; pwmStart(&PWMD8, &pwmcfg_d1_d8); switch (g_pwmOutput[PWM_OUT_YAW].dt_cmd_id & PWM_OUT_DT_ID_MASK) { case PWM_OUT_DT750NS: pwmOutTIM4_5_DT = PWM_OUT_TIM4_5_DT_US7; break; case PWM_OUT_DT1000NS: pwmOutTIM4_5_DT = PWM_OUT_TIM4_5_DT_1US; break; case PWM_OUT_DT2000NS: pwmOutTIM4_5_DT = PWM_OUT_TIM4_5_DT_2US; break; case PWM_OUT_DT3000NS: pwmOutTIM4_5_DT = PWM_OUT_TIM4_5_DT_3US; break; case PWM_OUT_DT4000NS: pwmOutTIM4_5_DT = PWM_OUT_TIM4_5_DT_4US; break; case PWM_OUT_DT5000NS: pwmOutTIM4_5_DT = PWM_OUT_TIM4_5_DT_5US; break; default: pwmOutTIM4_5_DT = PWM_OUT_TIM4_5_DT_5US; } pwmStart(&PWMD4, &pwmcfg_d4); pwmStart(&PWMD5, &pwmcfg_d5); /* Configure TIM5 as slave timer: */ PWMD5.tim->SMCR = STM32_TIM_SMCR_SMS(6) | // Trigger Mode; STM32_TIM_SMCR_TS(3); // Trigger event comes from TIM8; /* Configure TIM4 as slave timer: */ PWMD4.tim->SMCR = STM32_TIM_SMCR_SMS(6) | // Trigger Mode; STM32_TIM_SMCR_TS(3); // Trigger event comes from TIM8; /* Switch to center-aligned mode 1 and start timers. */ PWMD5.tim->CR1 |= (STM32_TIM_CR1_CMS(1)); // This is a slave timer - do not start; PWMD4.tim->CR1 |= (STM32_TIM_CR1_CMS(1)); // This is a slave timer - do not start; PWMD1.tim->CR1 |= (STM32_TIM_CR1_CMS(1) | STM32_TIM_CR1_CEN); PWMD8.tim->CR1 |= (STM32_TIM_CR1_CMS(1) | STM32_TIM_CR1_CEN); // Start TIM8, TIM4 and TIM5 simultaneously; }
/** * @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]; } }