Peripheral advanced timer complementary output with dead zone control experiment

Introduction to complementary output with dead zone control, H bridge, channel introduction

In this section, we will learn to use the complementary output with dead zone control function of the advanced timer. Friends who are new to this knowledge may ask: What is complementary output? And with dead zone control? What? Let me tell you briefly below.

In the picture above, CH1 outputs yellow PWM, and its complementary channel CH1N outputs green PWM. By comparison, we can know that the two PWMs are just the opposite. During the period when the PWM of CH1 is high level, the PWM of CH1N is low level, and vice versa. This is the complementary output.

Let’s take a look at what is complementary output with dead zone control?

In the figure above, the PWM output by CH1 and the PWM output by CH1N are inserted for a period of time between high and low level transitions before realizing complementary output. This period of time is called dead time, and the length of the dead time can be controlled through the DTG[7:0] bit configuration. How to configure the dead time will be explained in detail later. In the figure above, the lengths of the two periods of dead time pointed out by the arrows are the same because they are both generated by the same dead time generator.

Now that we understand complementary output and complementary output with dead zone control, let’s take a look at what is the use of complementary output with dead zone control? Complementary outputs with dead zone control are often used in H-bridges to control motors. Here is a simplified diagram of an H-bridge:

Figure 22.4.3 is a simplified diagram of the H-bridge. The actual H-bridge that controls the forward and reverse rotation of the motor is more complicated, and more often uses MOS tubes. This is just to explain the complementary output with dead zone control in the H-bridge. As long as everyone understands the principles of control logic. The H-bridge in the picture above is built entirely using NPN, and the conduction logic is turned on when the base is at a high level. If the transistors Q1 and Q4 are turned on, then the direction of the motor’s current is from left to right (assuming the motor is rotating forward); if the transistors Q2 and Q3 are turned on, then the direction of the motor’s current is from right to left (assuming the motor is rotating reversely). The above is the logical principle of H-bridge controlling the forward and reverse rotation of the motor. However, transistors on the same side cannot be turned on at the same time, otherwise they will be short-circuited. For example, Q1 and Q2 are turned on at the same time or Q3 and Q4 are turned on at the same time. This is not advisable.

Now let’s think about what happens if the PWM output by OC1 (CH1) and OC1N (CH1N) in Figure 22.4.1 is input to the H bridge in Figure 22.4.3? Logically speaking, when OC1N outputs high level, OC1 outputs low level, which happens to be when Q2 and Q3 are turned on, and the motor’s current direction is from right to left (assuming the motor is reversed); otherwise, OC1 outputs high level. When , the OC1N output is low level, just when Q1 and Q4 are turned on, the motor’s current direction is from left to right (assuming the motor is rotating forward), which seems to have perfectly solved the problem of forward and reverse rotation of the motor. In fact, components have delay characteristics. For example, it takes a certain amount of time for the control signal to be transmitted from OC1 to the motor, especially for complex H-bridge circuits. Due to the characteristics of the components, there will be a short circuit phenomenon when the complementary output signal is directly used to drive the H-bridge. In order to avoid this situation, there is a complementary output with dead zone control to drive the H-bridge circuit. The dead time as shown in Figure 22.4.2 is to solve the delay characteristics of components. The user must adjust the dead time according to the device connected to the output and its characteristics (intrinsic delay of the level shifter, delay caused by the switching device).

Dead time calculation

Advanced timer complementary output with dead zone control experiment configuration steps

1. HAL_TIMEx_ConfigBreakDeadTime function

The circuit break and dead time configuration initialization function of the timer is declared as follows:

HAL_StatusTypeDef HAL_TIMEx_ConfigBreakDeadTime(TIM_HandleTypeDef *htim,
 TIM_BreakDeadTimeConfigTypeDef *sBreakDeadTimeConfig);

? Function description: Used to initialize the circuit break (i.e. brake) and dead time of the timer.

? Function parameters: Formal parameter 1 is a TIM_HandleTypeDef structure type pointer variable, which has been introduced in the basic timer. Formal parameter 2 is a TIM_BreakDeadTimeConfigTypeDef structure type pointer variable, used to configure circuit break and dead zone parameters, which is defined as follows:

typedef struct
{
     uint32_t OffStateRunMode; /* Off state selection in run mode */
     uint32_t OffStateIDLEMode; /* Off state selection in idle mode */
     uint32_t LockLevel; /* Register lock configuration */
     uint32_t DeadTime; /* Dead time setting */
     uint32_t BreakState; /* Break (i.e. brake) input enable control */
     uint32_t BreakPolarity; /* Break input polarity */
     uint32_t BreakFilter; /* Break input filter */
     uint32_t AutomaticOutput; /* Automatic recovery output enable control */
} TIM_BreakDeadTimeConfigTypeDef;

? Function return value: HAL_StatusTypeDef enumeration type value.

2. HAL_TIMEx_PWMN_Start function

Complementary output start function for timer. Its statement is as follows:

HAL_StatusTypeDef HAL_TIMEx_PWMN_Start(TIM_HandleTypeDef *htim,
                                            uint32_t Channel);

? Function description: This function is used to start the complementary output of the timer.

? Function parameters: Formal parameter 1 is a TIM_HandleTypeDef structure type pointer variable, used to configure the basic parameters of the timer. Formal parameter 2 is the timer channel, ranging from TIM_CHANNEL_1 to TIM_CHANNEL_4.

? Function return value: HAL_StatusTypeDef enumeration type value.

Code

atim.c

#include "./BSP/ATIM/atim.h"

TIM_HandleTypeDef g_timx_cplm_pwm_handle;/* timer x handle */
TIM_BreakDeadTimeConfigTypeDef g_sbreak_dead_time_config = {0};/* Dead time setting */

void atim_timx_cplm_pwm_init(uint16_t psc, uint16_t arr)
{
    TIM_OC_InitTypeDef tim_oc_cplm_pwm = {0};
    
    g_timx_cplm_pwm_handle.Instance = TIM1;
    g_timx_cplm_pwm_handle.Init.Prescaler = psc;
    g_timx_cplm_pwm_handle.Init.CounterMode = TIM_COUNTERMODE_UP;
    g_timx_cplm_pwm_handle.Init.Period = arr;
    g_timx_cplm_pwm_handle.Init.ClockDivision = TIM_CLOCKDIVISION_DIV4;
    g_timx_cplm_pwm_handle.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE; /* Enable shadow register TIMx_ARR */
    HAL_TIM_PWM_Init( & amp;g_timx_cplm_pwm_handle);
    
    tim_oc_cplm_pwm.OCMode = TIM_OCMODE_PWM1;
    tim_oc_cplm_pwm.OCPolarity = TIM_OCPOLARITY_HIGH;/* OCy high level active */
    tim_oc_cplm_pwm.OCNPolarity = TIM_OCNPOLARITY_HIGH;/* OCyN high level active */
    tim_oc_cplm_pwm.OCIdleState = TIM_OCIDLESTATE_RESET;/* When MOE=0, OCx=0 */
    tim_oc_cplm_pwm.OCNIdleState = TIM_OCNIDLESTATE_RESET;/* When MOE=0, OCxN=0 */
    HAL_TIM_PWM_ConfigChannel( & amp;g_timx_cplm_pwm_handle, & amp;tim_oc_cplm_pwm, TIM_CHANNEL_1);
    
    g_sbreak_dead_time_config.OffStateRunMode = TIM_OSSR_DISABLE;
    g_sbreak_dead_time_config.OffStateIDLEMode = TIM_OSSI_DISABLE;
    g_sbreak_dead_time_config.LockLevel = TIM_LOCKLEVEL_OFF;
    g_sbreak_dead_time_config.BreakState = TIM_BREAK_ENABLE;
    g_sbreak_dead_time_config.BreakPolarity = TIM_BREAKPOLARITY_HIGH;/* The polarity of the brake input valid signal is high */
    g_sbreak_dead_time_config.AutomaticOutput = TIM_AUTOMATICOUTPUT_ENABLE;/* Enable the AOE bit to allow automatic recovery of output after braking is completed */
    HAL_TIMEx_ConfigBreakDeadTime( & amp;g_timx_cplm_pwm_handle, & amp;g_sbreak_dead_time_config);
    
     HAL_TIM_PWM_Start( & amp;g_timx_cplm_pwm_handle, TIM_CHANNEL_1);/* Enable OCy output */
     HAL_TIMEx_PWMN_Start( & amp;g_timx_cplm_pwm_handle, TIM_CHANNEL_1);/* Enable OCyN output */
}

void HAL_TIM_PWM_MspInit(TIM_HandleTypeDef *htim)
{
    if(htim->Instance == TIM1)
    {
        GPIO_InitTypeDef gpio_init_struct = {0};
        __HAL_RCC_TIM1_CLK_ENABLE();
        __HAL_RCC_GPIOE_CLK_ENABLE();
        
        gpio_init_struct.Pin = GPIO_PIN_9;
        gpio_init_struct.Mode = GPIO_MODE_AF_PP;
        gpio_init_struct.Speed = GPIO_SPEED_FREQ_HIGH;
        HAL_GPIO_Init(GPIOE, & amp;gpio_init_struct);
        
        gpio_init_struct.Pin = GPIO_PIN_8;
        HAL_GPIO_Init(GPIOE, & amp;gpio_init_struct);
        
        gpio_init_struct.Pin = GPIO_PIN_15;
        HAL_GPIO_Init(GPIOE, & amp;gpio_init_struct);
        
        __HAL_RCC_AFIO_CLK_ENABLE();
        __HAL_AFIO_REMAP_TIM1_ENABLE();/* Mapping timer IO, PE is not the default IO of the timer used in this routine and needs to be reused */
    }
}

void atim_timx_cplm_pwm_set(uint16_t ccr, uint16_t dtg)
{
    __HAL_TIM_SET_COMPARE( & amp;g_timx_cplm_pwm_handle, TIM_CHANNEL_1, ccr);/* Set comparison register */
    
    g_sbreak_dead_time_config.DeadTime = dtg;/* Dead time setting */
    HAL_TIMEx_ConfigBreakDeadTime( & amp;g_timx_cplm_pwm_handle, & amp;g_sbreak_dead_time_config);
}



main.c

#include "./SYSTEM/sys/sys.h"
#include "./SYSTEM/usart/usart.h"
#include "./SYSTEM/delay/delay.h"
#include "./BSP/LED/led.h"
#include "./BSP/ATIM/atim.h"

int main(void)
{
    uint8_t t;
    
    HAL_Init(); /* Initialize HAL library */
    sys_stm32_clock_init(RCC_PLL_MUL9); /* Set clock, 72Mhz */
    delay_init(72); /* Delay initialization */
    usart_init(115200); /* The serial port is initialized to 115200 */
    
    led_init();
    atim_timx_cplm_pwm_init(72 - 1, 1000 - 1);
    atim_timx_cplm_pwm_set(700 - 1, 100);
    
    while(1)
    {
        
        
        t + + ;
        if(t > 20)
        {
            t = 0;
            LED0_TOGGLE();
        }
        delay_ms(10);
    }
}




Note: Because PE8/PE9/PE15 is not the multiplexing function pin of TIM1 by default, full remapping must be enabled.

The first part is to enable the timer and the GPIO clock corresponding to the related channel, and initialize the related IO pins.

In the second part, the parameters such as ARR and PSC of the timer are initialized through the HAL_TIM_PWM_Init function.

The third part sets PWM mode 1, output polarity, and output idle state through the HAL_TIM_PWM_ConfigChannel function.

The fourth part is to configure the circuit breaking function through the HAL_TIMEx_ConfigBreakDeadTime function.

Finally, remember to call the HAL_TIM_PWM_Start function and HAL_TIMEx_PWMN_Start function to start the channel output and complementary channel output.

Set the dead time by re-calling the HAL_TIMEx_ConfigBreakDeadTime function. Note that g_sbreak_dead_time_config here is a global structure variable. Other structure members have been initialized in the atim_timx_cplm_pwm_init function. Here, only the DeadTime member (dead time) is configured.

First look at the statement atim_timx_cplm_pwm_init(1000 – 1, 72 – 1). These two formal parameters set the value of the auto-reload register to 999 and the value of the timer prescaler register to 71 respectively. Let’s look at the prescaler coefficient first. We set it to divide by 72. The clock source frequency of timer 1 is equal to the APB2 bus clock frequency, which is 72MHz. We can get that the counting frequency of the counter is 1MHz, that is, counting once every 1us. Then the value of the auto-reload register is 999, which determines the frequency (period) of the PWM. The period of the PWM can be obtained as (999 + 1)*1us = 1000us = 1ms. In edge-aligned mode, using PWM mode 1 or PWM mode 2, the resulting PWM period is the timer overflow time. The 1ms here can also be obtained directly through the timer overflow time calculation formula Tout= ((arr + 1)*(psc + 1))/Tclk.

Calling the statement atim_timx_cplm_pwm_set(700, 100) is equivalent to setting the value of the capture/compare register to 700 and the value of DTG[7:0] to 100. Through calculation, it can be found that the PWM duty cycle is 70% and the dead time is 5.56us. According to the analysis of the PWM generation principle and the configuration of the PWM mode in the atim_timx_cplm_pwm_init function 1. The OCy output polarity is high, and the calculation of the duty cycle is very simple and can be obtained from 700/1000.

The value of the positive pulse width of the complementary output PWM wave minus the negative pulse width of the normal PWM divided by 2 is the dead time. It can also be the positive pulse width of the normal PWM minus the negative pulse width of the complementary output PWM wave. Divide the value by 2. We use the first method to get: dead time = (705 – 694)/2 us=5.5us. It is basically the same as our theoretical value of 5.56us. This error is normal.

Braking function verification: When the brake input pin (PE15) is connected to a high level (here, PE15 is directly connected to 3.3V with a Dupont line), braking will occur, that is, PE9 and PE8 stop outputting PWM waves, and the MOE bit is set by hardware. Clear. We set when MOE=0, OCx=0, OCxN=0, that is, PE9 and PE8 both output low level.

In addition, because we enable the AOE bit (that is, set this bit to 1), if the brake input is of invalid polarity, the MOE bit will automatically be set to 1 when the next update event occurs, and the running mode will be restored (that is, continue to output PWM). Therefore, when you stop connecting PE15 to a low level (unplug the previously connected DuPont line), the PWM will automatically resume output.