iTOP-STM32MP157开发板采用ST推出的双核cortex-A7+单核cortex-M4异构处理器,既可用Linux、又可以用于STM32单片机开发。开发板采用核心板+底板结构,主频650M、1G内存、8G存储,核心板采用工业级板对板连接器,高可靠,牢固耐用,可满足高速信号环境下使用。共240PIN,CPU功能全部引出:底板扩展接口丰富底板板载4G接口(选配)、千兆以太网、WIFI蓝牙模块HDMI、CAN、RS485、LVDS接口、温湿度传感器(选配)光环境传感器、六轴传感器、2路USB OTG、3路串口,CAMERA接口、ADC电位器、SPDIF、SDIO接口等
第三十章Cortex-M4通用定时器实验
本章节最终所完成的实验例程存放路径为“iTOP-STM32MP157开发板网盘资料汇总\06_Cortex-M4实验例程\06_TIME.zip”。
30.1定时器简介
30.1.1 什么是定时器
定时器实际上就是Soc当中的一个内部外设。主要用来实现定时执行代码的功能。定时器可以让SoC在执行主程序的同时进行计时,当到了一定时间之后,CPU会去处理中断并执行定时器的ISR。从而去执行预先设定好的事件。
STM32MP1有众多的定时器,其中包括 2 个基本定时器(TIM6 和 TIM7)、10 个通用定时器(TIM2~TIM5,TIM12~ TIM17)、2 个高级控制定时器(TIM1 和 TIM8)和 5 个低功耗定时器(LPTIM1~LPTIM5)。这些定时器彼此完全独立,不共享任何资源。
而在我们这章节所要进行的实验便是通过这两个基本定时器之中的TIM6来实现的。
30.1.2 基本定时器的初步认识
基本定时器 TIM6 和 TIM7 是一个 16 位的只能向上计数的定时器,只能定时,没有外部 IO。
下图为基本定时器的框图,下面我们将对该框图进行一定的解读
1、时钟源
定时器要实现计数必须存在时钟源,基本定时器时钟只能来自内部时钟,高级控制定时器和通用定时器还可以选择外部时钟源或者直接来自其他定时器等待模式。基本定时器挂在 APB1 上,其时钟来源于 PCLK1,但是基本定时器时钟不是直接由 APB1 提供,而是经过一个倍频器,当 APB1DIV 的分频数为 1 的时候,此倍频器倍频值为 1,当 APB1DIV 的分频数大于 1 的时候,此倍频器倍频值始终为 2。APB1 的时钟频率最大为 104.5MHz,所以基本定时器的计数器的时钟频率最大为 209MHz,如下图所示:
2、计数器时钟
定时器时钟经过 PSC 预分频器之后,即 CK_CNT,用来驱动计数器计数。PSC 是一个16 位的预分频器,可以对定时器时钟 TIMxCLK 进行 1~65536 之间的任何一个数进行分频。
具体计算方式为:CK_CNT=TIMxCLK/(PSC+1)。在后续的实验步骤之中我们还会对此进行讲解。
3.计数器
计数器 CNT 是一个 16 位的计数器,只能往上计数,最大计数值为 65535。当计数达到自动重装载寄存器的时候产生更新事件,并清零从头开始计数。
4、自动重装载寄存器
自动重装载寄存器 ARR 是一个 16 位的寄存器,这里面装着计数器能计数的最大数值。当计数到这个值的时候,如果使能了中断的话,定时器就产生溢出中断。
5. 定时时间的计算
定时器的定时时间等于计数器的中断周期乘以中断的次数。计数器在 CK_CNT 的驱动下,计一个数的时间则是 CK_CLK 的倒数,等于:1/(TIMxCLK/(PSC+1)),产生一次中断的时间则等于:1/(CK_CLK * ARR)。如果在中断服务程序里面设置一个变量 time,用来记录中断的次数,那么就可以计算出我们需要的定时时间等于: 1/CK_CLK *(ARR+1)*time。
而我们这个实验内容为,LED2和LED3初始状态为LED2亮起LED3熄灭,然后每一秒钟状态进行反转。
30.2实验目的
1)学习使用STM32CubeIED配置基本定时器
2)学习基本定时器的使用
3)STM32CubeIED的熟练
30.3实验步骤
30.3.1建立TIME工程
首先我们打开STM32CubeIDE软件,进入软件界面之后,我们点击File属性,选择NEW下的STM32 Project的选项,如下图所示:
然后我们会进入下图所示界面:在Part Number选择框输入STM32MP157A,然后在右边的选择界面选择STM32MP157AAA,然后点击Next选项
在Project Name框中输入工程名字LED,然后点击Finish选项即可,如下图所示:
等待工程创建完毕,会询问我们是否要安装OpenSTLinux ,由于我们是在windows环境下,所以我们不需要安装,点击NO即可
至此我们的工程创建完毕,进入工程界面如下图所示界面:
30.3.2 GPIO功能引脚配置
首先我们在下面的搜索框之中输入我们要配置的引脚,我们在这里以PE1为例进行搜索,输入名称之后,对应的引脚在工程中会闪烁,如下图所示:
然后我们使用鼠标左键点击对应的引脚会弹出PE1的复用功能选择,我们在这里选择复用为GPIO_Output功能,如下图所示:
配置完复用功能之后,我们还要配置 Pin Reserved 选项,如果不配置此项,在生成工程代码的时候将不会看到有关这个 Pin 的初始化代码。继续选中 PE1,右键弹出设置项,我们选择Pin ReservedàCortex-M4。如下图所示:
第二个LED的控制管脚PE14按同样的方法进行配置。
配置完成之后打开左侧菜单的 System CoreàGPIO 进入 GPIO 模式配置界面:如下图所示:
点击对应的引脚配置之后会弹出右下方的管脚配置界面,如上图所示:
在下方会列出要配置选项的具体说明和我们要进行的配置。
1)选项 GPIO output level 用来设置IO口的输出电平的高低,这这里我们选择LOW
2)选项 GPIO mode 用来设置 IO 口输出模式为 Output Push Pull(推挽)还是 Output Open Drain(开漏)。本实验我们设置为推挽输出 Output Push Pull。
3)选项 GPIO Pull-up/Pull-down 用来设置 IO 口是上拉/下拉/没有上下拉。本实验我们设置为上拉(Pull-up)。
4)选项 Mzximum ouput speed 用来设置 IO 口输出速度为低速(Low)/中速(Medium)/高速 (Hign)/快速(Very High)。我们设置为高速 High 。
5)选项 User Label 是用来设置初始化的 IO 口 Pin 值为我们自定义的宏,这里我们填写为 LED3。按照如上要求设置后的界面如下(由于PE14的配置相同,只是最后的Label值不同,也在下方列了出来):
30.3.3 时钟与定时器的配置
首先我们本次实验所采用的时钟为外部时钟HSE,所以我们要在左侧属性栏中的System Core 属性下找到RCC将High Speed Clock选择为Crystal/Ceramic Resonator(晶体/陶瓷晶振)。如下图所示:
然后在Clock Configuration里我们选择 HSE,作为锁相环 PLL3P 的时钟源,在 MCU 子系统时钟里输入 209 并回车,软件会自动设置相应的倍频和分频,如下图所示:
设置完成之后,如下图所示,然后再手动配置 APB1DIV、APB2DIV 和 APB3DIV的分频值为 2。当 APB1DIV 的分频数大于 1 的时候,基本定时器的倍频器倍频值始终为 2,所以基本定时器的时钟频率为 209MHz。
配置完时钟之后,下面我们将要对TIM6进行配置按照步骤配置 :
首先将TIM6 分配给 M4 (由于TIM6 只能给 A7 和 M4 内核两者中的某一个使用)。
然后将预分频器寄存器(TIMx_PSC)的值配置为 20900-1;自动重载寄存器 (TIMx_ARR)的值设置为10000-1。
开启自动重装载模式,定时器溢出时会自动重装初值。这里注意的是,自动重载寄存器 (TIMx_ARR)的值不能设置为 0
基本定时器的时钟频率是 209MHz,以上参数预分频器分频值为 20900-1,计算出计数器 CK_CNT 的时钟频率是
那么计数器计数 10000 次就会溢出产生中断,所以每次溢出时间是:
定时器要每秒溢出产生中断,所以我们要使能定时器全局中断,并配置中断优先级。如下图,勾选 TIM6 定时器全局中断:
最后由于在系统初始化的过程之中会用到System tick timer,而System tick timer的默认优先级是低于定时器中断的,不进行默认优先级修改的话,程序会卡死在Error_Handler的while死循环之中。
在左侧菜单栏中的System Core下选择NVIC进入如下图所示:
可以看到Time base:System tick timer 的优先级默认设置为15,而定时器中断的优先级默认为1,定时器中断的优先级是高于默认优先级的,所以我们要对优先级进行修改我们将Time base:System tick timer 的优先级设置为1,而定时器中断的优先级设置为2,修改完成如下图所示:
配置完成之后我们需要在Project Manage下的Code Generator选项下勾选 Generate peripheral initialization as a pair of ".c/.h' files per peripheral 选项,这样可以独立生成对应外设的初始化.h 和.c 文件(方便配置的查看),如下图所示:
30.3.4工程的生成与完善
在上述的步骤完成之后,按下键盘的“Ctrl+S”组合键保存保存 WWDG.ioc 文件,系统开始生成初始化代码,工程生成之后如下图所示:
然后我们进行工程的完善,以及添加对应的逻辑代码。
30.3.4.1 对应文件与文件夹的添加
由于我们在前面章节已经完善了对应的LED文件,所以我们将iTOP-STM32MP157开发板网盘资料汇总\06_Cortex-M4实验例程\01_LED\LED\CM4\Core\BSP文件拷贝到当前工程对应的位置,拷贝完成如下下图所示:
30.3.4.2 tim.c文件的完善
我们对tim.c文件进行代码的添加,tim.c文件的存放位置如下图所示:
在 #include "tim.h"下添加以下内容
#include "../BSP/Include/led.h"
在/* USER CODE BEGIN 0 */和/* USER CODE END 0 */之间添加以下内容:
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{if (htim == (&htim6)){LED2_TOGGLE();LED3_TOGGLE();}
}
添加完成如下图所示:
30.3.4.3 main.c文件的完善
我们要修改的main.c文件路径如下图所示:
打开main.c文件,为了规范我们在/* USER CODE BEGIN Includes */和/* USER CODE END Includes */之间添加以下内容
#include "../BSP/Include/led.h"
添加完成如下图所示:
然后在 /* USER CODE BEGIN 2 */和/* USER CODE END 2 */之间添加以下内容:
led_init();
HAL_TIM_Base_Start_IT(&htim6);
通过调用led_init()函数来使LED2和LED3的初始状态分别为亮和灭。
通过调用HAL_TIM_Base_Start_IT(&htim6); 更新定时器中断和使能定时器。
至此我们的代码完善就结束了,该工程所实现的功能为LED2、LED3的状态每一秒反转一次。
30.3.5工程的编译
在完成以上步骤之后我们点击工具栏的小锤子进行编译,编译图标如下图所示:
编译完成会在下方的终端中显示打印信息,如下图所示:
如果报错,需要自己根据错误的提示信息来进行问题的寻找和改正。
30.3.6工程的调试
由于STM32MP157的裸机部分和一般的单片机有些区别,他没有内部的存储,所以只能在程序编译成功之后,通过debug的方式来进行调试(将程序放在内存之中),调试过程如下:
首先,点击菜单栏中的小甲虫Debug调试按钮,弹出以下界面,
在弹出来的界面,按步骤,选择响应的属性(该步骤为Jlink的步骤,如果是STLink,调试探头选择对应的即可)。如下图所示:
选择完成之后,点击右下角的Debug按钮,点击之后,会进行再一次的编译,编译完成之后会弹出如下内容(作者用的是J-LinK),这里弹出的是J-link关于设备的选择,不同调试器的弹窗可能会不同
在弹出来的界面中,选择Accept接受,会弹出以下内容,继续点击下方的OK。
之后会来到设备选择界面,我们选择Cortex-M4,如下图所示:
选择Cortex-M4之后,点击右下角的OK,会弹出以下界面,选择右下角Switch.
然后会弹出一个新的页面,选择菜单栏的 resume按钮开始调试。
此时,LED2和LED3每一秒钟状态进行反转
如果想关闭调试,则点击菜单栏的终止按钮即可。