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.

[参考译文] MSP430FR2355:UCRXBUFx's 接收移位寄存器在 LPM3中的位移、其中 UART/SMCLK 被禁用?

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

https://e2e.ti.com/support/microcontrollers/msp-low-power-microcontrollers-group/msp430/f/msp-low-power-microcontroller-forum/1482325/msp430fr2355-does-the-ucrxbufx-s-receive-shift-register-shift-in-bits-in-lpm3-where-uart-smclk-is-disabled

器件型号:MSP430FR2355

工具与软件:

我有一个在启动时默认进入 LPM3的主循环。 我还配置了一个计时器(TB2)、以每2秒唤醒 CPU 大约10ms。 一个相应的 UART (eUSCI_A1)中断会将设置 enter_LPM3标志、该标志要么将 CPU 从 LPM3唤醒、要么将其返回到 LPM3。

由于 LPM3中禁用了 SMCLK 和 UART、因此我预计 CPU 能够捕获'w'(唤醒)命令的唯一方法是命令在10ms 窗口期间到达。 这只是每2秒10毫秒–大约是0.5%的时间。 逻辑上,这应该失败的大部分时间(99.5%),但在实践中,我的代码神奇地工作100%的时间。 我可以将 CPU 置入 LPM3或随时将其唤醒、而且我绝不会错过该'w'命令。

除非我错译了自己的代码、否则我猜是 CPU 在 LPM3中、而 SMCLK/UART 据称是关闭的 接收移位寄存器 仍然可能会移入 UART 数据。 然后、只要 CPU 在该10ms 窗口内唤醒并启用 SMCLK、数据就会显示在中 UCAxRXBUF并触发中断。 否则、我无法解释为什么我的代码能够如此可靠地工作。  希望有人能告诉我这一点。

我不确定是否假设代码是必要的,但这里是它只是在情况下:

我的主循环:
  

// Beginning of my main loop
// 'enter_LPM3' is initialized to be true
// Main loop
while(1)
{
    // 'enter_LPM3' is initialized to be true, meaning we enter LPM3 after power up
    if (enter_LPM3)
    {
        // (LPM3) Small delay to increase the time-window in catching 'w' UART command (~10ms @ 1MHz MCLK) 
        // before entering LPM3. 
        __delay_cycles(10000);
        
        P1OUT &= ~BIT0; // LED Off                   

        // Check enter_LPM3 again before entering LPM3 because the UART ISR may set 'enter_LPM3' to false 
        // with a 'w' wake-up command
        if (enter_LPM3) 
        {
            __bis_SR_register(LPM3_bits | GIE);  // Enter LPM3 (Wake up by Timer_B2)
        }
    }
    // Other work
}

我的计时器和计时器 ISR:

// (LPM3) Configure Timer2_B3 (TB2)
void configure_tb2_wakeup(void)
{
    TB2CTL |= TBCLR;            // (TB2) Clear Timer_B2
    TB2CTL |= TBSSEL__ACLK;     // (TB2) Source Timer_B2 from ACLK (32.768 kHz)
    
    //TB2CTL |= ID__1;            // (TB2) No clock division
    //TB2EX0 |= TBIDEX__1;        // (TB2) No extra division   
    //TB2CCR0 = 327;              // (TB2) Set wake-up interval (~10ms: 327 / 32.768kHz ≈ 10ms)
    //TB2CCR0 = 32768;            // (TB2) Set wake-up interval (~1s: 32768 / 32.768kHz ≈ 1s)
    //TB2CCR0 = 65535;            // (CANNOT USE - OVERFLOW!)(TB2) Set wake-up interval (~2s: 32.768kHz / 65536 ≈ 2s)

    // Because TB2CCR0 is a 16-bit counter that has a maximum value of 65535 and overflows at 65536,
    // we can use the clock divider to slow down ACLK in order to achieve a more accurate 2s interrupt
    TB2CTL |= ID__4;             // (TB2) Divide ACLK by 4 (32.768 kHz / 4 = 8.192 kHz)
    TB2EX0 |= TBIDEX__8;         // (TB2) Further divide by 8 (8.192 kHz / 8 = 1.024 kHz)
    TB2CCR0 = 2048;              // (TB2) Set wake-up interval (~2s: 2048 / 1.024 kHz = ~2s interval

    TB2CCTL0 |= CCIE;           // (TB2) Enable Timer_B2 interrupt
    TB2CTL |= MC__UP;           // (TB2) Set Timer_B2 to UP mode
}

#pragma vector = TIMER2_B0_VECTOR
__interrupt void ISR_TB2_Wakeup(void)
{
    // Wake up the CPU if it's in LPM3. Otherwise, do nothing (CPU is already awake).
    if (enter_LPM3)                             
    {
        P1OUT |= BIT0;                          // LED On  
        __bic_SR_register_on_exit(LPM3_bits);   // Wake up from LPM3 (not immediately but after we exit this ISR)
    }
}

UART 和 UART ISR:

void configure_uart(void)
{
     UCA1CTLW0 |= UCSWRST;       // (eUSCI_A1)(UART) hold eUSCI_A1 in SW reset
     UCA1CTLW0 |= UCSSEL__SMCLK; // (eUSCI_A1)(UART) clock source: use SMCLK 1MHz

     UCA1BRW = 8;                // (eUSCI_A1)(UART) 115200 baud (UG-p.589) <-- neg error
     UCA1MCTLW |= 0xD600;        // (eUSCI_A1)(UART) 115200 baud (UG-p.589) <-- neg error

     P4SEL1 &= ~BIT3;            // (eUSCI_A1)(UART) P4.3/TXD (P4SEL1.3=0)
     P4SEL0 |= BIT3;             // (eUSCI_A1)(UART) P4.3/TXD (P4SEL0.3=1)

     P4SEL1 &= ~BIT2;            // (eUSCI_A1)(UART) P4.2/RXD (P4SEL1.2=0)
     P4SEL0 |= BIT2;             // (eUSCI_A1)(UART) P4.2/RXD (P4SEL0.2=1)

     UCA1CTLW0 &= ~UCSWRST;      // Take UART out of reset
}


#pragma vector = EUSCI_A1_VECTOR
__interrupt void ISR_EUSCI_A1(void)
{
    if((UCA1IFG & UCRXIFG) != 0)
    {
        char rx_char = UCA1RXBUF;                   // Read UART input

        if(rx_char == 'w')                          // UCRXIFG is cleared automatically when UCA1RXBUF is read
        {
            P1OUT |= BIT0;                          // LED On
            enter_LPM3 = false;                     // (LPM3) Stays awake
            __bic_SR_register_on_exit(LPM3_bits);   // (LPM3) * Forces wake-up immediately *
        } 
        else if(rx_char == 's')
        {
            P1OUT &= ~BIT0;                         // LED Off
            enter_LPM3 = true;                      // (LPM3) Let main.c enters LPM3
        }
    }

    // UART transmit the byte read from the SPI
    if((UCA1IFG & UCTXCPTIFG) != 0)
    {
        // See INFO.txt
        if(position_UART == ((sizeof(read_result)/2) - 1))  // if all characters in a string has completed its transmission
        {
            UCA1IE &= ~UCTXCPTIE;                       // (eUSCI_A1)(UART) disable UCTXCPTIE IRQ
        }
        else                                            // more characters to be sent
        {
            position_UART++;
            UCA1TXBUF = read_result[position_UART];
        }
        UCA1IFG &= ~UCTXCPTIFG;                         // (eUSCI_A1)(UART) clear UCTXCPTIFG IFG
    }
}

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

    在指南中:

    "如果要求外设模块正确、它将从 CS 模块自动请求时钟源
    运行、无论当前运行模式如何(请参阅图3-5)。"

    或者、当 UART 在其输入上检测到一个下降沿(起始位)时、系统处于 LPM3模式。 它请求其时钟、从而使其运行。 当数据接收完成时、时钟可以停止并返回到 LPM3。

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

    谢谢您、我 在指南中错过了该内容。  UART (1)在自动返回到 LPM3前立即在 LPM3中处理中断、或者(2)它只设定中断标志、并且 ISR 只 在 CPU 退出 LPM3后才被处理?