CLK(1)——fixed-clock

本文详细介绍了Linux内核中固定时钟和固定分频因子时钟的概念,以及它们在设备节点如CAN节点中的配置。通过分析相关驱动函数,展示了如何初始化和使用这些时钟。同时,提供了相关驱动源代码,如`clk_osc24m`和`clk_pll_periph0x2`,展示了如何将pll时钟作为固定分频因子时钟的源。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

简析内核中固定时钟及相关时钟的定义和初始化:

参考链接:
https://blog.youkuaiyun.com/zgtzqzg2020/article/details/109220048
https://www.freesion.com/article/4436438726/

can节点中配置的24M的固定时钟:

clk_osc24m: osc24m {
	#clock-cells = <0>;
	compatible = "allwinner,fixed-clock";
	clock-frequency = <24000000>;
	clock-output-names = "osc24m";
};

can0: can@0 {
	compatible = "microchip,mcp2515";
	pinctrl-names = "default";
	clocks = <&clk_osc24m>;
	status = "okay";
};
相关文件:
linux-4.9/drivers/clk/sunxi/clk-sunxi.c
linux-4.9/drivers/clk/sunxi/clk-sun50iw9.c
linux-4.9/include/linux/clk-provider.h

pll-clock和fixed-factor-clock(固定分频因子时钟),可以看到clk_pll_periph0x2使用clk_pll_periph0作为其时钟源:

clk_pll_periph0: pll_periph0 {
                        #clock-cells = <0>;
                        compatible = "allwinner,pll-clock";
                        assigned-clocks = <&clk_pll_periph0>;
                        assigned-clock-rates = <600000000>;
                        lock-mode = "new";
                        clock-output-names = "pll_periph0";
                };

clk_pll_periph0x2: pll_periph0x2 {
                        #clock-cells = <0>;
                        compatible = "allwinner,fixed-factor-clock";
                        clocks = <&clk_pll_periph0>;
                        clock-mult = <2>;
                        clock-div = <1>;
                        clock-output-names = "pll_periph0x2";
                };
固定时钟驱动函数:
static void __init of_sunxi_fixed_clk_setup(struct device_node *node)
{
        struct clk *clk;
        const char *clk_name = node->name;
        u32 rate;

        if (of_property_read_u32(node, "clock-frequency", &rate))
                return;

        if (of_property_read_string(node, "clock-output-names", &clk_name)) {
                pr_err("%s:get clock-output-names failed in %s node\n",
                                                __func__, node->full_name);
                return;
        }

        clk = clk_register_fixed_rate(NULL, clk_name, NULL, CLK_IS_ROOT, rate);
        if (!IS_ERR(clk)) {
                clk_register_clkdev(clk, clk_name, NULL);
                of_clk_add_provider(node, of_clk_src_simple_get, clk);
        }
}

固定分频因子时钟驱动函数:
static void __init of_sunxi_fixed_factor_clk_setup(struct device_node *node)
{
        struct clk *clk;
        const char *clk_name = node->name;
        const char *parent_name;
        u32 div, mult;

        if (of_property_read_u32(node, "clock-div", &div)) {
                pr_err("%s Fixed factor clock <%s> must have a clock-div property\n",
                        __func__, node->name);
                return;
        }

        if (of_property_read_u32(node, "clock-mult", &mult)) {
                pr_err("%s Fixed factor clock <%s> must have a clokc-mult property\n",
                        __func__, node->name);
                return;
        }

        if (of_property_read_string(node, "clock-output-names", &clk_name)) {
                pr_err("%s:get clock-output-names failed in %s node\n",
                                                __func__, node->full_name);
                return;
        }
        parent_name = of_clk_get_parent_name(node, 0);

        clk = clk_register_fixed_factor(NULL, clk_name, parent_name, 0,
                                        mult, div);
        if (!IS_ERR(clk)) {
                clk_register_clkdev(clk, clk_name, NULL);
                of_clk_add_provider(node, of_clk_src_simple_get, clk);
        }
}

CLK_OF_DECLARE(sunxi_clocks_init, "allwinner,clk-init", of_sunxi_clocks_init);
CLK_OF_DECLARE(sunxi_fixed_clk, "allwinner,fixed-clock", of_sunxi_fixed_clk_setup);
CLK_OF_DECLARE(sunxi_pll_clk, "allwinner,pll-clock", of_sunxi_pll_clk_setup);
CLK_OF_DECLARE(sunxi_fixed_factor_clk, "allwinner,fixed-factor-clock", of_sunxi_fixed_factor_clk_setup);
CLK_OF_DECLARE(sunxi_cpu_clk, "allwinner,cpu-clock", of_sunxi_cpu_clk_setup);
CLK_OF_DECLARE(sunxi_periph_clk, "allwinner,periph-clock", of_sunxi_periph_clk_setup);
CLK_OF_DECLARE(periph_cpus_clk, "allwinner,periph-cpus-clock", of_sunxi_periph_cpus_clk_setup);
#define CLK_OF_DECLARE(name, compat, fn) OF_DECLARE_1(clk, name, compat, fn)

TBC

### 设计十进制减法计数器 #### 电路设计概述 74LS161 是一款同步四位二进制加法计数器,具有清零、置数等功能。为了实现十进制减法计数器,可以通过修改其工作模式并结合外部逻辑来达到目标。具体来说,可以利用反馈清零的方法将计数值限制在 0 至 9 的范围内。 --- #### 实现方法 以下是使用 74LS161 构建十进制减法计数器的主要思路: 1. **初始设置** 设置 74LS161 的 LD(加载)端为高电平,确保不启用预置功能。同时,CLR(异步清零)端应连接到适当的控制信号,以便在需要时清除计数器的状态[^2]。 2. **反馈清零机制** 当计数值达到 10 (即二进制 `1010`) 时,通过检测 Q3 和 Q1 输出的组合 (`Q3=1` 并且 `Q1=1`) 来激活 CLR 输入,从而强制计数器回到 0 状态。这种反馈清零技术能够有效地限定计数范围为 0 到 9[^2]。 3. **倒序计数** 默认情况下,74LS161 是一个加法计数器。要将其转换成减法计数器,则需借助额外的反向逻辑或者级联多个芯片形成递减序列。一种常见做法是在主时钟线上加入反相器,使得每次脉冲下降沿触发递减动作[^4]。 4. **完整的电路结构** - 主体部分由单片或多片串联起来的74LS161组成; - 添加必要的门电路处理溢出条件下的重置操作; - 可选地增加显示驱动模块便于观察实际效果。 下面给出具体的硬件连线实例以及对应的软件模拟建议: ```plaintext CLK ----> Clock Input of IC1 LD -------> High Level Fixed Signal CLR ------> Output from AND Gate connected to Q3 & Q1 Outputs Respectively. ``` 对于更复杂的场景比如多位数字运算则可能涉及到更多组件间的协调配合,这里仅讨论单一单元的情况. --- #### 示例代码片段 如果考虑用编程方式辅助理解该过程的话,可以用如下伪代码表示整个流程: ```python class DecadeCounter: def __init__(self): self.value = 0 def decrement(self): if self.value > 0: self.value -= 1 elif self.value == 0: # Simulate rollover behavior with feedback reset logic self.value = 9 def get_value(self): return bin(self.value)[2:].zfill(4) counter = DecadeCounter() for _ in range(15): counter.decrement() print(f"Current Value: {int(counter.get_value(), base=2)} Binary Representation:{counter.get_value()} ") ``` 此段Python程序简单模仿了基于74LS161构建的实际物理设备的行为特征——每当调用decrement函数就会减少当前存储值直到循环回至最大容量为止。 --- ### 注意事项 - 上述设计方案假设电源电压稳定,并已妥善安排去耦电容器以抑制噪声干扰。 - 如果计划扩展成为多字节数组形式的操作对象,请特别注意各子部件间的数据传递延迟现象及其补偿措施[^4].
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值