/**
 * @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);
}
Example #2
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];
  }
}
/**
 * @brief   Starts every channel.
 *
 * @param[in] eicup     Pointer to the @p EICUDriver object
 */
static void start_channels(EICUDriver *eicup) {

  /* Set each input channel that is used as: a normal input capture channel,
     link the corresponding CCR register and set polarity. */

  /* Input capture channel 1 */
  if (eicup->config->iccfgp[0] != NULL) {
    /* Normal capture input input */
    eicup->tim->CCMR1 |= STM32_TIM_CCMR1_CC1S(1);

    /* Link CCR register */
    eicup->channel[0].ccrp = &eicup->tim->CCR[0];

    /* Set input polarity */
    if (eicup->config->iccfgp[0]->alvl == EICU_INPUT_ACTIVE_HIGH)
      eicup->tim->CCER |= STM32_TIM_CCER_CC1E;
    else
      eicup->tim->CCER |= STM32_TIM_CCER_CC1E | STM32_TIM_CCER_CC1P;
  }

  /* Input capture channel 2 */
  if (eicup->config->iccfgp[1] != NULL) {
    /* Normal capture input input */
    eicup->tim->CCMR1 |= STM32_TIM_CCMR1_CC2S(1);

    /* Link CCR register */
    eicup->channel[1].ccrp = &eicup->tim->CCR[1];

    /* Set input polarity */
    if (eicup->config->iccfgp[1]->alvl == EICU_INPUT_ACTIVE_HIGH)
      eicup->tim->CCER |= STM32_TIM_CCER_CC2E;
    else
      eicup->tim->CCER |= STM32_TIM_CCER_CC2E | STM32_TIM_CCER_CC2P;
  }

  /* Input capture channel 3 (not for TIM 9 and 12) */
  if (eicup->config->iccfgp[2] != NULL) {
    /* Normal capture input input */
    eicup->tim->CCMR2 |= STM32_TIM_CCMR2_CC3S(1);

    /* Link CCR register */
    eicup->channel[2].ccrp = &eicup->tim->CCR[2];

    /* Set input polarity */
    if (eicup->config->iccfgp[2]->alvl == EICU_INPUT_ACTIVE_HIGH)
      eicup->tim->CCER |= STM32_TIM_CCER_CC3E;
    else
      eicup->tim->CCER |= STM32_TIM_CCER_CC3E | STM32_TIM_CCER_CC3P;
  }

  /* Input capture channel 4 (not for TIM 9 and 12) */
  if (eicup->config->iccfgp[3] != NULL) {
    /* Normal capture input input */
    eicup->tim->CCMR2 |= STM32_TIM_CCMR2_CC4S(1);

    /* Link CCR register */
    eicup->channel[3].ccrp = &eicup->tim->CCR[3];

    /* Set input polarity */
    if (eicup->config->iccfgp[3]->alvl == EICU_INPUT_ACTIVE_HIGH)
      eicup->tim->CCER |= STM32_TIM_CCER_CC4E;
    else
      eicup->tim->CCER |= STM32_TIM_CCER_CC4E | STM32_TIM_CCER_CC4P;
  }
}