虽然 28379D 有两个核,但工作时钟的配置方法还是一致的,所以可以从单核的角度来学习时钟配置的方法
# 时钟框图
无论什么外设都离不开功能框图,所以还是先从功能框图入手分析时钟配置的基本信息
# 时钟源部分
TMS320F28379D 有三个时钟源,两个内部时钟源和一个内部时钟源,通过 CLKSRCCTL1 来选择时钟源
INTOSC2
是默认的 10M 内部晶振,但是容差太差,如果要使用 USB 或者 CAN 外设则需要使用外部晶振
INTOSC1
是备用的 10M 内部晶振,但是只能用于 DCM 和看门狗。
XTAL
是外部晶振接口,提供稳定的时钟频率
# 振荡器 + 倍频
时钟产生震荡稳定后,通过 SYSPLLCTL1
来选择 是通过 PLL 对 OSCCLK
进行倍频后输出,或是直接输出 OSCCLK
# 分频
输出的时钟要经过分频器将主频降低到想要的频率,然后分别传输给 CPU 和 外设
# 寄存器
时钟的内容在第三章的第 7 节,但寄存器内容在第三章的末尾
这一张涉及的功能配置比较多,所以寄存器章节的内容也比较杂
我这里只调用到的寄存器来讲
PS: 说实话,TI 在时钟寄存器上常常 标志位和控制位 混在一块,看的头大
# CLKSRCCTL1
用于选择和开启时钟源,以及 CPU1 看门狗的工作状态
名称 | 功能 | 注解 |
---|---|---|
OSCCLKSRCSEL | 选择 OSCCLK 的时钟源 | 00: INTOSC2<br />01: XTAL<br />10: INTOSC1 |
INTOSC2OFF | 控制 INTOSC2 是否开启 | 0: 开启 <br />1: 关闭 |
XTALOFF | 控制 XTAL 是否开启 | 0: 开启 <br />1: 关闭 |
# SYSPLLCTL1
名称 | 功能 | 注解 |
---|---|---|
PLLEN | 控制 PLL 是否开启 | 0: 开启 <br />1: 关闭 <br /> 默认为 0 |
PLLCLKEN | 控制是否经过 PLL | 0: PLL 倍频输出 <br /> 1: PLL 旁路 |
# SYSPLLMULT
名称 | 功能 | 注解 |
---|---|---|
IMULT | PLL 倍频参数的整数部分 | 1~127 |
FMULT | PLL 倍频参数的小鼠部分 | 00: 0<br />01: 0.25<br />10: 0.5<br />11: 0.75<br /> |
PS: 倍频参数为
# SYSCLKDIVSEL
名称 | 功能 | 注解 |
---|---|---|
LLSYSCLKDIV | PLL 分频参数的整数部分 | 2 的倍数,从 /1 到 /126 |
# PLL 工作模式
进行实例说明之前先科普一下 PLL 的三种工作模式:关闭、旁路、使能
功能 | 说明 | 配置 |
---|---|---|
关闭 | 时钟直接传入 OSCCLK 可以减少系统噪声和功耗. | SYSPLLCTL1.PLLEN = 0; |
旁路 | 上电复位或复位后, PLL 会进入该模式.<br /> 时钟信号不经过 PLL 而是从 PLL 边上绕开,但 PLL 处于工作状态 | SYSPLLCTL1.PLLEN = 1; <br /> SYSPLLCTL. PLLCLKEN = 0; |
使能 | PLL 处于使能状态,时钟信号倍频后输入到 OSCCLK 中 | SYSPLLCTL1.PLLEN = 1; SYSPLLCTL. PLLCLKEN = 1; |
# 时钟配置
# 文档配置方法
在文档 3.7.6.2 处可知,具体的时钟配置方法,大致意思如下
- 选择时钟源,将对应值写入
CLKSRCCTL1.OSCCLKSRCSEL
- 清除
SYSPLLCTL1.PLLCLKEN
, 将时钟源切换为旁路 - 通过清除
SYSCLKDIVSEL[ PLLSYSCLKDIV]
的值,将 时钟分频设置为\1
, 保证 PLL 最快的被配置 - 同时将积分乘法器和分数乘法器写入 SYSPLLMULT, 就可以自动使能 PLL (倍频后,需要保障主频在额定工作范围内)
- 至少锁定 PLL 五次,次数越多成功概率越高,当然最好放一个看门狗,防止一直尝试
- 将分频器的分频数值 配置为 比目标值大一档,便于 PLL 模块快速打到目标值
- 保证
SCRS.WDOVERRIDE
在 PLL 锁定之后清除 SYSDBGCTL.BIT_0
置位,这里可以检测到 PLL 启动的错误- 通过置位
SYSPLLCTL1.PLLCLKEN
, 将 PLL 作为系统时钟 - 清除
SYSDBGCTL.BIT_0
- 将分配器中的数值,修改为目标数值
- 重新为应用配置对应的 看门狗
# 思路
PS: 这里以 使用 10M 的外部晶振生成 100M 的系统时钟为例
从文档中可以看出 时钟配置的核心步骤为:
- 选择时钟源
- 选择 PLL 工作模式
- 设定 PLL 参数
- 设定 分频器 参数
那么从寄存器表中可知会涉及到以下寄存器的操作
ClkCfgRegs.CLKSRCCTL1.bit.OSCCLKSRCSEL = 0x1; // 外部晶振
ClkCfgRegs.SYSCLKDIVSEL.bit.PLLEN = 0x00;// 开启PLL
ClkCfgRegs.SYSCLKDIVSEL.bit.PLLCLKEN = 0x00;// PLL 使能模式
ClkCfgRegs.SYSPLLMULT.bit.IMULT = 0x0A; // 10倍频
ClkCfgRegs.SYSPLLMULT.bit.FMULT = 0x00; // 不使用小数
ClkCfgRegs.SYSCLKDIVSEL.bit.PLLSYSCLKDIV = 0x00;// 不分频
按照思路来实现代码,对应的寄存器在第三章的最后一节中可以查找
这里用电平翻转来实现 和 计数 100 次来作为衡量时间的标准
虽然有些不靠谱,但是由于没有学 ePWM 的配置只能先将就一下,等以后学完之后再来更新
函数库版本的 时钟初始化函数有两个,分为不同的库文件,可以按需选择SysCtl_setClock(DEVICE_SETCLOCK_CFG);
InitSysPll(XTAL_OSC,IMULT_40,FMULT_0,PLLCLK_BY_2);
第一个函数需要 driverlib
库的支持
第二个函数需要 device_support
库的支持
第一个参数,将所有工作模式设置了一个位,函数 对应掩码按位 & 来确定是否需要开启当前模式
相对而言第二个函数的参数要更加容易理解一些,第一个参数使用的时钟源,第二个 PLL
的倍频参数,第三个分频器的 分频参数
# 代码实现
# 寄存器实现
100M 主频
#include "F28x_Project.h" | |
#include "driverlib.h" | |
#include "device.h" | |
void randomDelay(void); | |
void sysclk_cfg(void); | |
void gpio_cfg(void); | |
// | |
// Main | |
// | |
void main(void) | |
{ | |
sysclk_cfg(); | |
gpio_cfg(); | |
while (1) | |
{ | |
GpioDataRegs.GPATOGGLE.bit.GPIO25 = 1; | |
randomDelay(); | |
} | |
} | |
/** | |
* @b GPIO 初始化 25pin 输出 | |
*/ | |
void gpio_cfg(void) | |
{ | |
EALLOW; | |
GpioDataRegs.GPASET.bit.GPIO25 = 0; | |
GpioCtrlRegs.GPAMUX2.bit.GPIO25 = 0; | |
GpioCtrlRegs.GPADIR.bit.GPIO25 = 1; | |
GpioCtrlRegs.GPAODR.bit.GPIO25 = 0; | |
EDIS; | |
} | |
/** | |
* @b 随机延时测试函数 | |
*/ | |
void randomDelay(void) | |
{ | |
Uint32 i = 1000; | |
while (i) | |
{ | |
i--; | |
} | |
} | |
/** | |
* @b 时钟初始化 | |
*/ | |
void sysclk_cfg(void) | |
{ | |
EALLOW; | |
// 10M * 10 / 1 | |
ClkCfgRegs.CLKSRCCTL1.bit.OSCCLKSRCSEL = 0x1; // 外部晶振 | |
ClkCfgRegs.SYSPLLMULT.bit.IMULT = 0x0a; // 10 倍频 | |
ClkCfgRegs.SYSPLLMULT.bit.FMULT = 0x00; // 不使用小数 | |
ClkCfgRegs.SYSCLKDIVSEL.bit.PLLSYSCLKDIV = 0x00; // 不分频 | |
EDIS; | |
} |
# 函数库实现
再生成一个 200M 的系统时钟
#include "F28x_Project.h" | |
#include "driverlib.h" | |
#include "device.h" | |
void randomDelay(void); | |
void sysclk_cfg(void); | |
void gpio_cfg(void); | |
// | |
// Main | |
// | |
void main(void) | |
{ | |
// 二选一即可,第一个参数比较不容易理解,第二参数容易理解 | |
SysCtl_setClock(DEVICE_SETCLOCK_CFG); | |
// InitSysPll(XTAL_OSC,IMULT_40,FMULT_0,PLLCLK_BY_2); | |
gpio_cfg(); | |
while (1) | |
{ | |
GpioDataRegs.GPATOGGLE.bit.GPIO25 = 1; | |
randomDelay(); | |
} | |
} | |
/** | |
* @b GPIO 初始化 25pin 输出 | |
*/ | |
void gpio_cfg(void) | |
{ | |
EALLOW; | |
GpioDataRegs.GPASET.bit.GPIO25 = 0; | |
GpioCtrlRegs.GPAMUX2.bit.GPIO25 = 0; | |
GpioCtrlRegs.GPADIR.bit.GPIO25 = 1; | |
GpioCtrlRegs.GPAODR.bit.GPIO25 = 0; | |
EDIS; | |
} | |
/** | |
* @b 随机延时测试函数 | |
*/ | |
void randomDelay(void) | |
{ | |
Uint32 i = 1000; | |
while (i) | |
{ | |
i--; | |
} | |
} |
测试效果如图
-------2023 年 1 月 23 日 -------
# 使用 LunchPad 的注意事项
最开始的时候不知道为什么 C2000Ware 的例子运行在 LunchPad 上 频率总感觉不对, 好像是是一半的感觉。 后来进到 Device_init()
和 InitSysCtrl()
两个函数 默认使用外部晶振,而且程序默认外部晶振是 20MHz
的,所以导致频率为原本的一半。
两个函数的函数的时钟配置是在 SysCtl_setClock()
和 InitSysPll()
图中可以看到,需要定义一个 _LAUNCH_F28379D
的宏,所以需要在 properties
中去配置,进去后在 C2000 Compiler >> Build >> predefined symbols
中添加宏定义
最开始的时候不知道为什么 C2000Ware 的例子运行在 LunchPad 上 频率总感觉不对, 好像是是一半的感觉。 后来进到 Device_init()
和 InitSysCtrl()
两个函数 默认使用外部晶振,而且程序默认外部晶振是 20MHz
的,所以导致频率为原本的一半。
两个函数的函数的时钟配置是在 SysCtl_setClock()
和 InitSysPll()
图中可以看到,需要定义一个 _LAUNCH_F28379D
的宏,所以需要在 properties
中去配置,进去后在 C2000 Compiler >> Build >> predefined symbols
中添加宏定义
目前只学最简单的时钟配置,对应的的异常处理,以及外设时钟,定时器,ePWM 配置还未来得急涉足
等以后学完在来完善这篇文章
如有错误之处,望大佬斧正
大道五十,天衍四十九,人遁其一!