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.

MSPM0G3519: How to Flush the UART Tx and Rx FIFO?

Part Number: MSPM0G3519

Tool/software:

We are using Single wire UART communication for our application, So trying to Disable Rx during Transmit and Vice versa.

In one of the thread it was suggested to configure the Rx pin as GPIO Input during transmit and vice versa to isolate the communication and it was suggested to flush the FIFO as well.

But I'm not sure how we can flush the FIFO in this micro, We don't have any registers to clear the data as per the TRM, How can we clear the FIFO?

Currently we are reconfiguring the Rx pin as GPIO and we are still facing some issue. Do we have a different approach recommended for MSPM0G3519 micro?

I have shared a thread below which i was used as reference,

MSPM0G1507: UART0 Half Duplex IRDA issues - Arm-based microcontrollers forum - Arm-based microcontrollers - TI E2E support forums

  • Flushing the Tx FIFO can be done by setting CTL0:FEN=0 then =1 [Ref TRM (SLAU846B) Sec 18.3.28. Since you have control over the Tx FIFO contents you could also wait until STAT:TXFE=1.

    Flushing the Rx FIFO would be done by reading (and throwing away) RXDATA until STAT:RXFE=1 [Ref TRM Table 18-43]. (Once you disconnect the pin from the UART you won't get any new Rx FIFO entries.)

  • Flushing the Rx FIFO would be done by reading (and throwing away) RXDATA until STAT:RXFE=1 [Ref TRM Table 18-43]. (Once you disconnect the pin from the UART you won't get any new Rx FIFO entries.)

    When I change the Port configuration to GPIO, Frame Error and Break Error being set and I'm not getting the RX interrupt after changing it back to UART. It goes to overrun and then the errors are getting cleared. After that Rx is working for me.

    And sometimes during transmit, Tx interrupt is not received, at that time Busy bit was SET and Tx FIFO is also empty but there is no interrupt so it got stuck waiting for that interrupt.

    Can you suggest a solution please?

  • If you want to actually send the Tx data (rather than throwing it away) you should probably not flush the Tx FIFO and rather wait (spin?) until STAT:TXFE=1 and STAT:BUSY=0. (STAT:BUSY should be enough, but I don't know whether there are any moments when BUSY=0 between bytes.)

    I'm not too surprised if disconnecting the pin (mid-Rx-byte) would cause a framing error, but I don't expect the UART to get stuck because of it (since the error is stored with the byte). What sequence are you using? Is there a way for you to tell if the Rx (from the other end) is idle before you do this?

  • Yes, Rx on the other end is idle. Right now, I'm just using a terminal to send/receive the data on the other end.

    So, there is no data on the other end.

  • Sometimes During transmit, when we do the port configuration to GPIO Input, Busy bit was set and it's not getting cleared.

    After transmit is called, Tx interrupt is not getting triggered, so UART is getting stuck, Data was not transmitting or receiving at this point, How to do the recovery at this point?

  • I'm not sure I understand the sequence you're using. Are you setting/clearing CTL0:RXE/TXE as needed?

  • Also, what terminal emulator are you using? I haven't found one that does one-wire.

    -----

    I tried a naive hack of a copy of uart_echo_interrupts to connect the pins dynamically, and I don't see any unusual symptoms. 

    .c

    // UART IOMUX experiment.
    // Author: Bruce McKenney, 2025. No warranty, no support. I may not even exist.
    // Started life as TI example uart_echo_interrupts, which is
    // Copyright (c) 2020, Texas Instruments Incorporated
    
    #include "ti_msp_dl_config.h"
    
    #define IOMUX_PF_GPIO   1
    volatile uint8_t gEchoData = ':';
    uint8_t dummy[1];       // bit-bucket
    
    inline void
    switch_iomux(uint32_t IOPIN, uint32_t PF)
    {
        IOMUX->SECCFG.PINCM[IOPIN] = (IOMUX->SECCFG.PINCM[IOPIN] & ~IOMUX_PINCM_PF_MASK)
                                       | IOMUX_PINCM_INENA_ENABLE | PF;
        return;
    }
    
    int
    main(void)
    {
        SYSCFG_DL_init();
    
        NVIC_ClearPendingIRQ(UART_0_INST_INT_IRQN);
        NVIC_EnableIRQ(UART_0_INST_INT_IRQN);
        switch_iomux(GPIO_UART_0_IOMUX_RX, IOMUX_PF_GPIO);  // Disconnect Rx
        switch_iomux(GPIO_UART_0_IOMUX_TX, IOMUX_PINCM21_PF_UART0_TX);  // Connect Tx
        DL_UART_Main_transmitData(UART_0_INST, gEchoData);  // Tell 'em we're here
    
        while (1) {
            __WFI();
        }
    }
    
    void UART_0_INST_IRQHandler(void)
    {
        switch (DL_UART_Main_getPendingInterrupt(UART_0_INST)) {
        case DL_UART_MAIN_IIDX_EOT_DONE:
            switch_iomux(GPIO_UART_0_IOMUX_TX, IOMUX_PF_GPIO);              // Disconnect Tx
            while (DL_UART_receiveDataCheck(UART_0_INST, &dummy[0])) {/*EMPTY*/;} // Drain Rx FIFO
            switch_iomux(GPIO_UART_0_IOMUX_RX, IOMUX_PINCM22_PF_UART0_RX);  // Connect Rx
            break;
        case DL_UART_MAIN_IIDX_RX:
            DL_GPIO_togglePins(GPIO_LEDS_PORT, GPIO_LEDS_USER_LED_1_PIN | GPIO_LEDS_USER_TEST_PIN);
            gEchoData = DL_UART_Main_receiveData(UART_0_INST);
            switch_iomux(GPIO_UART_0_IOMUX_RX, IOMUX_PF_GPIO);              // Disconnect Rx
            //  We know the Tx FIFO is empty
            switch_iomux(GPIO_UART_0_IOMUX_TX, IOMUX_PINCM21_PF_UART0_TX);  // Connect Tx
            DL_UART_Main_transmitData(UART_0_INST, gEchoData);
            break;
         default:
            break;
        }
    }
    

    .syscfg

    /**
     * These arguments were used when this file was generated. They will be automatically applied on subsequent loads
     * via the GUI or CLI. Run CLI with '--help' for additional information on how to override these arguments.
     * @cliArgs --device "MSPM0G350X" --part "Default" --package "LQFP-64(PM)" --product "mspm0_sdk@2.04.00.06"
     * @v2CliArgs --device "MSPM0G3507" --package "LQFP-64(PM)" --product "mspm0_sdk@2.04.00.06"
     * @versions {"tool":"1.21.0+3721"}
     */
    
    /**
     * Import the modules used in this configuration.
     */
    const GPIO   = scripting.addModule("/ti/driverlib/GPIO", {}, false);
    const GPIO1  = GPIO.addInstance();
    const SYSCTL = scripting.addModule("/ti/driverlib/SYSCTL");
    const UART   = scripting.addModule("/ti/driverlib/UART", {}, false);
    const UART1  = UART.addInstance();
    
    /**
     * Write custom configuration values to the imported modules.
     */
    GPIO1.$name                          = "GPIO_LEDS";
    GPIO1.associatedPins.create(2);
    GPIO1.associatedPins[0].$name        = "USER_LED_1";
    GPIO1.associatedPins[0].assignedPort = "PORTA";
    GPIO1.associatedPins[0].initialValue = "SET";
    GPIO1.associatedPins[0].assignedPin  = "0";
    GPIO1.associatedPins[0].pin.$assign  = "PA0";
    GPIO1.associatedPins[1].$name        = "USER_TEST";
    GPIO1.associatedPins[1].assignedPort = "PORTA";
    GPIO1.associatedPins[1].assignedPin  = "15";
    GPIO1.associatedPins[1].initialValue = "SET";
    
    const Board           = scripting.addModule("/ti/driverlib/Board", {}, false);
    Board.configureUnused = true;
    
    SYSCTL.forceDefaultClkConfig = true;
    SYSCTL.clockTreeEn           = true;
    
    UART1.$name                        = "UART_0";
    UART1.rxFifoThreshold              = "DL_UART_RX_FIFO_LEVEL_ONE_ENTRY";
    UART1.enableDMARX                  = false;
    UART1.enableDMATX                  = false;
    UART1.uartClkSrc                   = "LFCLK";
    UART1.ovsRate                      = "3";
    UART1.enabledInterrupts            = ["EOT_DONE","RX"];
    UART1.peripheral.$assign           = "UART0";
    UART1.peripheral.rxPin.$assign     = "PA11";
    UART1.peripheral.txPin.$assign     = "PA10";
    UART1.txPinConfig.$name            = "ti_driverlib_gpio_GPIOPinGeneric0";
    UART1.txPinConfig.enableConfig     = true;
    UART1.txPinConfig.internalResistor = "PULL_UP";
    UART1.rxPinConfig.$name            = "ti_driverlib_gpio_GPIOPinGeneric1";
    UART1.rxPinConfig.enableConfig     = true;
    UART1.rxPinConfig.internalResistor = "PULL_UP";
    
    /**
     * Pinmux solution for unlocked pins/peripherals. This ensures that minor changes to the automatic solver in a future
     * version of the tool will not impact the pinmux you originally saw.  These lines can be completely deleted in order to
     * re-solve from scratch.
     */
    GPIO1.associatedPins[1].pin.$suggestSolution = "PA15";
    Board.peripheral.$suggestSolution            = "DEBUGSS";
    Board.peripheral.swclkPin.$suggestSolution   = "PA20";
    Board.peripheral.swdioPin.$suggestSolution   = "PA19";
    

  • No, We are not doing anything on the CTL0 register.

  • Do you want us to enable and disable Rx and Tx accordingly.?

  • We are using Docklight.

    Single wire is handled via external circuit, we have a circuit that converts 2 wire to 1 wire and vice versa on both ends.

  • Below is the Sequence followed for single wire UART,

    Initially UART will be in receive mode (Tx INT is disabled and Rx INT alone was enabled). It's a Request and Send data flow, So UART will always be in receive and transmit will only happen if the data is received. Based on the command the response will vary.

    When a command was received via UART, Rx INT will be disabled, next port mode will be changed to GPIO and then Transmit API will be called.

    Again in the UART Tx Interrupt, callback will be provided and port mode will be changed to UART again, Tx interrupt will be disabled then Rx INT will be enabled to receive the next command.

    This flow continues for each command.

  • Working with RXE/TXE seemed like one possible answer until I (1) tried the code above (which doesn't do anything with RXE/TXE) and saw no ill effects from leaving RXE/TXE=1 all the time and (2) noticed Erratum UART_ERR_02 [Ref Errata (SLAZ758B) p. 18], wherein EOT stops working if RXE=0.

    I (now) suggest you Not change TXE/RXE.

  • I'm not familiar with Docklight. Does the Tap do the electrical direction-reversal? (I'm imagining something like an RS-485 chip.)

  • 1) "next port mode will be changed to GPIO": Does this mean (1) Rx pin set to GPIO then (2) Tx pin set to UART? (As seen above.)

    2) "in the UART Tx Interrupt, [...] port mode will be changed to UART". The Tx interrupt happens when the byte is moved to the shift register, which is probably too early. EOT (or BUSY) indicates when both the FIFO and the shift register are empty.

  • 1)Yes, Rx pin was set to GPIO, Tx pin was always set to UART.  We are trying to eliminate the loopback data and Tx will only happen after receiving the command, so Tx pin was not reconfigured.

    2)Port Mode again changed to UART in the callback and callback will only be triggered when all the data were transmitted and Tx interrupt was disabled before the callback.

  • If you leave the Tx pin connected all the time, what prevents it from driving the (shared) wire when it's idle? How does the line turnaround happen?

  • We are disabling the Tx interrupt and not allow transmit when rx is in process, this is done with busy bit implementation.

  • We are able to resolve this issue by enabling Frame and Break error interrupts and flushing the FIFO (Reading the Rx FIFO until its empty) in the Frame/break error interrupts. Both Frame and Error interrupts were also cleared after setting the pinmode to GPIO before transmitting.

    Thank you for the support