2015-04-07 06:43 AM
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); }2015-04-07 09:34 AM
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.2015-04-07 12:16 PM
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 ?2015-04-07 01:28 PM
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.
2015-04-07 01:35 PM
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];
}
}
2015-04-07 11:08 PM
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.