ARM架构——时钟系统与定时器详解

目录

一、时钟系统基础

[1.1 基本概念](#1.1 基本概念)

[1.2 时钟系统核心组件](#1.2 时钟系统核心组件)

[1.2.1 时钟源](#1.2.1 时钟源)

[1.2.2 时钟树关键组件](#1.2.2 时钟树关键组件)

二、时钟系统代码实现

[2.1 关键时钟计算](#2.1 关键时钟计算)

[2.2 时钟初始化](#2.2 时钟初始化)

三、定时器模块详解

[3.1 EPIT 定时器](#3.1 EPIT 定时器)

[3.2 GPT定时器](#3.2 GPT定时器)

四、总结


一、时钟系统基础

1.1 基本概念

  • **时钟(clock):**在电子系统中是一个产生稳定、周期性振荡信号的电路或组件。这个信号像节拍器或心跳一样,为数字电路中的各种操作提供同步时序基准。
  • **定时器(EPIT GPT):**是一个通过对已知频率的时钟信号进行计数,来实现定时、延时或事件计数功能的硬件模块或软件机制。
  • **实时时钟(RTC, real time clock):**是微处理器中的一个功能模块,用于在系统主电源关闭的情况下,继续提供精确的日历和时间信息。

1.2 时钟系统核心组件

1.2.1 时钟源

时钟源是整个时钟系统的起点,提供稳定的原始时钟信号。

  • 晶体振荡器:将石英晶体切割成音叉,施加电压产生稳定震荡
  • 通常使用 8MHz 或 24MHz 的晶振作为基础时钟源

1.2.2 时钟树关键组件

ARM架构的时钟系统由多个关键组件构成,形成一个复杂的时钟树:
IMX6ULL时钟树

组件 作用 代码示例
PLL(锁相环) 倍频,将低频时钟提升到更高频率 CCM_ANALOG->PLL_ARM
Prescale(分频器) 分频,将高频时钟降低到所需频率 CCM->CACRR
PFD(相位分数分频器) 输出频率可升可降,提供更灵活的频率选择 CCM_ANALOG->PFD_528
MUX(多路选择器) 选择不同的时钟源 CCM->CBCMRCCM->CSCMR1
CG门(Clock Gating 控制时钟门控,节省功耗 CCM->CCGR0-CCM->CCGR6

二、时钟系统代码实现

2.1 关键时钟计算

IMX6ULL时钟树

  • ARM 内核时钟 :通过PLL倍频提升到高频率。
    • PLL1 倍频系数 88(24MHz×88=2112MHz)→ 二分频 → 1056MHz(可通过 CACRR 寄存器调整分频系数);
  • AHB 总线时钟 :系统总线时钟,用于处理器和外设。
    • PLL2 输出 528MHz → 4 分频 → 132MHz(CBCDR 寄存器的 AHB_PODF 配置);
  • IPG 总线时钟 :外设接口时钟,用于GPIO、UART等外设。
    • AHB 时钟 132MHz → 2 分频 → 66MHz(CBCDR 寄存器的 IPG_PODF 配置);
  • PERCLK时钟 :外设时钟,用于定时器、ADC等。
    • AHB 时钟 132MHz → 2 分频 → 66MHz(CSCMR1 寄存器的 PERCLK_PODF 配置)。

2.2 时钟初始化

cpp 复制代码
void clock_init(void)
{
  // ARM内核时钟切换(避免配置PLL时内核故障)
  CCM->CCSR &= ~(1 << 8);  // 选择osc_clk作为step_clk(24MHz)
  CCM->CCSR |= (1 << 2);   // 让ARM暂时工作在step_clk(24MHz)
  
  // 配置ARM内核分频器(CACRR)
  CCM->CACRR &= ~(7 << 0);
  CCM->CACRR |= (1 << 0);  // 二分频(后续PLL1输出1056MHz,分频后528MHz)
  
  // 配置PLL1(ARM PLL)为1056MHz
  unsigned int t = CCM_ANALOG->PLL_ARM;
  t &= ~(3 << 4);          // 清除原有倍频系数
  t |= (1 << 13);          // 使能PLL
  t &= ~(0x7F << 0);
  t |= (88 << 0);          // 倍频系数88(24×88=2112MHz,二分频后1056MHz)
  CCM_ANALOG->PLL_ARM = t;
  CCM->CCSR &= ~(1 << 2);  // 切换回PLL1输出(pll1_main_clk)
  
  // 配置PLL2(528MHz)的PFD分频器
  t = CCM_ANALOG->PFD_528;
  t &= ~((0x3F << 0) | (0x3F << 8) | (0x3F << 16) | (0x3F << 24));
  // PFD0=27→352M,PFD1=16→594M,PFD2=24→396M,PFD3=32→297M
  t |= ((27 << 0) | (16 << 8) | (24 << 16) | (32 << 24));
  CCM_ANALOG->PFD_528 = t;
  
  // 配置PLL3(480MHz)的PFD分频器
  t = CCM_ANALOG->PFD_480;
  t &= ~((0x3F << 0) | (0x3F << 8) | (0x3F << 16) | (0x3F << 24));
  t |= ((27 << 0) | (16 << 8) | (24 << 16) | (32 << 24));
  CCM_ANALOG->PFD_480 = t;
  
  // 配置AHB_CLK_ROOT(132M)
  t = CCM->CBCMR;
  t &= ~(3 << 18);
  t |= (1 << 18);          // 选择PLL2_PFD2(396M)作为输入
  CCM->CBCMR = t;
  t = CCM->CBCDR;
  t &= ~(1 << 25);
  t &= ~(7 << 10);
  t |= (2 << 10);          // AHB分频系数3(396M/3=132M)
  CCM->CBCDR = t;
  
  // 配置IPG_CLK_ROOT(66M)
  t &= ~(3 << 8);
  t |= (1 << 8);           // IPG分频系数2(132M/2=66M)
  CCM->CBCDR = t;
  
  // 配置PERCLK_CLK_ROOT(66M)
  t = CCM->CSCMR1;
  t &= ~(1 << 6);          // 选择IPG_CLK_ROOT作为输入
  t &= ~(0x3F << 0);       // 不分频
  CCM->CSCMR1 = t;
  
  // 使能所有外设时钟门控(CG)
  clock_cg_init();
}

时钟配置关键注意事项:

  • 时钟切换顺序:配置 PLL1 时,必须先将 ARM 内核切换到 24MHz 的 step_clk,避免倍频过程中内核因时钟突变而故障;
  • 分频系数匹配:外设时钟必须与器件手册要求一致(如 USB 需 480MHz,以太网需特定频率),否则会导致外设工作异常;
  • 时钟门控使能:clock_cg_init() 函数将所有 CCGR 寄存器置为 0xFFFFFFFF,即开启所有外设时钟,实际项目中可按需关闭未使用外设的时钟以降低功耗。

三、定时器模块详解

3.1 EPIT 定时器

Enhanced Periodic Interrupt Timer ------ 增强型周期中断定时器

**应用场景:**周期性任务,如 1 秒翻转一次 LED。

工作原理:

  • 定时器根据配置的时钟源进行计数。
  • 当计数达到 LR (Load Register) 设定的值时,产生中断,并将计数器自动重置为 LR 值。

实验: 1秒中断翻转 LED

使用 PERCLK_CLK_ROOT (66MHz) 作为时钟源。

  • 目标频率:1Hz(即每1秒一次)。
  • 1秒中断的计算:1000 * 1000 = 1MHz(1MHz时钟,100万计数=1秒)
  • 代码实现:
cpp 复制代码
void epit1_init(void)
{
    unsigned int t;
    t = EPIT1->CR;
    t &= ~(3 << 24);    // 清除时钟源选择
    t |= (1 << 24);     // 选择PERCLK_CLK_ROOT(66M)作为时钟源
    t |= (1 << 17);     // 覆盖计数器值
    t &= ~(0xFFF << 4); // 清除预分频值
    t |= (65 << 4);     // 分频系数66(66M/66=1MHz)
    t |= (1 << 3);      // 计数器达到零时,从模数寄存器重新加载(置位-遗忘模式)
    t |= (1 << 2);      // 启用中断
    t |= (1 << 1);      // 从加载值开始计数
    EPIT1->CR = t;
    
    EPIT1->LR = 1000 * 1000;  // 载入值 = 1MHz时钟,1秒
    EPIT1->CMPR = 0;          // 比较寄存器
    EPIT1->CNR = 1000 * 1000; // 当前计数值
    
    // 中断配置
    GIC_EnableIRQ(EPIT1_IRQn);
    GIC_SetPriority(EPIT1_IRQn, 0);
    system_interrupt_register(EPIT1_IRQn, epit_irq_handler);
    
    EPIT1->CR |= (1 << 0); // 使能定时器
}

// 中断服务函数:1s翻转LED和蜂鸣器
void epit_irq_handler(void)
{
  if ((EPIT1->SR & (1 << 0)) != 0)
  {
    led_nor();
    beep_nor();
    EPIT1->SR |= (1 << 0); // 清除中断标志
  }
}

3.2 GPT定时器

General Purpose Timer ------ 通用目的定时器

**应用场景:**高精度延时函数。

**工作原理:**GPT 支持自由运行模式、输入捕获和比较输出。我们利用其自由运行模式读取当前计数值来实现软件延时。

实验: 精准延时

通过读取 GPT1->CNT 寄存器,对比当前值与上一次的值,累加时间差,直到达到所需的微秒数。

  • 代码实现:
cpp 复制代码
void gpt1_init(void)
{
    // 复位定时器
    reset_fun();
    
    unsigned int t;
    t = GPT1->CR;
    t &= ~(7 << 26);  // 输出断开
    t &= ~(3 << 18);  // 捕获已禁用
    t |= (1 << 9);    // 自由运行模式
    t &= ~(7 << 6);   // 清除时钟源选择
    t |= (1 << 6);    // 选择PERCLK_CLK_ROOT(66M)作为时钟源
    t &= ~(1 << 1);   // 失能定时器后保留原来的值
    GPT1->CR = t;
    
    GPT1->PR &= ~(0xFFF << 0); // 清除预分频值
    GPT1->PR |= (65 << 0);     // 分频系数66(66M/66=1MHz)
    GPT1->CNT = 0;             // 清零计数器
    GPT1->CR |= (1 << 0);      // 使能定时器
}

// 微秒级延时函数
void delay_us(unsigned int us)  
{  
    unsigned int count = 0;  
    unsigned int old_count = 0, new_count = 0;  
    
    old_count = GPT1->CNT; // 记录起始时刻  
    while (1)  
    {  
        new_count = GPT1->CNT;  
      
        // 计算溢出情况(例如从0xFFFFFFFF变到0)  
        if (new_count != old_count)  
        {  
            if (new_count > old_count)  
            {  
                count += new_count - old_count;  
            }  
            else  
            {  
                count += 0xFFFFFFFF - old_count + new_count;  
            }  
        }  
      
        if (count >= us)  
        {  
            return;  
        }  
        old_count = new_count;  
    }  
}  

四、总结

ARM架构的时钟系统和定时器模块是嵌入式系统设计的核心组件。理解时钟树的结构和工作原理,对于实现精确的定时控制、优化系统功耗和性能至关重要。

  • 时钟系统:通过PLL、分频器和多路选择器构建复杂的时钟树,为系统提供精确的时序基准
  • 定时器:EPIT提供精确的周期中断,GPT提供灵活的延时功能,两者在嵌入式系统中广泛应用
  • 配置实践:通过寄存器配置,实现时钟频率的精确控制和定时器的精准工作
相关推荐
optimistic_chen5 小时前
【Docker入门】Docker Registry(镜像仓库)
linux·运维·服务器·docker·容器·镜像仓库·空间隔离
宵时待雨5 小时前
STM32笔记归纳3:串口
笔记·stm32·嵌入式硬件
JiMoKuangXiangQu5 小时前
Linux perf 子系统一览
linux·perf
国科安芯5 小时前
抗辐照MCU在核电站交换机中的可靠性验证方法研究
单片机·嵌入式硬件·架构·安全性测试
松涛和鸣5 小时前
60、嵌入式定时器深度解析:EPIT与GPT
c语言·arm开发·单片机·嵌入式硬件·gpt·fpga开发
中国lanwp5 小时前
RedHat/CentOS 系统中根目录作用说明
linux·运维·centos
屹立芯创ELEADTECH6 小时前
CoWoS封装技术全面解析:架构、演进与AI时代的基石作用
人工智能·架构
Coder_Boy_6 小时前
基于SpringAI的在线考试系统-知识点管理与试题管理模块联合回归测试文档
前端·人工智能·spring boot·架构·领域驱动
乐亦_Lee6 小时前
在Ubuntu下如何提升下载速度
linux·嵌入式硬件·ubuntu