文章目录
- RT1052 核心板的资源
- 型号为:RT1052CVL5B。
- GPIO端口原理
- LDO
- EEPROM
- 复位电路
- 启动模式设置电路
- BootLoader地址
- 开发环境搭建
- 新建 基于 FSL 库的 MDK5 工程
- 软件
- 下载SDK包
- SDK包内容
- boards 文件夹
- CMSIS 文件夹
- devices 文件夹
- middleware 文件夹:
- 新建工程注意
- 型号
- 初始化配置
- MPU_Memory_Protection
- RT1052_Clock_Init
- CLOCK_SetXtalFreq() 和 CLOCK_SetRtcXtalFreq() 函数
- CLOCK_SetMux()
- CLOCK_SetDiv()
- CLOCK_InitXXXPll() 函数
- CLOCK_InitSysPfd()和 和 CLOCK_InitUsb1Pfd 函数
- CLOCK_EnableClock() 和 CLOCK_DisableClock()
- SystemCoreClockUpdate 函数
RT1052 核心板的资源
型号为:RT1052CVL5B。
- 该芯片采用六级流水线
- 自带指令和数据 Cache
- 集成双精度硬件浮点计算单元(DPFPU)和 DSP 指令
- 具有 512KB SRAM
- 2个通用定时器(GPT)
- 4 个周期定时器(PIT)
- 4 个四定时器(QTIMER)
- 4 个 FlexPWM
- 1个 eDMA 控制器(32 个通道)
- 2 个 FlexSPI
- 4 个 SPI
- 2 个看门狗
- 3 个 SAI
- 4 个 IIC
- 8 个串口
- 2 个 USB(高速,带 PHY)
- 2 个 FlexCAN
- 2 个 12 位 ADC
- 1 个 SPDIF 接口
- 2 个RTC
- 2 个 USDHC 接口
- 1 个 SEMC 接口
- 1 个 TFTLCD 控制器(ELCDIF)
- 1 个 10/100M以太网 MAC 控制器
- 1 个摄像头接口
- 1 个硬件随机数生成器
- 127 个通用 IO 口。
芯片主频高达 528Mhz(可超频到 600Mhz)
GPIO端口原理
RT1052 的 IO 口总共分成 5 组:GPIO1~GPIO5
- 其中:GPIO1、GPIO2 和 GPIO4 每组 32个 IO,GPIO3 只有 28 个 IO,GPIO5 最少,只有 3 个 IO,这样总共是 127 个 IO 口
LDO
自带的 LDO 稳压芯片(U5),型号为:RT9013-33GB,支持 500mA 大电流输出,小体积,低噪声,保证了 RT1052 电源的纯净,有利于核心板稳定运行。
EEPROM
板载的 EEPROM 芯片(U3),型号为:24C02,容量为 2Kb,也就是 256 字节。
用于存储一些掉电不能丢失的重要数据
复位电路
RT1052 是低电平复位的,上拉电阻和上电复位电容,在转接板上面带了
R1 和 C3,就是上拉电阻和上电复位电容
启动模式设置电路
启动模式是通过 BOOT_MODE0(即 GPIO1_IO04)和 BOOT_MODE1(即 GPIO1_IO05)来设置。启动模式选择如下:
- 注 1,eFUSE 是指 RT1052 内部的熔丝,从 0X400 开始~到 0X6F0 结束,熔丝是一次性设置的(设置完以后,无法再改回来),所以不要乱写,否则可能写死芯片。
- 注 2,RT1052 内部有 96KB 的 BOOT ROM,出厂时已经有固化的启动代码在里面了,这部分 ROM 没有对用户开放,所以我们是无法使用的。
- RT1052 如果需要正常运行代码,必须设置 BOOT_MODE[1:0]=00/10,而 00 和 10 这两种方式,非常相似,通过对熔丝的设置(BT_FUSE_SEL=1),10 完全可以替代00 的功能。
- BOOT_MODE[1:0]=01,是 USB 下载模式,此模式仅用于 USB(USB1)下载代码,下载完成后,必须设置成 00/10,否则代码是没办法正常运行的。
- 当 BOOT_MODE[1:0]=10,且仿真器下载代码出错时,则可以通过设置BOOT_MODE[1:0]=01 进入 USB 下载模式,从而重新下载代码,达到恢复下载的目的。
一般只要用到BOOT_MODE1:0]=01/10 这两个设置即可,刚好两个位是相反的,在开发板上设计有一个反相电路,只需要控制 BOOT_MODE[0],就可以达到同时设置BOOT_MODE[1]的目的。
BOOT_MODE[1:0]设置好了,RT1052 的启动过程,还要通过 BOOT_CFG1[0~7] 和 BOOT_CFG2[0~3]来决定具体从哪个器件启动以及相关参数。
BOOT_CFG1[0~7]和 BOOT_CFG2[0~3]的设置是可以通过 eFUSE 和 GPIO 两种方式来决定的,我们一般通过 GPIO 设置(也可以通过 eFUSE 设置,不过 eFUSE 设置以后,无法再修改,请谨慎选择!) GPIO 配置的这部分电路在转接板上
BOOT_CFG1[0~7]和 BOOT_CFG2[0~3]全部接了下拉电阻,也就是全部设置为 0。
这样,当我们设置 BOOT_MODE[1:0]=10 的时候,BOOT_CFG1[7:4]=0000,即:选择从 SPI FLASH 启动代码(SPI FLASH 地址:0X6000 0000)。
BootLoader地址
__disable_irq();
SCB->VTOR = flash_app_state_address;//将中断向量指向app地址
__enable_irq();
复制中断向量到新的地址。
BOOTLoader笔记
开发环境搭建
在 MDK5 安装完成后,要安装 RT1052 的器件支持包:
- NXP.MIMXRT1052_DFP.10.0.1.pack (RT1052 系列的器件包)。
- 还需要将 RT1052 的 FLASH下载 算法(MIMXRT105x_QuadSPI_4KB_SEC.FLM ),拷贝到 MDK 安装路径 →ARM →Flash文件夹里面。
- MDK5.23、RT1052 器件包和 RT1052 Flash 下载算法(见:光盘资料→6,软件资料→1,软件→MDK5 文件夹)
新建 基于 FSL 库的 MDK5 工程
软件
MCUXpresso_Config_Tools_V2_64.exe
下载SDK包
SDK 可以在 NXP 的官网下载到,下载地址。
-
NXP 官方的 SDK 是针对 NXP 自己的 RT1050-EVK 开发板写的,所以在选择 Boards 的时候选择 NXP 官方的 RT1052 开发板,如果需要下载 NXP 其他
型号的 MCU SDK 的时候就选择相应的 Boards
跳转到
进一步配置 SDK,比如开发主机系统:是 windows 还是 linux?所使用的 IDE 环境:是 KEIL、IAR 还是 GCC?是否需要第三方组件?都需要些啥组件等等,配置好以后点击下面的“Request Build”
SDK包下载
-
也可光盘资料→8,RT1052 参考资料→2,RT1052 官方 SDK→SDK_2.3.1_EVKB-IMXRT1050
-
用过SDK_2_10_0 MIMXRT1060_EVKB
SDK包内容
NXP 官方的 SDK 包一共有 7 个文件夹和 3 个其他文件
boards 文件夹
NXP 针对 RT1050 系列 MCU 写的一些例程
NXP 提供的例程共有 8 种,有 USB 的、emiwn 的、基础例程的和RTOS 操作系统的等等。学习 RT1052 重点就是参考官方 SDK 包里面提供的这些例程。
CMSIS 文件夹
CMSIS 全称: Cortex Microcontroller Software
Interface Standard,叫做 Cortex 微控制器软件接口标准。
此文件夹里面有一些重要的跟 Cortex-M 架构有关的头文件,在 include 文件夹里面,创建工程需要用到!此文件夹还有重要的 DSP 库,在 Lib 文件夹里面。
devices 文件夹
此文件夹是 RT1052 相关的东西,包括 FSL 库。
FSL 库就在 drivers 文件夹里面,我们创建库函数工程模板的时候就需要 FSL 库,还有一些其他的跟 RT1052 有关的.c 和.h 文件。
middleware 文件夹:
此文件夹包含了一些常用的第三方组件,比如 fatfs、lijpeg 库、usb、emwi 等。
新建工程注意
型号
- 安装 光盘:6,软件资料\1,软件\MDK5\NXP.MIMXRT1052_DFP.10.0.1.pack 这个安装包
- 号令者 RT1052 开发板所使用的 MCU 型号为 RT1052CVL5B,所以我们选择:NXP→MIMXRT1052→MIMXRT1052xxxxx→MIMXRT1052CVL5B
MDK 会弹出 Manage Run-Time Environment 对话框
在这个界面,我们可以添加自己需要的组件,从而方便构建开发环境。我们直接点击 Cancel,即可。
初始化配置
MPU_Memory_Protection(); //初始化MPU
RT1052_Clock_Init(); //配置系统时钟
MPU_Memory_Protection
MPU_Memory_Protection,用于对 RT1052 内部各个存储区域进行保护设置(RT1052 各存储区的分配和地址,详见《RT1050 参考手册》第 2 章 Memory Maps)
该函数里面总共对 8 个内存区域进行了保护设置,分别是:
- 区域 0,起始地址:0XC0000000,大小:1GB。存储属性;设备类型(TEX=2),禁止共享(S=0)、禁止 Cache(C=0)、禁止缓存(B=0)。此地址段属于 SEMC3。
- 区域 1,起始地址:0X80000000,大小:512MB。存储属性;设备类型(TEX=2),禁止共享(S=0)、禁止 Cache(C=0)、禁止缓存(B=0)。此地址段属于 SEMC0~2,包括:SDRAM 和
DBI 等。
区域 2,起始地址:0X60000000,大小:512MB。存储属性;普通类型(TEX=0),禁止共享(S=0)、允许 Cache(C=1)、允许缓存(B=1)。此地址段属于 FlexSPI,包括:FlexSPIA 和
FlexSPIB 等。 - 区域 3,起始地址:0X00000000,大小:1GB。设备类型(TEX=2),禁止共享(S=0)、禁止 Cache(C=0)、禁止缓存(B=0)。此地址段属于 ITCM/ROMCP/DTCM 和 OCRAM 等。
- 区域 4,起始地址:0X00000000,大小:128KB。存储属性;普通类型(TEX=0),禁止共享(S=0)、允许 Cache(C=1)、允许缓存(B=1)。此地址段属于 ITCM。MPU 属性规则:区域大的覆盖区域小的,所以 ITCM 的属性以区域 4 的设置为准,区域 3 的设置,对 ITCM 无效。
- 区域 5,起始地址:0X20000000,大小:128KB。存储属性;普通类型(TEX=0),禁止共享(S=0)、允许 Cache(C=1)、允许缓存(B=1)。此地址段属于 DTCM。同理,DTCM 的属性以区域 5 的设置为准。
- 区域 6,起始地址:0X20200000,大小:256KB。存储属性;强序类型(TEX=0),禁止共享(S=0)、禁止 Cache(C=0)、禁止缓存(B=0)。此地址段属于 OCRAM。同理,OCRAM 的属性以区域 6 的设置为准。
- 区域 7,起始地址:0X80000000,大小:2MB。存储属性;普通类型(TEX=0),禁止共享(S=0)、允许 Cache(C=1)、允许缓存(B=1)。此地址段属于 SDRAM(前 2MB 范围)。同理,SDRAM 的前 2MB 地址空间属性以区域 7 的设置为准。
经过这样的设置,我们对 RT1052 用到的地址空间都进行了 MPU 保护设置,在实际
使用时,可以很好的运行。
-
该函数调用了好多外部函数,其中: SCB_DisableICache、SCB_DisableDCache 、SCB_EnableICache 和 SCB_EnableDCache 这几个函数,用于禁止/使能 I chache 和 D cahche,来自 core_cm7.h(放在 CORE 文件夹下)。
-
而:ARM_MPU_Disable、ARM_MPU_Enable、ARM_MPU_RBAR 和ARM_MPU_RASR 这几个函数,用于关闭/开启 MPU 保护,以及设置 MPU 的 RBAR 和 RASR 寄存器,来自mpu_armv7.h(放在 CORE 文件夹下)。
注意:这个函数最终是会开启 MPU 保护和 I Cache 和 D Cache 的,所以一旦调用,肯定就开 Cache 和内存保护了。
- 大家只要记住有这么个函数,作用就是给各个内存段做保护,避免开了 Cache 以后访问出错,而且每个例程都需要调用,就可以了。
RT1052_Clock_Init
//设置RT1052的系统时钟
void RT1052_Clock_Init(void)
{
CLOCK_SetXtalFreq(24000000); //芯片主晶振24MHz
CLOCK_SetRtcXtalFreq(32768); //RTC晶振32.728KHz
//初始化时钟阶段先设置为低速的24M时钟,
//后面会重新将PLL1设置为1200MHz,主频设置为600MHz
CLOCK_SetMux(kCLOCK_PeriphClk2Mux,1); //设置PERIPH_CLK2的时钟源为OSC时钟,也就是24M晶振
CLOCK_SetMux(kCLOCK_PeriphMux,1); //设置PERIPH_CLK为PERIPH_CLK2=24MHz
//设置VDD_SOC电压为1.25V,这样的话AHB就可以到600MHz
DCDC->REG3=(DCDC->REG3&(~DCDC_REG3_TRG_MASK))|DCDC_REG3_TRG(0x12);
//等待DCDC的稳定,即DCDC->REG0寄存器的bit31(STS_DC_OK)为1
while(DCDC_REG0_STS_DC_OK_MASK!=(DCDC_REG0_STS_DC_OK_MASK&DCDC->REG0)){};
//下面配置中的1200Mhz,528Mhz和480Mhz等频率均按照PLL1为1200Mhz来配置的
//因为后面会重新配置PLL1的,不要纠结于上面配置的24MHz!!!!
CLOCK_InitArmPll(&armPllConfig); //配置PLL1(ARM PLL)为1200MHz
CLOCK_InitSysPll(&sysPllConfig); //配置PLL2(SYS PLL)为528MHz
CLOCK_InitUsb1Pll(&usb1PllConfig); //配置PLL3(USB1 PLL)为480MHz
CLOCK_SetDiv(kCLOCK_ArmDiv,1); //ARM PODF 2分频,可选择0~7分别对应1~8分频,1200Mhz/2=600MHz
CLOCK_SetMux(kCLOCK_PrePeriphMux,3); //设置PRE_PERIPH_CLK的时钟源为PLL1经过ARM PODF分频后的时钟
//即:PRE_PERIPH_CLK=PLL1/ARM PODF=1200MHz/2=600MHz
CLOCK_SetMux(kCLOCK_PeriphMux,0); //设置PERIPH_CLK为PRE_PERIPH_CLK=600MHz
CLOCK_SetDiv(kCLOCK_AhbDiv,0); //AHB_CLK_ROOT=PERIPH_CLK/1=600/1=600Mhz
CLOCK_SetDiv(kCLOCK_IpgDiv,3); //IPG_CLK_ROOT=AHB_CLK_ROOT/4=600/4=150MHz
CLOCK_SetDiv(kCLOCK_PerclkDiv,1); //PER_CLK_ROOT=IPG_CLK_ROOT/2=150/2=75MHz
//设置PLL2(SYS PLL)各个PFD
CLOCK_InitSysPfd(kCLOCK_Pfd0,27); //PLL2_PFD0=528*18/27=352Mhz
CLOCK_InitSysPfd(kCLOCK_Pfd1,16); //PLL2_PFD1=528*18/16=594Mhz
CLOCK_InitSysPfd(kCLOCK_Pfd2,24); //PLL2_PFD2=528*18/24=396Mhz
CLOCK_InitSysPfd(kCLOCK_Pfd3,32); //PLL2_PFD3=528*18/32=297Mhz
//设置PLL3(USB1 PLL)各个PFD
CLOCK_InitUsb1Pfd(kCLOCK_Pfd0,15); //PLL3_PFD0=480*18/12=720Mhz
CLOCK_InitUsb1Pfd(kCLOCK_Pfd1,13); //PLL3_PFD1=480*18/13=664.62Mhz
CLOCK_InitUsb1Pfd(kCLOCK_Pfd2,17); //PLL3_PFD2=480*18/17=508.24Mhz
CLOCK_InitUsb1Pfd(kCLOCK_Pfd3,19); //PLL3_PFD3=480*18/19=454.74Mhz
//一共7个PLL,上面初始化了PLL1(ARM PLL)、PLL2(SYS PLL)和USB1 PLL(USB1 PLL)
//其它四个PLL后面根据实际使用情况在做初始化。
CLOCK_DeinitAudioPll(); //关闭AUDIO PLL (PLL4)
CLOCK_DeinitVideoPll(); //关闭VIDEO PLL (PLL5)
CLOCK_DeinitEnetPll(); //关闭ENET PLL (PLL6)
CLOCK_DeinitUsb2Pll(); //关闭USB2 PLL (PLL7)
//更新内核时钟,此函数计算全局变量SystemCoreClock的值,
//SystemCoreClock就是内核时钟,按照上面的配置此时钟就是600MHz
SystemCoreClockUpdate();
//使能SNVS时钟
CLOCK_EnableClock(kCLOCK_IomuxcSnvs);
CLOCK_SetMux(kCLOCK_SemcMux,0); //PERIPH_CLK作为SEMC时钟源,PERIPH_CLK=600M
CLOCK_SetDiv(kCLOCK_SemcDiv,3); //设置SEMC时钟由PERIPH_CLK四分频得到,即SEMC Clock=600/4=150Mhz
}
NXP 的 FSL 库提供了一套用于设置系统时钟,包括各个外设时钟的 API 函数,我们在使用 FSL 库函数开发 RT1052 的时候就可以使用这些 API 函数来设置相应的时钟。
CLOCK_SetXtalFreq() 和 CLOCK_SetRtcXtalFreq() 函数
CLOCK_SetXtalFreq()和 CLOCK_SetRtcXtalFreq()这两个函数用来设置所使用的主晶振和RTC 晶振
这两个函数在 fsl_clock.h 中定义,如下:
static inline void CLOCK_SetXtalFreq(uint32_t freq)
{
g_xtalFreq = freq;
}
static inline void CLOCK_SetRtcXtalFreq(uint32_t freq)
{
g_rtcXtalFreq = freq;
}
CLOCK_SetMux()
Mux 是多路复用器的意思,用来在可选的多路输入时钟中选择其中的一路作为使用时钟。
CLOCK_SetMux 函数最终肯定是要操作 CCM→CBCDR 的 PERIPH_CLK_SEL 位。
static inline void CLOCK_SetMux(clock_mux_t mux, uint32_t value)
此函数有两个参数:mux 和 value,mux 用来指定要设置的是哪个时钟,value 肯定就是要设置的值,mux 是个 clock_mux_t 类型的变量,而 clock_mux_t 是个枚举类型,枚举出来 RT1052所有可设置的时钟,clock_mux_t 在文件 fsl_clock.t 中有定义
typedef enum _clock_mux
{
kCLOCK_Pll3SwMux = CCM_TUPLE(CCSR,
CCM_CCSR_PLL3_SW_CLK_SEL_SHIFT,
CCM_CCSR_PLL3_SW_CLK_SEL_MASK,
CCM_NO_BUSY_WAIT), /*!< pll3_sw_clk mux name */
kCLOCK_PeriphMux = CCM_TUPLE(CBCDR,
CCM_CBCDR_PERIPH_CLK_SEL_SHIFT,
CCM_CBCDR_PERIPH_CLK_SEL_MASK,
CCM_CDHIPR_PERIPH_CLK_SEL_BUSY_SHIFT), /*!< periph mux name */
kCLOCK_SemcAltMux = CCM_TUPLE(CBCDR,
CCM_CBCDR_SEMC_ALT_CLK_SEL_SHIFT,
CCM_CBCDR_SEMC_ALT_CLK_SEL_MASK,
CCM_NO_BUSY_WAIT), /*!< semc mux name */
kCLOCK_SemcMux = CCM_TUPLE(
CBCDR, CCM_CBCDR_SEMC_CLK_SEL_SHIFT, CCM_CBCDR_SEMC_CLK_SEL_MASK, CCM_NO_BUSY_WAIT), /*!< semc mux name */
kCLOCK_PrePeriphMux = CCM_TUPLE(CBCMR,
CCM_CBCMR_PRE_PERIPH_CLK_SEL_SHIFT,
CCM_CBCMR_PRE_PERIPH_CLK_SEL_MASK,
CCM_NO_BUSY_WAIT), /*!< pre-periph mux name */
kCLOCK_TraceMux = CCM_TUPLE(
CBCMR, CCM_CBCMR_TRACE_CLK_SEL_SHIFT, CCM_CBCMR_TRACE_CLK_SEL_MASK, CCM_NO_BUSY_WAIT), /*!< trace mux name */
kCLOCK_PeriphClk2Mux = CCM_TUPLE(CBCMR,
CCM_CBCMR_PERIPH_CLK2_SEL_SHIFT,
CCM_CBCMR_PERIPH_CLK2_SEL_MASK,
CCM_NO_BUSY_WAIT), /*!< periph clock2 mux name */
}
以上通过名字就可以设置,可以通过如下设置将 PERIPH CLK 的时钟选择为 PERIPH_CLK2__CLK。
//设置 PERIPH_CLK 为 PERIPH_CLK2=24MHz
CLOCK_SetMux(kCLOCK_PeriphMux, 1);
CLOCK_SetDiv()
Div 是单词 Division 的缩写,意思是分频,所以这个函数是用来设置时钟分频的。
- 这里是设置 AHB_CLK_ROOT 时钟频率的,此时钟是对 PERIPH CLK 进行分频得来的,由 CCM→CBCDR 的 AHB_PODF 位控制
可以看出 AHB_PODF 可设置的值为:0~7,分别对应 1~8 分频,假设 PERIPH CLK此时为600M,那么设置AHB_PODF位为0,也就是一分频,AHB_CLK_ROOT就为600M。
static inline void CLOCK_SetDiv(clock_div_t divider, uint32_t value)
此函数有两个参数:divider 和 value,divider 用来指定要设置的是哪个时钟的分频值,value明显的就是要设置的分频值。
- divider 是 clock_div_t 类型的,clock_div_t 同样是个枚举类型,枚
举出了所有可以分频的时钟,在文件 fsl_clock.h 中有如下定义
typedef enum _clock_div
{
kCLOCK_ArmDiv = CCM_TUPLE(
CACRR, CCM_CACRR_ARM_PODF_SHIFT, CCM_CACRR_ARM_PODF_MASK, CCM_CDHIPR_ARM_PODF_BUSY_SHIFT), /*!< core div name */
kCLOCK_PeriphClk2Div = CCM_TUPLE(CBCDR,
CCM_CBCDR_PERIPH_CLK2_PODF_SHIFT,
CCM_CBCDR_PERIPH_CLK2_PODF_MASK,
CCM_NO_BUSY_WAIT), /*!< periph clock2 div name */
kCLOCK_SemcDiv = CCM_TUPLE(CBCDR,
CCM_CBCDR_SEMC_PODF_SHIFT,
CCM_CBCDR_SEMC_PODF_MASK,
CCM_CDHIPR_SEMC_PODF_BUSY_SHIFT), /*!< semc div name */
kCLOCK_AhbDiv = CCM_TUPLE(
CBCDR, CCM_CBCDR_AHB_PODF_SHIFT, CCM_CBCDR_AHB_PODF_MASK, CCM_CDHIPR_AHB_PODF_BUSY_SHIFT), /*!< ahb div name */
kCLOCK_IpgDiv =
CCM_TUPLE(CBCDR, CCM_CBCDR_IPG_PODF_SHIFT, CCM_CBCDR_IPG_PODF_MASK, CCM_NO_BUSY_WAIT), /*!< ipg div name */
}
如果要设置 AHB_CLK_ROOT 的时钟分频的话就可以使用如下代码:
//AHB PODF 1 分频,可选择 0~7 分别对应 1~8 分频,
CLOCK_SetDiv(kCLOCK_AhbDiv,0);
CLOCK_InitXXXPll() 函数
CLOCK_InitXXXPll 里面的 XXX 表示其他字母,看名字里面有个 Pll,那么基本可以猜出这一系列函数是用来设置 PLL 的,前面说了,RT1052 一共 7 个 PLL,所以有七个这样的函数。
以表中设置 PLL1 的函数 CLOCK_InitArmPll 为例,主时钟图③处就是设置 ARM PLL(PLL1),通过这个 PLL 可以将输入时钟(一般为 24M)倍频到一个比较高的频率。
- 具体是通过 CCM_ANALOG→PLL_ARM 寄存器的 DIV_SELECT 位设置,取值范围:54~108。
- PLL 输出频 率 = 输 入 频 率 *div_select/2 。 因 此 函 数 CLOCK_InitArmPll 最 终 肯 定 是 会 操 作CCM_ANALOG→PLL_ARM 寄存器的,自行查看函数 CLOCK_InitArmPll 源码,里面就是操作的 CCM_ANALOG→PLL_ARM 寄存器。
CLOCK_InitSysPfd()和 和 CLOCK_InitUsb1Pfd 函数
这两个函数是分别来设置 PLL2 和 PLL3 的 PFD 时钟频率的, PLL2和 PLL3 各有 4 个 PFD,总共 8 个。这 8 个 PFD 就通过函数 CLOCK_InitSysPfd 和CLOCK_InitUsb1Pfd 来设置。
CLOCK_EnableClock() 和 CLOCK_DisableClock()
为了降低系统功耗,RT1052 是可以单独开关指定外设时钟的。通过设置 CCM→CCGR0~CCGR6 这 7 个寄存器中指定的位来开关指定外设 的 时 钟 , FSL 库 提 供 了 两 个 函 数 来 实 现 这 个 功 能 : CLOCK_EnableClock 和
CLOCK_DisableClock,前者打开指定外设的时钟,后者关闭指定外设的时钟
static inline void CLOCK_EnableClock(clock_ip_name_t name)
static inline void CLOCK_DisableClock(clock_ip_name_t name)
这两个函数都只有一个参数 name,这个参数就是用来指定要开关哪个外设的时钟。
- 参数name 是个枚举类型,类型为 clock_ip_name_t,此类型枚举出了所有可以设置外设时钟的外设,在文件 fsl_clock.h 中有如下定义
比如我们要开关串口 LPUART1 的时钟,那么就可以使用如下代码:
CLOCK_EnableClock(kCLOCK_Lpuart1); //打开 LPUART1 时钟
CLOCK_DisableClock (kCLOCK_Lpuart1); //关闭 LPUART1 时钟
SystemCoreClockUpdate 函数
FSL库里面提供了一个全局变量来记录系统内核时钟频率,这个变量就是SystemCoreClock,在文件 system_MIMXRT1052.c 中有如下定义:
#define DEFAULT_SYSTEM_CLOCK 528000000UL //默认值
uint32_t SystemCoreClock = DEFAULT_SYSTEM_CLOCK;
SystemCoreClock 默认为 DEFAULT_SYSTEM_CLOCK,DEFAULT_SYSTEM_CLOCK 是个宏,在 system_MIMXRT1052.h 中定义为 528000000UL,也就是说默认为 528M。
- 但是我们要把内核时钟设置为其他值,比如 600M,因此变量 SystemCoreClock 要根据我们的设置同步的更新。
- 这个更新变量 SystemCoreClock 的功能就是函数 SystemCoreClockUpdate()来完成的。