Question

I'm trying to generate a phase shift PWM signal using three timers.

  • TIM1 is used as reference(Running at 1MHz)
  • TIM3 is used as a trigger to phase shift TIM4
  • TIM4 is used to generate the phase shifted signal triggerd by TIM3

To Sum up: TIM1 --- triggers --> TIM3 --- triggers ---> TIM4

The signal should look like:

Reference: TIM1 (1 MHz) 
                 ___     ___     ___     ___
             ___|   |___|   |___|   |___|   |___| 
TIM Count    0  84 168
Update Event ^      ^       ^       ^       ^

Trigger signal: TIM 3 triggered by TIM1 ((SINGLE PULSE MODE!!) 1MHz
              /|      /|      /|      /|      /|
             / |     / |     / |     / |     / |
TIM Count    0 20 
Update Event   ^       ^       ^       ^       ^

Phase shift signal TIM4 (1MHZ) same duty cycle as TIM1 triggered by TIM3
            ___     ___     ___     ___     ___
        ___|   |___|   |___|   |___|   |___|   |_

Here is my current code. The Reference is running correctly at 1MHz. But the trigger signal is not working by now. The error should be anywhere in initReferenceTimer() or initReferencePWM() function. Up to now it's not working to generate the trigger signal like mentioned above. So I was not able to test, if the phased shift signal will be triggered correctly.

Does anybody have an good idea about it?

For debugging I also bind the trigger signal to an output pin.

#define TIMER_CLOCK 84
#define TIM1_TIMER_CLOCK 168
#define FREQU 1 //MHz
#define SHIFT 20 
#define MasterPeriod (TIM1_TIMER_CLOCK/FREQU)-1
#define MasterPulse ((TIM1_TIMER_CLOCK/FREQU)-1)/2
#define ReferencePeriod SHIFT
#define ReferencePulse (SHIFT/2)
#define SlavePeriod (TIM1_TIMER_CLOCK/FREQU)-1
#define SlavePulse ((TIM1_TIMER_CLOCK/FREQU)-1)/2

//TIM1 Channel1: PA7 N
void initMasterPin()
{
    GPIO_InitTypeDef     GPIO_InitStructureTimer;

    // Port clock enable
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);

    // Set PWM Port, Pin and method
    GPIO_InitStructureTimer.GPIO_Pin = GPIO_Pin_7;
    GPIO_InitStructureTimer.GPIO_Mode = GPIO_Mode_AF;
    GPIO_InitStructureTimer.GPIO_Speed = GPIO_Speed_100MHz;
    GPIO_InitStructureTimer.GPIO_OType = GPIO_OType_PP;
    GPIO_InitStructureTimer.GPIO_PuPd = GPIO_PuPd_UP ;
    GPIO_Init(GPIOA, &GPIO_InitStructureTimer);

    // Connect TIM pin to AF
    GPIO_PinAFConfig(GPIOA, GPIO_PinSource7, GPIO_AF_TIM1);
}
//TIM3 Channel1 PC6
void initReferencePin()
{
    GPIO_InitTypeDef     GPIO_InitStructureTimer;

    // Port clock enable
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC, ENABLE);

    // Set PWM Port, Pin and method
    GPIO_InitStructureTimer.GPIO_Pin = GPIO_Pin_6;
    GPIO_InitStructureTimer.GPIO_Mode = GPIO_Mode_AF;
    GPIO_InitStructureTimer.GPIO_Speed = GPIO_Speed_100MHz;
    GPIO_InitStructureTimer.GPIO_OType = GPIO_OType_PP;
    GPIO_InitStructureTimer.GPIO_PuPd = GPIO_PuPd_UP ;
    GPIO_Init(GPIOC, &GPIO_InitStructureTimer);

    // Connect TIM pin to AF
    GPIO_PinAFConfig(GPIOC, GPIO_PinSource6, GPIO_AF_TIM3);
}
//TIM4 Channel1: PB6
void initSlavePin()
{
    GPIO_InitTypeDef     GPIO_InitStructureTimer;

    // Port clock enable
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);

    // Set PWM Port, Pin and method
    GPIO_InitStructureTimer.GPIO_Pin = GPIO_Pin_6;
    GPIO_InitStructureTimer.GPIO_Mode = GPIO_Mode_AF;
    GPIO_InitStructureTimer.GPIO_Speed = GPIO_Speed_100MHz;
    GPIO_InitStructureTimer.GPIO_OType = GPIO_OType_PP;
    GPIO_InitStructureTimer.GPIO_PuPd = GPIO_PuPd_UP ;
    GPIO_Init(GPIOB, &GPIO_InitStructureTimer);

    // Connect TIM pin to AF
    GPIO_PinAFConfig(GPIOB, GPIO_PinSource6, GPIO_AF_TIM4);
}

//Tim1 Channel1: PA7
void initMasterTimer()
{
    // set timer frequencies
    TIM_TimeBaseInitTypeDef TIM_Config;

    // 1.Enable TIM clock
    RCC_APB2PeriphClockCmd (RCC_APB2Periph_TIM1, ENABLE);

    // 2.Fill the TIM_TimeBaseInitStruct with the desired parameters.
    // Time Base configuration
    TIM_TimeBaseStructInit (&TIM_Config);
    TIM_Config.TIM_Period = MasterPeriod;
    TIM_Config.TIM_Prescaler = 0;
    TIM_Config.TIM_CounterMode = TIM_CounterMode_Up;
    TIM_Config.TIM_ClockDivision = TIM_CKD_DIV1;
    TIM_Config.TIM_RepetitionCounter = 0;
    //configure the Time Base unit with the corresponding configuration
    TIM_TimeBaseInit (TIM1, &TIM_Config);

    // Enable the NVIC if you need to generate the update interrupt.
    // Enable the corresponding interrupt
}
//TIM3 Channel1 PC6
void initReferenceTimer()
{
     // set timer frequencies
    TIM_TimeBaseInitTypeDef TIM_Config;

    // 1.Enable TIM clock
    RCC_APB1PeriphClockCmd (RCC_APB1Periph_TIM3, ENABLE);

    // 2.Fill the TIM_TimeBaseInitStruct with the desired parameters.
    // Time Base configuration
    TIM_TimeBaseStructInit (&TIM_Config);
    TIM_Config.TIM_Period = ReferencePeriod;//One Step Phase Shift
    TIM_Config.TIM_Prescaler = 0;
    TIM_Config.TIM_CounterMode = TIM_CounterMode_Up;
    TIM_Config.TIM_ClockDivision = TIM_CKD_DIV1;
    TIM_Config.TIM_RepetitionCounter = 0;
    //configure the Time Base unit with the corresponding configuration
    TIM_TimeBaseInit (TIM3, &TIM_Config);

    // Enable the NVIC if you need to generate the update interrupt.
    // Enable the corresponding interrupt
}
//TIM4 Channel1: PB6
void initSlaveTimer()
{
    // set timer frequencies
    TIM_TimeBaseInitTypeDef TIM_Config;

    // 1.Enable TIM clock
    RCC_APB1PeriphClockCmd (RCC_APB1Periph_TIM4, ENABLE);

    // 2.Fill the TIM_TimeBaseInitStruct with the desired parameters.
    // Time Base configuration
    TIM_TimeBaseStructInit (&TIM_Config);
    TIM_Config.TIM_Period = SlavePeriod;
    TIM_Config.TIM_Prescaler = 0;
    TIM_Config.TIM_CounterMode = TIM_CounterMode_Up;
    TIM_Config.TIM_ClockDivision = TIM_CKD_DIV1;
    TIM_Config.TIM_RepetitionCounter = 0;
    //configure the Time Base unit with the corresponding configuration
    TIM_TimeBaseInit (TIM4, &TIM_Config);

    // Enable the NVIC if you need to generate the update interrupt.
    // Enable the corresponding interrupt
}

//Tim1 Channel1: PA7
void initMasterPWM(void)
{
    TIM_OCInitTypeDef TIM_OCInitStructure;
    TIM_OCStructInit(&TIM_OCInitStructure);
    TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
    TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
    TIM_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Enable;
    TIM_OCInitStructure.TIM_Pulse = MasterPulse;
    TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
    TIM_OCInitStructure.TIM_OCNPolarity = TIM_OCNPolarity_High;

    TIM_OC1Init(TIM1, &TIM_OCInitStructure);

    /* Master Mode selection */
    TIM_SelectOutputTrigger(TIM1, TIM_TRGOSource_Update);
    /* Select the Master Slave Mode */
    TIM_SelectMasterSlaveMode(TIM1, TIM_MasterSlaveMode_Enable);
}
//TIM3 Channel1 PC6
void initReferencePWM(void)
{
    TIM_OCInitTypeDef TIM_OCInitStructure;
    TIM_OCStructInit(&TIM_OCInitStructure);
    TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
    TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
    TIM_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Enable;
    TIM_OCInitStructure.TIM_Pulse = ReferencePulse; // set the duty cycle / pulse here!
    TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
    TIM_OCInitStructure.TIM_OCNPolarity = TIM_OCNPolarity_High;

    TIM_OC1Init(TIM3, &TIM_OCInitStructure);

    TIM_SelectOnePulseMode(TIM3, TIM_OPMode_Single);

    /* Slave Mode selection: TIM3 */
    TIM_SelectInputTrigger(TIM3, TIM_TS_ITR0);
    TIM_SelectSlaveMode(TIM2, TIM_SlaveMode_Gated);

    /* Select the Master Slave Mode */
    TIM_SelectOutputTrigger(TIM3, TIM_TRGOSource_Update);
    TIM_SelectMasterSlaveMode(TIM3, TIM_MasterSlaveMode_Enable);
}
//TIM4 Channel1: PB6
void initSlavePWM(void)
{
    TIM_OCInitTypeDef TIM_OCInitStructure;
    TIM_OCStructInit(&TIM_OCInitStructure);
    TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
    TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
    TIM_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Enable;
    TIM_OCInitStructure.TIM_Pulse = SlavePulse; 
    TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
    TIM_OCInitStructure.TIM_OCNPolarity = TIM_OCNPolarity_High;

    TIM_OC1Init(TIM4, &TIM_OCInitStructure);

    TIM_SelectInputTrigger(TIM4, TIM_TS_ITR2);
    TIM_SelectSlaveMode(TIM4, TIM_SlaveMode_Gated);
    TIM_SelectOnePulseMode(TIM4, TIM_OPMode_Single);
}

int main(void)
{
   initMasterPin();
   initReferencePin(); //FOR DEBUGGING ONLY
   initSlavePin();

   initMasterTimer();
   initReferenceTimer();
   initSlaveTimer();

   initMasterPWM();
   initReferencePWM();
   initSlavePWM();

   // enable timer / counter
   TIM_Cmd(TIM1, ENABLE);
   TIM_Cmd(TIM3, ENABLE);
   TIM_Cmd(TIM4, ENABLE);

       TIM_CtrlPWMOutputs(TIM1, ENABLE);
   TIM_CtrlPWMOutputs(TIM3, ENABLE);
   TIM_CtrlPWMOutputs(TIM4, ENABLE);

  /* Busy loop */
   int i;
  while (1)
  {
    i++;
  }
}
Was it helpful?

Solution

Are you sure you don't have a typo in your initReferencePWM?

void initReferencePWM(void)
{
    ...
    TIM_SelectSlaveMode(TIM2, TIM_SlaveMode_Gated);
    ...
}

Why TIM2 all the sudden?

OTHER TIPS

This is general purpose advice - I have no experience of your particular processor.

It's hard to get visibility of timers, so work up from the bottom:

  • slow down all the timers - turn the prescaler options to maximum.
  • ensure your ref clk timer is counting - use a debugger or printf to show that the counter register is going in the direction you expect
  • check it resets
  • repeat for the other timers (independently - no triggers)

You now have three timers that you know are counting. Often by this stage you've found an extra "enable bit" you weren't aware of, or the direction is the opposite of what you expect, or some such "head-slappingly trivial" issue (as Chris Stratton so vividly describes it!)

  • now set up the first triggering
  • verify that the triggering starts the timer you want at the time you expect - again printf or debugger
  • connect it to the next timer in the chain and repeat.

Once they are all triggering each other, you can start winding up the frequencies and see if it all works at speed.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top