0

I'm trying to measure the pulse width of a signal on the STM32G431RB, and I keep getting random values from the counter registers. I've checked the signal and it's fine (PWM Signal from a receiver).

void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim){

    if (htim -> Instance == TIM2 && htim -> Channel == HAL_TIM_ACTIVE_CHANNEL_1 && state == 0) {
        IC_Val1 = TIM2 -> CNT;
        __HAL_TIM_SET_CAPTUREPOLARITY(&htim2, TIM_CHANNEL_1, TIM_INPUTCHANNELPOLARITY_FALLING);
        state = 1;
    }

    if(htim -> Instance == TIM2 && htim -> Channel == HAL_TIM_ACTIVE_CHANNEL_1 && state == 1){
        IC_CH1 == TIM2 -> CNT;

        if (IC_Val1 > IC_CH1){
            Difference = IC_Val1 - IC_CH1;
        }
        else {
            Difference = (0xffffffff  - IC_CH1) + IC_Val1;
        }

        __HAL_TIM_SET_CAPTUREPOLARITY(&htim2, TIM_CHANNEL_1, TIM_INPUTCHANNELPOLARITY_RISING);
        state = 0;
    }


}

I have determined the capture callback interrupt routine is being called okay, but the "Difference" variable (uint32_T) keeps giving me random numbers.

Apologies for any bad formatting, its my first post lol.

6
  • How is TIM2 configured? How long is the pulse you're trying to measure? Could TIM2 have wrapped multiple times during a pulse? Commented Apr 30, 2023 at 22:02
  • I can't remember the exact config I'm not at home, but the signal is 50hz (20ms) and the register should take at least 100ms to fill up. The pulse is 1 - 2 Ms (for a drone if your familiar) Commented Apr 30, 2023 at 22:21
  • That is the timing for a typical RC micro-servo - it is not specific to "drones" - they have many applications. Commented May 2, 2023 at 5:24
  • You have not included important information. Insufficient context. For example that is the data type of Difference?, Is it declared volatile. An example of the output would be helpful, they may not be truly "random". Also, how are you making this observation? It is possible that the code you are using to read the result is flawed. Commented May 2, 2023 at 5:31
  • There is no reason for a different calculation depending on IC_Val1 > IC_CH1, so long as all data types are unsigned and the same width as TIM2:CNT using Modulo 2^n arithmetic. Commented May 2, 2023 at 5:38

1 Answer 1

0

You are modifying state and the re-testing it. The test for the correct timer should be independent to the test if state which should not then be retested after it is modified.

if (htim -> Instance == TIM2 && 
   htim -> Channel == HAL_TIM_ACTIVE_CHANNEL_1 )
{
    if( state == 0 )
    {
        IC_Val1 = TIM2 -> CNT;
        __HAL_TIM_SET_CAPTUREPOLARITY(&htim2, TIM_CHANNEL_1, TIM_INPUTCHANNELPOLARITY_FALLING);
        state = 1;
    }
    else
    {
        IC_CH1 == TIM2 -> CNT;

        if (IC_Val1 > IC_CH1){
            Difference = IC_Val1 - IC_CH1;
        }
        else {
            Difference = (0xffffffff  - IC_CH1) + IC_Val1;
        }
    
        __HAL_TIM_SET_CAPTUREPOLARITY(&htim2, TIM_CHANNEL_1, TIM_INPUTCHANNELPOLARITY_RISING);
        state = 0;
    }
}

However, the handler is incorrect in any case - that is not how Input Capture works. You are attempting to do in software waht the hardware already does for you. In Input Capture the clock runs and its value us transferred to the input capture register on the external trigger event. The value you need is in the Input Capture register you should not be reading the Counter itself:

enter image description here

Image from https://controllerstech.com/input-capture-in-stm32/

Note that TIMx_CNT continues running, and TIMx_CCR1 contains the time period between trigger events which you are unnecessarily attempting to do in software.

Note also that you could simplify this code by using the dual-edge trigger. Because you know that in this application (from comments RC micro-servo), the mark period is always <= 2ms and the space period >= 18ms, discrimination of the mark from the space is possible without having to know which edge you have just triggered on. Pseudo-code:

if( period < 10ms )
{
    servo_position = period ;
}
Sign up to request clarification or add additional context in comments.

2 Comments

Thanks so much, I will try to implement this now. As for the dual edge, im trying to make the code faster, as there is 10 channels to record, so I want to just capture 1 start point (All channel rising edges start at the same time) and then just have a value for each of the channel falling edges, so im just using channel 1 of the receiver as the start time of all the other channels. Thanks again.
@Brandon your idea to make the code "faster" makes no sense if you use the input capture as described - the timing is handled by the hardware and there is zero software overhead. If you need to use the timer in that way, you should remove the mention of running input capture from your question, because that is not what you are doing.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.