Why the number of pulses is less than expected when I am using One Pulse Mode and Repetition Counter (RCR) to generate adjustable PWM pulses with number and frequency?
I need to generate PWM signals with adjustable number and frequency to drive a step motor. I expect the frequency ranges from 50Hz to 200KHz and the pulses count ranges from 1 to 2k.
I have tried 3 different ways including: using timer interrupt to count the pulse number; setting the PWM timer as master and using a slave timer in gated mode to count the pulse; using One Pulse Mode and the 16bit Repetition Counter (RCR). I used to think the last is the simplest and the most reliable cause all of the work is done by hardware. But the problem is the same. When the frequency reaches 200kHz the pulses count is inaccurate. More precisely, the count is always less than expected.
Details of my MCU settings and code are in below.


#define CLK_FREQ 144000 /* CLK_INT / 1000 */
#define DT 1 /* dt in millisecond */
#include "tim.h"
#include "gpio.h"
#include "math.h"
void motorMove(uint8_t xdir,uint16_t xsteps, uint8_t ydir,uint16_t ysteps)
{
uint16_t psc = 0;
uint16_t arr = 0;
uint16_t ccr = 0;
xdirOut(xdir);
getFreq(xsteps, DT, &psc, &arr, &ccr);
xpwmOut(psc, arr, ccr, xsteps);
ydirOut(ydir);
getFreq(ysteps, DT, &psc, &arr, &ccr);
ypwmOut(psc, arr, ccr, ysteps);
}
void xpwmOut(uint16_t psc,uint16_t arr,uint16_t ccr,uint16_t stp)
{
htim1.Init.Prescaler = psc;
htim1.Init.Period = arr;
__HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_1, ccr);
htim1.Init.RepetitionCounter = stp - 1;
HAL_TIM_Base_Init(&htim1);
HAL_TIM_PWM_Start_IT(&htim1, TIM_CHANNEL_1);
}
void ypwmOut(uint16_t psc,uint16_t arr,uint16_t ccr,uint16_t stp)
{
htim8.Init.Prescaler = psc;
htim8.Init.Period = arr;
__HAL_TIM_SET_COMPARE(&htim8, TIM_CHANNEL_1, ccr);
htim8.Init.RepetitionCounter = stp - 1;
HAL_TIM_Base_Init(&htim8);
HAL_TIM_PWM_Start_IT(&htim8, TIM_CHANNEL_1);
}
void xdirOut(uint8_t dir)
{
if(dir)
{
HAL_GPIO_WritePin(X_DIR_GPIO_Port, X_DIR_Pin, GPIO_PIN_RESET);
}
else
{
HAL_GPIO_WritePin(X_DIR_GPIO_Port, X_DIR_Pin, GPIO_PIN_SET);
}
}
void ydirOut(uint8_t dir)
{
if(dir)
{
HAL_GPIO_WritePin(Y_DIR_GPIO_Port, Y_DIR_Pin, GPIO_PIN_RESET);
}
else
{
HAL_GPIO_WritePin(Y_DIR_GPIO_Port, Y_DIR_Pin, GPIO_PIN_SET);
}
}
void getFreq(uint16_t steps, const uint16_t dt, uint16_t* psc, uint16_t* arr, uint16_t* ccr)
{
double temp;
temp = CLK_FREQ * dt / steps;
temp = sqrt(temp);
*(psc) = ((uint16_t) temp) - 1;
*(arr) = *(psc);
*(ccr) = *(arr) / 2;
}