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-MSP430FR2476:反向通道 UART 奇偶校验位不工作

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

https://e2e.ti.com/support/microcontrollers/msp-low-power-microcontrollers-group/msp430/f/msp-low-power-microcontroller-forum/1239125/lp-msp430fr2476-backchannel-uart-parity-bit-not-working

器件型号:LP-MSP430FR2476

我有一个应用程序使用 eUSCI_A0、其工作原理是115200 BD、8个数据位、1个停止位和奇校验。 某些字符在任何一个方向上都不能通过、这似乎是由于内置 USB 串行转换器对奇偶校验位的错误处理造成的。 使用另一个 USB 串行转换器(基于 CP2102)时、一切都能按预期工作。

程序会在启动时发送字符串"Initialization Done"。 在我的 Linux PC 上使用 picocom、我收到的此值为"itilitiooe"。 进一步调查我发现字符串"0123456789abcdefghijklmkopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"被接收为"03569cefijloqrtwxABDGHKMNPSUVYZ"。 巧合的是、在奇偶校验位为'0'的情况下、所有字符都缺失、我认为这是一个无效的停止位。 picocom 输出和示波器跟踪(在板上标记为"TXD>>"的跳线处)如下:

picocom v3.1

port is        : /dev/ttyACM1
flowcontrol    : none
baudrate is    : 115200
parity is      : odd
databits are   : 8
stopbits are   : 1
escape is      : C-a
local echo is  : no
noinit is      : no
noreset is     : no
hangup is      : no
nolock is      : no
send_cmd is    : sz -vv
receive_cmd is : rz -vv -E
imap is        : 
omap is        : crlf,
emap is        : crcrlf,delbs,
logfile is     : none
initstring     : none
exit_after is  : not set
exit is        : no

Type [C-a] [C-h] to see available commands
Terminal ready
itilitiooe
          03569cefijloqrtwxABDGHKMNPSUVYZ

将示波器的串行解码器设置为奇偶校验=none 后、您可以看到未接收到的字符"i"和"n"在结尾有一个错误标记。

电路板也不会在 RX 方向生成奇偶校验位:发送"i"和 picocom (奇偶校验位设置为"奇数")会产生以下范围跟踪(这次板上的"RXD<";串行解码器设置为奇偶校验=奇偶校验!):

如您所见、没有生成奇偶校验位。 MSP430程序不接收字符(它应该在奇偶校验位错误时接收)。

当我不启用 MSP430侧的奇偶校验位(不会设置/清除 UCA0CTLW0的 UCPEN)时、微控制器和 picocom 之间的通信正常工作。

这看起来像是 eZ-FET 固件的错误。 picocom 将引导驱动程序启用奇偶校验位、这可以通过以下事实来证明:它适用于基于 CP2102的板以及'TTY -F /dev/ttyACM1 -A'的输出(请注意"aroke parodd"):

speed 115200 baud; rows 0; columns 0; line = 0;
intr = ^C; quit = ^\; erase = ^?; kill = ^U; eof = ^D; eol = <undef>; eol2 = <undef>; swtch = <undef>; start = ^Q; stop = ^S; susp = ^Z; rprnt = ^R; werase = ^W;
lnext = ^V; discard = ^O; min = 1; time = 0;
parenb parodd -cmspar cs8 hupcl -cstopb cread clocal -crtscts
-ignbrk -brkint -ignpar -parmrk -inpck -istrip -inlcr -igncr -icrnl -ixon -ixoff -iuclc -ixany -imaxbel -iutf8
-opost -olcuc -ocrnl onlcr -onocr -onlret -ofill -ofdel nl0 cr0 tab0 bs0 vt0 ff0
-isig -icanon -iexten -echo echoe echok -echonl -noflsh -xcase -tostop -echoprt echoctl echoke -flusho -extproc

是否有新的固件版本? 如果有的话、我该如何闪烁它?

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

    我忘记提一下、我使用的是 mspdebug、在刷写程序时会报告以下情况:

    MSPDebug version 0.25 - debugging tool for MSP430 MCUs
    Copyright (C) 2009-2017 Daniel Beer <dlbeer@gmail.com>
    This is free software; see the source for copying conditions.  There is NO
    warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
    Chip info database from MSP430.dll v3.3.1.4 Copyright (C) 2013 TI, Inc.
    
    Using new (SLAC460L+) API
    MSP430_GetNumberOfUsbIfs
    MSP430_GetNameOfUsbIf
    Found FET: ttyACM0
    MSP430_Initialize: ttyACM0
    Firmware version is 31501001
    MSP430_VCC: 3000 mV
    MSP430_OpenDevice
    MSP430_GetFoundDevice
    Device: MSP430FR2476 (id = 0x0210)
    3 breakpoints available
    MSP430_EEM_Init
    Chip ID data:
      ver_id:         832a
      ver_sub_id:     0000
      revision:       10
      fab:            55
      self:           5555
      config:         10
      fuses:          55
    warning: unknown chip
    Erasing...
    Programming...
    Writing    2 bytes at ffe0 [section: __interrupt_vector_31]...
    Writing    2 bytes at fffe [section: __reset_vector]...
    Writing   87 bytes at 8000 [section: .rodata]...
    Writing    2 bytes at 8058 [section: .upper.data]...
    Writing 1458 bytes at 805a [section: .text]...
    Done, 1551 bytes total
    MSP430_Run
    MSP430_Close

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

    您如何初始化串行端口?

    您如何发送和接收数据? 发送是否在发送第三个字节之前为字符清零留出了足够的时间?

    您是否使用中断和串行缓冲器?

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

    正如我所说的、如果我使用不同的串行转 USB 适配器、或者禁用 MSP430侧的奇偶校验位生成和检查、可以很好地工作。 这使得它不太可能与我的代码有任何关系。

    无论如何、我已经将我的代码的相关部分复制在一起作为 MRE、您应该能够按原样对其进行编译和测试。 如果我将第45行替换为"UCA0CTLW0 |= UCSSEL__SMCLK;"并在 picocom 中禁用奇偶校验、则可以正常运行、否则行为如上所述。

    #include <msp430.h>
    #include <stdbool.h>
    #include <stdlib.h>
    #include <stddef.h>
    #include <stdint.h>
    
    #define MCLK_FREQ_MHZ 8 // MCLK = 8MHz
    #define F_CPU (1000000 * MCLK_FREQ_MHZ)
    #define T_MS (F_CPU / 1000)
    
    #define UART_BAUD_RATE 115200
    #define UART_TX_BUFFER_SIZE 128
    #define UART_TX_BUFFER_INDEX_MASK (UART_TX_BUFFER_SIZE - 1)
    #define UART_RX_BUFFER_SIZE 128
    #define UART_RX_BUFFER_INDEX_MASK (UART_TX_BUFFER_SIZE - 1)
    
    static char uart_tx_buffer[UART_TX_BUFFER_SIZE];
    static size_t uart_tx_buffer_write_index = 0;
    static volatile size_t uart_tx_buffer_read_index = 0;
    static char uart_rx_buffer[UART_RX_BUFFER_SIZE];
    static volatile size_t uart_rx_buffer_write_index = 0;
    static size_t uart_rx_buffer_read_index = 0;
    static volatile bool uart_tx_active = false;
    
    /**
     * P1.4: UCA0TXD (UART to USB)
     * P1.5: UCA0RXD (UART to USB)
     */
    void uart_init_io() {
        P1SEL0 |= BIT4 | BIT5;
    }
    
    void uart_enable() {
        UCA0CTLW0 = UCSWRST;
        // Character length: 8 bit, Stop bits: 1, LSB first, Parity: odd
        UCA0CTLW0 |= UCSSEL__SMCLK | UCPEN;
        UCA0CTLW1 = UCGLIT_3;
        // Configuration for 115200 bd with BRCLK = 8 MHz
        // UCOS16 = 1, UCBRx = 4, UCBRFx = 5, UCBRSx = 0x55
        UCA0BRW = 4;
        UCA0MCTLW = UCOS16 | (5 << 4) | (0x55 << 8);
        UCA0CTLW0 &= ~UCSWRST;
    
        uart_tx_active = false;
    
        UCA0IFG = 0;
        UCA0IE = UCRXIE | UCTXIE;
    }
    
    size_t uart_putc(char c) {
        size_t ret = 0;
        __dint();
        if (uart_tx_active) {
            // Transmission is in progress, character will be taken out of the buffer when the current one has been sent
            size_t read_index = uart_tx_buffer_read_index;
            size_t write_index = uart_tx_buffer_write_index;
            if (((write_index + 1) & UART_TX_BUFFER_INDEX_MASK) == read_index) {
                // Buffer full
                ret = 0;
                goto reenable_interrupts;
            }
            uart_tx_buffer[write_index] = c;
            uart_tx_buffer_write_index = (write_index + 1) & UART_TX_BUFFER_INDEX_MASK;
            ret = 1;
            goto reenable_interrupts;
        } else {
            // Transmission not in progress
            uart_tx_active = true;
            UCA0TXBUF = c;
            ret = 1;
            goto reenable_interrupts;
        }
    reenable_interrupts:
        __eint();
        return ret;
    }
    
    size_t uart_puts(char *str) {
        size_t len = 0;
        while (*str != '\0') {
            size_t transmitted = uart_putc(*str);
            if (transmitted == 0) {
                break;
            }
            str++;
            len++;
        }
        return len;
    }
    
    static size_t uart_tx_buffer_getc(char *c_out) {
        size_t read_index = uart_tx_buffer_read_index;
        if (read_index == uart_tx_buffer_write_index) {
            return 0;
        }
        *c_out = uart_tx_buffer[read_index];
        uart_tx_buffer_read_index = (read_index + 1) & UART_TX_BUFFER_INDEX_MASK;
        return 1;
    }
    
    static size_t uart_rx_buffer_putc(char c) {
        size_t write_index = uart_rx_buffer_write_index;
        if (((write_index + 1) & UART_RX_BUFFER_INDEX_MASK) == uart_rx_buffer_read_index) {
            // Buffer full
            return 0;
        }
        uart_rx_buffer[write_index] = c;
        uart_rx_buffer_write_index = (write_index + 1) & UART_RX_BUFFER_INDEX_MASK;
        return 1;
    }
    
    size_t uart_getc(char *c_out) {
        // No need to __dint() since uart_rx_buffer_write_index is read in a single cycle
        __dint();
        size_t write_index = uart_rx_buffer_write_index;
        __eint();
        size_t read_index = uart_rx_buffer_read_index;
        if (read_index == write_index) {
            return 0;
        }
        *c_out = uart_rx_buffer[read_index];
        uart_rx_buffer_read_index = (read_index + 1) & UART_RX_BUFFER_INDEX_MASK;
        return 1;
    }
    
    __attribute__((interrupt(EUSCI_A0_VECTOR)))
    void isr_USCI_A0(void) {
        uint16_t source = UCA0IV;
        switch (source) {
            case UCIV__UCRXIFG: {
                uint16_t stat = UCA0STATW;
                // Reading from UCAxRXBUF automatically clears any receive error flags
                uint8_t data = UCA0RXBUF;
                // Discard data if any error occurred
                if (!(stat & UCRXERR)) {
                    uart_rx_buffer_putc(data);
                }
    
                __low_power_mode_off_on_exit();
                break;
            }
            case UCIV__UCTXIFG: {
                char next_c;
                size_t l = uart_tx_buffer_getc(&next_c);
                if (l > 0) {
                    UCA0TXBUF = next_c;
                } else {
                    uart_tx_active = false;
                }
                break;
            }
        }
    }
    
    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 * MCLK_FREQ_MHZ);// 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
    }
    
    void init_clocks() {
        __bis_SR_register(SCG0);                // disable FLL
        CSCTL3 = SELREF__REFOCLK;              // Set REFO as FLL reference source
        CSCTL1 = DCOFTRIMEN_1 | DCOFTRIM0 | DCOFTRIM1 | DCORSEL_3;// DCOFTRIM=3, DCO Range = 8MHz
        CSCTL2 = FLLD__1 | (243 & FLLN);                  // DCODIV = 8MHz
        __delay_cycles(3);
        __bic_SR_register(SCG0);                // enable FLL
        Software_Trim();                        // Software Trim to get the best DCOFTRIM value
    
        CSCTL4 = SELMS__DCOCLKDIV | SELA__REFOCLK; // set default REFO(~32768Hz) as ACLK source, DCODIV as MCLK and SMCLK source
    }
    
    static void set_up_io_defaults() {
        // The MSP430FR2xx family user's guide specifies:
        //   - Unused IOs should be configured as outputs and driven low to reduce power consumption
        //   - PxDIR, PxREN, PxOUT and PxIES have undefined values after power up
    
        P1DIR = 0xff;
        P1REN = 0x00;
        P1OUT = 0x00;
        P1IES = 0x00;
    
        P2DIR = 0xff;
        P2REN = 0x00;
        P2OUT = 0x00;
        P2IES = 0x00;
    
        P3DIR = 0xff;
        P3REN = 0x00;
        P3OUT = 0x00;
        P3IES = 0x00;
    
        P4DIR = 0xff;
        P4REN = 0x00;
        P4OUT = 0x00;
        P4IES = 0x00;
    
        P5DIR = 0xff;
        P5REN = 0x00;
        P5OUT = 0x00;
        P5IES = 0x00;
    }
    
    static void enable_port_interrupts() {
        // Clear all PxIFGs to avoid erroneous port interrupts
        P1IFG = 0x00;
        P2IFG = 0x00;
        P3IFG = 0x00;
        P4IFG = 0x00;
        P5IFG = 0x00;
    
        P1IE = 0x00;
        P2IE = 0x00;
        P3IE = 0x00;
        P4IE = 0x00;
        P5IE = 0x00;
    }
    
    int main(void) {
        // Disable the watchdog timer
        WDTCTL = WDTPW | WDTHOLD;
    
        init_clocks();
    
        set_up_io_defaults();
    
        uart_init_io();
    
        // Disable the GPIO power-on default high-impedance mode to activate previously configured port settings
        PM5CTL0 &= ~LOCKLPM5;
    
        uart_enable();
    
        enable_port_interrupts();
    
        __eint();
    
        __delay_cycles(10000);
    
        uart_puts("Initialization done\r\n");
        uart_puts("0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ\r\n");
    
        while (1) {
            uart_putc('~');
    
            char c;
            size_t len = uart_getc(&c);
    
            if (len > 0) {
                uart_putc(c);
            }
    
            __low_power_mode_0();
        }
    }
    
    

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

    默认情况下、它不支持奇偶校验。 您可以尝试以下设置来启用它。

    有关更多详细信息、请参阅此文档:www.ti.com/.../slau647o.pdf