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.

Passing Data between two internal UARTs

Hello,

I am trying to pass data internally between two UARTs- for example, Rx data from UART0 goes to Tx on UART1, and Rx data from UART1 goes to Tx on UART0.  I'm basically a passthrough for UART data between two peripherals.  I've been simply putting the incoming data into buffers and then transferring the data from those buffers periodically, but with heavy data flow I can't keep up.  Is there a way to directly pass this UART data through, or do I need to set up uDMA for this traffic?

Thanks!

Cindy

  • Such analysis seems to make assumptions the data source is of constant flow as if it never has NUL time and or the RX side ring buffer a threshold. Not seeing posted pass through buffer size only stated TX/RX - anything less total 8192KB seemingly bates trouble absent CTS/RTS. The threshold of said buffer comes into play and that has to be restrictive, no less the 256 bytes. BTW 115200 baud is a turtle slow serial rate where other priority tasks may be in play, who even knows absent interrupt priority list being posted. Where my USBprinf is accelerating data into Windows client up to 480KBPS with less than 2049KB of TX buffer. There are some trade offs USB usage of (uint8_t) versus (char) and questions as to why Tivaware would suddenly switch away from the convention so tried and true Stellarisware set down.

    That said much of TI example code encourage HWREGBITW macros for blocking, seems absent any thought of speed where a simple Boolean switch has far superior instruction times. Not to forget personal struggles and numerous bus fault exceptions 11 resulting mostly from timing about such macro flags and ring buffer conditions. Albeit Ethernet speed is far greater than UART serial data rates. Changing the serial baud rate may lead to causality and effect scenarios helping to enlighten the human visual senses. No one said either side of the pass-through was rate restrictive and or had to be exactly the same on either side, it was only a easier configuration and suggestion 1:1, the exact ratio in the end has to be determined.

    Seems more than on a few occasions some forum members of late choose rushing to personal condemnation and judgment rather than offer creative solutions or quick WA.  

  • There has NEVER been "personal condemnation" - there has been (proper) identification of suggestions which appear, "wildly off mark."   (i.e. {again} poster's operation "suffers" when she encounters, "High Data Rates."   Suggestion is (then) made to, "Increase that Data Rate.")   Should that pass unnoted?   Really?

    That suggestion was judged (unwise) almost hinted that proponent had "lost track" of poster's noting of, "suffering under high data rates."   And - in fact - far from "condemnation" was it not pointed out (by others - in your behalf) that this thread has, "gone on & on" which (may) explain (why) her key "high data rate identication" had been (apparently) totally missed?

    Are "unsound" suggestions to be wildly accepted - encouraged?   There's nothing "personal" - there's everything toward soundness...

  • >but with heavy data flow I can't keep up!
    That's no wonder the middle guy can't keep up when paddles alone can not push water faster than a propeller. Perhaps I missed the post indicating setting the date rate lower ruled out 115200 being to fast or slow. By the same token setting the rate 2400bps should avert any buffer over flow and or bus faults. The words (heavy data flow can't keep up), a vague and general description. The middle MCU Keeping up with ring buffer fetches/puts may have more to do with blocking turn around time and NVIC more than data rate alone.

    Good observation can only occur by doing a million and one things different than you already tried, before going insane not doing anything different "Albert Einstein." So if you believe gravity can bend light rays and everyone doubts you what is a scientists to do other than try again to prove causality in a different way for the millionth time, "The Source" Matrix I.

    Again setting the data rate even higher or perhaps even lower may reveal more than one hidden pipe rat lives in the middle.
  • We (still) suspect that "Danica" would (much) prefer "full Brakes" to, "No Brakes" - which does qualify as an apt (and most illustrative) impersonal, forum comparison.

  • >My process worked fine in all my normal situations- but when the other processor is printing constantly, I end up in the ISR for the majority of the time and the TM4C ends up unable to do anything.

    That's no wonder printing constantly in turtle speed 115200 the ISR is majority time being fired. Does not NVIC take priority over general embedded application read buffer pre-fetches, if so Robert confirmed what Cindy stated above. It took several changes of prop pitch my Mercruiser IO to stop the rats of cavitation. Once in slip all bets are off that ideal and even keel is gone for good.

    Happy Turkey Day Forum Folks!
  • Hello Again,

    So I took your advice and used a scope and a GPIO line to do some timing calculations. But first I considered how fast my input buffer (that is currently overflowing) could fill, given my baud rate of 115200. Since there are 10 bits per character (with overhead), I have a character rate of 11520, which means 86usec between characters, for a total of 0.089sec for a buffer of 1024 characters. So if I don't process that buffer within that amount of time, the buffer could overflow. In the original structure of my program, it took 6.3usec to process a character (worst case- given an interrupt firing for every character). So the actual processing of the UART input isn’t the problem.

    Looking through my code I found two obvious problem areas. First, my health checking. I timed it and it takes 0.1328 seconds. So my buffer will overflow if health checking is happening when there is heavy UART traffic. The second problem I found is the printing I am doing to my console (via another UART). I am using the TI supplied uartstdio.c routines without buffering. These routines are blocking and do time-consuming formatting. This is another area where my buffer will overflow if I'm printing a large amount of data to my console while there is heavy incoming UART traffic.

    I'm still working on a solution to the problem (I’ve modified the health checking so it isn't all done at one time, allowing the buffer to be cleared more frequently, and I'm only using the uarstdio.c routines in buffered mode and only when necessary for formatted printing). uDMA is still a possibility, as is lowering the baud rate of the UARTs. But just making the changes I’ve noted here, I have stopped the buffer overflow problems in all the tests I’ve run so far.

    Thanks again for suggesting the timing tests. They were edifying and let me see where the problems were and where they weren’t.

    And thanks for all the time you put into helping me in general!

    Cindy

  • Cynthia, I'll add some notes later on an alternate way to look at the problem with your latest information but for now let me give you a well done!

    Robert
  • Thank you so much! Any further insight you might have would be appreciated!

    Cindy :)
  • Cindy,
    Hopefully this edits reasonably.

    You appear to have 4 processes.
    Serial from UART0 to UART1
    Serial from UART1 to UART0
    Health check
    Console

    Your description seems to imply you are performing serial I/O in interrupts but the rest of the processing in some sort of loop where you process a bit of serial transfer then a bit of health then a bit of console I/O and repeat. There is no RTOS involved.

    If that's correct then I'm going to suggest you've reached the limits of that approach and you are currently applying successive ad hoc patches to keep it working.

    Consider instead a RTK/RTOS. There are free versions available. What they allow you to do is develop each process almost as if they were running on their own separate processor. This simplifies your task considerably. I.E. you do not break up the health process into small chunks of minimal time but rather develop as a natural continuous process. The question is, how do you keep your health process from blocking your serial processes as you have observed. The answer lies in the very problem you have observed and in the priorities of the processes.

    If the health process is running and thus prevents the serial process from running we are back to where we started. There are several approaches that can be used in an RTOS to deal with this. One is time slicing, each task gets a fraction of the available CPU time. This can work but has issues with wasted time and very short processes. The other major approach is priority based switching, tasks have a priority and whichever process with work to do that has the highest priority runs. So how to assign priorities to tasks? I'll go over two approaches. The one that seems a fairly obvious one to have a chance of success is called earliest deadlines first, whichever process must finish first has priority. This requires a fair amount of support to continuously update priorities as conditions change so most small RTOS use the next approach.

    This approach is to give each process a fixed priority. The big question this leaves for the designer is how to assign priorities. The answer is a technique called Rate Monotonic Analysis (RMA). The idea is to assign the highest frequency tasks the highest priority, note how this mirrors the EDF approach. Non periodic tasks are assigned based on their highest frequency.

    Since your health process runs relatively infrequently it gets the lowest priority, I suspect the console would be next and the serial processes would be highest.

    Now consider what happens when you are running in idle and the time comes to run the health process

    The health process starts
    A console character arrives. Console is now the highest runnable process and starts processing the character.
    A serial byte arrives. Serial process is now the highest runnable process and starts processing. You now have two processes waiting to run.
    Serial process finishes with byte and becomes non runnable. Processor switches to console and conti nues running
    Console finishes and becomes non runnable waiting for the next character.
    Health process resumes from where it was interrupted.

    Note that as far as the health process is concerned it appears to be on a slower processor.

    Robert

    And if you are using a RTOS it looks like you have your priorities inverted
  • Cynthia,

    There is no reason that your device should be unable to keep up with this task, since the data rate is the same on both sides.    I've moved data at much higher rates with slower devices.    115k means a char every 89us, or 1200 cpu clock cycles.   Interrupt handling time is 12 cycles, max.    The fact that you can't do this suggests that your software isn't right.

    Ideally, you would do this all with DMA.  That will keep up with anything.    Two sets of ping-pong buffers with an arbitration size of one.  

    If you want to do this with software,  there are a few things that you need to do -

    1. Fix your interrupt priorities - the UART has the tightest latency requirement, so it needs to be at a different, higher priority than all of the other handlers.   There is no reason for your health check to prevent UART processing.
    2. Set your FIFO thresholds - set the RX fifo thresholds low so that you have more time to clean out the FIFOs.
    3. Don't use blocking operations in interrupt handlers.
    4. Use greedy operations to make the best use of the interrupt overhead.
    5.  

    Some variation on this should get you there - 

    do {
    
    retry = 0;
    if ( U0RXFifo has data ) {
     if ( U1TXFIFO is full )  retry++;
     else {  move data from U0Rx to U1Tx }  
    }
    
    if ( U1RxFifo has data ) { 
     if ( U0TXFIFO is full )  retry++;
     else {  move data from U1Rx to U0Tx }  
    }
    
    } while(retry)
    
    clean interrupt flags as needed.
    
    

    do 

    if ( RX fifo has data ) 

  • Hi Robert,

    I agree that RTOS would be the way to go.  I came to that conclusion a while ago, but by that time, the powers that be weren't willing to a rework of a mostly working system.  I agree that I've probably reached the limits of the current approach.  The only reason the current situation is considered tolerable is that the communication throughput I've been struggling is not considered critical.

    If all goes as planned, there will eventually be another iteration of our board and a reworking of the software, and I'll use RTOS at the point.

    Thanks again for the timing advice.  Analyzing my system in that fashion really helped me!

    Cindy 

  • Thanks for your input- I did implement your suggestions, including servicing the UART in question separately and with a high priority and I added fifo processing.  Thanks for taking the time to lend me a hand!

    Cindy

  • Glad we could help Cindy,

    Beware of promised reworks, often it is "just small feature", "it'll be faster just to modify the existing, we wouldn't want to delay adding it to rework and debug something that works".

    Measuring actual performance is mandatory. I fight to keep spare pins for precisely that. It's not always possible but the attempt is worthwhile.

    Robert

    BTW, it's possible to add an RTOS incrementally, without an initial wholesale replacement. Your current loop becomes a task, and you carve out pieces into higher and lower priority tasks until the job is complete. That allows conversion while making other changes.