RA MCU 有两种定时器外设:GPT(General PWM Timer)定时器和 AGT(Asynchronous General Purpose Timer)定时器。 在它们之间进行选择时,需要考虑以下因素:
低功耗异步通用定时器(AGT)是 16 位的定时器,可用于基本的定时、脉冲输出、外部脉冲宽度或周期测量,以及外部事件计数。 该定时器主要由一个重加载寄存器和一个递减计数器组成。
RA MCU 的不同型号之间可能拥有不同数量的 AGT 定时器, 规格也有可能不同,比如适用于电机控制的 RA6T2 型号MCU拥有 AGTW 定时器,AGTW 的计数器位数加宽到了32位。 而对于野火启明6M5开发板上板载的 RA6M5 芯片拥有 6 个16位的 AGT 定时器(AGTn (n=0~5))。
AGT 定时器的详细功能参数如下表所示:
见图中标注 ① 处。
AGT 的计数器是一个 16 位的递减计数器,因此它仅支持递减计数。
重装载寄存器和递减计数器被分配到相同的地址,并且可以通过 AGT 计数器寄存器(AGT Counter Register)访问。 当我们向该地址写入值的时候,写入的值会被写入重载寄存器,读取的值会从计数器中读取。
见图中标注 ② 处。
16 位的重装载寄存器对应的是 16 位的计数器。
一般当计数器产生下溢时,重装载寄存器会对计数器进行重装载。
见图中标注 ③ 处。
主要有四类时钟输入源:
PCLKB:PCLKB, PCLKB/2, PCLKB/8
LOCO, SUBCLK:AGTLCLK/d, AGTSCLK/d (d = 1, 2, 4, 8, 16, 32, 64, 128)
仅 AGTn (n = 1, 3, 5) 也可以连接到 AGTn (n = 0, 2, 4) 的下溢信号进行计数
外部事件输入(通过 AGTIO 引脚)
见图中标注 ④ 处。
比较匹配功能可以用来输出 PWM。
见图中标注 ⑤ 处。
比较匹配的结果输出到 AGTOAn、AGTOBn 引脚。
见图中标注 ⑥ 处。
这部分连接到 AGTOn 输出引脚。
见图中标注 ⑦ 处。
下溢事件信号/测量完成事件信号属于内部信号,通过这两个信号均可触发中断。
定时器模式
在定时器模式下,计数值在计数源的每个上升沿递减1。 当计数值到达 0x0000 并输入下一个计数源时,发生计数器下溢事件并产生中断请求。
脉冲输出模式
可以从 AGTIOn 和 AGTOn 引脚输出脉冲。每次发生下溢时,输出电平都会反转。
事件计数器模式
在事件计数器模式下,计数器由输入到 AGTIOn 引脚的外部事件信号(计数源)驱动(递减计数)。
脉冲宽度测量模式
在脉冲宽度测量模式下,测量输入到 AGTIOn 引脚的外部信号的脉冲宽度。
脉冲周期测量模式
在脉冲周期测量模式下,测量输入到 AGTIOn 引脚的外部信号的脉冲周期。 仅测量周期长于计数源周期两倍的输入脉冲。此外,低电平和高电平宽度都必须长于计数源的周期。 如果输入比这些条件短的脉冲周期,输入可能会被忽略。
比较匹配功能:PWM模式
比较匹配功能可用于 PWM 输出。
PWM 输出引脚使用的开发板引出的 IO 引脚: P500,如下图所示。
_AGT_PWM_Output
├─ ......
└─ src
├─ led
│ ├─ bsp_led.c
│ └─ bsp_led.h
├─ debug_uart
│ ├─ bsp_debug_uart.c
│ └─ bsp_debug_uart.h
├─ agt
│ ├─ bsp_agt_pwm_output.c
│ └─ bsp_agt_pwm_output.h
└─ hal_entry.c
因为 PWM 输出需要使用 IO 口进行输出,因此需要先在“Pins”配置页中为 AGT 配置引脚, 将 AGT 的 AGTOA0 信号输出连接到 P500 引脚,如下图所示。
随后在“Stacks”配置页中加入 AGT 模块,并对其作如下图所示的配置。
AGT 的“Output”部分属性描述如下表所示。
/* AGT初始化函数 */
void AGT_PWM_Init(void)
{
/* 初始化 AGT 模块 */
R_AGT_Open(&g_timer_agt0_ctrl, &g_timer_agt0_cfg);
/* 启动 AGT 定时器 */
R_AGT_Start(&g_timer_agt0_ctrl);
/* 重新设置占空比为 80% */
AGT_PWM_SetDuty(80);
}
需要注意的是,在 AGT 初始化函数里面,我们重新设置了占空比:50% → 80%。 设置PWM占空比使用了我们自己写的 AGT_PWM_SetDuty 函数。
/** 自定义函数:设置PWM占空比
@param duty 占空比范围:0~100 %
*/
void AGT_PWM_SetDuty(uint8_t duty)
{
timer_info_t info;
uint32_t current_period_counts;
uint32_t duty_cycle_counts;
if (duty > 100)
duty = 100; //限制占空比范围:0~100
/* 获得AGT的信息 */
R_AGT_InfoGet(&g_timer_agt0_ctrl, &info);
/* 获得计时器一个周期需要的计数次数 */
current_period_counts = info.period_counts;
/* 根据占空比和一个周期的计数次数计算比较匹配寄存器的值 */
duty_cycle_counts = (uint32_t)(((uint64_t) current_period_counts * duty) / 100);
/* 最后调用FSP库函数设置占空比 */
R_AGT_DutyCycleSet(&g_timer_agt0_ctrl, duty_cycle_counts, AGT_OUTPUT_PIN_AGTOA);
}
该函数的主要思路是需要先知道计数器的计数周期(即当前输出的PWM信号的一个周期需要计数的值 current_period_counts), 然后计算与要设定的占空比(duty)对应的计数值(duty_cycle_counts), 最后调用FSP库函数 R_AGT_DutyCycleSet 写入该占空比对应的计数值。
调用 R_AGT_DutyCycleSet 函数时需要注意传入的第三个参数是 AGT_OUTPUT_PIN_AGTOA, 因为使用的PWM输出引脚 P500 连接到的是 AGT0 的 AGTOA 信号。 如果换用别的引脚,需要注意检查这个参数是否需要修改。
/* 用户头文件包含 */
#include "led/bsp_led.h"
#include "debug_uart/bsp_debug_uart.h"
#include "gpt/bsp_gpt_pwm_output.h"
void hal_entry(void)
{
/* TODO: add your own code here */
LED_Init(); // LED 初始化
Debug_UART4_Init(); // SCI4 UART 调试串口初始化
AGT_PWM_Init(); // AGT 初始化
printf("这是一个 AGT 的PWM输出功能实验\r\n");
printf("使用示波器测量 P500 输出的PWM波形\r\n");
// LED1 闪烁指示程序正在运行...
while(1)
{
LED1_ON;
R_BSP_SoftwareDelay(1, BSP_DELAY_UNITS_SECONDS);
LED1_OFF;
R_BSP_SoftwareDelay(1, BSP_DELAY_UNITS_SECONDS);
}
#if BSP_TZ_SECURE_BUILD
/* Enter non-secure code */
R_BSP_NonSecureEnter();
#endif
}