cancel
Showing results for 
Search instead for 
Did you mean: 

PWM Capture with EXTI Interrupts: Eliminating Noise Spikes

GroundSky
Visitor

Hello guys,

 

I am currently creating a drone using a BluePill STM32F103 and IDECube. I need to read PWM signals from a receiver (FS-IA10B) that provides me a 50Hz signal with a duty cycle between 5% and 10% (I am using a flysky transmiter)

I don't have enough timers on the BluePill (only x4) to read PWM with the function 'Combined Channels' and, at the same time, generate PWM using the function 'PWM Generation.' So, I came up with the idea to use EXTI pins to measure the high state of my 4x pins. The results I got are really precise, but the problem I am currently facing is that I randomly get some 'spikes' on some of the 4x pins.

For information, I am using Timer1 with a prescaler of (72 - 1) and counting to 65535 in order to have a resolution of 1us. I manage the buffer overflow of Timer1 as well in my callback.

 

The spikes looks like that (Thrust channel in blue):

spikes.pngThe spikes are really high at the beginning, and they start to slow down and eventually disappear for some time, before coming back again.

My interrupt code looks like that:

 

 

...
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
    if(GPIO_Pin == PWM_Killswitch_Pin){ // Killswitch PWM measure
        uint32_t Current_Ticks = __HAL_TIM_GET_COUNTER(&htim1);
        uint32_t PWM_Time = 0;
        static uint32_t Previous_Killswitch_Ticks = 0;
 
        if(HAL_GPIO_ReadPin(PWM_Killswitch_GPIO_Port, PWM_Killswitch_Pin)){
            Previous_Killswitch_Ticks = Current_Ticks;
        }
        else{
            if(Current_Ticks >= Previous_Killswitch_Ticks){
                PWM_Time = Current_Ticks - Previous_Killswitch_Ticks;
            }
            else{
                PWM_Time = 0xFFFF - Previous_Killswitch_Ticks + Current_Ticks + 1;
            }
        }
 
        if(PWM_Time > 1300){
            KILL_SWITCH = true;
 
            PWM_CHANNEL1_PERIOD = 1750;
            PWM_CHANNEL2_PERIOD = 1750;
            PWM_CHANNEL3_PERIOD = 1750;
            PWM_CHANNEL4_PERIOD = 1750;
            __HAL_TIM_SET_COMPARE(&htim2, TIM_CHANNEL_1, 1750);
            __HAL_TIM_SET_COMPARE(&htim2, TIM_CHANNEL_2, 1750);
            __HAL_TIM_SET_COMPARE(&htim2, TIM_CHANNEL_3, 1750);
            __HAL_TIM_SET_COMPARE(&htim2, TIM_CHANNEL_4, 1750);
 
            HAL_GPIO_TogglePin(LED_13_GPIO_Port, LED_13_Pin);
            Error_Handler();
        }
 
    }
 
    else if(GPIO_Pin == PWM_Roll_Pin){
        uint32_t Current_Ticks = __HAL_TIM_GET_COUNTER(&htim1);
        static uint32_t Previous_Roll_Ticks = 0;
 
        if(HAL_GPIO_ReadPin(PWM_Roll_GPIO_Port, PWM_Roll_Pin)){
            Previous_Roll_Ticks = Current_Ticks;
        }
        else{
            if(Current_Ticks >= Previous_Roll_Ticks){
                PWM_Roll = Current_Ticks - Previous_Roll_Ticks;
            }
            else{
                PWM_Roll = 0xFFFF - Previous_Roll_Ticks + Current_Ticks + 1;
            }
        }
    }
 
    else if(GPIO_Pin == PWM_Pitch_Pin){
        uint32_t Current_Ticks = __HAL_TIM_GET_COUNTER(&htim1);
        static uint32_t Previous_Pitch_Ticks = 0;
 
        if(HAL_GPIO_ReadPin(PWM_Pitch_GPIO_Port, PWM_Pitch_Pin)){
            Previous_Pitch_Ticks = Current_Ticks;
        }
        else{
            if(Current_Ticks >= Previous_Pitch_Ticks){
                PWM_Pitch = Current_Ticks - Previous_Pitch_Ticks;
            }
            else{
                PWM_Pitch = 0xFFFF - Previous_Pitch_Ticks + Current_Ticks + 1;
            }
        }
    }
 
    else if(GPIO_Pin == PWM_Thrust_Pin){
        uint32_t Current_Ticks = __HAL_TIM_GET_COUNTER(&htim1);
        static uint32_t Previous_Thrust_Ticks = 0;
 
        if(HAL_GPIO_ReadPin(PWM_Thrust_GPIO_Port, PWM_Thrust_Pin)){
            Previous_Thrust_Ticks = Current_Ticks;
        }
        else{
            if(Current_Ticks >= Previous_Thrust_Ticks){
                PWM_Thrust = Current_Ticks - Previous_Thrust_Ticks;
            }
            else{
                PWM_Thrust = 0xFFFF - Previous_Thrust_Ticks + Current_Ticks + 1;
            }
        }
    }
 
    else if(GPIO_Pin == PWM_Yaw_Pin){
        uint32_t Current_Ticks = __HAL_TIM_GET_COUNTER(&htim1);
        static uint32_t Previous_Yaw_Ticks = 0;
 
        if(HAL_GPIO_ReadPin(PWM_Yaw_GPIO_Port, PWM_Yaw_Pin)){
            Previous_Yaw_Ticks = Current_Ticks;
        }
        else{
            if(Current_Ticks >= Previous_Yaw_Ticks){
                PWM_Yaw = Current_Ticks - Previous_Yaw_Ticks;
            }
            else{
                PWM_Yaw = 0xFFFF - Previous_Yaw_Ticks + Current_Ticks + 1;
            }
        }
    }
}

 

 

 

I believe that some other higher-priority interrupt occurs at the same time, causing my timer to keep running during the other interrupt. However, even after setting my callback to the highest priority and all other interrupts to a lower priority (just for the test), I still encounter the same problem.

 

Do you guys have any ideas where the problem might be?

Thank you in advance for your help.

Sorry for my English; it is not my native language.

2 REPLIES 2
Carl_G
Senior

Using input capture won't be susceptible to cpu load based delays like manual counting and capturing will be.

Your graph showed some pulses. Are you calling those spikes? Or did i look at the wrong graph?

 

Thank you for your answer, Carl_G.

Yes, I believe "pulses" is a better word than "spikes". On the graph, you can count approximately ~12-13 pulses on the blue curve.

My first intuition was that the line below in my callbacks:

__HAL_TIM_GET_COUNTER(&htim1);

was still counting a little bit more (causing the pulse) during the activation of another unknown callback with a higher priority than my own PWM counting callback. The pulses happens approximately every 20 seconds. There is sometime only one pulse, sometime 6, sometime more...

I haven't resolved the problem yet; I just came up with a temporary solution by averaging 30 values to "smooth" the curve. However, this adds calculation time to the CPU, so it's not a good and final solution.