[En-Nut-Discussion] Proposal: Extending the USART(AVR) driver to support DMA-style read functionality

Matthias Ringwald mringwal at inf.ethz.ch
Fri Apr 9 20:01:20 CEST 2004


Hi there.

I have a proposal that looks quite promising in our work of writing a 
bluteooth stack for Nut/OS
but might also be interesting to all of you doing packet-based 
communication.

first: the problem:

assume you do packet-based communication over the uart.
so, in the beginning of a packet, a length entry is to be found.
how would someone read that package?

I imaging the following code.
(I don't do any error checking, because... there's no way to recover
from an error in the bluetooth hci uart specification... and I assume 
that
the packet only gets processed after it is completely read,
maybe there is also a CRC at the end..)

u_char[MAX_PACKET_SIZE] myPacket;

main(){
... uart open & init
... create processPacketsThread
}

THREAD processPackets(){
	int lenght;
	int rc;
	u_char[2] buffer;
	u_char* ptr = myPacket;

	// read first two bytes
	read( uart, buffer, 1);
	read( uart, buffer+1, 1);
	
	length = buffer[0] + buffer[1] << 8;

	// now length is known, read all data
	while ( length > 0) {
		rc = read(uart, ptr, length);
		length -= rc;
		ptr += rc;
	}

	// packet ready
	processPacket...
}

ok. the interesting part is the while loop.
what happens, if the load on the processor is low
(or the thread has a high priority)?

for every received byte, the thread would wake up,
get its one byte, figure out that the packet is not finished
call read and be put to sleep again.

it should be clear that this is not very efficient... :)

a/my solution:

I would like to add an ioctl call that changes the semantic
of read from
[current]: at least one byte is read or timeout occured to
[new:] all bytes are read or timeout occured.
(if timeout occured, the return value [nr of read bytes]
would be lower then the count value)

I call this DMA read because the uart driver then would write the byte
directly into the buffer provided by the app, instead of the ringbuffer.
(hence, avoiding a lot of task switches, and buffer copying).

to implement this, one check has to be added to the uart
rx complete function:
...
if ( DMA_bytes_to_read)
{
	store byte directly into app buffer
	DMA_bytes_to_read--;
	DMA_ptr++;
	// also realize that no flowcontrol is needed here
	// because there's always the ringbuffer waiting...
	return;
}

the code in UsartRead() is a bit tricky, as all bytes from ringbuffer 
need to
be copied to app buffer before switching to DMA mode.
but to me it is  clear how to write this.

the benefit of this is:
reducing the number of read calls reduces the nr of thread
switches, which leads to savings in processing power depending
on the cpu load and the packet size.

I will implement this soon, and (maybe) do some speed comparisons
and/or throughput tests like loop-back data from uart0 to uart1
from/to my 4port high speed serial pci card (921600 baud max..) :)


thanks for reading, I"m open for comments,
matthias




More information about the En-Nut-Discussion mailing list