[ARM]修改clock freq on imx8m

本文探讨了在嵌入式系统中如何通过U-Boot和内核修改时钟频率,重点介绍了在内核中通过DTS和代码两种方式进行时钟配置的方法。详细解析了DTS配置时钟的原理,包括时钟提供者和使用者的概念,以及如何通过时钟说明符连接两者。同时,也提到了代码方式修改时钟的具体操作。

关于修改clock freq, 在uboot和kernel中都是可以修改的,但是当在uboot中修改后,由于kernel也有修改clock freq的能力,这时就要注意kernel可能会覆盖uboot中已经设置好的频率。

所以最好的办法还是在kernel中进行clock的配置。
而在kernel中配置时钟的方法据我现在所知又有两种,一种是在DTS里设置,另一种则是用代码设置,了解到这些以后会发现修改时钟频率其实是一种比较简单的事情,前提是分清楚这些方法,避免重复设置。


1,DTS方式

这种方式我在这里就直接放上官方文档和其翻译,具体位置在
Documentation/devicetree/bindings/clock/clock-bindings.txt


该绑定是一个进行中的工作,它基于benh [1]的一些实验工作。

时钟信号源可以由设备树中的任何节点表示。 这些节点被指定为时钟提供者。 时钟使用者节点使用虚拟机和时钟说明符对连接时钟提供者输出到时钟输入。 与gpio说明符相似,时钟说明符是一个零数组,一个或多个单元标识一个设备上的时钟输出。 时钟说明符的长度由时钟提供程序节点中的#clock-cells属性的值定义。
在这里插入图片描述
译:
== 时钟提供者 ==

必需的属性:
#clock-cells:时钟说明符中的单元数;通常,对于具有单个时钟输出的节点为0,对于具有多个时钟输出的节点通常为1。

可选属性:
#clock-output-names:建议是由时钟说明符中从第一个节点开始索引的时钟输出信号名称的字符串列表。
但是,clock-output-names的含义是特定于时钟提供者的域,并且仅用于鼓励大多数时钟提供者使用相同的含义。此格式可能不适用于使用复杂时钟说明符格式的时钟提供程序。在这种情况下,建议忽略此属性并创建绑定特定名称的属性。

时钟使用者节点绝对不能直接引用提供者的clock-output-names属性。

例如:

     oscillator{
         #clock-cells = <1>;
         clock-output-names =“ ckil”,“ ckih”;
     };

-该节点定义了一个具有两个时钟输出的设备,第一个名为“ ckil”,第二个名为“ ckih”。 消费者节点始终按索引引用时钟。 名称应反映设备的时钟输出信号名称。

clock-indices:如果节点中时钟的标识号不是从零线性开始的,则这允许将标识符映射到clock-output-names数组中。

例如,如果我们有两个时钟<&oscillator 1>和<&oscillator 3>:

oscillator {
compatible = “myclocktype”;
#clock-cells = <1>;
clock-indices = <1>, <3>;
clock-output-names = “clka”, “clkb”;
}

这样可以确保我们在clock-output-names中没有任何空字符串
在这里插入图片描述
在这里插入图片描述
译:
== 时钟使用者 ==

必需的属性:
clocks:一对phandle和时钟说明符对(即&clk),每个输入到设备的时钟一对。 注意:如果时钟提供者将#clock-cells指定为“ 0”,则仅会出现该对中的phandle部分。

可选属性:
clock-names:以与clocks属性相同的顺序排序的时钟输入名称字符串的列表。 使用者驱动程序将使用时钟名称来将时钟输入名称与时钟说明符进行匹配。
clock-ranges:空属性表示子节点可以从该节点继承命名的时钟。 对于总线节点向其子节点提供时钟非常有用。

例如:

device {
    clocks = <&osc 1>, <&ref 0>;
    clock-names = "baud", "register";
};

这表示具有两个时钟输入的设备,分别称为"baud"和"register"。
波特时钟连接到&osc1时钟,寄存器时钟连接到&ref0时钟。

例如:

    /* external oscillator */
    osc: oscillator {
        compatible = "fixed-clock";
        #clock-cells = <1>;
        clock-frequency  = <32678>;
        clock-output-names = "osc";
    };

    /* phase-locked-loop device, generates a higher frequency clock
     * from the external oscillator reference */
    pll: pll@4c000 {
        compatible = "vendor,some-pll-interface"
        #clock-cells = <1>;
        clocks = <&osc 0>;
        clock-names = "ref";
        reg = <0x4c000 0x1000>;
        clock-output-names = "pll", "pll-switched";
    };

    /* UART, using the low frequency oscillator for the baud clock,
     * and the high frequency switched PLL output for register
     * clocking */
    uart@a000 {
        compatible = "fsl,imx-uart";
        reg = <0xa000 0x1000>;
        interrupts = <33>;
        clocks = <&osc 0>, <&pll 1>;
        clock-names = "baud", "register";
    };

该DT片段定义了三个设备:一个提供低频参考时钟的外部振荡器,一个产生更高频率时钟信号的PLL设备以及一个UART。

**振荡器为固定频率,并提供一个时钟输出,称为“ osc”。
**PLL既是时钟提供者又是时钟消耗者。 它使用外部振荡器产生的时钟信号,并提供两个输出信号(“ pll”和“ pll-switched”)。
**UART的波特率时钟连接到外部振荡器,寄存器时钟连接到PLL时钟(“ PLL切换”信号)
在这里插入图片描述
译:
== 分配的父时钟和速率 ==
某些平台可能需要初始配置默认的父时钟和时钟频率。 可以在设备树节点中通过已分配的时钟,已分配的时钟父对象和已分配的时钟速率属性指定这种配置。 Assigned-clock-parents属性应包含一对以phandle和clock标识符对形式的父时钟,而assigned-clock-rates属性应包含以Hz为单位的频率列表。 这两个属性都应对应于assigned-clocks属性中列出的时钟。

要跳过设置时钟的父级或时钟速率,应将其相应的条目设置为0,如果后面没有任何非零条目,则可以将其省略。

    uart@a000 {
        compatible = "fsl,imx-uart";
        reg = <0xa000 0x1000>;
        ...
        clocks = <&osc 0>, <&pll 1>;
        clock-names = "baud", "register";

        assigned-clocks = <&clkcon 0>, <&pll 2>;
        assigned-clock-parents = <&pll 2>;
        assigned-clock-rates = <0>, <460800>;
    };

在此示例中,<&pll 2>时钟被设置为时钟<&clkcon 0>的父级,并且<&pll 2>时钟被分配了460800 Hz的频率值。

通过使用该时钟的设备节点配置时钟的父级和速率只能对具有单个用户的时钟进行。 禁止在多个使用方节点中为共享时钟指定冲突的父级或速率配置。

可以在时钟提供程序节点中类似地指定影响多个用户设备的公共时钟配置。

2,在clock驱动中代码修改

在代码中就比较简单如下:

imx_clk_set_parent(clk[IMX6QDL_CLK_VPU_AXI_SEL], clk[IMX6QDL_CLK_PLL2_PFD2_396M]);
imx_clk_set_rate(clk[IMX6QDL_CLK_VPU_AXI_PODF], 396000000);

但是这种方法不太灵活,相比较而言还是推荐修改DTS的方法。


既然你已经看到这里了,再说几个我的发现:
1, PLL是在uboot里设好的,也就是说在kernel boot之前这些pll源要准备好。
2, 可变频率的pll其实在uboot中已经固定了,也就是说,可变只是kernel启动之前可变
3, source clock的频率虽说可以是待设频率的整数倍,但是也要注意,source clock不是随便设的,要和clock parent table 对应起来。

<think>嗯,用户问的是“xpar_cpu_core_clock_freq_hz”,我需要先弄清楚这个术语的来源和含义。首先,这个变量名看起来像是某种代码中的变量,可能是在嵌入式系统或硬件相关的项目中使用的。名字中的“xpar”可能是一个前缀,常见于Xilinx的平台或工具中,比如Xilinx Platform Studio(XPS)或Vivado设计工具。 接下来,“cpu_core_clock_freq_hz”显然指的是CPU核心时钟频率,以赫兹(Hz)为单位。所以,这个变量可能用于存储或配置CPU的时钟频率。在Xilinx的嵌入式系统中,比如使用Zynq芯片或MicroBlaze处理器时,时钟配置是非常关键的,通常会在硬件配置文件中定义,然后通过头文件或参数传递给软件部分。 用户可能是在开发FPGA项目,或者在使用Xilinx的工具链时遇到了这个变量,需要了解它的具体作用。也有可能他们在查看代码或文档时遇到了这个变量,想要确认它的用途和如何正确使用。此外,用户可能没有明确说明上下文,需要我假设常见的使用场景,比如嵌入式系统设计或硬件描述中的配置参数。 另外,我需要考虑用户的技术背景。如果他们使用的是Xilinx工具,可能已经有一定的硬件设计经验,但可能对具体的参数命名规则不太熟悉。因此,解释时应该结合常见的Xilinx设计流程,说明这个变量通常在哪个环节出现,如何影响系统设计,以及可能的取值范围和配置方法。 还有可能用户遇到了编译错误或配置问题,比如这个变量的值没有被正确设置,导致他们的项目无法正常运行。这时候需要解释如何检查和设置这个变量的值,可能需要指导他们查找相关的配置文件或使用工具界面进行调整。 总结下来,用户的需求可能是理解这个变量的含义、它在项目中的作用、如何正确配置它,以及相关的注意事项。需要给出清晰的解释,并可能提供配置示例或常见问题的解决方法,帮助他们顺利应用这个参数到自己的项目中。</think>### 逐步理解 `xpar_cpu_core_clock_freq_hz` 的含义与用途 #### 1. **术语拆解** - **`xpar`**:通常为 **Xilinx Platform Auto-generated Parameters** 的缩写,常见于 Xilinx(现 AMD)的 FPGA/SoC 开发工具(如 Vivado、Vitis、Xilinx SDK)中,表示由工具自动生成的硬件配置参数。 - **`cpu_core_clock_freq_hz`**:字面含义是 **CPU 核心的时钟频率(单位:赫兹)**,即 CPU 运行的主频。 #### 2. **上下文定位** - **应用场景**: 该变量常见于 **嵌入式系统开发**,尤其是使用 Xilinx Zynq SoC(如 Zynq-7000、Zynq UltraScale+)或 MicroBlaze 软核处理器的项目中。 - **生成来源**: 当开发者通过 Vivado 工具配置硬件系统(如设置 CPU 时钟源、分频器等参数)后,工具会**自动生成一组头文件(如 `xparameters.h`)**,其中包含类似 `XPAR_CPU_CORE_CLOCK_FREQ_HZ` 的宏定义,用于软件层访问硬件配置信息。 #### 3. **具体作用** - **硬件与软件的桥梁**: 该宏定义将硬件设计中配置的 CPU 时钟频率传递给软件(如 C/C++ 代码),确保软件能够基于实际硬件参数运行。 例如:初始化定时器、计算延时周期或优化算法时,需依赖准确的时钟频率值。 - **典型取值**: 根据硬件设计不同,可能为 `666666687`(约 666.67 MHz)、`100000000`(100 MHz)等。 公式可表示为: $$ \text{CPU 主频} = \frac{\text{输入时钟频率}}{\text{分频系数}} $$ #### 4. **实际使用示例** ```c // 在代码中引用该参数 #include "xparameters.h" void init_timer() { // 获取 CPU 主频 uint64_t cpu_freq = XPAR_CPU_CORE_CLOCK_FREQ_HZ; // 计算 1 毫秒对应的时钟周期数 uint64_t ticks_per_ms = cpu_freq / 1000; // 配置定时器... } ``` #### 5. **调试与修改** - **查看当前值**: 在 Vivado 工程中,打开 `xparameters.h` 文件,搜索 `XPAR_CPU_CORE_CLOCK_FREQ_HZ` 即可找到定义。 - **修改时钟频率**: 需通过 Vivado Block Design 调整硬件设计中的时钟配置(如修改 PLL 分频参数),重新生成比特流和 SDK 工程,软件层宏定义会自动更新。 #### 6. **注意事项** - **一致性**:软件中若直接修改 `xparameters.h` 中的值,可能导致与硬件实际频率不匹配,引发逻辑错误。 - **依赖关系**:某些外设(如 UART、以太网)的驱动初始化可能依赖此参数,需确保其准确性。 ### 总结 `xpar_cpu_core_clock_freq_hz` 是 Xilinx 工具链生成的硬件参数宏,用于**在软件代码中获取 CPU 核心的实际运行频率**。理解此参数有助于实现软硬件协同开发,尤其在时序敏感型应用(如实时控制、高速通信)中至关重要。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

山猫Show

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值