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.

[参考译文] EVM430-FR6043:避免 USS_initAlgorithms ()后续引导延迟、在 FRAM 中缓存配置数据

Guru**** 2315160 points
Other Parts Discussed in Thread: EVM430-FR6043
请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

https://e2e.ti.com/support/microcontrollers/msp-low-power-microcontrollers-group/msp430/f/msp-low-power-microcontroller-forum/1507600/evm430-fr6043-avoid-uss_initalgorithms-delay-in-subsequent-boots-cache-configuration-data-in-fram

器件型号:EVM430-FR6043

工具/软件:

大家好:

我正在设计基于 EVM430-FR6043的 OEM 气流表。 固件工作正常、测量正常、但我发现启动通常需要大约400ms、这对于"简单"的传感器来说是相当长的时间。 使用一些调试引脚输出和示波器、我能够将其与`USS_initAlgorithms()`函数联系起来、该函数在我的代码启动前执行、占用大部分初始化时间。

因为它只采用配置结构并命名为 init 来解决 (),我假设它实际上只是预先计算一些值,这些值肯定可以缓存到 FRAM 中,以便仅在 MCU 编程后第一次上电时才获得此延迟。 `_USS_SW_Library_configuration_`结构实际上已经包含一个`validationKey`字段、并且位于持久存储器(FRAM)中、因此该库在设计时就考虑到了这一点。

我尝试的是仅在没有有效密钥时运行一次初始化功能、并在所有后续引导中跳过初始化:

    if (gUssSWConfig.validationKey != CONFIG_VALIDATION_KEY) {
        code = USS_initAlgorithms(&gUssSWConfig);
        checkCode(code, USS_message_code_no_error);
        gUssSWConfig.validationKey = CONFIG_VALIDATION_KEY;
    }

这将成功跳过首次启动以外的每次启动中的初始化(以及延迟)、但也会中断应用程序。 在这种情况下、只要调用`uss_runAlgorithms()`、MCU 就会崩溃并重新启动。

我已经在运行`USS_initAlgorithms()`前后使用调试器检查了__no_init 内存缓冲区、以检查它是否在那里初始化一些数据、但没有发现变化。

我的问题:

  • `USS_initAlgorithms()`需要这么长时间?
  • 它修改了哪些未在 FRAM 中保留的数据?
  • 是否有方法可以使用所述的缓存方法或其他任何方法来消除此延迟?

谢谢!

此致、
Philipp

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

    您好、

    很抱歉晚回复。 我以前在度假。  

    您的想法看起来非常有趣和 实用。 我知道 `USS_initAlgorithms()`需要一些时间、但没有确切了解它需要多长时间。  

    大致检查 USS_initAlgorithms 中完成的操作。

    1.验证参数

    2.设置过滤器、算法参数等参数。

    3.调用 USS_init ()和 USS_updateClockRelativeError ()

    这些修改似乎仅发生在 FRAM 中。 但是有一个 USS_Lea_init ();在  USS_init ()内部调用,用于配置 LEA 外设。 如果添加此 USS_Lea_init()可以解决您的问题、您可以尝试添加此 USS_Lea_init()。  

    此致、

    现金好

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

    尊敬的 Cash Hao:

    感谢您的答复。 这听起来很有希望。 但是、我没有 USS_init ()和 USS_Lea_init ()的调用签名。 我的硬件当前正在使用中、因此我无法测试仅调用 USS_Lea_init (&gUssSWConfig)是否可以正常工作、但无论如何、我更希望拥有官方签名。 您能提供这个吗?

    此致、
    Philipp

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

    您好、

    您提供 正式签名的意思是什么?  

    此致、

    现金好

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

    尊敬的 Cash Hao:

    我只是指将放置在头文件中的函数的正确调用签名。 类似"USS_message_code USS_Lea_init (USS_SW_Library_configuration * config)"或类似内容。

    此致、
    Philipp

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

    您好、

    我可以向您发送下面的函数代码。  

    USS_FRAM_FUNCTION (USS_LEA_INIT)
    void USS_Lea_init (void)

    //初始化 LEA 寄存器
    LEACNF0 = LEALPR | LEAILPM;
    LEACNF1 = 0;
    LEACNF2 = LEAMT >> 2;
    LEAPMS1 = 0;
    LEAPMS0 = 0;
    LEAPMDST = 0;
    LEAPMCTL |= LEACMDEN;
    LEAIE |= LEAPMCMDIE;
    LEACMCTL = 0;
    USS_LEA_IFG = 0;

    返回;
    }

    此致、

    现金好

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

    尊敬的 Cash Hao:

    太棒了、谢谢! 我将在再次访问硬件后立即进行测试。

    此致、
    Philipp

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

    好的。  

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

    尊敬的 Cash Hao:

    我尝试了你的建议,但没有运气。 MCU 在编程后运行正常、但在重置后、当它跳过 USS_initAlgorithms()并且只运行 USS_Lea_init()时、它会在第一次调用 USS_runAlgorithms()时崩溃。 无论我是调用 USS 库中已有的 USS_Lea_init ()实现还是您发布的实现,都会发生这种情况。 因此必须缺少更多配置工作。

    我不知道在失败期间到底发生了什么。 我只是看到,当程序自由运行时,我们的应用程序不再工作,当我使用调试器单步执行它时,对 USS_runAlgorithmsFixedPoint ()的调用永远不会返回。 我没有更多的细节、因为下面的代码在编译的库中是完全不透明的。

    FWIW、这是我目前的实施方式:

    // This is where I would normally just call USS_initAlgorithms() unconditionally.
    
        if (gUssSWConfig.validationKey != CONFIG_VALIDATION_KEY) {
            code = USS_initAlgorithms(&gUssSWConfig);
            checkCode(code, USS_message_code_no_error);
            gUssSWConfig.validationKey = CONFIG_VALIDATION_KEY;
        } else {
            USS_lea_init();
        }
    

    还有其他想法吗?

    谢谢、此致、
    Philipp

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

    您好、

    获取反馈。  

    我将在下周在我的网站上进行调试、并检查我在这里可以找到的内容。  

    此致、

    现金好

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

    尊敬的 Cash Hao:

    是否对此有任何更新?

    此致、
    Philipp

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

    您好、

    很抱歉晚回复。  

    我在调用 USS_initAlgorithms()函数之前和之后读出了内存数据。  

    存储器的不同之处在于一些外设寄存器和 FRAM 配置。 RAM 部分没有差异。 根据这个结果、它应该能够绕过这一功能。 我没有更多关于这种行为的线索。  

    e2e.ti.com/.../before-inite2e.ti.com/.../after-init

    此致、

    现金好

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

    尊敬的 Cash Hao:

    调用之前和之后转储整个存储器内容肯定是一个好主意。 但是、在分析差异时、我不确定解释:

    • 在外设部分、我看到 SYS (0180h)、数字 I/O (0200h)、TA1 (0380h)、TA2 (0400h)、MPY32 (04C0h)的寄存器存在差异。 DMA (0500h)、LEA (0A80h)。 这使我相信转储不是在调用 USS_initAlgorithms()之前和之后立即获取的,但也显示了其他初始化工作。
    • 01860h 处的字节从0x00更改为0x76。 数据表中根本没有记录该位置、它将位于 BSL (ROM)和 TI 校准和配置数据(FRAM)之间。 你知道这可能是什么吗?
    • 如果我正确解释了数据表和链接器文件、2xxxh 范围中有相当多的更改、这个范围应该是系统(而不是 LEA) RAM。

    无论如何,我觉得只是转储整个内存调用前后相当有吸引力的想法,这应该可以跳过长初始化。 至少只要我能弄清楚一些变化属于哪个符号,这似乎已经是一个挑战。

    当我对当前代码执行同样的操作,并在调用 USS_initAlgorithms ()之前和之后立即停止调试器时,我得到了一些数据结构的差异,我无法在代码中找到:

    • gUSSAlgObject
    • gHilbertFilterConstant

    是否有任何关于这些符号、尤其是其大小的文档? 我当然可以在代码中引用它们、但如果没有它们的大小、在 FRAM 中保存和恢复它们会出现问题。

    谢谢、此致、
    Philipp

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

    尊敬的 Philipp:

    1.不知道什么保存在0x1860。 它可以是一个隐藏的寄存器、但我不知道它是什么。  

    2.哦,是的。 系统 RAM 有一些变化。 我以前只关注与 LEA 共享的 RAM。 init 函数会更改 RAM 中的一些参数。  

     gUSSAlgObject 从0x21A0到0x22AC

     gHilbertFilterConstant 从0x4F68开始到0x4F80

    此致、

    现金好

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

    尊敬的 Cash Hao:

    感谢您的意见。 我现在成功地使用以下代码进行了一个有效的设置:

    /*
     * A replacement for USS_initAlgorithms() that only runs the
     * full initialization during the first boot and then caches
     * the results in FRAM for faster subsequent boots.
     *
     * NOTE: The internal workings of the USS library are not
     * really documented and it needed some reverse engineering
     * to get this to work:
     * 1. Take full memory dump before USS_initAlgorithms()
     * 2. Take full memory dump after USS_initAlgorithms()
     * 3. Find differing data
     * 4. Use linker map file to find out to which symbols the
     *    differences belong.
     * 5. Use `nm -S USS_SW_CCS_large_code_large_data.lib` to find
     *    the size of each of these symbols.
     * For this reason, the implementation is rather fragile and
     * may fail if USS parameters are changed, as these may cause
     * other symbols to become relevant.
     *
     * See also: 
     * e2e.ti.com/.../
     */
    extern void USS_lea_init(void);
    extern void *gFilterConstant;
    extern void *gHilbertFilterConstant;
    extern void *gUSSAlgObject;
    typedef struct uss_init_buffer_ {
        uint8_t gFilterConstant[0x28];
        uint8_t gHilbertFilterConstant[0x18];
        uint8_t gUSSAlgObject[0x116];
    } uss_init_buffer_t;
    #pragma PERSISTENT(persist_uss_init_buffer)
    static uss_init_buffer_t persist_uss_init_buffer = {0};
    static void uss_init_quick(void) {
        if (gUssSWConfig.validationKey != CONFIG_VALIDATION_KEY) {
            USS_initAlgorithms(&gUssSWConfig);
            /* Store initialized data to nonvolatile memory (FRAM). */
            memcpy(persist_uss_init_buffer.gFilterConstant, &gFilterConstant, sizeof(persist_uss_init_buffer.gFilterConstant));
            memcpy(persist_uss_init_buffer.gHilbertFilterConstant, &gHilbertFilterConstant, sizeof(persist_uss_init_buffer.gHilbertFilterConstant));
            memcpy(persist_uss_init_buffer.gUSSAlgObject, &gUSSAlgObject, sizeof(persist_uss_init_buffer.gUSSAlgObject));
            /* Take the shortcut on next boot. */
            gUssSWConfig.validationKey = CONFIG_VALIDATION_KEY;
        } else {
            USS_lea_init();
            /* Initialize LEA hardware, but otherwise just restore precalculated
             * data from nonvolatile memory. */
            memcpy(&gFilterConstant, persist_uss_init_buffer.gFilterConstant, sizeof(persist_uss_init_buffer.gFilterConstant));
            memcpy(&gHilbertFilterConstant, persist_uss_init_buffer.gHilbertFilterConstant, sizeof(persist_uss_init_buffer.gHilbertFilterConstant));
            memcpy(&gUSSAlgObject, persist_uss_init_buffer.gUSSAlgObject, sizeof(persist_uss_init_buffer.gUSSAlgObject));
        }
    }

    不幸的是,我现在才发现,我在初始分析过程中犯了一个错误。 USS_initAlgorithms()需要它的时间、但只有几个100us。 真正实质性的延迟来自 USS_configureUltrasonicMeasure()、更具体地说、来自 commonConfigureMultiTone()中发射脉冲模式的计算。 但至少"修复"这是相当容易的:由于结果存储在持久 USS 配置数据中,它足以在慢代码周围加上"if":

    #if defined(__MSP430_HAS_SAPH_A__) && (USS_PULSE_MODE == USS_PULSE_MODE_MULTI_TONE)
    USS_message_code commonConfigureMultiTone(USS_SW_Library_configuration *config)
    {
    
        USS_Pulse_Multitone_Configuration* multConf;
        int32_t i,f1Freq,f2Freq,pulseCenterFreq, pulseBandwidth;
        uint32_t fSinInc, pPGFreq;
        _iq30 iq30Btemp;
        _iq23 iq23B;
        _iq18 iq18FIncrease;
        _iq12 iq12PulseDurFreq, iq12pPGCycles;
        _iq10 iq10FIncreased;
        uint16_t *pCurrArray;
        int16_t dmaCycles, xCycles,eCycles, stopAddr,pPGCycles;
        uint8_t ehperIndex, elperIndex, xhperIndex, xlperIndex,currentState;
        int8_t currentValue, previousValue;
    
        multConf =
                (USS_Pulse_Multitone_Configuration*) config->measurementConfig->pulseConfig->pToneConfig;
    
        /* The calculation of the pulse streams takes a considerable amount of
         * time (approx. 400ms), but the results are going into FRAM, and are
         * persistent anyway. So it is fine to just skip the calculation except for
         * the first boot after a firmware download. */
        if (config->validationKey != CONFIG_VALIDATION_KEY) {
    
            // Note: It is assumed that f1Freq<f2Freq
            f1Freq = (int32_t)config->measurementConfig->pulseConfig->F1Frequency;
            f2Freq = (int32_t)config->measurementConfig->pulseConfig->F2Frequency;
    
            // Calculate the excitation pulse bandwidth
            pulseBandwidth = (f2Freq -f1Freq);
    
            // ... more code ...
            
            }
    
    
            privatePadMultiToneConfig(config, multConf);
        }  // End of skipping for faster boots, the remaining code must stay.
    
    
     /*
      * Configure e-pulses and x-pulses RAM memory
      */
    
        eCycles = (multConf->numOfTrillcycles);
        xCycles = (multConf->numOfTrillcycles) -1;
        dmaCycles = eCycles + xCycles;
        stopAddr = (xCycles)*6+3;
    
        // ...

    现在、我们的传感器在大约30ms 后开始提供数据。 仍然不是瞬间,但更合理的比半秒.

    再次感谢!

    祝您愉快的周末、
    Philipp