Author Topic: Uart Question  (Read 9651 times)

Offline neil

  • Sr. Member
  • ****
  • Posts: 438
    • View Profile
Uart Question
« on: September 07, 2007, 08:46:49 PM »
Hi,
  When any of the 3 uarts are setup (in 52235) to be used for DMA or interupt driven. I would like to check to make sure any previous data within buffer has been fully sent before sending next one, how do I do this?  This will prevent me of having a large buffer, preventing overflow.

Regards
Neil

Offline mark

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 3236
    • View Profile
    • uTasker
Re: Uart Question
« Reply #1 on: September 07, 2007, 10:21:00 PM »
Hi Neil

When you call the write - fnWrite(serial_handle, buffer, length); it will copy the buffer to the tty output queue (its length is defined when opening the serial interface (tInterfaceParameters.Rx_tx_sizes.TxQueueSize = TX_BUFFER_SIZE;)).

If not set for DMA it will work with interrupts or else it will transfer blocks using DMA. It will continue sending the queue contents until it becomes empty – you can perform more writes while transmission is in progress since the contents will be added to the TTY output queue and sent in the serial stream as soon as previous bytes or blocks have been sent.

If you try to send more data that there is place in the queue it will copy as much as it can and the rest will be lost (overflow). This is not a problem for printf type debug outputs but in critical cases it may be necessary to check the available space and wait if there is not adequate space (increasing the buffer size helps but memory is quite expensive in some applications).

 
The tx buffer size has in fact been set to be quite small in the uTasker demo project to illustrate how this work. The menu which is displayed (when hitting the Enter key) is much larger than the available buffer space and so the menu is in fact built up in several steps when space becomes available again. You can see how it is used in debug.c:

 

if (!fnWrite(DebugHandle, 0, MAX_MENU_LINE)) {
    ....
}


 

Calling the write with a zero pointer and a length to be checked, will return the available space (after the advertised length were copied). If the returned space is zero, the calling task calls:

fnDriver( DebugHandle, MODIFY_WAKEUP, (MODIFY_TX | OWN_TASK) );

This sets itself to be woken by an interrupt (TX_FREE) when the buffer space reduces to the low water mark (tInterfaceParameters.ucFlowLowWater).

The TX_FREE interrupt which later wakes the task is used to continue with the menu output (the same technique is in fact used with TCP flow control, for example when TELNET buffer is full).

 

Note that the flow control high and low water marks can be configured when SUPPORT_FLOW_HIGH_LOW is enable – else they are fixed values.

For the TX_FREE support to be used, WAKE_BLOCKED_TX must be activated (both are already active in the demo project configuration).

In your particular case you can set tInterfaceParameters.ucFlowLowWater to 0. If you need to wait for the TX_FREE it will then be sent when the output buffer is completely free (as long as you do have a little extra space in the output buffer you can of course set tInterfaceParameters.ucFlowLowWater to a higher value so that you can already prepare the tx data so that it is immediately sent in the tx stream. This value is 0..100 and is means the % level in the buffer.
Also polling with the following would recognise when the message has been fully transmitted (when the tx buffer becomes completely free):
if (fnWrite(DebugHandle, 0, 0) == TX_BUFFER_SIZE) {
  // buffer completely free now
}


Regards

Mark