
Update on 2021.1.3
最近为了驱动一块SPI通信的4.0寸TFT带触摸彩色屏幕,配置MSP432P401R的时钟抓破了头皮。我跑遍了各大论坛,总算找到了详细且能够使用的决办法。具体代码配置链接如下,方便大家查看,我也对代码进行了粘贴和注释处理:
http://dev.ti.com/tirex/explore/node?node=AIt11.GE8nvJkpoVjCiItQz-lQYNjLATEST 官方配置例程
//******************************************************************************// MSP432P401 Demo - Device configuration for operation @ MCLK = DCO = 48MHz//// Description: Proper device configuration to enable operation at MCLK=48MHz// including:// 1. Configure VCORE level to 1// 2. Configure flash wait-state to 1// 3. Configure DCO frequency to 48MHz// 4. Ensure MCLK is sourced by DCO//// After configuration is complete, MCLK is output to port pin P4.3.//// MSP432P401x// -----------------// /|\| |// | | |// --|RST |// | P4.3|----> MCLK// | |//// William Goh// Texas Instruments Inc.// June 2016 (updated) | November 2013 (created)// Built with CCSv6.1, IAR, Keil, GCC//******************************************************************************#include "ti/devices/msp432p4xx/inc/msp.h"#include "stdint.h"void error(void);int main(void){volatile uint32_t i;uint32_t currentPowerState;WDT_A->CTL = WDT_A_CTL_PW |WDT_A_CTL_HOLD; // Stop WDTP1->DIR |= BIT0; // P1.0 set as output/* NOTE: This example assumes the default power state is AM0_LDO.* Refer to msp432p401x_pcm_0x code examples for more complete PCM* operations to exercise various power state transitions between active* modes.*//* Step 1: Transition to VCORE Level 1: AM0_LDO --> AM1_LDO *//* Get current power state, if it's not AM0_LDO, error out */currentPowerState = PCM->CTL0 & PCM_CTL0_CPM_MASK;if (currentPowerState != PCM_CTL0_CPM_0)error();while ((PCM->CTL1 & PCM_CTL1_PMR_BUSY));PCM->CTL0 = PCM_CTL0_KEY_VAL | PCM_CTL0_AMR_1;while ((PCM->CTL1 & PCM_CTL1_PMR_BUSY));if (PCM->IFG & PCM_IFG_AM_INVALID_TR_IFG)error(); // Error if transition was not successfulif ((PCM->CTL0 & PCM_CTL0_CPM_MASK) != PCM_CTL0_CPM_1)error(); // Error if device is not in AM1_LDO mode/* Step 2: Configure Flash wait-state to 1 for both banks 0 & 1 */FLCTL->BANK0_RDCTL = (FLCTL->BANK0_RDCTL & ~(FLCTL_BANK0_RDCTL_WAIT_MASK)) |FLCTL_BANK0_RDCTL_WAIT_1;FLCTL->BANK1_RDCTL = (FLCTL->BANK0_RDCTL & ~(FLCTL_BANK1_RDCTL_WAIT_MASK)) |FLCTL_BANK1_RDCTL_WAIT_1;/* Step 3: Configure DCO to 48MHz, ensure MCLK uses DCO as source*/CS->KEY = CS_KEY_VAL ; // Unlock CS module for register accessCS->CTL0 = 0; // Reset tuning parametersCS->CTL0 = CS_CTL0_DCORSEL_5; // Set DCO to 48MHz/* Select MCLK = DCO, no divider */CS->CTL1 = (CS->CTL1 & ~(CS_CTL1_SELM_MASK | CS_CTL1_DIVM_MASK)) |CS_CTL1_SELM_3;CS->KEY = 0; // Lock CS module from unintended accesses/* Step 4: Output MCLK to port pin to demonstrate 48MHz operation */P4->DIR |= BIT3;P4->SEL0 |=BIT3; // Output MCLKP4->SEL1 &= ~(BIT3);while (1) // continuous loop{P1->OUT ^= BIT0; // Blink P1.0 LEDfor (i = 200000; i > 0; i--); // Delay}}void error(void){volatile uint32_t i;while (1){P1->OUT ^= BIT0;for(i = 20000; i > 0; i--); // Blink LED forever}}
以上是官方的历程,英文有点晦涩,配合具体配置步骤,我加入了自己的翻译:
// Description: Proper device configuration to enable operation at MCLK=48MHz// including:// 1. Configure VCORE level to 1// 2. Configure flash wait-state to 1// 3. Configure DCO frequency to 48MHz// 4. Ensure MCLK is sourced by DCO
官方原文提到,如果想要将MSP432P401R主频飙至48MHz,必须包括以下4个步骤,先不管它具体内部的原理是怎样的,翻译就完了=_=:
- 配置电压核心水平等级到1
- 配置Flash等待状态到1
- 配置数控时钟振荡频率到48MHz
- 确保主时钟MCLK的时钟源来自DCO
步骤一:配置电压核心水平等级到1
官方的历程中引入了P1.0作为电压等级是否配置完成的提示标志,如果配置不成功,将会执行错误自定义函数,其中变量currentPowerState用来获取当前电压等级,如果此时没有处在AM0_LDO, 将会执行error函数,error函数中主要执行的内容是进行LED闪烁报警,提示用户电压等级目前配置异常。仔细想了一下其中LED的报警对我的项目没有实质性的作用,不出意外肯定能够配置成功,所以此处不严谨地把LED地报警代码删除了。currentPowerState = PCM->CTL0 & PCM_CTL0_CPM_MASK;//获取电压状态语句if (currentPowerState != PCM_CTL0_CPM_0) error();//判断MSP432P401R的电压等级现在是否是AM0_LDO,如果此时没有处在AM0_LDO, 将会执行error函数,提示用户电压等级目前配置异常。while ((PCM->CTL1 & PCM_CTL1_PMR_BUSY));//判断此时电源模式转换是否忙,忙的话执行空循环,直到电源模式转换完成PCM->CTL0 = PCM_CTL0_KEY_VAL | PCM_CTL0_AMR_1;while ((PCM->CTL1 & PCM_CTL1_PMR_BUSY));//判断此时电源模式转换是否忙,忙的话执行空循环,直到电源模式转换完成if (PCM->IFG & PCM_IFG_AM_INVALID_TR_IFG)error(); // Error if transition was not successfulif ((PCM->CTL0 & PCM_CTL0_CPM_MASK) != PCM_CTL0_CPM_1)error(); // Error if device is not in AM1_LDO mode
其中PCM是个什么东西??
找到官方的Datasheet【MSP432P401R, MSP432P401M SimpleLink™ Mixed-Signal Microcontrollers datasheet (Rev. H)】的第121页提到PCM(Power Control Manager)控制设备的工作模式和模式之间的切换。这是由应用程序控制的,它可以选择模式来满足其功率和性能要求。
在参数手册【MSP432P4xx SimpleLink™ Microcontrollers Technical Reference Manual (Rev. I)】中详细给出了PCM(Power Control Manager)的各个控制寄存器,具体内容如下:

CPM(Current Power Mode)电源模式。这些位反映当前电源模式,并将在电源模式请求完成后更新。
PMR_BUSY(Power mode request busy flag)。电源模式请求忙位。此标志是在处理功率更改请求时设置的。当请求完成时,标志将被清除。清楚了这些寄存器表示的功能后,再对官方的代码进行注释。
PCMKEY(Current Power Mode KEY)。参数手册的解释是必须编写适当的密钥以允许对PMR的写访问。任何不正确的密钥都不允许写入PMR,也不会生成功率更改请求。PCMCTL0和PCMCTL1都有PCMKEY位。
AMR(Active Mode Request)。用于请求活动模式。只有当PCMCTL1的PMR_BUSY = 0时,才能修改这些位。
接下来是PCMIFG(PCM Interrupt Flag Register),电源控制管理中断标志寄存器。
LPM_INVALID_TR_IFG(LPM invalid transition flag),如果请求的活动模式到LPM3的转换无效,则设置此标志。标志将保持设置,直到软件清除。简单的理解就是转换不成功将会把这个标志变量置1。
步骤二:配置Flash等待状态到1
//将存储体0和1的Flash等待状态都配置为1FLCTL->BANK0_RDCTL = (FLCTL->BANK0_RDCTL & ~(FLCTL_BANK0_RDCTL_WAIT_MASK)) | FLCTL_BANK0_RDCTL_WAIT_1;FLCTL->BANK1_RDCTL = (FLCTL->BANK0_RDCTL & ~(FLCTL_BANK1_RDCTL_WAIT_MASK)) | FLCTL_BANK1_RDCTL_WAIT_1;
Flash等待状态?????What are you talking about??为什么要配置??这有什么关系么??在【MSP432P4xx SimpleLink™ Microcontrollers Technical Reference Manual (Rev. I)】参数手册中,官方做出了如下解释:
FLCTL(Flash Controller)闪存是字节、字(4字节)和全字(16字节)可寻址和可编程的。flash控制器是软件(应用程序)与设备上flash存储器所支持的各种功能之间的控制和访问接口,一堆废话是不是。。。。。
接下来我们看看代码中提到的具体寄存器地详细信息:

在该页的底部,有不起眼的小字,但是它非常重要,具体翻译如下:
- 读取所需的等待状态的数量取决于总线时钟频率和读取模式。
- 如果总线时钟频率被更改为更高的值,则由应用程序负责确保在频率更改之前更改等待状态值。如果没有执行这个命令,设备的行为就不是确定的。
- 只有FLCTL_RDBRST_CTLSTAT的burst status(17:16)显示为Idle状态时,该字段才可写。在所有其他情况下,位保持锁定状态,以不中断正在进行的操作。
简单地来说就是时钟频率很高时,这个Flash的状态必须要提高,因为不更改Flash的状态的话,设备的运行状态将会不确定。
步骤三:配置数控时钟振荡频率到48MHz
//步骤3:将DCO配置为48MHz,确保MCLK使用DCO作为源CS->KEY = CS_KEY_VAL ; // 解锁CS模块以进行寄存器访问CS->CTL0 = 0; // 重置调整参数CS->CTL0 = CS_CTL0_DCORSEL_5; // Set DCO to 48MHz/* Select MCLK =SMCLK= DCO=48MHz, no divider */CS->CTL1 = CS_CTL1_SELS_3 | CS_CTL1_SELM_3;CS->KEY = 0; // 锁定CS模块以防止意外访问

CSKEY(Clock Status Key)时钟状态密匙:Write CSKEY = xxxx_695Ah解锁CS寄存器。所有16个lsb需要一起编写。使用任何其他值写入CSKEY会导致CS寄存器被锁定,对这些寄存器的任何写操作都会被忽略,而读操作仍然被执行。总是回读A596h。
简单地来说,只有输入密匙正确才能够对CS寄存器进行配置。

解锁CS寄存器后,接下来将DCO的时钟配置到48MHz的区间段。
CS->CTL0 = CS_CTL0_DCORSEL_5;
接下来将MCLK,SMCLK的时钟源配置为DCO=48MHz的时钟运行。
CS->CTL1 = CS_CTL1_SELS_3 | CS_CTL1_SELM_3;CS->KEY = 0; // 锁定CS模块以防止意外访问
步骤四:确保主时钟MCLK的时钟源来自DCO
确保MCLK时钟是否来自DCO=48MHz最快速的方法是运用MSP432P401R的引脚复用功能,将IO引脚复用作为MCLK的时钟输出。查阅官方参数手册【MSP432P401R, MSP432P401M SimpleLink™ Mixed-Signal Microcontrollers datasheet (Rev. H)】的第150页的引脚配置表格如下:



P4DIR |= BIT3; //将P4.3作为MCLK的输出引脚P4SEL0 |= BIT3;P4SEL1 &= ~BIT3;
当然Px口的寄存器不止这些,只是本次项目只用到了这些寄存器而已。根据程序,首先P4.3设置为输出,将P4SEL0的第3位置1,将P4SEL1的第3位置0,这样一来,上电运行后P4.3就会输出48MHz时钟,不信??见下图:
示波器采用正点原子DS100,50M带宽,250M采样率,可以观察到手持示波器显示的是48MHz,时钟配置正确,MCLK确实是运行在48MHz上的。
以下给出我消化官方的例子后精简的代码,已经去除LED的时钟配置异常报警,因为这个几乎不会出现,干脆就删了,嘿嘿。经过烧录,完全有效:
#include "ti/devices/msp432p4xx/inc/msp.h"void system_clk_init() //将运行频率锁定在48MHz,开启步骤原因详见:http://dev.ti.com/tirex/explore/node?node=AIt11.GE8nvJkpoVjCiItQ__z-lQYNj__LATEST{P4DIR |= BIT3; //将P4.3作为MCLK的输出引脚P4SEL0 |= BIT3;P4SEL1 &= ~BIT3;while ((PCM->CTL1 & PCM_CTL1_PMR_BUSY));//判断此时电源模式转换是否忙,忙的话执行空循环,直到电源模式转换完成PCM->CTL0 = PCM_CTL0_KEY_VAL | PCM_CTL0_AMR_1;while ((PCM->CTL1 & PCM_CTL1_PMR_BUSY));//判断此时电源模式转换是否忙,忙的话执行空循环,直到电源模式转换完成//将存储体0和1的Flash等待状态都配置为1FLCTL->BANK0_RDCTL = (FLCTL->BANK0_RDCTL & ~(FLCTL_BANK0_RDCTL_WAIT_MASK)) | FLCTL_BANK0_RDCTL_WAIT_1;FLCTL->BANK1_RDCTL = (FLCTL->BANK0_RDCTL & ~(FLCTL_BANK1_RDCTL_WAIT_MASK)) | FLCTL_BANK1_RDCTL_WAIT_1;//步骤3:将DCO配置为48MHz,确保MCLK使用DCO作为源CS->KEY = CS_KEY_VAL ; // 解锁CS模块以进行寄存器访问CS->CTL0 = 0; // 重置调整参数CS->CTL0 = CS_CTL0_DCORSEL_5; // Set DCO to 48MHz/* Select MCLK =SMCLK= DCO=48MHz, no divider */CS->CTL1 = CS_CTL1_SELS_3 | CS_CTL1_SELM_3;CS->KEY = 0; // 锁定CS模块以防止意外访问}


