cancel
Showing results for 
Search instead for 
Did you mean: 

PWM input capture

kmorri2004
Associate II
Posted on March 17, 2010 at 08:23

Hello,

I'm attempting to design a stabilization system for a hobby level RC-UAV, using stm8s Discovery dev board.

Right Now I'm just trying to get the mcu to:

1)Capture the input signals on-time and off-time, and store them in respective variables.

2)Output a PWM signal that identical to the input, as well as adjust the on-time and off-time to match.

So far I haven't had any success, if anybody has any suggestions or advice it would be much appreciated. The code that I have gotten the closest to working is the TIM1 or 2 Input capture example included with the firmware. Here's a copy of the portion I use.

/**

  ******************************************************************************

  * @file TIM2_Input_Capture\main.c

  * @brief This file contains the main function for TIM2 Input Capture example.

  * @author STMicroelectronics - MCD Application Team

  * @version V1.1.1

  * @date 06/05/2009

  ******************************************************************************

  *

  * THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS

  * WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE

  * TIME. AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY

  * DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING

  * FROM THE CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE

  * CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.

  *

  * <h2><center>&copy; COPYRIGHT 2009 STMicroelectronics</center></h2>

  * @image html logo.bmp

  ******************************************************************************

  */

/* Includes ------------------------------------------------------------------*/

#include ''stm8s.h''

/**

  * @addtogroup TIM2_Input_Capture

  * @{

  */

/* Private typedef -----------------------------------------------------------*/

/* Private define ------------------------------------------------------------*/

#define TIM2ClockFreq  ((u32)2000000)

/* Private macro -------------------------------------------------------------*/

/* Private variables ---------------------------------------------------------*/

u32 LSIClockFreq = 0;

u16 ICValue1 =0, ICValue2 =0;

void main(void)

{

 

    /* Capture only every 8 events!!! */

  /* Enable capture of TI1 */

    TIM2_ICInit(TIM2_CHANNEL_1, TIM2_ICPOLARITY_FALLING, TIM2_ICSELECTION_DIRECTTI, TIM2_ICPSC_DIV8, 0x00);

 

    /* Enable CC1 interrupt */

    TIM2_ITConfig(TIM2_IT_CC1, ENABLE);

   

    /* Enable TIM2 */

  TIM2_Cmd(ENABLE);

       

    /* Clear CC1 Flag*/

  TIM2_ClearFlag(TIM2_FLAG_CC1);

 

    /* Connect LSI to COO pin*/

  GPIO_Init(GPIOE, GPIO_PIN_0, GPIO_MODE_OUT_PP_LOW_FAST);

    CLK_CCOConfig(CLK_OUTPUT_LSI);

    CLK_CCOCmd(ENABLE);

   

   

    /* wait a capture on CC1 */

  while((TIM2->SR1 & TIM2_FLAG_CC1) != TIM2_FLAG_CC1);

  /* Get CCR1 value*/

    ICValue1 = TIM2_GetCapture1();

    TIM2_ClearFlag(TIM2_FLAG_CC1);

 

    /* wait a capture on cc1 */

  while((TIM2->SR1 & TIM2_FLAG_CC1) != TIM2_FLAG_CC1);

  /* Get CCR1 value*/

    ICValue2 = TIM2_GetCapture1();

    TIM2_ClearFlag(TIM2_FLAG_CC1);

  /* Compute LSI clock frequency */

  LSIClockFreq = (8 * TIM2ClockFreq) / (ICValue2 - ICValue1);

 

    /* Insert a break point here */

  while (1);  

}

11 REPLIES 11
kmorri2004
Associate II
Posted on March 21, 2010 at 00:57

I'm not sure what you mean by synchronization of the signals.

As for id the pwm frame is constant yes and no, yes its constant but its closer to 20ms exactly, and no because it does shift slightly but only by 1ms.

I wanted the off-time originaly because that was the only was I was able to get the 1ms-2ms on-time output, not realizing that pwm mode 2 on the outputs is a beter choice for this and I have since switch the outputs from pwm1 mode to pwm2 which is working much beter, since I can just send the cptured value directly to the output with a few exceptions in ch3 and 4 since the capture after ch2 so their values are the sum of the previous channels and that channel combined so there is a little math involved but not much.

I have also fixed most of my servo signal outputs except for CH1 it works now but incorrectly, instead of stay at say the neutral servo position it oscillates but I pinpointed it down to me using TI1F_ED to reset the counter at the start of the pulse sequence, and still be able to get a usable capture value for CH1.

Here's a revised version with all the updates.

#include ''stm8s.h''

u16 CH1on =0, CH2on =0, CH3on = 0, CH4on = 0;

u16 CH1ontime = 0, CH2ontime = 0, CH3ontime = 0, CH4ontime = 0;

u16 dtcy = 0, periodcount = 40100, periodcountX = 0, periodcounty = 0, periodcountz = 0;

void main(void){

   

    TIM1_DeInit();

       

    /* Enable capture*/

    TIM1_ICInit(TIM1_CHANNEL_1, TIM1_ICPOLARITY_RISING, TIM1_ICSELECTION_DIRECTTI, TIM1_ICPSC_DIV8, 0);

    TIM1_ICInit(TIM1_CHANNEL_2, TIM1_ICPOLARITY_FALLING, TIM1_ICSELECTION_DIRECTTI, TIM1_ICPSC_DIV1, 0);

    TIM1_ICInit(TIM1_CHANNEL_3, TIM1_ICPOLARITY_FALLING, TIM1_ICSELECTION_DIRECTTI, TIM1_ICPSC_DIV1, 0);

    TIM1_ICInit(TIM1_CHANNEL_4, TIM1_ICPOLARITY_FALLING, TIM1_ICSELECTION_DIRECTTI, TIM1_ICPSC_DIV1, 0);

       

    /*Set TIM1 SMCR register to trigger counter reset on Ch1 Rising Edge*/

    TIM1->SMCR = 0x44;

       

    /* Enable TIM2 */

  TIM1_Cmd(ENABLE);

   

    /* Enable CC1 interrupt */

    TIM1_ITConfig(TIM1_IT_CC1, ENABLE);

    TIM1_ITConfig(TIM1_IT_CC2, ENABLE);

    TIM1_ITConfig(TIM1_IT_CC3, ENABLE);

    TIM1_ITConfig(TIM1_IT_CC4, ENABLE);

       

    /* Clear CC1 Flag*/

  TIM1_ClearFlag(TIM1_FLAG_CC1);

    TIM1_ClearFlag(TIM1_FLAG_CC2);

    TIM1_ClearFlag(TIM1_FLAG_CC3);

    TIM1_ClearFlag(TIM1_FLAG_CC4);

       

    TIM2_DeInit();

   

    TIM3_DeInit();

           

    for (;;){   

   

    while((TIM1->SR1 & TIM1_FLAG_CC1) != TIM1_FLAG_CC1);

  /* Get CCR1 value*/

    CH1on = TIM1_GetCapture1();

    TIM1_ClearFlag(TIM1_FLAG_CC1);

   

    while((TIM1->SR1 & TIM1_FLAG_CC2) != TIM1_FLAG_CC2);

  /* Get CCR1 value*/

    CH2on = TIM1_GetCapture2();

    TIM1_ClearFlag(TIM1_FLAG_CC2);

   

    while((TIM1->SR1 & TIM1_FLAG_CC3) != TIM1_FLAG_CC3);

  /* Get CCR1 value*/

    CH3on = TIM1_GetCapture3();

    TIM1_ClearFlag(TIM1_FLAG_CC3);

   

    while((TIM1->SR1 & TIM1_FLAG_CC4) != TIM1_FLAG_CC4);

  /* Get CCR1 value*/

    CH4on = TIM1_GetCapture4();

    TIM1_ClearFlag(TIM1_FLAG_CC4);

   

    periodcountX = (CH2on + CH2ontime);

    periodcounty = (CH3on + CH3ontime);

    periodcountz = (CH4on + CH4ontime);

   

    CH3ontime = (CH3on - CH2on);

   

    CH4ontime = (CH4on - CH3on);

   

    /*TIM1_PWMIConfig(TIM1_CHANNEL_2,TIM1_ICPOLARITY_RISING, TIM1_ICSELECTION_DIRECTTI, TIM1_ICPSC_DIV1,0);*/

    TIM2_TimeBaseInit(TIM2_PRESCALER_1, periodcount);   

    // Initialise output channel 2 of TIM3.

  TIM2_OC3Init(TIM2_OCMODE_PWM1, TIM2_OUTPUTSTATE_ENABLE, CH1on, TIM2_OCPOLARITY_LOW);

  // Initialise output channel 2 of TIM3.

  TIM2_OC1Init(TIM2_OCMODE_PWM2, TIM2_OUTPUTSTATE_ENABLE, CH2on, TIM2_OCPOLARITY_LOW);   

  // Enable TIM3.

  TIM2_Cmd(ENABLE);

   

    /*TIM1_PWMIConfig(TIM1_CHANNEL_2,TIM1_ICPOLARITY_RISING, TIM1_ICSELECTION_DIRECTTI, TIM1_ICPSC_DIV1,0);*/

    TIM3_TimeBaseInit(TIM3_PRESCALER_1, periodcount);   

    // Initialise output channel 2 of TIM3.

  TIM3_OC1Init(TIM3_OCMODE_PWM2, TIM3_OUTPUTSTATE_ENABLE, CH3ontime, TIM3_OCPOLARITY_LOW);

  // Initialise output channel 2 of TIM3.

  TIM3_OC2Init(TIM3_OCMODE_PWM2, TIM3_OUTPUTSTATE_ENABLE, CH4ontime, TIM3_OCPOLARITY_LOW);   

  // Enable TIM3.

  TIM3_Cmd(ENABLE);

    }

}

kmorri2004
Associate II
Posted on March 26, 2010 at 18:05

Well I finally got the the code to work just the way I wanted to with a few minor issues but they are hardware related, and just in case someone wants to use the Discovery board for use in a remote control application, to capture the receivers pulses and then output them to servos or motor controls here is the code to date.

#include ''stm8s.h''

u16 CH1on =0, CH2on =0, CH3on = 0, CH4on = 0;

u16 Throttle3 = 0, Rudder4 = 0, Rightmotor = 0, Leftmotor = 0, Frontmotor =0, Rearmotor = 0;

u16 periodcount = 40100;

void main(void){

   

    TIM1_DeInit();

       

    /* Enable capture*/

    TIM1_ICInit(TIM1_CHANNEL_1, TIM1_ICPOLARITY_FALLING, TIM1_ICSELECTION_DIRECTTI, TIM1_ICPSC_DIV1, 0);

    TIM1_ICInit(TIM1_CHANNEL_2, TIM1_ICPOLARITY_FALLING, TIM1_ICSELECTION_DIRECTTI, TIM1_ICPSC_DIV1, 0);

    TIM1_ICInit(TIM1_CHANNEL_3, TIM1_ICPOLARITY_FALLING, TIM1_ICSELECTION_DIRECTTI, TIM1_ICPSC_DIV1, 0);

    TIM1_ICInit(TIM1_CHANNEL_4, TIM1_ICPOLARITY_FALLING, TIM1_ICSELECTION_DIRECTTI, TIM1_ICPSC_DIV1, 0);

       

    /*Set TIM1 SMCR register to trigger counter reset on Ch1 Rising Edge and falling edge*/

    TIM1->SMCR = 0x44;

       

    /* Enable TIM1 */

  TIM1_Cmd(ENABLE);

   

    /* Enable CC1, 2, 3, 4 interrupt */

    TIM1_ITConfig(TIM1_IT_CC1, ENABLE);

    TIM1_ITConfig(TIM1_IT_CC2, ENABLE);

    TIM1_ITConfig(TIM1_IT_CC3, ENABLE);

    TIM1_ITConfig(TIM1_IT_CC4, ENABLE);

       

    /* Clear CC1, 2, 3, 4 Flag*/

  TIM1_ClearFlag(TIM1_FLAG_CC1);

    TIM1_ClearFlag(TIM1_FLAG_CC2);

    TIM1_ClearFlag(TIM1_FLAG_CC3);

    TIM1_ClearFlag(TIM1_FLAG_CC4);

       

    /*Clear all of TIM2 and TIM3's bits*/

    TIM2_DeInit();

    TIM3_DeInit();

           

    for (;;){   

   

    while((TIM1->SR1 & TIM1_FLAG_CC1) != TIM1_FLAG_CC1);

  /* Get CCR1 value*/

    CH1on = TIM1_GetCapture1();

    TIM1_ClearFlag(TIM1_FLAG_CC1);

   

    while((TIM1->SR1 & TIM1_FLAG_CC2) != TIM1_FLAG_CC2);

  /* Get CCR2 value*/

    CH2on = TIM1_GetCapture2();

    TIM1_ClearFlag(TIM1_FLAG_CC2);

   

    while((TIM1->SR1 & TIM1_FLAG_CC3) != TIM1_FLAG_CC3);

  /* Get CCR3 value*/

    CH3on = TIM1_GetCapture3();

    TIM1_ClearFlag(TIM1_FLAG_CC3);

   

    while((TIM1->SR1 & TIM1_FLAG_CC4) != TIM1_FLAG_CC4);

  /* Get CCR4 value*/

    CH4on = TIM1_GetCapture4();

    TIM1_ClearFlag(TIM1_FLAG_CC4);

   

    /*Subtract CH2 on time from CH3 ontime to get CH3 correct ontime*/

    Throttle3 = (CH3on - CH2on);

   

    /*Subtract CH3 ontime from CH4 ontime to get CH4 true ontime*/

    Rudder4 = (CH4on - CH3on);

   

    /*Set Throttle3 to control all 4 motors throttle initially*/

    Rearmotor = Throttle3;

    Leftmotor = Throttle3;

    Rightmotor = Throttle3;

    Frontmotor = Throttle3;

   

    if ((CH2on < 2950) & (Throttle3 > 2180)){

        Rearmotor = (Throttle3 - (3000 - CH2on));

    } else if ((CH2on >3050) & (Throttle3 > 2180)){

        Frontmotor = (Throttle3 - (CH2on -3000));

    }

       

    if ((CH1on < 2950) & (Throttle3 > 2180)) {

        Leftmotor = (Throttle3 -(3000 - CH1on));

    }else if ((CH1on >3050) & (Throttle3 > 2180)) {

        Rightmotor = (Throttle3 - (CH1on -3000));

    }

   

    if ((Rudder4 < 2950) & (Throttle3 > 2180)){

        Leftmotor = (Throttle3 -(3000 - Rudder4));

        Rightmotor = (Throttle3 -(3000 - Rudder4));

    } else if ((Rudder4 > 3050) & (Throttle3 > 2180)){

        Rearmotor = (Throttle3 - (3000 - Rudder4));

        Frontmotor = (Throttle3 - (3000 - Rudder4));

    }

   

       

    /*Set TIM2 and TIM3 to run at 50Hz with a 2MHz clock pulse*/

     TIM2_TimeBaseInit(TIM2_PRESCALER_1, periodcount);   

    TIM3_TimeBaseInit(TIM3_PRESCALER_1, periodcount);

   

    // Initialise output channel 1 and 3 of TIM2 to control the left and right motors.

  TIM2_OC3Init(TIM2_OCMODE_PWM2, TIM2_OUTPUTSTATE_ENABLE, Frontmotor, TIM2_OCPOLARITY_LOW);

  TIM2_OC1Init(TIM2_OCMODE_PWM2, TIM2_OUTPUTSTATE_ENABLE, Leftmotor, TIM2_OCPOLARITY_LOW);   

 

    // Enable TIM2.

  TIM2_Cmd(ENABLE);

           

    // Initialise output channel 1 and 2 of TIM3 to control the front and rear motors.

  TIM3_OC1Init(TIM3_OCMODE_PWM2, TIM3_OUTPUTSTATE_ENABLE, Rightmotor, TIM3_OCPOLARITY_LOW);

  TIM3_OC2Init(TIM3_OCMODE_PWM2, TIM3_OUTPUTSTATE_ENABLE, Rearmotor, TIM3_OCPOLARITY_LOW);   

 

    // Enable TIM3.

  TIM3_Cmd(ENABLE);

    }

}