ATIM

ATIM (Advanced Timer) 基于一个32比特计数器,可实现计时、测量输入信号的脉冲长度(输入捕获)或者产生输出波形(输出比较和PWM)等功能, 支持3路带死区保护的PWM互补输出,支持多路PWM同时换相,并有2路刹车输入可快速将输出切换至安全状态。计数器本身可以进行向上、向下或者向上/向下计数, 计数时钟为系统pclk或外部输入信号,并可进行1~65536倍的预分频。ATIM共有6个channel,可以分别独立配置为输入捕获或输出模式。计数,输入捕获和输出比较 的结果可以通过中断或者DMA的方式通知系统。ATIM包含主从模式接口,可以进行多级级联,实现多级计数或同步触发等功能。

ATIM主要特性:

  • 32位向上、向下、向上/向下自动重装载计数器

  • 16位可编程(可以实时修改)预分频器,计数器时钟频率的分频系数为1~65536之间的任意数值

  • 16位可配置重复计数

  • 支持单笔计数模式(OPM),当重复计数完成后自动停止计数器

  • 6个独立通道

    • 通道1~3可分别配置为输入或输出模式,其中每个通道可输出两路带死区保护的互补PWM

    • 通道4可配置为输入或输出模式,可输出单路PWM

    • 通道5~6可配置为输出比较模式

  • 输入模式

    • 上升沿/下降沿捕获

    • PWM脉宽和周期捕获(需占用两个通道)

    • 可选4个输入端口之一或1个外部触发端口,支持防抖动滤波和预降频

  • 输出模式

    • 强制输出高/低电平

    • 计数到比较值时输出高/低/翻转电平

    • PWM输出,可配脉宽和周期

    • 多通道PWM组合输出,可产生有相互关系的多路PWM

    • 单脉冲/重触发单脉冲模式输出

  • 主从模式

    • 支持多GPT互连,可在作为主设备产生控制信号的同时,作为从设备被外部输入或其它主设备控制

    • 控制模式包括复位、触发、门控等

    • 支持多GPT同步启动、复位等

  • 编码模式输入,控制计数器向上/向下计数

  • 支持用于定位的霍尔传感器电路

  • 2路刹车输入,支持防抖动滤波,可将输出快速置于安全状态。刹车信号源包括:

    • CPU异常

    • 比较器

    • 外部输入

    • 软件触发

  • 如下事件发生时产生中断/DMA:

    • 更新:计数器向上溢出/向下溢出,计数器初始化(通过软件或者内部/外部触发)

    • 触发事件(计数器启动、停止、初始化或者由内部/外部触发计数)

    • 输入捕获

    • 输出比较

    • 刹车

    • 换相

SF32LB58X的HCPU有两个ATIM,分别是ATIM1和ATIM2。 SF32LB56X的HCPU有一个ATIM,为ATIM1。

ATIM的详细接口,请参考TIM_EX

使用ATIM

以下是ATIM 的使用和GPT基本函数的使用是一样的,只是初始化的时候,将Instance置为ATIMx. 具体使用方式请参考GPT

使用atimer的HAL接口实现定时功能

{
    #define FREQENCY (10000)
    #define TIME_MS  (3500)
    static GPT_HandleTypeDef TIM_Handle = {0};

    TIM_Handle.Instance = (GPT_TypeDef *)hwp_atim1;
    TIM_Handle.Init.Prescaler = HAL_RCC_GetPCLKFreq(CORE_ID_HCPU, 1) / FREQENCY; /*Prescaler is 16 bits, please select correct frequency*/
    TIM_Handle.core = CORE_ID_HCPU;
    TIM_Handle.Init.CounterMode = GPT_COUNTERMODE_UP; /*GPTIM could support counter up/down, BTIM only support count up*/
    TIM_Handle.Init.RepetitionCounter = 0;
    TIM_Handle.Init.Period = TIME_MS * FREQENCY / 1000;
    if (HAL_GPT_Base_Init(&TIM_Handle) == HAL_OK) /*init timer*/
    {
        HAL_NVIC_SetPriority(ATIM1_IRQn, 3, 0); /* set the TIMx priority */
        HAL_NVIC_EnableIRQ(ATIM1_IRQn); /* enable the TIMx global Interrupt */
        __HAL_GPT_CLEAR_FLAG(&TIM_Handle, GPT_FLAG_UPDATE); /* clear update flag */
        __HAL_GPT_URS_ENABLE(&TIM_Handle); /* enable update request source */
    }
    else
    {
        LOG_E("Timer init error");
        return;
    }
    if (HAL_GPT_Base_Start_IT(&TIM_Handle) != HAL_OK) /* start timer */
    {
        LOG_E("Timer start error");
        return;
    }

    /*atimer interrupt handler*/
    void ATIM1_IRQHandler(void)
    {
        ENTER_INTERRUPT();
        HAL_GPT_IRQHandler(&TIM_Handle);
        LEAVE_INTERRUPT();
    }
}

使用atimer的HAL接口实现互补PWM输出功能

atimer pwm init code:

{
    GPT_HandleTypeDef gpt_Handle = {0};
    GPT_OC_InitTypeDef oc_config = {0};
    GPT_ClockConfigTypeDef clock_config = {0};

    gpt_Handle.Instance = (GPT_TypeDef *)hwp_atim1;
    gpt_Handle.core = CORE_ID_HCPU;
    gpt_Handle.Channel = GPT_CHANNEL_1;
    gpt_Handle.Init.CounterMode = GPT_COUNTERMODE_UP;
    /*atimer base init*/
    if (HAL_GPT_Base_Init(&gpt_Handle) != HAL_OK)
    {
        LOG_E("atimer base init failed");
        return;
    }
    /*atimer clock source select*/
    clock_config.ClockSource = GPT_CLOCKSOURCE_INTERNAL;
    if (HAL_GPT_ConfigClockSource(&gpt_Handle, &clock_config) != HAL_OK)
    {
        LOG_E("atimer clock init failed");
        return;
    }
    /*atimer pwm init*/
    if (HAL_GPT_PWM_Init(&gpt_Handle) != HAL_OK)
    {
        LOG_E("atimer pwm init failed");
        return;
    }
    /*atimer pwm channel config*/
    oc_config.OCMode = GPT_OCMODE_PWM1;
    oc_config.Pulse = 0;
    oc_config.OCPolarity = GPT_OCPOLARITY_HIGH;
    oc_config.OCFastMode = GPT_OCFAST_DISABLE;
    if (HAL_GPT_PWM_ConfigChannel(&gpt_Handle, &oc_config, GPT_CHANNEL_1) != HAL_OK)
    {
        LOG_E("atimer pwm channel config failed");
        return;
    }
}

atime pwm param set:

{
    #define PWM_PERIOD  (500000000) //ns
    #define PWM_PULSE   (250000000) //ns
    #define MAX_PERIOD_ATM (0xFFFFFFFF) //32bit

    rt_uint32_t period, pulse;
    rt_uint32_t GPT_clock, psc;

    GPT_clock = HAL_RCC_GetPCLKFreq(CORE_ID_HCPU, 1);
    /* Convert nanosecond to frequency and duty cycle. 1s = 1 * 1000 * 1000 * 1000 ns */
    GPT_clock /= 1000000UL;
    period = (unsigned long long)PWM_PERIOD * GPT_clock / 1000ULL;
    psc = period / MAX_PERIOD_ATM + 1;
    period = period / psc;
    /*set atimer prescaler*/
    __HAL_GPT_SET_PRESCALER(&gpt_Handle, psc - 1);
    /*set atimer auto reload*/
    __HAL_GPT_SET_AUTORELOAD(&gpt_Handle, period - 1);
    /*set atimer pulse*/
    pulse = (unsigned long long)PWM_PULSE * GPT_clock / psc / 1000ULL;
    __HAL_GPT_SET_COMPARE(htim, GPT_CHANNEL_1, pulse - 1);

    HAL_GPT_GenerateEvent(htim, GPT_EVENTSOURCE_UPDATE);
}

atime pwm break dead time set:

{
    TIMEx_BreakDeadTimeConfigTypeDef bdt = {0};

    bdt.AutomaticOutput = 0;
    bdt.BreakFilter = 0;
    bdt.BreakPolarity = 0;
    bdt.BreakState = 0;
    bdt.Break2Filter = 0;
    bdt.Break2Polarity = 0;
    bdt.Break2State = 0;
    bdt.DeadTime = 200; /*0~1023*/
    bdt.OffStateIDLEMode = 0;
    bdt.OffStateRunMode = 0;
    bdt.DeadTimePsc = 0;

    HAL_TIMEx_ConfigBreakDeadTime(htim, &bdt);
}

API参考

bf0_hal_tim_ex.h