Example #1
0
/**
 * @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);
}
Example #2
0
/**
 * @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
}
Example #3
0
/**
 * @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];
  }
}
Example #4
0
/**
 * @brief Init function executed in first lines of tests. Started properly Chibios and ARM
 */
void init(void)
{
	/*
	 * System initializations.
	 * - HAL initialization, this also initializes the configured device drivers
	 *   and performs the board-specific initializations.
	 * - Kernel initialization, the main() function becomes a thread and the
	 *   RTOS is active.
	 */
	halInit();
	chSysInit();

        /* Timer configuration.*/
        rccEnableTIM3(FALSE);
        rccResetTIM3();
        rccEnableTIM4(FALSE);
        rccResetTIM4();

        TIM3->CR1  = 0;                          /* Initially stopped.       */
        TIM4->CR1  = 0;                          /* Initially stopped.       */

        TIM3->CR2  = TIM_CR2_MMS_1;
        TIM3->PSC  = ((STM32_TIMCLK2 / 1000000) - 1);                        /* Prescaler value.         */
        TIM3->SR   = 0;                          /* Clear pending IRQs.      */
        TIM3->DIER = 0;
        TIM3->SMCR = TIM_SMCR_MSM;

        TIM4->CR2  = 0;
        TIM4->PSC  = 0;                        /* Prescaler value.         */
        TIM4->SR   = 0;                          /* Clear pending IRQs.      */
        TIM4->DIER = 0;
        TIM4->SMCR = TIM_SMCR_TS_1 | TIM_SMCR_MSM | TIM_SMCR_SMS_2 | TIM_SMCR_SMS_1 | TIM_SMCR_SMS_0;

        TIM4->CR1 = TIM_CR1_CEN;

        TIM3->CNT  = 0;                          /* Initially stopped.       */
        TIM4->CNT  = 0;                          /* Initially stopped.       */

        start_count_time();
        chThdSleepMilliseconds(1000);
        stop_count_time();

        /*
         * Initializes a serial-over-USB CDC driver.
         */
        sduObjectInit(&SDU1);
        sduStart(&SDU1, &serusbcfg);

        /*
         * Activates the USB driver and then the USB bus pull-up on D+.
         * Note, a delay is inserted in order to not have to disconnect the cable
         * after a reset.
         */
        usbDisconnectBus(serusbcfg.usbp);
        chThdSleepMilliseconds(250);
        usbStart(serusbcfg.usbp, &usbcfg);
        usbConnectBus(serusbcfg.usbp);

        /*
         * Stopping and restarting the USB in order to test the stop procedure. The
         * following lines are not usually required.
         */
        chThdSleepMilliseconds(3000);
	info("---------------ECDSA ECDH Test Suite---------------");
        info("CPU frequency %f MHz", STM32_SYSCLK/1000000.0);
	info("---------------------------------------------------");
        info("-----------------Timer second test-----------------");
        info("Start timer and wait 1 sec");
        start_count_time();
        chThdSleepMilliseconds(1000);
        stop_count_time();
        info("Timer result 1sec = %u us", get_us());
        info("---------------------------------------------------");
}
Example #5
0
/**
 * @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;
}
Example #6
0
/**
 * @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);
}
Example #9
0
/**
 * @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;
}
Example #10
0
/**
 * @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;
}