微波EDA网,见证研发工程师的成长!
首页 > 研发问答 > 嵌入式设计讨论 > MCU和单片机设计讨论 > 第四篇?细说阿波罗的时钟以及通用定时器测试

第四篇?细说阿波罗的时钟以及通用定时器测试

时间:10-02 整理:3721RD 点击:
老实说,用过很多的芯片,但是都没有太仔细的研究过芯片的细节,只要做的工作还是停留在调用函数的层面,但是要想更深入的学习一款芯片不了解细节是不行的。于是,我就拿阿波罗来班门弄斧了。粗略看了阿波罗的时钟体系,做一些笔记,记录下来(如果说的有错误,希望大家积极指正,我将不胜感激):从时钟源的角度,分为两类外部时钟(E)和内部时钟(I)。
从时钟速率的角度,分为两类高速时钟(HS)和低速时钟(LS)。

而把它们组合起来就有四种时钟:HSE、HIS、LSE、LSI。至于为什么会有这么复杂的时钟配置,主要是考虑到系统的性能和功耗两个方面的因素吧。单一时钟的话可能会导致性能过剩并且功耗过高。多个时钟的话可以平衡功耗和性能之间的平衡。

特此说明一下,系统复位后,默认初始化的是HIS时钟提供sysclock。也就是16MHZ。为了提示系统性能,我们需要使能外部时钟晶振(板载25MHz)。使能后也明显可以看出来芯片的温度升高了(使用内部的温度传感器测试,在后续有图片为证)。

这四类时钟在芯片内部通过配置,完成对各个外设的驱动。到了芯片内部,对应到那么多的外设,时钟的分类就更多了,但是主要考虑到桥的存在,分为五类:AHB3、AHB2、AHB1、APB2、APB1。芯片内的所有外设都分别挂载在这五个总线上,至于哪个外设挂歪在哪个总线上,我们就需要查看芯片的RM0410 Reference manual(Page74)了。

今天为了测试时钟的配置,我就用通用定时器TIM2做下示范操作:

首先查看TIM2挂载在哪条总线:


可知挂载在APB1总线上。


接着就可以查看TIM的时钟回路:


从上述截图中可以看出,最后TIM时钟的周期是54MHZ。具体配置关键代码如下:

  1. void SystemClock_Config(void)
  2. {
  3.   RCC_ClkInitTypeDef RCC_ClkInitStruct;
  4.   RCC_OscInitTypeDef RCC_OscInitStruct;

  5.   /* Enable HSE Oscillator and activate PLL with HSE as source */
  6.   RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
  7.   RCC_OscInitStruct.HSEState = RCC_HSE_ON;
  8.   RCC_OscInitStruct.HSIState = RCC_HSI_OFF;
  9.   RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  10.   RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
  11.   RCC_OscInitStruct.PLL.PLLM = 25;
  12.   RCC_OscInitStruct.PLL.PLLN = 432;
  13.   RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_div2;
  14.   RCC_OscInitStruct.PLL.PLLQ = 9;
  15.   RCC_OscInitStruct.PLL.PLLR = 7;
  16.   if(HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  17.   {
  18.     while(1) {};
  19.   }

  20.   /* Activate the OverDrive to reach the 216 Mhz Frequency */
  21.   if(HAL_PWREx_EnableOverDrive() != HAL_OK)
  22.   {
  23.     while(1) {};
  24.   }

  25.   /* Select PLL as system clock source and configure the HCLK, PCLK1 and PCLK2
  26.      clocks dividers */
  27.   RCC_ClkInitStruct.ClockType = (RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2);
  28.   RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
  29.   RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_div1;
  30.   RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_div4;
  31.   RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_div2;
  32.   if(HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_7) != HAL_OK)
  33.   {
  34.     while(1) {};
  35.   }
  36. }

复制代码

考虑到ST的代码很清晰明了,对照着我作的标记大家应该可以看明白吧。


接着就进行配置TIM2的时钟分频,以及计数周期。由于TIM2的时钟可以由多个来源,既然我们用的是APB1时钟,那么就输入内部时钟也就是:


贴出对应的关键代码

  1. void TIM_init(TIM_HandleTypeDef *ITIMX)
  2. {
  3.   ITIMX->Instance=TIM3;
  4.   ITIMX->Init.Period=999;
  5.   ITIMX->Init.Prescaler=53999;
  6.   ITIMX->Init.CounterMode=TIM_COUNTERMODE_UP;
  7.   HAL_TIM_Base_Init(ITIMX);
  8.   HAL_TIM_Base_Start_IT(ITIMX);
  9. }

复制代码

539999对应上图中的PSC Prescaler,分频后时钟频率为54MHz/(53999+1)=1KHz。接下来就要注意一点了,在TIM2采样时钟之前,有


如果APB的分频比是1,那么频率不变,否则频率 乘以2,这样一来可以确定TIM2的采样频率是2kHz了。


接下来配置计数周期为999。也就是对应0.5s。在中断函数中又如下代码:

  1. void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
  2. {
  3.   led_flag++;
  4.   if(led_flag%2)
  5.     LED_on();
  6.   else
  7.     LED_off();
  8. }

复制代码

这样一来,就可以实现DS0和DS1交替1s闪烁,通过计时测试,成功了。


由此,使用TIM2演示时钟配置的任务已经完成了。


声明一下,此次阿波罗的试用,我会把我各个阶段的完整的代码托管到github上,如需查看欢迎fork。

https://github.com/iysheng/apollo



补充一下升频道216MHZ,之后的芯片温度和16MHZ的对比:16MHz


平均在18摄氏度.
216MHz


平均在25摄氏度.

LZ很仔细啊!研究的透彻

今天上午又添加输入捕获PWM周期的功能,具体代码都在我的github上:阿波罗的源码,欢迎fork
如果有关于原代码的疑问欢迎交流:
展示下PWM的周期测试,用的手机秒表定时,误差还行,准备过段时间借用一个示波器去,
串口输出周期;


手机秒表测试数据:


Copyright © 2017-2020 微波EDA网 版权所有

网站地图

Top