cancel
Showing results for 
Search instead for 
Did you mean: 

STM32F4-discovery DDS

baev_al
Associate II
Posted on April 07, 2015 at 15:43

Hi.

I try to make DDS. The code is below. The idea is to get new value of capture-compare register after Update event. This is done in the update interrupt. I have the following problems: 1) I do not see zero in the train of pulses, while it is present in the array; 2) I see some pulses which should not be (I attached the images - in the lower one is shown the marked pule of the upper image, only one pulse has such artifacts others pulses are ok ).

How those problems can be solved?

Maybe I should use one pulse mode?

Thanks!

/*

My file as replacement for main.c of TIM_PWMOutput project

This is DDS test

Original main.c is excluded from compiling

*/

#include ''stm32f4xx.h''

TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;

TIM_OCInitTypeDef  TIM_OCInitStructure;

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

uint16_t CCR1_Val = 350;

uint16_t PrescalerValue = 0;

int sinus[60]={349, 385, 422, 457, 491, 523, 554, 583, 608, 631, 651, 668,

681, 690, 696, 698, 696, 690, 681, 668, 651, 631, 608, 583, 554, 524, 491,

457, 422, 385, 349, 313, 276, 241, 207, 175, 144, 115, 90, 67, 47, 30, 17,

8, 2, 0, 2, 8, 17, 30, 47, 67, 90, 115, 144, 174, 207, 241, 276, 313};

void TIM_Config(void);

void TIM4_IRQHandler(void);

int main (void)

{

  /

  /* TIM Configuration */

  TIM_Config();

 

  /* -----------------------------------------------------------------------

    TIM4 Configuration: generate 4 PWM signals with 4 different duty cycles.

    

    In this example TIM4 input clock (TIM4CLK) is set to 4 * APB1 clock (PCLK1),

    since TIMPRE bit from RCC_DCKCFGR register is set.   

      TIM4CLK = 4 * PCLK1

      PCLK1 = HCLK / 4

      => TIM4CLK = HCLK = SystemCoreClock

          

    To get TIM4 counter clock at 21 MHz, the prescaler is computed as follows:

       Prescaler = (TIM4CLK / TIM4 counter clock) - 1

       Prescaler = (SystemCoreClock /21 MHz) - 1

                                              

    To get TIM4 output clock at 30 KHz, the period (ARR)) is computed as follows:

       ARR = (TIM4 counter clock / TIM4 output clock) - 1

           = 699

                  

   

  ----------------------------------------------------------------------- */   

  RCC_TIMCLKPresConfig(RCC_TIMPrescActivated);

  /* Compute the prescaler value */

  PrescalerValue = (uint16_t) (SystemCoreClock / 21000000) - 1;

  /* Time base configuration */

  TIM_TimeBaseStructure.TIM_Period = 699;

  TIM_TimeBaseStructure.TIM_Prescaler = PrescalerValue;

  TIM_TimeBaseStructure.TIM_ClockDivision = 0;

  TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;

  TIM_TimeBaseInit(TIM4, &TIM_TimeBaseStructure);

  /* PWM1 Mode configuration: Channel1 */

  TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;

  TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;

  TIM_OCInitStructure.TIM_Pulse = CCR1_Val;

  TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;

  TIM_OC1Init(TIM4, &TIM_OCInitStructure);

//  TIM_OC1PreloadConfig(TIM4, TIM_OCPreload_Enable);

//  TIM_ARRPreloadConfig(TIM4, ENABLE);

 

  TIM_ITConfig(TIM4, TIM_IT_Update, ENABLE);

 

  NVIC_InitTypeDef NVIC_InitStructure;

  NVIC_InitStructure.NVIC_IRQChannel = TIM4_IRQn;

  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;

  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;

  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;

  NVIC_Init(&NVIC_InitStructure);

  /* TIM4 enable counter */

  TIM_Cmd(TIM4, ENABLE);

  while (1)

  {}

}

void TIM4_IRQHandler(void)

{

  static int i = 0;

  i++;

  if (i == 60) i = 0;

  TIM4->CCR1 = sinus[i];

  TIM_ClearFlag(TIM4, TIM_FLAG_Update);

}

void TIM_Config(void)

{

  GPIO_InitTypeDef GPIO_InitStructure;

  /* TIM4 clock enable */

  RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE);

  /* GPIOD clock enable */

  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD, ENABLE);

 

  /* GPIOD Configuration: TIM4 CH1 (PD12)*/

  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;

  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;

  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;

  GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;

  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP ;

  GPIO_Init(GPIOD, &GPIO_InitStructure);

  /* Connect TIM4 pins to AF2 */  

  GPIO_PinAFConfig(GPIOD, GPIO_PinSource12, GPIO_AF_TIM4);

 

}

0690X00000603D4QAI.jpg

0690X00000603JuQAI.jpg
5 REPLIES 5
Posted on April 07, 2015 at 18:34

TIM4CLK != 4 *APB1CLK

It would be twice the APB1 clock in the DIV4 case.

You should confirm and clear the Update interrupt, and definitely clear the Update source well before you exit the handler, as there is a race hazard here in the way the NVIC/TIM and tailchaining interact.

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
baev_al
Associate II
Posted on April 07, 2015 at 21:16

void TIM4_IRQHandler(void)

{

  static int i = 0;

  i++;

  if (i == 60) i = 0;

  TIM4->CCR1 = sinus[i];

  TIM_ClearFlag(TIM4, TIM_FLAG_Update);

}

Is clearing flag not the same as clearing interrupt? What is confirming an interrupt?

What is clearing an update source ?

Posted on April 07, 2015 at 22:28

void TIM4_IRQHandler(void)
{
static int i = 0;
i++;
if (i == 60) i = 0;
TIM4->CCR1 = sinus[i];
TIM_ClearFlag(TIM4, TIM_FLAG_Update); // <<< THERE IS A RACE CONDITION HERE AS IT IMMEDIATELY EXITS, DO IT FIRST ^^^
}

Before the write propagates to the timer, to clear the interrupt, it remains pending in the eyes of the NVIC and the processor. When it leaves the routine, it will immediate re-enter via ''tail-chaining'' mechanism. You do not check the source, and your routine will run for a second time. You can save yourself grief, by a) checking what the source of the interrupt is, and b) clearing it before the body code in your routine executes so that it is actually clear by the time it leaves.
Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
Posted on April 07, 2015 at 22:35

void TIM4_IRQHandler(void)
{
static int i = 0;
if (TIM_GetITStatus(TIM4, TIM_IT_Update) == SET) /* Confirm it's an Update, VALIDATE */
{
TIM_ClearITPendingBit(TIM4, TIM_IT_Update); /* Clear TIM4 Update interrupt pending bit, EARLY */
i++;
if (i == 60) i = 0;
TIM4->CCR1 = sinus[i];
}
}

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
baev_al
Associate II
Posted on April 08, 2015 at 08:08

I changed the handler to the above. Now I see zero among the pulses. But still the second pulse after zero pulse is wrong. I attached the pictures.

0690X00000603JyQAI.jpg0690X00000603K3QAI.jpg