2025-08-27 10:58 PM
Hi everyone,
I am trying to generate sinewave using PWM mode of microcontroller.
I am using Discovery Board having STM32F407 microcontroller. System clock and Timer clock are of 8Mhz
I am using two timers
Timer1 for High Frequency switching (500Hz) and Timer2 for Low Frequency switching (50Hz).
waveforms I am getting are OK but there is one issue, after every 7 cycles I am getting an extra PWM sample in my output.
I don't know why it is so. I am attaching image of the output and code. may be there is a minor mistake which I am doing but not sure. can you guys let me know if there is an issue
uint16_t sineTable[SINE_TABLE_SIZE] = {400,635,780,780,635,400,165,20,20,165};
// Initializing Timer1
void MX_TIM1_Init(void) {
TIM_ClockConfigTypeDef sClockSourceConfig = {0};
TIM_OC_InitTypeDef sConfigOC = {0};
TIM_BreakDeadTimeConfigTypeDef sBreakDeadTimeConfig = {0};
htim1.Instance = TIM1;
htim1.Init.Prescaler = PRESCALER_REQUIRED;
htim1.Init.CounterMode = TIM_COUNTERMODE_UP;
htim1.Init.Period = ARR_VALUE;
htim1.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
htim1.Init.RepetitionCounter = 0;
htim1.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE;
HAL_TIM_PWM_Init(&htim1);
sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
HAL_TIM_ConfigClockSource(&htim1, &sClockSourceConfig);
sConfigOC.OCMode = TIM_OCMODE_PWM1;
sConfigOC.Pulse = sineTable[0];
sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
sConfigOC.OCNPolarity = TIM_OCNPOLARITY_HIGH;
sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
sConfigOC.OCIdleState = TIM_OCIDLESTATE_RESET;
sConfigOC.OCNIdleState = TIM_OCNIDLESTATE_RESET;
HAL_TIM_PWM_ConfigChannel(&htim1, &sConfigOC, TIM_CHANNEL_1);
HAL_TIM_PWM_ConfigChannel(&htim1, &sConfigOC, TIM_CHANNEL_2);
sBreakDeadTimeConfig.OffStateRunMode = TIM_OSSR_DISABLE;
sBreakDeadTimeConfig.OffStateIDLEMode = TIM_OSSI_DISABLE;
sBreakDeadTimeConfig.LockLevel = TIM_LOCKLEVEL_OFF;
sBreakDeadTimeConfig.DeadTime = 10;
sBreakDeadTimeConfig.BreakState = TIM_BREAK_DISABLE;
sBreakDeadTimeConfig.BreakPolarity = TIM_BREAKPOLARITY_HIGH;
sBreakDeadTimeConfig.AutomaticOutput = TIM_AUTOMATICOUTPUT_DISABLE;
HAL_TIMEx_ConfigBreakDeadTime(&htim1, &sBreakDeadTimeConfig);
}
// Initializing Timer 2
void MX_TIM2_Init(void) {
TIM_ClockConfigTypeDef sClockSourceConfig = {0};
htim2.Instance = TIM2;
htim2.Init.Prescaler = PRESCALER_TIMER2; // value 80 for 10mS interrupt
htim2.Init.CounterMode = TIM_COUNTERMODE_UP;
htim2.Init.Period = ARR_VALUE_TIMER2;
htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
htim2.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE;
HAL_TIM_Base_Init(&htim2);
}
void SPWM_Start(void) {
// Start PWM generation
HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_1);
HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_2);
HAL_TIMEx_PWMN_Start(&htim1, TIM_CHANNEL_1);
HAL_TIMEx_PWMN_Start(&htim1, TIM_CHANNEL_2);
// Enable update interrupt
__HAL_TIM_ENABLE_IT(&htim1, TIM_IT_UPDATE);
// Start SPWM update timer (10kHz)
HAL_TIM_Base_Start_IT(&htim1);
// Start synchronization timer (50Hz)
HAL_TIM_Base_Start_IT(&htim2);
}
// Callback Routine
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) {
if (htim->Instance == TIM1) {
HAL_GPIO_TogglePin(GPIOD, GPIO_PIN_15);
uint16_t value;
if(currentHalfCycle == 0){
// First 10ms: Use first 5 samples for CH1
value = sineTable[sineIndex];
__HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_1, value);
__HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_2,0);
ind = sineIndex;
sine = value;
}
else{
// Second 10ms: Use next 5 samples for CH2
value = sineTable[sineIndex + 5];
__HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_2, value);
__HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_1, 0);
ind = sineIndex + 5;
sine = value;
}
flag = 1;
sineIndex++;
if (sineIndex >= 5) sineIndex = 0; // Reset every 5 samples
}
else if (htim->Instance == TIM2) {
currentHalfCycle ^= 1;
sineIndex = 0;
HAL_GPIO_TogglePin(GPIOD, GPIO_PIN_13);
}
}
2025-08-28 12:59 AM
Maybe you want to toggle currentHalfCycle based on counting sineIndex (as you already do for resetting every 5 samples), and avoid using TIM2 altogether.
JW