This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

[参考译文] LP-MSPM0G3507:在 SDK 中设置 PLL 参数

Guru**** 2482105 points
Other Parts Discussed in Thread: SYSCONFIG

请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

https://e2e.ti.com/support/microcontrollers/msp-low-power-microcontrollers-group/msp430/f/msp-low-power-microcontroller-forum/1251378/lp-mspm0g3507-setting-pll-parameters-in-the-sdk

器件型号:LP-MSPM0G3507
主题中讨论的其他器件:SysConfig

您好、在 SDK 中设置 PLL 参数是什么可以接受的方法。 具体来说、各种输入频率的 PLL 参数位于存储器的出厂设置区域、因此需要复制。 对于40MHz 输入频率、我可以

#define HWREGW(x) (*((volatile uint32_t *)(x)))
  SYSCTL->SOCLOCK.SYSPLLPARAM0=HWREGW(0x41C40034); // f_LOOPIN = 40MHz    
  SYSCTL->SOCLOCK.SYSPLLPARAM1=HWREGW(0x41C40038); // f_LOOPIN = 40MHz

但那是使用原始内存读取、我已经定义了如何操作;并且在代码中具有原始地址。

现在、0x41c40034我可以使用 DL_SYSCTL_SYSPLL_INPUT_FREQ_32_48_MHZ 抽象出来

0x41c40038我能做的最好的事情是 DL_SYSCTL_SYSPLL_INPUT_FREQ_32_48_MHZ + 4 ;这是丑陋的地狱...

那么、SDK 中 TI 首选的编码风格是什么呢?

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    尊敬的 David:
    TI 的原始值(地址、常量等)格式是为每个值使用独立的名称、作为用于0x41C40034的名称。 此外、TI 建议使用 Driverlib 编码。

    此致、
    迭戈·阿巴德

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    让我更详细地解释一下。 source/ti/driverlib 中的 SDK 1_10_00_5包含文件 dl_sysctl_mspm0g1x0x_g3x0x.h。

    此文件包含:

    /** @enum DL_SYSCTL_SYSPLL_INPUT_FREQ */
    typedef enum {
        /*! PLL feedback loop input clock frequency [4MHz, 8MHz) */
        DL_SYSCTL_SYSPLL_INPUT_FREQ_4_8_MHZ = 0x41C4001C,
        /*! PLL feedback loop input clock frequency [8MHz, 16MHz) */
        DL_SYSCTL_SYSPLL_INPUT_FREQ_8_16_MHZ = 0x41C40024,
        /*! PLL feedback loop input clock frequency [16MHz, 32MHz) */
        DL_SYSCTL_SYSPLL_INPUT_FREQ_16_32_MHZ = 0x41C4002C,
        /*! PLL feedback loop input clock frequency [32MHz, 48MHz] */
        DL_SYSCTL_SYSPLL_INPUT_FREQ_32_48_MHZ = 0x41C40034,
    } DL_SYSCTL_SYSPLL_INPUT_FREQ;
    

    并且内存中不对 SYSCTL SYSPLL 输入频率的出厂设置进行任何其他引用。 因此、我们的代码应该类似:

    uint32_t *sysctl_syspll_params[]=DL_SYSCTL_SYSPLL_INPUT_FREQ_32_48_MHZ;
    SYSCTL->SOCLOCK.SYSPLLPARAM0=sysctl_syspll_params[0]; // f_LOOPIN = 40MHz    
    SYSCTL->SOCLOCK.SYSPLLPARAM1=sysctl_syspll_params[1]; // f_LOOPIN = 40MHz

    或者、标头中是否应该有代码可将指针矢量设置为参数?

    或者该标头是否应包含 PARAM1的引用?

    或者用户是否有问题执行上述操作?

    或者、我们是否可以注意到 TRM slau846在第1.6.1.14节和15节中定义了工厂寄存器-它为这些常量提供了固定值。 因此、不需要读取存储器的因数寄存器区域、而是使用 TRM 中的值直接将 PARAM0和 PARAM1设置为32-48MHz 所需的值?

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    尊敬的 David:


    这绝对是你提议的后者。 TI 不建议修改 h 文件、因此如果您需要在寄存器级别修改模块、请在调用 SysConfig 后执行该操作。

    此致、
    迭戈·阿巴德

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    嗯、我最后说的是"或者我们是否可以注意到 TRM slau846在第1.6.1.14节和第15节工厂寄存器中定义了"、因此:

      SYSCTL->SOCLOCK.SYSPLLPARAM0=0x0005060a; // TRM slau846 1.6.1.14   
      SYSCTL->SOCLOCK.SYSPLLPARAM1=0x01000110; // TRM slau846 1.6.1.15

    现在

    uint32_t *sysctl_syspll_params[]=DL_SYSCTL_SYSPLL_INPUT_FREQ_32_48_MHZ;

    假设 param1和 param0之间恰好有4个字节、并且 TRM 没有显示此内容、但确实如此。

    所以这是一个问题,许多方式皮肤一只猫,但没有一个是好的。 他们都假设某件事-这不是一件伟大的事情做。

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    尊敬的 David:

    只是为了说明一下。 您是否要问您是否可以修改这些位、是否应该修改这些位、或者应在何处根据需要修改这些位以配置 PLL?  

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    它实际上是一个风格问题、而且可能是 SDK 中的一个风格问题。

    TRM 会清晰显示、它提示您可以从存储器的 FactoryRegion 中读取这些参数:

    #define HWREGW(x) (*((volatile uint32_t *)(x)))
      SYSCTL->SOCLOCK.SYSPLLPARAM0=HWREGW(0x41C40034); // f_LOOPIN = 40MHz    
      SYSCTL->SOCLOCK.SYSPLLPARAM1=HWREGW(0x41C40038); // f_LOOPIN = 40MHz

    或使用 TRM 中给出的参数值:

      SYSCTL->SOCLOCK.SYSPLLPARAM0=0x0005060a; // CapBEn=0 CapBOv=0 CPC=5 StUpELP=6 StELC=10  
      SYSCTL->SOCLOCK.SYSPLLPARAM1=0x01000110; // LFRC=1 LFRA=1 LFCA=16

    虽然这两个命令都可以为 TRM 提供正确的代码并且可以正确运行-但它们通过在代码中使用硬数字而不是隐藏在.h 文件中而被冻结。

    因此、开始的地方是在 PLL 的存储器映射区域中设置参数、我们在 SDK .h 文件中具有如下代码:

    typedef struct {
    ...
      __IO uint32_t SYSPLLPARAM0;                      /* !< (@ 0x00001128) SYSPLL PARAM0 (load from FACTORY region) */
      __IO uint32_t SYSPLLPARAM1;                      /* !< (@ 0x0000112C) SYSPLL PARAM1 (load from FACTORY region) */
    ...
    } SYSCTL_SOCLOCK_Regs;
    
    typedef struct {
    ...
      SYSCTL_SOCLOCK_Regs  SOCLOCK;                           /* !< (@ 0x00001000) SYSCTL SOCLOCK Region */
    ...
    } SYSCTL_Regs;
    
    static SYSCTL_Regs                              * const SYSCTL                         = ((SYSCTL_Regs *) SYSCTL_BASE);
    
     

    因此设置了一个指向一个结构的指针、该结构映射到 PLL 的存储器映射区域、具体而言是设置了 ah -并且通过搜索代码刚刚找到答案、有一个类似的针对出厂寄存器的存储器设置的映射。 所以可以:

      SYSCTL->SOCLOCK.SYSPLLPARAM0=FACTORYREGION->PLLSTARTUP0_32_48MHZ; // f_LOOPIN = 40MHz    
      SYSCTL->SOCLOCK.SYSPLLPARAM1=FACTORYREGION->PLLSTARTUP1_32_48MHZ; // f_LOOPIN = 40MHz

    我漏掉了文件 hw_factoryregion.h、

    这优于使用 uint32_t [2]矢量,因为在哪里两个寄存器被定义为矢量,它们只是存储器中碰巧相邻的两个 uint32_t。

    唯一的遗憾与上述(并尚未编译以检查),但它可能需要大约6个 CPU 周期来执行上述复制,由于加载的区域地址到寄存器,然后在区域中做位置偏移..

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    而只是关闭它(主要是为了我的信息)。 执行上述代码(gcc -O2)所需的周期:

    1) 1) SYSCTL 的基址已位于寄存器中:0个周期
    2) 2) FACTORYREGION 的基址需要加载到寄存器中:1个周期
    3) SYSCTL 中 SOCLOCK.SYSPLLPARM*的偏移量较大,因此需要加载到寄存器中:2个周期
    4) FACTORYREGION 偏移很小,所以可以包含在负载操作中。 因此加载:2个周期
    5) 5)可以使用上述寄存器将内容保存到 SYSCTL 中:2个周期

    因此、总共(以 gcc 为单位)其7个周期。 该代码在启动时仅运行一次、因此速度不是问题。 如果我们使用了原始存储器地址、那么每个操作将需要2个周期(加载地址、加载/保存值)-因此需要8个周期、如此之慢。 这个操作在这里有用、它是通过一个小偏移来读取/保存的;所以 FACTORYREGION 读取非常快(总共3个周期)。 如果我们可以以类似的方式执行 SYSCTL (例如 address off SYSCTL->SOCLOCK;and offset from here)、那么可能能够将这减少到6个周期。

    因此、上述实现、尽管是几个周期、但实际上不能有太多改进。  

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    此外、为了闭合提出的点、您可以使用指向 SOCLOCK 的指针加快 SYSCTL 的读取速度。 昨晚实施了,它结束了。

    因此请更改代码:

      SYSCTL->SOCLOCK.SYSPLLPARAM0=FACTORYREGION->PLLSTARTUP0_32_48MHZ; // f_LOOPIN = 40MHz    
      SYSCTL->SOCLOCK.SYSPLLPARAM1=FACTORYREGION->PLLSTARTUP1_32_48MHZ; // f_LOOPIN = 40MHz
    

      SYSCTL_SOCLOCK_Regs *soclock=&(SYSCTL->SOCLOCK);
    
      soclock->SYSPLLPARAM0=FACTORYREGION->PLLSTARTUP0_32_48MHZ; // f_LOOPIN = 40MHz    
      soclock->SYSPLLPARAM1=FACTORYREGION->PLLSTARTUP1_32_48MHZ; // f_LOOPIN = 40MHz
    

    现在、在第二个优先的地方、是设置 Soclock 的指针、这一切都在编译器中完成-因此可执行文件中只保存了 Soclock 的地址。 在这里它再次赢,是当设置时钟, Soclock 被使用了很多-所以你可以使用这个指针到处.

    但它提供更小、更快的代码吗、它非常严格、是可能会少几个字节、并且可能更快、也可能不更快。 造成问题的是、SOCLOCK 结构非常大、或者说大约1024字节(没有确切的数字)。 现在是读取/写入偏移量到寄存器(指针)的拇指寻址模式、可放入汇编器的偏移量受代码的16位性质的限制、只有5位可用作偏移量; 这意味着只能进行最大124的偏移、并且它们必须按字对齐。 124的限制是问题-它远小于 SOCLOCK 的1024大小。 这意味着、要通过偏移量访问 SOCLOCK 中的大多数寄存器;根据经验、您必须将偏移量放在寄存器中并使用它。 如果需要将偏移加载到寄存器中、则需要额外花费一个周期。 这意味着、虽然优化确实会重新排列代码、但它的作用与左图类似 移位 我不太明白。 但其最重要的一行-改为具有 SoCLOCK 指针的代码、可能更易读、也可能不更小、并且可能运行速度更快。

    总之,它是您通常不会遇到的优化,除非设计非常严格,需要尝试。