Here are several ways to generate pulses with [STM32](https://www.ampheo.com/search/STM32), from simple to advanced methods:

**1. Basic GPIO Pulse (Software Timing)**
**Simple Digital Write with Delay:**
```
c
#include "main.h"
#include "stm32f1xx_hal.h" // Adjust for your series
#define PULSE_PIN GPIO_PIN_0
#define PULSE_PORT GPIOA
void generateBasicPulse(uint32_t highTime_us, uint32_t lowTime_us) {
HAL_GPIO_WritePin(PULSE_PORT, PULSE_PIN, GPIO_PIN_SET); // High
delayMicroseconds(highTime_us);
HAL_GPIO_WritePin(PULSE_PORT, PULSE_PIN, GPIO_PIN_RESET); // Low
delayMicroseconds(lowTime_us);
}
// Custom microsecond delay (approximate)
void delayMicroseconds(uint32_t us) {
uint32_t start = HAL_GetTick() * 1000;
while ((HAL_GetTick() * 1000 - start) < us) {
__NOP(); // No operation
}
}
```
**Precise Software Pulse (Using DWT Cycle Counter):**
```
c
#include "core_cm4.h" // For DWT (Cortex-M4/M7)
void DWT_Init(void) {
if (!(CoreDebug->DEMCR & CoreDebug_DEMCR_TRCENA_Msk)) {
CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk;
DWT->CYCCNT = 0;
DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk;
}
}
void delayCycles(uint32_t cycles) {
uint32_t start = DWT->CYCCNT;
while ((DWT->CYCCNT - start) < cycles);
}
void generatePrecisePulse(uint32_t highTime_ns, uint32_t lowTime_ns) {
uint32_t cpuFreq = 160000000; // 160 MHz
uint32_t highCycles = (highTime_ns * cpuFreq) / 1000000000;
uint32_t lowCycles = (lowTime_ns * cpuFreq) / 1000000000;
HAL_GPIO_WritePin(PULSE_PORT, PULSE_PIN, GPIO_PIN_SET);
delayCycles(highCycles);
HAL_GPIO_WritePin(PULSE_PORT, PULSE_PIN, GPIO_PIN_RESET);
delayCycles(lowCycles);
}
```
**2. Timer-Based PWM Pulse (Hardware Generated)**
**Using Timer PWM Mode:**
```
c
TIM_HandleTypeDef htim2;
void PWM_Pulse_Init(void) {
TIM_OC_InitTypeDef sConfigOC = {0};
// Timer clock enable
__HAL_RCC_TIM2_CLK_ENABLE();
htim2.Instance = TIM2;
htim2.Init.Prescaler = 1600 - 1; // 16MHz/1600 = 10kHz
htim2.Init.CounterMode = TIM_COUNTERMODE_UP;
htim2.Init.Period = 10000 - 1; // 1Hz PWM
htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
HAL_TIM_PWM_Init(&htim2);
// PWM configuration
sConfigOC.OCMode = TIM_OCMODE_PWM1;
sConfigOC.Pulse = 5000; // 50% duty cycle
sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
HAL_TIM_PWM_ConfigChannel(&htim2, &sConfigOC, TIM_CHANNEL_1);
HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_1);
}
```
**Single Pulse Mode (One-Shot):**
```
c
void generateSinglePulse(uint32_t pulseWidth_us) {
TIM_HandleTypeDef htim3;
htim3.Instance = TIM3;
htim3.Init.Prescaler = 16 - 1; // 16MHz/16 = 1MHz (1us per tick)
htim3.Init.Period = pulseWidth_us - 1; // Pulse width in microseconds
htim3.Init.CounterMode = TIM_COUNTERMODE_UP;
htim3.Init.RepetitionCounter = 0;
HAL_TIM_OnePulse_Init(&htim3, TIM_OPMODE_SINGLE);
// Start single pulse
HAL_TIM_OnePulse_Start(&htim3, TIM_CHANNEL_1);
}
```
**3. Advanced Pulse Generation Methods**
**Pulse Train with DMA (Burst Pulses):**
```
c
uint32_t pulsePattern[] = {
1000, // High for 1000 cycles
500, // Low for 500 cycles
2000, // High for 2000 cycles
500, // Low for 500 cycles
// ... more pulses
};
void generatePulseTrain_DMA(void) {
// Configure timer for PWM
// Use DMA to transfer pulse pattern to timer CCR register
HAL_TIM_PWM_Start_DMA(&htim2, TIM_CHANNEL_1,
(uint32_t*)pulsePattern,
sizeof(pulsePattern)/sizeof(pulsePattern[0]));
}
```
**Input Capture + Output Compare (Precise Timing):**
```
c
// Generate pulse after external trigger
void TriggeredPulse_Init(void) {
// Configure input capture on Channel 1
// Configure output compare on Channel 2
// Generate pulse when trigger detected
}
```
**4. STM32CubeMX Configuration**
**Graphical PWM Setup:**
1. Open .ioc file in STM32CubeIDE
2. Select timer (TIM1, TIM2, etc.)
3. Set channel to "PWM Generation CHx"
4. Configure parameters:
* Prescaler: Timer clock divider
* Counter Period: PWM frequency
* Pulse: Duty cycle
**Code Generation:**
```
c
// CubeMX generates this in main.c
MX_TIM2_Init(); // Auto-generated timer initialization
// Start PWM
HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_1);
// Change duty cycle dynamically
__HAL_TIM_SET_COMPARE(&htim2, TIM_CHANNEL_1, newPulseValue);
```
**5. Complete Practical Examples**
**Example 1: Variable Width Pulse Generator**
```
c
#include "main.h"
TIM_HandleTypeDef htim3;
GPIO_TypeDef* PULSE_PORT = GPIOA;
uint16_t PULSE_PIN = GPIO_PIN_0;
void PulseGenerator_Init(void) {
// GPIO setup
GPIO_InitTypeDef GPIO_InitStruct = {0};
__HAL_RCC_GPIOA_CLK_ENABLE();
GPIO_InitStruct.Pin = PULSE_PIN;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF2_TIM3; // Check datasheet
HAL_GPIO_Init(PULSE_PORT, &GPIO_InitStruct);
// Timer setup for 1MHz (1us resolution)
htim3.Instance = TIM3;
htim3.Init.Prescaler = 16 - 1; // 16MHz/16 = 1MHz
htim3.Init.Period = 10000 - 1; // 10ms max pulse width
htim3.Init.CounterMode = TIM_COUNTERMODE_UP;
htim3.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
HAL_TIM_PWM_Init(&htim3);
// PWM channel setup
TIM_OC_InitTypeDef sConfigOC = {0};
sConfigOC.OCMode = TIM_OCMODE_PWM1;
sConfigOC.Pulse = 1000; // 1ms initial pulse width
sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
HAL_TIM_PWM_ConfigChannel(&htim3, &sConfigOC, TIM_CHANNEL_1);
HAL_TIM_PWM_Start(&htim3, TIM_CHANNEL_1);
}
void setPulseWidth_us(uint32_t width_us) {
if (width_us > 10000) width_us = 10000; // Limit to 10ms
__HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_1, width_us);
}
void generateSinglePulse_us(uint32_t width_us) {
setPulseWidth_us(width_us);
HAL_Delay(1); // Ensure pulse is generated
setPulseWidth_us(0); // Turn off
}
```
**Example 2: High-Frequency Pulse Burst**
```
c
// Generate burst of pulses at high frequency
void generatePulseBurst(uint32_t frequency_Hz, uint32_t pulseCount, uint32_t pulseWidth_us) {
uint32_t period_us = 1000000 / frequency_Hz;
// Configure timer for desired frequency
htim2.Init.Prescaler = 16 - 1; // 1MHz timer
htim2.Init.Period = period_us - 1;
htim2.Init.RepetitionCounter = pulseCount - 1; // Number of pulses
HAL_TIM_OnePulse_Init(&htim2, TIM_OPMODE_REPETITIVE);
// Set pulse width
__HAL_TIM_SET_COMPARE(&htim2, TIM_CHANNEL_1, pulseWidth_us);
HAL_TIM_OnePulse_Start(&htim2, TIM_CHANNEL_1);
}
```
**6. Advanced Techniques**
**Using HRTIM (High-Resolution Timer) - [STM32G4](https://www.ampheo.com/search/STM32G4)/F3/H7:**
```
c
// For ultra-precise pulses (picosecond resolution)
void HRTIM_Pulse_Init(void) {
// HRTIM provides much higher resolution than standard timers
// Suitable for power electronics, digital power conversion
}
```
**Pulse with Dead Time (For H-Bridges):**
```
c
// Complementary outputs with dead time
void ComplementaryPulse_Init(void) {
TIM_BreakDeadTimeConfigTypeDef sBreakDeadTimeConfig = {0};
// Configure dead time (prevents shoot-through in bridges)
sBreakDeadTimeConfig.OffStateRunMode = TIM_OSSR_DISABLE;
sBreakDeadTimeConfig.OffStateIDLEMode = TIM_OSSI_DISABLE;
sBreakDeadTimeConfig.DeadTime = 100; // Dead time in timer ticks
sBreakDeadTimeConfig.BreakState = TIM_BREAK_DISABLE;
HAL_TIMEx_ConfigBreakDeadTime(&htim1, &sBreakDeadTimeConfig);
}
```
**7. Measurement and Verification**
**Pulse Measurement Function:**
```
c
uint32_t measurePulseWidth(GPIO_TypeDef* port, uint16_t pin) {
uint32_t startTime, endTime;
// Wait for rising edge
while (HAL_GPIO_ReadPin(port, pin) == GPIO_PIN_RESET);
startTime = DWT->CYCCNT;
// Wait for falling edge
while (HAL_GPIO_ReadPin(port, pin) == GPIO_PIN_SET);
endTime = DWT->CYCCNT;
return (endTime - startTime) * (1000000000 / SystemCoreClock); // ns
}
```
**8. Performance Considerations**
**Method Selection Guide:**

**Optimization Tips:**
* Use DMA for pulse trains to avoid CPU intervention
* Select appropriate [timer clock](https://www.onzuu.com/category/clock-timing-ics) for required resolution
* Enable timer preload registers for glitch-free updates
* Use advanced timers (TIM1, TIM8) for complementary outputs
**9. Complete Working Example**
```
c
#include "main.h"
TIM_HandleTypeDef htim2;
int main(void) {
HAL_Init();
SystemClock_Config();
// Initialize pulse generator (1MHz timer, 10ms max period)
PulseGenerator_Init();
while (1) {
// Generate 100μs pulse
generateSinglePulse_us(100);
HAL_Delay(1000); // Wait 1 second
// Generate 500μs pulse
generateSinglePulse_us(500);
HAL_Delay(1000);
// Continuous PWM at 1kHz, 25% duty cycle
setPulseWidth_us(250); // 250μs high, 750μs low
HAL_Delay(5000);
setPulseWidth_us(0); // Stop PWM
}
}
```
**Key Points:**
* Use software methods for simple, low-frequency pulses
* Use hardware timers for precise, high-frequency pulses
* DMA + timers for complex pulse patterns without CPU load
* Always verify pulse characteristics with oscilloscope
Choose the method based on your specific requirements for precision, frequency, and complexity!