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.

[参考译文] MSP430FR2476:测试时钟系统 ISR

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

https://e2e.ti.com/support/microcontrollers/msp-low-power-microcontrollers-group/msp430/f/msp-low-power-microcontroller-forum/1625435/msp430fr2476-testing-the-clock-system-isr

器件型号: MSP430FR2476

您好:

我目前正在测试时钟系统驱动程序及其相关的 ISR。 我随附了下面的 ISR 实现以供参考。

我想征询您关于如何正确测试故障标志 DCOFFG 和 XT1OFFG 的建议 。 是否有必要在寄存器中手动设置这些标志来模拟故障条件、或者是否有更优的方法在测试期间触发这些标志?

如果能就建议的测试方法提供任何指导、将不胜感激。

#include "msp430fr2xx_4xx_hal_cs.h"
#include "msp430.h"
#include <stdbool.h>
#include <stddef.h> 
#include "framctl.h"

static volatile uint8_t count_DCO_fail = 0;

//------------------------------------------------------FRAM FLAG ----------------------------------------------------------------

// This flag tells init not to attempt to source XT1 again if it was already declared dead.
#pragma PERSISTENT (cs_xt1_faulty)
static volatile bool cs_xt1_faulty = false;

//----------------------------------------------------------FOR ISR - FLL AND DCO ---------------------------------------------------------------//

#define XT1_LF_FREQ_HZ      32768UL     // standard 32.768 kHz watch crystal 
#define FLL_REF_FREQ_HZ     32768UL     // FLL reference FLLREFDIV=1 // I am assuming LF XT1

// XT1 recalibration using the hw counter threshold
#define XT1_HW_RETRY_MAX        3

// DCO recalibration retries per NMI entry 
#define DCO_RECAL_RETRY_MAX     3

// Threshold for the amount of DCO fault flag tries
#define DCO_POR_THRESHOLD       10

//Variable that stores the csctl4 register
static uint16_t xt1_saved_csctl4 = 0;
//this one tells is if we saved the contents in the csctl4 and switched the ref clock to refo
static bool     xt1_csctl4_saved = false;

//This is the amount of time we wil be waiting for the xt1 to recver by itself using its HW counter
static uint32_t xt1_hw_wait_cycles(void)
{
    uint32_t mclk = CS_getMCLK();
    uint16_t csctl6 = HWREG16(CS_BASE + OFS_CSCTL6);

    if (!(csctl6 & XTS)) {
        /* LF mode: 8192 ticks / 32768 Hz = 0.25 s
         * cycles = 0.25 × MCLK = (8192 × MCLK) / 32768            */
        return (8192UL * mclk) / XT1_LF_FREQ_HZ;
    }

    return (8192UL * mclk) / XT1_LF_FREQ_HZ;
}

//-------------------------------------------------------------- DCO--------------------------------------------------------------------------
static bool CS_recalibrateDCO_ISR(void)
{
    /* Steps 11–12: track the configuration closest to midrange (256) */
    uint16_t bestCsCtl0 = 0;
    uint16_t bestCsCtl1 = 0;
    uint16_t bestDelta = 0xFFFFu;

    uint16_t dcoftrim = (HWREG16(CS_BASE + OFS_CSCTL1) >> 4) & 0x07u;
    uint8_t  attempts = 0;
    bool     fllLocked = false;

    // Step 1: Disable the FLL
    __bis_SR_register(SCG0);

    // Step 2: I did made like a global variable for the ref clock - in our application we will only be using the XT1 in LF mode as the ref clock for FLL

    // Step 3: Enable DCOFTRIMEN so the trim takes effect.
    HWREG16(CS_BASE + OFS_CSCTL1) |= DCOFTRIMEN;

    // Step 5: Three NOPs BEFORE re-enabling the FLL.
    __no_operation();
    __no_operation();
    __no_operation();

    // Step 6: Re-enable FLL. 
    __bic_SR_register(SCG0);

    // Steps 7–14 :  trim search loop. 
    while (attempts < DCO_RECAL_RETRY_MAX)
    {
        // Step 7: Preset DCO tap = 256 (midrange)
        HWREG16(CS_BASE + OFS_CSCTL0) = DCO8;

        // Step 8: Clear DCOFFG BEFORE the wait so the hardware
        HWREG8(CS_BASE + OFS_CSCTL7_L) &= ~DCOFFG;
        HWREG8(SFR_BASE + OFS_SFRIFG1) &= ~OFIFG;

        // Step 9: Wait ≥ 24 / fFLLREF for FLLUNLOCK to stabilise. - (24 × MCLK) / FLLREF.
        // __delay_cycles((24UL * CS_getMCLK()) / FLL_REF_FREQ_HZ);

        // More accurate — accounts for ~3 cycles per iteration ((decrement + compare + branch))
        uint32_t delay_val = ((24UL * CS_getMCLK()) / FLL_REF_FREQ_HZ) / 3u;
        while (delay_val--) {
            __no_operation();
        }

        // Step 10: Poll - spin until locked OR DCO fault re-fires.   
        while ((HWREG16(CS_BASE + OFS_CSCTL7) & (FLLUNLOCK0 | FLLUNLOCK1)) &&
            !(HWREG16(CS_BASE + OFS_CSCTL7) & DCOFFG));

        // Step 11: Read settled tap, compute delta from midrange.    
        uint16_t tap = HWREG16(CS_BASE + OFS_CSCTL0) & 0x01FFu;
        uint16_t delta = (tap >= 256u) ? (tap - 256u) : (256u - tap);

        // Step 12: Record best (closest to 256) CSCTL0/CSCTL1.      
        if (delta < bestDelta) {
            bestDelta = delta;
            bestCsCtl0 = HWREG16(CS_BASE + OFS_CSCTL0);
            bestCsCtl1 = HWREG16(CS_BASE + OFS_CSCTL1);
        }

        // Check if FLL locked cleanly (DCOFFG did not re-fire).      
        if (!(HWREG8(CS_BASE + OFS_CSCTL7_L) & DCOFFG)) {
            fllLocked = true;
            break;
        }

        // Step 13: Adjust DCOFTRIM toward midrange.
        if (tap < 256u && dcoftrim > 0u) {
            dcoftrim--;
        }
        else if (tap >= 256u && dcoftrim < 7u) {
            dcoftrim++;
        }
        else {
            break;   // already at boundary, cannot adjust further 
        }

        // Write updated DCOFTRIM, preserving all other CSCTL1 bits.  
        HWREG16(CS_BASE + OFS_CSCTL1) =
            (HWREG16(CS_BASE + OFS_CSCTL1) & ~(0x07u << 4)) |
            ((uint16_t)dcoftrim << 4);

        // Step 14: Repeat from step 7. 
        attempts++;
    }

    // Step 15 — Reload best CSCTL0/CSCTL1 recorded across iterations. 
    if (bestDelta < 0xFFFFu) {
        HWREG16(CS_BASE + OFS_CSCTL0) = bestCsCtl0;
        HWREG16(CS_BASE + OFS_CSCTL1) = bestCsCtl1;
    }

    return fllLocked;
}

//--------------------------------------Functions using TI DriverLib ------------------------------------------------------------//

#if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__)
#pragma vector=UNMI_VECTOR
__interrupt void UNMI_ISR(void)
#elif defined(__GNUC__)
void __attribute__((interrupt(UNMI_VECTOR))) UNMI_ISR(void)
#else
#error Compiler not supported!
#endif
{
    switch (__even_in_range(HWREG16(__MSP430_BASEADDRESS_SYS__ + OFS_SYSUNIV), SYSUNIV__OFIFG)) {

    case SYSUNIV__NONE: //OFFSET 0
        break;

    case SYSUNIV__NMIIFG: //OFFSET 2
        break;

    case SYSUNIV__OFIFG: {  //OFFSET 4

        uint8_t csctl7 = HWREG8(CS_BASE + OFS_CSCTL7_L);
        if (csctl7 & DCOFFG) {

            bool recal_ok = CS_recalibrateDCO_ISR();

            if (recal_ok) {
                count_DCO_fail = 0;     /* recovery succeeded */
            }
            else {
                count_DCO_fail++;

                HWREG8(CS_BASE + OFS_CSCTL7_L) &= ~DCOFFG;
                HWREG8(SFR_BASE + OFS_SFRIFG1) &= ~OFIFG;

                if (count_DCO_fail >= DCO_POR_THRESHOLD) {
                    HWREG16(PMM_BASE + OFS_PMMCTL0) =
                        PMMPW | PMMSWPOR;
                }
            }
        }


        else if (csctl7 & XT1OFFG)
        {

            HWREG8(CS_BASE + OFS_CSCTL7_L) |= ENSTFCNT1;

            // Save CSCTL4 before we change SELMS/SELA. So once the xt1 recovers we use the old settings
            if (!xt1_csctl4_saved) {
                xt1_saved_csctl4 = HWREG16(CS_BASE + OFS_CSCTL4);
                xt1_csctl4_saved = true;
            }

            bool    xt1_recovered = false;
            uint8_t hw_retry = 0;

            while (hw_retry < XT1_HW_RETRY_MAX)
            {
                HWREG8(CS_BASE + OFS_CSCTL7_L) &= ~XT1OFFG;
                HWREG8(SFR_BASE + OFS_SFRIFG1) &= ~OFIFG;

                // __delay_cycles(xt1_hw_wait_cycles());
                // REPLACEMENT:
                uint32_t xt1_wait = xt1_hw_wait_cycles() / 3u;
                while (xt1_wait--) {
                    __no_operation();
                }

                if (!(HWREG8(CS_BASE + OFS_CSCTL7_L) & XT1OFFG)) {
                    xt1_recovered = true;
                    break;
                }
                hw_retry++;
            }

            if (xt1_recovered)
            {
                // we check if the csclt4 contents were saved
                if (xt1_csctl4_saved) {
                    HWREG16(CS_BASE + OFS_CSCTL4) = xt1_saved_csctl4;
                    xt1_csctl4_saved = false;
                    cs_xt1_faulty = false;
                }

                HWREG8(CS_BASE + OFS_CSCTL7_L) &= ~XT1OFFG;
                HWREG8(SFR_BASE + OFS_SFRIFG1) &= ~OFIFG;
            }
            else
            {
                /* XT1 did not recover — commit REFO fallback.   */


                if ((HWREG16(CS_BASE + OFS_CSCTL4) & SELMS) == CS_XT1CLK_SELECT) {
                    HWREG16(CS_BASE + OFS_CSCTL4) &= ~SELMS;
                    HWREG16(CS_BASE + OFS_CSCTL4) |= CS_REFOCLK_SELECT;
                }
                if ((HWREG16(CS_BASE + OFS_CSCTL4) & SELA) == SELA__XT1CLK) {
                    HWREG16(CS_BASE + OFS_CSCTL4) &= ~SELA;
                    HWREG16(CS_BASE + OFS_CSCTL4) |= SELA__REFOCLK;
                }

                // FRAM: survives POR — blocks XT1 on next boot. 
                cs_xt1_faulty = true;

                HWREG8(CS_BASE + OFS_CSCTL7_L) &= ~XT1OFFG;
                HWREG8(SFR_BASE + OFS_SFRIFG1) &= ~OFIFG;
            }
        }
        break;
    }

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

    尊敬的 Ahlam:

    总的来说、代码看起来不错。 但我建议 先清除 DCOFFG 和 XT1OFFG 、然后清除 OFIFG 标志 以验证 OFIFG 是否保持清零状态、从而确保振荡器的稳定性。  

    此致、

    Bill

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

    1) 您应该能够通过关闭 XT1 振荡器触发 XT1OFFG、即将 P2SEL0.0/.1 设置为=0。 我期望 XT1OFFG 的恢复将是重新启动 XT1、方法是先将这些 PSEL 设置为=0、然后再设置为=1、然后等待(希望)它启动。

    2) 您可以通过将 CSCTL2:FLLN 设置为荒谬的内容(例如 0x1FF)来触发 DCOFFG、DCO 无法在 DCORSEL 内调优到该值。 这种情况下的恢复大概是将 FLLN/DCORSEL(反向)设置为所需值、然后查看 FLL 是否稳定。

    [编辑:固定 PSEL 寄存器名称。]

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

    使用调试程序。

    在适当的位置设置断点。 (在您的 ISR 中!) 开始执行并等待断点。

    使用调试器设置中断标志(如果未设置中断启用,请先执行) 、然后继续执行。 看看会发生什么情况。 根据需要对其他中断重复。