AnsweredAssumed Answered

4 Input PWM and 4 output PWM

Question asked by wybranczyk.dominik on Nov 14, 2011
Latest reply on Nov 16, 2011 by wybranczyk.dominik
Helo,
I have difficult situation with STM32F103VB uc. I need to capture and check 4 input PWM, and generate also 4 PWM.

In this uc I have only TIM1 to TIM4, so I can't check PWM iputs with timers special function and generate 4 pwm at the same time.

I figured out a solution with EXTI interrupts, but it dont work as it should, and I dont know where the error is.

The idea:
Connect PWM inputs to EXTI, configure it for rising of falling edges. Like so:
PWM1 -> PD12 // rising edge - to calculate duty
PWM1 -> PD11 // falling edge -  calculate PWM1 duty cycle
PWM2 -> PD10 // falling edge -  calculate PWM2 duty cycle
PWM3 -> PD9  // falling edge -  calculate PWM3 duty cycle
PWM4 -> PD8  // falling edge -  calculate PWM4 duty cycle

1) Start the timer TIM2
2) interrupt by PD12, set TIM2 counter to 0, start counting.
3) if Interrupt by PD8 - PD11 -> get TIM2->CNT, and write it to tGetCnt[number]
4) Interrupt by PD12 -> get TIM2->CNT  as it is the whole duty.
5) Calculate the whole duty, frequency, and duty cycle for inputs.
6) go to 1).

Unfortunately the calculations that I do give strange results - like duty cycle above 100% and so on. (like 5000% or 104%, what is impossible).

This is my code:
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// TIMER 2 conf:
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void TIM2_Conf(void)
{

    TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
    TIM_OCInitTypeDef  TIM_OCInitStructure;

    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);

      TIM_TimeBaseStructure.TIM_Period = 65000;
      TIM_TimeBaseStructure.TIM_Prescaler = 0;
      TIM_TimeBaseStructure.TIM_ClockDivision = 0;
      TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;

      TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);

      TIM_Cmd(TIM2, ENABLE);
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// EXTI:
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void EXTI_Conf(void)
{
    EXTI_InitTypeDef EXTI_InitStructure;
    GPIO_InitTypeDef GPIO_InitStructure;
    NVIC_InitTypeDef NVIC_InitStructure;

  // Enable GPIOD clock
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOD, ENABLE);

  // Configure PD8-12 pins as input floating
        // todo ewentualnie mozna pd12 zamienic bo to jest tim4_ch1;
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8|GPIO_Pin_9|GPIO_Pin_10|GPIO_Pin_11|GPIO_Pin_12;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
  GPIO_Init(GPIOD, &GPIO_InitStructure);

  // Enable AFIO clock
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);

  // Connect EXTI Lines to PD8-12 pins
  GPIO_EXTILineConfig(GPIO_PortSourceGPIOD, GPIO_PinSource8);
  GPIO_EXTILineConfig(GPIO_PortSourceGPIOD, GPIO_PinSource9);
  GPIO_EXTILineConfig(GPIO_PortSourceGPIOD, GPIO_PinSource10);
  GPIO_EXTILineConfig(GPIO_PortSourceGPIOD, GPIO_PinSource11);
  GPIO_EXTILineConfig(GPIO_PortSourceGPIOD, GPIO_PinSource12);


  // Configure EXTI lines
  // PD8-11 Get Counter;
  EXTI_InitStructure.EXTI_Line = EXTI_Line8;
  EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
  EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;
  EXTI_InitStructure.EXTI_LineCmd = ENABLE;
  EXTI_Init(&EXTI_InitStructure);

  EXTI_InitStructure.EXTI_Line = EXTI_Line9;
  EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
  EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;
  EXTI_InitStructure.EXTI_LineCmd = ENABLE;
  EXTI_Init(&EXTI_InitStructure);

  EXTI_InitStructure.EXTI_Line = EXTI_Line10;
  EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
  EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;
  EXTI_InitStructure.EXTI_LineCmd = ENABLE;
  EXTI_Init(&EXTI_InitStructure);

  EXTI_InitStructure.EXTI_Line = EXTI_Line11;
  EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
  EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;
  EXTI_InitStructure.EXTI_LineCmd = ENABLE;
  EXTI_Init(&EXTI_InitStructure);

  // PD12 Get Counter, calculate, reset timer2
  EXTI_InitStructure.EXTI_Line = EXTI_Line12;
  EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
  EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising;
  EXTI_InitStructure.EXTI_LineCmd = ENABLE;
  EXTI_Init(&EXTI_InitStructure);


  // Enable and set EXTI9_5 Interrupt to the lowest priority
  NVIC_InitStructure.NVIC_IRQChannel = EXTI9_5_IRQn;
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x03;
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x0F;
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  NVIC_Init(&NVIC_InitStructure);

  // Enable and set EXTI15_10 Interrupt to the lowest+1 priority
  NVIC_InitStructure.NVIC_IRQChannel = EXTI15_10_IRQn;
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x03;
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x0E;
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  NVIC_Init(&NVIC_InitStructure);
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Interrupt handlers form stm32f10x_it.c
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void EXTI9_5_IRQHandler(void)
{
    uint32_t tTemp[5];

    if(EXTI_GetITStatus(EXTI_Line8) != RESET)
    {

        tGetCnt[1] = TIM2->CNT;
        EXTI_ClearITPendingBit(EXTI_Line8);
    }
    else if(EXTI_GetITStatus(EXTI_Line9) != RESET)
    {
        tGetCnt[2] = TIM2->CNT;
        EXTI_ClearITPendingBit(EXTI_Line9);
    }
    else while(1);  // błąd
}


void EXTI15_10_IRQHandler(void)
{

    uint32_t tTemp[5];

    if(EXTI_GetITStatus(EXTI_Line10) != RESET)
    {
        tGetCnt[3] = TIM2->CNT;
        EXTI_ClearITPendingBit(EXTI_Line10);
    }
    else if(EXTI_GetITStatus(EXTI_Line11) != RESET)
    {
        tGetCnt[4] = TIM2->CNT;
        EXTI_ClearITPendingBit(EXTI_Line11);
    }
    else if(EXTI_GetITStatus(EXTI_Line12) != RESET)
    {

        tGetCnt[0] = TIM2->CNT;

        TIM_SetCounter(TIM2, 0);

          if (tGetCnt[0] != 0)
          {
            // Obliczenie wsp_wyp - w %
              tWspWyp[1] = tGetCnt[1] * 100 / tGetCnt[0];
              tWspWyp[2] = tGetCnt[2] * 100 / tGetCnt[0];
              tWspWyp[3] = tGetCnt[3] * 100 / tGetCnt[0];
              tWspWyp[4] = tGetCnt[4] * 100 / tGetCnt[0];


            // Wyznaczenie czestotliwosci sygnalu
            tFreq[0] = 72000000 / tGetCnt[0];
          }
          else
          {
              tWspWyp[1] = 0;
              tWspWyp[2] = 0;
              tWspWyp[3] = 0;
              tWspWyp[4] = 0;
            tFreq[0]   = 0;
          }

        EXTI_ClearITPendingBit(EXTI_Line12);

    }
    else while(1); // błąd
}


My last question is - how to generate 50Hz PWM, with my calculations, the prescaler is so big - that I cant fill it in structure.
For example I have found this configuration for TIM1:

      TIM_TimeBaseStructure.TIM_Period = 65535;
      TIM_TimeBaseStructure.TIM_Prescaler = 1440;  //fclk = 72MHz/1440 = 50kHz
      TIM_TimeBaseStructure.TIM_ClockDivision = 0;
      TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
      TIM_TimeBaseInit(TIM1, &TIM_TimeBaseStructure);

OK, so to get 50Hz I should write 14 000 000 to period, its to much. So I fill ClockDivision to max TIM_CKD_DIV4, than I get
72 000 000 / 4 = 18 000 000
To get 50 i need to divide it one more time, by 280 000 but this is still to much.
Is there any way to generate 50Hz with TIM1? Or there is something wrong with my calculations?

Thank you for help

Outcomes