MSP432P401R主频飙至48MHz - 图1
Update on 2021.1.3
最近为了驱动一块SPI通信的4.0寸TFT带触摸彩色屏幕,配置MSP432P401R的时钟抓破了头皮。我跑遍了各大论坛,总算找到了详细且能够使用的决办法。具体代码配置链接如下,方便大家查看,我也对代码进行了粘贴和注释处理:
http://dev.ti.com/tirex/explore/node?node=AIt11.GE8nvJkpoVjCiItQz-lQYNjLATEST 官方配置例程

  1. //******************************************************************************
  2. // MSP432P401 Demo - Device configuration for operation @ MCLK = DCO = 48MHz
  3. //
  4. // Description: Proper device configuration to enable operation at MCLK=48MHz
  5. // including:
  6. // 1. Configure VCORE level to 1
  7. // 2. Configure flash wait-state to 1
  8. // 3. Configure DCO frequency to 48MHz
  9. // 4. Ensure MCLK is sourced by DCO
  10. //
  11. // After configuration is complete, MCLK is output to port pin P4.3.
  12. //
  13. // MSP432P401x
  14. // -----------------
  15. // /|\| |
  16. // | | |
  17. // --|RST |
  18. // | P4.3|----> MCLK
  19. // | |
  20. //
  21. // William Goh
  22. // Texas Instruments Inc.
  23. // June 2016 (updated) | November 2013 (created)
  24. // Built with CCSv6.1, IAR, Keil, GCC
  25. //******************************************************************************
  26. #include "ti/devices/msp432p4xx/inc/msp.h"
  27. #include "stdint.h"
  28. void error(void);
  29. int main(void)
  30. {
  31. volatile uint32_t i;
  32. uint32_t currentPowerState;
  33. WDT_A->CTL = WDT_A_CTL_PW |
  34. WDT_A_CTL_HOLD; // Stop WDT
  35. P1->DIR |= BIT0; // P1.0 set as output
  36. /* NOTE: This example assumes the default power state is AM0_LDO.
  37. * Refer to msp432p401x_pcm_0x code examples for more complete PCM
  38. * operations to exercise various power state transitions between active
  39. * modes.
  40. */
  41. /* Step 1: Transition to VCORE Level 1: AM0_LDO --> AM1_LDO */
  42. /* Get current power state, if it's not AM0_LDO, error out */
  43. currentPowerState = PCM->CTL0 & PCM_CTL0_CPM_MASK;
  44. if (currentPowerState != PCM_CTL0_CPM_0)
  45. error();
  46. while ((PCM->CTL1 & PCM_CTL1_PMR_BUSY));
  47. PCM->CTL0 = PCM_CTL0_KEY_VAL | PCM_CTL0_AMR_1;
  48. while ((PCM->CTL1 & PCM_CTL1_PMR_BUSY));
  49. if (PCM->IFG & PCM_IFG_AM_INVALID_TR_IFG)
  50. error(); // Error if transition was not successful
  51. if ((PCM->CTL0 & PCM_CTL0_CPM_MASK) != PCM_CTL0_CPM_1)
  52. error(); // Error if device is not in AM1_LDO mode
  53. /* Step 2: Configure Flash wait-state to 1 for both banks 0 & 1 */
  54. FLCTL->BANK0_RDCTL = (FLCTL->BANK0_RDCTL & ~(FLCTL_BANK0_RDCTL_WAIT_MASK)) |
  55. FLCTL_BANK0_RDCTL_WAIT_1;
  56. FLCTL->BANK1_RDCTL = (FLCTL->BANK0_RDCTL & ~(FLCTL_BANK1_RDCTL_WAIT_MASK)) |
  57. FLCTL_BANK1_RDCTL_WAIT_1;
  58. /* Step 3: Configure DCO to 48MHz, ensure MCLK uses DCO as source*/
  59. CS->KEY = CS_KEY_VAL ; // Unlock CS module for register access
  60. CS->CTL0 = 0; // Reset tuning parameters
  61. CS->CTL0 = CS_CTL0_DCORSEL_5; // Set DCO to 48MHz
  62. /* Select MCLK = DCO, no divider */
  63. CS->CTL1 = (CS->CTL1 & ~(CS_CTL1_SELM_MASK | CS_CTL1_DIVM_MASK)) |
  64. CS_CTL1_SELM_3;
  65. CS->KEY = 0; // Lock CS module from unintended accesses
  66. /* Step 4: Output MCLK to port pin to demonstrate 48MHz operation */
  67. P4->DIR |= BIT3;
  68. P4->SEL0 |=BIT3; // Output MCLK
  69. P4->SEL1 &= ~(BIT3);
  70. while (1) // continuous loop
  71. {
  72. P1->OUT ^= BIT0; // Blink P1.0 LED
  73. for (i = 200000; i > 0; i--); // Delay
  74. }
  75. }
  76. void error(void)
  77. {
  78. volatile uint32_t i;
  79. while (1)
  80. {
  81. P1->OUT ^= BIT0;
  82. for(i = 20000; i > 0; i--); // Blink LED forever
  83. }
  84. }

以上是官方的历程,英文有点晦涩,配合具体配置步骤,我加入了自己的翻译:

  1. // Description: Proper device configuration to enable operation at MCLK=48MHz
  2. // including:
  3. // 1. Configure VCORE level to 1
  4. // 2. Configure flash wait-state to 1
  5. // 3. Configure DCO frequency to 48MHz
  6. // 4. Ensure MCLK is sourced by DCO

官方原文提到,如果想要将MSP432P401R主频飙至48MHz,必须包括以下4个步骤,先不管它具体内部的原理是怎样的,翻译就完了=_=:

  1. 配置电压核心水平等级到1
  2. 配置Flash等待状态到1
  3. 配置数控时钟振荡频率到48MHz
  4. 确保主时钟MCLK的时钟源来自DCO

    步骤一:配置电压核心水平等级到1

    1. currentPowerState = PCM->CTL0 & PCM_CTL0_CPM_MASK;//获取电压状态语句
    2. if (currentPowerState != PCM_CTL0_CPM_0) error();//判断MSP432P401R的电压等级现在是否是AM0_LDO,如果此时没有处在AM0_LDO, 将会执行error函数,提示用户电压等级目前配置异常。
    3. while ((PCM->CTL1 & PCM_CTL1_PMR_BUSY));//判断此时电源模式转换是否忙,忙的话执行空循环,直到电源模式转换完成
    4. PCM->CTL0 = PCM_CTL0_KEY_VAL | PCM_CTL0_AMR_1;
    5. while ((PCM->CTL1 & PCM_CTL1_PMR_BUSY));//判断此时电源模式转换是否忙,忙的话执行空循环,直到电源模式转换完成
    6. if (PCM->IFG & PCM_IFG_AM_INVALID_TR_IFG)
    7. error(); // Error if transition was not successful
    8. if ((PCM->CTL0 & PCM_CTL0_CPM_MASK) != PCM_CTL0_CPM_1)
    9. error(); // Error if device is not in AM1_LDO mode
    官方的历程中引入了P1.0作为电压等级是否配置完成的提示标志,如果配置不成功,将会执行错误自定义函数,其中变量currentPowerState用来获取当前电压等级,如果此时没有处在AM0_LDO, 将会执行error函数,error函数中主要执行的内容是进行LED闪烁报警,提示用户电压等级目前配置异常。仔细想了一下其中LED的报警对我的项目没有实质性的作用,不出意外肯定能够配置成功,所以此处不严谨地把LED地报警代码删除了。

其中PCM是个什么东西??

找到官方的Datasheet【MSP432P401R, MSP432P401M SimpleLink™ Mixed-Signal Microcontrollers datasheet (Rev. H)】的第121页提到PCM(Power Control Manager)控制设备的工作模式和模式之间的切换。这是由应用程序控制的,它可以选择模式来满足其功率和性能要求
MSP432P401R主频飙至48MHz - 图2
在参数手册【MSP432P4xx SimpleLink™ Microcontrollers Technical Reference Manual (Rev. I)】中详细给出了PCM(Power Control Manager)的各个控制寄存器,具体内容如下:
MSP432P401R主频飙至48MHz - 图3MSP432P401R主频飙至48MHz - 图4
CPM(Current Power Mode)电源模式。这些位反映当前电源模式,并将在电源模式请求完成后更新。
MSP432P401R主频飙至48MHz - 图5
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时,才能修改这些位。
MSP432P401R主频飙至48MHz - 图6
接下来是PCMIFG(PCM Interrupt Flag Register),电源控制管理中断标志寄存器。
LPM_INVALID_TR_IFG(LPM invalid transition flag),如果请求的活动模式到LPM3的转换无效,则设置此标志。标志将保持设置,直到软件清除。简单的理解就是转换不成功将会把这个标志变量置1。

步骤二:配置Flash等待状态到1

  1. //将存储体0和1的Flash等待状态都配置为1
  2. FLCTL->BANK0_RDCTL = (FLCTL->BANK0_RDCTL & ~(FLCTL_BANK0_RDCTL_WAIT_MASK)) | FLCTL_BANK0_RDCTL_WAIT_1;
  3. 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)】参数手册中,官方做出了如下解释:
MSP432P401R主频飙至48MHz - 图7
FLCTL(Flash Controller)闪存是字节、字(4字节)和全字(16字节)可寻址和可编程的。flash控制器是软件(应用程序)与设备上flash存储器所支持的各种功能之间的控制和访问接口,一堆废话是不是。。。。。
接下来我们看看代码中提到的具体寄存器地详细信息:
MSP432P401R主频飙至48MHz - 图8MSP432P401R主频飙至48MHz - 图9
在该页的底部,有不起眼的小字,但是它非常重要,具体翻译如下:

  1. 读取所需的等待状态的数量取决于总线时钟频率和读取模式。
  2. 如果总线时钟频率被更改为更高的值,则由应用程序负责确保在频率更改之前更改等待状态值。如果没有执行这个命令,设备的行为就不是确定的。
  3. 只有FLCTL_RDBRST_CTLSTAT的burst status(17:16)显示为Idle状态时,该字段才可写。在所有其他情况下,位保持锁定状态,以不中断正在进行的操作。

简单地来说就是时钟频率很高时,这个Flash的状态必须要提高,因为不更改Flash的状态的话,设备的运行状态将会不确定。

步骤三:配置数控时钟振荡频率到48MHz

  1. //步骤3:将DCO配置为48MHz,确保MCLK使用DCO作为源
  2. CS->KEY = CS_KEY_VAL ; // 解锁CS模块以进行寄存器访问
  3. CS->CTL0 = 0; // 重置调整参数
  4. CS->CTL0 = CS_CTL0_DCORSEL_5; // Set DCO to 48MHz
  5. /* Select MCLK =SMCLK= DCO=48MHz, no divider */
  6. CS->CTL1 = CS_CTL1_SELS_3 | CS_CTL1_SELM_3;
  7. CS->KEY = 0; // 锁定CS模块以防止意外访问

MSP432P401R主频飙至48MHz - 图10
CSKEY(Clock Status Key)时钟状态密匙:Write CSKEY = xxxx_695Ah解锁CS寄存器。所有16个lsb需要一起编写。使用任何其他值写入CSKEY会导致CS寄存器被锁定,对这些寄存器的任何写操作都会被忽略,而读操作仍然被执行。总是回读A596h。
简单地来说,只有输入密匙正确才能够对CS寄存器进行配置。
MSP432P401R主频飙至48MHz - 图11MSP432P401R主频飙至48MHz - 图12
解锁CS寄存器后,接下来将DCO的时钟配置到48MHz的区间段。

  1. CS->CTL0 = CS_CTL0_DCORSEL_5;

接下来将MCLK,SMCLK的时钟源配置为DCO=48MHz的时钟运行。

  1. CS->CTL1 = CS_CTL1_SELS_3 | CS_CTL1_SELM_3;
  2. CS->KEY = 0; // 锁定CS模块以防止意外访问

MSP432P401R主频飙至48MHz - 图13MSP432P401R主频飙至48MHz - 图14MSP432P401R主频飙至48MHz - 图15

步骤四:确保主时钟MCLK的时钟源来自DCO

确保MCLK时钟是否来自DCO=48MHz最快速的方法是运用MSP432P401R的引脚复用功能,将IO引脚复用作为MCLK的时钟输出。查阅官方参数手册【MSP432P401R, MSP432P401M SimpleLink™ Mixed-Signal Microcontrollers datasheet (Rev. H)】的第150页的引脚配置表格如下:
MSP432P401R主频飙至48MHz - 图16MSP432P401R主频飙至48MHz - 图17MSP432P401R主频飙至48MHz - 图18MSP432P401R主频飙至48MHz - 图19

  1. P4DIR |= BIT3; //将P4.3作为MCLK的输出引脚
  2. P4SEL0 |= BIT3;
  3. P4SEL1 &= ~BIT3;

当然Px口的寄存器不止这些,只是本次项目只用到了这些寄存器而已。根据程序,首先P4.3设置为输出,将P4SEL0的第3位置1,将P4SEL1的第3位置0,这样一来,上电运行后P4.3就会输出48MHz时钟,不信??见下图:
MSP432P401R主频飙至48MHz - 图20
示波器采用正点原子DS100,50M带宽,250M采样率,可以观察到手持示波器显示的是48MHz,时钟配置正确,MCLK确实是运行在48MHz上的。


以下给出我消化官方的例子后精简的代码,已经去除LED的时钟配置异常报警,因为这个几乎不会出现,干脆就删了,嘿嘿。经过烧录,完全有效:

  1. #include "ti/devices/msp432p4xx/inc/msp.h"
  2. void system_clk_init() //将运行频率锁定在48MHz,开启步骤原因详见:http://dev.ti.com/tirex/explore/node?node=AIt11.GE8nvJkpoVjCiItQ__z-lQYNj__LATEST
  3. {
  4. P4DIR |= BIT3; //将P4.3作为MCLK的输出引脚
  5. P4SEL0 |= BIT3;
  6. P4SEL1 &= ~BIT3;
  7. while ((PCM->CTL1 & PCM_CTL1_PMR_BUSY));//判断此时电源模式转换是否忙,忙的话执行空循环,直到电源模式转换完成
  8. PCM->CTL0 = PCM_CTL0_KEY_VAL | PCM_CTL0_AMR_1;
  9. while ((PCM->CTL1 & PCM_CTL1_PMR_BUSY));//判断此时电源模式转换是否忙,忙的话执行空循环,直到电源模式转换完成
  10. //将存储体0和1的Flash等待状态都配置为1
  11. FLCTL->BANK0_RDCTL = (FLCTL->BANK0_RDCTL & ~(FLCTL_BANK0_RDCTL_WAIT_MASK)) | FLCTL_BANK0_RDCTL_WAIT_1;
  12. FLCTL->BANK1_RDCTL = (FLCTL->BANK0_RDCTL & ~(FLCTL_BANK1_RDCTL_WAIT_MASK)) | FLCTL_BANK1_RDCTL_WAIT_1;
  13. //步骤3:将DCO配置为48MHz,确保MCLK使用DCO作为源
  14. CS->KEY = CS_KEY_VAL ; // 解锁CS模块以进行寄存器访问
  15. CS->CTL0 = 0; // 重置调整参数
  16. CS->CTL0 = CS_CTL0_DCORSEL_5; // Set DCO to 48MHz
  17. /* Select MCLK =SMCLK= DCO=48MHz, no divider */
  18. CS->CTL1 = CS_CTL1_SELS_3 | CS_CTL1_SELM_3;
  19. CS->KEY = 0; // 锁定CS模块以防止意外访问
  20. }