2020-09-22 07:09 PM
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.
2020-09-22 08:37 PM
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?
2020-09-22 11:05 PM
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.
#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);
}
}
2020-09-23 02:25 AM
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
2020-09-23 06:58 PM
Maybe I know what you said,thanks a lot!