Search code examples
inputembeddedstm32capturepwm

(STM32) Is it possible to capture two different signals using Timer1, CH1 and CH2 only?


I am currently working on a project and I am trying to measure duty cycle and frequency of a two different signals connected to Timer1 (channel 1 and channel 2) PE9 ------> TIM1_CH1 PE11 ------> TIM1_CH2

My plan is to switch between CH1 and CH2 at every 100ms, calling a function named PwmInput_SwitchChannels(BOOL) which contains the right configurations for every channel. In the interrupt function I want to capture the values and to store them in an array of two element of pwm_capture type.

typedef struct
       {
   __IO UInt16            uhIC2Value;
   __IO UInt16            uhDutyCycle;
   __IO UInt32            uwFrequency;
        }
        pwm_capture;
pwm_capture input_capture[2];

The problem is that the captured values for 1 channel ​​do not match the real ones and it seems to be a problem in the PwmInput_SwitchChannels. When I independently tested both channels the code worked very well and the interrupt function was doing its job.

            #define PIN18_PWM_A ((BOOL)  0)
            #define PIN19_PWM_B ((BOOL)  1)

            typedef struct
                    {
               __IO UInt16            uhIC2Value;
               __IO UInt16            uhDutyCycle;
               __IO UInt32            uwFrequency;
                    }
                    pwm_capture;

             pwm_capture input_capture[2];
             BOOL Tim1_Channels = 0;
             UInt16 counter_pwm = 0;


            void HalTim_MainFunction(void)
            {
                if ( FALSE != rb_InitStatus )
                {
                    counter_pwm++;
                    if(counter_pwm % 100 == 0)
                    {
                        Tim1_Channels = ! Tim1_Channels;
                        PwmInput_SwitchChannels(Tim1_Channels);
                    }
                }
                else {
                    ;
                }
            }





            void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
            {
                if(htim->Instance == TIM1)
                {
                switch(Tim1_Channels){
                  case PIN18_PWM_A:
                  {
                    if (htim->Channel == HAL_TIM_ACTIVE_CHANNEL_2)
                    {
                        /* Get the Input Capture value */
                        input_capture[0].uhIC2Value = HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_2);

                        if (input_capture[0].uhIC2Value != 0)
                        {
                            /* Duty cycle computation */
                            input_capture[0].uhDutyCycle = ((HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_1)) * 100) / input_capture[0].uhIC2Value;

                            /* uwFrequency computation
                  TIM1 counter clock = (RCC_Clocks.HCLK_Frequency)/2 */
                            input_capture[0].uwFrequency = (HAL_RCC_GetHCLKFreq()) / input_capture[0].uhIC2Value;
                        }
                        else
                        {
                            input_capture[0].uhDutyCycle = 0;
                            input_capture[0].uwFrequency = 0;
                        }

                    }
                  break;
                  }
                  case PIN19_PWM_B:
                  {
                      if (htim->Channel == HAL_TIM_ACTIVE_CHANNEL_1)
                      {
                          /* Get the Input Capture value */
                          input_capture[1].uhIC2Value = HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_1);

                          if (input_capture[1].uhIC2Value != 0)
                          {
                              /* Duty cycle computation */
                              input_capture[1].uhDutyCycle = ((HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_2)) * 100) / input_capture[1].uhIC2Value;

                              /* uwFrequency computation
                               TIM1 counter clock = (RCC_Clocks.HCLK_Frequency)/2 */
                              input_capture[1].uwFrequency = (HAL_RCC_GetHCLKFreq()) / input_capture[1].uhIC2Value;
                          }
                          else
                          {
                              input_capture[1].uhDutyCycle = 0;
                              input_capture[1].uwFrequency = 0;
                          }

                      }
                  break;
                  }
                  default:
                          Error_Handler();

                }
              }
            }





            void PwmInput_SwitchChannels(BOOL aux)
            {
                TIM_SlaveConfigTypeDef sSlaveConfig_aux = {0};
                TIM_MasterConfigTypeDef sMasterConfig_aux = {0};
                TIM_IC_InitTypeDef sConfigIC_aux = {0};

                /*##-4- Stop the Input Capture in interrupt mode ##########################*/
                 if (HAL_TIM_IC_Stop_IT(&htim1, TIM_CHANNEL_2) != HAL_OK)
                {
                 /* Starting Error */
                 Error_Handler();
                }

                 /*##-5- Stop the Input Capture in interrupt mode ##########################*/
                if (HAL_TIM_IC_Stop_IT(&htim1, TIM_CHANNEL_1) != HAL_OK)
                {
                 /* Starting Error */
                 Error_Handler();
                }

               switch (aux){
               case PIN18_PWM_A:
               {
                        sSlaveConfig_aux.SlaveMode = TIM_SLAVEMODE_RESET;
                        sSlaveConfig_aux.InputTrigger = TIM_TS_TI2FP2;
                        sSlaveConfig_aux.TriggerPolarity = TIM_INPUTCHANNELPOLARITY_RISING;
                        sSlaveConfig_aux.TriggerFilter = 0;
                        if (HAL_TIM_SlaveConfigSynchronization(&htim1, &sSlaveConfig_aux) != HAL_OK)
                        {
                           Error_Handler();
                         }
                        sMasterConfig_aux.MasterOutputTrigger = TIM_TRGO_RESET;
                        sMasterConfig_aux.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
                        if (HAL_TIMEx_MasterConfigSynchronization(&htim1, &sMasterConfig_aux) != HAL_OK)
                         {
                            Error_Handler();
                         }
                         sConfigIC_aux.ICPolarity = TIM_INPUTCHANNELPOLARITY_FALLING;
                         sConfigIC_aux.ICSelection = TIM_ICSELECTION_INDIRECTTI;
                         sConfigIC_aux.ICPrescaler = TIM_ICPSC_DIV1;
                         sConfigIC_aux.ICFilter = 0;
                         if (HAL_TIM_IC_ConfigChannel(&htim1, &sConfigIC_aux, TIM_CHANNEL_1) != HAL_OK)
                         {
                            Error_Handler();
                         }
                         sConfigIC_aux.ICPolarity = TIM_INPUTCHANNELPOLARITY_RISING;
                         sConfigIC_aux.ICSelection = TIM_ICSELECTION_DIRECTTI;
                         if (HAL_TIM_IC_ConfigChannel(&htim1, &sConfigIC_aux, TIM_CHANNEL_2) != HAL_OK)
                         {
                            Error_Handler();
                         }
                        break;
               }
               case PIN19_PWM_B:
               {
                        sSlaveConfig_aux.SlaveMode = TIM_SLAVEMODE_RESET;
                        sSlaveConfig_aux.InputTrigger = TIM_TS_TI1FP1;
                        sSlaveConfig_aux.TriggerPolarity = TIM_INPUTCHANNELPOLARITY_RISING;
                        sSlaveConfig_aux.TriggerFilter = 0;
                        if (HAL_TIM_SlaveConfigSynchronization(&htim1, &sSlaveConfig_aux) != HAL_OK)
                        {
                           Error_Handler();
                         }
                        sMasterConfig_aux.MasterOutputTrigger = TIM_TRGO_RESET;
                        sMasterConfig_aux.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
                        if (HAL_TIMEx_MasterConfigSynchronization(&htim1, &sMasterConfig_aux) != HAL_OK)
                         {
                            Error_Handler();
                         }
                         sConfigIC_aux.ICPolarity = TIM_INPUTCHANNELPOLARITY_FALLING;
                         sConfigIC_aux.ICSelection = TIM_ICSELECTION_INDIRECTTI;
                         sConfigIC_aux.ICPrescaler = TIM_ICPSC_DIV1;
                         sConfigIC_aux.ICFilter = 0;
                         if (HAL_TIM_IC_ConfigChannel(&htim1, &sConfigIC_aux, TIM_CHANNEL_2) != HAL_OK)
                         {
                            Error_Handler();
                         }
                         sConfigIC_aux.ICPolarity = TIM_INPUTCHANNELPOLARITY_RISING;
                         sConfigIC_aux.ICSelection = TIM_ICSELECTION_DIRECTTI;
                         if (HAL_TIM_IC_ConfigChannel(&htim1, &sConfigIC_aux, TIM_CHANNEL_1) != HAL_OK)
                         {
                            Error_Handler();
                         }
                        break;
                }
                default:
                      Error_Handler();

                 /*##-4- Start the Input Capture in interrupt mode ##########################*/
                if (HAL_TIM_IC_Start_IT(&htim1, TIM_CHANNEL_2) != HAL_OK)
                {
                  /* Starting Error */
                  Error_Handler();
                }

                 /*##-5- Start the Input Capture in interrupt mode ##########################*/
                if (HAL_TIM_IC_Start_IT(&htim1, TIM_CHANNEL_1) != HAL_OK)
                {
                  /* Starting Error */
                  Error_Handler();
                }
            }
            }

My intention is to switch correctly between the two channels (only using Tim1_CH1 and Tim1_CH2, due to the hardware limitations) without affect the results and the performance.


Solution

  • One possible cause is that Tim1_Channels is not declared volatile. It is written to in the main function, and accessed in the interrupt handler. Lacking the volatile qualifier, nothing prevents the optimizer to hold the value in a register, and never write it back to memory. As far as the optimizer knows, the interrupt handler where the value is accessesd, is never called from the main program.