#include "stm32f4xx.h"
#include <math.h>
#define PWM_FREQ 400000 // Base frequency of the PWM output
#define PWM_PERIOD_US 100 // Period of the PWM output in microseconds
#define NUM_SAMPLES 100 // Number of samples per PWM period
#define PI 3.14159265358979323846
uint16_t duty_cycles[NUM_SAMPLES]; // Array of duty cycles for each sample
uint16_t current_sample = 0; // Index of current sample in the duty_cycles array
void TIM2_IRQHandler(void) {
if (TIM2->SR & TIM_SR_UIF) { // Check if the update interrupt flag is set
TIM2->SR &= ~TIM_SR_UIF; // Clear the update interrupt flag
// Set the duty cycle for the current sample
TIM2->CCR1 = duty_cycles[current_sample];
// Increment the sample index, wrapping around if necessary
current_sample = (current_sample + 1) % NUM_SAMPLES;
}
}
int main(void) {
// Enable clock for GPIOA and TIM2
RCC->AHB1ENR |= RCC_AHB1ENR_GPIOAEN;
RCC->APB1ENR |= RCC_APB1ENR_TIM2EN;
// Configure GPIOA pin 0 as alternate function mode
GPIOA->MODER &= ~GPIO_MODER_MODE0;
GPIOA->MODER |= GPIO_MODER_MODE0_1;
GPIOA->AFR[0] |= GPIO_AFRL_AFRL0_1; // Set alternate function to TIM2_CH1
// Generate duty cycle values for a sinusoidal waveform
for (uint16_t i = 0; i < NUM_SAMPLES; i++) {
float phase = 2.0 * PI * i / NUM_SAMPLES;
duty_cycles[i] = (uint16_t)((1.0 + sin(phase)) * 0.5 * 65535.0);
}
// Configure TIM2 for one-shot PWM output on CH1
TIM2->PSC = 0; // Set prescaler to 1
TIM2->ARR = PWM_PERIOD_US * (SystemCoreClock / 1000000) - 1; // Set auto-reload value for PWM period
TIM2->CCR1 = 0; // Set initial duty cycle to 0%
TIM2->CCMR1 |= TIM_CCMR1_OC1M_2 | TIM_CCMR1_OC1M_1; // Set PWM mode to mode 1
TIM2->CCER |= TIM_CCER_CC1E; // Enable capture/compare channel 1 output
TIM2->DIER |= TIM_DIER_UIE; // Enable update interrupt
NVIC_EnableIRQ(TIM2_IRQn); // Enable TIM2 interrupt in NVIC
TIM2->CR1 |= TIM_CR1_CEN; // Start the timer
while (1) {
// Wait for interrupt to update duty cycle
}
}
using HAL:
#include "main.h"
#include "stm32f4xx_hal.h"
#include <math.h>
#define PWM_FREQ 400000 // Base frequency of the PWM output
#define PWM_PERIOD_US 100 // Period of the PWM output in microseconds
#define NUM_SAMPLES 100 // Number of samples per PWM period
#define PI 3.14159265358979323846
TIM_HandleTypeDef htim2;
uint16_t duty_cycles[NUM_SAMPLES]; // Array of duty cycles for each sample
uint16_t current_sample = 0; // Index of current sample in the duty_cycles array
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) {
if (htim->Instance == TIM2) {
// Set the duty cycle for the current sample
TIM2->Instance->CCR1 = duty_cycles[current_sample];
// Increment the sample index, wrapping around if necessary
current_sample = (current_sample + 1) % NUM_SAMPLES;
}
}
int main(void) {
// Initialize HAL
HAL_Init();
// Enable clock for GPIOA and TIM2
__HAL_RCC_GPIOA_CLK_ENABLE();
__HAL_RCC_TIM2_CLK_ENABLE();
// Configure GPIOA pin 0 as alternate function mode
GPIO_InitTypeDef GPIO_InitStruct = {0};
GPIO_InitStruct.Pin = GPIO_PIN_0;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF1_TIM2;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
// Generate duty cycle values for a sinusoidal waveform
for (uint16_t i = 0; i < NUM_SAMPLES; i++) {
float phase = 2.0 * PI * i / NUM_SAMPLES;
duty_cycles[i] = (uint16_t)((1.0 + sin(phase)) * 0.5 * 65535.0);
}
// Configure TIM2 for one-shot PWM output on CH1
htim2.Instance = TIM2;
htim2.Init.Prescaler = 0;
htim2.Init.CounterMode = TIM_COUNTERMODE_UP;
htim2.Init.Period = PWM_PERIOD_US * (SystemCoreClock / 1000000) - 1;
htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
htim2.Init.RepetitionCounter = 0;
HAL_TIM_PWM_Init(&htim2);
TIM_OC_InitTypeDef sConfigOC = {0};
sConfigOC.OCMode = TIM_OCMODE_PWM1;
sConfigOC.Pulse = 0;
sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
HAL_TIM_PWM_ConfigChannel(&htim2, &sConfigOC, TIM_CHANNEL_1);
HAL_TIM_PWM_Start_IT(&htim2, TIM_CHANNEL_1);
while (1) {
// Wait for interrupt to update duty cycle
}
}