cancel
Showing results for 
Search instead for 
Did you mean: 

Output PWM through TIM+DMA mode, the pulse number will be one more

JCK.1
Associate II

I use the TIM3+DMA function of STM32F103VCT6 to generate PWM. I need to generate a series of adjustable frequencies, adjustable duty ratio and controllable pulse number.Such as 10KHz, 200KHz, 500KHz, 1MHz, 2MHz, 5MHz.I modify the VALUE of TIM's CCR by generating DMA requests through TIM comparison events. Given Pulse +1 as a DMA count value, the value is reduced to 0 to trigger a DMA interrupt to clear the value of TIM's CCR.At present, When I am generating 500 pulses with a duty cycle of 50% and a frequency of 500 KHZ, I am actually emitting 501 pulses.What's the reason for this?Listen for the reply.

4 REPLIES 4
TDK
Guru

I think the answer will depend on a lot of the details you're not giving here. But if you're getting N+1 instead of N, why not just decrease the amount you set by 1?

If you feel a post has answered your question, please click "Accept as Solution".
JCK.1
Associate II

Yes, thank you for your answer.I didn't upload the more detailed implementation code.So I will upload part of the implementation code.I have considered your suggestion, but I think it is not for that reason. I am sorry that I did not make the situation clear.I'm going to output an indeterminate number of pulses in 1ms, so I'm going to select some pulses to verify that.When I output less than 500 pulses, the number of pulses is actually accurate.I get one more pulse when I send 500 or more pulses.And I catch the wave in photo,from the photo we can see the extra pluse.0693W000004GnOAQA0.png0693W000004GnNvQAK.png

#define PWM_CK_CNT1                42000000              //count clock(42M times per sec)
#define PWM_PRESCALER1        (SystemCoreClock/2/PWM_CK_CNT1) //SystemCoreClock=72M
#define PWM_TEST 			TIM3
 
oid TIMx_Dma_Pwm_Output_Init(void)
{
	GPIO_InitTypeDef         GPIO_InitStructure;
	TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
	TIM_OCInitTypeDef        TIM_OCInitStructure;
	DMA_InitTypeDef          DMA_InitStructure;
	NVIC_InitTypeDef         NVIC_InitStructure;
 
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);
	TIM_TimeBaseStructInit(&TIM_TimeBaseStructure);
	TIM_OCStructInit(&TIM_OCInitStructure);
 
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3 , ENABLE);		
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA | RCC_AHB1Periph_DMA1, ENABLE);  
	
	GPIO_PinAFConfig(GPIOA,GPIO_PinSource6,GPIO_AF_TIM3);
 
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; 
	GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
	GPIO_Init(GPIOA, &GPIO_InitStructure);
 
	TIM_DeInit(PWM1_TIM);
	TIM_TimeBaseStructure.TIM_Period = 0xFFFF;                      			
	TIM_TimeBaseStructure.TIM_Prescaler =PWM_PRESCALER1-1;                   	
	TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;              
	TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
	TIM_TimeBaseStructure.TIM_RepetitionCounter = 0;
	TIM_TimeBaseInit(PWM1_TIM, &TIM_TimeBaseStructure);          
	
	TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;            				
	TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
	TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; 
	TIM_OCInitStructure.TIM_Pulse = 0;
	TIM_OC1Init(PWM1_TIM, &TIM_OCInitStructure); 
	TIM_OC1PreloadConfig(PWM1_TIM, TIM_OCPreload_Enable);
 
	DMA_DeInit(DMA1_Stream4);														
	DMA_InitStructure.DMA_Channel = DMA_Channel_5;
	DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)&PWM1_TIM->CCR1;            
	DMA_InitStructure.DMA_Memory0BaseAddr    = (u32)&PWM_Duty1;					
	DMA_InitStructure.DMA_DIR                = DMA_DIR_MemoryToPeripheral;          	
	DMA_InitStructure.DMA_BufferSize         = 0;                          
	DMA_InitStructure.DMA_PeripheralInc      = DMA_PeripheralInc_Disable;      	
	DMA_InitStructure.DMA_MemoryInc          = DMA_MemoryInc_Disable;     
	DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;	
	DMA_InitStructure.DMA_MemoryDataSize     = DMA_MemoryDataSize_HalfWord;   
	DMA_InitStructure.DMA_Mode               = DMA_Mode_Normal;
	DMA_InitStructure.DMA_Priority           = DMA_Priority_High;            		
	DMA_InitStructure.DMA_FIFOMode 			 = DMA_FIFOMode_Disable;         
	DMA_InitStructure.DMA_FIFOThreshold		 = DMA_FIFOThreshold_Full;
	DMA_InitStructure.DMA_MemoryBurst		 = DMA_MemoryBurst_Single;
	DMA_InitStructure.DMA_PeripheralBurst	 = DMA_PeripheralBurst_Single;
 
	DMA_Init(DMA1_Stream4, &DMA_InitStructure);                               			  	
	//DMA_Cmd(DMA1_Stream4, ENABLE);                                            		
	
	TIM_DMACmd(PWM1_TIM, TIM_DMA_CC1, ENABLE);
 
	NVIC_InitStructure.NVIC_IRQChannel = DMA1_Stream4_IRQn;   
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;      
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x00;
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
	NVIC_Init(&NVIC_InitStructure);		
	DMA_ClearFlag(DMA1_Stream4,DMA_FLAG_TCIF4);    
	DMA_ITConfig(DMA1_Stream4,DMA_IT_TC,ENABLE);          
	
	TIM_SetCompare1(PWM1_TIM,0);
	//TIM_Cmd(PWM1_TIM, ENABLE);
}
 
void TIMx_Dma_Pwm_Output_Test(void)
{
	int i = 0,j = 0;
	while(1)
	{
		for(i = 0;i < 6;i++)
		{
			TIMx_Dma_Pwm_Output(PWM_TEST,(u32)(pls_num1[i]*1000),50,pls_num1[i],1);
			delay_ms(300);
		}
	}
}
 
void TIMx_Dma_Pwm_Output(TIM_TypeDef* TIMx,u32 Frequency,u8 Duty,u16 PluseNum,bool DIR) 
{
	uint32_t pwm_period;
 
	if(TIMx == PWM1_TIM)
	{
		pwm_period = PWM_CK_CNT1/Frequency - 1; 
		PWM_Duty1=(pwm_period+1)*Duty/100; 
 
		TIM_Cmd(PWM1_TIM, DISABLE);
		
		TIM_SetCounter(PWM1_TIM, 0); 
		TIM_SetAutoreload(PWM1_TIM, pwm_period);                
		
		TIM_SetCompare1(PWM1_TIM,PWM_Duty1);                   
 
		DMA_Cmd(DMA1_Stream4, DISABLE);                  
		DMA_SetCurrDataCounter(DMA1_Stream4,PluseNum+1);   
		DMA_Cmd(DMA1_Stream4, ENABLE);                    
		TIM_Cmd(PWM1_TIM, ENABLE);                            
	}
}
 
void DMA1_Stream4_IRQHandler(void)
{
    if(DMA1->HISR & 0x00000020)
    {
	//PWM1_TIM->CCR1 = 0;//Zeroing in this way will generate one more pulse when output 500 pulses
	DMA1->HIFCR = (uint32_t)(DMA_FLAG_TCIF4|DMA_FLAG_HTIF4 & (uint32_t)0x0F7D0F7D );
	DMA_ClearFlag(DMA1_Stream4,DMA_FLAG_TCIF4|DMA_FLAG_HTIF4);
    }
}

It's not a good idea to try to stop the PWM output based on interrupts. You should use linked timers instead, count cycles of the PWM-generating timer by another linked timer, and then that another timer can drive DMA which changes the first timer's CCRx.

JW

Maybe I know what you said,thanks a lot!