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:19200年以上时 UART 不工作?

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

https://e2e.ti.com/support/microcontrollers/msp-low-power-microcontrollers-group/msp430/f/msp-low-power-microcontroller-forum/1120462/msp430fr2355-uart-not-working-above-19200

器件型号:MSP430FR2355

下午好...

我使用的是连接到 PC 的 MSP430FR2355开发板。  在 PC 端使用 RealTerm ...

我可以将波特率设置为19200和9600、并且都可以正常工作、但如果我将其设置为高于19200、我将得到错误的字符。  我已经验证了以下寄存器   是否按照用户指南设置为高于19.2的多个波特率

1. smclk 8MHz (在 P1.0上验证)、也验证了在 UART 控制寄存器设置中使用 SMCLK

2.还对照用户手册设置表22.5进行了验证: UCOS16、UCBR、UCBRF、UCBRS……

3. 已验证 RealTerm 是否设置为正确的波特。

ISR 开头的断点会验证 ISR 前端是否存在 RXBUFFER 错误、这使我认为设置中缺少什么??

有人对我可能遗漏的内容有什么想法、也有什么值得尝试的、因为我都不知道为什么我不能更快地走?  (代码(在 main 中)除了 LPM3之外什么也不做(我在 LPM0中看不到任何改进)。  它等待 UART 字符进入、然后运行。

ISR 非常简单(如果字符停止、ISR 内部会布设超时)

      case USCI_UART_UCRXIFG:
          buffer[mssgLength] = UCA1RXBUF;
          mssgLength++;
          if (monitor == 0)
              TimerCC_Delay(TIMER0, CC_ZERO, ONE_SECOND);

          monitor = 1;
          if (UCA1RXBUF == 0x0D)
          {
              mssgLength--;
              ISR.UARTmssgRcvdFlag = T;
              LPM3_EXIT;
          }
          break;

谢谢

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

    您好、Steve、

    根据 MSP 调试器 文档、ezFET 可支持的波特率存在限制。 请注意、只有支持频率。  摘录如下:

    此致、

    Evan

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

    不是很相信……我从 SBWTDIO 和 SBWTCK 上取下跳线使调试器处于非活动状态……16MHz 时的 MCLK、针对 smclk 除以2……波特率设置为115200……寄存器看起来都很好……仍然是不可以的……然后尝试了38400,寄存器看起来很好…

    我加载了代码并验证了寄存器设置、然后停止运行调试器、断开的跳线关闭目标电源并重新加电、但无法正常工作???

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

    我在发布的代码中看不到 RXBUFFER。 我担心该 ISR。 接收到完整的线路后、您唤醒主程序、但 ISR 仍在运行、这可能会导致缓冲区出现问题。

    我可以向您指出一个示例、即我经常以38400运行(我没有尝试过更高版本)、但它在汇编中。 我对数据使用 FIFO 队列。

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

    RXBUFFER (抱歉我的错误)……这只是表示缓冲区……如果你看看 ISR,你会看到正确的分配,即 UCA1RXBUF……

    我已经成功地使用了这个概念...这是唤醒后主代码的第一行  

            if (ISR.UARTmssgRcvdFlag)
            {
                applicationUART.pSysCommsA->UCAxIE &= ~UCRXIE;
    

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

    我正在使用外部32kHz 晶体...

    你能评论一下 REFOLP 位设置和 DISMOD 位设置。。。我尝试将这些设置翻转为 REFOLP=0 (即高功率),但没有结果。。。我看到我有一些代码(由于项目的性质有些不同)。 以更高的波特运行、但它的 DISMOD =1看起来对 me....in 来说是错误的。这个项目我的 DISMOD = 0?? (这些位于 CS 部分)

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

    所以我把应用程序缩小到了裸块...我发现在38400时,接收到的第一个字节的信息是损坏的...所以我更改为 LPM0,它们都是在38400 ...然后我移至115200,我看到在 LPM0时,第一个字节再次是坏的...它 看起来处理器无法及时唤醒或唤醒某个东西???   

    我的时钟是8MHz,调试器是连接的,根据上面 Evan 的图片,应该可以正常工作……我真的想在 LPM3....ca上操作它,但我不想这样做……我的 SMCLKREQEN 是 set....seems,我应该唤醒它  

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

    我想听听 TI 的意见吗??  从 LPM3接收唤醒时,似乎无法获得>19.2K 波特  

    我已经查看过数据表、数据表显示从 LPM3唤醒的典型时间是10us……115.2Kbaud 是8.7us,因此我必须相信无法在 UART RX 中断上唤醒并以 115200 波特率成功工作。  我无法使用 LPM3从 UART RX 中唤醒并捕获高于19.2kBaud 的所有传入字符...如果我转到 LPM0、我可以得到38400....

    下面是38400处的一些基本代码(我删除了所有库并将 UART 和 clk inits 移动到文件中,以防分支导致麻烦),LPM3错误地引入了第一个字符....

    #include "main.h"
    
    void init_ClockTo16MHz(void);
    static void Software_Trim();
    void UART_Init(void);
    uint16_t itoa(uint16_t k);
    
    struct HardFlags ISR = {F};
    
    static __vo uint8_t buffer[MSSG_LENGTH] = { [ 0 ... MSSG_LENGTH - 1] = 0 }, monitor = 0;
    
    __vo uint8_t mssgLength = 0;
    
    
    int main(void)
    {
        WDTCTL = WDTPW | WDTHOLD;   // stop watchdog timer
        PM5CTL0 &= ~LOCKLPM5;
        init_ClockTo16MHz();
        UART_Init();
    
    
    
        while(1)
        {
            __bis_SR_register( LPM3_bits + GIE);
    
            if (ISR.UARTmssgRcvdFlag)
            {
                UCA1IE &= ~UCRXIE;
                ISR.UARTmssgRcvdFlag = F;
                mssgLength = 0;
                UCA1IFG &= ~UCRXIFG;
                UCA1IE |= UCRXIE;
            }
    
        }
    }
    
    #pragma vector=USCI_A1_VECTOR
    __interrupt void COMM_ISR(void)
    {
        switch(__even_in_range(UCA1IV, USCI_UART_UCTXCPTIFG))
        {
          case USCI_NONE: break;
          case USCI_UART_UCRXIFG:
              buffer[mssgLength] = UCA1RXBUF;
    
    
              if (buffer[mssgLength] == 0x0D)
              {
                  ISR.UARTmssgRcvdFlag = T;
                  LPM3_EXIT;
              }
    
              mssgLength++;
              break;
          case USCI_UART_UCTXIFG:
              break;
          case USCI_UART_UCSTTIFG: break;
          case USCI_UART_UCTXCPTIFG: break;
        }
    }
    
    #ifdef LOCAL
    void UART_Init(void)
    {
        P4SEL0 |= BIT3 | BIT2;
        UCA1CTLW0 |= UCSWRST;
        UCA1CTLW0 |= UCSSEL__SMCLK;
        //UCA1BR0 = 52; //19200
        UCA1BR0 = 13; //115200
        UCA1BR1 = 0x00;
        //UCA1MCTLW = 0x4900 | UCOS16 | UCBRF_1; //19200
        UCA1MCTLW = 0x8400 | UCOS16 | UCBRF_0; //115200
        UCA1CTLW0 &= ~UCSWRST;
    
        UCA1IFG &= ~UCRXIFG;
        UCA1IE |= UCRXIE;
    
    }
    
    
    void init_ClockTo16MHz(void)
    {
        FRCTL0 = FRCTLPW | NWAITS_1;
        P2SEL1 |= BIT6 | BIT7;
        do
        {
            CSCTL7 &= ~(XT1OFFG | DCOFFG);           // Clear XT1 and DCO fault flag
            SFRIFG1 &= ~OFIFG;
        } while (SFRIFG1 & OFIFG);                   // Test oscillator fault flag
    
        __bis_SR_register(SCG0);                     // disable FLL
        CSCTL3 |= SELREF__XT1CLK;                    // Set XT1 as FLL reference source
        CSCTL1 |= DCOFTRIMEN_1 | DCOFTRIM0 | DCOFTRIM1 | DCORSEL_5;// DCOFTRIM=5, DCO Range = 16MHz
        CSCTL2 = FLLD_0 + 487;                       // DCOCLKDIV = 16MHz
        __delay_cycles(3);
        __bic_SR_register(SCG0);                     // enable FLL
        Software_Trim();
        while(CSCTL7 & (FLLUNLOCK0 | FLLUNLOCK1));
        CSCTL5 |= DIVS_1;
        CSCTL4 = SELMS__DCOCLKDIV | SELA__XT1CLK;   // set XT1 (~32768Hz) as ACLK source, ACLK = 32768Hz
    }
    
    
    static void Software_Trim()
    {
        unsigned int oldDcoTap = 0xffff;
        unsigned int newDcoTap = 0xffff;
        unsigned int newDcoDelta = 0xffff;
        unsigned int bestDcoDelta = 0xffff;
        unsigned int csCtl0Copy = 0;
        unsigned int csCtl1Copy = 0;
        unsigned int csCtl0Read = 0;
        unsigned int csCtl1Read = 0;
        unsigned int dcoFreqTrim = 3;
        unsigned char endLoop = 0;
    
        do
        {
            CSCTL0 = 0x100;                         // DCO Tap = 256
            do
            {
                CSCTL7 &= ~DCOFFG;                  // Clear DCO fault flag
            }while (CSCTL7 & DCOFFG);               // Test DCO fault flag
    
            __delay_cycles((unsigned int)3000 * 16);// Wait FLL lock status (FLLUNLOCK) to be stable
                                                               // Suggest to wait 24 cycles of divided FLL reference clock
            while((CSCTL7 & (FLLUNLOCK0 | FLLUNLOCK1)) && ((CSCTL7 & DCOFFG) == 0));
    
            csCtl0Read = CSCTL0;                   // Read CSCTL0
            csCtl1Read = CSCTL1;                   // Read CSCTL1
    
            oldDcoTap = newDcoTap;                 // Record DCOTAP value of last time
            newDcoTap = csCtl0Read & 0x01ff;       // Get DCOTAP value of this time
            dcoFreqTrim = (csCtl1Read & 0x0070)>>4;// Get DCOFTRIM value
    
            if(newDcoTap < 256)                    // DCOTAP < 256
            {
                newDcoDelta = 256 - newDcoTap;     // Delta value between DCPTAP and 256
                if((oldDcoTap != 0xffff) && (oldDcoTap >= 256)) // DCOTAP cross 256
                    endLoop = 1;                   // Stop while loop
                else
                {
                    dcoFreqTrim--;
                    CSCTL1 = (csCtl1Read & (~DCOFTRIM)) | (dcoFreqTrim<<4);
                }
            }
            else                                   // DCOTAP >= 256
            {
                newDcoDelta = newDcoTap - 256;     // Delta value between DCPTAP and 256
                if(oldDcoTap < 256)                // DCOTAP cross 256
                    endLoop = 1;                   // Stop while loop
                else
                {
                    dcoFreqTrim++;
                    CSCTL1 = (csCtl1Read & (~DCOFTRIM)) | (dcoFreqTrim<<4);
                }
            }
    
            if(newDcoDelta < bestDcoDelta)         // Record DCOTAP closest to 256
            {
                csCtl0Copy = csCtl0Read;
                csCtl1Copy = csCtl1Read;
                bestDcoDelta = newDcoDelta;
            }
    
        }while(endLoop == 0);                      // Poll until endLoop == 1
    
        CSCTL0 = csCtl0Copy;                       // Reload locked DCOTAP
        CSCTL1 = csCtl1Copy;                       // Reload locked DCOFTRIM
        while(CSCTL7 & (FLLUNLOCK0 | FLLUNLOCK1)); // Poll until FLL is locked
    }
    #endif
    

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

    数据表中有一个表(5-2)、该表告诉您唤醒所需的时间。 从 LPM3的唤醒时间为10us。

    虽然 UART 能够唤醒、但它在起始位的下降沿执行此操作。 如果时钟未运行、则时序将成为一个问题、因为所有内容都以该下降沿为基准。 或时钟启动时、以最后的时间为准。

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

    尊敬的 David:

    是的,这就是我所处的位置...我不认为它可以完成...尽管它看起来不能达到57.6kBaud?

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

    虽然很难理解用户指南似乎建议在中间进行采样...所以可能57.6也不在...但在 LPM3下似乎可以达到38.4?  您提到过您是在汇编语言中实现的、但使用 FIFO??  我不知道汇编语言,但......我在上面的38.4号发布了代码,但它不起作用......有什么想法吗?

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

    我的示例在大多数情况下都不使用低功耗模式。 我用一个运行它、不会忘记任何问题。 我提到了汇编器件、因为这会使许多 C 语言编程器感到害怕。 它中实际上没有任何东西无法在 C 语言中完成、但项目必须在汇编语言中完成。

    在38、400 bps 时、10us 延迟会使您接近位的中心。 即使检测到起始位、所有后续位也将具有相同的偏移。 假设调制器正在使用中(它必须具有8MHz 参考时钟)、则还必须添加这些误差。 因此、38、400会有问题、因为采样时间会非常接近位的边缘。

    如果必须使用 LPM3和更高的位速率、则必须找到一种在数据到达之前启动时钟的方法。 然后使其保持活动状态、直到接收到所有数据。