M-Arch(7)第六个示例:时钟频率

前言

回顾下之前的章节:

  • 第一章节中我们描述了整个框架的核心设计思路以及主要的文件架构

  • 第二章节中我们基于一个简单的定时器OS实现了串口的数据打印,并完成了通用crc模块的设计和测试

  • 第三章节中我们给出了真随机数和伪随机数的概念和代码示例,并在架构上对接口进行了重构

  • 第四章节中我们回顾了FMC的基本知识,并给出了示例,后面我们将在设计IAP的时候再次使用到FMC

  • 第五章节中我们使用ADC和DMA搭建了一个通用的采样框架,并通过串口给出了采样的数据示例

  • 第六章节中我们总结了DAC的基本使用方法,并通过DAC生成了任意频率的正弦波,三角波和方波

本文我们总结下时钟的概念,并介绍下如何获取系统中各模块的时钟频率。

什么是系统时钟?

通常所说的系统时钟就是指时钟系统,它是由振荡器(信号源)、定时唤醒器、分频器等组成的电路。常用的信号源有晶体振荡器和RC振荡器,如下图所示:

a3cd8d6909906bf524a395671c3e1058.png
时钟系统

ARM的时钟系统包括4部分,分为晶体振荡器、唤醒定时器、锁相环(PLL)和VPB分频器。其中晶体振荡器为系统提供基本的时钟信号(频率为Fosc)。当复位或者处理器从掉电模式唤醒时,“唤醒定时器”要对输入的时钟信号做计数延时,使芯片内部的部件有时间进行初始化。然后Fosc被PLL提高到一个符合用户需要的频率Fcclk,Fcclk用于CPU内核。因为CPU内核通常比外设部件的工作速度要快,用户可以通过设置VPB分频器,把Fcclk信号降低到一个合适的值Fpclk,该信号用于外设部件。

信号源也就是时钟源,外部晶振的频率一般是8M,25M,可以在电路板上的晶振上看到,标号一般是Y*。在keil中需要在魔术棒的Target中进行设置:

1e0df7d997710d34bf77b8b9ffb849d0.png
Keil时钟配置

时钟是嵌入式系统的脉搏,处理器内核在时钟驱动下完成指令执行,状态变换等动作。外设部件在时钟的驱动下完成各种工作,比如串口数据的发送、A/D转换、定时器计数等等。因此时钟对于计算机系统是至关重要的,通常时钟系统出现问题也是致命的,比如振荡器不起振、振荡不稳、停振等。

什么是时钟树?

通常略微复杂的单片机系统中会给出时钟树,描述了系统中所有用到时钟的设备对应的时钟。软件中需要根据时钟树来配置硬件管脚。

以STM32F103ZE为例:

02344552962b8bd03b6c784b9da55086.png
STM32F103ZE时钟树

上图中:假设使能HSE,外部晶振为8MHZ。

1线为使用外部晶振时的系统时钟的配置:外部晶振OSC_IN A为8MHZ,在B处9倍倍频PLL,那么SYSCLK就为72MHZ。

2线为TIM2-7的时钟配置:假设:C处AHB分频为1,D处APB1分频为2,那么E的输入为36MHZ,E的输出为else X2 = 72MHZ。TIM2-7的时钟频率为72MHZ。

定时器中断

在软件设计中,我们常常需要用到软件定时,这是需要我们使用定时器来产生周期定时。

如何产生周期定时,需要用到定时器,需要用到2个参数:预分频值Prescaler和重装值Period。

预分频值决定了最小分辨率,假设72MHZ的TIM3定时器:

  • 如果我们需要1us(1MHZ)的最小分辨率,那么:Prescaler=71 (72-1)

  • 如果我们需要100us(10KHZ)的最小分辨率,那么:Prescaler=7199 (7200-1)

重装值表示计数到此数之后会产生一个定时器中断,假设Prescaler=7199(10KHZ):

  • 如果我们需要1ms的中断,那么计数到10就产生中断,Period=9 (10-1)

  • 如果我们需要10ms的中断,那么计数到100就产生中断,Period=99 (100-1)

  • 如果我们需要100ms的中断,那么计数到1000就产生中断,Period=999 (1000-1)

软件中如何读取各时钟频率?

STM32提供了库函数 RCC_GetClocksFreq

typedef struct
{
  uint32_t SYSCLK_Frequency;  
  uint32_t HCLK_Frequency;    
  uint32_t PCLK1_Frequency;   
  uint32_t PCLK2_Frequency;   
  uint32_t ADCCLK_Frequency;  
}RCC_ClocksTypeDef;

RCC_ClocksTypeDef clock;
RCC_GetClocksFreq(&clock);

GD32提供了库函数 rcu_clock_freq_get

uint32_t rcu_clock_freq_get(rcu_clock_freq_enum clock)

参数:CK_SYS, CK_AHB, CK_APB1, CK_APB2

没有提供接口的外设频率怎么查询?

看芯片手册外设配置和时钟树自己算

以GD32的ADC为例,ADC_SYNCCTL寄存器中bit16-18为ADC的时钟频率ADCCK[2:0]:

18:16 ADCCK[2:0] ADC时钟
这些位配置所有ADC的时钟
000:PCLK2 2分频
001:PCLK2 4分频
010:PCLK2 6分频
011:PCLK2 8分频
100:HCLK 5分频
101:HCLK 6分频
110:HCLK 10分频
111:HCLK 20分频

#define ADC_SYNCCTL_ADCCK               BITS(16,18)

那么:

  • 如果ADC配置为ADC_ADCCK_PCLK2_DIV4,那么:

    • 其寄存器值为:(ADC_SYNCCTL>>16)&0x07)=1

    • 其频率为:rcu_clock_freq_get(CK_APB2)/4

  • 如果ADC配置为ADC_ADCCK_HCLK_DIV10,那么:

    • 其寄存器值为:(ADC_SYNCCTL>>16)&0x07)=6

    • 其频率为:rcu_clock_freq_get(CK_AHB)/10

例行给出运行结果

STM32F1-COM3,GD32F4-COM9

f22af38c8ad0f9713a558edd691114e9.gif
时钟频率获取

--EOF--

例行求粉,谢谢!

f18583eecfd5219b93d300841c172a03.png
求粉
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值