18. GPTMR

18.1. 概述

  • 主要特征功能

    • 主要介绍先楫的gptmr外设的主要驱动接口说明和调用方法。更多内容请参考 hpm_gptmr_drv.h 的API说明以及相关用户手册。

    • 每个定时器拥有4个独立通道,每个通道配置了一个32位分辨率的计数器(仅支持向上模式)、可配置的32位重装载寄存器。

    • 定时器的每个通道的计数器支持同步。 可参考 gptmr_sync_counter 例子

    • 定时器每个通道可同时支持输入捕获和输出比较,可参考 gptmr_input_captrue 例子, gptmr_output_compare 例子

    • 定时器每个通道支持两个输出比较器,生成边沿PWM和中心对齐PWM。 可参考 gptmr_generate_pwm 例子

    • 定时器每个通道支持上升沿/下降沿捕获,支持硬件测量PWM周期和占空比。可参考 gptmr_measure_pwm 例子

    • 支持外部信号计数。 可参考 gptmr_external_counter_mode 例子

    • 支持生成DMA请求。可参考 dma_use_gptmr_event_transfer 例子

    • 定时器支持单次模式、burst模式、循环模式。可参考 gptmr_one_shot_counter_mode 例子

    • 支持中断请求。可参考 timer_basic 例子

18.2. GPTMR通道配置

  • 需要确保GPTMR的时钟源已经开启,并且初始化了相关GPTMR外设引脚。

    • 可使用`clock_add_to_group` 函数用于将GPTMR时钟源添加到时钟组中,从而确保GPTMR时钟源已经开启。

  • GPTMR每个通道支持独立配置,可配置不同功能,比如输入捕获、输出比较、PWM等。

  • 相关枚举值介绍:

    • 定时器通道硬件输入同步触发的边沿

      typedef enum gptmr_synci_edge {
      
          /* 无触发 */
          gptmr_synci_edge_none = 0,
      
          /* 下降沿触发 */
          gptmr_synci_edge_falling = GPTMR_CHANNEL_CR_SYNCIFEN_MASK,
      
          /* 上升沿触发 */
          gptmr_synci_edge_rising = GPTMR_CHANNEL_CR_SYNCIREN_MASK,
      
          /* 上升沿和下降沿都触发 */
          gptmr_synci_edge_both = gptmr_synci_edge_falling | gptmr_synci_edge_rising,
      } gptmr_synci_edge_t;
      
      • 这个枚举是用于配置定时器通道的硬件输入同步触发的边沿。硬件SYNCI输入信号是通过电机系统中的TRGM信号连接到定时器通道的内部SYNCI输入上。

      • 可以使用 void gptmr_channel_select_synci_valid_edge API函数来选择定时器通道的硬件输入同步触发的边沿。

      • 对于没有电机系统的外设,比如HPM6800,硬件同步SYNCI不是通过 TRGM 来的,而是来自GPTMR7的CMP0~3,GPTMR7的每一个CMP通道分别控制两个GPTMR。

    • 定时器通道输入捕获工作模式

      typedef enum gptmr_work_mode {
      
          /* 无捕获 */
          gptmr_work_mode_no_capture = 0,
      
          /* 上升沿捕获 */
          gptmr_work_mode_capture_at_rising_edge = 1,
      
          /* 下降沿捕获 */
          gptmr_work_mode_capture_at_falling_edge = 2,
      
          /* 上升沿和下降沿都捕获 */
          gptmr_work_mode_capture_at_both_edge = 3,
      
          /* 测量PWM模式 */
          gptmr_work_mode_measure_width = 4,
      } gptmr_work_mode_t;
      
      • 这个枚举是用于配置定时器通道的输入捕获工作模式。

      • 可以使用 gptmr_channel_set_capmode API函数来选择定时器通道的输入捕获工作模式。

      • 可以使用 gptmr_channel_get_capmode API函数来获取定时器通道的输入捕获工作模式。

      • gptmr_work_mode_measure_width 模式下,捕获到输入信号上升沿时,会产生对应的中断事件或者DMA请求。

    • 定时器通道DMA请求事件

      typedef enum gptmr_dma_request_event {
      
          /* CMP0 DMA请求: 当计数器到达CMP0的时,定时器通道会请求一次DMA */
          gptmr_dma_request_on_cmp0 = 0,
      
          /* CMP1 DMA请求:当计数器到达CMP1的时,定时器通道会请求一次DMA */
          gptmr_dma_request_on_cmp1 = 1,
      
          /* 输入信号翻转DMA请求:输入捕获信号发生翻转时,定时器通道会请求一次DMA*/
          gptmr_dma_request_on_input_signal_toggle = 2,
      
          /* 重载DMA请求:当计数器达到重装载reload时,定时器通道会请求一次DMA */
          gptmr_dma_request_on_reload = 3,
      
          /* 关闭DMA请求 */
          gptmr_dma_request_disabled = 0xFF,
      } gptmr_dma_request_event_t;
      
      • 这个枚举是用于配置定时器通道的DMA请求事件。

    • 定时器获取计数器类型

      typedef enum gptmr_counter_type {
      
          /* 获取上升沿捕获的计数器值 */
          gptmr_counter_type_rising_edge = 0,
      
          /* 获取下降沿捕获的计数器值 */
          gptmr_counter_type_falling_edge,
      
          /* 获取PWM模式下的PWM宽度 */
          gptmr_counter_type_measured_period,
      
          /* 获取PWM模式下的PWM占空比 */
          gptmr_counter_type_measured_duty_cycle,
      
          /* 获取正常模式下的计数器值 */
          gptmr_counter_type_normal,
      } gptmr_counter_type_t;
      
      • 可以使用 gptmr_channel_get_counter API函数来获取定时器通道的各类类型的计数器值。

    • 定时器计数器模式

      typedef enum gptmr_counter_mode {
      
          /* 内部计数器模式 */
          gptmr_counter_mode_internal = 0,
      
          /* 外部计数器模式 */
          gptmr_counter_mode_external,
      } gptmr_counter_mode_t;
      
      • 仅适用于 hpm_soc_ip_feature.hHPM_IP_FEATURE_GPTMR_CNT_MODE 宏定义的SOC

    • 定时器通道监控信号类型

      typedef enum gptmr_channel_monitor_type {
      
          /* 监控输入信号的周期 */
          monitor_signal_period = 0,
      
          /* 监控输入信号的高电平时间 */
          monitor_signal_high_level_time,
      } gptmr_channel_monitor_type_t;
      
      • 仅适用于 hpm_soc_ip_feature.hHPM_IP_FEATURE_GPTMR_MONITOR 宏定义的SOC

  • 相关结构体介绍:

    • 定时器通道监控信号配置

      typedef struct gptmr_channel_monitor_config {
      
          /* 监控信号类型 */
          gptmr_channel_monitor_type_t monitor_type;
      
          /* 监控信号的最大和最小值 */
          uint32_t max_value;
          uint32_t min_value;
      } gptmr_channel_monitor_config_t;
      
    • 定时器通道配置

      typedef struct gptmr_channel_config {
      
          /* 输入捕获的工作模式 */
          gptmr_work_mode_t mode;
      
          /* DMA请求事件 */
          gptmr_dma_request_event_t dma_request_event;
      
          /* 输入捕获的同步触发边沿 */
          gptmr_synci_edge_t synci_edge;
      
          /* 两个输出比较的比较值 */
          uint32_t cmp[GPTMR_CH_CMP_COUNT];
      
          /* 重装载值 */
          uint32_t reload;
      
          /* 输出比较的极性 */
          bool cmp_initial_polarity_high;
      
          /* 是否使能输出比较 */
          bool enable_cmp_output;
      
          /* 是否使能该通道计数器会随着上一通道计数器的一起重载。 该参数不适用于通道0 */
          bool enable_sync_follow_previous_channel;
      
          /* 是否使能软件同步 */
          bool enable_software_sync;
      
          /* 是否使能调试模式 */
          bool debug_mode;
      
          /* 当前SOC是否支持监控信号 */
      #if defined(HPM_IP_FEATURE_GPTMR_MONITOR) && (HPM_IP_FEATURE_GPTMR_MONITOR == 1)
      
          /* 是否使能监控信号 */
          bool enable_monitor;
          /* 监控信号配置 */
          gptmr_channel_monitor_config_t monitor_config;
      #endif
      
          /* 当前SOC是否支持外部计数器模式 */
      #if defined(HPM_IP_FEATURE_GPTMR_CNT_MODE) && (HPM_IP_FEATURE_GPTMR_CNT_MODE == 1)
      
          /* 计数器模式 */
          gptmr_counter_mode_t counter_mode;
      #endif
      
          /* 当前SOC是否支持OPMODE 循环模式或者单次模式 */
      #if defined(HPM_IP_FEATURE_GPTMR_OP_MODE) && (HPM_IP_FEATURE_GPTMR_OP_MODE == 1)
          bool enable_opmode;
      #endif
      } gptmr_channel_config_t;
      
      • 单次模式,计时器到达重载值后会停止计时,软件需要清除CEN 后重新置位 CEN,开始下一次计数。下一次开启可以直接使用 gptmr_start_counter API函数来开启,内部已做了清除步骤。

      • 单次模式下,若需要使用重载中断,则需要在重载中断中关闭计数器使能、复位计数器、清除重载中断状态,方可清除重载中断。推荐使用CMP比较中断。可参考 gptmr_one_shot_counter_mode 例子

  • 缺省配置API:

    • 建议在配置gptmr通道前,先使用 gptmr_channel_get_default_config API函数获取默认配置,然后根据需要修改配置。

    void gptmr_channel_get_default_config(GPTMR_Type *ptr, gptmr_channel_config_t *config);
    
    • 默认配置如下:

      • 输入捕获工作模式: gptmr_work_mode_no_capture

      • DMA请求事件: gptmr_dma_request_disabled

      • 输入捕获的同步触发边沿: gptmr_synci_edge_none

      • 两个输出比较的比较值: 0xFFFFFFFEUL

      • 重装载值: 0xFFFFFFFEUL

      • 输出比较的极性: high

      • 是否使能输出比较: true

      • 是否使能该通道计数器会随着上一通道计数器的一起重载。 该参数不适用于通道0: false

      • 是否使能软件同步: true

      • 是否使能调试模式: true

      • 是否使能监控信号: false

      • 计数器模式: gptmr_counter_mode_internal

      • 是否使能OPMODE 循环模式或者单次模式: false

    • 注意

      • 输出比较支持快速输出逻辑 0 和逻辑 1,即把 CMP0 配置为 32’hFFFFFFFF 时,通道输出始终为逻辑 0。把CMP1 配置为 32’hFFFFFFFF,且 CMP0 不为全 1 时,通道输出始终为逻辑 1。

      • 默认使能输出比较,如果需要恒定输出高电平或者低电平,则需要配置对应的输出比较的比较值为0xFFFFFFFFUL。

  • 定时器通道配置API:

    hpm_stat_t gptmr_channel_config(GPTMR_Type *ptr, uint8_t ch_index,gptmr_channel_config_t *config, bool enable);
    
    • 参数说明:

      参数名

      类型

      描述

      ptr

      GPTMR_Type *

      指向GPTMR控制器的指针

      ch_index

      uint8_t

      通道索引,取值范围为0-3

      config

      gptmr_channel_config_t *

      指向通道配置结构体的指针

      enable

      bool

      是否使能通道的计数器开启计数

    • 返回值:

      返回值

      描述

      status_invalid_argument

      无效的参数

      status_success

      配置成功

    • 举例:

      • 配置定时器0通道0定时1ms

        gptmr_channel_config_t config;
        uint32_t gptmr_freq;
        gptmr_channel_get_default_config(HPM_GPTMR0, &config);
        gptmr_freq = clock_get_frequency(clock_gptmr0); /* 获取GPTMR0的时钟频率 */
        config.mode = gptmr_work_mode_no_capture;  /* 无捕获 */
        config.reload = gptmr_freq / (1000 * 1);  /* 1ms */
        config.enable_cmp_output = false;        /* 不使能输出比较 */
        config.enable_software_sync = false;      /* 不使能软件同步 */
        gptmr_channel_config(HPM_GPTMR0, 0, &config, true);
        
      • 配置定时器0通道1生成100KHz,50%占空比的边沿对齐PWM

        gptmr_channel_config_t config;
        uint32_t gptmr_freq;
        gptmr_channel_get_default_config(HPM_GPTMR0, &config);
        gptmr_freq = clock_get_frequency(clock_gptmr0); /* 获取GPTMR0的时钟频率 */
        config.mode = gptmr_work_mode_no_capture;  /* 无捕获 */
        config.reload = gptmr_freq / 100000;  /* 100KHz */
        config.cmp[0] = config.reload / 2;  /* 50%占空比 */
        config.enable_cmp_output = true;        /* 使能输出比较 */
        config.enable_software_sync = false;      /* 不使能软件同步 */
        gptmr_channel_config(HPM_GPTMR0, 1, &config, true);
        

18.3. Burst 模式

  • burst 模式:计时器到达重载值达到指定的次数(burst_cfg)后停止计数。

  • 仅适用于 hpm_soc_ip_feature.hHPM_IP_FEATURE_GPTMR_BURST_MODE 宏定义的SOC

  • 相关枚举值介绍:

    • Burst模式下的两种计数器启动模式

      typedef enum gptmr_burst_counter_mode {
          gptmr_burst_counter_restart = 0,   /* 重新开始计数 */
          gptmr_burst_counter_continue,      /* 继续计数 */
      } gptmr_burst_counter_mode_t;
      
      • gptmr_burst_counter_restart:重启模式。在此模式下,启动计数器,会重置当前计数(通常从 0 开始), GPTMR的 BURST_COUNT 清零 并重新开始新的突发周期。

      • gptmr_burst_counter_continue:继续模式。在此模式下,启动计数器时,若当前突发计数未达到配置的最大次数(由 BURST_CFG 设置),则继续从当前值计数;若已达到最大次数,则重置后继续。

  • 注意

    • 单次循环模式和Burst模式最多只能有一个使能

      • 可使用 gptmr_channel_enable_burst_mode API使能Burst模式,如果使能了单次循环模式,该API会返回参数错误。

      • 可使用 gptmr_channel_disable_burst_mode API禁能Burst模式。

      • 判断是否使能了Burst模式可使用 gptmr_channel_is_burst_mode API

    • 当 GPTMR的 BURST_COUNT 等于 BURST_CFG 时,BURST_COUNT 不会再自增, 计数器也不会再计数。如果需要开启下一次计数,需要清除 ‘CEN’ 再置位 ‘CEN’,然后复位计数器 ‘CNTRST’。如果复位GPTMR的 BURST_COUNT,可间接操作复位计数器 ‘CNTRST’。

      • 开启Busrt模式计数,可使用 gptmr_channel_burst_mode_start_counter API。计数模式按照 gptmr_burst_counter_mode_t 配置。

      • 关闭Burst模式计数,可使用 gptmr_channel_burst_mode_stop_counter API。

      • 获取GPTMR的 BURST_COUNT 可使用 gptmr_channel_get_current_burst_count API。

      • 设置GPTMR的 BURST_CFG 可使用 gptmr_channel_set_target_burst_count API。

      • 获取GPTMR的 BURST_CFG 可使用 gptmr_channel_get_target_burst_count API。

  • 举例:GPTMR0通道1 Burst模式配置,重载为1S,计数10次,计数模式为重启模式

    #include <stdio.h>
    #include "board.h"
    #include "hpm_sysctl_drv.h"
    #include "hpm_gptmr_drv.h"
    #include "hpm_debug_console.h"
    
    #define APP_BOARD_GPTMR               BOARD_GPTMR
    #define APP_BOARD_GPTMR_CH            BOARD_GPTMR_CHANNEL
    #define APP_BOARD_GPTMR_IRQ           BOARD_GPTMR_IRQ
    
    #define APP_TICK_MS                   (1000)
    
    static void timer_config(void);
    
    uint32_t target_burst_count, current_burst_count;
    
    SDK_DECLARE_EXT_ISR_M(APP_BOARD_GPTMR_IRQ, tick_ms_isr)
    void tick_ms_isr(void)
    {
        target_burst_count = gptmr_channel_get_target_burst_count(APP_BOARD_GPTMR, APP_BOARD_GPTMR_CH);
        current_burst_count = gptmr_channel_get_current_burst_count(APP_BOARD_GPTMR, APP_BOARD_GPTMR_CH);
        if (gptmr_check_status(APP_BOARD_GPTMR, GPTMR_CH_RLD_STAT_MASK(APP_BOARD_GPTMR_CH))) {
            gptmr_clear_status(APP_BOARD_GPTMR, GPTMR_CH_RLD_STAT_MASK(APP_BOARD_GPTMR_CH));
            printf("timer tick %d ms\n", APP_TICK_MS);
            board_led_toggle();
            /* 若BURST_COUNT等于BURST_CFG,说明已经计数BURST_CFG次 */
            if (target_burst_count == current_burst_count) {
                gptmr_channel_burst_mode_start_counter(APP_BOARD_GPTMR, APP_BOARD_GPTMR_CH, gptmr_burst_counter_restart);
                printf("gptmr channel burst\n");
            }
        }
    }
    
    int main(void)
    {
        board_init();
        board_init_led_pins();
        init_gptmr_pins(APP_BOARD_GPTMR);
        printf("gptmr timer basic test\n");
        timer_config();
        while (1) {
        }
    }
    
    static void timer_config(void)
    {
        uint32_t gptmr_freq;
        gptmr_channel_config_t config;
    
        gptmr_freq = board_init_gptmr_clock(APP_BOARD_GPTMR);
        /* config 缺省关闭了单次模式-OP mode */
        gptmr_channel_get_default_config(APP_BOARD_GPTMR, &config);
        /* reload为1S */
        config.reload = gptmr_freq / 1000 * APP_TICK_MS;
        gptmr_channel_config(APP_BOARD_GPTMR, APP_BOARD_GPTMR_CH, &config, false);
    
        /*设置GPTMR的 `BURST_CFG` 为10,计数10次 */
        gptmr_channel_set_target_burst_count(APP_BOARD_GPTMR, APP_BOARD_GPTMR_CH, 10);
        /* 使能Burst模式 */
        gptmr_channel_enable_burst_mode(APP_BOARD_GPTMR, APP_BOARD_GPTMR_CH);
        /* 使能计数器 */
        gptmr_start_counter(APP_BOARD_GPTMR, APP_BOARD_GPTMR_CH);
        /* 使能 reload中断 */
        gptmr_enable_irq(APP_BOARD_GPTMR, GPTMR_CH_RLD_IRQ_MASK(APP_BOARD_GPTMR_CH));
        intc_m_enable_irq_with_priority(APP_BOARD_GPTMR_IRQ, 1);
    }
    

18.4. GPTMR例子