时钟系统与定时器
一、基本概念定义
1. 核心术语解析
-
定时器 (Timer):通过对已知频率的时钟信号进行计数,实现时间测量、延时控制或事件计数功能的硬件模块或软件机制。
-
时钟 (Clock):在电子系统中产生稳定周期性振荡信号的电路或组件,为数字电路提供同步时序基准。
-
实时时钟 (RTC):独立供电的时间保持模块,在主系统电源关闭时继续提供精确的日历和时间信息。
2. 频率单位说明
-
频率计算:1 MHz = 1,000 × 1,000 = 1,000,000 Hz
-
存储计算:1 MByte = 1,024 × 1,024 = 1,048,576 Byte
二、时钟硬件架构
1. 时钟源:晶体振荡器
工作原理:
石英晶体 → 切割成音叉形状 → 施加电压 → 压电效应 → 稳定机械振荡 → 电信号输出
频率特性:24 MHz(i.MX6ULL基准频率)
稳定性:±10 ppm(百万分之十)
2. 锁相环电路 (PLL)
功能:频率合成与倍频
输入频率 F_in → 鉴相器 → 环路滤波器 → 压控振荡器 → 输出频率 F_out
数学模型:F_out = F_in × (N/D)
其中:N为倍频因子,D为分频因子
3. 预分频器 (Prescaler)
功能:整数分频
F_out = F_in / M
M为整数分频系数(1-64)
4. 相位分数分频器 (PFD)
功能:分数分频,实现非整数分频比
F_out = F_in × (N/M)
可精确控制输出相位
三、i.MX6ULL时钟系统架构
1. PLL配置总览
外部晶振 (24MHz)
↓
├── PLL1 (ARM PLL) - Cortex-A7内核时钟,可配置至1056MHz
├── PLL2 (528 PLL) - 系统PLL,固定528MHz
├── PLL3 (480 PLL) - USB1 PLL,固定480MHz
├── PLL4 (Audio PLL) - 音频设备
├── PLL5 (Video PLL) - 视频设备
├── PLL6 (Ethernet PLL)- 以太网设备
└── PLL7 (USB2 PLL) - USB2设备
2. PFD配置
每个主PLL包含4个PFD通道:
PLL2 (528MHz) PFD通道:
PFD0: 352MHz
PFD1: 594MHz
PFD2: 396MHz
PFD3: 297MHz
PLL3 (480MHz) PFD通道:
PFD0: 720MHz
PFD1: 540MHz
PFD2: 508.2MHz
PFD3: 454.7MHz
3. 时钟树关键节点
ARM内核时钟路径:
24MHz晶振 → PLL1倍频 → 二分频 → Cortex-A7内核 (1056MHz)
系统总线时钟:
24MHz → PLL2 (528MHz) → 各PFD通道 → 多路选择器 → 分频器 → 外设时钟
四、时钟配置代码实现
1. ARM PLL配置流程
void configure_arm_pll(void)
{
/* 步骤1:切换到安全时钟源 */
// CBCMR[18:19] PRE_PERIPH_CLK_SEL = 00 (osc_clk)
CCM->CBCMR &= ~(3 << 18);
// CBCDR[25] PERIPH_CLK_SEL = 0 (选择step_clk)
CCM->CBCDR &= ~(1 << 25);
/* 步骤2:旁路PLL,使用24MHz直接工作 */
// CBCDR[25] PERIPH_CLK_SEL = 1 (选择pll1_sw_clk)
CCM->CBCDR |= (1 << 25);
/* 步骤3:配置PLL1参数(关键安全步骤)*/
// 先设置输出分频,避免过高频率
CCM_ANALOG->PLL_ARM |= (1 << 19); // 使能二分频
// 配置倍频因子:N=88
CCM_ANALOG->PLL_ARM &= ~0x7F; // 清除DIV_SELECT
CCM_ANALOG->PLL_ARM |= (88 << 0); // DIV_SELECT=88
// 计算:24MHz × 88 = 2112MHz,二分频后=1056MHz
/* 步骤4:等待PLL锁定 */
while(!(CCM_ANALOG->PLL_ARM & (1 << 31))); // 检查LOCK位
/* 步骤5:切换回PLL输出 */
CCM->CBCDR &= ~(1 << 25); // PERIPH_CLK_SEL=0
}
2. 系统时钟配置
// AHB_CLK_ROOT配置为132MHz
void configure_ahb_clk(void)
{
// 选择时钟源:PLL2 PFD2 (396MHz)
CCM->CBCMR |= (1 << 18); // PRE_PERIPH_CLK_SEL=01
CCM->CBCDR &= ~(1 << 25); // PERIPH_CLK_SEL=0
// 设置AHB分频:396MHz ÷ 3 = 132MHz
CCM->CBCDR &= ~(7 << 10); // 清除AHB_PODF
CCM->CBCDR |= (2 << 10); // AHB_PODF=010 (3分频)
}
// IPG_CLK_ROOT配置为66MHz
void configure_ipg_clk(void)
{
// AHB时钟 ÷ 2 = 66MHz
CCM->CBCDR &= ~(3 << 8); // 清除IPG_PODF
CCM->CBCDR |= (1 << 8); // IPG_PODF=01 (2分频)
}
// PERCLK_CLK_ROOT配置为66MHz
void configure_perclk(void)
{
// 选择IPG时钟作为源
CCM->CSCMR1 &= ~(1 << 6); // PERCLK_CLK_SEL=0
// 设置分频系数
CCM->CSCMR1 &= ~(0x3F << 0); // 清除PERCLK_PODF
CCM->CSCMR1 |= (0 << 0); // PERCLK_PODF=0 (1分频)
}
五、定时器工作原理
1. 51单片机定时器
基本结构:
-
Timer0/Timer1:16位定时器/计数器
-
工作模式:
-
模式0:13位定时器
-
模式1:16位定时器
-
模式2:8位自动重装
-
模式3:双8位定时器
-
配置示例:
// Timer0 16位定时器配置
void timer0_init(void)
{
TMOD &= 0xF0; // 清除Timer0配置位
TMOD |= 0x01; // 模式1:16位定时器
// 计算初值(12MHz晶振,1ms定时)
// 机器周期 = 1μs,计数1000次=1ms
TH0 = (65536 - 1000) / 256;
TL0 = (65536 - 1000) % 256;
ET0 = 1; // 使能Timer0中断
TR0 = 1; // 启动Timer0
}
// 中断服务程序
void timer0_isr() interrupt 1
{
TH0 = (65536 - 1000) / 256; // 手动重装初值
TL0 = (65536 - 1000) % 256;
// 用户处理代码
}
2. i.MX6ULL EPIT定时器
特性:
-
32位递减计数器
-
自动重载功能
-
精确周期性中断
1秒LED闪烁实验:
// EPIT1初始化
void epit1_init(void)
{
// 1. 禁用EPIT1
EPIT1->CR = 0;
// 2. 配置控制寄存器
EPIT1->CR = (1 << 24) | // ENMOD:计数器初始加载值
(1 << 3) | // OCIEN:使能比较中断
(1 << 2) | // RLD:使能重载模式
(0 << 1) | // OM:输出模式(比较输出)
(0 << 0); // EN:暂不使能
// 3. 设置预分频(66MHz ÷ 66 = 1MHz)
EPIT1->CR |= (65 << 4); // PRESCALAR = 65
// 4. 设置加载值(1MHz时钟,1秒计数)
EPIT1->LR = 1000000; // 加载寄存器
// 5. 设置比较值
EPIT1->CMPR = 0; // 比较寄存器
// 6. 清除中断标志
EPIT1->SR |= (1 << 0);
// 7. 使能中断
enable_irq(EPIT1_IRQn);
// 8. 启动定时器
EPIT1->CR |= (1 << 0);
}
// EPIT1中断服务函数
void epit1_irq_handler(void)
{
if (EPIT1->SR & (1 << 0)) {
EPIT1->SR |= (1 << 0); // 清除中断标志
gpio_toggle(LED_GPIO); // 翻转LED
}
}
3. GPT定时器
特性:
-
32位递增计数器
-
输入捕获功能
-
比较输出功能
-
多种工作模式
精准延时函数实现:
// GPT1微秒级延时
void gpt_delay_us(uint32_t us)
{
// 1. 复位GPT1
GPT1->CR = (1 << 15); // SWR:软件复位
// 2. 配置GPT1
GPT1->CR = (0 << 9) | // CLKSRC:ipg_clk (66MHz)
(1 << 6) | // ENMOD:使能模式
(0 << 1) | // FRR:自由运行模式
(0 << 0); // EN:暂不使能
// 3. 设置预分频(66MHz ÷ 66 = 1MHz)
GPT1->PR = 65; // 分频寄存器
// 4. 启动GPT1
GPT1->CR |= (1 << 0);
// 5. 获取起始计数值
uint32_t start_time = GPT1->CNT;
// 6. 等待指定时间
uint32_t target_cnt = us; // 1MHz时钟,1计数=1μs
while ((GPT1->CNT - start_time) < target_cnt) {
// 处理计数器溢出
if (GPT1->CNT < start_time) {
target_cnt -= (0xFFFFFFFF - start_time + GPT1->CNT + 1);
start_time = GPT1->CNT;
}
}
// 7. 停止GPT1
GPT1->CR &= ~(1 << 0);
}
// GPT1毫秒级延时
void gpt_delay_ms(uint32_t ms)
{
for (uint32_t i = 0; i < ms; i++) {
gpt_delay_us(1000);
}
}
六、重点问题详解
问题1:PLL、Prescaler、PFD的作用
| 模块 | 功能 | 数学关系 | 应用场景 |
|---|---|---|---|
| PLL | 频率合成与倍频 | F_out = F_in × N/D | 产生高频系统时钟 |
| Prescaler | 整数分频 | F_out = F_in / M | 降低时钟频率 |
| PFD | 分数分频 | F_out = F_in × N/M | 精确频率控制 |
问题2:i.MX6ULL PLL和PFD数量
-
PLL总数:7个
-
PLL1:ARM PLL(1056MHz)
-
PLL2:System PLL(528MHz)
-
PLL3:USB1 PLL(480MHz)
-
PLL4:Audio PLL
-
PLL5:Video PLL
-
PLL6:Ethernet PLL
-
PLL7:USB2 PLL
-
-
PFD总数:28个(每个PLL有4个PFD通道)
问题3:ARM PLL配置流程
-
时钟源切换:选择24MHz OSC作为临时时钟源
-
PLL旁路:绕过PLL,直接使用低频时钟
-
参数配置:
-
设置输出分频(安全措施)
-
配置倍频因子(N=88)
-
等待PLL锁定
-
-
时钟切换:切回PLL输出时钟
-
频率验证:确认时钟稳定工作
问题4:EPIT与GPT工作原理对比
| 特性 | EPIT | GPT |
|---|---|---|
| 计数方向 | 递减计数 | 递增计数 |
| 重载方式 | 自动重载 | 多种模式 |
| 主要用途 | 周期性中断 | 通用定时 |
| 输出模式 | 比较输出 | 捕获/比较 |
| 时钟源 | ipg_clk/ipg_clk_highfreq | 多种选择 |
问题5:时钟树中各模块作用
| 模块 | 功能描述 | 在时钟树中的位置 |
|---|---|---|
| 锁相环PLL | 频率提升,将低频时钟倍频到工作频率 | 时钟树前端 |
| 预分频器 | 整数分频,降低时钟频率 | 各级时钟通路 |
| 相位分数分频器 | 精确分数分频,实现任意频率比 | PLL输出后 |
| 多路选择器 | 时钟源选择,动态切换时钟 | 各时钟节点 |
| CG门 | 时钟门控,低功耗控制 | 各外设时钟入口 |
七、实践注意事项
1. 时钟配置安全规范
// 错误示例:直接修改PLL倍频因子
CCM_ANALOG->PLL_ARM |= (88 << 0); // 危险!可能造成系统崩溃
// 正确示例:安全的PLL配置流程
// 1. 切换到低频时钟源
// 2. 设置输出分频
// 3. 配置倍频因子
// 4. 等待锁定
// 5. 切换回高频时钟
2. 定时器精度考虑因素
-
时钟源精度:晶体振荡器的稳定度
-
分频误差:整数分频的量化误差
-
中断延迟:中断响应时间
-
软件开销:中断服务程序执行时间
3. 调试技巧
// 时钟频率测量方法
void measure_clock_frequency(void)
{
uint32_t start, end;
// 使用GPT测量1秒内计数
GPT1->CR = 0;
GPT1->CR = (1 << 6) | (1 << 0); // ENMOD + EN
GPT1->PR = 0; // 不分频
start = GPT1->CNT;
gpt_delay_ms(1000); // 延时1秒
end = GPT1->CNT;
printf("频率:%lu Hz\n", end - start);
}
八、总结
时钟系统和定时器是嵌入式系统的核心基础组件,理解其工作原理和配置方法对于系统稳定性、性能和功耗控制至关重要。i.MX6ULL提供了灵活的时钟架构和多种定时器,能够满足不同应用场景的需求。配置时钟时应遵循安全规范,定时器使用时要考虑精度和实时性要求。