2

Possible Duplicate:
UART ISR Tx Rx Architecture

I'm working with a TI micro right now that includes a DMA UART Driver and an operating system that supports parallel tasks. The UART driver's functions include:

  • static void HalUARTInitDMA(void);
  • static void HalUARTOpenDMA(halUARTCfg_t *config);
  • static uint16 HalUARTReadDMA(uint8 *buf, uint16 len);
  • static uint16 HalUARTWriteDMA(uint8 *buf, uint16 len);
  • static void HalUARTPollDMA(void);
  • static uint16 HalUARTRxAvailDMA(void);
  • static void HalUARTSuspendDMA(void);
  • static void HalUARTResumeDMA(void);

I'm trying to communicate with another peripheral that accepts messages terminated with a carriage return and responds with messages afterwards with a carriage return.

I was curious what the best way to architect this type of communication state machine. My problem is designing the callback function for the UART port such that it...

  1. does not hang the system waiting for a response. (Some sort of timeout)
  2. If a response is read too soon, it will concat the responses together
  3. A carriage return will signify the end of the message

The basic theory is something like this:

//send messsage to peripheral
HalUARTWriteDMA("tx\r",4);

//wait a little bit for the device to process the message

//start reading from the peripheral    
do {
    //how many bytes are at the RX port?
    int len = HalUARTRxAvailDMA();

    //Read those bytes
    HalUARTReadDMA(msg, len);

    //append the rx msg to the buffer
    strcat(rxbuf, msg)

    //does the response contain a CR?
} while(strchr(rxbuf, 0x0D));

There are a couple of obvious flaws with this idea. I was hoping someone could share some ideas on how this type of communication is performed?

Thanks!

Community
  • 1
  • 1
Jonathan
  • 1,498
  • 2
  • 20
  • 41
  • The basic algorithm is fine, especially to get it up and running (keep it simple); ideally, this would be implemented as an ISR that is triggered on data arrival at the UART (maybe it is, can't tell from code), so you're not constantly spinning on the arrival of data. Even if there's a preemptive OS that keeps the thread from hogging the CPU, you'll at least be drawing more power than necessary. At the very least, you might put a sleep() in the loop to reduce CPU/power usage and only process the 2nd 2 lines if len > 0. Haven't done embedded in a couple years so this is comment not an answer;-) – Mark Stevens Oct 22 '12 at 01:55
  • So right now, with the DMA driver, there is a callback function that gets called on the arrival of a UART message. Although this is not using the ISR, I have the feeling it's similar to how ISR is implemented. The thought is still in the back of my mind as to whether I should ditch the DMA and implement ISR for simplicity sake. – Jonathan Oct 22 '12 at 13:56
  • Do you have an OS with threads and semaphores? – Martin James Oct 22 '12 at 23:06
  • The OS provided by TI has threads, but no semaphores or mutexes. They explain that the OS handles the threads in a 'round-robin' approach, so if you were to put a while(1){} in one of them, it would cause all the threads to halt. This leads me to believe that a new thread won't start until the previous thread finishes. – Jonathan Oct 23 '12 at 14:07
  • Weeks after I asked this question, I ended up rephrasing it and have a great discussion about it here: http://stackoverflow.com/questions/13520272/uart-isr-tx-rx-architecture – Jonathan Dec 03 '12 at 18:08
  • The question marked as duplicate has nothing to do with DMA which is the main point here. – Étienne Jul 10 '13 at 09:33

2 Answers2

1

There is one immediate problem with the design as you describe it if you intend to block the thread waiting for messages - which is the use variable sized messages and a CR as the delimiter.

I imagine that HalUARTReadDMA() is designed to block the calling thread until len bytes have been received so you clearly cannot reliably use it to block for a variable length message.

The code would look something like (making a few assumptions):

while (1) 
{
    static const size_t bufferSize = sizeof(Message_t);
    uint8_t buffer[bufferSize];

    // blocks until message received 
    unsigned len = HalUARTReadDMA(buffer, bufferSize);

    if (len == bufferSize)
        processMessage(buffer);
}

There's no particularly nice or reliable solution to the problem of using variable sized messages with DMA that doesn't involve polling - unless the DMA controller can detect end-of-message delimiters for you.
If you can't change the message format, you'd be better off with interrupt-driven IO in which you block on reception of individual message bytes - especially in the case of a UART, which has relatively low data rate.

marko
  • 9,029
  • 4
  • 30
  • 46
0

Unless your DMA driver has the functinality to accept a queue of buffer pointers, can generate an interrupt when a CR is received and move on its own to the next buffer pointer, you are going to be stuck with iterating the rx data, looking for a CR.

If you have to iterate the data, you may as well do it in a 'classic' ISR, fetching the chars one-by-one from the rx FIFO and shoving them into a buffer until a CR is received.

You could then queue the buffer pointer into a suitable circular queue, fetch another buffer from another circular pool queue of 'empty' buffers for the next message, signal a semaphore so that the thread that is going to handle the message will be run and exit from your ISR via the OS so that an immediate reschedule is performed.

The rx thread could dequeue the message, process it and then requeue it to the pool queue for re-use by the ISR.

Continually searching a complete buffer for a CR with strchr() is not likely to be particularly efficient or easy - the CR may be in the middle of the DMA buffer and you involve yourself with data copying of the remining partial buffer.

.

Martin James
  • 24,453
  • 3
  • 36
  • 60