{"id":4104,"date":"2025-12-24T09:31:32","date_gmt":"2025-12-24T09:31:32","guid":{"rendered":"https:\/\/blog.embeddedexpert.io\/?p=4104"},"modified":"2025-12-24T09:37:00","modified_gmt":"2025-12-24T09:37:00","slug":"stm32-timers-applications-complementary-pwm-generation-with-dead-time","status":"publish","type":"post","link":"https:\/\/blog.embeddedexpert.io\/?p=4104","title":{"rendered":"STM32 Timers Applications: Complementary PWM Generation with Dead Time"},"content":{"rendered":"\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"683\" src=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/12\/ChatGPT-Image-Dec-20-2025-at-07_36_21-AM-1-1024x683.png\" alt=\"\" class=\"wp-image-4105\" srcset=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/12\/ChatGPT-Image-Dec-20-2025-at-07_36_21-AM-1-1024x683.png 1024w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/12\/ChatGPT-Image-Dec-20-2025-at-07_36_21-AM-1-300x200.png 300w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/12\/ChatGPT-Image-Dec-20-2025-at-07_36_21-AM-1-768x512.png 768w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/12\/ChatGPT-Image-Dec-20-2025-at-07_36_21-AM-1-1150x767.png 1150w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/12\/ChatGPT-Image-Dec-20-2025-at-07_36_21-AM-1-750x500.png 750w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/12\/ChatGPT-Image-Dec-20-2025-at-07_36_21-AM-1-400x267.png 400w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/12\/ChatGPT-Image-Dec-20-2025-at-07_36_21-AM-1-250x167.png 250w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/12\/ChatGPT-Image-Dec-20-2025-at-07_36_21-AM-1.png 1536w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p>This guide explains how to configure and use\u00a0<strong>TIM1 on STM32F4<\/strong>\u00a0to generate precise PWM and complementary PWMN signals with configurable dead-time insertion. It covers the principles of dead-time generation, complementary waveform synchronization, and the practical considerations required for safe and efficient power-stage control.<\/p>\n\n\n\n<p><\/p>\n\n\n\n<p>In this guide, we shall cover the following:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Why dead time is needed.<\/li>\n\n\n\n<li>Calculating dead time.<\/li>\n\n\n\n<li>STM32CubeMX modification.<\/li>\n\n\n\n<li>Results.<\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\">1. Why Dead Time is Needed:<br><\/h2>\n\n\n\n<p>In STM32 microcontrollers, TIM1 is an advanced-control timer capable of generating complementary PWM outputs (PWM and PWMN) with high precision. These signals are widely used to drive half-bridge or full-bridge power stages in applications such as motor control, DC-DC converters, inverters, and industrial power electronics. A fundamental requirement in all these applications is that&nbsp;<strong>high-side and low-side switches must never be on simultaneously<\/strong>, as this condition can create a short-circuit path directly across the supply rail. This potentially catastrophic condition is referred to as&nbsp;<strong>shoot-through<\/strong>. Even very short overlaps of a few nanoseconds at high voltages or currents can result in MOSFET\/IGBT damage, excessive heating, voltage spikes, or electromagnetic interference (EMI).<\/p>\n\n\n\n<p>Dead time is a carefully inserted delay between the switching of complementary outputs that ensures the&nbsp;<strong>high-side device turns off completely before the low-side device turns on<\/strong>, and vice versa. TIM1 provides&nbsp;<strong>hardware-based dead-time generation<\/strong>, which guarantees precise timing independent of CPU load, interrupts, or software execution delays. This feature is critical because software-based dead-time management is prone to latency, jitter, and timing errors, particularly at high PWM frequencies. Without hardware dead time, even small timing inconsistencies could lead to overlapping conduction, degraded efficiency, thermal stress, and possible device failure.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Key Reasons Dead Time Is Crucial<\/strong><\/h2>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>Prevention of Shoot-Through:<\/strong><br>The primary role of dead time is to eliminate the risk of simultaneous conduction in complementary power devices. By enforcing a minimum delay between the turn-off of one device and the turn-on of the other, shoot-through is avoided, protecting the devices and associated circuitry from catastrophic failure.<\/li>\n\n\n\n<li><strong>Hardware-Enforced Precision:<\/strong><br>TIM1 implements dead-time insertion internally using the\u00a0<strong>Dead-Time Generator (DTG)<\/strong>\u00a0in the\u00a0<strong>BDTR register<\/strong>, allowing sub-microsecond delays at very high PWM frequencies. Hardware enforcement ensures that the delay is\u00a0<strong>deterministic<\/strong>,\u00a0<strong>cycle-accurate<\/strong>, and free from jitter caused by software or interrupt handling, which is essential for stable and reliable operation.<\/li>\n\n\n\n<li><strong>Maintaining Signal Integrity:<\/strong><br>Complementary PWM outputs without dead time may overlap or switch too closely, causing voltage spikes and high dv\/dt transitions that can stress gate drivers, increase EMI, or generate ringing in power traces. Dead time ensures that PWM and PWMN waveforms are cleanly separated, maintaining waveform integrity for safe switching.<\/li>\n\n\n\n<li><strong>Efficiency and Thermal Management:<\/strong><br>By preventing simultaneous conduction, dead time reduces unnecessary power dissipation, ensuring that MOSFETs\/IGBTs operate within safe thermal limits. This helps maintain high efficiency in power conversion applications and prolongs the lifetime of components.<\/li>\n\n\n\n<li><strong>Consistent Operation at High PWM Frequencies:<\/strong><br>As PWM frequency increases, the time available for switching decreases. Hardware dead time allows precise insertion of necessary delays even at high frequencies (tens or hundreds of kHz), where software-based control would struggle to maintain timing accuracy.<\/li>\n\n\n\n<li><strong>Support for Safe Advanced Control Features:<\/strong><br>Dead time is essential when using additional TIM1 features such as\u00a0<strong>break inputs<\/strong>,\u00a0<strong>complementary outputs with polarity control<\/strong>, or\u00a0<strong>synchronized multi-phase PWM<\/strong>. It ensures safe operation under all fault conditions and prevents inadvertent shoot-through when the timer dynamically changes duty cycles or phase alignment.<\/li>\n<\/ol>\n\n\n\n<p><\/p>\n\n\n\n<h2 class=\"wp-block-heading\">2. Dead Time Calculation:<\/h2>\n\n\n\n<p>Dead Time Calculation<\/p>\n\n\n\n<p>For STM32F4 timers:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>The dead\u2011time generator uses a\u00a0<strong>dead\u2011time clock<\/strong>\u00a0(typically the APB2 timer clock, often 2\u00d7 PCLK2).<\/li>\n\n\n\n<li>Dead time is expressed in timer ticks based on the clock frequency.<\/li>\n<\/ul>\n\n\n\n<p><\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"332\" height=\"206\" src=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/12\/2025-12-24_12-10-08.jpg\" alt=\"\" class=\"wp-image-4106\" srcset=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/12\/2025-12-24_12-10-08.jpg 332w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/12\/2025-12-24_12-10-08-300x186.jpg 300w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/12\/2025-12-24_12-10-08-250x155.jpg 250w\" sizes=\"(max-width: 332px) 100vw, 332px\" \/><\/figure><\/div>\n\n\n<p>To compute the dead\u2011time value (DTG register value):<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"404\" height=\"100\" src=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/12\/2025-12-24_12-13-23.jpg\" alt=\"\" class=\"wp-image-4107\" srcset=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/12\/2025-12-24_12-13-23.jpg 404w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/12\/2025-12-24_12-13-23-300x74.jpg 300w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/12\/2025-12-24_12-13-23-400x100.jpg 400w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/12\/2025-12-24_12-13-23-250x62.jpg 250w\" sizes=\"(max-width: 404px) 100vw, 404px\" \/><\/figure><\/div>\n\n\n<p>Where:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Tdts\u00a0is the dead\u2011time clock period (inverse of timer clock frequency)<\/li>\n\n\n\n<li>N is the integer count configured in the\u00a0<strong>BDTR.DTG<\/strong>\u00a0field<\/li>\n<\/ul>\n\n\n\n<p><strong>Example:<\/strong><br>If the timer clock is&nbsp;<strong>16\u202fMHz<\/strong>, and we want&nbsp;<strong>500\u202fns<\/strong>&nbsp;of dead time:<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"948\" height=\"204\" src=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/12\/2025-12-24_12-17-23.jpg\" alt=\"\" class=\"wp-image-4108\" srcset=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/12\/2025-12-24_12-17-23.jpg 948w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/12\/2025-12-24_12-17-23-300x65.jpg 300w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/12\/2025-12-24_12-17-23-768x165.jpg 768w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/12\/2025-12-24_12-17-23-750x161.jpg 750w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/12\/2025-12-24_12-17-23-400x86.jpg 400w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/12\/2025-12-24_12-17-23-250x54.jpg 250w\" sizes=\"(max-width: 948px) 100vw, 948px\" \/><\/figure>\n\n\n\n<p>Thus, set\u00a0<strong>DTG = 8<\/strong>\u00a0to approximate a 500\u202fns dead\u2011time delay.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">3. STM32CubeMX Modification:<\/h2>\n\n\n\n<p>We shall continue from <a href=\"https:\/\/blog.embeddedexpert.io\/?p=4095\" data-type=\"link\" data-id=\"https:\/\/blog.embeddedexpert.io\/?p=4095\" target=\"_blank\" rel=\"noreferrer noopener\">here<\/a>.<\/p>\n\n\n\n<p>Open the project using STM32CubeMX.<\/p>\n\n\n\n<p>Once the project has been opened:<\/p>\n\n\n\n<p>In Parameters Settings of TIM1, set the dead time to 8 and click on generate project as follows:<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"588\" src=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/12\/2025-12-24_12-25-05-1024x588.jpg\" alt=\"\" class=\"wp-image-4109\" srcset=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/12\/2025-12-24_12-25-05-1024x588.jpg 1024w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/12\/2025-12-24_12-25-05-300x172.jpg 300w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/12\/2025-12-24_12-25-05-768x441.jpg 768w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/12\/2025-12-24_12-25-05-1536x882.jpg 1536w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/12\/2025-12-24_12-25-05-2048x1176.jpg 2048w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/12\/2025-12-24_12-25-05-1150x661.jpg 1150w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/12\/2025-12-24_12-25-05-750x431.jpg 750w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/12\/2025-12-24_12-25-05-400x230.jpg 400w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/12\/2025-12-24_12-25-05-250x144.jpg 250w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p><\/p>\n\n\n\n<h2 class=\"wp-block-heading\">4. Results:<\/h2>\n\n\n\n<p>Once you opened the project using STM32CubeIDE, run the project as follows:<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"37\" src=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/12\/2025-12-17_16-34-38-1024x37.jpg\" alt=\"\" class=\"wp-image-4091\" srcset=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/12\/2025-12-17_16-34-38-1024x37.jpg 1024w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/12\/2025-12-17_16-34-38-300x11.jpg 300w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/12\/2025-12-17_16-34-38-768x28.jpg 768w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/12\/2025-12-17_16-34-38-1536x55.jpg 1536w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/12\/2025-12-17_16-34-38-1150x41.jpg 1150w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/12\/2025-12-17_16-34-38-750x27.jpg 750w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/12\/2025-12-17_16-34-38-400x14.jpg 400w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/12\/2025-12-17_16-34-38-250x9.jpg 250w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/12\/2025-12-17_16-34-38.jpg 1726w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p><\/p>\n\n\n\n<p>BAfter building and flashing the firmware:<\/p>\n\n\n\n<p>Run the application.<\/p>\n\n\n\n<p>Connect a logic analyzer or oscilloscope to the PWM output pins (e.g.,\u00a0<strong>PA7<\/strong>\u00a0for PWM,\u00a0<strong>PA8<\/strong>\u00a0for PWMN).<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"630\" src=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/12\/RigolDS2.png\" alt=\"\" class=\"wp-image-4110\" srcset=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/12\/RigolDS2.png 1024w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/12\/RigolDS2-300x185.png 300w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/12\/RigolDS2-768x473.png 768w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/12\/RigolDS2-750x461.png 750w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/12\/RigolDS2-400x246.png 400w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/12\/RigolDS2-250x154.png 250w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p><\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"630\" src=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/12\/RigolDS3.png\" alt=\"\" class=\"wp-image-4111\" srcset=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/12\/RigolDS3.png 1024w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/12\/RigolDS3-300x185.png 300w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/12\/RigolDS3-768x473.png 768w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/12\/RigolDS3-750x461.png 750w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/12\/RigolDS3-400x246.png 400w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/12\/RigolDS3-250x154.png 250w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p>You should observe:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Two complementary PWM signals<\/li>\n\n\n\n<li>A clean dead\u2011time gap between transitions<\/li>\n\n\n\n<li>~500\u202fns delay between turn\u2011off and turn\u2011on edges<\/li>\n<\/ul>\n\n\n\n<p>This confirms that the hardware dead\u2011time generator is functioning as expected and ensures safe switching transitions.<\/p>\n\n\n\n<p>Happy coding \ud83d\ude09<\/p>\n\n\n\n<p><\/p>\n","protected":false},"excerpt":{"rendered":"<p>This guide explains how to configure and use\u00a0TIM1 on STM32F4\u00a0to generate precise PWM and complementary PWMN signals with configurable dead-time insertion. It covers the principles of dead-time generation, complementary waveform synchronization, and the practical considerations required for safe and efficient power-stage control. In this guide, we shall cover the following: 1. Why Dead Time is [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[2,11,12],"tags":[],"class_list":["post-4104","post","type-post","status-publish","format-standard","hentry","category-embedded-systems","category-peripheral-drivers","category-stm32"],"_links":{"self":[{"href":"https:\/\/blog.embeddedexpert.io\/index.php?rest_route=\/wp\/v2\/posts\/4104"}],"collection":[{"href":"https:\/\/blog.embeddedexpert.io\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blog.embeddedexpert.io\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blog.embeddedexpert.io\/index.php?rest_route=\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.embeddedexpert.io\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=4104"}],"version-history":[{"count":4,"href":"https:\/\/blog.embeddedexpert.io\/index.php?rest_route=\/wp\/v2\/posts\/4104\/revisions"}],"predecessor-version":[{"id":4116,"href":"https:\/\/blog.embeddedexpert.io\/index.php?rest_route=\/wp\/v2\/posts\/4104\/revisions\/4116"}],"wp:attachment":[{"href":"https:\/\/blog.embeddedexpert.io\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=4104"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.embeddedexpert.io\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=4104"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.embeddedexpert.io\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=4104"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}