Peripheral advanced timer outputs a specified number of PWM experiments

Introduction to Advanced Timers

Advanced timer block diagram

The block diagram of the advanced timer is very similar to the general timer block diagram, except that some other functions are added, such as: repetition counter, complementary output channel with dead zone control, break input, etc. The location of these functions in the advanced timer block diagram is as follows: In the picture above, three parts are framed. This is different from the general timer. Let’s introduce them separately below.

① Repeat Counter

In the F1 series, the advanced timers TIM1 and TIM8 have repeat counters. Let’s introduce what the repeat counter does? When learning basic timers and general timers, we know that when the timer overflows or underflows, an update event will be directly generated. But the timer with a repetition counter is not exactly like this. Every time the timer overflows or underflows, the value of the repetition counter will be reduced by one. When the value of the repetition counter is 0, another overflow or underflow occurs. The timer update event will be generated only after overflow. If we set the value of the repetition counter register RCR to N, then the update event will occur when the timer overflows or underflows N + 1 times.

It should be noted here that the repetition counter register has a shadow register, so the RCR register only acts as a buffer. The value of the RCR register will be transferred to its shadow register when an update event occurs, so that it truly takes effect.

The characteristics of the repetition counter are very useful when controlling the generation of PWM signals. There will be corresponding experiments later.

② Output comparison

Compared with the general timer, the advanced timer output comparison part has an additional complementary output function with dead zone control. Figure 22.1.1 TIMx_CH1N, TIMx_CH2N and TIMx_CH3N in part ② are the complementary output channels of timer channel 1, channel 2 and channel 3 respectively. Channel 4 has no complementary output channel. DTG is a dead-time generator, and the dead-time is configured by the DTG[7:0] bits. If complementary channels and dead time control are not used, the use of the output comparison part of the advanced timers TIM1 and TIM8 is basically the same as that of the general timer, except that the MOE bit must be set to 1 before the timer can output.

If complementary channels are used, there will be certain differences. We will introduce the details in the advanced timer complementary output with dead zone control experiment section.

③ Circuit Breaking Function

The circuit breaker function is also called the brake function and is generally used for motor-controlled braking. The F1 series has a trip channel, and the trip source can be the brake input pin (TIMx_BKIN) or a clock failure event. A clock failure event is generated by resetting the clock safety system in the clock controller. After system reset, the circuit breaker function is disabled by default and the MOE bit is low.

To enable the circuit breaker function: Set bit BKE of TIMx_BDTR to 1. The input active level of the trip input pin TIMx_BKIN can be set via bit BKP of the TIMx_BDTR register.

After the braking function is enabled: the OCx and OCxN output states are controlled by the MOE, OSSI, OSSR bits of TIMx_BDTR, the OISx, OISxN bits of TIMx_CR2, and the CCxE and CCxNE bits of TIMx_CCER. At no time can the OCx and OCxN outputs be active at the same time.

What happens when an input break occurs?

1, the MOE bit is cleared asynchronously, and OCx and OCxN are inactive, idle, or reset state (selected by the OSSI bit).

2. The status of OCx and OCxN: determined by the status of the relevant control bits. When using complementary output: the output level is automatically controlled according to the situation. Refer to Table 75 on page 245 of the manual “STM32F10xxx Reference Manual_V10 (Chinese version).pdf” Control bits of complementary channels Ocx and OcxN with brake function.

3. The BIF bit is set to 1. If the BIE bit is enabled, a brake interrupt will be generated; if the TDE bit is enabled, a DMA request will be generated.

4. If the AOE bit is set to 1, the MOE bit is automatically set to 1 at the next update event UEV.

The advanced timer block diagram is briefly introduced here. Next, we will learn advanced timers through actual experiments.

Advanced timer outputs a specified number of PWM experimental principles

Advanced timer output specified number of PWM experiment configuration steps

Introduction to related HAL library functions

Code

atim.c

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

TIM_HandleTypeDef g_timx_npwm_chy_handle;/* timer x handle */

/* g_npwm_remain indicates how many pulses are left to send.
 * Send up to 256 pulses each time
 */
static uint8_t g_npwm_remain = 0;

void atim_timx_npwm_chy_init(uint16_t psc, uint16_t arr)
{
    TIM_OC_InitTypeDef timx_oc_npwm_chy = {0};/* timer output */
    
    g_timx_npwm_chy_handle.Instance = TIM8;
    g_timx_npwm_chy_handle.Init.Prescaler = psc;
    g_timx_npwm_chy_handle.Init.CounterMode = TIM_COUNTERMODE_UP;
    g_timx_npwm_chy_handle.Init.Period = arr;
    g_timx_npwm_chy_handle.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE; /*Enable TIMx_ARR for buffering */
    g_timx_npwm_chy_handle.Init.RepetitionCounter = 0;
    HAL_TIM_PWM_Init( & amp;g_timx_npwm_chy_handle);
    
    timx_oc_npwm_chy.OCMode = TIM_OCMODE_PWM1;
    timx_oc_npwm_chy.Pulse = arr / 2;
    timx_oc_npwm_chy.OCPolarity = TIM_OCPOLARITY_HIGH;
    HAL_TIM_PWM_ConfigChannel( & amp;g_timx_npwm_chy_handle, & amp;timx_oc_npwm_chy, TIM_CHANNEL_1);/* Configure TIMx channel y */
    
    __HAL_TIM_ENABLE_IT( & amp;g_timx_npwm_chy_handle, TIM_IT_UPDATE);/* Allow update interrupt */
    HAL_TIM_PWM_Start( & amp;g_timx_npwm_chy_handle, TIM_CHANNEL_1);/* Open the corresponding PWM channel */
}

void HAL_TIM_PWM_MspInit(TIM_HandleTypeDef *htim)
{
    if(htim->Instance == TIM8)
    {
        GPIO_InitTypeDef gpio_init_struct;
        __HAL_RCC_TIM8_CLK_ENABLE();
        __HAL_RCC_GPIOC_CLK_ENABLE();
        
        gpio_init_struct.Pin = GPIO_PIN_6;
        gpio_init_struct.Mode = GPIO_MODE_AF_PP;
        gpio_init_struct.Pull = GPIO_PULLUP;
        gpio_init_struct.Speed = GPIO_SPEED_FREQ_HIGH;
        HAL_GPIO_Init(GPIOC, & amp;gpio_init_struct);
        
        HAL_NVIC_SetPriority(TIM8_UP_IRQn, 1, 3);
        HAL_NVIC_EnableIRQ(TIM8_UP_IRQn);
    }
}

void atim_timx_npwm_chy_set(uint8_t npwm)
{
    if(npwm==0)
    {
        return;
    }
    else
    {
        g_npwm_remain = npwm;/* Save the number of pulses */
        HAL_TIM_GenerateEvent( & amp;g_timx_npwm_chy_handle, TIM_EVENTSOURCE_UPDATE);/* Generate an update event and process the pulse output in the interrupt */
        __HAL_TIM_ENABLE( & amp;g_timx_npwm_chy_handle);
    }
}

void TIM8_UP_IRQHandler(void)
{
    HAL_TIM_IRQHandler( & amp;g_timx_npwm_chy_handle);
}

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
    if(htim->Instance == TIM8)
    {
        if(g_npwm_remain)
        {
            TIM8->RCR = g_npwm_remain - 1;
            HAL_TIM_GenerateEvent( & amp;g_timx_npwm_chy_handle, TIM_EVENTSOURCE_UPDATE);
            __HAL_TIM_ENABLE( & amp;g_timx_npwm_chy_handle);
            g_npwm_remain = 0;
        }
        else
        {
            TIM8->CR1 & amp;= ~(1 << 0);
        }
    }
}






main.c

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

int main(void)
{
    uint8_t key;
    uint8_t t = 0;
    
    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();
    key_init();
    atim_timx_npwm_chy_init(7200 - 1, 5000 - 1); /* 10Khz counting frequency, 2hz PWM frequency. */
    atim_timx_npwm_chy_set(5);/* Output 5 PWM waves (control LED1 (BLUE) to flash 5 times) */
    
    /* Set the LED1 pin to input mode to avoid conflict with PC6 */
    GPIO_InitTypeDef gpio_init_struct;
    __HAL_RCC_GPIOE_CLK_ENABLE();
    gpio_init_struct.Pin = GPIO_PIN_5;
    gpio_init_struct.Mode = GPIO_MODE_AF_INPUT;
    gpio_init_struct.Pull = GPIO_PULLUP;
    HAL_GPIO_Init(GPIOE, & amp;gpio_init_struct);
    
    while(1)
    {
        key = key_scan(0);
        if(key == KEY0_PRES)/* KEY0 pressed */
        {
            atim_timx_npwm_chy_set(6);/* Output 6 PWM waves (control TIM8_CH1, that is, PC6 outputs 6 pulses) */
        }
        
        t + + ;
        if(t > 20)
        {
            t=0;
            LED0_TOGGLE();
        }
        delay_ms(10);
    }
}