引言
在嵌入式系统开发中,定时器是不可或缺的外设之一。复旦微电子公司的FPGA芯片(如FMQL20S400)提供了丰富的外设资源,其中TTC(Triple Timer Counter)是PS(Processing System)端的重要定时器模块。本文将基于TTC定时器产生中断控制led灯,详细解析复旦微FPGA芯片PS端TTC的工作原理、配置方法和应用场景。
TTC概述
PSOC提供了不同类型的定时器用来满足不同的应用需求,包括通用定时器GTC、系统看门狗定时器WDT和三重定时器TTC。FMQL20S400上有两个TTC定时器,procise新建工程添加ps的IP核后TTC的频率默认未83.333Mhz。
TTC寄存器
基地址:
0xE000_7000(TTC0)
0xE002_4000(TTC1)
代码解析
以下是一个基于复旦微JFMQL100TAI芯片的TTC定时器控制PS端LED灯闪烁的例程,我们将逐部分解析其实现原理。
头文件包含和宏定义
#include <stdio.h>
#include "platform.h"
#include "fmsh_common.h"
#include "ps_init.h"
#include "fmsh_print.h"
#include "fmsh_gic.h"
#include "fmsh_gpio_public.h"
#include "fmsh_ps_parameters.h"
#include "fmsh_ttc_public.h"
这部分代码包含了必要的头文件。这些头文件提供了访问复旦微FPGA芯片各种外设所需的API和数据结构。
全局变量声明
FGpioPs_T GpioOutput;
FGpioPs_Config *gpio_cfgPpr;
FTtcPs_T g_ttc_dev;
FTtcPs_Config* cfg;
volatile u8 g_ttc0_flag = 0;
u8 g_led_flag = 0;
这里声明了多个全局变量,包括看门狗、GPIO和TTC的设备实例和配置结构。g_ttc0_flag
是一个易失性变量,用于在中断和主程序之间传递状态信息。
主函数
int main()
{
init_platform();
fmsh_print("Hello World\n\r");
// GPIO初始化
gpio_cfgPpr = FGpioPs_LookupConfig(FPAR_GPIOPS_0_DEVICE_ID);
FGpioPs_init(&GpioOutput, gpio_cfgPpr);
FGpioPs_setDirection(&GpioOutput, 0x0080); //MIO 7
FGpioPs_writeData(&GpioOutput, 0x0);
// 中断控制器初始化
FGicPs_CommonInit(&IntcInstance);
// TTC定时器初始化
init_timer();
// 主循环
while(1) {
if(g_ttc0_flag == 1) {
FTtcPs_setTimerEnble(&g_ttc_dev, timer1, FMSH_set);
}
}
return 0;
}
主函数完成了平台初始化、外设初始化和主循环。特别注意,主循环中检查g_ttc0_flag
标志,并在条件满足时重新启用定时器。
TTC初始化函数
int init_timer()
{
// 查找并初始化TTC配置
cfg=FTtcPs_LookupConfig(FPAR_TTCPS_0_DEVICE_ID);
FTtcPs_init(&g_ttc_dev, cfg);
cfg=NULL;
// 连接中断处理函数
FGicPs_Connect(&IntcInstance, TIMER0_1_INT_ID, (FMSH_InterruptHandler)timer1_handler, &g_ttc_dev);
FGicPs_Enable(&IntcInstance, TIMER0_1_INT_ID);
// 配置TTC定时器
FTtcPs_setTimerEnble(&g_ttc_dev, timer1, FMSH_clear);
FTtcPs_setTimerMode(&g_ttc_dev, timer1, user_DefinedCount_mode);
FTtcPs_setTimerInterruptMask(&g_ttc_dev, timer1, FMSH_clear);
FTtcPs_setTIMERPWM(&g_ttc_dev, timer1, FMSH_clear);
// 设置定时器计数值(2秒)
FTtcPs_TimerNLoadCount(&g_ttc_dev, timer1, 83333333*2);
g_ttc0_flag = 0;
// 启用定时器
FTtcPs_setTimerEnble(&g_ttc_dev, timer1, FMSH_set);
return 0;
}
这是TTC初始化的核心函数,完成了以下关键操作:
-
查找和初始化TTC配置:通过设备ID查找TTC配置并初始化设备实例。
-
连接中断:将TTC中断连接到中断控制器,并指定中断处理函数。
-
配置定时器模式:设置为用户定义计数模式,禁用PWM功能。
-
设置计数值:计算并设置2秒定时所需的计数值。
-
启用定时器:最后启用定时器开始计数。
中断处理函数
void timer1_handler(FTtcPs_T *DevPtr)
{
// 控制LED状态
led_run();
// 清除定时器中断
FTtcPs_ClearTimerNInterrupt(DevPtr, 1);
// 禁用定时器
FTtcPs_setTimerEnble(DevPtr, timer1, FMSH_clear);
// 设置标志,通知主循环
g_ttc0_flag = 1;
}
中断处理函数完成了以下任务:
-
调用
led_run()
函数切换LED状态 -
清除定时器中断标志
-
禁用定时器(防止重复进入中断)
-
设置标志位,通知主循环可以重新启用定时器
LED控制函数
void led_run()
{
if(g_led_flag) {
FGpioPs_writeData(&GpioOutput, 0x0); //按位改变灯的状态
g_led_flag = 0;
} else {
FGpioPs_writeData(&GpioOutput, 0x80);
g_led_flag = 1;
}
}
这个函数简单地切换LED的状态,通过写GPIO数据寄存器实现。
TTC工作原理解析
工作模式
TTC支持多种工作模式,本例中使用的是user_DefinedCount_mode
(用户定义计数模式)。在这种模式下:
-
定时器从加载的计数值开始递减计数
-
当计数到0时,产生中断
-
定时器可以配置为自动重载或单次模式
中断处理流程
-
定时器计数到0,触发中断
-
CPU跳转到中断处理函数
-
在处理函数中执行相关操作(如切换LED)
-
清除中断标志,防止重复进入中断
-
禁用定时器(本例中),等待主循环重新启用
应用场景
TTC定时器在嵌入式系统中有广泛的应用:
-
周期性任务调度:如操作系统的时钟节拍
-
外设时序控制:如通信接口的超时检测
-
PWM生成:控制电机、LED亮度等
-
时间测量:测量事件持续时间
注意事项
在使用TTC时,需要注意以下几点:
-
中断优先级:合理设置中断优先级,避免高优先级中断阻塞TTC中断
-
计数值计算:准确计算计数值,考虑时钟分频和系统时钟频率
-
中断清除:必须在中断处理函数中清除中断标志,否则会重复进入中断
-
资源冲突:避免多个任务或中断同时访问同一个TTC实例
-
低功耗考虑:在低功耗应用中,合理配置TTC以平衡性能和功耗