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.

Interrupt-driven UART I/O best practice...

Other Parts Discussed in Thread: MSP430FR5969

Hi,

Another "getting back into MSP430s" question...

I''ve been using the backchannel UART with putty to message to-and-fro with an MSP430FR5969 Launchpad... all working fine... I'm using CCS 6.2 with a fully-licensed TI compiler & the latest driverlib/MSPware & C++ (not C).

The UART example that comes with driverlib has the EUSCI_A_UART_receiveData call in the USCI_A0_VECTOR ISR under USCI_UART_UCRXIFG UCA0IV case statement.

All well & good, except the ULP Advisor complains about it (understandably) as really, best practice should be to set a flag in the ISR and then to act on that in the main loop outside of LPM... the driverlib example is simplistic and not an exemplar.

I'm concerned about not dropping characters if I move the RX read outside of the ISR.... I'm thinking that for both USCI_UART_UCRXIFG & USCI_UART_UCTXIFG I should set an appropriate volatile flag and cancel LPM, then in the main loop, if there is RX data, read a byte, then check tx ready, and if OK send a byte, then process other stuff and if nothing left to do, go back into LPM3.x

It would seem sensible to always read data first (before trying to write) as that would help stop dropping characters. "other stuff" would seeing if the read buffer now contained a sensible string, e.g. a GPS NMEA sentence, and then processing it...

However, I'm still nervous about data loss when processing something that takes a while in the main code - I might lose input characters...

Is this scheme flawed, or is there a decent, interrupt-driven, TX/RX example of best practice?

Thanks

  • Nick de Smith said:
    best practice

    In order to not loose any characters you should definitely use the receive interrupt. This interrupt can write the incoming data into a buffer that can be processed once a complete message was received. For example a message ends with 0x0A (line feed). Now the controller can sleep until a byte arrives that causes an interrupt. Save the byte into a receive buffer and increment an index for the next byte. Check if it was 0x0A - if not, go to sleep. This goes on until 0x0A was received - now exit the low power mode and process the data.

    This is only one example, of course. If you do not use the low power mode you can also set a flag to signal the main that data has to be processed. If receiving of data continues during processing the other, you may need a pointer that points to the start of the message inside the buffer. The "end" character could also be a fixed bytecount if known. The best practice depends on the application. A so called "ring buffer" or "circular buffer" is a good way, but not always necessary.

    Nick de Smith said:
    It would seem sensible to always read data first (before trying to write) as that would help stop dropping characters.

    Even the MSP treats receiving with a higher priority as sending, so a RX interrupt will always be serviced before the TX interrupt.

    Nick de Smith said:
    However, I'm still nervous about data loss when processing something that takes a while in the main code

    Always remember that UART is a pretty slow communication, even at higher baudrates. This does not mean that is impossible to loose data, but I never experienced this myself. When using an ISR to save the byte, you will not loose anything. Except you have other ISRs that take too long, of course. But in this case your other ISRs are programmed wrong.

  • Nick de Smith said:

    However, I'm still nervous about data loss when processing something that takes a while in the main code - I might lose input characters...

    Is this scheme flawed, or is there a decent, interrupt-driven, TX/RX example of best practice?

    UART interrupts should be very light. RX interrupt should store received byte (few CPU cycles) to circular buffer (big enough to not lose any characters). Received information (for example 128 bytes) can be analyzed (after wake up) inside main. Sending should be triggered from main, and flushed by TX interrupt (few CPU cycles).

    I made dual CDC / UART bridge based on MSP430F5xx family with USB module that can go over 1 Mbps without problems, in full duplex, with both bridges active. There was TI open source example for the same thing inside TI USB stack, that was remove later. It was working, but from my point of view, implemented on wrong way. My point is, if you want to see how things can be done, use TI open source examples, but if you want the real thing, than you must do it by yourself.

  • Both my TX and RX UART routines are tiny ISR.
    for TX, I set up dual memory pointers and length, and then enable IE2
    and off it goes sending one or two chucks of byte blocks.

    RX it just fills in a buffer, as TX routine always reset the RX's buff pointer I have to play ping pong nicely and parse data accordingly.

**Attention** This is a public forum